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