2
Linux Real Mode Interface - A library of DPMI-like functions for Linux.
4
Copyright (C) 1998 by Josh Vanderhoof
6
You are free to distribute and modify this file, as long as you
7
do not remove this copyright notice and clearly label modified
8
versions as being modified.
10
This software has NO WARRANTY. Use it at your own risk.
21
#if defined(__linux__)
23
#define TF_MASK X86_EFLAGS_TF
26
#define IF_MASK X86_EFLAGS_IF
29
#define IOPL_MASK X86_EFLAGS_IOPL
32
#define VIF_MASK X86_EFLAGS_VIF
36
#include <sys/types.h>
44
#define REAL_MEM_BASE ((void *)0x10000)
45
#define REAL_MEM_SIZE 0x10000
46
#define REAL_MEM_BLOCKS 0x100
50
unsigned int size : 20;
51
unsigned int free : 1;
58
struct mem_block blocks[REAL_MEM_BLOCKS];
70
fd_zero = open("/dev/zero", O_RDONLY);
73
perror("open /dev/zero");
77
m = mmap((void *)REAL_MEM_BASE, REAL_MEM_SIZE,
78
PROT_READ | PROT_WRITE | PROT_EXEC,
79
MAP_FIXED | MAP_PRIVATE, fd_zero, 0);
83
perror("mmap /dev/zero");
90
mem_info.blocks[0].size = REAL_MEM_SIZE;
91
mem_info.blocks[0].free = 1;
101
mem_info.blocks + i + 1,
103
(mem_info.count - i) * sizeof(struct mem_block));
115
mem_info.blocks + i + 1,
116
(mem_info.count - i) * sizeof(struct mem_block));
120
LRMI_alloc_real(int size)
123
char *r = (char *)REAL_MEM_BASE;
128
if (mem_info.count == REAL_MEM_BLOCKS)
131
size = (size + 15) & ~15;
133
for (i = 0; i < mem_info.count; i++)
135
if (mem_info.blocks[i].free && size < mem_info.blocks[i].size)
139
mem_info.blocks[i].size = size;
140
mem_info.blocks[i].free = 0;
141
mem_info.blocks[i + 1].size -= size;
146
r += mem_info.blocks[i].size;
154
LRMI_free_real(void *m)
157
char *r = (char *)REAL_MEM_BASE;
163
while (m != (void *)r)
165
r += mem_info.blocks[i].size;
167
if (i == mem_info.count)
171
mem_info.blocks[i].free = 1;
173
if (i + 1 < mem_info.count && mem_info.blocks[i + 1].free)
175
mem_info.blocks[i].size += mem_info.blocks[i + 1].size;
179
if (i - 1 >= 0 && mem_info.blocks[i - 1].free)
181
mem_info.blocks[i - 1].size += mem_info.blocks[i].size;
187
#define DEFAULT_VM86_FLAGS (IF_MASK | IOPL_MASK)
188
#define DEFAULT_STACK_SIZE 0x1000
189
#define RETURN_TO_32_INT 255
194
unsigned short ret_seg, ret_off;
195
unsigned short stack_seg, stack_off;
196
struct vm86_struct vm;
201
set_bit(unsigned int bit, void *array)
203
unsigned char *a = array;
205
a[bit / 8] |= (1 << (bit % 8));
209
static inline unsigned int
212
return *(unsigned short *)(i * 4 + 2);
216
static inline unsigned int
219
return *(unsigned short *)(i * 4);
224
pushw(unsigned short i)
226
struct vm86_regs *r = &context.vm.regs;
228
*(unsigned short *)(((unsigned int)r->ss << 4) + r->esp) = i;
241
if (!real_mem_init())
245
Map the Interrupt Vectors (0x0 - 0x400) + BIOS data (0x400 - 0x502)
246
and the ROM (0xa0000 - 0x100000)
248
fd_mem = open("/dev/mem", O_RDWR);
252
perror("open /dev/mem");
256
m = mmap((void *)0, 0x502,
257
PROT_READ | PROT_WRITE | PROT_EXEC,
258
MAP_FIXED | MAP_PRIVATE, fd_mem, 0);
262
perror("mmap /dev/mem");
266
m = mmap((void *)0xa0000, 0x100000 - 0xa0000,
267
PROT_READ | PROT_WRITE,
268
MAP_FIXED | MAP_SHARED, fd_mem, 0xa0000);
272
perror("mmap /dev/mem");
280
m = LRMI_alloc_real(DEFAULT_STACK_SIZE);
282
context.stack_seg = (unsigned int)m >> 4;
283
context.stack_off = DEFAULT_STACK_SIZE;
286
Allocate the return to 32 bit routine
288
m = LRMI_alloc_real(2);
290
context.ret_seg = (unsigned int)m >> 4;
291
context.ret_off = (unsigned int)m & 0xf;
293
((unsigned char *)m)[0] = 0xcd; /* int opcode */
294
((unsigned char *)m)[1] = RETURN_TO_32_INT;
296
memset(&context.vm, 0, sizeof(context.vm));
299
Enable kernel emulation of all ints except RETURN_TO_32_INT
301
memset(&context.vm.int_revectored, 0, sizeof(context.vm.int_revectored));
302
set_bit(RETURN_TO_32_INT, &context.vm.int_revectored);
311
set_regs(struct LRMI_regs *r)
313
context.vm.regs.edi = r->edi;
314
context.vm.regs.esi = r->esi;
315
context.vm.regs.ebp = r->ebp;
316
context.vm.regs.ebx = r->ebx;
317
context.vm.regs.edx = r->edx;
318
context.vm.regs.ecx = r->ecx;
319
context.vm.regs.eax = r->eax;
320
context.vm.regs.eflags = DEFAULT_VM86_FLAGS;
321
context.vm.regs.es = r->es;
322
context.vm.regs.ds = r->ds;
323
context.vm.regs.fs = r->fs;
324
context.vm.regs.gs = r->gs;
329
get_regs(struct LRMI_regs *r)
331
r->edi = context.vm.regs.edi;
332
r->esi = context.vm.regs.esi;
333
r->ebp = context.vm.regs.ebp;
334
r->ebx = context.vm.regs.ebx;
335
r->edx = context.vm.regs.edx;
336
r->ecx = context.vm.regs.ecx;
337
r->eax = context.vm.regs.eax;
338
r->flags = context.vm.regs.eflags;
339
r->es = context.vm.regs.es;
340
r->ds = context.vm.regs.ds;
341
r->fs = context.vm.regs.fs;
342
r->gs = context.vm.regs.gs;
345
#define DIRECTION_FLAG (1 << 10)
350
unsigned int edx, edi;
352
edx = context.vm.regs.edx & 0xffff;
353
edi = context.vm.regs.edi & 0xffff;
354
edi += (unsigned int)context.vm.regs.ds << 4;
356
if (context.vm.regs.eflags & DIRECTION_FLAG)
359
asm volatile ("std; insl; cld"
360
: "=D" (edi) : "d" (edx), "0" (edi));
362
asm volatile ("std; insw; cld"
363
: "=D" (edi) : "d" (edx), "0" (edi));
365
asm volatile ("std; insb; cld"
366
: "=D" (edi) : "d" (edx), "0" (edi));
371
asm volatile ("cld; insl"
372
: "=D" (edi) : "d" (edx), "0" (edi));
374
asm volatile ("cld; insw"
375
: "=D" (edi) : "d" (edx), "0" (edi));
377
asm volatile ("cld; insb"
378
: "=D" (edi) : "d" (edx), "0" (edi));
381
edi -= (unsigned int)context.vm.regs.ds << 4;
383
context.vm.regs.edi &= 0xffff0000;
384
context.vm.regs.edi |= edi & 0xffff;
390
unsigned int ecx, edx, edi;
392
ecx = context.vm.regs.ecx & 0xffff;
393
edx = context.vm.regs.edx & 0xffff;
394
edi = context.vm.regs.edi & 0xffff;
395
edi += (unsigned int)context.vm.regs.ds << 4;
397
if (context.vm.regs.eflags & DIRECTION_FLAG)
400
asm volatile ("std; rep; insl; cld"
401
: "=D" (edi), "=c" (ecx)
402
: "d" (edx), "0" (edi), "1" (ecx));
404
asm volatile ("std; rep; insw; cld"
405
: "=D" (edi), "=c" (ecx)
406
: "d" (edx), "0" (edi), "1" (ecx));
408
asm volatile ("std; rep; insb; cld"
409
: "=D" (edi), "=c" (ecx)
410
: "d" (edx), "0" (edi), "1" (ecx));
415
asm volatile ("cld; rep; insl"
416
: "=D" (edi), "=c" (ecx)
417
: "d" (edx), "0" (edi), "1" (ecx));
419
asm volatile ("cld; rep; insw"
420
: "=D" (edi), "=c" (ecx)
421
: "d" (edx), "0" (edi), "1" (ecx));
423
asm volatile ("cld; rep; insb"
424
: "=D" (edi), "=c" (ecx)
425
: "d" (edx), "0" (edi), "1" (ecx));
428
edi -= (unsigned int)context.vm.regs.ds << 4;
430
context.vm.regs.edi &= 0xffff0000;
431
context.vm.regs.edi |= edi & 0xffff;
433
context.vm.regs.ecx &= 0xffff0000;
434
context.vm.regs.ecx |= ecx & 0xffff;
440
unsigned int edx, esi;
442
edx = context.vm.regs.edx & 0xffff;
443
esi = context.vm.regs.esi & 0xffff;
444
esi += (unsigned int)context.vm.regs.ds << 4;
446
if (context.vm.regs.eflags & DIRECTION_FLAG)
449
asm volatile ("std; outsl; cld"
450
: "=S" (esi) : "d" (edx), "0" (esi));
452
asm volatile ("std; outsw; cld"
453
: "=S" (esi) : "d" (edx), "0" (esi));
455
asm volatile ("std; outsb; cld"
456
: "=S" (esi) : "d" (edx), "0" (esi));
461
asm volatile ("cld; outsl"
462
: "=S" (esi) : "d" (edx), "0" (esi));
464
asm volatile ("cld; outsw"
465
: "=S" (esi) : "d" (edx), "0" (esi));
467
asm volatile ("cld; outsb"
468
: "=S" (esi) : "d" (edx), "0" (esi));
471
esi -= (unsigned int)context.vm.regs.ds << 4;
473
context.vm.regs.esi &= 0xffff0000;
474
context.vm.regs.esi |= esi & 0xffff;
478
em_rep_outs(int size)
480
unsigned int ecx, edx, esi;
482
ecx = context.vm.regs.ecx & 0xffff;
483
edx = context.vm.regs.edx & 0xffff;
484
esi = context.vm.regs.esi & 0xffff;
485
esi += (unsigned int)context.vm.regs.ds << 4;
487
if (context.vm.regs.eflags & DIRECTION_FLAG)
490
asm volatile ("std; rep; outsl; cld"
491
: "=S" (esi), "=c" (ecx)
492
: "d" (edx), "0" (esi), "1" (ecx));
494
asm volatile ("std; rep; outsw; cld"
495
: "=S" (esi), "=c" (ecx)
496
: "d" (edx), "0" (esi), "1" (ecx));
498
asm volatile ("std; rep; outsb; cld"
499
: "=S" (esi), "=c" (ecx)
500
: "d" (edx), "0" (esi), "1" (ecx));
505
asm volatile ("cld; rep; outsl"
506
: "=S" (esi), "=c" (ecx)
507
: "d" (edx), "0" (esi), "1" (ecx));
509
asm volatile ("cld; rep; outsw"
510
: "=S" (esi), "=c" (ecx)
511
: "d" (edx), "0" (esi), "1" (ecx));
513
asm volatile ("cld; rep; outsb"
514
: "=S" (esi), "=c" (ecx)
515
: "d" (edx), "0" (esi), "1" (ecx));
518
esi -= (unsigned int)context.vm.regs.ds << 4;
520
context.vm.regs.esi &= 0xffff0000;
521
context.vm.regs.esi |= esi & 0xffff;
523
context.vm.regs.ecx &= 0xffff0000;
524
context.vm.regs.ecx |= ecx & 0xffff;
530
asm volatile ("inb (%w1), %b0"
531
: "=a" (context.vm.regs.eax)
532
: "d" (context.vm.regs.edx), "0" (context.vm.regs.eax));
538
asm volatile ("inw (%w1), %w0"
539
: "=a" (context.vm.regs.eax)
540
: "d" (context.vm.regs.edx), "0" (context.vm.regs.eax));
546
asm volatile ("inl (%w1), %0"
547
: "=a" (context.vm.regs.eax)
548
: "d" (context.vm.regs.edx));
554
asm volatile ("outb %b0, (%w1)"
555
: : "a" (context.vm.regs.eax),
556
"d" (context.vm.regs.edx));
562
asm volatile ("outw %w0, (%w1)"
563
: : "a" (context.vm.regs.eax),
564
"d" (context.vm.regs.edx));
570
asm volatile ("outl %0, (%w1)"
571
: : "a" (context.vm.regs.eax),
572
"d" (context.vm.regs.edx));
581
unsigned int size : 1;
582
unsigned int rep : 1;
586
insn = (unsigned char *)((unsigned int)context.vm.regs.cs << 4);
587
insn += context.vm.regs.eip;
593
prefix.size = 1 - prefix.size;
596
else if (insn[i] == 0xf3)
601
else if (insn[i] == 0xf0 || insn[i] == 0xf2
602
|| insn[i] == 0x26 || insn[i] == 0x2e
603
|| insn[i] == 0x36 || insn[i] == 0x3e
604
|| insn[i] == 0x64 || insn[i] == 0x65
607
/* these prefixes are just ignored */
610
else if (insn[i] == 0x6c)
619
else if (insn[i] == 0x6d)
638
else if (insn[i] == 0x6e)
647
else if (insn[i] == 0x6f)
666
else if (insn[i] == 0xec)
672
else if (insn[i] == 0xed)
681
else if (insn[i] == 0xee)
687
else if (insn[i] == 0xef)
701
context.vm.regs.eip += i;
707
I don't know how to make sure I get the right vm86() from libc.
708
The one I want is syscall # 113 (vm86old() in libc 5, vm86() in glibc)
709
which should be declared as "int vm86(struct vm86_struct *);" in
712
This just does syscall 113 with inline asm, which should work
713
for both libc's (I hope).
715
#if !defined(USE_LIBC_VM86)
717
lrmi_vm86(struct vm86_struct *vm)
727
: "0" (113), "r" (vm));
732
: "0" (113), "b" (vm));
737
#define lrmi_vm86 vm86
747
fputs("vm86() failed\n", stderr);
748
fprintf(stderr, "return = 0x%x\n", vret);
749
fprintf(stderr, "eax = 0x%08lx\n", context.vm.regs.eax);
750
fprintf(stderr, "ebx = 0x%08lx\n", context.vm.regs.ebx);
751
fprintf(stderr, "ecx = 0x%08lx\n", context.vm.regs.ecx);
752
fprintf(stderr, "edx = 0x%08lx\n", context.vm.regs.edx);
753
fprintf(stderr, "esi = 0x%08lx\n", context.vm.regs.esi);
754
fprintf(stderr, "edi = 0x%08lx\n", context.vm.regs.edi);
755
fprintf(stderr, "ebp = 0x%08lx\n", context.vm.regs.ebp);
756
fprintf(stderr, "eip = 0x%08lx\n", context.vm.regs.eip);
757
fprintf(stderr, "cs = 0x%04x\n", context.vm.regs.cs);
758
fprintf(stderr, "esp = 0x%08lx\n", context.vm.regs.esp);
759
fprintf(stderr, "ss = 0x%04x\n", context.vm.regs.ss);
760
fprintf(stderr, "ds = 0x%04x\n", context.vm.regs.ds);
761
fprintf(stderr, "es = 0x%04x\n", context.vm.regs.es);
762
fprintf(stderr, "fs = 0x%04x\n", context.vm.regs.fs);
763
fprintf(stderr, "gs = 0x%04x\n", context.vm.regs.gs);
764
fprintf(stderr, "eflags = 0x%08lx\n", context.vm.regs.eflags);
766
fputs("cs:ip = [ ", stderr);
768
p = (unsigned char *)((context.vm.regs.cs << 4) + (context.vm.regs.eip & 0xffff));
770
for (i = 0; i < 16; ++i)
771
fprintf(stderr, "%02x ", (unsigned int)p[i]);
773
fputs("]\n", stderr);
784
vret = lrmi_vm86(&context.vm);
786
if (VM86_TYPE(vret) == VM86_INTx)
788
unsigned int v = VM86_ARG(vret);
790
if (v == RETURN_TO_32_INT)
793
pushw(context.vm.regs.eflags);
794
pushw(context.vm.regs.cs);
795
pushw(context.vm.regs.eip);
797
context.vm.regs.cs = get_int_seg(v);
798
context.vm.regs.eip = get_int_off(v);
799
context.vm.regs.eflags &= ~(VIF_MASK | TF_MASK);
804
if (VM86_TYPE(vret) != VM86_UNKNOWN)
818
LRMI_call(struct LRMI_regs *r)
822
memset(&context.vm.regs, 0, sizeof(context.vm.regs));
826
context.vm.regs.cs = r->cs;
827
context.vm.regs.eip = r->ip;
829
if (r->ss == 0 && r->sp == 0)
831
context.vm.regs.ss = context.stack_seg;
832
context.vm.regs.esp = context.stack_off;
836
context.vm.regs.ss = r->ss;
837
context.vm.regs.esp = r->sp;
840
pushw(context.ret_seg);
841
pushw(context.ret_off);
852
LRMI_int(int i, struct LRMI_regs *r)
855
unsigned int seg, off;
857
seg = get_int_seg(i);
858
off = get_int_off(i);
861
If the interrupt is in regular memory, it's probably
862
still pointing at a dos TSR (which is now gone).
864
if (seg < 0xa000 || (seg << 4) + off >= 0x100000)
866
fprintf(stderr, "Int 0x%x is not in rom (%04x:%04x)\n", i, seg, off);
870
memset(&context.vm.regs, 0, sizeof(context.vm.regs));
874
context.vm.regs.cs = seg;
875
context.vm.regs.eip = off;
877
if (r->ss == 0 && r->sp == 0)
879
context.vm.regs.ss = context.stack_seg;
880
context.vm.regs.esp = context.stack_off;
884
context.vm.regs.ss = r->ss;
885
context.vm.regs.esp = r->sp;
888
pushw(DEFAULT_VM86_FLAGS);
889
pushw(context.ret_seg);
890
pushw(context.ret_off);