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

Split tdx feature into tdcall and tdvmcall features as tdvmcall usage may be optional for some use cases #768

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
6d6116c
tdx-tdcall: Add a feature and separate tdvmcall to a dedicated file
sgrams Mar 3, 2025
c85adc3
tdx-tdcall: Split tdx.rs into tdcall.rs and tdvmcall.rs
sgrams Mar 3, 2025
3f7069d
tdx-tdcall: move remaining tdcall functions into tdcall.rs
sgrams Mar 3, 2025
614c4ad
tdx-tdcall: remove tdvmcall_ prefix
sgrams Mar 3, 2025
6cb7de4
tdx-tdcall: remove tdcall_ prefix
sgrams Mar 3, 2025
5bf8e83
Replace tdvmcall_ with tdvmcall::
sgrams Mar 3, 2025
ebc17ee
Replace tdcall_ with tdcall::
sgrams Mar 3, 2025
383f9fa
tdx-tdcall: Revert rename in CHANGELOG.md
sgrams Mar 5, 2025
4afbf1f
tdx-tdcall: add tdcall feature and add default features
sgrams Mar 3, 2025
1746f9b
td-payload: adapt to new tdx-tdcall layout
sgrams Mar 3, 2025
bc5bf16
td-logger: adapt to new tdx-tdcall layout
sgrams Mar 3, 2025
8485407
td-exception: adapt to new tdx-tdcall layout
sgrams Mar 3, 2025
93e3ca4
td-shim: adapt to new tdx-tdcall layout
sgrams Mar 3, 2025
fe36056
tests: adapt to new tdx-tdcall layout
sgrams Mar 3, 2025
6961b90
xtask: adapt to new tdx-tdcall layout
sgrams Mar 4, 2025
013c6c0
tdx-tdcall: move td-report under tdcall feature
sgrams Mar 4, 2025
eb829c5
td-payload: add non-tdvmcall version of enable_apic_interrupt
sgrams Mar 4, 2025
50056a3
td-payload: add non-tdvmcall versions of decrypt and encrypt
sgrams Mar 4, 2025
97db275
tdx-tdcall: Bump version after changing the API
sgrams Mar 3, 2025
0a39437
Cargo.lock: lock tdx-tdcall version after bump
sgrams Mar 4, 2025
e8faa4c
xtask: enable tdvmcall feature by default
sgrams Mar 5, 2025
9ccd236
tdx-tdcall: fix-up src/asm after tdcall rename
sgrams Mar 5, 2025
b4c44a3
.github: update CI to use tdcall and tdvmcall instead of tdx feature
sgrams Mar 5, 2025
5212396
tdx-tdcall: fix-up clippy errors
sgrams Mar 5, 2025
ddc36b7
tdx-tdcall,td-payload: fix-up cargo fmt errors
sgrams Mar 5, 2025
a7c03cb
sh_script: replace tdx feature with tdcall and tdvmcall
sgrams Mar 5, 2025
4b445f0
tdx-tdcall: Update CHANGELOG.md
sgrams Mar 5, 2025
e4d0c6f
xtask,td-shim,sh_script: tdx feature now consists of tdcall and tdvmcall
sgrams Mar 7, 2025
36fc18a
td-payload: add td-exception/tdvmcall dependency to tdvmcall feature
sgrams Mar 7, 2025
15c85e2
sh_script,td-payload,xtask: replace tdcall,tdvmcall with tdx for back…
sgrams Mar 7, 2025
8785968
td-shim,tdx-tdcall: gate asm_td_call and asm_td_vmcall
sgrams Mar 5, 2025
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
8 changes: 4 additions & 4 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,16 @@ jobs:

- name: Add `x86_64-unknown-none` target
run: rustup target add x86_64-unknown-none

- name: Preparation Work
run: bash sh_script/preparation.sh

- name: Test Shim Crates
run: make test
run: make test

- name: Build Release TdShim
run: cargo build -p td-shim --target x86_64-unknown-none --release --features=main,tdx

- name: Build Debug TdShim
run: cargo build -p td-shim --target x86_64-unknown-none --features=main,tdx --no-default-features

Expand All @@ -73,7 +73,7 @@ jobs:
- name: Build image without payload
run: |
cargo image --release

- name: Meta data check
run: |
cargo run -p td-shim-tools --bin td-shim-checker --no-default-features --features=loader -- target/release/final.bin
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

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

