c68d753bfb2f5969d6fa70a181b9f14b97356b56
[v86d.git] / libs / lrmi-0.10 / lrmi.c
blobc68d753bfb2f5969d6fa70a181b9f14b97356b56
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 | PROT_EXEC,
345 MAP_FIXED | MAP_SHARED, "/dev/mem", 0)) {
346 real_mem_deinit();
347 return 0;
350 if (!map_file((void *)0xa0000, 0x100000 - 0xa0000,
351 PROT_READ | PROT_WRITE | PROT_EXEC,
352 MAP_FIXED | MAP_SHARED, "/dev/mem", 0xa0000)) {
353 munmap((void *)0, 0x502);
354 real_mem_deinit();
355 return 0;
359 Allocate a stack
361 m = LRMI_alloc_real(DEFAULT_STACK_SIZE);
363 context.stack_seg = (unsigned int)m >> 4;
364 context.stack_off = DEFAULT_STACK_SIZE;
367 Allocate the return to 32 bit routine
369 m = LRMI_alloc_real(2);
371 context.ret_seg = (unsigned int)m >> 4;
372 context.ret_off = (unsigned int)m & 0xf;
374 ((unsigned char *)m)[0] = 0xcd; /* int opcode */
375 ((unsigned char *)m)[1] = RETURN_TO_32_INT;
377 memset(&context.vm, 0, sizeof(context.vm));
380 Enable kernel emulation of all ints except RETURN_TO_32_INT
382 #if defined(__linux__)
383 memset(&context.vm.int_revectored, 0, sizeof(context.vm.int_revectored));
384 set_bit(RETURN_TO_32_INT, &context.vm.int_revectored);
385 #elif defined(__NetBSD__) || defined(__OpenBSD__)
386 set_bit(RETURN_TO_32_INT, &context.vm.int_byuser);
387 #elif defined(__FreeBSD__)
388 set_bit(RETURN_TO_32_INT, &context.vm.init.int_map);
389 #endif
391 context.ready = 1;
393 return 1;
397 static void
398 set_regs(struct LRMI_regs *r)
400 CONTEXT_REGS.REG(edi) = r->edi;
401 CONTEXT_REGS.REG(esi) = r->esi;
402 CONTEXT_REGS.REG(ebp) = r->ebp;
403 CONTEXT_REGS.REG(ebx) = r->ebx;
404 CONTEXT_REGS.REG(edx) = r->edx;
405 CONTEXT_REGS.REG(ecx) = r->ecx;
406 CONTEXT_REGS.REG(eax) = r->eax;
407 CONTEXT_REGS.REG(eflags) = DEFAULT_VM86_FLAGS;
408 CONTEXT_REGS.REG(es) = r->es;
409 CONTEXT_REGS.REG(ds) = r->ds;
410 CONTEXT_REGS.REG(fs) = r->fs;
411 CONTEXT_REGS.REG(gs) = r->gs;
415 static void
416 get_regs(struct LRMI_regs *r)
418 r->edi = CONTEXT_REGS.REG(edi);
419 r->esi = CONTEXT_REGS.REG(esi);
420 r->ebp = CONTEXT_REGS.REG(ebp);
421 r->ebx = CONTEXT_REGS.REG(ebx);
422 r->edx = CONTEXT_REGS.REG(edx);
423 r->ecx = CONTEXT_REGS.REG(ecx);
424 r->eax = CONTEXT_REGS.REG(eax);
425 r->flags = CONTEXT_REGS.REG(eflags);
426 r->es = CONTEXT_REGS.REG(es);
427 r->ds = CONTEXT_REGS.REG(ds);
428 r->fs = CONTEXT_REGS.REG(fs);
429 r->gs = CONTEXT_REGS.REG(gs);
432 #define DIRECTION_FLAG (1 << 10)
434 enum {
435 CSEG = 0x2e, SSEG = 0x36, DSEG = 0x3e,
436 ESEG = 0x26, FSEG = 0x64, GSEG = 0x65,
439 static void
440 em_ins(int size)
442 unsigned int edx, edi;
444 edx = CONTEXT_REGS.REG(edx) & 0xffff;
445 edi = CONTEXT_REGS.REG(edi) & 0xffff;
446 edi += (unsigned int)CONTEXT_REGS.REG(es) << 4;
448 if (CONTEXT_REGS.REG(eflags) & DIRECTION_FLAG) {
449 if (size == 4)
450 asm volatile ("std; insl; cld"
451 : "=D" (edi) : "d" (edx), "0" (edi));
452 else if (size == 2)
453 asm volatile ("std; insw; cld"
454 : "=D" (edi) : "d" (edx), "0" (edi));
455 else
456 asm volatile ("std; insb; cld"
457 : "=D" (edi) : "d" (edx), "0" (edi));
458 } else {
459 if (size == 4)
460 asm volatile ("cld; insl"
461 : "=D" (edi) : "d" (edx), "0" (edi));
462 else if (size == 2)
463 asm volatile ("cld; insw"
464 : "=D" (edi) : "d" (edx), "0" (edi));
465 else
466 asm volatile ("cld; insb"
467 : "=D" (edi) : "d" (edx), "0" (edi));
470 edi -= (unsigned int)CONTEXT_REGS.REG(es) << 4;
472 CONTEXT_REGS.REG(edi) &= 0xffff0000;
473 CONTEXT_REGS.REG(edi) |= edi & 0xffff;
476 static void
477 em_rep_ins(int size)
479 unsigned int cx;
481 cx = CONTEXT_REGS.REG(ecx) & 0xffff;
483 while (cx--)
484 em_ins(size);
486 CONTEXT_REGS.REG(ecx) &= 0xffff0000;
489 static void
490 em_outs(int size, int seg)
492 unsigned int edx, esi, base;
494 edx = CONTEXT_REGS.REG(edx) & 0xffff;
495 esi = CONTEXT_REGS.REG(esi) & 0xffff;
497 switch (seg) {
498 case CSEG: base = CONTEXT_REGS.REG(cs); break;
499 case SSEG: base = CONTEXT_REGS.REG(ss); break;
500 case ESEG: base = CONTEXT_REGS.REG(es); break;
501 case FSEG: base = CONTEXT_REGS.REG(fs); break;
502 case GSEG: base = CONTEXT_REGS.REG(gs); break;
503 default:
504 case DSEG: base = CONTEXT_REGS.REG(ds); break;
507 esi += base << 4;
509 if (CONTEXT_REGS.REG(eflags) & DIRECTION_FLAG) {
510 if (size == 4)
511 asm volatile ("std; outsl; cld"
512 : "=S" (esi) : "d" (edx), "0" (esi));
513 else if (size == 2)
514 asm volatile ("std; outsw; cld"
515 : "=S" (esi) : "d" (edx), "0" (esi));
516 else
517 asm volatile ("std; outsb; cld"
518 : "=S" (esi) : "d" (edx), "0" (esi));
519 } else {
520 if (size == 4)
521 asm volatile ("cld; outsl"
522 : "=S" (esi) : "d" (edx), "0" (esi));
523 else if (size == 2)
524 asm volatile ("cld; outsw"
525 : "=S" (esi) : "d" (edx), "0" (esi));
526 else
527 asm volatile ("cld; outsb"
528 : "=S" (esi) : "d" (edx), "0" (esi));
531 esi -= base << 4;
533 CONTEXT_REGS.REG(esi) &= 0xffff0000;
534 CONTEXT_REGS.REG(esi) |= esi & 0xffff;
537 static void
538 em_rep_outs(int size, int seg)
540 unsigned int cx;
542 cx = CONTEXT_REGS.REG(ecx) & 0xffff;
544 while (cx--)
545 em_outs(size, seg);
547 CONTEXT_REGS.REG(ecx) &= 0xffff0000;
550 static void
551 em_inbl(unsigned char literal)
553 asm volatile ("inb %w1, %b0"
554 : "=a" (CONTEXT_REGS.REG(eax))
555 : "d" (literal), "0" (CONTEXT_REGS.REG(eax)));
558 static void
559 em_inb(void)
561 asm volatile ("inb %w1, %b0"
562 : "=a" (CONTEXT_REGS.REG(eax))
563 : "d" (CONTEXT_REGS.REG(edx)), "0" (CONTEXT_REGS.REG(eax)));
566 static void
567 em_inw(void)
569 asm volatile ("inw %w1, %w0"
570 : "=a" (CONTEXT_REGS.REG(eax))
571 : "d" (CONTEXT_REGS.REG(edx)), "0" (CONTEXT_REGS.REG(eax)));
574 static void
575 em_inl(void)
577 asm volatile ("inl %w1, %0"
578 : "=a" (CONTEXT_REGS.REG(eax))
579 : "d" (CONTEXT_REGS.REG(edx)));
582 static void
583 em_outbl(unsigned char literal)
585 asm volatile ("outb %b0, %w1"
586 : : "a" (CONTEXT_REGS.REG(eax)),
587 "d" (literal));
590 static void
591 em_outb(void)
593 asm volatile ("outb %b0, %w1"
594 : : "a" (CONTEXT_REGS.REG(eax)),
595 "d" (CONTEXT_REGS.REG(edx)));
598 static void
599 em_outw(void)
601 asm volatile ("outw %w0, %w1"
602 : : "a" (CONTEXT_REGS.REG(eax)),
603 "d" (CONTEXT_REGS.REG(edx)));
606 static void
607 em_outl(void)
609 asm volatile ("outl %0, %w1"
610 : : "a" (CONTEXT_REGS.REG(eax)),
611 "d" (CONTEXT_REGS.REG(edx)));
614 static int
615 emulate(void)
617 unsigned char *insn;
618 struct {
619 unsigned char seg;
620 unsigned int size : 1;
621 unsigned int rep : 1;
622 } prefix = { DSEG, 0, 0 };
623 int i = 0;
625 insn = (unsigned char *)((unsigned int)CONTEXT_REGS.REG(cs) << 4);
626 insn += CONTEXT_REGS.REG(eip);
628 while (1) {
629 if (insn[i] == 0x66) {
630 prefix.size = 1 - prefix.size;
631 i++;
632 } else if (insn[i] == 0xf3) {
633 prefix.rep = 1;
634 i++;
635 } else if (insn[i] == CSEG || insn[i] == SSEG
636 || insn[i] == DSEG || insn[i] == ESEG
637 || insn[i] == FSEG || insn[i] == GSEG) {
638 prefix.seg = insn[i];
639 i++;
640 } else if (insn[i] == 0xf0 || insn[i] == 0xf2
641 || insn[i] == 0x67) {
642 /* these prefixes are just ignored */
643 i++;
644 } else if (insn[i] == 0x6c) {
645 if (prefix.rep)
646 em_rep_ins(1);
647 else
648 em_ins(1);
649 i++;
650 break;
651 } else if (insn[i] == 0x6d) {
652 if (prefix.rep) {
653 if (prefix.size)
654 em_rep_ins(4);
655 else
656 em_rep_ins(2);
657 } else {
658 if (prefix.size)
659 em_ins(4);
660 else
661 em_ins(2);
663 i++;
664 break;
665 } else if (insn[i] == 0x6e) {
666 if (prefix.rep)
667 em_rep_outs(1, prefix.seg);
668 else
669 em_outs(1, prefix.seg);
670 i++;
671 break;
672 } else if (insn[i] == 0x6f) {
673 if (prefix.rep) {
674 if (prefix.size)
675 em_rep_outs(4, prefix.seg);
676 else
677 em_rep_outs(2, prefix.seg);
678 } else {
679 if (prefix.size)
680 em_outs(4, prefix.seg);
681 else
682 em_outs(2, prefix.seg);
684 i++;
685 break;
686 } else if (insn[i] == 0xe4) {
687 em_inbl(insn[i + 1]);
688 i += 2;
689 break;
690 } else if (insn[i] == 0xec) {
691 em_inb();
692 i++;
693 break;
694 } else if (insn[i] == 0xed) {
695 if (prefix.size)
696 em_inl();
697 else
698 em_inw();
699 i++;
700 break;
701 } else if (insn[i] == 0xe6) {
702 em_outbl(insn[i + 1]);
703 i += 2;
704 break;
705 } else if (insn[i] == 0xee) {
706 em_outb();
707 i++;
708 break;
709 } else if (insn[i] == 0xef) {
710 if (prefix.size)
711 em_outl();
712 else
713 em_outw();
715 i++;
716 break;
717 } else
718 return 0;
721 CONTEXT_REGS.REG(eip) += i;
722 return 1;
726 #if defined(__linux__)
728 I don't know how to make sure I get the right vm86() from libc.
729 The one I want is syscall # 113 (vm86old() in libc 5, vm86() in glibc)
730 which should be declared as "int vm86(struct vm86_struct *);" in
731 <sys/vm86.h>.
733 This just does syscall 113 with inline asm, which should work
734 for both libc's (I hope).
736 #if !defined(USE_LIBC_VM86)
737 static int
738 lrmi_vm86(struct vm86_struct *vm)
740 int r;
741 #ifdef __PIC__
742 asm volatile (
743 "pushl %%ebx\n\t"
744 "movl %2, %%ebx\n\t"
745 "int $0x80\n\t"
746 "popl %%ebx"
747 : "=a" (r)
748 : "0" (113), "r" (vm));
749 #else
750 asm volatile (
751 "int $0x80"
752 : "=a" (r)
753 : "0" (113), "b" (vm));
754 #endif
755 return r;
757 #else
758 #define lrmi_vm86 vm86
759 #endif
760 #endif /* __linux__ */
763 static void
764 debug_info(int vret)
766 #ifdef LRMI_DEBUG
767 int i;
768 unsigned char *p;
770 fputs("vm86() failed\n", stderr);
771 fprintf(stderr, "return = 0x%x\n", vret);
772 fprintf(stderr, "eax = 0x%08x\n", CONTEXT_REGS.REG(eax));
773 fprintf(stderr, "ebx = 0x%08x\n", CONTEXT_REGS.REG(ebx));
774 fprintf(stderr, "ecx = 0x%08x\n", CONTEXT_REGS.REG(ecx));
775 fprintf(stderr, "edx = 0x%08x\n", CONTEXT_REGS.REG(edx));
776 fprintf(stderr, "esi = 0x%08x\n", CONTEXT_REGS.REG(esi));
777 fprintf(stderr, "edi = 0x%08x\n", CONTEXT_REGS.REG(edi));
778 fprintf(stderr, "ebp = 0x%08x\n", CONTEXT_REGS.REG(ebp));
779 fprintf(stderr, "eip = 0x%08x\n", CONTEXT_REGS.REG(eip));
780 fprintf(stderr, "cs = 0x%04x\n", CONTEXT_REGS.REG(cs));
781 fprintf(stderr, "esp = 0x%08x\n", CONTEXT_REGS.REG(esp));
782 fprintf(stderr, "ss = 0x%04x\n", CONTEXT_REGS.REG(ss));
783 fprintf(stderr, "ds = 0x%04x\n", CONTEXT_REGS.REG(ds));
784 fprintf(stderr, "es = 0x%04x\n", CONTEXT_REGS.REG(es));
785 fprintf(stderr, "fs = 0x%04x\n", CONTEXT_REGS.REG(fs));
786 fprintf(stderr, "gs = 0x%04x\n", CONTEXT_REGS.REG(gs));
787 fprintf(stderr, "eflags = 0x%08x\n", CONTEXT_REGS.REG(eflags));
789 fputs("cs:ip = [ ", stderr);
791 p = (unsigned char *)((CONTEXT_REGS.REG(cs) << 4) + (CONTEXT_REGS.REG(eip) & 0xffff));
793 for (i = 0; i < 16; ++i)
794 fprintf(stderr, "%02x ", (unsigned int)p[i]);
796 fputs("]\n", stderr);
797 #endif
801 #if defined(__linux__)
802 static int
803 run_vm86(void)
805 unsigned int vret;
806 sigset_t all_sigs, old_sigs;
807 unsigned long old_gs, old_fs;
809 while (1) {
810 // FIXME: may apply this to BSD equivalents?
811 sigfillset(&all_sigs);
812 sigprocmask(SIG_SETMASK, &all_sigs, &old_sigs);
813 asm volatile ("mov %%gs, %0" : "=rm" (old_gs));
814 asm volatile ("mov %%fs, %0" : "=rm" (old_fs));
815 vret = lrmi_vm86(&context.vm);
816 asm volatile ("mov %0, %%gs" :: "rm" (old_gs));
817 asm volatile ("mov %0, %%fs" :: "rm" (old_fs));
818 sigprocmask(SIG_SETMASK, &old_sigs, NULL);
820 if (VM86_TYPE(vret) == VM86_INTx) {
821 unsigned int v = VM86_ARG(vret);
823 if (v == RETURN_TO_32_INT)
824 return 1;
826 pushw(CONTEXT_REGS.REG(eflags));
827 pushw(CONTEXT_REGS.REG(cs));
828 pushw(CONTEXT_REGS.REG(eip));
830 CONTEXT_REGS.REG(cs) = get_int_seg(v);
831 CONTEXT_REGS.REG(eip) = get_int_off(v);
832 CONTEXT_REGS.REG(eflags) &= ~(VIF_MASK | TF_MASK);
834 continue;
837 if (VM86_TYPE(vret) != VM86_UNKNOWN)
838 break;
840 if (!emulate())
841 break;
844 debug_info(vret);
846 return 0;
848 #elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
849 #if defined(__NetBSD__) || defined(__OpenBSD__)
850 static void
851 vm86_callback(int sig, int code, struct sigcontext *sc)
853 /* Sync our context with what the kernel develivered to us. */
854 memcpy(&CONTEXT_REGS, sc, sizeof(*sc));
856 switch (VM86_TYPE(code)) {
857 case VM86_INTx:
859 unsigned int v = VM86_ARG(code);
861 if (v == RETURN_TO_32_INT) {
862 context.success = 1;
863 longjmp(context.env, 1);
866 pushw(CONTEXT_REGS.REG(eflags));
867 pushw(CONTEXT_REGS.REG(cs));
868 pushw(CONTEXT_REGS.REG(eip));
870 CONTEXT_REGS.REG(cs) = get_int_seg(v);
871 CONTEXT_REGS.REG(eip) = get_int_off(v);
872 CONTEXT_REGS.REG(eflags) &= ~(VIF_MASK | TF_MASK);
874 break;
877 case VM86_UNKNOWN:
878 if (emulate() == 0) {
879 context.success = 0;
880 context.vret = code;
881 longjmp(context.env, 1);
883 break;
885 default:
886 context.success = 0;
887 context.vret = code;
888 longjmp(context.env, 1);
889 return;
892 /* ...and sync our context back to the kernel. */
893 memcpy(sc, &CONTEXT_REGS, sizeof(*sc));
895 #elif defined(__FreeBSD__)
896 static void
897 vm86_callback(int sig, int code, struct sigcontext *sc)
899 unsigned char *addr;
901 /* Sync our context with what the kernel develivered to us. */
902 memcpy(&CONTEXT_REGS, sc, sizeof(*sc));
904 if (code) {
905 /* XXX probably need to call original signal handler here */
906 context.success = 0;
907 context.vret = code;
908 longjmp(context.env, 1);
911 addr = (unsigned char *)((CONTEXT_REGS.REG(cs) << 4) +
912 CONTEXT_REGS.REG(eip));
914 if (addr[0] == 0xcd) { /* int opcode */
915 if (addr[1] == RETURN_TO_32_INT) {
916 context.success = 1;
917 longjmp(context.env, 1);
920 pushw(CONTEXT_REGS.REG(eflags));
921 pushw(CONTEXT_REGS.REG(cs));
922 pushw(CONTEXT_REGS.REG(eip));
924 CONTEXT_REGS.REG(cs) = get_int_seg(addr[1]);
925 CONTEXT_REGS.REG(eip) = get_int_off(addr[1]);
926 CONTEXT_REGS.REG(eflags) &= ~(VIF_MASK | TF_MASK);
927 } else {
928 if (emulate() == 0) {
929 context.success = 0;
930 longjmp(context.env, 1);
934 /* ...and sync our context back to the kernel. */
935 memcpy(sc, &CONTEXT_REGS, sizeof(*sc));
937 #endif /* __FreeBSD__ */
939 static int
940 run_vm86(void)
942 if (context.old_sighandler) {
943 #ifdef LRMI_DEBUG
944 fprintf(stderr, "run_vm86: callback already installed\n");
945 #endif
946 return (0);
949 #if defined(__NetBSD__) || defined(__OpenBSD__)
950 context.old_sighandler = signal(SIGURG, (void (*)(int))vm86_callback);
951 #elif defined(__FreeBSD__)
952 context.old_sighandler = signal(SIGBUS, (void (*)(int))vm86_callback);
953 #endif
955 if (context.old_sighandler == (void *)-1) {
956 context.old_sighandler = NULL;
957 #ifdef LRMI_DEBUG
958 fprintf(stderr, "run_vm86: cannot install callback\n");
959 #endif
960 return (0);
963 if (setjmp(context.env)) {
964 #if defined(__NetBSD__) || defined(__OpenBSD__)
965 (void) signal(SIGURG, context.old_sighandler);
966 #elif defined(__FreeBSD__)
967 (void) signal(SIGBUS, context.old_sighandler);
968 #endif
969 context.old_sighandler = NULL;
971 if (context.success)
972 return (1);
973 debug_info(context.vret);
974 return (0);
977 #if defined(__NetBSD__) || defined(__OpenBSD__)
978 if (i386_vm86(&context.vm) == -1)
979 return (0);
980 #elif defined(__FreeBSD__)
981 if (i386_vm86(VM86_INIT, &context.vm.init))
982 return 0;
984 CONTEXT_REGS.REG(eflags) |= PSL_VM | PSL_VIF;
985 sigreturn(&context.vm.uc);
986 #endif /* __FreeBSD__ */
988 /* NOTREACHED */
989 return (0);
991 #endif /* __NetBSD__ || __FreeBSD__ || __OpenBSD__ */
994 LRMI_call(struct LRMI_regs *r)
996 unsigned int vret;
998 memset(&CONTEXT_REGS, 0, sizeof(CONTEXT_REGS));
1000 set_regs(r);
1002 CONTEXT_REGS.REG(cs) = r->cs;
1003 CONTEXT_REGS.REG(eip) = r->ip;
1005 if (r->ss == 0 && r->sp == 0) {
1006 CONTEXT_REGS.REG(ss) = context.stack_seg;
1007 CONTEXT_REGS.REG(esp) = context.stack_off;
1008 } else {
1009 CONTEXT_REGS.REG(ss) = r->ss;
1010 CONTEXT_REGS.REG(esp) = r->sp;
1013 pushw(context.ret_seg);
1014 pushw(context.ret_off);
1016 vret = run_vm86();
1018 get_regs(r);
1020 return vret;
1025 LRMI_int(int i, struct LRMI_regs *r)
1027 unsigned int vret;
1028 unsigned int seg, off;
1030 seg = get_int_seg(i);
1031 off = get_int_off(i);
1034 If the interrupt is in regular memory, it's probably
1035 still pointing at a dos TSR (which is now gone).
1037 if (seg < 0xa000 || (seg << 4) + off >= 0x100000) {
1038 #ifdef LRMI_DEBUG
1039 fprintf(stderr, "Int 0x%x is not in rom (%04x:%04x)\n", i, seg, off);
1040 #endif
1041 return 0;
1044 memset(&CONTEXT_REGS, 0, sizeof(CONTEXT_REGS));
1046 set_regs(r);
1048 CONTEXT_REGS.REG(cs) = seg;
1049 CONTEXT_REGS.REG(eip) = off;
1051 if (r->ss == 0 && r->sp == 0) {
1052 CONTEXT_REGS.REG(ss) = context.stack_seg;
1053 CONTEXT_REGS.REG(esp) = context.stack_off;
1054 } else {
1055 CONTEXT_REGS.REG(ss) = r->ss;
1056 CONTEXT_REGS.REG(esp) = r->sp;
1059 pushw(DEFAULT_VM86_FLAGS);
1060 pushw(context.ret_seg);
1061 pushw(context.ret_off);
1063 vret = run_vm86();
1065 get_regs(r);
1067 return vret;
1070 #else /* (__linux__ || __NetBSD__ || __FreeBSD__ || __OpenBSD__) && __i386__ */
1071 #warning "LRMI is not supported on your system!"
1072 #endif