Remove dynamically generated code from LRMI.
[v86d.git] / libs / lrmi-0.10 / lrmi.c
blob7f733ef78b2216a1709fbfc2cee190837308d9f1
1 /*
2 Linux Real Mode Interface - A library of DPMI-like functions for Linux.
4 Copyright (C) 1998 by Josh Vanderhoof
6 Permission is hereby granted, free of charge, to any person obtaining
7 a copy of this software and associated documentation files (the
8 "Software"), to deal in the Software without restriction, including
9 without limitation the rights to use, copy, modify, merge, publish,
10 distribute, sublicense, and/or sell copies of the Software, and to
11 permit persons to whom the Software is furnished to do so, subject to
12 the following conditions:
14 The above copyright notice and this permission notice shall be
15 included in all copies or substantial portions of the Software.
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 IN NO EVENT SHALL JOSH VANDERHOOF BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 OTHER DEALINGS IN THE SOFTWARE.
26 #if defined(__i386__) && (defined(__linux__) || defined(__NetBSD__) \
27 || defined(__FreeBSD__) || defined(__OpenBSD__))
29 #include <stdio.h>
30 #include <string.h>
32 #if defined(__linux__)
34 #include <asm/vm86.h>
35 #include <signal.h>
37 #ifdef USE_LIBC_VM86
38 #include <sys/vm86.h>
39 #endif
41 #elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
43 #include <sys/param.h>
44 #include <signal.h>
45 #include <setjmp.h>
46 #include <machine/psl.h>
47 #include <machine/vm86.h>
48 #include <machine/sysarch.h>
50 #endif /* __NetBSD__ || __FreeBSD__ || __OpenBSD__ */
52 #if defined(__FreeBSD__)
53 #include <sys/ucontext.h>
54 #endif
56 #include <sys/types.h>
57 #include <sys/stat.h>
58 #include <sys/mman.h>
59 #include <unistd.h>
60 #include <fcntl.h>
62 #include "lrmi.h"
64 /* 2.6.26+ kernels don't define the legacy masks. */
65 #if defined(__linux__) && !defined(TF_MASK)
66 #define TF_MASK X86_EFLAGS_TF
67 #define IF_MASK X86_EFLAGS_IF
68 #define VIF_MASK X86_EFLAGS_VIF
69 #define IOPL_MASK X86_EFLAGS_IOPL
70 #endif
72 #define REAL_MEM_BASE ((void *)0x10000)
73 #define REAL_MEM_SIZE 0x40000
74 #define REAL_MEM_BLOCKS 0x100
76 struct mem_block {
77 unsigned int size : 20;
78 unsigned int free : 1;
81 static struct {
82 int ready;
83 int count;
84 struct mem_block blocks[REAL_MEM_BLOCKS];
85 } mem_info = { 0 };
87 static int
88 read_file(char *name, void *p, size_t n)
90 int fd;
92 fd = open(name, O_RDONLY);
94 if (fd == -1) {
95 perror("open");
96 return 0;
99 if (read(fd, p, n) != n) {
100 perror("read");
101 close(fd);
102 return 0;
105 close(fd);
107 return 1;
110 static int
111 map_file(void *start, size_t length, int prot, int flags, char *name, long offset)
113 void *m;
114 int fd;
116 fd = open(name, (flags & MAP_SHARED) ? O_RDWR : O_RDONLY);
118 if (fd == -1) {
119 perror("open");
120 return 0;
123 m = mmap(start, length, prot, flags, fd, offset);
125 if (m == (void *)-1) {
126 perror("mmap");
127 close(fd);
128 return 0;
131 close(fd);
132 return 1;
135 static int
136 real_mem_init(void)
138 if (mem_info.ready)
139 return 1;
141 if (!map_file((void *)REAL_MEM_BASE, REAL_MEM_SIZE,
142 PROT_READ | PROT_WRITE | PROT_EXEC,
143 MAP_FIXED | MAP_PRIVATE, "/dev/zero", 0))
144 return 0;
146 mem_info.ready = 1;
147 mem_info.count = 1;
148 mem_info.blocks[0].size = REAL_MEM_SIZE;
149 mem_info.blocks[0].free = 1;
151 return 1;
154 static void
155 real_mem_deinit(void)
157 if (mem_info.ready) {
158 munmap((void *)REAL_MEM_BASE, REAL_MEM_SIZE);
159 mem_info.ready = 0;
164 static void
165 insert_block(int i)
167 memmove(
168 mem_info.blocks + i + 1,
169 mem_info.blocks + i,
170 (mem_info.count - i) * sizeof(struct mem_block));
172 mem_info.count++;
175 static void
176 delete_block(int i)
178 mem_info.count--;
180 memmove(
181 mem_info.blocks + i,
182 mem_info.blocks + i + 1,
183 (mem_info.count - i) * sizeof(struct mem_block));
186 void *
187 LRMI_alloc_real(int size)
189 int i;
190 char *r = (char *)REAL_MEM_BASE;
192 if (!mem_info.ready)
193 return NULL;
195 if (mem_info.count == REAL_MEM_BLOCKS)
196 return NULL;
198 size = (size + 15) & ~15;
200 for (i = 0; i < mem_info.count; i++) {
201 if (mem_info.blocks[i].free && size < mem_info.blocks[i].size) {
202 insert_block(i);
204 mem_info.blocks[i].size = size;
205 mem_info.blocks[i].free = 0;
206 mem_info.blocks[i + 1].size -= size;
208 return (void *)r;
211 r += mem_info.blocks[i].size;
214 return NULL;
218 void
219 LRMI_free_real(void *m)
221 int i;
222 char *r = (char *)REAL_MEM_BASE;
224 if (!mem_info.ready)
225 return;
227 i = 0;
228 while (m != (void *)r) {
229 r += mem_info.blocks[i].size;
230 i++;
231 if (i == mem_info.count)
232 return;
235 mem_info.blocks[i].free = 1;
237 if (i + 1 < mem_info.count && mem_info.blocks[i + 1].free) {
238 mem_info.blocks[i].size += mem_info.blocks[i + 1].size;
239 delete_block(i + 1);
242 if (i - 1 >= 0 && mem_info.blocks[i - 1].free) {
243 mem_info.blocks[i - 1].size += mem_info.blocks[i].size;
244 delete_block(i);
249 #if defined(__linux__)
250 #define DEFAULT_VM86_FLAGS (IF_MASK | IOPL_MASK)
251 #elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
252 #define DEFAULT_VM86_FLAGS (PSL_I | PSL_IOPL)
253 #define TF_MASK PSL_T
254 #define VIF_MASK PSL_VIF
255 #endif
256 #define DEFAULT_STACK_SIZE 0x1000
257 #define RETURN_TO_32_INT 255
259 #if defined(__linux__)
260 #define CONTEXT_REGS context.vm.regs
261 #define REG(x) x
262 #elif defined(__NetBSD__) || defined(__OpenBSD__)
263 #define CONTEXT_REGS context.vm.substr.regs
264 #define REG(x) vmsc.sc_ ## x
265 #elif defined(__FreeBSD__)
266 #define CONTEXT_REGS context.vm.uc
267 #define REG(x) uc_mcontext.mc_ ## x
268 #endif
270 static struct {
271 int ready;
272 unsigned short ret_seg, ret_off;
273 unsigned short stack_seg, stack_off;
274 #if defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__)
275 struct vm86_struct vm;
276 #elif defined(__FreeBSD__)
277 struct {
278 struct vm86_init_args init;
279 ucontext_t uc;
280 } vm;
281 #endif
282 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
283 int success;
284 jmp_buf env;
285 void *old_sighandler;
286 int vret;
287 #endif
288 } context = { 0 };
291 static inline void
292 set_bit(unsigned int bit, void *array)
294 unsigned char *a = array;
296 a[bit / 8] |= (1 << (bit % 8));
300 static inline unsigned int
301 get_int_seg(int i)
303 return *(unsigned short *)(i * 4 + 2);
307 static inline unsigned int
308 get_int_off(int i)
310 return *(unsigned short *)(i * 4);
314 static inline void
315 pushw(unsigned short i)
317 CONTEXT_REGS.REG(esp) -= 2;
318 *(unsigned short *)(((unsigned int)CONTEXT_REGS.REG(ss) << 4) +
319 CONTEXT_REGS.REG(esp)) = i;
324 LRMI_init(void)
326 void *m;
328 if (context.ready)
329 return 1;
331 if (!real_mem_init())
332 return 0;
335 Map the Interrupt Vectors (0x0 - 0x400) + BIOS data (0x400 - 0x502)
336 and the ROM (0xa0000 - 0x100000)
340 * v86d: map the IVTBDA area as shared, see note in v86_mem.c for
341 * an explanation
343 if (!map_file((void *)0, 0x502,
344 PROT_READ | PROT_WRITE,
345 MAP_FIXED | MAP_SHARED, "/dev/mem", 0)) {
346 real_mem_deinit();
347 return 0;
350 if (!map_file((void *)0xa0000, 0x20000,
351 PROT_READ | PROT_WRITE,
352 MAP_FIXED | MAP_SHARED, "/dev/mem", 0xa0000)) {
353 munmap((void *)0, 0x502);
354 real_mem_deinit();
355 return 0;
358 if (!map_file((void *)0xc0000, 0x40000,
359 PROT_READ | PROT_EXEC,
360 MAP_FIXED | MAP_SHARED, "/dev/mem", 0xc0000)) {
361 munmap((void *)0, 0x502);
362 munmap((void *)0xa0000, 0x20000);
363 real_mem_deinit();
364 return 0;
368 Allocate a stack
370 m = LRMI_alloc_real(DEFAULT_STACK_SIZE);
372 context.stack_seg = (unsigned int)m >> 4;
373 context.stack_off = DEFAULT_STACK_SIZE;
375 #if defined(__linux__)
377 The return to 32-bit code (vm86_ret section) is linked
378 into the absolute address 0x9000.
380 context.ret_seg = 0x0900;
381 context.ret_off = 0x0000;
383 asm (".pushsection vm86_ret, \"ax\"\nint %0\n.popsection"
384 : /* no return value */
385 : "i" (RETURN_TO_32_INT));
386 #else
388 Allocate the return to 32 bit routine
390 m = LRMI_alloc_real(2);
392 context.ret_seg = (unsigned int)m >> 4;
393 context.ret_off = (unsigned int)m & 0xf;
395 ((unsigned char *)m)[0] = 0xcd; /* int opcode */
396 ((unsigned char *)m)[1] = RETURN_TO_32_INT;
398 #endif /* __linux__ */
399 memset(&context.vm, 0, sizeof(context.vm));
402 Enable kernel emulation of all ints except RETURN_TO_32_INT
404 #if defined(__linux__)
405 memset(&context.vm.int_revectored, 0, sizeof(context.vm.int_revectored));
406 set_bit(RETURN_TO_32_INT, &context.vm.int_revectored);
407 #elif defined(__NetBSD__) || defined(__OpenBSD__)
408 set_bit(RETURN_TO_32_INT, &context.vm.int_byuser);
409 #elif defined(__FreeBSD__)
410 set_bit(RETURN_TO_32_INT, &context.vm.init.int_map);
411 #endif
413 context.ready = 1;
415 return 1;
419 static void
420 set_regs(struct LRMI_regs *r)
422 CONTEXT_REGS.REG(edi) = r->edi;
423 CONTEXT_REGS.REG(esi) = r->esi;
424 CONTEXT_REGS.REG(ebp) = r->ebp;
425 CONTEXT_REGS.REG(ebx) = r->ebx;
426 CONTEXT_REGS.REG(edx) = r->edx;
427 CONTEXT_REGS.REG(ecx) = r->ecx;
428 CONTEXT_REGS.REG(eax) = r->eax;
429 CONTEXT_REGS.REG(eflags) = DEFAULT_VM86_FLAGS;
430 CONTEXT_REGS.REG(es) = r->es;
431 CONTEXT_REGS.REG(ds) = r->ds;
432 CONTEXT_REGS.REG(fs) = r->fs;
433 CONTEXT_REGS.REG(gs) = r->gs;
437 static void
438 get_regs(struct LRMI_regs *r)
440 r->edi = CONTEXT_REGS.REG(edi);
441 r->esi = CONTEXT_REGS.REG(esi);
442 r->ebp = CONTEXT_REGS.REG(ebp);
443 r->ebx = CONTEXT_REGS.REG(ebx);
444 r->edx = CONTEXT_REGS.REG(edx);
445 r->ecx = CONTEXT_REGS.REG(ecx);
446 r->eax = CONTEXT_REGS.REG(eax);
447 r->flags = CONTEXT_REGS.REG(eflags);
448 r->es = CONTEXT_REGS.REG(es);
449 r->ds = CONTEXT_REGS.REG(ds);
450 r->fs = CONTEXT_REGS.REG(fs);
451 r->gs = CONTEXT_REGS.REG(gs);
454 #define DIRECTION_FLAG (1 << 10)
456 enum {
457 CSEG = 0x2e, SSEG = 0x36, DSEG = 0x3e,
458 ESEG = 0x26, FSEG = 0x64, GSEG = 0x65,
461 static void
462 em_ins(int size)
464 unsigned int edx, edi;
466 edx = CONTEXT_REGS.REG(edx) & 0xffff;
467 edi = CONTEXT_REGS.REG(edi) & 0xffff;
468 edi += (unsigned int)CONTEXT_REGS.REG(es) << 4;
470 if (CONTEXT_REGS.REG(eflags) & DIRECTION_FLAG) {
471 if (size == 4)
472 asm volatile ("std; insl; cld"
473 : "=D" (edi) : "d" (edx), "0" (edi));
474 else if (size == 2)
475 asm volatile ("std; insw; cld"
476 : "=D" (edi) : "d" (edx), "0" (edi));
477 else
478 asm volatile ("std; insb; cld"
479 : "=D" (edi) : "d" (edx), "0" (edi));
480 } else {
481 if (size == 4)
482 asm volatile ("cld; insl"
483 : "=D" (edi) : "d" (edx), "0" (edi));
484 else if (size == 2)
485 asm volatile ("cld; insw"
486 : "=D" (edi) : "d" (edx), "0" (edi));
487 else
488 asm volatile ("cld; insb"
489 : "=D" (edi) : "d" (edx), "0" (edi));
492 edi -= (unsigned int)CONTEXT_REGS.REG(es) << 4;
494 CONTEXT_REGS.REG(edi) &= 0xffff0000;
495 CONTEXT_REGS.REG(edi) |= edi & 0xffff;
498 static void
499 em_rep_ins(int size)
501 unsigned int cx;
503 cx = CONTEXT_REGS.REG(ecx) & 0xffff;
505 while (cx--)
506 em_ins(size);
508 CONTEXT_REGS.REG(ecx) &= 0xffff0000;
511 static void
512 em_outs(int size, int seg)
514 unsigned int edx, esi, base;
516 edx = CONTEXT_REGS.REG(edx) & 0xffff;
517 esi = CONTEXT_REGS.REG(esi) & 0xffff;
519 switch (seg) {
520 case CSEG: base = CONTEXT_REGS.REG(cs); break;
521 case SSEG: base = CONTEXT_REGS.REG(ss); break;
522 case ESEG: base = CONTEXT_REGS.REG(es); break;
523 case FSEG: base = CONTEXT_REGS.REG(fs); break;
524 case GSEG: base = CONTEXT_REGS.REG(gs); break;
525 default:
526 case DSEG: base = CONTEXT_REGS.REG(ds); break;
529 esi += base << 4;
531 if (CONTEXT_REGS.REG(eflags) & DIRECTION_FLAG) {
532 if (size == 4)
533 asm volatile ("std; outsl; cld"
534 : "=S" (esi) : "d" (edx), "0" (esi));
535 else if (size == 2)
536 asm volatile ("std; outsw; cld"
537 : "=S" (esi) : "d" (edx), "0" (esi));
538 else
539 asm volatile ("std; outsb; cld"
540 : "=S" (esi) : "d" (edx), "0" (esi));
541 } else {
542 if (size == 4)
543 asm volatile ("cld; outsl"
544 : "=S" (esi) : "d" (edx), "0" (esi));
545 else if (size == 2)
546 asm volatile ("cld; outsw"
547 : "=S" (esi) : "d" (edx), "0" (esi));
548 else
549 asm volatile ("cld; outsb"
550 : "=S" (esi) : "d" (edx), "0" (esi));
553 esi -= base << 4;
555 CONTEXT_REGS.REG(esi) &= 0xffff0000;
556 CONTEXT_REGS.REG(esi) |= esi & 0xffff;
559 static void
560 em_rep_outs(int size, int seg)
562 unsigned int cx;
564 cx = CONTEXT_REGS.REG(ecx) & 0xffff;
566 while (cx--)
567 em_outs(size, seg);
569 CONTEXT_REGS.REG(ecx) &= 0xffff0000;
572 static void
573 em_inbl(unsigned char literal)
575 asm volatile ("inb %w1, %b0"
576 : "=a" (CONTEXT_REGS.REG(eax))
577 : "d" (literal), "0" (CONTEXT_REGS.REG(eax)));
580 static void
581 em_inb(void)
583 asm volatile ("inb %w1, %b0"
584 : "=a" (CONTEXT_REGS.REG(eax))
585 : "d" (CONTEXT_REGS.REG(edx)), "0" (CONTEXT_REGS.REG(eax)));
588 static void
589 em_inw(void)
591 asm volatile ("inw %w1, %w0"
592 : "=a" (CONTEXT_REGS.REG(eax))
593 : "d" (CONTEXT_REGS.REG(edx)), "0" (CONTEXT_REGS.REG(eax)));
596 static void
597 em_inl(void)
599 asm volatile ("inl %w1, %0"
600 : "=a" (CONTEXT_REGS.REG(eax))
601 : "d" (CONTEXT_REGS.REG(edx)));
604 static void
605 em_outbl(unsigned char literal)
607 asm volatile ("outb %b0, %w1"
608 : : "a" (CONTEXT_REGS.REG(eax)),
609 "d" (literal));
612 static void
613 em_outb(void)
615 asm volatile ("outb %b0, %w1"
616 : : "a" (CONTEXT_REGS.REG(eax)),
617 "d" (CONTEXT_REGS.REG(edx)));
620 static void
621 em_outw(void)
623 asm volatile ("outw %w0, %w1"
624 : : "a" (CONTEXT_REGS.REG(eax)),
625 "d" (CONTEXT_REGS.REG(edx)));
628 static void
629 em_outl(void)
631 asm volatile ("outl %0, %w1"
632 : : "a" (CONTEXT_REGS.REG(eax)),
633 "d" (CONTEXT_REGS.REG(edx)));
636 static int
637 emulate(void)
639 unsigned char *insn;
640 struct {
641 unsigned char seg;
642 unsigned int size : 1;
643 unsigned int rep : 1;
644 } prefix = { DSEG, 0, 0 };
645 int i = 0;
647 insn = (unsigned char *)((unsigned int)CONTEXT_REGS.REG(cs) << 4);
648 insn += CONTEXT_REGS.REG(eip);
650 while (1) {
651 if (insn[i] == 0x66) {
652 prefix.size = 1 - prefix.size;
653 i++;
654 } else if (insn[i] == 0xf3) {
655 prefix.rep = 1;
656 i++;
657 } else if (insn[i] == CSEG || insn[i] == SSEG
658 || insn[i] == DSEG || insn[i] == ESEG
659 || insn[i] == FSEG || insn[i] == GSEG) {
660 prefix.seg = insn[i];
661 i++;
662 } else if (insn[i] == 0xf0 || insn[i] == 0xf2
663 || insn[i] == 0x67) {
664 /* these prefixes are just ignored */
665 i++;
666 } else if (insn[i] == 0x6c) {
667 if (prefix.rep)
668 em_rep_ins(1);
669 else
670 em_ins(1);
671 i++;
672 break;
673 } else if (insn[i] == 0x6d) {
674 if (prefix.rep) {
675 if (prefix.size)
676 em_rep_ins(4);
677 else
678 em_rep_ins(2);
679 } else {
680 if (prefix.size)
681 em_ins(4);
682 else
683 em_ins(2);
685 i++;
686 break;
687 } else if (insn[i] == 0x6e) {
688 if (prefix.rep)
689 em_rep_outs(1, prefix.seg);
690 else
691 em_outs(1, prefix.seg);
692 i++;
693 break;
694 } else if (insn[i] == 0x6f) {
695 if (prefix.rep) {
696 if (prefix.size)
697 em_rep_outs(4, prefix.seg);
698 else
699 em_rep_outs(2, prefix.seg);
700 } else {
701 if (prefix.size)
702 em_outs(4, prefix.seg);
703 else
704 em_outs(2, prefix.seg);
706 i++;
707 break;
708 } else if (insn[i] == 0xe4) {
709 em_inbl(insn[i + 1]);
710 i += 2;
711 break;
712 } else if (insn[i] == 0xec) {
713 em_inb();
714 i++;
715 break;
716 } else if (insn[i] == 0xed) {
717 if (prefix.size)
718 em_inl();
719 else
720 em_inw();
721 i++;
722 break;
723 } else if (insn[i] == 0xe6) {
724 em_outbl(insn[i + 1]);
725 i += 2;
726 break;
727 } else if (insn[i] == 0xee) {
728 em_outb();
729 i++;
730 break;
731 } else if (insn[i] == 0xef) {
732 if (prefix.size)
733 em_outl();
734 else
735 em_outw();
737 i++;
738 break;
739 } else
740 return 0;
743 CONTEXT_REGS.REG(eip) += i;
744 return 1;
748 #if defined(__linux__)
750 I don't know how to make sure I get the right vm86() from libc.
751 The one I want is syscall # 113 (vm86old() in libc 5, vm86() in glibc)
752 which should be declared as "int vm86(struct vm86_struct *);" in
753 <sys/vm86.h>.
755 This just does syscall 113 with inline asm, which should work
756 for both libc's (I hope).
758 #if !defined(USE_LIBC_VM86)
759 static int
760 lrmi_vm86(struct vm86_struct *vm)
762 int r;
763 #ifdef __PIC__
764 asm volatile (
765 "pushl %%ebx\n\t"
766 "movl %2, %%ebx\n\t"
767 "int $0x80\n\t"
768 "popl %%ebx"
769 : "=a" (r)
770 : "0" (113), "r" (vm));
771 #else
772 asm volatile (
773 "int $0x80"
774 : "=a" (r)
775 : "0" (113), "b" (vm));
776 #endif
777 return r;
779 #else
780 #define lrmi_vm86 vm86
781 #endif
782 #endif /* __linux__ */
785 static void
786 debug_info(int vret)
788 #ifdef LRMI_DEBUG
789 int i;
790 unsigned char *p;
792 fputs("vm86() failed\n", stderr);
793 fprintf(stderr, "return = 0x%x\n", vret);
794 fprintf(stderr, "eax = 0x%08x\n", CONTEXT_REGS.REG(eax));
795 fprintf(stderr, "ebx = 0x%08x\n", CONTEXT_REGS.REG(ebx));
796 fprintf(stderr, "ecx = 0x%08x\n", CONTEXT_REGS.REG(ecx));
797 fprintf(stderr, "edx = 0x%08x\n", CONTEXT_REGS.REG(edx));
798 fprintf(stderr, "esi = 0x%08x\n", CONTEXT_REGS.REG(esi));
799 fprintf(stderr, "edi = 0x%08x\n", CONTEXT_REGS.REG(edi));
800 fprintf(stderr, "ebp = 0x%08x\n", CONTEXT_REGS.REG(ebp));
801 fprintf(stderr, "eip = 0x%08x\n", CONTEXT_REGS.REG(eip));
802 fprintf(stderr, "cs = 0x%04x\n", CONTEXT_REGS.REG(cs));
803 fprintf(stderr, "esp = 0x%08x\n", CONTEXT_REGS.REG(esp));
804 fprintf(stderr, "ss = 0x%04x\n", CONTEXT_REGS.REG(ss));
805 fprintf(stderr, "ds = 0x%04x\n", CONTEXT_REGS.REG(ds));
806 fprintf(stderr, "es = 0x%04x\n", CONTEXT_REGS.REG(es));
807 fprintf(stderr, "fs = 0x%04x\n", CONTEXT_REGS.REG(fs));
808 fprintf(stderr, "gs = 0x%04x\n", CONTEXT_REGS.REG(gs));
809 fprintf(stderr, "eflags = 0x%08x\n", CONTEXT_REGS.REG(eflags));
811 fputs("cs:ip = [ ", stderr);
813 p = (unsigned char *)((CONTEXT_REGS.REG(cs) << 4) + (CONTEXT_REGS.REG(eip) & 0xffff));
815 for (i = 0; i < 16; ++i)
816 fprintf(stderr, "%02x ", (unsigned int)p[i]);
818 fputs("]\n", stderr);
819 #endif
823 #if defined(__linux__)
824 static int
825 run_vm86(void)
827 unsigned int vret;
828 sigset_t all_sigs, old_sigs;
829 unsigned long old_gs, old_fs;
831 while (1) {
832 // FIXME: may apply this to BSD equivalents?
833 sigfillset(&all_sigs);
834 sigprocmask(SIG_SETMASK, &all_sigs, &old_sigs);
835 asm volatile ("mov %%gs, %0" : "=rm" (old_gs));
836 asm volatile ("mov %%fs, %0" : "=rm" (old_fs));
837 vret = lrmi_vm86(&context.vm);
838 asm volatile ("mov %0, %%gs" :: "rm" (old_gs));
839 asm volatile ("mov %0, %%fs" :: "rm" (old_fs));
840 sigprocmask(SIG_SETMASK, &old_sigs, NULL);
842 if (VM86_TYPE(vret) == VM86_INTx) {
843 unsigned int v = VM86_ARG(vret);
845 if (v == RETURN_TO_32_INT)
846 return 1;
848 pushw(CONTEXT_REGS.REG(eflags));
849 pushw(CONTEXT_REGS.REG(cs));
850 pushw(CONTEXT_REGS.REG(eip));
852 CONTEXT_REGS.REG(cs) = get_int_seg(v);
853 CONTEXT_REGS.REG(eip) = get_int_off(v);
854 CONTEXT_REGS.REG(eflags) &= ~(VIF_MASK | TF_MASK);
856 continue;
859 if (VM86_TYPE(vret) != VM86_UNKNOWN)
860 break;
862 if (!emulate())
863 break;
866 debug_info(vret);
868 return 0;
870 #elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
871 #if defined(__NetBSD__) || defined(__OpenBSD__)
872 static void
873 vm86_callback(int sig, int code, struct sigcontext *sc)
875 /* Sync our context with what the kernel develivered to us. */
876 memcpy(&CONTEXT_REGS, sc, sizeof(*sc));
878 switch (VM86_TYPE(code)) {
879 case VM86_INTx:
881 unsigned int v = VM86_ARG(code);
883 if (v == RETURN_TO_32_INT) {
884 context.success = 1;
885 longjmp(context.env, 1);
888 pushw(CONTEXT_REGS.REG(eflags));
889 pushw(CONTEXT_REGS.REG(cs));
890 pushw(CONTEXT_REGS.REG(eip));
892 CONTEXT_REGS.REG(cs) = get_int_seg(v);
893 CONTEXT_REGS.REG(eip) = get_int_off(v);
894 CONTEXT_REGS.REG(eflags) &= ~(VIF_MASK | TF_MASK);
896 break;
899 case VM86_UNKNOWN:
900 if (emulate() == 0) {
901 context.success = 0;
902 context.vret = code;
903 longjmp(context.env, 1);
905 break;
907 default:
908 context.success = 0;
909 context.vret = code;
910 longjmp(context.env, 1);
911 return;
914 /* ...and sync our context back to the kernel. */
915 memcpy(sc, &CONTEXT_REGS, sizeof(*sc));
917 #elif defined(__FreeBSD__)
918 static void
919 vm86_callback(int sig, int code, struct sigcontext *sc)
921 unsigned char *addr;
923 /* Sync our context with what the kernel develivered to us. */
924 memcpy(&CONTEXT_REGS, sc, sizeof(*sc));
926 if (code) {
927 /* XXX probably need to call original signal handler here */
928 context.success = 0;
929 context.vret = code;
930 longjmp(context.env, 1);
933 addr = (unsigned char *)((CONTEXT_REGS.REG(cs) << 4) +
934 CONTEXT_REGS.REG(eip));
936 if (addr[0] == 0xcd) { /* int opcode */
937 if (addr[1] == RETURN_TO_32_INT) {
938 context.success = 1;
939 longjmp(context.env, 1);
942 pushw(CONTEXT_REGS.REG(eflags));
943 pushw(CONTEXT_REGS.REG(cs));
944 pushw(CONTEXT_REGS.REG(eip));
946 CONTEXT_REGS.REG(cs) = get_int_seg(addr[1]);
947 CONTEXT_REGS.REG(eip) = get_int_off(addr[1]);
948 CONTEXT_REGS.REG(eflags) &= ~(VIF_MASK | TF_MASK);
949 } else {
950 if (emulate() == 0) {
951 context.success = 0;
952 longjmp(context.env, 1);
956 /* ...and sync our context back to the kernel. */
957 memcpy(sc, &CONTEXT_REGS, sizeof(*sc));
959 #endif /* __FreeBSD__ */
961 static int
962 run_vm86(void)
964 if (context.old_sighandler) {
965 #ifdef LRMI_DEBUG
966 fprintf(stderr, "run_vm86: callback already installed\n");
967 #endif
968 return (0);
971 #if defined(__NetBSD__) || defined(__OpenBSD__)
972 context.old_sighandler = signal(SIGURG, (void (*)(int))vm86_callback);
973 #elif defined(__FreeBSD__)
974 context.old_sighandler = signal(SIGBUS, (void (*)(int))vm86_callback);
975 #endif
977 if (context.old_sighandler == (void *)-1) {
978 context.old_sighandler = NULL;
979 #ifdef LRMI_DEBUG
980 fprintf(stderr, "run_vm86: cannot install callback\n");
981 #endif
982 return (0);
985 if (setjmp(context.env)) {
986 #if defined(__NetBSD__) || defined(__OpenBSD__)
987 (void) signal(SIGURG, context.old_sighandler);
988 #elif defined(__FreeBSD__)
989 (void) signal(SIGBUS, context.old_sighandler);
990 #endif
991 context.old_sighandler = NULL;
993 if (context.success)
994 return (1);
995 debug_info(context.vret);
996 return (0);
999 #if defined(__NetBSD__) || defined(__OpenBSD__)
1000 if (i386_vm86(&context.vm) == -1)
1001 return (0);
1002 #elif defined(__FreeBSD__)
1003 if (i386_vm86(VM86_INIT, &context.vm.init))
1004 return 0;
1006 CONTEXT_REGS.REG(eflags) |= PSL_VM | PSL_VIF;
1007 sigreturn(&context.vm.uc);
1008 #endif /* __FreeBSD__ */
1010 /* NOTREACHED */
1011 return (0);
1013 #endif /* __NetBSD__ || __FreeBSD__ || __OpenBSD__ */
1016 LRMI_call(struct LRMI_regs *r)
1018 unsigned int vret;
1020 memset(&CONTEXT_REGS, 0, sizeof(CONTEXT_REGS));
1022 set_regs(r);
1024 CONTEXT_REGS.REG(cs) = r->cs;
1025 CONTEXT_REGS.REG(eip) = r->ip;
1027 if (r->ss == 0 && r->sp == 0) {
1028 CONTEXT_REGS.REG(ss) = context.stack_seg;
1029 CONTEXT_REGS.REG(esp) = context.stack_off;
1030 } else {
1031 CONTEXT_REGS.REG(ss) = r->ss;
1032 CONTEXT_REGS.REG(esp) = r->sp;
1035 pushw(context.ret_seg);
1036 pushw(context.ret_off);
1038 vret = run_vm86();
1040 get_regs(r);
1042 return vret;
1047 LRMI_int(int i, struct LRMI_regs *r)
1049 unsigned int vret;
1050 unsigned int seg, off;
1052 seg = get_int_seg(i);
1053 off = get_int_off(i);
1056 If the interrupt is in regular memory, it's probably
1057 still pointing at a dos TSR (which is now gone).
1059 if (seg < 0xa000 || (seg << 4) + off >= 0x100000) {
1060 #ifdef LRMI_DEBUG
1061 fprintf(stderr, "Int 0x%x is not in rom (%04x:%04x)\n", i, seg, off);
1062 #endif
1063 return 0;
1066 memset(&CONTEXT_REGS, 0, sizeof(CONTEXT_REGS));
1068 set_regs(r);
1070 CONTEXT_REGS.REG(cs) = seg;
1071 CONTEXT_REGS.REG(eip) = off;
1073 if (r->ss == 0 && r->sp == 0) {
1074 CONTEXT_REGS.REG(ss) = context.stack_seg;
1075 CONTEXT_REGS.REG(esp) = context.stack_off;
1076 } else {
1077 CONTEXT_REGS.REG(ss) = r->ss;
1078 CONTEXT_REGS.REG(esp) = r->sp;
1081 pushw(DEFAULT_VM86_FLAGS);
1082 pushw(context.ret_seg);
1083 pushw(context.ret_off);
1085 vret = run_vm86();
1087 get_regs(r);
1089 return vret;
1092 #else /* (__linux__ || __NetBSD__ || __FreeBSD__ || __OpenBSD__) && __i386__ */
1093 #warning "LRMI is not supported on your system!"
1094 #endif