feat: kvm and qemu patches grouped by the detection each clears

This commit is contained in:
2026-09-06 00:14:56 +02:00
commit 2e5269995a
17 changed files with 1912 additions and 0 deletions

9
LICENSE Normal file
View File

@@ -0,0 +1,9 @@
This project consists of patches to the Linux kernel and to QEMU, plus tooling
that configures and measures a libvirt guest.
The kernel patches under patches/kvm/ and the QEMU patches under patches/qemu/
are derivative works of GPL-2.0 projects and are distributed under GPL-2.0.
The scripts, packaging and benchmark are likewise GPL-2.0 for consistency.
See https://www.gnu.org/licenses/old-licenses/gpl-2.0.html

86
patches/README.md Normal file
View File

@@ -0,0 +1,86 @@
# Patchsets, by the detection each one clears
Every patch here is grouped by the VMAware check it targets, so a patchset can be taken or left
on its own. Apply from the relevant source root with `patch -p1 < <file>`.
## KVM - `kvm/`
Built against kernel 7.2.x. Builds as `arch/x86/kvm` only, about five minutes; no full kernel
build is needed. See `packaging/` for a PKGBUILD that does it and keeps it rebuilt.
| Patch | Clears | What it does |
| --- | --- | --- |
| `0001-KVM-SVM-intercept-GP-when-guest-EFER.SVME-is-clear` | `SVM_EXCEPTIONS` | Closes a `FIXME` KVM already carries: a CPL3 SVM instruction faults `#GP` where hardware gives `#UD`. |
| `0002-KVM-x86-emulator-UD-not-GP-for-VMCALL-at-CPL-0` | `KVM_INTERCEPTION` | Adds `PrivUD` so `VMCALL` at CPL>0 raises `#UD` like hardware. |
| `0003-KVM-x86-UD-for-KVM-hypercalls-issued-at-CPL-0` | `KVM_INTERCEPTION` | A CPL>0 hypercall raised no exception at all; now raises `#UD`. |
| `0004-KVM-SVM-intercept-ICEBP-and-skip-it-before-injecting-its-DB` | `DBVM` | SVM re-injected the `ICEBP` `#DB` with RIP still on the `F1` byte; VMX and hardware report the next instruction. |
| `0005-KVM-selftests-verify-ICEBP-DB-reports-RIP-past-the-ICEBP` | - | The selftest for 0004: fails on unpatched SVM, passes with it. |
| `EXPERIMENTAL-0006-runtime-cpuid-passthrough` | `TIMER` | Drops CPUID and RDPRU interception on a 1:1-pinned vCPU and reprograms the AMD Processor Name String MSRs so raw `CPUID` still returns the declared brand. Opt-in via the `cpuid_passthrough` module parameter. |
**0002 and 0003 are a pair.** Either alone leaves `KVM_INTERCEPTION` standing, because the check
tries two stubs and only reports the first one that misbehaves.
The first five are written to be acceptable upstream: they make KVM match the architecture rather
than add anything on top of it, each carries its rationale in the commit message, and all four
pass `checkpatch.pl --strict`. `0000-cover-letter.txt` is the series cover letter. They
have been tested on AMD only; 0002 and 0003 are vendor-neutral code and the Intel reasoning is in
the cover letter.
**`EXPERIMENTAL-0006` is built into the `vfio-native-kvm-dkms` package but off by default.** It
removes the cost the `TIMER` instruction-latency detector measures, and with it the guest reads
raw host CPUID, so it applies itself only to vCPU threads confined to exactly one CPU and must be
enabled through the `cpuid_passthrough` module parameter after the guest has booted.
`docs/ANALYSIS.md` has the measurements and the constraints.
## QEMU - `qemu/`
Against QEMU v11.1.1. Apply in numeric order.
| Patch | Clears |
| --- | --- |
| `01-firmware` | `FIRMWARE` - ACPI link-device names, `PNP0A06` stubs, FADT C-state latencies |
| `02-disk-identity` | `VIRTUAL_DISK`, `DISK_SERIAL` - `QEMU HARDDISK`, empty serials, SCSI inquiry strings |
| `03-pci-ids` | `PCI_VENDOR`, `DEVICES` - Red Hat/QEMU vendor and subsystem IDs, ICH9 layout |
| `04-fw-cfg` | `QEMU_FW_CFG` - the fw_cfg device signature |
| `05-usb-hid` | `QEMU_USB` - USB HID descriptor strings |
| `06-audio` | `DEVICES` - HDA codec and controller identity |
| `07-edid` | none. Carried for other detectors; VMAware does not read EDID. |
| `08-cpu-misc` | none. CPU feature plumbing and one upstream backport. |
`patch -p1 < qemu/01-firmware.patch` and so on, then build with the prefix set to `/opt` so the
system QEMU package is left alone:
```sh
./configure --prefix=/opt/qemu-native --target-list=x86_64-softmmu
ninja -C build && ninja -C build install
```
## Approaches tried and rejected - kept so they are not re-derived
| Approach | Result |
| --- | --- |
| Patched OVMF firmware (`edk2`) | Builds, then hangs before console init at 100% CPU, cause undiagnosed. Stock OVMF is fine and costs only the boot-logo warning. |
| TSC compensation for `TIMER` (BetterTiming) | No detection change, 6x slower boot. |
| CPUID leaf override (Hypervisor-Phantom) | Halved the timing signature, still detected, and *added* a `SINGLE_STEP` detection. |
| Clearing `INTERCEPT_CPUID` outright | Guest never boots. |
| Intercept clearing, minimal hypercall | Triple fault, or no effect. |
`TIMER` has two detectors that OR together. The exception-latency one passes on stock KVM once it
is measured the way VMAware measures it; the instruction-latency one is removable with
`EXPERIMENTAL-0006`. `docs/ANALYSIS.md` has the measurements, including a direct reproduction of
both in `bench/timerprobe.c`.
## Identity values in these patches
Several patches carry a concrete make and model because no real machine leaves the field blank.
Every one of them is a placeholder. Change them before you use this, or a detector gains a
fingerprint shared by everyone who ran the same patch series.
| Where | Value | Replace with |
| --- | --- | --- |
| `02-disk-identity` | disk serial `S0123456789ABCD` | set `<serial>` on the disk in the domain XML; this fallback then never runs |
| `02-disk-identity` | disk and optical drive model strings | a drive you actually own, from `lsblk -o NAME,MODEL` |
| `07-edid` | monitor vendor and model | your own panel, from `edid-decode < /sys/class/drm/*/edid` |
The SMBIOS values are not patched into QEMU at all - they are domain XML, taken from a real
machine with `dmidecode`. Change every serial there too.

View File

