Skip to content

Commit 8b6c45e

Browse files
committed
refactor: move configure_system_for_boot into arch module
Split `configure_system_for_boot` into 2 arch specific functions and move it into arch module. Signed-off-by: Egor Lazarchuk <[email protected]>
1 parent 00fb869 commit 8b6c45e

File tree

5 files changed

+193
-180
lines changed

5 files changed

+193
-180
lines changed

src/vmm/src/arch/aarch64/mod.rs

Lines changed: 82 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,23 @@ use std::ffi::CString;
2222
use std::fmt::Debug;
2323
use std::fs::File;
2424

25-
use linux_loader::loader::KernelLoader;
2625
use linux_loader::loader::pe::PE as Loader;
26+
use linux_loader::loader::{Cmdline, KernelLoader};
2727
use vm_memory::GuestMemoryError;
2828

2929
use self::gic::GICDevice;
30+
use crate::arch::aarch64::regs::Aarch64RegisterVec;
31+
use crate::arch::aarch64::vcpu::{VcpuArchError, get_registers};
3032
use crate::arch::{BootProtocol, DeviceType, EntryPoint};
33+
use crate::cpu_config::aarch64::{CpuConfiguration, CpuConfigurationError};
34+
use crate::cpu_config::templates::CustomCpuTemplate;
3135
use crate::device_manager::mmio::MMIODeviceInfo;
3236
use crate::devices::acpi::vmgenid::VmGenId;
3337
use crate::initrd::InitrdConfig;
38+
use crate::vmm_config::machine_config::MachineConfig;
3439
use crate::vstate::memory::{Address, Bytes, GuestAddress, GuestMemory, GuestMemoryMmap};
40+
use crate::vstate::vcpu::KvmVcpuError;
41+
use crate::{Vcpu, VcpuConfig, Vmm};
3542

3643
/// Errors thrown while configuring aarch64 system.
3744
#[derive(Debug, thiserror::Error, displaydoc::Display)]
@@ -44,6 +51,14 @@ pub enum ConfigurationError {
4451
KernelFile,
4552
/// Cannot load kernel due to invalid memory configuration or invalid kernel image: {0}
4653
KernelLoader(linux_loader::loader::Error),
54+
/// Error initializing the vcpu: {0}
55+
VcpuInit(KvmVcpuError),
56+
/// Error configuring the vcpu: {0}
57+
VcpuConfigure(KvmVcpuError),
58+
/// Error reading vcpu registers: {0}
59+
VcpuGetRegs(VcpuArchError),
60+
/// Error applying vcpu template: {0}
61+
VcpuApplyTemplate(CpuConfigurationError),
4762
}
4863

4964
/// The start of the memory area reserved for MMIO devices.
@@ -58,18 +73,73 @@ pub fn arch_memory_regions(size: usize) -> Vec<(GuestAddress, usize)> {
5873
vec![(GuestAddress(layout::DRAM_MEM_START), dram_size)]
5974
}
6075

