@@ -20,8 +20,9 @@ use vm_fdt::FdtWriter;
2020use vm_memory:: GuestMemoryRegion ;
2121use vm_memory:: { Address , Bytes , GuestAddress , GuestMemory } ;
2222
23+ use super :: fdt_utils:: * ;
2324use super :: Error ;
24- use crate :: { InitrdConfig , Result } ;
25+ use crate :: Result ;
2526
2627// This is a value for uniquely identifying the FDT node declaring the interrupt controller.
2728const GIC_PHANDLE : u32 = 1 ;
@@ -48,19 +49,15 @@ const GIC_FDT_IRQ_TYPE_PPI: u32 = 1;
4849const IRQ_TYPE_EDGE_RISING : u32 = 1 ;
4950const IRQ_TYPE_LEVEL_HI : u32 = 4 ;
5051
51- #[ allow( clippy:: borrowed_box) ]
5252/// Creates the flattened device tree for this aarch64 microVM.
53- pub fn create_fdt < T : DeviceInfoForFDT + Clone + Debug , M : GuestMemory > (
54- guest_mem : & M ,
55- // field 0: boot_onlined, decides whether to online this cpu at boot
56- // field 1: vcpu_mpidr
57- vcpu_state : Vec < ( u32 , u64 ) > ,
58- cmdline : & str ,
59- device_info : Option < & HashMap < ( DeviceType , String ) , T > > ,
60- gic_device : & Box < dyn GICDevice > ,
61- initrd : & Option < InitrdConfig > ,
62- vpmu_feature : & VpmuFeatureLevel ,
63- ) -> Result < Vec < u8 > > {
53+ pub fn create_fdt < T > (
54+ fdt_vm_info : FdtVmInfo ,
55+ _fdt_numa_info : FdtNumaInfo ,
56+ fdt_device_info : FdtDeviceInfo < T > ,
57+ ) -> Result < Vec < u8 > >
58+ where
59+ T : DeviceInfoForFDT + Clone + Debug ,
60+ {
6461 let mut fdt = FdtWriter :: new ( ) ?;
6562
6663 // For an explanation why these nodes were introduced in the blob take a look at
@@ -77,15 +74,17 @@ pub fn create_fdt<T: DeviceInfoForFDT + Clone + Debug, M: GuestMemory>(
7774 // This is not mandatory but we use it to point the root node to the node
7875 // containing description of the interrupt controller for this VM.
7976 fdt. property_u32 ( "interrupt-parent" , GIC_PHANDLE ) ?;
80- create_cpu_nodes ( & mut fdt, & vcpu_state ) ?;
81- create_memory_node ( & mut fdt, guest_mem ) ?;
82- create_chosen_node ( & mut fdt, cmdline , initrd ) ?;
83- create_gic_node ( & mut fdt, gic_device . as_ref ( ) ) ?;
77+ create_cpu_nodes ( & mut fdt, & fdt_vm_info ) ?;
78+ create_memory_node ( & mut fdt, fdt_vm_info . get_guest_memory ( ) ) ?;
79+ create_chosen_node ( & mut fdt, & fdt_vm_info ) ?;
80+ create_gic_node ( & mut fdt, fdt_device_info . get_irqchip ( ) ) ?;
8481 create_timer_node ( & mut fdt) ?;
8582 create_clock_node ( & mut fdt) ?;
8683 create_psci_node ( & mut fdt) ?;
87- device_info. map_or ( Ok ( ( ) ) , |v| create_devices_node ( & mut fdt, v) ) ?;
88- create_pmu_node ( & mut fdt, vpmu_feature) ?;
84+ fdt_device_info
85+ . get_mmio_device_info ( )
86+ . map_or ( Ok ( ( ) ) , |v| create_devices_node ( & mut fdt, v) ) ?;
87+ create_pmu_node ( & mut fdt, fdt_vm_info. get_vpmu_feature ( ) ) ?;
8988
9089 // End Header node.
9190 fdt. end_node ( root_node) ?;
@@ -94,21 +93,25 @@ pub fn create_fdt<T: DeviceInfoForFDT + Clone + Debug, M: GuestMemory>(
9493 let fdt_final = fdt. finish ( ) ?;
9594
9695 // Write FDT to memory.
97- let fdt_address = GuestAddress ( super :: get_fdt_addr ( guest_mem) ) ;
98- guest_mem. write_slice ( fdt_final. as_slice ( ) , fdt_address) ?;
96+ let fdt_address = GuestAddress ( super :: get_fdt_addr ( fdt_vm_info. get_guest_memory ( ) ) ) ;
97+ fdt_vm_info
98+ . get_guest_memory ( )
99+ . write_slice ( fdt_final. as_slice ( ) , fdt_address) ?;
99100 Ok ( fdt_final)
100101}
101102
102103// Following are the auxiliary function for creating the different nodes that we append to our FDT.
103- fn create_cpu_nodes ( fdt : & mut FdtWriter , vcpu_state : & [ ( u32 , u64 ) ] ) -> Result < ( ) > {
104+ fn create_cpu_nodes ( fdt : & mut FdtWriter , fdt_vm_info : & FdtVmInfo ) -> Result < ( ) > {
104105 // See https://github.com/torvalds/linux/blob/master/Documentation/devicetree/bindings/arm/cpus.yaml.
105106 let cpus_node = fdt. begin_node ( "cpus" ) ?;
106107 // As per documentation, on ARM v8 64-bit systems value should be set to 2.
107108 fdt. property_u32 ( "#address-cells" , 0x02 ) ?;
108109 fdt. property_u32 ( "#size-cells" , 0x0 ) ?;
109- let num_cpus = vcpu_state. len ( ) ;
110+ let vcpu_mpidr = fdt_vm_info. get_vcpu_mpidr ( ) ;
111+ let vcpu_boot_onlined = fdt_vm_info. get_boot_onlined ( ) ;
112+ let num_cpus = vcpu_mpidr. len ( ) ;
110113
111- for ( cpu_index, iter ) in vcpu_state . iter ( ) . enumerate ( ) . take ( num_cpus) {
114+ for ( cpu_index, mpidr ) in vcpu_mpidr . iter ( ) . enumerate ( ) . take ( num_cpus) {
112115 let cpu_name = format ! ( "cpu@{cpu_index:x}" ) ;
113116 let cpu_node = fdt. begin_node ( & cpu_name) ?;
114117 fdt. property_string ( "device_type" , "cpu" ) ?;
@@ -119,10 +122,10 @@ fn create_cpu_nodes(fdt: &mut FdtWriter, vcpu_state: &[(u32, u64)]) -> Result<()
119122 }
120123 // boot-onlined attribute is used to indicate whether this cpu should be onlined at boot.
121124 // 0 means offline, 1 means online.
122- fdt. property_u32 ( "boot-onlined" , iter . 0 ) ?;
125+ fdt. property_u32 ( "boot-onlined" , vcpu_boot_onlined [ cpu_index ] ) ?;
123126 // Set the field to first 24 bits of the MPIDR - Multiprocessor Affinity Register.
124127 // See http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0488c/BABHBJCI.html.
125- fdt. property_u64 ( "reg" , iter . 1 & 0x7FFFFF ) ?;
128+ fdt. property_u64 ( "reg" , mpidr & 0x7FFFFF ) ?;
126129 fdt. end_node ( cpu_node) ?;
127130 }
128131 fdt. end_node ( cpus_node) ?;
@@ -142,15 +145,11 @@ fn create_memory_node<M: GuestMemory>(fdt: &mut FdtWriter, guest_mem: &M) -> Res
142145 Ok ( ( ) )
143146}
144147
145- fn create_chosen_node (
146- fdt : & mut FdtWriter ,
147- cmdline : & str ,
148- initrd : & Option < InitrdConfig > ,
149- ) -> Result < ( ) > {
148+ fn create_chosen_node ( fdt : & mut FdtWriter , fdt_vm_info : & FdtVmInfo ) -> Result < ( ) > {
150149 let chosen_node = fdt. begin_node ( "chosen" ) ?;
151- fdt. property_string ( "bootargs" , cmdline ) ?;
150+ fdt. property_string ( "bootargs" , fdt_vm_info . get_cmdline ( ) ) ?;
152151
153- if let Some ( initrd_config) = initrd {
152+ if let Some ( initrd_config) = fdt_vm_info . get_initrd_config ( ) {
154153 fdt. property_u64 ( "linux,initrd-start" , initrd_config. address . raw_value ( ) ) ?;
155154 fdt. property_u64 (
156155 "linux,initrd-end" ,
@@ -373,8 +372,8 @@ fn create_devices_node<T: DeviceInfoForFDT + Clone + Debug>(
373372 Ok ( ( ) )
374373}
375374
376- fn create_pmu_node ( fdt : & mut FdtWriter , vpmu_feature : & VpmuFeatureLevel ) -> Result < ( ) > {
377- if * vpmu_feature == VpmuFeatureLevel :: Disabled {
375+ fn create_pmu_node ( fdt : & mut FdtWriter , vpmu_feature : VpmuFeatureLevel ) -> Result < ( ) > {
376+ if vpmu_feature == VpmuFeatureLevel :: Disabled {
378377 return Ok ( ( ) ) ;
379378 } ;
380379
@@ -396,14 +395,16 @@ mod tests {
396395 use std:: io:: Write ;
397396 use std:: path:: PathBuf ;
398397
399- use dbs_arch:: { gic:: create_gic, pmu:: initialize_pmu, Error as ArchError } ;
398+ use dbs_arch:: { gic:: create_gic, pmu:: initialize_pmu} ;
400399 use device_tree:: DeviceTree ;
401400 use kvm_bindings:: { kvm_vcpu_init, KVM_ARM_VCPU_PMU_V3 , KVM_ARM_VCPU_PSCI_0_2 } ;
402401 use kvm_ioctls:: { Kvm , VcpuFd , VmFd } ;
403402 use vm_memory:: GuestMemoryMmap ;
404403
404+ use super :: super :: tests:: MMIODeviceInfo ;
405405 use super :: * ;
406406 use crate :: layout:: { DRAM_MEM_MAX_SIZE , DRAM_MEM_START , FDT_MAX_SIZE } ;
407+ use crate :: InitrdConfig ;
407408
408409 const LEN : u64 = 4096 ;
409410
@@ -412,27 +413,6 @@ mod tests {
412413 vec ! [ ( GuestAddress ( DRAM_MEM_START ) , dram_size) ]
413414 }
414415
415- #[ derive( Clone , Debug ) ]
416- pub struct MMIODeviceInfo {
417- addr : u64 ,
418- irq : u32 ,
419- }
420-
421- impl DeviceInfoForFDT for MMIODeviceInfo {
422- fn addr ( & self ) -> u64 {
423- self . addr
424- }
425- fn irq ( & self ) -> std:: result:: Result < u32 , ArchError > {
426- Ok ( self . irq )
427- }
428- fn length ( & self ) -> u64 {
429- LEN
430- }
431- fn get_device_id ( & self ) -> Option < u32 > {
432- None
433- }
434- }
435-
436416 // The `load` function from the `device_tree` will mistakenly check the actual size
437417 // of the buffer with the allocated size. This works around that.
438418 fn set_size ( buf : & mut [ u8 ] , pos : usize , val : usize ) {
@@ -485,18 +465,15 @@ mod tests {
485465 let dev_info: HashMap < ( DeviceType , String ) , MMIODeviceInfo > = [
486466 (
487467 ( DeviceType :: Serial , DeviceType :: Serial . to_string ( ) ) ,
488- MMIODeviceInfo { addr : 0x00 , irq : 1 } ,
468+ MMIODeviceInfo :: new ( 0 , 1 ) ,
489469 ) ,
490470 (
491471 ( DeviceType :: Virtio ( 1 ) , "virtio" . to_string ( ) ) ,
492- MMIODeviceInfo { addr : LEN , irq : 2 } ,
472+ MMIODeviceInfo :: new ( LEN , 2 ) ,
493473 ) ,
494474 (
495475 ( DeviceType :: RTC , "rtc" . to_string ( ) ) ,
496- MMIODeviceInfo {
497- addr : 2 * LEN ,
498- irq : 3 ,
499- } ,
476+ MMIODeviceInfo :: new ( 2 * LEN , 3 ) ,
500477 ) ,
501478 ]
502479 . iter ( )
@@ -507,13 +484,14 @@ mod tests {
507484 let gic = create_gic ( & vm, 1 ) . unwrap ( ) ;
508485 let vpmu_feature = VpmuFeatureLevel :: Disabled ;
509486 assert ! ( create_fdt(
510- & mem,
511- vec![ ( 1 , 0 ) ] ,
512- "console=tty0" ,
513- Some ( & dev_info) ,
514- & gic,
515- & None ,
516- & vpmu_feature
487+ FdtVmInfo :: new(
488+ & mem,
489+ "console=tty0" ,
490+ None ,
491+ FdtVcpuInfo :: new( vec![ 0 ] , vec![ 1 ] , vpmu_feature, false )
492+ ) ,
493+ FdtNumaInfo :: default ( ) ,
494+ FdtDeviceInfo :: new( Some ( & dev_info) , gic. as_ref( ) )
517495 )
518496 . is_ok( ) )
519497 }
@@ -527,13 +505,14 @@ mod tests {
527505 let gic = create_gic ( & vm, 1 ) . unwrap ( ) ;
528506 let vpmu_feature = VpmuFeatureLevel :: Disabled ;
529507 let dtb = create_fdt (
530- & mem,
531- vec ! [ ( 1 , 0 ) ] ,
532- "console=tty0" ,
533- None :: < & HashMap < ( DeviceType , String ) , MMIODeviceInfo > > ,
534- & gic,
535- & None ,
536- & vpmu_feature,
508+ FdtVmInfo :: new (
509+ & mem,
510+ "console=tty0" ,
511+ None ,
512+ FdtVcpuInfo :: new ( vec ! [ 0 ] , vec ! [ 1 ] , vpmu_feature, false ) ,
513+ ) ,
514+ FdtNumaInfo :: default ( ) ,
515+ FdtDeviceInfo :: < MMIODeviceInfo > :: new ( None , gic. as_ref ( ) ) ,
537516 )
538517 . unwrap ( ) ;
539518
@@ -548,7 +527,7 @@ mod tests {
548527
549528 let original_fdt = DeviceTree :: load ( & buf) . unwrap ( ) ;
550529 let generated_fdt = DeviceTree :: load ( & dtb) . unwrap ( ) ;
551- assert ! ( format!( "{original_fdt:?}" ) == format!( "{generated_fdt:?}" ) ) ;
530+ assert_eq ! ( format!( "{original_fdt:?}" ) , format!( "{generated_fdt:?}" ) ) ;
552531 }
553532
554533 #[ test]
@@ -564,13 +543,14 @@ mod tests {
564543 } ;
565544 let vpmu_feature = VpmuFeatureLevel :: Disabled ;
566545 let dtb = create_fdt (
567- & mem,
568- vec ! [ ( 1 , 0 ) ] ,
569- "console=tty0" ,
570- None :: < & HashMap < ( DeviceType , String ) , MMIODeviceInfo > > ,
571- & gic,
572- & Some ( initrd) ,
573- & vpmu_feature,
546+ FdtVmInfo :: new (
547+ & mem,
548+ "console=tty0" ,
549+ Some ( & initrd) ,
550+ FdtVcpuInfo :: new ( vec ! [ 0 ] , vec ! [ 1 ] , vpmu_feature, false ) ,
551+ ) ,
552+ FdtNumaInfo :: default ( ) ,
553+ FdtDeviceInfo :: < MMIODeviceInfo > :: new ( None , gic. as_ref ( ) ) ,
574554 )
575555 . unwrap ( ) ;
576556
@@ -585,7 +565,7 @@ mod tests {
585565
586566 let original_fdt = DeviceTree :: load ( & buf) . unwrap ( ) ;
587567 let generated_fdt = DeviceTree :: load ( & dtb) . unwrap ( ) ;
588- assert ! ( format!( "{original_fdt:?}" ) == format!( "{generated_fdt:?}" ) ) ;
568+ assert_eq ! ( format!( "{original_fdt:?}" ) , format!( "{generated_fdt:?}" ) ) ;
589569 }
590570
591571 #[ test]
@@ -601,13 +581,14 @@ mod tests {
601581
602582 let vpmu_feature = VpmuFeatureLevel :: FullyEnabled ;
603583 let dtb = create_fdt (
604- & mem,
605- vec ! [ ( 1 , 0 ) ] ,
606- "console=tty0" ,
607- None :: < & std:: collections:: HashMap < ( DeviceType , std:: string:: String ) , MMIODeviceInfo > > ,
608- & gic,
609- & None ,
610- & vpmu_feature,
584+ FdtVmInfo :: new (
585+ & mem,
586+ "console=tty0" ,
587+ None ,
588+ FdtVcpuInfo :: new ( vec ! [ 0 ] , vec ! [ 1 ] , vpmu_feature, false ) ,
589+ ) ,
590+ FdtNumaInfo :: default ( ) ,
591+ FdtDeviceInfo :: < MMIODeviceInfo > :: new ( None , gic. as_ref ( ) ) ,
611592 )
612593 . unwrap ( ) ;
613594
@@ -622,6 +603,6 @@ mod tests {
622603
623604 let original_fdt = DeviceTree :: load ( & buf) . unwrap ( ) ;
624605 let generated_fdt = DeviceTree :: load ( & dtb) . unwrap ( ) ;
625- assert ! ( format!( "{original_fdt:?}" ) == format!( "{generated_fdt:?}" ) ) ;
606+ assert_eq ! ( format!( "{original_fdt:?}" ) , format!( "{generated_fdt:?}" ) ) ;
626607 }
627608}
0 commit comments