@@ -41,17 +41,23 @@ use linux_loader::loader::elf::Elf as Loader;
4141use 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 } ;
4545use log:: debug;
4646
4747use super :: EntryPoint ;
48+ use crate :: acpi:: create_acpi_tables;
4849use 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} ;
4952use crate :: device_manager:: resources:: ResourceAllocator ;
5053use crate :: initrd:: InitrdConfig ;
5154use crate :: utils:: { mib_to_bytes, u64_to_usize} ;
55+ use crate :: vmm_config:: machine_config:: MachineConfig ;
5256use 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;
6268const 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 ) ]
6672pub 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.
@@ -128,17 +142,81 @@ 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+ . map_err ( ConfigurationError :: VcpuConfigure ) ?;
180+ }
181+
182+ // Write the kernel command line to guest memory. This is x86_64 specific, since on
183+ // aarch64 the command line will be specified through the FDT.
184+ let cmdline_size = boot_cmdline
185+ . as_cstring ( )
186+ . map ( |cmdline_cstring| cmdline_cstring. as_bytes_with_nul ( ) . len ( ) )
187+ . expect ( "Cannot create cstring from cmdline string" ) ;
188+
189+ load_cmdline :: < GuestMemoryMmap > (
190+ vmm. guest_memory ( ) ,
191+ GuestAddress ( crate :: arch:: x86_64:: layout:: CMDLINE_START ) ,
192+ & boot_cmdline,
193+ )
194+ . map_err ( ConfigurationError :: LoadCommandline ) ?;
195+ configure_system (
196+ & vmm. guest_memory ,
197+ & mut vmm. resource_allocator ,
198+ GuestAddress ( crate :: arch:: x86_64:: layout:: CMDLINE_START ) ,
199+ cmdline_size,
200+ initrd,
201+ vcpu_config. vcpu_count ,
202+ entry_point. protocol ,
203+ ) ?;
204+
205+ // Create ACPI tables and write them in guest memory
206+ // For the time being we only support ACPI in x86_64
207+ create_acpi_tables (
208+ & vmm. guest_memory ,
209+ & mut vmm. resource_allocator ,
210+ & vmm. mmio_device_manager ,
211+ & vmm. acpi_device_manager ,
212+ vcpus,
213+ )
214+ . map_err ( ConfigurationError :: Acpi ) ?;
215+ Ok ( ( ) )
216+ }
217+
131218/// 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 (
219+ fn configure_system (
142220 guest_mem : & GuestMemoryMmap ,
143221 resource_allocator : & mut ResourceAllocator ,
144222 cmdline_addr : GuestAddress ,
@@ -436,10 +514,10 @@ mod tests {
436514 1 ,
437515 BootProtocol :: LinuxBoot ,
438516 ) ;
439- assert_eq ! (
517+ assert ! ( matches !(
440518 config_err. unwrap_err( ) ,
441519 super :: ConfigurationError :: MpTableSetup ( mptable:: MptableError :: NotEnoughMemory )
442- ) ;
520+ ) ) ;
443521
444522 // Now assigning some memory that falls before the 32bit memory hole.
445523 let mem_size = mib_to_bytes ( 128 ) ;
0 commit comments