From 8f634a6516caca0e4be875e696820a820e480cff Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 20 Oct 2000 00:19:51 +0000 Subject: Add VGA BIOS modes to Tiny-X Xvesa server --- hw/kdrive/trident/Imakefile | 4 +- hw/kdrive/trident/trident.c | 48 +- hw/kdrive/trident/trident.h | 5 +- hw/kdrive/vesa/Imakefile | 6 +- hw/kdrive/vesa/Xvesa.man | 25 +- hw/kdrive/vesa/vbe.c | 1344 ++++++++++++------------------------------- hw/kdrive/vesa/vbe.h | 141 ++--- hw/kdrive/vesa/vesa.c | 880 ++++++++++++++++++---------- hw/kdrive/vesa/vesa.h | 123 +++- hw/kdrive/vesa/vesainit.c | 2 +- hw/kdrive/vesa/vga.c | 240 ++++++++ hw/kdrive/vesa/vga.h | 61 ++ hw/kdrive/vesa/vm86.c | 697 ++++++++++++++++++++++ hw/kdrive/vesa/vm86.h | 165 ++++++ 14 files changed, 2339 insertions(+), 1402 deletions(-) create mode 100644 hw/kdrive/vesa/vga.c create mode 100644 hw/kdrive/vesa/vga.h create mode 100644 hw/kdrive/vesa/vm86.c create mode 100644 hw/kdrive/vesa/vm86.h diff --git a/hw/kdrive/trident/Imakefile b/hw/kdrive/trident/Imakefile index 838cca4d1..1f881a49d 100644 --- a/hw/kdrive/trident/Imakefile +++ b/hw/kdrive/trident/Imakefile @@ -1,5 +1,5 @@ XCOMM $XConsortium: Imakefile /main/10 1996/12/02 10:20:33 lehors $ -XCOMM $XFree86: xc/programs/Xserver/hw/kdrive/trident/Imakefile,v 1.4 2000/09/15 07:25:12 keithp Exp $ +XCOMM $XFree86: xc/programs/Xserver/hw/kdrive/trident/Imakefile,v 1.5 2000/09/19 23:49:55 keithp Exp $ KDRIVE=.. #include "../Kdrive.tmpl" @@ -7,7 +7,7 @@ SRCS = trident.c tridentdraw.c tridentcurs.c tridentstub.c OBJS = trident.o tridentdraw.o tridentcurs.o tridentstub.o -DEFINES = -DVESA +DEFINES = -DVESA /* -DUSE_PCI*/ INCLUDES = -I. $(KDINCS) -I$(KDRIVE)/fbdev -I$(KDRIVE)/vesa diff --git a/hw/kdrive/trident/trident.c b/hw/kdrive/trident/trident.c index df4e6cde9..7c8c9cc69 100644 --- a/hw/kdrive/trident/trident.c +++ b/hw/kdrive/trident/trident.c @@ -21,7 +21,7 @@ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ -/* $XFree86: xc/programs/Xserver/hw/kdrive/trident/trident.c,v 1.12 2000/09/27 20:46:36 keithp Exp $ */ +/* $XFree86: xc/programs/Xserver/hw/kdrive/trident/trident.c,v 1.13 2000/10/11 06:04:40 keithp Exp $ */ #include "trident.h" #define extern @@ -33,14 +33,32 @@ Bool tridentCardInit (KdCardInfo *card) { - int k; - char *pixels; + int k; + char *pixels; TridentCardInfo *tridentc; + CARD8 r39; tridentc = (TridentCardInfo *) xalloc (sizeof (TridentCardInfo)); if (!tridentc) return FALSE; + iopl (3); + tridentc->cop_base = (CARD8 *) KdMapDevice (TRIDENT_COP_BASE(card), + TRIDENT_COP_SIZE(card)); + tridentc->cop = (Cop *) (tridentc->cop_base + TRIDENT_COP_OFF(card)); + tridentc->mmio = FALSE; + r39 = tridentReadIndex (tridentc, 0x3d4, 0x39); + if (r39 & 1) + { + tridentc->mmio = TRUE; + r39 = tridentReadIndex (tridentc, 0x3d4, 0x39); + if ((r39 & 1) == 0) + { + ErrorF ("Trident: inconsisent IO mapping values\n"); + return FALSE; + } + } + #ifdef VESA if (!vesaInitialize (card, &tridentc->vesa)) #else @@ -51,11 +69,6 @@ tridentCardInit (KdCardInfo *card) return FALSE; } - iopl (3); - tridentc->cop_base = (CARD8 *) KdMapDevice (TRIDENT_COP_BASE(card), - TRIDENT_COP_SIZE(card)); - tridentc->cop = (Cop *) (tridentc->cop_base + TRIDENT_COP_OFF(card)); - tridentc->mmio = FALSE; #ifdef USE_PCI tridentc->window = (CARD32 *) (tridentc->cop_base + 0x10000); #else @@ -92,15 +105,32 @@ tridentScreenInit (KdScreenInfo *screen) if (tridents->vesa.mapping != VESA_LINEAR) screen->dumb = TRUE; tridents->screen = tridents->vesa.fb; + memory = tridents->vesa.fb_size; #else tridents->screen = tridentc->fb.fb; + memory = (2048 + 512) * 1024; #endif screen_size = screen->fb[0].byteStride * screen->height; - memory = (2048 + 512) * 1024; if (tridents->screen && memory >= screen_size + 2048) + { + memory -= 2048; tridents->cursor_base = tridents->screen + memory - 2048; + } else tridents->cursor_base = 0; + memory -= screen_size; +#if 0 + if (memory > screen->fb[0].byteStride) + { + screen->off_screen = tridents->screen + screen_size; + screen->off_screen_size = memory - screen_size; + } + else + { + screen->off_screen = 0; + screen->off_screen_size = 0; + } +#endif screen->driver = tridents; return TRUE; } diff --git a/hw/kdrive/trident/trident.h b/hw/kdrive/trident/trident.h index 15b64a01f..46ba6c0f6 100644 --- a/hw/kdrive/trident/trident.h +++ b/hw/kdrive/trident/trident.h @@ -21,7 +21,7 @@ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ -/* $XFree86: xc/programs/Xserver/hw/kdrive/trident/trident.h,v 1.6 2000/09/15 07:25:12 keithp Exp $ */ +/* $XFree86: xc/programs/Xserver/hw/kdrive/trident/trident.h,v 1.7 2000/10/11 06:04:40 keithp Exp $ */ #ifndef _TRIDENT_H_ #define _TRIDENT_H_ @@ -34,7 +34,6 @@ /* * offset from ioport beginning */ -#define USE_PCI #ifdef USE_PCI #define TRIDENT_COP_BASE(c) (c->attr.address[1]) @@ -219,6 +218,8 @@ typedef struct _tridentScreenInfo { #endif CARD8 *cursor_base; CARD8 *screen; + CARD8 *off_screen; + int off_screen_size; TridentCursor cursor; } TridentScreenInfo; diff --git a/hw/kdrive/vesa/Imakefile b/hw/kdrive/vesa/Imakefile index b891e70b3..4a30f94a0 100644 --- a/hw/kdrive/vesa/Imakefile +++ b/hw/kdrive/vesa/Imakefile @@ -1,10 +1,10 @@ -XCOMM $XFree86$ +XCOMM $XFree86: xc/programs/Xserver/hw/kdrive/vesa/Imakefile,v 1.2 2000/09/03 05:11:22 keithp Exp $ KDRIVE=.. #include "../Kdrive.tmpl" -SRCS = vesa.c vesainit.c vbe.c +SRCS = vesa.c vesainit.c vbe.c vga.c vm86.c -OBJS = vesa.o vesainit.o vbe.o +OBJS = vesa.o vesainit.o vbe.o vga.o vm86.o INCLUDES = -I. $(KDINCS) diff --git a/hw/kdrive/vesa/Xvesa.man b/hw/kdrive/vesa/Xvesa.man index 958934aa9..766ac8145 100644 --- a/hw/kdrive/vesa/Xvesa.man +++ b/hw/kdrive/vesa/Xvesa.man @@ -1,4 +1,4 @@ -.\" $XFree86$ +.\" $XFree86: xc/programs/Xserver/hw/kdrive/vesa/Xvesa.man,v 1.2 2000/09/03 05:11:22 keithp Exp $ .TH Xvesa 1 .SH NAME Xvesa \- VESA VBE tiny X server @@ -11,10 +11,13 @@ Xvesa \- VESA VBE tiny X server is a generic X server for Linux on the x86 platform. .B Xvesa doesn't know about any particular hardware, and sets the video mode by -running the video BIOS in VM86 mode. +running the video BIOS in VM86 mode. .B Xvesa therefore runs untrusted code with full priviledges, and is one of the most insecure X servers available. +.B Xvesa +uses both standard VGA BIOS modes and any modes advertised by a VESA 2.0 +BIOS if available. .B Run at your own risk. .SH OPTIONS In addition to the normal tiny-X server's options (to be described in @@ -28,9 +31,9 @@ specifies the VESA video mode to use. If mode is not supported by your BIOS and hardware, .B Xvesa will fail, hang your system, or make your monitor explode; you are on -your own. This option is ignored if the +your own. This option overrides any .B -screen -option was used. +options. .TP 8 .B -listmodes tells the server to list all supported video modes. If @@ -55,8 +58,11 @@ don't use a linear framebuffer even if one is available. You don't want to use this option. .TP 8 .B -swaprgb -pass RGB values in the order that works on my machine. Use this if +pass RGB values in the order that works on broken BIOSes. Use this if the colours are wrong in PseudoColor modes. +.TP 8 +.B -verbose +emit diagnostic messages during BIOS initialization and teardown. .SH KEYBOARD Xvesa handles the keyboard in the same manner as the .B Xfbdev @@ -69,10 +75,17 @@ assumed to be buggy. Allowing your users to run is a major security hole. Allowing yourself to run .B Xvesa is probably a mistake. +.B Xvesa +records the current BIOS mode when it starts and restores that mode on +termination; if the video card has been reprogrammed by another application, +the display will almost certainly be trashed. The alternative of saving and +restoring the complete video card state has proven unreliable on most video +cards. .SH SEE ALSO X(1), Xserver(1), xdm(1), xinit(1), Xfbdev(1). .SH AUTHORS The tiny-X server was written by Keith Packard, and the VESA driver was added by Juliusz Chroboczek who didn't realise what he was doing until it was too late. Tiny-X uses code from XFree86, which in turn -is based on the Sample Implementation. +is based on the Sample Implementation. Keith Packard then added support for +standard VGA BIOS modes and is especially proud of 320x200 16 color mode. diff --git a/hw/kdrive/vesa/vbe.c b/hw/kdrive/vesa/vbe.c index fa2fbeaa3..d4a2817c8 100644 --- a/hw/kdrive/vesa/vbe.c +++ b/hw/kdrive/vesa/vbe.c @@ -19,539 +19,409 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/* $XFree86$ */ +/* $XFree86: xc/programs/Xserver/hw/kdrive/vesa/vbe.c,v 1.5 2000/09/27 20:46:37 keithp Exp $ */ -#include -#include -#include -#include -#include -#include -#include -#include "vbe.h" +#include "vesa.h" -#ifdef NOT_IN_X_SERVER -#include -#include -#include -static void ErrorF(char*, ...); -#define xalloc(a) malloc(a) -#define xcalloc(a,b) calloc(a,b) -#define xfree(a) free(a) -#else -#include "X.h" -#include "Xproto.h" -#include "Xos.h" -#include "os.h" -#endif - -static int vm86old(struct vm86_struct *vms); -static int vm86_loop(VbeInfoPtr vi); - -static U8 rev_ints[32] = -{ 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0x80, -}; - -static U8 retcode_data[2] = -{ 0xCD, 0xFF }; - -#define LM(vi,i) (((char*)vi->loMem)[i-LOMEM_BASE]) -#define LMW(vi,i) (*(U16*)(&LM(vi,i))) -#define LML(vi,i) (*(U32*)(&LM(vi,i))) -#define MM(vi,i) (((char*)vi->magicMem)[i-MAGICMEM_BASE]) -#define MMW(vi,i) (*(U16*)(&MM(vi,i))) -#define MML(vi,i) (*(U32*)(&MM(vi,i))) -#define HM(vi,i) (((char*)vi->hiMem)[i-HIMEM_BASE]) -#define HMW(vi,i) (*(U16*)(&MM(vi,i))) -#define HML(vi,i) (*(U32*)(&MM(vi,i))) - -#define PUSHW(vi, i) \ -{ vi->vms.regs.esp -= 2;\ - LMW(vi,MAKE_POINTER(vi->vms.regs.ss, vi->vms.regs.esp)) = i;} - -VbeInfoPtr -VbeSetup() +int +VbeGetVib (Vm86InfoPtr vi, VbeInfoBlock *vib) { - int devmem = -1, devzero = -1; - void *magicMem, *loMem, *hiMem; - U32 stack_base, vib_base, vmib_base, ret_code; - VbeInfoPtr vi = NULL; - - devmem = open("/dev/mem", O_RDWR); - if(devmem < 0) { - perror("open /dev/mem"); - goto fail; - } - - devzero = open("/dev/zero", O_RDWR); - if(devmem < 0) { - perror("open /dev/zero"); - goto fail; - } - - - magicMem = mmap((void*)MAGICMEM_BASE, MAGICMEM_SIZE, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_PRIVATE | MAP_FIXED, devmem, MAGICMEM_BASE); - if(magicMem == MAP_FAILED) { - ErrorF("Couldn't map magic memory\n"); - goto fail; - } - - loMem = mmap((void*)LOMEM_BASE, LOMEM_SIZE, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_PRIVATE | MAP_FIXED, devzero, LOMEM_BASE); - if(loMem == MAP_FAILED) { - ErrorF("Couldn't map low memory\n"); - munmap(magicMem, MAGICMEM_SIZE); - goto fail; - } - - hiMem = mmap((void*)HIMEM_BASE, HIMEM_SIZE, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_SHARED | MAP_FIXED, - devmem, HIMEM_BASE); - if(hiMem == MAP_FAILED) { - ErrorF("Couldn't map high memory\n"); - munmap(magicMem, MAGICMEM_SIZE); - munmap(loMem, LOMEM_SIZE); - goto fail; + int code; + int mark; + int vib_base; + VbeInfoBlock *vib_low; + + mark = Vm86MarkMemory (vi); + vib_base = Vm86AllocateMemory (vi, sizeof (VbeInfoBlock)); + vib_low = (VbeInfoBlock*)&(LM(vi, vib_base)); + vi->vms.regs.eax = 0x4F00; + vi->vms.regs.es = POINTER_SEGMENT(vib_base); + vi->vms.regs.edi = POINTER_OFFSET(vib_base); + memcpy(vib_low->VbeSignature, "VBE2", 4); + code = VbeDoInterrupt10(vi); + if(code >= 0) + { + if(memcmp(vib_low->VbeSignature, "VESA", 4) == 0) + *vib = *vib_low; + else + code = -1; } + Vm86ReleaseMemory (vi, mark); + return code; +} - vi = xalloc(sizeof(VbeInfoRec)); - if (!vi) - goto unmapfail; - - vi->devmem = devmem; - vi->devzero = devzero; - vi->magicMem = magicMem; - vi->loMem = loMem; - vi->hiMem = hiMem; - vi->brk = LOMEM_BASE; - - stack_base = VbeAllocateMemory(vi, STACK_SIZE); - if(stack_base == ALLOC_FAIL) - goto unmapfail; - ret_code = VbeAllocateMemory(vi, sizeof(retcode_data)); - if(ret_code == ALLOC_FAIL) - goto unmapfail; - vib_base = VbeAllocateMemory(vi, sizeof(VbeInfoBlock)); - if(vib_base == ALLOC_FAIL) - goto unmapfail; - vmib_base = VbeAllocateMemory(vi, sizeof(VbeModeInfoBlock)); - if(vmib_base == ALLOC_FAIL) - goto unmapfail; - - vi->stack_base = stack_base; - vi->ret_code = ret_code; - vi->vib_base = vib_base; - vi->vmib_base = vmib_base; - vi->statebuffer_base = ~0; - vi->palette_scratch_base = ~0; - vi->palette_format = 6; - vi->palette_wait = 0; - vi->windowA_offset = vi->windowB_offset = -1; - vi->last_window = 1; - vi->vga_palette = 1; +int +VbeGetVmib (Vm86InfoPtr vi, int mode, VbeModeInfoBlock *vmib) +{ + int code; + int mark; + int vib_base; + int vmib_base; + VbeModeInfoBlock *vmib_low; - memset(&vi->vms, 0, sizeof(struct vm86_struct)); - vi->vms.flags = 0; - vi->vms.screen_bitmap = 0; - vi->vms.cpu_type = CPU_586; - memcpy(&vi->vms.int_revectored, rev_ints, sizeof(rev_ints)); - - ioperm(0, 0x400, 1); - iopl(3); - - return vi; - - unmapfail: - munmap(magicMem, MAGICMEM_SIZE); - munmap(loMem, LOMEM_SIZE); - munmap(hiMem, HIMEM_SIZE); - fail: - if(devmem >= 0) - close(devmem); - if(devzero >= 0) - close(devzero); - if(vi) - xfree(vi); - return NULL; + mark = Vm86MarkMemory (vi); + + vmib_base = Vm86AllocateMemory (vi, sizeof (VbeModeInfoBlock)); + vmib_low = (VbeModeInfoBlock*)&(LM(vi, vmib_base)); + + vi->vms.regs.eax = 0x4F01; + vi->vms.regs.ecx = mode&0xFFFF; + vi->vms.regs.es = POINTER_SEGMENT(vmib_base); + vi->vms.regs.edi = POINTER_OFFSET(vmib_base); + code = VbeDoInterrupt10(vi); + + if(code >= 0) + *vmib = *vmib_low; + Vm86ReleaseMemory (vi, mark); + return code; } void -VbeCleanup(VbeInfoPtr vi) +VbeReportInfo (Vm86InfoPtr vi) { - munmap(vi->magicMem, MAGICMEM_SIZE); - munmap(vi->loMem, LOMEM_SIZE); - munmap(vi->hiMem, HIMEM_SIZE); - close (vi->devmem); - close (vi->devzero); - xfree(vi); -} + VbeInfoBlock vib; + int code; -VbeInfoBlock * -VbeGetInfo(VbeInfoPtr vi) -{ - int code; - VbeInfoBlock *vib = (VbeInfoBlock*)&(LM(vi, vi->vib_base)); - vi->vms.regs.eax = 0x4F00; - vi->vms.regs.es = POINTER_SEGMENT(vi->vib_base); - vi->vms.regs.edi = POINTER_OFFSET(vi->vib_base); - memcpy(vib->VbeSignature, "VBE2", 4); - code = VbeDoInterrupt10(vi); - if(code < 0) - return NULL; - if(memcmp(vib->VbeSignature, "VESA", 4) != 0) { - ErrorF("Int 10 didn't return VESA signature in info block"); - return NULL; - } - return vib; + code = VbeGetVib (vi, &vib); + if (code >= 0) + VbeReportVib(vi, &vib); } -VbeModeInfoBlock * -VbeGetModeInfo(VbeInfoPtr vi, int mode) +int +VbeGetNmode (Vm86InfoPtr vi) { - int code; - U32 p; - VbeInfoBlock *vib = (VbeInfoBlock*)&(LM(vi, vi->vib_base)); - VbeModeInfoBlock *vmib = (VbeModeInfoBlock*)&(LM(vi, vi->vmib_base)); - p = MAKE_POINTER_1(vib->VideoModePtr); - if(!VbeIsMemory(vi, p)) { - ErrorF("VideoModePtr 0x%08X doesn't point at low memory\n", - vib->VideoModePtr); - return NULL; + VbeInfoBlock vib; + int code; + int ret = 0; + unsigned int p; + int n; + int mode; + + code = VbeGetVib (vi, &vib); + if (code >= 0) + { + p = MAKE_POINTER_1(vib.VideoModePtr); + for (n = 0; ; n++) + { + mode = Vm86MemoryW(vi, p); + if (mode == 0xffff) + break; + p += 2; + } + code = n; } - vi->vms.regs.eax = 0x4F01; - vi->vms.regs.ecx = mode&0xFFFF; - vi->vms.regs.es = POINTER_SEGMENT(vi->vmib_base); - vi->vms.regs.edi = POINTER_OFFSET(vi->vmib_base); - code = VbeDoInterrupt10(vi); - if(code < 0) - return NULL; - else - return vmib; + return code; } int -VbeSetMode(VbeInfoPtr vi, int mode, int linear) +VbeGetModes (Vm86InfoPtr vi, VesaModePtr modes, int nmode) { - int code; + VbeInfoBlock vib; + int code; + int ret = 0; + unsigned int p; + int n; + int mode; + VbeModeInfoBlock vmib; - vi->windowA_offset = vi->windowB_offset = -1; - vi->last_window = 1; + code = VbeGetVib (vi, &vib); + if (code < 0) + return code; + + memset (modes, '\0', n * sizeof (VesaModeRec)); - vi->vms.regs.eax = 0x4F02; - vi->vms.regs.ebx = (mode & 0xFFFF) | 0x8000; - if(linear) - vi->vms.regs.ebx |= 0x4000; - code = VbeDoInterrupt10(vi); - if(code < 0) - return -1; - return 0; + p = MAKE_POINTER_1(vib.VideoModePtr); + for (n = 0; n < nmode; n++) + { + mode = Vm86MemoryW(vi, p); + if (mode == 0xffff) + break; + modes[n].mode = mode; + modes[n].vbe = 1; + p += 2; + } + + nmode = n; + + for (n = 0; n < nmode; n++) + { + code = VbeGetVmib (vi, modes[n].mode, &vmib); + if (code >= 0) + { + modes[n].ModeAttributes = vmib.ModeAttributes; + modes[n].NumberOfPlanes = vmib.NumberOfPlanes; + modes[n].BitsPerPixel = vmib.BitsPerPixel; + modes[n].MemoryModel = vmib.MemoryModel; + modes[n].RedMaskSize = vmib.RedMaskSize; + modes[n].RedFieldPosition = vmib.RedFieldPosition; + modes[n].GreenMaskSize = vmib.GreenMaskSize; + modes[n].GreenFieldPosition = vmib.GreenFieldPosition; + modes[n].BlueMaskSize = vmib.BlueMaskSize; + modes[n].BlueFieldPosition = vmib.BlueFieldPosition; + modes[n].RsvdMaskSize = vmib.RsvdMaskSize; + modes[n].RsvdFieldPosition = vmib.RsvdFieldPosition; + modes[n].DirectColorModeInfo = vmib.DirectColorModeInfo; + modes[n].XResolution = vmib.XResolution; + modes[n].YResolution = vmib.YResolution; + modes[n].BytesPerScanLine = vmib.BytesPerScanLine; + } + } + + return nmode; } -int -VbeGetMode(VbeInfoPtr vi, int *mode) +VbeInfoPtr +VbeInit (Vm86InfoPtr vi) { - int code; - vi->vms.regs.eax = 0x4F03; - code = VbeDoInterrupt10(vi); - if(code < 0) - return - 1; - *mode = vi->vms.regs.ebx & 0xFFFF; - return 0; -} + VbeInfoPtr vbe; + int code; + VbeInfoBlock vib; -int -VbeSetupStateBuffer(VbeInfoPtr vi) -{ - int code; - if(vi->statebuffer_base != ~0) - return 0; - vi->vms.regs.eax = 0x4F04; - vi->vms.regs.edx = 0x0000; - vi->vms.regs.ecx = 0x000F; - code = VbeDoInterrupt10(vi); - if(code < 0) - return -1; - vi->statebuffer_base = VbeAllocateMemory(vi, vi->vms.regs.ebx & 0xFFFF); - return 0; + code = VbeGetVib (vi, &vib); + if (code < 0) + return 0; + + vbe = xalloc (sizeof (VbeInfoRec)); + if (!vbe) + return 0; + vbe->palette_format = 6; + vbe->palette_wait = TRUE; + return vbe; } -int -VbeSaveState(VbeInfoPtr vi) +void +VbeCleanup (Vm86InfoPtr vi, VbeInfoPtr vbe) { - int code; - code = VbeSetupStateBuffer(vi); - if(code < 0) - return -1; - vi->vms.regs.eax = 0x4F04; - vi->vms.regs.edx = 0x0001; - vi->vms.regs.ecx = 0x000F; - vi->vms.regs.es = POINTER_SEGMENT(vi->statebuffer_base); - vi->vms.regs.ebx = POINTER_OFFSET(vi->statebuffer_base); - code = VbeDoInterrupt10(vi); - if(code < 0) - return -1; - return 0; + xfree (vbe); } int -VbeRestoreState(VbeInfoPtr vi) +VbeSetMode (Vm86InfoPtr vi, VbeInfoPtr vbe, int mode, int linear) { - int code; - vi->vms.regs.eax = 0x4F04; - vi->vms.regs.edx = 0x0002; - vi->vms.regs.ecx = 0x000F; - vi->vms.regs.es = POINTER_SEGMENT(vi->statebuffer_base); - vi->vms.regs.ebx = POINTER_OFFSET(vi->statebuffer_base); + int code; + VbeInfoBlock vib; + int palette_wait = 0, palette_hi = 0; + + code = VbeGetVib (vi, &vib); + if (code < 0) + return -1; + + code = VbeGetVmib (vi, mode, &vbe->vmib); + if (code < 0) + return -1; + + mode = (mode & 0xffff) | 0x8000; + if (linear) + mode |= 0x4000; + + vi->vms.regs.eax = 0x4F02; + vi->vms.regs.ebx = mode; code = VbeDoInterrupt10(vi); if(code < 0) return -1; + + vbe->windowA_offset = vbe->windowB_offset = -1; + vbe->last_window = 1; + + if(vib.Capabilities[0] & 1) + palette_hi = 1; + if(vib.Capabilities[0] & 4) + palette_wait = 1; + + if(palette_hi || palette_wait) + VbeSetPaletteOptions(vi, vbe, palette_hi?8:6, palette_wait); + return 0; } -int -VbeSetTextMode(VbeInfoPtr vi, int mode) +int +VbeGetMode(Vm86InfoPtr vi, int *mode) { int code; - vi->vms.regs.eax = mode & 0x7f; + vi->vms.regs.eax = 0x4F03; code = VbeDoInterrupt10(vi); if(code < 0) - return -1; + return - 1; + *mode = vi->vms.regs.ebx & 0xFFFF; return 0; } void * -VbeMapFramebuffer(VbeInfoPtr vi, - VbeModeInfoBlock *vmib) -{ - U8 *fb; - VbeInfoBlock *vib = (VbeInfoBlock*)&(LM(vi, vi->vib_base)); - int size; - int pagesize = getpagesize(), before, after; - - size = 1024 * 64L * vib->TotalMemory; +VbeMapFramebuffer(Vm86InfoPtr vi, VbeInfoPtr vbe, int mode, int *ret_size) +{ + U8 *fb; + VbeInfoBlock vib; + VbeModeInfoBlock vmib; + int size; + int pagesize = getpagesize(); + int before, after; + int devmem; + + if (VbeGetVib (vi, &vib) < 0) + return 0; + + if (VbeGetVmib (vi, mode, &vmib) < 0) + return 0; + + size = 1024 * 64L * vib.TotalMemory; + + *ret_size = size; - before = vmib->PhysBasePtr % pagesize; - after = pagesize - ((vmib->PhysBasePtr + size) % pagesize); + before = vmib.PhysBasePtr % pagesize; + after = pagesize - ((vmib.PhysBasePtr + size) % pagesize); if(after == pagesize) after = 0; - fb = mmap(0, before + size + after, - PROT_READ | PROT_WRITE, MAP_SHARED, - vi->devmem, vmib->PhysBasePtr - before); - if(fb == MAP_FAILED) { - ErrorF("Failed to map framebuffer: %d\n", errno); + fb = KdMapDevice (vmib.PhysBasePtr - before, before + size + after); + + if(fb == 0) + { + ErrorF("Failed to map framebuffer\n"); return NULL; } return fb + before; } -int -VbeUnmapFramebuffer(VbeInfoPtr vi, - VbeModeInfoBlock *vmib, - void *fb) +void +VbeUnmapFramebuffer(Vm86InfoPtr vi, VbeInfoPtr vbe, int mode, void *fb) { - int code; - VbeInfoBlock *vib = (VbeInfoBlock*)&(LM(vi, vi->vib_base)); - int size; - int pagesize = getpagesize(), before, after; + VbeInfoBlock vib; + VbeModeInfoBlock vmib; + int size; + int pagesize = getpagesize(); + int before, after; - size = 1024 * 64L * vib->TotalMemory; + if (VbeGetVib (vi, &vib) < 0) + return; + + if (VbeGetVmib (vi, mode, &vmib) < 0) + return; + + size = 1024 * 64L * vib.TotalMemory; - before = vmib->PhysBasePtr % pagesize; - after = pagesize - ((vmib->PhysBasePtr + size) % pagesize); + before = vmib.PhysBasePtr % pagesize; + after = pagesize - ((vmib.PhysBasePtr + size) % pagesize); if(after == pagesize) after = 0; fb = (void *) ((char *) fb - before); - code = munmap(fb, before + size + after); - if(code) { - ErrorF("Couldn't unmap framebuffer: %d\n", errno); - return -1; - } - return 0; -} - -static int -PreparePalette(VbeInfoPtr vi) -{ - int code; - if(vi->palette_scratch_base == ~0) { - vi->palette_scratch_base = VbeAllocateMemory(vi, 4*256); - if(vi->palette_scratch_base == ALLOC_FAIL) { - ErrorF("Couldn't allocate scratch area for palette transfer\n"); - return -1; - } - } - if(!vi->palette_format) { - /* This isn't used currently */ - vi->vms.regs.eax = 0x4F08; - vi->vms.regs.ebx = 0x01; - code = VbeDoInterrupt10(vi); - if(code < 0) - return -1; - vi->palette_format = vi->vms.regs.ebx & 0xFF; - } - return 0; + KdUnmapDevice (fb, before + size + after); } int -VbeSetPalette(VbeInfoPtr vi, int first, int number, U8 *entries) +VbeSetPalette(Vm86InfoPtr vi, VbeInfoPtr vbe, int first, int number, U8 *entries) { - U8 *palette_scratch; - int i, j, code; + U8 *palette_scratch; + int mark; + int palette_base; + int i, j, code; if(number == 0) return 0; - code = PreparePalette(vi); - if(code < 0) - return -1; - if(first < 0 || number < 0 || first + number > 256) { ErrorF("Cannot set %d, %d palette entries\n", first, number); return -1; } - palette_scratch = &LM(vi, vi->palette_scratch_base); - - if(vi->palette_format < 6 || vi->palette_format > 8) { - ErrorF("Impossible palette format %d\n", vi->palette_format); + if(vbe->palette_format < 6 || vbe->palette_format > 8) { + ErrorF("Impossible palette format %d\n", vbe->palette_format); return -1; } - if (vi->vga_palette) - { - vi->vms.regs.eax = 0x1012; - vi->vms.regs.ebx = first; - vi->vms.regs.ecx = number; - vi->vms.regs.es = POINTER_SEGMENT(vi->palette_scratch_base); - vi->vms.regs.edx = POINTER_OFFSET(vi->palette_scratch_base); - j = 0; - i = 0; - while (number--) - { - palette_scratch[j++] = entries[i++] >> (8-vi->palette_format); - palette_scratch[j++] = entries[i++] >> (8-vi->palette_format); - palette_scratch[j++] = entries[i++] >> (8-vi->palette_format); - i++; - } - } + mark = Vm86MarkMemory (vi); + palette_base = Vm86AllocateMemory (vi, 4 * 256); + + palette_scratch = &LM(vi, palette_base); + + for(i=0; i> (8 - vbe->palette_format); + + vi->vms.regs.eax = 0x4F09; + if(vbe->palette_wait) + vi->vms.regs.ebx = 0x80; else - { - for(i=0; i> (8 - vi->palette_format); - - vi->vms.regs.eax = 0x4F09; - if(vi->palette_wait) - vi->vms.regs.ebx = 0x80; - else - vi->vms.regs.ebx = 0x00; - vi->vms.regs.ecx = number; - vi->vms.regs.edx = first; - vi->vms.regs.es = POINTER_SEGMENT(vi->palette_scratch_base); - vi->vms.regs.edi = POINTER_OFFSET(vi->palette_scratch_base); - } + vi->vms.regs.ebx = 0x00; + vi->vms.regs.ecx = number; + vi->vms.regs.edx = first; + vi->vms.regs.es = POINTER_SEGMENT(palette_base); + vi->vms.regs.edi = POINTER_OFFSET(palette_base); code = VbeDoInterrupt10(vi); + Vm86ReleaseMemory (vi, mark); + if(code < 0) return -1; return 0; -} +} int -VbeGetPalette(VbeInfoPtr vi, int first, int number, U8 *entries) +VbeGetPalette(Vm86InfoPtr vi, VbeInfoPtr vbe, int first, int number, U8 *entries) { - U8 *palette_scratch; - int i, j, code; + U8 *palette_scratch; + int mark; + int palette_base; + int i, j, code; - code = PreparePalette(vi); - if(code < 0) - return -1; + if(number == 0) + return 0; - if(first< 0 || number < 0 || first + number > 256) { + if(first < 0 || number < 0 || first + number > 256) { ErrorF("Cannot get %d, %d palette entries\n", first, number); return -1; } - palette_scratch = &LM(vi, vi->palette_scratch_base); - - if(vi->palette_format < 6 || vi->palette_format > 8) { - ErrorF("Impossible palette format %d\n", vi->palette_format); + if(vbe->palette_format < 6 || vbe->palette_format > 8) { + ErrorF("Impossible palette format %d\n", vbe->palette_format); return -1; } -retry: - if (vi->vga_palette) - { - vi->vms.regs.eax = 0x1017; - vi->vms.regs.ebx = first; - vi->vms.regs.ecx = number; - vi->vms.regs.es = POINTER_SEGMENT(vi->palette_scratch_base); - vi->vms.regs.edx = POINTER_OFFSET(vi->palette_scratch_base); - code = VbeDoInterrupt10(vi); - if(code < 0) - return -1; - j = 0; - i = 0; - while (number--) - { - entries[i++] = palette_scratch[j++] << (8-vi->palette_format); - entries[i++] = palette_scratch[j++] << (8-vi->palette_format); - entries[i++] = palette_scratch[j++] << (8-vi->palette_format); - entries[i++] = 0; - } - } - else - { - vi->vms.regs.eax = 0x4F09; - vi->vms.regs.ebx = 0x01; - vi->vms.regs.ecx = number; - vi->vms.regs.edx = first; - vi->vms.regs.es = POINTER_SEGMENT(vi->palette_scratch_base); - vi->vms.regs.edi = POINTER_OFFSET(vi->palette_scratch_base); - code = VbeDoInterrupt10(vi); - if(code < 0) - { - vi->vga_palette = TRUE; - goto retry; - } + mark = Vm86MarkMemory (vi); + palette_base = Vm86AllocateMemory (vi, 4 * 256); + palette_scratch = &LM(vi, palette_base); + + vi->vms.regs.eax = 0x4F09; + vi->vms.regs.ebx = 0x01; + vi->vms.regs.ecx = number; + vi->vms.regs.edx = first; + vi->vms.regs.es = POINTER_SEGMENT(palette_base); + vi->vms.regs.edi = POINTER_OFFSET(palette_base); + code = VbeDoInterrupt10(vi); + if(code >= 0) + { for(i=0; ipalette_format); + entries[i] = palette_scratch[i] << (8-vbe->palette_format); } + Vm86ReleaseMemory (vi, mark); return 0; } int -VbeSetPaletteOptions(VbeInfoPtr vi, U8 bits, int wait) +VbeSetPaletteOptions(Vm86InfoPtr vi, VbeInfoPtr vbe, U8 bits, int wait) { int code; + if(bits < 6 || bits > 8) { - ErrorF("Impossible palette format %d\n", vi->palette_format); + ErrorF("Impossible palette format %d\n", bits); return -1; } - if(bits != vi->palette_format) { - vi->palette_format = 0; + if(bits != vbe->palette_format) + { + vbe->palette_format = 0; vi->vms.regs.eax = 0x4F08; vi->vms.regs.ebx = bits << 8; code = VbeDoInterrupt10(vi); if(code < 0) return -1; - vi->palette_format = bits; + vbe->palette_format = bits; } - vi->palette_wait = wait; + vbe->palette_wait = wait; return 0; } static int -VbeReallySetWindow(VbeInfoPtr vi, U8 window, U16 winnum) +VbeReallySetWindow(Vm86InfoPtr vi, U8 window, U16 winnum) { int code; vi->vms.regs.eax = 0x4F05; @@ -564,82 +434,66 @@ VbeReallySetWindow(VbeInfoPtr vi, U8 window, U16 winnum) } void * -VbeSetWindow(VbeInfoPtr vi, int offset, int purpose, int *size_return) +VbeSetWindow(Vm86InfoPtr vi, VbeInfoPtr vbe, int offset, int purpose, int *size_return) { - VbeModeInfoBlock *vmib = (VbeModeInfoBlock*)&(LM(vi, vi->vmib_base)); - int window_size = vmib->WinSize * 1024; + int window_size = vbe->vmib.WinSize * 1024; int code; int winnum; - if(vi->windowA_offset >= 0) - if(vi->windowA_offset <= offset && vi->windowA_offset + window_size > offset) - if(vmib->WinAAttributes & purpose) - goto windowA; + if(vbe->windowA_offset >= 0) + if(vbe->windowA_offset <= offset && vbe->windowA_offset + window_size > offset) + if(vbe->vmib.WinAAttributes & purpose) + goto windowA; - if(vi->windowB_offset >= 0) - if(vi->windowB_offset <= offset && vi->windowB_offset + window_size > offset) - if(vmib->WinBAttributes & purpose) - goto windowB; + if(vbe->windowB_offset >= 0) + if(vbe->windowB_offset <= offset && vbe->windowB_offset + window_size > offset) + if(vbe->vmib.WinBAttributes & purpose) + goto windowB; - if(!(vmib->WinBAttributes & purpose) || - !(vmib->WinBAttributes & VBE_WINDOW_RELOCATE)) - goto set_windowA; + if(!(vbe->vmib.WinBAttributes & purpose) || + !(vbe->vmib.WinBAttributes & VBE_WINDOW_RELOCATE)) + goto set_windowA; - if(!(vmib->WinAAttributes & purpose) || - !(vmib->WinAAttributes & VBE_WINDOW_RELOCATE)) - goto set_windowB; + if(!(vbe->vmib.WinAAttributes & purpose) || + !(vbe->vmib.WinAAttributes & VBE_WINDOW_RELOCATE)) + goto set_windowB; - if(vi->last_window) - goto set_windowA; + if(vbe->last_window) + goto set_windowA; else - goto set_windowB; + goto set_windowB; - set_windowA: - winnum = offset / (vmib->WinGranularity * 1024); +set_windowA: + winnum = offset / (vbe->vmib.WinGranularity * 1024); code = VbeReallySetWindow(vi, 0, winnum); if(code < 0) { - ErrorF("Couldn't set window A to %d*%d\n", - (int)winnum, (int)vmib->WinGranularity); - return NULL; - } - vi->windowA_offset = winnum * vmib->WinGranularity * 1024; - windowA: - vi->last_window = 0; - *size_return = vmib->WinSize * 1024 - (offset - vi->windowA_offset); - return ((U8*)&(LM(vi, MAKE_POINTER(vmib->WinASegment, 0)))) + - offset - vi->windowA_offset; - - set_windowB: - winnum = offset / (vmib->WinGranularity * 1024); + ErrorF("Couldn't set window A to %d*%d\n", + (int)winnum, (int)vbe->vmib.WinGranularity); + return NULL; + } + vbe->windowA_offset = winnum * vbe->vmib.WinGranularity * 1024; +windowA: + vbe->last_window = 0; + *size_return = vbe->vmib.WinSize * 1024 - (offset - vbe->windowA_offset); + return ((U8*)&(LM(vi, MAKE_POINTER(vbe->vmib.WinASegment, 0)))) + offset - vbe->windowA_offset; + +set_windowB: + winnum = offset / (vbe->vmib.WinGranularity * 1024); code = VbeReallySetWindow(vi, 1, winnum); if(code < 0) { - ErrorF("Couldn't set window B to %d*%d\n", - (int)winnum, (int)vmib->WinGranularity); - return NULL; + ErrorF("Couldn't set window B to %d*%d\n", + (int)winnum, (int)vbe->vmib.WinGranularity); + return NULL; } - vi->windowB_offset = winnum * vmib->WinGranularity * 1024; - windowB: - vi->last_window = 1; - *size_return = vmib->WinSize * 1024 - (offset - vi->windowB_offset); - return ((U8*)&(LM(vi, MAKE_POINTER(vmib->WinBSegment, 0)))) + offset - vi->windowB_offset; -} - -int -VbeSetWritePlaneMask(VbeInfoPtr vi, int mask) -{ - asm volatile ("outb %b0,%w1" : : "a" (2), "d" (0x3c4)); - asm volatile ("outb %b0,%w1" : : "a" (mask), "d" (0x3c5)); -} - -int -VbeSetReadPlaneMap(VbeInfoPtr vi, int map) -{ - asm volatile ("outb %b0,%w1" : : "a" (4), "d" (0x3ce)); - asm volatile ("outb %b0,%w1" : : "a" (map), "d" (0x3cf)); + vbe->windowB_offset = winnum * vbe->vmib.WinGranularity * 1024; +windowB: + vbe->last_window = 1; + *size_return = vbe->vmib.WinSize * 1024 - (offset - vbe->windowB_offset); + return ((U8*)&(LM(vi, MAKE_POINTER(vbe->vmib.WinBSegment, 0)))) + offset - vbe->windowB_offset; } int -VbeReportInfo(VbeInfoPtr vi, VbeInfoBlock *vib) +VbeReportVib(Vm86InfoPtr vi, VbeInfoBlock *vib) { U32 i, p; unsigned char c; @@ -649,9 +503,10 @@ VbeReportInfo(VbeInfoPtr vi, VbeInfoBlock *vib) (vib->VbeVersion & 0xFF)+'0'); p = vib->OemStringPtr; for(i = 0; 1; i++) { - c = VbeMemory(vi, MAKE_POINTER_1(p+i)); + c = Vm86Memory(vi, MAKE_POINTER_1(p+i)); if(!c) break; - ErrorF("%c", c); + if (c >= ' ') + ErrorF("%c", c); if (i > 32000) { error = 1; break; @@ -669,7 +524,7 @@ VbeReportInfo(VbeInfoPtr vi, VbeInfoBlock *vib) } int -VbeReportModeInfo(VbeInfoPtr vi, U16 mode, VbeModeInfoBlock *vmib) +VbeReportModeInfo(Vm86InfoPtr vi, U16 mode, VbeModeInfoBlock *vmib) { int supported = (vmib->ModeAttributes&0x1)?1:0; int colour = (vmib->ModeAttributes&0x8)?1:0; @@ -725,526 +580,43 @@ VbeReportModeInfo(VbeInfoPtr vi, U16 mode, VbeModeInfoBlock *vmib) ErrorF("\n"); return 0; } + int -VbeDoInterrupt10(VbeInfoPtr vi) +VbeDoInterrupt10(Vm86InfoPtr vi) { int code; int oldax; oldax = vi->vms.regs.eax & 0xFFFF; - code = VbeDoInterrupt(vi, 0x10); - + code = Vm86DoInterrupt(vi, 0x10); if(code < 0) - return -1; + return -1; if((vi->vms.regs.eax & 0xFFFF) != 0x4F && (oldax & 0xFF00) == 0x4F00) { - ErrorF("Int 10h (0x%04X) failed: 0x%04X", - oldax, vi->vms.regs.eax & 0xFFFF); - if((oldax & 0xFF00) == 0x4F00) { - switch((vi->vms.regs.eax & 0xFF00)>>8) { - case 0: - ErrorF(" (success)\n"); - break; - case 1: - ErrorF(" (function call failed)\n"); - break; - case 2: - ErrorF(" (function not supported on this hardware)\n"); - break; - case 3: - ErrorF(" (function call invalid in this video mode)\n"); - break; - default: - ErrorF(" (unknown error)\n"); - break; - } - return -1; - } else { - ErrorF("\n"); - } + ErrorF("Int 10h (0x%04X) failed: 0x%04X", + oldax, vi->vms.regs.eax & 0xFFFF); + if((oldax & 0xFF00) == 0x4F00) { + switch((vi->vms.regs.eax & 0xFF00)>>8) { + case 0: + ErrorF(" (success)\n"); + return 0; + case 1: + ErrorF(" (function call failed)\n"); + break; + case 2: + ErrorF(" (function not supported on this hardware)\n"); + break; + case 3: + ErrorF(" (function call invalid in this video mode)\n"); + break; + default: + ErrorF(" (unknown error)\n"); + break; + } return -1; + } else { + ErrorF("\n"); + } } return code; } - -int -VbeDoInterrupt(VbeInfoPtr vi, int num) -{ - U16 seg, off; - int code; - - if(num < 0 || num>256) { - ErrorF("Interrupt %d doesn't exist\n"); - return -1; - } - seg = MMW(vi,num * 4 + 2); - off = MMW(vi,num * 4); - if(MAKE_POINTER(seg, off) < ROM_BASE || - MAKE_POINTER(seg, off) >= ROM_BASE + ROM_SIZE) { - ErrorF("Interrupt pointer doesn't point at ROM\n"); - return -1; - } - memcpy(&(LM(vi,vi->ret_code)), retcode_data, sizeof(retcode_data)); - vi->vms.regs.eflags = IF_MASK | IOPL_MASK; - vi->vms.regs.ss = POINTER_SEGMENT(vi->stack_base); - vi->vms.regs.esp = STACK_SIZE; - PUSHW(vi, IF_MASK | IOPL_MASK); - PUSHW(vi, POINTER_SEGMENT(vi->ret_code)); - PUSHW(vi, POINTER_OFFSET(vi->ret_code)); - vi->vms.regs.cs = seg; - vi->vms.regs.eip = off; - OsBlockSignals (); - code = vm86_loop(vi); - OsReleaseSignals (); - if(code < 0) { - perror("vm86 failed"); - return -1; - } else if(code != 0) { - ErrorF("vm86 returned 0x%04X\n", code); - return -1; - } else - return 0; -} - -static inline U8 -vm86_inb(U16 port) -{ - U8 value; - asm volatile ("inb %w1,%b0" : "=a" (value) : "d" (port)); - return value; -} - -static inline U16 -vm86_inw(U16 port) -{ - U16 value; - asm volatile ("inw %w1,%w0" : "=a" (value) : "d" (port)); - return value; -} - -static inline U32 -vm86_inl(U16 port) -{ - U32 value; - asm volatile ("inl %w1,%0" : "=a" (value) : "d" (port)); - return value; -} - -static inline void -vm86_outb(U16 port, U8 value) -{ - asm volatile ("outb %b0,%w1" : : "a" (value), "d" (port)); -} - -static inline void -vm86_outw(U16 port, U16 value) -{ - asm volatile ("outw %w0,%w1" : : "a" (value), "d" (port)); -} - -static inline void -vm86_outl(U16 port, U32 value) -{ - asm volatile ("outl %0,%w1" : : "a" (value), "d" (port)); -} - -#define SEG_CS 1 -#define SEG_DS 2 -#define SEG_ES 3 -#define SEG_SS 4 -#define SEG_GS 5 -#define SEG_FS 6 -#define REP 1 -#define REPNZ 2 -#define SET_8(_x, _y) (_x) = (_x & ~0xFF) | (_y & 0xFF); -#define SET_16(_x, _y) (_x) = (_x & ~0xFFFF) | (_y & 0xFFFF); -#define INC_IP(_i) SET_16(regs->eip, (regs->eip + _i)) -#define AGAIN INC_IP(1); goto again; - -static int -vm86_emulate(VbeInfoPtr vi) -{ - struct vm86_regs *regs = &vi->vms.regs; - U8 opcode; - int size; - int pref_seg = 0, pref_rep = 0, pref_66 = 0, pref_67 = 0; - U32 count; - int code; - - again: - if(!VbeIsMemory(vi, MAKE_POINTER(regs->cs, regs->eip))) { - ErrorF("Trying to execute unmapped memory\n"); - return -1; - } - opcode = VbeMemory(vi, MAKE_POINTER(regs->cs, regs->eip)); - switch(opcode) { - case 0x2E: pref_seg = SEG_CS; AGAIN; - case 0x3E: pref_seg = SEG_DS; AGAIN; - case 0x26: pref_seg = SEG_ES; AGAIN; - case 0x36: pref_seg = SEG_SS; AGAIN; - case 0x65: pref_seg = SEG_GS; AGAIN; - case 0x64: pref_seg = SEG_FS; AGAIN; - case 0x66: pref_66 = 1; AGAIN; - case 0x67: pref_67 = 1; AGAIN; - case 0xF2: pref_rep = REPNZ; AGAIN; - case 0xF3: pref_rep = REP; AGAIN; - - case 0xEC: /* IN AL, DX */ - SET_8(regs->eax, vm86_inb(regs->edx & 0xFFFF)); - INC_IP(1); - break; - case 0xED: /* IN AX, DX */ - if(pref_66) - regs->eax = vm86_inl(regs->edx & 0xFFFF); - else - SET_16(regs->eax, vm86_inw(regs->edx & 0xFFFF)); - INC_IP(1); - break; - case 0xE4: /* IN AL, imm8 */ - SET_8(regs->eax, - vm86_inb(VbeMemory(vi, MAKE_POINTER(regs->cs, regs->eip+1)))); - INC_IP(2); - break; - case 0xE5: /* IN AX, imm8 */ - if(pref_66) - regs->eax = - vm86_inl(VbeMemory(vi, MAKE_POINTER(regs->cs, regs->eip+1))); - else - SET_16(regs->eax, - vm86_inw(VbeMemory(vi, MAKE_POINTER(regs->cs, regs->eip+1)))); - INC_IP(2); - break; - case 0x6C: /* INSB */ - case 0x6D: /* INSW */ - if(opcode == 0x6C) { - VbeWriteMemory(vi, MAKE_POINTER(regs->es, regs->edi), - vm86_inb(regs->edx & 0xFFFF)); - size = 1; - } else if(pref_66) { - VbeWriteMemoryL(vi, MAKE_POINTER(regs->es, regs->edi), - vm86_inl(regs->edx & 0xFFFF)); - size = 4; - } else { - VbeWriteMemoryW(vi, MAKE_POINTER(regs->es, regs->edi), - vm86_inw(regs->edx & 0xFFFF)); - size = 2; - } - if(regs->eflags & (1<<10)) - regs->edi -= size; - else - regs->edi += size; - if(pref_rep) { - if(pref_66) { - regs->ecx--; - if(regs->ecx != 0) { - goto again; - } else { - SET_16(regs->ecx, regs->ecx - 1); - if(regs->ecx & 0xFFFF != 0) - goto again; - } - } - } - INC_IP(1); - break; - - case 0xEE: /* OUT DX, AL */ - vm86_outb(regs->edx & 0xFFFF, regs->eax & 0xFF); - INC_IP(1); - break; - case 0xEF: /* OUT DX, AX */ - if(pref_66) - vm86_outl(regs->edx & 0xFFFF, regs->eax); - else - vm86_outw(regs->edx & 0xFFFF, regs->eax & 0xFFFF); - INC_IP(1); - break; - case 0xE6: /* OUT imm8, AL */ - vm86_outb(VbeMemory(vi, MAKE_POINTER(regs->cs, regs->eip+1)), - regs->eax & 0xFF); - INC_IP(2); - break; - case 0xE7: /* OUT imm8, AX */ - if(pref_66) - vm86_outl(VbeMemory(vi, MAKE_POINTER(regs->cs, regs->eip+1)), - regs->eax); - else - vm86_outw(VbeMemory(vi, MAKE_POINTER(regs->cs, regs->eip+1)), - regs->eax & 0xFFFF); - INC_IP(2); - break; - case 0x6E: /* OUTSB */ - case 0x6F: /* OUTSW */ - if(opcode == 0x6E) { - vm86_outb(regs->edx & 0xFFFF, - VbeMemory(vi, MAKE_POINTER(regs->es, regs->edi))); - size = 1; - } else if(pref_66) { - vm86_outl(regs->edx & 0xFFFF, - VbeMemory(vi, MAKE_POINTER(regs->es, regs->edi))); - size = 4; - } else { - vm86_outw(regs->edx & 0xFFFF, - VbeMemory(vi, MAKE_POINTER(regs->es, regs->edi))); - size = 2; - } - if(regs->eflags & (1<<10)) - regs->edi -= size; - else - regs->edi += size; - if(pref_rep) { - if(pref_66) { - regs->ecx--; - if(regs->ecx != 0) { - goto again; - } else { - SET_16(regs->ecx, regs->ecx - 1); - if(regs->ecx & 0xFFFF != 0) - goto again; - } - } - } - INC_IP(1); - break; - - case 0x0F: - ErrorF("Hit 0F trap in VM86 code\n"); - return -1; - case 0xF0: - ErrorF("Hit lock prefix in VM86 code\n"); - return -1; - case 0xF4: - ErrorF("Hit HLT in VM86 code\n"); - return -1; - - default: - ErrorF("Unhandled GP fault in VM86 code (opcode = 0x%02X)\n", - opcode); - return -1; - } - return 0; -} -#undef SEG_CS -#undef SEG_DS -#undef SEG_ES -#undef SEG_SS -#undef SEG_GS -#undef SEG_FS -#undef REP -#undef REPNZ -#undef SET_8 -#undef SET_16 -#undef INC_IP -#undef AGAIN - -static int -vm86_loop(VbeInfoPtr vi) -{ - int code; - - while(1) { - code = vm86old(&vi->vms); - switch(VM86_TYPE(code)) { - case VM86_SIGNAL: - continue; - case VM86_UNKNOWN: - code = vm86_emulate(vi); - if(code < 0) { - VbeDebug(vi); - return -1; - } - break; - case VM86_INTx: - if(VM86_ARG(code) == 0xFF) - return 0; - else { - PUSHW(vi, vi->vms.regs.eflags) - PUSHW(vi, vi->vms.regs.cs); - PUSHW(vi, vi->vms.regs.eip); - vi->vms.regs.cs = MMW(vi,VM86_ARG(code) * 4 + 2); - vi->vms.regs.eip = MMW(vi,VM86_ARG(code) * 4); - } - break; - case VM86_STI: - ErrorF("VM86 code enabled interrupts\n"); - VbeDebug(vi); - return -1; - default: - ErrorF("Unexpected result code 0x%X from vm86\n", code); - VbeDebug(vi); - return -1; - } - } -} - -int -VbeIsMemory(VbeInfoPtr vi, U32 i) -{ - if(i >= MAGICMEM_BASE && i< MAGICMEM_BASE + MAGICMEM_SIZE) - return 1; - else if(i >= LOMEM_BASE && i< LOMEM_BASE + LOMEM_SIZE) - return 1; - else if(i >= HIMEM_BASE && i< HIMEM_BASE + HIMEM_SIZE) - return 1; - else - return 0; -} - -U8 -VbeMemory(VbeInfoPtr vi, U32 i) -{ - if(i >= MAGICMEM_BASE && i< MAGICMEM_BASE + MAGICMEM_SIZE) - return MM(vi, i); - else if(i >= LOMEM_BASE && i< LOMEM_BASE + LOMEM_SIZE) - return LM(vi, i); - else if(i >= HIMEM_BASE && i< HIMEM_BASE + HIMEM_SIZE) - return HM(vi, i); - else { - ErrorF("Reading unmapped memory at 0x%08X\n", i); - } -} - -U16 -VbeMemoryW(VbeInfoPtr vi, U32 i) -{ - if(i >= MAGICMEM_BASE && i< MAGICMEM_BASE + MAGICMEM_SIZE) - return MMW(vi, i); - else if(i >= LOMEM_BASE && i< LOMEM_BASE + LOMEM_SIZE) - return LMW(vi, i); - else if(i >= HIMEM_BASE && i< HIMEM_BASE + HIMEM_SIZE) - return HMW(vi, i); - else { - ErrorF("Reading unmapped memory at 0x%08X\n", i); - return 0; - } -} - -U32 -VbeMemoryL(VbeInfoPtr vi, U32 i) -{ - if(i >= MAGICMEM_BASE && i< MAGICMEM_BASE + MAGICMEM_SIZE) - return MML(vi, i); - else if(i >= LOMEM_BASE && i< LOMEM_BASE + LOMEM_SIZE) - return LML(vi, i); - else if(i >= HIMEM_BASE && i< HIMEM_BASE + HIMEM_SIZE) - return HML(vi, i); - else { - ErrorF("Reading unmapped memory at 0x%08X\n", i); - return 0; - } -} - -void -VbeWriteMemory(VbeInfoPtr vi, U32 i, U8 val) -{ - if(i >= MAGICMEM_BASE && i< MAGICMEM_BASE + MAGICMEM_SIZE) - MM(vi, i) = val; - else if(i >= LOMEM_BASE && i< LOMEM_BASE + LOMEM_SIZE) - LM(vi, i) = val; - else if(i >= HIMEM_BASE && i< HIMEM_BASE + HIMEM_SIZE) - HM(vi, i) = val; - else { - ErrorF("Writing unmapped memory at 0x%08X\n", i); - } -} - -void -VbeWriteMemoryW(VbeInfoPtr vi, U32 i, U16 val) -{ - if(i >= MAGICMEM_BASE && i< MAGICMEM_BASE + MAGICMEM_SIZE) - MMW(vi, i) = val; - else if(i >= LOMEM_BASE && i< LOMEM_BASE + LOMEM_SIZE) - LMW(vi, i) = val; - else if(i >= HIMEM_BASE && i< HIMEM_BASE + HIMEM_SIZE) - HMW(vi, i) = val; - else { - ErrorF("Writing unmapped memory at 0x%08X\n", i); - } -} - -void -VbeWriteMemoryL(VbeInfoPtr vi, U32 i, U32 val) -{ - if(i >= MAGICMEM_BASE && i< MAGICMEM_BASE + MAGICMEM_SIZE) - MML(vi, i) = val; - else if(i >= LOMEM_BASE && i< LOMEM_BASE + LOMEM_SIZE) - LML(vi, i) = val; - else if(i >= HIMEM_BASE && i< HIMEM_BASE + HIMEM_SIZE) - HML(vi, i) = val; - else { - ErrorF("Writing unmapped memory at 0x%08X\n", i); - } -} - -int -VbeAllocateMemory(VbeInfoPtr vi, int n) -{ - int ret; - if(n<0) { - ErrorF("Asked to allocate negative amount of memory\n"); - return vi->brk; - } - - n = (n + 15) & ~15; - if(vi->brk + n > LOMEM_BASE + LOMEM_SIZE) { - ErrorF("Out of low memory\n"); - exit(2); - } - ret = vi->brk; - vi->brk += n; - return ret; -} - -static int -vm86old(struct vm86_struct *vm) -{ - int res; - - asm volatile ( - "pushl %%ebx\n\t" - "movl %2, %%ebx\n\t" - "movl %1,%%eax\n\t" - "int $0x80\n\t" - "popl %%ebx" - : "=a" (res) : "n" (113), "r" (vm)); - if(res < 0) { - errno = -res; - res = -1; - } else - errno = 0; - OsReleaseSignals (); - return res; -} - -void -VbeDebug(VbeInfoPtr vi) -{ - struct vm86_regs *regs = &vi->vms.regs; - int i; - - ErrorF("eax=0x%08lX ebx=0x%08lX ecx=0x%08lX edx=0x%08lX\n", - regs->eax, regs->ebx, regs->ecx, regs->edx); - ErrorF("esi=0x%08lX edi=0x%08lX ebp=0x%08lX\n", - regs->esi, regs->edi, regs->ebp); - ErrorF("eip=0x%08lX esp=0x%08lX eflags=0x%08lX\n", - regs->eip, regs->esp, regs->eflags); - ErrorF("cs=0x%04lX ds=0x%04lX es=0x%04lX fs=0x%04lX gs=0x%04lX\n", - regs->cs, regs->ds, regs->es, regs->fs, regs->gs); - for(i=-7; i<8; i++) { - ErrorF(" %s%02X", - i==0?"->":"", - VbeMemory(vi, MAKE_POINTER(regs->cs, regs->eip + i))); - } - ErrorF("\n"); -} - -#ifdef NOT_IN_X_SERVER -static void -ErrorF(char *f, ...) -{ - va_list args; - va_start(args, f); - vfprintf(stderr, f, args); - va_end(args); -} -#endif diff --git a/hw/kdrive/vesa/vbe.h b/hw/kdrive/vesa/vbe.h index 29210310a..2bc3aab2a 100644 --- a/hw/kdrive/vesa/vbe.h +++ b/hw/kdrive/vesa/vbe.h @@ -28,56 +28,6 @@ THE SOFTWARE. #define VBE_WINDOW_READ 2 #define VBE_WINDOW_WRITE 4 -#ifndef U8 -#define U8 unsigned char -#define U16 unsigned short -#define U32 unsigned int -#endif - -/* The whole addressable memory */ -#define SYSMEM_BASE 0x00000 -#define SYSMEM_SIZE 0x100000 - -/* Interrupt vectors and BIOS data area */ -/* This is allocated privately from /dev/mem */ -#define MAGICMEM_BASE 0x00000 -#define MAGICMEM_SIZE 0x01000 - -/* The low memory, allocated privately from /dev/zero */ -/* 64KB should be enough for anyone, as they used to say */ -#define LOMEM_BASE 0x10000 -#define LOMEM_SIZE 0x10000 - -/* The video memory and BIOS ROM, allocated shared from /dev/mem */ -#define HIMEM_BASE 0xA0000 -#define HIMEM_SIZE (SYSMEM_BASE + SYSMEM_SIZE - HIMEM_BASE) - -/* The BIOS ROM */ -#define ROM_BASE 0xC0000 -#define ROM_SIZE 0x30000 - -#define STACK_SIZE 0x1000 - -#define POINTER_SEGMENT(ptr) (((unsigned int)ptr)>>4) -#define POINTER_OFFSET(ptr) (((unsigned int)ptr)&0x000F) -#define MAKE_POINTER(seg, off) (((((unsigned int)(seg))<<4) + (unsigned int)(off))) -#define MAKE_POINTER_1(lw) MAKE_POINTER(((lw)&0xFFFF0000)/0x10000, (lw)&0xFFFF) -#define ALLOC_FAIL ((U32)-1) - -typedef struct _VbeInfoRec { - int devmem, devzero; - void *magicMem, *loMem, *hiMem; - U32 brk; - struct vm86_struct vms; - U32 ret_code, stack_base, vib_base, vmib_base, statebuffer_base, palette_scratch_base; - U8 palette_format; - int palette_wait; - int windowA_offset; - int windowB_offset; - int last_window; - int vga_palette; -} VbeInfoRec, *VbeInfoPtr; - typedef struct _VbeInfoBlock { U8 VbeSignature[4]; /* VBE Signature */ U16 VbeVersion; /* VBE Version */ @@ -134,6 +84,15 @@ typedef struct _VbeModeInfoBlock { U8 Reserved2[206]; /* remainder of ModeInfoBlock */ } __attribute__((packed)) VbeModeInfoBlock; +typedef struct _VbeInfoRec { + U8 palette_format; + int palette_wait; + int windowA_offset; + int windowB_offset; + int window_size; + int last_window; + VbeModeInfoBlock vmib; +} VbeInfoRec, *VbeInfoPtr; typedef struct _SupVbeInfoBlock { U8 SupVbeSignature[7]; /* Supplemental VBE Signature */ @@ -147,32 +106,58 @@ typedef struct _SupVbeInfoBlock { U8 Reserved[221]; /* Reserved */ } __attribute__((packed)) SupVbeInfoBlock; -VbeInfoPtr VbeSetup(void); -void VbeCleanup(VbeInfoPtr vi); -VbeInfoBlock *VbeGetInfo(VbeInfoPtr vi); -VbeModeInfoBlock *VbeGetModeInfo(VbeInfoPtr vi, int mode); -int VbeSetMode(VbeInfoPtr vi, int mode, int linear); -int VbeGetMode(VbeInfoPtr vi, int *mode); -int VbeSetupStateBuffer(VbeInfoPtr vi); -int VbeSaveState(VbeInfoPtr vi); -int VbeRestoreState(VbeInfoPtr vi); -void *VbeMapFramebuffer(VbeInfoPtr vi, VbeModeInfoBlock *vmib); -int VbeUnmapFrambuffer(VbeInfoPtr vi, VbeModeInfoBlock *vmib, void *fb); -int VbeSetPalette(VbeInfoPtr vi, int first, int number, U8 *entries); -int VbeSetPaletteOptions(VbeInfoPtr vi, U8 bits, int wait); -void *VbeSetWindow(VbeInfoPtr vi, int offset, int purpose, int *size_return); -int VbeReportInfo(VbeInfoPtr, VbeInfoBlock *); -int VbeReportModeInfo(VbeInfoPtr, U16 mode, VbeModeInfoBlock *); - -int VbeDoInterrupt(VbeInfoPtr, int num); -int VbeDoInterrupt10(VbeInfoPtr vi); -int VbeIsMemory(VbeInfoPtr vi, U32 i); -U8 VbeMemory(VbeInfoPtr, U32); -U16 VbeMemoryW(VbeInfoPtr, U32); -U32 VbeMemoryL(VbeInfoPtr, U32); -void VbeWriteMemory(VbeInfoPtr, U32, U8); -void VbeWriteMemoryW(VbeInfoPtr, U32, U16); -void VbeWriteMemoryL(VbeInfoPtr, U32, U32); -int VbeAllocateMemory(VbeInfoPtr, int); -void VbeDebug(VbeInfoPtr vi); +int +VbeGetVib (Vm86InfoPtr vi, VbeInfoBlock *vib); + +int +VbeGetVmib (Vm86InfoPtr vi, int mode, VbeModeInfoBlock *vmib); + +void +VbeReportInfo (Vm86InfoPtr vi); + +int +VbeGetNmode (Vm86InfoPtr vi); + +int +VbeGetModes (Vm86InfoPtr vi, VesaModePtr modes, int nmode); + +int +VbeGetModeInfo(Vm86InfoPtr vi, int m, VesaModePtr mode); + +VbeInfoPtr +VbeInit (Vm86InfoPtr vi); + +int +VbeSetMode (Vm86InfoPtr vi, VbeInfoPtr vbe, int mode, int linear); + +int +VbeGetMode(Vm86InfoPtr vi, int *mode); + +void * +VbeMapFramebuffer(Vm86InfoPtr vi, VbeInfoPtr vbe, int mode, int *size); + +void +VbeUnmapFramebuffer(Vm86InfoPtr vi, VbeInfoPtr vbe, int mode, void *fb); + +int +VbeSetPalette(Vm86InfoPtr vi, VbeInfoPtr vbe, int first, int number, U8 *entries); + +int +VbeGetPalette(Vm86InfoPtr vi, VbeInfoPtr vbe, int first, int number, U8 *entries); + +int +VbeSetPaletteOptions(Vm86InfoPtr vi, VbeInfoPtr vbe, U8 bits, int wait); + +void * +VbeSetWindow(Vm86InfoPtr vi, VbeInfoPtr vbe, int offset, int purpose, int *size_return); + +int +VbeReportVib(Vm86InfoPtr vi, VbeInfoBlock *vib); + +int +VbeReportModeInfo(Vm86InfoPtr vi, U16 mode, VbeModeInfoBlock *vmib); + +int +VbeDoInterrupt10(Vm86InfoPtr vi); + #endif diff --git a/hw/kdrive/vesa/vesa.c b/hw/kdrive/vesa/vesa.c index fa5bfc62d..5f7f44237 100644 --- a/hw/kdrive/vesa/vesa.c +++ b/hw/kdrive/vesa/vesa.c @@ -30,6 +30,7 @@ Bool vesa_shadow = FALSE; Bool vesa_linear_fb = TRUE; Bool vesa_restore = FALSE; Bool vesa_rotate = FALSE; +Bool vesa_verbose = FALSE; #define VesaPriv(scr) ((VesaScreenPrivPtr) (scr)->driver) @@ -38,166 +39,216 @@ Bool vesa_rotate = FALSE; #define vesaHeight(scr,vmib) (ScreenRotated(scr) ? vmib->XResolution : vmib->YResolution) static Bool -vesaModeSupported(VbeInfoPtr vi, VbeModeInfoBlock *vmib, Bool complain) +vesaModeSupportable (VesaModePtr mode, Bool complain) { - if((vmib->ModeAttributes & 0x10) == 0) { - if(complain) - ErrorF("Text mode specified.\n"); - return FALSE; + if((mode->ModeAttributes & 0x10) == 0) { + if(complain) + ErrorF("Text mode specified.\n"); + return FALSE; } - if(vmib->MemoryModel != 0x06 && vmib->MemoryModel != 0x04 && vmib->MemoryModel != 0x03) { - if(complain) - ErrorF("Unsupported memory model 0x%X\n", vmib->MemoryModel); - return FALSE; + if(mode->MemoryModel != 0x06 && mode->MemoryModel != 0x04 && mode->MemoryModel != 0x03) { + if(complain) + ErrorF("Unsupported memory model 0x%X\n", mode->MemoryModel); + return FALSE; } - if((vmib->ModeAttributes & 0x80) == 0) { - if ((vmib->WinAAttributes & 0x5) != 0x5) { + if((mode->ModeAttributes & 0x80) == 0) { + if ((mode->ModeAttributes & 0x40) != 0) { if(complain) ErrorF("Neither linear nor windowed framebuffer available in this mode\n"); return FALSE; } } - if(!(vmib->ModeAttributes & 1)) { - if(complain) - ErrorF("Mode not supported on this hardware\n"); - return FALSE; + if(!(mode->ModeAttributes & 1)) { + if(complain) + ErrorF("Mode not supported on this hardware\n"); + return FALSE; } return TRUE; } -Bool -vesaListModes() +static Bool +vesaModeSupported (VesaCardPrivPtr priv, VesaModePtr mode, Bool complain) { - int code; - VbeInfoPtr vi = NULL; - VbeInfoBlock *vib; - VbeModeInfoBlock *vmib; - unsigned p, num_modes, i; - CARD16 *modes_list = NULL; - - vi = VbeSetup(); - if(!vi) - goto fail; - - vib = VbeGetInfo(vi); - if(!vib) - goto fail; - - VbeReportInfo(vi, vib); - /* The spec says you need to copy the list */ - p = MAKE_POINTER_1(vib->VideoModePtr); - num_modes = 0; - while(VbeMemoryW(vi, p) != 0xFFFF) { - num_modes++; - p+=2; - } - modes_list = ALLOCATE_LOCAL(num_modes * sizeof(CARD16)); - if(!modes_list) - goto fail; - p = MAKE_POINTER_1(vib->VideoModePtr); - for(i=0; ivbeInfo && mode->vbe) { + if (complain) + ErrorF("VBE bios mode not usable.\n"); + return FALSE; + } + return vesaModeSupportable (mode, complain); } -Bool -vesaGetModes (KdCardInfo *card, VesaCardPrivPtr priv) +void +vesaReportMode (VesaModePtr mode) { - VesaModePtr mode; - int nmode; - unsigned int i; - VbeInfoPtr vi = priv->vi; - VbeInfoBlock *vib = priv->vib; - VbeModeInfoBlock *vmib; - - /* The spec says you need to copy the list */ - i = MAKE_POINTER_1(vib->VideoModePtr); - nmode = 0; - while(VbeMemoryW(vi, i) != 0xFFFF) { - nmode++; - i+=2; - } - if (!nmode) - return FALSE; - priv->modes = xalloc (nmode * sizeof (VesaModeRec)); - if (!priv->modes) - return FALSE; - priv->nmode = nmode; - i = MAKE_POINTER_1(vib->VideoModePtr); - nmode = 0; - while(nmode < priv->nmode) { - priv->modes[nmode].mode = VbeMemoryW(vi, i); - nmode++; - i+=2; - } - i = MAKE_POINTER_1(vib->VideoModePtr); - nmode = 0; - while(nmode < priv->nmode) { - vmib = VbeGetModeInfo(vi, priv->modes[nmode].mode); - if(!vmib) - break; - priv->modes[nmode].vmib = *vmib; - i += 2; - nmode++; + int supported = (mode->ModeAttributes&MODE_SUPPORTED)?1:0; + int colour = (mode->ModeAttributes&MODE_COLOUR)?1:0; + int graphics = (mode->ModeAttributes&MODE_GRAPHICS)?1:0; + int vga_compatible = !((mode->ModeAttributes&MODE_VGA)?1:0); + int linear_fb = (mode->ModeAttributes&MODE_LINEAR)?1:0; + + ErrorF("0x%04X: %dx%dx%d%s", + (unsigned)mode->mode, + (int)mode->XResolution, (int)mode->YResolution, + vesaDepth (mode), + colour?"":" (monochrome)"); + switch(mode->MemoryModel) { + case MEMORY_TEXT: + ErrorF(" text mode"); + break; + case MEMORY_CGA: + ErrorF(" CGA graphics"); + break; + case MEMORY_HERCULES: + ErrorF(" Hercules graphics"); + break; + case MEMORY_PLANAR: + ErrorF(" Planar (%d planes)", mode->NumberOfPlanes); + break; + case MEMORY_PSEUDO: + ErrorF(" PseudoColor"); + break; + case MEMORY_NONCHAIN: + ErrorF(" Non-chain 4, 256 colour"); + break; + case MEMORY_DIRECT: + if(mode->DirectColorModeInfo & MODE_DIRECT) + ErrorF(" DirectColor"); + else + ErrorF(" TrueColor"); + ErrorF(" [%d:%d:%d:%d]", + mode->RedMaskSize, mode->GreenMaskSize, mode->BlueMaskSize, + mode->RsvdMaskSize); + if(mode->DirectColorModeInfo & 2) + ErrorF(" (reserved bits are reserved)"); + break; + case MEMORY_YUV: + ErrorF("YUV"); + break; + default: + ErrorF("unknown MemoryModel 0x%X ", mode->MemoryModel); } - return TRUE; + if(!supported) + ErrorF(" (unsupported)"); + else if(!linear_fb) + ErrorF(" (no linear framebuffer)"); + ErrorF("\n"); } +VesaModePtr +vesaGetModes (Vm86InfoPtr vi, int *ret_nmode) +{ + VesaModePtr modes; + int nmode, nmodeVbe, nmodeVga; + int code; + + code = VgaGetNmode (vi); + if (code <= 0) + nmodeVga = 0; + else + nmodeVga = code; + + code = VbeGetNmode (vi); + if (code <= 0) + nmodeVbe = 0; + else + nmodeVbe = code; + + nmode = nmodeVga + nmodeVbe; + if (nmode <= 0) + return 0; + + modes = xalloc (nmode * sizeof (VesaModeRec)); + + if (nmodeVga) + { + code = VgaGetModes (vi, modes, nmodeVga); + if (code <= 0) + nmodeVga = 0; + else + nmodeVga = code; + } + + if (nmodeVbe) + { + code = VbeGetModes (vi, modes + nmodeVga, nmodeVbe); + if (code <= 0) + nmodeVbe = 0; + else + nmodeVbe = code; + } + + nmode = nmodeVga + nmodeVbe; + + if (nmode == 0) + { + xfree (modes); + modes = 0; + return 0; + } + *ret_nmode = nmode; + return modes; +} Bool vesaInitialize (KdCardInfo *card, VesaCardPrivPtr priv) { int code; - - priv->vi = VbeSetup(); - if(!priv->vi) - goto fail; - - priv->vib = VbeGetInfo(priv->vi); - if(!priv->vib) - goto fail; - code = VbeSetupStateBuffer(priv->vi); - if(code < 0) - goto fail; - - code = VbeSaveState(priv->vi); - if(code<0) - goto fail; + priv->vi = Vm86Setup(); + if(!priv->vi) + goto fail; - if (!vesaGetModes (card, priv)) + priv->modes = vesaGetModes (priv->vi, &priv->nmode); + + if (!priv->modes) goto fail; + + priv->vbeInfo = VbeInit (priv->vi); card->driver = priv; return TRUE; - fail: +fail: if(priv->vi) - VbeCleanup(priv->vi); + Vm86Cleanup(priv->vi); return FALSE; } +void +vesaListModes (void) +{ + Vm86InfoPtr vi; + VesaModePtr modes; + int nmode; + int n; + + vi = Vm86Setup (); + if (!vi) + { + ErrorF ("Can't setup vm86\n"); + } + else + { + modes = vesaGetModes (vi, &nmode); + if (!modes) + { + ErrorF ("No modes available\n"); + } + else + { + VbeReportInfo (vi); + for (n = 0; n < nmode; n++) + { + if (vesa_force_mode || vesaModeSupportable (modes+n, 0)) + vesaReportMode (modes+n); + } + xfree (modes); + } + Vm86Cleanup (vi); + } +} + Bool vesaCardInit(KdCardInfo *card) { @@ -217,19 +268,19 @@ vesaCardInit(KdCardInfo *card) } int -vesaDepth (VbeModeInfoBlock *m) +vesaDepth (VesaModePtr mode) { - if (m->MemoryModel == 0x06) - return (m->RedMaskSize + - m->GreenMaskSize + - m->BlueMaskSize); + if (mode->MemoryModel == MEMORY_DIRECT) + return (mode->RedMaskSize + + mode->GreenMaskSize + + mode->BlueMaskSize); else - return m->BitsPerPixel; + return mode->BitsPerPixel; } Bool -vesaModeGood (KdScreenInfo *screen, - VbeModeInfoBlock *a) +vesaModeGood (KdScreenInfo *screen, + VesaModePtr a) { if (vesaWidth(screen,a) <= screen->width && vesaHeight(screen,a) <= screen->height && @@ -242,8 +293,8 @@ vesaModeGood (KdScreenInfo *screen, #define vabs(a) ((a) >= 0 ? (a) : -(a)) int -vesaSizeError (KdScreenInfo *screen, - VbeModeInfoBlock *a) +vesaSizeError (KdScreenInfo *screen, + VesaModePtr a) { int xdist, ydist; xdist = vabs (screen->width - vesaWidth(screen,a)); @@ -252,9 +303,9 @@ vesaSizeError (KdScreenInfo *screen, } Bool -vesaModeBetter (KdScreenInfo *screen, - VbeModeInfoBlock *a, - VbeModeInfoBlock *b) +vesaModeBetter (KdScreenInfo *screen, + VesaModePtr a, + VesaModePtr b) { int aerr, berr; @@ -290,21 +341,21 @@ vesaSelectMode (KdScreenInfo *screen) { for (best = 0; best < priv->nmode; best++) if (priv->modes[best].mode == vesa_video_mode && - (vesaModeSupported (priv->vi, &priv->modes[best].vmib, FALSE) || + (vesaModeSupported (priv, &priv->modes[best], FALSE) || vesa_force_mode)) return &priv->modes[best]; } for (best = 0; best < priv->nmode; best++) { - if (vesaModeSupported (priv->vi, &priv->modes[best].vmib, FALSE)) + if (vesaModeSupported (priv, &priv->modes[best], FALSE)) break; } if (best == priv->nmode) return 0; for (i = best + 1; i < priv->nmode; i++) - if (vesaModeSupported (priv->vi, &priv->modes[i].vmib, FALSE) && - vesaModeBetter (screen, &priv->modes[i].vmib, - &priv->modes[best].vmib)) + if (vesaModeSupported (priv, &priv->modes[i], FALSE) && + vesaModeBetter (screen, &priv->modes[i], + &priv->modes[best])) best = i; return &priv->modes[best]; } @@ -313,19 +364,43 @@ Bool vesaScreenInitialize (KdScreenInfo *screen, VesaScreenPrivPtr pscr) { VesaCardPrivPtr priv = screen->card->driver; - VbeModeInfoBlock *vmib; + VesaModePtr mode; Pixel allbits; int depth; - int bpp; + int bpp, fbbpp; screen->driver = pscr; pscr->rotate = FALSE; if (screen->width < screen->height) pscr->rotate = TRUE; + + if (!screen->width || !screen->height) + { + screen->width = 640; + screen->height = 480; + } + if (!screen->fb[0].depth) + screen->fb[0].depth = 4; + + if (vesa_verbose) + ErrorF ("Mode requested %dx%dx%d\n", + screen->width, screen->height, screen->fb[0].depth); + pscr->mode = vesaSelectMode (screen); + if (!pscr->mode) + { + if (vesa_verbose) + ErrorF ("No selectable mode\n"); return FALSE; + } + if (vesa_verbose) + { + ErrorF ("\t"); + vesaReportMode (pscr->mode); + } + pscr->shadow = vesa_shadow; pscr->origDepth = screen->fb[0].depth; if (vesa_linear_fb) @@ -333,21 +408,35 @@ vesaScreenInitialize (KdScreenInfo *screen, VesaScreenPrivPtr pscr) else pscr->mapping = VESA_WINDOWED; - vmib = &pscr->mode->vmib; + mode = pscr->mode; - depth = vesaDepth (vmib); - bpp = vmib->BitsPerPixel; + depth = vesaDepth (mode); + bpp = mode->BitsPerPixel; - switch (vmib->MemoryModel) { - case 0x06: + if (bpp > 24) + bpp = 32; + else if (bpp > 16) + bpp = 24; + else if (bpp > 8) + bpp = 16; + else if (bpp > 4) + bpp = 8; + else if (bpp > 1) + bpp = 4; + else + bpp = 1; + fbbpp = bpp; + + switch (mode->MemoryModel) { + case MEMORY_DIRECT: /* TrueColor or DirectColor */ screen->fb[0].visuals = (1 << TrueColor); screen->fb[0].redMask = - FbStipMask(vmib->RedFieldPosition, vmib->RedMaskSize); + FbStipMask(mode->RedFieldPosition, mode->RedMaskSize); screen->fb[0].greenMask = - FbStipMask(vmib->GreenFieldPosition, vmib->GreenMaskSize); + FbStipMask(mode->GreenFieldPosition, mode->GreenMaskSize); screen->fb[0].blueMask = - FbStipMask(vmib->BlueFieldPosition, vmib->BlueMaskSize); + FbStipMask(mode->BlueFieldPosition, mode->BlueMaskSize); allbits = screen->fb[0].redMask | screen->fb[0].greenMask | @@ -355,8 +444,14 @@ vesaScreenInitialize (KdScreenInfo *screen, VesaScreenPrivPtr pscr) depth = 32; while (depth && !(allbits & (1 << (depth - 1)))) depth--; + if (vesa_verbose) + ErrorF ("\tTrue Color bpp %d depth %d red 0x%x green 0x%x blue 0x%x\n", + bpp, depth, + screen->fb[0].redMask, + screen->fb[0].greenMask, + screen->fb[0].blueMask); break; - case 0x04: + case MEMORY_PSEUDO: /* PseudoColor */ screen->fb[0].visuals = ((1 << StaticGray) | (1 << GrayScale) | @@ -367,43 +462,73 @@ vesaScreenInitialize (KdScreenInfo *screen, VesaScreenPrivPtr pscr) screen->fb[0].blueMask = 0x00; screen->fb[0].greenMask = 0x00; screen->fb[0].redMask = 0x00; + if (vesa_verbose) + ErrorF ("\tPseudo Color bpp %d depth %d\n", + bpp, depth); break; - case 0x03: + case MEMORY_PLANAR: /* 4 plane planar */ - screen->fb[0].visuals = (1 << StaticColor); + if (mode->ModeAttributes & MODE_COLOUR) + screen->fb[0].visuals = (1 << StaticColor); + else + screen->fb[0].visuals = (1 << StaticGray); screen->fb[0].blueMask = 0x00; screen->fb[0].greenMask = 0x00; screen->fb[0].redMask = 0x00; - bpp = screen->fb[0].bitsPerPixel; - if (bpp != 8) - bpp = 4; - depth = bpp; - pscr->mapping = VESA_PLANAR; + if (bpp == 4) + { + bpp = screen->fb[0].bitsPerPixel; + if (bpp != 8) + bpp = 4; + depth = bpp; + } + if (bpp == 1) + { + pscr->mapping = VESA_MONO; + if (vesa_verbose) + ErrorF ("\tMonochrome\n"); + } + else + { + pscr->mapping = VESA_PLANAR; + if (vesa_verbose) + ErrorF ("\tStatic color bpp %d depth %d\n", + bpp, depth); + } pscr->rotate = FALSE; break; default: ErrorF("Unsupported VESA MemoryModel 0x%02X\n", - vmib->MemoryModel); + mode->MemoryModel); return FALSE; } - screen->width = vesaWidth(screen, vmib); - screen->height = vesaHeight(screen, vmib); + screen->width = vesaWidth(screen, mode); + screen->height = vesaHeight(screen, mode); screen->fb[0].depth = depth; screen->fb[0].bitsPerPixel = bpp; - screen->fb[0].byteStride = vmib->BytesPerScanLine; - screen->fb[0].pixelStride = ((vmib->BytesPerScanLine * 8) / - vmib->BitsPerPixel); + screen->fb[0].byteStride = mode->BytesPerScanLine; + screen->fb[0].pixelStride = ((mode->BytesPerScanLine * 8) / fbbpp); - if (pscr->mapping == VESA_LINEAR && !(vmib->ModeAttributes & 0x80)) + if (pscr->mapping == VESA_LINEAR && !(mode->ModeAttributes & MODE_LINEAR)) pscr->mapping = VESA_WINDOWED; if (pscr->rotate) pscr->shadow = TRUE; switch (pscr->mapping) { + case VESA_MONO: + pscr->shadow = TRUE; + /* fall through */ case VESA_LINEAR: - pscr->fb = VbeMapFramebuffer(priv->vi, vmib); + if (mode->vbe) + pscr->fb = VbeMapFramebuffer(priv->vi, priv->vbeInfo, + pscr->mode->mode, + &pscr->fb_size); + else + pscr->fb = VgaMapFramebuffer (priv->vi, + pscr->mode->mode, + &pscr->fb_size); break; case VESA_WINDOWED: pscr->fb = NULL; @@ -424,6 +549,10 @@ vesaScreenInitialize (KdScreenInfo *screen, VesaScreenPrivPtr pscr) if (pscr->shadow) return KdShadowScreenInit (screen); + if (vesa_verbose) + ErrorF ("Mode selected %dx%dx%d\n", + screen->width, screen->height, screen->fb[0].depth); + return TRUE; } @@ -441,7 +570,7 @@ vesaScreenInit(KdScreenInfo *screen) } void * -vesaWindowPlanar (ScreenPtr pScreen, +vesaSetWindowPlanar(ScreenPtr pScreen, CARD32 row, CARD32 offset, int mode, @@ -450,24 +579,95 @@ vesaWindowPlanar (ScreenPtr pScreen, KdScreenPriv(pScreen); VesaCardPrivPtr priv = pScreenPriv->card->driver; VesaScreenPrivPtr pscr = pScreenPriv->screen->driver; - VbeModeInfoBlock *vmib = &pscr->mode->vmib; static int plane; int winSize; void *base; - if (!pScreenPriv->enabled) - return 0; plane = offset & 3; - VbeSetWritePlaneMask (priv->vi, (1 << plane)); + VgaSetWritePlaneMask (priv->vi, (1 << plane)); offset = offset >> 2; - base = VbeSetWindow (priv->vi, - vmib->BytesPerScanLine * row + offset, - mode, - &winSize); + if (pscr->mode->vbe) + { + base = VbeSetWindow (priv->vi, + priv->vbeInfo, + pscr->mode->BytesPerScanLine * row + offset, + mode, + &winSize); + } + else + { + base = VgaSetWindow (priv->vi, + pscr->mode->mode, + pscr->mode->BytesPerScanLine * row + offset, + mode, + &winSize); + } + *size = (CARD32) winSize; + return base; +} + +void * +vesaSetWindowLinear (ScreenPtr pScreen, + CARD32 row, + CARD32 offset, + int mode, + CARD32 *size) +{ + KdScreenPriv(pScreen); + VesaCardPrivPtr priv = pScreenPriv->card->driver; + VesaScreenPrivPtr pscr = pScreenPriv->screen->driver; + + *size = pscr->mode->BytesPerScanLine; + return (CARD8 *) pscr->fb + row * pscr->mode->BytesPerScanLine + offset; +} + +void * +vesaSetWindowWindowed (ScreenPtr pScreen, + CARD32 row, + CARD32 offset, + int mode, + CARD32 *size) +{ + KdScreenPriv(pScreen); + VesaCardPrivPtr priv = pScreenPriv->card->driver; + VesaScreenPrivPtr pscr = pScreenPriv->screen->driver; + int winSize; + void *base; + + if (pscr->mode->vbe) + { + base = VbeSetWindow (priv->vi, + priv->vbeInfo, + pscr->mode->BytesPerScanLine * row + offset, + mode, + &winSize); + } + else + { + base = VgaSetWindow (priv->vi, + pscr->mode->mode, + pscr->mode->BytesPerScanLine * row + offset, + mode, + &winSize); + } *size = (CARD32) winSize; return base; } +void * +vesaWindowPlanar (ScreenPtr pScreen, + CARD32 row, + CARD32 offset, + int mode, + CARD32 *size) +{ + KdScreenPriv(pScreen); + + if (!pScreenPriv->enabled) + return 0; + return vesaSetWindowPlanar (pScreen, row, offset, mode, size); +} + void * vesaWindowLinear (ScreenPtr pScreen, CARD32 row, @@ -476,14 +676,10 @@ vesaWindowLinear (ScreenPtr pScreen, CARD32 *size) { KdScreenPriv(pScreen); - VesaCardPrivPtr priv = pScreenPriv->card->driver; - VesaScreenPrivPtr pscr = pScreenPriv->screen->driver; - VbeModeInfoBlock *vmib = &pscr->mode->vmib; if (!pScreenPriv->enabled) return 0; - *size = vmib->BytesPerScanLine; - return (CARD8 *) pscr->fb + row * vmib->BytesPerScanLine + offset; + return vesaSetWindowLinear (pScreen, row, offset, mode, size); } void * @@ -494,41 +690,114 @@ vesaWindowWindowed (ScreenPtr pScreen, CARD32 *size) { KdScreenPriv(pScreen); + + if (!pScreenPriv->enabled) + return 0; + return vesaSetWindowWindowed (pScreen, row, offset, mode, size); +} + +#define vesaInvertBits32(v) { \ + v = ((v & 0x55555555) << 1) | ((v >> 1) & 0x55555555); \ + v = ((v & 0x33333333) << 2) | ((v >> 2) & 0x33333333); \ + v = ((v & 0x0f0f0f0f) << 4) | ((v >> 4) & 0x0f0f0f0f); \ +} + +void * +vesaWindowCga (ScreenPtr pScreen, + CARD32 row, + CARD32 offset, + int mode, + CARD32 *size) +{ + KdScreenPriv(pScreen); VesaCardPrivPtr priv = pScreenPriv->card->driver; VesaScreenPrivPtr pscr = pScreenPriv->screen->driver; - VbeModeInfoBlock *vmib = &pscr->mode->vmib; - int winSize; - void *base; - + int line; + if (!pScreenPriv->enabled) return 0; - base = VbeSetWindow (priv->vi, - vmib->BytesPerScanLine * row + offset, - mode, - &winSize); - *size = (CARD32) winSize; - return base; + *size = pscr->mode->BytesPerScanLine; + line = ((row & 1) << 13) + (row >> 1) * pscr->mode->BytesPerScanLine; + return (CARD8 *) pscr->fb + line + offset; } -static CARD16 vga16Colors[16][3] = { -#if 0 - { 0, 0, 0, }, /* 0 */ - { 0, 0, 0x80,}, /* 1 */ - { 0, 0x80,0, }, /* 2 */ - { 0, 0x80,0x80,}, /* 3 */ - { 0x80,0, 0, }, /* 4 */ - { 0x80,0, 0x80,}, /* 5 */ - { 0x80,0x80,0, }, /* 6 */ - { 0xC0,0xC0,0xC0,}, /* 7 */ - { 0x80,0x80,0x80,}, /* 8 */ - { 0, 0, 0xFF,}, /* 9 */ - { 0, 0xFF,0 ,}, /* 10 */ - { 0, 0xFF,0xFF,}, /* 11 */ - { 0xFF,0, 0 ,}, /* 12 */ - { 0xFF,0, 0xFF,}, /* 13 */ - { 0xFF,0xFF,0 ,}, /* 14 */ - { 0xFF,0xFF,0xFF,}, /* 15 */ -#else +void +vesaUpdateMono (ScreenPtr pScreen, + PixmapPtr pShadow, + RegionPtr damage) +{ + shadowScrPriv(pScreen); + int nbox = REGION_NUM_RECTS (damage); + BoxPtr pbox = REGION_RECTS (damage); + FbBits *shaBase, *shaLine, *sha; + FbBits s; + FbStride shaStride; + int scrBase, scrLine, scr; + int shaBpp; + int x, y, w, h, width; + int i; + FbBits *winBase, *winLine, *win; + CARD32 winSize; + FbBits bits; + int plane; + + fbGetDrawable (&pShadow->drawable, shaBase, shaStride, shaBpp); + while (nbox--) + { + x = pbox->x1 * shaBpp; + y = pbox->y1; + w = (pbox->x2 - pbox->x1) * shaBpp; + h = pbox->y2 - pbox->y1; + + scrLine = (x >> FB_SHIFT); + shaLine = shaBase + y * shaStride + (x >> FB_SHIFT); + + x &= FB_MASK; + w = (w + x + FB_MASK) >> FB_SHIFT; + + while (h--) + { + winSize = 0; + scrBase = 0; + width = w; + scr = scrLine; + sha = shaLine; + while (width) { + /* how much remains in this window */ + i = scrBase + winSize - scr; + if (i <= 0 || scr < scrBase) + { + winBase = (FbBits *) (*pScrPriv->window) (pScreen, + y, + scr * sizeof (FbBits), + SHADOW_WINDOW_WRITE, + &winSize); + if(!winBase) + return; + scrBase = scr; + winSize /= sizeof (FbBits); + i = winSize; + } + win = winBase + (scr - scrBase); + if (i > width) + i = width; + width -= i; + scr += i; + while (i--) + { + bits = *sha++; + vesaInvertBits32(bits); + *win++ = bits; + } + } + shaLine += shaStride; + y++; + } + pbox++; + } +} + +static const CARD16 vga16Colors[16][3] = { { 0, 0, 0, }, /* 0 */ { 0, 0, 0xAA,}, /* 1 */ { 0, 0xAA,0, }, /* 2 */ @@ -545,7 +814,6 @@ static CARD16 vga16Colors[16][3] = { { 0xFF,0x55,0xFF,}, /* 13 */ { 0xFF,0xFF,0x55,}, /* 14 */ { 0xFF,0xFF,0xFF,}, /* 15 */ -#endif }; Bool @@ -586,26 +854,20 @@ vesaInitScreen(ScreenPtr pScreen) case VESA_PLANAR: pScreen->CreateColormap = vesaCreateColormap16; if (pScreenPriv->screen->fb[0].bitsPerPixel == 8) - { -#if 0 - int i; - - for (i = 0; i < pScreen->numVisuals; i++) - { - if (pScreen->visuals[i].nplanes == - pScreenPriv->screen->fb[0].depth) - { - pScreen->visuals[i].ColormapEntries = 16; - } - } -#endif update = shadowUpdatePlanar4x8; - } else update = shadowUpdatePlanar4; window = vesaWindowPlanar; pscr->rotate = FALSE; break; + case VESA_MONO: + update = vesaUpdateMono; + if (pscr->mode->mode < 8) + window = vesaWindowCga; + else + window = vesaWindowLinear; + pscr->rotate = FALSE; + break; } if (pscr->rotate) { @@ -629,55 +891,41 @@ Bool vesaEnable(ScreenPtr pScreen) { KdScreenPriv(pScreen); - VesaCardPrivPtr priv = pScreenPriv->card->driver; + VesaCardPrivPtr priv = pScreenPriv->card->driver; VesaScreenPrivPtr pscr = pScreenPriv->screen->driver; - int code; - int palette_wait = 0, palette_hi = 0; - int i; - int size; - char *p; + int code; + int i; + CARD32 size; + char *p; KdMouseMatrix m; - code = VbeSetMode(priv->vi, pscr->mode->mode, pscr->mapping == VESA_LINEAR); - if(code < 0) - return FALSE; - + if (pscr->mode->vbe) { - int p; - CARD8 scratch[4] = {0x40,0x40,0x40,0}; - for (p = 0; p < 256; p++) - { - if (20 <= p && p < 21) - { - scratch[0] = 255; - scratch[1] = 255; - scratch[2] = 255; - } - else - { - scratch[0] = 0; - scratch[1] = 0; - scratch[2] = 0; - } - VbeSetPalette(priv->vi, p, 1, scratch); - } + if (vesa_verbose) + ErrorF ("Enable VBE mode 0x%x\n", pscr->mode->mode); + code = VbeSetMode(priv->vi, priv->vbeInfo, pscr->mode->mode, + pscr->mapping == VESA_LINEAR); + } + else + { + if (vesa_verbose) + ErrorF ("Enable BIOS mode 0x%x\n", pscr->mode->mode); + code = VgaSetMode (priv->vi, pscr->mode->mode); } - if(priv->vib->Capabilities[0] & 1) - palette_hi = 1; - if(priv->vib->Capabilities[0] & 4) - palette_wait = 1; - if(palette_hi || palette_wait) - VbeSetPaletteOptions(priv->vi, palette_hi?8:6, palette_wait); - + if(code < 0) + return FALSE; + switch (pscr->mapping) { + case VESA_MONO: + VgaSetWritePlaneMask (priv->vi, 0x1); case VESA_LINEAR: memcpy (priv->text, pscr->fb, VESA_TEXT_SAVE); break; case VESA_WINDOWED: for (i = 0; i < VESA_TEXT_SAVE;) { - p = VbeSetWindow(priv->vi, i, VBE_WINDOW_READ, &size); + p = vesaSetWindowWindowed (pScreen, 0, i, VBE_WINDOW_READ, &size); if(!p) { ErrorF("Couldn't set window for saving VGA font\n"); break; @@ -689,10 +937,9 @@ vesaEnable(ScreenPtr pScreen) } break; case VESA_PLANAR: - p = VbeSetWindow (priv->vi, 0, VBE_WINDOW_READ, &size); for (i = 0; i < 4; i++) { - VbeSetReadPlaneMap (priv->vi, i); + p = vesaSetWindowPlanar (pScreen, 0, i, VBE_WINDOW_READ, &size); memcpy (((char *)priv->text) + i * (VESA_TEXT_SAVE/4), p, (VESA_TEXT_SAVE/4)); } @@ -716,19 +963,20 @@ void vesaDisable(ScreenPtr pScreen) { KdScreenPriv(pScreen); - VesaCardPrivPtr priv = pScreenPriv->card->driver; + VesaCardPrivPtr priv = pScreenPriv->card->driver; VesaScreenPrivPtr pscr = pScreenPriv->screen->driver; - int i=0; - int size; - char *p; + int i=0; + CARD32 size; + char *p; switch (pscr->mapping) { case VESA_LINEAR: + case VESA_MONO: memcpy(pscr->fb, priv->text, VESA_TEXT_SAVE); break; case VESA_WINDOWED: while(i < VESA_TEXT_SAVE) { - p = VbeSetWindow(priv->vi, i, VBE_WINDOW_WRITE, &size); + p = vesaSetWindowWindowed (pScreen, 0, i, VBE_WINDOW_WRITE, &size); if(!p) { ErrorF("Couldn't set window for restoring VGA font\n"); break; @@ -740,10 +988,9 @@ vesaDisable(ScreenPtr pScreen) } break; case VESA_PLANAR: - p = VbeSetWindow (priv->vi, 0, VBE_WINDOW_WRITE, &size); for (i = 0; i < 4; i++) { - VbeSetWritePlaneMask (priv->vi, 1 << i); + p = vesaSetWindowPlanar (pScreen, 0, i, VBE_WINDOW_WRITE, &size); memcpy (p, ((char *)priv->text) + i * (VESA_TEXT_SAVE/4), (VESA_TEXT_SAVE/4)); @@ -761,29 +1008,49 @@ vesaPreserve(KdCardInfo *card) /* The framebuffer might not be valid at this point, so we cannot save the VGA fonts now; we do it in vesaEnable. */ - code = VbeSaveState(priv->vi); - if(code < 0) - FatalError("Couldn't save state\n"); + if (VbeGetMode (priv->vi, &priv->old_vbe_mode) < 0) + priv->old_vbe_mode = -1; - return; + if (VgaGetMode (priv->vi, &priv->old_vga_mode) < 0) + priv->old_vga_mode = -1; + + if (vesa_verbose) + ErrorF ("Previous modes: VBE 0x%x BIOS 0x%x\n", + priv->old_vbe_mode, priv->old_vga_mode); } void vesaRestore(KdCardInfo *card) { VesaCardPrivPtr priv = card->driver; - VbeRestoreState(priv->vi); - return; + int n; + + for (n = 0; n < priv->nmode; n++) + if (priv->modes[n].vbe && priv->modes[n].mode == (priv->old_vbe_mode&0x3fff)) + break; + + if (n < priv->nmode) + { + if (vesa_verbose) + ErrorF ("Restore VBE mode 0x%x\n", priv->old_vbe_mode); + VbeSetMode (priv->vi, priv->vbeInfo, priv->old_vbe_mode, 0); + } + else + { + if (vesa_verbose) + ErrorF ("Restore BIOS mode 0x%x\n", priv->old_vga_mode); + VgaSetMode (priv->vi, priv->old_vga_mode); + } } void vesaCardFini(KdCardInfo *card) { VesaCardPrivPtr priv = card->driver; - if (vesa_restore) - VbeSetTextMode(priv->vi,3); - VbeCleanup(priv->vi); - return; + + if (priv->vbeInfo) + VbeCleanup (priv->vi, priv->vbeInfo); + Vm86Cleanup(priv->vi); } void @@ -793,14 +1060,47 @@ vesaScreenFini(KdScreenInfo *screen) VesaCardPrivPtr priv = screen->card->driver; if (pscr->fb) - VbeUnmapFramebuffer(priv->vi, &pscr->mode->vmib, pscr->fb); + { + if (pscr->mode->vbe) + VbeUnmapFramebuffer(priv->vi, priv->vbeInfo, pscr->mode->mode, pscr->fb); + else + VgaUnmapFramebuffer (priv->vi); + } if (pscr->shadow) KdShadowScreenFini (screen); screen->fb[0].depth = pscr->origDepth; - return; } +int +vesaSetPalette(VesaCardPrivPtr priv, int first, int number, U8 *entries) +{ + if (priv->vga_palette) + return VgaSetPalette (priv->vi, first, number, entries); + else + return VbeSetPalette (priv->vi, priv->vbeInfo, first, number, entries); +} + + +int +vesaGetPalette(VesaCardPrivPtr priv, int first, int number, U8 *entries) +{ + int code; + + if (priv->vga_palette) + code = VgaGetPalette (priv->vi, first, number, entries); + else + { + code = VbeGetPalette (priv->vi, priv->vbeInfo, first, number, entries); + if (code < 0) + { + priv->vga_palette = 1; + code = VgaGetPalette (priv->vi, first, number, entries); + } + } + return code; +} + void vesaPutColors (ScreenPtr pScreen, int fb, int n, xColorItem *pdefs) { @@ -841,15 +1141,15 @@ vesaPutColors (ScreenPtr pScreen, int fb, int n, xColorItem *pdefs) */ if (p < 16) { - VbeSetPalette (priv->vi, p, 1, scratch); + vesaSetPalette (priv, p, 1, scratch); if (p >= 8) - VbeSetPalette (priv->vi, p+0x30, 1, scratch); + vesaSetPalette (priv, p+0x30, 1, scratch); else if (p == 6) - VbeSetPalette (priv->vi, 0x14, 1, scratch); + vesaSetPalette (priv, 0x14, 1, scratch); } } else - VbeSetPalette(priv->vi, p, 1, scratch); + vesaSetPalette(priv, p, 1, scratch); } } @@ -876,7 +1176,7 @@ vesaGetColors (ScreenPtr pScreen, int fb, int n, xColorItem *pdefs) } for(i = 0; ivi, pdefs[i].pixel, 1, scratch); + vesaGetPalette(priv, pdefs[i].pixel, 1, scratch); pdefs[i].red = scratch[red]<<8; pdefs[i].green = scratch[green]<<8; pdefs[i].blue = scratch[blue]<<8; @@ -907,8 +1207,8 @@ vesaProcessArgument (int argc, char **argv, int i) } else if(!strcmp(argv[i], "-nolinear")) { vesa_linear_fb = FALSE; return 1; - } else if(!strcmp(argv[i], "-restore")) { - vesa_restore = TRUE; + } else if(!strcmp(argv[i], "-verbose")) { + vesa_verbose = TRUE; return 1; } diff --git a/hw/kdrive/vesa/vesa.h b/hw/kdrive/vesa/vesa.h index 8ded2ab67..9b521698d 100644 --- a/hw/kdrive/vesa/vesa.h +++ b/hw/kdrive/vesa/vesa.h @@ -25,54 +25,127 @@ THE SOFTWARE. #define _VESA_H_ #include "kdrive.h" -#include -#include "vbe.h" +#include "vm86.h" #define VESA_TEXT_SAVE (64*1024) +#define MODE_SUPPORTED 0x01 +#define MODE_COLOUR 0x08 +#define MODE_GRAPHICS 0x10 +#define MODE_VGA 0x20 +#define MODE_LINEAR 0x80 + +#define MODE_DIRECT 0x1 + +#define MEMORY_TEXT 0 +#define MEMORY_CGA 1 +#define MEMORY_HERCULES 2 +#define MEMORY_PLANAR 3 +#define MEMORY_PSEUDO 4 +#define MEMORY_NONCHAIN 5 +#define MEMORY_DIRECT 6 +#define MEMORY_YUV 7 + typedef struct _VesaMode { - int mode; - VbeModeInfoBlock vmib; + int mode; /* mode number */ + int vbe; /* a VBE mode */ + int ModeAttributes; /* mode attributes */ + int NumberOfPlanes; /* number of memory planes */ + int BitsPerPixel; /* bits per pixel */ + int MemoryModel; /* memory model type */ + int RedMaskSize; /* size of direct color red mask in bits */ + int RedFieldPosition; /* bit position of lsb of red mask */ + int GreenMaskSize; /* size of direct color green mask in bits */ + int GreenFieldPosition; /* bit position of lsb of green mask */ + int BlueMaskSize; /* size of direct color blue mask in bits */ + int BlueFieldPosition; /* bit position of lsb of blue mask */ + int RsvdMaskSize; /* size of direct color reserved mask bits*/ + int RsvdFieldPosition; /* bit position of lsb of reserved mask */ + int DirectColorModeInfo; /* direct color mode attributes */ + int XResolution; /* horizontal resolution */ + int YResolution; /* vertical resolution */ + int BytesPerScanLine; /* bytes per scan line */ } VesaModeRec, *VesaModePtr; +#include "vbe.h" +#include "vga.h" + typedef struct _VesaCardPriv { - VbeInfoPtr vi; - VbeInfoBlock *vib; + int vbe; + Vm86InfoPtr vi; VesaModePtr modes; - int nmode; - char text[VESA_TEXT_SAVE]; + int nmode; + int vga_palette; + int old_vbe_mode; + int old_vga_mode; + VbeInfoPtr vbeInfo; + char text[VESA_TEXT_SAVE]; } VesaCardPrivRec, *VesaCardPrivPtr; #define VESA_LINEAR 0 #define VESA_WINDOWED 1 #define VESA_PLANAR 2 +#define VESA_MONO 3 + typedef struct _VesaScreenPriv { VesaModePtr mode; Bool shadow; Bool rotate; int mapping; int origDepth; - void *fb; + void *fb; + int fb_size; } VesaScreenPrivRec, *VesaScreenPrivPtr; extern int vesa_video_mode; extern Bool vesa_force_mode; -Bool vesaListModes(void); -Bool vesaInitialize(KdCardInfo *card, VesaCardPrivPtr priv); -Bool vesaCardInit(KdCardInfo *card); -Bool vesaInitialize (KdCardInfo *card, VesaCardPrivPtr priv); -Bool vesaScreenInitialize (KdScreenInfo *screen, VesaScreenPrivPtr pscr); -Bool vesaScreenInit(KdScreenInfo *screen); -Bool vesaInitScreen(ScreenPtr pScreen); -Bool vesaEnable(ScreenPtr pScreen); -void vesaDisable(ScreenPtr pScreen); -void vesaPreserve(KdCardInfo *card); -void vesaRestore(KdCardInfo *card); -void vesaCardFini(KdCardInfo *card); -void vesaScreenFini(KdScreenInfo *screen); -void vesaPutColors (ScreenPtr pScreen, int fb, int n, xColorItem *pdefs); -void vesaGetColors (ScreenPtr pScreen, int fb, int n, xColorItem *pdefs); -int vesaProcessArgument (int argc, char **argv, int i); +void +vesaListModes(void); + +Bool +vesaInitialize(KdCardInfo *card, VesaCardPrivPtr priv); + +Bool +vesaCardInit(KdCardInfo *card); + +Bool +vesaInitialize (KdCardInfo *card, VesaCardPrivPtr priv); + +Bool +vesaScreenInitialize (KdScreenInfo *screen, VesaScreenPrivPtr pscr); + +Bool +vesaScreenInit(KdScreenInfo *screen); + +Bool +vesaInitScreen(ScreenPtr pScreen); + +Bool +vesaEnable(ScreenPtr pScreen); + +void +vesaDisable(ScreenPtr pScreen); + +void +vesaPreserve(KdCardInfo *card); + +void +vesaRestore(KdCardInfo *card); + +void +vesaCardFini(KdCardInfo *card); + +void +vesaScreenFini(KdScreenInfo *screen); + +void +vesaPutColors (ScreenPtr pScreen, int fb, int n, xColorItem *pdefs); + +void +vesaGetColors (ScreenPtr pScreen, int fb, int n, xColorItem *pdefs); + +int +vesaProcessArgument (int argc, char **argv, int i); #endif _VESA_H_ diff --git a/hw/kdrive/vesa/vesainit.c b/hw/kdrive/vesa/vesainit.c index 580977058..0f640db2d 100644 --- a/hw/kdrive/vesa/vesainit.c +++ b/hw/kdrive/vesa/vesainit.c @@ -23,7 +23,7 @@ THE SOFTWARE. #include "vesa.h" -KdCardFuncs vesaFuncs = { +const KdCardFuncs vesaFuncs = { vesaCardInit, /* cardinit */ vesaScreenInit, /* scrinit */ vesaInitScreen, /* initScreen */ diff --git a/hw/kdrive/vesa/vga.c b/hw/kdrive/vesa/vga.c new file mode 100644 index 000000000..24b23e885 --- /dev/null +++ b/hw/kdrive/vesa/vga.c @@ -0,0 +1,240 @@ +/* + * $XFree86$ + * + * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "vesa.h" + +static const VesaModeRec vgaModes[] = { + { + 6, 0, + MODE_SUPPORTED | MODE_GRAPHICS | MODE_VGA | MODE_LINEAR, + 1, 1, MEMORY_PLANAR, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 640, 200, 80, + }, + { + 0xd, 0, + MODE_SUPPORTED | MODE_GRAPHICS | MODE_VGA | MODE_COLOUR, + 4, 4, MEMORY_PLANAR, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 320, 200, 40, + }, + { + 0xe, 0, + MODE_SUPPORTED | MODE_GRAPHICS | MODE_VGA | MODE_COLOUR, + 4, 4, MEMORY_PLANAR, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 640, 200, 80, + }, + { + 0x10, 0, + MODE_SUPPORTED | MODE_GRAPHICS | MODE_VGA | MODE_COLOUR, + 4, 4, MEMORY_PLANAR, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 640, 350, 80, + }, + { + 0x11, 0, + MODE_SUPPORTED | MODE_GRAPHICS | MODE_VGA | MODE_LINEAR, + 1, 1, MEMORY_PLANAR, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 640, 480, 80, + }, + { + 0x12, 0, + MODE_SUPPORTED | MODE_GRAPHICS | MODE_VGA | MODE_COLOUR, + 4, 4, MEMORY_PLANAR, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 640, 480, 80, + }, + { + 0x13, 0, + MODE_SUPPORTED | MODE_GRAPHICS | MODE_VGA | MODE_COLOUR | MODE_LINEAR, + 8, 8, MEMORY_PSEUDO, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 320, 200, 320, + }, +}; + +#define NUM_VGA_MODE (sizeof vgaModes / sizeof vgaModes[0]) + +int +VgaGetNmode (Vm86InfoPtr vi) +{ + return NUM_VGA_MODE; +} + +int +VgaGetModes (Vm86InfoPtr vi, VesaModePtr mode, int nmode) +{ + if (nmode > NUM_VGA_MODE) + nmode = NUM_VGA_MODE; + memcpy (mode, vgaModes, nmode * sizeof (VesaModeRec)); + return nmode; +} + +int +VgaSetMode(Vm86InfoPtr vi, int mode) +{ + int code; + + vi->vms.regs.eax = mode & 0x7f; + code = Vm86DoInterrupt (vi, 0x10); + if(code < 0) + return -1; + return 0; +} + +int +VgaGetMode (Vm86InfoPtr vi, int *mode) +{ + *mode = Vm86Memory (vi, 0x449); + return 0; +} + +int +VgaSetWritePlaneMask(Vm86InfoPtr vi, int mask) +{ + asm volatile ("outb %b0,%w1" : : "a" (2), "d" (0x3c4)); + asm volatile ("outb %b0,%w1" : : "a" (mask), "d" (0x3c5)); +} + +int +VgaSetReadPlaneMap(Vm86InfoPtr vi, int map) +{ + asm volatile ("outb %b0,%w1" : : "a" (4), "d" (0x3ce)); + asm volatile ("outb %b0,%w1" : : "a" (map), "d" (0x3cf)); +} + +int +VgaSetPalette(Vm86InfoPtr vi, int first, int number, U8 *entries) +{ + U8 *palette_scratch; + int mark; + int palette_base; + int i, j, code; + + if(number == 0) + return 0; + + if(first < 0 || number < 0 || first + number > 256) { + ErrorF("Cannot set %d, %d palette entries\n", first, number); + return -1; + } + + mark = Vm86MarkMemory (vi); + palette_base = Vm86AllocateMemory (vi, 3 * 256); + + palette_scratch = &LM(vi, palette_base); + + vi->vms.regs.eax = 0x1012; + vi->vms.regs.ebx = first; + vi->vms.regs.ecx = number; + vi->vms.regs.es = POINTER_SEGMENT(palette_base); + vi->vms.regs.edx = POINTER_OFFSET(palette_base); + j = 0; + i = 0; + while (number--) + { + palette_scratch[j++] = entries[i++] >> 2; + palette_scratch[j++] = entries[i++] >> 2; + palette_scratch[j++] = entries[i++] >> 2; + i++; + } + code = Vm86DoInterrupt(vi, 0x10); + Vm86ReleaseMemory (vi, mark); + + if(code < 0) + return -1; + return 0; +} + +int +VgaGetPalette(Vm86InfoPtr vi, int first, int number, U8 *entries) +{ + U8 *palette_scratch; + int mark; + int palette_base; + int i, j, code; + + if(number == 0) + return 0; + + if(first < 0 || number < 0 || first + number > 256) { + ErrorF("Cannot get %d, %d palette entries\n", first, number); + return -1; + } + + mark = Vm86MarkMemory (vi); + palette_base = Vm86AllocateMemory (vi, 3 * 256); + + palette_scratch = &LM(vi, palette_base); + + vi->vms.regs.eax = 0x1017; + vi->vms.regs.ebx = first; + vi->vms.regs.ecx = number; + vi->vms.regs.es = POINTER_SEGMENT(palette_base); + vi->vms.regs.edx = POINTER_OFFSET(palette_base); + + code = VbeDoInterrupt10(vi); + if(code < 0) + return -1; + + j = 0; + i = 0; + while (number--) + { + entries[i++] = palette_scratch[j++] << 2; + entries[i++] = palette_scratch[j++] << 2; + entries[i++] = palette_scratch[j++] << 2; + entries[i++] = 0; + } + + Vm86ReleaseMemory (vi, mark); + + return 0; +} + +#define VGA_FB(vm) ((vm) < 8 ? 0xb8000 : 0xa0000) + +void * +VgaSetWindow (Vm86InfoPtr vi, int vmode, int bytes, int mode, int *size) +{ + *size = 0x10000 - bytes; + return &LM(vi,VGA_FB(vmode) + bytes); +} + +void * +VgaMapFramebuffer (Vm86InfoPtr vi, int vmode, int *size) +{ + if (VGA_FB(vmode) == 0xa0000) + *size = 0x10000; + else + *size = 0x4000; + return &LM(vi,VGA_FB(vmode)); +} + +void +VgaUnmapFramebuffer (Vm86InfoPtr vi) +{ +} diff --git a/hw/kdrive/vesa/vga.h b/hw/kdrive/vesa/vga.h new file mode 100644 index 000000000..0637c2177 --- /dev/null +++ b/hw/kdrive/vesa/vga.h @@ -0,0 +1,61 @@ +/* + * $XFree86$ + * + * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _VGA_H_ +#define _VGA_H_ + +int +VgaGetNmode (Vm86InfoPtr vi); + +int +VgaGetModes (Vm86InfoPtr vi, VesaModePtr mode, int nmode); + +int +VgaSetMode(Vm86InfoPtr vi, int mode); + +int +VgaGetMode (Vm86InfoPtr vi, int *mode); + +int +VgaSetWritePlaneMask(Vm86InfoPtr vi, int mask); + +int +VgaSetReadPlaneMap(Vm86InfoPtr vi, int map); + +int +VgaSetPalette(Vm86InfoPtr vi, int first, int number, U8 *entries); + +int +VgaGetPalette(Vm86InfoPtr vi, int first, int number, U8 *entries); + +void * +VgaSetWindow (Vm86InfoPtr vi, int vmode, int bytes, int mode, int *size); + +void * +VgaMapFramebuffer (Vm86InfoPtr vi, int vmode, int *size); + +void +VgaUnmapFramebuffer (Vm86InfoPtr vi); + +#endif /* _VGA_H_ */ diff --git a/hw/kdrive/vesa/vm86.c b/hw/kdrive/vesa/vm86.c new file mode 100644 index 000000000..4bb90daf2 --- /dev/null +++ b/hw/kdrive/vesa/vm86.c @@ -0,0 +1,697 @@ +/* + * $XFree86$ + * + * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/* +Copyright (c) 2000 by Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "vm86.h" + +#define PUSHW(vi, i) \ +{ vi->vms.regs.esp -= 2;\ + LMW(vi,MAKE_POINTER(vi->vms.regs.ss, vi->vms.regs.esp)) = i;} + +static int vm86old(struct vm86_struct *vms); +static int vm86_loop(Vm86InfoPtr vi); + +static const U8 rev_ints[32] = +{ 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0x80, +}; + +static const U8 retcode_data[2] = +{ 0xCD, 0xFF }; + +Vm86InfoPtr +Vm86Setup(void) +{ + int devmem = -1, devzero = -1; + void *magicMem, *loMem, *hiMem; + U32 stack_base, ret_code; + Vm86InfoPtr vi = NULL; + + devmem = open("/dev/mem", O_RDWR); + if(devmem < 0) { + perror("open /dev/mem"); + goto fail; + } + + devzero = open("/dev/zero", O_RDWR); + if(devmem < 0) { + perror("open /dev/zero"); + goto fail; + } + + + magicMem = mmap((void*)MAGICMEM_BASE, MAGICMEM_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_FIXED, devmem, MAGICMEM_BASE); + + if(magicMem == MAP_FAILED) { + ErrorF("Couldn't map magic memory\n"); + goto fail; + } + + loMem = mmap((void*)LOMEM_BASE, LOMEM_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_FIXED, devzero, LOMEM_BASE); + if(loMem == MAP_FAILED) { + ErrorF("Couldn't map low memory\n"); + munmap(magicMem, MAGICMEM_SIZE); + goto fail; + } + + hiMem = mmap((void*)HIMEM_BASE, HIMEM_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_SHARED | MAP_FIXED, + devmem, HIMEM_BASE); + if(hiMem == MAP_FAILED) { + ErrorF("Couldn't map high memory\n"); + munmap(magicMem, MAGICMEM_SIZE); + munmap(loMem, LOMEM_SIZE); + goto fail; + } + + vi = xalloc(sizeof(Vm86InfoRec)); + if (!vi) + goto unmapfail; + + vi->magicMem = magicMem; + vi->loMem = loMem; + vi->hiMem = hiMem; + vi->brk = LOMEM_BASE; + + stack_base = Vm86AllocateMemory(vi, STACK_SIZE); + if(stack_base == ALLOC_FAIL) + goto unmapfail; + ret_code = Vm86AllocateMemory(vi, sizeof(retcode_data)); + if(ret_code == ALLOC_FAIL) + goto unmapfail; + + vi->stack_base = stack_base; + vi->ret_code = ret_code; + + memset(&vi->vms, 0, sizeof(struct vm86_struct)); + vi->vms.flags = 0; + vi->vms.screen_bitmap = 0; + vi->vms.cpu_type = CPU_586; + memcpy(&vi->vms.int_revectored, rev_ints, sizeof(rev_ints)); + + iopl(3); + + if(devmem >= 0) + close(devmem); + if(devzero >= 0) + close(devzero); + + return vi; + +unmapfail: + munmap(magicMem, MAGICMEM_SIZE); + munmap(loMem, LOMEM_SIZE); + munmap(hiMem, HIMEM_SIZE); +fail: + if(devmem >= 0) + close(devmem); + if(devzero >= 0) + close(devzero); + if(vi) + xfree(vi); + return NULL; +} + +void +Vm86Cleanup(Vm86InfoPtr vi) +{ + munmap(vi->magicMem, MAGICMEM_SIZE); + munmap(vi->loMem, LOMEM_SIZE); + munmap(vi->hiMem, HIMEM_SIZE); + xfree(vi); +} + +int +Vm86DoInterrupt(Vm86InfoPtr vi, int num) +{ + U16 seg, off; + int code; + + if(num < 0 || num>256) { + ErrorF("Interrupt %d doesn't exist\n"); + return -1; + } + seg = MMW(vi,num * 4 + 2); + off = MMW(vi,num * 4); + if(MAKE_POINTER(seg, off) < ROM_BASE || + MAKE_POINTER(seg, off) >= ROM_BASE + ROM_SIZE) { + ErrorF("Interrupt pointer doesn't point at ROM\n"); + return -1; + } + memcpy(&(LM(vi,vi->ret_code)), retcode_data, sizeof(retcode_data)); + vi->vms.regs.eflags = IF_MASK | IOPL_MASK; + vi->vms.regs.ss = POINTER_SEGMENT(vi->stack_base); + vi->vms.regs.esp = STACK_SIZE; + PUSHW(vi, IF_MASK | IOPL_MASK); + PUSHW(vi, POINTER_SEGMENT(vi->ret_code)); + PUSHW(vi, POINTER_OFFSET(vi->ret_code)); + vi->vms.regs.cs = seg; + vi->vms.regs.eip = off; + OsBlockSignals (); + code = vm86_loop(vi); + OsReleaseSignals (); + if(code < 0) { + perror("vm86 failed"); + return -1; + } else if(code != 0) { + ErrorF("vm86 returned 0x%04X\n", code); + return -1; + } else + return 0; +} + +#define DEBUG_VBE 0 +#if DEBUG_VBE +#define DBG(x) ErrorF x; usleep(10*1000) +#else +#define DBG(x) +#endif + +static inline U8 +vm86_inb(U16 port) +{ + U8 value; + + if (port != 0x3da) + { + DBG(("inb 0x%04x", port)); + } + asm volatile ("inb %w1,%b0" : "=a" (value) : "d" (port)); + if (port != 0x3da) + { + DBG((" = 0x%02x\n", value)); + } + return value; +} + +static inline U16 +vm86_inw(U16 port) +{ + U16 value; + DBG(("inw 0x%04x", port)); + asm volatile ("inw %w1,%w0" : "=a" (value) : "d" (port)); + DBG((" = 0x%04x\n", value)); + return value; +} + +static inline U32 +vm86_inl(U16 port) +{ + U32 value; + DBG(("inl 0x%04x", port)); + asm volatile ("inl %w1,%0" : "=a" (value) : "d" (port)); + DBG((" = 0x%08x\n", value)); + return value; +} + +static inline void +vm86_outb(U16 port, U8 value) +{ +#if 0 + static U8 CR; + + if (port == 0x3d4) + CR = value; + if (port == 0x3d5 && CR == 0xa4) + { + DBG(("outb 0x%04x = 0x%02x (skipped)\n", port, value)); + return; + } +#endif + DBG(("outb 0x%04x = 0x%02x\n", port, value)); + asm volatile ("outb %b0,%w1" : : "a" (value), "d" (port)); +} + +static inline void +vm86_outw(U16 port, U16 value) +{ + DBG(("outw 0x%04x = 0x%04x\n", port, value)); + asm volatile ("outw %w0,%w1" : : "a" (value), "d" (port)); +} + +static inline void +vm86_outl(U16 port, U32 value) +{ + DBG(("outl 0x%04x = 0x%08x\n", port, value)); + asm volatile ("outl %0,%w1" : : "a" (value), "d" (port)); +} + +#define SEG_CS 1 +#define SEG_DS 2 +#define SEG_ES 3 +#define SEG_SS 4 +#define SEG_GS 5 +#define SEG_FS 6 +#define REP 1 +#define REPNZ 2 +#define SET_8(_x, _y) (_x) = (_x & ~0xFF) | (_y & 0xFF); +#define SET_16(_x, _y) (_x) = (_x & ~0xFFFF) | (_y & 0xFFFF); +#define INC_IP(_i) SET_16(regs->eip, (regs->eip + _i)) +#define AGAIN INC_IP(1); goto again; + +static int +vm86_emulate(Vm86InfoPtr vi) +{ + struct vm86_regs *regs = &vi->vms.regs; + U8 opcode; + int size; + int pref_seg = 0, pref_rep = 0, pref_66 = 0, pref_67 = 0; + U32 count; + int code; + + again: + if(!Vm86IsMemory(vi, MAKE_POINTER(regs->cs, regs->eip))) { + ErrorF("Trying to execute unmapped memory\n"); + return -1; + } + opcode = Vm86Memory(vi, MAKE_POINTER(regs->cs, regs->eip)); + switch(opcode) { + case 0x2E: pref_seg = SEG_CS; AGAIN; + case 0x3E: pref_seg = SEG_DS; AGAIN; + case 0x26: pref_seg = SEG_ES; AGAIN; + case 0x36: pref_seg = SEG_SS; AGAIN; + case 0x65: pref_seg = SEG_GS; AGAIN; + case 0x64: pref_seg = SEG_FS; AGAIN; + case 0x66: pref_66 = 1; AGAIN; + case 0x67: pref_67 = 1; AGAIN; + case 0xF2: pref_rep = REPNZ; AGAIN; + case 0xF3: pref_rep = REP; AGAIN; + + case 0xEC: /* IN AL, DX */ + SET_8(regs->eax, vm86_inb(regs->edx & 0xFFFF)); + INC_IP(1); + break; + case 0xED: /* IN AX, DX */ + if(pref_66) + regs->eax = vm86_inl(regs->edx & 0xFFFF); + else + SET_16(regs->eax, vm86_inw(regs->edx & 0xFFFF)); + INC_IP(1); + break; + case 0xE4: /* IN AL, imm8 */ + SET_8(regs->eax, + vm86_inb(Vm86Memory(vi, MAKE_POINTER(regs->cs, regs->eip+1)))); + INC_IP(2); + break; + case 0xE5: /* IN AX, imm8 */ + if(pref_66) + regs->eax = + vm86_inl(Vm86Memory(vi, MAKE_POINTER(regs->cs, regs->eip+1))); + else + SET_16(regs->eax, + vm86_inw(Vm86Memory(vi, MAKE_POINTER(regs->cs, regs->eip+1)))); + INC_IP(2); + break; + case 0x6C: /* INSB */ + case 0x6D: /* INSW */ + if(opcode == 0x6C) { + Vm86WriteMemory(vi, MAKE_POINTER(regs->es, regs->edi), + vm86_inb(regs->edx & 0xFFFF)); + size = 1; + } else if(pref_66) { + Vm86WriteMemoryL(vi, MAKE_POINTER(regs->es, regs->edi), + vm86_inl(regs->edx & 0xFFFF)); + size = 4; + } else { + Vm86WriteMemoryW(vi, MAKE_POINTER(regs->es, regs->edi), + vm86_inw(regs->edx & 0xFFFF)); + size = 2; + } + if(regs->eflags & (1<<10)) + regs->edi -= size; + else + regs->edi += size; + if(pref_rep) { + if(pref_66) { + regs->ecx--; + if(regs->ecx != 0) { + goto again; + } else { + SET_16(regs->ecx, regs->ecx - 1); + if(regs->ecx & 0xFFFF != 0) + goto again; + } + } + } + INC_IP(1); + break; + + case 0xEE: /* OUT DX, AL */ + vm86_outb(regs->edx & 0xFFFF, regs->eax & 0xFF); + INC_IP(1); + break; + case 0xEF: /* OUT DX, AX */ + if(pref_66) + vm86_outl(regs->edx & 0xFFFF, regs->eax); + else + vm86_outw(regs->edx & 0xFFFF, regs->eax & 0xFFFF); + INC_IP(1); + break; + case 0xE6: /* OUT imm8, AL */ + vm86_outb(Vm86Memory(vi, MAKE_POINTER(regs->cs, regs->eip+1)), + regs->eax & 0xFF); + INC_IP(2); + break; + case 0xE7: /* OUT imm8, AX */ + if(pref_66) + vm86_outl(Vm86Memory(vi, MAKE_POINTER(regs->cs, regs->eip+1)), + regs->eax); + else + vm86_outw(Vm86Memory(vi, MAKE_POINTER(regs->cs, regs->eip+1)), + regs->eax & 0xFFFF); + INC_IP(2); + break; + case 0x6E: /* OUTSB */ + case 0x6F: /* OUTSW */ + if(opcode == 0x6E) { + vm86_outb(regs->edx & 0xFFFF, + Vm86Memory(vi, MAKE_POINTER(regs->es, regs->edi))); + size = 1; + } else if(pref_66) { + vm86_outl(regs->edx & 0xFFFF, + Vm86Memory(vi, MAKE_POINTER(regs->es, regs->edi))); + size = 4; + } else { + vm86_outw(regs->edx & 0xFFFF, + Vm86Memory(vi, MAKE_POINTER(regs->es, regs->edi))); + size = 2; + } + if(regs->eflags & (1<<10)) + regs->edi -= size; + else + regs->edi += size; + if(pref_rep) { + if(pref_66) { + regs->ecx--; + if(regs->ecx != 0) { + goto again; + } else { + SET_16(regs->ecx, regs->ecx - 1); + if(regs->ecx & 0xFFFF != 0) + goto again; + } + } + } + INC_IP(1); + break; + + case 0x0F: + ErrorF("Hit 0F trap in VM86 code\n"); + return -1; + case 0xF0: + ErrorF("Hit lock prefix in VM86 code\n"); + return -1; + case 0xF4: + ErrorF("Hit HLT in VM86 code\n"); + return -1; + + default: + ErrorF("Unhandled GP fault in VM86 code (opcode = 0x%02X)\n", + opcode); + return -1; + } + return 0; +} +#undef SEG_CS +#undef SEG_DS +#undef SEG_ES +#undef SEG_SS +#undef SEG_GS +#undef SEG_FS +#undef REP +#undef REPNZ +#undef SET_8 +#undef SET_16 +#undef INC_IP +#undef AGAIN + +static int +vm86_loop(Vm86InfoPtr vi) +{ + int code; + + while(1) { + code = vm86old(&vi->vms); + switch(VM86_TYPE(code)) { + case VM86_SIGNAL: + continue; + case VM86_UNKNOWN: + code = vm86_emulate(vi); + if(code < 0) { + Vm86Debug(vi); + return -1; + } + break; + case VM86_INTx: + if(VM86_ARG(code) == 0xFF) + return 0; + else { + PUSHW(vi, vi->vms.regs.eflags) + PUSHW(vi, vi->vms.regs.cs); + PUSHW(vi, vi->vms.regs.eip); + vi->vms.regs.cs = MMW(vi,VM86_ARG(code) * 4 + 2); + vi->vms.regs.eip = MMW(vi,VM86_ARG(code) * 4); + } + break; + case VM86_STI: + ErrorF("VM86 code enabled interrupts\n"); + Vm86Debug(vi); + return -1; + default: + ErrorF("Unexpected result code 0x%X from vm86\n", code); + Vm86Debug(vi); + return -1; + } + } +} + +int +Vm86IsMemory(Vm86InfoPtr vi, U32 i) +{ + if(i >= MAGICMEM_BASE && i< MAGICMEM_BASE + MAGICMEM_SIZE) + return 1; + else if(i >= LOMEM_BASE && i< LOMEM_BASE + LOMEM_SIZE) + return 1; + else if(i >= HIMEM_BASE && i< HIMEM_BASE + HIMEM_SIZE) + return 1; + else + return 0; +} + +U8 +Vm86Memory(Vm86InfoPtr vi, U32 i) +{ + if(i >= MAGICMEM_BASE && i< MAGICMEM_BASE + MAGICMEM_SIZE) + return MM(vi, i); + else if(i >= LOMEM_BASE && i< LOMEM_BASE + LOMEM_SIZE) + return LM(vi, i); + else if(i >= HIMEM_BASE && i< HIMEM_BASE + HIMEM_SIZE) + return HM(vi, i); + else { + ErrorF("Reading unmapped memory at 0x%08X\n", i); + } +} + +U16 +Vm86MemoryW(Vm86InfoPtr vi, U32 i) +{ + if(i >= MAGICMEM_BASE && i< MAGICMEM_BASE + MAGICMEM_SIZE) + return MMW(vi, i); + else if(i >= LOMEM_BASE && i< LOMEM_BASE + LOMEM_SIZE) + return LMW(vi, i); + else if(i >= HIMEM_BASE && i< HIMEM_BASE + HIMEM_SIZE) + return HMW(vi, i); + else { + ErrorF("Reading unmapped memory at 0x%08X\n", i); + return 0; + } +} + +U32 +Vm86MemoryL(Vm86InfoPtr vi, U32 i) +{ + if(i >= MAGICMEM_BASE && i< MAGICMEM_BASE + MAGICMEM_SIZE) + return MML(vi, i); + else if(i >= LOMEM_BASE && i< LOMEM_BASE + LOMEM_SIZE) + return LML(vi, i); + else if(i >= HIMEM_BASE && i< HIMEM_BASE + HIMEM_SIZE) + return HML(vi, i); + else { + ErrorF("Reading unmapped memory at 0x%08X\n", i); + return 0; + } +} + +void +Vm86WriteMemory(Vm86InfoPtr vi, U32 i, U8 val) +{ + if(i >= MAGICMEM_BASE && i< MAGICMEM_BASE + MAGICMEM_SIZE) + MM(vi, i) = val; + else if(i >= LOMEM_BASE && i< LOMEM_BASE + LOMEM_SIZE) + LM(vi, i) = val; + else if(i >= HIMEM_BASE && i< HIMEM_BASE + HIMEM_SIZE) + HM(vi, i) = val; + else { + ErrorF("Writing unmapped memory at 0x%08X\n", i); + } +} + +void +Vm86WriteMemoryW(Vm86InfoPtr vi, U32 i, U16 val) +{ + if(i >= MAGICMEM_BASE && i< MAGICMEM_BASE + MAGICMEM_SIZE) + MMW(vi, i) = val; + else if(i >= LOMEM_BASE && i< LOMEM_BASE + LOMEM_SIZE) + LMW(vi, i) = val; + else if(i >= HIMEM_BASE && i< HIMEM_BASE + HIMEM_SIZE) + HMW(vi, i) = val; + else { + ErrorF("Writing unmapped memory at 0x%08X\n", i); + } +} + +void +Vm86WriteMemoryL(Vm86InfoPtr vi, U32 i, U32 val) +{ + if(i >= MAGICMEM_BASE && i< MAGICMEM_BASE + MAGICMEM_SIZE) + MML(vi, i) = val; + else if(i >= LOMEM_BASE && i< LOMEM_BASE + LOMEM_SIZE) + LML(vi, i) = val; + else if(i >= HIMEM_BASE && i< HIMEM_BASE + HIMEM_SIZE) + HML(vi, i) = val; + else { + ErrorF("Writing unmapped memory at 0x%08X\n", i); + } +} + +int +Vm86AllocateMemory(Vm86InfoPtr vi, int n) +{ + int ret; + if(n<0) { + ErrorF("Asked to allocate negative amount of memory\n"); + return vi->brk; + } + + n = (n + 15) & ~15; + if(vi->brk + n > LOMEM_BASE + LOMEM_SIZE) { + ErrorF("Out of low memory\n"); + exit(2); + } + ret = vi->brk; + vi->brk += n; + return ret; +} + +int +Vm86MarkMemory (Vm86InfoPtr vi) +{ + return vi->brk; +} + +void +Vm86ReleaseMemory (Vm86InfoPtr vi, int mark) +{ + vi->brk = mark; +} + +static int +vm86old(struct vm86_struct *vm) +{ + int res; + + asm volatile ( + "pushl %%ebx\n\t" + "movl %2, %%ebx\n\t" + "movl %1,%%eax\n\t" + "int $0x80\n\t" + "popl %%ebx" + : "=a" (res) : "n" (113), "r" (vm)); + if(res < 0) { + errno = -res; + res = -1; + } else + errno = 0; + return res; +} + +void +Vm86Debug(Vm86InfoPtr vi) +{ + struct vm86_regs *regs = &vi->vms.regs; + int i; + + ErrorF("eax=0x%08lX ebx=0x%08lX ecx=0x%08lX edx=0x%08lX\n", + regs->eax, regs->ebx, regs->ecx, regs->edx); + ErrorF("esi=0x%08lX edi=0x%08lX ebp=0x%08lX\n", + regs->esi, regs->edi, regs->ebp); + ErrorF("eip=0x%08lX esp=0x%08lX eflags=0x%08lX\n", + regs->eip, regs->esp, regs->eflags); + ErrorF("cs=0x%04lX ds=0x%04lX es=0x%04lX fs=0x%04lX gs=0x%04lX\n", + regs->cs, regs->ds, regs->es, regs->fs, regs->gs); + for(i=-7; i<8; i++) { + ErrorF(" %s%02X", + i==0?"->":"", + Vm86Memory(vi, MAKE_POINTER(regs->cs, regs->eip + i))); + } + ErrorF("\n"); +} + +#ifdef NOT_IN_X_SERVER +static void +ErrorF(char *f, ...) +{ + va_list args; + va_start(args, f); + vfprintf(stderr, f, args); + va_end(args); +} +#endif diff --git a/hw/kdrive/vesa/vm86.h b/hw/kdrive/vesa/vm86.h new file mode 100644 index 000000000..c0338e9d2 --- /dev/null +++ b/hw/kdrive/vesa/vm86.h @@ -0,0 +1,165 @@ +/* + * $XFree86$ + * + * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/* +Copyright (c) 2000 by Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef _VM86_H_ +#define _VM86_H_ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef NOT_IN_X_SERVER +#include +#include +#include +static void ErrorF(char*, ...); +#define xalloc(a) malloc(a) +#define xcalloc(a,b) calloc(a,b) +#define xfree(a) free(a) +#else +#include "X.h" +#include "Xproto.h" +#include "Xos.h" +#include "os.h" +#endif + +typedef unsigned char U8; +typedef unsigned short U16; +typedef unsigned int U32; + +/* The whole addressable memory */ +#define SYSMEM_BASE 0x00000 +#define SYSMEM_SIZE 0x100000 + +/* Interrupt vectors and BIOS data area */ +/* This is allocated privately from /dev/mem */ +#define MAGICMEM_BASE 0x00000 +#define MAGICMEM_SIZE 0x01000 + +/* The low memory, allocated privately from /dev/zero */ +/* 64KB should be enough for anyone, as they used to say */ +#define LOMEM_BASE 0x10000 +#define LOMEM_SIZE 0x10000 + +/* The video memory and BIOS ROM, allocated shared from /dev/mem */ +#define HIMEM_BASE 0xA0000 +#define HIMEM_SIZE (SYSMEM_BASE + SYSMEM_SIZE - HIMEM_BASE) + +/* The BIOS ROM */ +#define ROM_BASE 0xC0000 +#define ROM_SIZE 0x30000 + +#define STACK_SIZE 0x1000 + +#define POINTER_SEGMENT(ptr) (((unsigned int)ptr)>>4) +#define POINTER_OFFSET(ptr) (((unsigned int)ptr)&0x000F) +#define MAKE_POINTER(seg, off) (((((unsigned int)(seg))<<4) + (unsigned int)(off))) +#define MAKE_POINTER_1(lw) MAKE_POINTER(((lw)&0xFFFF0000)/0x10000, (lw)&0xFFFF) +#define ALLOC_FAIL ((U32)-1) + +typedef struct _Vm86InfoRec { + void *magicMem, *loMem, *hiMem; + U32 brk; + struct vm86_struct vms; + U32 ret_code, stack_base; +} Vm86InfoRec, *Vm86InfoPtr; + +#define LM(vi,i) (((char*)vi->loMem)[i-LOMEM_BASE]) +#define LMW(vi,i) (*(U16*)(&LM(vi,i))) +#define LML(vi,i) (*(U32*)(&LM(vi,i))) +#define MM(vi,i) (((char*)vi->magicMem)[i-MAGICMEM_BASE]) +#define MMW(vi,i) (*(U16*)(&MM(vi,i))) +#define MML(vi,i) (*(U32*)(&MM(vi,i))) +#define HM(vi,i) (((char*)vi->hiMem)[i-HIMEM_BASE]) +#define HMW(vi,i) (*(U16*)(&MM(vi,i))) +#define HML(vi,i) (*(U32*)(&MM(vi,i))) + +Vm86InfoPtr +Vm86Setup(void); + +void +Vm86Cleanup(Vm86InfoPtr vi); + +int +Vm86DoInterrupt(Vm86InfoPtr vi, int num); + +int +Vm86IsMemory(Vm86InfoPtr vi, U32 i); + +U8 +Vm86Memory(Vm86InfoPtr, U32); + +U16 +Vm86MemoryW(Vm86InfoPtr, U32); + +U32 +Vm86MemoryL(Vm86InfoPtr, U32); + +void +Vm86WriteMemory(Vm86InfoPtr, U32, U8); + +void +Vm86WriteMemoryW(Vm86InfoPtr, U32, U16); + +void +Vm86WriteMemoryL(Vm86InfoPtr, U32, U32); + +int +Vm86AllocateMemory(Vm86InfoPtr, int); + +int +Vm86MarkMemory (Vm86InfoPtr vi); + +void +Vm86ReleaseMemory (Vm86InfoPtr vi, int mark); + +void +Vm86Debug(Vm86InfoPtr vi); + +#endif /* _VM86_H_ */ -- cgit v1.2.3