76+
/// Configures the system for booting Linux.
77+
pub fn configure_system_for_boot(
78+
vmm: &mut Vmm,
79+
vcpus: &mut [Vcpu],
80+
machine_config: &MachineConfig,
81+
cpu_template: &CustomCpuTemplate,
82+
entry_point: EntryPoint,
83+
initrd: &Option<InitrdConfig>,
84+
boot_cmdline: Cmdline,
85+
) -> Result<(), ConfigurationError> {
86+
// Construct the base CpuConfiguration to apply CPU template onto.
87+
let cpu_config = {
88+
for vcpu in vcpus.iter_mut() {
89+
vcpu.kvm_vcpu
90+
.init(&cpu_template.vcpu_features)
91+
.map_err(ConfigurationError::VcpuInit)?;
92+
}
93+
94+
let mut regs = Aarch64RegisterVec::default();
95+
get_registers(&vcpus[0].kvm_vcpu.fd, &cpu_template.reg_list(), &mut regs)
96+
.map_err(ConfigurationError::VcpuGetRegs)?;
97+
CpuConfiguration { regs }
98+
};
99+
100+
// Apply CPU template to the base CpuConfiguration.
101+
let cpu_config = CpuConfiguration::apply_template(cpu_config, cpu_template)
102+
.map_err(ConfigurationError::VcpuApplyTemplate)?;
103+
104+
let vcpu_config = VcpuConfig {
105+
vcpu_count: machine_config.vcpu_count,
106+
smt: machine_config.smt,
107+
cpu_config,
108+
};
109+
110+
let optional_capabilities = vmm.kvm.optional_capabilities();
111+
// Configure vCPUs with normalizing and setting the generated CPU configuration.
112+
for vcpu in vcpus.iter_mut() {
113+
vcpu.kvm_vcpu
114+
.configure(
115+
vmm.guest_memory(),
116+
entry_point,
117+
&vcpu_config,
118+
&optional_capabilities,
119+
)
120+
.map_err(ConfigurationError::VcpuConfigure)?;
121+
}
122+
let vcpu_mpidr = vcpus
123+
.iter_mut()
124+
.map(|cpu| cpu.kvm_vcpu.get_mpidr())
125+
.collect();
126+
let cmdline = boot_cmdline
127+
.as_cstring()
128+
.expect("Cannot create cstring from cmdline string");
129+
configure_system(
130+
&vmm.guest_memory,
131+
cmdline,
132+
vcpu_mpidr,
133+
vmm.mmio_device_manager.get_device_info(),
134+
vmm.vm.get_irqchip(),
135+
&vmm.acpi_device_manager.vmgenid,
136+
initrd,
137+
)?;
138+
Ok(())
139+
}
140+
61141
/// Configures the system and should be called once per vm before starting vcpu threads.
62-
/// For aarch64, we only setup the FDT.
63-
///
64-
/// # Arguments
65-
///
66-
/// * `guest_mem` - The memory to be used by the guest.
67-
/// * `cmdline_cstring` - The kernel commandline.
68-
/// * `vcpu_mpidr` - Array of MPIDR register values per vcpu.
69-
/// * `device_info` - A hashmap containing the attached devices for building FDT device nodes.
70-
/// * `gic_device` - The GIC device.
71-
/// * `initrd` - Information about an optional initrd.
72-
pub fn configure_system(
142+
fn configure_system(
73143
guest_mem: &GuestMemoryMmap,
74144
cmdline_cstring: CString,
75145
vcpu_mpidr: Vec<u64>,

src/vmm/src/arch/mod.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,10 @@ pub use aarch64::vcpu::*;
2020
pub use aarch64::vm::{ArchVm, ArchVmError, VmState};
2121
#[cfg(target_arch = "aarch64")]
2222
pub use aarch64::{
23-
ConfigurationError, MMIO_MEM_SIZE, MMIO_MEM_START, arch_memory_regions, configure_system,
24-
get_kernel_start, initrd_load_addr, layout::CMDLINE_MAX_SIZE, layout::IRQ_BASE,
25-
layout::IRQ_MAX, layout::SYSTEM_MEM_SIZE, layout::SYSTEM_MEM_START, load_kernel,
23+
ConfigurationError, MMIO_MEM_SIZE, MMIO_MEM_START, arch_memory_regions,
24+
configure_system_for_boot, get_kernel_start, initrd_load_addr, layout::CMDLINE_MAX_SIZE,
25+
layout::IRQ_BASE, layout::IRQ_MAX, layout::SYSTEM_MEM_SIZE, layout::SYSTEM_MEM_START,
26+
load_kernel,
2627
};
2728

2829
/// Module for x86_64 related functionality.
@@ -35,12 +36,13 @@ pub use x86_64::kvm::{Kvm, KvmArchError};
3536
pub use x86_64::vcpu::*;
3637
#[cfg(target_arch = "x86_64")]
3738
pub use x86_64::vm::{ArchVm, ArchVmError, VmState};
39+
3840
#[cfg(target_arch = "x86_64")]
39-
pub use x86_64::{
40-
ConfigurationError, MMIO_MEM_SIZE, MMIO_MEM_START, arch_memory_regions, configure_system,
41-
get_kernel_start, initrd_load_addr, layout::APIC_ADDR, layout::CMDLINE_MAX_SIZE,
42-
layout::IOAPIC_ADDR, layout::IRQ_BASE, layout::IRQ_MAX, layout::SYSTEM_MEM_SIZE,
43-
layout::SYSTEM_MEM_START, load_kernel,
41+
pub use crate::arch::x86_64::{
42+
ConfigurationError, MMIO_MEM_SIZE, MMIO_MEM_START, arch_memory_regions,
43+
configure_system_for_boot, get_kernel_start, initrd_load_addr, layout::APIC_ADDR,
44+
layout::CMDLINE_MAX_SIZE, layout::IOAPIC_ADDR, layout::IRQ_BASE, layout::IRQ_MAX,
45+
layout::SYSTEM_MEM_SIZE, layout::SYSTEM_MEM_START, load_kernel,
4446
};
4547

4648
/// Types of devices that can get attached to this platform.

src/vmm/src/arch/x86_64/mod.rs

Lines changed: 92 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -41,17 +41,23 @@ use linux_loader::loader::elf::Elf as Loader;
4141
use linux_loader::loader::elf::start_info::{
4242
hvm_memmap_table_entry, hvm_modlist_entry, hvm_start_info,
4343
};
44-
use linux_loader::loader::{KernelLoader, PvhBootCapability};
44+
use linux_loader::loader::{Cmdline, KernelLoader, PvhBootCapability, load_cmdline};
4545
use log::debug;
4646

4747
use super::EntryPoint;
48+
use crate::acpi::create_acpi_tables;
4849
use crate::arch::{BootProtocol, SYSTEM_MEM_SIZE, SYSTEM_MEM_START};
50+
use crate::cpu_config::templates::{CustomCpuTemplate, GuestConfigError};
51+
use crate::cpu_config::x86_64::{CpuConfiguration, cpuid};
4952
use crate::device_manager::resources::ResourceAllocator;
5053
use crate::initrd::InitrdConfig;
5154
use crate::utils::{mib_to_bytes, u64_to_usize};
55+
use crate::vmm_config::machine_config::MachineConfig;
5256
use crate::vstate::memory::{
5357
Address, GuestAddress, GuestMemory, GuestMemoryMmap, GuestMemoryRegion,
5458
};
59+
use crate::vstate::vcpu::KvmVcpuConfigureError;
60+
use crate::{Vcpu, VcpuConfig, Vmm};
5561

5662
// Value taken from https://elixir.bootlin.com/linux/v5.10.68/source/arch/x86/include/uapi/asm/e820.h#L31
5763
// Usable normal RAM
@@ -62,7 +68,7 @@ const E820_RESERVED: u32 = 2;
6268
const MEMMAP_TYPE_RAM: u32 = 1;
6369

6470
/// Errors thrown while configuring x86_64 system.
65-
#[derive(Debug, PartialEq, Eq, thiserror::Error, displaydoc::Display)]
71+
#[derive(Debug, thiserror::Error, displaydoc::Display)]
6672
pub enum ConfigurationError {
6773
/// Invalid e820 setup params.
6874
E820Configuration,
@@ -80,6 +86,14 @@ pub enum ConfigurationError {
8086
KernelFile,
8187
/// Cannot load kernel due to invalid memory configuration or invalid kernel image: {0}
8288
KernelLoader(linux_loader::loader::Error),
89+
/// Failed to create guest config: {0}
90+
CreateGuestConfig(#[from] GuestConfigError),
91+
/// Error configuring the vcpu for boot: {0}
92+
VcpuConfigure(KvmVcpuConfigureError),
93+
/// Cannot load command line string: {0}
94+
LoadCommandline(linux_loader::loader::Error),
95+
/// Error configuring ACPI: {0}
96+
Acpi(#[from] crate::acpi::AcpiError),
8397
}
8498

8599
/// First address that cannot be addressed using 32 bit anymore.
@@ -130,17 +144,81 @@ pub fn initrd_load_addr(guest_mem: &GuestMemoryMmap, initrd_size: usize) -> Opti
130144
Some(align_to_pagesize(lowmem_size - initrd_size) as u64)
131145
}
132146

147+
/// Configures the system for booting Linux.
148+
pub fn configure_system_for_boot(
149+
vmm: &mut Vmm,
150+
vcpus: &mut [Vcpu],
151+
machine_config: &MachineConfig,
152+
cpu_template: &CustomCpuTemplate,
153+
entry_point: EntryPoint,
154+
initrd: &Option<InitrdConfig>,
155+
boot_cmdline: Cmdline,
156+
) -> Result<(), ConfigurationError> {
157+
// Construct the base CpuConfiguration to apply CPU template onto.
158+
let cpu_config = {
159+
let cpuid = cpuid::Cpuid::try_from(vmm.kvm.supported_cpuid.clone())
160+
.map_err(GuestConfigError::CpuidFromKvmCpuid)?;
161+
let msrs = vcpus[0]
162+
.kvm_vcpu
163+
.get_msrs(cpu_template.msr_index_iter())
164+
.map_err(GuestConfigError::VcpuIoctl)?;
165+
CpuConfiguration { cpuid, msrs }
166+
};
167+
168+
// Apply CPU template to the base CpuConfiguration.
169+
let cpu_config = CpuConfiguration::apply_template(cpu_config, cpu_template)?;
170+
171+
let vcpu_config = VcpuConfig {
172+
vcpu_count: machine_config.vcpu_count,
173+
smt: machine_config.smt,
174+
cpu_config,
175+
};
176+
177+
// Configure vCPUs with normalizing and setting the generated CPU configuration.
178+
for vcpu in vcpus.iter_mut() {
179+
vcpu.kvm_vcpu
180+
.configure(vmm.guest_memory(), entry_point, &vcpu_config)
181+
.map_err(ConfigurationError::VcpuConfigure)?;
182+
}
183+
184+
// Write the kernel command line to guest memory. This is x86_64 specific, since on
185+
// aarch64 the command line will be specified through the FDT.
186+
let cmdline_size = boot_cmdline
187+
.as_cstring()
188+
.map(|cmdline_cstring| cmdline_cstring.as_bytes_with_nul().len())
189+
.expect("Cannot create cstring from cmdline string");
190+
191+
load_cmdline::<GuestMemoryMmap>(
192+
vmm.guest_memory(),
193+
GuestAddress(crate::arch::x86_64::layout::CMDLINE_START),
194+
&boot_cmdline,
195+
)
196+
.map_err(ConfigurationError::LoadCommandline)?;
197+
configure_system(
198+
&vmm.guest_memory,
199+
&mut vmm.resource_allocator,
200+
GuestAddress(crate::arch::x86_64::layout::CMDLINE_START),
201+
cmdline_size,
202+
initrd,
203+
vcpu_config.vcpu_count,
204+
entry_point.protocol,
205+
)?;
206+
207+
// Create ACPI tables and write them in guest memory
208+
// For the time being we only support ACPI in x86_64
209+
create_acpi_tables(
210+
&vmm.guest_memory,
211+
&mut vmm.resource_allocator,
212+
&vmm.mmio_device_manager,
213+
&vmm.acpi_device_manager,
214+
vcpus,
215+
)
216+
.map_err(ConfigurationError::Acpi)?;
217+
Ok(())
218+
}
219+
133220
/// Configures the system and should be called once per vm before starting vcpu threads.
134-
///
135-
/// # Arguments
136-
///
137-
/// * `guest_mem` - The memory to be used by the guest.
138-
/// * `cmdline_addr` - Address in `guest_mem` where the kernel command line was loaded.
139-
/// * `cmdline_size` - Size of the kernel command line in bytes including the null terminator.
140-
/// * `initrd` - Information about where the ramdisk image was loaded in the `guest_mem`.
141-
/// * `num_cpus` - Number of virtual CPUs the guest will have.
142-
/// * `boot_prot` - Boot protocol that will be used to boot the guest.
143-
pub fn configure_system(
221+
fn configure_system(
144222
guest_mem: &GuestMemoryMmap,
145223
resource_allocator: &mut ResourceAllocator,
146224
cmdline_addr: GuestAddress,
@@ -438,10 +516,10 @@ mod tests {
438516
1,
439517
BootProtocol::LinuxBoot,
440518
);
441-
assert_eq!(
519+
assert!(matches!(
442520
config_err.unwrap_err(),
443521
super::ConfigurationError::MpTableSetup(mptable::MptableError::NotEnoughMemory)
444-
);
522+
));
445523

446524
// Now assigning some memory that falls before the 32bit memory hole.
447525
let mem_size = mib_to_bytes(128);

0 commit comments

Comments
 (0)