Skip to content

Commit

Permalink
arch: implement SHM region management
Browse files Browse the repository at this point in the history
We have multiple devices (fs and gpu) that can use SHM regions. So far,
we were creating a single SHM region so only one device could make use
of it. In this commit, we implement SHM region management so multiple
devices can request their own regions.

For the moment, we're hardcoding the SHM region sizes for gpu and fs. A
future commit will extend the API so users can configure those sizes as
desired.

Signed-off-by: Sergio Lopez <[email protected]>
  • Loading branch information
slp committed Aug 29, 2024
1 parent 8a80132 commit c49f774
Show file tree
Hide file tree
Showing 11 changed files with 261 additions and 82 deletions.
17 changes: 6 additions & 11 deletions src/arch/src/aarch64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,11 @@ pub mod macos;
#[cfg(target_os = "macos")]
pub use self::macos::*;

use std::cmp::min;
use std::collections::HashMap;
use std::fmt::Debug;

use self::gic::GICDevice;
use crate::ArchMemoryInfo;
use crate::{round_up, ArchMemoryInfo};
use vm_memory::{Address, GuestAddress, GuestMemory, GuestMemoryMmap};

#[cfg(feature = "efi")]
Expand All @@ -42,35 +41,31 @@ pub enum Error {

/// The start of the memory area reserved for MMIO devices.
pub const MMIO_MEM_START: u64 = layout::MAPPED_IO_START;
/// The size of the MMIO shared memory area used by virtio-fs DAX.
pub const MMIO_SHM_SIZE: u64 = 1 << 33;

pub use self::fdt::DeviceInfoForFDT;
use crate::DeviceType;

/// Returns a Vec of the valid memory addresses for aarch64.
/// See [`layout`](layout) module for a drawing of the specific memory model for this platform.
pub fn arch_memory_regions(size: usize) -> (ArchMemoryInfo, Vec<(GuestAddress, usize)>) {
let dram_size = min(size as u64, layout::DRAM_MEM_MAX_SIZE) as usize;
let page_size: usize = unsafe { libc::sysconf(libc::_SC_PAGESIZE).try_into().unwrap() };
let dram_size = round_up(size, page_size);
let ram_last_addr = layout::DRAM_MEM_START + (dram_size as u64);
let shm_start_addr = ((ram_last_addr / 0x4000_0000) + 1) * 0x4000_0000;

let info = ArchMemoryInfo {
ram_last_addr,
shm_start_addr,
shm_size: MMIO_SHM_SIZE,
page_size,
};
let regions = if cfg!(feature = "efi") {
vec![
// Space for loading EDK2 and its variables
(GuestAddress(0u64), 0x800_0000),
(GuestAddress(layout::DRAM_MEM_START), dram_size),
(GuestAddress(shm_start_addr), MMIO_SHM_SIZE as usize),
]
} else {
vec![
(GuestAddress(layout::DRAM_MEM_START), dram_size),
(GuestAddress(shm_start_addr), MMIO_SHM_SIZE as usize),
]
vec![(GuestAddress(layout::DRAM_MEM_START), dram_size)]
};

(info, regions)
Expand Down
14 changes: 11 additions & 3 deletions src/arch/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::result;
pub struct ArchMemoryInfo {
pub ram_last_addr: u64,
pub shm_start_addr: u64,
pub shm_size: u64,
pub page_size: usize,
}

/// Module for aarch64 related functionality.
Expand All @@ -22,7 +22,6 @@ pub mod aarch64;
pub use aarch64::{
arch_memory_regions, configure_system, get_kernel_start, initrd_load_addr,
layout::CMDLINE_MAX_SIZE, layout::IRQ_BASE, layout::IRQ_MAX, Error, MMIO_MEM_START,
MMIO_SHM_SIZE,
};

/// Module for x86_64 related functionality.
Expand All @@ -33,7 +32,7 @@ pub mod x86_64;
pub use crate::x86_64::{
arch_memory_regions, configure_system, get_kernel_start, initrd_load_addr,
layout::CMDLINE_MAX_SIZE, layout::IRQ_BASE, layout::IRQ_MAX, Error, BIOS_SIZE, BIOS_START,
MMIO_MEM_START, MMIO_SHM_SIZE, RESET_VECTOR,
MMIO_MEM_START, RESET_VECTOR,
};

/// Type for returning public functions outcome.
Expand Down Expand Up @@ -66,6 +65,15 @@ pub struct InitrdConfig {
/// Default (smallest) memory page size for the supported architectures.
pub const PAGE_SIZE: usize = 4096;

pub fn round_up(size: usize, align: usize) -> usize {
let page_mask = align - 1;
(size + page_mask) & !page_mask
}
pub fn round_down(size: usize, align: usize) -> usize {
let page_mask = !(align - 1);
size & page_mask
}

impl fmt::Display for DeviceType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{self:?}")
Expand Down
21 changes: 11 additions & 10 deletions src/arch/src/x86_64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ pub mod msr;
/// Logic for configuring x86_64 registers.
pub mod regs;

use crate::ArchMemoryInfo;
use crate::InitrdConfig;
use crate::{round_up, ArchMemoryInfo, InitrdConfig};
use arch_gen::x86::bootparam::{boot_params, E820_RAM};
use vm_memory::Bytes;
use vm_memory::{
Expand Down Expand Up @@ -60,8 +59,6 @@ const FIRST_ADDR_PAST_32BITS: u64 = 1 << 32;
const MEM_32BIT_GAP_SIZE: u64 = 768 << 20;
/// The start of the memory area reserved for MMIO devices.
pub const MMIO_MEM_START: u64 = FIRST_ADDR_PAST_32BITS - MEM_32BIT_GAP_SIZE;
/// The size of the MMIO shared memory area used by virtio-fs DAX.
pub const MMIO_SHM_SIZE: u64 = 1 << 33;

/// Returns a Vec of the valid memory addresses.
/// These should be used to configure the GuestMemoryMmap structure for the platform.
Expand All @@ -73,6 +70,9 @@ pub fn arch_memory_regions(
kernel_load_addr: u64,
kernel_size: usize,
) -> (ArchMemoryInfo, Vec<(GuestAddress, usize)>) {
let page_size: usize = unsafe { libc::sysconf(libc::_SC_PAGESIZE).try_into().unwrap() };

let size = round_up(size, page_size);
if size < (kernel_load_addr + kernel_size as u64) as usize {
panic!("Kernel doesn't fit in RAM");
}
Expand All @@ -90,7 +90,6 @@ pub fn arch_memory_regions(
vec![
(GuestAddress(0), kernel_load_addr as usize),
(GuestAddress(kernel_load_addr + kernel_size as u64), size),
(GuestAddress(FIRST_ADDR_PAST_32BITS), MMIO_SHM_SIZE as usize),
],
)
}
Expand All @@ -108,15 +107,14 @@ pub fn arch_memory_regions(
(MMIO_MEM_START - (kernel_load_addr + kernel_size as u64)) as usize,
),
(GuestAddress(FIRST_ADDR_PAST_32BITS), remaining),
(GuestAddress(shm_start_addr), MMIO_SHM_SIZE as usize),
],
)
}
};
let info = ArchMemoryInfo {
ram_last_addr,
shm_start_addr,
shm_size: MMIO_SHM_SIZE,
page_size,
};
(info, regions)
}
Expand All @@ -132,6 +130,9 @@ pub fn arch_memory_regions(
kernel_load_addr: u64,
kernel_size: usize,
) -> (ArchMemoryInfo, Vec<(GuestAddress, usize)>) {
let page_size: usize = unsafe { libc::sysconf(libc::_SC_PAGESIZE).try_into().unwrap() };

let size = round_up(size, page_size);
if size < (kernel_load_addr + kernel_size as u64) as usize {
panic!("Kernel doesn't fit in RAM");
}
Expand Down Expand Up @@ -170,7 +171,7 @@ pub fn arch_memory_regions(
let info = ArchMemoryInfo {
ram_last_addr,
shm_start_addr,
shm_size: 0,
page_size,
};
(info, regions)
}
Expand Down Expand Up @@ -319,7 +320,7 @@ mod tests {
#[test]
fn regions_lt_4gb() {
let (_info, regions) = arch_memory_regions(1usize << 29, KERNEL_LOAD_ADDR, KERNEL_SIZE);
assert_eq!(3, regions.len());
assert_eq!(2, regions.len());
assert_eq!(GuestAddress(0), regions[0].0);
assert_eq!(KERNEL_LOAD_ADDR as usize, regions[0].1);
assert_eq!(
Expand All @@ -333,7 +334,7 @@ mod tests {
fn regions_gt_4gb() {
let (_info, regions) =
arch_memory_regions((1usize << 32) + 0x8000, KERNEL_LOAD_ADDR, KERNEL_SIZE);
assert_eq!(4, regions.len());
assert_eq!(3, regions.len());
assert_eq!(GuestAddress(0), regions[0].0);
assert_eq!(KERNEL_LOAD_ADDR as usize, regions[0].1);
assert_eq!(
Expand Down
12 changes: 10 additions & 2 deletions src/devices/src/virtio/fs/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,19 @@ impl<F: FileSystem + Sync> Server<F> {
x if x == Opcode::CopyFileRange as u32 => self.copyfilerange(in_header, r, w),
x if (x == Opcode::SetupMapping as u32) && shm_region.is_some() => {
let shm = shm_region.unwrap();
self.setupmapping(in_header, r, w, shm.host_addr, shm.size as u64)
#[cfg(target_os = "linux")]
let shm_base_addr = shm.host_addr;
#[cfg(target_os = "macos")]
let shm_base_addr = shm.guest_addr;
self.setupmapping(in_header, r, w, shm_base_addr, shm.size as u64)
}
x if (x == Opcode::RemoveMapping as u32) && shm_region.is_some() => {
let shm = shm_region.unwrap();
self.removemapping(in_header, r, w, shm.host_addr, shm.size as u64)
#[cfg(target_os = "linux")]
let shm_base_addr = shm.host_addr;
#[cfg(target_os = "macos")]
let shm_base_addr = shm.guest_addr;
self.removemapping(in_header, r, w, shm_base_addr, shm.size as u64)
}
_ => reply_error(
linux_error(io::Error::from_raw_os_error(libc::ENOSYS)),
Expand Down
3 changes: 2 additions & 1 deletion src/devices/src/virtio/gpu/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@ use utils::eventfd::EventFd;
use vm_memory::{GuestAddress, GuestMemoryMmap};

use super::super::descriptor_utils::{Reader, Writer};
use super::super::{GpuError, Queue as VirtQueue, VirtioShmRegion, VIRTIO_MMIO_INT_VRING};
use super::super::{GpuError, Queue as VirtQueue, VIRTIO_MMIO_INT_VRING};
use super::protocol::{
virtio_gpu_ctrl_hdr, virtio_gpu_mem_entry, GpuCommand, GpuResponse, VirtioGpuResult,
};
use super::virtio_gpu::VirtioGpu;
use crate::legacy::Gic;
use crate::virtio::gpu::protocol::{VIRTIO_GPU_FLAG_FENCE, VIRTIO_GPU_FLAG_INFO_RING_IDX};
use crate::virtio::gpu::virtio_gpu::VirtioGpuRing;
use crate::virtio::VirtioShmRegion;
use crate::Error as DeviceError;

pub struct Worker {
Expand Down
Loading

0 comments on commit c49f774

Please sign in to comment.