8 changes: 4 additions & 4 deletions sh_script/build_final.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ final_boot_kernel() {

final_elf() {
echo final-elf
cargo --example-payload -o target/release/final-elf.bin
cargo --example-payload -o target/release/final-elf.bin
}

final_elf_test() {
Expand All @@ -37,15 +37,15 @@ final_elf_test() {
-p target/x86_64-unknown-none/release/test-td-payload \
--enroll-file F10E684E-3ABD-20E4-5932-8F973C355E57,tests/test-td-payload/config/test_config_${i}.json \
-o target/release/final-elf-test${i}.bin
done
done
}

final_elf_sb_test() {
echo "Build final binaries with ELF format td payload for secure boot test"
cargo build -p td-payload --target x86_64-unknown-none --release --bin example --features=tdx,start,cet-shstk,stack-guard
cargo run -p td-shim-tools --bin td-shim-strip-info -- -n example --target x86_64-unknown-none

cargo run -p td-shim-tools --bin td-shim-sign-payload -- -A ECDSA_NIST_P384_SHA384 data/sample-keys/ecdsa-p384-private.pk8 target/x86_64-unknown-none/release/example 1 1
cargo run -p td-shim-tools --bin td-shim-sign-payload -- -A ECDSA_NIST_P384_SHA384 data/sample-keys/ecdsa-p384-private.pk8 target/x86_64-unknown-none/release/example 1 1

echo "Build final binary with unsigned td payload"
cargo image --release -t executable --features secure-boot \
Expand Down Expand Up @@ -77,5 +77,5 @@ case "${1:-}" in
elf) final_elf ;;
elf_test) final_elf_test ;;
elf_sb_test) final_elf_sb_test ;;
*) final_boot_kernel && final_elf && final_elf_test && final_elf_sb_test;;
*) final_boot_kernel && final_elf && final_elf_test && final_elf_sb_test;;
esac
3 changes: 2 additions & 1 deletion td-exception/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@ spin = "0.9.2"

[features]
cet-shstk = []
tdx = ["tdx-tdcall"]
tdcall = ["tdx-tdcall/tdcall"]
tdvmcall = ["tdx-tdcall/tdvmcall"]
integration-test = []
60 changes: 32 additions & 28 deletions td-exception/src/interrupt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@

use core::arch::asm;
use spin::Mutex;
#[cfg(feature = "tdx")]
use tdx_tdcall::tdx;

#[cfg(feature = "tdvmcall")]
use tdx_tdcall::tdcall;

#[cfg(feature = "tdvmcall")]
use tdx_tdcall::tdvmcall;

use crate::{idt::IDT_ENTRY_COUNT, ExceptionError};

