Skip to content

Commit ed5bc96

Browse files
committed
arm: describe swiotlb region in FDT
describe the swiotlb region as a restricted-mem node in the flattened device tree, and force all virtio devices to use it for their vrings and buffers by setting their `memory-region` property. Signed-off-by: Patrick Roy <[email protected]>
1 parent 56750f6 commit ed5bc96

File tree

2 files changed

+45
-5
lines changed

2 files changed

+45
-5
lines changed

src/vmm/src/arch/aarch64/fdt.rs

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,23 @@ use std::ffi::CString;
1010
use std::fmt::Debug;
1111

1212
use vm_fdt::{Error as VmFdtError, FdtWriter, FdtWriterNode};
13-
use vm_memory::GuestMemoryError;
13+
use vm_memory::{GuestMemoryError, GuestMemoryRegion};
1414

1515
use super::super::DeviceType;
1616
use super::cache_info::{CacheEntry, read_cache_config};
1717
use super::gic::GICDevice;
1818
use crate::device_manager::mmio::MMIODeviceInfo;
1919
use crate::devices::acpi::vmgenid::{VMGENID_MEM_SIZE, VmGenId};
2020
use 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.
2424
const GIC_PHANDLE: u32 = 1;
2525
// This is a value for uniquely identifying the FDT node containing the clock definition.
2626
const 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.
@@ -58,6 +61,7 @@ pub enum FdtError {
5861
/// Creates the flattened device tree for this aarch64 microVM.
5962
pub fn create_fdt(
6063
guest_mem: &GuestMemoryMmap,
64+
swiotlb_region: Option<&KvmRegion>,
6165
vcpu_mpidr: Vec<u64>,
6266
cmdline: CString,
6367
device_info: &HashMap<(DeviceType, String), MMIODeviceInfo>,
@@ -83,7 +87,7 @@ pub fn create_fdt(
8387
// containing description of the interrupt controller for this VM.
8488
fdt_writer.property_u32("interrupt-parent", GIC_PHANDLE)?;
8589
create_cpu_nodes(&mut fdt_writer, &vcpu_mpidr)?;
86-
create_memory_node(&mut fdt_writer, guest_mem)?;
90+
create_memory_node(&mut fdt_writer, guest_mem, swiotlb_region)?;
8791
create_chosen_node(&mut fdt_writer, cmdline, initrd)?;
8892
create_gic_node(&mut fdt_writer, gic_device)?;
8993
create_timer_node(&mut fdt_writer)?;
@@ -208,7 +212,11 @@ fn create_cpu_nodes(fdt: &mut FdtWriter, vcpu_mpidr: &[u64]) -> Result<(), FdtEr
208212
Ok(())
209213
}
210214

211-
fn create_memory_node(fdt: &mut FdtWriter, guest_mem: &GuestMemoryMmap) -> Result<(), FdtError> {
215+
fn create_memory_node(
216+
fdt: &mut FdtWriter,
217+
guest_mem: &GuestMemoryMmap,
218+
swiotlb_region: Option<&KvmRegion>,
219+
) -> Result<(), FdtError> {
212220
// See https://github.com/torvalds/linux/blob/master/Documentation/devicetree/booting-without-of.txt#L960
213221
// for an explanation of this.
214222

@@ -220,9 +228,13 @@ fn create_memory_node(fdt: &mut FdtWriter, guest_mem: &GuestMemoryMmap) -> Resul
220228
// The reason we do this is that Linux does not allow remapping system memory. However, without
221229
// remap, kernel drivers cannot get virtual addresses to read data from device memory. Leaving
222230
// this memory region out allows Linux kernel modules to remap and thus read this region.
231+
//
232+
// The generic memory description must include the range that we later declare as a reserved
233+
// carve out.
223234
let mem_size = guest_mem.last_addr().raw_value()
224235
- super::layout::DRAM_MEM_START
225236
- super::layout::SYSTEM_MEM_SIZE
237+
+ swiotlb_region.map(|r| r.len()).unwrap_or(0)
226238
+ 1;
227239
let mem_reg_prop = &[
228240
super::layout::DRAM_MEM_START + super::layout::SYSTEM_MEM_SIZE,
@@ -233,6 +245,19 @@ fn create_memory_node(fdt: &mut FdtWriter, guest_mem: &GuestMemoryMmap) -> Resul
233245
fdt.property_array_u64("reg", mem_reg_prop)?;
234246
fdt.end_node(mem)?;
235247

248+
if let Some(region) = swiotlb_region {
249+
let rmem = fdt.begin_node("reserved-memory")?;
250+
fdt.property_u32("#address-cells", ADDRESS_CELLS)?;
251+
fdt.property_u32("#size-cells", SIZE_CELLS)?;
252+
fdt.property_null("ranges")?;
253+
let dma = fdt.begin_node("bouncy_boi")?;
254+
fdt.property_string("compatible", "restricted-dma-pool")?;
255+
fdt.property_phandle(IO_MEM_PHANDLE)?;
256+
fdt.property_array_u64("reg", &[region.start_addr().0, region.len()])?;
257+
fdt.end_node(dma)?;
258+
fdt.end_node(rmem)?;
259+
}
260+
236261
Ok(())
237262
}
238263

@@ -358,6 +383,9 @@ fn create_virtio_node(fdt: &mut FdtWriter, dev_info: &MMIODeviceInfo) -> Result<
358383

359384
fdt.property_string("compatible", "virtio,mmio")?;
360385
fdt.property_array_u64("reg", &[dev_info.addr, dev_info.len])?;
386+
// Force all virtio device to place their vrings and buffer into the dedicated I/O memory region
387+
// that is backed by traditional memory (e.g. not secret-free).
388+
fdt.property_u32("memory-region", IO_MEM_PHANDLE)?;
361389
fdt.property_array_u32(
362390
"interrupts",
363391
&[
@@ -499,6 +527,7 @@ mod tests {
499527
let gic = create_gic(&vm, 1, None).unwrap();
500528
create_fdt(
501529
&mem,
530+
None,
502531
vec![0],
503532
CString::new("console=tty0").unwrap(),
504533
&dev_info,
@@ -519,6 +548,7 @@ mod tests {
519548
let gic = create_gic(&vm, 1, None).unwrap();
520549
create_fdt(
521550
&mem,
551+
None,
522552
vec![0],
523553
CString::new("console=tty0").unwrap(),
524554
&HashMap::<(DeviceType, std::string::String), MMIODeviceInfo>::new(),
@@ -544,6 +574,7 @@ mod tests {
544574

545575
let current_dtb_bytes = create_fdt(
546576
&mem,
577+
None,
547578
vec![0],
548579
CString::new("console=tty0").unwrap(),
549580
&HashMap::<(DeviceType, std::string::String), MMIODeviceInfo>::new(),
@@ -606,6 +637,7 @@ mod tests {
606637

607638
let current_dtb_bytes = create_fdt(
608639
&mem,
640+
None,
609641
vec![0],
610642
CString::new("console=tty0").unwrap(),
611643
&HashMap::<(DeviceType, std::string::String), MMIODeviceInfo>::new(),

src/vmm/src/arch/aarch64/mod.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ use crate::cpu_config::templates::CustomCpuTemplate;
3030
use crate::initrd::InitrdConfig;
3131
use crate::utils::{align_up, usize_to_u64};
3232
use crate::vmm_config::machine_config::MachineConfig;
33-
use crate::vstate::memory::{Address, Bytes, GuestAddress, GuestMemory, GuestMemoryMmap};
33+
use crate::vstate::memory::{
34+
Address, Bytes, GuestAddress, GuestMemory, GuestMemoryMmap,
35+
};
3436
use crate::vstate::vcpu::KvmVcpuError;
3537
use crate::{Vcpu, VcpuConfig, Vmm};
3638

@@ -114,8 +116,14 @@ pub fn configure_system_for_boot(
114116
.as_cstring()
115117
.expect("Cannot create cstring from cmdline string");
116118

119+
let swiotlb_region = match vmm.vm.swiotlb_regions().num_regions() {
120+
0 | 1 => vmm.vm.swiotlb_regions().iter().next(),
121+
_ => panic!("Firecracker tried to configure more than one swiotlb region. This is a logic bug.")
122+
};
123+
117124
let fdt = fdt::create_fdt(
118125
vmm.vm.guest_memory(),
126+
swiotlb_region,
119127
vcpu_mpidr,
120128
cmdline,
121129
vmm.mmio_device_manager.get_device_info(),

0 commit comments

Comments
 (0)