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