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

Implement an EFI flavor #161

Merged
merged 24 commits into from
Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
4049d24
devices/block: use our wrapper for EFD_NONBLOCK
slp Feb 6, 2024
6a54675
device/block: import the MetdataExt of each OS
slp Feb 6, 2024
250226c
Move virtio-blk from the tee to the blk feature
slp Feb 6, 2024
72ee881
arch/fdt: fix memory size calculation
slp Feb 6, 2024
a8d3eb2
arch/gicv2: use a more compatible model definition
slp Feb 6, 2024
794b6a0
edk2: add a prebuilt EDK2 binary
slp Feb 7, 2024
10db347
Introduce the "efi" feature
slp Feb 6, 2024
095940c
builder: enable a legacy serial port for EFI
slp Feb 6, 2024
ad45580
aarch64/efi: return the right fdt address for efi
slp Feb 6, 2024
119fe73
virtio/queue: relax queue restrictions
slp Feb 6, 2024
3d20353
virtio/console: open console on PORT_READY
slp Feb 6, 2024
300aff6
devices/virtio: simplify reset method
slp Feb 6, 2024
80892ac
devices/block: implement reset method
slp Feb 6, 2024
56ee37b
devices/rng: implement reset method
slp Feb 6, 2024
91460ef
devices/console: implement reset method
slp Feb 6, 2024
dbff6f8
Allow the efi flavor to not link against libkrunfw
slp Feb 7, 2024
071f6df
devices/fs/macos: don't bundle init in efi flavor
slp Feb 7, 2024
6417072
Makefile: introduce EFI vars to build efi flavor
slp Feb 7, 2024
4b5e9e6
examples: add an example for booting from EFI
slp Feb 7, 2024
e87edfd
macos/epoll: use EV_CLEAR instead of EV_ONESHOT
slp Feb 7, 2024
41bd095
virtio/net: propagate interrupt controller
slp Feb 7, 2024
2cd5b6e
ci/darwin: run clippy checks on EFI feature
slp Feb 7, 2024
faa90e9
epoll/macos: avoid unnecessary cast
slp Feb 7, 2024
0f7e979
builder: gate AsRawFd behind linux conditional
slp Feb 7, 2024
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
7 changes: 5 additions & 2 deletions .github/workflows/code_quality-aarch64-darwin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ jobs:
run: cargo fmt -- --check

- name: Clippy (default features)
run: cargo clippy -- -D warnings
run: cargo clippy --target aarch64-apple-darwin -- -D warnings

- name: Clippy (net feature)
run: cargo clippy --features net -- -D warnings
run: cargo clippy --target aarch64-apple-darwin --features net -- -D warnings

- name: Clippy (efi feature)
run: cargo clippy --target aarch64-apple-darwin --features efi -- -D warnings
15 changes: 11 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,24 @@ SNP_INIT_SRC = init/tee/snp_attest.c \
KBS_LD_FLAGS = -lcurl -lidn2 -lssl -lcrypto -lzstd -lz -lbrotlidec-static \
-lbrotlicommon-static

BUILD_INIT = 1
INIT_DEFS =
ifeq ($(SEV),1)
VARIANT = -sev
FEATURE_FLAGS := --features amd-sev
INIT_DEFS += -DSEV=1
INIT_DEFS += $(KBS_LD_FLAGS)
INIT_SRC += $(SNP_INIT_SRC)
BUILD_INIT = 0
endif
ifeq ($(NET),1)
FEATURE_FLAGS += --features net
endif
ifeq ($(EFI),1)
VARIANT = -efi
FEATURE_FLAGS := --features efi
BUILD_INIT = 0
endif

ifeq ($(ROSETTA),1)
INIT_DEFS += -D__ROSETTA__
Expand All @@ -42,9 +49,9 @@ KRUN_BINARY_Linux = libkrun$(VARIANT).so.$(FULL_VERSION)
KRUN_SONAME_Linux = libkrun$(VARIANT).so.$(ABI_VERSION)
KRUN_BASE_Linux = libkrun$(VARIANT).so

KRUN_BINARY_Darwin = libkrun.$(FULL_VERSION).dylib
KRUN_SONAME_Darwin = libkrun.$(ABI_VERSION).dylib
KRUN_BASE_Darwin = libkrun.dylib
KRUN_BINARY_Darwin = libkrun$(VARIANT).$(FULL_VERSION).dylib
KRUN_SONAME_Darwin = libkrun$(VARIANT).$(ABI_VERSION).dylib
KRUN_BASE_Darwin = libkrun$(VARIANT).dylib

LIBRARY_RELEASE_Linux = target/release/$(KRUN_BINARY_Linux)
LIBRARY_DEBUG_Linux = target/debug/$(KRUN_BINARY_Linux)
Expand All @@ -64,7 +71,7 @@ all: $(LIBRARY_RELEASE_$(OS)) libkrun.pc

debug: $(LIBRARY_DEBUG_$(OS)) libkrun.pc

