2
* $RCSId: xc/programs/Xserver/hw/kdrive/vesa/vm86.c,v 1.2 2002/02/19 00:18:05 keithp Exp $
4
* Copyright � 2000 Keith Packard
6
* Permission to use, copy, modify, distribute, and sell this software and its
7
* documentation for any purpose is hereby granted without fee, provided that
8
* the above copyright notice appear in all copies and that both that
9
* copyright notice and this permission notice appear in supporting
10
* documentation, and that the name of Keith Packard not be used in
11
* advertising or publicity pertaining to distribution of the software without
12
* specific, written prior permission. Keith Packard makes no
13
* representations about the suitability of this software for any purpose. It
14
* is provided "as is" without express or implied warranty.
16
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22
* PERFORMANCE OF THIS SOFTWARE.
25
Copyright (c) 2000 by Juliusz Chroboczek
27
Permission is hereby granted, free of charge, to any person obtaining a copy
28
of this software and associated documentation files (the "Software"), to deal
29
in the Software without restriction, including without limitation the rights
30
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
31
copies of the Software, and to permit persons to whom the Software is
32
furnished to do so, subject to the following conditions:
34
The above copyright notice and this permission notice shall be included in
35
all copies or substantial portions of the Software.
37
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
38
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
39
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
40
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
41
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
42
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
47
#include <kdrive-config.h>
51
#define PUSHW(vi, i) \
52
{ vi->vms.regs.esp -= 2;\
53
LMW(vi,MAKE_POINTER(vi->vms.regs.ss, vi->vms.regs.esp)) = i;}
55
static int vm86old(struct vm86_struct *vms);
56
static int vm86_loop(Vm86InfoPtr vi);
58
static const U8 rev_ints[32] =
59
{ 0, 0, 0, 0, 0, 0, 0, 0,
60
0, 0, 0, 0, 0, 0, 0, 0,
61
0, 0, 0, 0, 0, 0, 0, 0,
62
0, 0, 0, 0, 0, 0, 0, 0x80,
65
static const U8 retcode_data[2] =
69
Vm86Setup(int mapHoles)
71
int devmem = -1, devzero = -1;
72
void *magicMem, *loMem, *hiMem;
74
U32 stack_base, ret_code;
75
Vm86InfoPtr vi = NULL;
77
devmem = open("/dev/mem", O_RDWR);
79
perror("open /dev/mem");
83
devzero = open("/dev/zero", O_RDWR);
85
perror("open /dev/zero");
89
magicMem = MAP_FAILED;
96
magicMem = mmap((void*)MAGICMEM_BASE, MAGICMEM_SIZE,
97
PROT_READ | PROT_WRITE | PROT_EXEC,
98
MAP_PRIVATE | MAP_FIXED, devmem, MAGICMEM_BASE);
100
if(magicMem == MAP_FAILED) {
101
ErrorF("Couldn't map magic memory\n");
106
hole1 = mmap((void*)HOLE1_BASE, HOLE1_SIZE,
107
PROT_READ | PROT_WRITE | PROT_EXEC,
108
MAP_PRIVATE | MAP_FIXED, devzero, HOLE1_BASE);
110
if(hole1 == MAP_FAILED) {
111
ErrorF("Couldn't map first hole\n");
116
loMem = mmap((void*)LOMEM_BASE, LOMEM_SIZE,
117
PROT_READ | PROT_WRITE | PROT_EXEC,
118
MAP_PRIVATE | MAP_FIXED, devzero, LOMEM_BASE);
119
if(loMem == MAP_FAILED) {
120
ErrorF("Couldn't map low memory\n");
121
munmap(magicMem, MAGICMEM_SIZE);
126
hole2 = mmap((void*)HOLE2_BASE, HOLE2_SIZE,
127
PROT_READ | PROT_WRITE | PROT_EXEC,
128
MAP_PRIVATE | MAP_FIXED, devzero, HOLE2_BASE);
130
if(hole2 == MAP_FAILED) {
131
ErrorF("Couldn't map first hole\n");
136
hiMem = mmap((void*)HIMEM_BASE, HIMEM_SIZE,
137
PROT_READ | PROT_WRITE | PROT_EXEC,
138
MAP_SHARED | MAP_FIXED,
140
if(hiMem == MAP_FAILED) {
141
ErrorF("Couldn't map high memory\n");
145
vi = xalloc(sizeof(Vm86InfoRec));
149
vi->magicMem = magicMem;
154
vi->brk = LOMEM_BASE;
156
stack_base = Vm86AllocateMemory(vi, STACK_SIZE);
157
if(stack_base == ALLOC_FAIL)
159
ret_code = Vm86AllocateMemory(vi, sizeof(retcode_data));
160
if(ret_code == ALLOC_FAIL)
163
vi->stack_base = stack_base;
164
vi->ret_code = ret_code;
166
memset(&vi->vms, 0, sizeof(struct vm86_struct));
168
vi->vms.screen_bitmap = 0;
169
vi->vms.cpu_type = CPU_586;
170
memcpy(&vi->vms.int_revectored, rev_ints, sizeof(rev_ints));
182
if(magicMem != MAP_FAILED) munmap(magicMem, MAGICMEM_SIZE);
183
if(hole1 != MAP_FAILED) munmap(hole1, HOLE1_SIZE);
184
if(loMem != MAP_FAILED) munmap(loMem, LOMEM_SIZE);
185
if(hole2 != MAP_FAILED) munmap(hole2, HOLE2_SIZE);
186
if(hiMem != MAP_FAILED) munmap(hiMem, HIMEM_SIZE);
198
Vm86Cleanup(Vm86InfoPtr vi)
200
if(vi->magicMem != MAP_FAILED) munmap(vi->magicMem, MAGICMEM_SIZE);
201
if(vi->hole1 != MAP_FAILED) munmap(vi->hole1, HOLE1_SIZE);
202
if(vi->loMem != MAP_FAILED) munmap(vi->loMem, LOMEM_SIZE);
203
if(vi->hole2 != MAP_FAILED) munmap(vi->hole2, HOLE2_SIZE);
204
if(vi->hiMem != MAP_FAILED) munmap(vi->hiMem, HIMEM_SIZE);
209
Vm86DoInterrupt(Vm86InfoPtr vi, int num)
214
if(num < 0 || num>256) {
215
ErrorF("Interrupt %d doesn't exist\n");
218
seg = MMW(vi,num * 4 + 2);
219
off = MMW(vi,num * 4);
220
if(MAKE_POINTER(seg, off) < ROM_BASE ||
221
MAKE_POINTER(seg, off) >= ROM_BASE + ROM_SIZE) {
222
ErrorF("Interrupt pointer (seg %x off %x) doesn't point at ROM\n",
226
memcpy(&(LM(vi,vi->ret_code)), retcode_data, sizeof(retcode_data));
227
vi->vms.regs.eflags = IF_MASK | IOPL_MASK;
228
vi->vms.regs.ss = POINTER_SEGMENT(vi->stack_base);
229
vi->vms.regs.esp = STACK_SIZE;
230
PUSHW(vi, IF_MASK | IOPL_MASK);
231
PUSHW(vi, POINTER_SEGMENT(vi->ret_code));
232
PUSHW(vi, POINTER_OFFSET(vi->ret_code));
233
vi->vms.regs.cs = seg;
234
vi->vms.regs.eip = off;
236
code = vm86_loop(vi);
239
ErrorF("vm86 failed (errno %d)\n", errno);
241
} else if(code != 0) {
242
ErrorF("vm86 returned 0x%04X\n", code);
249
Vm86DoPOST(Vm86InfoPtr vi)
256
if(MAKE_POINTER(seg, off) < ROM_BASE ||
257
MAKE_POINTER(seg, off) >= ROM_BASE + ROM_SIZE) {
258
ErrorF("BIOS pointer (seg %x off %x) doesn't point at ROM\n",
262
memcpy(&(LM(vi,vi->ret_code)), retcode_data, sizeof(retcode_data));
263
vi->vms.regs.ss = POINTER_SEGMENT(vi->stack_base);
264
vi->vms.regs.esp = STACK_SIZE;
265
PUSHW(vi, POINTER_SEGMENT(vi->ret_code));
266
PUSHW(vi, POINTER_OFFSET(vi->ret_code));
267
vi->vms.regs.cs = seg;
268
vi->vms.regs.eip = off;
270
code = vm86_loop(vi);
273
ErrorF("vm86 failed (errno %d)\n", errno);
275
} else if(code != 0) {
276
ErrorF("vm86 returned 0x%04X\n", code);
284
#define DBG(x) ErrorF x; usleep(10*1000)
296
DBG(("inb 0x%04x", port));
298
asm volatile ("inb %w1,%b0" : "=a" (value) : "d" (port));
301
DBG((" = 0x%02x\n", value));
310
DBG(("inw 0x%04x", port));
311
asm volatile ("inw %w1,%w0" : "=a" (value) : "d" (port));
312
DBG((" = 0x%04x\n", value));
320
DBG(("inl 0x%04x", port));
321
asm volatile ("inl %w1,%0" : "=a" (value) : "d" (port));
322
DBG((" = 0x%08x\n", value));
327
vm86_outb(U16 port, U8 value)
334
if (port == 0x3d5 && CR == 0xa4)
336
DBG(("outb 0x%04x = 0x%02x (skipped)\n", port, value));
340
DBG(("outb 0x%04x = 0x%02x\n", port, value));
341
asm volatile ("outb %b0,%w1" : : "a" (value), "d" (port));
345
vm86_outw(U16 port, U16 value)
347
DBG(("outw 0x%04x = 0x%04x\n", port, value));
348
asm volatile ("outw %w0,%w1" : : "a" (value), "d" (port));
352
vm86_outl(U16 port, U32 value)
354
DBG(("outl 0x%04x = 0x%08x\n", port, value));
355
asm volatile ("outl %0,%w1" : : "a" (value), "d" (port));
366
#define SET_8(_x, _y) (_x) = ((_x) & ~0xFF) | ((_y) & 0xFF);
367
#define SET_16(_x, _y) (_x) = ((_x) & ~0xFFFF) | ((_y) & 0xFFFF);
368
#define INC_IP(_i) SET_16(regs->eip, (regs->eip + _i))
369
#define AGAIN INC_IP(1); goto again;
372
vm86_emulate(Vm86InfoPtr vi)
374
struct vm86_regs *regs = &vi->vms.regs;
377
int pref_seg = 0, pref_rep = 0, pref_66 = 0, pref_67 = 0;
380
if(!Vm86IsMemory(vi, MAKE_POINTER(regs->cs, regs->eip))) {
381
ErrorF("Trying to execute unmapped memory\n");
384
opcode = Vm86Memory(vi, MAKE_POINTER(regs->cs, regs->eip));
386
case 0x2E: pref_seg = SEG_CS; AGAIN;
387
case 0x3E: pref_seg = SEG_DS; AGAIN;
388
case 0x26: pref_seg = SEG_ES; AGAIN;
389
case 0x36: pref_seg = SEG_SS; AGAIN;
390
case 0x65: pref_seg = SEG_GS; AGAIN;
391
case 0x64: pref_seg = SEG_FS; AGAIN;
392
case 0x66: pref_66 = 1; AGAIN;
393
case 0x67: pref_67 = 1; AGAIN;
394
case 0xF2: pref_rep = REPNZ; AGAIN;
395
case 0xF3: pref_rep = REP; AGAIN;
397
case 0xEC: /* IN AL, DX */
398
SET_8(regs->eax, vm86_inb(regs->edx & 0xFFFF));
401
case 0xED: /* IN AX, DX */
403
regs->eax = vm86_inl(regs->edx & 0xFFFF);
405
SET_16(regs->eax, vm86_inw(regs->edx & 0xFFFF));
408
case 0xE4: /* IN AL, imm8 */
410
vm86_inb(Vm86Memory(vi, MAKE_POINTER(regs->cs, regs->eip+1))));
413
case 0xE5: /* IN AX, imm8 */
416
vm86_inl(Vm86Memory(vi, MAKE_POINTER(regs->cs, regs->eip+1)));
419
vm86_inw(Vm86Memory(vi, MAKE_POINTER(regs->cs, regs->eip+1))));
422
case 0x6C: /* INSB */
423
case 0x6D: /* INSW */
425
Vm86WriteMemory(vi, MAKE_POINTER(regs->es, regs->edi),
426
vm86_inb(regs->edx & 0xFFFF));
429
Vm86WriteMemoryL(vi, MAKE_POINTER(regs->es, regs->edi),
430
vm86_inl(regs->edx & 0xFFFF));
433
Vm86WriteMemoryW(vi, MAKE_POINTER(regs->es, regs->edi),
434
vm86_inw(regs->edx & 0xFFFF));
437
if(regs->eflags & (1<<10))
447
SET_16(regs->ecx, regs->ecx - 1);
448
if((regs->ecx & 0xFFFF) != 0)
455
case 0xEE: /* OUT DX, AL */
456
vm86_outb(regs->edx & 0xFFFF, regs->eax & 0xFF);
459
case 0xEF: /* OUT DX, AX */
461
vm86_outl(regs->edx & 0xFFFF, regs->eax);
463
vm86_outw(regs->edx & 0xFFFF, regs->eax & 0xFFFF);
466
case 0xE6: /* OUT imm8, AL */
467
vm86_outb(Vm86Memory(vi, MAKE_POINTER(regs->cs, regs->eip+1)),
471
case 0xE7: /* OUT imm8, AX */
473
vm86_outl(Vm86Memory(vi, MAKE_POINTER(regs->cs, regs->eip+1)),
476
vm86_outw(Vm86Memory(vi, MAKE_POINTER(regs->cs, regs->eip+1)),
480
case 0x6E: /* OUTSB */
481
case 0x6F: /* OUTSW */
483
vm86_outb(regs->edx & 0xFFFF,
484
Vm86Memory(vi, MAKE_POINTER(regs->es, regs->edi)));
487
vm86_outl(regs->edx & 0xFFFF,
488
Vm86Memory(vi, MAKE_POINTER(regs->es, regs->edi)));
491
vm86_outw(regs->edx & 0xFFFF,
492
Vm86Memory(vi, MAKE_POINTER(regs->es, regs->edi)));
495
if(regs->eflags & (1<<10))
505
SET_16(regs->ecx, regs->ecx - 1);
506
if((regs->ecx & 0xFFFF) != 0)
514
ErrorF("Hit 0F trap in VM86 code\n");
517
ErrorF("Hit lock prefix in VM86 code\n");
520
ErrorF("Hit HLT in VM86 code\n");
524
ErrorF("Unhandled GP fault in VM86 code (opcode = 0x%02X)\n",
544
vm86_loop(Vm86InfoPtr vi)
549
code = vm86old(&vi->vms);
550
switch(VM86_TYPE(code)) {
554
code = vm86_emulate(vi);
561
if(VM86_ARG(code) == 0xFF)
564
PUSHW(vi, vi->vms.regs.eflags)
565
PUSHW(vi, vi->vms.regs.cs);
566
PUSHW(vi, vi->vms.regs.eip);
567
vi->vms.regs.cs = MMW(vi,VM86_ARG(code) * 4 + 2);
568
vi->vms.regs.eip = MMW(vi,VM86_ARG(code) * 4);
572
ErrorF("VM86 code enabled interrupts\n");
576
ErrorF("Unexpected result code 0x%X from vm86\n", code);
584
Vm86IsMemory(Vm86InfoPtr vi, U32 i)
586
if(i >= MAGICMEM_BASE && i< MAGICMEM_BASE + MAGICMEM_SIZE)
588
else if(i >= LOMEM_BASE && i< LOMEM_BASE + LOMEM_SIZE)
590
else if(i >= HIMEM_BASE && i< HIMEM_BASE + HIMEM_SIZE)
597
Vm86Memory(Vm86InfoPtr vi, U32 i)
599
if(i >= MAGICMEM_BASE && i< MAGICMEM_BASE + MAGICMEM_SIZE)
601
else if(i >= LOMEM_BASE && i< LOMEM_BASE + LOMEM_SIZE)
603
else if(i >= HIMEM_BASE && i< HIMEM_BASE + HIMEM_SIZE)
606
ErrorF("Reading unmapped memory at 0x%08X\n", i);
612
Vm86MemoryW(Vm86InfoPtr vi, U32 i)
614
if(i >= MAGICMEM_BASE && i< MAGICMEM_BASE + MAGICMEM_SIZE)
616
else if(i >= LOMEM_BASE && i< LOMEM_BASE + LOMEM_SIZE)
618
else if(i >= HIMEM_BASE && i< HIMEM_BASE + HIMEM_SIZE)
621
ErrorF("Reading unmapped memory at 0x%08X\n", i);
627
Vm86MemoryL(Vm86InfoPtr vi, U32 i)
629
if(i >= MAGICMEM_BASE && i< MAGICMEM_BASE + MAGICMEM_SIZE)
631
else if(i >= LOMEM_BASE && i< LOMEM_BASE + LOMEM_SIZE)
633
else if(i >= HIMEM_BASE && i< HIMEM_BASE + HIMEM_SIZE)
636
ErrorF("Reading unmapped memory at 0x%08X\n", i);
642
Vm86WriteMemory(Vm86InfoPtr vi, U32 i, U8 val)
644
if(i >= MAGICMEM_BASE && i< MAGICMEM_BASE + MAGICMEM_SIZE)
646
else if(i >= LOMEM_BASE && i< LOMEM_BASE + LOMEM_SIZE)
648
else if(i >= HIMEM_BASE && i< HIMEM_BASE + HIMEM_SIZE)
651
ErrorF("Writing unmapped memory at 0x%08X\n", i);
656
Vm86WriteMemoryW(Vm86InfoPtr vi, U32 i, U16 val)
658
if(i >= MAGICMEM_BASE && i< MAGICMEM_BASE + MAGICMEM_SIZE)
660
else if(i >= LOMEM_BASE && i< LOMEM_BASE + LOMEM_SIZE)
662
else if(i >= HIMEM_BASE && i< HIMEM_BASE + HIMEM_SIZE)
665
ErrorF("Writing unmapped memory at 0x%08X\n", i);
670
Vm86WriteMemoryL(Vm86InfoPtr vi, U32 i, U32 val)
672
if(i >= MAGICMEM_BASE && i< MAGICMEM_BASE + MAGICMEM_SIZE)
674
else if(i >= LOMEM_BASE && i< LOMEM_BASE + LOMEM_SIZE)
676
else if(i >= HIMEM_BASE && i< HIMEM_BASE + HIMEM_SIZE)
679
ErrorF("Writing unmapped memory at 0x%08X\n", i);
684
Vm86AllocateMemory(Vm86InfoPtr vi, int n)
688
ErrorF("Asked to allocate negative amount of memory\n");
693
if(vi->brk + n > LOMEM_BASE + LOMEM_SIZE) {
694
ErrorF("Out of low memory\n");
703
Vm86MarkMemory (Vm86InfoPtr vi)
709
Vm86ReleaseMemory (Vm86InfoPtr vi, int mark)
715
vm86old(struct vm86_struct *vm)
725
: "=a" (res) : "n" (113), "r" (vm));
735
Vm86Debug(Vm86InfoPtr vi)
737
struct vm86_regs *regs = &vi->vms.regs;
740
ErrorF("eax=0x%08lX ebx=0x%08lX ecx=0x%08lX edx=0x%08lX\n",
741
regs->eax, regs->ebx, regs->ecx, regs->edx);
742
ErrorF("esi=0x%08lX edi=0x%08lX ebp=0x%08lX\n",
743
regs->esi, regs->edi, regs->ebp);
744
ErrorF("eip=0x%08lX esp=0x%08lX eflags=0x%08lX\n",
745
regs->eip, regs->esp, regs->eflags);
746
ErrorF("cs=0x%04lX ds=0x%04lX es=0x%04lX fs=0x%04lX gs=0x%04lX\n",
747
regs->cs, regs->ds, regs->es, regs->fs, regs->gs);
748
for(i=-7; i<8; i++) {
751
Vm86Memory(vi, MAKE_POINTER(regs->cs, regs->eip + i)));
756
#ifdef NOT_IN_X_SERVER
762
vfprintf(stderr, f, args);