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

Getting Zig example fully working #18

Merged
merged 18 commits into from
Nov 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
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
12 changes: 6 additions & 6 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ jobs:
run: sudo apt update && sudo apt install -y make clang lld llvm qemu-system-arm device-tree-compiler expect
- name: Install Zig
run: |
wget https://ziglang.org/download/0.11.0/zig-linux-x86_64-0.11.0.tar.xz
tar xf zig-linux-x86_64-0.11.0.tar.xz
echo "${PWD}/zig-linux-x86_64-0.11.0/:$PATH" >> $GITHUB_PATH
wget https://ziglang.org/builds/zig-linux-x86_64-0.12.0-dev.1594+7048e9366.tar.xz
tar xf zig-linux-x86_64-0.12.0-dev.1594+7048e9366.tar.xz
echo "${PWD}/zig-linux-x86_64-0.12.0-dev.1594+7048e9366/:$PATH" >> $GITHUB_PATH
- name: Install Rust
run: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
- name: Build and run examples
Expand Down Expand Up @@ -74,9 +74,9 @@ jobs:
echo "/usr/local/opt/llvm/bin:$PATH" >> $GITHUB_PATH
- name: Install Zig
run: |
wget https://ziglang.org/download/0.11.0/zig-macos-x86_64-0.11.0.tar.xz
tar xf zig-macos-x86_64-0.11.0.tar.xz
echo "${PWD}/zig-macos-x86_64-0.11.0/:$PATH" >> $GITHUB_PATH
wget https://ziglang.org/builds/zig-macos-x86_64-0.12.0-dev.1594+7048e9366.tar.xz
tar xf zig-macos-x86_64-0.12.0-dev.1594+7048e9366.tar.xz
echo "${PWD}/zig-macos-x86_64-0.12.0-dev.1594+7048e9366/:$PATH" >> $GITHUB_PATH
- name: Install Rust
run: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
- name: Build and run examples
Expand Down
39 changes: 39 additions & 0 deletions ci/examples.sh
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,22 @@ build_rust() {
MICROKIT_SDK=${SDK_PATH}
}

build_zig() {
echo "CI|INFO: building Zig example with config: $1, Zig optimize is: $2"
CONFIG=$1
ZIG_OPTIMIZE=$2
BUILD_DIR="${PWD}/build/examples/zig/qemu_arm_virt/${CONFIG}/${ZIG_OPTIMIZE}"
EXAMPLE_DIR="${PWD}/examples/zig"
mkdir -p ${BUILD_DIR}
pushd ${EXAMPLE_DIR}
zig build \
-Dsdk=${SDK_PATH} \
-Dconfig=${CONFIG} \
-Doptimize=${ZIG_OPTIMIZE} \
-p ${BUILD_DIR}
popd
}

