-
Notifications
You must be signed in to change notification settings - Fork 40
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
base: main
Are you sure you want to change the base?
Conversation
285a867
to
a323d9f
Compare
Will update this PR again after #432 is merged since that impacts our stage1 trampoline logic |
a323d9f
to
01a984d
Compare
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]>
01a984d
to
c70ec34
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I 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.
fn validate_page_range( | ||
&self, | ||
region: MemoryRegion<VirtAddr>, | ||
paddr: PhysAddr, | ||
) -> Result<(), SvsmError>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This 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()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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..."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This 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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for catching this! Will fix in my update.
@@ -52,6 +55,33 @@ impl IOPort for SVSMIOPort { | |||
} | |||
} | |||
|
|||
#[derive(Clone, Copy, Debug, Default)] | |||
pub struct SvsmTdIOPort {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we 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).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the reason for this change? Is this related to TDP?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this bled into the patchset when I created this PR. I can just create a clean-up patch for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. I wasn't planning on tackling this in this PR yet but this becomes easier with a common SVSMIOPort
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe add a TODO
comment to point out that this is a known future work item.
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.