@@ -0,0 +1,105 @@
Subject: [PATCH 0/5] KVM: x86: match the architecture in four guest-observable exception cases
To: Sean Christopherson <seanjc@google.com>, Paolo Bonzini <pbonzini@redhat.com>
Cc: Thomas Gleixner <tglx@kernel.org>, Ingo Molnar <mingo@redhat.com>,
Borislav Petkov <bp@alien8.de>, Dave Hansen <dave.hansen@linux.intel.com>,
"H. Peter Anvin" <hpa@zytor.com>, x86@kernel.org,
kvm@vger.kernel.org, linux-kernel@vger.kernel.org
Four cases where a guest observes a different exception, or a different
RIP in the exception frame, than the same instruction produces on bare
metal. All four are reachable from unprivileged guest code, none needs
a debugger attached, and each is a one-hunk fix on a path KVM already
owns. The series does not add any new behaviour; it makes the existing
behaviour match the AMD64 architecture (and, for 2/5 and 3/5, what the
VMX side of KVM already does).
1/5 KVM: SVM: intercept #GP when guest EFER.SVME is clear
svm_set_efer() forces EFER_SVME=1 in the VMCB, so a CPL>0
VMLOAD/VMSAVE/STGI/CLGI passes the hardware SVME check and #GPs
before the instruction intercept can fire. Bare metal, where
SVME really is clear, #UDs. svm_recalc_instruction_intercepts()
already carries a FIXME for this. Intercept #GP while the
guest's SVME is clear so gp_interception() can decode the
instruction and route it to nested_svm_check_permissions(),
which injects the #UD. SEV guests are excluded as KVM cannot
decode their instructions, mirroring the erratum workaround.
2/5 KVM: x86: emulator: #UD, not #GP, for VMCALL at CPL > 0
group7_rm0[] declares VMCALL as Priv without PrivUD, so the CPL
check in x86_emulate_insn() injects #GP(0). 0F 01 C1 is not an
AMD instruction and is invalid outside VMX operation on Intel;
hardware #UDs at CPL > 0 on both vendors. This path is reached
on AMD through the #UD intercept (a guest built for Intel running
on AMD) and on Intel only under forced emulation.
3/5 KVM: x86: #UD for KVM hypercalls issued at CPL > 0
kvm_emulate_hypercall() returns -KVM_EPERM and skips the
instruction for a CPL > 0 caller, so the guest observes no
exception at all. VMMCALL/VMCALL is only a legal instruction
because the hypervisor intercepts it; bare metal #UDs. Inject
#UD instead. This is a guest-observable ABI change, argued
below.
4/5 KVM: SVM: intercept ICEBP and skip it before injecting its #DB
ICEBP's #DB is trap-like: the exception frame RIP is the next
instruction. SVM does not route ICEBP's #DB through the #DB
exception intercept, so the guest normally takes it correctly,
but when the delivery is interrupted by a VM-exit (an NPT fault
on a cold IDT/handler page) EXITINTINFO reports the pending #DB
with RIP saved on the ICEBP and svm_complete_interrupts()
re-injects it as-is, so the guest handler sees the ICEBP's own
address. VMX tags ICEBP (is_icebp()) and skips the instruction;
SVM has the dedicated ICEBP intercept, which fires before the #DB
exists. Enable it and skip.
5/5 KVM: selftests: verify ICEBP #DB reports RIP past the ICEBP
On the 3/5 ABI change: every KVM_HC_* already fails for a CPL > 0
caller, so only the shape of the failure changes, from a silent skip to
#UD. The Xen and Hyper-V dispatch sit before the check and keep their
own CPL semantics; kvm_hv_hypercall() already injects #UD for CPL > 0
(hyperv.c), so this makes the KVM PV path consistent with it rather
than inventing new behaviour. No in-tree guest issues a KVM hypercall
from userspace: Linux paravirt patches VMMCALL/VMCALL at CPL0 only, and
svm_patch_hypercall() / vmx_patch_hypercall() likewise. Windows guests
issue neither.
Vendor coverage: 1/5 and 4/5 are SVM-only. 2/5 and 3/5 live in
emulate.c and x86.c and affect Intel as well. On VMX a CPL > 0 VMCALL
unconditionally VM-exits to handle_vmcall() -> kvm_emulate_hypercall(),
so 3/5 changes its outcome from "skipped silently" to #UD there too,
which is what VMCALL outside VMX operation does on bare metal. The
series has been tested on AMD only (Zen 4, 7950X); the Intel reasoning
is from the code and has not been run on Intel hardware.
Nested: for 1/5, gp_interception() already routes decoded SVM
instructions from L2 through nested_svm_check_permissions(); when L1
intercepts #GP itself the exit is reflected to L1 as before. For 4/5
the #DB is reflected to L1 with L2's RIP past the ICEBP, matching what
the VMX path does today.
SEV: 1/5 does not arm the #GP intercept for SEV guests, and SEV-ES
guests additionally clear it in sev_es_init_vmcb(). 4/5 uses
svm_skip_emulated_instruction(), which already special-cases SEV-ES.
Testing: a Windows 11 guest, a Linux guest and a Hyper-V-enlightened
Windows guest boot and run normally on the patched modules. The
userspace probes that first exposed the divergences (CPL3 VMLOAD, CPL3
VMMCALL, ICEBP under SEH) now observe #UD / #UD / RIP+1, as on bare
metal, and the ICEBP one no longer regresses when the delivery hits a
cold page. 5/5 fails on unpatched SVM (Zen 4, kvm_exit trace shows the
NPT fault with the #DB pending in EXITINTINFO) and passes with 4/5. A
selftest for the CPL > 0 cases would need user-mode guest code, which
the x86 selftest library does not currently provide.
arch/x86/kvm/emulate.c | 7 ++-
arch/x86/kvm/svm/svm.c | 44 ++++++++++++---
arch/x86/kvm/x86.c | 17 +++++-
tools/testing/selftests/kvm/Makefile.kvm | 1 +
tools/testing/selftests/kvm/x86/icebp_test.c | 58 ++++++++++++++++++++
5 files changed, 117 insertions(+), 10 deletions(-)

View File

@@ -0,0 +1,94 @@
From 0a6b8d86c62bd4caebf27872019c7f66b753d61b Mon Sep 17 00:00:00 2001
From: Sandwich <sandwich@archworks.co>
Date: Sat, 5 Sep 2026 12:02:50 +0200
Subject: [PATCH 1/5] KVM: SVM: intercept #GP when guest EFER.SVME is clear
svm_set_efer() unconditionally sets EFER_SVME in the VMCB, because
hardware requires it to run the guest at all. A guest that has not
itself enabled SVM therefore still runs with SVME set from the CPU's
point of view.
When such a guest executes an SVM instruction at CPL > 0, hardware
passes the SVME check, observes CPL != 0, and injects #GP before the
instruction intercept can fire. Bare metal, where SVME really is clear,
raises #UD instead. The divergence is directly observable from
unprivileged guest code.
svm_recalc_instruction_intercepts() already carries a FIXME describing
exactly this. Close it by intercepting #GP while the guest's EFER.SVME
is clear, so gp_interception() can decode the instruction and route it
to its real handler, which injects the #UD the architecture specifies.
The intercept is kept across a guest clearing SVME, and dropped again on
SVME=1 where the erratum workaround does not need it.
SEV guests are excluded for the same reason the erratum workaround
excludes them: KVM can't decode their instructions, so the intercept
would only reinject the same #GP. SEV-ES guests additionally clear
the #GP intercept in sev_es_init_vmcb().
For nested guests, gp_interception() already routes a decoded SVM
instruction through nested_svm_check_permissions(), which injects #UD
when L2's SVME is clear. When L1 intercepts #GP itself, the exit is
reflected to L1 as before.
Signed-off-by: Sandwich <sandwich@archworks.co>
---
arch/x86/kvm/svm/svm.c | 22 +++++++++++++++-------
1 file changed, 15 insertions(+), 7 deletions(-)
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 1158f3e28..b0db02615 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -237,9 +237,11 @@ int svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
svm_leave_nested(vcpu);
- /* #GP intercept is still needed for vmware backdoor */
- if (!enable_vmware_backdoor)
- clr_exception_intercept(svm, GP_VECTOR);
+ /*
+ * #GP stays intercepted: with SVME=0 it routes CPL>0
+ * SVM instructions to the #UD the architecture requires,
+ * see svm_recalc_instruction_intercepts().
+ */
/*
* Free the nested guest state, unless we are in SMM.
@@ -263,6 +265,8 @@ int svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
*/
if (svm_gp_erratum_intercept && !is_sev_guest(vcpu))
set_exception_intercept(svm, GP_VECTOR);
+ else if (!enable_vmware_backdoor)
+ clr_exception_intercept(svm, GP_VECTOR);
}
svm_pmu_handle_nested_transition(svm);
@@ -1073,16 +1077,20 @@ static void svm_recalc_instruction_intercepts(struct kvm_vcpu *vcpu)
* are set when the VMCB is initialized and never cleared (if the
* relevant intercepts are set, the enablements are meaningless anyway).
*
- * FIXME: When #GP is not intercepted, a #GP on these instructions (e.g.
- * due to CPL > 0) could be injected by hardware before the instruction
- * is intercepted, leading to #GP taking precedence over #UD from the
- * guest's perspective.
+ * Because hardware sees SVME=1, a #GP on these instructions (e.g. due
+ * to CPL > 0) is injected before the instruction intercept fires, and
+ * would take precedence over the #UD the guest should observe. Also
+ * intercept #GP so that gp_interception() can decode the instruction
+ * and route it to its handler, which injects the #UD. SEV guests are
+ * excluded as KVM can't decode their instructions.
*/
if (!(vcpu->arch.efer & EFER_SVME)) {
svm_set_intercept(svm, INTERCEPT_VMLOAD);
svm_set_intercept(svm, INTERCEPT_VMSAVE);
svm_set_intercept(svm, INTERCEPT_CLGI);
svm_set_intercept(svm, INTERCEPT_STGI);
+ if (!is_sev_guest(vcpu))
+ set_exception_intercept(svm, GP_VECTOR);
} else {
/*
* If hardware supports Virtual VMLOAD VMSAVE then enable it
--
2.55.0

View File

@@ -0,0 +1,47 @@
From 9826e3e9edc355aea6b2f2f386e538aa0f199542 Mon Sep 17 00:00:00 2001
From: Sandwich <sandwich@archworks.co>
Date: Sat, 5 Sep 2026 11:58:18 +0200
Subject: [PATCH 2/5] KVM: x86: emulator: #UD, not #GP, for VMCALL at CPL > 0
Targets VMAware check: KVM_INTERCEPTION
0F 01 C1 is not an AMD instruction, and on Intel VMCALL is invalid
outside VMX operation. Hardware raises #UD for it at CPL > 0 on both
vendors.
The emulator declares VMCALL as Priv without PrivUD, so the generic CPL
check injects #GP(0) instead. Windows surfaces that to userspace as an
access violation rather than an illegal instruction, which is guest-
observable and differs from every physical machine.
Add PrivUD so the existing branch injects #UD. RIP is not advanced
either way, and CPL0 VMCALL is unaffected, so a guest built for Intel
and migrated onto an AMD host keeps working through
emulator_fix_hypercall().
Signed-off-by: Sandwich <sandwich@archworks.co>
---
arch/x86/kvm/emulate.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index b566ab5c7..a723d05d9 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -3969,7 +3969,12 @@ static const struct opcode ud = I(SrcNone, emulate_ud);
static const struct opcode group7_rm0[] = {
N,
- I(SrcNone | Priv | EmulateOnUD, em_hypercall),
+ /*
+ * 0F 01 C1 is not an AMD instruction, and on Intel VMCALL is invalid
+ * outside VMX operation, i.e. hardware raises #UD at CPL > 0. Without
+ * PrivUD the CPL check below injects #GP, which is guest-observable.
+ */
+ I(SrcNone | Priv | PrivUD | EmulateOnUD, em_hypercall),
N, N, N, N, N, N,
};
--
2.55.0

View File

@@ -0,0 +1,64 @@
From 122f8478087bd13892672a6feb3e3417e882c316 Mon Sep 17 00:00:00 2001
From: Sandwich <sandwich@archworks.co>
Date: Sat, 5 Sep 2026 11:58:18 +0200
Subject: [PATCH 3/5] KVM: x86: #UD for KVM hypercalls issued at CPL > 0
Targets VMAware check: KVM_INTERCEPTION
VMMCALL is only a legal instruction because the hypervisor intercepts
it; bare metal raises #UD. kvm_emulate_hypercall() instead returns
-KVM_EPERM for a CPL > 0 caller and skips the instruction, so the guest
observes no exception at all - which is directly observable and differs
from every physical machine.
Inject #UD for CPL > 0 instead. Every KVM_HC_* already failed for such
callers, so only the shape of the failure changes, and no legitimate
hypercall is issued from userspace.
The check is placed after the Xen and Hyper-V dispatch, so enlightened
guests keep their own CPL semantics. kvm_hv_hypercall() already does
the identical thing for the Hyper-V ABI, so this makes the KVM PV path
consistent with it.
Signed-off-by: Sandwich <sandwich@archworks.co>
---
arch/x86/kvm/x86.c | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 47cb9eba1..0dd7ebcc0 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -10503,14 +10503,27 @@ EXPORT_SYMBOL_FOR_KVM_INTERNAL(____kvm_emulate_hypercall);
int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
{
+ int cpl;
+
if (kvm_xen_hypercall_enabled(vcpu->kvm))
return kvm_xen_hypercall(vcpu);
if (kvm_hv_hypercall_enabled(vcpu))
return kvm_hv_hypercall(vcpu);
- return __kvm_emulate_hypercall(vcpu, kvm_x86_call(get_cpl)(vcpu),
- complete_hypercall_exit);
+ /*
+ * Bare metal #UDs on VMMCALL from CPL > 0 (the intercept is what
+ * makes it legal at all); returning -KVM_EPERM and skipping the
+ * insn instead is guest-observable. Xen and Hyper-V guests are
+ * dispatched above and keep their own CPL semantics.
+ */
+ cpl = kvm_x86_call(get_cpl)(vcpu);
+ if (cpl) {
+ kvm_queue_exception(vcpu, UD_VECTOR);
+ return 1;
+ }
+
+ return __kvm_emulate_hypercall(vcpu, cpl, complete_hypercall_exit);
}
EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_emulate_hypercall);
--
2.55.0

View File