simulate_rust() {
echo "CI|INFO: simulating Rust example with config: $1"
BUILD_DIR="${PWD}/build/examples/rust/qemu_arm_virt/${CONFIG}"
Expand Down Expand Up @@ -81,11 +97,18 @@ build_virtio() {
MICROKIT_SDK=${SDK_PATH}
}

simulate_zig() {
echo "CI|INFO: simulating Zig example with config: $1"
BUILD_DIR="${PWD}/build/examples/zig/qemu_arm_virt/${CONFIG}/${ZIG_OPTIMIZE}"
./ci/buildroot_login.exp ${BUILD_DIR}/bin/loader.img
}

build_simple_make "qemu_arm_virt" "debug"
simulate_simple_make "qemu_arm_virt" "debug"
build_simple_make "qemu_arm_virt" "release"
simulate_simple_make "qemu_arm_virt" "release"

# @ivanv: we should incorporate the zig optimisation levels as well
build_simple_zig "qemu_arm_virt" "debug"
simulate_simple_zig "qemu_arm_virt" "debug"
build_simple_zig "qemu_arm_virt" "release"
Expand All @@ -102,6 +125,22 @@ simulate_rust "debug"
build_rust "release"
simulate_rust "release"

# Here there are two kinds of configuration that we need to test. There is the
# configuration of Microkit itself for which we test debug and release. This
# also dictates the configuration of seL4 that is used.
# There is also the optimisations that Zig applies to the VMM code, Zig has
# three optimisation levels (other than debug), that realistically would be
# used with the "release" configuration of Microkit. For details on each
# optimisation level, see the Zig documentation.
build_zig "debug" "Debug"
simulate_zig "debug" "Debug"
build_zig "release" "ReleaseFast"
simulate_zig "release" "ReleaseFast"
build_zig "release" "ReleaseSafe"
simulate_zig "release" "ReleaseSafe"
build_zig "release" "ReleaseSmall"
simulate_zig "release" "ReleaseSmall"

build_virtio "qemu_arm_virt" "debug"
build_virtio "qemu_arm_virt" "release"

Expand Down
7 changes: 5 additions & 2 deletions examples/simple/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,11 @@ system running the whole system.
For educational purposes, you can also build and run this example using the
[Zig](https://ziglang.org/) build system.

You will first need Zig version 0.11.x (e.g 0.11.0 or 0.11.1) which can be
downloaded from [here](https://ziglang.org/download/).
At the moment, Zig still under heavy development and hence this example depends
on the 'master' version of Zig for now. This example has been built using
`0.12.0-dev.1533+b2ed2c4d4`, so anything equal to or above that version should work.

You can download Zig [here](https://ziglang.org/download/).

```sh
zig build -Dsdk=/path/to/sdk -Dboard=<BOARD>
Expand Down
97 changes: 52 additions & 45 deletions examples/simple/build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,7 @@ pub fn build(b: *std.Build) void {
}
const microkit_sdk = microkit_sdk_arg.?;

const microkit_config_option = b.option(ConfigOptions, "config", "Microkit config to build for")
orelse ConfigOptions.debug;
const microkit_config_option = b.option(ConfigOptions, "config", "Microkit config to build for") orelse ConfigOptions.debug;
const microkit_config = @tagName(microkit_config_option);

// Get the Microkit SDK board we want to target
Expand All @@ -83,11 +82,11 @@ pub fn build(b: *std.Build) void {

// Since we are relying on Zig to produce the final ELF, it needs to do the
// linking step as well.
const sdk_board_dir = fmtPrint("{s}/board/{s}/{s}", .{ microkit_sdk, microkit_board, microkit_config });
const sdk_tool = fmtPrint("{s}/bin/microkit", .{ microkit_sdk });
const libmicrokit = fmtPrint("{s}/lib/libmicrokit.a", .{ sdk_board_dir });
const libmicrokit_linker_script = fmtPrint("{s}/lib/microkit.ld", .{ sdk_board_dir });
const sdk_board_include_dir = fmtPrint("{s}/include", .{ sdk_board_dir });
const microkit_board_dir = fmtPrint("{s}/board/{s}/{s}", .{ microkit_sdk, microkit_board, microkit_config });
const microkit_tool = fmtPrint("{s}/bin/microkit", .{ microkit_sdk });
const libmicrokit = fmtPrint("{s}/lib/libmicrokit.a", .{ microkit_board_dir });
const libmicrokit_linker_script = fmtPrint("{s}/lib/microkit.ld", .{ microkit_board_dir });
const sdk_board_include_dir = fmtPrint("{s}/include", .{ microkit_board_dir });

const libvmm = b.addStaticLibrary(.{
.name = "vmm",
Expand All @@ -100,25 +99,28 @@ pub fn build(b: *std.Build) void {
const libvmm_src = libvmm_path ++ "/src/";
// Right now we only support AArch64 so this is a safe assumption.
const libvmm_src_arch = libvmm_src ++ "arch/aarch64/";
libvmm.addCSourceFiles(&.{
libvmm_src ++ "guest.c",
libvmm_src ++ "util/util.c",
libvmm_src ++ "util/printf.c",
libvmm_src_arch ++ "vgic/vgic.c",
libvmm_src_arch ++ "vgic/vgic_v2.c",
libvmm_src_arch ++ "fault.c",
libvmm_src_arch ++ "psci.c",
libvmm_src_arch ++ "smc.c",
libvmm_src_arch ++ "virq.c",
libvmm_src_arch ++ "linux.c",
libvmm_src_arch ++ "tcb.c",
libvmm_src_arch ++ "vcpu.c",
}, &.{
"-Wall",
"-Werror",
"-Wno-unused-function",
"-mstrict-align",
"-DBOARD_qemu_arm_virt",
libvmm.addCSourceFiles(.{
.files = &.{
libvmm_src ++ "guest.c",
libvmm_src ++ "util/util.c",
libvmm_src ++ "util/printf.c",
libvmm_src_arch ++ "vgic/vgic.c",
libvmm_src_arch ++ "vgic/vgic_v2.c",
libvmm_src_arch ++ "fault.c",
libvmm_src_arch ++ "psci.c",
libvmm_src_arch ++ "smc.c",
libvmm_src_arch ++ "virq.c",
libvmm_src_arch ++ "linux.c",
libvmm_src_arch ++ "tcb.c",
libvmm_src_arch ++ "vcpu.c",
},
.flags = &.{
"-Wall",
"-Werror",
"-Wno-unused-function",
"-mstrict-align",
"-DBOARD_qemu_arm_virt", // @ivanv: should not be necessary
}
});

libvmm.addIncludePath(.{ .path = libvmm_src });
Expand All @@ -137,14 +139,13 @@ pub fn build(b: *std.Build) void {

// For actually compiling the DTS into a DTB
const dts_path = fmtPrint("board/{s}/linux.dts", .{ microkit_board });
const dtb_image_path = "linux.dtb";
const dtc_command = b.addSystemCommand(&[_][]const u8{
"dtc", "-I", "dts", "-O", "dtb", dts_path, "-o", dtb_image_path
const dtc_cmd = b.addSystemCommand(&[_][]const u8{
"dtc", "-q", "-I", "dts", "-O", "dtb", dts_path
});
const dtb = dtc_cmd.captureStdOut();

// Add microkit.h to be used by the API wrapper.
exe.addIncludePath(.{ .path = sdk_board_include_dir });
// The VMM code will include
exe.addIncludePath(.{ .path = libvmm_src });
exe.addIncludePath(.{ .path = libvmm_src_arch });
// Add the static library that provides each protection domain's entry
Expand All @@ -154,12 +155,15 @@ pub fn build(b: *std.Build) void {
// Specify the linker script, this is necessary to set the ELF entry point address.
exe.setLinkerScriptPath(.{ .path = libmicrokit_linker_script });

exe.addCSourceFiles(&.{"vmm.c"}, &.{
"-Wall",
"-Werror",
"-Wno-unused-function",
"-mstrict-align",
"-DBOARD_qemu_arm_virt", // @ivanv: shouldn't be needed as the library should not depend on the board
exe.addCSourceFiles(.{
.files = &.{"vmm.c"},
.flags = &.{
"-Wall",
"-Werror",
"-Wno-unused-function",
"-mstrict-align",
"-DBOARD_qemu_arm_virt", // @ivanv: shouldn't be needed as the library should not depend on the board
}
});

const guest_images = b.addObject(.{
Expand All @@ -168,20 +172,23 @@ pub fn build(b: *std.Build) void {
.optimize = optimize,
});
// We need to produce the DTB from the DTS before doing anything to produce guest_images
guest_images.step.dependOn(&dtc_command.step);
guest_images.step.dependOn(&b.addInstallFileWithDir(dtb, .prefix, "linux.dtb").step);

const linux_image_path = fmtPrint("board/{s}/linux", .{ microkit_board });
const kernel_image_arg = fmtPrint("-DGUEST_KERNEL_IMAGE_PATH=\"{s}\"", .{ linux_image_path });

const initrd_image_path = fmtPrint("board/{s}/rootfs.cpio.gz", .{ microkit_board });
const initrd_image_arg = fmtPrint("-DGUEST_INITRD_IMAGE_PATH=\"{s}\"", .{ initrd_image_path });
const dtb_image_arg = fmtPrint("-DGUEST_DTB_IMAGE_PATH=\"{s}\"", .{ dtb_image_path });
guest_images.addCSourceFiles(&.{ libvmm_tools ++ "package_guest_images.S" }, &.{
kernel_image_arg,
dtb_image_arg,
initrd_image_arg,
"-x",
"assembler-with-cpp",
const dtb_image_arg = fmtPrint("-DGUEST_DTB_IMAGE_PATH=\"{s}\"", .{ b.getInstallPath(.prefix, "linux.dtb") });
guest_images.addCSourceFiles(.{
.files = &.{ libvmm_tools ++ "package_guest_images.S" },
.flags = &.{
kernel_image_arg,
dtb_image_arg,
initrd_image_arg,
"-x",
"assembler-with-cpp",
}
});

exe.addObject(guest_images);
Expand All @@ -190,7 +197,7 @@ pub fn build(b: *std.Build) void {
const system_description_path = fmtPrint("board/{s}/simple.system", .{ microkit_board });
const final_image_dest = b.getInstallPath(.bin, "./loader.img");
const microkit_tool_cmd = b.addSystemCommand(&[_][]const u8{
sdk_tool,
microkit_tool,
system_description_path,
"--search-path",
b.getInstallPath(.bin, ""),
Expand Down
51 changes: 45 additions & 6 deletions examples/zig/README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,51 @@
# Zig VMM example

This example aims to show using [Zig]() to interact with the VMM library. While
Zig is most-often thought of as a programming language, the project actually
provides three-things:
This example aims to show using [Zig](https://ziglang.org/) to interact with
the VMM library. Although Zig is most-often thought of as a programming
language, the project actually provides three things:
1. The Zig programming language
2. The Zig build system
3. A portable C/C++ cross-compiler
3. A portable drop-in C/C++ cross-compiler

In this example we make use of all three of these to have a VMM example where the
VMM is written in Zig, interacting with the VMM library, written in C,
This example makes use of all three. The VMM code itself is written in the
Zig programming langauge, it calls into `libvmm` which has been compiled using
the Zig C compiler. Building the example is done via the Zig build system.

## Building the example

At the moment, Zig still under heavy development and hence this example depends
on the 'master' version of Zig for now. This example has been built using
`0.12.0-dev.1533+b2ed2c4d4`, so anything equal to or above that version should work.

You can download Zig [here](https://ziglang.org/download/).

```sh
zig build -Dsdk=/path/to/sdk
```

To view other options available when building the example (such as optimisation
level or the target Microkit configuration), run the following command:
```sh
zig build -Dsdk=/path/to/sdk -h
```

## Running the example

To also run the example via QEMU, run the following command:
```sh
zig build -Dsdk=/path/to/sdk qemu
```

You should see the following output after a couple of seconds:
```
Welcome to Buildroot
buildroot login:
```

The login is `root`. There is no password necessary. After logging in, you will
see the console prompt where you can input commands:
```
Welcome to Buildroot
buildroot login: root
#
```
Loading
Loading