]>
Commit | Line | Data |
---|---|---|
14ed5546 FE |
1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
2 | From: Paolo Bonzini <pbonzini@redhat.com> | |
3 | Date: Fri, 29 Apr 2022 21:16:28 +0200 | |
4 | Subject: [PATCH] target/i386: do not consult nonexistent host leaves | |
5 | ||
6 | When cache_info_passthrough is requested, QEMU passes the host values | |
7 | of the cache information CPUID leaves down to the guest. However, | |
8 | it blindly assumes that the CPUID leaf exists on the host, and this | |
9 | cannot be guaranteed: for example, KVM has recently started to | |
10 | synthesize AMD leaves up to 0x80000021 in order to provide accurate | |
11 | CPU bug information to guests. | |
12 | ||
13 | Querying a nonexistent host leaf fills the output arguments of | |
14 | host_cpuid with data that (albeit deterministic) is nonsensical | |
15 | as cache information, namely the data in the highest Intel CPUID | |
16 | leaf. If said highest leaf is not ECX-dependent, this can even | |
17 | cause an infinite loop when kvm_arch_init_vcpu prepares the input | |
18 | to KVM_SET_CPUID2. The infinite loop is only terminated by an | |
19 | abort() when the array gets full. | |
20 | ||
21 | Reported-by: Maxim Levitsky <mlevitsk@redhat.com> | |
22 | Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com> | |
23 | Cc: qemu-stable@nongnu.org | |
24 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | |
25 | (cherry-picked from commit 798d8ec0dacd4cc0034298d94f430c14f23e2919) | |
26 | Signed-off-by: Fabian Ebner <f.ebner@proxmox.com> | |
27 | --- | |
28 | target/i386/cpu.c | 41 ++++++++++++++++++++++++++++++++++++----- | |
29 | 1 file changed, 36 insertions(+), 5 deletions(-) | |
30 | ||
31 | diff --git a/target/i386/cpu.c b/target/i386/cpu.c | |
32 | index 6e6945139b..c79e151887 100644 | |
33 | --- a/target/i386/cpu.c | |
34 | +++ b/target/i386/cpu.c | |
35 | @@ -5030,6 +5030,37 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, | |
36 | return r; | |
37 | } | |
38 | ||
39 | +static void x86_cpu_get_cache_cpuid(uint32_t func, uint32_t index, | |
40 | + uint32_t *eax, uint32_t *ebx, | |
41 | + uint32_t *ecx, uint32_t *edx) | |
42 | +{ | |
43 | + uint32_t level, unused; | |
44 | + | |
45 | + /* Only return valid host leaves. */ | |
46 | + switch (func) { | |
47 | + case 2: | |
48 | + case 4: | |
49 | + host_cpuid(0, 0, &level, &unused, &unused, &unused); | |
50 | + break; | |
51 | + case 0x80000005: | |
52 | + case 0x80000006: | |
53 | + case 0x8000001d: | |
54 | + host_cpuid(0x80000000, 0, &level, &unused, &unused, &unused); | |
55 | + break; | |
56 | + default: | |
57 | + return; | |
58 | + } | |
59 | + | |
60 | + if (func > level) { | |
61 | + *eax = 0; | |
62 | + *ebx = 0; | |
63 | + *ecx = 0; | |
64 | + *edx = 0; | |
65 | + } else { | |
66 | + host_cpuid(func, index, eax, ebx, ecx, edx); | |
67 | + } | |
68 | +} | |
69 | + | |
70 | /* | |
71 | * Only for builtin_x86_defs models initialized with x86_register_cpudef_types. | |
72 | */ | |
73 | @@ -5288,7 +5319,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, | |
74 | case 2: | |
75 | /* cache info: needed for Pentium Pro compatibility */ | |
76 | if (cpu->cache_info_passthrough) { | |
77 | - host_cpuid(index, 0, eax, ebx, ecx, edx); | |
78 | + x86_cpu_get_cache_cpuid(index, 0, eax, ebx, ecx, edx); | |
79 | break; | |
80 | } else if (cpu->vendor_cpuid_only && IS_AMD_CPU(env)) { | |
81 | *eax = *ebx = *ecx = *edx = 0; | |
82 | @@ -5308,7 +5339,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, | |
83 | case 4: | |
84 | /* cache info: needed for Core compatibility */ | |
85 | if (cpu->cache_info_passthrough) { | |
86 | - host_cpuid(index, count, eax, ebx, ecx, edx); | |
87 | + x86_cpu_get_cache_cpuid(index, count, eax, ebx, ecx, edx); | |
88 | /* QEMU gives out its own APIC IDs, never pass down bits 31..26. */ | |
89 | *eax &= ~0xFC000000; | |
90 | if ((*eax & 31) && cs->nr_cores > 1) { | |
91 | @@ -5710,7 +5741,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, | |
92 | case 0x80000005: | |
93 | /* cache info (L1 cache) */ | |
94 | if (cpu->cache_info_passthrough) { | |
95 | - host_cpuid(index, 0, eax, ebx, ecx, edx); | |
96 | + x86_cpu_get_cache_cpuid(index, 0, eax, ebx, ecx, edx); | |
97 | break; | |
98 | } | |
99 | *eax = (L1_DTLB_2M_ASSOC << 24) | (L1_DTLB_2M_ENTRIES << 16) | | |
100 | @@ -5723,7 +5754,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, | |
101 | case 0x80000006: | |
102 | /* cache info (L2 cache) */ | |
103 | if (cpu->cache_info_passthrough) { | |
104 | - host_cpuid(index, 0, eax, ebx, ecx, edx); | |
105 | + x86_cpu_get_cache_cpuid(index, 0, eax, ebx, ecx, edx); | |
106 | break; | |
107 | } | |
108 | *eax = (AMD_ENC_ASSOC(L2_DTLB_2M_ASSOC) << 28) | | |
109 | @@ -5783,7 +5814,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, | |
110 | case 0x8000001D: | |
111 | *eax = 0; | |
112 | if (cpu->cache_info_passthrough) { | |
113 | - host_cpuid(index, count, eax, ebx, ecx, edx); | |
114 | + x86_cpu_get_cache_cpuid(index, count, eax, ebx, ecx, edx); | |
115 | break; | |
116 | } | |
117 | switch (count) { |