@@ -0,0 +1,93 @@
From 93bb902ad3516b0c5a31482e27a5ecfd93f6799d Mon Sep 17 00:00:00 2001
From: Sandwich <sandwich@archworks.co>
Date: Sat, 5 Sep 2026 12:31:16 +0200
Subject: [PATCH 4/5] KVM: SVM: intercept ICEBP and skip it before injecting
its #DB
ICEBP (INT1, opcode F1) generates a trap-like #DB: the return RIP pushed
for the exception is that of the instruction following the ICEBP.
SVM does not report ICEBP's #DB through the #DB exception intercept, so
the guest normally takes it directly and correctly. But when delivery
of that #DB is interrupted by a VM-exit - a nested page fault on a cold
IDT, handler or stack page is the common case - the exit reports the
pending #DB in EXITINTINFO with the saved RIP still on the ICEBP, and
svm_complete_interrupts() re-queues it as a plain hardware exception.
The injected #DB then pushes that RIP, so the guest's handler sees the
ICEBP's own address and an IRET re-executes it. The divergence is
observable from unprivileged guest code (an SEH/signal handler reading
the context RIP) and is sporadic, since it needs the delivery to touch
a page KVM has not mapped.
VMX already handles ICEBP: the #DB VM-exit is tagged as a privileged
software exception (is_icebp()) and handle_exception_nmi() skips the
instruction before queueing the #DB. SVM has the equivalent signal in
the dedicated ICEBP instruction intercept, which fires before the #DB
exists.
Enable the ICEBP intercept alongside the #DB exception intercept, skip
the instruction and queue the #DB with the same DR6 payload the
exception path uses. Once RIP has been advanced, an injection that is
itself interrupted is re-injected with the advanced RIP. The vendor
skip helper is used deliberately, as on VMX: a pending single-step #DB
on the ICEBP itself is superseded by the ICEBP's #DB. The emulator
decodes 0xF1, so the non-NRIPS fallback works.
For nested guests the #DB is reflected to L1 with L2's RIP past the
ICEBP, matching what the VMX path does today.
Signed-off-by: Sandwich <sandwich@archworks.co>
---
arch/x86/kvm/svm/svm.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index b0db02615..5b37855ee 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -1153,6 +1153,7 @@ static void init_vmcb(struct kvm_vcpu *vcpu, bool init_event)
set_exception_intercept(svm, MC_VECTOR);
set_exception_intercept(svm, AC_VECTOR);
set_exception_intercept(svm, DB_VECTOR);
+ svm_set_intercept(svm, INTERCEPT_ICEBP);
/*
* Guest access to VMware backdoor ports could legitimately
* trigger #GP because of TSS I/O permission bitmap.
@@ -2078,6 +2079,26 @@ static int db_interception(struct kvm_vcpu *vcpu)
return 1;
}
+static int icebp_interception(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+ u32 payload = svm->vmcb->save.dr6 ^ DR6_ACTIVE_LOW;
+
+ /*
+ * ICEBP generates a trap-like #DB, but is intercepted as an
+ * instruction, i.e. RIP still points at the ICEBP itself. Skip it
+ * before injecting the #DB so the guest observes the RIP of the next
+ * instruction, as it does on bare metal and under VMX (see is_icebp()).
+ * Use the vendor skip helper: a single-step #DB on the ICEBP is
+ * superseded by the ICEBP's own #DB.
+ */
+ if (!svm_skip_emulated_instruction(vcpu))
+ return 0;
+
+ kvm_queue_exception_p(vcpu, DB_VECTOR, payload);
+ return 1;
+}
+
static int bp_interception(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
@@ -3369,6 +3390,7 @@ static int (*const svm_exit_handlers[])(struct kvm_vcpu *vcpu) = {
[SVM_EXIT_WRITE_DR6] = dr_interception,
[SVM_EXIT_WRITE_DR7] = dr_interception,
[SVM_EXIT_EXCP_BASE + DB_VECTOR] = db_interception,
+ [SVM_EXIT_ICEBP] = icebp_interception,
[SVM_EXIT_EXCP_BASE + BP_VECTOR] = bp_interception,
[SVM_EXIT_EXCP_BASE + UD_VECTOR] = ud_interception,
[SVM_EXIT_EXCP_BASE + PF_VECTOR] = pf_interception,
--
2.55.0

View File

@@ -0,0 +1,127 @@
From 1cc0b5d1d2f61b76c2b9124646b827abda525828 Mon Sep 17 00:00:00 2001
From: Sandwich <sandwich@archworks.co>
Date: Sat, 5 Sep 2026 12:31:16 +0200
Subject: [PATCH 5/5] KVM: selftests: verify ICEBP #DB reports RIP past the
ICEBP
Execute ICEBP (INT1) in the guest under a #DB handler that records the
exception frame's RIP, and assert it is the address of the following
instruction, as on bare metal. The handler advances RIP itself if it
finds it still on the ICEBP so a failing KVM does not loop forever.
The first ICEBP in a fresh VM faults on the unmapped IDT and handler
pages during delivery, which is the interrupted-delivery case where SVM
re-injected the #DB with the wrong RIP. Fails on SVM without the
preceding patch, passes with it, and passes on VMX, which already skips
the instruction.
Signed-off-by: Sandwich <sandwich@archworks.co>
---
arch/x86/kvm/svm/svm.c | 7 ++-
tools/testing/selftests/kvm/Makefile.kvm | 1 +
tools/testing/selftests/kvm/x86/icebp_test.c | 63 ++++++++++++++++++++
3 files changed, 68 insertions(+), 3 deletions(-)
create mode 100644 tools/testing/selftests/kvm/x86/icebp_test.c
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 5b37855ee..34e025cba 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -2087,9 +2087,10 @@ static int icebp_interception(struct kvm_vcpu *vcpu)
/*
* ICEBP generates a trap-like #DB, but is intercepted as an
* instruction, i.e. RIP still points at the ICEBP itself. Skip it
- * before injecting the #DB so the guest observes the RIP of the next
- * instruction, as it does on bare metal and under VMX (see is_icebp()).
- * Use the vendor skip helper: a single-step #DB on the ICEBP is
+ * before injecting the #DB so that the guest, and any re-injection
+ * after an exit interrupts the delivery, sees the RIP of the next
+ * instruction, as on bare metal and under VMX (see is_icebp()). Use
+ * the vendor skip helper: a single-step #DB on the ICEBP is
* superseded by the ICEBP's own #DB.
*/
if (!svm_skip_emulated_instruction(vcpu))
diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index 6fc34e9bf..b45fe0a13 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -138,6 +138,7 @@ TEST_GEN_PROGS_x86 += x86/xapic_tpr_test
TEST_GEN_PROGS_x86 += x86/xcr0_cpuid_test
TEST_GEN_PROGS_x86 += x86/xss_msr_test
TEST_GEN_PROGS_x86 += x86/debug_regs
+TEST_GEN_PROGS_x86 += x86/icebp_test
TEST_GEN_PROGS_x86 += x86/tsc_msrs_test
TEST_GEN_PROGS_x86 += x86/vmx_pmu_caps_test
TEST_GEN_PROGS_x86 += x86/xen_shinfo_test
diff --git a/tools/testing/selftests/kvm/x86/icebp_test.c b/tools/testing/selftests/kvm/x86/icebp_test.c
new file mode 100644
index 000000000..7890fa949
--- /dev/null
+++ b/tools/testing/selftests/kvm/x86/icebp_test.c
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * icebp_test
+ *
+ * Verify that the #DB generated by ICEBP (INT1) is delivered with RIP
+ * pointing at the instruction following the ICEBP, as on bare metal.
+ *
+ * The first ICEBP in a fresh VM faults on the not-yet-mapped IDT and
+ * handler pages while the #DB is being delivered, so the delivery is
+ * interrupted by a VM-exit and re-injected by KVM. That is exactly the
+ * case where SVM used to re-inject with RIP still on the ICEBP.
+ */
+#include "test_util.h"
+#include "kvm_util.h"
+#include "processor.h"
+
+static u64 db_rip;
+
+static void db_handler(struct ex_regs *regs)
+{
+ db_rip = regs->rip;
+
+ /* Don't loop forever if RIP was left on the ICEBP itself. */
+ if (*(u8 *)regs->rip == 0xf1)
+ regs->rip++;
+}
+
+static void guest_code(void)
+{
+ u64 next_rip;
+
+ asm volatile(".byte 0xf1\n\t" /* icebp */
+ "1: lea 1b(%%rip), %0"
+ : "=r"(next_rip) : : "memory");
+
+ GUEST_ASSERT_EQ(db_rip, next_rip);
+ GUEST_DONE();
+}
+
+int main(int argc, char *argv[])
+{
+ struct kvm_vcpu *vcpu;
+ struct kvm_vm *vm;
+ struct ucall uc;
+
+ vm = vm_create_with_one_vcpu(&vcpu, guest_code);
+ vm_install_exception_handler(vm, DB_VECTOR, db_handler);
+
+ vcpu_run(vcpu);
+ TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
+
+ switch (get_ucall(vcpu, &uc)) {
+ case UCALL_ABORT:
+ REPORT_GUEST_ASSERT(uc);
+ case UCALL_DONE:
+ break;
+ default:
+ TEST_FAIL("Unknown ucall 0x%lx.", uc.cmd);
+ }
+
+ kvm_vm_free(vm);
+ return 0;
+}
--
2.55.0

View File

@@ -0,0 +1,195 @@
From ddc09a6009d5016130acfd1aa8eef69f99da5972 Mon Sep 17 00:00:00 2001
From: Sandwich <sandwich@archworks.co>
Date: Sat, 5 Sep 2026 12:23:22 +0200
Subject: [PATCH] KVM: SVM: opt-in runtime CPUID passthrough with brand-string
override
NOT FOR UPSTREAM. Targets VMAware check: TIMER (instruction-latency
detector).
The detector times an intercepted CPUID against LFENCE using a cross-core
cache-line counter, so the #VMEXIT world switch itself is what it
measures and no clock can be adjusted to hide it. The only way to stop
paying it is to not exit.
With cpuid_passthrough=1 the CPUID intercept is cleared on every guest
entry and the guest executes raw CPUID. Raw CPUID reports the host SKU,
which contradicts a smaller declared topology, so the AMD Processor Name
String MSRs (0xC0010030-35) are reprogrammed on the pinned core while the
vCPU runs and restored in svm_vcpu_put(). Raw CPUID also advertises
RDPRU, which KVM masks out and #UDs on; the RDPRU intercept is dropped
together with the CPUID one so the guest gets the real instruction.
Constraints, all deliberate:
- AMD only; the name-string MSRs are probed for writability at load and
the brand override is skipped when the probe fails.
- Requires strict 1:1 vCPU pinning, or the override leaks onto host
cores and the guest reads inconsistent brands. The vCPU thread's
allowed-CPU mask is checked on every entry and passthrough is
withheld from any thread not confined to exactly one CPU.
- Enable only after the guest has booted. Windows enumerates KVM's
synthetic leaf-1 bits (x2apic, tsc-deadline) during boot and hangs if
they vanish mid-enumeration.
- The #DB intercept is untouched. Clearing it breaks KVM's single-step
re-injection and DR6 handling, which is separately detectable.
Signed-off-by: Sandwich <sandwich@archworks.co>
---
arch/x86/kvm/svm/svm.c | 120 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 120 insertions(+)
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 34e025cba..bfc316505 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -179,6 +179,120 @@ module_param(vnmi, bool, 0444);
module_param(enable_mediated_pmu, bool, 0444);
+/*
+ * vfio-native: neutralise the VMAware TIMER instruction-latency detector on a
+ * strictly 1:1-pinned guest. That detector times the #VMEXIT world switch on an
+ * intercepted CPUID with a cross-core cache counter; dropping CPUID interception
+ * removes the exit so the guest measures like bare metal. Raw CPUID would then
+ * report the host SKU and trip VMAware's thread/brand checks, so the AMD
+ * Processor Name String MSRs (0xC0010030-35) are reprogrammed on the pinned core
+ * while the guest runs and restored when the vCPU yields the core.
+ *
+ * Opt-in and runtime-toggled (cpuid_passthrough). It does NOT touch the #DB
+ * intercept: clearing that breaks KVM's single-step re-injection and DR6, which
+ * is separately detectable. Requires 1:1 vCPU pinning - without it the dropped
+ * interception and reprogrammed brand leak onto the wrong cores.
+ */
+static bool cpuid_passthrough;
+module_param(cpuid_passthrough, bool, 0644);
+MODULE_PARM_DESC(cpuid_passthrough,
+ "Drop CPUID/RDPRU interception and override the CPU brand on a 1:1-pinned guest (AMD only)");
+
+static char brand_string[48];
+module_param_string(brand_string, brand_string, sizeof(brand_string), 0644);
+MODULE_PARM_DESC(brand_string,
+ "48-byte CPU brand string exposed via CPUID 0x80000002-4 while cpuid_passthrough is active");
+
+#define MSR_AMD_NAME_STRING 0xc0010030 /* AMD Processor Name String, 6 consecutive MSRs */
+
+static u64 hw_brand[6];
+static bool brand_msr_ok __ro_after_init; /* the name-string MSRs are writable here */
+static DEFINE_PER_CPU(bool, brand_applied); /* this core currently holds the override */
+
+static void svm_brand_probe(void)
+{
+ int i;
+
+ if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
+ return;
+ for (i = 0; i < 6; i++)
+ if (rdmsrq_safe(MSR_AMD_NAME_STRING + i, &hw_brand[i]))
+ return;
+ if (wrmsrq_safe(MSR_AMD_NAME_STRING, hw_brand[0])) /* confirm writable */
+ return;
+ brand_msr_ok = true;
+}
+
+/* current cpu, preemption disabled */
+static void svm_brand_write(void)
+{
+ u64 regs[6] = {};
+ int i;
+
+ memcpy(regs, brand_string, sizeof(brand_string));
+ for (i = 0; i < 6; i++)
+ wrmsrq_safe(MSR_AMD_NAME_STRING + i, regs[i]);
+}
+
+/* current cpu, preemption disabled */
+static void svm_brand_restore(void)
+{
+ int i;
+
+ for (i = 0; i < 6; i++)
+ wrmsrq_safe(MSR_AMD_NAME_STRING + i, hw_brand[i]);
+}
+
+/* on guest entry */
+static void svm_passthrough_apply(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+ /*
+ * Only a vCPU thread confined to exactly one CPU may run with raw
+ * CPUID and the brand override: on any other core the override is
+ * missing and the guest reads two different brands. Checking the
+ * thread's own allowed mask here verifies the 1:1 pinning instead of
+ * trusting the operator to have set it.
+ */
+ bool on = cpuid_passthrough && vcpu->guest_debug == 0 &&
+ cpumask_weight(current->cpus_ptr) == 1;
+
+ if (likely(!on)) {
+ if (unlikely(!svm_is_intercept(svm, INTERCEPT_CPUID))) {
+ svm_set_intercept(svm, INTERCEPT_CPUID);
+ svm_set_intercept(svm, INTERCEPT_RDPRU);
+ }
+ if (brand_msr_ok && this_cpu_read(brand_applied)) {
+ svm_brand_restore();
+ this_cpu_write(brand_applied, false);
+ }
+ return;
+ }
+
+ if (svm_is_intercept(svm, INTERCEPT_CPUID)) {
+ svm_clr_intercept(svm, INTERCEPT_CPUID);
+ /*
+ * Raw CPUID advertises RDPRU, which KVM masks out and #UDs on.
+ * A guest that sees the bit and executes the instruction must
+ * get the real one, or the #UD is itself a hypervisor tell.
+ */
+ svm_clr_intercept(svm, INTERCEPT_RDPRU);
+ }
+ if (brand_msr_ok && !this_cpu_read(brand_applied)) {
+ svm_brand_write();
+ this_cpu_write(brand_applied, true);
+ }
+}
+
+/* current cpu, preemption disabled */
+static void svm_passthrough_leave_cpu(void)
+{
+ if (brand_msr_ok && this_cpu_read(brand_applied)) {
+ svm_brand_restore();
+ this_cpu_write(brand_applied, false);
+ }
+}
+
static bool __ro_after_init svm_gp_erratum_intercept = true;
static u8 rsm_ins_bytes[] = "\x0f\xaa";
@@ -1500,6 +1614,8 @@ static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
static void svm_vcpu_put(struct kvm_vcpu *vcpu)
{
+ svm_passthrough_leave_cpu();
+
if (kvm_vcpu_apicv_active(vcpu))
avic_vcpu_put(vcpu);
@@ -4517,6 +4633,8 @@ static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu, u64 run_flags)
struct vcpu_svm *svm = to_svm(vcpu);
unsigned enter_flags = 0;
+ svm_passthrough_apply(vcpu);
+
if (!msr_write_intercepted(svm, MSR_IA32_SPEC_CTRL))
enter_flags |= KVM_ENTER_SAVE_SPEC_CTRL;
@@ -5652,6 +5770,8 @@ static __init int svm_hardware_setup(void)
void *iopm_va;
int cpu, r;
+ svm_brand_probe();
+
/*
* NX is required for shadow paging and for NPT if the NX huge pages
* mitigation is enabled.
--
2.55.0

View File

@@ -0,0 +1,397 @@
Subject: [PATCH] firmware: FIRMWARE
Targets VMAware check: FIRMWARE
ACPI table fingerprints: PCI link-device names, PNP0A06 resource stubs, the
FADT C-state latencies and the AML the checker string-matches on.
Applies to QEMU v11.1.1. Apply from the source root with:
patch -p1 < 01-firmware.patch
---
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 8837b69..4001d9d 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -165,8 +165,8 @@ static void init_common_fadt_data(MachineState *ms, Object *o,
(1 << ACPI_FADT_F_FORCE_APIC_CLUSTER_MODEL) : 0),
.int_model = 1 /* Multiple APIC */,
.rtc_century = RTC_CENTURY,
- .plvl2_lat = 0xfff /* C2 state not supported */,
- .plvl3_lat = 0xfff /* C3 state not supported */,
+ .plvl2_lat = 0xffe /* C2 state not supported */,
+ .plvl3_lat = 0xffe /* C3 state not supported */,
.smi_cmd = smm_enabled ? ACPI_PORT_SMI_CMD : 0,
.sci_int = object_property_get_uint(o, ACPI_PM_PROP_SCI_INT, NULL),
.acpi_enable_cmd =
@@ -748,9 +748,9 @@ static void build_q35_pci0_int(Aml *table)
aml_append(table, method);
aml_append(pci0_scope,
- aml_name_decl("PRTP", build_q35_routing_table("LNK")));
+ aml_name_decl("IRQP", build_q35_routing_table("LNK")));
aml_append(pci0_scope,
- aml_name_decl("PRTA", build_q35_routing_table("GSI")));
+ aml_name_decl("IRQA", build_q35_routing_table("APC")));
method = aml_method("_PRT", 0, AML_NOTSERIALIZED);
{
@@ -762,10 +762,10 @@ static void build_q35_pci0_int(Aml *table)
/* Note: we provide the same info as the PCI routing
table of the Bochs BIOS */
if_ctx = aml_if(aml_equal(aml_name("PICF"), aml_int(0)));
- aml_append(if_ctx, aml_return(aml_name("PRTP")));
+ aml_append(if_ctx, aml_return(aml_name("IRQP")));
aml_append(method, if_ctx);
else_ctx = aml_else();
- aml_append(else_ctx, aml_return(aml_name("PRTA")));
+ aml_append(else_ctx, aml_return(aml_name("IRQA")));
aml_append(method, else_ctx);
}
aml_append(pci0_scope, method);
@@ -783,14 +783,14 @@ static void build_q35_pci0_int(Aml *table)
aml_append(sb_scope, build_link_dev("LNKG", 6, aml_name("PRQG")));
aml_append(sb_scope, build_link_dev("LNKH", 7, aml_name("PRQH")));
- aml_append(sb_scope, build_gsi_link_dev("GSIA", 0x10, 0x10));
- aml_append(sb_scope, build_gsi_link_dev("GSIB", 0x11, 0x11));
- aml_append(sb_scope, build_gsi_link_dev("GSIC", 0x12, 0x12));
- aml_append(sb_scope, build_gsi_link_dev("GSID", 0x13, 0x13));
- aml_append(sb_scope, build_gsi_link_dev("GSIE", 0x14, 0x14));
- aml_append(sb_scope, build_gsi_link_dev("GSIF", 0x15, 0x15));
- aml_append(sb_scope, build_gsi_link_dev("GSIG", 0x16, 0x16));
- aml_append(sb_scope, build_gsi_link_dev("GSIH", 0x17, 0x17));
+ aml_append(sb_scope, build_gsi_link_dev("APCA", 0x10, 0x10));
+ aml_append(sb_scope, build_gsi_link_dev("APCB", 0x11, 0x11));
+ aml_append(sb_scope, build_gsi_link_dev("APCC", 0x12, 0x12));
+ aml_append(sb_scope, build_gsi_link_dev("APCD", 0x13, 0x13));
+ aml_append(sb_scope, build_gsi_link_dev("APCE", 0x14, 0x14));
+ aml_append(sb_scope, build_gsi_link_dev("APCF", 0x15, 0x15));
+ aml_append(sb_scope, build_gsi_link_dev("APCG", 0x16, 0x16));
+ aml_append(sb_scope, build_gsi_link_dev("APCH", 0x17, 0x17));
aml_append(table, sb_scope);
}
@@ -801,7 +801,7 @@ static Aml *build_q35_dram_controller(const AcpiMcfgInfo *mcfg)
Aml *resource_template;
/* DRAM controller */
- dev = aml_device("DRAC");
+ dev = aml_device("MCFG");
aml_append(dev, aml_name_decl("_HID", aml_string("PNP0C01")));
resource_template = aml_resource_template();
@@ -885,7 +885,6 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
acpi_table_begin(&table, table_data);
dsdt = init_aml_allocator();
- build_dbg_aml(dsdt);
if (i440fx) {
sb_scope = aml_scope("_SB");
dev = aml_device("PCI0");
@@ -901,6 +900,36 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
build_piix4_pci0_int(dsdt);
} else if (q35) {
sb_scope = aml_scope("_SB");
+
+ /*
+ * Emulate Windows ACPI OSYS/_OSI logic in DSDT.
+ * Adds Windows 2001/2006/2009/2012/2013/2015.
+ */
+ static const struct {
+ const char *osi;
+ uint32_t osys;
+ } win_osi[] = {
+ { "Windows 2001", 0x07D1 },
+ { "Windows 2001 SP1", 0x07D1 },
+ { "Windows 2001 SP2", 0x07D2 },
+ { "Windows 2001.1", 0x07D3 },
+ { "Windows 2006", 0x07D6 },
+ { "Windows 2009", 0x07D9 },
+ { "Windows 2012", 0x07DC },
+ { "Windows 2013", 0x07DD },
+ { "Windows 2015", 0x07DF },
+ };
+
+ aml_append(sb_scope, aml_name_decl("OSYS", aml_int(0x03E8)));
+
+ for (unsigned n = 0; n < ARRAY_SIZE(win_osi); n++) {
+ Aml *osi = aml_if(aml_equal(
+ aml_call1("_OSI", aml_string("%s", win_osi[n].osi)), aml_int(1)));
+ aml_append(osi, aml_store(aml_int(win_osi[n].osys),
+ aml_name("OSYS")));
+ aml_append(sb_scope, osi);
+ }
+
dev = aml_device("PCI0");
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A08")));
aml_append(dev, aml_name_decl("_CID", aml_eisaid("PNP0A03")));
@@ -916,7 +945,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
/* reserve SMI block resources, IO ports 0xB2, 0xB3 */
dev = aml_device("PCI0.SMI0");
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A06")));
- aml_append(dev, aml_name_decl("_UID", aml_string("SMI resources")));
+ aml_append(dev, aml_name_decl("_UID", aml_string("Reserved resources A")));
crs = aml_resource_template();
aml_append(crs,
aml_io(
@@ -967,22 +996,6 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
}
aml_append(dsdt, scope);
- {
- CPUHotplugFeatures opts = {
- .acpi_1_compatible = true,
- .smi_path = pm->smi_on_cpuhp ? "\\_SB.PCI0.SMI0.SMIC" : NULL,
- .fw_unplugs_cpu = pm->smi_on_cpu_unplug,
- };
- build_cpus_aml(dsdt, machine, opts, pc_madt_cpu_entry,
- pm->cpu_hp_io_base, "\\_SB.PCI0", "\\_GPE._E02",
- AML_SYSTEM_IO);
- }
-
- if (pcms->memhp_io_base && nr_mem) {
- build_memory_hotplug_aml(dsdt, nr_mem, "\\_SB.PCI0",
- "\\_GPE._E03", AML_SYSTEM_IO,
- pcms->memhp_io_base);
- }
crs_range_set_init(&crs_range_set);
bus = PC_MACHINE(machine)->pcibus;
@@ -1133,9 +1146,9 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
aml_append(scope, aml_name_decl("_CRS", crs));
/* reserve GPE0 block resources */
- dev = aml_device("GPE0");
+ dev = aml_device("RSRA");
aml_append(dev, aml_name_decl("_HID", aml_string("PNP0A06")));
- aml_append(dev, aml_name_decl("_UID", aml_string("GPE0 resources")));
+ aml_append(dev, aml_name_decl("_UID", aml_int(0)));
/* device present, functioning, decoding, not shown in UI */
aml_append(dev, aml_name_decl("_STA", aml_int(0xB)));
crs = aml_resource_template();
@@ -1188,12 +1201,6 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
aml_append(scope, aml_name_decl("_S5", pkg));
aml_append(dsdt, scope);
- /* create fw_cfg node, unconditionally */
- {
- scope = aml_scope("\\_SB.PCI0");
- fw_cfg_add_acpi_dsdt(scope, x86ms->fw_cfg);
- aml_append(dsdt, scope);
- }
sb_scope = aml_scope("\\_SB");
{
@@ -2168,8 +2175,6 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
x86ms->oem_id, x86ms->oem_table_id, &pcms->cxl_devices_state);
}
- acpi_add_table(table_offsets, tables_blob);
- build_waet(tables_blob, tables->linker, x86ms->oem_id, x86ms->oem_table_id);
if (pcms->wdat_enabled == true) {
g_assert(pm.tco_io_base);
diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c
index 87162ff..4c303cb 100644
--- a/hw/acpi/pcihp.c
+++ b/hw/acpi/pcihp.c
@@ -687,10 +687,10 @@ void build_append_pcihp_resources(Aml *scope /* \\_SB.PCI0 */,
{
Aml *dev, *crs;
- dev = aml_device("PHPR");
+ dev = aml_device("RSRB");
aml_append(dev, aml_name_decl("_HID", aml_string("PNP0A06")));
aml_append(dev,
- aml_name_decl("_UID", aml_string("PCI Hotplug resources")));
+ aml_name_decl("_UID", aml_string("Reserved resources B")));
/* device present, functioning, decoding, not shown in UI */
aml_append(dev, aml_name_decl("_STA", aml_int(0xB)));
crs = aml_resource_template();
@@ -699,6 +699,83 @@ void build_append_pcihp_resources(Aml *scope /* \\_SB.PCI0 */,
aml_append(scope, dev);
}
+/*
+ * Helper to generate "Real Hardware" looking ACPI names.
+ * This removes the "S<hex>" signature and ensures unique naming
+ * for multifunction devices.
+ */
+static void get_mimic_pci_name(char *name, int devfn) {
+ int slot = PCI_SLOT(devfn);
+ int func = PCI_FUNC(devfn);
+
+ switch (slot) {
+ case 0:
+ // Host Bridge is almost always Slot 0, Function 0 (and also bus 0 but we cant access bus number in this context)
+ if (func == 0) sprintf(name, "MCHC");
+ else sprintf(name, "H%X", func);
+ break;
+
+ case 2:
+ // Slot 2: Graphics + associated HDMI Audio
+ if (func == 0) sprintf(name, "GFX0"); // Primary GPU
+ else if (func == 1) sprintf(name, "HDAU"); // HDMI Audio
+ else sprintf(name, "GFX%X", func); // Fallback uniqueness
+ break;
+
+ case 3:
+ // Slot 3: Network
+ if (func == 0) sprintf(name, "GLAN");
+ else sprintf(name, "NET%X", func);
+ break;
+
+ case 4:
+ // Slot 4: Multimedia / Audio
+ if (func == 0) sprintf(name, "HDEF");
+ else sprintf(name, "MM%02X", func);
+ break;
+
+ case 5:
+ // Slot 5: USB XHCI (QEMU default often)
+ if (func == 0) sprintf(name, "XHC1");
+ else sprintf(name, "XHC%X", func);
+ break;
+
+ case 6:
+ // Slot 6: SATA (AHCI)
+ if (func == 0) sprintf(name, "SAT0");
+ else sprintf(name, "SAT%X", func);
+ break;
+
+ case 29:
+ // Slot 29 (0x1D): USB EHCI (Intel Standard)
+ if (func == 0) sprintf(name, "EHC1");
+ else sprintf(name, "EHC%X", func);
+ break;
+
+ case 20:
+ // Slot 20 (0x14): LPC / SMBus / SATA 2
+ if (func == 0) sprintf(name, "LPCB"); // ISA Bridge
+ else if (func == 2) sprintf(name, "SAT1"); // 2nd SATA
+ else if (func == 3) sprintf(name, "SBUS"); // SMBus
+ else sprintf(name, "S20%X", func); // Fallback
+ break;
+
+ default:
+ /*
+ * For generic slots, we use "RP" (Root Port) + devfn (Hex).
+ *
+ * Why 'devfn' and not 'slot'?
+ * - Slot 10, Func 0 (devfn 0x50) -> RP50
+ * - Slot 10, Func 1 (devfn 0x51) -> RP51
+ *
+ * This guarantees ACPI uniqueness for multifunction devices
+ * while completely breaking the "S" + hex signature.
+ */
+ sprintf(name, "RP%02X", devfn);
+ break;
+ }
+}
+
bool build_append_notification_callback(Aml *parent_scope, const PCIBus *bus)
{
Aml *method;
@@ -912,7 +989,11 @@ void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus)
}
/* start to compose PCI device descriptor */
- dev = aml_device("S%.02X", devfn);
+
+ char mimic_name[5];
+ get_mimic_pci_name(mimic_name, devfn);
+ dev = aml_device("%s", mimic_name);
+
aml_append(dev, aml_name_decl("_ADR", aml_int(adr)));
call_dev_aml_func(DEVICE(bus->devices[devfn]), dev);
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index 990abc6..01c8fc4 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -1751,15 +1751,14 @@ void acpi_table_begin(AcpiTable *desc, GArray *array)
* reserve space for Length field, which will be patched by
* acpi_table_end() when the table creation is finished.
*/
- build_append_int_noprefix(array, 0, 4); /* Length */
- build_append_int_noprefix(array, desc->rev, 1); /* Revision */
- build_append_int_noprefix(array, 0, 1); /* Checksum */
- build_append_padded_str(array, desc->oem_id, 6, '\0'); /* OEMID */
- /* OEM Table ID */
- build_append_padded_str(array, desc->oem_table_id, 8, '\0');
- build_append_int_noprefix(array, 1, 4); /* OEM Revision */
- g_array_append_vals(array, ACPI_BUILD_APPNAME8, 4); /* Creator ID */
- build_append_int_noprefix(array, 1, 4); /* Creator Revision */
+ build_append_int_noprefix(array, 0, 4); /* Length */
+ build_append_int_noprefix(array, desc->rev, 1); /* Revision */
+ build_append_int_noprefix(array, 0, 1); /* Checksum */
+ build_append_padded_str(array, ACPI_BUILD_APPNAME6, 6, '\0'); /* OEMID */
+ build_append_padded_str(array, ACPI_BUILD_APPNAME8, 8, '\0'); /* OEM Table ID */
+ build_append_int_noprefix(array, 1, 4); /* OEM Revision */
+ g_array_append_vals(array, "ACPI", 4); /* Creator ID */
+ build_append_int_noprefix(array, 1, 4); /* Creator Revision */
}
void acpi_table_end(BIOSLinker *linker, AcpiTable *desc)
@@ -2488,7 +2487,7 @@ void build_fadt(GArray *tbl, BIOSLinker *linker, const AcpiFadtData *f,
/* ACPI1.0: INT_MODEL, ACPI2.0+: Reserved */
build_append_int_noprefix(tbl, f->int_model /* Multiple APIC */, 1);
/* Preferred_PM_Profile */
- build_append_int_noprefix(tbl, 0 /* Unspecified */, 1);
+ build_append_int_noprefix(tbl, 1 /* Desktop */, 1);
build_append_int_noprefix(tbl, f->sci_int, 2); /* SCI_INT */
build_append_int_noprefix(tbl, f->smi_cmd, 4); /* SMI_CMD */
build_append_int_noprefix(tbl, f->acpi_enable_cmd, 1); /* ACPI_ENABLE */
@@ -2585,7 +2584,7 @@ void build_fadt(GArray *tbl, BIOSLinker *linker, const AcpiFadtData *f,
}
/* Hypervisor Vendor Identity */
- build_append_padded_str(tbl, "QEMU", 8, '\0');
+ build_append_int_noprefix(tbl, 0, 8);
/* TODO: extra fields need to be added to support revisions above rev6 */
assert(f->rev == 6);
diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h
index eaff025..9c3b434 100644
--- a/include/hw/acpi/aml-build.h
+++ b/include/hw/acpi/aml-build.h
@@ -5,8 +5,8 @@
#include "hw/acpi/bios-linker-loader.h"
#include "hw/core/cpu.h"
-#define ACPI_BUILD_APPNAME6 "BOCHS "
-#define ACPI_BUILD_APPNAME8 "BXPC "
+#define ACPI_BUILD_APPNAME6 "ALASKA"
+#define ACPI_BUILD_APPNAME8 "A M I "
#define ACPI_BUILD_TABLE_FILE "etc/acpi/tables"
#define ACPI_BUILD_RSDP_FILE "etc/acpi/rsdp"
diff --git a/include/hw/i386/x86.h b/include/hw/i386/x86.h
index 71fe6b5..755c9d8 100644
--- a/include/hw/i386/x86.h
+++ b/include/hw/i386/x86.h
@@ -136,7 +136,7 @@ bool x86_machine_is_acpi_enabled(const X86MachineState *x86ms);
/* Global System Interrupts */
-#define ACPI_BUILD_PCI_IRQS ((1<<5) | (1<<9) | (1<<10) | (1<<11))
+#define ACPI_BUILD_PCI_IRQS ((1<<4) | (1<<5) | (1<<6) | (1<<10) | (1<<11) | (1<<14) | (1<<15))
typedef struct GSIState {
qemu_irq i8259_irq[ISA_NUM_IRQS];
diff --git a/hw/pci-host/gpex.c b/hw/pci-host/gpex.c
index e66784c..8f748f9 100644
--- a/hw/pci-host/gpex.c
+++ b/hw/pci-host/gpex.c
@@ -243,8 +243,8 @@ static void gpex_root_class_init(ObjectClass *klass, const void *data)
dc->desc = "QEMU generic PCIe host bridge";
dc->vmsd = &vmstate_gpex_root;
- k->vendor_id = PCI_VENDOR_ID_REDHAT;
- k->device_id = PCI_DEVICE_ID_REDHAT_PCIE_HOST;
+ k->vendor_id = PCI_VENDOR_ID_AMD;
+ k->device_id = PCI_DEVICE_ID_INTEL_P35_MCH;
k->revision = 0;
k->class_id = PCI_CLASS_BRIDGE_HOST;
/*

View File

@@ -0,0 +1,115 @@
Subject: [PATCH] disk-identity: VIRTUAL_DISK / DISK_SERIAL
Targets VMAware check: VIRTUAL_DISK / DISK_SERIAL
Storage that announces itself as emulated: 'QEMU HARDDISK', 'QEMU DVD-ROM',
empty serials and the QEMU vendor string in SCSI inquiry data.
Applies to QEMU v11.1.1. Apply from the source root with:
patch -p1 < 02-disk-identity.patch
---
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index 1b0cce1..0e8ded4 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -2551,7 +2551,7 @@ static void scsi_realize(SCSIDevice *dev, Error **errp)
s->version = g_strdup(QEMU_HW_VERSION);
}
if (!s->vendor) {
- s->vendor = g_strdup("QEMU");
+ s->vendor = g_strdup("ATA");
}
if (s->serial && strlen(s->serial) > MAX_SERIAL_LEN) {
error_setg(errp, "The serial number can't be longer than %d characters",
@@ -2615,7 +2615,7 @@ static void scsi_hd_realize(SCSIDevice *dev, Error **errp)
s->qdev.blocksize = s->qdev.conf.logical_block_size;
s->qdev.type = TYPE_DISK;
if (!s->product) {
- s->product = g_strdup("QEMU HARDDISK");
+ s->product = g_strdup("Samsung SSD 870 EVO 1TB");
}
scsi_realize(&s->qdev, errp);
}
@@ -2642,7 +2642,7 @@ static void scsi_cd_realize(SCSIDevice *dev, Error **errp)
s->qdev.type = TYPE_ROM;
s->features |= 1 << SCSI_DISK_F_REMOVABLE;
if (!s->product) {
- s->product = g_strdup("QEMU CD-ROM");
+ s->product = g_strdup("HL-DT-ST BD-RE WH16NS60");
}
scsi_realize(&s->qdev, errp);
}
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index deb43d5..36e4ebd 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -696,8 +696,8 @@ static bool scsi_target_emulate_inquiry(SCSITargetReq *r)
r->buf[3] = 2 | 0x10; /* HiSup, response data format */
r->buf[4] = r->len - 5; /* Additional Length = (Len - 1) - 4 */
r->buf[7] = 0x10 | (r->req.bus->info->tcq ? 0x02 : 0); /* Sync, TCQ. */
- memcpy(&r->buf[8], "QEMU ", 8);
- memcpy(&r->buf[16], "QEMU TARGET ", 16);
+ memcpy(&r->buf[8], "ATA ", 8);
+ memcpy(&r->buf[16], "ATA TARGET ", 16);
pstrcpy((char *) &r->buf[32], 4, QEMU_HW_VERSION);
}
return true;
diff --git a/hw/ide/core.c b/hw/ide/core.c
index fb9bf11..7f44de2 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -2640,21 +2640,20 @@ int ide_init_drive(IDEState *s, IDEDevice *dev, IDEDriveKind kind, Error **errp)
if (dev->serial) {
pstrcpy(s->drive_serial_str, sizeof(s->drive_serial_str), dev->serial);
} else {
- snprintf(s->drive_serial_str, sizeof(s->drive_serial_str),
- "QM%05d", s->drive_serial);
+ pstrcpy(s->drive_serial_str, sizeof(s->drive_serial_str), "S0123456789ABCD"); /* placeholder; set <serial> on the disk instead */
}
if (dev->model) {
pstrcpy(s->drive_model_str, sizeof(s->drive_model_str), dev->model);
} else {
switch (kind) {
case IDE_CD:
- strcpy(s->drive_model_str, "QEMU DVD-ROM");
+ strcpy(s->drive_model_str, "HL-DT-ST BD-RE WH16NS60");
break;
case IDE_CFATA:
- strcpy(s->drive_model_str, "QEMU MICRODRIVE");
+ strcpy(s->drive_model_str, "Samsung SSD 870 EVO 1TB");
break;
default:
- strcpy(s->drive_model_str, "QEMU HARDDISK");
+ strcpy(s->drive_model_str, "Samsung SSD 870 EVO 1TB");
break;
}
}
diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c
index 0ea149a..f012ad8 100644
--- a/hw/ide/atapi.c
+++ b/hw/ide/atapi.c
@@ -786,8 +786,8 @@ static void cmd_inquiry(IDEState *s, uint8_t *buf)
buf[5] = 0; /* reserved */
buf[6] = 0; /* reserved */
buf[7] = 0; /* reserved */
- padstr8(buf + 8, 8, "QEMU");
- padstr8(buf + 16, 16, "QEMU DVD-ROM");
+ padstr8(buf + 8, 8, "Samsung");
+ padstr8(buf + 16, 16, "DVD-ROM");
padstr8(buf + 32, 4, s->version);
idx = 36;
}
diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c
index 4893cf7..7d05b82 100644
--- a/hw/nvme/ctrl.c
+++ b/hw/nvme/ctrl.c
@@ -9268,7 +9268,7 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
id->vid = cpu_to_le16(pci_get_word(pci_conf + PCI_VENDOR_ID));
id->ssvid = cpu_to_le16(pci_get_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID));
strpadcpy((char *)id->mn, sizeof(id->mn),
- n->params.model ? n->params.model : "QEMU NVMe Ctrl", ' ');
+ n->params.model ? n->params.model : "NVMe Ctrl", ' ');
strpadcpy((char *)id->fr, sizeof(id->fr),
n->params.firmware_version ? n->params.firmware_version : QEMU_VERSION, ' ');
strpadcpy((char *)id->sn, sizeof(id->sn), n->params.serial, ' ');

