1 /*
2 Linux Real Mode Interface - A library of DPMI-like functions for Linux.
3
4 Copyright (C) 1998 by Josh Vanderhoof
5
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:
13
14 The above copyright notice and this permission notice shall be
15 included in all copies or substantial portions of the Software.
16
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.
24 */
25
26 #include <stdio.h>
27 #include <string.h>
28
29 #if defined(__linux__) && defined(__i386__)
30
31 #include <asm/vm86.h>
32
33 #ifdef USE_LIBC_VM86
34 #include <sys/vm86.h>
35 #endif
36
37 #elif defined(__NetBSD__) || defined(__FreeBSD__)
38
39 #include <sys/param.h>
40 #include <signal.h>
41 #include <setjmp.h>
42 #include <machine/psl.h>
43 #include <machine/vm86.h>
44 #include <machine/sysarch.h>
45
46 #endif /* __NetBSD__ || __FreeBSD__ */
47
48 #include <sys/types.h>
49 #include <sys/stat.h>
50 #include <sys/mman.h>
51 #include <unistd.h>
52 #include <fcntl.h>
53
54 #include "lrmi.h"
55 #include "x86-common.h"
56
57 #if defined(__linux__)
58 #define DEFAULT_VM86_FLAGS (IF_MASK | IOPL_MASK)
59 #elif defined(__NetBSD__) || defined(__FreeBSD__)
60 #define DEFAULT_VM86_FLAGS (PSL_I | PSL_IOPL)
61 #define TF_MASK PSL_T
62 #define VIF_MASK PSL_VIF
63 #endif
64 #define DEFAULT_STACK_SIZE 0x1000
65 #define RETURN_TO_32_INT 255
66
67 #if defined(__linux__)
68 #define CONTEXT_REGS context.vm.regs
69 #define REG(x) x
70 #elif defined(__NetBSD__)
71 #define CONTEXT_REGS context.vm.substr.regs
72 #define REG(x) vmsc.sc_ ## x
73 #elif defined(__FreeBSD__)
74 #define CONTEXT_REGS context.vm.uc
75 #define REG(x) uc_mcontext.mc_ ## x
76 #endif
77
78 static struct {
79 int ready;
80 unsigned short ret_seg, ret_off;
81 unsigned short stack_seg, stack_off;
82 #if defined(__linux__) || defined(__NetBSD__)
83 struct vm86_struct vm;
84 #elif defined(__FreeBSD__)
85 struct {
86 struct vm86_init_args init;
87 ucontext_t uc;
88 } vm;
89 #endif
90 #if defined(__NetBSD__) || defined(__FreeBSD__)
91 int success;
92 jmp_buf env;
93 void *old_sighandler;
94 int vret;
95 #endif
96 } context = { 0 };
97
98
99 static inline void
set_bit(unsigned int bit,void * array)100 set_bit(unsigned int bit, void *array)
101 {
102 unsigned char *a = array;
103
104 a[bit / 8] |= (1 << (bit % 8));
105 }
106
107
108 static inline unsigned int
get_int_seg(int i)109 get_int_seg(int i)
110 {
111 return *(unsigned short *)(i * 4 + 2);
112 }
113
114
115 static inline unsigned int
get_int_off(int i)116 get_int_off(int i)
117 {
118 return *(unsigned short *)(i * 4);
119 }
120
121
122 static inline void
pushw(unsigned short i)123 pushw(unsigned short i)
124 {
125 CONTEXT_REGS.REG(esp) -= 2;
126 *(unsigned short *)(((unsigned int)CONTEXT_REGS.REG(ss) << 4) +
127 CONTEXT_REGS.REG(esp)) = i;
128 }
129
130
131 int
LRMI_init(void)132 LRMI_init(void)
133 {
134 void *m;
135
136 if (context.ready)
137 return 1;
138
139 if (!LRMI_common_init())
140 return 0;
141
142 /*
143 Allocate a stack
144 */
145 m = LRMI_alloc_real(DEFAULT_STACK_SIZE);
146
147 context.stack_seg = (unsigned int)m >> 4;
148 context.stack_off = DEFAULT_STACK_SIZE;
149
150 /*
151 Allocate the return to 32 bit routine
152 */
153 m = LRMI_alloc_real(2);
154
155 context.ret_seg = (unsigned int)m >> 4;
156 context.ret_off = (unsigned int)m & 0xf;
157
158 ((unsigned char *)m)[0] = 0xcd; /* int opcode */
159 ((unsigned char *)m)[1] = RETURN_TO_32_INT;
160
161 memset(&context.vm, 0, sizeof(context.vm));
162
163 /*
164 Enable kernel emulation of all ints except RETURN_TO_32_INT
165 */
166 #if defined(__linux__)
167 memset(&context.vm.int_revectored, 0, sizeof(context.vm.int_revectored));
168 set_bit(RETURN_TO_32_INT, &context.vm.int_revectored);
169 #elif defined(__NetBSD__)
170 set_bit(RETURN_TO_32_INT, &context.vm.int_byuser);
171 #elif defined(__FreeBSD__)
172 set_bit(RETURN_TO_32_INT, &context.vm.init.int_map);
173 #endif
174
175 context.ready = 1;
176
177 return 1;
178 }
179
180
181 static void
set_regs(struct LRMI_regs * r)182 set_regs(struct LRMI_regs *r)
183 {
184 CONTEXT_REGS.REG(edi) = r->edi;
185 CONTEXT_REGS.REG(esi) = r->esi;
186 CONTEXT_REGS.REG(ebp) = r->ebp;
187 CONTEXT_REGS.REG(ebx) = r->ebx;
188 CONTEXT_REGS.REG(edx) = r->edx;
189 CONTEXT_REGS.REG(ecx) = r->ecx;
190 CONTEXT_REGS.REG(eax) = r->eax;
191 CONTEXT_REGS.REG(eflags) = DEFAULT_VM86_FLAGS;
192 CONTEXT_REGS.REG(es) = r->es;
193 CONTEXT_REGS.REG(ds) = r->ds;
194 CONTEXT_REGS.REG(fs) = r->fs;
195 CONTEXT_REGS.REG(gs) = r->gs;
196 }
197
198
199 static void
get_regs(struct LRMI_regs * r)200 get_regs(struct LRMI_regs *r)
201 {
202 r->edi = CONTEXT_REGS.REG(edi);
203 r->esi = CONTEXT_REGS.REG(esi);
204 r->ebp = CONTEXT_REGS.REG(ebp);
205 r->ebx = CONTEXT_REGS.REG(ebx);
206 r->edx = CONTEXT_REGS.REG(edx);
207 r->ecx = CONTEXT_REGS.REG(ecx);
208 r->eax = CONTEXT_REGS.REG(eax);
209 r->flags = CONTEXT_REGS.REG(eflags);
210 r->es = CONTEXT_REGS.REG(es);
211 r->ds = CONTEXT_REGS.REG(ds);
212 r->fs = CONTEXT_REGS.REG(fs);
213 r->gs = CONTEXT_REGS.REG(gs);
214 }
215
216 #define DIRECTION_FLAG (1 << 10)
217
218 enum {
219 CSEG = 0x2e, SSEG = 0x36, DSEG = 0x3e,
220 ESEG = 0x26, FSEG = 0x64, GSEG = 0x65
221 };
222
223 static void
em_ins(int size)224 em_ins(int size)
225 {
226 unsigned int edx, edi;
227
228 edx = CONTEXT_REGS.REG(edx) & 0xffff;
229 edi = CONTEXT_REGS.REG(edi) & 0xffff;
230 edi += (unsigned int)CONTEXT_REGS.REG(es) << 4;
231
232 if (CONTEXT_REGS.REG(eflags) & DIRECTION_FLAG) {
233 if (size == 4)
234 asm volatile ("std; insl; cld"
235 : "=D" (edi) : "d" (edx), "0" (edi));
236 else if (size == 2)
237 asm volatile ("std; insw; cld"
238 : "=D" (edi) : "d" (edx), "0" (edi));
239 else
240 asm volatile ("std; insb; cld"
241 : "=D" (edi) : "d" (edx), "0" (edi));
242 } else {
243 if (size == 4)
244 asm volatile ("cld; insl"
245 : "=D" (edi) : "d" (edx), "0" (edi));
246 else if (size == 2)
247 asm volatile ("cld; insw"
248 : "=D" (edi) : "d" (edx), "0" (edi));
249 else
250 asm volatile ("cld; insb"
251 : "=D" (edi) : "d" (edx), "0" (edi));
252 }
253
254 edi -= (unsigned int)CONTEXT_REGS.REG(es) << 4;
255
256 CONTEXT_REGS.REG(edi) &= 0xffff0000;
257 CONTEXT_REGS.REG(edi) |= edi & 0xffff;
258 }
259
260 static void
em_rep_ins(int size)261 em_rep_ins(int size)
262 {
263 unsigned int cx;
264
265 cx = CONTEXT_REGS.REG(ecx) & 0xffff;
266
267 while (cx--)
268 em_ins(size);
269
270 CONTEXT_REGS.REG(ecx) &= 0xffff0000;
271 }
272
273 static void
em_outs(int size,int seg)274 em_outs(int size, int seg)
275 {
276 unsigned int edx, esi, base;
277
278 edx = CONTEXT_REGS.REG(edx) & 0xffff;
279 esi = CONTEXT_REGS.REG(esi) & 0xffff;
280
281 switch (seg) {
282 case CSEG: base = CONTEXT_REGS.REG(cs); break;
283 case SSEG: base = CONTEXT_REGS.REG(ss); break;
284 case ESEG: base = CONTEXT_REGS.REG(es); break;
285 case FSEG: base = CONTEXT_REGS.REG(fs); break;
286 case GSEG: base = CONTEXT_REGS.REG(gs); break;
287 default:
288 case DSEG: base = CONTEXT_REGS.REG(ds); break;
289 }
290
291 esi += base << 4;
292
293 if (CONTEXT_REGS.REG(eflags) & DIRECTION_FLAG) {
294 if (size == 4)
295 asm volatile ("std; outsl; cld"
296 : "=S" (esi) : "d" (edx), "0" (esi));
297 else if (size == 2)
298 asm volatile ("std; outsw; cld"
299 : "=S" (esi) : "d" (edx), "0" (esi));
300 else
301 asm volatile ("std; outsb; cld"
302 : "=S" (esi) : "d" (edx), "0" (esi));
303 } else {
304 if (size == 4)
305 asm volatile ("cld; outsl"
306 : "=S" (esi) : "d" (edx), "0" (esi));
307 else if (size == 2)
308 asm volatile ("cld; outsw"
309 : "=S" (esi) : "d" (edx), "0" (esi));
310 else
311 asm volatile ("cld; outsb"
312 : "=S" (esi) : "d" (edx), "0" (esi));
313 }
314
315 esi -= base << 4;
316
317 CONTEXT_REGS.REG(esi) &= 0xffff0000;
318 CONTEXT_REGS.REG(esi) |= esi & 0xffff;
319 }
320
321 static void
em_rep_outs(int size,int seg)322 em_rep_outs(int size, int seg)
323 {
324 unsigned int cx;
325
326 cx = CONTEXT_REGS.REG(ecx) & 0xffff;
327
328 while (cx--)
329 em_outs(size, seg);
330
331 CONTEXT_REGS.REG(ecx) &= 0xffff0000;
332 }
333
334 static void
em_inbl(unsigned char literal)335 em_inbl(unsigned char literal)
336 {
337 asm volatile ("inb %w1, %b0"
338 : "=a" (CONTEXT_REGS.REG(eax))
339 : "d" (literal), "0" (CONTEXT_REGS.REG(eax)));
340 }
341
342 static void
em_inb(void)343 em_inb(void)
344 {
345 asm volatile ("inb %w1, %b0"
346 : "=a" (CONTEXT_REGS.REG(eax))
347 : "d" (CONTEXT_REGS.REG(edx)), "0" (CONTEXT_REGS.REG(eax)));
348 }
349
350 static void
em_inw(void)351 em_inw(void)
352 {
353 asm volatile ("inw %w1, %w0"
354 : "=a" (CONTEXT_REGS.REG(eax))
355 : "d" (CONTEXT_REGS.REG(edx)), "0" (CONTEXT_REGS.REG(eax)));
356 }
357
358 static void
em_inl(void)359 em_inl(void)
360 {
361 asm volatile ("inl %w1, %0"
362 : "=a" (CONTEXT_REGS.REG(eax))
363 : "d" (CONTEXT_REGS.REG(edx)));
364 }
365
366 static void
em_outbl(unsigned char literal)367 em_outbl(unsigned char literal)
368 {
369 asm volatile ("outb %b0, %w1"
370 : : "a" (CONTEXT_REGS.REG(eax)),
371 "d" (literal));
372 }
373
374 static void
em_outb(void)375 em_outb(void)
376 {
377 asm volatile ("outb %b0, %w1"
378 : : "a" (CONTEXT_REGS.REG(eax)),
379 "d" (CONTEXT_REGS.REG(edx)));
380 }
381
382 static void
em_outw(void)383 em_outw(void)
384 {
385 asm volatile ("outw %w0, %w1"
386 : : "a" (CONTEXT_REGS.REG(eax)),
387 "d" (CONTEXT_REGS.REG(edx)));
388 }
389
390 static void
em_outl(void)391 em_outl(void)
392 {
393 asm volatile ("outl %0, %w1"
394 : : "a" (CONTEXT_REGS.REG(eax)),
395 "d" (CONTEXT_REGS.REG(edx)));
396 }
397
398 static int
emulate(void)399 emulate(void)
400 {
401 unsigned char *insn;
402 struct {
403 unsigned char seg;
404 unsigned int size : 1;
405 unsigned int rep : 1;
406 } prefix = { DSEG, 0, 0 };
407 int i = 0;
408
409 insn = (unsigned char *)((unsigned int)CONTEXT_REGS.REG(cs) << 4);
410 insn += CONTEXT_REGS.REG(eip);
411
412 while (1) {
413 if (insn[i] == 0x66) {
414 prefix.size = 1 - prefix.size;
415 i++;
416 } else if (insn[i] == 0xf3) {
417 prefix.rep = 1;
418 i++;
419 } else if (insn[i] == CSEG || insn[i] == SSEG
420 || insn[i] == DSEG || insn[i] == ESEG
421 || insn[i] == FSEG || insn[i] == GSEG) {
422 prefix.seg = insn[i];
423 i++;
424 } else if (insn[i] == 0xf0 || insn[i] == 0xf2
425 || insn[i] == 0x67) {
426 /* these prefixes are just ignored */
427 i++;
428 } else if (insn[i] == 0x6c) {
429 if (prefix.rep)
430 em_rep_ins(1);
431 else
432 em_ins(1);
433 i++;
434 break;
435 } else if (insn[i] == 0x6d) {
436 if (prefix.rep) {
437 if (prefix.size)
438 em_rep_ins(4);
439 else
440 em_rep_ins(2);
441 } else {
442 if (prefix.size)
443 em_ins(4);
444 else
445 em_ins(2);
446 }
447 i++;
448 break;
449 } else if (insn[i] == 0x6e) {
450 if (prefix.rep)
451 em_rep_outs(1, prefix.seg);
452 else
453 em_outs(1, prefix.seg);
454 i++;
455 break;
456 } else if (insn[i] == 0x6f) {
457 if (prefix.rep) {
458 if (prefix.size)
459 em_rep_outs(4, prefix.seg);
460 else
461 em_rep_outs(2, prefix.seg);
462 } else {
463 if (prefix.size)
464 em_outs(4, prefix.seg);
465 else
466 em_outs(2, prefix.seg);
467 }
468 i++;
469 break;
470 } else if (insn[i] == 0xe4) {
471 em_inbl(insn[i + 1]);
472 i += 2;
473 break;
474 } else if (insn[i] == 0xec) {
475 em_inb();
476 i++;
477 break;
478 } else if (insn[i] == 0xed) {
479 if (prefix.size)
480 em_inl();
481 else
482 em_inw();
483 i++;
484 break;
485 } else if (insn[i] == 0xe6) {
486 em_outbl(insn[i + 1]);
487 i += 2;
488 break;
489 } else if (insn[i] == 0xee) {
490 em_outb();
491 i++;
492 break;
493 } else if (insn[i] == 0xef) {
494 if (prefix.size)
495 em_outl();
496 else
497 em_outw();
498
499 i++;
500 break;
501 } else
502 return 0;
503 }
504
505 CONTEXT_REGS.REG(eip) += i;
506 return 1;
507 }
508
509
510 #if defined(__linux__)
511 /*
512 I don't know how to make sure I get the right vm86() from libc.
513 The one I want is syscall # 113 (vm86old() in libc 5, vm86() in glibc)
514 which should be declared as "int vm86(struct vm86_struct *);" in
515 <sys/vm86.h>.
516
517 This just does syscall 113 with inline asm, which should work
518 for both libc's (I hope).
519 */
520 #if !defined(USE_LIBC_VM86)
521 static int
lrmi_vm86(struct vm86_struct * vm)522 lrmi_vm86(struct vm86_struct *vm)
523 {
524 int r;
525 #ifdef __PIC__
526 asm volatile (
527 "pushl %%ebx\n\t"
528 "movl %2, %%ebx\n\t"
529 "int $0x80\n\t"
530 "popl %%ebx"
531 : "=a" (r)
532 : "0" (113), "r" (vm));
533 #else
534 asm volatile (
535 "int $0x80"
536 : "=a" (r)
537 : "0" (113), "b" (vm));
538 #endif
539 return r;
540 }
541 #else
542 #define lrmi_vm86 vm86
543 #endif
544 #endif /* __linux__ */
545
546
547 static void
debug_info(int vret)548 debug_info(int vret)
549 {
550 #ifdef LRMI_DEBUG
551 int i;
552 unsigned char *p;
553
554 fputs("vm86() failed\n", stderr);
555 fprintf(stderr, "return = 0x%x\n", vret);
556 fprintf(stderr, "eax = 0x%08x\n", CONTEXT_REGS.REG(eax));
557 fprintf(stderr, "ebx = 0x%08x\n", CONTEXT_REGS.REG(ebx));
558 fprintf(stderr, "ecx = 0x%08x\n", CONTEXT_REGS.REG(ecx));
559 fprintf(stderr, "edx = 0x%08x\n", CONTEXT_REGS.REG(edx));
560 fprintf(stderr, "esi = 0x%08x\n", CONTEXT_REGS.REG(esi));
561 fprintf(stderr, "edi = 0x%08x\n", CONTEXT_REGS.REG(edi));
562 fprintf(stderr, "ebp = 0x%08x\n", CONTEXT_REGS.REG(ebp));
563 fprintf(stderr, "eip = 0x%08x\n", CONTEXT_REGS.REG(eip));
564 fprintf(stderr, "cs = 0x%04x\n", CONTEXT_REGS.REG(cs));
565 fprintf(stderr, "esp = 0x%08x\n", CONTEXT_REGS.REG(esp));
566 fprintf(stderr, "ss = 0x%04x\n", CONTEXT_REGS.REG(ss));
567 fprintf(stderr, "ds = 0x%04x\n", CONTEXT_REGS.REG(ds));
568 fprintf(stderr, "es = 0x%04x\n", CONTEXT_REGS.REG(es));
569 fprintf(stderr, "fs = 0x%04x\n", CONTEXT_REGS.REG(fs));
570 fprintf(stderr, "gs = 0x%04x\n", CONTEXT_REGS.REG(gs));
571 fprintf(stderr, "eflags = 0x%08x\n", CONTEXT_REGS.REG(eflags));
572
573 fputs("cs:ip = [ ", stderr);
574
575 p = (unsigned char *)((CONTEXT_REGS.REG(cs) << 4) + (CONTEXT_REGS.REG(eip) & 0xffff));
576
577 for (i = 0; i < 16; ++i)
578 fprintf(stderr, "%02x ", (unsigned int)p[i]);
579
580 fputs("]\n", stderr);
581 #endif
582 }
583
584
585 #if defined(__linux__)
586 static int
run_vm86(void)587 run_vm86(void)
588 {
589 unsigned int vret;
590
591 while (1) {
592 vret = lrmi_vm86(&context.vm);
593
594 if (VM86_TYPE(vret) == VM86_INTx) {
595 unsigned int v = VM86_ARG(vret);
596
597 if (v == RETURN_TO_32_INT)
598 return 1;
599
600 /* fprintf(stderr, "Calling INT 0x%X (%04X:%04X)\n",
601 v,
602 get_int_seg(v),
603 get_int_off(v));
604 fprintf(stderr, " EAX is 0x%lX\n",
605 CONTEXT_REGS.REG(eax));
606 */
607 pushw(CONTEXT_REGS.REG(eflags));
608 pushw(CONTEXT_REGS.REG(cs));
609 pushw(CONTEXT_REGS.REG(eip));
610
611 CONTEXT_REGS.REG(cs) = get_int_seg(v);
612 CONTEXT_REGS.REG(eip) = get_int_off(v);
613 CONTEXT_REGS.REG(eflags) &= ~(VIF_MASK | TF_MASK);
614
615 continue;
616 }
617
618 if (VM86_TYPE(vret) != VM86_UNKNOWN)
619 break;
620
621 if (!emulate())
622 break;
623 }
624
625 debug_info(vret);
626
627 return 0;
628 }
629 #elif defined(__NetBSD__) || defined(__FreeBSD__)
630 #if defined(__NetBSD__)
631 static void
vm86_callback(int sig,int code,struct sigcontext * sc)632 vm86_callback(int sig, int code, struct sigcontext *sc)
633 {
634 /* Sync our context with what the kernel develivered to us. */
635 memcpy(&CONTEXT_REGS, sc, sizeof(*sc));
636
637 switch (VM86_TYPE(code)) {
638 case VM86_INTx:
639 {
640 unsigned int v = VM86_ARG(code);
641
642 if (v == RETURN_TO_32_INT) {
643 context.success = 1;
644 longjmp(context.env, 1);
645 }
646
647 pushw(CONTEXT_REGS.REG(eflags));
648 pushw(CONTEXT_REGS.REG(cs));
649 pushw(CONTEXT_REGS.REG(eip));
650
651 CONTEXT_REGS.REG(cs) = get_int_seg(v);
652 CONTEXT_REGS.REG(eip) = get_int_off(v);
653 CONTEXT_REGS.REG(eflags) &= ~(VIF_MASK | TF_MASK);
654
655 break;
656 }
657
658 case VM86_UNKNOWN:
659 if (emulate() == 0) {
660 context.success = 0;
661 context.vret = code;
662 longjmp(context.env, 1);
663 }
664 break;
665
666 default:
667 context.success = 0;
668 context.vret = code;
669 longjmp(context.env, 1);
670 return;
671 }
672
673 /* ...and sync our context back to the kernel. */
674 memcpy(sc, &CONTEXT_REGS, sizeof(*sc));
675 }
676 #elif defined(__FreeBSD__)
677 static void
vm86_callback(int sig,int code,struct sigcontext * sc)678 vm86_callback(int sig, int code, struct sigcontext *sc)
679 {
680 unsigned char *addr;
681
682 /* Sync our context with what the kernel develivered to us. */
683 memcpy(&CONTEXT_REGS, sc, sizeof(*sc));
684
685 if (code) {
686 /* XXX probably need to call original signal handler here */
687 context.success = 0;
688 context.vret = code;
689 longjmp(context.env, 1);
690 }
691
692 addr = (unsigned char *)((CONTEXT_REGS.REG(cs) << 4) +
693 CONTEXT_REGS.REG(eip));
694
695 if (addr[0] == 0xcd) { /* int opcode */
696 if (addr[1] == RETURN_TO_32_INT) {
697 context.success = 1;
698 longjmp(context.env, 1);
699 }
700
701 pushw(CONTEXT_REGS.REG(eflags));
702 pushw(CONTEXT_REGS.REG(cs));
703 pushw(CONTEXT_REGS.REG(eip));
704
705 CONTEXT_REGS.REG(cs) = get_int_seg(addr[1]);
706 CONTEXT_REGS.REG(eip) = get_int_off(addr[1]);
707 CONTEXT_REGS.REG(eflags) &= ~(VIF_MASK | TF_MASK);
708 } else {
709 if (emulate() == 0) {
710 context.success = 0;
711 longjmp(context.env, 1);
712 }
713 }
714
715 /* ...and sync our context back to the kernel. */
716 memcpy(sc, &CONTEXT_REGS, sizeof(*sc));
717 }
718 #endif /* __FreeBSD__ */
719
720 static int
run_vm86(void)721 run_vm86(void)
722 {
723 if (context.old_sighandler) {
724 #ifdef LRMI_DEBUG
725 fprintf(stderr, "run_vm86: callback already installed\n");
726 #endif
727 return (0);
728 }
729
730 #if defined(__NetBSD__)
731 context.old_sighandler = signal(SIGURG, (void (*)(int))vm86_callback);
732 #elif defined(__FreeBSD__)
733 context.old_sighandler = signal(SIGBUS, (void (*)(int))vm86_callback);
734 #endif
735
736 if (context.old_sighandler == (void *)-1) {
737 context.old_sighandler = NULL;
738 #ifdef LRMI_DEBUG
739 fprintf(stderr, "run_vm86: cannot install callback\n");
740 #endif
741 return (0);
742 }
743
744 if (setjmp(context.env)) {
745 #if defined(__NetBSD__)
746 (void) signal(SIGURG, context.old_sighandler);
747 #elif defined(__FreeBSD__)
748 (void) signal(SIGBUS, context.old_sighandler);
749 #endif
750 context.old_sighandler = NULL;
751
752 if (context.success)
753 return (1);
754 debug_info(context.vret);
755 return (0);
756 }
757
758 #if defined(__NetBSD__)
759 if (i386_vm86(&context.vm) == -1)
760 return (0);
761 #elif defined(__FreeBSD__)
762 if (i386_vm86(VM86_INIT, &context.vm.init))
763 return 0;
764
765 CONTEXT_REGS.REG(eflags) |= PSL_VM | PSL_VIF;
766 sigreturn(&context.vm.uc);
767 #endif /* __FreeBSD__ */
768
769 /* NOTREACHED */
770 return (0);
771 }
772 #endif /* __NetBSD__ || __FreeBSD__ */
773
774 int
LRMI_call(struct LRMI_regs * r)775 LRMI_call(struct LRMI_regs *r)
776 {
777 unsigned int vret;
778
779 memset(&CONTEXT_REGS, 0, sizeof(CONTEXT_REGS));
780
781 set_regs(r);
782
783 CONTEXT_REGS.REG(cs) = r->cs;
784 CONTEXT_REGS.REG(eip) = r->ip;
785
786 if (r->ss == 0 && r->sp == 0) {
787 CONTEXT_REGS.REG(ss) = context.stack_seg;
788 CONTEXT_REGS.REG(esp) = context.stack_off;
789 } else {
790 CONTEXT_REGS.REG(ss) = r->ss;
791 CONTEXT_REGS.REG(esp) = r->sp;
792 }
793
794 pushw(context.ret_seg);
795 pushw(context.ret_off);
796
797 vret = run_vm86();
798
799 get_regs(r);
800
801 return vret;
802 }
803
804
805 int
LRMI_int(int i,struct LRMI_regs * r)806 LRMI_int(int i, struct LRMI_regs *r)
807 {
808 unsigned int vret;
809 unsigned int seg, off;
810
811 seg = get_int_seg(i);
812 off = get_int_off(i);
813
814 /*
815 If the interrupt is in regular memory, it's probably
816 still pointing at a dos TSR (which is now gone).
817 */
818 if (seg < 0xa000 || (seg << 4) + off >= 0x100000) {
819 #ifdef LRMI_DEBUG
820 fprintf(stderr, "Int 0x%x is not in rom (%04x:%04x)\n", i, seg, off);
821 #endif
822 return 0;
823 }
824
825 memset(&CONTEXT_REGS, 0, sizeof(CONTEXT_REGS));
826
827 set_regs(r);
828
829 CONTEXT_REGS.REG(cs) = seg;
830 CONTEXT_REGS.REG(eip) = off;
831
832 if (r->ss == 0 && r->sp == 0) {
833 CONTEXT_REGS.REG(ss) = context.stack_seg;
834 CONTEXT_REGS.REG(esp) = context.stack_off;
835 } else {
836 CONTEXT_REGS.REG(ss) = r->ss;
837 CONTEXT_REGS.REG(esp) = r->sp;
838 }
839
840 pushw(DEFAULT_VM86_FLAGS);
841 pushw(context.ret_seg);
842 pushw(context.ret_off);
843
844 vret = run_vm86();
845
846 get_regs(r);
847
848 return vret;
849 }
850
851 size_t
LRMI_base_addr(void)852 LRMI_base_addr(void)
853 {
854 return 0;
855 }
856