Skip to content

Commit 8379fcd

Browse files
ShadowCurseroypat
authored andcommitted
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 97f602f commit 8379fcd

File tree

5 files changed

+192
-179
lines changed

5 files changed

+192
-179
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(#[from] 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: 93 additions & 16 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,
@@ -79,7 +85,15 @@ pub enum ConfigurationError {
7985
/// Cannot copy kernel file fd
8086
KernelFile,
8187
/// Cannot load kernel due to invalid memory configuration or invalid kernel image: {0}
82-
KernelLoader(#[from] linux_loader::loader::Error),
88+
KernelLoader(linux_loader::loader::Error),
89+
/// Cannot load command line string: {0}
90+
LoadCommandline(linux_loader::loader::Error),
91+
/// Failed to create guest config: {0}
92+
CreateGuestConfig(#[from] GuestConfigError),
93+
/// Error configuring the vcpu for boot: {0}
94+
VcpuConfigure(#[from] KvmVcpuConfigureError),
95+
/// Error configuring ACPI: {0}
96+
Acpi(#[from] crate::acpi::AcpiError),
8397
}
8498

8599
/// First address that cannot be addressed using 32 bit anymore.
@@ -128,17 +142,79 @@ pub fn initrd_load_addr(guest_mem: &GuestMemoryMmap, initrd_size: usize) -> Opti
128142
Some(align_to_pagesize(lowmem_size - initrd_size) as u64)
129143
}
130144

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

385462
let mut entry_point_addr: GuestAddress = entry_addr.kernel_load;
386463
let mut boot_prot: BootProtocol = BootProtocol::LinuxBoot;
@@ -435,10 +512,10 @@ mod tests {
435512
1,
436513
BootProtocol::LinuxBoot,
437514
);
438-
assert_eq!(
515+
assert!(matches!(
439516
config_err.unwrap_err(),
440517
super::ConfigurationError::MpTableSetup(mptable::MptableError::NotEnoughMemory)
441-
);
518+
));
442519

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

0 commit comments

Comments
 (0)