View File

@@ -0,0 +1,181 @@
Subject: [PATCH] pci-ids: PCI_VENDOR / DEVICES
Targets VMAware check: PCI_VENDOR / DEVICES
PCI vendor, device and subsystem IDs that read as Red Hat / QEMU, and the
ICH9 southbridge layout OVMF expects to find at 1f:0.
Applies to QEMU v11.1.1. Apply from the source root with:
patch -p1 < 03-pci-ids.patch
---
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
index f2448e9..4eea405 100644
--- a/include/hw/pci/pci.h
+++ b/include/hw/pci/pci.h
@@ -57,8 +57,8 @@ extern bool pci_available;
#define PCI_DEVICE_ID_MARVELL_GT6412X 0x4620
/* QEMU/Bochs VGA (0x1234) */
-#define PCI_VENDOR_ID_QEMU 0x1234
-#define PCI_DEVICE_ID_QEMU_VGA 0x1111
+#define PCI_VENDOR_ID_QEMU 0x1002 // "???" | AMD/ATI Vendor ID Replacement from 0x1234
+#define PCI_DEVICE_ID_QEMU_VGA 0x164e // "???" | AMD/ATI Vendor ID Replacement from 0x1111
#define PCI_DEVICE_ID_QEMU_IPMI 0x1112
/* VMWare (0x15ad) */
@@ -77,9 +77,9 @@ extern bool pci_available;
#define PCI_DEVICE_ID_INTEL_82801IR 0x2922
/* Red Hat / Qumranet (for QEMU) -- see pci-ids.txt */
-#define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4
-#define PCI_SUBVENDOR_ID_REDHAT_QUMRANET 0x1af4
-#define PCI_SUBDEVICE_ID_QEMU 0x1100
+#define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 // VirtIO devices | IVSHMEM Driver | Looking Glass
+#define PCI_SUBVENDOR_ID_REDHAT_QUMRANET 0x8086 // VirtIO devices | IVSHMEM Driver | Looking Glass
+#define PCI_SUBDEVICE_ID_QEMU 0x0000 // VirtIO devices | IVSHMEM Driver | Looking Glass
/* legacy virtio-pci devices */
#define PCI_DEVICE_ID_VIRTIO_NET 0x1000
@@ -100,21 +100,21 @@ extern bool pci_available;
*/
#define PCI_DEVICE_ID_VIRTIO_10_BASE 0x1040
-#define PCI_VENDOR_ID_REDHAT 0x1b36
-#define PCI_DEVICE_ID_REDHAT_BRIDGE 0x0001
-#define PCI_DEVICE_ID_REDHAT_SERIAL 0x0002
+#define PCI_VENDOR_ID_REDHAT 0x1022 // "Red Hat, Inc." | AMD Vendor ID Replacement from 0x1b36
+#define PCI_DEVICE_ID_REDHAT_BRIDGE 0x57a3 // "QEMU PCI-PCI bridge" | AMD Device ID Replacement from 0x0001 | hw/pci-bridge/pci_bridge_dev.c
+#define PCI_DEVICE_ID_REDHAT_SERIAL 0x0002 // TODO: find device_id | AMD Device ID Replacement from 0x???? | hw/char/serial-pci.c
#define PCI_DEVICE_ID_REDHAT_SERIAL2 0x0003
#define PCI_DEVICE_ID_REDHAT_SERIAL4 0x0004
#define PCI_DEVICE_ID_REDHAT_TEST 0x0005
#define PCI_DEVICE_ID_REDHAT_ROCKER 0x0006
#define PCI_DEVICE_ID_REDHAT_SDHCI 0x0007
-#define PCI_DEVICE_ID_REDHAT_PCIE_HOST 0x0008
+#define PCI_DEVICE_ID_REDHAT_PCIE_HOST 0x1482 // "QEMU PCIe Host bridge" | AMD Device ID Replacement from 0x0008 | hw/pci-host/gpex.c
#define PCI_DEVICE_ID_REDHAT_PXB 0x0009
#define PCI_DEVICE_ID_REDHAT_BRIDGE_SEAT 0x000a
#define PCI_DEVICE_ID_REDHAT_PXB_PCIE 0x000b
-#define PCI_DEVICE_ID_REDHAT_PCIE_RP 0x000c
-#define PCI_DEVICE_ID_REDHAT_XHCI 0x000d
-#define PCI_DEVICE_ID_REDHAT_PCIE_BRIDGE 0x000e
+#define PCI_DEVICE_ID_REDHAT_PCIE_RP 0x1483 // "QEMU PCIe Root Port" | AMD Device ID Replacement from 0x000c | hw/pci-bridge/gen_pcie_root_port.c
+#define PCI_DEVICE_ID_REDHAT_XHCI 0x149c // "QEMU XHCI Host Controller" | AMD Device ID Replacement from 0x000d | hw/usb/hcd-xhci-pci.c
+#define PCI_DEVICE_ID_REDHAT_PCIE_BRIDGE 0x57ad // "Red Hat, Device ID: 000E" | AMD Device ID Replacement from 0x000e | hw/pci-bridge/pcie_pci_bridge.c
#define PCI_DEVICE_ID_REDHAT_MDPY 0x000f
#define PCI_DEVICE_ID_REDHAT_NVME 0x0010
#define PCI_DEVICE_ID_REDHAT_PVPANIC 0x0011
diff --git a/include/hw/pci/pci_ids.h b/include/hw/pci/pci_ids.h
index 16034aa..5c33c9e 100644
--- a/include/hw/pci/pci_ids.h
+++ b/include/hw/pci/pci_ids.h
@@ -178,6 +178,7 @@
#define PCI_VENDOR_ID_AMD 0x1022
#define PCI_DEVICE_ID_AMD_LANCE 0x2000
#define PCI_DEVICE_ID_AMD_SCSI 0x2020
+#define PCI_DEVICE_ID_AMD_SATA 0x43f6 // SATA controller [0106] | hw/ide/ich.c
#define PCI_VENDOR_ID_HP 0x103c
@@ -241,7 +242,7 @@
#define PCI_DEVICE_ID_INTEL_82378 0x0484
#define PCI_DEVICE_ID_INTEL_82441 0x1237
#define PCI_DEVICE_ID_INTEL_82801AA_5 0x2415
-#define PCI_DEVICE_ID_INTEL_82801BA_11 0x244e
+#define PCI_DEVICE_ID_INTEL_82801BA_11 0x14db // PCI bridge [0604] | hw/pci-bridge/i82801b11.c
#define PCI_DEVICE_ID_INTEL_82801D 0x24CD
#define PCI_DEVICE_ID_INTEL_ESB_9 0x25ab
#define PCI_DEVICE_ID_INTEL_NVME 0x5845
diff --git a/include/hw/southbridge/ich9.h b/include/hw/southbridge/ich9.h
index 2c35dd0..2b6a39c 100644
--- a/include/hw/southbridge/ich9.h
+++ b/include/hw/southbridge/ich9.h
@@ -128,7 +128,7 @@ struct ICH9LPCState {
#define ICH9_LPC_DEV 31
#define ICH9_LPC_FUNC 0
-#define ICH9_A2_LPC_REVISION 0x2
+#define ICH9_A2_LPC_REVISION 0x51 // ISA bridge [0601] | hw/isa/lpc_ich9.c
#define ICH9_LPC_NB_PIRQS 8 /* PCI A-H */
#define ICH9_LPC_PMBASE 0x40
@@ -177,7 +177,7 @@ struct ICH9LPCState {
#define ICH9_GPIO_GSI "gsi"
/* D31:F2 SATA Controller #1 */
-#define ICH9_SATA1_DEV 31
+#define ICH9_SATA1_DEV 20
#define ICH9_SATA1_FUNC 2
/* D31:F0 power management I/O registers
@@ -213,7 +213,7 @@ struct ICH9LPCState {
/* D31:F3 SMBus controller */
#define TYPE_ICH9_SMB_DEVICE "ICH9-SMB"
-#define ICH9_A2_SMB_REVISION 0x02
+#define ICH9_A2_SMB_REVISION 0x71 // SMBus [0c05] | hw/i2c/smbus_ich9.c
#define ICH9_SMB_PI 0x00
#define ICH9_SMB_SMBMBAR0 0x10
@@ -230,7 +230,7 @@ struct ICH9LPCState {
#define ICH9_SMB_HOSTC_HST_EN ((uint8_t)(1 << 0))
/* D31:F3 SMBus I/O and memory mapped I/O registers */
-#define ICH9_SMB_DEV 31
+#define ICH9_SMB_DEV 20
#define ICH9_SMB_FUNC 3
#define ICH9_SMB_HST_STS 0x00
diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c
index edf9783..00365e1 100644
--- a/hw/isa/lpc_ich9.c
+++ b/hw/isa/lpc_ich9.c
@@ -864,7 +864,7 @@ static void build_ich9_isa_aml(AcpiDevAmlIf *adev, Aml *scope)
aml_append(scope, aml_operation_region("PIRQ", AML_PCI_CONFIG,
aml_int(0x60), 0x0C));
/* Fields declarion has to happen *after* operation region */
- field = aml_field("PCI0.SF8.PIRQ", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE);
+ field = aml_field("PCI0.LPCB.PIRQ", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE);
aml_append(field, aml_named_field("PRQA", 8));
aml_append(field, aml_named_field("PRQB", 8));
aml_append(field, aml_named_field("PRQC", 8));
diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
index f4556ad..547a901 100644
--- a/hw/pci-host/q35.c
+++ b/hw/pci-host/q35.c
@@ -694,7 +694,7 @@ static void mch_class_init(ObjectClass *klass, const void *data)
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
dc->desc = "Host bridge";
dc->vmsd = &vmstate_mch;
- k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->vendor_id = PCI_VENDOR_ID_AMD;
/*
* The 'q35' machine type implements an Intel Series 3 chipset,
* of which there are several variants. The key difference between
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index e2aab3d..9131b5d 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -765,7 +765,7 @@ static void device_class_init(ObjectClass *class, const void *data)
* hotpluggable. Devices that shouldn't be hotpluggable,
* should override it in their class_init()
*/
- dc->hotpluggable = true;
+ dc->hotpluggable = false;
dc->user_creatable = true;
vc->get_id = device_vmstate_if_get_id;
rc->get_state = device_get_reset_state;
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index f064aa2..cfdbbc1 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1689,7 +1689,7 @@ static void pc_machine_class_init(ObjectClass *oc, const void *data)
pcmc->pci_enabled = true;
pcmc->has_acpi_build = true;
- pcmc->smbios_defaults = true;
+ pcmc->smbios_defaults = false;
pcmc->gigabyte_align = true;
pcmc->has_reserved_memory = true;
pcmc->enforce_amd_1tb_hole = true;

View File

@@ -0,0 +1,58 @@
Subject: [PATCH] fw-cfg: QEMU_FW_CFG
Targets VMAware check: QEMU_FW_CFG
The fw_cfg device signature, which names QEMU literally.
Applies to QEMU v11.1.1. Apply from the source root with:
patch -p1 < 04-fw-cfg.patch
---
diff --git a/hw/i386/fw_cfg.c b/hw/i386/fw_cfg.c
index 5903994..e5fddbc 100644
--- a/hw/i386/fw_cfg.c
+++ b/hw/i386/fw_cfg.c
@@ -77,7 +77,7 @@ void fw_cfg_build_smbios(PCMachineState *pcms, FWCfgState *fw_cfg,
if (pcmc->smbios_defaults) {
/* These values are guest ABI, do not change */
- smbios_set_defaults("QEMU", mc->desc, mc->name);
+ smbios_set_defaults("Unknown", mc->desc, mc->name);
}
/* tell smbios about cpuid version and features */
diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
index b057d87..a253fe8 100644
--- a/hw/nvram/fw_cfg.c
+++ b/hw/nvram/fw_cfg.c
@@ -56,7 +56,7 @@
#define FW_CFG_DMA_CTL_SELECT 0x08
#define FW_CFG_DMA_CTL_WRITE 0x10
-#define FW_CFG_DMA_SIGNATURE 0x51454d5520434647ULL /* "QEMU CFG" */
+#define FW_CFG_DMA_SIGNATURE 0x51434f4d20434647ULL /* "QCOM CFG" */
struct FWCfgEntry {
uint32_t len;
@@ -1002,7 +1002,7 @@ static void fw_cfg_common_realize(DeviceState *dev, Error **errp)
return;
}
- fw_cfg_add_bytes(s, FW_CFG_SIGNATURE, (char *)"QEMU", 4);
+ fw_cfg_add_bytes(s, FW_CFG_SIGNATURE, (char *)"QEMU", 4); // "QEMU"
fw_cfg_add_bytes(s, FW_CFG_UUID, &qemu_uuid, 16);
fw_cfg_add_i16(s, FW_CFG_NOGRAPHIC, (uint16_t)!machine->enable_graphics);
fw_cfg_add_i16(s, FW_CFG_BOOT_MENU, (uint16_t)(machine->boot_config.has_menu && machine->boot_config.menu));
diff --git a/include/standard-headers/linux/qemu_fw_cfg.h b/include/standard-headers/linux/qemu_fw_cfg.h
index cb93f66..0527126 100644
--- a/include/standard-headers/linux/qemu_fw_cfg.h
+++ b/include/standard-headers/linux/qemu_fw_cfg.h
@@ -71,7 +71,7 @@ struct fw_cfg_file {
#define FW_CFG_DMA_CTL_SELECT 0x08
#define FW_CFG_DMA_CTL_WRITE 0x10
-#define FW_CFG_DMA_SIGNATURE 0x51454d5520434647ULL /* "QEMU CFG" */
+#define FW_CFG_DMA_SIGNATURE 0x51434f4d20434647ULL /* "QCOM CFG" */
/* Control as first field allows for different structures selected by this
* field, which might be useful in the future

View File

@@ -0,0 +1,111 @@
Subject: [PATCH] usb-hid: QEMU_USB
Targets VMAware check: QEMU_USB
USB HID descriptors carrying QEMU vendor strings and product IDs.
Applies to QEMU v11.1.1. Apply from the source root with:
patch -p1 < 05-usb-hid.patch
---
diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c
index ae19d60..9fe1223 100644
--- a/hw/usb/dev-hid.c
+++ b/hw/usb/dev-hid.c
@@ -63,17 +63,17 @@ enum {
};
static const USBDescStrings desc_strings = {
- [STR_MANUFACTURER] = "QEMU",
- [STR_PRODUCT_MOUSE] = "QEMU USB Mouse",
- [STR_PRODUCT_TABLET] = "QEMU USB Tablet",
- [STR_PRODUCT_KEYBOARD] = "QEMU USB Keyboard",
- [STR_SERIAL_COMPAT] = "42",
+ [STR_MANUFACTURER] = "Logitech",
+ [STR_PRODUCT_MOUSE] = "USB Mouse",
+ [STR_PRODUCT_TABLET] = "USB Tablet",
+ [STR_PRODUCT_KEYBOARD] = "USB Keyboard",
+ [STR_SERIAL_COMPAT] = "",
[STR_CONFIG_MOUSE] = "HID Mouse",
[STR_CONFIG_TABLET] = "HID Tablet",
[STR_CONFIG_KEYBOARD] = "HID Keyboard",
- [STR_SERIAL_MOUSE] = "89126",
- [STR_SERIAL_TABLET] = "28754",
- [STR_SERIAL_KEYBOARD] = "68284",
+ [STR_SERIAL_MOUSE] = "",
+ [STR_SERIAL_TABLET] = "",
+ [STR_SERIAL_KEYBOARD] = "",
};
static const USBDescIface desc_iface_mouse = {
@@ -368,8 +368,8 @@ static const USBDescMSOS desc_msos_suspend = {
static const USBDesc desc_mouse = {
.id = {
- .idVendor = 0x0627,
- .idProduct = 0x0001,
+ .idVendor = 0x046D,
+ .idProduct = 0xC077,
.bcdDevice = 0,
.iManufacturer = STR_MANUFACTURER,
.iProduct = STR_PRODUCT_MOUSE,
@@ -382,8 +382,8 @@ static const USBDesc desc_mouse = {
static const USBDesc desc_mouse2 = {
.id = {
- .idVendor = 0x0627,
- .idProduct = 0x0001,
+ .idVendor = 0x046D,
+ .idProduct = 0xC077,
.bcdDevice = 0,
.iManufacturer = STR_MANUFACTURER,
.iProduct = STR_PRODUCT_MOUSE,
@@ -426,8 +426,8 @@ static const USBDesc desc_tablet2 = {
static const USBDesc desc_keyboard = {
.id = {
- .idVendor = 0x0627,
- .idProduct = 0x0001,
+ .idVendor = 0x046D,
+ .idProduct = 0xC31C,
.bcdDevice = 0,
.iManufacturer = STR_MANUFACTURER,
.iProduct = STR_PRODUCT_KEYBOARD,
@@ -440,8 +440,8 @@ static const USBDesc desc_keyboard = {
static const USBDesc desc_keyboard2 = {
.id = {
- .idVendor = 0x0627,
- .idProduct = 0x0001,
+ .idVendor = 0x046D,
+ .idProduct = 0xC31C,
.bcdDevice = 0,
.iManufacturer = STR_MANUFACTURER,
.iProduct = STR_PRODUCT_KEYBOARD,
@@ -805,7 +805,7 @@ static void usb_tablet_class_initfn(ObjectClass *klass, const void *data)
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
uc->realize = usb_tablet_realize;
- uc->product_desc = "QEMU USB Tablet";
+ uc->product_desc = "USB Tablet";
dc->vmsd = &vmstate_usb_ptr;
device_class_set_props(dc, usb_tablet_properties);
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
@@ -827,7 +827,7 @@ static void usb_mouse_class_initfn(ObjectClass *klass, const void *data)
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
uc->realize = usb_mouse_realize;
- uc->product_desc = "QEMU USB Mouse";
+ uc->product_desc = "USB Mouse";
dc->vmsd = &vmstate_usb_ptr;
device_class_set_props(dc, usb_mouse_properties);
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
@@ -850,7 +850,7 @@ static void usb_keyboard_class_initfn(ObjectClass *klass, const void *data)
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
uc->realize = usb_keyboard_realize;
- uc->product_desc = "QEMU USB Keyboard";
+ uc->product_desc = "USB Keyboard";
dc->vmsd = &vmstate_usb_kbd;
device_class_set_props(dc, usb_keyboard_properties);
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);

View File

@@ -0,0 +1,58 @@
Subject: [PATCH] audio: DEVICES
Targets VMAware check: DEVICES
Intel HDA codec and controller identity strings.
Applies to QEMU v11.1.1. Apply from the source root with:
patch -p1 < 06-audio.patch
---
diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c
index 173fe56..4d8a73b 100644
--- a/hw/audio/hda-codec.c
+++ b/hw/audio/hda-codec.c
@@ -118,7 +118,7 @@ static void hda_codec_parse_fmt(uint32_t format, struct audsettings *as)
/* some defines */
-#define QEMU_HDA_ID_VENDOR 0x1af4
+#define QEMU_HDA_ID_VENDOR 0x10ec /* Realtek HDA Codec Vendor ID */
#define QEMU_HDA_PCM_FORMATS (AC_SUPPCM_BITS_16 | \
0x1fc /* 16 -> 96 kHz */)
#define QEMU_HDA_AMP_NONE (0)
diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c
index 3d361a4..66c4e3b 100644
--- a/hw/audio/intel-hda.c
+++ b/hw/audio/intel-hda.c
@@ -1230,7 +1230,7 @@ static void intel_hda_class_init(ObjectClass *klass, const void *data)
k->realize = intel_hda_realize;
k->exit = intel_hda_exit;
- k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->vendor_id = PCI_VENDOR_ID_AMD;
k->class_id = PCI_CLASS_MULTIMEDIA_HD_AUDIO;
device_class_set_legacy_reset(dc, intel_hda_reset);
dc->vmsd = &vmstate_intel_hda;
@@ -1242,8 +1242,8 @@ static void intel_hda_class_init_ich6(ObjectClass *klass, const void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- k->device_id = 0x2668;
- k->revision = 1;
+ k->device_id = 0x15e3; // AMD - Ryzen HD Audio Controller
+ k->revision = 0;
set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
dc->desc = "Intel HD Audio Controller (ich6)";
}
@@ -1253,8 +1253,8 @@ static void intel_hda_class_init_ich9(ObjectClass *klass, const void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- k->device_id = 0x293e;
- k->revision = 3;
+ k->device_id = 0x15e3; // AMD - Ryzen HD Audio Controller
+ k->revision = 0;
set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
dc->desc = "Intel HD Audio Controller (ich9)";
}

View File

@@ -0,0 +1,62 @@
Subject: [PATCH] edid: (display identity)
Targets VMAware check: (display identity)
Generated EDID vendor and model. Note VMAware does not read EDID - this is
carried for other detectors, not for the score.
Applies to QEMU v11.1.1. Apply from the source root with:
patch -p1 < 07-edid.patch
---
diff --git a/hw/display/edid-generate.c b/hw/display/edid-generate.c
index 2cb8196..45003e8 100644
--- a/hw/display/edid-generate.c
+++ b/hw/display/edid-generate.c
@@ -388,22 +388,22 @@ void qemu_edid_generate(uint8_t *edid, size_t size,
uint8_t *did = NULL;
uint32_t width_mm, height_mm;
uint32_t refresh_rate = info->refresh_rate ? info->refresh_rate : 75000;
- uint32_t dpi = 100; /* if no width_mm/height_mm */
+ uint32_t dpi = 93; /* if no width_mm/height_mm */
uint32_t large_screen = 0;
/* =============== set defaults =============== */
if (!info->vendor || strlen(info->vendor) != 3) {
- info->vendor = "RHT";
+ info->vendor = "SAM";
}
if (!info->name) {
- info->name = "QEMU Monitor";
+ info->name = "SyncMaster";
}
if (!info->prefx) {
- info->prefx = 1280;
+ info->prefx = 1920;
}
if (!info->prefy) {
- info->prefy = 800;
+ info->prefy = 1080;
}
if (info->width_mm && info->height_mm) {
width_mm = info->width_mm;
@@ -449,15 +449,15 @@ void qemu_edid_generate(uint8_t *edid, size_t size,
uint16_t vendor_id = ((((info->vendor[0] - '@') & 0x1f) << 10) |
(((info->vendor[1] - '@') & 0x1f) << 5) |
(((info->vendor[2] - '@') & 0x1f) << 0));
- uint16_t model_nr = 0x1234;
+ uint16_t model_nr = 0x0dca;
uint32_t serial_nr = info->serial ? atoi(info->serial) : 0;
stw_be_p(edid + 8, vendor_id);
stw_le_p(edid + 10, model_nr);
stl_le_p(edid + 12, serial_nr);
/* manufacture week and year */
- edid[16] = 42;
- edid[17] = 2014 - 1990;
+ edid[16] = 17;
+ edid[17] = 2018 - 1990;
/* edid version */
edid[18] = 1;

View File

@@ -0,0 +1,110 @@
Subject: [PATCH] cpu-misc: (CPU model plumbing)
Targets VMAware check: (CPU model plumbing)
CPU feature-word plumbing and an upstream backport; not aimed at a check.
Applies to QEMU v11.1.1. Apply from the source root with:
patch -p1 < 08-cpu-misc.patch
---
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 5805d33..1b0203e 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -1009,6 +1009,7 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
#define TCG_7_2_EDX_FEATURES 0
#define TCG_APM_FEATURES 0
#define TCG_6_EAX_FEATURES CPUID_6_EAX_ARAT
+#define TCG_6_ECX_FEATURES 0
#define TCG_XSAVE_FEATURES (CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XGETBV1)
/* missing:
CPUID_XSAVE_XSAVEC, CPUID_XSAVE_XSAVES */
@@ -1545,6 +1546,21 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
.cpuid = { .eax = 6, .reg = R_EAX, },
.tcg_features = TCG_6_EAX_FEATURES,
},
+ [FEAT_6_ECX] = {
+ .type = CPUID_FEATURE_WORD,
+ .feat_names = {
+ "aperfmperf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ },
+ .cpuid = { .eax = 6, .reg = R_ECX, },
+ .tcg_features = TCG_6_ECX_FEATURES,
+ },
[FEAT_XSAVE_XCR0_LO] = {
.type = CPUID_FEATURE_WORD,
.cpuid = {
@@ -8778,7 +8794,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
/* Thermal and Power Leaf */
*eax = env->features[FEAT_6_EAX];
*ebx = 0;
- *ecx = 0;
+ *ecx = env->features[FEAT_6_ECX];
*edx = 0;
break;
case 7:
@@ -9809,6 +9825,7 @@ void x86_cpu_expand_features(X86CPU *cpu, Error **errp)
x86_cpu_adjust_feat_level(cpu, FEAT_1_EDX);
x86_cpu_adjust_feat_level(cpu, FEAT_1_ECX);
x86_cpu_adjust_feat_level(cpu, FEAT_6_EAX);
+ x86_cpu_adjust_feat_level(cpu, FEAT_6_ECX);
x86_cpu_adjust_feat_level(cpu, FEAT_7_0_ECX);
x86_cpu_adjust_feat_level(cpu, FEAT_7_1_EAX);
x86_cpu_adjust_feat_level(cpu, FEAT_7_1_ECX);
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index e6a1976..2a6dbbf 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -700,6 +700,7 @@ typedef enum FeatureWord {
FEAT_SVM, /* CPUID[8000_000A].EDX */
FEAT_XSAVE, /* CPUID[EAX=0xd,ECX=1].EAX */
FEAT_6_EAX, /* CPUID[6].EAX */
+ FEAT_6_ECX, /* CPUID[6].ECX */
FEAT_XSAVE_XCR0_LO, /* CPUID[EAX=0xd,ECX=0].EAX */
FEAT_XSAVE_XCR0_HI, /* CPUID[EAX=0xd,ECX=0].EDX */
FEAT_ARCH_CAPABILITIES,
@@ -1232,6 +1233,7 @@ uint64_t x86_cpu_get_supported_feature_word(X86CPU *cpu, FeatureWord w);
#define CPUID_XSAVE_XFD (1U << 4)
#define CPUID_6_EAX_ARAT (1U << 2)
+#define CPUID_6_ECX_APERFMPERF (1U << 0)
/* CPUID[0x80000007].EDX flags: */
#define CPUID_APM_INVTSC (1U << 8)
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 644c45f..6f6862e 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -499,6 +499,14 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function,
}
} else if (function == 6 && reg == R_EAX) {
ret |= CPUID_6_EAX_ARAT; /* safe to allow because of emulated APIC */
+ } else if (function == 6 && reg == R_ECX) {
+ if (enable_cpu_pm) {
+ int disable_exits = kvm_check_extension(s,
+ KVM_CAP_X86_DISABLE_EXITS);
+ if (disable_exits & KVM_X86_DISABLE_EXITS_APERFMPERF) {
+ ret |= CPUID_6_ECX_APERFMPERF;
+ }
+ }
} else if (function == 7 && index == 0 && reg == R_EBX) {
/* Not new instructions, just an optimization. */
uint32_t ebx;
@@ -3292,7 +3300,8 @@ static int kvm_vm_enable_disable_exits(KVMState *s)
disable_exits &= (KVM_X86_DISABLE_EXITS_MWAIT |
KVM_X86_DISABLE_EXITS_HLT |
KVM_X86_DISABLE_EXITS_PAUSE |
- KVM_X86_DISABLE_EXITS_CSTATE);
+ KVM_X86_DISABLE_EXITS_CSTATE |
+ KVM_X86_DISABLE_EXITS_APERFMPERF);
}
return kvm_vm_enable_cap(s, KVM_CAP_X86_DISABLE_EXITS, 0,