ifneq ($(SEV),1)
ifeq ($(BUILD_INIT),1)
INIT_BINARY = init/init
$(INIT_BINARY): $(INIT_SRC)
gcc -O2 -static -Wall $(INIT_DEFS) -o $@ $(INIT_SRC) $(INIT_DEFS)
Expand Down
Binary file added edk2/KRUN_EFI.silent.fd
Binary file not shown.
51 changes: 51 additions & 0 deletions edk2/License.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
Copyright (c) 2019, TianoCore and contributors. All rights reserved.

SPDX-License-Identifier: BSD-2-Clause-Patent

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

Subject to the terms and conditions of this license, each copyright holder
and contributor hereby grants to those receiving rights under this license
a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except for failure to satisfy the conditions of this license) patent
license to make, have made, use, offer to sell, sell, import, and otherwise
transfer this software, where such license applies only to those patent
claims, already acquired or hereafter acquired, licensable by such copyright
holder or contributor that are necessarily infringed by:

(a) their Contribution(s) (the licensed copyrights of copyright holders and
non-copyrightable additions of contributors, in source or binary form)
alone; or

(b) combination of their Contribution(s) with the work of authorship to
which such Contribution(s) was added by such copyright holder or
contributor, if, at the time the Contribution is added, such addition
causes such combination to be necessarily infringed. The patent license
shall not apply to any other combinations which include the
Contribution.

Except as expressly stated above, no rights or licenses from any copyright
holder or contributor is granted under this license, whether expressly, by
implication, estoppel or otherwise.

DISCLAIMER

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
1 change: 1 addition & 0 deletions edk2/Sources.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
KRUN_EFI.silent.fd was built from commit 82563b1d62ba029bd7bbfff73d49cce21af302c0 of the https://github.com/slp/edk2 repository.
22 changes: 15 additions & 7 deletions examples/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,37 @@ LDFLAGS_x86_64_Linux = -lkrun
LDFLAGS_aarch64_Linux = -lkrun
LDFLAGS_arm64_Darwin = -L/opt/homebrew/lib -lkrun
LDFLAGS_sev = -lkrun-sev
CFLAGS_Linux = -O2 -g
CFLAGS_Darwin = -O2 -g -I/opt/homebrew/include
LDFLAGS_efi = -L/opt/homebrew/lib -lkrun-efi
CFLAGS = -O2 -g -I../include
ROOTFS_DISTRO := fedora
ROOTFS_DIR = rootfs_$(ROOTFS_DISTRO)

.PHONY: clean rootfs

EXAMPLES := chroot_vm
ifeq ($(SEV),1)
EXAMPLES := launch-tee
else
EXAMPLES := chroot_vm
endif
ifeq ($(EFI),1)
EXAMPLES := boot_efi
endif

all: $(EXAMPLES)

chroot_vm: chroot_vm.c
gcc -o $@ $< $(CFLAGS_$(OS)) $(LDFLAGS_$(ARCH)_$(OS))
gcc -o $@ $< $(CFLAGS) $(LDFLAGS_$(ARCH)_$(OS))
ifeq ($(OS),Darwin)
codesign --entitlements chroot_vm.entitlements --force -s - $@
endif

launch-tee: launch-tee.c
gcc -o $@ $< $(CFLAGS_$(OS)) $(LDFLAGS_sev)
gcc -o $@ $< $(CFLAGS) $(LDFLAGS_sev)

boot_efi: boot_efi.c
gcc -o $@ $< $(CFLAGS) $(LDFLAGS_efi)
ifeq ($(OS),Darwin)
codesign --entitlements chroot_vm.entitlements --force -s - $@
endif

# Build the rootfs to be used with chroot_vm.
rootfs:
Expand All @@ -36,4 +44,4 @@ rootfs:
podman rm libkrun_chroot_vm

clean:
rm -rf chroot_vm $(ROOTFS_DIR) launch-tee
rm -rf chroot_vm $(ROOTFS_DIR) launch-tee boot_efi
181 changes: 181 additions & 0 deletions examples/boot_efi.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/*
* This is an example implementing chroot-like functionality with libkrun.
*
* It executes the requested command (relative to NEWROOT) inside a fresh
* Virtual Machine created and managed by libkrun.
*/

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <libkrun.h>
#include <getopt.h>
#include <stdbool.h>
#include <assert.h>

#define MAX_ARGS_LEN 4096
#ifndef MAX_PATH
#define MAX_PATH 4096
#endif

static void print_help(char *const name)
{
fprintf(stderr,
"Usage: %s [OPTIONS] DISK\n"
"OPTIONS: \n"
" -h --help Show help\n"
" --passt-socket=PATH Connect to passt socket at PATH"
"\n"
"DISK: path to the vm's disk image in raw format\n",
name
);
}

static const struct option long_options[] = {
{ "help", no_argument, NULL, 'h' },
{ "passt-socket", required_argument, NULL, 'P' },
{ NULL, 0, NULL, 0 }
};

struct cmdline {
bool show_help;
char const *passt_socket_path;
char const *disk_image;
};

