this patch fixes some crashes and lockups related to vga screen resize. removed the memimagedraw call from devvga's initdraw command, as it overdraws the screen after we notified the client in the size command. (we clear the screen in screensize instead) properly handle softscreen case in screensize(). the bug was that the old paged vga case set scr->paddr causing it in the vesa resize case to use VGAMEM() as the framebuffer. also free the old softscreen after we finished. scr->useflush was never reset in case you switch drivers from vesa to something else. clear the framebuffer in screensize() instead of in the initdraw command of devvga. add mtrr to vgalinearaddr() so all framebuffers including vesa benefit from it. vgavesa was changed to use /dev/realmode instead of the direct realmode() call so it works with realmode emulator (/n/sources/contrib/cinap_lenrek/realemu.tgz) use normal vgalinearaddr() to map the framebuffer. in case we want to use softscreen, we clear scr->paddr, scr->vaddr adn scr->apsize cause screensize() to allocate the softscreen for us and call our flush routine. flush does nothing if we dont use softscreen. Reference: /n/sources/patch/applied/vesa-softscreen-resize Date: Tue Mar 1 21:06:57 CET 2011 Signed-off-by: cinap_lenrek@gmx.de --- /sys/src/9/pc/screen.c Tue Mar 1 20:51:50 2011 +++ /sys/src/9/pc/screen.c Tue Mar 1 20:51:46 2011 @@ -21,6 +21,7 @@ Memdata gscreendata; Memimage *gscreen; +void *softscreen; VGAscr vgascreen[1]; @@ -44,43 +45,45 @@ screensize(int x, int y, int z, ulong chan) { VGAscr *scr; + void *oldsoft; lock(&vgascreenlock); + if(waserror()){ + unlock(&vgascreenlock); + nexterror(); + } + memimageinit(); scr = &vgascreen[0]; + oldsoft = softscreen; - /* - * BUG: need to check if any xalloc'ed memory needs to - * be given back if aperture is set. - */ if(scr->paddr == 0){ int width = (x*z)/BI2WD; + void *p; - gscreendata.bdata = xalloc(width*BY2WD*y); - if(gscreendata.bdata == 0) + p = xalloc(width*BY2WD*y); + if(p == nil) error("screensize: vga soft memory"); -/* memset(gscreendata.bdata, 0x72, width*BY2WD*y); /* not really black */ + softscreen = p; + gscreendata.bdata = p; + if(scr->dev && scr->dev->page){ + scr->vaddr = KADDR(VGAMEM()); + scr->apsize = 1<<16; + } scr->useflush = 1; - scr->paddr = VGAMEM(); - scr->vaddr = KADDR(scr->paddr); - scr->apsize = 1<<16; } - else + else{ gscreendata.bdata = scr->vaddr; + scr->useflush = scr->dev && scr->dev->flush; + } + scr->gscreen = nil; if(gscreen) freememimage(gscreen); - scr->gscreen = nil; - gscreen = allocmemimaged(Rect(0,0,x,y), chan, &gscreendata); + if(gscreen == nil) + error("screensize: gscreen"); vgaimageinit(chan); - if(gscreen == nil){ - unlock(&vgascreenlock); - return -1; - } - - if(scr->dev && scr->dev->flush) - scr->useflush = 1; scr->palettedepth = 6; /* default */ scr->gscreendata = &gscreendata; @@ -89,10 +92,18 @@ physgscreenr = gscreen->r; unlock(&vgascreenlock); + poperror(); + if(oldsoft) + xfree(oldsoft); + + memimagedraw(gscreen, gscreen->r, memblack, ZP, nil, ZP, S); + flushmemscreen(gscreen->r); if(didswcursorinit) swcursorinit(); drawcmap(); + + return 0; } @@ -528,6 +539,10 @@ scr->vaddr = (char*)scr->vaddr+x; scr->paddr = paddr; scr->apsize = nsize; + if(!waserror()){ + mtrr(npaddr, nsize, "wc"); + poperror(); + } } --- /sys/src/9/pc/vgavesa.c Tue Mar 1 20:51:57 2011 +++ /sys/src/9/pc/vgavesa.c Mon Mar 7 22:36:23 2011 @@ -19,36 +19,60 @@ #include #include "screen.h" +enum { + USESOFTSCREEN = 1, +}; static void *hardscreen; +static uchar modebuf[0x1000]; #define WORD(p) ((p)[0] | ((p)[1]<<8)) #define LONG(p) ((p)[0] | ((p)[1]<<8) | ((p)[2]<<16) | ((p)[3]<<24)) #define PWORD(p, v) (p)[0] = (v); (p)[1] = (v)>>8 #define PLONG(p, v) (p)[0] = (v); (p)[1] = (v)>>8; (p)[2] = (v)>>16; (p)[3] = (v)>>24 -extern void realmode(Ureg*); - static uchar* vbesetup(Ureg *u, int ax) { ulong pa; pa = PADDR(RMBUF); + memset(modebuf, 0, sizeof modebuf); memset(u, 0, sizeof *u); u->ax = ax; u->es = (pa>>4)&0xF000; u->di = pa&0xFFFF; - return (void*)RMBUF; + return modebuf; } static void vbecall(Ureg *u) { + Chan *creg, *cmem; + ulong pa; + + cmem = namec("/dev/realmodemem", Aopen, ORDWR, 0); + if(waserror()){ + cclose(cmem); + nexterror(); + } + creg = namec("/dev/realmode", Aopen, ORDWR, 0); + if(waserror()){ + cclose(creg); + nexterror(); + } + pa = PADDR(RMBUF); + devtab[cmem->type]->write(cmem, modebuf, sizeof modebuf, pa); u->trap = 0x10; - realmode(u); + devtab[creg->type]->write(creg, u, sizeof *u, 0); + devtab[creg->type]->read(creg, u, sizeof *u, 0); if((u->ax&0xFFFF) != 0x004F) error("vesa bios error"); + devtab[cmem->type]->read(cmem, modebuf, sizeof modebuf, pa); + poperror(); + cclose(creg); + poperror(); + cclose(cmem); } static void @@ -91,10 +115,13 @@ static void vesalinear(VGAscr *scr, int, int) { + Pcidev *pci; int i, mode, size; uchar *p; ulong paddr; - Pcidev *pci; + + if(hardscreen) + goto havehardscreen; vbecheck(); mode = vbegetmode(); @@ -139,11 +166,16 @@ if(size > 16*1024*1024) /* probably arbitrary; could increase */ size = 16*1024*1024; vgalinearaddr(scr, paddr, size); - hardscreen = scr->vaddr; - /* let mtrr harmlessly fail on old CPUs, e.g., P54C */ - if (!waserror()){ - mtrr(paddr, size, "wc"); - poperror(); + if(scr->apsize) + addvgaseg("vesascreen", scr->paddr, scr->apsize); + + if(USESOFTSCREEN){ + hardscreen = scr->vaddr; + +havehardscreen: + scr->paddr = 0; + scr->vaddr = 0; + scr->apsize = 0; } } @@ -153,11 +185,10 @@ int t, w, wid, off; ulong *hp, *sp, *esp; + if(hardscreen == nil) + return; if(rectclip(&r, scr->gscreen->r) == 0) return; - - hp = hardscreen; - assert(hp != nil); sp = (ulong*)(scr->gscreendata->bdata + scr->gscreen->zero); t = (r.max.x * scr->gscreen->depth + 2*BI2WD-1) / BI2WD; w = (r.min.x * scr->gscreen->depth) / BI2WD; @@ -165,6 +196,7 @@ wid = scr->gscreen->width; off = r.min.y * wid + (r.min.x * scr->gscreen->depth) / BI2WD; + hp = hardscreen; hp += off; sp += off; esp = sp + Dy(r) * wid;