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