ring 0 ops

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@254 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
bellard 2003-06-21 13:13:13 +00:00
parent 7501267e22
commit d8bc1fd0ae
4 changed files with 469 additions and 51 deletions

View File

@ -123,6 +123,11 @@ typedef struct CCTable {
extern CCTable cc_table[];
void load_seg(int seg_reg, int selector, unsigned cur_eip);
void jmp_seg(int selector, unsigned int new_eip);
void helper_lldt_T0(void);
void helper_ltr_T0(void);
void helper_movl_crN_T0(int reg);
void helper_movl_drN_T0(int reg);
void __hidden cpu_lock(void);
void __hidden cpu_unlock(void);
void raise_interrupt(int intno, int is_int, int error_code,

View File

@ -157,7 +157,7 @@ void raise_interrupt(int intno, int is_int, int error_code,
break;
}
dpl = (e2 >> DESC_DPL_SHIFT) & 3;
cpl = env->segs[R_CS] & 3;
cpl = env->segs[R_CS].selector & 3;
/* check privledge if software int */
if (is_int && dpl < cpl)
raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
@ -176,7 +176,7 @@ void raise_interrupt(int intno, int is_int, int error_code,
void raise_interrupt(int intno, int is_int, int error_code,
unsigned int next_eip)
{
SegmentDescriptorTable *dt;
SegmentCache *dt;
uint8_t *ptr;
int dpl, cpl;
uint32_t e2;
@ -331,21 +331,98 @@ void helper_cpuid(void)
}
}
static inline void load_seg_cache(SegmentCache *sc, uint32_t e1, uint32_t e2)
{
sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000);
if (e2 & (1 << 23))
sc->limit = (sc->limit << 12) | 0xfff;
sc->seg_32bit = (e2 >> 22) & 1;
}
void helper_lldt_T0(void)
{
int selector;
SegmentCache *dt;
uint32_t e1, e2;
int index;
uint8_t *ptr;
selector = T0 & 0xffff;
if ((selector & 0xfffc) == 0) {
/* XXX: NULL selector case: invalid LDT */
env->ldt.base = NULL;
env->ldt.limit = 0;
} else {
if (selector & 0x4)
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
dt = &env->gdt;
index = selector & ~7;
if ((index + 7) > dt->limit)
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
ptr = dt->base + index;
e1 = ldl(ptr);
e2 = ldl(ptr + 4);
if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
if (!(e2 & DESC_P_MASK))
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
load_seg_cache(&env->ldt, e1, e2);
}
env->ldt.selector = selector;
}
void helper_ltr_T0(void)
{
int selector;
SegmentCache *dt;
uint32_t e1, e2;
int index, type;
uint8_t *ptr;
selector = T0 & 0xffff;
if ((selector & 0xfffc) == 0) {
/* XXX: NULL selector case: invalid LDT */
env->tr.base = NULL;
env->tr.limit = 0;
} else {
if (selector & 0x4)
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
dt = &env->gdt;
index = selector & ~7;
if ((index + 7) > dt->limit)
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
ptr = dt->base + index;
e1 = ldl(ptr);
e2 = ldl(ptr + 4);
type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
if ((e2 & DESC_S_MASK) ||
(type != 2 && type != 9))
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
if (!(e2 & DESC_P_MASK))
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
load_seg_cache(&env->tr, e1, e2);
e2 |= 0x00000200; /* set the busy bit */
stl(ptr + 4, e2);
}
env->tr.selector = selector;
}
/* only works if protected mode and not VM86 */
void load_seg(int seg_reg, int selector, unsigned cur_eip)
void load_seg(int seg_reg, int selector, unsigned int cur_eip)
{
SegmentCache *sc;
SegmentDescriptorTable *dt;
SegmentCache *dt;
int index;
uint32_t e1, e2;
uint8_t *ptr;
sc = &env->seg_cache[seg_reg];
sc = &env->segs[seg_reg];
if ((selector & 0xfffc) == 0) {
/* null selector case */
if (seg_reg == R_SS) {
EIP = cur_eip;
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
raise_exception_err(EXCP0D_GPF, 0);
} else {
/* XXX: each access should trigger an exception */
sc->base = NULL;
@ -390,18 +467,93 @@ void load_seg(int seg_reg, int selector, unsigned cur_eip)
else
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
}
sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000);
if (e2 & (1 << 23))
sc->limit = (sc->limit << 12) | 0xfff;
sc->seg_32bit = (e2 >> 22) & 1;
load_seg_cache(sc, e1, e2);
#if 0
fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx seg_32bit=%d\n",
selector, (unsigned long)sc->base, sc->limit, sc->seg_32bit);
#endif
}
env->segs[seg_reg] = selector;
sc->selector = selector;
}
/* protected mode jump */
void jmp_seg(int selector, unsigned int new_eip)
{
SegmentCache sc1;
SegmentCache *dt;
int index;
uint32_t e1, e2, cpl, dpl, rpl;
uint8_t *ptr;
if ((selector & 0xfffc) == 0) {
raise_exception_err(EXCP0D_GPF, 0);
}
if (selector & 0x4)
dt = &env->ldt;
else
dt = &env->gdt;
index = selector & ~7;
if ((index + 7) > dt->limit)
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
ptr = dt->base + index;
e1 = ldl(ptr);
e2 = ldl(ptr + 4);
cpl = env->segs[R_CS].selector & 3;
if (e2 & DESC_S_MASK) {
if (!(e2 & DESC_CS_MASK))
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
dpl = (e2 >> DESC_DPL_SHIFT) & 3;
if (e2 & DESC_CS_MASK) {
/* conforming code segment */
if (dpl > cpl)
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
} else {
/* non conforming code segment */
rpl = selector & 3;
if (rpl > cpl)
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
if (dpl != cpl)
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
}
if (!(e2 & DESC_P_MASK))
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
load_seg_cache(&sc1, e1, e2);
if (new_eip > sc1.limit)
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
env->segs[R_CS] = sc1;
env->segs[R_CS].selector = (selector & 0xfffc) | cpl;
EIP = new_eip;
} else {
cpu_abort(env, "jmp to call/task gate not supported 0x%04x:0x%08x",
selector, new_eip);
}
}
/* XXX: do more */
void helper_movl_crN_T0(int reg)
{
switch(reg) {
case 0:
default:
env->cr[0] = reg;
break;
case 2:
env->cr[2] = reg;
break;
case 3:
env->cr[3] = reg;
break;
case 4:
env->cr[4] = reg;
break;
}
}
/* XXX: do more */
void helper_movl_drN_T0(int reg)
{
env->dr[reg] = T0;
}
/* rdtsc */
@ -425,7 +577,7 @@ void helper_rdtsc(void)
void helper_lsl(void)
{
unsigned int selector, limit;
SegmentDescriptorTable *dt;
SegmentCache *dt;
int index;
uint32_t e1, e2;
uint8_t *ptr;
@ -452,7 +604,7 @@ void helper_lsl(void)
void helper_lar(void)
{
unsigned int selector;
SegmentDescriptorTable *dt;
SegmentCache *dt;
int index;
uint32_t e2;
uint8_t *ptr;

View File

@ -357,6 +357,11 @@ void OPPROTO op_andl_T0_ffff(void)
T0 = T0 & 0xffff;
}
void OPPROTO op_andl_T0_im(void)
{
T0 = T0 & PARAM1;
}
void OPPROTO op_movl_T0_T1(void)
{
T0 = T1;
@ -665,7 +670,7 @@ void op_pushl_ss32_T0(void)
{
uint32_t offset;
offset = ESP - 4;
stl(env->seg_cache[R_SS].base + offset, T0);
stl(env->segs[R_SS].base + offset, T0);
/* modify ESP after to handle exceptions correctly */
ESP = offset;
}
@ -674,7 +679,7 @@ void op_pushw_ss32_T0(void)
{
uint32_t offset;
offset = ESP - 2;
stw(env->seg_cache[R_SS].base + offset, T0);
stw(env->segs[R_SS].base + offset, T0);
/* modify ESP after to handle exceptions correctly */
ESP = offset;
}
@ -683,7 +688,7 @@ void op_pushl_ss16_T0(void)
{
uint32_t offset;
offset = (ESP - 4) & 0xffff;
stl(env->seg_cache[R_SS].base + offset, T0);
stl(env->segs[R_SS].base + offset, T0);
/* modify ESP after to handle exceptions correctly */
ESP = (ESP & ~0xffff) | offset;
}
@ -692,7 +697,7 @@ void op_pushw_ss16_T0(void)
{
uint32_t offset;
offset = (ESP - 2) & 0xffff;
stw(env->seg_cache[R_SS].base + offset, T0);
stw(env->segs[R_SS].base + offset, T0);
/* modify ESP after to handle exceptions correctly */
ESP = (ESP & ~0xffff) | offset;
}
@ -710,22 +715,22 @@ void op_popw_T0(void)
void op_popl_ss32_T0(void)
{
T0 = ldl(env->seg_cache[R_SS].base + ESP);
T0 = ldl(env->segs[R_SS].base + ESP);
}
void op_popw_ss32_T0(void)
{
T0 = lduw(env->seg_cache[R_SS].base + ESP);
T0 = lduw(env->segs[R_SS].base + ESP);
}
void op_popl_ss16_T0(void)
{
T0 = ldl(env->seg_cache[R_SS].base + (ESP & 0xffff));
T0 = ldl(env->segs[R_SS].base + (ESP & 0xffff));
}
void op_popw_ss16_T0(void)
{
T0 = lduw(env->seg_cache[R_SS].base + (ESP & 0xffff));
T0 = lduw(env->segs[R_SS].base + (ESP & 0xffff));
}
void op_addl_ESP_4(void)
@ -909,17 +914,18 @@ void OPPROTO op_movl_seg_T0(void)
void OPPROTO op_movl_seg_T0_vm(void)
{
int selector;
SegmentCache *sc;
selector = T0 & 0xffff;
/* env->segs[] access */
*(uint32_t *)((char *)env + PARAM1) = selector;
/* env->seg_cache[] access */
((SegmentCache *)((char *)env + PARAM2))->base = (void *)(selector << 4);
sc = (SegmentCache *)((char *)env + PARAM1);
sc->selector = selector;
sc->base = (void *)(selector << 4);
}
void OPPROTO op_movl_T0_seg(void)
{
T0 = env->segs[PARAM1];
T0 = env->segs[PARAM1].selector;
}
void OPPROTO op_movl_A0_seg(void)
@ -942,6 +948,61 @@ void OPPROTO op_lar(void)
helper_lar();
}
/* T0: segment, T1:eip */
void OPPROTO op_ljmp_T0_T1(void)
{
jmp_seg(T0 & 0xffff, T1);
}
void OPPROTO op_lldt_T0(void)
{
helper_lldt_T0();
}
void OPPROTO op_ltr_T0(void)
{
helper_ltr_T0();
}
/* CR registers access */
void OPPROTO op_movl_crN_T0(void)
{
helper_movl_crN_T0(PARAM1);
}
/* DR registers access */
void OPPROTO op_movl_drN_T0(void)
{
helper_movl_drN_T0(PARAM1);
}
void OPPROTO op_lmsw_T0(void)
{
/* only 4 lower bits of CR0 are modified */
T0 = (env->cr[0] & ~0xf) | (T0 & 0xf);
helper_movl_crN_T0(0);
}
void OPPROTO op_movl_T0_env(void)
{
T0 = *(uint32_t *)((char *)env + PARAM1);
}
void OPPROTO op_movl_env_T0(void)
{
*(uint32_t *)((char *)env + PARAM1) = T0;
}
void OPPROTO op_movl_env_T1(void)
{
*(uint32_t *)((char *)env + PARAM1) = T1;
}
void OPPROTO op_clts(void)
{
env->cr[0] &= ~CR0_TS_MASK;
}
/* flags handling */
/* slow jumps cases : in order to avoid calling a function with a

View File

@ -575,7 +575,7 @@ static inline void gen_string_ds(DisasContext *s, int ot, GenOpFunc **func)
if (s->addseg && override < 0)
override = R_DS;
if (override >= 0) {
gen_op_movl_A0_seg(offsetof(CPUX86State,seg_cache[override].base));
gen_op_movl_A0_seg(offsetof(CPUX86State,segs[override].base));
index = 3 + ot;
} else {
index = ot;
@ -583,7 +583,7 @@ static inline void gen_string_ds(DisasContext *s, int ot, GenOpFunc **func)
} else {
if (override < 0)
override = R_DS;
gen_op_movl_A0_seg(offsetof(CPUX86State,seg_cache[override].base));
gen_op_movl_A0_seg(offsetof(CPUX86State,segs[override].base));
/* 16 address, always override */
index = 6 + ot;
}
@ -878,7 +878,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_
else
override = R_DS;
}
gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base));
gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base));
}
} else {
switch (mod) {
@ -944,7 +944,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_
else
override = R_DS;
}
gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base));
gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base));
}
}
@ -1146,8 +1146,7 @@ static void gen_movl_seg_T0(DisasContext *s, int seg_reg, unsigned int cur_eip)
if (!s->vm86)
gen_op_movl_seg_T0(seg_reg, cur_eip);
else
gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[seg_reg]),
offsetof(CPUX86State,seg_cache[seg_reg].base));
gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[seg_reg]));
if (!s->addseg && seg_reg < R_FS)
s->is_jmp = 2; /* abort translation because the register may
have a non zero base */
@ -1230,7 +1229,7 @@ static void gen_stack_A0(DisasContext *s)
gen_op_andl_A0_ffff();
gen_op_movl_T1_A0();
if (s->addseg)
gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[R_SS].base));
gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base));
}
/* NOTE: wrap around in 16 bit not fully handled */
@ -1243,7 +1242,7 @@ static void gen_pusha(DisasContext *s)
gen_op_andl_A0_ffff();
gen_op_movl_T1_A0();
if (s->addseg)
gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[R_SS].base));
gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base));
for(i = 0;i < 8; i++) {
gen_op_mov_TN_reg[OT_LONG][0][7 - i]();
gen_op_st_T0_A0[OT_WORD + s->dflag]();
@ -1262,7 +1261,7 @@ static void gen_popa(DisasContext *s)
gen_op_movl_T1_A0();
gen_op_addl_T1_im(16 << s->dflag);
if (s->addseg)
gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[R_SS].base));
gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base));
for(i = 0;i < 8; i++) {
/* ESP is not reloaded */
if (i != 3) {
@ -1291,7 +1290,7 @@ static void gen_enter(DisasContext *s, int esp_addend, int level)
gen_op_andl_A0_ffff();
gen_op_movl_T1_A0();
if (s->addseg)
gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[R_SS].base));
gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base));
/* push bp */
gen_op_mov_TN_reg[OT_LONG][0][R_EBP]();
gen_op_st_T0_A0[ot]();
@ -1714,9 +1713,15 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
gen_op_ld_T1_A0[ot]();
gen_op_addl_A0_im(1 << (ot - OT_WORD + 1));
gen_op_lduw_T0_A0();
gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base);
gen_op_movl_T0_T1();
gen_op_jmp_T0();
if (!s->vm86) {
/* we compute EIP to handle the exception case */
gen_op_jmp_im(pc_start - s->cs_base);
gen_op_ljmp_T0_T1();
} else {
gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS]));
gen_op_movl_T0_T1();
gen_op_jmp_T0();
}
s->is_jmp = 1;
break;
case 6: /* push Ev */
@ -2085,7 +2090,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
override = R_DS;
}
if (must_add_seg) {
gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base));
gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base));
}
}
if ((b & 2) == 0) {
@ -2113,7 +2118,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
override = R_DS;
}
if (must_add_seg) {
gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base));
gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base));
}
}
gen_op_ldub_T0_A0();
@ -2619,12 +2624,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
break;
case 0x1c:
switch(rm) {
case 0: /* feni (287 only, just do nop here) */
break;
case 1: /* fdisi (287 only, just do nop here) */
break;
case 2: /* fclex */
gen_op_fclex();
break;
case 3: /* fninit */
gen_op_fninit();
break;
case 4: /* fsetpm (287 only, just do nop here) */
break;
default:
goto illegal_op;
}
@ -3011,8 +3022,15 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
/* change cs and pc */
gen_op_movl_T0_im(selector);
gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base);
gen_op_jmp_im((unsigned long)offset);
if (!s->vm86) {
/* we compute EIP to handle the exception case */
gen_op_jmp_im(pc_start - s->cs_base);
gen_op_movl_T1_im(offset);
gen_op_ljmp_T0_T1();
} else {
gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS]));
gen_op_jmp_im((unsigned long)offset);
}
s->is_jmp = 1;
}
break;
@ -3343,6 +3361,111 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
/* XXX: if cpl == 0, then should do something else */
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
break;
case 0x100:
modrm = ldub(s->pc++);
mod = (modrm >> 6) & 3;
op = (modrm >> 3) & 7;
switch(op) {
case 0: /* sldt */
gen_op_movl_T0_env(offsetof(CPUX86State,ldt.selector));
ot = OT_WORD;
if (mod == 3)
ot += s->dflag;
gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
break;
case 2: /* lldt */
if (s->cpl != 0) {
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else {
gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
gen_op_jmp_im(pc_start - s->cs_base);
gen_op_lldt_T0();
}
break;
case 1: /* str */
gen_op_movl_T0_env(offsetof(CPUX86State,tr.selector));
ot = OT_WORD;
if (mod == 3)
ot += s->dflag;
gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
break;
case 3: /* ltr */
if (s->cpl != 0) {
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else {
gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
gen_op_jmp_im(pc_start - s->cs_base);
gen_op_ltr_T0();
}
break;
case 4: /* verr */
case 5: /* verw */
default:
goto illegal_op;
}
break;
case 0x101:
modrm = ldub(s->pc++);
mod = (modrm >> 6) & 3;
op = (modrm >> 3) & 7;
switch(op) {
case 0: /* sgdt */
case 1: /* sidt */
if (mod == 3)
goto illegal_op;
gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
if (op == 0)
gen_op_movl_T0_env(offsetof(CPUX86State,gdt.limit));
else
gen_op_movl_T0_env(offsetof(CPUX86State,idt.limit));
gen_op_stw_T0_A0();
gen_op_addl_A0_im(2);
if (op == 0)
gen_op_movl_T0_env(offsetof(CPUX86State,gdt.base));
else
gen_op_movl_T0_env(offsetof(CPUX86State,idt.base));
if (!s->dflag)
gen_op_andl_T0_im(0xffffff);
gen_op_stl_T0_A0();
break;
case 2: /* lgdt */
case 3: /* lidt */
if (mod == 3)
goto illegal_op;
if (s->cpl != 0) {
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else {
gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
gen_op_lduw_T1_A0();
gen_op_addl_A0_im(2);
gen_op_ldl_T0_A0();
if (!s->dflag)
gen_op_andl_T0_im(0xffffff);
if (op == 2) {
gen_op_movl_env_T0(offsetof(CPUX86State,gdt.base));
gen_op_movl_env_T1(offsetof(CPUX86State,gdt.limit));
} else {
gen_op_movl_env_T0(offsetof(CPUX86State,idt.base));
gen_op_movl_env_T1(offsetof(CPUX86State,idt.limit));
}
}
break;
case 4: /* smsw */
gen_op_movl_T0_env(offsetof(CPUX86State,cr[0]));
gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 1);
break;
case 6: /* lmsw */
if (s->cpl != 0) {
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else {
gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
gen_op_lmsw_T0();
}
break;
default:
goto illegal_op;
}
break;
case 0x102: /* lar */
case 0x103: /* lsl */
if (s->vm86)
@ -3361,6 +3484,83 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
s->cc_op = CC_OP_EFLAGS;
gen_op_mov_reg_T1[ot][reg]();
break;
case 0x118:
modrm = ldub(s->pc++);
mod = (modrm >> 6) & 3;
op = (modrm >> 3) & 7;
switch(op) {
case 0: /* prefetchnta */
case 1: /* prefetchnt0 */
case 2: /* prefetchnt0 */
case 3: /* prefetchnt0 */
if (mod == 3)
goto illegal_op;
gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
/* nothing more to do */
break;
default:
goto illegal_op;
}
break;
case 0x120: /* mov reg, crN */
case 0x122: /* mov crN, reg */
if (s->cpl != 0) {
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else {
modrm = ldub(s->pc++);
if ((modrm & 0xc0) != 0xc0)
goto illegal_op;
rm = modrm & 7;
reg = (modrm >> 3) & 7;
switch(reg) {
case 0:
case 2:
case 3:
case 4:
if (b & 2) {
gen_op_mov_TN_reg[OT_LONG][0][rm]();
gen_op_movl_crN_T0(reg);
s->is_jmp = 2;
} else {
gen_op_movl_T0_env(offsetof(CPUX86State,cr[reg]));
gen_op_mov_reg_T0[OT_LONG][rm]();
}
break;
default:
goto illegal_op;
}
}
break;
case 0x121: /* mov reg, drN */
case 0x123: /* mov drN, reg */
if (s->cpl != 0) {
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else {
modrm = ldub(s->pc++);
if ((modrm & 0xc0) != 0xc0)
goto illegal_op;
rm = modrm & 7;
reg = (modrm >> 3) & 7;
/* XXX: do it dynamically with CR4.DE bit */
if (reg == 4 || reg == 5)
goto illegal_op;
if (b & 2) {
gen_op_mov_TN_reg[OT_LONG][0][rm]();
gen_op_movl_drN_T0(reg);
s->is_jmp = 2;
} else {
gen_op_movl_T0_env(offsetof(CPUX86State,dr[reg]));
gen_op_mov_reg_T0[OT_LONG][rm]();
}
}
break;
case 0x106: /* clts */
if (s->cpl != 0) {
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else {
gen_op_clts();
}
break;
default:
goto illegal_op;
}
@ -3859,12 +4059,12 @@ void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags)
eflags & CC_P ? 'P' : '-',
eflags & CC_C ? 'C' : '-');
fprintf(f, "CS=%04x SS=%04x DS=%04x ES=%04x FS=%04x GS=%04x\n",
env->segs[R_CS],
env->segs[R_SS],
env->segs[R_DS],
env->segs[R_ES],
env->segs[R_FS],
env->segs[R_GS]);
env->segs[R_CS].selector,
env->segs[R_SS].selector,
env->segs[R_DS].selector,
env->segs[R_ES].selector,
env->segs[R_FS].selector,
env->segs[R_GS].selector);
if (flags & X86_DUMP_CCOP) {
if ((unsigned)env->cc_op < CC_OP_NB)
strcpy(cc_op_name, cc_op_str[env->cc_op]);