diff --git a/.devcontainer.json b/.devcontainer.json index 1b5ffda7653..f913a6f635f 100644 --- a/.devcontainer.json +++ b/.devcontainer.json @@ -4,7 +4,7 @@ // - https://code.visualstudio.com/docs/remote/devcontainerjson-reference { // Do not modify manually. This value is automatically updated by ./scripts/docker_build . - "image": "sha256:ae9a0f15ff37574d5584cebaaa563393369dac4ae35b1c5c9e7e991750021301", + "image": "sha256:d2ac0f6ad41502fdfe336b8074fbf1e4eff462fdb39b164f1cfba419f5eb3a60", "extensions": [ "bazelbuild.vscode-bazel", "bodil.prettier-toml", diff --git a/Cargo.toml b/Cargo.toml index 3516c05f012..e4493af3034 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,4 +40,4 @@ members = [ "remote_attestation/rust", "xtask", ] -exclude = ["oak_functions/loader/fuzz"] +exclude = ["experimental/uefi", "oak_functions/loader/fuzz"] diff --git a/Dockerfile b/Dockerfile index 2a08629aab7..d96c95170f5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -37,6 +37,7 @@ RUN apt-get --yes update \ python3 \ python3-six \ python3-distutils \ + qemu-system-x86 \ shellcheck \ software-properties-common \ vim \ @@ -59,10 +60,11 @@ RUN echo "deb [arch=amd64] https://download.docker.com/linux/debian buster stabl && apt-get clean \ && rm --recursive --force /var/lib/apt/lists/* -# Use a later version of clang-format from buster-backports. +# Use a later version of clang-format and OVMF (UEFI firmware) from buster-backports. RUN echo 'deb http://deb.debian.org/debian buster-backports main' > /etc/apt/sources.list.d/backports.list \ && apt-get --yes update \ && apt-get install --no-install-recommends --yes clang-format-8 \ + && apt-get install --no-install-recommends --yes --target-release buster-backports ovmf \ && apt-get clean \ && rm --recursive --force /var/lib/apt/lists/* \ && ln --symbolic --force clang-format-8 /usr/bin/clang-format diff --git a/experimental/uefi/.cargo/config.toml b/experimental/uefi/.cargo/config.toml new file mode 100644 index 00000000000..6de0441b091 --- /dev/null +++ b/experimental/uefi/.cargo/config.toml @@ -0,0 +1,9 @@ +[build] +target = "x86_64-unknown-uefi" + +[target.x86_64-unknown-uefi] +runner = "qemu-system-x86_64 -nodefaults -nographic -bios /usr/share/OVMF/OVMF_CODE.fd -serial stdio -machine q35 -device isa-debug-exit,iobase=0xf4,iosize=0x04 -kernel" + +[unstable] +build-std = ["core"] +build-std-features = ["compiler-builtins-mem"] diff --git a/experimental/uefi/Cargo.lock b/experimental/uefi/Cargo.lock new file mode 100644 index 00000000000..230b1dc3808 --- /dev/null +++ b/experimental/uefi/Cargo.lock @@ -0,0 +1,123 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "bit_field" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb6dd1c2376d2e096796e234a70e17e94cc2d5d54ff8ce42b28cef1d0d359a4" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "proc-macro2" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "qemu-exit" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ff023245bfcc73fb890e1f8d5383825b3131cc920020a5c487d6f113dfc428a" + +[[package]] +name = "quote" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "1.0.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e59d925cf59d8151f25a3bedf97c9c157597c9df7324d32d68991cc399ed08b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "ucs2" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad643914094137d475641b6bab89462505316ec2ce70907ad20102d28a79ab8" +dependencies = [ + "bit_field", +] + +[[package]] +name = "uefi" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21398a404f6fa14f6df34756714874eccdf73587eba863cb5bd55d8bada7496" +dependencies = [ + "bitflags", + "log", + "ucs2", + "uefi-macros", +] + +[[package]] +name = "uefi-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7006b85ae8acaf2b448c5f1630a434caaacaedcc0907f12404e4e31c9dafcdb3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "uefi-services" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7840bddc6477dc443cc5652ca9683de9f10bd173691151c3160d734521bef3bd" +dependencies = [ + "cfg-if", + "log", + "qemu-exit", + "uefi", +] + +[[package]] +name = "uefi-simple" +version = "0.1.0" +dependencies = [ + "uefi", + "uefi-services", +] + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" diff --git a/experimental/uefi/Cargo.toml b/experimental/uefi/Cargo.toml new file mode 100644 index 00000000000..a864dc3c014 --- /dev/null +++ b/experimental/uefi/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "uefi-simple" +version = "0.1.0" +authors = ["Andri Saar "] +edition = "2021" +license = "Apache-2.0" + +[dependencies] +uefi = "*" +uefi-services = "*" + +[dev-dependencies] +uefi-services = { version = "*", features = ["qemu"] } diff --git a/experimental/uefi/src/main.rs b/experimental/uefi/src/main.rs new file mode 100644 index 00000000000..f162537db4f --- /dev/null +++ b/experimental/uefi/src/main.rs @@ -0,0 +1,76 @@ +// +// Copyright 2022 The Project Oak Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#![no_main] +#![no_std] +#![feature(abi_efiapi)] +#![feature(custom_test_frameworks)] +// As we're in a `no_std` environment, testing requires special handling. This +// approach was inspired by https://os.phil-opp.com/testing/. +#![test_runner(crate::test_runner)] +#![reexport_test_harness_main = "test_main"] + +use uefi::{prelude::*, table::runtime::ResetType, ResultExt}; + +// The main entry point of the UEFI application. +// +// The choice of name (`_start`) is entirely arbitrary; what matters is that +// there's exactly one function with the `#[entry]` attribute in the +// dependency graph. +#[entry] +fn _start(_handle: Handle, mut system_table: SystemTable) -> Status { + uefi_services::init(&mut system_table).unwrap_success(); + + // As we're not relying on the normal Rust test harness, we need to call + // the tests ourselves if necessary. + let status = if cfg!(test) { + #[cfg(test)] + test_main(); + Status::SUCCESS + } else { + main(_handle, &mut system_table) + }; + + // After we're done running our code, we also tell the UEFI runtime to shut + // down the machine, otherwise we'd go back to the UEFI shell. + system_table + .runtime_services() + .reset(ResetType::Shutdown, status, None); +} + +fn main(_handle: Handle, system_table: &mut SystemTable) -> Status { + use core::fmt::Write; + + let status = writeln!(system_table.stdout(), "Hello World!"); + + status + .map(|_| Status::SUCCESS) + .unwrap_or(Status::DEVICE_ERROR) +} + +#[cfg(test)] +fn test_runner(tests: &[&dyn Fn()]) { + for test in tests { + test(); + } +} + +// Simple silly test just to prove that the test infrastructure works. +#[test_case] +fn test_simple() { + let x = 1; + assert_eq!(x, 1); +} diff --git a/scripts/common b/scripts/common index 51a7a93a99d..b54d4ff5390 100644 --- a/scripts/common +++ b/scripts/common @@ -20,10 +20,10 @@ readonly DOCKER_IMAGE_NAME='gcr.io/oak-ci/oak:latest' # from a registry first. # Do not modify manually. This value is automatically updated by ./scripts/docker_build . -readonly DOCKER_IMAGE_ID='sha256:ae9a0f15ff37574d5584cebaaa563393369dac4ae35b1c5c9e7e991750021301' +readonly DOCKER_IMAGE_ID='sha256:d2ac0f6ad41502fdfe336b8074fbf1e4eff462fdb39b164f1cfba419f5eb3a60' # Do not modify manually. This value is automatically updated by ./scripts/docker_push . -readonly DOCKER_IMAGE_REPO_DIGEST='gcr.io/oak-ci/oak@sha256:aafe171f215dda322b45fc93a1b96ae0a270624a9402769bf17f11da12dd7aba' +readonly DOCKER_IMAGE_REPO_DIGEST='gcr.io/oak-ci/oak@sha256:4572fcc1f3f738f7db9faff26909a51afa4781bc5397356b3e8aaa8efb847f68' readonly SERVER_DOCKER_IMAGE_NAME='gcr.io/oak-ci/oak-server' diff --git a/xtask/src/diffs.rs b/xtask/src/diffs.rs index 63eb7f2b062..eb59721168a 100644 --- a/xtask/src/diffs.rs +++ b/xtask/src/diffs.rs @@ -42,6 +42,10 @@ impl ModifiedContent { .unwrap() .contains(&file_name.to_string()) } + + pub fn contains_path(&self, file_name: &Path) -> bool { + self.contains(file_name.to_str().unwrap()) + } } /// Get all the files that have been modified in the given `scope`. If the scope is `Scope::All` diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 5ad296fa8a3..44c350cfecd 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -681,37 +681,45 @@ fn run_cargo_test(opt: &RunTestsOpt, all_affected_crates: &ModifiedContent) -> S steps: crate_manifest_files() // Exclude `fuzz` crates, as there are no tests and binaries should not be executed. .filter(|path| !is_fuzzing_toml_file(path)) - .map(to_string) - .filter(|path| all_affected_crates.contains(path)) + .filter(|path| all_affected_crates.contains_path(path)) .map(|entry| { + // Run `cargo test` in the directory of the crate, not the top-level directory. + // This is needed as otherwise any crate-specific `.cargo/config.toml` files would + // be ignored. If a crate does not have a config file, Cargo will just backtrack + // up the tree and pick up the `.cargo/config.toml` file from the root directory. let test_run_step = |name| Step::Single { name, - command: Cmd::new( + command: Cmd::new_in_dir( "cargo", &[ "test", "--all-features", - &format!("--manifest-path={}", &entry), + &format!( + "--manifest-path={}", + entry.file_name().unwrap().to_str().unwrap() + ), ], + entry.parent().unwrap(), ), }; - let target_path = &entry.replace("Cargo.toml", "target"); - // If `cleanup` is enabled, add a cleanup step to remove the generated files. Do - // this only if `target_path` is a non-empty, valid target path. - if opt.cleanup && target_path.ends_with("/target") { + // If `cleanup` is enabled, add a cleanup step to remove the generated files. + if opt.cleanup { Step::Multiple { - name: entry.clone(), + name: entry.to_str().unwrap().to_string(), steps: vec![ test_run_step("run".to_string()), Step::Single { name: "cleanup".to_string(), - command: Cmd::new("rm", &["-rf", target_path]), + command: Cmd::new( + "rm", + &["-rf", entry.with_file_name("target").to_str().unwrap()], + ), }, ], } } else { - test_run_step(entry.clone()) + test_run_step(entry.to_str().unwrap().to_string()) } }) .collect(),