aboutsummaryrefslogtreecommitdiff
path: root/target-i386
diff options
context:
space:
mode:
Diffstat (limited to 'target-i386')
-rw-r--r--target-i386/cpu.c252
-rw-r--r--target-i386/cpu.h38
-rw-r--r--target-i386/helper.c102
-rw-r--r--target-i386/machine.c5
-rw-r--r--target-i386/misc_helper.c11
-rw-r--r--target-i386/seg_helper.c9
6 files changed, 267 insertions, 150 deletions
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 78bd61e..333745b 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -95,6 +95,17 @@ static const char *ext3_feature_name[] = {
NULL, NULL, NULL, NULL,
};
+static const char *ext4_feature_name[] = {
+ NULL, NULL, "xstore", "xstore-en",
+ NULL, NULL, "xcrypt", "xcrypt-en",
+ "ace2", "ace2-en", "phe", "phe-en",
+ "pmm", "pmm-en", NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+};
+
static const char *kvm_feature_name[] = {
"kvmclock", "kvm_nopiodelay", "kvm_mmu", "kvmclock",
"kvm_asyncpf", "kvm_steal_time", "kvm_pv_eoi", NULL,
@@ -124,6 +135,47 @@ static const char *cpuid_7_0_ebx_feature_name[] = {
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
};
+typedef struct FeatureWordInfo {
+ const char **feat_names;
+ uint32_t cpuid_eax; /* Input EAX for CPUID */
+ int cpuid_reg; /* R_* register constant */
+} FeatureWordInfo;
+
+static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
+ [FEAT_1_EDX] = {
+ .feat_names = feature_name,
+ .cpuid_eax = 1, .cpuid_reg = R_EDX,
+ },
+ [FEAT_1_ECX] = {
+ .feat_names = ext_feature_name,
+ .cpuid_eax = 1, .cpuid_reg = R_ECX,
+ },
+ [FEAT_8000_0001_EDX] = {
+ .feat_names = ext2_feature_name,
+ .cpuid_eax = 0x80000001, .cpuid_reg = R_EDX,
+ },
+ [FEAT_8000_0001_ECX] = {
+ .feat_names = ext3_feature_name,
+ .cpuid_eax = 0x80000001, .cpuid_reg = R_ECX,
+ },
+ [FEAT_C000_0001_EDX] = {
+ .feat_names = ext4_feature_name,
+ .cpuid_eax = 0xC0000001, .cpuid_reg = R_EDX,
+ },
+ [FEAT_KVM] = {
+ .feat_names = kvm_feature_name,
+ .cpuid_eax = KVM_CPUID_FEATURES, .cpuid_reg = R_EAX,
+ },
+ [FEAT_SVM] = {
+ .feat_names = svm_feature_name,
+ .cpuid_eax = 0x8000000A, .cpuid_reg = R_EDX,
+ },
+ [FEAT_7_0_EBX] = {
+ .feat_names = cpuid_7_0_ebx_feature_name,
+ .cpuid_eax = 7, .cpuid_reg = R_EBX,
+ },
+};
+
const char *get_register_name_32(unsigned int reg)
{
static const char *reg_names[CPU_NB_REGS32] = {
@@ -148,9 +200,7 @@ const char *get_register_name_32(unsigned int reg)
typedef struct model_features_t {
uint32_t *guest_feat;
uint32_t *host_feat;
- const char **flag_names;
- uint32_t cpuid;
- int reg;
+ FeatureWord feat_word;
} model_features_t;
int check_cpuid = 0;
@@ -159,7 +209,6 @@ int enforce_cpuid = 0;
#if defined(CONFIG_KVM)
static uint32_t kvm_default_features = (1 << KVM_FEATURE_CLOCKSOURCE) |
(1 << KVM_FEATURE_NOP_IO_DELAY) |
- (1 << KVM_FEATURE_MMU_OP) |
(1 << KVM_FEATURE_CLOCKSOURCE2) |
(1 << KVM_FEATURE_ASYNC_PF) |
(1 << KVM_FEATURE_STEAL_TIME) |
@@ -272,23 +321,20 @@ static bool lookup_feature(uint32_t *pval, const char *s, const char *e,
return found;
}
-static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features,
- uint32_t *ext_features,
- uint32_t *ext2_features,
- uint32_t *ext3_features,
- uint32_t *kvm_features,
- uint32_t *svm_features,
- uint32_t *cpuid_7_0_ebx_features)
+static void add_flagname_to_bitmaps(const char *flagname,
+ FeatureWordArray words)
{
- if (!lookup_feature(features, flagname, NULL, feature_name) &&
- !lookup_feature(ext_features, flagname, NULL, ext_feature_name) &&
- !lookup_feature(ext2_features, flagname, NULL, ext2_feature_name) &&
- !lookup_feature(ext3_features, flagname, NULL, ext3_feature_name) &&
- !lookup_feature(kvm_features, flagname, NULL, kvm_feature_name) &&
- !lookup_feature(svm_features, flagname, NULL, svm_feature_name) &&
- !lookup_feature(cpuid_7_0_ebx_features, flagname, NULL,
- cpuid_7_0_ebx_feature_name))
- fprintf(stderr, "CPU feature %s not found\n", flagname);
+ FeatureWord w;
+ for (w = 0; w < FEATURE_WORDS; w++) {
+ FeatureWordInfo *wi = &feature_word_info[w];
+ if (wi->feat_names &&
+ lookup_feature(&words[w], flagname, NULL, wi->feat_names)) {
+ break;
+ }
+ }
+ if (w == FEATURE_WORDS) {
+ fprintf(stderr, "CPU feature %s not found\n", flagname);
+ }
}
typedef struct x86_def_t {
@@ -952,55 +998,69 @@ static void kvm_cpu_fill_host(x86_def_t *x86_cpu_def)
#endif /* CONFIG_KVM */
}
-static int unavailable_host_feature(struct model_features_t *f, uint32_t mask)
+static int unavailable_host_feature(FeatureWordInfo *f, uint32_t mask)
{
int i;
for (i = 0; i < 32; ++i)
if (1 << i & mask) {
- const char *reg = get_register_name_32(f->reg);
+ const char *reg = get_register_name_32(f->cpuid_reg);
assert(reg);
fprintf(stderr, "warning: host doesn't support requested feature: "
"CPUID.%02XH:%s%s%s [bit %d]\n",
- f->cpuid, reg,
- f->flag_names[i] ? "." : "",
- f->flag_names[i] ? f->flag_names[i] : "", i);
+ f->cpuid_eax, reg,
+ f->feat_names[i] ? "." : "",
+ f->feat_names[i] ? f->feat_names[i] : "", i);
break;
}
return 0;
}
-/* best effort attempt to inform user requested cpu flags aren't making
- * their way to the guest.
+/* Check if all requested cpu flags are making their way to the guest
+ *
+ * Returns 0 if all flags are supported by the host, non-zero otherwise.
*
* This function may be called only if KVM is enabled.
*/
-static int kvm_check_features_against_host(x86_def_t *guest_def)
+static int kvm_check_features_against_host(X86CPU *cpu)
{
+ CPUX86State *env = &cpu->env;
x86_def_t host_def;
uint32_t mask;
int rv, i;
struct model_features_t ft[] = {
- {&guest_def->features, &host_def.features,
- feature_name, 0x00000001, R_EDX},
- {&guest_def->ext_features, &host_def.ext_features,
- ext_feature_name, 0x00000001, R_ECX},
- {&guest_def->ext2_features, &host_def.ext2_features,
- ext2_feature_name, 0x80000001, R_EDX},
- {&guest_def->ext3_features, &host_def.ext3_features,
- ext3_feature_name, 0x80000001, R_ECX}
+ {&env->cpuid_features, &host_def.features,
+ FEAT_1_EDX },
+ {&env->cpuid_ext_features, &host_def.ext_features,
+ FEAT_1_ECX },
+ {&env->cpuid_ext2_features, &host_def.ext2_features,
+ FEAT_8000_0001_EDX },
+ {&env->cpuid_ext3_features, &host_def.ext3_features,
+ FEAT_8000_0001_ECX },
+ {&env->cpuid_ext4_features, &host_def.ext4_features,
+ FEAT_C000_0001_EDX },
+ {&env->cpuid_7_0_ebx_features, &host_def.cpuid_7_0_ebx_features,
+ FEAT_7_0_EBX },
+ {&env->cpuid_svm_features, &host_def.svm_features,
+ FEAT_SVM },
+ {&env->cpuid_kvm_features, &host_def.kvm_features,
+ FEAT_KVM },
};
assert(kvm_enabled());
kvm_cpu_fill_host(&host_def);
- for (rv = 0, i = 0; i < ARRAY_SIZE(ft); ++i)
- for (mask = 1; mask; mask <<= 1)
+ for (rv = 0, i = 0; i < ARRAY_SIZE(ft); ++i) {
+ FeatureWord w = ft[i].feat_word;
+ FeatureWordInfo *wi = &feature_word_info[w];
+ for (mask = 1; mask; mask <<= 1) {
if (*ft[i].guest_feat & mask &&
!(*ft[i].host_feat & mask)) {
- unavailable_host_feature(&ft[i], mask);
- rv = 1;
- }
+ unavailable_host_feature(wi, mask);
+ rv = 1;
+ }
+ }
+ }
return rv;
}
@@ -1284,35 +1344,19 @@ static int cpu_x86_parse_featurestr(x86_def_t *x86_cpu_def, char *features)
unsigned int i;
char *featurestr; /* Single 'key=value" string being parsed */
/* Features to be added */
- uint32_t plus_features = 0, plus_ext_features = 0;
- uint32_t plus_ext2_features = 0, plus_ext3_features = 0;
- uint32_t plus_kvm_features = kvm_default_features, plus_svm_features = 0;
- uint32_t plus_7_0_ebx_features = 0;
+ FeatureWordArray plus_features = { 0 };
/* Features to be removed */
- uint32_t minus_features = 0, minus_ext_features = 0;
- uint32_t minus_ext2_features = 0, minus_ext3_features = 0;
- uint32_t minus_kvm_features = 0, minus_svm_features = 0;
- uint32_t minus_7_0_ebx_features = 0;
+ FeatureWordArray minus_features = { 0 };
uint32_t numvalue;
- add_flagname_to_bitmaps("hypervisor", &plus_features,
- &plus_ext_features, &plus_ext2_features, &plus_ext3_features,
- &plus_kvm_features, &plus_svm_features, &plus_7_0_ebx_features);
-
featurestr = features ? strtok(features, ",") : NULL;
while (featurestr) {
char *val;
if (featurestr[0] == '+') {
- add_flagname_to_bitmaps(featurestr + 1, &plus_features,
- &plus_ext_features, &plus_ext2_features,
- &plus_ext3_features, &plus_kvm_features,
- &plus_svm_features, &plus_7_0_ebx_features);
+ add_flagname_to_bitmaps(featurestr + 1, plus_features);
} else if (featurestr[0] == '-') {
- add_flagname_to_bitmaps(featurestr + 1, &minus_features,
- &minus_ext_features, &minus_ext2_features,
- &minus_ext3_features, &minus_kvm_features,
- &minus_svm_features, &minus_7_0_ebx_features);
+ add_flagname_to_bitmaps(featurestr + 1, minus_features);
} else if ((val = strchr(featurestr, '='))) {
*val = 0; val++;
if (!strcmp(featurestr, "family")) {
@@ -1412,24 +1456,22 @@ static int cpu_x86_parse_featurestr(x86_def_t *x86_cpu_def, char *features)
}
featurestr = strtok(NULL, ",");
}
- x86_cpu_def->features |= plus_features;
- x86_cpu_def->ext_features |= plus_ext_features;
- x86_cpu_def->ext2_features |= plus_ext2_features;
- x86_cpu_def->ext3_features |= plus_ext3_features;
- x86_cpu_def->kvm_features |= plus_kvm_features;
- x86_cpu_def->svm_features |= plus_svm_features;
- x86_cpu_def->cpuid_7_0_ebx_features |= plus_7_0_ebx_features;
- x86_cpu_def->features &= ~minus_features;
- x86_cpu_def->ext_features &= ~minus_ext_features;
- x86_cpu_def->ext2_features &= ~minus_ext2_features;
- x86_cpu_def->ext3_features &= ~minus_ext3_features;
- x86_cpu_def->kvm_features &= ~minus_kvm_features;
- x86_cpu_def->svm_features &= ~minus_svm_features;
- x86_cpu_def->cpuid_7_0_ebx_features &= ~minus_7_0_ebx_features;
- if (check_cpuid && kvm_enabled()) {
- if (kvm_check_features_against_host(x86_cpu_def) && enforce_cpuid)
- goto error;
- }
+ x86_cpu_def->features |= plus_features[FEAT_1_EDX];
+ x86_cpu_def->ext_features |= plus_features[FEAT_1_ECX];
+ x86_cpu_def->ext2_features |= plus_features[FEAT_8000_0001_EDX];
+ x86_cpu_def->ext3_features |= plus_features[FEAT_8000_0001_ECX];
+ x86_cpu_def->ext4_features |= plus_features[FEAT_C000_0001_EDX];
+ x86_cpu_def->kvm_features |= plus_features[FEAT_KVM];
+ x86_cpu_def->svm_features |= plus_features[FEAT_SVM];
+ x86_cpu_def->cpuid_7_0_ebx_features |= plus_features[FEAT_7_0_EBX];
+ x86_cpu_def->features &= ~minus_features[FEAT_1_EDX];
+ x86_cpu_def->ext_features &= ~minus_features[FEAT_1_ECX];
+ x86_cpu_def->ext2_features &= ~minus_features[FEAT_8000_0001_EDX];
+ x86_cpu_def->ext3_features &= ~minus_features[FEAT_8000_0001_ECX];
+ x86_cpu_def->ext4_features &= ~minus_features[FEAT_C000_0001_EDX];
+ x86_cpu_def->kvm_features &= ~minus_features[FEAT_KVM];
+ x86_cpu_def->svm_features &= ~minus_features[FEAT_SVM];
+ x86_cpu_def->cpuid_7_0_ebx_features &= ~minus_features[FEAT_7_0_EBX];
return 0;
error:
@@ -1549,17 +1591,23 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model)
model_pieces = g_strsplit(cpu_model, ",", 2);
if (!model_pieces[0]) {
- goto error;
+ error_setg(&error, "Invalid/empty CPU model name");
+ goto out;
}
name = model_pieces[0];
features = model_pieces[1];
if (cpu_x86_find_by_name(def, name) < 0) {
- goto error;
+ error_setg(&error, "Unable to find CPU definition: %s", name);
+ goto out;
}
+ def->kvm_features |= kvm_default_features;
+ def->ext_features |= CPUID_EXT_HYPERVISOR;
+
if (cpu_x86_parse_featurestr(def, features) < 0) {
- goto error;
+ error_setg(&error, "Invalid cpu_model string format: %s", cpu_model);
+ goto out;
}
assert(def->vendor1);
env->cpuid_vendor1 = def->vendor1;
@@ -1584,17 +1632,15 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model)
"tsc-frequency", &error);
object_property_set_str(OBJECT(cpu), def->model_id, "model-id", &error);
+
+out:
+ g_strfreev(model_pieces);
if (error) {
fprintf(stderr, "%s\n", error_get_pretty(error));
error_free(error);
- goto error;
+ return -1;
}
-
- g_strfreev(model_pieces);
return 0;
-error:
- g_strfreev(model_pieces);
- return -1;
}
#if !defined(CONFIG_USER_ONLY)
@@ -1691,8 +1737,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
*ebx = (env->cpuid_apic_id << 24) | 8 << 8; /* CLFLUSH size in quad words, Linux wants it. */
*ecx = env->cpuid_ext_features;
*edx = env->cpuid_features;
- if (env->nr_cores * env->nr_threads > 1) {
- *ebx |= (env->nr_cores * env->nr_threads) << 16;
+ if (cs->nr_cores * cs->nr_threads > 1) {
+ *ebx |= (cs->nr_cores * cs->nr_threads) << 16;
*edx |= 1 << 28; /* HTT bit */
}
break;
@@ -1705,8 +1751,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
break;
case 4:
/* cache info: needed for Core compatibility */
- if (env->nr_cores > 1) {
- *eax = (env->nr_cores - 1) << 26;
+ if (cs->nr_cores > 1) {
+ *eax = (cs->nr_cores - 1) << 26;
} else {
*eax = 0;
}
@@ -1725,8 +1771,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
break;
case 2: /* L2 cache info */
*eax |= 0x0000143;
- if (env->nr_threads > 1) {
- *eax |= (env->nr_threads - 1) << 14;
+ if (cs->nr_threads > 1) {
+ *eax |= (cs->nr_threads - 1) << 14;
}
*ebx = 0x3c0003f;
*ecx = 0x0000fff;
@@ -1830,7 +1876,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
* discards multiple thread information if it is set.
* So dont set it here for Intel to make Linux guests happy.
*/
- if (env->nr_cores * env->nr_threads > 1) {
+ if (cs->nr_cores * cs->nr_threads > 1) {
uint32_t tebx, tecx, tedx;
get_cpuid_vendor(env, &tebx, &tecx, &tedx);
if (tebx != CPUID_VENDOR_INTEL_1 ||
@@ -1878,8 +1924,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
*ebx = 0;
*ecx = 0;
*edx = 0;
- if (env->nr_cores * env->nr_threads > 1) {
- *ecx |= (env->nr_cores * env->nr_threads) - 1;
+ if (cs->nr_cores * cs->nr_threads > 1) {
+ *ecx |= (cs->nr_cores * cs->nr_threads) - 1;
}
break;
case 0x8000000A:
@@ -1936,7 +1982,7 @@ static void x86_cpu_reset(CPUState *s)
int i;
if (qemu_loglevel_mask(CPU_LOG_RESET)) {
- qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+ qemu_log("CPU Reset (CPU %d)\n", s->cpu_index);
log_cpu_state(env, CPU_DUMP_FPU | CPU_DUMP_CCOP);
}
@@ -2010,7 +2056,7 @@ static void x86_cpu_reset(CPUState *s)
#if !defined(CONFIG_USER_ONLY)
/* We hard-wire the BSP to the first CPU. */
- if (env->cpu_index == 0) {
+ if (s->cpu_index == 0) {
apic_designate_bsp(env->apic_state);
}
@@ -2128,6 +2174,11 @@ void x86_cpu_realize(Object *obj, Error **errp)
#ifdef CONFIG_KVM
filter_features_for_kvm(cpu);
#endif
+ if (check_cpuid && kvm_check_features_against_host(cpu)
+ && enforce_cpuid) {
+ error_setg(errp, "Host's CPU doesn't support requested features");
+ return;
+ }
}
#ifndef CONFIG_USER_ONLY
@@ -2148,6 +2199,7 @@ void x86_cpu_realize(Object *obj, Error **errp)
static void x86_cpu_initfn(Object *obj)
{
+ CPUState *cs = CPU(obj);
X86CPU *cpu = X86_CPU(obj);
CPUX86State *env = &cpu->env;
static int inited;
@@ -2179,7 +2231,7 @@ static void x86_cpu_initfn(Object *obj)
x86_cpuid_get_tsc_freq,
x86_cpuid_set_tsc_freq, NULL, NULL, NULL);
- env->cpuid_apic_id = env->cpu_index;
+ env->cpuid_apic_id = cs->cpu_index;
/* init various static tables used in TCG mode */
if (tcg_enabled() && !inited) {
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index e56921b..4e091cd 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -231,6 +231,12 @@
#define DR7_TYPE_SHIFT 16
#define DR7_LEN_SHIFT 18
#define DR7_FIXED_1 0x00000400
+#define DR7_LOCAL_BP_MASK 0x55
+#define DR7_MAX_BP 4
+#define DR7_TYPE_BP_INST 0x0
+#define DR7_TYPE_DATA_WR 0x1
+#define DR7_TYPE_IO_RW 0x2
+#define DR7_TYPE_DATA_RW 0x3
#define PG_PRESENT_BIT 0
#define PG_RW_BIT 1
@@ -361,6 +367,21 @@
#define MSR_VM_HSAVE_PA 0xc0010117
+/* CPUID feature words */
+typedef enum FeatureWord {
+ FEAT_1_EDX, /* CPUID[1].EDX */
+ FEAT_1_ECX, /* CPUID[1].ECX */
+ FEAT_7_0_EBX, /* CPUID[EAX=7,ECX=0].EBX */
+ FEAT_8000_0001_EDX, /* CPUID[8000_0001].EDX */
+ FEAT_8000_0001_ECX, /* CPUID[8000_0001].ECX */
+ FEAT_C000_0001_EDX, /* CPUID[C000_0001].EDX */
+ FEAT_KVM, /* CPUID[4000_0001].EAX (KVM_CPUID_FEATURES) */
+ FEAT_SVM, /* CPUID[8000_000A].EDX */
+ FEATURE_WORDS,
+} FeatureWord;
+
+typedef uint32_t FeatureWordArray[FEATURE_WORDS];
+
/* cpuid_features bits */
#define CPUID_FP87 (1 << 0)
#define CPUID_VME (1 << 1)
@@ -993,9 +1014,20 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
#define cpu_handle_mmu_fault cpu_x86_handle_mmu_fault
void cpu_x86_set_a20(CPUX86State *env, int a20_state);
-static inline int hw_breakpoint_enabled(unsigned long dr7, int index)
+static inline bool hw_local_breakpoint_enabled(unsigned long dr7, int index)
+{
+ return (dr7 >> (index * 2)) & 1;
+}
+
+static inline bool hw_global_breakpoint_enabled(unsigned long dr7, int index)
+{
+ return (dr7 >> (index * 2)) & 2;
+
+}
+static inline bool hw_breakpoint_enabled(unsigned long dr7, int index)
{
- return (dr7 >> (index * 2)) & 3;
+ return hw_global_breakpoint_enabled(dr7, index) ||
+ hw_local_breakpoint_enabled(dr7, index);
}
static inline int hw_breakpoint_type(unsigned long dr7, int index)
@@ -1011,7 +1043,7 @@ static inline int hw_breakpoint_len(unsigned long dr7, int index)
void hw_breakpoint_insert(CPUX86State *env, int index);
void hw_breakpoint_remove(CPUX86State *env, int index);
-int check_hw_breakpoints(CPUX86State *env, int force_dr6_update);
+bool check_hw_breakpoints(CPUX86State *env, bool force_dr6_update);
void breakpoint_handler(CPUX86State *env);
/* will be suppressed */
diff --git a/target-i386/helper.c b/target-i386/helper.c
index dca1360..547c25e 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -966,30 +966,35 @@ hwaddr cpu_get_phys_page_debug(CPUX86State *env, target_ulong addr)
void hw_breakpoint_insert(CPUX86State *env, int index)
{
- int type, err = 0;
+ int type = 0, err = 0;
switch (hw_breakpoint_type(env->dr[7], index)) {
- case 0:
- if (hw_breakpoint_enabled(env->dr[7], index))
+ case DR7_TYPE_BP_INST:
+ if (hw_breakpoint_enabled(env->dr[7], index)) {
err = cpu_breakpoint_insert(env, env->dr[index], BP_CPU,
&env->cpu_breakpoint[index]);
+ }
break;
- case 1:
+ case DR7_TYPE_DATA_WR:
type = BP_CPU | BP_MEM_WRITE;
- goto insert_wp;
- case 2:
- /* No support for I/O watchpoints yet */
break;
- case 3:
+ case DR7_TYPE_IO_RW:
+ /* No support for I/O watchpoints yet */
+ break;
+ case DR7_TYPE_DATA_RW:
type = BP_CPU | BP_MEM_ACCESS;
- insert_wp:
+ break;
+ }
+
+ if (type != 0) {
err = cpu_watchpoint_insert(env, env->dr[index],
hw_breakpoint_len(env->dr[7], index),
type, &env->cpu_watchpoint[index]);
- break;
}
- if (err)
+
+ if (err) {
env->cpu_breakpoint[index] = NULL;
+ }
}
void hw_breakpoint_remove(CPUX86State *env, int index)
@@ -997,39 +1002,60 @@ void hw_breakpoint_remove(CPUX86State *env, int index)
if (!env->cpu_breakpoint[index])
return;
switch (hw_breakpoint_type(env->dr[7], index)) {
- case 0:
- if (hw_breakpoint_enabled(env->dr[7], index))
+ case DR7_TYPE_BP_INST:
+ if (hw_breakpoint_enabled(env->dr[7], index)) {
cpu_breakpoint_remove_by_ref(env, env->cpu_breakpoint[index]);
+ }
break;
- case 1:
- case 3:
+ case DR7_TYPE_DATA_WR:
+ case DR7_TYPE_DATA_RW:
cpu_watchpoint_remove_by_ref(env, env->cpu_watchpoint[index]);
break;
- case 2:
+ case DR7_TYPE_IO_RW:
/* No support for I/O watchpoints yet */
break;
}
}
-int check_hw_breakpoints(CPUX86State *env, int force_dr6_update)
+bool check_hw_breakpoints(CPUX86State *env, bool force_dr6_update)
{
target_ulong dr6;
- int reg, type;
- int hit_enabled = 0;
+ int reg;
+ bool hit_enabled = false;
dr6 = env->dr[6] & ~0xf;
- for (reg = 0; reg < 4; reg++) {
- type = hw_breakpoint_type(env->dr[7], reg);
- if ((type == 0 && env->dr[reg] == env->eip) ||
- ((type & 1) && env->cpu_watchpoint[reg] &&
- (env->cpu_watchpoint[reg]->flags & BP_WATCHPOINT_HIT))) {
+ for (reg = 0; reg < DR7_MAX_BP; reg++) {
+ bool bp_match = false;
+ bool wp_match = false;
+
+ switch (hw_breakpoint_type(env->dr[7], reg)) {
+ case DR7_TYPE_BP_INST:
+ if (env->dr[reg] == env->eip) {
+ bp_match = true;
+ }
+ break;
+ case DR7_TYPE_DATA_WR:
+ case DR7_TYPE_DATA_RW:
+ if (env->cpu_watchpoint[reg] &&
+ env->cpu_watchpoint[reg]->flags & BP_WATCHPOINT_HIT) {
+ wp_match = true;
+ }
+ break;
+ case DR7_TYPE_IO_RW:
+ break;
+ }
+ if (bp_match || wp_match) {
dr6 |= 1 << reg;
- if (hw_breakpoint_enabled(env->dr[7], reg))
- hit_enabled = 1;
+ if (hw_breakpoint_enabled(env->dr[7], reg)) {
+ hit_enabled = true;
+ }
}
}
- if (hit_enabled || force_dr6_update)
+
+ if (hit_enabled || force_dr6_update) {
env->dr[6] = dr6;
+ }
+
return hit_enabled;
}
@@ -1040,16 +1066,17 @@ void breakpoint_handler(CPUX86State *env)
if (env->watchpoint_hit) {
if (env->watchpoint_hit->flags & BP_CPU) {
env->watchpoint_hit = NULL;
- if (check_hw_breakpoints(env, 0))
+ if (check_hw_breakpoints(env, false)) {
raise_exception(env, EXCP01_DB);
- else
+ } else {
cpu_resume_from_signal(env, NULL);
+ }
}
} else {
QTAILQ_FOREACH(bp, &env->breakpoints, entry)
if (bp->pc == env->eip) {
if (bp->flags & BP_CPU) {
- check_hw_breakpoints(env, 1);
+ check_hw_breakpoints(env, true);
raise_exception(env, EXCP01_DB);
}
break;
@@ -1059,7 +1086,7 @@ void breakpoint_handler(CPUX86State *env)
typedef struct MCEInjectionParams {
Monitor *mon;
- CPUX86State *env;
+ X86CPU *cpu;
int bank;
uint64_t status;
uint64_t mcg_status;
@@ -1071,7 +1098,8 @@ typedef struct MCEInjectionParams {
static void do_inject_x86_mce(void *data)
{
MCEInjectionParams *params = data;
- CPUX86State *cenv = params->env;
+ CPUX86State *cenv = &params->cpu->env;
+ CPUState *cpu = CPU(params->cpu);
uint64_t *banks = cenv->mce_banks + 4 * params->bank;
cpu_synchronize_state(cenv);
@@ -1094,7 +1122,7 @@ static void do_inject_x86_mce(void *data)
if ((cenv->mcg_cap & MCG_CTL_P) && cenv->mcg_ctl != ~(uint64_t)0) {
monitor_printf(params->mon,
"CPU %d: Uncorrected error reporting disabled\n",
- cenv->cpu_index);
+ cpu->cpu_index);
return;
}
@@ -1106,7 +1134,7 @@ static void do_inject_x86_mce(void *data)
monitor_printf(params->mon,
"CPU %d: Uncorrected error reporting disabled for"
" bank %d\n",
- cenv->cpu_index, params->bank);
+ cpu->cpu_index, params->bank);
return;
}
@@ -1115,7 +1143,7 @@ static void do_inject_x86_mce(void *data)
monitor_printf(params->mon,
"CPU %d: Previous MCE still in progress, raising"
" triple fault\n",
- cenv->cpu_index);
+ cpu->cpu_index);
qemu_log_mask(CPU_LOG_RESET, "Triple fault\n");
qemu_system_reset_request();
return;
@@ -1148,7 +1176,7 @@ void cpu_x86_inject_mce(Monitor *mon, X86CPU *cpu, int bank,
CPUX86State *cenv = &cpu->env;
MCEInjectionParams params = {
.mon = mon,
- .env = cenv,
+ .cpu = cpu,
.bank = bank,
.status = status,
.mcg_status = mcg_status,
@@ -1188,7 +1216,7 @@ void cpu_x86_inject_mce(Monitor *mon, X86CPU *cpu, int bank,
if (cenv == env) {
continue;
}
- params.env = env;
+ params.cpu = x86_env_get_cpu(env);
run_on_cpu(CPU(cpu), do_inject_x86_mce, &params);
}
}
diff --git a/target-i386/machine.c b/target-i386/machine.c
index 8354572..8df6a6b 100644
--- a/target-i386/machine.c
+++ b/target-i386/machine.c
@@ -265,10 +265,11 @@ static int cpu_post_load(void *opaque, int version_id)
cpu_breakpoint_remove_all(env, BP_CPU);
cpu_watchpoint_remove_all(env, BP_CPU);
- for (i = 0; i < 4; i++)
+ for (i = 0; i < DR7_MAX_BP; i++) {
hw_breakpoint_insert(env, i);
-
+ }
tlb_flush(env, 1);
+
return 0;
}
diff --git a/target-i386/misc_helper.c b/target-i386/misc_helper.c
index db3126b..b6d5740 100644
--- a/target-i386/misc_helper.c
+++ b/target-i386/misc_helper.c
@@ -110,7 +110,7 @@ void helper_into(CPUX86State *env, int next_eip_addend)
void helper_single_step(CPUX86State *env)
{
#ifndef CONFIG_USER_ONLY
- check_hw_breakpoints(env, 1);
+ check_hw_breakpoints(env, true);
env->dr[6] |= DR6_BS;
#endif
raise_exception(env, EXCP01_DB);
@@ -197,11 +197,11 @@ void helper_movl_drN_T0(CPUX86State *env, int reg, target_ulong t0)
env->dr[reg] = t0;
hw_breakpoint_insert(env, reg);
} else if (reg == 7) {
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < DR7_MAX_BP; i++) {
hw_breakpoint_remove(env, i);
}
env->dr[7] = t0;
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < DR7_MAX_BP; i++) {
hw_breakpoint_insert(env, i);
}
} else {
@@ -580,14 +580,17 @@ void helper_monitor(CPUX86State *env, target_ulong ptr)
void helper_mwait(CPUX86State *env, int next_eip_addend)
{
+ CPUState *cpu;
+
if ((uint32_t)ECX != 0) {
raise_exception(env, EXCP0D_GPF);
}
cpu_svm_check_intercept_param(env, SVM_EXIT_MWAIT, 0);
EIP += next_eip_addend;
+ cpu = CPU(x86_env_get_cpu(env));
/* XXX: not complete but not completely erroneous */
- if (env->cpu_index != 0 || env->next_cpu != NULL) {
+ if (cpu->cpu_index != 0 || env->next_cpu != NULL) {
/* more than one CPU: do not sleep because another CPU may
wake this one */
} else {
diff --git a/target-i386/seg_helper.c b/target-i386/seg_helper.c
index c2a99ee..3247dee 100644
--- a/target-i386/seg_helper.c
+++ b/target-i386/seg_helper.c
@@ -465,13 +465,14 @@ static void switch_tss(CPUX86State *env, int tss_selector,
#ifndef CONFIG_USER_ONLY
/* reset local breakpoints */
- if (env->dr[7] & 0x55) {
- for (i = 0; i < 4; i++) {
- if (hw_breakpoint_enabled(env->dr[7], i) == 0x1) {
+ if (env->dr[7] & DR7_LOCAL_BP_MASK) {
+ for (i = 0; i < DR7_MAX_BP; i++) {
+ if (hw_local_breakpoint_enabled(env->dr[7], i) &&
+ !hw_global_breakpoint_enabled(env->dr[7], i)) {
hw_breakpoint_remove(env, i);
}
}
- env->dr[7] &= ~0x55;
+ env->dr[7] &= ~DR7_LOCAL_BP_MASK;
}
#endif
}