Commit d8bc1fd0aeb0423074b5063c8dc94dddd7285321
1 parent
7501267e
ring 0 ops
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@254 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
4 changed files
with
469 additions
and
51 deletions
exec-i386.h
... | ... | @@ -123,6 +123,11 @@ typedef struct CCTable { |
123 | 123 | extern CCTable cc_table[]; |
124 | 124 | |
125 | 125 | void load_seg(int seg_reg, int selector, unsigned cur_eip); |
126 | +void jmp_seg(int selector, unsigned int new_eip); | |
127 | +void helper_lldt_T0(void); | |
128 | +void helper_ltr_T0(void); | |
129 | +void helper_movl_crN_T0(int reg); | |
130 | +void helper_movl_drN_T0(int reg); | |
126 | 131 | void __hidden cpu_lock(void); |
127 | 132 | void __hidden cpu_unlock(void); |
128 | 133 | void raise_interrupt(int intno, int is_int, int error_code, | ... | ... |
helper-i386.c
... | ... | @@ -157,7 +157,7 @@ void raise_interrupt(int intno, int is_int, int error_code, |
157 | 157 | break; |
158 | 158 | } |
159 | 159 | dpl = (e2 >> DESC_DPL_SHIFT) & 3; |
160 | - cpl = env->segs[R_CS] & 3; | |
160 | + cpl = env->segs[R_CS].selector & 3; | |
161 | 161 | /* check privledge if software int */ |
162 | 162 | if (is_int && dpl < cpl) |
163 | 163 | raise_exception_err(EXCP0D_GPF, intno * 8 + 2); |
... | ... | @@ -176,7 +176,7 @@ void raise_interrupt(int intno, int is_int, int error_code, |
176 | 176 | void raise_interrupt(int intno, int is_int, int error_code, |
177 | 177 | unsigned int next_eip) |
178 | 178 | { |
179 | - SegmentDescriptorTable *dt; | |
179 | + SegmentCache *dt; | |
180 | 180 | uint8_t *ptr; |
181 | 181 | int dpl, cpl; |
182 | 182 | uint32_t e2; |
... | ... | @@ -331,21 +331,98 @@ void helper_cpuid(void) |
331 | 331 | } |
332 | 332 | } |
333 | 333 | |
334 | +static inline void load_seg_cache(SegmentCache *sc, uint32_t e1, uint32_t e2) | |
335 | +{ | |
336 | + sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); | |
337 | + sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000); | |
338 | + if (e2 & (1 << 23)) | |
339 | + sc->limit = (sc->limit << 12) | 0xfff; | |
340 | + sc->seg_32bit = (e2 >> 22) & 1; | |
341 | +} | |
342 | + | |
343 | +void helper_lldt_T0(void) | |
344 | +{ | |
345 | + int selector; | |
346 | + SegmentCache *dt; | |
347 | + uint32_t e1, e2; | |
348 | + int index; | |
349 | + uint8_t *ptr; | |
350 | + | |
351 | + selector = T0 & 0xffff; | |
352 | + if ((selector & 0xfffc) == 0) { | |
353 | + /* XXX: NULL selector case: invalid LDT */ | |
354 | + env->ldt.base = NULL; | |
355 | + env->ldt.limit = 0; | |
356 | + } else { | |
357 | + if (selector & 0x4) | |
358 | + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
359 | + dt = &env->gdt; | |
360 | + index = selector & ~7; | |
361 | + if ((index + 7) > dt->limit) | |
362 | + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
363 | + ptr = dt->base + index; | |
364 | + e1 = ldl(ptr); | |
365 | + e2 = ldl(ptr + 4); | |
366 | + if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) | |
367 | + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
368 | + if (!(e2 & DESC_P_MASK)) | |
369 | + raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); | |
370 | + load_seg_cache(&env->ldt, e1, e2); | |
371 | + } | |
372 | + env->ldt.selector = selector; | |
373 | +} | |
374 | + | |
375 | +void helper_ltr_T0(void) | |
376 | +{ | |
377 | + int selector; | |
378 | + SegmentCache *dt; | |
379 | + uint32_t e1, e2; | |
380 | + int index, type; | |
381 | + uint8_t *ptr; | |
382 | + | |
383 | + selector = T0 & 0xffff; | |
384 | + if ((selector & 0xfffc) == 0) { | |
385 | + /* XXX: NULL selector case: invalid LDT */ | |
386 | + env->tr.base = NULL; | |
387 | + env->tr.limit = 0; | |
388 | + } else { | |
389 | + if (selector & 0x4) | |
390 | + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
391 | + dt = &env->gdt; | |
392 | + index = selector & ~7; | |
393 | + if ((index + 7) > dt->limit) | |
394 | + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
395 | + ptr = dt->base + index; | |
396 | + e1 = ldl(ptr); | |
397 | + e2 = ldl(ptr + 4); | |
398 | + type = (e2 >> DESC_TYPE_SHIFT) & 0xf; | |
399 | + if ((e2 & DESC_S_MASK) || | |
400 | + (type != 2 && type != 9)) | |
401 | + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
402 | + if (!(e2 & DESC_P_MASK)) | |
403 | + raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); | |
404 | + load_seg_cache(&env->tr, e1, e2); | |
405 | + e2 |= 0x00000200; /* set the busy bit */ | |
406 | + stl(ptr + 4, e2); | |
407 | + } | |
408 | + env->tr.selector = selector; | |
409 | +} | |
410 | + | |
334 | 411 | /* only works if protected mode and not VM86 */ |
335 | -void load_seg(int seg_reg, int selector, unsigned cur_eip) | |
412 | +void load_seg(int seg_reg, int selector, unsigned int cur_eip) | |
336 | 413 | { |
337 | 414 | SegmentCache *sc; |
338 | - SegmentDescriptorTable *dt; | |
415 | + SegmentCache *dt; | |
339 | 416 | int index; |
340 | 417 | uint32_t e1, e2; |
341 | 418 | uint8_t *ptr; |
342 | - | |
343 | - sc = &env->seg_cache[seg_reg]; | |
419 | + | |
420 | + sc = &env->segs[seg_reg]; | |
344 | 421 | if ((selector & 0xfffc) == 0) { |
345 | 422 | /* null selector case */ |
346 | 423 | if (seg_reg == R_SS) { |
347 | 424 | EIP = cur_eip; |
348 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
425 | + raise_exception_err(EXCP0D_GPF, 0); | |
349 | 426 | } else { |
350 | 427 | /* XXX: each access should trigger an exception */ |
351 | 428 | sc->base = NULL; |
... | ... | @@ -390,18 +467,93 @@ void load_seg(int seg_reg, int selector, unsigned cur_eip) |
390 | 467 | else |
391 | 468 | raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); |
392 | 469 | } |
393 | - | |
394 | - sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); | |
395 | - sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000); | |
396 | - if (e2 & (1 << 23)) | |
397 | - sc->limit = (sc->limit << 12) | 0xfff; | |
398 | - sc->seg_32bit = (e2 >> 22) & 1; | |
470 | + load_seg_cache(sc, e1, e2); | |
399 | 471 | #if 0 |
400 | 472 | fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx seg_32bit=%d\n", |
401 | 473 | selector, (unsigned long)sc->base, sc->limit, sc->seg_32bit); |
402 | 474 | #endif |
403 | 475 | } |
404 | - env->segs[seg_reg] = selector; | |
476 | + sc->selector = selector; | |
477 | +} | |
478 | + | |
479 | +/* protected mode jump */ | |
480 | +void jmp_seg(int selector, unsigned int new_eip) | |
481 | +{ | |
482 | + SegmentCache sc1; | |
483 | + SegmentCache *dt; | |
484 | + int index; | |
485 | + uint32_t e1, e2, cpl, dpl, rpl; | |
486 | + uint8_t *ptr; | |
487 | + | |
488 | + if ((selector & 0xfffc) == 0) { | |
489 | + raise_exception_err(EXCP0D_GPF, 0); | |
490 | + } | |
491 | + | |
492 | + if (selector & 0x4) | |
493 | + dt = &env->ldt; | |
494 | + else | |
495 | + dt = &env->gdt; | |
496 | + index = selector & ~7; | |
497 | + if ((index + 7) > dt->limit) | |
498 | + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
499 | + ptr = dt->base + index; | |
500 | + e1 = ldl(ptr); | |
501 | + e2 = ldl(ptr + 4); | |
502 | + cpl = env->segs[R_CS].selector & 3; | |
503 | + if (e2 & DESC_S_MASK) { | |
504 | + if (!(e2 & DESC_CS_MASK)) | |
505 | + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
506 | + dpl = (e2 >> DESC_DPL_SHIFT) & 3; | |
507 | + if (e2 & DESC_CS_MASK) { | |
508 | + /* conforming code segment */ | |
509 | + if (dpl > cpl) | |
510 | + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
511 | + } else { | |
512 | + /* non conforming code segment */ | |
513 | + rpl = selector & 3; | |
514 | + if (rpl > cpl) | |
515 | + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
516 | + if (dpl != cpl) | |
517 | + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
518 | + } | |
519 | + if (!(e2 & DESC_P_MASK)) | |
520 | + raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); | |
521 | + load_seg_cache(&sc1, e1, e2); | |
522 | + if (new_eip > sc1.limit) | |
523 | + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
524 | + env->segs[R_CS] = sc1; | |
525 | + env->segs[R_CS].selector = (selector & 0xfffc) | cpl; | |
526 | + EIP = new_eip; | |
527 | + } else { | |
528 | + cpu_abort(env, "jmp to call/task gate not supported 0x%04x:0x%08x", | |
529 | + selector, new_eip); | |
530 | + } | |
531 | +} | |
532 | + | |
533 | +/* XXX: do more */ | |
534 | +void helper_movl_crN_T0(int reg) | |
535 | +{ | |
536 | + switch(reg) { | |
537 | + case 0: | |
538 | + default: | |
539 | + env->cr[0] = reg; | |
540 | + break; | |
541 | + case 2: | |
542 | + env->cr[2] = reg; | |
543 | + break; | |
544 | + case 3: | |
545 | + env->cr[3] = reg; | |
546 | + break; | |
547 | + case 4: | |
548 | + env->cr[4] = reg; | |
549 | + break; | |
550 | + } | |
551 | +} | |
552 | + | |
553 | +/* XXX: do more */ | |
554 | +void helper_movl_drN_T0(int reg) | |
555 | +{ | |
556 | + env->dr[reg] = T0; | |
405 | 557 | } |
406 | 558 | |
407 | 559 | /* rdtsc */ |
... | ... | @@ -425,7 +577,7 @@ void helper_rdtsc(void) |
425 | 577 | void helper_lsl(void) |
426 | 578 | { |
427 | 579 | unsigned int selector, limit; |
428 | - SegmentDescriptorTable *dt; | |
580 | + SegmentCache *dt; | |
429 | 581 | int index; |
430 | 582 | uint32_t e1, e2; |
431 | 583 | uint8_t *ptr; |
... | ... | @@ -452,7 +604,7 @@ void helper_lsl(void) |
452 | 604 | void helper_lar(void) |
453 | 605 | { |
454 | 606 | unsigned int selector; |
455 | - SegmentDescriptorTable *dt; | |
607 | + SegmentCache *dt; | |
456 | 608 | int index; |
457 | 609 | uint32_t e2; |
458 | 610 | uint8_t *ptr; | ... | ... |
op-i386.c
... | ... | @@ -357,6 +357,11 @@ void OPPROTO op_andl_T0_ffff(void) |
357 | 357 | T0 = T0 & 0xffff; |
358 | 358 | } |
359 | 359 | |
360 | +void OPPROTO op_andl_T0_im(void) | |
361 | +{ | |
362 | + T0 = T0 & PARAM1; | |
363 | +} | |
364 | + | |
360 | 365 | void OPPROTO op_movl_T0_T1(void) |
361 | 366 | { |
362 | 367 | T0 = T1; |
... | ... | @@ -665,7 +670,7 @@ void op_pushl_ss32_T0(void) |
665 | 670 | { |
666 | 671 | uint32_t offset; |
667 | 672 | offset = ESP - 4; |
668 | - stl(env->seg_cache[R_SS].base + offset, T0); | |
673 | + stl(env->segs[R_SS].base + offset, T0); | |
669 | 674 | /* modify ESP after to handle exceptions correctly */ |
670 | 675 | ESP = offset; |
671 | 676 | } |
... | ... | @@ -674,7 +679,7 @@ void op_pushw_ss32_T0(void) |
674 | 679 | { |
675 | 680 | uint32_t offset; |
676 | 681 | offset = ESP - 2; |
677 | - stw(env->seg_cache[R_SS].base + offset, T0); | |
682 | + stw(env->segs[R_SS].base + offset, T0); | |
678 | 683 | /* modify ESP after to handle exceptions correctly */ |
679 | 684 | ESP = offset; |
680 | 685 | } |
... | ... | @@ -683,7 +688,7 @@ void op_pushl_ss16_T0(void) |
683 | 688 | { |
684 | 689 | uint32_t offset; |
685 | 690 | offset = (ESP - 4) & 0xffff; |
686 | - stl(env->seg_cache[R_SS].base + offset, T0); | |
691 | + stl(env->segs[R_SS].base + offset, T0); | |
687 | 692 | /* modify ESP after to handle exceptions correctly */ |
688 | 693 | ESP = (ESP & ~0xffff) | offset; |
689 | 694 | } |
... | ... | @@ -692,7 +697,7 @@ void op_pushw_ss16_T0(void) |
692 | 697 | { |
693 | 698 | uint32_t offset; |
694 | 699 | offset = (ESP - 2) & 0xffff; |
695 | - stw(env->seg_cache[R_SS].base + offset, T0); | |
700 | + stw(env->segs[R_SS].base + offset, T0); | |
696 | 701 | /* modify ESP after to handle exceptions correctly */ |
697 | 702 | ESP = (ESP & ~0xffff) | offset; |
698 | 703 | } |
... | ... | @@ -710,22 +715,22 @@ void op_popw_T0(void) |
710 | 715 | |
711 | 716 | void op_popl_ss32_T0(void) |
712 | 717 | { |
713 | - T0 = ldl(env->seg_cache[R_SS].base + ESP); | |
718 | + T0 = ldl(env->segs[R_SS].base + ESP); | |
714 | 719 | } |
715 | 720 | |
716 | 721 | void op_popw_ss32_T0(void) |
717 | 722 | { |
718 | - T0 = lduw(env->seg_cache[R_SS].base + ESP); | |
723 | + T0 = lduw(env->segs[R_SS].base + ESP); | |
719 | 724 | } |
720 | 725 | |
721 | 726 | void op_popl_ss16_T0(void) |
722 | 727 | { |
723 | - T0 = ldl(env->seg_cache[R_SS].base + (ESP & 0xffff)); | |
728 | + T0 = ldl(env->segs[R_SS].base + (ESP & 0xffff)); | |
724 | 729 | } |
725 | 730 | |
726 | 731 | void op_popw_ss16_T0(void) |
727 | 732 | { |
728 | - T0 = lduw(env->seg_cache[R_SS].base + (ESP & 0xffff)); | |
733 | + T0 = lduw(env->segs[R_SS].base + (ESP & 0xffff)); | |
729 | 734 | } |
730 | 735 | |
731 | 736 | void op_addl_ESP_4(void) |
... | ... | @@ -909,17 +914,18 @@ void OPPROTO op_movl_seg_T0(void) |
909 | 914 | void OPPROTO op_movl_seg_T0_vm(void) |
910 | 915 | { |
911 | 916 | int selector; |
917 | + SegmentCache *sc; | |
912 | 918 | |
913 | 919 | selector = T0 & 0xffff; |
914 | 920 | /* env->segs[] access */ |
915 | - *(uint32_t *)((char *)env + PARAM1) = selector; | |
916 | - /* env->seg_cache[] access */ | |
917 | - ((SegmentCache *)((char *)env + PARAM2))->base = (void *)(selector << 4); | |
921 | + sc = (SegmentCache *)((char *)env + PARAM1); | |
922 | + sc->selector = selector; | |
923 | + sc->base = (void *)(selector << 4); | |
918 | 924 | } |
919 | 925 | |
920 | 926 | void OPPROTO op_movl_T0_seg(void) |
921 | 927 | { |
922 | - T0 = env->segs[PARAM1]; | |
928 | + T0 = env->segs[PARAM1].selector; | |
923 | 929 | } |
924 | 930 | |
925 | 931 | void OPPROTO op_movl_A0_seg(void) |
... | ... | @@ -942,6 +948,61 @@ void OPPROTO op_lar(void) |
942 | 948 | helper_lar(); |
943 | 949 | } |
944 | 950 | |
951 | +/* T0: segment, T1:eip */ | |
952 | +void OPPROTO op_ljmp_T0_T1(void) | |
953 | +{ | |
954 | + jmp_seg(T0 & 0xffff, T1); | |
955 | +} | |
956 | + | |
957 | +void OPPROTO op_lldt_T0(void) | |
958 | +{ | |
959 | + helper_lldt_T0(); | |
960 | +} | |
961 | + | |
962 | +void OPPROTO op_ltr_T0(void) | |
963 | +{ | |
964 | + helper_ltr_T0(); | |
965 | +} | |
966 | + | |
967 | +/* CR registers access */ | |
968 | +void OPPROTO op_movl_crN_T0(void) | |
969 | +{ | |
970 | + helper_movl_crN_T0(PARAM1); | |
971 | +} | |
972 | + | |
973 | +/* DR registers access */ | |
974 | +void OPPROTO op_movl_drN_T0(void) | |
975 | +{ | |
976 | + helper_movl_drN_T0(PARAM1); | |
977 | +} | |
978 | + | |
979 | +void OPPROTO op_lmsw_T0(void) | |
980 | +{ | |
981 | + /* only 4 lower bits of CR0 are modified */ | |
982 | + T0 = (env->cr[0] & ~0xf) | (T0 & 0xf); | |
983 | + helper_movl_crN_T0(0); | |
984 | +} | |
985 | + | |
986 | +void OPPROTO op_movl_T0_env(void) | |
987 | +{ | |
988 | + T0 = *(uint32_t *)((char *)env + PARAM1); | |
989 | +} | |
990 | + | |
991 | +void OPPROTO op_movl_env_T0(void) | |
992 | +{ | |
993 | + *(uint32_t *)((char *)env + PARAM1) = T0; | |
994 | +} | |
995 | + | |
996 | +void OPPROTO op_movl_env_T1(void) | |
997 | +{ | |
998 | + *(uint32_t *)((char *)env + PARAM1) = T1; | |
999 | +} | |
1000 | + | |
1001 | +void OPPROTO op_clts(void) | |
1002 | +{ | |
1003 | + env->cr[0] &= ~CR0_TS_MASK; | |
1004 | +} | |
1005 | + | |
945 | 1006 | /* flags handling */ |
946 | 1007 | |
947 | 1008 | /* slow jumps cases : in order to avoid calling a function with a | ... | ... |
translate-i386.c
... | ... | @@ -575,7 +575,7 @@ static inline void gen_string_ds(DisasContext *s, int ot, GenOpFunc **func) |
575 | 575 | if (s->addseg && override < 0) |
576 | 576 | override = R_DS; |
577 | 577 | if (override >= 0) { |
578 | - gen_op_movl_A0_seg(offsetof(CPUX86State,seg_cache[override].base)); | |
578 | + gen_op_movl_A0_seg(offsetof(CPUX86State,segs[override].base)); | |
579 | 579 | index = 3 + ot; |
580 | 580 | } else { |
581 | 581 | index = ot; |
... | ... | @@ -583,7 +583,7 @@ static inline void gen_string_ds(DisasContext *s, int ot, GenOpFunc **func) |
583 | 583 | } else { |
584 | 584 | if (override < 0) |
585 | 585 | override = R_DS; |
586 | - gen_op_movl_A0_seg(offsetof(CPUX86State,seg_cache[override].base)); | |
586 | + gen_op_movl_A0_seg(offsetof(CPUX86State,segs[override].base)); | |
587 | 587 | /* 16 address, always override */ |
588 | 588 | index = 6 + ot; |
589 | 589 | } |
... | ... | @@ -878,7 +878,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ |
878 | 878 | else |
879 | 879 | override = R_DS; |
880 | 880 | } |
881 | - gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base)); | |
881 | + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); | |
882 | 882 | } |
883 | 883 | } else { |
884 | 884 | switch (mod) { |
... | ... | @@ -944,7 +944,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ |
944 | 944 | else |
945 | 945 | override = R_DS; |
946 | 946 | } |
947 | - gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base)); | |
947 | + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); | |
948 | 948 | } |
949 | 949 | } |
950 | 950 | |
... | ... | @@ -1146,8 +1146,7 @@ static void gen_movl_seg_T0(DisasContext *s, int seg_reg, unsigned int cur_eip) |
1146 | 1146 | if (!s->vm86) |
1147 | 1147 | gen_op_movl_seg_T0(seg_reg, cur_eip); |
1148 | 1148 | else |
1149 | - gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[seg_reg]), | |
1150 | - offsetof(CPUX86State,seg_cache[seg_reg].base)); | |
1149 | + gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[seg_reg])); | |
1151 | 1150 | if (!s->addseg && seg_reg < R_FS) |
1152 | 1151 | s->is_jmp = 2; /* abort translation because the register may |
1153 | 1152 | have a non zero base */ |
... | ... | @@ -1230,7 +1229,7 @@ static void gen_stack_A0(DisasContext *s) |
1230 | 1229 | gen_op_andl_A0_ffff(); |
1231 | 1230 | gen_op_movl_T1_A0(); |
1232 | 1231 | if (s->addseg) |
1233 | - gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[R_SS].base)); | |
1232 | + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); | |
1234 | 1233 | } |
1235 | 1234 | |
1236 | 1235 | /* NOTE: wrap around in 16 bit not fully handled */ |
... | ... | @@ -1243,7 +1242,7 @@ static void gen_pusha(DisasContext *s) |
1243 | 1242 | gen_op_andl_A0_ffff(); |
1244 | 1243 | gen_op_movl_T1_A0(); |
1245 | 1244 | if (s->addseg) |
1246 | - gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[R_SS].base)); | |
1245 | + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); | |
1247 | 1246 | for(i = 0;i < 8; i++) { |
1248 | 1247 | gen_op_mov_TN_reg[OT_LONG][0][7 - i](); |
1249 | 1248 | gen_op_st_T0_A0[OT_WORD + s->dflag](); |
... | ... | @@ -1262,7 +1261,7 @@ static void gen_popa(DisasContext *s) |
1262 | 1261 | gen_op_movl_T1_A0(); |
1263 | 1262 | gen_op_addl_T1_im(16 << s->dflag); |
1264 | 1263 | if (s->addseg) |
1265 | - gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[R_SS].base)); | |
1264 | + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); | |
1266 | 1265 | for(i = 0;i < 8; i++) { |
1267 | 1266 | /* ESP is not reloaded */ |
1268 | 1267 | if (i != 3) { |
... | ... | @@ -1291,7 +1290,7 @@ static void gen_enter(DisasContext *s, int esp_addend, int level) |
1291 | 1290 | gen_op_andl_A0_ffff(); |
1292 | 1291 | gen_op_movl_T1_A0(); |
1293 | 1292 | if (s->addseg) |
1294 | - gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[R_SS].base)); | |
1293 | + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); | |
1295 | 1294 | /* push bp */ |
1296 | 1295 | gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); |
1297 | 1296 | gen_op_st_T0_A0[ot](); |
... | ... | @@ -1714,9 +1713,15 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
1714 | 1713 | gen_op_ld_T1_A0[ot](); |
1715 | 1714 | gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); |
1716 | 1715 | gen_op_lduw_T0_A0(); |
1717 | - gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); | |
1718 | - gen_op_movl_T0_T1(); | |
1719 | - gen_op_jmp_T0(); | |
1716 | + if (!s->vm86) { | |
1717 | + /* we compute EIP to handle the exception case */ | |
1718 | + gen_op_jmp_im(pc_start - s->cs_base); | |
1719 | + gen_op_ljmp_T0_T1(); | |
1720 | + } else { | |
1721 | + gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS])); | |
1722 | + gen_op_movl_T0_T1(); | |
1723 | + gen_op_jmp_T0(); | |
1724 | + } | |
1720 | 1725 | s->is_jmp = 1; |
1721 | 1726 | break; |
1722 | 1727 | case 6: /* push Ev */ |
... | ... | @@ -2085,7 +2090,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
2085 | 2090 | override = R_DS; |
2086 | 2091 | } |
2087 | 2092 | if (must_add_seg) { |
2088 | - gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base)); | |
2093 | + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); | |
2089 | 2094 | } |
2090 | 2095 | } |
2091 | 2096 | if ((b & 2) == 0) { |
... | ... | @@ -2113,7 +2118,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
2113 | 2118 | override = R_DS; |
2114 | 2119 | } |
2115 | 2120 | if (must_add_seg) { |
2116 | - gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base)); | |
2121 | + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); | |
2117 | 2122 | } |
2118 | 2123 | } |
2119 | 2124 | gen_op_ldub_T0_A0(); |
... | ... | @@ -2619,12 +2624,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
2619 | 2624 | break; |
2620 | 2625 | case 0x1c: |
2621 | 2626 | switch(rm) { |
2627 | + case 0: /* feni (287 only, just do nop here) */ | |
2628 | + break; | |
2629 | + case 1: /* fdisi (287 only, just do nop here) */ | |
2630 | + break; | |
2622 | 2631 | case 2: /* fclex */ |
2623 | 2632 | gen_op_fclex(); |
2624 | 2633 | break; |
2625 | 2634 | case 3: /* fninit */ |
2626 | 2635 | gen_op_fninit(); |
2627 | 2636 | break; |
2637 | + case 4: /* fsetpm (287 only, just do nop here) */ | |
2638 | + break; | |
2628 | 2639 | default: |
2629 | 2640 | goto illegal_op; |
2630 | 2641 | } |
... | ... | @@ -3011,8 +3022,15 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
3011 | 3022 | |
3012 | 3023 | /* change cs and pc */ |
3013 | 3024 | gen_op_movl_T0_im(selector); |
3014 | - gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); | |
3015 | - gen_op_jmp_im((unsigned long)offset); | |
3025 | + if (!s->vm86) { | |
3026 | + /* we compute EIP to handle the exception case */ | |
3027 | + gen_op_jmp_im(pc_start - s->cs_base); | |
3028 | + gen_op_movl_T1_im(offset); | |
3029 | + gen_op_ljmp_T0_T1(); | |
3030 | + } else { | |
3031 | + gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS])); | |
3032 | + gen_op_jmp_im((unsigned long)offset); | |
3033 | + } | |
3016 | 3034 | s->is_jmp = 1; |
3017 | 3035 | } |
3018 | 3036 | break; |
... | ... | @@ -3343,6 +3361,111 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
3343 | 3361 | /* XXX: if cpl == 0, then should do something else */ |
3344 | 3362 | gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
3345 | 3363 | break; |
3364 | + case 0x100: | |
3365 | + modrm = ldub(s->pc++); | |
3366 | + mod = (modrm >> 6) & 3; | |
3367 | + op = (modrm >> 3) & 7; | |
3368 | + switch(op) { | |
3369 | + case 0: /* sldt */ | |
3370 | + gen_op_movl_T0_env(offsetof(CPUX86State,ldt.selector)); | |
3371 | + ot = OT_WORD; | |
3372 | + if (mod == 3) | |
3373 | + ot += s->dflag; | |
3374 | + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); | |
3375 | + break; | |
3376 | + case 2: /* lldt */ | |
3377 | + if (s->cpl != 0) { | |
3378 | + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); | |
3379 | + } else { | |
3380 | + gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); | |
3381 | + gen_op_jmp_im(pc_start - s->cs_base); | |
3382 | + gen_op_lldt_T0(); | |
3383 | + } | |
3384 | + break; | |
3385 | + case 1: /* str */ | |
3386 | + gen_op_movl_T0_env(offsetof(CPUX86State,tr.selector)); | |
3387 | + ot = OT_WORD; | |
3388 | + if (mod == 3) | |
3389 | + ot += s->dflag; | |
3390 | + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); | |
3391 | + break; | |
3392 | + case 3: /* ltr */ | |
3393 | + if (s->cpl != 0) { | |
3394 | + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); | |
3395 | + } else { | |
3396 | + gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); | |
3397 | + gen_op_jmp_im(pc_start - s->cs_base); | |
3398 | + gen_op_ltr_T0(); | |
3399 | + } | |
3400 | + break; | |
3401 | + case 4: /* verr */ | |
3402 | + case 5: /* verw */ | |
3403 | + default: | |
3404 | + goto illegal_op; | |
3405 | + } | |
3406 | + break; | |
3407 | + case 0x101: | |
3408 | + modrm = ldub(s->pc++); | |
3409 | + mod = (modrm >> 6) & 3; | |
3410 | + op = (modrm >> 3) & 7; | |
3411 | + switch(op) { | |
3412 | + case 0: /* sgdt */ | |
3413 | + case 1: /* sidt */ | |
3414 | + if (mod == 3) | |
3415 | + goto illegal_op; | |
3416 | + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); | |
3417 | + if (op == 0) | |
3418 | + gen_op_movl_T0_env(offsetof(CPUX86State,gdt.limit)); | |
3419 | + else | |
3420 | + gen_op_movl_T0_env(offsetof(CPUX86State,idt.limit)); | |
3421 | + gen_op_stw_T0_A0(); | |
3422 | + gen_op_addl_A0_im(2); | |
3423 | + if (op == 0) | |
3424 | + gen_op_movl_T0_env(offsetof(CPUX86State,gdt.base)); | |
3425 | + else | |
3426 | + gen_op_movl_T0_env(offsetof(CPUX86State,idt.base)); | |
3427 | + if (!s->dflag) | |
3428 | + gen_op_andl_T0_im(0xffffff); | |
3429 | + gen_op_stl_T0_A0(); | |
3430 | + break; | |
3431 | + case 2: /* lgdt */ | |
3432 | + case 3: /* lidt */ | |
3433 | + if (mod == 3) | |
3434 | + goto illegal_op; | |
3435 | + if (s->cpl != 0) { | |
3436 | + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); | |
3437 | + } else { | |
3438 | + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); | |
3439 | + gen_op_lduw_T1_A0(); | |
3440 | + gen_op_addl_A0_im(2); | |
3441 | + gen_op_ldl_T0_A0(); | |
3442 | + if (!s->dflag) | |
3443 | + gen_op_andl_T0_im(0xffffff); | |
3444 | + if (op == 2) { | |
3445 | + gen_op_movl_env_T0(offsetof(CPUX86State,gdt.base)); | |
3446 | + gen_op_movl_env_T1(offsetof(CPUX86State,gdt.limit)); | |
3447 | + } else { | |
3448 | + gen_op_movl_env_T0(offsetof(CPUX86State,idt.base)); | |
3449 | + gen_op_movl_env_T1(offsetof(CPUX86State,idt.limit)); | |
3450 | + } | |
3451 | + } | |
3452 | + break; | |
3453 | + case 4: /* smsw */ | |
3454 | + gen_op_movl_T0_env(offsetof(CPUX86State,cr[0])); | |
3455 | + gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 1); | |
3456 | + break; | |
3457 | + case 6: /* lmsw */ | |
3458 | + if (s->cpl != 0) { | |
3459 | + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); | |
3460 | + } else { | |
3461 | + gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); | |
3462 | + gen_op_lmsw_T0(); | |
3463 | + } | |
3464 | + break; | |
3465 | + default: | |
3466 | + goto illegal_op; | |
3467 | + } | |
3468 | + break; | |
3346 | 3469 | case 0x102: /* lar */ |
3347 | 3470 | case 0x103: /* lsl */ |
3348 | 3471 | if (s->vm86) |
... | ... | @@ -3361,6 +3484,83 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
3361 | 3484 | s->cc_op = CC_OP_EFLAGS; |
3362 | 3485 | gen_op_mov_reg_T1[ot][reg](); |
3363 | 3486 | break; |
3487 | + case 0x118: | |
3488 | + modrm = ldub(s->pc++); | |
3489 | + mod = (modrm >> 6) & 3; | |
3490 | + op = (modrm >> 3) & 7; | |
3491 | + switch(op) { | |
3492 | + case 0: /* prefetchnta */ | |
3493 | + case 1: /* prefetchnt0 */ | |
3494 | + case 2: /* prefetchnt0 */ | |
3495 | + case 3: /* prefetchnt0 */ | |
3496 | + if (mod == 3) | |
3497 | + goto illegal_op; | |
3498 | + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); | |
3499 | + /* nothing more to do */ | |
3500 | + break; | |
3501 | + default: | |
3502 | + goto illegal_op; | |
3503 | + } | |
3504 | + break; | |
3505 | + case 0x120: /* mov reg, crN */ | |
3506 | + case 0x122: /* mov crN, reg */ | |
3507 | + if (s->cpl != 0) { | |
3508 | + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); | |
3509 | + } else { | |
3510 | + modrm = ldub(s->pc++); | |
3511 | + if ((modrm & 0xc0) != 0xc0) | |
3512 | + goto illegal_op; | |
3513 | + rm = modrm & 7; | |
3514 | + reg = (modrm >> 3) & 7; | |
3515 | + switch(reg) { | |
3516 | + case 0: | |
3517 | + case 2: | |
3518 | + case 3: | |
3519 | + case 4: | |
3520 | + if (b & 2) { | |
3521 | + gen_op_mov_TN_reg[OT_LONG][0][rm](); | |
3522 | + gen_op_movl_crN_T0(reg); | |
3523 | + s->is_jmp = 2; | |
3524 | + } else { | |
3525 | + gen_op_movl_T0_env(offsetof(CPUX86State,cr[reg])); | |
3526 | + gen_op_mov_reg_T0[OT_LONG][rm](); | |
3527 | + } | |
3528 | + break; | |
3529 | + default: | |
3530 | + goto illegal_op; | |
3531 | + } | |
3532 | + } | |
3533 | + break; | |
3534 | + case 0x121: /* mov reg, drN */ | |
3535 | + case 0x123: /* mov drN, reg */ | |
3536 | + if (s->cpl != 0) { | |
3537 | + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); | |
3538 | + } else { | |
3539 | + modrm = ldub(s->pc++); | |
3540 | + if ((modrm & 0xc0) != 0xc0) | |
3541 | + goto illegal_op; | |
3542 | + rm = modrm & 7; | |
3543 | + reg = (modrm >> 3) & 7; | |
3544 | + /* XXX: do it dynamically with CR4.DE bit */ | |
3545 | + if (reg == 4 || reg == 5) | |
3546 | + goto illegal_op; | |
3547 | + if (b & 2) { | |
3548 | + gen_op_mov_TN_reg[OT_LONG][0][rm](); | |
3549 | + gen_op_movl_drN_T0(reg); | |
3550 | + s->is_jmp = 2; | |
3551 | + } else { | |
3552 | + gen_op_movl_T0_env(offsetof(CPUX86State,dr[reg])); | |
3553 | + gen_op_mov_reg_T0[OT_LONG][rm](); | |
3554 | + } | |
3555 | + } | |
3556 | + break; | |
3557 | + case 0x106: /* clts */ | |
3558 | + if (s->cpl != 0) { | |
3559 | + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); | |
3560 | + } else { | |
3561 | + gen_op_clts(); | |
3562 | + } | |
3563 | + break; | |
3364 | 3564 | default: |
3365 | 3565 | goto illegal_op; |
3366 | 3566 | } |
... | ... | @@ -3859,12 +4059,12 @@ void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags) |
3859 | 4059 | eflags & CC_P ? 'P' : '-', |
3860 | 4060 | eflags & CC_C ? 'C' : '-'); |
3861 | 4061 | fprintf(f, "CS=%04x SS=%04x DS=%04x ES=%04x FS=%04x GS=%04x\n", |
3862 | - env->segs[R_CS], | |
3863 | - env->segs[R_SS], | |
3864 | - env->segs[R_DS], | |
3865 | - env->segs[R_ES], | |
3866 | - env->segs[R_FS], | |
3867 | - env->segs[R_GS]); | |
4062 | + env->segs[R_CS].selector, | |
4063 | + env->segs[R_SS].selector, | |
4064 | + env->segs[R_DS].selector, | |
4065 | + env->segs[R_ES].selector, | |
4066 | + env->segs[R_FS].selector, | |
4067 | + env->segs[R_GS].selector); | |
3868 | 4068 | if (flags & X86_DUMP_CCOP) { |
3869 | 4069 | if ((unsigned)env->cc_op < CC_OP_NB) |
3870 | 4070 | strcpy(cc_op_name, cc_op_str[env->cc_op]); | ... | ... |