bool parse_cmdline(int argc, char *const argv[], struct cmdline *cmdline)
{
assert(cmdline != NULL);

// set the defaults
*cmdline = (struct cmdline){
.show_help = false,
.passt_socket_path = "/tmp/network.sock",
.disk_image = NULL,
};

int option_index = 0;
int c;
// the '+' in optstring is a GNU extension that disables permutating argv
while ((c = getopt_long(argc, argv, "+h", long_options, &option_index)) != -1) {
switch (c) {
case 'h':
cmdline->show_help = true;
return true;
case 'P':
cmdline->passt_socket_path = optarg;
break;
case '?':
return false;
default:
fprintf(stderr, "internal argument parsing error (returned character code 0x%x)\n", c);
return false;
}
}

if (optind <= argc - 1) {
cmdline->disk_image = argv[optind];
return true;
}

if (optind == argc) {
fprintf(stderr, "Missing DISK argument\n");
}

return false;
}

int connect_to_passt(char *socket_path)
{
struct sockaddr_un addr;
int socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (socket_fd < 0) {
perror("Failed to create passt socket fd");
return -1;
}

memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1);

if (connect(socket_fd, (const struct sockaddr *) &addr, sizeof(addr)) < 0) {
perror("Failed to bind passt socket");
return -1;
}

return socket_fd;
}

int main(int argc, char *const argv[])
{
int ctx_id;
int err;
struct cmdline cmdline;

if (!parse_cmdline(argc, argv, &cmdline)) {
putchar('\n');
print_help(argv[0]);
return -1;
}

if (cmdline.show_help){
print_help(argv[0]);
return 0;
}

// Set the log level to "off".
err = krun_set_log_level(0);
if (err) {
errno = -err;
perror("Error configuring log level");
return -1;
}

// Create the configuration context.
ctx_id = krun_create_ctx();
if (ctx_id < 0) {
errno = -ctx_id;
perror("Error creating configuration context");
return -1;
}

// Configure the number of vCPUs (2) and the amount of RAM (1024 MiB).
if (err = krun_set_vm_config(ctx_id, 2, 1024)) {
errno = -err;
perror("Error configuring the number of vCPUs and/or the amount of RAM");
return -1;
}

if (err = krun_set_root_disk(ctx_id, cmdline.disk_image)) {
errno = -err;
perror("Error configuring disk image");
return -1;
}

int passt_fd = connect_to_passt(cmdline.passt_socket_path);

if (passt_fd < 0) {
return -1;
}

if (err = krun_set_passt_fd(ctx_id, passt_fd)) {
errno = -err;
perror("Error configuring net mode");
return -1;
}

// Start and enter the microVM. Unless there is some error while creating the microVM
// this function never returns.
if (err = krun_start_enter(ctx_id)) {
errno = -err;
perror("Error creating the microVM");
return -1;
}

// Not reached.
return 0;
}
1 change: 1 addition & 0 deletions src/arch/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ edition = "2021"
[features]
tee = []
amd-sev = [ "tee" ]
efi = []

[dependencies]
libc = ">=0.2.39"
Expand Down
2 changes: 1 addition & 1 deletion src/arch/src/aarch64/fdt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ fn create_memory_node(
_guest_mem: &GuestMemoryMmap,
arch_memory_info: &ArchMemoryInfo,
) -> Result<()> {
let mem_size = arch_memory_info.ram_last_addr - super::layout::DRAM_MEM_START + 1;
let mem_size = arch_memory_info.ram_last_addr - super::layout::DRAM_MEM_START;
// See https://github.com/torvalds/linux/blob/master/Documentation/devicetree/booting-without-of.txt#L960
// for an explanation of this.
let mem_reg_prop = generate_prop64(&[super::layout::DRAM_MEM_START, mem_size]);
Expand Down
6 changes: 6 additions & 0 deletions src/arch/src/aarch64/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@
// Taken from (http://infocenter.arm.com/help/topic/com.arm.doc.den0001c/DEN0001C_principles_of_arm_memory_maps.pdf).

/// Start of RAM on 64 bit ARM.
#[cfg(not(feature = "efi"))]
pub const DRAM_MEM_START: u64 = 0x8000_0000; // 2 GB.
#[cfg(feature = "efi")]
pub const DRAM_MEM_START: u64 = 0x4000_0000; // 1 GB.
/// The maximum addressable RAM address.
pub const DRAM_MEM_END: u64 = 0x00FF_8000_0000; // 1024 - 2 = 1022 GB.
/// The maximum RAM size.
Expand Down Expand Up @@ -82,4 +85,7 @@ pub const GTIMER_VIRT: u32 = 11;
pub const GTIMER_PHYS: u32 = 12;

/// Below this address will reside the GIC, above this address will reside the MMIO devices.
#[cfg(not(feature = "efi"))]
pub const MAPPED_IO_START: u64 = 1 << 30; // 1 GB
#[cfg(feature = "efi")]
pub const MAPPED_IO_START: u64 = 0x0a00_0000;
2 changes: 1 addition & 1 deletion src/arch/src/aarch64/macos/gicv2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ impl GICDevice for GICv2 {
}

fn fdt_compatibility(&self) -> &str {
"arm,gic-400"
"arm,cortex-a15-gic"
}

fn fdt_maint_irq(&self) -> u32 {
Expand Down
Loading
Loading