Skip to content

Commit

Permalink
Merge pull request #1394 from hermit-os/fdt-bootargs
Browse files Browse the repository at this point in the history
feat(env): parse env=KEY=VALUE for env vars
  • Loading branch information
mkroening authored Sep 23, 2024
2 parents e608471 + a5f952b commit cecfc26
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 144 deletions.
10 changes: 1 addition & 9 deletions src/arch/aarch64/kernel/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,15 +91,7 @@ pub fn get_processor_count() -> u32 {
}

pub fn args() -> Option<&'static str> {
let dtb = unsafe {
hermit_dtb::Dtb::from_raw(ptr::with_exposed_provenance(
boot_info().hardware_info.device_tree.unwrap().get() as usize,
))
.expect(".dtb file has invalid header")
};

dtb.get_property("/chosen", "bootargs")
.map(|property| str::from_utf8(property).unwrap())
None
}

/// Earliest initialization function called by the Boot Processor.
Expand Down
5 changes: 1 addition & 4 deletions src/arch/riscv64/kernel/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,7 @@ pub fn get_base_address() -> VirtAddr {
}

pub fn args() -> Option<&'static str> {
unsafe {
let fdt = Fdt::from_ptr(get_dtb_ptr()).expect("FDT is invalid");
fdt.chosen().bootargs()
}
None
}

pub fn get_dtb_ptr() -> *const u8 {
Expand Down
44 changes: 34 additions & 10 deletions src/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

use alloc::string::{String, ToString};
use alloc::vec::Vec;
use core::str;
use core::{ptr, str};

use ahash::RandomState;
use fdt::Fdt;
use hashbrown::hash_map::Iter;
use hashbrown::HashMap;
use hermit_entry::boot_info::PlatformInfo;
Expand Down Expand Up @@ -36,6 +37,17 @@ pub fn is_uhyve() -> bool {
matches!(boot_info().platform_info, PlatformInfo::Uhyve { .. })
}

pub fn fdt() -> Option<Fdt<'static>> {
kernel::boot_info().hardware_info.device_tree.map(|fdt| {
let ptr = ptr::with_exposed_provenance(fdt.get().try_into().unwrap());
unsafe { Fdt::from_ptr(ptr).unwrap() }
})
}

pub fn fdt_args() -> Option<&'static str> {
fdt().and_then(|fdt| fdt.chosen().bootargs())
}

