├── rust-toolchain ├── devtools ├── test-runner-client │ ├── README.md │ ├── Cargo.toml │ └── src │ │ ├── serial.rs │ │ └── lib.rs ├── dev_container │ ├── cargo_config │ └── Dockerfile ├── td-layout-config │ ├── src │ │ ├── lib.rs │ │ ├── memory.rs │ │ ├── template │ │ │ ├── memory.jinja │ │ │ └── image.jinja │ │ └── main.rs │ ├── config_image.json │ ├── Cargo.toml │ ├── config_memory_exec.json │ ├── README.md │ ├── config_memory_linux.json │ └── config_memory.json ├── rustc-targets │ ├── x86_64-custom.json │ └── x86_64-unknown-none.json ├── test-runner-server │ ├── Cargo.toml │ └── README.md ├── td-benchmark │ ├── Cargo.toml │ └── src │ │ └── lib.rs └── Makefile ├── tests ├── test-td-paging │ ├── x86_64-custom.json │ └── Cargo.toml ├── test-td-exception │ ├── x86_64-custom.json │ ├── Cargo.toml │ └── src │ │ └── lib.rs └── test-td-payload │ ├── config │ └── README.md │ ├── src │ ├── testtdve.rs │ ├── testcetibt.rs │ ├── lib.rs │ ├── teststackguard.rs │ ├── testcetshstk.rs │ ├── testiorw8.rs │ └── testiorw32.rs │ └── Cargo.toml ├── doc ├── fuzz.png ├── td-shim-diagram.png ├── td-shim-introduction.pdf ├── igvm_image.md ├── test_heap_stack_usage.md ├── cargo-deny.md └── design-for-payload.md ├── .github ├── CODEOWNERS ├── dependabot.yml └── workflows │ ├── deny.yml │ ├── oss-fuzz.yml │ ├── weekly-cargo-update.yml │ ├── devtools.yml │ ├── fuzz.yml │ ├── trivy.yml │ ├── integration.yml │ ├── library.yml │ ├── format.yml │ └── main.yml ├── data ├── blobs │ ├── td-payload.efi │ └── td-payload.elf └── sample-keys │ ├── ecdsa-p384-public.der │ ├── rsa-3072-private.pk8 │ ├── rsa-3072-public.der │ └── ecdsa-p384-private.pk8 ├── td-payload ├── src │ ├── event.rs │ ├── arch │ │ ├── mod.rs │ │ └── x86_64 │ │ │ ├── mod.rs │ │ │ ├── guard_page.rs │ │ │ ├── idt.rs │ │ │ ├── serial.rs │ │ │ ├── shared.rs │ │ │ ├── apic.rs │ │ │ └── gdt.rs │ ├── console.rs │ ├── mm │ │ ├── heap.rs │ │ ├── layout.rs │ │ └── page_table.rs │ ├── hob.rs │ ├── bin │ │ └── example │ │ │ ├── stack.rs │ │ │ └── mp.rs │ ├── lib.rs │ └── acpi.rs └── Cargo.toml ├── .gitmodules ├── td-loader ├── fuzz │ ├── seeds │ │ ├── pe │ │ │ └── td-shim.efi │ │ └── elf │ │ │ └── rust-td-payload │ ├── fuzz_targets │ │ ├── elf.rs │ │ ├── pe.rs │ │ ├── afl_pe.rs │ │ └── afl_elf.rs │ └── Cargo.toml ├── src │ └── lib.rs └── Cargo.toml ├── td-shim ├── fuzz │ ├── seeds │ │ ├── secure_boot_cfv │ │ │ └── cfv │ │ └── secure_boot_payload │ │ │ └── td-payload-signed │ ├── fuzz_targets │ │ ├── secure_boot_cfv.rs │ │ ├── secure_boot_payload.rs │ │ ├── fuzzlib.rs │ │ ├── afl_secure_boot_cfv.rs │ │ └── afl_secure_boot_payload.rs │ └── Cargo.toml ├── src │ └── bin │ │ └── td-shim │ │ ├── linux │ │ └── mod.rs │ │ ├── td │ │ ├── dummy.rs │ │ ├── mod.rs │ │ └── tdx.rs │ │ ├── asm │ │ ├── msr64.asm │ │ ├── exception_notdvmcall.asm │ │ ├── exception.asm │ │ ├── mod.rs │ │ ├── ap_loop_notdvmcall.asm │ │ └── ap_loop.asm │ │ └── heap.rs ├── ResetVector │ ├── DebugDisabled.asm │ ├── Port80Debug.asm │ ├── PostCodes.inc │ ├── ResetVector.nasm │ ├── Ia32 │ │ ├── Flat32ToFlat64.asm │ │ ├── ResetVectorVtf0.asm │ │ └── ValidateBfvBase.asm │ └── X64 │ │ ├── PageTables.asm │ │ └── TestHob.asm └── Cargo.toml ├── td-shim-interface ├── fuzz │ ├── seeds │ │ ├── cfv_parser │ │ │ └── cfv │ │ ├── hob_parser │ │ │ └── hob_buffer │ │ └── payload_parser │ │ │ └── fv_buffer │ ├── fuzz_targets │ │ ├── cfv_parser.rs │ │ ├── payload_parser.rs │ │ ├── hob_parser.rs │ │ ├── afl_cfv_parser.rs │ │ ├── afl_hob_parser.rs │ │ ├── afl_payload_parser.rs │ │ └── fuzzlib.rs │ └── Cargo.toml ├── Cargo.toml ├── src │ └── td_uefi_pi │ │ ├── pi │ │ ├── mod.rs │ │ └── boot_mode.rs │ │ └── mod.rs └── README.md ├── td-layout ├── src │ ├── runtime │ │ ├── mod.rs │ │ └── exec.rs │ └── mailbox.rs └── Cargo.toml ├── td-exception ├── src │ ├── asm │ │ ├── mod.rs │ │ └── handler.asm │ └── lib.rs └── Cargo.toml ├── .gitignore ├── sh_script ├── switch_root_run_cmd.sh ├── preparation.sh ├── unit_test_coverage.sh ├── update_toolchain.sh ├── rudra.sh ├── docker.sh └── launch-rust-td.sh ├── xtask ├── Cargo.toml └── src │ └── main.rs ├── td-paging ├── src │ ├── consts.rs │ └── lib.rs └── Cargo.toml ├── td-shim-tools ├── src │ ├── bin │ │ ├── td-shim-tee-info-hash │ │ │ ├── sample_manifest.json │ │ │ └── readme.md │ │ ├── td-shim-checker │ │ │ └── README.md │ │ ├── td-shim-sign-payload │ │ │ └── README.md │ │ ├── td-payload-reference-calculator │ │ │ └── README.md │ │ ├── td-shim-enroll │ │ │ └── README.md │ │ └── td-shim-strip-info │ │ │ └── readme.md │ └── read_file.rs ├── etc │ └── sample_metadata.json └── Cargo.toml ├── .cargo └── config.toml ├── cc-measurement └── Cargo.toml ├── .pre-commit-config.yaml ├── td-logger ├── Cargo.toml └── src │ └── logger.rs ├── tdx-tdcall ├── Cargo.toml ├── CHANGELOG.md ├── README.md └── src │ └── asm │ ├── mod.rs │ ├── tdcall_emu.asm │ └── tdcall.asm ├── LICENSE ├── Cargo.toml └── library └── patches └── 0002-Disable-checks-for-SSE-and-SSE2.patch /rust-toolchain: -------------------------------------------------------------------------------- 1 | 1.88.0 2 | -------------------------------------------------------------------------------- /devtools/test-runner-client/README.md: -------------------------------------------------------------------------------- 1 | ../test-runner-server/README.md -------------------------------------------------------------------------------- /devtools/dev_container/cargo_config: -------------------------------------------------------------------------------- 1 | [net] 2 | git-fetch-with-cli = true 3 | -------------------------------------------------------------------------------- /tests/test-td-paging/x86_64-custom.json: -------------------------------------------------------------------------------- 1 | ../../devtools/rustc-targets/x86_64-custom.json -------------------------------------------------------------------------------- /doc/fuzz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/confidential-containers/td-shim/HEAD/doc/fuzz.png -------------------------------------------------------------------------------- /tests/test-td-exception/x86_64-custom.json: -------------------------------------------------------------------------------- 1 | ../../devtools/rustc-targets/x86_64-custom.json -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Repository maintainers are added to every pull request. 2 | * @jyao1 3 | -------------------------------------------------------------------------------- /doc/td-shim-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/confidential-containers/td-shim/HEAD/doc/td-shim-diagram.png -------------------------------------------------------------------------------- /data/blobs/td-payload.efi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/confidential-containers/td-shim/HEAD/data/blobs/td-payload.efi -------------------------------------------------------------------------------- /data/blobs/td-payload.elf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/confidential-containers/td-shim/HEAD/data/blobs/td-payload.elf -------------------------------------------------------------------------------- /doc/td-shim-introduction.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/confidential-containers/td-shim/HEAD/doc/td-shim-introduction.pdf -------------------------------------------------------------------------------- /td-payload/src/event.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "library/ring"] 2 | path = library/ring 3 | url = https://github.com/briansmith/ring.git 4 | ignore = dirty 5 | -------------------------------------------------------------------------------- /td-loader/fuzz/seeds/pe/td-shim.efi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/confidential-containers/td-shim/HEAD/td-loader/fuzz/seeds/pe/td-shim.efi -------------------------------------------------------------------------------- /data/sample-keys/ecdsa-p384-public.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/confidential-containers/td-shim/HEAD/data/sample-keys/ecdsa-p384-public.der -------------------------------------------------------------------------------- /data/sample-keys/rsa-3072-private.pk8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/confidential-containers/td-shim/HEAD/data/sample-keys/rsa-3072-private.pk8 -------------------------------------------------------------------------------- /data/sample-keys/rsa-3072-public.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/confidential-containers/td-shim/HEAD/data/sample-keys/rsa-3072-public.der -------------------------------------------------------------------------------- /td-shim/fuzz/seeds/secure_boot_cfv/cfv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/confidential-containers/td-shim/HEAD/td-shim/fuzz/seeds/secure_boot_cfv/cfv -------------------------------------------------------------------------------- /data/sample-keys/ecdsa-p384-private.pk8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/confidential-containers/td-shim/HEAD/data/sample-keys/ecdsa-p384-private.pk8 -------------------------------------------------------------------------------- /td-loader/fuzz/seeds/elf/rust-td-payload: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/confidential-containers/td-shim/HEAD/td-loader/fuzz/seeds/elf/rust-td-payload -------------------------------------------------------------------------------- /td-shim-interface/fuzz/seeds/cfv_parser/cfv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/confidential-containers/td-shim/HEAD/td-shim-interface/fuzz/seeds/cfv_parser/cfv -------------------------------------------------------------------------------- /td-shim-interface/fuzz/seeds/hob_parser/hob_buffer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/confidential-containers/td-shim/HEAD/td-shim-interface/fuzz/seeds/hob_parser/hob_buffer -------------------------------------------------------------------------------- /td-layout/src/runtime/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | pub mod exec; 6 | pub mod linux; 7 | -------------------------------------------------------------------------------- /td-shim-interface/fuzz/seeds/payload_parser/fv_buffer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/confidential-containers/td-shim/HEAD/td-shim-interface/fuzz/seeds/payload_parser/fv_buffer -------------------------------------------------------------------------------- /td-payload/src/arch/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | mod x86_64; 6 | pub use self::x86_64::*; 7 | -------------------------------------------------------------------------------- /td-shim/fuzz/seeds/secure_boot_payload/td-payload-signed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/confidential-containers/td-shim/HEAD/td-shim/fuzz/seeds/secure_boot_payload/td-payload-signed -------------------------------------------------------------------------------- /td-shim/src/bin/td-shim/linux/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | pub mod boot; 6 | pub mod kernel_param; 7 | -------------------------------------------------------------------------------- /td-exception/src/asm/mod.rs: -------------------------------------------------------------------------------- 1 | use core::arch::global_asm; 2 | 3 | global_asm!(include_str!("handler.asm")); 4 | 5 | extern "C" { 6 | pub(crate) static interrupt_handler_table: u8; 7 | } 8 | -------------------------------------------------------------------------------- /devtools/td-layout-config/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | pub mod image; 6 | mod layout; 7 | pub mod memory; 8 | mod render; 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | 3 | # Cargo Junk 4 | target/ 5 | *.bin 6 | *.igvm 7 | *.obj 8 | # afl fuzz and cargo fuzz 9 | *.profraw 10 | corpus 11 | artifacts 12 | coverage 13 | # Intellj working directory 14 | .idea 15 | # vscode working directory 16 | .vscode 17 | -------------------------------------------------------------------------------- /devtools/td-layout-config/config_image.json: -------------------------------------------------------------------------------- 1 | { 2 | "Config": "0x040000", 3 | "Mailbox": "0x001000", 4 | "TempStack": "0x020000", 5 | "TempHeap": "0x020000", 6 | "Metadata": "0x001000", 7 | "Payload": "0xC2D000", 8 | "Ipl": "0x349000", 9 | "ResetVector": "0x008000" 10 | } -------------------------------------------------------------------------------- /td-loader/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | #![cfg_attr(not(test), no_std)] 6 | #![forbid(unsafe_code)] 7 | 8 | #[macro_use] 9 | extern crate scroll; 10 | 11 | pub mod elf; 12 | pub mod elf64; 13 | pub mod pe; 14 | -------------------------------------------------------------------------------- /sh_script/switch_root_run_cmd.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect 2 | spawn su root 3 | expect "Password:" 4 | send "1\r" # Change to you password 5 | send "echo core >/proc/sys/kernel/core_pattern\r" 6 | send "cd /sys/devices/system/cpu\r" 7 | send "echo performance | tee cpu*/cpufreq/scaling_governor\r" 8 | 9 | expect eof 10 | exit 11 | -------------------------------------------------------------------------------- /td-loader/fuzz/fuzz_targets/elf.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | #![no_main] 5 | 6 | mod fuzzlib; 7 | use fuzzlib::fuzz_elf_loader; 8 | 9 | libfuzzer_sys::fuzz_target!(|data: &[u8]| { 10 | // fuzzed code goes here 11 | fuzz_elf_loader(data); 12 | }); 13 | -------------------------------------------------------------------------------- /td-loader/fuzz/fuzz_targets/pe.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | #![no_main] 5 | 6 | mod fuzzlib; 7 | use fuzzlib::fuzz_pe_loader; 8 | 9 | libfuzzer_sys::fuzz_target!(|data: &[u8]| { 10 | // fuzzed code goes here 11 | fuzz_pe_loader(data); 12 | }); 13 | -------------------------------------------------------------------------------- /xtask/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "xtask" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | clap = { version = "4.0", features = ["derive"] } 10 | xshell = "0.2" 11 | lazy_static = "1.4.0" 12 | anyhow = "1.0" -------------------------------------------------------------------------------- /td-payload/src/arch/x86_64/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | pub mod apic; 6 | pub mod cet; 7 | pub mod gdt; 8 | pub mod guard_page; 9 | pub mod idt; 10 | pub mod init; 11 | pub mod paging; 12 | pub mod serial; 13 | #[cfg(feature = "tdx")] 14 | pub mod shared; 15 | -------------------------------------------------------------------------------- /td-shim-interface/fuzz/fuzz_targets/cfv_parser.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | #![no_main] 5 | 6 | mod fuzzlib; 7 | use fuzzlib::fuzz_cfv_parser; 8 | 9 | libfuzzer_sys::fuzz_target!(|data: &[u8]| { 10 | // fuzzed code goes here 11 | fuzz_cfv_parser(data); 12 | }); 13 | -------------------------------------------------------------------------------- /td-shim-interface/fuzz/fuzz_targets/payload_parser.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | #![no_main] 5 | 6 | mod fuzzlib; 7 | use fuzzlib::fuzz_payload_parser; 8 | 9 | libfuzzer_sys::fuzz_target!(|data: &[u8]| { 10 | // fuzzed code goes here 11 | fuzz_payload_parser(data); 12 | }); 13 | -------------------------------------------------------------------------------- /td-shim/fuzz/fuzz_targets/secure_boot_cfv.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | #![no_main] 5 | use libfuzzer_sys::fuzz_target; 6 | 7 | mod fuzzlib; 8 | use fuzzlib::fuzz_secure_boot_cfv; 9 | 10 | fuzz_target!(|data: &[u8]| { 11 | // fuzzed code goes here 12 | fuzz_secure_boot_cfv(data); 13 | }); -------------------------------------------------------------------------------- /sh_script/preparation.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | preparation() { 4 | # apply the patch set for ring 5 | pushd library/ring 6 | git reset --hard 2723abbca9e83347d82b056d5b239c6604f786df 7 | git clean -f -d 8 | git apply ../patches/ring.diff 9 | git apply ../patches/0002-Disable-checks-for-SSE-and-SSE2.patch 10 | popd 11 | } 12 | 13 | preparation 14 | -------------------------------------------------------------------------------- /td-shim-interface/fuzz/fuzz_targets/hob_parser.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | #![no_main] 5 | use libfuzzer_sys::fuzz_target; 6 | 7 | mod fuzzlib; 8 | use fuzzlib::fuzz_hob_parser; 9 | 10 | fuzz_target!(|data: &[u8]| { 11 | // fuzzed code goes here 12 | fuzz_hob_parser(data); 13 | }); 14 | -------------------------------------------------------------------------------- /td-shim/fuzz/fuzz_targets/secure_boot_payload.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | #![no_main] 5 | use libfuzzer_sys::fuzz_target; 6 | 7 | mod fuzzlib; 8 | use fuzzlib::fuzz_secure_boot_payload; 9 | 10 | fuzz_target!(|data: &[u8]| { 11 | // fuzzed code goes here 12 | fuzz_secure_boot_payload(data); 13 | }); -------------------------------------------------------------------------------- /td-shim/src/bin/td-shim/td/dummy.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Alibaba Cloud 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | pub fn get_shared_page_mask() -> u64 { 6 | 0 7 | } 8 | 9 | pub fn accept_memory_resource_range(_cpu_num: u32, _address: u64, _size: u64) {} 10 | 11 | pub fn get_num_vcpus() -> u32 { 12 | 1 13 | } 14 | 15 | pub fn extend_rtmr(_data: &[u8], _pcr_index: u32) {} 16 | -------------------------------------------------------------------------------- /td-shim/src/bin/td-shim/td/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Alibaba Cloud 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | #[cfg(feature = "tdx")] 6 | mod tdx; 7 | #[cfg(all(feature = "tdx", not(feature = "no-mailbox")))] 8 | mod tdx_mailbox; 9 | #[cfg(feature = "tdx")] 10 | pub use tdx::*; 11 | 12 | #[cfg(not(feature = "tdx"))] 13 | mod dummy; 14 | #[cfg(not(feature = "tdx"))] 15 | pub use dummy::*; 16 | -------------------------------------------------------------------------------- /tests/test-td-payload/config/README.md: -------------------------------------------------------------------------------- 1 | # Test TD Payload Configuration 2 | Test will cover 5 combinations of cpus and memory, each json file has 1 combination: 3 | 4 | - 1vCpu + 1G memory [test_config_1.json](test_config_1.json) 5 | - 1vCpu + 2G memory [test_config_2.json](test_config_2.json) 6 | - 2vCpu + 4G memory [test_config_3.json](test_config_3.json) 7 | - 4vCpu + 8G memory [test_config_4.json](test_config_4.json) 8 | - 8vCpu + 16G memory [test_config_5.json](test_config_5.json) -------------------------------------------------------------------------------- /td-payload/src/console.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | use spin::Mutex; 6 | 7 | use crate::arch::serial; 8 | 9 | pub static CONSOLE: Mutex = Mutex::new(Console {}); 10 | 11 | pub struct Console; 12 | 13 | impl core::fmt::Write for Console { 14 | fn write_str(&mut self, s: &str) -> core::fmt::Result { 15 | serial::serial_write_string(s); 16 | Ok(()) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /td-paging/src/consts.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | /// Guest physical to virtual address mapping offset. 0 means identity mapping. 6 | pub const PHYS_VIRT_OFFSET: usize = 0; 7 | /// Page size. 8 | pub const PAGE_SIZE: usize = 0x1000; 9 | 10 | /// Default PTE(page table entry) size. 11 | pub const PAGE_SIZE_DEFAULT: usize = 0x4000_0000; 12 | /// Minimal PTE(page table entry) size. 13 | pub const PAGE_SIZE_4K: usize = 0x1000; 14 | -------------------------------------------------------------------------------- /td-shim-tools/src/bin/td-shim-tee-info-hash/sample_manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "attributes": "0000ffff0000ffff", 3 | "xfam": "ffffffffffffffff", 4 | "mrconfigid": "fe23e15e1b7ee8f48a7f878fedbee8f72a57fdf7c6141ddb0b00d23056c9da30e6c0c51588f0f888c830cfce8f29604c", 5 | "mrowner": "9c1cc37e0845981dfe6f89091c713cd69ab8878c6152d62c27eb5d12b43f9990cb9195fc823f394702bc2c5468938c0c", 6 | "mrownerconfig": "1a69fd4f39f309d63b8cb8cb4fbabc02d43f8e99db739f3aeaa18c26f0f7095c6f0ff6bd42d1806344bd2b59a19fdcd1" 7 | } 8 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | 4 | - package-ecosystem: "cargo" 5 | directory: "/" 6 | schedule: 7 | # Check for updates to cargo dependencies every week 8 | interval: "weekly" 9 | open-pull-requests-limit: 1 10 | allow: 11 | - dependency-type: direct 12 | - dependency-type: indirect 13 | 14 | - package-ecosystem: "github-actions" 15 | directory: "/" 16 | schedule: 17 | # Check for updates to GitHub Actions every week 18 | interval: "weekly" -------------------------------------------------------------------------------- /devtools/rustc-targets/x86_64-custom.json: -------------------------------------------------------------------------------- 1 | { 2 | "llvm-target": "x86_64-unknown-none", 3 | "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", 4 | "arch": "x86_64", 5 | "target-endian": "little", 6 | "target-pointer-width": "64", 7 | "target-c-int-width": "32", 8 | "os": "none", 9 | "executables": true, 10 | "linker": "rust-lld", 11 | "linker-flavor": "ld.lld", 12 | "panic-strategy": "abort", 13 | "disable-redzone": true, 14 | "features": "-mmx,-sse,+soft-float" 15 | } 16 | -------------------------------------------------------------------------------- /devtools/test-runner-server/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "test-runner-server" 3 | version = "0.1.0" 4 | description = "Server to run test cases inside a qemu virtual machine" 5 | repository = "https://github.com/confidential-containers/td-shim" 6 | homepage = "https://github.com/confidential-containers" 7 | license = "Apache-2.0" 8 | edition = "2018" 9 | 10 | [dependencies] 11 | clap = { version = "4.0", features = ["cargo"] } 12 | runner-utils = "0.0.2" # small helper functions for custom runners (e.g. timeouts) 13 | serde_json = "1.0.114" 14 | -------------------------------------------------------------------------------- /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [target.'cfg(target_os = "none")'] 2 | runner = "cargo run --package test-runner-server --" 3 | 4 | [alias] 5 | kbuild = "build --target x86_64-custom.json -Zbuild-std=core -Zbuild-std-features=compiler-builtins-mem" 6 | kimage = "run --target x86_64-custom.json -Zbuild-std=core -Zbuild-std-features=compiler-builtins-mem -- --no-run" 7 | krun = "run --target x86_64-custom.json -Zbuild-std=core -Zbuild-std-features=compiler-builtins-mem" 8 | ktest = "xtest --target x86_64-custom.json" 9 | xtask = "run -p xtask --" 10 | image = "xtask image" -------------------------------------------------------------------------------- /td-shim/ResetVector/DebugDisabled.asm: -------------------------------------------------------------------------------- 1 | ;------------------------------------------------------------------------------ 2 | ; @file 3 | ; Debug disabled 4 | ; 5 | ; Copyright (c) 2021, Intel Corporation. All rights reserved.
6 | ; SPDX-License-Identifier: BSD-2-Clause-Patent 7 | ; 8 | ;------------------------------------------------------------------------------ 9 | 10 | BITS 16 11 | 12 | %macro debugInitialize 0 13 | ; 14 | ; No initialization is required 15 | ; 16 | %endmacro 17 | 18 | %macro debugShowPostCode 1 19 | %endmacro 20 | -------------------------------------------------------------------------------- /cc-measurement/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cc-measurement" 3 | version = "0.1.0" 4 | license = "BSD-2-Clause-Patent" 5 | edition = "2021" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | sha2 = { version = "0.10.6", default-features = false, features = ["force-soft"], optional = true } 11 | ring = { version = "0.17.14", default-features = false, features = ["alloc"], optional = true } 12 | zerocopy = { version = "0.7.31", features = ["derive"] } 13 | 14 | [features] 15 | default = ["sha2"] 16 | -------------------------------------------------------------------------------- /td-shim/src/bin/td-shim/asm/msr64.asm: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021 Intel Corporation 2 | # SPDX-License-Identifier: BSD-2-Clause-Patent 3 | 4 | .section .text 5 | # asm_read_msr64( 6 | # index: u32, // rcx 7 | # ); 8 | .global asm_read_msr64 9 | asm_read_msr64: 10 | 11 | rdmsr 12 | shl rdx, 0x20 13 | or rax, rdx 14 | ret 15 | 16 | # asm_write_msr64( 17 | # index: u32, // rcx 18 | # value: u64, // rdx 19 | # ); 20 | .global asm_write_msr64 21 | asm_write_msr64: 22 | 23 | mov rax, rdx 24 | shr rdx, 0x20 25 | wrmsr 26 | ret 27 | -------------------------------------------------------------------------------- /devtools/rustc-targets/x86_64-unknown-none.json: -------------------------------------------------------------------------------- 1 | { 2 | "llvm-target": "x86_64-unknown-none", 3 | "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128", 4 | "arch": "x86_64", 5 | "target-endian": "little", 6 | "target-pointer-width": "64", 7 | "target-c-int-width": "32", 8 | "os": "none", 9 | "executables": true, 10 | "linker": "rust-lld", 11 | "linker-flavor": "ld.lld", 12 | "panic-strategy": "abort", 13 | "disable-redzone": true, 14 | "features": "-mmx,-sse,+soft-float", 15 | "position-independent-executables": true 16 | } 17 | -------------------------------------------------------------------------------- /td-paging/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "td-paging" 3 | version = "0.1.0" 4 | description = "A simple page table manager" 5 | repository = "https://github.com/confidential-containers/td-shim" 6 | homepage = "https://github.com/confidential-containers" 7 | license = "BSD-2-Clause-Patent" 8 | edition = "2018" 9 | 10 | [dependencies] 11 | bitfield = "0.13.2" 12 | log = "0.4.13" 13 | spin = "0.9.2" 14 | td-layout = { path = "../td-layout" } 15 | # Lock down to 0.44, otherwise it depends on inline asm 16 | x86 = "0.47.0" 17 | x86_64 = { version = "0.14.9", default-features = false, features = ["instructions"] } 18 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/doublify/pre-commit-rust.git 3 | rev: v1.0 4 | hooks: 5 | - id: fmt 6 | - id: cargo-check 7 | - id: clippy 8 | args: ["--", "-A", "clippy::redundant_field_names", "-D", "warnings"] 9 | - repo: https://github.com/pre-commit/pre-commit-hooks.git 10 | rev: v4.0.1 11 | hooks: 12 | - id: mixed-line-ending 13 | args: [--fix=lf] 14 | - id: check-toml 15 | - id: trailing-whitespace 16 | - id: check-added-large-files 17 | args: ['--maxkb=1024'] 18 | - id: end-of-file-fixer 19 | -------------------------------------------------------------------------------- /td-shim/ResetVector/Port80Debug.asm: -------------------------------------------------------------------------------- 1 | ;------------------------------------------------------------------------------ 2 | ; @file 3 | ; Port 0x80 debug support macros 4 | ; 5 | ; Copyright (c) 2021, Intel Corporation. All rights reserved.
6 | ; SPDX-License-Identifier: BSD-2-Clause-Patent 7 | ; 8 | ;------------------------------------------------------------------------------ 9 | 10 | BITS 16 11 | 12 | %macro debugInitialize 0 13 | ; 14 | ; No initialization is required 15 | ; 16 | %endmacro 17 | 18 | %macro debugShowPostCode 1 19 | mov al, %1 20 | out 0x80, al 21 | %endmacro 22 | -------------------------------------------------------------------------------- /devtools/test-runner-client/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "test-runner-client" 3 | version = "0.1.0" 4 | description = "Client cooperating with test-runner-server to execute unit test cases in virtual machines" 5 | repository = "https://github.com/confidential-containers/td-shim" 6 | homepage = "https://github.com/confidential-containers" 7 | license = "Apache-2.0" 8 | edition = "2018" 9 | 10 | [dependencies] 11 | linked_list_allocator = "0.10.4" 12 | spin = { version = "0.9.2", features = ["lazy"]} 13 | uart_16550 = "0.2.17" 14 | x86_64 = { version = "0.14.9", default-features = false, features = ["instructions"] } 15 | -------------------------------------------------------------------------------- /td-layout/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "td-layout" 3 | version = "0.1.0" 4 | description = "Define build time and runtime layout for trusted domain" 5 | repository = "https://github.com/confidential-containers/td-shim" 6 | homepage = "https://github.com/confidential-containers" 7 | license = "BSD-2-Clause-Patent" 8 | edition = "2018" 9 | 10 | [features] 11 | no-config = [] 12 | no-mailbox = [] 13 | 14 | [dependencies] 15 | scroll = { version = "0.10", default-features = false, features = ["derive"]} 16 | log = "0.4.13" 17 | td-shim-interface = { path = "../td-shim-interface" } 18 | 19 | [dev-dependencies] 20 | memoffset = "0.6" 21 | -------------------------------------------------------------------------------- /sh_script/unit_test_coverage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [[ ! $PWD =~ rust-td$ ]];then 4 | pushd .. 5 | fi 6 | 7 | git clean -f 8 | 9 | export RUSTFLAGS="-Zinstrument-coverage" 10 | export LLVM_PROFILE_FILE="your_name-%p-%m.profraw" 11 | 12 | cd ./pe-loader 13 | cargo test 14 | cd .. 15 | 16 | cd ./elf-loader 17 | cargo test 18 | cd .. 19 | 20 | cargo test 21 | 22 | grcov . --binary-path ./target/debug/ -s . -t html --branch --ignore-not-existing -o ./target/debug/coverage/ 23 | 24 | grcov . --binary-path ./target/debug/ -s . -t lcov --branch --ignore-not-existing -o ./lcov.infoba 25 | 26 | unset RUSTFLAGS 27 | unset LLVM_PROFILE_FILE 28 | -------------------------------------------------------------------------------- /sh_script/update_toolchain.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | TOOLCHAIN_VER=$1 4 | TRY_TIMES=5 5 | echo ${TOOLCHAIN_VER} 6 | 7 | while [ ${TRY_TIMES} -gt 0 ] 8 | do 9 | exist=`rustup toolchain list | grep ${TOOLCHAIN_VER} | wc -l` 10 | if [[ ${exist} == 0 ]] 11 | then 12 | rustup toolchain install ${TOOLCHAIN_VER} --component rust-src 13 | else 14 | rustup component add rust-src 15 | echo "Toolchain ${TOOLCHAIN_VER} is installed." 16 | break 17 | fi 18 | sleep 30 19 | let "TRY_TIMES--" 20 | done 21 | 22 | if [[ ${TRY_TIMES} == 0 ]] 23 | then 24 | echo "Install toolchian ${TOOLCHAIN_VER} failed." 25 | exit 1 26 | fi -------------------------------------------------------------------------------- /td-loader/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "td-loader" 3 | version = "0.1.0" 4 | edition = "2018" 5 | description = "Parser and loader for 64 bit Portable Executable (PE+) or 32/64 bit Executable and Linkable Format(ELF) binary objects" 6 | repository = "https://github.com/confidential-containers/td-shim" 7 | homepage = "https://github.com/confidential-containers" 8 | license = "Apache-2.0" 9 | 10 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 11 | 12 | [dependencies] 13 | log = "0.4.13" 14 | scroll = { version = "0.10", default-features=false, features = ["derive"] } 15 | 16 | [dev-dependencies] 17 | env_logger = "0.10" -------------------------------------------------------------------------------- /td-exception/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2021 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | #![no_std] 6 | 7 | mod asm; 8 | pub mod idt; 9 | pub mod interrupt; 10 | 11 | /// Initialize exception/interrupt handlers. 12 | pub fn setup_exception_handlers() { 13 | unsafe { idt::init() }; 14 | } 15 | 16 | #[cfg(feature = "integration-test")] 17 | lazy_static::lazy_static! { 18 | pub static ref DIVIDED_BY_ZERO_EVENT_COUNT: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0); 19 | } 20 | 21 | pub enum ExceptionError { 22 | // Caller gives an input that is not expected. 23 | InvalidParameter, 24 | } 25 | -------------------------------------------------------------------------------- /td-shim/ResetVector/PostCodes.inc: -------------------------------------------------------------------------------- 1 | ;------------------------------------------------------------------------------ 2 | ; @file 3 | ; Definitions of POST CODES for the reset vector module 4 | ; 5 | ; Copyright (c) 2021, Intel Corporation. All rights reserved.
6 | ; SPDX-License-Identifier: BSD-2-Clause-Patent 7 | ; 8 | ;------------------------------------------------------------------------------ 9 | 10 | %define POSTCODE_16BIT_MODE 0x16 11 | %define POSTCODE_32BIT_MODE 0x32 12 | %define POSTCODE_64BIT_MODE 0x64 13 | 14 | %define POSTCODE_BFV_NOT_FOUND 0xb0 15 | %define POSTCODE_BFV_FOUND 0xb1 16 | 17 | %define POSTCODE_SEC_NOT_FOUND 0xf0 18 | %define POSTCODE_SEC_FOUND 0xf1 19 | -------------------------------------------------------------------------------- /td-shim/src/bin/td-shim/asm/exception_notdvmcall.asm: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, 2025 Intel Corporation 2 | # SPDX-License-Identifier: BSD-2-Clause-Patent 3 | 4 | .section .text 5 | 6 | #-------------------------------------------------------------------- 7 | # empty_exception_handler 8 | # 9 | # We do not need to save the context here because this function will 10 | # never return. 11 | #-------------------------------------------------------------------- 12 | .global empty_exception_handler 13 | empty_exception_handler: 14 | hlt 15 | .exception_loop: 16 | jmp .exception_loop 17 | 18 | .global empty_exception_handler_end 19 | empty_exception_handler_end: 20 | jmp .exception_loop 21 | -------------------------------------------------------------------------------- /devtools/td-layout-config/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "td-layout-config" 3 | version = "0.1.0" 4 | description = "Generate td-shim build-time/runtime layout from a json configuration file" 5 | repository = "https://github.com/confidential-containers/td-shim" 6 | homepage = "https://github.com/confidential-containers" 7 | license = "BSD-2-Clause-Patent" 8 | edition = "2018" 9 | 10 | [[bin]] 11 | name = "td-layout-config" 12 | 13 | [dependencies] 14 | clap = { version = "4.0", features = ["derive"] } 15 | Inflector = "0.11.4" 16 | parse_int = "0.6.0" 17 | scroll = { version = "0.10", default-features = false, features = ["derive"]} 18 | serde = { version = "1.0", features = ["derive"] } 19 | serde_json = "1.0" 20 | tera = "1.17.1" 21 | -------------------------------------------------------------------------------- /td-shim-tools/src/bin/td-shim-checker/README.md: -------------------------------------------------------------------------------- 1 | ## td-shim checker 2 | 3 | This tool accepts td-shim file as input and extracts the TdxMetadata with the format of (TdxMetadataDescriptor, Vec\) if the TdxMetadata is valid in the input td-shim file. After that the TdxMetadata is dump out. 4 | 5 | ### TdxMetadata 6 | 7 | Quotation from [TD Shim Metadata](../../../../doc/tdshim_spec.md#td-shim-metadata), 8 | 9 | ### td-shim checker 10 | 11 | Run the tool: 12 | ``` 13 | cargo run -p td-shim-tools --bin td-shim-checker --no-default-features --features="loader" -- {tdshim_file} 14 | ``` 15 | 16 | For example: 17 | ``` 18 | cargo run -p td-shim-tools --bin td-shim-checker -- target/release/final.bin 19 | ``` 20 | -------------------------------------------------------------------------------- /td-shim-interface/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "td-shim-interface" 3 | version = "0.1.1" 4 | license = "BSD-2-Clause-Patent" 5 | description = "TD-shim metadata data structures and related functions. UEFI Platform Initializaiton data structures and accessors" 6 | 7 | edition = "2018" 8 | homepage = "https://github.com/confidential-containers/td-shim" 9 | repository = "https://github.com/confidential-containers/td-shim" 10 | readme = "README.md" 11 | keywords = ["td-shim", "TDX", "intel"] 12 | 13 | [dependencies] 14 | r-efi = "3.2.0" 15 | scroll = { version = "0.10", default-features = false, features = ["derive"] } 16 | zerocopy = { version = "0.7.31", features = ["derive"] } 17 | 18 | log = "0.4.13" 19 | 20 | [features] 21 | no-metadata-checks = [] 22 | -------------------------------------------------------------------------------- /td-exception/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "td-exception" 3 | version = "0.1.0" 4 | description = "Setup Interrupt Descriptor Table for td-shim" 5 | repository = "https://github.com/confidential-containers/td-shim" 6 | homepage = "https://github.com/confidential-containers" 7 | license = "Apache-2.0" 8 | edition = "2018" 9 | 10 | [dependencies] 11 | bitflags = "1.2.1" 12 | lazy_static = { version = "1.0", features = ["spin_no_std"] } 13 | log = "0.4.13" 14 | tdx-tdcall = { path = "../tdx-tdcall", optional = true } 15 | x86_64 = { version = "0.14.9", default-features = false, features = ["instructions"] } 16 | spin = "0.9.2" 17 | 18 | [features] 19 | cet-shstk = [] 20 | tdx = ["tdx-tdcall"] 21 | integration-test = [] 22 | no-tdvmcall = ["tdx-tdcall/no-tdvmcall"] 23 | -------------------------------------------------------------------------------- /tests/test-td-exception/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "test-td-exception" 3 | version = "0.1.0" 4 | description = "Run td-exception unit test cases inside a VM" 5 | repository = "https://github.com/confidential-containers/td-shim" 6 | homepage = "https://github.com/confidential-containers" 7 | license = "BSD-2-Clause-Patent" 8 | edition = "2018" 9 | 10 | [dependencies] 11 | # Keep it as `dependencies` to satisfy bootloader-locator's requirement, though it should be `dev-dependencies` 12 | bootloader = "0.10.12" 13 | 14 | [dev-dependencies] 15 | td-exception = { path = "../../td-exception", features = ["integration-test"] } 16 | test-runner-client = { path = "../../devtools/test-runner-client" } 17 | 18 | [package.metadata.bootloader] 19 | map-physical-memory = true 20 | -------------------------------------------------------------------------------- /devtools/td-benchmark/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "td-benchmark" 3 | version = "0.1.0" 4 | description = "Library to support benchmark for no_std binaries" 5 | repository = "https://github.com/confidential-containers/td-shim" 6 | homepage = "https://github.com/confidential-containers" 7 | license = "BSD-2-Clause-Patent" 8 | edition = "2018" 9 | 10 | [dependencies] 11 | linked_list_allocator = "0.10.4" 12 | log = "0.4.13" 13 | x86 = { version = "0.47.0", optional = true } 14 | scroll = { version = "0.10", default-features = false, features = ["derive"], optional = true } 15 | td-layout = { path = "../../td-layout", optional = true } 16 | 17 | lazy_static = { version = "1.4.0", features = ["spin_no_std"] } 18 | spin = "0.9.2" 19 | 20 | [dev-dependencies] 21 | alloca = "0.3.3" 22 | -------------------------------------------------------------------------------- /td-logger/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "td-logger" 3 | version = "0.1.0" 4 | description = "Simple logger backend for td-shim" 5 | repository = "https://github.com/confidential-containers/td-shim" 6 | homepage = "https://github.com/confidential-containers" 7 | license = "BSD-2-Clause-Patent" 8 | edition = "2018" 9 | 10 | [dependencies] 11 | lazy_static = { version = "1.0", features = ["spin_no_std"] } 12 | log = { version = "0.4.13" } 13 | spin = "0.9.2" 14 | tdx-tdcall = { path = "../tdx-tdcall", optional = true } 15 | # Lock down to 0.44, otherwise it depends on inline asm 16 | x86 = { version = "0.47.0", optional = true } 17 | 18 | [features] 19 | tdx = ["tdx-tdcall"] 20 | serial-port = ["x86"] 21 | no-tdvmcall = ["tdx-tdcall/no-tdvmcall"] 22 | tdg_dbg = ["tdx-tdcall/tdg_dbg"] 23 | -------------------------------------------------------------------------------- /td-payload/src/arch/x86_64/guard_page.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | use crate::mm::SIZE_4K; 6 | 7 | use super::{gdt::tss_set_ist, idt::idt_set_ist, paging::set_not_present}; 8 | 9 | pub fn set_guard_page(base: u64) { 10 | set_not_present(base, SIZE_4K); 11 | } 12 | 13 | /// Set the known good stack to the Interrupt Stack Table. System will switch 14 | /// to the exception stack automatically when `Page Fault`exception occurs. 15 | /// 16 | /// # Safety 17 | /// The GDT/IDT and TSS must have been initialized when calling this function. 18 | pub unsafe fn set_exception_stack(good_stack_top: u64, idt_index: u8, ist_index: u8) { 19 | tss_set_ist(ist_index - 1, good_stack_top); 20 | idt_set_ist(idt_index, ist_index); 21 | } 22 | -------------------------------------------------------------------------------- /td-shim/src/bin/td-shim/heap.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | use linked_list_allocator::LockedHeap; 6 | use td_layout::build_time::{TD_SHIM_TEMP_HEAP_BASE, TD_SHIM_TEMP_HEAP_SIZE}; 7 | 8 | #[cfg(not(test))] 9 | #[global_allocator] 10 | static HEAP_ALLOCATOR: LockedHeap = LockedHeap::empty(); 11 | 12 | /// Initialize the heap allocator. 13 | pub(super) fn init() { 14 | let heap_start = TD_SHIM_TEMP_HEAP_BASE as usize; 15 | let heap_size = TD_SHIM_TEMP_HEAP_SIZE as usize; 16 | 17 | unsafe { 18 | #[cfg(not(test))] 19 | HEAP_ALLOCATOR.lock().init(heap_start as *mut u8, heap_size); 20 | } 21 | log::info!( 22 | "Heap allocator init done: {:#x?}\n", 23 | heap_start..heap_start + heap_size 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /xtask/src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | mod build; 6 | 7 | use std::process::exit; 8 | 9 | use clap::{Parser, Subcommand}; 10 | 11 | #[derive(Parser)] 12 | struct Program { 13 | #[clap(subcommand)] 14 | command: Commands, 15 | } 16 | 17 | #[derive(Subcommand)] 18 | enum Commands { 19 | Image(build::BuildArgs), 20 | } 21 | 22 | fn main() { 23 | match Program::parse().command { 24 | Commands::Image(args) => match args.build() { 25 | Ok(image) => { 26 | println!("Successfully generate TD-Shim image: {}", image.display()); 27 | } 28 | Err(e) => { 29 | eprintln!("[ERROR]: {}", e); 30 | exit(-1) 31 | } 32 | }, 33 | }; 34 | } 35 | -------------------------------------------------------------------------------- /.github/workflows/deny.yml: -------------------------------------------------------------------------------- 1 | name: cargo-deny 2 | on: 3 | push: 4 | branches: [ "main" ] 5 | pull_request: 6 | # The branches below must be a subset of the branches above 7 | branches: [ "main" ] 8 | schedule: 9 | - cron: '0 0 * * *' 10 | 11 | jobs: 12 | cargo-deny: 13 | runs-on: ubuntu-latest 14 | strategy: 15 | matrix: 16 | checks: 17 | - advisories 18 | - sources 19 | - bans 20 | 21 | # Prevent sudden announcement of a new advisory from failing ci: 22 | continue-on-error: ${{ matrix.checks == 'sources' }} 23 | 24 | steps: 25 | - uses: actions/checkout@v6 26 | with: 27 | submodules: recursive 28 | - run: make preparation 29 | - uses: EmbarkStudios/cargo-deny-action@v2 30 | with: 31 | command: check ${{ matrix.checks }} 32 | -------------------------------------------------------------------------------- /td-shim-interface/src/td_uefi_pi/pi/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2019 Intel Corporation 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //! Constants and Structures defined by the UEFI Platform Initialization (UEFI-PI) Spec. 16 | 17 | pub mod boot_mode; 18 | pub mod fv; 19 | pub mod guid; 20 | pub mod hob; 21 | -------------------------------------------------------------------------------- /tdx-tdcall/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tdx-tdcall" 3 | version = "0.2.3" 4 | description = "Constants, stuctures and wrappers to access TDCALL services" 5 | repository = "https://github.com/confidential-containers/td-shim" 6 | homepage = "https://github.com/confidential-containers" 7 | license = "BSD-2-Clause-Patent" 8 | edition = "2018" 9 | 10 | readme = "README.md" 11 | keywords = ["TDCALL", "TDX", "intel"] 12 | 13 | [dependencies] 14 | cfg-if = "1.0.0" 15 | lazy_static = { version = "1.0", features = ["spin_no_std"] } 16 | log = "0.4.13" 17 | scroll = { version = "0.10", default-features = false, features = ["derive"] } 18 | spin = "0.9.2" 19 | x86_64 = { version = "0.14.9", default-features = false, features = ["instructions"] } 20 | bitfield-struct = "0.11" 21 | 22 | [features] 23 | default = [] 24 | use_tdx_emulation = [] 25 | no-tdvmcall = [] 26 | no-tdaccept = [] 27 | tdg_dbg = [] 28 | -------------------------------------------------------------------------------- /tests/test-td-paging/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "test-td-paging" 3 | version = "0.1.0" 4 | description = "Run td-paging unit test cases inside a VM" 5 | repository = "https://github.com/confidential-containers/td-shim" 6 | homepage = "https://github.com/confidential-containers" 7 | license = "BSD-2-Clause-Patent" 8 | edition = "2018" 9 | 10 | [dependencies] 11 | # Keep it as `dependencies` to satisfy bootloader-locator's requirement, though it should be `dev-dependencies` 12 | bootloader = "0.10.12" 13 | 14 | [dev-dependencies] 15 | td-paging = { path = "../../td-paging" } 16 | td-layout = { path = "../../td-layout" } 17 | test-runner-client = { path = "../../devtools/test-runner-client" } 18 | x86_64 = { version = "0.14.9", default-features = false, features = ["instructions"] } 19 | 20 | [package.metadata.bootloader] 21 | map-physical-memory = true 22 | map-page-table-recursively = true 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This project uses BSD-2-Clause-Patent license. 2 | 3 | [SPDX-License-Identifier](https://spdx.org/licenses/): [BSD-2-Clause-Patent](https://spdx.org/licenses/BSD-2-Clause-Patent.html). 4 | 5 | ``` 6 | Copyright (c) 2021, Intel Corporation. All rights reserved. 7 | 8 | SPDX-License-Identifier: BSD-2-Clause-Patent 9 | ``` 10 | 11 | Some of the files are derived from [edkii](https://github.com/tianocore/edk2) project. 12 | They reuse [edkii license](https://github.com/tianocore/edk2/blob/master/License.txt) - [BSD-2-Clause-Patent](https://spdx.org/licenses/BSD-2-Clause-Patent.html). 13 | 14 | Some of the files are derived from [rust-hypervisor-firmware](https://github.com/cloud-hypervisor/rust-hypervisor-firmware) project. 15 | They reuse [rust-hypervisor-firmware license](https://github.com/cloud-hypervisor/rust-hypervisor-firmware/blob/master/LICENSE) - [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html). 16 | -------------------------------------------------------------------------------- /sh_script/rudra.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [[ ! $PWD =~ td-shim$ ]]; then 4 | pushd .. 5 | fi 6 | 7 | type rudra 8 | 9 | if [[ $? != 0 ]]; then 10 | echo -e "\033[31m Please install rudra \033[0m" 11 | exit 1 12 | fi 13 | 14 | rudra_rust_version=nightly-2021-08-20 15 | 16 | if [[ ! $(cat rust-toolchain) =~ $rudra_rust_version ]]; then 17 | echo -e "\033[31m Now rudra version supports $rudra_rust_version, please refer to https://github.com/sslab-gatech/Rudra or doc/static_analyzer.md \033[0m" 18 | exit 1 19 | fi 20 | paths=( 21 | "td-exception" 22 | "td-layout" 23 | "td-loader" 24 | "td-logger" 25 | "td-paging" 26 | "td-payload" 27 | "td-shim" 28 | "td-shim-interface" 29 | "td-shim-tools" 30 | "tdx-tdcall" 31 | ) 32 | 33 | for i in ${paths[@]}; do 34 | pushd $PWD/$i 35 | 36 | case "$i" in 37 | td-shim) cargo rudra --features main,tdx ;; 38 | *) cargo rudra ;; 39 | esac 40 | 41 | popd 42 | done 43 | -------------------------------------------------------------------------------- /td-paging/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | #![no_std] 6 | 7 | extern crate alloc; 8 | 9 | mod consts; 10 | mod frame; 11 | mod page_table; 12 | 13 | pub use consts::*; 14 | pub use page_table::{cr3_write, create_mapping, create_mapping_with_flags, set_page_flags}; 15 | 16 | #[derive(Debug)] 17 | pub enum Error { 18 | InvalidArguments, 19 | MappingError(u64, u64), // physical address, frame size 20 | } 21 | 22 | type Result = core::result::Result; 23 | 24 | /// Initialize the page table management subsystem. 25 | pub fn init(base: u64, size: usize) -> Result<()> { 26 | if base as usize % PAGE_SIZE != 0 || size % PAGE_SIZE != 0 { 27 | return Err(Error::InvalidArguments); 28 | } 29 | 30 | frame::init(base, size); 31 | Ok(()) 32 | } 33 | 34 | /// Reserve page table page at physical address `addr`. 35 | pub fn reserve_page(addr: u64) { 36 | frame::FRAME_ALLOCATOR.lock().reserve(addr); 37 | } 38 | -------------------------------------------------------------------------------- /devtools/td-layout-config/config_memory_exec.json: -------------------------------------------------------------------------------- 1 | { 2 | "memory_regions": [ 3 | { 4 | "name": "Bootloader", 5 | "size": "0x800000", 6 | "type": "Memory" 7 | }, 8 | { 9 | "name": "TdHob", 10 | "size": "0x20000", 11 | "type": "Memory" 12 | }, 13 | { 14 | "name": "EventLog", 15 | "size": "0x100000", 16 | "type": "Nvs" 17 | }, 18 | { 19 | "name": "RelocatedMailbox", 20 | "size": "0x2000", 21 | "type": "Nvs" 22 | }, 23 | { 24 | "name": "PayloadPageTable", 25 | "size": "0x20000", 26 | "type": "Reserved" 27 | }, 28 | { 29 | "name": "Payload", 30 | "size": "0x2000000", 31 | "type": "Reserved" 32 | }, 33 | { 34 | "name": "Acpi", 35 | "size": "0x100000", 36 | "type": "Acpi" 37 | } 38 | ] 39 | } -------------------------------------------------------------------------------- /td-shim/ResetVector/ResetVector.nasm: -------------------------------------------------------------------------------- 1 | ;------------------------------------------------------------------------------ 2 | ; @file 3 | ; This file includes all other code files to assemble the reset vector code 4 | ; 5 | ; Copyright (c) 2021, Intel Corporation. All rights reserved.
6 | ; SPDX-License-Identifier: BSD-2-Clause-Patent 7 | ; 8 | ;------------------------------------------------------------------------------ 9 | 10 | %define ARCH_X64 11 | 12 | %include "CommonMacros.inc" 13 | 14 | StartOfResetVectorCode: 15 | 16 | %define ADDR_OF_START_OF_RESET_CODE ADDR_OF(StartOfResetVectorCode) 17 | 18 | %include "PostCodes.inc" 19 | %include "X64/PageTables.asm" 20 | 21 | %ifdef DEBUG_PORT80 22 | %include "Port80Debug.asm" 23 | %elifdef DEBUG_SERIAL 24 | %include "SerialDebug.asm" 25 | %else 26 | %include "DebugDisabled.asm" 27 | %endif 28 | 29 | %include "Ia32/ValidateBfvBase.asm" 30 | 31 | %include "Ia32/Flat32ToFlat64.asm" 32 | %include "Ia32/ReloadFlat32.asm" 33 | %include "Main.asm" 34 | %include "Ia32/ResetVectorVtf0.asm" 35 | -------------------------------------------------------------------------------- /td-loader/fuzz/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "td-loader-fuzz" 3 | version = "0.0.0" 4 | authors = ["Automatically generated"] 5 | publish = false 6 | edition = "2018" 7 | 8 | [package.metadata] 9 | cargo-fuzz = true 10 | 11 | [dependencies] 12 | libfuzzer-sys = {version = "0.4", optional = true } 13 | afl = {version = "*", optional = true } 14 | log = "0.4.13" 15 | arbitrary = "=1.1.3" 16 | serde = "=1.0.198" 17 | 18 | [dependencies.td-loader] 19 | path = ".." 20 | 21 | # Prevent this from interfering with workspaces 22 | [workspace] 23 | members = ["."] 24 | 25 | [features] 26 | default = ["libfuzzer-sys"] 27 | fuzz = ["afl"] 28 | 29 | [[bin]] 30 | name = "pe" 31 | path = "fuzz_targets/pe.rs" 32 | test = false 33 | doc = false 34 | 35 | [[bin]] 36 | name = "elf" 37 | path = "fuzz_targets/elf.rs" 38 | test = false 39 | doc = false 40 | 41 | [[bin]] 42 | name = "afl_pe" 43 | path = "fuzz_targets/afl_pe.rs" 44 | test = false 45 | doc = false 46 | 47 | [[bin]] 48 | name = "afl_elf" 49 | path = "fuzz_targets/afl_elf.rs" 50 | test = false 51 | doc = false 52 | 53 | -------------------------------------------------------------------------------- /td-payload/src/arch/x86_64/idt.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | pub use td_exception::idt::*; 6 | pub use td_exception::interrupt::*; 7 | 8 | pub const PAGE_FAULT_EXCEPTION: u8 = 14; 9 | pub const PAGE_FAULT_IST: u8 = 1; 10 | 11 | /// Initialize exception/interrupt handlers. 12 | /// 13 | /// # Safety 14 | /// `CS` needs to be set before this function is called 15 | pub unsafe fn init_idt() { 16 | init(); 17 | } 18 | 19 | pub fn register(vector: u8, func: unsafe extern "C" fn()) { 20 | unsafe { register_handler(vector, func) } 21 | } 22 | 23 | /// # Safety 24 | /// 25 | /// IDT needs to be initialized before this function is called 26 | pub unsafe fn idt_set_ist(vector: u8, index: u8) { 27 | let idtr = store_idtr(); 28 | let idt_entries = read_idt(&idtr); 29 | if usize::from(vector) < idt_entries.len() { 30 | idt_entries[vector as usize].set_ist(index); 31 | } else { 32 | panic!("Set idt ist fail"); 33 | } 34 | 35 | load_idtr(&idtr) 36 | } 37 | -------------------------------------------------------------------------------- /td-payload/src/arch/x86_64/serial.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | /// Write a byte to the debug port, converting `\n' to '\r\n`. 6 | fn serial_write_byte(byte: u8) { 7 | if byte == b'\n' { 8 | io_write(b'\r') 9 | } 10 | io_write(byte) 11 | } 12 | 13 | /// Write a string to the debug port. 14 | pub fn serial_write_string(s: &str) { 15 | for c in s.chars() { 16 | serial_write_byte(c as u8); 17 | } 18 | } 19 | 20 | #[cfg(any( 21 | all(feature = "tdx", not(feature = "no-tdvmcall")), 22 | not(feature = "tdx") 23 | ))] 24 | const SERIAL_IO_PORT: u16 = 0x3F8; 25 | 26 | #[cfg(all(feature = "tdx", not(feature = "no-tdvmcall")))] 27 | fn io_write(byte: u8) { 28 | tdx_tdcall::tdx::tdvmcall_io_write_8(SERIAL_IO_PORT, byte); 29 | } 30 | 31 | #[cfg(all(feature = "tdx", feature = "no-tdvmcall"))] 32 | fn io_write(_byte: u8) {} 33 | 34 | #[cfg(not(feature = "tdx"))] 35 | fn io_write(byte: u8) { 36 | unsafe { x86::io::outb(SERIAL_IO_PORT, byte) }; 37 | } 38 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | default-members = ["td-shim", "td-payload"] 4 | members = [ 5 | "cc-measurement", 6 | "devtools/td-layout-config", 7 | "devtools/td-benchmark", 8 | "devtools/test-runner-server", 9 | "devtools/test-runner-client", 10 | "td-exception", 11 | "td-layout", 12 | "td-logger", 13 | "td-paging", 14 | "td-payload", 15 | "td-shim", 16 | "td-shim-tools", 17 | "tdx-tdcall", 18 | "tests/test-td-exception", 19 | "tests/test-td-paging", 20 | "tests/test-td-payload", 21 | "xtask", 22 | "td-shim-interface", 23 | ] 24 | 25 | # the profile used for debug build of `td-shim` and `td-payload` 26 | [profile.dev-opt] 27 | inherits = "dev" 28 | panic = "abort" # disable stack unwinding on panic 29 | opt-level = "z" 30 | lto = true 31 | 32 | # the profile used for `cargo build --release` 33 | [profile.release] 34 | panic = "abort" # disable stack unwinding on panic 35 | lto = true # Link-time optimization 36 | 37 | [patch.crates-io] 38 | ring = { path = "library/ring" } 39 | -------------------------------------------------------------------------------- /tdx-tdcall/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | ## [0.2.3] - 2025-03-13 5 | +### Added 6 | +- Added new tdcall_tdg_debug_write_8 API under tdg_dbg feature. 7 | 8 | ## [0.2.1] - 2024-07-23 9 | ### Changed 10 | - Remove nightly feature in the x86_64 crate 11 | - Fix TdCallError parsing 12 | 13 | ## [0.2.0] - 2024-06-21 14 | ### Added 15 | - Wrapper to tdcall_accept_page to accept a memory range (for both normal 4K as well as 2M large pages). 16 | - Add tdcall_vm_read/write to access TD-scope meta field of a TD. 17 | - Add tdcall_vp_read/write is to access vCPU-scope meta field of a TD. 18 | - Add tdcall_vp_invept/invvpid to provide SEPT flushing support. 19 | - Add tdcall_vp_enter support. 20 | - Add tdcall to support memory attribute write. 21 | 22 | ### Changed 23 | - Change return type for tdvmcall_wrmsr, tdvmcall_rdmsr 24 | - Replace the & operator with addr_of! macro for tdvmcall_mmio_write/tdvmcall_mmio_read 25 | - Extend TdInfo struct to add vcpu_index field 26 | 27 | ## [0.1.0] - 2024-06-07 28 | ### Added 29 | - Add README.md for publishing to crates.io 30 | -------------------------------------------------------------------------------- /tdx-tdcall/README.md: -------------------------------------------------------------------------------- 1 | [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fconfidential-containers%2Ftd-shim.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fconfidential-containers%2Ftd-shim?ref=badge_shield) 2 | # TDX-tdcall - Trust Domain Extensions tdcall 3 | 4 | ## Documents 5 | 6 | * [Intel TDX](https://software.intel.com/content/www/us/en/develop/articles/intel-trust-domain-extensions.html) 7 | 8 | ## Introduction 9 | 10 | Intel’s Trust Domain Extensions (TDX) protect confidential guest VMs from the host and physical attacks by isolating the guest register state and by encrypting the guest memory. In TDX, a special module running in a special mode sits between the host and the guest and manages the guest/host separation. 11 | 12 | This tdx-tdcall crate provides constants, stuctures and wrappers to support user access TDCALL services. 13 | 14 | 15 | ## License 16 | [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fconfidential-containers%2Ftd-shim.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fconfidential-containers%2Ftd-shim?ref=badge_large) 17 | -------------------------------------------------------------------------------- /tdx-tdcall/src/asm/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | use core::arch::global_asm; 6 | use core::ffi::c_void; 7 | 8 | #[cfg(feature = "use_tdx_emulation")] 9 | global_asm!(include_str!("tdcall_emu.asm")); 10 | 11 | #[cfg(all(feature = "use_tdx_emulation", not(feature = "no-tdvmcall")))] 12 | global_asm!(include_str!("tdvmcall_emu.asm")); 13 | 14 | #[cfg(not(feature = "use_tdx_emulation"))] 15 | global_asm!(include_str!("tdcall.asm")); 16 | 17 | #[cfg(all(not(feature = "use_tdx_emulation"), not(feature = "no-tdvmcall")))] 18 | global_asm!(include_str!("tdvmcall.asm")); 19 | 20 | #[cfg(all(not(feature = "use_tdx_emulation"), not(feature = "no-tdvmcall")))] 21 | global_asm!(include_str!("tdvmcall_ex.asm")); 22 | 23 | extern "win64" { 24 | pub(crate) fn asm_td_call(args: *mut c_void) -> u64; 25 | #[cfg(not(feature = "no-tdvmcall"))] 26 | pub(crate) fn asm_td_vmcall(args: *mut c_void, do_sti: u64) -> u64; 27 | #[cfg(not(feature = "no-tdvmcall"))] 28 | pub(crate) fn asm_td_vmcall_ex(args: *mut c_void, do_sti: u64) -> u64; 29 | } 30 | -------------------------------------------------------------------------------- /td-shim/src/bin/td-shim/asm/exception.asm: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 Intel Corporation 2 | # SPDX-License-Identifier: BSD-2-Clause-Patent 3 | 4 | .set TDVMCALL_EXPOSE_REGS_MASK, 0xfc00 5 | .set TDVMCALL, 0x0 6 | .set INSTRUCTION_HLT, 0xc 7 | 8 | .section .text 9 | 10 | #-------------------------------------------------------------------- 11 | # empty_exception_handler 12 | # 13 | # We do not need to save the context here because this function will 14 | # never return. 15 | #-------------------------------------------------------------------- 16 | .global empty_exception_handler 17 | empty_exception_handler: 18 | mov rax, TDVMCALL 19 | mov rcx, TDVMCALL_EXPOSE_REGS_MASK 20 | mov r10, 0 21 | mov r11, INSTRUCTION_HLT 22 | mov r12, 0 23 | mov r13, 0 24 | mov r14, 0 25 | mov r15, 0 26 | # TDVMCALL 27 | .byte 0x66, 0x0f, 0x01, 0xcc 28 | .exception_loop: 29 | jmp .exception_loop 30 | 31 | .global empty_exception_handler_end 32 | empty_exception_handler_end: 33 | jmp .exception_loop 34 | -------------------------------------------------------------------------------- /td-payload/src/mm/heap.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | use core::panic::PanicInfo; 6 | #[cfg(not(feature = "test_heap_size"))] 7 | use linked_list_allocator::LockedHeap; 8 | #[cfg(feature = "test_heap_size")] 9 | use td_benchmark::Alloc; 10 | 11 | #[cfg(feature = "test_heap_size")] 12 | #[global_allocator] 13 | static HEAP: Alloc = Alloc; 14 | 15 | #[cfg(not(feature = "test_heap_size"))] 16 | #[global_allocator] 17 | static HEAP: LockedHeap = LockedHeap::empty(); 18 | 19 | #[panic_handler] 20 | #[allow(clippy::empty_loop)] 21 | fn panic(_info: &PanicInfo) -> ! { 22 | use crate::println; 23 | 24 | println!("panic ... {:?}", _info); 25 | x86_64::instructions::hlt(); 26 | loop {} 27 | } 28 | 29 | /// The initialization method for the global heap allocator. 30 | pub fn init_heap(heap_start: u64, heap_size: usize) { 31 | #[cfg(not(feature = "test_heap_size"))] 32 | unsafe { 33 | HEAP.lock().init(heap_start as *mut u8, heap_size); 34 | } 35 | #[cfg(feature = "test_heap_size")] 36 | td_benchmark::HeapProfiling::init(heap_start, heap_size); 37 | } 38 | -------------------------------------------------------------------------------- /td-shim/ResetVector/Ia32/Flat32ToFlat64.asm: -------------------------------------------------------------------------------- 1 | ;------------------------------------------------------------------------------ 2 | ; @file 3 | ; Transition from 32 bit flat protected mode into 64 bit flat protected mode 4 | ; 5 | ; Copyright (c) 2021, Intel Corporation. All rights reserved.
6 | ; SPDX-License-Identifier: BSD-2-Clause-Patent 7 | ; 8 | ;------------------------------------------------------------------------------ 9 | 10 | BITS 32 11 | 12 | ; 13 | ; Modified: EAX. ECX 14 | ; 15 | Transition32FlatTo64Flat: 16 | 17 | mov eax, cr4 18 | bts eax, 5 ; enable PAE 19 | mov cr4, eax 20 | 21 | mov ecx, ADDR_OF(TopLevelPageDirectory) 22 | add ecx, 0x1000 ; point to level-4 page table entry 23 | mov cr3, ecx 24 | mov eax, cr0 25 | bts eax, 31 ; set PG 26 | mov cr0, eax ; enable paging 27 | 28 | jmp LINEAR_CODE64_SEL:ADDR_OF(jumpTo64BitAndLandHere) 29 | BITS 64 30 | jumpTo64BitAndLandHere: 31 | 32 | debugShowPostCode POSTCODE_64BIT_MODE 33 | 34 | OneTimeCallRet Transition32FlatTo64Flat 35 | -------------------------------------------------------------------------------- /.github/workflows/oss-fuzz.yml: -------------------------------------------------------------------------------- 1 | name: oss-fuzz 2 | on: [pull_request] 3 | permissions: {} 4 | jobs: 5 | Fuzzing: 6 | runs-on: ubuntu-latest 7 | permissions: 8 | security-events: write 9 | steps: 10 | - name: Build Fuzzers 11 | id: build 12 | uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master 13 | with: 14 | oss-fuzz-project-name: 'td-shim' 15 | language: rust 16 | - name: Run Fuzzers 17 | uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master 18 | with: 19 | oss-fuzz-project-name: 'td-shim' 20 | language: rust 21 | fuzz-seconds: 600 22 | output-sarif: true 23 | - name: Upload Crash 24 | uses: actions/upload-artifact@v5 25 | if: failure() && steps.build.outcome == 'success' 26 | with: 27 | name: artifacts 28 | path: ./out/artifacts 29 | - name: Upload Sarif 30 | if: always() && steps.build.outcome == 'success' 31 | uses: github/codeql-action/upload-sarif@v4 32 | with: 33 | # Path to SARIF file relative to the root of the repository 34 | sarif_file: cifuzz-sarif/results.sarif 35 | checkout_path: cifuzz-sarif 36 | -------------------------------------------------------------------------------- /td-shim/fuzz/Cargo.toml: -------------------------------------------------------------------------------- 1 | 2 | [package] 3 | name = "td-shim-fuzz" 4 | version = "0.0.0" 5 | authors = ["Automatically generated"] 6 | publish = false 7 | edition = "2018" 8 | 9 | [package.metadata] 10 | cargo-fuzz = true 11 | 12 | [dependencies] 13 | libfuzzer-sys = {version = "0.4", optional = true } 14 | afl = {version = "*", optional = true } 15 | r-efi = "3.2.0" 16 | arbitrary = "=1.1.3" 17 | serde = "=1.0.198" 18 | 19 | [dependencies.td-shim] 20 | path = ".." 21 | 22 | # Prevent this from interfering with workspaces 23 | [workspace] 24 | members = ["."] 25 | 26 | [features] 27 | default = ["libfuzzer-sys"] 28 | fuzz = ["afl"] 29 | 30 | [[bin]] 31 | name = "afl_secure_boot_payload" 32 | path = "fuzz_targets/afl_secure_boot_payload.rs" 33 | test = false 34 | doc = false 35 | 36 | [[bin]] 37 | name = "afl_secure_boot_cfv" 38 | path = "fuzz_targets/afl_secure_boot_cfv.rs" 39 | test = false 40 | doc = false 41 | 42 | [[bin]] 43 | name = "secure_boot_payload" 44 | path = "fuzz_targets/secure_boot_payload.rs" 45 | test = false 46 | doc = false 47 | 48 | [[bin]] 49 | name = "secure_boot_cfv" 50 | path = "fuzz_targets/secure_boot_cfv.rs" 51 | test = false 52 | doc = false 53 | 54 | 55 | -------------------------------------------------------------------------------- /devtools/td-layout-config/README.md: -------------------------------------------------------------------------------- 1 | ## td-shim-layout-builder tool 2 | 3 | This tool is for td-payload and td-shim to generate runtime layout config(td-layout/src/runtime.rs). 4 | 5 | ### How to build 6 | 7 | ``` 8 | pushd devtools/td-layout-config 9 | cargo build 10 | popd 11 | ``` 12 | 13 | ### How to use 14 | 15 | - Help 16 | ``` 17 | ./target/debug/td-layout-config -h 18 | ``` 19 | 20 | - Generate memory layout source file for Linux payload from default `devtools/td-layout-config/config_memory_linux.json` file 21 | ``` 22 | ./target/debug/td-layout-config -t memory devtools/td-layout-config/config_memory_linux.json -o td-layout/src/runtime/linux.rs 23 | ``` 24 | 25 | - Generate memory layout source file for executable payload from default `devtools/td-layout-config/config_memory.json` file 26 | ``` 27 | ./target/debug/td-layout-config -t memory devtools/td-layout-config/config_memory_exec.json -o td-layout/src/runtime/exec.rs 28 | ``` 29 | 30 | - Generate image layout source file from default `devtools/td-layout-config/config_image.json` file 31 | ``` 32 | ./target/debug/td-layout-config -t image devtools/td-layout-config/config_image.json -o td-layout/src/build_time.rs 33 | ``` -------------------------------------------------------------------------------- /td-shim/src/bin/td-shim/asm/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2022, 2025 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | use core::arch::global_asm; 5 | 6 | global_asm!(include_str!("msr64.asm")); 7 | 8 | #[cfg(not(feature = "no-tdvmcall"))] 9 | global_asm!(include_str!("ap_loop.asm")); 10 | #[cfg(not(feature = "no-tdvmcall"))] 11 | global_asm!(include_str!("exception.asm")); 12 | 13 | #[cfg(feature = "no-tdvmcall")] 14 | global_asm!(include_str!("ap_loop_notdvmcall.asm")); 15 | #[cfg(feature = "no-tdvmcall")] 16 | global_asm!(include_str!("exception_notdvmcall.asm")); 17 | 18 | extern "C" { 19 | fn ap_relocated_func(); 20 | fn ap_relocated_func_end(); 21 | pub fn empty_exception_handler(); 22 | fn empty_exception_handler_end(); 23 | } 24 | 25 | pub fn ap_relocated_func_addr() -> u64 { 26 | ap_relocated_func as *const fn() as u64 27 | } 28 | 29 | pub fn ap_relocated_func_size() -> u64 { 30 | ap_relocated_func_end as *const fn() as u64 - ap_relocated_func as *const fn() as u64 31 | } 32 | 33 | pub fn empty_exception_handler_size() -> usize { 34 | empty_exception_handler_end as *const fn() as usize 35 | - empty_exception_handler as *const fn() as usize 36 | } 37 | -------------------------------------------------------------------------------- /devtools/td-layout-config/src/memory.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | use serde::Deserialize; 6 | 7 | use super::{layout::LayoutConfig, render}; 8 | 9 | #[derive(Deserialize, Debug, PartialEq)] 10 | struct Region { 11 | pub name: String, 12 | pub size: String, 13 | pub r#type: String, 14 | } 15 | 16 | #[derive(Deserialize, Debug)] 17 | struct MemoryConfig { 18 | memory_regions: Vec, 19 | } 20 | 21 | pub fn parse_memory(data: String) -> String { 22 | let memory_config = serde_json::from_str::(&data) 23 | .expect("Content is configuration file is invalid"); 24 | 25 | let mut memory_layout = LayoutConfig::new(0x0, 0x8000_0000); 26 | 27 | for region in memory_config.memory_regions { 28 | let size = parse_int::parse::(®ion.size).unwrap(); 29 | if region.r#type.as_str() == "Memory" { 30 | memory_layout.reserve_low(®ion.name, size, ®ion.r#type); 31 | } else { 32 | memory_layout.reserve_high(®ion.name, size, ®ion.r#type); 33 | } 34 | } 35 | 36 | render::render_memory(&memory_layout).expect("Render memory layout failed!") 37 | } 38 | -------------------------------------------------------------------------------- /td-shim-interface/src/td_uefi_pi/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2019 Intel Corporation 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //! UEFI Platform Initialization data structures and accessors. 16 | //! 17 | //! This crate defines constants and data structures defined by the 18 | //! [UEFI-PI Spec](https://uefi.org/sites/default/files/resources/PI_Spec_1_6.pdf) 19 | //! and needed by the `td-shim` project. It also provides functions to parse those data structures 20 | //! from raw data buffer. 21 | //! 22 | //! Constants and data structures defined by [UEFI PI Spec] are hosted by [crate::pi], functions 23 | //! to access them are hosted by [crate::fv] and [crate::hob]. 24 | 25 | pub mod fv; 26 | pub mod hob; 27 | pub mod pi; 28 | -------------------------------------------------------------------------------- /td-shim/fuzz/fuzz_targets/fuzzlib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | #![allow(unused)] 6 | use td_shim::secure_boot::{PayloadVerifier, VerifyErr}; 7 | 8 | pub fn fuzz_secure_boot_payload(buffer: &[u8]) { 9 | let cfv = include_bytes!("../seeds/secure_boot_cfv/cfv"); 10 | let verifier = PayloadVerifier::new(buffer, cfv); 11 | let trust_anchor = PayloadVerifier::get_trust_anchor(cfv); 12 | if verifier.is_ok() && trust_anchor.is_ok() { 13 | if verifier.as_ref().unwrap().verify().is_ok() { 14 | let svn = verifier.unwrap().get_payload_svn(); 15 | PayloadVerifier::get_payload_image(buffer); 16 | } 17 | } 18 | } 19 | 20 | pub fn fuzz_secure_boot_cfv(buffer: &[u8]) { 21 | let payload = include_bytes!("../seeds/secure_boot_payload/td-payload-signed"); 22 | let verifier = PayloadVerifier::new(payload, buffer); 23 | let trust_anchor = PayloadVerifier::get_trust_anchor(buffer); 24 | if verifier.is_ok() && trust_anchor.is_ok() { 25 | if verifier.as_ref().unwrap().verify().is_ok() { 26 | let svn = verifier.unwrap().get_payload_svn(); 27 | PayloadVerifier::get_payload_image(payload); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /td-payload/src/mm/layout.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | pub const DEFAULT_HEAP_SIZE: usize = 0x1000000; 6 | pub const DEFAULT_STACK_SIZE: usize = 0x800000; 7 | pub const DEFAULT_PAGE_TABLE_SIZE: usize = 0x800000; 8 | #[cfg(not(feature = "no-shared-mem"))] 9 | pub const DEFAULT_SHARED_MEMORY_SIZE: usize = 0x100000; 10 | #[cfg(feature = "cet-shstk")] 11 | pub const DEFAULT_SHADOW_STACK_SIZE: usize = 0x10000; 12 | 13 | #[derive(Debug)] 14 | pub struct RuntimeLayout { 15 | pub heap_size: usize, 16 | pub stack_size: usize, 17 | pub page_table_size: usize, 18 | #[cfg(not(feature = "no-shared-mem"))] 19 | pub shared_memory_size: usize, 20 | #[cfg(feature = "cet-shstk")] 21 | pub shadow_stack_size: usize, 22 | } 23 | 24 | impl Default for RuntimeLayout { 25 | fn default() -> Self { 26 | Self { 27 | heap_size: DEFAULT_HEAP_SIZE, 28 | stack_size: DEFAULT_STACK_SIZE, 29 | page_table_size: DEFAULT_PAGE_TABLE_SIZE, 30 | #[cfg(not(feature = "no-shared-mem"))] 31 | shared_memory_size: DEFAULT_SHARED_MEMORY_SIZE, 32 | #[cfg(feature = "cet-shstk")] 33 | shadow_stack_size: DEFAULT_SHADOW_STACK_SIZE, 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /td-payload/src/mm/page_table.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | use core::{alloc::Layout, ptr::NonNull}; 6 | use linked_list_allocator::LockedHeap; 7 | 8 | use super::SIZE_4K; 9 | 10 | static FRAME_ALLOCATOR: LockedHeap = LockedHeap::empty(); 11 | 12 | // Initialize the page table frame allocator 13 | pub fn init_pt_frame_allocator(start: u64, size: usize) { 14 | unsafe { 15 | FRAME_ALLOCATOR.lock().init(start as *mut u8, size); 16 | } 17 | } 18 | 19 | /// # Safety 20 | /// The caller needs to explicitly call the `free_pt_frame` function after use 21 | pub unsafe fn alloc_pt_frame() -> Option { 22 | let addr = FRAME_ALLOCATOR 23 | .lock() 24 | .allocate_first_fit(Layout::from_size_align(SIZE_4K, SIZE_4K).ok()?) 25 | .map(|ptr| ptr.as_ptr() as usize) 26 | .ok()?; 27 | 28 | core::slice::from_raw_parts_mut(addr as *mut u8, SIZE_4K).fill(0); 29 | 30 | Some(addr) 31 | } 32 | 33 | /// # Safety 34 | /// The caller needs to ensure the correctness of the addr 35 | pub unsafe fn free_pt_frame(addr: usize) { 36 | FRAME_ALLOCATOR.lock().deallocate( 37 | NonNull::new(addr as *mut u8).unwrap(), 38 | Layout::from_size_align(SIZE_4K, SIZE_4K).unwrap(), 39 | ); 40 | } 41 | -------------------------------------------------------------------------------- /.github/workflows/weekly-cargo-update.yml: -------------------------------------------------------------------------------- 1 | name: Weekly Cargo Update 2 | 3 | on: 4 | schedule: 5 | - cron: '0 12 * * 4' # Every Thursday at 12:00 UTC 6 | workflow_dispatch: 7 | 8 | env: 9 | RUST_TOOLCHAIN: 1.88.0 10 | 11 | jobs: 12 | update: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout code 16 | uses: actions/checkout@v4 17 | with: 18 | submodules: recursive 19 | 20 | - name: Install rust 21 | uses: dtolnay/rust-toolchain@master 22 | with: 23 | toolchain: ${{ env.RUST_TOOLCHAIN }} 24 | 25 | - name: Run preparation script 26 | run: ./sh_script/preparation.sh 27 | 28 | - name: Update Cargo dependencies 29 | run: cargo update 30 | 31 | - name: Create Pull Request 32 | uses: peter-evans/create-pull-request@v5 33 | with: 34 | token: ${{ secrets.GITHUB_TOKEN }} 35 | commit-message: "chore: weekly cargo update" 36 | title: "chore: weekly cargo update" 37 | body: | 38 | Weekly cargo update. 39 | 40 | Auto-generated by [create-pull-request][1] 41 | 42 | [1]: https://github.com/peter-evans/create-pull-request 43 | branch: cargo-update 44 | delete-branch: true 45 | add-paths: Cargo.lock 46 | -------------------------------------------------------------------------------- /devtools/td-layout-config/config_memory_linux.json: -------------------------------------------------------------------------------- 1 | { 2 | "memory_regions": [ 3 | { 4 | "name": "Bootloader", 5 | "size": "0x800000", 6 | "type": "Memory" 7 | }, 8 | { 9 | "name": "TdHob", 10 | "size": "0x20000", 11 | "type": "Memory" 12 | }, 13 | { 14 | "name": "UnacceptedMemoryBitmap", 15 | "size": "0x40000", 16 | "type": "Memory" 17 | }, 18 | { 19 | "name": "PayloadParameter", 20 | "size": "0x1000", 21 | "type": "Memory" 22 | }, 23 | { 24 | "name": "Payload", 25 | "size": "0x2000000", 26 | "type": "Memory" 27 | }, 28 | { 29 | "name": "EventLog", 30 | "size": "0x100000", 31 | "type": "Nvs" 32 | }, 33 | { 34 | "name": "RelocatedMailbox", 35 | "size": "0x2000", 36 | "type": "Nvs" 37 | }, 38 | { 39 | "name": "PayloadPageTable", 40 | "size": "0x20000", 41 | "type": "Reserved" 42 | }, 43 | { 44 | "name": "Acpi", 45 | "size": "0x100000", 46 | "type": "Acpi" 47 | } 48 | ] 49 | } -------------------------------------------------------------------------------- /doc/igvm_image.md: -------------------------------------------------------------------------------- 1 | # IGVM Image 2 | 3 | Support for IGVM (Independent Guest Virtual Machine) file format has been added to td-shim (rather than TDVF image). This use case only supports metadata-based image layout, it does not support TD_HOB. 4 | 5 | ## Build IGVM image 6 | 7 | Build TdShim image in native IGVM format. 8 | 9 | ``` 10 | cargo run -p td-layout-config --bin td-layout-config devtools/td-layout-config/config_image.json -t image -m devtools/td-layout-config/config_memory.json -o td-layout/src/build_time.rs 11 | 12 | cargo build -p td-shim --target x86_64-unknown-none --release --features=main,tdx 13 | 14 | cargo run -p td-shim-tools --bin td-shim-ld --features=linker -- target/x86_64-unknown-none/release/ResetVector.bin target/x86_64-unknown-none/release/td-shim -o target/release/final.igvm --image-format igvm 15 | ``` 16 | 17 | ## Firmware relocation 18 | 19 | By default, the FW payload is placed at GPA range [4G - fw_size, 4G]. This range is not usable on all VM stacks (e.g. Hyper-V creates GPA memory hole in VMs for range [3.5G, 4G]). The optional command-line argument -m for td-shim-layout-config specifies the metadata config file and loads FW after the PermMem section rather than beneath 4G. 20 | 21 | ## Reference 22 | 23 | * https://crates.io/crates/igvm_defs 24 | * https://github.com/microsoft/igvm -------------------------------------------------------------------------------- /td-payload/src/hob.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | use core::mem::size_of; 6 | use scroll::Pread; 7 | use spin::Once; 8 | use td_shim_interface::td_uefi_pi::{ 9 | hob::check_hob_integrity, 10 | pi::hob::{HandoffInfoTable, HOB_TYPE_HANDOFF}, 11 | }; 12 | 13 | use crate::Error; 14 | 15 | static HOB: Once<&'static [u8]> = Once::new(); 16 | 17 | pub fn init(ptr: u64) -> Result<&'static [u8], Error> { 18 | // Get the HOB size from PHIT 19 | let phit = 20 | unsafe { core::slice::from_raw_parts(ptr as *const u8, size_of::()) } 21 | .pread::(0) 22 | .map_err(|_| Error::ParseHob)?; 23 | 24 | // Sanity check 25 | let hob = if phit.header.r#type == HOB_TYPE_HANDOFF 26 | && phit.header.length as usize >= size_of::() 27 | { 28 | let size = phit.efi_end_of_hob_list - ptr; 29 | unsafe { core::slice::from_raw_parts(ptr as *const u8, size as usize) } 30 | } else { 31 | return Err(Error::ParseHob); 32 | }; 33 | 34 | let hob = check_hob_integrity(hob).ok_or(Error::ParseHob)?; 35 | HOB.call_once(|| hob); 36 | 37 | Ok(hob) 38 | } 39 | 40 | pub fn get_hob() -> Option<&'static [u8]> { 41 | HOB.get().copied() 42 | } 43 | -------------------------------------------------------------------------------- /td-shim-tools/src/bin/td-shim-tee-info-hash/readme.md: -------------------------------------------------------------------------------- 1 | # td-shim-tee-info-hash 2 | 3 | This tool can calculate MRTD(Implemented) and RTMR(WIP) values base upon inputs, e.g. shim binary, td hob, payload and payload parameter. And it can generate a tee hash info binary at last. 4 | 5 | A json format td manifest file is required and includes informations: attributes, xfam, mrconfigid, mrowner, mroenerconfig. Example [sample_manifest.json](sample_manifest.json) 6 | 7 | ## Tool Usage 8 | 9 | ``` 10 | USAGE: 11 | td-shim-tee-info-hash [OPTIONS] --image --manifest --seperator 0 12 | 13 | OPTIONS: 14 | -h, --help Print help information 15 | -i, --image shim binary file 16 | -l, --log-level logging level: [off, error, warn, info, debug, trace] [default: 17 | info] 18 | -m, --manifest td manifest 19 | -o, --out_bin output tee info hash binary 20 | -V, --version Print version information 21 | -s, --seperator The seperator to be extended into rtmr 22 | ``` 23 | 24 | example:
25 | ``` 26 | cargo run -p td-shim-tools --bin td-shim-tee-info-hash --features tee -- --manifest --image --out_bin --seperator 0 27 | ``` 28 | -------------------------------------------------------------------------------- /td-shim/ResetVector/Ia32/ResetVectorVtf0.asm: -------------------------------------------------------------------------------- 1 | ;------------------------------------------------------------------------------ 2 | ; @file 3 | ; First code executed by processor after resetting. 4 | ; 5 | ; Copyright (c) 2021, Intel Corporation. All rights reserved.
6 | ; SPDX-License-Identifier: BSD-2-Clause-Patent 7 | ; 8 | ;------------------------------------------------------------------------------ 9 | 10 | BITS 32 11 | 12 | ALIGN 16 13 | 14 | ; 15 | ; Pad the image size to 4k when page tables are in VTF0 16 | ; 17 | ; If the VTF0 image has page tables built in, then we need to make 18 | ; sure the end of VTF0 is 4k above where the page tables end. 19 | ; 20 | ; This is required so the page tables will be 4k aligned when VTF0 is 21 | ; located just below 0x100000000 (4GB) in the firmware device. 22 | ; 23 | TIMES (0x1000 - ($ - EndOfPageTables) - 0x20) DB 0 24 | 25 | dummy: 26 | jmp $ 27 | 28 | ALIGN 8 29 | 30 | DD 0 31 | 32 | ; 33 | ; The VTF signature 34 | ; 35 | ; VTF-0 means that the VTF (Volume Top File) code does not require 36 | ; any fixups. 37 | ; 38 | vtfSignature: 39 | DB 'V', 'T', 'F', 0 40 | 41 | ALIGN 16 42 | 43 | resetVector: 44 | ; 45 | ; Reset Vector 46 | ; 47 | ; This is where the processor will begin execution 48 | ; 49 | nop 50 | nop 51 | jmp Main32 52 | 53 | ALIGN 16 54 | 55 | endOfResetVector: 56 | -------------------------------------------------------------------------------- /td-shim/ResetVector/X64/PageTables.asm: -------------------------------------------------------------------------------- 1 | ;------------------------------------------------------------------------------ 2 | ; @file 3 | ; Emits Page Tables for 1:1 mapping of the addresses 0 - 0x100000000 (4GB) 4 | ; 5 | ; Copyright (c) 2021, Intel Corporation. All rights reserved.
6 | ; SPDX-License-Identifier: BSD-2-Clause-Patent 7 | ; 8 | ;------------------------------------------------------------------------------ 9 | 10 | BITS 64 11 | 12 | %define PGTBLS_OFFSET(x) ((x) - TopLevelPageDirectory) 13 | %define PGTBLS_ADDR(x) (ADDR_OF(TopLevelPageDirectory) + (x)) 14 | %define PDP(offset) (ADDR_OF(TopLevelPageDirectory) + (offset) + PAGE_PDP_ATTR) 15 | 16 | %define PTE_2MB(x) ((x << 21) + PAGE_2M_PDE_ATTR) 17 | 18 | TopLevelPageDirectory: 19 | 20 | ; 21 | ; Top level Page Directory Pointers (1 * 512GB entry) 22 | ; 23 | DQ PDP(0x1000) 24 | ; 25 | ; Next level Page Directory Pointers (4 * 1GB entries => 4GB) 26 | ; 27 | TIMES 511 DQ 0 28 | 29 | DQ PDP(0x2000) 30 | TIMES 511 DQ 0 31 | DQ PDP(0x3000) 32 | DQ PDP(0x4000) 33 | DQ PDP(0x5000) 34 | DQ PDP(0x6000) 35 | 36 | ; 37 | ; Page Table Entries (2048 * 2MB entries => 4GB) 38 | ; 39 | TIMES 508 DQ 0 40 | 41 | %assign i 0 42 | %rep 0x800 43 | DQ PTE_2MB(i) 44 | %assign i i+1 45 | %endrep 46 | 47 | EndOfPageTables: 48 | -------------------------------------------------------------------------------- /td-loader/fuzz/fuzz_targets/afl_pe.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | mod fuzzlib; 6 | use fuzzlib::fuzz_pe_loader; 7 | 8 | fn main() { 9 | #[cfg(not(feature = "fuzz"))] 10 | { 11 | // Command line input seed file location 12 | let mut args = std::env::args().skip(1); 13 | if let Some(arg) = args.next() { 14 | println!("{}", arg); 15 | let paths = std::path::Path::new(&arg); 16 | 17 | if paths.is_file() { 18 | let data = std::fs::read(&paths).expect("read crash file fail"); 19 | fuzz_pe_loader(data.as_slice()); 20 | } else if paths.is_dir() { 21 | for path in std::fs::read_dir(paths).unwrap() { 22 | let path = &path.unwrap().path(); 23 | if path.ends_with("README.txt") { 24 | continue; 25 | } 26 | 27 | let data = std::fs::read(path).expect("read crash file fail"); 28 | fuzz_pe_loader(data.as_slice()); 29 | } 30 | } else { 31 | println!("No valid file path entered"); 32 | } 33 | } 34 | } 35 | #[cfg(feature = "fuzz")] 36 | afl::fuzz!(|data: &[u8]| { 37 | fuzz_pe_loader(data); 38 | }); 39 | } 40 | -------------------------------------------------------------------------------- /td-loader/fuzz/fuzz_targets/afl_elf.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | mod fuzzlib; 6 | use fuzzlib::fuzz_elf_loader; 7 | 8 | fn main() { 9 | #[cfg(not(feature = "fuzz"))] 10 | { 11 | // Command line input seed file location 12 | let mut args = std::env::args().skip(1); 13 | if let Some(arg) = args.next() { 14 | println!("{}", arg); 15 | let paths = std::path::Path::new(&arg); 16 | 17 | if paths.is_file() { 18 | let data = std::fs::read(&paths).expect("read crash file fail"); 19 | fuzz_elf_loader(data.as_slice()); 20 | } else if paths.is_dir() { 21 | for path in std::fs::read_dir(paths).unwrap() { 22 | let path = &path.unwrap().path(); 23 | if path.ends_with("README.txt") { 24 | continue; 25 | } 26 | 27 | let data = std::fs::read(path).expect("read crash file fail"); 28 | fuzz_elf_loader(data.as_slice()); 29 | } 30 | } else { 31 | println!("No valid file path entered"); 32 | } 33 | } 34 | } 35 | #[cfg(feature = "fuzz")] 36 | afl::fuzz!(|data: &[u8]| { 37 | fuzz_elf_loader(data); 38 | }); 39 | } 40 | -------------------------------------------------------------------------------- /td-shim-interface/fuzz/Cargo.toml: -------------------------------------------------------------------------------- 1 | 2 | [package] 3 | name = "td-shim-interface-fuzz" 4 | version = "0.0.0" 5 | authors = ["Automatically generated"] 6 | publish = false 7 | edition = "2018" 8 | 9 | [package.metadata] 10 | cargo-fuzz = true 11 | 12 | [dependencies] 13 | libfuzzer-sys = {version = "0.4", optional = true } 14 | afl = {version = "*", optional = true } 15 | r-efi = "3.2.0" 16 | arbitrary = "=1.1.3" 17 | serde = "=1.0.198" 18 | 19 | [dependencies.td-shim-interface] 20 | path = ".." 21 | 22 | # Prevent this from interfering with workspaces 23 | [workspace] 24 | members = ["."] 25 | 26 | [features] 27 | default = ["libfuzzer-sys"] 28 | fuzz = ["afl"] 29 | 30 | [[bin]] 31 | name = "payload_parser" 32 | path = "fuzz_targets/payload_parser.rs" 33 | test = false 34 | doc = false 35 | 36 | [[bin]] 37 | name = "cfv_parser" 38 | path = "fuzz_targets/cfv_parser.rs" 39 | test = false 40 | doc = false 41 | 42 | [[bin]] 43 | name = "hob_parser" 44 | path = "fuzz_targets/hob_parser.rs" 45 | test = false 46 | doc = false 47 | 48 | [[bin]] 49 | name = "afl_hob_parser" 50 | path = "fuzz_targets/afl_hob_parser.rs" 51 | test = false 52 | doc = false 53 | 54 | [[bin]] 55 | name = "afl_payload_parser" 56 | path = "fuzz_targets/afl_payload_parser.rs" 57 | test = false 58 | doc = false 59 | 60 | [[bin]] 61 | name = "afl_cfv_parser" 62 | path = "fuzz_targets/afl_cfv_parser.rs" 63 | test = false 64 | doc = false 65 | -------------------------------------------------------------------------------- /td-payload/src/bin/example/stack.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2019 Intel Corporation 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // This function will cause page fault by memory protection. 15 | 16 | use core::arch::asm; 17 | use td_benchmark::StackProfiling; 18 | use td_payload::{mm::layout::DEFAULT_STACK_SIZE, println}; 19 | 20 | fn test_stack() { 21 | let mut a = [0u8; 0x3000]; 22 | for i in a.iter_mut() { 23 | *i = 0xcc; 24 | } 25 | let rsp: usize; 26 | unsafe { 27 | asm!("mov {}, rsp", out(reg) rsp); 28 | } 29 | println!("Testa RSP: {:x}\n", rsp); 30 | let b = vec![1u8, 2, 3, 4]; 31 | } 32 | 33 | pub fn bench_stack() { 34 | StackProfiling::init(0x5a5a_5a5a_5a5a_5a5a, 0x20_0000); 35 | test_stack(); 36 | let stack_usage = StackProfiling::stack_usage().unwrap(); 37 | println!("Stack bench result: {:#x}\n", stack_usage); 38 | } 39 | -------------------------------------------------------------------------------- /sh_script/docker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | FOLDER="" 5 | 6 | usage() { 7 | cat << EOM 8 | Usage: $(basename "$0") [OPTION]... 9 | -d Path of Dockerfile. 10 | EOM 11 | } 12 | 13 | error() { 14 | echo -e "\e[1;31mERROR: $*\e[0;0m" 15 | exit 1 16 | } 17 | 18 | process_args() { 19 | while getopts ":f:h" option; do 20 | case "$option" in 21 | f) FOLDER=$OPTARG;; 22 | h) usage 23 | exit 0 24 | ;; 25 | *) 26 | echo "Invalid option '-$OPTARG'" 27 | usage 28 | exit 1 29 | ;; 30 | esac 31 | done 32 | 33 | if [[ -z ${FOLDER} ]]; then 34 | error "Please specify the folder of where the Dockerfile is located through -f." 35 | fi 36 | 37 | if [[ ! -f "${FOLDER}/Dockerfile" ]]; then 38 | error "Dockerfile does not exist." 39 | fi 40 | } 41 | 42 | process_args $@ 43 | 44 | pushd ${FOLDER} 45 | 46 | # If the docker image does not exist, build the docker image 47 | set +e && docker image inspect tdshim.build.env:latest > /dev/null 2>&1 && set -e 48 | if [ $? != 0 ]; then 49 | docker build -t tdshim.build.env \ 50 | --build-arg https_proxy=$https_proxy \ 51 | --build-arg http_proxy=$http_proxy \ 52 | . 53 | fi 54 | 55 | popd 56 | 57 | # Run the docker image 58 | docker run -it --rm tdshim.build.env 59 | -------------------------------------------------------------------------------- /td-shim-interface/fuzz/fuzz_targets/afl_cfv_parser.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | mod fuzzlib; 6 | use fuzzlib::fuzz_cfv_parser; 7 | 8 | fn main() { 9 | #[cfg(not(feature = "fuzz"))] 10 | { 11 | // Command line input seed file location 12 | let mut args = std::env::args().skip(1); 13 | if let Some(arg) = args.next() { 14 | println!("{}", arg); 15 | let paths = std::path::Path::new(&arg); 16 | 17 | if paths.is_file() { 18 | let data = std::fs::read(&paths).expect("read crash file fail"); 19 | fuzz_cfv_parser(data.as_slice()); 20 | } 21 | else if paths.is_dir() { 22 | for path in std::fs::read_dir(paths).unwrap() { 23 | let path = &path.unwrap().path(); 24 | if path.ends_with("README.txt") { 25 | continue; 26 | } 27 | 28 | let data = std::fs::read(path).expect("read crash file fail"); 29 | fuzz_cfv_parser(data.as_slice()); 30 | } 31 | } 32 | else { 33 | println!("No valid file path entered"); 34 | } 35 | } 36 | } 37 | #[cfg(feature = "fuzz")] 38 | afl::fuzz!(|data: &[u8]| { 39 | fuzz_cfv_parser(data); 40 | }); 41 | } 42 | -------------------------------------------------------------------------------- /td-shim-interface/fuzz/fuzz_targets/afl_hob_parser.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | mod fuzzlib; 6 | use fuzzlib::fuzz_hob_parser; 7 | 8 | fn main() { 9 | #[cfg(not(feature = "fuzz"))] 10 | { 11 | // Command line input seed file location 12 | let mut args = std::env::args().skip(1); 13 | if let Some(arg) = args.next() { 14 | println!("{}", arg); 15 | let paths = std::path::Path::new(&arg); 16 | 17 | if paths.is_file() { 18 | let data = std::fs::read(&paths).expect("read crash file fail"); 19 | fuzz_hob_parser(data.as_slice()); 20 | } 21 | else if paths.is_dir() { 22 | for path in std::fs::read_dir(paths).unwrap() { 23 | let path = &path.unwrap().path(); 24 | if path.ends_with("README.txt") { 25 | continue; 26 | } 27 | 28 | let data = std::fs::read(path).expect("read crash file fail"); 29 | fuzz_hob_parser(data.as_slice()); 30 | } 31 | } 32 | else { 33 | println!("No valid file path entered"); 34 | } 35 | } 36 | } 37 | #[cfg(feature = "fuzz")] 38 | afl::fuzz!(|data: &[u8]| { 39 | fuzz_hob_parser(data); 40 | }); 41 | } 42 | -------------------------------------------------------------------------------- /devtools/dev_container/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | 3 | # Adding rust binaries to PATH. 4 | ENV PATH="$PATH:/root/.cargo/bin" 5 | ENV CC=clang 6 | ENV AR=llvm-ar 7 | 8 | # Install all required packages in one go to optimize the image 9 | # https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#run 10 | # DEBIAN_FRONTEND is set for tzdata. 11 | RUN apt-get update && \ 12 | DEBIAN_FRONTEND="noninteractive" apt-get install --no-install-recommends -y \ 13 | build-essential ca-certificates curl gcc git libssl-dev pkg-config ssh \ 14 | clang llvm nasm \ 15 | screen expect \ 16 | # cleanup 17 | && apt-get clean && rm -rf /var/lib/apt/lists/* 18 | 19 | # Install rustup and a fixed version of Rust. 20 | RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.88.0 21 | RUN rustup component add rust-src 22 | RUN rustup component add llvm-tools-preview 23 | COPY cargo_config /root/.cargo/config 24 | RUN cargo install cargo-xbuild 25 | 26 | # Install fuzzing tools 27 | # For more information, please see doc/fuzzing.md. 28 | RUN cargo install cargo-afl 29 | RUN cargo install cargo-fuzz --version 0.12.0 30 | 31 | # Install rudra 32 | RUN rustup component add rustc-dev 33 | RUN cargo install sccache 34 | RUN set -eux; \ 35 | git clone https://github.com/sslab-gatech/Rudra.git; \ 36 | cd Rudra; \ 37 | ./install-release.sh; 38 | 39 | RUN git clone https://github.com/confidential-containers/td-shim.git 40 | -------------------------------------------------------------------------------- /devtools/td-layout-config/config_memory.json: -------------------------------------------------------------------------------- 1 | { 2 | "memory_regions": [ 3 | { 4 | "name": "Bootloader", 5 | "size": "0x800000", 6 | "type": "Memory" 7 | }, 8 | { 9 | "name": "TdHob", 10 | "size": "0x20000", 11 | "type": "Memory" 12 | }, 13 | { 14 | "name": "UnacceptedMemoryBitmap", 15 | "size": "0x40000", 16 | "type": "Memory" 17 | }, 18 | { 19 | "name": "KernelParameter", 20 | "size": "0x1000", 21 | "type": "Memory" 22 | }, 23 | { 24 | "name": "Kernel", 25 | "size": "0x2000000", 26 | "type": "Memory" 27 | }, 28 | { 29 | "name": "EventLog", 30 | "size": "0x100000", 31 | "type": "Nvs" 32 | }, 33 | { 34 | "name": "RelocatedMailbox", 35 | "size": "0x2000", 36 | "type": "Nvs" 37 | }, 38 | { 39 | "name": "PayloadPageTable", 40 | "size": "0x20000", 41 | "type": "Reserved" 42 | }, 43 | { 44 | "name": "Payload", 45 | "size": "0x2000000", 46 | "type": "Reserved" 47 | }, 48 | { 49 | "name": "Acpi", 50 | "size": "0x100000", 51 | "type": "Acpi" 52 | } 53 | ] 54 | } -------------------------------------------------------------------------------- /td-shim/fuzz/fuzz_targets/afl_secure_boot_cfv.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | mod fuzzlib; 6 | use fuzzlib::fuzz_secure_boot_cfv; 7 | 8 | fn main() { 9 | #[cfg(not(feature = "fuzz"))] 10 | { 11 | // Command line input seed file location 12 | let mut args = std::env::args().skip(1); 13 | if let Some(arg) = args.next() { 14 | println!("{}", arg); 15 | let paths = std::path::Path::new(&arg); 16 | 17 | if paths.is_file() { 18 | let data = std::fs::read(&paths).expect("read crash file fail"); 19 | fuzz_secure_boot_cfv(data.as_slice()); 20 | } 21 | else if paths.is_dir() { 22 | for path in std::fs::read_dir(paths).unwrap() { 23 | let path = &path.unwrap().path(); 24 | if path.ends_with("README.txt") { 25 | continue; 26 | } 27 | 28 | let data = std::fs::read(path).expect("read crash file fail"); 29 | fuzz_secure_boot_cfv(data.as_slice()); 30 | } 31 | } 32 | else { 33 | println!("No valid file path entered"); 34 | } 35 | } 36 | } 37 | #[cfg(feature = "fuzz")] 38 | afl::fuzz!(|data: &[u8]| { 39 | fuzz_secure_boot_cfv(data); 40 | }); 41 | } 42 | -------------------------------------------------------------------------------- /td-shim-interface/fuzz/fuzz_targets/afl_payload_parser.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | mod fuzzlib; 6 | use fuzzlib::fuzz_payload_parser; 7 | 8 | fn main() { 9 | #[cfg(not(feature = "fuzz"))] 10 | { 11 | // Command line input seed file location 12 | let mut args = std::env::args().skip(1); 13 | if let Some(arg) = args.next() { 14 | println!("{}", arg); 15 | let paths = std::path::Path::new(&arg); 16 | 17 | if paths.is_file() { 18 | let data = std::fs::read(&paths).expect("read crash file fail"); 19 | fuzz_payload_parser(data.as_slice()); 20 | } 21 | else if paths.is_dir() { 22 | for path in std::fs::read_dir(paths).unwrap() { 23 | let path = &path.unwrap().path(); 24 | if path.ends_with("README.txt") { 25 | continue; 26 | } 27 | 28 | let data = std::fs::read(path).expect("read crash file fail"); 29 | fuzz_payload_parser(data.as_slice()); 30 | } 31 | } 32 | else { 33 | println!("No valid file path entered"); 34 | } 35 | } 36 | } 37 | #[cfg(feature = "fuzz")] 38 | afl::fuzz!(|data: &[u8]| { 39 | fuzz_payload_parser(data); 40 | }); 41 | } 42 | -------------------------------------------------------------------------------- /td-exception/src/asm/handler.asm: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2024 Intel Corporation 2 | # SPDX-License-Identifier: BSD-2-Clause-Patent 3 | 4 | # Mask the exception vectors that push an error code on the stack 5 | .equ EXCEPTION_ERROR_CODE_MASK, 0x20027d00 6 | 7 | .section .text 8 | interrupt_handler_entry: 9 | push rax 10 | push rcx 11 | push rdx 12 | push rdi 13 | push rsi 14 | push r8 15 | push r9 16 | push r10 17 | push r11 18 | push rbx 19 | push rbp 20 | push r12 21 | push r13 22 | push r14 23 | push r15 24 | 25 | mov rdi, rsp 26 | call generic_interrupt_handler 27 | 28 | pop r15 29 | pop r14 30 | pop r13 31 | pop r12 32 | pop rbp 33 | pop rbx 34 | pop r11 35 | pop r10 36 | pop r9 37 | pop r8 38 | pop rsi 39 | pop rdi 40 | pop rdx 41 | pop rcx 42 | pop rax 43 | 44 | # vector number and error code 45 | add rsp, 16 46 | 47 | iretq 48 | 49 | .align 32 50 | .global interrupt_handler_table 51 | interrupt_handler_table: 52 | i = 0 53 | .rept 256 54 | .align 32 55 | .if i > 31 || ((EXCEPTION_ERROR_CODE_MASK >> i) & 1) == 0 56 | push 0 57 | .endif 58 | push i 59 | jmp interrupt_handler_entry 60 | i = i + 1 61 | .endr 62 | 63 | ret 64 | -------------------------------------------------------------------------------- /td-shim/fuzz/fuzz_targets/afl_secure_boot_payload.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | mod fuzzlib; 6 | use fuzzlib::fuzz_secure_boot_payload; 7 | 8 | fn main() { 9 | #[cfg(not(feature = "fuzz"))] 10 | { 11 | // Command line input seed file location 12 | let mut args = std::env::args().skip(1); 13 | if let Some(arg) = args.next() { 14 | println!("{}", arg); 15 | let paths = std::path::Path::new(&arg); 16 | 17 | if paths.is_file() { 18 | let data = std::fs::read(&paths).expect("read crash file fail"); 19 | fuzz_secure_boot_payload(data.as_slice()); 20 | } 21 | else if paths.is_dir() { 22 | for path in std::fs::read_dir(paths).unwrap() { 23 | let path = &path.unwrap().path(); 24 | if path.ends_with("README.txt") { 25 | continue; 26 | } 27 | 28 | let data = std::fs::read(path).expect("read crash file fail"); 29 | fuzz_secure_boot_payload(data.as_slice()); 30 | } 31 | } 32 | else { 33 | println!("No valid file path entered"); 34 | } 35 | } 36 | } 37 | #[cfg(feature = "fuzz")] 38 | afl::fuzz!(|data: &[u8]| { 39 | fuzz_secure_boot_payload(data); 40 | }); 41 | } 42 | -------------------------------------------------------------------------------- /.github/workflows/devtools.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | paths-ignore: 4 | - "**.md" 5 | pull_request: 6 | paths-ignore: 7 | - "**.md" 8 | workflow_dispatch: 9 | 10 | name: Devtools 11 | 12 | env: 13 | AS: nasm 14 | RUST_TOOLCHAIN: 1.88.0 15 | TOOLCHAIN_PROFILE: minimal 16 | 17 | jobs: 18 | devtools_install: 19 | name: Install 20 | runs-on: ${{ matrix.host_os }} 21 | timeout-minutes: 30 22 | 23 | strategy: 24 | matrix: 25 | host_os: 26 | - ubuntu-latest 27 | - windows-2022 28 | steps: 29 | - name: Install LLVM and Clang 30 | uses: KyleMayes/install-llvm-action@v2 31 | with: 32 | version: "10.0" 33 | directory: ${{ runner.temp }}/llvm 34 | 35 | - name: install NASM 36 | uses: ilammy/setup-nasm@v1 37 | 38 | - name: Checkout sources 39 | uses: actions/checkout@v6 40 | with: 41 | submodules: recursive 42 | 43 | - name: Install stable toolchain 44 | uses: dtolnay/rust-toolchain@master 45 | with: 46 | toolchain: ${{ env.RUST_TOOLCHAIN }} 47 | 48 | - name: Preparation work 49 | run: make preparation 50 | 51 | - name: Install devtools 52 | run: make install-devtools 53 | 54 | - name: Set PATH 55 | shell: bash 56 | run: | 57 | echo "$GITHUB_WORKSPACE/devtools/bin" >> $GITHUB_PATH 58 | 59 | - name: Exec Runner Server 60 | run: test-runner-server -h 61 | -------------------------------------------------------------------------------- /td-shim-interface/src/td_uefi_pi/pi/boot_mode.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2019 Intel Corporation 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //! Boot mode defined in [UEFI-PI Spec](https://uefi.org/sites/default/files/resources/PI_Spec_1_6.pdf), 16 | //! section "4.3 Boot Mode Services". 17 | pub type BootMode = u32; 18 | 19 | pub const BOOT_WITH_FULL_CONFIGURATION: u32 = 0x00; 20 | pub const BOOT_WITH_MINIMAL_CONFIGURATION: u32 = 0x01; 21 | pub const BOOT_ASSUMING_NO_CONFIGURATION_CHANGES: u32 = 0x02; 22 | pub const BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS: u32 = 0x03; 23 | pub const BOOT_WITH_DEFAULT_SETTINGS: u32 = 0x04; 24 | pub const BOOT_ON_S4_RESUME: u32 = 0x05; 25 | pub const BOOT_ON_S5_RESUME: u32 = 0x06; 26 | pub const BOOT_WITH_MFG_MODE_SETTINGS: u32 = 0x07; 27 | pub const BOOT_ON_S2_RESUME: u32 = 0x10; 28 | pub const BOOT_ON_S3_RESUME: u32 = 0x11; 29 | pub const BOOT_ON_FLASH_UPDATE: u32 = 0x12; 30 | pub const BOOT_IN_RECOVERY_MODE: u32 = 0x20; 31 | -------------------------------------------------------------------------------- /.github/workflows/fuzz.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | paths-ignore: 4 | - "**.md" 5 | pull_request: 6 | paths-ignore: 7 | - "**.md" 8 | workflow_dispatch: 9 | 10 | name: Fuzzing Test 11 | 12 | env: 13 | AS: nasm 14 | AR_x86_64_unknown_none: llvm-ar 15 | CC_x86_64_unknown_none: clang 16 | RUST_TOOLCHAIN: nightly 17 | TOOLCHAIN_PROFILE: minimal 18 | 19 | jobs: 20 | test: 21 | name: Fuzzing Test 22 | 23 | strategy: 24 | fail-fast: false 25 | matrix: 26 | os: [ubuntu-latest] 27 | runs-on: ${{ matrix.os }} 28 | timeout-minutes: 30 29 | 30 | steps: 31 | - uses: actions/checkout@v6 32 | with: 33 | submodules: recursive 34 | - uses: dtolnay/rust-toolchain@stable 35 | with: 36 | toolchain: ${{ env.RUST_TOOLCHAIN }} 37 | components: rust-src, llvm-tools-preview 38 | 39 | - name: install NASM 40 | uses: ilammy/setup-nasm@v1 41 | 42 | - name: Install AFL (Linux) 43 | run: cargo +nightly install cargo-afl 44 | if: runner.os == 'Linux' 45 | 46 | - name: Install Cargo-Fuzz (Linux) 47 | run: cargo +nightly install cargo-fuzz 48 | if: runner.os == 'Linux' 49 | 50 | - name: Preparation work 51 | run: bash sh_script/preparation.sh 52 | 53 | - name: Run all afl fuzzing test cases (Linux) 54 | run: make afl-test 55 | 56 | - name: Run all libfuzzer fuzzing test cases (Linux) 57 | run: make libfuzzer-test 58 | -------------------------------------------------------------------------------- /tests/test-td-payload/src/testtdve.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | #![no_std] 6 | extern crate alloc; 7 | 8 | use crate::lib::{TestCase, TestResult}; 9 | use alloc::string::String; 10 | 11 | use serde::{Deserialize, Serialize}; 12 | 13 | /** 14 | * Test #VE 15 | */ 16 | #[derive(Debug, Serialize, Deserialize)] 17 | pub struct TdVE { 18 | pub name: String, 19 | pub result: TestResult, 20 | pub run: bool, 21 | } 22 | 23 | /** 24 | * Implement the TestCase trait for TdVE 25 | */ 26 | impl TestCase for TdVE { 27 | /** 28 | * set up the Test case of TdVE 29 | */ 30 | fn setup(&mut self) { 31 | self.result = TestResult::Fail; 32 | } 33 | 34 | /** 35 | * run the test case 36 | * io read Century of RTC 37 | */ 38 | fn run(&mut self) { 39 | unsafe { x86::io::outb(0x70, 0x32) }; 40 | 41 | let century = unsafe { x86::io::inb(0x71) }; 42 | log::info!("Current century is {}\n", century); 43 | 44 | self.result = TestResult::Pass; 45 | } 46 | 47 | /** 48 | * Tear down the test case. 49 | */ 50 | fn teardown(&mut self) {} 51 | 52 | /** 53 | * get the name of the test case. 54 | */ 55 | fn get_name(&mut self) -> String { 56 | String::from(&self.name) 57 | } 58 | 59 | /** 60 | * get the result of the test case. 61 | */ 62 | fn get_result(&mut self) -> TestResult { 63 | self.result 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /.github/workflows/trivy.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | 6 | name: trivy 7 | 8 | on: 9 | push: 10 | branches: [ "main" ] 11 | pull_request: 12 | # The branches below must be a subset of the branches above 13 | branches: [ "main" ] 14 | schedule: 15 | - cron: '0 0 * * 0' 16 | 17 | permissions: 18 | contents: read 19 | 20 | jobs: 21 | build: 22 | permissions: 23 | contents: read # for actions/checkout to fetch code 24 | security-events: write # for github/codeql-action/upload-sarif to upload SARIF results 25 | actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status 26 | name: Build 27 | runs-on: "ubuntu-latest" 28 | steps: 29 | - name: Checkout code 30 | uses: actions/checkout@v6 31 | with: 32 | submodules: recursive 33 | 34 | - name: Run Trivy vulnerability scanner 35 | uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 36 | with: 37 | scan-type: 'fs' 38 | scanners: 'vuln' 39 | format: 'sarif' 40 | output: 'trivy-results.sarif' 41 | severity: 'CRITICAL,HIGH' 42 | 43 | - name: Upload Trivy scan results to GitHub Security tab 44 | uses: github/codeql-action/upload-sarif@v4 45 | with: 46 | sarif_file: 'trivy-results.sarif' 47 | -------------------------------------------------------------------------------- /td-payload/src/bin/example/mp.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2019 Intel Corporation 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // This function will cause page fault by memory protection. 15 | 16 | use alloc::vec::Vec; 17 | 18 | pub fn mp_test() { 19 | static mut INS: [u8; 2] = [0xEB, 0xFE]; 20 | 21 | // Test NX on payload data sections 22 | unsafe { 23 | let address = INS.as_ptr() as u64; 24 | log::info!("NX test address: {:x}\n", address); 25 | let nx = &address as *const u64 as *const fn(); 26 | (*nx)(); 27 | } 28 | 29 | // Test NX on heap 30 | unsafe { 31 | let ins_heap: Vec = vec![0xEB, 0xFE]; 32 | let address = ins_heap.as_ptr() as u64; 33 | log::info!("NX test address: {:x}\n", address); 34 | let nx = &address as *const u64 as *const fn(); 35 | (*nx)(); 36 | } 37 | 38 | // Test WP on a hardcode payload code section (PE) 39 | unsafe { 40 | let ptr_to_wp: *mut u32 = 0x403_3000 as *mut core::ffi::c_void as *mut u32; 41 | *ptr_to_wp = 0x1000; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /td-shim-tools/src/bin/td-shim-sign-payload/README.md: -------------------------------------------------------------------------------- 1 | ## Payload signing 2 | 3 | This tool accepts **DER encoded PKCS8 format** private key file as input. It generates signed payload binary which 4 | contains verify header, public key and signature. 5 | 6 | ### Generate Key 7 | 8 | 1. ECDSA NIST P384 9 | 10 | Run below command to generate a DER encoded PKCS8 formate EC private key file (on Linux). 11 | ``` 12 | openssl genpkey -algorithm EC \ 13 | -pkeyopt ec_paramgen_curve:P-384 \ 14 | -pkeyopt ec_param_enc:named_curve \ 15 | -outform der -out ecdsa-p384-private.der 16 | 17 | openssl pkcs8 -topk8 -nocrypt -inform der -in ecdsa-p384-private.der -outform der -out ecdsa-p384-private.pk8 18 | ``` 19 | 20 | 2. RSA 3072 21 | 22 | Run below command to generate a DER encoded PKCS8 formate RSA private key file (on Linux). 23 | ``` 24 | openssl genpkey -algorithm RSA \ 25 | -pkeyopt rsa_keygen_bits:3072 \ 26 | -pkeyopt rsa_keygen_pubexp:65537 | \ 27 | openssl pkcs8 -topk8 -nocrypt -outform der > rsa-3072-private.pk8 28 | ``` 29 | 30 | ### Sign 31 | Clear environment varibles CC and AR at first: 32 | ``` 33 | set CC= 34 | set AR= 35 | ``` 36 | 37 | Then run the tool: 38 | ``` 39 | cargo run -p td-shim-tools --bin td-shim-sign-payload -- [-A {signing_algorithm}] [-o output] {private_key_file} {payload_file} {payload_version} {payload_svn} 40 | ``` 41 | 42 | For example: 43 | ``` 44 | 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/td-payload 1 1 45 | ``` 46 | -------------------------------------------------------------------------------- /td-shim-tools/etc/sample_metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "Sections": [ 3 | { 4 | "DataOffset": "0x82000", 5 | "RawDataSize": "0xF7E000", 6 | "MemoryAddress": "0xFF082000", 7 | "MemoryDataSize": "0xF7E000", 8 | "Type": "BFV", 9 | "Attributes": "0x1" 10 | }, 11 | { 12 | "DataOffset": "0x0", 13 | "RawDataSize": "0x40000", 14 | "MemoryAddress": "0xFF000000", 15 | "MemoryDataSize": "0x40000", 16 | "Type": "CFV", 17 | "Attributes": "0x0" 18 | }, 19 | { 20 | "DataOffset": "0x0", 21 | "RawDataSize": "0x0", 22 | "MemoryAddress": "0xFF042000", 23 | "MemoryDataSize": "0x20000", 24 | "Type": "TempMem", 25 | "Attributes": "0x0" 26 | }, 27 | { 28 | "DataOffset": "0x0", 29 | "RawDataSize": "0x0", 30 | "MemoryAddress": "0xFF062000", 31 | "MemoryDataSize": "0x20000", 32 | "Type": "TempMem", 33 | "Attributes": "0x0" 34 | }, 35 | { 36 | "DataOffset": "0x0", 37 | "RawDataSize": "0x0", 38 | "MemoryAddress": "0x800000", 39 | "MemoryDataSize": "0x20000", 40 | "Type": "TD_HOB", 41 | "Attributes": "0x0" 42 | }, 43 | { 44 | "DataOffset": "0x0", 45 | "RawDataSize": "0x0", 46 | "MemoryAddress": "0xFF040000", 47 | "MemoryDataSize": "0x1000", 48 | "Type": "TempMem", 49 | "Attributes": "0x0" 50 | } 51 | ] 52 | } -------------------------------------------------------------------------------- /devtools/td-layout-config/src/template/memory.jinja: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 - {{now() | date(format="%Y")}} Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | // Auto-generated by `td-layout-config`, do not edit manually. 6 | 7 | /* 8 | Memory Layout Example 9 | Top of Low Memory: {{tolm|format_hex}} 10 | {%- for m in memory_regions | reverse%} 11 | {{true|format_layout_border}} <- {{m.region.end|format_hex}} 12 | |{{m.name_screaming_snake_case | format_name}}| ({{m.region.end - m.region.start|format_hex}}) {{m.region.end - m.region.start|filesizeformat}} 13 | {%- endfor %} 14 | {{true|format_layout_border}} <- {{memory_regions_base|format_hex}} 15 | Total Usage: {{total_usage|format_hex}} ({{total_usage|filesizeformat}}) 16 | */ 17 | 18 | pub const TOTAL_USAGE: usize = {{total_usage|format_hex}}; // ({{total_usage|filesizeformat}}) 19 | 20 | // Runtime Layout Configuration 21 | {%- for m in memory_regions %} 22 | {%- if m.entry_type != entry_type_filter %} 23 | {%- if m.tolm == false %} 24 | pub const {{m.name_screaming_snake_case}}_BASE: usize = {{m.region.start | format_hex }}; 25 | {%- endif %} 26 | pub const {{m.name_screaming_snake_case}}_SIZE: usize = {{m.region.end - m.region.start | format_hex }}; // {{m.region.end - m.region.start|filesizeformat}} 27 | {%- endif %} 28 | {%- endfor %} 29 | 30 | pub const MEMORY_LAYOUT_CONFIG: &[(&str, usize, &str)] = &[ 31 | // (name of memory region, region size, region type) 32 | {%- for m in memory_regions %} 33 | {%- if m.entry_type != entry_type_filter %} 34 | ("{{m.name}}", {{m.region.end - m.region.start | format_hex }}, "{{m.entry_type}}"), 35 | {%- endif %} 36 | {%- endfor %} 37 | ]; 38 | -------------------------------------------------------------------------------- /tests/test-td-payload/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "test-td-payload" 3 | version = "0.1.0" 4 | description = "Run TDX hardware specific unit test cases inside a VM" 5 | repository = "https://github.com/confidential-containers/td-shim" 6 | homepage = "https://github.com/confidential-containers" 7 | license = "BSD-2-Clause-Patent" 8 | edition = "2018" 9 | 10 | [dependencies] 11 | spin = "0.9.2" 12 | r-efi = "3.2.0" 13 | linked_list_allocator = "0.10.4" 14 | log = "0.4.13" 15 | cc-measurement = { path = "../../cc-measurement" } 16 | td-shim-interface = { path = "../../td-shim-interface" } 17 | tdx-tdcall = { path = "../../tdx-tdcall" , optional = true } 18 | td-logger = { path = "../../td-logger" } 19 | td-layout = { path = "../../td-layout" } 20 | td-paging = { path = "../../td-paging" } 21 | scroll = { version = "0.10.0", default-features = false, features = ["derive"]} 22 | serde = { version = "1.0", default-features = false, features = ["derive"]} 23 | serde_json = { version = "1.0", default-features = false, features = ["alloc"] } 24 | x86 = { version = "0.47.0" } 25 | ring = { version = "0.17.14", default-features = false, features = ["alloc"] } 26 | td-shim = { path = "../../td-shim" } 27 | td-payload = { path = "../../td-payload", features = ["tdx","cet-shstk","stack-guard"] } 28 | zerocopy = { version = "0.7.31", features = ["derive"] } 29 | 30 | minicov = { version = "0.2", default-features = false, optional = true } 31 | 32 | [dependencies.lazy_static] 33 | version = "1.0" 34 | features = ["spin_no_std"] 35 | 36 | [package.metadata.bootloader] 37 | map-physical-memory = true 38 | 39 | [features] 40 | tdx = ["tdx-tdcall", "td-logger/tdx"] 41 | main = [] 42 | coverage = ["minicov"] 43 | -------------------------------------------------------------------------------- /tests/test-td-payload/src/testcetibt.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | #![no_std] 6 | extern crate alloc; 7 | 8 | use crate::lib::{TestCase, TestResult}; 9 | use alloc::string::String; 10 | 11 | use serde::{Deserialize, Serialize}; 12 | 13 | /** 14 | * Test functionality of CET indirect branch tracking of `td-payload` 15 | */ 16 | #[derive(Debug, Serialize, Deserialize)] 17 | pub struct TestCetIbt { 18 | pub name: String, 19 | pub result: TestResult, 20 | pub run: bool, 21 | } 22 | 23 | /** 24 | * Implement the TestCase trait for TestCetIbt 25 | */ 26 | impl TestCase for TestCetIbt { 27 | /** 28 | * set up the Test case of TestCetIbt 29 | */ 30 | fn setup(&mut self) { 31 | self.result = TestResult::Fail; 32 | } 33 | 34 | /** 35 | * run the test case 36 | * unable to resume execution after triggering control flow exception 37 | * this function will never return 38 | */ 39 | fn run(&mut self) { 40 | unsafe { test_without_endbr() } 41 | } 42 | 43 | /** 44 | * Tear down the test case. 45 | */ 46 | fn teardown(&mut self) {} 47 | 48 | /** 49 | * get the name of the test case. 50 | */ 51 | fn get_name(&mut self) -> String { 52 | String::from(&self.name) 53 | } 54 | 55 | /** 56 | * get the result of the test case. 57 | */ 58 | fn get_result(&mut self) -> TestResult { 59 | self.result 60 | } 61 | } 62 | 63 | extern "sysv64" { 64 | fn test_without_endbr(); 65 | } 66 | 67 | core::arch::global_asm!( 68 | " 69 | .global test_without_endbr 70 | test_without_endbr: 71 | ret", 72 | ); 73 | -------------------------------------------------------------------------------- /td-shim/ResetVector/X64/TestHob.asm: -------------------------------------------------------------------------------- 1 | ;------------------------------------------------------------------------------ 2 | ; @file 3 | ; Emits Page Tables for 1:1 mapping of the addresses 0 - 0x100000000 (4GB) 4 | ; 5 | ; Copyright (c) 2021, Intel Corporation. All rights reserved.
6 | ; SPDX-License-Identifier: BSD-2-Clause-Patent 7 | ; 8 | ;------------------------------------------------------------------------------ 9 | 10 | KvmTestHob: 11 | DW EFI_HOB_TYPE_HANDOFF 12 | DW 0x38 13 | DD 0 14 | DD 9 15 | DD 0 ; boot-mode 16 | DQ 0 17 | DQ 0 18 | DQ 0 19 | DQ 0 20 | DQ ADDR_OF(KvmTestHobEnd) 21 | DW EFI_HOB_TYPE_GUID_EXTENSION 22 | DW 0x1c 23 | DD 0 24 | ; 0xc4a567a3, 0xc8a5, 0x44ea, 0xac, 0x78, 0xa4, 0xc3, 0x8b, 0x85, 0x49, 0xd0 Name 25 | DD 0xc4a567a3 26 | DW 0xc8a5, 0x44ea 27 | DB 0xac, 0x78, 0xa4, 0xc3, 0x8b, 0x85, 0x49, 0xd0 28 | DD 0 ; Feature 29 | DW EFI_HOB_TYPE_RESOURCE_DESCRIPTOR 30 | DW 0x30 31 | DD 0 32 | TIMES 16 DB 0 ; Owner 33 | DD EFI_RESOURCE_SYSTEM_MEMORY ; ResourceType 34 | DD EFI_LOW_MEM_ATTR ; ResourceAttribute 35 | DQ 0x100000 ; PhysicalStart 36 | DQ 0x7FF00000 ; ResourceLength 37 | DW EFI_HOB_TYPE_RESOURCE_DESCRIPTOR 38 | DW 0x30 39 | DD 0 40 | TIMES 16 DB 0 ; Owner 41 | DD EFI_RESOURCE_SYSTEM_MEMORY ; ResourceType 42 | DD EFI_LOW_MEM_ATTR ; ResourceAttribute 43 | DQ 0x0 ; PhysicalStart 44 | DQ 0xa0000 ; ResourceLength 45 | DW EFI_HOB_TYPE_RESOURCE_DESCRIPTOR 46 | DW 0x30 47 | DD 0 48 | TIMES 16 DB 0 ; Owner 49 | DD EFI_RESOURCE_SYSTEM_MEMORY ; ResourceType 50 | DD EFI_LOW_MEM_ATTR ; ResourceAttribute 51 | DQ 0x1a00000000 ; PhysicalStart 52 | DQ 0x80000000 ; ResourceLength 53 | DW EFI_HOB_TYPE_END_OF_HOB_LIST 54 | DW 0x08 55 | DD 0 56 | KvmTestHobEnd: 57 | -------------------------------------------------------------------------------- /devtools/td-layout-config/src/template/image.jinja: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 - {{now() | date(format="%Y")}} Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | // Auto-generated by `td-layout-config`, do not edit manually. 6 | 7 | /* 8 | Image Layout 9 | {%-for i in image_regions%} 10 | {{true|format_layout_border}} <- {{i.region.start|format_hex}} 11 | |{{i.name_screaming_snake_case | format_name}}| ({{i.region.end - i.region.start|format_hex}}) {{i.region.end - i.region.start|filesizeformat}} 12 | {%-endfor%} 13 | {{true|format_layout_border}} <- {{image_size|format_hex}} 14 | Image size: {{image_size|format_hex}} ({{image_size|filesizeformat}}) 15 | */ 16 | 17 | // Image Layout Configuration 18 | {%for i in image_regions%} 19 | pub const TD_SHIM_{{i.name_screaming_snake_case}}_OFFSET: u32 = {{i.region.start | format_hex }}; 20 | pub const TD_SHIM_{{i.name_screaming_snake_case}}_SIZE: u32 = {{i.region.end - i.region.start | format_hex }}; // {{i.region.end - i.region.start|filesizeformat}} 21 | {%endfor%} 22 | // Offset when Loading into Memory 23 | pub const TD_SHIM_FIRMWARE_BASE: u32 = {{memory_offset | format_hex }}; 24 | pub const TD_SHIM_FIRMWARE_SIZE: u32 = {{image_size | format_hex }}; 25 | 26 | // TD_SHIM_SEC_INFO_OFFSET equals to firmware size - metadata pointer offset - 27 | // OVMF GUID table size - SEC Core information size. 28 | pub const TD_SHIM_SEC_CORE_INFO_OFFSET: u32 = {{sec_info_offset | format_hex }}; 29 | pub const TD_SHIM_SEC_CORE_INFO_BASE: u32 = {{memory_offset + sec_info_offset | format_hex }}; 30 | 31 | // Base Address after Loaded into Memory 32 | {%-for i in image_regions%} 33 | pub const TD_SHIM_{{i.name_screaming_snake_case}}_BASE: u32 = {{memory_offset + i.region.start | format_hex }}; 34 | {%-endfor%} 35 | -------------------------------------------------------------------------------- /tdx-tdcall/src/asm/tdcall_emu.asm: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 Intel Corporation 2 | # SPDX-License-Identifier: BSD-2-Clause-Patent 3 | 4 | .section .text 5 | .equ USE_TDX_EMULATION, 1 6 | .equ number_of_regs_pushed, 8 7 | .equ number_of_parameters, 4 8 | 9 | .equ first_variable_on_stack_offset, (number_of_regs_pushed * 8) + (number_of_parameters * 8) + 8 10 | .equ second_variable_on_stack_offset, first_variable_on_stack_offset + 8 11 | 12 | # TdCall ( 13 | # UINT64 Leaf, 14 | # UINT64 P1, 15 | # UINT64 P2, 16 | # UINT64 P3, 17 | # UINT64 Results, 18 | # ) 19 | .global td_call 20 | td_call: 21 | endbr64 22 | # tdcall_push_regs 23 | push rbp 24 | mov rbp, rsp 25 | push r15 26 | push r14 27 | push r13 28 | push r12 29 | push rbx 30 | push rsi 31 | push rdi 32 | 33 | mov rax, rcx 34 | mov rcx, rdx 35 | mov rdx, r8 36 | mov r8, r9 37 | 38 | # tdcall 39 | .if USE_TDX_EMULATION != 0 40 | vmcall 41 | .else 42 | .byte 0x66,0x0f,0x01,0xcc 43 | .endif 44 | 45 | # exit if tdcall reports failure. 46 | test rax, rax 47 | jnz exit 48 | 49 | # test if caller wanted results 50 | mov r12, [rsp + first_variable_on_stack_offset] 51 | test r12, r12 52 | jz exit 53 | mov [r12], rcx 54 | mov [r12+8], rdx 55 | mov [r12+16], r8 56 | mov [r12+24], r9 57 | mov [r12+32], r10 58 | mov [r12+40], r11 59 | exit: 60 | # tdcall_pop_regs 61 | pop rdi 62 | pop rsi 63 | pop rbx 64 | pop r12 65 | pop r13 66 | pop r14 67 | pop r15 68 | pop rbp 69 | 70 | ret 71 | -------------------------------------------------------------------------------- /td-payload/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Intel Corporation 2 | // Copyright (c) 2022 Alibaba Cloud 3 | // 4 | // SPDX-License-Identifier: BSD-2-Clause-Patent 5 | 6 | #![cfg_attr(not(test), no_std)] 7 | #![cfg_attr(not(test), no_main)] 8 | 9 | use console::CONSOLE; 10 | use core::fmt::{Arguments, Write}; 11 | 12 | extern crate alloc; 13 | 14 | pub mod acpi; 15 | pub mod arch; 16 | pub mod console; 17 | pub mod hob; 18 | pub mod mm; 19 | 20 | /// The entry point of Payload 21 | /// 22 | /// For the x86_64-unknown-uefi target, the entry point name is 'efi_main' 23 | /// For the x86_64-unknown-none target, the entry point name is '_start' 24 | #[no_mangle] 25 | #[cfg(all(not(test), feature = "start"))] 26 | #[cfg_attr(target_os = "uefi", export_name = "efi_main")] 27 | pub extern "C" fn _start(hob: u64, _payload: u64) -> ! { 28 | use mm::layout::RuntimeLayout; 29 | extern "C" { 30 | fn main(); 31 | } 32 | 33 | let layout = RuntimeLayout::default(); 34 | 35 | arch::init::pre_init( 36 | hob, 37 | &layout, 38 | #[cfg(not(feature = "no-shared-mem"))] 39 | false, 40 | ); 41 | arch::init::init(&layout, main); 42 | } 43 | 44 | pub fn console(args: Arguments) { 45 | CONSOLE 46 | .lock() 47 | .write_fmt(args) 48 | .expect("Failed to write console"); 49 | } 50 | 51 | #[macro_export] 52 | macro_rules! print { 53 | ($($arg:tt)*) => ($crate::console(format_args!($($arg)*))); 54 | } 55 | 56 | #[macro_export] 57 | macro_rules! println { 58 | ($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*))); 59 | } 60 | 61 | #[derive(Debug)] 62 | pub enum Error { 63 | ParseHob, 64 | GetMemoryMap, 65 | GetAcpiTable, 66 | SetupMemoryLayout, 67 | SetupPageTable, 68 | } 69 | -------------------------------------------------------------------------------- /tests/test-td-payload/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | #![no_std] 6 | extern crate alloc; 7 | 8 | use alloc::boxed::Box; 9 | use alloc::string::String; 10 | use alloc::vec::Vec; 11 | use serde::{Deserialize, Serialize}; 12 | use td_payload::print; 13 | 14 | #[derive(Debug, Copy, Clone, Serialize, Deserialize)] 15 | pub enum TestResult { 16 | Pass, 17 | Fail, 18 | None, 19 | } 20 | 21 | pub trait TestCase { 22 | fn setup(&mut self); 23 | fn run(&mut self); 24 | fn teardown(&mut self); 25 | fn get_name(&mut self) -> String; 26 | fn get_result(&mut self) -> TestResult; 27 | } 28 | 29 | pub struct TestSuite { 30 | pub testsuite: Vec>, 31 | pub passed_cases: u32, 32 | pub failed_cases: u32, 33 | } 34 | 35 | impl TestSuite { 36 | pub fn run(&mut self) { 37 | for tc in self.testsuite.iter_mut() { 38 | print!("[Test: {}]\n", String::from(tc.get_name())); 39 | tc.setup(); 40 | tc.run(); 41 | tc.teardown(); 42 | 43 | let res = tc.get_result(); 44 | match res { 45 | TestResult::Pass => { 46 | self.passed_cases += 1; 47 | print!("[Test: {0}] - Pass\n", tc.get_name()); 48 | } 49 | TestResult::Fail => { 50 | self.failed_cases += 1; 51 | print!("[Test: {0}] - Fail\n", tc.get_name()); 52 | } 53 | TestResult::None => { 54 | print!("[Test: {0}] - Skip\n", tc.get_name()); 55 | } 56 | } 57 | 58 | print!("---------------------------------------------\n") 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /td-shim-tools/src/read_file.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | use anyhow::*; 6 | use log::debug; 7 | use std::fs; 8 | use std::io::Read; 9 | use std::io::Seek; 10 | use td_shim_interface::metadata::TDX_METADATA_OFFSET; 11 | 12 | fn read_from_file(file: &mut std::fs::File, pos: u64, buffer: &mut [u8]) -> Result<()> { 13 | debug!("Read at pos={0:X}, len={1:X}", pos, buffer.len()); 14 | let _pos = std::io::SeekFrom::Start(pos); 15 | file.seek(_pos)?; 16 | file.read_exact(buffer)?; 17 | debug!("{:X?}", buffer); 18 | Ok(()) 19 | } 20 | 21 | pub fn read_from_binary_file(filename: &String) -> Result> { 22 | let f = fs::File::open(filename); 23 | if f.is_err() { 24 | bail!("Problem opening the file"); 25 | } 26 | 27 | let mut file = f.unwrap(); 28 | 29 | let file_metadata = fs::metadata(filename); 30 | if file_metadata.is_err() { 31 | bail!("Problem read file meatadata"); 32 | } 33 | 34 | let file_metadata = file_metadata.unwrap(); 35 | let file_size = file_metadata.len(); 36 | 37 | // Then read 4 bytes at the pos of [file_len - 0x20] 38 | // This is the offset of TdxMetadata 39 | let mut metadata_buffer: Vec = vec![0; 4]; 40 | if read_from_file( 41 | &mut file, 42 | file_size - TDX_METADATA_OFFSET as u64, 43 | &mut metadata_buffer, 44 | ) 45 | .is_err() 46 | { 47 | bail!("Failed to read metadata offset"); 48 | } 49 | 50 | // Read whole binary file and return binary string 51 | let mut buffer: Vec = vec![0; file_size as usize]; 52 | if read_from_file(&mut file, 0, &mut buffer).is_err() { 53 | bail!("Failed to read tdshim binary file"); 54 | } 55 | Ok(buffer) 56 | } 57 | -------------------------------------------------------------------------------- /tests/test-td-payload/src/teststackguard.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | #![no_std] 6 | extern crate alloc; 7 | 8 | use crate::lib::{TestCase, TestResult}; 9 | use alloc::string::String; 10 | 11 | use serde::{Deserialize, Serialize}; 12 | 13 | /** 14 | * Test functionality of stack guard (guard page) of `td-payload` 15 | */ 16 | #[derive(Debug, Serialize, Deserialize)] 17 | pub struct TestStackGuard { 18 | pub name: String, 19 | pub result: TestResult, 20 | pub run: bool, 21 | } 22 | 23 | /** 24 | * Implement the TestCase trait for TestStackGuard 25 | */ 26 | impl TestCase for TestStackGuard { 27 | /** 28 | * set up the Test case of TestStackGuard 29 | */ 30 | fn setup(&mut self) { 31 | self.result = TestResult::Fail; 32 | } 33 | 34 | /** 35 | * run the test case 36 | * unable to resume execution after triggering page fault exception 37 | * this function will never return 38 | */ 39 | fn run(&mut self) { 40 | // Recursive call, ending with a page fault exception 41 | unsafe { 42 | recursive(); 43 | } 44 | } 45 | 46 | /** 47 | * Tear down the test case. 48 | */ 49 | fn teardown(&mut self) {} 50 | 51 | /** 52 | * get the name of the test case. 53 | */ 54 | fn get_name(&mut self) -> String { 55 | String::from(&self.name) 56 | } 57 | 58 | /** 59 | * get the result of the test case. 60 | */ 61 | fn get_result(&mut self) -> TestResult { 62 | self.result 63 | } 64 | } 65 | 66 | extern "C" { 67 | fn recursive(); 68 | } 69 | 70 | core::arch::global_asm!( 71 | " 72 | .global recursive 73 | recursive: 74 | call recursive 75 | ret", 76 | ); 77 | -------------------------------------------------------------------------------- /devtools/test-runner-client/src/serial.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2019 Intel Corporation 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use core::fmt::Write; 16 | use spin::{Lazy, Mutex}; 17 | use uart_16550::SerialPort; 18 | use x86_64::instructions::interrupts; 19 | 20 | pub static SERIAL1: Lazy> = Lazy::new(|| { 21 | let mut serial_port = unsafe { SerialPort::new(0x3F8) }; 22 | serial_port.init(); 23 | Mutex::new(serial_port) 24 | }); 25 | 26 | #[doc(hidden)] 27 | pub fn _print(args: ::core::fmt::Arguments) { 28 | interrupts::without_interrupts(|| { 29 | SERIAL1 30 | .lock() 31 | .write_fmt(args) 32 | .expect("Printing to serial failed"); 33 | }); 34 | } 35 | 36 | /// Prints to the host through the serial interface. 37 | #[macro_export] 38 | macro_rules! serial_print { 39 | ($($arg:tt)*) => { 40 | $crate::serial::_print(format_args!($($arg)*)); 41 | }; 42 | } 43 | 44 | /// Prints to the host through the serial interface, appending a newline. 45 | #[macro_export] 46 | macro_rules! serial_println { 47 | () => ($crate::serial_print!("\n")); 48 | ($fmt:expr) => ($crate::serial_print!(concat!($fmt, "\n"))); 49 | ($fmt:expr, $($arg:tt)*) => ($crate::serial_print!( 50 | concat!($fmt, "\n"), $($arg)*)); 51 | } 52 | -------------------------------------------------------------------------------- /doc/test_heap_stack_usage.md: -------------------------------------------------------------------------------- 1 | ## Test runtime heap and stack usage. 2 | 3 | ### td-benchmark framework structure. 4 | 5 | Feature `benchmark` is enabled by default. The `benchmark` feature is added to be compatible with those codes that use benchmarks code. 6 | 7 | All code for testing heap and stack are located in [dev/tools/td-benchmark](../devtools/td-benchmark). 8 | 9 | [heap.rs](../devtools/td-benchmark/src/heap.rs) provide a global allocator which contains a function to obtain heap usage size. 10 | 11 | [stack.rs](../devtools/td-benchmark/src/stack.rs) provide functions to get the stack usage size. 12 | 13 | ### How to test heap and stack usage library. 14 | 15 | 0. Add `td-benchmark` crate into `Cargo.toml`. For example: 16 | ```Cargo.toml 17 | td-benchmark = { path = "devtools/td-benchmark", default-features = false} 18 | ``` 19 | 20 | ### How to get runtime heap usage. 21 | 22 | 1. Register `td_benchmark:Alloc` as global allocator 23 | 24 | ``` 25 | #[global_allocator] 26 | static ALLOC: td_benchmark::Alloc = td_benchmark::Alloc; 27 | ``` 28 | 29 | 2. `global_allocator` must be initialized before using heap. 30 | ``` 31 | HeapProfiling::init(heap_start, heap_size); 32 | ``` 33 | 34 | 3. Call `heap_usage` at the point you interest. 35 | ``` 36 | let stack_usage = HeapProfiling::heap_usage().unwrap(); 37 | ``` 38 | 39 | ### How to get runtime stack usage. 40 | 41 | 1. Mark stack with special mark value. 42 | 43 | ``` 44 | StackProfiling::init(0x5a5a_5a5a_5a5a_5a5a, 0x1A0000); 45 | ``` 46 | Note: Stack size should be choose carefully. 47 | 48 | 2. Get stack usage at the point you interest. 49 | ``` 50 | let stack_usage = StackProfiling::stack_usage().unwrap(); 51 | ``` 52 | 53 | ### Limitation 54 | 55 | This method is limited by execution coverage. If some functions are not reached at runtime, then no data is collected. 56 | -------------------------------------------------------------------------------- /tests/test-td-payload/src/testcetshstk.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | #![no_std] 6 | extern crate alloc; 7 | 8 | use crate::lib::{TestCase, TestResult}; 9 | use alloc::string::String; 10 | 11 | use serde::{Deserialize, Serialize}; 12 | 13 | /** 14 | * Test functionality of CET shadow stack of `td-payload` 15 | */ 16 | #[derive(Debug, Serialize, Deserialize)] 17 | pub struct TestCetShstk { 18 | pub name: String, 19 | pub result: TestResult, 20 | pub run: bool, 21 | } 22 | 23 | /** 24 | * Implement the TestCase trait for TestCetShstk 25 | */ 26 | impl TestCase for TestCetShstk { 27 | /** 28 | * set up the Test case of TestCetShstk 29 | */ 30 | fn setup(&mut self) { 31 | self.result = TestResult::Fail; 32 | } 33 | 34 | /** 35 | * run the test case 36 | * unable to resume execution after triggering control flow exception 37 | * this function will never return 38 | */ 39 | fn run(&mut self) { 40 | // Recursive call, ending with a page fault exception 41 | unsafe { 42 | tamper_return_address(); 43 | } 44 | } 45 | 46 | /** 47 | * Tear down the test case. 48 | */ 49 | fn teardown(&mut self) {} 50 | 51 | /** 52 | * get the name of the test case. 53 | */ 54 | fn get_name(&mut self) -> String { 55 | String::from(&self.name) 56 | } 57 | 58 | /** 59 | * get the result of the test case. 60 | */ 61 | fn get_result(&mut self) -> TestResult { 62 | self.result 63 | } 64 | } 65 | 66 | extern "sysv64" { 67 | fn tamper_return_address(); 68 | } 69 | 70 | core::arch::global_asm!( 71 | " 72 | .global tamper_return_address 73 | tamper_return_address: 74 | mov rax, rsp 75 | mov dword ptr [rax], 0xfefefefe 76 | ret", 77 | ); 78 | -------------------------------------------------------------------------------- /td-payload/src/acpi.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | use alloc::vec::Vec; 6 | use scroll::Pread; 7 | use spin::Once; 8 | use td_shim::TD_ACPI_TABLE_HOB_GUID; 9 | use td_shim_interface::td_uefi_pi::{ 10 | hob as hob_lib, 11 | pi::hob::{GuidExtension, Header, HOB_TYPE_END_OF_HOB_LIST, HOB_TYPE_GUID_EXTENSION}, 12 | }; 13 | 14 | use crate::Error; 15 | 16 | pub type AcpiTable = &'static [u8]; 17 | 18 | static ACPI_TBALES: Once> = Once::new(); 19 | 20 | pub fn init_acpi_tables(hob: &'static [u8]) -> Result<(), Error> { 21 | let mut acpi_tables = Vec::new(); 22 | let mut offset = 0; 23 | 24 | loop { 25 | let block = &hob[offset..]; 26 | let header: Header = block.pread(0).map_err(|_| Error::ParseHob)?; 27 | 28 | match header.r#type { 29 | HOB_TYPE_GUID_EXTENSION => { 30 | let header: GuidExtension = block.pread(0).map_err(|_| Error::ParseHob)?; 31 | if &header.name == TD_ACPI_TABLE_HOB_GUID.as_bytes() { 32 | acpi_tables.push(parse_guided_hob(block)?); 33 | } 34 | } 35 | HOB_TYPE_END_OF_HOB_LIST => { 36 | // End of the hob list, break the loop 37 | break; 38 | } 39 | _ => {} 40 | } 41 | offset = hob_lib::align_to_next_hob_offset(hob.len(), offset, header.length) 42 | .ok_or(Error::ParseHob)?; 43 | } 44 | 45 | ACPI_TBALES.call_once(|| acpi_tables); 46 | 47 | Ok(()) 48 | } 49 | 50 | fn parse_guided_hob(guided_hob: &'static [u8]) -> Result { 51 | let acpi_table = hob_lib::get_guid_data(guided_hob).ok_or(Error::ParseHob)?; 52 | 53 | Ok(acpi_table) 54 | } 55 | 56 | pub fn get_acpi_tables() -> Option<&'static [AcpiTable]> { 57 | ACPI_TBALES.get().map(|tables| tables.as_slice()) 58 | } 59 | -------------------------------------------------------------------------------- /td-shim/ResetVector/Ia32/ValidateBfvBase.asm: -------------------------------------------------------------------------------- 1 | ;------------------------------------------------------------------------------ 2 | ; @file 3 | ; Validates the Boot Firmware Volume (BFV) base address 4 | ; 5 | ; Copyright (c) 2021, Intel Corporation. All rights reserved.
6 | ; SPDX-License-Identifier: BSD-2-Clause-Patent 7 | ; 8 | ;------------------------------------------------------------------------------ 9 | 10 | ;#define EFI_FIRMWARE_FILE_SYSTEM2_GUID \ 11 | ; { 0x8c8ce578, 0x8a3d, 0x4f1c, { 0x99, 0x35, 0x89, 0x61, 0x85, 0xc3, 0x2d, 0xd3 } } 12 | %define FFS_GUID_DWORD0 0x8c8ce578 13 | %define FFS_GUID_DWORD1 0x4f1c8a3d 14 | %define FFS_GUID_DWORD2 0x61893599 15 | %define FFS_GUID_DWORD3 0xd32dc385 16 | 17 | BITS 32 18 | 19 | ; 20 | ; Modified: EAX 21 | ; Preserved: EDI, ESP 22 | ; 23 | ; @param[out] EBP Address of Boot Firmware Volume (BFV) 24 | ; 25 | Flat32ValidateBfv: 26 | 27 | mov eax, TOP_OF_BFV 28 | ; 29 | ; Check FFS GUID 30 | ; 31 | cmp dword [eax + 0x10], FFS_GUID_DWORD0 32 | jne BfvHeaderNotFound 33 | cmp dword [eax + 0x14], FFS_GUID_DWORD1 34 | jne BfvHeaderNotFound 35 | cmp dword [eax + 0x18], FFS_GUID_DWORD2 36 | jne BfvHeaderNotFound 37 | cmp dword [eax + 0x1c], FFS_GUID_DWORD3 38 | jne BfvHeaderNotFound 39 | 40 | ; 41 | ; Check FV Length 42 | ; 43 | cmp dword [eax + 0x24], 0 44 | jne BfvHeaderNotFound 45 | 46 | ; 47 | ; Return BFV in ebp 48 | ; 49 | mov ebp, eax 50 | 51 | debugShowPostCode POSTCODE_BFV_FOUND 52 | 53 | OneTimeCallRet Flat32ValidateBfv 54 | 55 | BfvHeaderNotFound: 56 | ; 57 | ; Hang if the SEC entry point was not found 58 | ; 59 | debugShowPostCode POSTCODE_BFV_NOT_FOUND 60 | 61 | ; 62 | ; 0xbfbfbfbf in the EAX & EBP registers helps signal what failed 63 | ; for debugging purposes. 64 | ; 65 | mov eax, 0xBFBFBFBF 66 | mov ebp, eax 67 | jmp $ 68 | -------------------------------------------------------------------------------- /td-layout/src/mailbox.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | use core::ptr::slice_from_raw_parts; 6 | use scroll::{Pread, Pwrite}; 7 | 8 | #[repr(C)] 9 | #[derive(Pwrite, Pread)] 10 | pub struct TdxMpWakeupMailbox { 11 | pub command: u16, 12 | pub rsvd: u16, 13 | pub apic_id: u32, 14 | pub wakeup_vector: u64, 15 | } 16 | 17 | impl Default for TdxMpWakeupMailbox { 18 | fn default() -> Self { 19 | TdxMpWakeupMailbox { 20 | command: 0, 21 | rsvd: 0, 22 | apic_id: 0xffff_ffff, 23 | wakeup_vector: 0, 24 | } 25 | } 26 | } 27 | 28 | impl TdxMpWakeupMailbox { 29 | pub fn as_bytes(&self) -> &[u8] { 30 | unsafe { 31 | &*slice_from_raw_parts( 32 | self as *const TdxMpWakeupMailbox as *const u8, 33 | core::mem::size_of::(), 34 | ) 35 | } 36 | } 37 | } 38 | 39 | #[cfg(test)] 40 | mod tests { 41 | use super::*; 42 | use core::mem::size_of; 43 | use memoffset::offset_of; 44 | 45 | #[test] 46 | fn ensure_data_struct_size() { 47 | assert_eq!(size_of::(), 16); 48 | assert_eq!(offset_of!(TdxMpWakeupMailbox, command), 0); 49 | assert_eq!(offset_of!(TdxMpWakeupMailbox, apic_id), 4); 50 | assert_eq!(offset_of!(TdxMpWakeupMailbox, wakeup_vector), 8); 51 | } 52 | 53 | #[test] 54 | fn test_tdx_mp_wakeup_mailbox() { 55 | let default_data: [u8; 16] = [ 56 | 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 57 | 0x00, 0x00, 58 | ]; 59 | let mail_box = TdxMpWakeupMailbox::default(); 60 | let mail_box_data = mail_box.as_bytes(); 61 | assert_eq!(mail_box_data, &default_data); 62 | 63 | let mail_box: TdxMpWakeupMailbox = default_data.pread(0).unwrap(); 64 | assert_eq!(mail_box.as_bytes(), &default_data); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /.github/workflows/integration.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | paths-ignore: 4 | - "**.md" 5 | pull_request: 6 | paths-ignore: 7 | - "**.md" 8 | workflow_dispatch: 9 | 10 | name: Integration Test 11 | 12 | env: 13 | AS: nasm 14 | RUST_TOOLCHAIN: nightly-2023-12-31 15 | TOOLCHAIN_PROFILE: minimal 16 | 17 | jobs: 18 | system_compile: 19 | name: Run Integration Test 20 | runs-on: ${{ matrix.host_os }} 21 | timeout-minutes: 30 22 | 23 | strategy: 24 | matrix: 25 | host_os: 26 | - ubuntu-latest 27 | # - windows-2019 28 | steps: 29 | # Install first since it's needed to build NASM 30 | - name: Install LLVM and Clang 31 | uses: KyleMayes/install-llvm-action@v2 32 | with: 33 | version: "10.0" 34 | directory: ${{ runner.temp }}/llvm 35 | 36 | - name: install NASM 37 | uses: ilammy/setup-nasm@v1 38 | 39 | - name: Checkout sources 40 | uses: actions/checkout@v6 41 | with: 42 | submodules: recursive 43 | 44 | - name: Install toolchain 45 | uses: dtolnay/rust-toolchain@master 46 | with: 47 | toolchain: ${{ env.RUST_TOOLCHAIN }} 48 | components: rust-src, llvm-tools-preview 49 | 50 | - name: Run cargo install cargo-xbuild 51 | run: cargo install cargo-xbuild 52 | 53 | # install QEMU 54 | - name: Install QEMU (Linux) 55 | run: sudo apt update && sudo apt install qemu-system-x86 56 | if: runner.os == 'Linux' 57 | - name: Install QEMU (Windows) 58 | run: | 59 | choco install qemu --version 2021.5.5 60 | echo "$Env:Programfiles\qemu" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append 61 | if: runner.os == 'Windows' 62 | shell: pwsh 63 | - name: "Print QEMU Version" 64 | run: qemu-system-x86_64 --version 65 | 66 | - name: Preparation Work 67 | run: make preparation 68 | 69 | # - name: Run Tests 70 | # run: make integration-test 71 | -------------------------------------------------------------------------------- /devtools/td-benchmark/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | //! This crate provides heap profiling and stack profiling capabilities 6 | //! only for TD environment. 7 | //! 8 | //! # Features 9 | //! - benchmark this features enabled by default. 10 | //! with this feature enabled, the customer `ALLOCATOR` is 11 | //! registered to `#[global_allocator]` automatic. It can 12 | //! be disabled by adding `--default-features = false`. 13 | //! 14 | //! # Stack usage testing 15 | //! 16 | //! `StackProfiling` provide functions for stack usage testing 17 | //! 18 | //! # Example 19 | //! 20 | //! ```no_run 21 | //! use td_benchmark::StackProfiling; 22 | //! StackProfiling::init(0x5a5a_5a5a_5a5a_5a5a, 0x1A0000); 23 | //! 24 | //! { 25 | //! let a = [0;1024]; 26 | //! // insert calls like this at the point of interest. 27 | //! let stack_usage = StackProfiling::stack_usage().unwrap(); 28 | //! } 29 | //! ``` 30 | //! 31 | //! # Heap usage testing 32 | //! 33 | //! `HeapProfiling` provide functions for stack usage testing 34 | //! 35 | //! Use `HeapProfiling` need disable `benchmark` feature by adding `default-features = false` 36 | //! For example in Cargo.toml: 37 | //! 38 | //! td-benchmark = { path = "path_to/td-shim/devtools/td-benchmark", default-features = false, optional = true} 39 | //! 40 | //! ```no_std 41 | //! // adding global allocator `Alloc` 42 | //! #[global_allocator] 43 | //! static ALLOC: td_benchmark::Alloc = td_benchmark::Alloc; 44 | //! 45 | //! // Then add the following code to your code to initialize alloc before allocation. 46 | //! // heap start heap end is the location where the heap is created. 47 | //! HeapProfiling::init(heap_start, heap_size); 48 | //! 49 | //! 50 | //! // call `heap_usage` at the point your interest. 51 | //! let stack_usage = HeapProfiling::heap_usage().unwrap(); 52 | //! ``` 53 | //! 54 | #![no_std] 55 | 56 | extern crate alloc; 57 | 58 | mod heap; 59 | mod stack; 60 | 61 | pub use heap::{Alloc, HeapProfiling}; 62 | pub use stack::StackProfiling; 63 | -------------------------------------------------------------------------------- /tests/test-td-payload/src/testiorw8.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | #![no_std] 6 | extern crate alloc; 7 | 8 | use crate::lib::{TestCase, TestResult}; 9 | use alloc::string::String; 10 | use core::ffi::c_void; 11 | use tdx_tdcall::tdx; 12 | 13 | use serde::{Deserialize, Serialize}; 14 | 15 | /** 16 | * Test tdvmcall io read/write 8 17 | */ 18 | #[derive(Debug, Serialize, Deserialize)] 19 | pub struct Tdiorw8 { 20 | pub name: String, 21 | pub result: TestResult, 22 | pub run: bool, 23 | } 24 | 25 | /** 26 | * Implement the TestCase trait for Tdiorw8 27 | */ 28 | impl TestCase for Tdiorw8 { 29 | /** 30 | * set up the Test case of Tdiorw8 31 | */ 32 | fn setup(&mut self) { 33 | self.result = TestResult::Fail; 34 | } 35 | 36 | /** 37 | * run the test case 38 | * io read Century of RTC 39 | */ 40 | fn run(&mut self) { 41 | tdx::tdvmcall_io_write_8(0x70, 0x32); 42 | 43 | let read1 = tdx::tdvmcall_io_read_8(0x71); 44 | log::info!("First time read {}\n", read1); 45 | 46 | tdx::tdvmcall_io_write_8(0x71, read1 + 1); 47 | 48 | let read2 = tdx::tdvmcall_io_read_8(0x71); 49 | log::info!("Second time read {}\n", read2); 50 | 51 | if (read1 + 1 != read2) { 52 | log::info!( 53 | "Second time value is not equal with the first time value + 1 - Expected {:?}: Actual {:?}\n", 54 | read1 + 1, 55 | read2 56 | ); 57 | return; 58 | } 59 | 60 | self.result = TestResult::Pass; 61 | } 62 | 63 | /** 64 | * Tear down the test case. 65 | */ 66 | fn teardown(&mut self) {} 67 | 68 | /** 69 | * get the name of the test case. 70 | */ 71 | fn get_name(&mut self) -> String { 72 | String::from(&self.name) 73 | } 74 | 75 | /** 76 | * get the result of the test case. 77 | */ 78 | fn get_result(&mut self) -> TestResult { 79 | self.result 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /td-payload/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "td-payload" 3 | version = "0.1.0" 4 | description = "A sample TD module/driver for TDX hardware platforms" 5 | repository = "https://github.com/confidential-containers/td-shim" 6 | homepage = "https://github.com/confidential-containers" 7 | license = "BSD-2-Clause-Patent" 8 | edition = "2018" 9 | 10 | [[bin]] 11 | name = "example" 12 | required-features = ["start"] 13 | 14 | [dependencies] 15 | bit_field = "0.10" 16 | linked_list_allocator = "0.10" 17 | lazy_static = "1.0" 18 | log = "0.4.13" 19 | r-efi = "3.2.0" 20 | scroll = { version = "0.10", default-features = false, features = ["derive"]} 21 | serde = { version = "1.0", default-features = false, features = ["derive"]} 22 | serde_json = { version = "1.0", default-features = false, features = ["alloc"] } 23 | spin = "0.9" 24 | td-layout = { path = "../td-layout" } 25 | td-logger = { path = "../td-logger" } 26 | td-shim = { path = "../td-shim", default-features = false } 27 | td-shim-interface = { path = "../td-shim-interface" } 28 | td-exception = { path = "../td-exception" } 29 | td-paging = { path = "../td-paging" } 30 | x86 = "0.47.0" 31 | x86_64 = { version = "0.14.9", default-features = false, features = ["instructions"] } 32 | td-benchmark = { path = "../devtools/td-benchmark", optional = true } 33 | tdx-tdcall = { path = "../tdx-tdcall", optional = true } 34 | zerocopy = { version = "0.7.31", features = ["derive"] } 35 | 36 | minicov = { version = "0.2", default-features = false, optional = true } 37 | 38 | [features] 39 | default = ["tdx"] 40 | tdx = ["tdx-tdcall", "td-logger/tdx", "td-exception/tdx"] 41 | stack-guard = [] 42 | cet-shstk = ["td-exception/cet-shstk"] 43 | cet-ibt = [] 44 | acpi = [] 45 | start = [] 46 | benches = ["td-benchmark"] 47 | coverage = ["minicov"] 48 | test_heap_size = ["td-benchmark"] 49 | no-tdvmcall = ["td-shim/no-tdvmcall", "tdx-tdcall/no-tdvmcall", "td-exception/no-tdvmcall", "td-logger/no-tdvmcall"] 50 | no-tdaccept = ["td-shim/no-tdaccept", "tdx-tdcall/no-tdaccept"] 51 | no-shared-mem = [] 52 | no-mailbox = ["td-shim/no-mailbox"] 53 | no-config = ["td-shim/no-config"] 54 | -------------------------------------------------------------------------------- /tests/test-td-payload/src/testiorw32.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | #![no_std] 6 | extern crate alloc; 7 | 8 | use crate::lib::{TestCase, TestResult}; 9 | use alloc::string::String; 10 | use core::ffi::c_void; 11 | use tdx_tdcall::tdx; 12 | 13 | use serde::{Deserialize, Serialize}; 14 | 15 | /** 16 | * Test tdvmcall io read/write 32 17 | */ 18 | #[derive(Debug, Serialize, Deserialize)] 19 | pub struct Tdiorw32 { 20 | pub name: String, 21 | pub result: TestResult, 22 | pub run: bool, 23 | } 24 | 25 | /** 26 | * Implement the TestCase trait for Tdiorw32 27 | */ 28 | impl TestCase for Tdiorw32 { 29 | /** 30 | * set up the Test case of Tdiorw32 31 | */ 32 | fn setup(&mut self) { 33 | self.result = TestResult::Fail; 34 | } 35 | 36 | /** 37 | * run the test case 38 | * io read Century of RTC 39 | */ 40 | fn run(&mut self) { 41 | tdx::tdvmcall_io_write_8(0x70, 0x32); 42 | 43 | let read1 = tdx::tdvmcall_io_read_32(0x71); 44 | log::info!("First time read {}\n", read1); 45 | 46 | tdx::tdvmcall_io_write_32(0x71, read1 + 1); 47 | 48 | let read2 = tdx::tdvmcall_io_read_32(0x71); 49 | log::info!("Second time read {}\n", read2); 50 | 51 | if (read1 + 1 != read2) { 52 | log::info!( 53 | "Second time value is not equal with the first time value + 10 - Expected {:?}: Actual {:?}\n", 54 | read1 + 1, 55 | read2 56 | ); 57 | return; 58 | } 59 | 60 | self.result = TestResult::Pass; 61 | } 62 | 63 | /** 64 | * Tear down the test case. 65 | */ 66 | fn teardown(&mut self) {} 67 | 68 | /** 69 | * get the name of the test case. 70 | */ 71 | fn get_name(&mut self) -> String { 72 | String::from(&self.name) 73 | } 74 | 75 | /** 76 | * get the result of the test case. 77 | */ 78 | fn get_result(&mut self) -> TestResult { 79 | self.result 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /td-payload/src/arch/x86_64/shared.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | #[cfg(not(feature = "no-tdaccept"))] 6 | use crate::mm::SIZE_4K; 7 | 8 | #[cfg(not(all(feature = "no-tdvmcall", feature = "no-tdaccept")))] 9 | use tdx_tdcall::tdx; 10 | 11 | use super::paging::{clear_shared_bit, set_shared_bit}; 12 | 13 | #[cfg(not(feature = "no-tdvmcall"))] 14 | pub fn decrypt(addr: u64, length: usize) { 15 | set_shared_bit(addr, length); 16 | 17 | // Safety: Fail to map GPA is a fatal error that we cannot handle 18 | if tdx::tdvmcall_mapgpa(true, addr, length).is_err() { 19 | panic!("Fail to map GPA to shared memory with TDVMCALL"); 20 | } 21 | } 22 | 23 | #[cfg(not(feature = "no-tdvmcall"))] 24 | pub fn encrypt(addr: u64, length: usize) { 25 | clear_shared_bit(addr, length); 26 | 27 | // Safety: Fail to map GPA is a fatal error that we cannot handle 28 | if tdx_tdcall::tdx::tdvmcall_mapgpa(false, addr, length).is_err() { 29 | panic!("Fail to map GPA to private memory with TDVMCALL"); 30 | } 31 | #[cfg(not(feature = "no-tdaccept"))] 32 | accept_memory(addr, length); 33 | } 34 | 35 | #[cfg(feature = "no-tdvmcall")] 36 | pub fn decrypt(addr: u64, length: usize) { 37 | set_shared_bit(addr, length); 38 | } 39 | 40 | #[cfg(feature = "no-tdvmcall")] 41 | pub fn encrypt(addr: u64, length: usize) { 42 | clear_shared_bit(addr, length); 43 | #[cfg(not(feature = "no-tdaccept"))] 44 | accept_memory(addr, length); 45 | } 46 | 47 | #[cfg(not(feature = "no-tdaccept"))] 48 | fn accept_memory(addr: u64, length: usize) { 49 | let page_num = length / SIZE_4K; 50 | 51 | for p in 0..page_num { 52 | if let Err(e) = tdx::tdcall_accept_page(addr + (p * SIZE_4K) as u64) { 53 | if let tdx_tdcall::TdCallError::LeafSpecific(error_code) = e { 54 | if error_code == tdx_tdcall::TDCALL_STATUS_PAGE_ALREADY_ACCEPTED { 55 | continue; 56 | } 57 | } 58 | panic!("Accept page error: 0x{:x}, size: {}\n", addr, length); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /td-shim/src/bin/td-shim/td/tdx.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Alibaba Cloud 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | use cc_measurement::log::CcEventLogError; 6 | use td_exception::idt::DescriptorTablePointer; 7 | use tdx_tdcall::tdx; 8 | 9 | extern "win64" { 10 | fn asm_read_msr64(index: u32) -> u64; 11 | fn asm_write_msr64(index: u32, value: u64) -> u64; 12 | } 13 | 14 | const EXTENDED_FUNCTION_INFO: u32 = 0x80000000; 15 | const EXTENDED_PROCESSOR_INFO: u32 = 0x80000001; 16 | 17 | const SHA384_DIGEST_SIZE: usize = 48; 18 | 19 | pub fn get_shared_page_mask() -> u64 { 20 | tdx::td_shared_mask().expect("Unable to get GPAW") 21 | } 22 | 23 | pub fn accept_memory_resource_range(address: u64, size: u64) { 24 | let cpu_num = get_num_vcpus(); 25 | #[cfg(not(feature = "no-mailbox"))] 26 | super::tdx_mailbox::accept_memory_resource_range(cpu_num, address, size) 27 | } 28 | 29 | pub fn relocate_mailbox(new_mailbox: &mut [u8]) { 30 | #[cfg(not(feature = "no-mailbox"))] 31 | super::tdx_mailbox::relocate_mailbox(new_mailbox).expect("Unable to relocate mailbox"); 32 | } 33 | 34 | pub fn relocate_ap_page_table(page_table_base: u64) { 35 | #[cfg(not(feature = "no-mailbox"))] 36 | super::tdx_mailbox::relocate_page_table(get_num_vcpus(), page_table_base); 37 | } 38 | 39 | pub fn set_idt(idt_ptr: &DescriptorTablePointer) { 40 | #[cfg(not(feature = "no-mailbox"))] 41 | super::tdx_mailbox::set_idt(get_num_vcpus(), idt_ptr); 42 | } 43 | 44 | pub fn get_num_vcpus() -> u32 { 45 | let td_info = tdx::tdcall_get_td_info().expect("Fail to get TDINFO"); 46 | 47 | log::info!("gpaw - {:?}\n", td_info.gpaw); 48 | log::info!("num_vcpus - {:?}\n", td_info.num_vcpus); 49 | 50 | td_info.num_vcpus 51 | } 52 | 53 | pub fn extend_rtmr(data: &[u8; SHA384_DIGEST_SIZE], mr_index: u32) -> Result<(), CcEventLogError> { 54 | let digest = tdx::TdxDigest { data: *data }; 55 | 56 | let rtmr_index = match mr_index { 57 | 1 | 2 | 3 | 4 => mr_index - 1, 58 | e => return Err(CcEventLogError::InvalidMrIndex(e)), 59 | }; 60 | 61 | tdx::tdcall_extend_rtmr(&digest, rtmr_index).map_err(|_| CcEventLogError::ExtendMr) 62 | } 63 | -------------------------------------------------------------------------------- /td-shim-tools/src/bin/td-payload-reference-calculator/README.md: -------------------------------------------------------------------------------- 1 | # TD Payload Reference Calculator 2 | A simple tool to calculate td-payload's reference value via bzImage, and kernel parameter 3 | 4 | ## Usage 5 | 6 | ### Kernel (bzImage) 7 | 8 | The test bzImage can be fetched via 9 | 10 | ```bash 11 | wget https://github.com/Xynnn007/td-payload-reference-provider/raw/main/tests/bzImage 12 | ``` 13 | Note: The protocol version of bzImage should be 2.06+. 14 | 15 | Test with the example bzImage 16 | ``` 17 | cargo run -p td-shim-tools --bin td-payload-reference-calculator -- kernel -k bzImage -s 0x10000000 18 | ``` 19 | 20 | The `kernel-size` parameter here means `KERNEL_SIZE` defined in guest firmware, s.t. [TD-SHIM](https://github.com/confidential-containers/td-shim) 21 | 22 | Will get the result 23 | ``` 24 | 5b7aa6572f649714ff00b6a2b9170516a068fd1a0ba72aa8de27574131d454e6396d3bfa1727d9baf421618a942977fa 25 | ``` 26 | 27 | which is from https://github.com/confidential-containers/attestation-service/pull/33/files#diff-1a4e5ad4c3b043c019c00bc3b3072fd6e1e5b03a5ce8c498e1c0acaf697d9d3fR265 28 | 29 | When using [TDVF](https://github.com/tianocore/edk2-staging/tree/2024-tdvf-ww01.4/OvmfPkg) + [QEMU](https://github.com/qemu/qemu) Kernel Direct Boot, the kernel eventlog digest will be pre-processed by QEMU Kernel Direct Boot logic. Which is from https://github.com/confidential-containers/td-shim/issues/633 30 | 31 | Test with the example bzImage 32 | ``` 33 | cargo run -p td-shim-tools --bin td-payload-reference-calculator -- kernel -k bzImage -q 34 | ``` 35 | 36 | Will get the result 37 | ``` 38 | a5e921ae5bde7ab989216da059057741688eae9114b854ce60733824f93ade8a848f19c719f3fdd5c4f0d7178164a5e2 39 | ``` 40 | 41 | ### Kernel Parameter 42 | 43 | Test 44 | ``` 45 | cargo run -p td-shim-tools --bin td-payload-reference-calculator -- param -p "root=/dev/vda1 console=hvc0 rw" -s 0x1000 46 | ``` 47 | 48 | Will get the result 49 | ``` 50 | 64ed1e5a47e8632f80faf428465bd987af3e8e4ceb10a5a9f387b6302e30f4993bded2331f0691c4a38ad34e4cbbc627 51 | ``` 52 | 53 | which is from https://github.com/confidential-containers/attestation-service/pull/33/files#diff-1a4e5ad4c3b043c019c00bc3b3072fd6e1e5b03a5ce8c498e1c0acaf697d9d3fR269 54 | -------------------------------------------------------------------------------- /devtools/Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | ${CARGO} +${STABLE_TOOLCHAIN} build ${BUILD_TYPE_FLAG} -p td-layout-config 3 | ${CARGO} +${STABLE_TOOLCHAIN} build ${BUILD_TYPE_FLAG} -p td-benchmark 4 | ${CARGO} +${STABLE_TOOLCHAIN} build ${BUILD_TYPE_FLAG} -p test-runner-client 5 | ${CARGO} +${STABLE_TOOLCHAIN} build ${BUILD_TYPE_FLAG} -p test-runner-server 6 | 7 | check: 8 | ${CARGO} +${STABLE_TOOLCHAIN} check ${BUILD_TYPE_FLAG} -p td-layout-config 9 | ${CARGO} +${STABLE_TOOLCHAIN} check ${BUILD_TYPE_FLAG} -p td-benchmark 10 | ${CARGO} +${STABLE_TOOLCHAIN} check ${BUILD_TYPE_FLAG} -p test-runner-client 11 | ${CARGO} +${STABLE_TOOLCHAIN} check ${BUILD_TYPE_FLAG} -p test-runner-server 12 | 13 | clean: 14 | ${CARGO} +${STABLE_TOOLCHAIN} clean ${BUILD_TYPE_FLAG} -p td-layout-config 15 | ${CARGO} +${STABLE_TOOLCHAIN} clean ${BUILD_TYPE_FLAG} -p td-benchmark 16 | ${CARGO} +${STABLE_TOOLCHAIN} clean ${BUILD_TYPE_FLAG} -p test-runner-client 17 | ${CARGO} +${STABLE_TOOLCHAIN} clean ${BUILD_TYPE_FLAG} -p test-runner-server 18 | 19 | install: 20 | mkdir -p ${TOPDIR}/devtools/bin 21 | install -m u+rx ${TOPDIR}/target/${BUILD_TYPE}/td-layout-config ${TOPDIR}/devtools/bin/td-layout-config 22 | install -m u+rx ${TOPDIR}/target/${BUILD_TYPE}/test-runner-server ${TOPDIR}/devtools/bin/test-runner-server 23 | 24 | uninstall: 25 | rm ${TOPDIR}/devtools/bin/td-layout-config 26 | rm ${TOPDIR}/devtools/bin/test-runner-server 27 | 28 | tools-init: 29 | docker build -t tools dev_container 30 | 31 | fuzz_test_afl: tools-init 32 | docker run -t --rm -v ${TOPDIR}:/td-shim -w /td-shim tools bash sh_script/fuzzing.sh afl 33 | 34 | fuzz_test_libfuzzer: tools-init 35 | docker run -t --rm -v ${TOPDIR}:/td-shim -w /td-shim tools bash sh_script/fuzzing.sh 36 | 37 | static_analyzer_rudra: tools-init 38 | mkdir -p ${TOPDIR}/target/report 39 | docker run -t --rm \ 40 | --env RUDRA_REPORT_PATH=/td-shim/target/report/report \ 41 | --env SCCACHE_DIR=/td-shim/target/sccache_home \ 42 | --env SCCACHE_CACHE_SIZE=10T \ 43 | -v ${TOPDIR}:/td-shim \ 44 | -v ${TOPDIR}/target/report:/td-shim/target/report \ 45 | -w /td-shim tools bash sh_script/rudra.sh 46 | 47 | all-tools: tools-init fuzz_test_afl fuzz_test_libfuzzer static_analyzer_rudra 48 | -------------------------------------------------------------------------------- /td-shim/src/bin/td-shim/asm/ap_loop_notdvmcall.asm: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, 2025 Intel Corporation 2 | # SPDX-License-Identifier: BSD-2-Clause-Patent 3 | 4 | .set CommandOffset, 0 5 | .set ApicIdOffset, 0x4 6 | .set WakeupVectorOffset, 0x8 7 | 8 | .set MpProtectedModeWakeupCommandNoop, 0 9 | .set MpProtectedModeWakeupCommandWakeup, 1 10 | .set MpProtectedModeWakeupCommandSleep, 2 11 | 12 | .set MailboxApicIdInvalid, 0xffffffff 13 | .set MailboxApicIdBroadcast, 0xfffffffe 14 | 15 | .section .text 16 | 17 | #-------------------------------------------------------------------- 18 | # ap_relocated_vector 19 | # 20 | # rbx: Relocated mailbox address 21 | # rbp: vCpuId 22 | #-------------------------------------------------------------------- 23 | .global ap_relocated_func 24 | ap_relocated_func: 25 | mov r8, rbx 26 | # 27 | # Get the APIC ID via CPUID 28 | mov rax, 1 29 | cpuid 30 | shr ebx, 24 31 | # 32 | # r8 will hold the APIC ID of current AP 33 | xchg r8, rbx 34 | 35 | .check_apicid: 36 | # 37 | # Determine if this is a broadcast or directly for my apic-id, if not, ignore 38 | cmp dword ptr[rbx + ApicIdOffset], MailboxApicIdBroadcast 39 | je .check_command 40 | cmp dword ptr[rbx + ApicIdOffset], r8d 41 | jne .check_apicid 42 | 43 | .check_command: 44 | mov eax, dword ptr[rbx + CommandOffset] 45 | cmp eax, MpProtectedModeWakeupCommandNoop 46 | je .check_apicid 47 | 48 | cmp eax, MpProtectedModeWakeupCommandWakeup 49 | je .wakeup 50 | 51 | jmp .check_apicid 52 | 53 | .wakeup: 54 | # 55 | # BSP sets these variables before unblocking APs 56 | mov rax, 0 57 | mov eax, dword ptr[rbx + WakeupVectorOffset] 58 | 59 | # 60 | # Clear the command as the acknowledgement that the wake up command is received 61 | mov qword ptr[rbx + CommandOffset], MpProtectedModeWakeupCommandNoop 62 | nop 63 | jmp rax 64 | 65 | .panic: 66 | ud2 67 | 68 | .global ap_relocated_func_end 69 | ap_relocated_func_end: 70 | jmp .panic 71 | -------------------------------------------------------------------------------- /td-shim-interface/README.md: -------------------------------------------------------------------------------- 1 | [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fconfidential-containers%2Ftd-shim.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fconfidential-containers%2Ftd-shim?ref=badge_shield) 2 | # TD-shim-interface - Confidential Containers Shim Firmware Interface 3 | 4 | ## Documents 5 | 6 | * [TD-Shim specification](https://github.com/confidential-containers/td-shim/tree/main/doc/tdshim_spec.md) 7 | 8 | * Introduction [PDF](https://github.com/confidential-containers/td-shim/tree/main/doc/td-shim-introduction.pdf) and [conference talk](https://fosdem.org/2023/schedule/event/cc_online_rust/) 9 | 10 | ## Introduction 11 | 12 | This td-shim-interface is to support user for creating data structures and functions required for td-shim, such as TdxMetadataDescriptor and TdxMetadataSection. 13 | Td-uefi-pi is used for UEFI Platform Initializaiton data structures and accessors. 14 | 15 | To import the data structure of metadata, TD HOB and related function, such as: 16 | ``` 17 | use td_shim_interface::{TD_ACPI_TABLE_HOB_GUID, TD_E820_TABLE_HOB_GUID, TD_PAYLOAD_INFO_HOB_GUID}; 18 | use td_shim_interface::PayloadInfo; 19 | use td_shim_interface::acpi; 20 | use td_shim_interface::td_uefi_pi::{hob, pi, pi::guid} 21 | ``` 22 | 23 | This is a Shim Firmware to support [Intel TDX](https://software.intel.com/content/www/us/en/develop/articles/intel-trust-domain-extensions.html). 24 | 25 | The API specification is at [td-shim specification](https://github.com/confidential-containers/td-shim/tree/main/doc/tdshim_spec.md). 26 | 27 | The secure boot specification for td-shim is at [secure boot specification](https://github.com/confidential-containers/td-shim/tree/main/doc/secure_boot.md) 28 | 29 | The design is at [td-shim design](https://github.com/confidential-containers/td-shim/tree/main/doc/design.md). 30 | 31 | The threat model analysis is at [td-shim threat model](https://github.com/confidential-containers/td-shim/tree/main/doc/threat_model.md). 32 | 33 | 34 | ## License 35 | [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fconfidential-containers%2Ftd-shim.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fconfidential-containers%2Ftd-shim?ref=badge_large) 36 | -------------------------------------------------------------------------------- /td-logger/src/logger.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | //! A standalone logger to directly log messages, independent of the log crate. 6 | 7 | use core::fmt::{self, Write}; 8 | use lazy_static::lazy_static; 9 | use spin::Mutex; 10 | 11 | use crate::{dbg_port_write, dbg_write_string}; 12 | 13 | pub const LOG_LEVEL_TRACE: usize = 5; 14 | pub const LOG_LEVEL_DEBUG: usize = 4; 15 | pub const LOG_LEVEL_INFO: usize = 3; 16 | pub const LOG_LEVEL_WARN: usize = 2; 17 | pub const LOG_LEVEL_ERROR: usize = 1; 18 | pub const LOG_LEVEL_NONE: usize = 0; 19 | 20 | pub const LOG_MASK_COMMON: u64 = 0x1; 21 | pub const LOG_MASK_ALL: u64 = 0xFFFFFFFFFFFFFFFF; 22 | 23 | // Use lazy_static here to prevent potential problems caused by compiler/linker optimization. 24 | lazy_static! { 25 | pub static ref LOGGER: Mutex = Mutex::new(Logger { 26 | level: LOG_LEVEL_INFO, 27 | mask: LOG_MASK_ALL, 28 | }); 29 | } 30 | 31 | pub struct Logger { 32 | level: usize, 33 | mask: u64, 34 | } 35 | 36 | impl Logger { 37 | pub fn write_byte(&mut self, byte: u8) { 38 | dbg_port_write(byte); 39 | } 40 | 41 | pub fn write_string(&mut self, s: &str) { 42 | dbg_write_string(s); 43 | } 44 | 45 | pub fn get_level(&self) -> usize { 46 | self.level 47 | } 48 | 49 | pub fn set_level(&mut self, level: usize) { 50 | self.level = level; 51 | } 52 | 53 | pub fn get_mask(&self) -> u64 { 54 | self.mask 55 | } 56 | 57 | pub fn set_mask(&mut self, mask: u64) { 58 | self.mask = mask; 59 | } 60 | } 61 | 62 | impl fmt::Write for Logger { 63 | fn write_str(&mut self, s: &str) -> fmt::Result { 64 | self.write_string(s); 65 | Ok(()) 66 | } 67 | } 68 | 69 | /// Log the message with level and subsystem filtering. 70 | pub fn _log_ex(level: usize, mask: u64, args: fmt::Arguments) { 71 | let mut logger = LOGGER.lock(); 72 | if level <= logger.get_level() && mask & logger.get_mask() != 0 { 73 | logger.write_fmt(args).unwrap(); 74 | } 75 | } 76 | 77 | /// Log the message without level and subsystem filtering. 78 | pub fn _log(args: fmt::Arguments) { 79 | LOGGER.lock().write_fmt(args).unwrap(); 80 | } 81 | -------------------------------------------------------------------------------- /tests/test-td-exception/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | #![no_std] 6 | #![cfg_attr(test, no_main)] 7 | // The `custom_test_frameworks` feature allows the use of `#[test_case]` and `#![test_runner]`. 8 | // Any function, const, or static can be annotated with `#[test_case]` causing it to be aggregated 9 | // (like #[test]) and be passed to the test runner determined by the `#![test_runner]` crate 10 | // attribute. 11 | #![feature(custom_test_frameworks)] 12 | #![test_runner(test_runner)] 13 | // Reexport the test harness main function under a different symbol. 14 | #![reexport_test_harness_main = "test_main"] 15 | 16 | #[cfg(test)] 17 | use bootloader::{boot_info, entry_point, BootInfo}; 18 | #[cfg(test)] 19 | use core::ops::Deref; 20 | #[cfg(test)] 21 | use test_runner_client::{init_heap, serial_println, test_runner}; 22 | 23 | #[cfg(test)] 24 | entry_point!(kernel_main); 25 | 26 | #[cfg(test)] 27 | fn kernel_main(boot_info: &'static mut BootInfo) -> ! { 28 | // turn the screen gray 29 | if let Some(framebuffer) = boot_info.framebuffer.as_mut() { 30 | for byte in framebuffer.buffer_mut() { 31 | *byte = 0x90; 32 | } 33 | } 34 | 35 | let memoryregions = boot_info.memory_regions.deref(); 36 | let offset = boot_info.physical_memory_offset.into_option().unwrap(); 37 | 38 | for usable in memoryregions.iter() { 39 | if usable.kind == boot_info::MemoryRegionKind::Usable { 40 | init_heap((usable.start + offset) as usize, 0x100000); 41 | break; 42 | } 43 | } 44 | 45 | serial_println!("Start to execute test cases..."); 46 | test_main(); 47 | panic!("Unexpected return from test_main()!!!"); 48 | } 49 | 50 | #[cfg(test)] 51 | mod tests { 52 | use td_exception::{setup_exception_handlers, DIVIDED_BY_ZERO_EVENT_COUNT}; 53 | 54 | #[test_case] 55 | fn test_divided_by_zero() { 56 | use core::sync::atomic::Ordering::Acquire; 57 | setup_exception_handlers(); 58 | 59 | assert_eq!(DIVIDED_BY_ZERO_EVENT_COUNT.load(Acquire), 0); 60 | // TODO: make this work:) 61 | //let _ = 1 / DIVIDED_BY_ZERO_EVENT_COUNT.load(Acquire); 62 | //assert_eq!(DIVIDED_BY_ZERO_EVENT_COUNT.load(Acquire), 1); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /td-payload/src/arch/x86_64/apic.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | // MSR registers 6 | pub const MSR_LVTT: u32 = 0x832; 7 | pub const MSR_INITIAL_COUNT: u32 = 0x838; 8 | pub const MSR_TSC_DEADLINE: u32 = 0x6E0; 9 | pub const MSR_DCR: u32 = 0x83e; 10 | 11 | // APIC registers 12 | pub const LOCAL_APIC_LVTT: u32 = 0xfee0_0320; 13 | pub const INITIAL_COUNT: u32 = 0xfee0_0380; 14 | pub const DIVIDE_CONFIGURATION_REGISTER: u32 = 0xfee0_03e0; 15 | 16 | pub fn enable_apic_interrupt() { 17 | // Enable the local APIC by setting bit 8 of the APIC spurious vector region (SVR) 18 | // Ref: Intel SDM Vol3. 8.4.4.1 19 | // In x2APIC mode, SVR is mapped to MSR address 0x80f. 20 | // Since SVR(SIVR) is not virtualized, before we implement the handling in #VE of MSRRD/WR, 21 | // use tdvmcall instead direct read/write operation. 22 | #[cfg(not(feature = "no-tdvmcall"))] 23 | let svr = tdx_tdcall::tdx::tdvmcall_rdmsr(0x80f).expect("fail to perform RDMSR operation\n"); 24 | #[cfg(not(feature = "no-tdvmcall"))] 25 | tdx_tdcall::tdx::tdvmcall_wrmsr(0x80f, svr | (0x1 << 8)) 26 | .expect("fail to perform WRMSR operation\n"); 27 | } 28 | 29 | pub fn enable_and_hlt() { 30 | #[cfg(all(feature = "tdx", not(feature = "no-tdvmcall")))] 31 | tdx_tdcall::tdx::tdvmcall_sti_halt(); 32 | #[cfg(not(feature = "tdx"))] 33 | x86_64::instructions::interrupts::enable_and_hlt() 34 | } 35 | 36 | pub fn disable() { 37 | x86_64::instructions::interrupts::disable() 38 | } 39 | 40 | pub fn one_shot_tsc_deadline_mode(period: u64) -> Option { 41 | unsafe { x86::msr::wrmsr(MSR_TSC_DEADLINE, 0) } 42 | 43 | let tsc = unsafe { x86::time::rdtsc() }; 44 | 45 | // Setup TSC Deadline Mode 46 | unsafe { 47 | x86::msr::wrmsr(MSR_TSC_DEADLINE, tsc.checked_add(period)?); 48 | } 49 | 50 | Some(period) 51 | } 52 | 53 | pub fn one_shot_tsc_deadline_mode_reset() { 54 | unsafe { x86::msr::wrmsr(MSR_TSC_DEADLINE, 0) } 55 | } 56 | 57 | pub fn one_shot(period: u64) -> Option { 58 | unsafe { 59 | x86::msr::wrmsr(MSR_DCR, 0x0b); // divide by 1 60 | x86::msr::wrmsr(MSR_INITIAL_COUNT, period); 61 | } 62 | 63 | Some(period) 64 | } 65 | 66 | pub fn one_shot_reset() { 67 | unsafe { x86::msr::wrmsr(MSR_INITIAL_COUNT, 0) } 68 | } 69 | -------------------------------------------------------------------------------- /td-layout/src/runtime/exec.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 - 2024 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | // Auto-generated by `td-layout-config`, do not edit manually. 6 | 7 | /* 8 | Memory Layout Example 9 | Top of Low Memory: 0x80000000 10 | +----------------------------------------+ <- 0x80000000 11 | | EVENT_LOG | (0x100000) 1 MB 12 | +----------------------------------------+ <- 0x7FF00000 13 | | RELOCATED_MAILBOX | (0x2000) 8 kB 14 | +----------------------------------------+ <- 0x7FEFE000 15 | | PAYLOAD_PAGE_TABLE | (0x20000) 128 kB 16 | +----------------------------------------+ <- 0x7FEDE000 17 | | PAYLOAD | (0x2000000) 32 MB 18 | +----------------------------------------+ <- 0x7DEDE000 19 | | ACPI | (0x100000) 1 MB 20 | +----------------------------------------+ <- 0x7DDDE000 21 | | FREE | (0x7D5BE000) 1.96 GB 22 | +----------------------------------------+ <- 0x820000 23 | | TD_HOB | (0x20000) 128 kB 24 | +----------------------------------------+ <- 0x800000 25 | | BOOTLOADER | (0x800000) 8 MB 26 | +----------------------------------------+ <- 0x0 27 | Total Usage: 0x2A42000 (42.26 MB) 28 | */ 29 | 30 | pub const TOTAL_USAGE: usize = 0x2A42000; // (42.26 MB) 31 | 32 | // Runtime Layout Configuration 33 | pub const BOOTLOADER_BASE: usize = 0x0; 34 | pub const BOOTLOADER_SIZE: usize = 0x800000; // 8 MB 35 | pub const TD_HOB_BASE: usize = 0x800000; 36 | pub const TD_HOB_SIZE: usize = 0x20000; // 128 kB 37 | pub const ACPI_SIZE: usize = 0x100000; // 1 MB 38 | pub const PAYLOAD_SIZE: usize = 0x2000000; // 32 MB 39 | pub const PAYLOAD_PAGE_TABLE_SIZE: usize = 0x20000; // 128 kB 40 | pub const RELOCATED_MAILBOX_SIZE: usize = 0x2000; // 8 kB 41 | pub const EVENT_LOG_SIZE: usize = 0x100000; // 1 MB 42 | 43 | pub const MEMORY_LAYOUT_CONFIG: &[(&str, usize, &str)] = &[ 44 | // (name of memory region, region size, region type) 45 | ("Bootloader", 0x800000, "Memory"), 46 | ("TdHob", 0x20000, "Memory"), 47 | ("Acpi", 0x100000, "Acpi"), 48 | ("Payload", 0x2000000, "Reserved"), 49 | ("PayloadPageTable", 0x20000, "Reserved"), 50 | ("RelocatedMailbox", 0x2000, "Nvs"), 51 | ("EventLog", 0x100000, "Nvs"), 52 | ]; 53 | -------------------------------------------------------------------------------- /devtools/td-layout-config/src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | use std::path::PathBuf; 6 | 7 | use clap::{Parser, ValueEnum}; 8 | use td_layout_config::{image, memory}; 9 | 10 | #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] 11 | pub enum ConfigType { 12 | /// Memory layout config 13 | Memory, 14 | /// Image layout config 15 | Image, 16 | } 17 | 18 | #[derive(Parser)] 19 | #[clap(version)] 20 | struct Cli { 21 | /// Memory config file pathname. 22 | config: String, 23 | /// Specify config file type, e.g. json, layout-config 24 | #[clap(short = 't', long = "config_type", value_enum)] 25 | config_type: ConfigType, 26 | /// Memory base address. 27 | #[clap(short = 'b', long = "base", default_value_t = String::from("0x0"))] 28 | base: String, 29 | /// Parse memory config to find FW top (only valid with -t image). 30 | #[clap(short = 'm', long = "metadata")] 31 | metadata: Option, 32 | /// Output to file 33 | #[clap(short = 'o', long = "output")] 34 | output: Option, 35 | /// Output to stdout 36 | #[clap(short = 'p', long = "print")] 37 | print_flag: bool, 38 | } 39 | 40 | fn main() { 41 | let cli = Cli::parse(); 42 | 43 | let config = std::fs::read_to_string(cli.config.to_string()) 44 | .expect("Content in configuration file is invalid"); 45 | 46 | let output_file = cli.output.as_ref().map(|path| PathBuf::from(&path)); 47 | 48 | match cli.config_type { 49 | ConfigType::Memory => output(&cli, memory::parse_memory(config), output_file), 50 | ConfigType::Image => { 51 | let metadata = match cli.metadata { 52 | Some(ref metadata) => Some( 53 | std::fs::read_to_string(metadata.to_string()) 54 | .expect("Content in configuration file is invalid"), 55 | ), 56 | None => None, 57 | }; 58 | output(&cli, image::parse_image(config, metadata), output_file); 59 | } 60 | }; 61 | } 62 | 63 | fn output(cli: &Cli, data: String, dir: Option) { 64 | if cli.print_flag { 65 | print!("{}", data); 66 | } 67 | 68 | if let Some(path) = dir { 69 | std::fs::write(path, data.as_bytes()).expect("Failed to create image layout file"); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /td-shim-interface/fuzz/fuzz_targets/fuzzlib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | #![allow(unused)] 6 | use core::mem::size_of; 7 | use r_efi::efi::Guid; 8 | use std::vec::Vec; 9 | use td_shim_interface::td_uefi_pi::{fv, hob, pi}; 10 | 11 | const EFI_END_OF_HOB_LIST_OFFSET: usize = 48; 12 | 13 | const HOB_ACPI_TABLE_GUID: [u8; 16] = [ 14 | 0x70, 0x58, 0x0c, 0x6a, 0xed, 0xd4, 0xf4, 0x44, 0xa1, 0x35, 0xdd, 0x23, 0x8b, 0x6f, 0xc, 0x8d, 15 | ]; 16 | 17 | const HOB_KERNEL_INFO_GUID: [u8; 16] = [ 18 | 0x12, 0xa4, 0x6f, 0xb9, 0x1f, 0x46, 0xe3, 0x4b, 0x8c, 0xd, 0xad, 0x80, 0x5a, 0x49, 0x7a, 0xc0, 19 | ]; 20 | 21 | /// GUID for secure boot trust anchor in the Configuration Firmware Volume (CFV). 22 | const CFV_FFS_HEADER_TRUST_ANCHOR_GUID: Guid = Guid::from_fields( 23 | 0x77a2742e, 24 | 0x9340, 25 | 0x4ac9, 26 | 0x8f, 27 | 0x85, 28 | &[0xb7, 0xb9, 0x78, 0x58, 0x0, 0x21], 29 | ); // {77A2742E-9340-4AC9-8F85-B7B978580021} 30 | 31 | pub fn fuzz_hob_parser(buffer: &[u8]) { 32 | let mut test_buffer = buffer.to_vec(); 33 | 34 | // Update ptr in buffer 35 | let ptr = test_buffer.as_ptr() as u64; 36 | if test_buffer.len() >= size_of::() { 37 | test_buffer[EFI_END_OF_HOB_LIST_OFFSET..size_of::()] 38 | .copy_from_slice(&u64::to_le_bytes(ptr + buffer.len() as u64)[..]); 39 | } 40 | 41 | let hob_list = hob::check_hob_integrity(&test_buffer); 42 | 43 | if hob_list.is_some() { 44 | hob::dump_hob(hob_list.unwrap()); 45 | hob::get_system_memory_size_below_4gb(hob_list.unwrap()); 46 | hob::get_total_memory_top(hob_list.unwrap()); 47 | hob::get_fv(hob_list.unwrap()); 48 | hob::get_next_extension_guid_hob(hob_list.unwrap(), &HOB_ACPI_TABLE_GUID); 49 | hob::get_next_extension_guid_hob(hob_list.unwrap(), &HOB_KERNEL_INFO_GUID); 50 | hob::get_guid_data(hob_list.unwrap()); 51 | hob::seek_to_next_hob(hob_list.unwrap()); 52 | } 53 | } 54 | 55 | pub fn fuzz_payload_parser(data: &[u8]) { 56 | let res = fv::get_image_from_fv(data, pi::fv::FV_FILETYPE_DXE_CORE, pi::fv::SECTION_PE32); 57 | } 58 | 59 | pub fn fuzz_cfv_parser(data: &[u8]) { 60 | let res = fv::get_file_from_fv( 61 | data, 62 | pi::fv::FV_FILETYPE_RAW, 63 | CFV_FFS_HEADER_TRUST_ANCHOR_GUID, 64 | ); 65 | } 66 | -------------------------------------------------------------------------------- /.github/workflows/library.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | paths-ignore: 4 | - "**.md" 5 | pull_request: 6 | paths-ignore: 7 | - "**.md" 8 | workflow_dispatch: 9 | 10 | name: Library Crates 11 | 12 | env: 13 | AS: nasm 14 | RUST_TOOLCHAIN: 1.88.0 15 | TOOLCHAIN_PROFILE: minimal 16 | 17 | jobs: 18 | compile: 19 | name: Build Library Crates 20 | runs-on: ${{ matrix.host_os }} 21 | timeout-minutes: 30 22 | 23 | strategy: 24 | matrix: 25 | host_os: 26 | - ubuntu-latest 27 | - windows-2022 28 | steps: 29 | # Install first since it's needed to build NASM 30 | - name: Install LLVM and Clang 31 | uses: KyleMayes/install-llvm-action@v2 32 | with: 33 | version: "10.0" 34 | directory: ${{ runner.temp }}/llvm 35 | 36 | - name: install NASM 37 | uses: ilammy/setup-nasm@v1 38 | 39 | - name: Install rust toolchain 40 | uses: dtolnay/rust-toolchain@master 41 | with: 42 | toolchain: ${{ env.RUST_TOOLCHAIN }} 43 | 44 | - name: Checkout sources 45 | uses: actions/checkout@v6 46 | with: 47 | submodules: recursive 48 | 49 | - name: Cache 50 | uses: Swatinem/rust-cache@v2 51 | 52 | - name: Preparation work 53 | run: bash sh_script/preparation.sh 54 | 55 | - name: Build library crates 56 | run: make lib-build 57 | 58 | test: 59 | name: Test Library Crates 60 | 61 | strategy: 62 | fail-fast: false 63 | matrix: 64 | os: [ubuntu-latest, windows-2022] 65 | runs-on: ${{ matrix.os }} 66 | timeout-minutes: 30 67 | 68 | steps: 69 | # Install first since it's needed to build NASM 70 | - name: Install LLVM and Clang 71 | uses: KyleMayes/install-llvm-action@v2 72 | with: 73 | version: "10.0" 74 | directory: ${{ runner.temp }}/llvm 75 | 76 | - name: install NASM 77 | uses: ilammy/setup-nasm@v1 78 | 79 | - name: Install rust toolchain 80 | uses: dtolnay/rust-toolchain@master 81 | with: 82 | toolchain: ${{ env.RUST_TOOLCHAIN }} 83 | 84 | - name: Checkout sources 85 | uses: actions/checkout@v6 86 | with: 87 | submodules: recursive 88 | 89 | - name: Preparation Work 90 | run: make preparation 91 | 92 | - name: Test library crates 93 | run: make lib-test 94 | -------------------------------------------------------------------------------- /devtools/test-runner-server/README.md: -------------------------------------------------------------------------------- 1 | # test-runner-server & test-runner-client 2 | 3 | Rust has a [built-in test framework](https://doc.rust-lang.org/book/ch11-00-testing.html) that is capable of running 4 | unit tests without the need to set anything up. 5 | Just create a function that checks some results through assertions and add the `#[test]` attribute to the function 6 | header. Then `cargo test` will automatically find and execute all test functions of your crate. 7 | 8 | Unfortunately it’s a bit more complicated for `#[no_std]` applications such as our case. The problem is that Rust’s 9 | test framework implicitly uses the built-in test library, which depends on the standard library. This means that we 10 | can’t use the default test framework for our `#[no_std]` shim and payload. 11 | 12 | To simplify the development, test cases are divided into two classes: 13 | - normal test cases: which may be run on the host (build machine) directly 14 | - vm-based test cases: which must be run inside a virtual machine, the virtual machine may or may not be a trusted 15 | domain. 16 | 17 | It's ease to deal with the normal unit test cases, just include the test cases in the crate source code and use the 18 | normal rust test framework for them. 19 | 20 | For vm-based test cases, two fundamental issues must be solved: 21 | - run `#[no_std]` unit test cases. This is solved by making use of the `custom_test_frameworks` feature which allows 22 | the use of `#[test_case]` and `#![test_runner]`. Any function, const, or static can be annotated with `#[test_case]` 23 | causing it to be aggregated (like #[test]) and be passed to the test runner determined by the `#![test_runner]` 24 | crate attribute. The `test-runner-client` provides a `test_runner()` for this purpose. 25 | - run unit test cases inside a vm. The `test-runner-server` prepares a boot disk image and boot a qemu virtual machine 26 | with the prepared boot image by using the `bootloader` and associated crates. The `test-runner-server` also 27 | communicates `test-runner-client` through serial port and io port to collect logs and result. 28 | 29 | And all vm-based test cases are implemented as dedicated crates under directory `tests`. 30 | 31 | ## Reference 32 | For more detailed design information, please refer to: 33 | - [Writing an OS in Rust: Testing](https://os.phil-opp.com/testing/) 34 | - [How to Build a Custom Test Harness in Rust](https://www.infinyon.com/blog/2021/04/rust-custom-test-harness/) 35 | -------------------------------------------------------------------------------- /doc/cargo-deny.md: -------------------------------------------------------------------------------- 1 | ## cargo-deny 2 | 3 | cargo-deny is a cargo plugin that lets you lint your project's 4 | dependency graph to ensure all your dependencies conform to 5 | your expectations and requirements. 6 | 7 | **Checks** 8 | 9 | cargo-deny supports several different classes of checks that 10 | can be performed on your project's crate graph. By default, 11 | cargo deny check will execute all of the supported checks, 12 | falling back to the default configuration for that check 13 | if one is not explicitly specified. 14 | 15 | - licenses 16 | 17 | Checks the license information for each crate. 18 | 19 | - bans 20 | 21 | Checks for specific crates in your graph, as well as duplicates. 22 | 23 | - advisories 24 | 25 | Checks advisory databases for crates with security vulnerabilities, 26 | or that have been marked as Unmaintained, or which have been yanked from 27 | their source registry. 28 | 29 | - sources 30 | 31 | Checks the source location for each crate. 32 | 33 | Install: 34 | 35 | `cargo install --locked cargo-deny` 36 | 37 | if the project edition is not 2021, you can install 0.10.3. 38 | 39 | `cargo install cargo-deny --version 0.10.3` 40 | 41 | Checks: 42 | 43 | `cargo deny check` 44 | 45 | Check a few of them 46 | 47 | `cargo deny check bans sources` 48 | 49 | If you want to use a configuration file and ignore some options. 50 | 51 | ``` 52 | # Create deny.toml file 53 | cargo init 54 | ``` 55 | 56 | GitHub Action 57 | 58 | For GitHub projects, one can run cargo-deny automatically as 59 | part of continuous integration using a GitHub Action: 60 | 61 | ``` 62 | 63 | name: cargo-deny 64 | on: [push, pull_request] 65 | jobs: 66 | cargo-deny: 67 | runs-on: ubuntu-latest 68 | strategy: 69 | matrix: 70 | checks: 71 | - advisories 72 | - sources 73 | - bans 74 | - licenses 75 | 76 | # Prevent sudden announcement of a new advisory from failing ci: 77 | continue-on-error: ${{ matrix.checks == 'sources' }} 78 | 79 | steps: 80 | - uses: actions/checkout@v2 81 | with: 82 | submodules: recursive 83 | 84 | - run: make preparation 85 | - uses: EmbarkStudios/cargo-deny-action@v1 86 | with: 87 | command: check ${{ matrix.checks }} 88 | ``` 89 | 90 | Reference: 91 | 92 | [cargo-deny book](https://embarkstudios.github.io/cargo-deny/index.html) 93 | 94 | [cargo-deny github](https://github.com/EmbarkStudios/cargo-deny) -------------------------------------------------------------------------------- /td-shim/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "td-shim" 3 | version = "0.1.0" 4 | license = "BSD-2-Clause-Patent" 5 | edition = "2018" 6 | 7 | # add build process 8 | build = "build.rs" 9 | 10 | [[bin]] 11 | name = "td-shim" 12 | required-features = ["main"] 13 | 14 | [build-dependencies] 15 | anyhow = "1.0.55" 16 | cc = "1.0" 17 | td-layout = { path = "../td-layout" } 18 | tdx-tdcall = { path = "../tdx-tdcall" } 19 | which = "5.0.0" 20 | 21 | [dependencies] 22 | lazy_static = { version = "1.4.0", features = ["spin_no_std"] } 23 | r-efi = "3.2.0" 24 | scroll = { version = "0.10", default-features = false, features = ["derive"] } 25 | td-layout = { path = "../td-layout" } 26 | td-shim-interface = { path = "../td-shim-interface" } 27 | cc-measurement = { path = "../cc-measurement" } 28 | zerocopy = { version = "0.7.31", features = ["derive"] } 29 | 30 | td-loader = { path = "../td-loader", optional = true } 31 | linked_list_allocator = { version = "0.10", optional = true } 32 | log = { version = "0.4.13", optional = true } 33 | ring = { version = "0.17.14", default-features = false, features = ["alloc"], optional = true } 34 | spin = { version = "0.9.2", optional = true } 35 | td-exception = { path = "../td-exception", optional = true } 36 | td-logger = { path = "../td-logger", optional = true } 37 | td-paging = { path = "../td-paging", optional = true } 38 | x86 = { version ="0.47.0", optional = true } 39 | x86_64 = { version = "0.14.9", default-features = false, features = ["instructions"], optional = true } 40 | 41 | # secure boot 42 | der = {version = "0.7.9", features = ["derive", "alloc"], optional = true} 43 | 44 | # TDX 45 | tdx-tdcall = { path = "../tdx-tdcall", optional = true } 46 | 47 | [features] 48 | default = ["secure-boot"] 49 | secure-boot = ["der", "ring"] 50 | tdx = ["tdx-tdcall", "td-exception/tdx", "td-logger/tdx", "x86"] 51 | lazy-accept = ["tdx"] 52 | ring-hash = ["cc-measurement/ring"] 53 | sha2-hash = ["cc-measurement/sha2"] 54 | no-tdvmcall = ["tdx-tdcall/no-tdvmcall", "td-logger/no-tdvmcall", "td-exception/no-tdvmcall"] 55 | no-tdaccept = ["tdx-tdcall/no-tdaccept"] 56 | no-metadata-checks = ["td-shim-interface/no-metadata-checks"] 57 | tdg_dbg = ["td-logger/tdg_dbg"] 58 | no-config = ["td-layout/no-config"] 59 | no-mailbox = ["td-layout/no-mailbox"] 60 | 61 | main = [ 62 | "log", 63 | "td-loader", 64 | "linked_list_allocator", 65 | "spin", 66 | "td-exception", 67 | "td-logger", 68 | "td-paging", 69 | "x86", 70 | "x86_64", 71 | ] 72 | -------------------------------------------------------------------------------- /.github/workflows/format.yml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | 3 | name: Format and Clippy 4 | 5 | env: 6 | AS: nasm 7 | AR: llvm-ar 8 | CC: clang 9 | RUST_TOOLCHAIN: 1.88.0 10 | 11 | jobs: 12 | clippy: 13 | name: Clippy 14 | runs-on: ubuntu-22.04 15 | steps: 16 | # Install first since it's needed to build NASM 17 | - name: Install LLVM and Clang 18 | uses: KyleMayes/install-llvm-action@v2 19 | with: 20 | version: "10.0" 21 | directory: ${{ runner.temp }}/llvm 22 | 23 | - name: Install libtinfo5 24 | run: sudo apt-get update -y && sudo apt-get install libtinfo5 -y 25 | 26 | - name: install NASM 27 | uses: ilammy/setup-nasm@v1 28 | 29 | - name: Checkout sources 30 | uses: actions/checkout@v6 31 | with: 32 | submodules: recursive 33 | 34 | - name: Install toolchain with clippy available 35 | uses: dtolnay/rust-toolchain@master 36 | with: 37 | toolchain: ${{ env.RUST_TOOLCHAIN }} 38 | components: clippy 39 | 40 | - name: Add target 41 | run: rustup target add x86_64-unknown-none 42 | 43 | - name: Preparation Work 44 | run: make preparation 45 | 46 | - name: Run cargo clippy 47 | run: cargo clippy --all-features --target=x86_64-unknown-none 48 | 49 | rustfmt: 50 | name: Format 51 | runs-on: ubuntu-22.04 52 | steps: 53 | 54 | # Install first since it's needed to build NASM 55 | - name: Install LLVM and Clang 56 | uses: KyleMayes/install-llvm-action@v2 57 | with: 58 | version: "10.0" 59 | directory: ${{ runner.temp }}/llvm 60 | 61 | - name: Install libtinfo5 62 | run: sudo apt-get update -y && sudo apt-get install libtinfo5 -y 63 | 64 | - name: install NASM 65 | uses: ilammy/setup-nasm@v1 66 | 67 | - name: Checkout sources 68 | uses: actions/checkout@v6 69 | with: 70 | submodules: recursive 71 | 72 | - name: Install toolchain with rustfmt available 73 | uses: dtolnay/rust-toolchain@master 74 | with: 75 | toolchain: ${{ env.RUST_TOOLCHAIN }} 76 | components: rustfmt 77 | 78 | - name: Preparation Work 79 | run: make preparation 80 | 81 | - name: Run cargo check 82 | run: cargo check 83 | 84 | - name: Run cargo fmt 85 | run: cargo fmt --all -- --check 86 | -------------------------------------------------------------------------------- /td-payload/src/arch/x86_64/gdt.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: BSD-2-Clause-Patent 4 | 5 | use bit_field::BitField; 6 | use core::mem::size_of; 7 | use lazy_static::lazy_static; 8 | use spin::Mutex; 9 | use x86_64::instructions::tables::load_tss; 10 | use x86_64::registers::segmentation::{Segment, CS, DS, ES, FS, GS, SS}; 11 | use x86_64::structures::gdt::{Descriptor, DescriptorFlags, GlobalDescriptorTable}; 12 | use x86_64::structures::tss::TaskStateSegment; 13 | use x86_64::VirtAddr; 14 | 15 | lazy_static! { 16 | pub static ref GDT: Mutex = Mutex::new(GlobalDescriptorTable::new()); 17 | pub static ref TSS: Mutex = Mutex::new(TaskStateSegment::new()); 18 | } 19 | 20 | pub fn init_gdt() { 21 | let gdt = &mut *GDT.lock(); 22 | unsafe { 23 | let _code32 = gdt.add_entry(Descriptor::UserSegment( 24 | DescriptorFlags::KERNEL_CODE32.bits(), 25 | )); 26 | let code = gdt.add_entry(Descriptor::kernel_code_segment()); 27 | let _code_exception = gdt.add_entry(Descriptor::kernel_code_segment()); 28 | let data = gdt.add_entry(Descriptor::kernel_data_segment()); 29 | gdt.load_unsafe(); 30 | 31 | CS::set_reg(code); 32 | DS::set_reg(data); 33 | ES::set_reg(data); 34 | SS::set_reg(data); 35 | FS::set_reg(data); 36 | GS::set_reg(data); 37 | 38 | init_tss(gdt); 39 | } 40 | } 41 | 42 | unsafe fn init_tss(gdt: &mut GlobalDescriptorTable) { 43 | let ptr = &mut *TSS.lock() as *const _ as u64; 44 | 45 | let mut low = DescriptorFlags::PRESENT.bits(); 46 | // base 47 | low.set_bits(16..40, ptr.get_bits(0..24)); 48 | low.set_bits(56..64, ptr.get_bits(24..32)); 49 | // limit 50 | low.set_bits(0..16, (size_of::() - 1) as u64); 51 | // type 52 | low.set_bits(40..44, 0b1001); 53 | 54 | let mut high = 0; 55 | high.set_bits(0..32, ptr.get_bits(32..64)); 56 | 57 | let tss_descriptor = Descriptor::SystemSegment(low, high); 58 | let tss_segment_selector = gdt.add_entry(tss_descriptor); 59 | 60 | gdt.load_unsafe(); 61 | 62 | load_tss(tss_segment_selector); 63 | } 64 | 65 | pub fn tss_set_ist(index: u8, stack: u64) { 66 | unsafe { 67 | let tss = &mut *TSS.lock(); 68 | tss.interrupt_stack_table[index as usize] = VirtAddr::new(stack); 69 | 70 | let gdt = &mut *GDT.lock(); 71 | gdt.load_unsafe(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /doc/design-for-payload.md: -------------------------------------------------------------------------------- 1 | # payload design 2 | 3 | `td-shim` supports boot a `td-payload`, which could be a normal OS kernel, or a bare-metal execution environment. 4 | 5 | ## dependency 6 | 7 | A rust-based bare-metal environment for `td-payload` can only have below dependency: 8 | 9 | 1) Rust Language `Core` - https://doc.rust-lang.org/core/. 10 | 11 | 2) 3rd party rust core crates registered at https://crates.io/, after evaluation. 12 | 13 | 3) The sharable tdx related crates for bare-metal service. 14 | 15 | Examples include crates in [td-shim](https://github.com/confidential-containers/td-shim) project, such as [td-exception](https://github.com/confidential-containers/td-shim/tree/main/td-exception), [tdx-tdcall](https://github.com/confidential-containers/td-shim/tree/main/tdx-tdcall), [td-logger](https://github.com/confidential-containers/td-shim/tree/main/td-logger), [td-paging](https://github.com/confidential-containers/td-shim/tree/main/td-paging) etc, also [rust-spdm](https://github.com/intel/rust-spdm). 16 | 17 | ## memory footprint 18 | 19 | The size of `td-payload` depends on the feature, and it is configurable. 20 | 21 | The [td-benchmark](https://github.com/confidential-containers/td-shim/tree/main/devtools/td-benchmark) tool to evaluated the stack and heap usage at runtime. Please refere to [test_heap_stack_usage](https://github.com/confidential-containers/td-shim/blob/main/doc/test_heap_stack_usage.md). 22 | 23 | For example: 24 | 1) [MigTD](https://github.com/intel/MigTD) 25 | 26 | 8M image and 32M runtime memory. They are configured at https://github.com/intel/MigTD/blob/main/config/metadata.json. 27 | 28 | 2) [vtpm-td](https://github.com/intel/vtpm-td) 29 | 30 | 8M image and 32M runtime memory. They are configured at https://github.com/intel/vtpm-td/blob/main/config/metadata.json. 31 | 32 | ## memory allocation 33 | 34 | We can use rust core alloc crate. 35 | 36 | For example: [linked_list_allocateor](https://github.com/rust-osdev/linked-list-allocator) 37 | 38 | ## crypto support 39 | 40 | Td-payload can use rust crypto libraries, such as [ring](https://github.com/briansmith/ring), [webpki](https://github.com/briansmith/webpki), or [rust-mbedtls](https://github.com/fortanix/rust-mbedtls), which support `no-std`. 41 | 42 | But [rustls](https://github.com/rustls/rustls) and [rust-openssl](https://github.com/sfackler/rust-openssl) require rust `std` support. 43 | 44 | To support linking different crypto crate, the consumer has better use crypto traits, such as https://github.com/RustCrypto/traits. 45 | 46 | -------------------------------------------------------------------------------- /td-shim-tools/src/bin/td-shim-enroll/README.md: -------------------------------------------------------------------------------- 1 | ## Public key enrollment 2 | 3 | This tool accepts **DER encoded** public key file as input and enrolls the **public key hash** into CFV. 4 | Public keys are a SubjectPublicKeyInfo as specified in [IETF RFC 3280](https://datatracker.ietf.org/doc/html/rfc3280). 5 | 6 | ### Configuration Firmware Volume (CFV) 7 | 8 | Quotation from [Intel TDX Virtual Firmware Design Guide](https://www.intel.com/content/dam/develop/external/us/en/documents/tdx-virtual-firmware-design-guide-rev-1.pdf), 9 | section 3.2: 10 | ``` 11 | TDVF/TD-SHIM may also include a configuration firmware volume (CFV) that is seperated from the boot firmware volume (BFV). 12 | The reason to do so is because the CFV is measured in the `RTMR`, while the BFV is measured in `TDMR`. 13 | 14 | Configuration Firmware Volume includes all the provisoned data and this region is read-only. One possible usage is to 15 | provide UEFI Secure Boot Variable content in this region, such as PK, KEK, db, dbx. 16 | 17 | The filesystem GUID must be `EFI_SYSTEM_NV_DATA_FV_GUID`, defined in 18 | [https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Include/Guid/SystemNvDataGuid.h](https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Include/Guid/SystemNvDataGuid.h) 19 | ``` 20 | 21 | ### Generate public key 22 | 23 | 1. ECDSA NIST P384 24 | 25 | Generate DER encoded public key from DER encoded EC private key file. 26 | ``` 27 | openssl ec -inform der -in ecdsa-p384-private.der -pubout -outform der -out ecdsa-p384-public.der 28 | ``` 29 | Note: for ECDSA, we only support uncompressed public key as input. 30 | 31 | 2. RSA 3072 32 | 33 | Generate DER encoded public key from DER encoded pkcs8 formated private key: 34 | ``` 35 | openssl rsa -inform der -in rsa-3072-private.pk8 -pubout -outform der -out rsa-3072-public.der 36 | ``` 37 | 38 | ### Enrollment 39 | 40 | Run the tool: 41 | ``` 42 | cargo run -p td-shim-tools --bin td-shim-enroll -- [-H {hash_algorithm}] [-o {output_file}] [-k {public_key_file}] [-f {Firmware_file}] {tdshim_file} 43 | ``` 44 | 45 | For example: 46 | ``` 47 | cargo run -p td-shim-tools --bin td-shim-enroll -- -H SHA384 -o final.sb.bin target/release/final.bin -k data/sample-keys/ecdsa-p384-public.der 48 | ``` 49 | 50 | To enroll raw files into CFV: 51 | ``` 52 | cargo run -p td-shim-tools --bin td-shim-enroll -- -o final.sb.bin target/release/final.bin -f AB122746-2735-4013-A5C4-90F739CA29BD data/sample-keys/ecdsa-p384-public.der 4EF32D2C-7DD1-44BD-A4C9-E0F8FCC5372A data/sample-keys/rsa-3072-public.der 53 | ``` 54 | -------------------------------------------------------------------------------- /td-shim/src/bin/td-shim/asm/ap_loop.asm: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 Intel Corporation 2 | # SPDX-License-Identifier: BSD-2-Clause-Patent 3 | 4 | .set TDVMCALL_EXPOSE_REGS_MASK, 0xffec 5 | .set TDVMCALL, 0x0 6 | .set INSTRUCTION_CPUID, 0xa 7 | 8 | .set CommandOffset, 0 9 | .set ApicIdOffset, 0x4 10 | .set WakeupVectorOffset, 0x8 11 | 12 | .set MpProtectedModeWakeupCommandNoop, 0 13 | .set MpProtectedModeWakeupCommandWakeup, 1 14 | .set MpProtectedModeWakeupCommandSleep, 2 15 | 16 | .set MailboxApicIdInvalid, 0xffffffff 17 | .set MailboxApicIdBroadcast, 0xfffffffe 18 | 19 | .section .text 20 | 21 | #-------------------------------------------------------------------- 22 | # ap_relocated_vector 23 | # 24 | # rbx: Relocated mailbox address 25 | # rbp: vCpuId 26 | #-------------------------------------------------------------------- 27 | .global ap_relocated_func 28 | ap_relocated_func: 29 | # 30 | # Get the APIC ID via TDVMCALL 31 | mov rax, TDVMCALL 32 | mov rcx, TDVMCALL_EXPOSE_REGS_MASK 33 | mov r10, 0 34 | mov r11, INSTRUCTION_CPUID 35 | mov r12, 0xb 36 | mov r13, 0 37 | # TDVMCALL 38 | .byte 0x66, 0x0f, 0x01, 0xcc 39 | test rax, rax 40 | jnz .panic 41 | # 42 | # r8 will hold the APIC ID of current AP 43 | mov r8, r15 44 | 45 | .check_apicid: 46 | # 47 | # Determine if this is a broadcast or directly for my apic-id, if not, ignore 48 | cmp dword ptr[rbx + ApicIdOffset], MailboxApicIdBroadcast 49 | je .check_command 50 | cmp dword ptr[rbx + ApicIdOffset], r8d 51 | jne .check_apicid 52 | 53 | .check_command: 54 | mov eax, dword ptr[rbx + CommandOffset] 55 | cmp eax, MpProtectedModeWakeupCommandNoop 56 | je .check_apicid 57 | 58 | cmp eax, MpProtectedModeWakeupCommandWakeup 59 | je .wakeup 60 | 61 | jmp .check_apicid 62 | 63 | .wakeup: 64 | # 65 | # BSP sets these variables before unblocking APs 66 | mov rax, 0 67 | mov eax, dword ptr[rbx + WakeupVectorOffset] 68 | 69 | # 70 | # Clear the command as the acknowledgement that the wake up command is received 71 | mov qword ptr[rbx + CommandOffset], MpProtectedModeWakeupCommandNoop 72 | nop 73 | jmp rax 74 | 75 | .panic: 76 | ud2 77 | 78 | .global ap_relocated_func_end 79 | ap_relocated_func_end: 80 | jmp .panic 81 | -------------------------------------------------------------------------------- /sh_script/launch-rust-td.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Default values 4 | QEMU_PATH="/usr/libexec/qemu-kvm" 5 | BIOS_IMAGE="final.bin" 6 | CPUS=1 7 | MEM="1G" 8 | 9 | # Function to display usage 10 | usage() { 11 | echo "Usage: $0 [options]" 12 | echo "Options:" 13 | echo " -p Specify the QEMU executable path. Default is /usr/libexec/qemu-kvm." 14 | echo " -c Number of CPUs. Default is 1." 15 | echo " -m Memory size. Default is 1G." 16 | echo " -b Path to the BIOS image file. Default is final.bin." 17 | echo " -h Display this help message and exit." 18 | exit 1 19 | } 20 | 21 | # Parse command line options 22 | while getopts ":p:c:m:b:h" opt; do 23 | case $opt in 24 | p) 25 | QEMU_PATH="$OPTARG" 26 | ;; 27 | c) 28 | CPUS="$OPTARG" 29 | ;; 30 | m) 31 | MEM="$OPTARG" 32 | ;; 33 | b) 34 | BIOS_IMAGE="$OPTARG" 35 | ;; 36 | h) 37 | usage 38 | ;; 39 | \?) 40 | echo "Invalid option: -$OPTARG" >&2 41 | usage 42 | ;; 43 | :) 44 | echo "Option -$OPTARG requires an argument." >&2 45 | usage 46 | ;; 47 | esac 48 | done 49 | 50 | # Timestamp for logfile 51 | now=$(date +"%m%d_%H%M") 52 | LOGFILE=stdout.${now}.log 53 | 54 | # Check QEMU version for memory backend options 55 | QEMU_VERSION=$(${QEMU_PATH} --version | grep -oP 'version \K[^\s]+') 56 | if [ "$(printf '%s\n' "8.0.0" "${QEMU_VERSION}" | sort -V | head -n1)" == "8.0.0" ]; then 57 | MEMORY_BACKEND="-object memory-backend-ram,id=ram1,size=${MEM},private=on" 58 | else 59 | MEMORY_BACKEND="-object memory-backend-memfd-private,id=ram1,size=${MEM}" 60 | fi 61 | 62 | # Construct the QEMU command 63 | QEMU_CMD="${QEMU_PATH} -accel kvm \ 64 | -name process=rust-td,debug-threads=on \ 65 | -smp ${CPUS} \ 66 | -object tdx-guest,id=tdx,debug=on \ 67 | -machine q35,memory-backend=ram1,kernel_irqchip=split,confidential-guest-support=tdx \ 68 | -no-hpet \ 69 | -cpu host,pmu=off,-kvm-steal-time \ 70 | -bios ${BIOS_IMAGE} \ 71 | -m ${MEM} -nographic -vga none \ 72 | -chardev stdio,id=mux,mux=on,signal=off \ 73 | -device virtio-serial,romfile= \ 74 | -device virtconsole,chardev=mux -serial chardev:mux -monitor chardev:mux \ 75 | -d int -no-reboot ${MEMORY_BACKEND}" 76 | 77 | # Execute the QEMU command and redirect output to logfile 78 | $QEMU_CMD 2>&1 | tee "${LOGFILE}" 79 | -------------------------------------------------------------------------------- /tdx-tdcall/src/asm/tdcall.asm: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020-2022 Intel Corporation 2 | # SPDX-License-Identifier: BSD-2-Clause-Patent 3 | 4 | .section .text 5 | 6 | # Arguments offsets in TdVmcallArgs struct 7 | .equ TDCALL_ARG_RAX, 0x0 8 | .equ TDCALL_ARG_RCX, 0x8 9 | .equ TDCALL_ARG_RDX, 0x10 10 | .equ TDCALL_ARG_R8, 0x18 11 | .equ TDCALL_ARG_R9, 0x20 12 | .equ TDCALL_ARG_R10, 0x28 13 | .equ TDCALL_ARG_R11, 0x30 14 | .equ TDCALL_ARG_R12, 0x38 15 | .equ TDCALL_ARG_R13, 0x40 16 | 17 | # asm_td_call -> u64 ( 18 | # args: *mut TdcallArgs, //rcx 19 | # ) 20 | .global asm_td_call 21 | asm_td_call: 22 | endbr64 23 | # Save the registers accroding to MS x64 calling convention 24 | push rbp 25 | mov rbp, rsp 26 | push r15 27 | push r14 28 | push r13 29 | push r12 30 | push rbx 31 | push rsi 32 | push rdi 33 | push rcx 34 | 35 | # Use RDI to save RCX value 36 | mov rdi, rcx 37 | 38 | # Test if input pointer is valid 39 | test rdi, rdi 40 | jz td_call_exit 41 | 42 | # Copy the input operands from memory to registers 43 | mov rax, [rdi + TDCALL_ARG_RAX] 44 | mov rcx, [rdi + TDCALL_ARG_RCX] 45 | mov rdx, [rdi + TDCALL_ARG_RDX] 46 | mov r8, [rdi + TDCALL_ARG_R8] 47 | mov r9, [rdi + TDCALL_ARG_R9] 48 | mov r10, [rdi + TDCALL_ARG_R10] 49 | mov r11, [rdi + TDCALL_ARG_R11] 50 | mov r12, [rdi + TDCALL_ARG_R12] 51 | mov r13, [rdi + TDCALL_ARG_R13] 52 | 53 | # tdcall 54 | .byte 0x66,0x0f,0x01,0xcc 55 | 56 | # On TDVM exit, RDI loses the RCX value (TdVmcallArgs struct) that was saved earlier. 57 | # so pop saved RCX back to RDI. 58 | # Note: TDG.VP.ENTER uses RDI to store CS base address but since it is not used, RDI is 59 | # repurposed here. 60 | pop rdi 61 | 62 | # Copy the output operands from registers to the struct 63 | mov [rdi + TDCALL_ARG_RAX], rax 64 | mov [rdi + TDCALL_ARG_RCX], rcx 65 | mov [rdi + TDCALL_ARG_RDX], rdx 66 | mov [rdi + TDCALL_ARG_R8], r8 67 | mov [rdi + TDCALL_ARG_R9], r9 68 | mov [rdi + TDCALL_ARG_R10], r10 69 | mov [rdi + TDCALL_ARG_R11], r11 70 | mov [rdi + TDCALL_ARG_R12], r12 71 | mov [rdi + TDCALL_ARG_R13], r13 72 | 73 | td_call_exit: 74 | # Restore saved RCX value 75 | mov rcx, rdi 76 | # Pop out saved registers from stack 77 | pop rdi 78 | pop rsi 79 | pop rbx 80 | pop r12 81 | pop r13 82 | pop r14 83 | pop r15 84 | pop rbp 85 | 86 | ret 87 | -------------------------------------------------------------------------------- /td-shim-tools/src/bin/td-shim-strip-info/readme.md: -------------------------------------------------------------------------------- 1 | # td-shim-strip-info 2 | 3 | ## Background 4 | 5 | Elements break reproducible build (x86_64-unknown-uefi + target x86_64-unknown-none)
6 |
7 | ``` 8 | 1. Debug related sections (PE + ELF) 9 | 2. Code base path like \home\USERNAME\rust-td-payload\xxx\xxx.rs (PE + ELF) 10 | 3. CARGO_HOME like \home\USERNAME\.cargo\xxx\xxx.rs (PE + ELF) 11 | 4. RUSTUP_HOME like \home\USERNAME\.rustup\xxx\xxx.rs (PE + ELF) 12 | 5. TimeDateStamp field in COFF file header (PE only) 13 | ``` 14 | 15 | Solution:
16 | 17 | ``` 18 | 1. Use strip = "symbols" option to [profile.release] 19 | 2. Use strip = "symbols" option to [profile.release] 20 | 3. Use a post-build tool to zero CARGO_HOME string 21 | 4. Use a post-build tool to zero RUSTUP_HOME string 22 | 5. Use a post-build tool to zero TimeDateStamp for PE 23 | ``` 24 | NOTE: 3 and 4 may be resolved directly after rust-lang RFC 3127. This tool provide a temp solution to solve 3 and 4 before RFC is implemented. 25 | 26 | NOTE: 1 and 2 are not applied because this strip feature has potential stability issue. For example, [bug](https://github.com/confidential-containers/td-shim/issues/272). It can be enabled after the strip becomes more robust. 27 | 28 | ## tool usage 29 | 30 | ``` 31 | td-shim-strip-info [OPTIONS] 32 | 33 | TD SHIM STRIP INFO TOOL 34 | 35 | Optional arguments: 36 | -h,--help Show this help message and exit 37 | -w,--workspace WORKSPACE 38 | Where to find the target folder. 39 | -n,--name NAME Name for the compiled binary. 40 | -t,--target TARGET The built target to find. 41 | -p,--profile PROFILE The built profile to find. 42 | -c,--cargo_home CARGO_HOME 43 | The cargo home. If not specify, system variable CARGO_HOME will be searched. 44 | -r,--rustup_home RUSTUP_HOME 45 | The rustup home. If not specify, system variable RUSTUP_HOME will be searched. 46 | -v,--verbose Verbose output. 47 | -s,--strip_path Strip rust file path. 48 | ``` 49 | 50 | example:
51 | Command used under x86_64-unknown-uefi target: 52 | ``` 53 | cargo run -p td-shim-tools --bin td-shim-strip-info -- -n rust-td-payload --target x86_64-unknown-uefi -p release -v 54 | ``` 55 | is equal to 56 | ``` 57 | cargo run -p td-shim-tools --bin td-shim-strip-info -- -w "." -n rust-td-payload.efi -t x86_64-unknown-uefi -p release -v 58 | ``` 59 |
60 | Command used under x86_64-unknown-none target: 61 | 62 | ``` 63 | cargo run -p td-shim-tools --bin td-shim-strip-info -- -n rust-td-payload --target x86_64-unknown-none -p release -v 64 | ``` -------------------------------------------------------------------------------- /devtools/test-runner-client/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2019 Intel Corporation 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #![no_std] 16 | 17 | use core::any; 18 | use core::panic::PanicInfo; 19 | use linked_list_allocator::LockedHeap; 20 | 21 | pub mod serial; 22 | 23 | #[panic_handler] 24 | pub fn panic(info: &PanicInfo) -> ! { 25 | serial_println!("[failed]\n"); 26 | serial_println!("Error: {}\n", info); 27 | exit_qemu(QemuExitCode::Failed); 28 | } 29 | 30 | #[global_allocator] 31 | pub static ALLOCATOR: LockedHeap = LockedHeap::empty(); 32 | 33 | pub fn init_heap(heap_start: usize, heap_size: usize) { 34 | unsafe { 35 | ALLOCATOR.lock().init(heap_start as *mut u8, heap_size); 36 | } 37 | } 38 | 39 | /// Unit test runner to hook the rust test harness. 40 | /// 41 | /// The `custom_test_frameworks` feature allows the use of `#[test_case]` and `#![test_runner]`. 42 | /// Any function, const, or static can be annotated with `#[test_case]` causing it to be aggregated 43 | /// (like #[test]) and be passed to the test runner determined by the `#![test_runner]` crate 44 | /// attribute. 45 | pub fn test_runner(tests: &[&dyn Testable]) { 46 | serial_println!("Running {} tests", tests.len()); 47 | for test in tests { 48 | test.run(); 49 | } 50 | exit_qemu(QemuExitCode::Success); 51 | } 52 | 53 | /// Trait for unit test functions. 54 | pub trait Testable { 55 | fn run(&self); 56 | } 57 | 58 | impl Testable for T 59 | where 60 | T: Fn(), 61 | { 62 | fn run(&self) { 63 | serial_print!("{}...\t", any::type_name::()); 64 | self(); 65 | serial_println!("[ok]"); 66 | } 67 | } 68 | 69 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 70 | #[repr(u32)] 71 | pub enum QemuExitCode { 72 | Success = 0x10, 73 | Failed = 0x11, 74 | } 75 | 76 | /// Notify qemu hypervisor to exit, with exit code. 77 | #[allow(clippy::empty_loop)] 78 | pub fn exit_qemu(exit_code: QemuExitCode) -> ! { 79 | use x86_64::instructions::port::Port; 80 | 81 | unsafe { 82 | let mut port = Port::new(0xf4); 83 | port.write(exit_code as u32); 84 | } 85 | 86 | loop {} 87 | } 88 | -------------------------------------------------------------------------------- /library/patches/0002-Disable-checks-for-SSE-and-SSE2.patch: -------------------------------------------------------------------------------- 1 | From e6dd2c965fb14b3ca3c20005f16d727ee12b589f Mon Sep 17 00:00:00 2001 2 | From: Zbigniew Lukwinski 3 | Date: Fri, 14 Mar 2025 11:07:55 +0100 4 | Subject: [PATCH] Disable checks for SSE and SSE2 5 | 6 | Signed-off-by: Zbigniew Lukwinski 7 | --- 8 | src/cpu/intel.rs | 16 ++++++++-------- 9 | 1 file changed, 8 insertions(+), 8 deletions(-) 10 | 11 | diff --git a/src/cpu/intel.rs b/src/cpu/intel.rs 12 | index f45052fe7..9c3ac044e 100644 13 | --- a/src/cpu/intel.rs 14 | +++ b/src/cpu/intel.rs 15 | @@ -22,8 +22,8 @@ mod abi_assumptions { 16 | // https://github.com/briansmith/ring/issues/1793#issuecomment-1793243725, 17 | // https://github.com/briansmith/ring/issues/1832, 18 | // https://github.com/briansmith/ring/issues/1833. 19 | - const _ASSUMES_SSE2: () = 20 | - assert!(cfg!(target_feature = "sse") && cfg!(target_feature = "sse2")); 21 | + // const _ASSUMES_SSE2: () = 22 | + // assert!(cfg!(target_feature = "sse") && cfg!(target_feature = "sse2")); 23 | 24 | #[cfg(target_arch = "x86_64")] 25 | const _ASSUMED_POINTER_SIZE: usize = 8; 26 | @@ -156,8 +156,8 @@ fn cpuid_to_caps_and_set_c_flags(cpuid: &[u32; 4]) -> u32 { 27 | // CMOV, it is likely that some of our timing side channel prevention does 28 | // not work. Presumably the people who delete these are verifying that it 29 | // all works fine. 30 | - const _SSE_REQUIRED: () = assert!(cfg!(target_feature = "sse")); 31 | - const _SSE2_REQUIRED: () = assert!(cfg!(target_feature = "sse2")); 32 | + // const _SSE_REQUIRED: () = assert!(cfg!(target_feature = "sse")); 33 | + // const _SSE2_REQUIRED: () = assert!(cfg!(target_feature = "sse2")); 34 | 35 | #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] 36 | { 37 | @@ -184,10 +184,10 @@ fn cpuid_to_caps_and_set_c_flags(cpuid: &[u32; 4]) -> u32 { 38 | // assertions in an attempt to support pre-SSE2 32-bit x86 systems. If they 39 | // do, hopefully they won't delete these redundant assertions, so that 40 | // x86_64 isn't affected. 41 | - #[cfg(target_arch = "x86_64")] 42 | - const _SSE2_REQUIRED_X86_64: () = assert!(cfg!(target_feature = "sse2")); 43 | - #[cfg(target_arch = "x86_64")] 44 | - const _SSE_REQUIRED_X86_64: () = assert!(cfg!(target_feature = "sse2")); 45 | + // #[cfg(target_arch = "x86_64")] 46 | + // const _SSE2_REQUIRED_X86_64: () = assert!(cfg!(target_feature = "sse2")); 47 | + // #[cfg(target_arch = "x86_64")] 48 | + // const _SSE_REQUIRED_X86_64: () = assert!(cfg!(target_feature = "sse2")); 49 | 50 | // Intel: "12.7.2 Checking for SSSE3 Support" 51 | // If/when we support dynamic detection of SSE/SSE2, make this conditional 52 | -- 53 | 2.34.1 54 | 55 | -------------------------------------------------------------------------------- /td-shim-tools/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "td-shim-tools" 3 | version = "0.1.0" 4 | description = "A set of tools to manipulate td-shim binary" 5 | repository = "https://github.com/confidential-containers/td-shim" 6 | homepage = "https://github.com/confidential-containers" 7 | license = "BSD-2-Clause-Patent" 8 | edition = "2018" 9 | 10 | [[bin]] 11 | name = "td-shim-enroll" 12 | required-features = ["enroller"] 13 | 14 | [[bin]] 15 | name = "td-shim-ld" 16 | required-features = ["linker"] 17 | 18 | [[bin]] 19 | name = "td-shim-sign-payload" 20 | required-features = ["signer"] 21 | 22 | [[bin]] 23 | name = "td-shim-checker" 24 | required-features = ["loader"] 25 | 26 | [[bin]] 27 | name = "td-shim-strip-info" 28 | 29 | [[bin]] 30 | name = "td-shim-tee-info-hash" 31 | required-features = ["tee"] 32 | 33 | [[bin]] 34 | name = "td-payload-reference-calculator" 35 | required-features = ["calculator"] 36 | 37 | [dependencies] 38 | r-efi = "3.2.0" 39 | argparse = "0.2.2" 40 | zeroize = "1.5.4" 41 | regex = "1" 42 | scroll = { version = "0.10", default-features = false, features = ["derive"]} 43 | td-layout = { path = "../td-layout" } 44 | td-shim = { path = "../td-shim", default-features = false } 45 | td-shim-interface = { path = "../td-shim-interface" } 46 | cfg-if = "1.0" 47 | 48 | anyhow = { version = "1.0.68", optional = true } 49 | block-padding = { version = "0.3.2", optional = true } 50 | clap = { version = "4.0", features = ["cargo"], optional = true } 51 | der = { version = "0.4.5", features = ["oid"], optional = true } 52 | env_logger = { version = "0.10", optional = true } 53 | log = { version = "0.4.5", optional = true } 54 | td-loader = { path = "../td-loader", optional = true } 55 | ring = { version = "0.17.14", optional = true } 56 | serde_json = { version = "1.0", optional = true } 57 | serde = { version = "1.0", features = ["derive"], optional = true } 58 | hex = { version = "0.4", features = ["serde"], optional = true } 59 | sha2 = { version = "0.10.2", optional = true } 60 | byteorder = { version = "1.4.3", optional = true } 61 | parse_int = { version = "0.6.0", optional = true } 62 | igvm = "0.3.4" 63 | igvm_defs = "0.3.4" 64 | zerocopy = { version = "0.8.14", features = ["derive"]} 65 | 66 | [features] 67 | default = ["enroller", "linker", "signer", "loader", "tee", "calculator"] 68 | enroller = ["clap", "der", "env_logger", "log", "ring", "td-shim/secure-boot"] 69 | linker = ["clap", "env_logger", "log", "parse_int", "serde_json", "serde", "td-loader"] 70 | signer = ["clap", "der", "env_logger", "log", "ring", "td-shim/secure-boot"] 71 | loader = ["clap", "env_logger", "log", "anyhow"] 72 | tee = ["clap", "env_logger", "log", "serde_json", "serde", "hex", "sha2", "byteorder"] 73 | calculator = ["clap", "hex", "parse_int", "sha2", "anyhow", "block-padding"] 74 | exec-payload-section = [] 75 | no-config = [] 76 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | paths-ignore: 4 | - "**.md" 5 | pull_request: 6 | paths-ignore: 7 | - "**.md" 8 | workflow_dispatch: 9 | 10 | name: Build 11 | 12 | env: 13 | AS: nasm 14 | AR_x86_64_unknown_linux_gnu: llvm-ar 15 | CC_x86_64_unknown_linux_gnu: clang 16 | AR_x86_64_unknown_none: llvm-ar 17 | CC_x86_64_unknown_none: clang 18 | RUST_TOOLCHAIN: 1.88.0 19 | TOOLCHAIN_PROFILE: minimal 20 | 21 | jobs: 22 | system_compile: 23 | name: Compile the final.bin file 24 | runs-on: ${{ matrix.host_os }} 25 | timeout-minutes: 30 26 | 27 | strategy: 28 | matrix: 29 | host_os: 30 | - ubuntu-22.04 31 | - windows-2022 32 | steps: 33 | # Install first since it's needed to build NASM 34 | - name: Install LLVM and Clang 35 | uses: KyleMayes/install-llvm-action@v2 36 | with: 37 | version: "10.0" 38 | directory: ${{ runner.temp }}/llvm 39 | 40 | - name: install NASM 41 | uses: ilammy/setup-nasm@v1 42 | 43 | - name: Checkout sources 44 | uses: actions/checkout@v6 45 | with: 46 | submodules: recursive 47 | 48 | - name: Install toolchain 49 | uses: dtolnay/rust-toolchain@master 50 | with: 51 | toolchain: ${{ env.RUST_TOOLCHAIN }} 52 | components: rust-src 53 | 54 | - name: Add `x86_64-unknown-none` target 55 | run: rustup target add x86_64-unknown-none 56 | 57 | - name: Preparation Work 58 | run: bash sh_script/preparation.sh 59 | 60 | - name: Install libtinfo5 61 | run: sudo apt-get update -y && sudo apt-get install libtinfo5 -y 62 | if: runner.os == 'Linux' 63 | 64 | - name: Test Shim Crates 65 | run: make test 66 | 67 | - name: Build Release TdShim 68 | run: cargo build -p td-shim --target x86_64-unknown-none --release --features=main,tdx 69 | 70 | - name: Build Debug TdShim 71 | run: cargo build -p td-shim --target x86_64-unknown-none --features=main,tdx --no-default-features 72 | 73 | - name: Build td-shim-tools 74 | run: | 75 | cargo build -p td-shim-tools 76 | 77 | - name: Build image without payload 78 | run: | 79 | cargo image --release 80 | 81 | - name: Meta data check 82 | run: | 83 | cargo run -p td-shim-tools --bin td-shim-checker --no-default-features --features=loader -- target/release/final.bin 84 | 85 | - name: Build debug image without payload 86 | run: | 87 | cargo image 88 | 89 | - name: Build Release Elf format payload 90 | run: | 91 | cargo image --example-payload --release 92 | 93 | - name: Build Debug Elf format payload 94 | run: | 95 | cargo image --example-payload 96 | --------------------------------------------------------------------------------