Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

stage2: add TD Partitioning support #419

Open
wants to merge 11 commits into
base: main
Choose a base branch
from

Conversation

peterfang
Copy link
Contributor

This is the second half of the TDX enabling work in stage2. It enables SVSM running on a TDP platform to boot until the last jump in stage2_main(). It also adds support for serial console.

@peterfang peterfang force-pushed the dev-tdp-stage2 branch 2 times, most recently from 285a867 to a323d9f Compare July 31, 2024 05:48
@peterfang
Copy link
Contributor Author

peterfang commented Aug 5, 2024

Will update this PR again after #432 is merged since that impacts our stage1 trampoline logic

@peterfang
Copy link
Contributor Author

PR updated. TDP boots stage2 with stage2 moved to 8MB.

Since both the stage2 bootloader and the SVSM kernel dump the CPUID
page, there needs to be a page present at the respective GPA on TDP
platforms. Insert a normal zero page at the CPUID page location so that
dump_cpuid_table() can work as expected.

Signed-off-by: Peter Fang <[email protected]>
Since the SVSM kernel touches the secrets page in svsm_start(), there
needs to be a page present at the respective GPA on TDP platforms.
Insert a normal zero page at the secrets page location so that the SVSM
kernel can touch it without issues.

Signed-off-by: Peter Fang <[email protected]>
Clean up formatting and crate ordering.

Signed-off-by: Peter Fang <[email protected]>
Add the tdx-tdcall crate in preparation for the upcoming TDX enabling
changes.

Signed-off-by: Peter Fang <[email protected]>
Stage2LaunchInfo has been increased to 48 bytes. Make the according
changes in stage1 trampoline.

Signed-off-by: Peter Fang <[email protected]>
Setting the initial location counter has no effect since all of the
addresses before edata are derived based on the subsequent locations.

Signed-off-by: Peter Fang <[email protected]>
Add the TDX implementation of IOPort. This implementation translates all
of the in/out operations to TDVMCALL operations as required by the GHCI
spec.

Signed-off-by: Peter Fang <[email protected]>
Rename struct SVSMIOPort for clarity and distinction from the TDX
implementation.

Signed-off-by: Peter Fang <[email protected]>
phys_addr_sizes should be the entirety of CPUID leaf 0x80000008.EAX, not
just the Physical Address Bits field.

Signed-off-by: Peter Fang <[email protected]>
validate_page_range() currently takes GVA due to the design of
PVALIDATE. In the case of TDX, GPA is required for page acceptance.

Add an additional input, paddr (PhysAddr), to validate_page_range(). An
explicit input for GPA is required because virt_to_phys() is not always
available. The input region may be out of range for the current
FIXED_MAPPING.

Signed-off-by: Peter Fang <[email protected]>
On TDP platforms, validate_page_range() means page acceptance. Use the
tdx-tdcall crate for this TDCALL operation.

Signed-off-by: Peter Fang <[email protected]>
@joergroedel joergroedel added the wait-for-review PR needs for approval by reviewers label Aug 27, 2024
Copy link
Member

@joergroedel joergroedel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pointed out two problems which need fixing, other than that it looks good to me. With the log::info! issue fixed it boots for me on SNP and testing passes.

Comment on lines +86 to +90
fn validate_page_range(
&self,
region: MemoryRegion<VirtAddr>,
paddr: PhysAddr,
) -> Result<(), SvsmError>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This interface change puzzles me a bit. I imposes certain constraints on the method caller (like that the virtual region maps physically contiguous memory).
At least the interface needs to be documented after that change. In general I think it is possible to get the physical address from within the method. Stage2 is identity-mapped and for the COCONUT kernel there is virt_to_phys().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

virt_to_phys() is limited in stage2 because FIXED_MAPPING is only limited to the first 640KB + the stage2 area, despite the fact that INIT_PGTABLE continues to be updated in map_and_validate(). Do you think we should try to improve virt_to_phys() instead so that it tracks the new page table mappings?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

validate_page_range() should really operate on a physical range, because all platforms consider the concept of "validation" as a property of GPAs. The fact that we use virtual addresses anywhere is an artifact of how PVALIDATE works on SNP. The best approach here would be to have valid_page_range() take a physical address range, and then on platforms that require virtual mappings (like SNP), to use phys_to_virt() or a temporary per-CPU virtual mapping to complete the request.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After taking a closer look, I think this is a big hack that really shouldn't be checked in. Yes, validate_page_range() should take a physical address span, but it should not also take a virtual address which might or might not have anything to do with the physical address. I will take a stab at changing the interface to use physical addresses (with per-CPU temporary mappings on SNP to obtain the virtual addresses required by PVALIDATE).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good. Will rebase this commit after your changes are merged.

@@ -440,6 +440,8 @@ pub extern "C" fn stage2_main(launch_info: &Stage2LaunchInfo) {
// Shut down the GHCB
shutdown_percpu();

log::info!("Starting SVSM kernel...");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to happen before shutdown_percpu(), otherwise it crashes on SNP. The shutdown_percpu() function also shuts down the GHCB on SNP which is required for serial port access, and as a consequence also to print any log messages.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for catching this! Will fix in my update.

@joergroedel joergroedel added wait-for-update PR is waiting to be updated to address review comments and removed wait-for-review PR needs for approval by reviewers labels Aug 27, 2024
@@ -52,6 +55,33 @@ impl IOPort for SVSMIOPort {
}
}

#[derive(Clone, Copy, Debug, Default)]
pub struct SvsmTdIOPort {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we not just change SVSMIOPort to use IN and OUT instructions natively, and then have the #VC handler issue GHCB calls and the #VE handler issue GHCI calls? This seems like it would be much cleaner because it restricts platform-specific functionality to code paths that are already platform-specific (exception handlers) instead of common code (the console code).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good to me. I can make that change if it's fine by @joergroedel .

@@ -215,7 +215,7 @@ impl WriteLockGuard<'static, IDT> {
/// Load an IDT. Its lifetime must be static so that its entries are
/// always available to the CPU.
pub fn load(&self) {
let desc: IdtDesc = IdtDesc {
let desc = IdtDesc {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the reason for this change? Is this related to TDP?

Copy link
Contributor Author

@peterfang peterfang Sep 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this bled into the patchset when I created this PR. I can just create a clean-up patch for this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I always prefer when the set of changes in a patch is limited to work described in the PR summary - i.e., that each patch be minimal and specific. Others may feel differently.

@@ -173,7 +173,7 @@ pub mod svsm_gdbstub {

static GDB_INITIALISED: AtomicBool = AtomicBool::new(false);
static GDB_STATE: SpinLock<Option<SvsmGdbStub<'_>>> = SpinLock::new(None);
static GDB_IO: SVSMIOPort = SVSMIOPort::new();
static GDB_IO: SvsmSevIOPort = SvsmSevIOPort::new();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this going to be problematic when we finally make GDB work on TDP? Wouldn't it be better to define a platform abstraction now since you are already forced to touch this code?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. I wasn't planning on tackling this in this PR yet but this becomes easier with a common SVSMIOPort.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a TODO comment to point out that this is a known future work item.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
wait-for-update PR is waiting to be updated to address review comments
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants