Skip to content

Commit

Permalink
tdx-tdcall: handle the retry result of mapgpa
Browse files Browse the repository at this point in the history
According to GHCI specification, if `TDG.VP.VMCALL_RETRY` is returned,
TD must retry the mapping for the pages in the region starting at the
GPA specified in r11.

Signed-off-by: Jiaqi Gao <[email protected]>
  • Loading branch information
gaojiaqi7 authored and jyao1 committed Oct 26, 2023
1 parent 2436aba commit 3f18d9f
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 20 deletions.
1 change: 1 addition & 0 deletions tdx-tdcall/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ pub const TDCALL_STATUS_PAGE_SIZE_MISMATCH: u64 = 0xC0000B0B00000001;

// TDVMCALL completion status code
const TDVMCALL_STATUS_SUCCESS: u64 = 0;
const TDVMCALL_STATUS_RETRY: u64 = 1;

// A public wrapper for use of asm_td_vmcall, this function takes a mutable reference of a
// TdcallArgs structure to ensure the input is valid
Expand Down
63 changes: 43 additions & 20 deletions tdx-tdcall/src/tdx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,32 +282,55 @@ pub fn tdvmcall_mmio_read<T: Clone + Copy + Sized>(address: usize) -> T {
/// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL<MapGPA>'
pub fn tdvmcall_mapgpa(shared: bool, paddr: u64, length: usize) -> Result<(), TdVmcallError> {
let share_bit = *SHARED_MASK;
let paddr = if shared {
let mut map_start = if shared {
paddr | share_bit
} else {
paddr & (!share_bit)
};

let mut args = TdVmcallArgs {
r11: TDVMCALL_MAPGPA,
r12: paddr,
r13: length as u64,
..Default::default()
};

let ret = td_vmcall(&mut args);

if ret != TDVMCALL_STATUS_SUCCESS {
return Err(ret.into());
let map_end = map_start
.checked_add(length as u64)
.ok_or(TdVmcallError::Other)?;

const MAX_RETRIES_PER_PAGE: usize = 3;
let mut retry_counter = 0;

while retry_counter < MAX_RETRIES_PER_PAGE {
log::trace!(
"tdvmcall mapgpa - start: {:x}, length: {:x}\n",
map_start,
map_end - map_start,
);
let mut args = TdVmcallArgs {
r11: TDVMCALL_MAPGPA,
r12: map_start,
r13: map_end - map_start,
..Default::default()
};

let ret = td_vmcall(&mut args);
if ret == TDVMCALL_STATUS_SUCCESS {
return Ok(());
} else if ret != TDVMCALL_STATUS_RETRY {
return Err(ret.into());
}

let retry_addr = args.r11;
if retry_addr < map_start || retry_addr >= map_end {
return Err(TdVmcallError::Other);
}

// Increase the retry count for the current page
if retry_addr == map_start {
retry_counter += 1;
continue;
}

// Failed in a new address, update the `map_start` and reset counter
map_start = retry_addr;
retry_counter = 0;
}

log::trace!(
"tdvmcall mapgpa - paddr: {:x}, length: {:x}\n",
paddr,
length
);

Ok(())
Err(TdVmcallError::Other)
}

/// Used to help perform RDMSR operation.
Expand Down

0 comments on commit 3f18d9f

Please sign in to comment.