@@ -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.
@@ -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