debuggers.hg

view tools/firmware/vmxassist/vm86.c @ 6641:f27205ea60ef

merge?
author cl349@firebug.cl.cam.ac.uk
date Sat Sep 03 16:58:50 2005 +0000 (2005-09-03)
parents dd668f7527cb ed474440decd
children 29808fef9148 b6c98fe62e1a
line source
1 /*
2 * vm86.c: A vm86 emulator. The main purpose of this emulator is to do as
3 * little work as possible.
4 *
5 * Leendert van Doorn, leendert@watson.ibm.com
6 * Copyright (c) 2005, International Business Machines Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place - Suite 330, Boston, MA 02111-1307 USA.
20 */
21 #include "vm86.h"
22 #include "util.h"
23 #include "machine.h"
25 #define HIGHMEM (1 << 20) /* 1MB */
26 #define MASK16(v) ((v) & 0xFFFF)
28 #define DATA32 0x0001
29 #define ADDR32 0x0002
30 #define SEG_CS 0x0004
31 #define SEG_DS 0x0008
32 #define SEG_ES 0x0010
33 #define SEG_SS 0x0020
34 #define SEG_FS 0x0040
35 #define SEG_GS 0x0080
37 unsigned prev_eip = 0;
38 enum vm86_mode mode;
40 #ifdef DEBUG
41 int traceset = 0;
43 char *states[] = {
44 "<VM86_REAL>",
45 "<VM86_REAL_TO_PROTECTED>",
46 "<VM86_PROTECTED_TO_REAL>",
47 "<VM86_PROTECTED>"
48 };
49 #endif /* DEBUG */
52 unsigned
53 address(struct regs *regs, unsigned seg, unsigned off)
54 {
55 unsigned long long entry;
56 unsigned addr;
58 /* real mode: segment is part of the address */
59 if (mode == VM86_REAL || mode == VM86_REAL_TO_PROTECTED)
60 return ((seg & 0xFFFF) << 4) + off;
62 /* protected mode: use seg as index into gdt */
63 if (seg > oldctx.gdtr_limit) {
64 printf("address: Invalid segment descriptor (0x%x)\n", seg);
65 return 0;
66 }
68 entry = ((unsigned long long *) oldctx.gdtr_base)[seg >> 3];
69 addr = (((entry >> (56-24)) & 0xFF000000) |
70 ((entry >> (32-16)) & 0x00FF0000) |
71 ((entry >> ( 16)) & 0x0000FFFF)) + off;
72 return addr;
73 }
75 #ifdef DEBUG
76 void
77 trace(struct regs *regs, int adjust, char *fmt, ...)
78 {
79 unsigned off = regs->eip - adjust;
80 va_list ap;
82 if ((traceset & (1 << mode)) &&
83 (mode == VM86_REAL_TO_PROTECTED || mode == VM86_REAL)) {
84 /* 16-bit, seg:off addressing */
85 unsigned addr = address(regs, regs->cs, off);
86 printf("0x%08x: 0x%x:0x%04x ", addr, regs->cs, off);
87 printf("(%d) ", mode);
88 va_start(ap, fmt);
89 vprintf(fmt, ap);
90 va_end(ap);
91 printf("\n");
92 }
93 if ((traceset & (1 << mode)) &&
94 (mode == VM86_PROTECTED_TO_REAL || mode == VM86_PROTECTED)) {
95 /* 16-bit, gdt addressing */
96 unsigned addr = address(regs, regs->cs, off);
97 printf("0x%08x: 0x%x:0x%08x ", addr, regs->cs, off);
98 printf("(%d) ", mode);
99 va_start(ap, fmt);
100 vprintf(fmt, ap);
101 va_end(ap);
102 printf("\n");
103 }
104 }
105 #endif /* DEBUG */
107 static inline unsigned
108 read32(unsigned addr)
109 {
110 return *(unsigned long *) addr;
111 }
113 static inline unsigned
114 read16(unsigned addr)
115 {
116 return *(unsigned short *) addr;
117 }
119 static inline unsigned
120 read8(unsigned addr)
121 {
122 return *(unsigned char *) addr;
123 }
125 static inline void
126 write32(unsigned addr, unsigned value)
127 {
128 *(unsigned long *) addr = value;
129 }
131 static inline void
132 write16(unsigned addr, unsigned value)
133 {
134 *(unsigned short *) addr = value;
135 }
137 static inline void
138 write8(unsigned addr, unsigned value)
139 {
140 *(unsigned char *) addr = value;
141 }
143 static inline void
144 push32(struct regs *regs, unsigned value)
145 {
146 regs->uesp -= 4;
147 write32(address(regs, regs->uss, MASK16(regs->uesp)), value);
148 }
150 static inline void
151 push16(struct regs *regs, unsigned value)
152 {
153 regs->uesp -= 2;
154 write16(address(regs, regs->uss, MASK16(regs->uesp)), value);
155 }
157 static inline unsigned
158 pop32(struct regs *regs)
159 {
160 unsigned value = read32(address(regs, regs->uss, MASK16(regs->uesp)));
161 regs->uesp += 4;
162 return value;
163 }
165 static inline unsigned
166 pop16(struct regs *regs)
167 {
168 unsigned value = read16(address(regs, regs->uss, MASK16(regs->uesp)));
169 regs->uesp += 2;
170 return value;
171 }
173 static inline unsigned
174 fetch32(struct regs *regs)
175 {
176 unsigned addr = address(regs, regs->cs, MASK16(regs->eip));
178 regs->eip += 4;
179 return read32(addr);
180 }
182 static inline unsigned
183 fetch16(struct regs *regs)
184 {
185 unsigned addr = address(regs, regs->cs, MASK16(regs->eip));
187 regs->eip += 2;
188 return read16(addr);
189 }
191 static inline unsigned
192 fetch8(struct regs *regs)
193 {
194 unsigned addr = address(regs, regs->cs, MASK16(regs->eip));
196 regs->eip++;
197 return read8(addr);
198 }
200 unsigned
201 getreg(struct regs *regs, int r)
202 {
203 switch (r & 7) {
204 case 0: return regs->eax;
205 case 1: return regs->ecx;
206 case 2: return regs->edx;
207 case 3: return regs->ebx;
208 case 4: return regs->esp;
209 case 5: return regs->ebp;
210 case 6: return regs->esi;
211 case 7: return regs->edi;
212 }
213 return ~0;
214 }
216 void
217 setreg(struct regs *regs, int r, unsigned v)
218 {
219 switch (r & 7) {
220 case 0: regs->eax = v; break;
221 case 1: regs->ecx = v; break;
222 case 2: regs->edx = v; break;
223 case 3: regs->ebx = v; break;
224 case 4: regs->esp = v; break;
225 case 5: regs->ebp = v; break;
226 case 6: regs->esi = v; break;
227 case 7: regs->edi = v; break;
228 }
229 }
231 /*
232 * Operand (modrm) decode
233 */
234 unsigned
235 operand(unsigned prefix, struct regs *regs, unsigned modrm)
236 {
237 int mod, disp = 0, seg;
239 seg = regs->vds;
240 if (prefix & SEG_ES)
241 seg = regs->ves;
242 if (prefix & SEG_DS)
243 seg = regs->vds;
244 if (prefix & SEG_CS)
245 seg = regs->cs;
246 if (prefix & SEG_SS)
247 seg = regs->uss;
248 if (prefix & SEG_FS)
249 seg = regs->fs;
250 if (prefix & SEG_GS)
251 seg = regs->gs;
253 if (prefix & ADDR32) { /* 32-bit addressing */
254 switch ((mod = (modrm >> 6) & 3)) {
255 case 0:
256 switch (modrm & 7) {
257 case 0: return address(regs, seg, regs->eax);
258 case 1: return address(regs, seg, regs->ecx);
259 case 2: return address(regs, seg, regs->edx);
260 case 3: return address(regs, seg, regs->ebx);
261 case 4: panic("No SIB decode (yet)");
262 case 5: return address(regs, seg, fetch32(regs));
263 case 6: return address(regs, seg, regs->esi);
264 case 7: return address(regs, seg, regs->edi);
265 }
266 break;
267 case 1:
268 case 2:
269 if ((modrm & 7) != 4) {
270 if (mod == 1)
271 disp = (char) fetch8(regs);
272 else
273 disp = (int) fetch32(regs);
274 }
275 switch (modrm & 7) {
276 case 0: return address(regs, seg, regs->eax + disp);
277 case 1: return address(regs, seg, regs->ecx + disp);
278 case 2: return address(regs, seg, regs->edx + disp);
279 case 3: return address(regs, seg, regs->ebx + disp);
280 case 4: panic("No SIB decode (yet)");
281 case 5: return address(regs, seg, regs->ebp + disp);
282 case 6: return address(regs, seg, regs->esi + disp);
283 case 7: return address(regs, seg, regs->edi + disp);
284 }
285 break;
286 case 3:
287 return getreg(regs, modrm);
288 }
289 } else { /* 16-bit addressing */
290 switch ((mod = (modrm >> 6) & 3)) {
291 case 0:
292 switch (modrm & 7) {
293 case 0: return address(regs, seg, MASK16(regs->ebx) +
294 MASK16(regs->esi));
295 case 1: return address(regs, seg, MASK16(regs->ebx) +
296 MASK16(regs->edi));
297 case 2: return address(regs, seg, MASK16(regs->ebp) +
298 MASK16(regs->esi));
299 case 3: return address(regs, seg, MASK16(regs->ebp) +
300 MASK16(regs->edi));
301 case 4: return address(regs, seg, MASK16(regs->esi));
302 case 5: return address(regs, seg, MASK16(regs->edi));
303 case 6: return address(regs, seg, fetch16(regs));
304 case 7: return address(regs, seg, MASK16(regs->ebx));
305 }
306 break;
307 case 1:
308 case 2:
309 if (mod == 1)
310 disp = (char) fetch8(regs);
311 else
312 disp = (int) fetch16(regs);
313 switch (modrm & 7) {
314 case 0: return address(regs, seg, MASK16(regs->ebx) +
315 MASK16(regs->esi) + disp);
316 case 1: return address(regs, seg, MASK16(regs->ebx) +
317 MASK16(regs->edi) + disp);
318 case 2: return address(regs, seg, MASK16(regs->ebp) +
319 MASK16(regs->esi) + disp);
320 case 3: return address(regs, seg, MASK16(regs->ebp) +
321 MASK16(regs->edi) + disp);
322 case 4: return address(regs, seg,
323 MASK16(regs->esi) + disp);
324 case 5: return address(regs, seg,
325 MASK16(regs->edi) + disp);
326 case 6: return address(regs, seg,
327 MASK16(regs->ebp) + disp);
328 case 7: return address(regs, seg,
329 MASK16(regs->ebx) + disp);
330 }
331 break;
332 case 3:
333 return MASK16(getreg(regs, modrm));
334 }
335 }
337 return 0;
338 }
340 /*
341 * Load new IDT
342 */
343 int
344 lidt(struct regs *regs, unsigned prefix, unsigned modrm)
345 {
346 unsigned eip = regs->eip - 3;
347 unsigned addr = operand(prefix, regs, modrm);
349 oldctx.idtr_limit = ((struct dtr *) addr)->size;
350 if ((prefix & DATA32) == 0)
351 oldctx.idtr_base = ((struct dtr *) addr)->base & 0xFFFFFF;
352 else
353 oldctx.idtr_base = ((struct dtr *) addr)->base;
354 TRACE((regs, regs->eip - eip, "lidt 0x%x <%d, 0x%x>",
355 addr, oldctx.idtr_limit, oldctx.idtr_base));
357 return 1;
358 }
360 /*
361 * Load new GDT
362 */
363 int
364 lgdt(struct regs *regs, unsigned prefix, unsigned modrm)
365 {
366 unsigned eip = regs->eip - 3;
367 unsigned addr = operand(prefix, regs, modrm);
369 oldctx.gdtr_limit = ((struct dtr *) addr)->size;
370 if ((prefix & DATA32) == 0)
371 oldctx.gdtr_base = ((struct dtr *) addr)->base & 0xFFFFFF;
372 else
373 oldctx.gdtr_base = ((struct dtr *) addr)->base;
374 TRACE((regs, regs->eip - eip, "lgdt 0x%x <%d, 0x%x>",
375 addr, oldctx.gdtr_limit, oldctx.gdtr_base));
377 return 1;
378 }
380 /*
381 * Modify CR0 either through an lmsw instruction.
382 */
383 int
384 lmsw(struct regs *regs, unsigned prefix, unsigned modrm)
385 {
386 unsigned eip = regs->eip - 3;
387 unsigned ax = operand(prefix, regs, modrm) & 0xF;
388 unsigned cr0 = (oldctx.cr0 & 0xFFFFFFF0) | ax;
390 TRACE((regs, regs->eip - eip, "lmsw 0x%x", ax));
391 #ifndef TEST
392 oldctx.cr0 = cr0 | CR0_PE | CR0_NE;
393 #else
394 oldctx.cr0 = cr0 | CR0_PE | CR0_NE | CR0_PG;
395 #endif
396 if (cr0 & CR0_PE)
397 set_mode(regs, VM86_REAL_TO_PROTECTED);
399 return 1;
400 }
402 /*
403 * Move to and from a control register.
404 */
405 int
406 movcr(struct regs *regs, unsigned prefix, unsigned opc)
407 {
408 unsigned eip = regs->eip - 2;
409 unsigned modrm = fetch8(regs);
410 unsigned cr = (modrm >> 3) & 7;
412 if ((modrm & 0xC0) != 0xC0) /* only registers */
413 return 0;
415 switch (opc) {
416 case 0x20: /* mov Rd, Cd */
417 TRACE((regs, regs->eip - eip, "movl %%cr%d, %%eax", cr));
418 switch (cr) {
419 case 0:
420 #ifndef TEST
421 setreg(regs, modrm,
422 oldctx.cr0 & ~(CR0_PE | CR0_NE));
423 #else
424 setreg(regs, modrm,
425 oldctx.cr0 & ~(CR0_PE | CR0_NE | CR0_PG));
426 #endif
427 break;
428 case 2:
429 setreg(regs, modrm, get_cr2());
430 break;
431 case 3:
432 setreg(regs, modrm, oldctx.cr3);
433 break;
434 case 4:
435 setreg(regs, modrm, oldctx.cr4);
436 break;
437 }
438 break;
439 case 0x22: /* mov Cd, Rd */
440 TRACE((regs, regs->eip - eip, "movl %%eax, %%cr%d", cr));
441 switch (cr) {
442 case 0:
443 oldctx.cr0 = getreg(regs, modrm) | (CR0_PE | CR0_NE);
444 #ifdef TEST
445 oldctx.cr0 |= CR0_PG;
446 #endif
447 if (getreg(regs, modrm) & CR0_PE)
448 set_mode(regs, VM86_REAL_TO_PROTECTED);
450 break;
451 case 3:
452 oldctx.cr3 = getreg(regs, modrm);
453 break;
454 case 4:
455 oldctx.cr4 = getreg(regs, modrm);
456 break;
457 }
458 break;
459 }
461 return 1;
462 }
464 /*
465 * Emulate a segment load in protected mode
466 */
467 int
468 load_seg(unsigned long sel, u32 *base, u32 *limit, union vmcs_arbytes *arbytes)
469 {
470 unsigned long long entry;
472 /* protected mode: use seg as index into gdt */
473 if (sel == 0 || sel > oldctx.gdtr_limit)
474 return 0;
476 entry = ((unsigned long long *) oldctx.gdtr_base)[sel >> 3];
477 *base = (((entry >> (56-24)) & 0xFF000000) |
478 ((entry >> (32-16)) & 0x00FF0000) |
479 ((entry >> ( 16)) & 0x0000FFFF));
480 *limit = (((entry >> (48-16)) & 0x000F0000) |
481 ((entry ) & 0x0000FFFF));
483 arbytes->bytes = 0;
484 arbytes->fields.seg_type = (entry >> (8+32)) & 0xF; /* TYPE */
485 arbytes->fields.s = (entry >> (12+32)) & 0x1; /* S */
486 if (arbytes->fields.s)
487 arbytes->fields.seg_type |= 1; /* accessed */
488 arbytes->fields.dpl = (entry >> (13+32)) & 0x3; /* DPL */
489 arbytes->fields.p = (entry >> (15+32)) & 0x1; /* P */
490 arbytes->fields.avl = (entry >> (20+32)) & 0x1; /* AVL */
491 arbytes->fields.default_ops_size = (entry >> (22+32)) & 0x1; /* D */
493 if (entry & (1ULL << (23+32))) { /* G */
494 arbytes->fields.g = 1;
495 *limit = (*limit << 12) | 0xFFF;
496 }
498 return 1;
499 }
501 /*
502 * Transition to protected mode
503 */
504 void
505 protected_mode(struct regs *regs)
506 {
507 regs->eflags &= ~(EFLAGS_TF|EFLAGS_VM);
509 oldctx.eip = regs->eip;
510 oldctx.esp = regs->uesp;
511 oldctx.eflags = regs->eflags;
513 /* reload all segment registers */
514 if (!load_seg(regs->cs, &oldctx.cs_base,
515 &oldctx.cs_limit, &oldctx.cs_arbytes))
516 panic("Invalid %%cs=0x%x for protected mode\n", regs->cs);
517 oldctx.cs_sel = regs->cs;
519 if (load_seg(regs->ves, &oldctx.es_base,
520 &oldctx.es_limit, &oldctx.es_arbytes))
521 oldctx.es_sel = regs->ves;
523 if (load_seg(regs->uss, &oldctx.ss_base,
524 &oldctx.ss_limit, &oldctx.ss_arbytes))
525 oldctx.ss_sel = regs->uss;
527 if (load_seg(regs->vds, &oldctx.ds_base,
528 &oldctx.ds_limit, &oldctx.ds_arbytes))
529 oldctx.ds_sel = regs->vds;
531 if (load_seg(regs->vfs, &oldctx.fs_base,
532 &oldctx.fs_limit, &oldctx.fs_arbytes))
533 oldctx.fs_sel = regs->vfs;
535 if (load_seg(regs->vgs, &oldctx.gs_base,
536 &oldctx.gs_limit, &oldctx.gs_arbytes))
537 oldctx.gs_sel = regs->vgs;
539 /* initialize jump environment to warp back to protected mode */
540 regs->cs = CODE_SELECTOR;
541 regs->ds = DATA_SELECTOR;
542 regs->es = DATA_SELECTOR;
543 regs->fs = DATA_SELECTOR;
544 regs->gs = DATA_SELECTOR;
545 regs->eip = (unsigned) &switch_to_protected_mode;
547 /* this should get us into 32-bit mode */
548 }
550 /*
551 * Start real-mode emulation
552 */
553 void
554 real_mode(struct regs *regs)
555 {
556 regs->eflags |= EFLAGS_VM | 0x02;
557 regs->ds = DATA_SELECTOR;
558 regs->es = DATA_SELECTOR;
559 regs->fs = DATA_SELECTOR;
560 regs->gs = DATA_SELECTOR;
562 /*
563 * When we transition from protected to real-mode and we
564 * have not reloaded the segment descriptors yet, they are
565 * interpreted as if they were in protect mode.
566 * We emulate this behavior by assuming that these memory
567 * reference are below 1MB and set %ss, %ds, %es accordingly.
568 */
569 if (regs->uss != 0) {
570 if (regs->uss >= HIGHMEM)
571 panic("%%ss 0x%lx higher than 1MB", regs->uss);
572 regs->uss = address(regs, regs->uss, 0) >> 4;
573 }
574 if (regs->vds != 0) {
575 if (regs->vds >= HIGHMEM)
576 panic("%%ds 0x%lx higher than 1MB", regs->vds);
577 regs->vds = address(regs, regs->vds, 0) >> 4;
578 }
579 if (regs->ves != 0) {
580 if (regs->ves >= HIGHMEM)
581 panic("%%es 0x%lx higher than 1MB", regs->ves);
582 regs->ves = address(regs, regs->ves, 0) >> 4;
583 }
585 /* this should get us into 16-bit mode */
586 }
588 /*
589 * This is the smarts of the emulator and handles the mode transitions. The
590 * emulator handles 4 different modes. 1) VM86_REAL: emulated real-mode, Just
591 * handle those instructions that are not supported under VM8086.
592 * 2) VM86_REAL_TO_PROTECTED: going from real-mode to protected mode. In this
593 * we single step through the instructions until we reload the new %cs (some
594 * OSes do a lot of computations before reloading %cs). 2) VM86_PROTECTED_TO_REAL
595 * when we are going from protected to real mode. In this case we emulate the
596 * instructions by hand. Finally, 4) VM86_PROTECTED when we transitioned to
597 * protected mode and we should abandon the emulator. No instructions are
598 * emulated when in VM86_PROTECTED mode.
599 */
600 void
601 set_mode(struct regs *regs, enum vm86_mode newmode)
602 {
603 switch (newmode) {
604 case VM86_REAL:
605 if (mode == VM86_PROTECTED_TO_REAL) {
606 real_mode(regs);
607 break;
608 } else if (mode == VM86_REAL) {
609 break;
610 } else
611 panic("unexpected real mode transition");
612 break;
614 case VM86_REAL_TO_PROTECTED:
615 if (mode == VM86_REAL) {
616 regs->eflags |= EFLAGS_TF;
617 break;
618 } else if (mode == VM86_REAL_TO_PROTECTED) {
619 break;
620 } else
621 panic("unexpected real-to-protected mode transition");
622 break;
624 case VM86_PROTECTED_TO_REAL:
625 if (mode == VM86_PROTECTED)
626 break;
627 else
628 panic("unexpected protected-to-real mode transition");
630 case VM86_PROTECTED:
631 if (mode == VM86_REAL_TO_PROTECTED) {
632 protected_mode(regs);
633 break;
634 } else
635 panic("unexpected protected mode transition");
636 break;
637 }
639 mode = newmode;
640 TRACE((regs, 0, states[mode]));
641 }
643 void
644 jmpl(struct regs *regs, int prefix)
645 {
646 unsigned n = regs->eip;
647 unsigned cs, eip;
649 if (mode == VM86_REAL_TO_PROTECTED) { /* jump to protected mode */
650 eip = (prefix & DATA32) ? fetch32(regs) : fetch16(regs);
651 cs = fetch16(regs);
653 TRACE((regs, (regs->eip - n) + 1, "jmpl 0x%x:0x%x", cs, eip));
655 regs->cs = cs;
656 regs->eip = eip;
657 set_mode(regs, VM86_PROTECTED);
658 } else if (mode == VM86_PROTECTED_TO_REAL) { /* jump to real mode */
659 eip = (prefix & DATA32) ? fetch32(regs) : fetch16(regs);
660 cs = fetch16(regs);
662 TRACE((regs, (regs->eip - n) + 1, "jmpl 0x%x:0x%x", cs, eip));
664 regs->cs = cs;
665 regs->eip = eip;
666 set_mode(regs, VM86_REAL);
667 } else
668 panic("jmpl");
669 }
671 void
672 retl(struct regs *regs, int prefix)
673 {
674 unsigned cs, eip;
676 if (prefix & DATA32) {
677 eip = pop32(regs);
678 cs = MASK16(pop32(regs));
679 } else {
680 eip = pop16(regs);
681 cs = pop16(regs);
682 }
684 TRACE((regs, 1, "retl (to 0x%x:0x%x)", cs, eip));
686 if (mode == VM86_REAL_TO_PROTECTED) { /* jump to protected mode */
687 regs->cs = cs;
688 regs->eip = eip;
689 set_mode(regs, VM86_PROTECTED);
690 } else if (mode == VM86_PROTECTED_TO_REAL) { /* jump to real mode */
691 regs->cs = cs;
692 regs->eip = eip;
693 set_mode(regs, VM86_REAL);
694 } else
695 panic("retl");
696 }
698 void
699 interrupt(struct regs *regs, int n)
700 {
701 TRACE((regs, 0, "external interrupt %d", n));
702 push16(regs, regs->eflags);
703 push16(regs, regs->cs);
704 push16(regs, regs->eip);
705 regs->eflags &= ~EFLAGS_IF;
706 regs->eip = read16(address(regs, 0, n * 4));
707 regs->cs = read16(address(regs, 0, n * 4 + 2));
708 }
710 enum { OPC_INVALID, OPC_EMULATED };
712 /*
713 * Emulate a single instruction, including all its prefixes. We only implement
714 * a small subset of the opcodes, and not all opcodes are implemented for each
715 * of the four modes we can operate in.
716 */
717 int
718 opcode(struct regs *regs)
719 {
720 unsigned eip = regs->eip;
721 unsigned opc, modrm, disp;
722 unsigned prefix = 0;
724 for (;;) {
725 switch ((opc = fetch8(regs))) {
726 case 0x0F: /* two byte opcode */
727 if (mode == VM86_PROTECTED)
728 goto invalid;
729 switch ((opc = fetch8(regs))) {
730 case 0x01:
731 switch (((modrm = fetch8(regs)) >> 3) & 7) {
732 case 0: /* sgdt */
733 case 1: /* sidt */
734 goto invalid;
735 case 2: /* lgdt */
736 if (!lgdt(regs, prefix, modrm))
737 goto invalid;
738 return OPC_EMULATED;
739 case 3: /* lidt */
740 if (!lidt(regs, prefix, modrm))
741 goto invalid;
742 return OPC_EMULATED;
743 case 4: /* smsw */
744 goto invalid;
745 case 5:
746 goto invalid;
747 case 6: /* lmsw */
748 if (!lmsw(regs, prefix, modrm))
749 goto invalid;
750 return OPC_EMULATED;
751 case 7: /* invlpg */
752 goto invalid;
753 }
754 break;
755 case 0x20: /* mov Rd, Cd (1h) */
756 case 0x22:
757 if (!movcr(regs, prefix, opc))
758 goto invalid;
759 return OPC_EMULATED;
760 default:
761 goto invalid;
762 }
763 goto invalid;
765 case 0x26:
766 TRACE((regs, regs->eip - eip, "%%es:"));
767 prefix |= SEG_ES;
768 continue;
770 case 0x2E:
771 TRACE((regs, regs->eip - eip, "%%cs:"));
772 prefix |= SEG_CS;
773 continue;
775 case 0x36:
776 TRACE((regs, regs->eip - eip, "%%ss:"));
777 prefix |= SEG_SS;
778 continue;
780 case 0x3E:
781 TRACE((regs, regs->eip - eip, "%%ds:"));
782 prefix |= SEG_DS;
783 continue;
785 case 0x64:
786 TRACE((regs, regs->eip - eip, "%%fs:"));
787 prefix |= SEG_FS;
788 continue;
790 case 0x65:
791 TRACE((regs, regs->eip - eip, "%%gs:"));
792 prefix |= SEG_GS;
793 continue;
795 case 0x66:
796 TRACE((regs, regs->eip - eip, "data32"));
797 prefix |= DATA32;
798 continue;
800 case 0x67:
801 TRACE((regs, regs->eip - eip, "addr32"));
802 prefix |= ADDR32;
803 continue;
805 case 0x90: /* nop */
806 TRACE((regs, regs->eip - eip, "nop"));
807 return OPC_EMULATED;
809 case 0x9C: /* pushf */
810 TRACE((regs, regs->eip - eip, "pushf"));
811 if (prefix & DATA32)
812 push32(regs, regs->eflags & ~EFLAGS_VM);
813 else
814 push16(regs, regs->eflags & ~EFLAGS_VM);
815 return OPC_EMULATED;
817 case 0x9D: /* popf */
818 TRACE((regs, regs->eip - eip, "popf"));
819 if (prefix & DATA32)
820 regs->eflags = pop32(regs);
821 else
822 regs->eflags = (regs->eflags & 0xFFFF0000L) |
823 pop16(regs);
824 regs->eflags |= EFLAGS_VM;
825 return OPC_EMULATED;
827 case 0xCB: /* retl */
828 if ((mode == VM86_REAL_TO_PROTECTED) ||
829 (mode == VM86_PROTECTED_TO_REAL)) {
830 retl(regs, prefix);
831 return OPC_EMULATED;
832 }
833 goto invalid;
835 case 0xCD: /* int $n */
836 TRACE((regs, regs->eip - eip, "int"));
837 interrupt(regs, fetch8(regs));
838 return OPC_EMULATED;
840 case 0xCF: /* iret */
841 if (prefix & DATA32) {
842 TRACE((regs, regs->eip - eip, "data32 iretd"));
843 regs->eip = pop32(regs);
844 regs->cs = pop32(regs);
845 regs->eflags = pop32(regs);
846 } else {
847 TRACE((regs, regs->eip - eip, "iret"));
848 regs->eip = pop16(regs);
849 regs->cs = pop16(regs);
850 regs->eflags = (regs->eflags & 0xFFFF0000L) |
851 pop16(regs);
852 }
853 return OPC_EMULATED;
855 case 0xEA: /* jmpl */
856 if ((mode == VM86_REAL_TO_PROTECTED) ||
857 (mode == VM86_PROTECTED_TO_REAL)) {
858 jmpl(regs, prefix);
859 return OPC_EMULATED;
860 }
861 goto invalid;
863 case 0xEB: /* short jump */
864 if ((mode == VM86_REAL_TO_PROTECTED) ||
865 (mode == VM86_PROTECTED_TO_REAL)) {
866 disp = (char) fetch8(regs);
867 TRACE((regs, 2, "jmp 0x%x", regs->eip + disp));
868 regs->eip += disp;
869 return OPC_EMULATED;
870 }
871 goto invalid;
873 case 0xF0: /* lock */
874 TRACE((regs, regs->eip - eip, "lock"));
875 continue;
877 case 0xFA: /* cli */
878 TRACE((regs, regs->eip - eip, "cli"));
879 regs->eflags &= ~EFLAGS_IF;
880 return OPC_EMULATED;
882 case 0xFB: /* sti */
883 TRACE((regs, regs->eip - eip, "sti"));
884 regs->eflags |= EFLAGS_IF;
885 return OPC_EMULATED;
887 default:
888 goto invalid;
889 }
890 }
892 invalid:
893 regs->eip = eip;
894 return OPC_INVALID;
895 }
897 void
898 emulate(struct regs *regs)
899 {
900 unsigned flteip;
901 int nemul = 0;
903 /* emulate as many instructions as possible */
904 while (opcode(regs) != OPC_INVALID)
905 nemul++;
907 /* detect the case where we are not making progress */
908 if (nemul == 0 && prev_eip == regs->eip) {
909 flteip = address(regs, MASK16(regs->cs), regs->eip);
910 panic("Unknown opcode at %04x:%04x=0x%x",
911 MASK16(regs->cs), regs->eip, flteip);
912 } else
913 prev_eip = regs->eip;
914 }
916 void
917 trap(int trapno, int errno, struct regs *regs)
918 {
919 /* emulate device interrupts */
920 if (trapno >= NR_EXCEPTION_HANDLER) {
921 int irq = trapno - NR_EXCEPTION_HANDLER;
922 if (irq < 8)
923 interrupt(regs, irq + 8);
924 else
925 interrupt(regs, 0x70 + (irq - 8));
926 return;
927 }
929 switch (trapno) {
930 case 1: /* Debug */
931 if (regs->eflags & EFLAGS_VM) {
932 /* emulate any 8086 instructions */
933 if (mode != VM86_REAL_TO_PROTECTED)
934 panic("not in real-to-protected mode");
935 emulate(regs);
936 return;
937 }
938 goto invalid;
940 case 13: /* GPF */
941 if (regs->eflags & EFLAGS_VM) {
942 /* emulate any 8086 instructions */
943 if (mode == VM86_PROTECTED)
944 panic("unexpected protected mode");
945 emulate(regs);
946 return;
947 }
948 goto invalid;
950 default:
951 invalid:
952 printf("Trap (0x%x) while in %s mode\n",
953 trapno, regs->eflags & EFLAGS_VM ? "real" : "protected");
954 if (trapno == 14)
955 printf("Page fault address 0x%x\n", get_cr2());
956 dump_regs(regs);
957 halt();
958 }
959 }