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__))
32 #if defined(__linux__)
41 #elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
43 #include <sys/param.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>
56 #include <sys/types.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
72 #define REAL_MEM_BASE ((void *)0x10000)
73 #define REAL_MEM_SIZE 0x40000
74 #define REAL_MEM_BLOCKS 0x100
77 unsigned int size
: 20;
78 unsigned int free
: 1;
84 struct mem_block blocks
[REAL_MEM_BLOCKS
];
88 read_file(char *name
, void *p
, size_t n
)
92 fd
= open(name
, O_RDONLY
);
99 if (read(fd
, p
, n
) != n
) {
111 map_file(void *start
, size_t length
, int prot
, int flags
, char *name
, long offset
)
116 fd
= open(name
, (flags
& MAP_SHARED
) ? O_RDWR
: O_RDONLY
);
123 m
= mmap(start
, length
, prot
, flags
, fd
, offset
);
125 if (m
== (void *)-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))
148 mem_info
.blocks
[0].size
= REAL_MEM_SIZE
;
149 mem_info
.blocks
[0].free
= 1;
155 real_mem_deinit(void)
157 if (mem_info
.ready
) {
158 munmap((void *)REAL_MEM_BASE
, REAL_MEM_SIZE
);
168 mem_info
.blocks
+ i
+ 1,
170 (mem_info
.count
- i
) * sizeof(struct mem_block
));
182 mem_info
.blocks
+ i
+ 1,
183 (mem_info
.count
- i
) * sizeof(struct mem_block
));
187 LRMI_alloc_real(int size
)
190 char *r
= (char *)REAL_MEM_BASE
;
195 if (mem_info
.count
== REAL_MEM_BLOCKS
)
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
) {
204 mem_info
.blocks
[i
].size
= size
;
205 mem_info
.blocks
[i
].free
= 0;
206 mem_info
.blocks
[i
+ 1].size
-= size
;
211 r
+= mem_info
.blocks
[i
].size
;
219 LRMI_free_real(void *m
)
222 char *r
= (char *)REAL_MEM_BASE
;
228 while (m
!= (void *)r
) {
229 r
+= mem_info
.blocks
[i
].size
;
231 if (i
== mem_info
.count
)
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
;
242 if (i
- 1 >= 0 && mem_info
.blocks
[i
- 1].free
) {
243 mem_info
.blocks
[i
- 1].size
+= mem_info
.blocks
[i
].size
;
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
256 #define DEFAULT_STACK_SIZE 0x1000
257 #define RETURN_TO_32_INT 255
259 #if defined(__linux__)
260 #define CONTEXT_REGS context.vm.regs
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
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__)
278 struct vm86_init_args init
;
282 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
285 void *old_sighandler
;
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
303 return *(unsigned short *)(i
* 4 + 2);
307 static inline unsigned int
310 return *(unsigned short *)(i
* 4);
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
;
331 if (!real_mem_init())
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
343 if (!map_file((void *)0, 0x502,
344 PROT_READ
| PROT_WRITE
,
345 MAP_FIXED
| MAP_SHARED
, "/dev/mem", 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);
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);
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
));
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
);
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
;
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)
457 CSEG
= 0x2e, SSEG
= 0x36, DSEG
= 0x3e,
458 ESEG
= 0x26, FSEG
= 0x64, GSEG
= 0x65,
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
) {
472 asm volatile ("std; insl; cld"
473 : "=D" (edi
) : "d" (edx
), "0" (edi
));
475 asm volatile ("std; insw; cld"
476 : "=D" (edi
) : "d" (edx
), "0" (edi
));
478 asm volatile ("std; insb; cld"
479 : "=D" (edi
) : "d" (edx
), "0" (edi
));
482 asm volatile ("cld; insl"
483 : "=D" (edi
) : "d" (edx
), "0" (edi
));
485 asm volatile ("cld; insw"
486 : "=D" (edi
) : "d" (edx
), "0" (edi
));
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;
503 cx
= CONTEXT_REGS
.REG(ecx
) & 0xffff;
508 CONTEXT_REGS
.REG(ecx
) &= 0xffff0000;
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;
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;
526 case DSEG
: base
= CONTEXT_REGS
.REG(ds
); break;
531 if (CONTEXT_REGS
.REG(eflags
) & DIRECTION_FLAG
) {
533 asm volatile ("std; outsl; cld"
534 : "=S" (esi
) : "d" (edx
), "0" (esi
));
536 asm volatile ("std; outsw; cld"
537 : "=S" (esi
) : "d" (edx
), "0" (esi
));
539 asm volatile ("std; outsb; cld"
540 : "=S" (esi
) : "d" (edx
), "0" (esi
));
543 asm volatile ("cld; outsl"
544 : "=S" (esi
) : "d" (edx
), "0" (esi
));
546 asm volatile ("cld; outsw"
547 : "=S" (esi
) : "d" (edx
), "0" (esi
));
549 asm volatile ("cld; outsb"
550 : "=S" (esi
) : "d" (edx
), "0" (esi
));
555 CONTEXT_REGS
.REG(esi
) &= 0xffff0000;
556 CONTEXT_REGS
.REG(esi
) |= esi
& 0xffff;
560 em_rep_outs(int size
, int seg
)
564 cx
= CONTEXT_REGS
.REG(ecx
) & 0xffff;
569 CONTEXT_REGS
.REG(ecx
) &= 0xffff0000;
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
)));
583 asm volatile ("inb %w1, %b0"
584 : "=a" (CONTEXT_REGS
.REG(eax
))
585 : "d" (CONTEXT_REGS
.REG(edx
)), "0" (CONTEXT_REGS
.REG(eax
)));
591 asm volatile ("inw %w1, %w0"
592 : "=a" (CONTEXT_REGS
.REG(eax
))
593 : "d" (CONTEXT_REGS
.REG(edx
)), "0" (CONTEXT_REGS
.REG(eax
)));
599 asm volatile ("inl %w1, %0"
600 : "=a" (CONTEXT_REGS
.REG(eax
))
601 : "d" (CONTEXT_REGS
.REG(edx
)));
605 em_outbl(unsigned char literal
)
607 asm volatile ("outb %b0, %w1"
608 : : "a" (CONTEXT_REGS
.REG(eax
)),
615 asm volatile ("outb %b0, %w1"
616 : : "a" (CONTEXT_REGS
.REG(eax
)),
617 "d" (CONTEXT_REGS
.REG(edx
)));
623 asm volatile ("outw %w0, %w1"
624 : : "a" (CONTEXT_REGS
.REG(eax
)),
625 "d" (CONTEXT_REGS
.REG(edx
)));
631 asm volatile ("outl %0, %w1"
632 : : "a" (CONTEXT_REGS
.REG(eax
)),
633 "d" (CONTEXT_REGS
.REG(edx
)));
642 unsigned int size
: 1;
643 unsigned int rep
: 1;
644 } prefix
= { DSEG
, 0, 0 };
647 insn
= (unsigned char *)((unsigned int)CONTEXT_REGS
.REG(cs
) << 4);
648 insn
+= CONTEXT_REGS
.REG(eip
);
651 if (insn
[i
] == 0x66) {
652 prefix
.size
= 1 - prefix
.size
;
654 } else if (insn
[i
] == 0xf3) {
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
];
662 } else if (insn
[i
] == 0xf0 || insn
[i
] == 0xf2
663 || insn
[i
] == 0x67) {
664 /* these prefixes are just ignored */
666 } else if (insn
[i
] == 0x6c) {
673 } else if (insn
[i
] == 0x6d) {
687 } else if (insn
[i
] == 0x6e) {
689 em_rep_outs(1, prefix
.seg
);
691 em_outs(1, prefix
.seg
);
694 } else if (insn
[i
] == 0x6f) {
697 em_rep_outs(4, prefix
.seg
);
699 em_rep_outs(2, prefix
.seg
);
702 em_outs(4, prefix
.seg
);
704 em_outs(2, prefix
.seg
);
708 } else if (insn
[i
] == 0xe4) {
709 em_inbl(insn
[i
+ 1]);
712 } else if (insn
[i
] == 0xec) {
716 } else if (insn
[i
] == 0xed) {
723 } else if (insn
[i
] == 0xe6) {
724 em_outbl(insn
[i
+ 1]);
727 } else if (insn
[i
] == 0xee) {
731 } else if (insn
[i
] == 0xef) {
743 CONTEXT_REGS
.REG(eip
) += i
;
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
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)
760 lrmi_vm86(struct vm86_struct
*vm
)
770 : "0" (113), "r" (vm
));
775 : "0" (113), "b" (vm
));
780 #define lrmi_vm86 vm86
782 #endif /* __linux__ */
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
);
823 #if defined(__linux__)
828 sigset_t all_sigs
, old_sigs
;
829 unsigned long old_gs
, old_fs
;
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
)
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
);
859 if (VM86_TYPE(vret
) != VM86_UNKNOWN
)
870 #elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
871 #if defined(__NetBSD__) || defined(__OpenBSD__)
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
)) {
881 unsigned int v
= VM86_ARG(code
);
883 if (v
== RETURN_TO_32_INT
) {
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
);
900 if (emulate() == 0) {
903 longjmp(context
.env
, 1);
910 longjmp(context
.env
, 1);
914 /* ...and sync our context back to the kernel. */
915 memcpy(sc
, &CONTEXT_REGS
, sizeof(*sc
));
917 #elif defined(__FreeBSD__)
919 vm86_callback(int sig
, int code
, struct sigcontext
*sc
)
923 /* Sync our context with what the kernel develivered to us. */
924 memcpy(&CONTEXT_REGS
, sc
, sizeof(*sc
));
927 /* XXX probably need to call original signal handler here */
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
) {
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
);
950 if (emulate() == 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__ */
964 if (context
.old_sighandler
) {
966 fprintf(stderr
, "run_vm86: callback already installed\n");
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
);
977 if (context
.old_sighandler
== (void *)-1) {
978 context
.old_sighandler
= NULL
;
980 fprintf(stderr
, "run_vm86: cannot install callback\n");
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
);
991 context
.old_sighandler
= NULL
;
995 debug_info(context
.vret
);
999 #if defined(__NetBSD__) || defined(__OpenBSD__)
1000 if (i386_vm86(&context
.vm
) == -1)
1002 #elif defined(__FreeBSD__)
1003 if (i386_vm86(VM86_INIT
, &context
.vm
.init
))
1006 CONTEXT_REGS
.REG(eflags
) |= PSL_VM
| PSL_VIF
;
1007 sigreturn(&context
.vm
.uc
);
1008 #endif /* __FreeBSD__ */
1013 #endif /* __NetBSD__ || __FreeBSD__ || __OpenBSD__ */
1016 LRMI_call(struct LRMI_regs
*r
)
1020 memset(&CONTEXT_REGS
, 0, sizeof(CONTEXT_REGS
));
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
;
1031 CONTEXT_REGS
.REG(ss
) = r
->ss
;
1032 CONTEXT_REGS
.REG(esp
) = r
->sp
;
1035 pushw(context
.ret_seg
);
1036 pushw(context
.ret_off
);
1047 LRMI_int(int i
, struct LRMI_regs
*r
)
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) {
1061 fprintf(stderr
, "Int 0x%x is not in rom (%04x:%04x)\n", i
, seg
, off
);
1066 memset(&CONTEXT_REGS
, 0, sizeof(CONTEXT_REGS
));
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
;
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
);
1092 #else /* (__linux__ || __NetBSD__ || __FreeBSD__ || __OpenBSD__) && __i386__ */
1093 #warning "LRMI is not supported on your system!"