Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ crucible = { git = "https://github.com/oxidecomputer/crucible", rev = "7103cd3a3
crucible-client-types = { git = "https://github.com/oxidecomputer/crucible", rev = "7103cd3a3d7b0112d2949dd135db06fef0c156bb" }

# External dependencies
acpi_tables = "0.2.0"
anyhow = "1.0"
async-trait = "0.1.88"
atty = "0.2.14"
Expand Down Expand Up @@ -180,6 +181,8 @@ usdt = { version = "0.5", default-features = false }
uuid = "1.3.2"
zerocopy = "0.8.25"

[patch.crates-io]
acpi_tables = { git = 'https://github.com/oxidecomputer/acpi_tables.git' }

#
# It's common during development to use a local copy of various complex
Expand Down
83 changes: 73 additions & 10 deletions bin/propolis-server/src/lib/initializer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,12 @@ pub enum MachineInitError {
/// Arbitrary ROM limit for now
const MAX_ROM_SIZE: usize = 0x20_0000;

/// End address of the 32-bit PCI MMIO window.
// XXX(acpi): Value inherited from the original EDK2 static tables. It should
// match the actual memory regions registered in the instance.
// https://github.com/oxidecomputer/edk2/blob/f33871f488bfbbc080e0f7e3881e04d0db0b6367/OvmfPkg/PlatformPei/Platform.c#L180-L192
const PCI_MMIO32_END: usize = 0xfeef_ffff;

fn get_spec_guest_ram_limits(spec: &Spec) -> (usize, usize) {
let memsize = spec.board.memory_mb as usize * MB;
let lowmem = memsize.min(3 * GB);
Expand Down Expand Up @@ -393,16 +399,25 @@ impl MachineInitializer<'_> {
continue;
}

let (irq, port) = match desc.num {
SerialPortNumber::Com1 => (ibmpc::IRQ_COM1, ibmpc::PORT_COM1),
SerialPortNumber::Com2 => (ibmpc::IRQ_COM2, ibmpc::PORT_COM2),
SerialPortNumber::Com3 => (ibmpc::IRQ_COM3, ibmpc::PORT_COM3),
SerialPortNumber::Com4 => (ibmpc::IRQ_COM4, ibmpc::PORT_COM4),
let (irq, port, uart_name) = match desc.num {
SerialPortNumber::Com1 => {
(ibmpc::IRQ_COM1, ibmpc::PORT_COM1, "COM1")
}
SerialPortNumber::Com2 => {
(ibmpc::IRQ_COM2, ibmpc::PORT_COM2, "COM2")
}
SerialPortNumber::Com3 => {
(ibmpc::IRQ_COM3, ibmpc::PORT_COM3, "COM3")
}
SerialPortNumber::Com4 => {
(ibmpc::IRQ_COM4, ibmpc::PORT_COM4, "COM4")
}
};

let dev = LpcUart::new(chipset.irq_pin(irq).unwrap());
let dev =
LpcUart::new(uart_name, irq, chipset.irq_pin(irq).unwrap());
dev.set_autodiscard(true);
LpcUart::attach(&dev, &self.machine.bus_pio, port);
dev.attach(&self.machine.bus_pio, port);
self.devices.insert(name.to_owned(), dev.clone());
if desc.num == SerialPortNumber::Com1 {
assert!(com1.is_none());
Expand Down Expand Up @@ -899,9 +914,14 @@ impl MachineInitializer<'_> {
// Set up an LPC uart for ASIC management comms from the guest.
//
// NOTE: SoftNpu squats on com4.
let uart = LpcUart::new(chipset.irq_pin(ibmpc::IRQ_COM4).unwrap());
let uart = LpcUart::new(
chipset.irq_pin(ibmpc::IRQ_COM4).unwrap(),
ibmpc::PORT_COM4,
ibmpc::IRQ_COM4,
"COM4",
);
uart.set_autodiscard(true);
LpcUart::attach(&uart, &self.machine.bus_pio, ibmpc::PORT_COM4);
uart.attach(&self.machine.bus_pio);
self.devices
.insert(SpecKey::Name("softnpu-uart".to_string()), uart.clone());

Expand Down Expand Up @@ -1224,8 +1244,38 @@ impl MachineInitializer<'_> {
Ok(Some(order.finish()))
}

fn generate_acpi_tables(
&self,
cpus: u8,
) -> Result<fwcfg::formats::AcpiTables, MachineInitError> {
let (lowmem, _) = get_spec_guest_ram_limits(self.spec);
let generators: Vec<_> = self
.devices
.values()
.filter_map(|dev| dev.as_dsdt_generator())
.collect();

let config = &fwcfg::formats::AcpiConfig {
num_cpus: cpus,
pci_window_32: fwcfg::formats::PciWindow {
base: lowmem as u64,
end: PCI_MMIO32_END as u64,
},
// XXX(acpi): Value inherited from the original EDK2 static tables,
// where the 64-bit PCI MMIO region was never set. It
// should match the actual memory regions registered in
// the instance.
// https://github.com/oxidecomputer/edk2/blob/f33871f488bfbbc080e0f7e3881e04d0db0b6367/OvmfPkg/AcpiPlatformDxe/Qemu.c#L284-L286
pci_window_64: fwcfg::formats::PciWindow { base: 0, end: 0 },
dsdt_generators: &generators,
};
let acpi_tables = fwcfg::formats::AcpiTablesBuilder::new(config);

Ok(acpi_tables.finish())
}

/// Initialize qemu `fw_cfg` device, and populate it with data including CPU
/// count, SMBIOS tables, and attached RAM-FB device.
/// count, SMBIOS and ACPI tables, and attached RAM-FB device.
///
/// Should not be called before [`Self::initialize_rom()`].
pub fn initialize_fwcfg(
Expand Down Expand Up @@ -1270,6 +1320,19 @@ impl MachineInitializer<'_> {
.insert_named("etc/e820", e820_entry)
.map_err(|e| MachineInitError::FwcfgInsertFailed("e820", e))?;

let acpi_entries = self.generate_acpi_tables(cpus)?;
fwcfg.insert_named("etc/acpi/tables", acpi_entries.tables).map_err(
|e| MachineInitError::FwcfgInsertFailed("acpi/tables", e),
)?;
fwcfg
.insert_named("etc/acpi/rsdp", acpi_entries.rsdp)
.map_err(|e| MachineInitError::FwcfgInsertFailed("acpi/rsdp", e))?;
fwcfg
.insert_named("etc/table-loader", acpi_entries.table_loader)
.map_err(|e| {
MachineInitError::FwcfgInsertFailed("table-loader", e)
})?;

let ramfb = ramfb::RamFb::create(
self.log.new(slog::o!("component" => "ramfb")),
);
Expand Down
80 changes: 72 additions & 8 deletions bin/propolis-standalone/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ const PAGE_OFFSET: u64 = 0xfff;
// Arbitrary ROM limit for now
const MAX_ROM_SIZE: usize = 0x20_0000;

/// End address of the 32-bit PCI MMIO window.
// XXX(acpi): Value inherited from the original EDK2 static tables. It should
// match the actual memory regions registered in the instance.
// https://github.com/oxidecomputer/edk2/blob/f33871f488bfbbc080e0f7e3881e04d0db0b6367/OvmfPkg/PlatformPei/Platform.c#L180-L192
const PCI_MMIO32_END: usize = 0xfeef_ffff;

const MIN_RT_THREADS: usize = 8;
const BASE_RT_THREADS: usize = 4;

Expand Down Expand Up @@ -1032,6 +1038,36 @@ fn generate_bootorder(
Ok(Some(order.finish()))
}

fn generate_acpi_tables(
cpus: u8,
lowmem: usize,
inventory: &Inventory,
) -> anyhow::Result<fwcfg::formats::AcpiTables> {
let generators: Vec<_> = inventory
.devs
.values()
.filter_map(|dev| dev.as_dsdt_generator())
.collect();

let config = &fwcfg::formats::AcpiConfig {
num_cpus: cpus,
pci_window_32: fwcfg::formats::PciWindow {
base: lowmem as u64,
end: PCI_MMIO32_END as u64,
},
// XXX(acpi): Value inherited from the original EDK2 static tables,
// where the 64-bit PCI MMIO region was never set. It
// should match the actual memory regions registered in
// the instance.
// https://github.com/oxidecomputer/edk2/blob/f33871f488bfbbc080e0f7e3881e04d0db0b6367/OvmfPkg/AcpiPlatformDxe/Qemu.c#L284-L286
pci_window_64: fwcfg::formats::PciWindow { base: 0, end: 0 },
dsdt_generators: &generators,
};
let acpi_tables = fwcfg::formats::AcpiTablesBuilder::new(config);

Ok(acpi_tables.finish())
}

fn setup_instance(
config: config::Config,
from_restore: bool,
Expand Down Expand Up @@ -1139,10 +1175,26 @@ fn setup_instance(
guard.inventory.register(&hpet);

// UARTs
let com1 = LpcUart::new(chipset_lpc.irq_pin(ibmpc::IRQ_COM1).unwrap());
let com2 = LpcUart::new(chipset_lpc.irq_pin(ibmpc::IRQ_COM2).unwrap());
let com3 = LpcUart::new(chipset_lpc.irq_pin(ibmpc::IRQ_COM3).unwrap());
let com4 = LpcUart::new(chipset_lpc.irq_pin(ibmpc::IRQ_COM4).unwrap());
let com1 = LpcUart::new(
"COM1",
ibmpc::IRQ_COM1,
chipset_lpc.irq_pin(ibmpc::IRQ_COM1).unwrap(),
);
let com2 = LpcUart::new(
"COM2",
ibmpc::IRQ_COM2,
chipset_lpc.irq_pin(ibmpc::IRQ_COM2).unwrap(),
);
let com3 = LpcUart::new(
"COM3",
ibmpc::IRQ_COM3,
chipset_lpc.irq_pin(ibmpc::IRQ_COM3).unwrap(),
);
let com4 = LpcUart::new(
"COM4",
ibmpc::IRQ_COM4,
chipset_lpc.irq_pin(ibmpc::IRQ_COM4).unwrap(),
);

com1_sock.spawn(
Arc::clone(&com1) as Arc<dyn Sink>,
Expand All @@ -1156,10 +1208,10 @@ fn setup_instance(
com4.set_autodiscard(true);

let pio = &machine.bus_pio;
LpcUart::attach(&com1, pio, ibmpc::PORT_COM1);
LpcUart::attach(&com2, pio, ibmpc::PORT_COM2);
LpcUart::attach(&com3, pio, ibmpc::PORT_COM3);
LpcUart::attach(&com4, pio, ibmpc::PORT_COM4);
com1.attach(pio, ibmpc::PORT_COM1);
com2.attach(pio, ibmpc::PORT_COM2);
com3.attach(pio, ibmpc::PORT_COM3);
com4.attach(pio, ibmpc::PORT_COM4);
guard.inventory.register_instance(&com1, "com1");
guard.inventory.register_instance(&com2, "com2");
guard.inventory.register_instance(&com3, "com3");
Expand Down Expand Up @@ -1375,6 +1427,18 @@ fn setup_instance(
let e820_entry = generate_e820(machine, log).expect("can build E820 table");
fwcfg.insert_named("etc/e820", e820_entry).unwrap();

let acpi_entries = generate_acpi_tables(cpus, lowmem, &guard.inventory)
.expect("failed to build ACPI tables");
fwcfg
.insert_named("etc/acpi/tables", acpi_entries.tables)
.context("failed to insert ACPI tables")?;
fwcfg
.insert_named("etc/acpi/rsdp", acpi_entries.rsdp)
.context("failed to insert ACPI RSDP")?;
fwcfg
.insert_named("etc/table-loader", acpi_entries.table_loader)
.context("failed to insert ACPI table-loader")?;

fwcfg.attach(pio, &machine.acc_mem);

guard.inventory.register(&fwcfg);
Expand Down
1 change: 1 addition & 0 deletions lib/propolis/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ tokio = { workspace = true, features = ["full"] }
futures.workspace = true
paste.workspace = true
pin-project-lite.workspace = true
acpi_tables.workspace = true
anyhow.workspace = true
rgb_frame.workspace = true
rfb.workspace = true
Expand Down
Loading