feat: kvm and qemu patches grouped by the detection each clears
This commit is contained in:
9
LICENSE
Normal file
9
LICENSE
Normal 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
86
patches/README.md
Normal 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.
|
||||
105
patches/kvm/0000-cover-letter.txt
Normal file
105
patches/kvm/0000-cover-letter.txt
Normal 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(-)
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
195
patches/kvm/EXPERIMENTAL-0006-runtime-cpuid-passthrough.patch
Normal file
195
patches/kvm/EXPERIMENTAL-0006-runtime-cpuid-passthrough.patch
Normal 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
|
||||
|
||||
397
patches/qemu/01-firmware.patch
Normal file
397
patches/qemu/01-firmware.patch
Normal 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;
|
||||
/*
|
||||
115
patches/qemu/02-disk-identity.patch
Normal file
115
patches/qemu/02-disk-identity.patch
Normal 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, ' ');
|
||||
181
patches/qemu/03-pci-ids.patch
Normal file
181
patches/qemu/03-pci-ids.patch
Normal 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;
|
||||
58
patches/qemu/04-fw-cfg.patch
Normal file
58
patches/qemu/04-fw-cfg.patch
Normal 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
|
||||
111
patches/qemu/05-usb-hid.patch
Normal file
111
patches/qemu/05-usb-hid.patch
Normal 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);
|
||||
58
patches/qemu/06-audio.patch
Normal file
58
patches/qemu/06-audio.patch
Normal 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)";
|
||||
}
|
||||
62
patches/qemu/07-edid.patch
Normal file
62
patches/qemu/07-edid.patch
Normal 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;
|
||||
110
patches/qemu/08-cpu-misc.patch
Normal file
110
patches/qemu/08-cpu-misc.patch
Normal 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,
|
||||
Reference in New Issue
Block a user