mirror of https://github.com/proxmox/mirror_qemu
ring 0 ops
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@254 c046a42c-6fe2-441c-8c8c-71466251a162master
parent
7501267e22
commit
d8bc1fd0ae
|
@ -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,
|
||||
|
|
182
helper-i386.c
182
helper-i386.c
|
@ -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;
|
||||
|
|
85
op-i386.c
85
op-i386.c
|
@ -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
|
||||
|
|
240
translate-i386.c
240
translate-i386.c
|
@ -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);
|
||||
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);
|
||||
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, ®_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, ®_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, ®_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]);
|
||||
|
|
Loading…
Reference in New Issue