@@ -10,20 +10,23 @@ use std::ffi::CString;
1010use std:: fmt:: Debug ;
1111
1212use vm_fdt:: { Error as VmFdtError , FdtWriter , FdtWriterNode } ;
13- use vm_memory:: GuestMemoryError ;
13+ use vm_memory:: { GuestMemoryError , GuestMemoryRegion } ;
1414
1515use super :: super :: DeviceType ;
1616use super :: cache_info:: { CacheEntry , read_cache_config} ;
1717use super :: gic:: GICDevice ;
1818use crate :: device_manager:: mmio:: MMIODeviceInfo ;
1919use crate :: devices:: acpi:: vmgenid:: { VMGENID_MEM_SIZE , VmGenId } ;
2020use crate :: initrd:: InitrdConfig ;
21- use crate :: vstate:: memory:: { Address , GuestMemory , GuestMemoryMmap } ;
21+ use crate :: vstate:: memory:: { Address , GuestMemory , GuestMemoryMmap , KvmRegion } ;
2222
2323// This is a value for uniquely identifying the FDT node declaring the interrupt controller.
2424const GIC_PHANDLE : u32 = 1 ;
2525// This is a value for uniquely identifying the FDT node containing the clock definition.
2626const CLOCK_PHANDLE : u32 = 2 ;
27+ /// Unique identifier for the /reserved-memory node describing the memory region the guest
28+ /// is allowed to use for swiotlb
29+ const IO_MEM_PHANDLE : u32 = 3 ;
2730// You may be wondering why this big value?
2831// This phandle is used to uniquely identify the FDT nodes containing cache information. Each cpu
2932// can have a variable number of caches, some of these caches may be shared with other cpus.
@@ -56,8 +59,10 @@ pub enum FdtError {
5659}
5760
5861/// Creates the flattened device tree for this aarch64 microVM.
62+ #[ allow( clippy:: too_many_arguments) ]
5963pub fn create_fdt (
6064 guest_mem : & GuestMemoryMmap ,
65+ swiotlb_region : Option < & KvmRegion > ,
6166 vcpu_mpidr : Vec < u64 > ,
6267 cmdline : CString ,
6368 device_info : & HashMap < ( DeviceType , String ) , MMIODeviceInfo > ,
@@ -83,7 +88,7 @@ pub fn create_fdt(
8388 // containing description of the interrupt controller for this VM.
8489 fdt_writer. property_u32 ( "interrupt-parent" , GIC_PHANDLE ) ?;
8590 create_cpu_nodes ( & mut fdt_writer, & vcpu_mpidr) ?;
86- create_memory_node ( & mut fdt_writer, guest_mem) ?;
91+ create_memory_node ( & mut fdt_writer, guest_mem, swiotlb_region ) ?;
8792 create_chosen_node ( & mut fdt_writer, cmdline, initrd) ?;
8893 create_gic_node ( & mut fdt_writer, gic_device) ?;
8994 create_timer_node ( & mut fdt_writer) ?;
@@ -208,7 +213,11 @@ fn create_cpu_nodes(fdt: &mut FdtWriter, vcpu_mpidr: &[u64]) -> Result<(), FdtEr
208213 Ok ( ( ) )
209214}
210215
211- fn create_memory_node ( fdt : & mut FdtWriter , guest_mem : & GuestMemoryMmap ) -> Result < ( ) , FdtError > {
216+ fn create_memory_node (
217+ fdt : & mut FdtWriter ,
218+ guest_mem : & GuestMemoryMmap ,
219+ swiotlb_region : Option < & KvmRegion > ,
220+ ) -> Result < ( ) , FdtError > {
212221 // See https://github.com/torvalds/linux/blob/master/Documentation/devicetree/booting-without-of.txt#L960
213222 // for an explanation of this.
214223
@@ -220,9 +229,13 @@ fn create_memory_node(fdt: &mut FdtWriter, guest_mem: &GuestMemoryMmap) -> Resul
220229 // The reason we do this is that Linux does not allow remapping system memory. However, without
221230 // remap, kernel drivers cannot get virtual addresses to read data from device memory. Leaving
222231 // this memory region out allows Linux kernel modules to remap and thus read this region.
232+ //
233+ // The generic memory description must include the range that we later declare as a reserved
234+ // carve out.
223235 let mem_size = guest_mem. last_addr ( ) . raw_value ( )
224236 - super :: layout:: DRAM_MEM_START
225237 - super :: layout:: SYSTEM_MEM_SIZE
238+ + swiotlb_region. map ( |r| r. len ( ) ) . unwrap_or ( 0 )
226239 + 1 ;
227240 let mem_reg_prop = & [
228241 super :: layout:: DRAM_MEM_START + super :: layout:: SYSTEM_MEM_SIZE ,
@@ -233,6 +246,19 @@ fn create_memory_node(fdt: &mut FdtWriter, guest_mem: &GuestMemoryMmap) -> Resul
233246 fdt. property_array_u64 ( "reg" , mem_reg_prop) ?;
234247 fdt. end_node ( mem) ?;
235248
249+ if let Some ( region) = swiotlb_region {
250+ let rmem = fdt. begin_node ( "reserved-memory" ) ?;
251+ fdt. property_u32 ( "#address-cells" , ADDRESS_CELLS ) ?;
252+ fdt. property_u32 ( "#size-cells" , SIZE_CELLS ) ?;
253+ fdt. property_null ( "ranges" ) ?;
254+ let dma = fdt. begin_node ( "bouncy_boi" ) ?;
255+ fdt. property_string ( "compatible" , "restricted-dma-pool" ) ?;
256+ fdt. property_phandle ( IO_MEM_PHANDLE ) ?;
257+ fdt. property_array_u64 ( "reg" , & [ region. start_addr ( ) . 0 , region. len ( ) ] ) ?;
258+ fdt. end_node ( dma) ?;
259+ fdt. end_node ( rmem) ?;
260+ }
261+
236262 Ok ( ( ) )
237263}
238264
@@ -358,6 +384,9 @@ fn create_virtio_node(fdt: &mut FdtWriter, dev_info: &MMIODeviceInfo) -> Result<
358384
359385 fdt. property_string ( "compatible" , "virtio,mmio" ) ?;
360386 fdt. property_array_u64 ( "reg" , & [ dev_info. addr , dev_info. len ] ) ?;
387+ // Force all virtio device to place their vrings and buffer into the dedicated I/O memory region
388+ // that is backed by traditional memory (e.g. not secret-free).
389+ fdt. property_u32 ( "memory-region" , IO_MEM_PHANDLE ) ?;
361390 fdt. property_array_u32 (
362391 "interrupts" ,
363392 & [
@@ -499,6 +528,7 @@ mod tests {
499528 let gic = create_gic ( & vm, 1 , None ) . unwrap ( ) ;
500529 create_fdt (
501530 & mem,
531+ None ,
502532 vec ! [ 0 ] ,
503533 CString :: new ( "console=tty0" ) . unwrap ( ) ,
504534 & dev_info,
@@ -519,6 +549,7 @@ mod tests {
519549 let gic = create_gic ( & vm, 1 , None ) . unwrap ( ) ;
520550 create_fdt (
521551 & mem,
552+ None ,
522553 vec ! [ 0 ] ,
523554 CString :: new ( "console=tty0" ) . unwrap ( ) ,
524555 & HashMap :: < ( DeviceType , std:: string:: String ) , MMIODeviceInfo > :: new ( ) ,
@@ -544,6 +575,7 @@ mod tests {
544575
545576 let current_dtb_bytes = create_fdt (
546577 & mem,
578+ None ,
547579 vec ! [ 0 ] ,
548580 CString :: new ( "console=tty0" ) . unwrap ( ) ,
549581 & HashMap :: < ( DeviceType , std:: string:: String ) , MMIODeviceInfo > :: new ( ) ,
@@ -606,6 +638,7 @@ mod tests {
606638
607639 let current_dtb_bytes = create_fdt (
608640 & mem,
641+ None ,
609642 vec ! [ 0 ] ,
610643 CString :: new ( "console=tty0" ) . unwrap ( ) ,
611644 & HashMap :: < ( DeviceType , std:: string:: String ) , MMIODeviceInfo > :: new ( ) ,
0 commit comments