@@ -41,17 +41,23 @@ use linux_loader::loader::elf::Elf as Loader;
41
41
use linux_loader:: loader:: elf:: start_info:: {
42
42
hvm_memmap_table_entry, hvm_modlist_entry, hvm_start_info,
43
43
} ;
44
- use linux_loader:: loader:: { KernelLoader , PvhBootCapability } ;
44
+ use linux_loader:: loader:: { Cmdline , KernelLoader , PvhBootCapability , load_cmdline } ;
45
45
use log:: debug;
46
46
47
47
use super :: EntryPoint ;
48
+ use crate :: acpi:: create_acpi_tables;
48
49
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} ;
49
52
use crate :: device_manager:: resources:: ResourceAllocator ;
50
53
use crate :: initrd:: InitrdConfig ;
51
54
use crate :: utils:: { mib_to_bytes, u64_to_usize} ;
55
+ use crate :: vmm_config:: machine_config:: MachineConfig ;
52
56
use crate :: vstate:: memory:: {
53
57
Address , GuestAddress , GuestMemory , GuestMemoryMmap , GuestMemoryRegion ,
54
58
} ;
59
+ use crate :: vstate:: vcpu:: KvmVcpuConfigureError ;
60
+ use crate :: { Vcpu , VcpuConfig , Vmm } ;
55
61
56
62
// Value taken from https://elixir.bootlin.com/linux/v5.10.68/source/arch/x86/include/uapi/asm/e820.h#L31
57
63
// Usable normal RAM
@@ -62,7 +68,7 @@ const E820_RESERVED: u32 = 2;
62
68
const MEMMAP_TYPE_RAM : u32 = 1 ;
63
69
64
70
/// Errors thrown while configuring x86_64 system.
65
- #[ derive( Debug , PartialEq , Eq , thiserror:: Error , displaydoc:: Display ) ]
71
+ #[ derive( Debug , thiserror:: Error , displaydoc:: Display ) ]
66
72
pub enum ConfigurationError {
67
73
/// Invalid e820 setup params.
68
74
E820Configuration ,
@@ -79,7 +85,15 @@ pub enum ConfigurationError {
79
85
/// Cannot copy kernel file fd
80
86
KernelFile ,
81
87
/// 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 ) ,
83
97
}
84
98
85
99
/// 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
128
142
Some ( align_to_pagesize ( lowmem_size - initrd_size) as u64 )
129
143
}
130
144
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
+
131
216
/// 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 (
142
218
guest_mem : & GuestMemoryMmap ,
143
219
resource_allocator : & mut ResourceAllocator ,
144
220
cmdline_addr : GuestAddress ,
@@ -380,7 +456,8 @@ pub fn load_kernel(
380
456
None ,
381
457
& mut kernel_file,
382
458
Some ( GuestAddress ( get_kernel_start ( ) ) ) ,
383
- ) ?;
459
+ )
460
+ . map_err ( ConfigurationError :: KernelLoader ) ?;
384
461
385
462
let mut entry_point_addr: GuestAddress = entry_addr. kernel_load ;
386
463
let mut boot_prot: BootProtocol = BootProtocol :: LinuxBoot ;
@@ -435,10 +512,10 @@ mod tests {
435
512
1 ,
436
513
BootProtocol :: LinuxBoot ,
437
514
) ;
438
- assert_eq ! (
515
+ assert ! ( matches !(
439
516
config_err. unwrap_err( ) ,
440
517
super :: ConfigurationError :: MpTableSetup ( mptable:: MptableError :: NotEnoughMemory )
441
- ) ;
518
+ ) ) ;
442
519
443
520
// Now assigning some memory that falls before the 32bit memory hole.
444
521
let mem_size = mib_to_bytes ( 128 ) ;
0 commit comments