Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: put memory and env vars into FDT #758

Merged
merged 5 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ uhyve-interface = { version = "0.1.1", path = "uhyve-interface", features = ["st
virtio-bindings = { version = "0.2", features = ["virtio-v4_14_0"] }
rftrace = { version = "0.1", optional = true }
rftrace-frontend = { version = "0.1", optional = true }
shell-words = "1"
sysinfo = { version = "0.31.4", default-features = false, features = ["system"] }
vm-fdt = "0.3"

[target.'cfg(target_os = "linux")'.dependencies]
kvm-bindings = "0.9"
Expand Down
8 changes: 2 additions & 6 deletions src/bin/uhyve.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
#![warn(rust_2018_idioms)]

use std::{
ffi::OsString, iter, num::ParseIntError, ops::RangeInclusive, path::PathBuf, process,
str::FromStr,
};
use std::{iter, num::ParseIntError, ops::RangeInclusive, path::PathBuf, process, str::FromStr};

use clap::{error::ErrorKind, Command, CommandFactory, Parser};
use core_affinity::CoreId;
Expand Down Expand Up @@ -63,8 +60,7 @@ struct Args {
kernel: PathBuf,

/// Arguments to forward to the kernel
#[clap(value_parser)]
kernel_args: Vec<OsString>,
kernel_args: Vec<String>,
}

#[derive(Parser, Debug)]
Expand Down
1 change: 1 addition & 0 deletions src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub const BOOT_PML4: GuestPhysAddr = GuestPhysAddr::new(0x10000);
pub const BOOT_PGT: GuestPhysAddr = BOOT_PML4;
pub const BOOT_PDPTE: GuestPhysAddr = GuestPhysAddr::new(0x11000);
pub const BOOT_PDE: GuestPhysAddr = GuestPhysAddr::new(0x12000);
pub const FDT_ADDR: GuestPhysAddr = GuestPhysAddr::new(0x5000);
pub const BOOT_INFO_ADDR: GuestPhysAddr = GuestPhysAddr::new(0x9000);
pub const EFER_SCE: u64 = 1; /* System Call Extensions */
pub const EFER_LME: u64 = 1 << 8; /* Long mode enable */
Expand Down
134 changes: 134 additions & 0 deletions src/fdt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
//! Flattened Device Trees (FDT).

use std::{fmt::Write, ops::Range};

use uhyve_interface::GuestPhysAddr;
use vm_fdt::{FdtWriter, FdtWriterNode, FdtWriterResult};

/// A builder for an FDT.
pub struct Fdt {
writer: FdtWriter,
root_node: FdtWriterNode,
kernel_args: String,
app_args: String,
}

impl Fdt {
/// Creates a new FDT builder.
pub fn new() -> FdtWriterResult<Self> {
let mut writer = FdtWriter::new()?;

let root_node = writer.begin_node("")?;
writer.property_string("compatible", "hermit,uhyve")?;
writer.property_u32("#address-cells", 0x2)?;
writer.property_u32("#size-cells", 0x2)?;

let kernel_args = String::new();
let app_args = String::new();

Ok(Self {
writer,
root_node,
kernel_args,
app_args,
})
}

/// Builds and returns the FDT.
pub fn finish(mut self) -> FdtWriterResult<Vec<u8>> {
// The bootargs have the format `[KERNEL_ARGS] -- [APP_ARGS]`
let bootargs = match (self.kernel_args.as_str(), self.app_args.as_str()) {
("", "") => String::new(),
(_kernel_args, "") => self.kernel_args,
("", app_args) => format!("-- {app_args}"),
(kernel_args, app_args) => format!("{kernel_args} -- {app_args}"),
};

let chosen_node = self.writer.begin_node("chosen")?;
self.writer.property_string("bootargs", &bootargs)?;
self.writer.end_node(chosen_node)?;

self.writer.end_node(self.root_node)?;

self.writer.finish()
}

/// Adds a `/memory` node to the FDT.
pub fn memory(mut self, memory: Range<GuestPhysAddr>) -> FdtWriterResult<Self> {
let node_name = format!("memory@{:x}", memory.start);
let reg = &[memory.start.as_u64(), memory.end - memory.start][..];

let memory_node = self.writer.begin_node(&node_name)?;
self.writer.property_string("device_type", "memory")?;
self.writer.property_array_u64("reg", reg)?;
self.writer.end_node(memory_node)?;

Ok(self)
}

/// Adds a kernel argument to the FDT.
pub fn kernel_arg(mut self, kernel_arg: &str) -> Self {
if !self.kernel_args.is_empty() {
self.kernel_args.push(' ');
}

self.kernel_args.push_str(kernel_arg);

self
}

/// Adds kernel arguments to the FDT.
pub fn kernel_args(mut self, kernel_args: impl IntoIterator<Item = impl AsRef<str>>) -> Self {
for arg in kernel_args {
self = self.kernel_arg(arg.as_ref());
}

self
}

/// Adds an environment variable to the FDT.
pub fn env(mut self, key: &str, value: &str) -> Self {
if !self.kernel_args.is_empty() {
self.kernel_args.push(' ');
}

let key = shell_words::quote(key);
let value = shell_words::quote(value);

write!(&mut self.kernel_args, "env={key}={value}").unwrap();

self
}

/// Adds environment variables to the FDT.
pub fn envs(
mut self,
envs: impl IntoIterator<Item = (impl AsRef<str>, impl AsRef<str>)>,
) -> Self {
for (key, value) in envs {
self = self.env(key.as_ref(), value.as_ref());
}

self
}

/// Adds an app argument to the FDT.
pub fn app_arg(mut self, app_arg: &str) -> Self {
if !self.app_args.is_empty() {
self.app_args.push(' ');
}

self.app_args.push_str(app_arg);

self
}

/// Adds app arguments to the FDT.
pub fn app_args(mut self, app_args: impl IntoIterator<Item = impl AsRef<str>>) -> Self {
for arg in app_args {
self = self.app_arg(arg.as_ref());
}

self
}
}
4 changes: 2 additions & 2 deletions src/hypercall.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::{
ffi::{OsStr, OsString},
ffi::OsStr,
io::{self, Error, ErrorKind, Write},
os::unix::ffi::OsStrExt,
};
Expand Down Expand Up @@ -172,7 +172,7 @@ pub fn uart_buffer(sysuart: &SerialWriteBufferParams, mem: &MmapMemory) {
}

/// Copies the arguments of the application into the VM's memory to the destinations specified in `syscmdval`.
pub fn copy_argv(path: &OsStr, argv: &[OsString], syscmdval: &CmdvalParams, mem: &MmapMemory) {
pub fn copy_argv(path: &OsStr, argv: &[String], syscmdval: &CmdvalParams, mem: &MmapMemory) {
// copy kernel path as first argument
let argvp = mem
.host_address(syscmdval.argv)
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ extern crate log;

mod arch;
pub mod consts;
mod fdt;
#[cfg(target_os = "linux")]
pub mod linux;
#[cfg(target_os = "linux")]
Expand Down
3 changes: 1 addition & 2 deletions src/params.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use std::{
ffi::OsString,
fmt,
num::{NonZeroU32, ParseIntError, TryFromIntError},
str::FromStr,
Expand Down Expand Up @@ -35,7 +34,7 @@ pub struct Params {
pub gdb_port: Option<u16>,

/// Arguments to forward to the kernel
pub kernel_args: Vec<OsString>,
pub kernel_args: Vec<String>,
}

#[allow(clippy::derivable_impls)]
Expand Down
44 changes: 37 additions & 7 deletions src/vm.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use std::{
ffi::OsString,
fmt, fs, io,
env, fmt, fs, io,
marker::PhantomData,
num::NonZeroU32,
path::PathBuf,
Expand All @@ -24,8 +23,14 @@ use crate::arch::x86_64::{
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
use crate::linux::x86_64::kvm_cpu::initialize_kvm;
use crate::{
arch, arch::FrequencyDetectionFailed, consts::*, mem::MmapMemory, os::HypervisorError,
params::Params, vcpu::VirtualCPU, virtio::*,
arch::{self, FrequencyDetectionFailed},
consts::*,
fdt::Fdt,
mem::MmapMemory,
os::HypervisorError,
params::Params,
vcpu::VirtualCPU,
virtio::*,
};

pub type HypervisorResult<T> = Result<T, HypervisorError>;
Expand Down Expand Up @@ -107,7 +112,7 @@ pub struct UhyveVm<VCpuType: VirtualCPU = VcpuDefault> {
pub mem: Arc<MmapMemory>,
num_cpus: u32,
path: PathBuf,
args: Vec<OsString>,
args: Vec<String>,
boot_info: *const RawBootInfo,
verbose: bool,
pub virtio_device: Arc<Mutex<VirtioNetPciDevice>>,
Expand Down Expand Up @@ -190,7 +195,7 @@ impl<VCpuType: VirtualCPU> UhyveVm<VCpuType> {
&self.path
}

pub fn args(&self) -> &Vec<OsString> {
pub fn args(&self) -> &Vec<String> {
&self.args
}

Expand Down Expand Up @@ -228,6 +233,31 @@ impl<VCpuType: VirtualCPU> UhyveVm<VCpuType> {
);
self.entry_point = entry_point;

let sep = self
.args
.iter()
.enumerate()
.find(|(_i, arg)| *arg == "--")
.map(|(i, _arg)| i)
.unwrap_or_else(|| self.args.len());

let fdt = Fdt::new()
.unwrap()
.memory(self.mem.guest_address..self.mem.guest_address + self.mem.memory_size as u64)
.unwrap()
.kernel_args(&self.args[..sep])
.app_args(self.args.get(sep + 1..).unwrap_or_default())
.envs(env::vars())
.finish()
.unwrap();

debug!("fdt.len() = {}", fdt.len());
assert!(fdt.len() < (BOOT_INFO_ADDR - FDT_ADDR) as usize);
unsafe {
let fdt_ptr = self.mem.host_address.add(FDT_ADDR.as_u64() as usize);
fdt_ptr.copy_from_nonoverlapping(fdt.as_ptr(), fdt.len());
}

let boot_info = BootInfo {
hardware_info: HardwareInfo {
phys_addr_range: self.mem.guest_address.as_u64()
Expand All @@ -236,7 +266,7 @@ impl<VCpuType: VirtualCPU> UhyveVm<VCpuType> {
SerialPortBase::new((uhyve_interface::HypercallAddress::Uart as u16).into())
.unwrap()
}),
device_tree: None,
device_tree: Some(FDT_ADDR.as_u64().try_into().unwrap()),
},
load_info,
platform_info: PlatformInfo::Uhyve {
Expand Down
2 changes: 1 addition & 1 deletion uhyve-interface/src/parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ impl CmdsizeParams {
/// - `args` is a list of strings that form the parameters. (E.g., `["-v", "myarg"]`)
///
/// Note that this hypercall only transfers the sizes. It usually has to be followed up with the [`Cmdval` Hypercall](crate::Hypercall::Cmdval).
pub fn update(&mut self, path: &std::path::Path, args: &[std::ffi::OsString]) {
pub fn update(&mut self, path: &std::path::Path, args: &[String]) {
self.argc = 0;

self.argsz[0] = path.as_os_str().len() as i32 + 1;
Expand Down