-
Notifications
You must be signed in to change notification settings - Fork 123
feat(opentmk): opentmk framework with first testcase #1210
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
base: main
Are you sure you want to change the base?
Conversation
feat: opentmk init feat: opentmk init feat: opentmk init feat: opentmk init feat: opentmk init feat: opentmk init feat: init 1 feat: init 2 feat: init 1 feat: opentmk feat: opentmk init 3 feat: opentmk init 4 feat: opentmk init 4
c3f74c0
to
056bf7d
Compare
@@ -22,7 +22,7 @@ pub fn create_gpt_efi_disk(out_img: &Path, with_files: &[(&Path, &Path)]) -> Res | |||
)); | |||
} | |||
|
|||
let disk_size = 1024 * 1024 * 32; // 32MB disk should be enough for our tests | |||
let disk_size = 1024 * 1024 * 512; // 32MB disk should be enough for our tests |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why the increase?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the image size of the compiled application goes beyond 300MB, So we had to increase the disk size.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should probably make it a parameter then, so that guest-test-uefi doesn't also get bigger.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is still open.
opentmk/Cargo.toml
Outdated
edition.workspace = true | ||
rust-version.workspace = true | ||
|
||
[dependencies] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: sort and switch to dotted syntax for crates that don't need features. Also move all crates to be workspaced.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@smalis-msft There is one issue where I want to use the serde package with default features off as I want to use a no_std env. Should I disable the feature in workspace?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, you'll have to.
opentmk/src/uefi/alloc.rs
Outdated
pub unsafe fn init(&self, size: usize) -> bool { | ||
let pages = ((SIZE_1MB * size) / 4096) + 1; | ||
let size = pages * 4096; | ||
let mem: Result<core::ptr::NonNull<u8>, uefi::Error> = boot::allocate_pages(AllocateType::AnyPages, MemoryType::BOOT_SERVICES_DATA, pages); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why the two different allocators?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is there to handler cases where we need to do the allocation before we exit boot services. After exit boot services we cant depend on the uefi allocator and we need to switch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. Is there some way we can make this cleaner? Like funadamentally splitting up these two allocators and switching between them at a higher level?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are fundamentally 2 different allocators, but they switch based on a flag.
opentmk/src/uefi/tests/mod.rs
Outdated
pub mod hv_processor; | ||
pub mod hv_misc; | ||
|
||
pub fn run_test() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think what we'll want here is some sort of type definition for a Test that has a string name and other niceties. Then we can have an array of Tests and decide what tests to run and how at runtime.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right the v1 plan is to have a config file which we can read using uefi APIs. The config can define the test to run.
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the MIT License. | ||
|
||
/// Writes a synthehtic register to tell the hypervisor the OS ID for the boot shim. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// Writes a synthehtic register to tell the hypervisor the OS ID for the boot shim. | |
/// Writes a synthetic register to tell the hypervisor the OS ID for the boot shim. |
opentmk/src/slog.rs
Outdated
@@ -0,0 +1,242 @@ | |||
#![feature(panic_location)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does "slog" refer to serial log? It's sort of an unfortunate file name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah. I am working on it. Steven suggested to abstract the module into two layers on how we log and the structure of the log.
opentmk/src/uefi/hypvctx.rs
Outdated
|
||
const ALIGNMENT: usize = 4096; | ||
|
||
type ComandTable = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
type ComandTable = | |
type CommandTable = |
opentmk/src/uefi/context.rs
Outdated
pub trait TestCtxTrait { | ||
fn get_vp_count(&self) -> u32; | ||
fn get_current_vp(&self) -> u32; | ||
fn get_current_vtl(&self) -> Vtl; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this (and similar methods, like switching VTLs) for the current VP?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar questions for get_register, etc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes. these APIs are for current VP. (I'll add more documentation to explicitly call that out)
opentmk/src/uefi/context.rs
Outdated
|
||
fn setup_partition_vtl(&mut self, vtl: Vtl); | ||
fn setup_interrupt_handler(&mut self); | ||
fn set_interupt_idx(&mut self, interrupt_idx: u8, handler: fn()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fn set_interupt_idx(&mut self, interrupt_idx: u8, handler: fn()); | |
fn set_interrupt_idx(&mut self, interrupt_idx: u8, handler: fn()); |
opentmk/src/uefi/hypvctx.rs
Outdated
.get_mut(&vp_index) | ||
.unwrap() | ||
.push_back((cmd, vtl)); | ||
if vp_index == self.my_vp_idx && self.hvcall.vtl != vtl { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does vtl refer to the VTL you want the current VP to be on, or the VTL you want the target vp to run the command on?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This VTL switch is for a case where we schedule a cmd on the current VP. The current context will switch to the target VTL on current VP and execute the command. The command is expected to return to initial VTL by calling HvCall/HvReturn.
opentmk/src/uefi/hypercall.rs
Outdated
|
||
let header = hvdef::hypercall::ModifyVtlProtectionMask { | ||
partition_id: hvdef::HV_PARTITION_ID_SELF, | ||
map_flags: hvdef::HV_MAP_GPA_PERMISSIONS_NONE, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could make this an input parameter? And then other functions like apply_vtl2_protections could build on top of it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense, I'll work o abstracting this more.
extern "x86-interrupt" fn no_op(stack_frame: InterruptStackFrame) {} | ||
|
||
pub fn register_interrupt_handler(idt: &mut InterruptDescriptorTable) { | ||
register_interrupt_handler!(idt, 0, handler_0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some of these are architectural (and might also be in x86 defs), it might be nice to include the actual name for them.
let vtl = ctx.get_current_vtl(); | ||
infolog!("vtl: {:?}", vtl); | ||
tmk_assert!(vtl == Vtl::Vtl1, format!("vtl should be Vtl0 for VP {}", i)); | ||
tx.send(()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eventually would be nice to check that the register state is what we expect, but that might be difficult if execution keeps going.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which registers would we want to assert? We can probably think of how we can do it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A lot of them, eventually. We need to make sure that we correctly get this shared/private split correct, to the extent that we can:
opentmk/src/uefi/tests/hv_misc.rs
Outdated
val != 0xAA, | ||
"heap memory should not be accessible from vtl0" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like we could eventually use the interrupt handler that you set on 0x30 to check that we did get a memory intercept?
(Pretty cool to all this in action though :))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apologies if I'm repeating something I said in the previous review, there's a lot of code here and it's been a little while.
Also, you'll need to run cargo xtask fmt
and have it succeed on this code before it can be merged.
That all said, this is shaping up really really nicely. Please don't let the large number of comments discourage you, I'm really happy with how this is shaping up.
@@ -42,6 +42,9 @@ members = [ | |||
"vm/loader/igvmfilegen", | |||
"vm/vmgs/vmgs_lib", | |||
"vm/vmgs/vmgstool", | |||
# opentmk | |||
"opentmk/opentmk", | |||
"opentmk/sync" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If something is a dependency below it shouldn't be a member, members only needs to be top-level crates.
@@ -520,6 +529,7 @@ winapi = "0.3" | |||
windows = "0.59" | |||
windows-service = "0.7" | |||
windows-sys = "0.52" | |||
x86_64 = "0.15.2" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How much functionality from x86_64 are we using? How difficult of a lift would it be to fill in things like x86defs and safe_intrinsics, or just call intrinsics directly?
@@ -445,9 +451,11 @@ jiff = "0.1" | |||
kvm-bindings = "0.7" | |||
# Use of these specific REPO will go away when changes are taken upstream. | |||
landlock = "0.3.1" | |||
lazy_static = { version = "1.4.0", features = ["spin_no_std"] } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't specify features in the workspace-level Cargo.toml, since that applies them to every crate whether they want them or not. Move it into the specific crates' Cargo.tomls that need it.
@@ -22,7 +22,7 @@ pub fn create_gpt_efi_disk(out_img: &Path, with_files: &[(&Path, &Path)]) -> Res | |||
)); | |||
} | |||
|
|||
let disk_size = 1024 * 1024 * 32; // 32MB disk should be enough for our tests | |||
let disk_size = 1024 * 1024 * 512; // 32MB disk should be enough for our tests |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is still open.
|
||
[[package]] | ||
name = "spin" | ||
version = "0.10.0" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we unify on the same version of spin that lazy_static is pulling in, so we only have the one?
unsafe { | ||
self.locked_heap.lock().init(ptr, size); | ||
} | ||
*self.use_locked_heap.lock().borrow_mut() = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're always setting this to true do we still need the uefi allocator? Can we get away with just using the linked_list_allocator directly in all cases?
If so, is there some way we could make this type be an enum with a variant for each allocator instead of keeping both around forever?
@@ -0,0 +1,13 @@ | |||
#![allow(dead_code)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: get rid of all these allow(dead_code)s everywhere
|
||
//! Imports and re-exports architecture-specific implementations. | ||
|
||
mod x86_64; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this not building the arm code currently?
|
||
pub fn run_test() { | ||
let mut ctx = HvTestCtx::new(); | ||
hv_processor::exec(&mut ctx); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the difference between the tests in here and the tests in uefi/ ?
/// | ||
/// The caller must be sure that the given port is safe to write to, and that the | ||
/// given value is safe for it. | ||
unsafe fn outb(port: u16, data: u8) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this stuff all shared with the boot shim too? If so we should try to move it somewhere shared instead of duplicating.
No description provided.