Expand Down Expand Up @@ -141,7 +145,7 @@ pub(crate) fn init_interrupt_callbacks() {
callbacks.table[17].func = alignment_check;
callbacks.table[18].func = machine_check;
callbacks.table[19].func = simd;
#[cfg(feature = "tdx")]
#[cfg(all(feature = "tdcall", feature = "tdvmcall"))]
{
callbacks.table[20].func = virtualization;
}
Expand Down Expand Up @@ -323,54 +327,54 @@ fn control_flow(stack: &mut InterruptStack) {
deadloop();
}

#[cfg(feature = "tdx")]
#[cfg(all(feature = "tdcall", feature = "tdvmcall"))]
const EXIT_REASON_CPUID: u32 = 10;
#[cfg(feature = "tdx")]
#[cfg(all(feature = "tdcall", feature = "tdvmcall"))]
const EXIT_REASON_HLT: u32 = 12;
#[cfg(feature = "tdx")]
#[cfg(all(feature = "tdcall", feature = "tdvmcall"))]
const EXIT_REASON_RDPMC: u32 = 15;
#[cfg(feature = "tdx")]
#[cfg(all(feature = "tdcall", feature = "tdvmcall"))]
const EXIT_REASON_VMCALL: u32 = 18;
#[cfg(feature = "tdx")]
#[cfg(all(feature = "tdcall", feature = "tdvmcall"))]
const EXIT_REASON_IO_INSTRUCTION: u32 = 30;
#[cfg(feature = "tdx")]
#[cfg(all(feature = "tdcall", feature = "tdvmcall"))]
const EXIT_REASON_MSR_READ: u32 = 31;
#[cfg(feature = "tdx")]
#[cfg(all(feature = "tdcall", feature = "tdvmcall"))]
const EXIT_REASON_MSR_WRITE: u32 = 32;
#[cfg(feature = "tdx")]
#[cfg(all(feature = "tdcall", feature = "tdvmcall"))]
const EXIT_REASON_MWAIT_INSTRUCTION: u32 = 36;
#[cfg(feature = "tdx")]
#[cfg(all(feature = "tdcall", feature = "tdvmcall"))]
const EXIT_REASON_MONITOR_INSTRUCTION: u32 = 39;
#[cfg(feature = "tdx")]
#[cfg(all(feature = "tdcall", feature = "tdvmcall"))]
const EXIT_REASON_WBINVD: u32 = 54;

#[cfg(feature = "tdx")]
#[cfg(all(feature = "tdcall", feature = "tdvmcall"))]
fn virtualization(stack: &mut InterruptStack) {
// Firstly get VE information from TDX module, halt it error occurs
let ve_info = tdx::tdcall_get_ve_info().expect("#VE handler: fail to get VE info\n");
let ve_info = tdcall::get_ve_info().expect("#VE handler: fail to get VE info\n");

match ve_info.exit_reason {
EXIT_REASON_HLT => {
tdx::tdvmcall_halt();
tdvmcall::halt();
}
EXIT_REASON_IO_INSTRUCTION => {
if !handle_tdx_ioexit(&ve_info, stack) {
tdx::tdvmcall_halt();
tdvmcall::halt();
}
}
EXIT_REASON_MSR_READ => {
let msr = tdx::tdvmcall_rdmsr(stack.scratch.rcx as u32)
let msr = tdvmcall::rdmsr(stack.scratch.rcx as u32)
.expect("fail to perform RDMSR operation\n");
stack.scratch.rax = (msr as u32 & u32::MAX) as usize; // EAX
stack.scratch.rdx = ((msr >> 32) as u32 & u32::MAX) as usize; // EDX
}
EXIT_REASON_MSR_WRITE => {
let data = stack.scratch.rax as u64 | ((stack.scratch.rdx as u64) << 32); // EDX:EAX
tdx::tdvmcall_wrmsr(stack.scratch.rcx as u32, data)
tdvmcall::wrmsr(stack.scratch.rcx as u32, data)
.expect("fail to perform WRMSR operation\n");
}
EXIT_REASON_CPUID => {
let cpuid = tdx::tdvmcall_cpuid(stack.scratch.rax as u32, stack.scratch.rcx as u32);
let cpuid = tdvmcall::cpuid(stack.scratch.rax as u32, stack.scratch.rcx as u32);
let mask = 0xFFFF_FFFF_0000_0000_usize;
stack.scratch.rax = (stack.scratch.rax & mask) | cpuid.eax as usize;
stack.preserved.rbx = (stack.preserved.rbx & mask) | cpuid.ebx as usize;
Expand Down Expand Up @@ -451,8 +455,8 @@ fn virtualization(stack: &mut InterruptStack) {
//
// Use TDVMCALL to realize IO read/write operation
// Return false if VE info is invalid
#[cfg(feature = "tdx")]
fn handle_tdx_ioexit(ve_info: &tdx::TdVeInfo, stack: &mut InterruptStack) -> bool {
#[cfg(all(feature = "tdcall", feature = "tdvmcall"))]
fn handle_tdx_ioexit(ve_info: &tdcall::TdVeInfo, stack: &mut InterruptStack) -> bool {
let size = ((ve_info.exit_qualification & 0x7) + 1) as usize; // 0 - 1bytes, 1 - 2bytes, 3 - 4bytes
let read = (ve_info.exit_qualification >> 3) & 0x1 == 1;
let string = (ve_info.exit_qualification >> 4) & 0x1 == 1;
Expand All @@ -471,17 +475,17 @@ fn handle_tdx_ioexit(ve_info: &tdx::TdVeInfo, stack: &mut InterruptStack) -> boo

// Define closure to perform IO port read with different size operands
let io_read = |size, port| match size {
1 => tdx::tdvmcall_io_read_8(port) as u32,
2 => tdx::tdvmcall_io_read_16(port) as u32,
4 => tdx::tdvmcall_io_read_32(port),
1 => tdvmcall::io_read_8(port) as u32,
2 => tdvmcall::io_read_16(port) as u32,
4 => tdvmcall::io_read_32(port),
_ => 0,
};

// Define closure to perform IO port write with different size operands
let io_write = |size, port, data| match size {
1 => tdx::tdvmcall_io_write_8(port, data as u8),
2 => tdx::tdvmcall_io_write_16(port, data as u16),
4 => tdx::tdvmcall_io_write_32(port, data),
1 => tdvmcall::io_write_8(port, data as u8),
2 => tdvmcall::io_write_16(port, data as u16),
4 => tdvmcall::io_write_32(port, data),
_ => {}
};

Expand Down
2 changes: 1 addition & 1 deletion td-logger/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ tdx-tdcall = { path = "../tdx-tdcall", optional = true }
x86 = { version = "0.47.0", optional = true }

[features]
tdx = ["tdx-tdcall"]
tdvmcall = ["tdx-tdcall/tdvmcall"]
serial-port = ["x86"]
10 changes: 5 additions & 5 deletions td-logger/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,20 +53,20 @@ pub fn dbg_write_string(s: &str) {
}
}

#[cfg(any(feature = "tdx", feature = "serial-port"))]
#[cfg(any(feature = "tdvmcall", feature = "serial-port"))]
const SERIAL_IO_PORT: u16 = 0x3F8;

#[cfg(feature = "tdx")]
#[cfg(feature = "tdvmcall")]
fn dbg_port_write(byte: u8) {
tdx_tdcall::tdx::tdvmcall_io_write_8(SERIAL_IO_PORT, byte);
tdx_tdcall::tdvmcall::io_write_8(SERIAL_IO_PORT, byte);
}

#[cfg(all(not(feature = "tdx"), feature = "serial-port"))]
#[cfg(all(not(feature = "tdvmcall"), feature = "serial-port"))]
fn dbg_port_write(byte: u8) {
unsafe { x86::io::outb(SERIAL_IO_PORT, byte) };
}

#[cfg(all(not(feature = "tdx"), not(feature = "serial-port")))]
#[cfg(all(not(feature = "tdvmcall"), not(feature = "serial-port")))]
fn dbg_port_write(_byte: u8) {}

#[cfg(test)]
Expand Down
4 changes: 3 additions & 1 deletion td-payload/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ minicov = { version = "0.2", default-features = false, optional = true }

[features]
default = ["tdx"]
tdx = ["tdx-tdcall", "td-logger/tdx", "td-exception/tdx"]
tdcall = ["tdx-tdcall/tdcall", "td-exception/tdcall"]
tdvmcall = ["tdx-tdcall/tdvmcall", "td-exception/tdvmcall", "td-logger/tdvmcall"]
tdx = ["tdcall", "tdvmcall"]
stack-guard = []
cet-shstk = ["td-exception/cet-shstk"]
cet-ibt = []
Expand Down
24 changes: 18 additions & 6 deletions td-payload/src/arch/x86_64/apic.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2022 Intel Corporation
// Copyright (c) 2022, 2025 Intel Corporation
//
// SPDX-License-Identifier: BSD-2-Clause-Patent

Expand All @@ -13,21 +13,33 @@ pub const LOCAL_APIC_LVTT: u32 = 0xfee0_0320;
pub const INITIAL_COUNT: u32 = 0xfee0_0380;
pub const DIVIDE_CONFIGURATION_REGISTER: u32 = 0xfee0_03e0;

#[cfg(feature = "tdvmcall")]
pub fn enable_apic_interrupt() {
// Enable the local APIC by setting bit 8 of the APIC spurious vector region (SVR)
// Ref: Intel SDM Vol3. 8.4.4.1
// In x2APIC mode, SVR is mapped to MSR address 0x80f.
// Since SVR(SIVR) is not virtualized, before we implement the handling in #VE of MSRRD/WR,
// use tdvmcall instead direct read/write operation.
let svr = tdx_tdcall::tdx::tdvmcall_rdmsr(0x80f).expect("fail to perform RDMSR operation\n");
tdx_tdcall::tdx::tdvmcall_wrmsr(0x80f, svr | (0x1 << 8))
let svr = tdx_tdcall::tdvmcall::rdmsr(0x80f).expect("fail to perform RDMSR operation\n");
tdx_tdcall::tdvmcall::wrmsr(0x80f, svr | (0x1 << 8))
.expect("fail to perform WRMSR operation\n");
}

#[cfg(not(feature = "tdvmcall"))]
pub fn enable_apic_interrupt() {
// Enable the local APIC by setting bit 8 of the APIC spurious vector region (SVR)
// Ref: Intel SDM Vol3. 8.4.4.1
// In x2APIC mode, SVR is mapped to MSR address 0x80f.
let svr = unsafe { x86::msr::rdmsr(0x80f) };
unsafe {
x86::msr::wrmsr(0x80f, svr | (0x1 << 8));
}
}

pub fn enable_and_hlt() {
#[cfg(feature = "tdx")]
tdx_tdcall::tdx::tdvmcall_sti_halt();
#[cfg(not(feature = "tdx"))]
#[cfg(feature = "tdvmcall")]
tdx_tdcall::tdvmcall::sti_halt();
#[cfg(not(feature = "tdvmcall"))]
x86_64::instructions::interrupts::enable_and_hlt()
}

Expand Down
1 change: 0 additions & 1 deletion td-payload/src/arch/x86_64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,4 @@ pub mod idt;
pub mod init;
pub mod paging;
pub mod serial;
#[cfg(feature = "tdx")]
pub mod shared;
14 changes: 7 additions & 7 deletions td-payload/src/arch/x86_64/paging.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2022 Intel Corporation
// Copyright (c) 2022, 2025 Intel Corporation
//
// SPDX-License-Identifier: BSD-2-Clause-Patent

Expand Down Expand Up @@ -129,13 +129,13 @@ pub fn set_not_present(address: u64, size: usize) {
set_page_flags(&mut pt, address, size, flags);
}

#[cfg(feature = "tdx")]
#[cfg(feature = "tdcall")]
pub fn set_shared_bit(address: u64, size: usize) {
let mut pt = offset_pt();
map_shared(&mut pt, address, size, true);
}

#[cfg(feature = "tdx")]
#[cfg(feature = "tdcall")]
pub fn clear_shared_bit(address: u64, size: usize) {
let mut pt = offset_pt();
map_shared(&mut pt, address, size, false);
Expand Down Expand Up @@ -202,7 +202,7 @@ pub(crate) fn set_page_flags(pt: &mut OffsetPageTable, va: u64, size: usize, fla
}
}

#[cfg(feature = "tdx")]
#[cfg(feature = "tdcall")]
fn map_shared(pt: &mut OffsetPageTable, va: u64, size: usize, shared: bool) {
let end = va + size as u64;
let mut va = VirtAddr::new(va);
Expand All @@ -217,7 +217,7 @@ fn map_shared(pt: &mut OffsetPageTable, va: u64, size: usize, shared: bool) {
}
}

#[cfg(feature = "tdx")]
#[cfg(feature = "tdcall")]
fn pt_set_shared_bit(pt: &mut OffsetPageTable, page: &Page, shared: bool) {
let p4 = pt.level_4_table();
let p3 = unsafe { &mut *(p4.index(page.p4_index()).addr().as_u64() as *mut PageTable) };
Expand All @@ -237,10 +237,10 @@ fn pt_set_shared_bit(pt: &mut OffsetPageTable, page: &Page, shared: bool) {
}
}

#[cfg(feature = "tdx")]
#[cfg(feature = "tdcall")]
fn pt_entry_set_shared_bit(page_table: &mut PageTable, index: PageTableIndex, shared: bool) {
let entry = page_table.index(index);
let shared_bit = tdx_tdcall::tdx::td_shared_mask().expect("Failed to get shared bit of GPA");
let shared_bit = tdx_tdcall::tdcall::td_shared_mask().expect("Failed to get shared bit of GPA");

let addr = if shared {
entry.addr().as_u64() | shared_bit
Expand Down
8 changes: 4 additions & 4 deletions td-payload/src/arch/x86_64/serial.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2022 Intel Corporation
// Copyright (c) 2022, 2025 Intel Corporation
//
// SPDX-License-Identifier: BSD-2-Clause-Patent

Expand All @@ -19,12 +19,12 @@ pub fn serial_write_string(s: &str) {

const SERIAL_IO_PORT: u16 = 0x3F8;

#[cfg(feature = "tdx")]
#[cfg(feature = "tdvmcall")]
fn io_write(byte: u8) {
tdx_tdcall::tdx::tdvmcall_io_write_8(SERIAL_IO_PORT, byte);
tdx_tdcall::tdvmcall::io_write_8(SERIAL_IO_PORT, byte);
}

#[cfg(not(feature = "tdx"))]
#[cfg(not(feature = "tdvmcall"))]
fn io_write(byte: u8) {
unsafe { x86::io::outb(SERIAL_IO_PORT, byte) };
}
Loading
Loading