impl Default for Cli {
fn default() -> Self {
let mut image_path = None;
Expand All @@ -44,18 +56,20 @@ impl Default for Cli {
let mut env_vars = HashMap::<String, String, RandomState>::with_hasher(
RandomState::with_seeds(0, 0, 0, 0),
);
let mut args = Vec::new();
let mut mmio = Vec::new();

let words = shell_words::split(kernel::args().unwrap_or_default()).unwrap();
debug!("cli_words = {words:?}");
let args = kernel::args().or_else(fdt_args).unwrap_or_default();
info!("bootargs = {args}");
let words = shell_words::split(args).unwrap();

let mut words = words.into_iter();
let expect_arg = |arg: Option<String>, name: &str| {
arg.unwrap_or_else(|| {
panic!("The argument '{name}' requires a value but none was supplied")
})
};

let mut args = Vec::new();
let mut mmio = Vec::new();
while let Some(word) = words.next() {
if word.as_str().starts_with("virtio_mmio.device=") {
let v: Vec<&str> = word.as_str().split('=').collect();
Expand Down Expand Up @@ -86,12 +100,22 @@ impl Default for Cli {
env_vars.insert(String::from("UHYVE_MOUNT"), gateway);
}
"--" => args.extend(&mut words),
word if word.contains('=') => {
let (arg, value) = word.split_once('=').unwrap();

match arg {
"env" => {
let Some((key, value)) = value.split_once('=') else {
error!("could not parse bootarg: {word}");
continue;
};
env_vars.insert(key.to_string(), value.to_string());
}
_ => error!("could not parse bootarg: {word}"),
}
}
_ if image_path.is_none() => image_path = Some(word),
word => warn!(
"Found argument '{word}' which wasn't expected, or isn't valid in this context
If you tried to supply `{word}` as a value rather than a flag, use `-- {word}`"
),
word => error!("could not parse bootarg: {word}"),
};
}

Expand Down
129 changes: 8 additions & 121 deletions src/syscalls/interfaces/uhyve.rs
Original file line number Diff line number Diff line change
@@ -1,91 +1,34 @@
use alloc::alloc::{alloc, Layout};
use alloc::boxed::Box;
use alloc::vec::Vec;
use core::{mem, ptr};

#[cfg(target_arch = "x86_64")]
use x86::io::*;
use core::ptr;

use crate::arch;
use crate::arch::mm::{paging, PhysAddr, VirtAddr};
use crate::arch::mm::{paging, VirtAddr};
use crate::syscalls::interfaces::SyscallInterface;

const UHYVE_PORT_EXIT: u16 = 0x540;
const UHYVE_PORT_CMDSIZE: u16 = 0x740;
const UHYVE_PORT_CMDVAL: u16 = 0x780;

/// forward a request to the hypervisor uhyve
#[inline]
#[cfg(target_arch = "x86_64")]
fn uhyve_send<T>(port: u16, data: &mut T) {
let ptr = VirtAddr(ptr::from_mut(data).addr() as u64);
let physical_address = paging::virtual_to_physical(ptr).unwrap();

#[cfg(target_arch = "x86_64")]
unsafe {
outl(port, physical_address.as_u64() as u32);
x86::io::outl(port, physical_address.as_u64() as u32);
}
}

/// forward a request to the hypervisor uhyve
#[inline]
#[cfg(target_arch = "aarch64")]
fn uhyve_send<T>(port: u16, data: &mut T) {
use core::arch::asm;

let ptr = VirtAddr(ptr::from_mut(data).addr() as u64);
let physical_address = paging::virtual_to_physical(ptr).unwrap();

#[cfg(target_arch = "aarch64")]
unsafe {
asm!(
core::arch::asm!(
"str x8, [{port}]",
port = in(reg) u64::from(port),
in("x8") physical_address.as_u64(),
options(nostack),
);
}
}

/// forward a request to the hypervisor uhyve
#[inline]
#[cfg(target_arch = "riscv64")]
fn uhyve_send<T>(_port: u16, _data: &mut T) {
todo!()
}

const MAX_ARGC_ENVC: usize = 128;

#[repr(C, packed)]
struct SysCmdsize {
argc: i32,
argsz: [i32; MAX_ARGC_ENVC],
envc: i32,
envsz: [i32; MAX_ARGC_ENVC],
}

impl SysCmdsize {
fn new() -> SysCmdsize {
SysCmdsize {
argc: 0,
argsz: [0; MAX_ARGC_ENVC],
envc: 0,
envsz: [0; MAX_ARGC_ENVC],
}
}
}

#[repr(C, packed)]
struct SysCmdval {
argv: PhysAddr,
envp: PhysAddr,
}

impl SysCmdval {
fn new(argv: VirtAddr, envp: VirtAddr) -> SysCmdval {
SysCmdval {
argv: paging::virtual_to_physical(argv).unwrap(),
envp: paging::virtual_to_physical(envp).unwrap(),
}
}
#[cfg(target_arch = "riscv64")]
todo!("uhyve_send(port = {port}, physical_address = {physical_address})");
}

#[repr(C, packed)]
Expand All @@ -102,62 +45,6 @@ impl SysExit {
pub struct Uhyve;

impl SyscallInterface for Uhyve {
/// ToDo: This function needs a description - also applies to trait in src/syscalls/interfaces/mod.rs
///
/// ToDo: Add Safety section under which circumctances this is safe/unsafe to use
/// ToDo: Add an Errors section - What happens when e.g. malloc fails, how is that handled (currently it isn't)
#[cfg(target_os = "none")]
fn get_application_parameters(&self) -> (i32, *const *const u8, *const *const u8) {
// determine the number of arguments and environment variables
let mut syscmdsize = SysCmdsize::new();
uhyve_send(UHYVE_PORT_CMDSIZE, &mut syscmdsize);

// create array to receive all arguments
let mut argv = Box::new(Vec::with_capacity(syscmdsize.argc as usize));
let mut argv_phy = Vec::with_capacity(syscmdsize.argc as usize);
for i in 0..syscmdsize.argc as usize {
let layout =
Layout::from_size_align(syscmdsize.argsz[i] as usize * mem::size_of::<u8>(), 1)
.unwrap();

argv.push(unsafe { alloc(layout).cast_const() });

argv_phy.push(ptr::with_exposed_provenance::<u8>(
paging::virtual_to_physical(VirtAddr(argv[i] as u64))
.unwrap()
.as_usize(),
));
}

// create array to receive the environment
let mut env = Box::new(Vec::with_capacity(syscmdsize.envc as usize + 1));
let mut env_phy = Vec::with_capacity(syscmdsize.envc as usize + 1);
for i in 0..syscmdsize.envc as usize {
let layout =
Layout::from_size_align(syscmdsize.envsz[i] as usize * mem::size_of::<u8>(), 1)
.unwrap();
env.push(unsafe { alloc(layout).cast_const() });

env_phy.push(ptr::with_exposed_provenance::<u8>(
paging::virtual_to_physical(VirtAddr(env[i] as u64))
.unwrap()
.as_usize(),
));
}
env.push(ptr::null::<u8>());

// ask uhyve for the environment
let mut syscmdval = SysCmdval::new(
VirtAddr(argv_phy.as_ptr() as u64),
VirtAddr(env_phy.as_ptr() as u64),
);
uhyve_send(UHYVE_PORT_CMDVAL, &mut syscmdval);

let argv = argv.leak().as_ptr();
let env = env.leak().as_ptr();
(syscmdsize.argc, argv, env)
}

fn shutdown(&self, error_code: i32) -> ! {
let mut sysexit = SysExit::new(error_code);
uhyve_send(UHYVE_PORT_EXIT, &mut sysexit);
Expand Down

0 comments on commit cecfc26

Please sign in to comment.