Skip to content

Commit

Permalink
Added hypercall for a serial output of a whole buffer
Browse files Browse the repository at this point in the history
  • Loading branch information
nathanwhyte authored and jounathaen committed Sep 17, 2024
1 parent a3ab47a commit a2b664c
Show file tree
Hide file tree
Showing 10 changed files with 226 additions and 0 deletions.
13 changes: 13 additions & 0 deletions src/hypercall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ pub unsafe fn address_to_hypercall(
Hypercall::Cmdval(syscmdval)
}
HypercallAddress::Uart => Hypercall::SerialWriteByte(data.as_u64() as u8),
HypercallAddress::SerialBufferWrite => {
let sysserialwrite = mem.get_ref_mut(data).unwrap();
Hypercall::SerialWriteBuffer(sysserialwrite)
}
_ => unimplemented!(),
})
} else {
Expand Down Expand Up @@ -158,6 +162,15 @@ pub fn uart(buf: &[u8]) -> io::Result<()> {
io::stdout().write_all(buf)
}

/// Handles a UART syscall by contructing a buffer from parameter
pub fn uart_buffer(sysuart: &SerialWriteBufferParams, mem: &MmapMemory) {
let buf = unsafe {
mem.slice_at(sysuart.buf, sysuart.len)
.expect("Systemcall parameters for SerialWriteBuffer are invalid")
};
io::stdout().write_all(buf).unwrap()
}

/// 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) {
// copy kernel path as first argument
Expand Down
3 changes: 3 additions & 0 deletions src/linux/x86_64/kvm_cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,9 @@ impl VirtualCPU for KvmCpu {
hypercall::unlink(&self.parent_vm.mem, sysunlink)
}
Hypercall::SerialWriteByte(buf) => hypercall::uart(&[buf])?,
Hypercall::SerialWriteBuffer(sysserialwrite) => {
hypercall::uart_buffer(sysserialwrite, &self.parent_vm.mem)
}
_ => panic!("Got unknown hypercall {:?}", hypercall),
};
} else {
Expand Down
3 changes: 3 additions & 0 deletions src/macos/aarch64/vcpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,9 @@ impl VirtualCPU for XhyveCpu {

hypercall::uart(&[x8]).unwrap();
}
Hypercall::SerialWriteBuffer(sysserialwrite) => {
hypercall::uart_buffer(sysserialwrite, &self.parent_vm.mem)
}
Hypercall::Exit(sysexit) => {
return Ok(VcpuStopReason::Exit(sysexit.arg));
}
Expand Down
3 changes: 3 additions & 0 deletions src/macos/x86_64/vcpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,9 @@ impl VirtualCPU for XhyveCpu {
hypercall::unlink(&self.parent_vm.mem, sysunlink)
}
Hypercall::SerialWriteByte(buf) => hypercall::uart(&[buf]).unwrap(),
Hypercall::SerialWriteBuffer(sysserialwrite) => {
hypercall::uart_buffer(sysserialwrite, &self.parent_vm.mem)
}
_ => panic!("Got unknown hypercall {:?}", hypercall),
}
self.vcpu.write_register(&Register::RIP, rip + len)?;
Expand Down
10 changes: 10 additions & 0 deletions tests/serial.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
mod common;

use common::{build_hermit_bin, run_simple_vm};

#[test]
fn serial_buffer_test() {
// TODO: Check the output once https://github.com/hermit-os/uhyve/issues/528 is resolved
let bin_path = build_hermit_bin("serial");
run_simple_vm(bin_path);
}
121 changes: 121 additions & 0 deletions tests/test-kernels/Cargo.lock

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

8 changes: 8 additions & 0 deletions tests/test-kernels/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,11 @@ publish = false

[target.'cfg(target_os = "hermit")'.dependencies]
hermit = "0.9"

[target.'cfg(target_arch = "x86_64")'.dependencies]
x86_64 = { version = "0.15", default-features = false, features = [
"instructions",
] }

[dependencies]
uhyve-interface = { path = "../../uhyve-interface" }
52 changes: 52 additions & 0 deletions tests/test-kernels/src/bin/serial.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#[cfg(target_os = "hermit")]
use hermit as _;
use uhyve_interface::{parameters::SerialWriteBufferParams, GuestPhysAddr, HypercallAddress};
#[cfg(target_arch = "x86_64")]
use x86_64::{
instructions::port::Port,
structures::paging::{PageTable, RecursivePageTable},
VirtAddr,
};

unsafe fn get_page_table() -> RecursivePageTable<'static> {
let level_4_table_addr: u64 = 0xFFFF_FFFF_FFFF_F000;
unsafe {
let level_4_table = &mut *(level_4_table_addr as *mut PageTable);
RecursivePageTable::new(level_4_table).unwrap()
}
}

/// Translate a virtual memory address to a physical one.
pub fn virtual_to_physical(virtual_address: VirtAddr) -> Option<GuestPhysAddr> {
use x86_64::structures::paging::mapper::Translate;

let page_table = unsafe { get_page_table() };
page_table
.translate_addr(virtual_address)
.map(|addr| GuestPhysAddr::new(addr.as_u64()))
}

fn main() {
println!("Test");

let mut serial_byte_port = Port::new(HypercallAddress::Uart as u16);
for c in "ABCD\n".bytes() {
unsafe { serial_byte_port.write(c) };
}

let mut serial_buf_port = Port::new(HypercallAddress::SerialBufferWrite as u16);
let testtext = "1234ASDF!@#$\n";
let serial_write_params = SerialWriteBufferParams {
buf: virtual_to_physical(VirtAddr::new(
core::ptr::addr_of!(*testtext) as *const u8 as u64
))
.unwrap(),
len: testtext.bytes().len(),
};
let params_addr = virtual_to_physical(VirtAddr::new(
core::ptr::addr_of!(serial_write_params) as u64
))
.unwrap();

unsafe { serial_buf_port.write(params_addr.as_u64() as u32) };
}
5 changes: 5 additions & 0 deletions uhyve-interface/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ pub enum HypercallAddress {
Uart = 0x800,
/// Port address = `0x840`
FileUnlink = 0x840,
/// Port address = `0x880`
SerialBufferWrite = 0x880,
}
impl From<Hypercall<'_>> for HypercallAddress {
fn from(value: Hypercall) -> Self {
Expand All @@ -83,6 +85,7 @@ impl From<Hypercall<'_>> for HypercallAddress {
Hypercall::FileWrite(_) => Self::FileWrite,
Hypercall::FileUnlink(_) => Self::FileUnlink,
Hypercall::SerialWriteByte(_) => Self::Uart,
Hypercall::SerialWriteBuffer(_) => Self::SerialBufferWrite,
}
}
}
Expand All @@ -107,6 +110,8 @@ pub enum Hypercall<'a> {
FileUnlink(&'a mut UnlinkParams),
/// Write a char to the terminal.
SerialWriteByte(u8),
/// Write a buffer to the terminal.
SerialWriteBuffer(&'a SerialWriteBufferParams),
}
impl<'a> Hypercall<'a> {
/// Get a hypercall's port address.
Expand Down
8 changes: 8 additions & 0 deletions uhyve-interface/src/parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,11 @@ pub struct LseekParams {
/// `whence` value of the lseek call.
pub whence: i32,
}

/// Parameters for a [`SerialWriteBuffer`](crate::Hypercall::SerialWriteBuffer) hypercall.
#[repr(C, packed)]
#[derive(Debug, Copy, Clone)]
pub struct SerialWriteBufferParams {
pub buf: GuestPhysAddr,
pub len: usize,
}

0 comments on commit a2b664c

Please sign in to comment.