target/i386: fix exceptions for MOV to DR

Use raise_exception_ra (without error code) when raising the illegal
opcode operation; raise #GP when setting bits 63:32 of DR6 or DR7.

Move helper_get_dr to sysemu/ since it is a privileged instruction
that is not needed on user-mode emulators.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Paolo Bonzini 2021-07-06 17:53:29 +02:00
parent acf23ffb58
commit 533883fd7e
7 changed files with 35 additions and 45 deletions

View File

@ -268,6 +268,8 @@ typedef enum X86Seg {
#define DR7_TYPE_IO_RW 0x2
#define DR7_TYPE_DATA_RW 0x3
#define DR_RESERVED_MASK 0xffffffff00000000ULL
#define PG_PRESENT_BIT 0
#define PG_RW_BIT 1
#define PG_USER_BIT 2

View File

@ -46,9 +46,8 @@ DEF_HELPER_1(clts, void, env)
#ifndef CONFIG_USER_ONLY
DEF_HELPER_FLAGS_3(set_dr, TCG_CALL_NO_WG, void, env, int, tl)
#endif /* !CONFIG_USER_ONLY */
DEF_HELPER_FLAGS_2(get_dr, TCG_CALL_NO_WG, tl, env, int)
#endif /* !CONFIG_USER_ONLY */
DEF_HELPER_1(sysenter, void, env)
DEF_HELPER_2(sysexit, void, env, int)

View File

@ -140,8 +140,6 @@
#define SVM_MSRPM_SIZE (1ULL << 13)
#define SVM_IOPM_SIZE ((1ULL << 13) + 1)
#define SVM_DR_RESERVED_MASK 0xffffffff00000000ULL
struct QEMU_PACKED vmcb_control_area {
uint16_t intercept_cr_read;
uint16_t intercept_cr_write;

View File

@ -37,24 +37,3 @@ void helper_rechecking_single_step(CPUX86State *env)
helper_single_step(env);
}
}
target_ulong helper_get_dr(CPUX86State *env, int reg)
{
switch (reg) {
case 0: case 1: case 2: case 3: case 6: case 7:
return env->dr[reg];
case 4:
if (env->cr[4] & CR4_DE_MASK) {
break;
} else {
return env->dr[6];
}
case 5:
if (env->cr[4] & CR4_DE_MASK) {
break;
} else {
return env->dr[7];
}
}
raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC());
}

View File

@ -234,10 +234,30 @@ void breakpoint_handler(CPUState *cs)
}
}
target_ulong helper_get_dr(CPUX86State *env, int reg)
{
if (reg >= 4 && reg < 6) {
if (env->cr[4] & CR4_DE_MASK) {
raise_exception_ra(env, EXCP06_ILLOP, GETPC());
} else {
reg += 2;
}
}
return env->dr[reg];
}
void helper_set_dr(CPUX86State *env, int reg, target_ulong t0)
{
switch (reg) {
case 0: case 1: case 2: case 3:
if (reg >= 4 && reg < 6) {
if (env->cr[4] & CR4_DE_MASK) {
raise_exception_ra(env, EXCP06_ILLOP, GETPC());
} else {
reg += 2;
}
}
if (reg < 4) {
if (hw_breakpoint_enabled(env->dr[7], reg)
&& hw_breakpoint_type(env->dr[7], reg) != DR7_TYPE_IO_RW) {
hw_breakpoint_remove(env, reg);
@ -246,25 +266,16 @@ void helper_set_dr(CPUX86State *env, int reg, target_ulong t0)
} else {
env->dr[reg] = t0;
}
return;
case 4:
if (env->cr[4] & CR4_DE_MASK) {
break;
} else {
if (t0 & DR_RESERVED_MASK) {
raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
}
/* fallthru */
case 6:
env->dr[6] = t0 | DR6_FIXED_1;
return;
case 5:
if (env->cr[4] & CR4_DE_MASK) {
break;
if (reg == 6) {
env->dr[6] = t0 | DR6_FIXED_1;
} else {
cpu_x86_update_dr7(env, t0);
}
/* fallthru */
case 7:
cpu_x86_update_dr7(env, t0);
return;
}
raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC());
}
/* Check if Port I/O is trapped by a breakpoint. */

View File

@ -270,10 +270,10 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
env->vm_vmcb + offsetof(struct vmcb, save.dr6));
#ifdef TARGET_X86_64
if (env->dr[6] & SVM_DR_RESERVED_MASK) {
if (env->dr[6] & DR_RESERVED_MASK) {
cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
}
if (env->dr[7] & SVM_DR_RESERVED_MASK) {
if (env->dr[7] & DR_RESERVED_MASK) {
cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
}
#endif

View File

@ -206,6 +206,7 @@ STUB_HELPER(outw, TCGv_env env, TCGv_i32 port, TCGv_i32 val)
STUB_HELPER(outl, TCGv_env env, TCGv_i32 port, TCGv_i32 val)
STUB_HELPER(rdmsr, TCGv_env env)
STUB_HELPER(read_crN, TCGv ret, TCGv_env env, TCGv_i32 reg)
STUB_HELPER(get_dr, TCGv ret, TCGv_env env, TCGv_i32 reg)
STUB_HELPER(set_dr, TCGv_env env, TCGv_i32 reg, TCGv val)
STUB_HELPER(stgi, TCGv_env env)
STUB_HELPER(svm_check_intercept, TCGv_env env, TCGv_i32 type)