Skip to content
Draft
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
52 changes: 16 additions & 36 deletions Cargo.lock

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

67 changes: 61 additions & 6 deletions examples/launch-tee.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

#include <errno.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Expand All @@ -30,17 +31,34 @@ int main(int argc, char *const argv[])
"6=4096:8192",
0
};
static const struct option long_opts[] = {
{ "td-shim", required_argument, 0, 's' },
{ 0, 0, 0, 0 }
};
const char *td_shim_path = NULL;
char current_path[MAX_PATH];
char volume_tail[] = ":/work\0";
char *volume;
int volume_len;
int ctx_id;
int err;
int i;
int opt;

while ((opt = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
switch (opt) {
case 's':
td_shim_path = optarg;
break;
default:
printf("Usage: %s [--td-shim PATH] ROOT_DISK_IMAGE TEE_CONFIG_FILE DATA_DISK_IMAGE\n", argv[0]);
return -1;
}
}

if (argc != 4) {
if (argc - optind != 3) {
printf("Invalid arguments\n");
printf("Usage: %s ROOT_DISK_IMAGE TEE_CONFIG_FILE DATA_DISK_IMAGE\n", argv[0]);
printf("Usage: %s [--td-shim PATH] ROOT_DISK_IMAGE TEE_CONFIG_FILE DATA_DISK_IMAGE\n", argv[0]);
return -1;
}

Expand All @@ -67,8 +85,8 @@ int main(int argc, char *const argv[])
return -1;
}

// Use the first command line argument as the disk image containing the root fs.
if (err = krun_set_root_disk(ctx_id, argv[1])) {
// Use the first positional argument as the disk image containing the root fs.
if (err = krun_add_disk2(ctx_id, "root", argv[optind], KRUN_DISK_FORMAT_RAW, false)) {
errno = -err;
perror("Error configuring root disk image");
return -1;
Expand Down Expand Up @@ -108,18 +126,55 @@ int main(int argc, char *const argv[])
return -1;
}

if (err = krun_set_tee_config_file(ctx_id, argv[2])) {
if (err = krun_set_tee_config_file(ctx_id, argv[optind + 1])) {
errno = -err;
perror("Error setting the TEE config file");
return -1;
}

if (err = krun_set_data_disk(ctx_id, argv[3])) {
if (td_shim_path != NULL) {
if (err = krun_set_tee_firmware(ctx_id, td_shim_path)) {
errno = -err;
perror("Error setting TD-Shim firmware path");
return -1;
}
}

if (err = krun_add_disk2(ctx_id, "data", argv[optind + 2], KRUN_DISK_FORMAT_RAW, false)) {
errno = -err;
perror("Error configuring the TEE config data disk");
return -1;
}

// Serial console (ttyS0) for early boot messages (earlyprintk=ttyS0) and
// the main kernel console (console=ttyS0). Shell stdin/stdout inherit ttyS0.
if (err = krun_add_serial_console_default(ctx_id, STDIN_FILENO, STDOUT_FILENO)) {
errno = -err;
perror("Error adding serial console");
return -1;
}

// Disable the implicit virtio console: without explicit TTY fds, the implicit
// console creates krun-stdin/krun-stdout ports connected to /dev/null.
// setup_redirects() in init.krun finds those ports and silently redirects the
// shell's stdin/stdout to /dev/null, making all I/O disappear.
if (err = krun_disable_implicit_console(ctx_id)) {
errno = -err;
perror("Error disabling implicit console");
return -1;
}

// Add an explicit virtio console (hvc0) with real TTY fds. With TTY fds,
// libkrun creates only a single console port — no krun-stdin/krun-stdout
// ports — so setup_redirects() finds /sys/class/virtio-ports (satisfying
// the existence check), iterates it, finds nothing to redirect, and returns 0.
// The shell then runs with the inherited ttyS0 fds from the serial console.
if (err = krun_add_virtio_console_default(ctx_id, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO)) {
errno = -err;
perror("Error adding virtio console");
return -1;
}

if (err = krun_split_irqchip(ctx_id, true)) {
errno = -err;
perror("Error setting split IRQCHIP property");
Expand Down
13 changes: 13 additions & 0 deletions include/libkrun.h
Original file line number Diff line number Diff line change
Expand Up @@ -974,6 +974,19 @@ int32_t krun_set_env(uint32_t ctx_id, const char *const envp[]);
*/
int32_t krun_set_tee_config_file(uint32_t ctx_id, const char *filepath);

/**
* Sets the path to a TD-Shim binary for TDX guests. If not called, the TDX guest uses
* the bundled qboot firmware from libkrunfw-tdx. Only available in libkrun-tdx.
*
* Arguments:
* "ctx_id" - the configuration context ID.
* "fw_path" - a null-terminated string representing the path to the TD-Shim binary.
*
* Returns:
* Zero on success or a negative error number on failure.
*/
int32_t krun_set_tee_firmware(uint32_t ctx_id, const char *fw_path);

/**
* Adds a port-path pairing for guest IPC with a process in the host.
*
Expand Down
8 changes: 4 additions & 4 deletions src/arch/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,16 @@ tdx = [ "tee", "dep:tdx" ]
[dependencies]
libc = ">=0.2.39"
vm-memory = { version = "0.17", features = ["backend-mmap"] }
vmm-sys-util = "0.14"
vmm-sys-util = "0.15"

arch_gen = { package = "krun-arch-gen", version = "=0.1.0-1.18.0", path = "../arch_gen" }
smbios = { package = "krun-smbios", version = "=0.1.0-1.18.0", path = "../smbios" }
utils = { package = "krun-utils", version = "=0.1.0-1.18.0", path = "../utils" }

[target.'cfg(target_os = "linux")'.dependencies]
kvm-bindings = { version = "0.12", features = ["fam-wrappers"] }
kvm-ioctls = "0.22"
tdx = { version = "0.1.0", optional = true }
kvm-bindings = { version = "0.14", features = ["fam-wrappers"] }
kvm-ioctls = "0.24"
tdx = { version = "0.1.1", optional = true }

[dev-dependencies]
utils = { package = "krun-utils", version = "=0.1.0-1.18.0", path = "../utils" }
38 changes: 30 additions & 8 deletions src/arch/src/x86_64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ mod gdt;
pub mod interrupts;
/// Layout for the x86_64 system.
pub mod layout;
#[cfg(not(feature = "tee"))]
#[cfg(any(not(feature = "tee"), feature = "tdx"))]
mod mptable;
/// Logic for configuring x86_64 model specific registers (MSRs).
pub mod msr;
Expand Down Expand Up @@ -43,7 +43,7 @@ pub enum Error {
/// Invalid e820 setup params.
E820Configuration,
/// Error writing MP table to memory.
#[cfg(not(feature = "tee"))]
#[cfg(any(not(feature = "tee"), feature = "tdx"))]
MpTableSetup(mptable::Error),
/// Error writing the zero page of guest memory.
ZeroPageSetup,
Expand Down Expand Up @@ -177,7 +177,7 @@ pub fn arch_memory_regions(
kernel_load_addr: Option<u64>,
kernel_size: usize,
_initrd_size: u64,
_firmware_size: Option<usize>,
firmware_range: Option<(u64, usize)>,
) -> (ArchMemoryInfo, Vec<(GuestAddress, usize)>) {
let page_size: usize = unsafe { libc::sysconf(libc::_SC_PAGESIZE).try_into().unwrap() };

Expand All @@ -196,29 +196,30 @@ pub fn arch_memory_regions(
None | Some(0) => {
let ram_last_addr = size as u64;
let shm_start_addr = 0u64;
let (fw_addr, fw_sz) =
firmware_range.unwrap_or((FIRMWARE_START, FIRMWARE_SIZE as usize));
(
size as u64,
0,
ram_last_addr,
shm_start_addr,
vec![
(GuestAddress(0), size),
(GuestAddress(FIRMWARE_START), FIRMWARE_SIZE as usize),
],
vec![(GuestAddress(0), size), (GuestAddress(fw_addr), fw_sz)],
)
}
// case2: guest memory extends beyond the gap
Some(remaining) => {
let ram_last_addr = FIRST_ADDR_PAST_32BITS + remaining as u64;
let shm_start_addr = 0u64;
let (fw_addr, fw_sz) =
firmware_range.unwrap_or((FIRMWARE_START, FIRMWARE_SIZE as usize));
(
MMIO_MEM_START,
remaining as u64,
ram_last_addr,
shm_start_addr,
vec![
(GuestAddress(0), MMIO_MEM_START as usize),
(GuestAddress(FIRMWARE_START), FIRMWARE_SIZE as usize),
(GuestAddress(fw_addr), fw_sz),
(GuestAddress(FIRST_ADDR_PAST_32BITS), remaining),
],
)
Expand All @@ -241,6 +242,14 @@ pub fn arch_memory_regions(
/// # Arguments
///
/// * `guest_mem` - The memory to be used by the guest.
/// Writes an MP table to guest memory. Only needed for the TD-Shim path: TD-Shim's
/// ACPI MADT has no IOAPIC entry, so without an MP table the kernel never programs
/// the IOAPIC and virtio-mmio IRQs stop working after the PIC→APIC transition.
#[cfg(feature = "tdx")]
pub fn setup_mptable_for_tdshim(guest_mem: &GuestMemoryMmap, num_cpus: u8) -> super::Result<()> {
mptable::setup_mptable(guest_mem, num_cpus).map_err(Error::MpTableSetup)
}

/// * `cmdline_addr` - Address in `guest_mem` where the kernel command line was loaded.
/// * `cmdline_size` - Size of the kernel command line in bytes including the null terminator.
/// * `initrd` - Information about where the ramdisk image was loaded in the `guest_mem`.
Expand Down Expand Up @@ -431,6 +440,19 @@ mod tests {
configure_system(&gm, &arch_mem_info, GuestAddress(0), 0, &None, no_vcpus).unwrap();
}

#[cfg(feature = "tee")]
#[test]
fn test_arch_memory_regions_tee_dynamic_firmware_hole() {
let fw_start = 0xfffe_0000u64;
let fw_size = 0x2_0000usize;
let (_info, regions) =
arch_memory_regions(1usize << 29, None, 0, 0, Some((fw_start, fw_size)));
let has_fw_region = regions
.iter()
.any(|&(addr, size)| addr.0 == fw_start && size == fw_size);
assert!(has_fw_region, "firmware region not found in memory regions");
}

#[test]
fn test_add_e820_entry() {
let e820_map = [(e820entry {
Expand Down
Loading
Loading