Skip to content

Commit f185f66

Browse files
doge-rgbCMGS
authored andcommitted
vmm: acpi: provide FADT PM1a event/control blocks for nested Hyper-V
A Windows guest that launches nested Hyper-V (for example to run WSL2) fails to start its hypervisor on cloud-hypervisor's HW-reduced-ACPI FADT. hvloader's hypervisor-launch path (0x18000f01c -> 0x180015628 -> 0x180015788) registers every legacy PM register block via 0x1800158dc and rejects any block whose GAS address is 0 with status 8 (STATUS_INVALID_DEVICE_REQUEST). hvix64 then never launches and HypervisorPresent stays False. The HW-reduced FADT leaves those blocks zero. Emit valid PM1a event/control blocks (I/O ports, lengths and X_GAS) in the FADT. The HW-reduced guest OS ignores the legacy ports; only hvloader's ACPI validation reads them. These blocks are only useful to a guest that itself runs a hypervisor, so emit them only when guest nesting is enabled (--cpu nested=on). Signed-off-by: doge <me@crackerben.com>
1 parent 438631d commit f185f66

2 files changed

Lines changed: 40 additions & 3 deletions

File tree

vmm/src/acpi.rs

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,11 @@ pub fn create_dsdt_table(
276276

277277
const FACP_DSDT_OFFSET: usize = 140;
278278

279-
fn create_facp_table(dsdt_offset: GuestAddress, device_manager: &DeviceManager) -> Sdt {
279+
fn create_facp_table(
280+
dsdt_offset: GuestAddress,
281+
device_manager: &DeviceManager,
282+
nested: bool,
283+
) -> Sdt {
280284
trace_scoped!("create_facp_table");
281285

282286
// Revision 6 of the ACPI FADT table is 276 bytes long
@@ -328,6 +332,28 @@ fn create_facp_table(dsdt_offset: GuestAddress, device_manager: &DeviceManager)
328332
// Hypervisor Vendor Identity
329333
facp.write_bytes(268, b"CLOUDHYP");
330334

335+
// PM1a event/control blocks for Windows nested Hyper-V's hvloader (which rejects a
336+
// FADT with a zero PM1a GAS). Gated on `nested`; HW-reduced ACPI hides it from guests.
337+
if nested {
338+
const PM1A_EVT_PORT: u16 = 0x60c;
339+
facp.write(56usize, PM1A_EVT_PORT as u32); // PM1a_EVT_BLK (0x38)
340+
facp.write(88usize, 4u8); // PM1_EVT_LEN (0x58)
341+
facp.write(148usize, 1u8); // X_PM1a_EVT_BLK GAS (0x94): AddressSpaceId=SystemIO
342+
facp.write(149usize, 32u8); // RegisterBitWidth
343+
facp.write(150usize, 0u8); // RegisterBitOffset
344+
facp.write(151usize, 2u8); // AccessSize = word (16-bit)
345+
facp.write(152usize, PM1A_EVT_PORT as u64); // Address
346+
347+
const PM1A_CNT_PORT: u16 = 0x610;
348+
facp.write(64usize, PM1A_CNT_PORT as u32); // PM1a_CNT_BLK (0x40)
349+
facp.write(89usize, 2u8); // PM1_CNT_LEN (0x59)
350+
facp.write(172usize, 1u8); // X_PM1a_CNT_BLK GAS (0xac): AddressSpaceId=SystemIO
351+
facp.write(173usize, 16u8); // RegisterBitWidth
352+
facp.write(174usize, 0u8); // RegisterBitOffset
353+
facp.write(175usize, 2u8); // AccessSize = word (16-bit)
354+
facp.write(176usize, PM1A_CNT_PORT as u64); // Address
355+
}
356+
331357
facp.update_checksum();
332358

333359
facp
@@ -857,7 +883,12 @@ fn create_acpi_tables_internal(
857883
tables_bytes.extend_from_slice(dsdt.as_slice());
858884

859885
// FACP aka FADT
860-
let facp = create_facp_table(dsdt_addr, device_manager);
886+
// PM1a blocks are x86-only; there is nothing to emit on other arches.
887+
#[cfg(target_arch = "x86_64")]
888+
let nested = cpu_manager.nested();
889+
#[cfg(not(target_arch = "x86_64"))]
890+
let nested = false;
891+
let facp = create_facp_table(dsdt_addr, device_manager, nested);
861892
let facp_addr = dsdt_addr.checked_add(dsdt.len() as u64).unwrap();
862893
tables_bytes.extend_from_slice(facp.as_slice());
863894
xsdt_table_pointers.push(facp_addr.0);
@@ -1132,7 +1163,8 @@ pub fn create_acpi_tables_tdx(
11321163
)];
11331164

11341165
// FACP aka FADT
1135-
tables.push(create_facp_table(GuestAddress(0), device_manager));
1166+
let nested = cpu_manager.nested();
1167+
tables.push(create_facp_table(GuestAddress(0), device_manager, nested));
11361168

11371169
// MADT
11381170
tables.push(cpu_manager.create_madt());

vmm/src/cpu.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1093,6 +1093,11 @@ impl CpuManager {
10931093
Ok(())
10941094
}
10951095

1096+
#[cfg(target_arch = "x86_64")]
1097+
pub fn nested(&self) -> bool {
1098+
self.config.nested
1099+
}
1100+
10961101
/// Only create new vCPUs if there aren't any inactive ones to reuse
10971102
fn create_vcpus(
10981103
&mut self,

0 commit comments

Comments
 (0)