Skip to content

Commit 777b393

Browse files
authored
hcl: Private generalized get_vp_register functions (#1643)
The generalized functions here should not be used unless we know the register is partition-wide, and not per-VP. This is easy to do accidentally. Make these functions private so this is harder, and add specialized accessors for some known good cases. Fix the bad case in the tlb lock check.
1 parent 8f1faf2 commit 777b393

File tree

4 files changed

+76
-38
lines changed

4 files changed

+76
-38
lines changed

openhcl/hcl/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ inspect.workspace = true
1919
user_driver.workspace = true
2020

2121
anyhow.workspace = true
22-
bitvec.workspace = true
22+
bitvec = { workspace = true, features = ["std"] }
2323
parking_lot.workspace = true
2424
signal-hook.workspace = true
2525
thiserror.workspace = true

openhcl/hcl/src/ioctl.rs

Lines changed: 55 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1431,7 +1431,7 @@ impl MshvHvcall {
14311431
/// Get a single VP register for the given VTL via hypercall. Only a select
14321432
/// set of registers are supported; others will cause a panic.
14331433
#[cfg(guest_arch = "x86_64")]
1434-
pub fn get_vp_register_for_vtl(
1434+
fn get_vp_register_for_vtl(
14351435
&self,
14361436
vtl: HvInputVtl,
14371437
name: HvX64RegisterName,
@@ -1473,7 +1473,7 @@ impl MshvHvcall {
14731473
/// Get a single VP register for the given VTL via hypercall. Only a select
14741474
/// set of registers are supported; others will cause a panic.
14751475
#[cfg(guest_arch = "aarch64")]
1476-
pub fn get_vp_register_for_vtl(
1476+
fn get_vp_register_for_vtl(
14771477
&self,
14781478
vtl: HvInputVtl,
14791479
name: HvArm64RegisterName,
@@ -1796,9 +1796,7 @@ impl<'a, T: Backing<'a>> ProcessorRunner<'a, T> {
17961796
actions.flush();
17971797
}
17981798
}
1799-
}
18001799

1801-
impl<'a, T: Backing<'a>> ProcessorRunner<'a, T> {
18021800
// Registers that are shared between VTLs need to be handled by the kernel
18031801
// as they may require special handling there. set_reg and get_reg will
18041802
// handle these registers using a dedicated ioctl, instead of the general-
@@ -1865,7 +1863,7 @@ impl<'a, T: Backing<'a>> ProcessorRunner<'a, T> {
18651863
Ok(())
18661864
}
18671865

1868-
fn get_reg(&mut self, vtl: GuestVtl, regs: &mut [HvRegisterAssoc]) -> Result<(), Error> {
1866+
fn get_reg(&mut self, vtl: Vtl, regs: &mut [HvRegisterAssoc]) -> Result<(), Error> {
18691867
if regs.is_empty() {
18701868
return Ok(());
18711869
}
@@ -2040,9 +2038,7 @@ impl<'a, T: Backing<'a>> ProcessorRunner<'a, T> {
20402038
pub fn is_sidecar(&self) -> bool {
20412039
self.sidecar.is_some()
20422040
}
2043-
}
20442041

2045-
impl<'a, T: Backing<'a>> ProcessorRunner<'a, T> {
20462042
fn get_vp_registers_inner<R: Copy + Into<HvRegisterName>>(
20472043
&mut self,
20482044
vtl: GuestVtl,
@@ -2065,7 +2061,7 @@ impl<'a, T: Backing<'a>> ProcessorRunner<'a, T> {
20652061
}
20662062
}
20672063

2068-
self.get_reg(vtl, &mut assoc)?;
2064+
self.get_reg(vtl.into(), &mut assoc)?;
20692065
for (&i, assoc) in offset.iter().zip(&assoc) {
20702066
values[i] = assoc.value;
20712067
}
@@ -2087,6 +2083,24 @@ impl<'a, T: Backing<'a>> ProcessorRunner<'a, T> {
20872083
Ok(value[0])
20882084
}
20892085

2086+
/// Get the following register on the current VP for VTL 2.
2087+
///
2088+
/// This will fail for registers that are in the mmapped CPU context, i.e.
2089+
/// registers that are shared between VTL0 and VTL2.
2090+
pub fn get_vp_vtl2_register(
2091+
&mut self,
2092+
#[cfg(guest_arch = "x86_64")] name: HvX64RegisterName,
2093+
#[cfg(guest_arch = "aarch64")] name: HvArm64RegisterName,
2094+
) -> Result<HvRegisterValue, Error> {
2095+
let mut assoc = [HvRegisterAssoc {
2096+
name: name.into(),
2097+
pad: Default::default(),
2098+
value: FromZeros::new_zeroed(),
2099+
}];
2100+
self.get_reg(Vtl::Vtl2, &mut assoc)?;
2101+
Ok(assoc[0].value)
2102+
}
2103+
20902104
/// Get the following VP registers on the current VP.
20912105
///
20922106
/// # Panics
@@ -2565,7 +2579,7 @@ impl Hcl {
25652579
/// Get a single VP register for the given VTL via hypercall. Only a select
25662580
/// set of registers are supported; others will cause a panic.
25672581
#[cfg(guest_arch = "x86_64")]
2568-
pub fn get_vp_register(
2582+
fn get_vp_register(
25692583
&self,
25702584
name: impl Into<HvX64RegisterName>,
25712585
vtl: HvInputVtl,
@@ -2576,7 +2590,7 @@ impl Hcl {
25762590
/// Get a single VP register for the given VTL via hypercall. Only a select
25772591
/// set of registers are supported; others will cause a panic.
25782592
#[cfg(guest_arch = "aarch64")]
2579-
pub fn get_vp_register(
2593+
fn get_vp_register(
25802594
&self,
25812595
name: impl Into<HvArm64RegisterName>,
25822596
vtl: HvInputVtl,
@@ -2933,6 +2947,37 @@ impl Hcl {
29332947
))
29342948
}
29352949

2950+
/// Get the [`hvdef::HvRegisterVsmPartitionStatus`] register
2951+
pub fn get_vsm_partition_status(&self) -> Result<hvdef::HvRegisterVsmPartitionStatus, Error> {
2952+
Ok(hvdef::HvRegisterVsmPartitionStatus::from(
2953+
self.get_vp_register(
2954+
HvAllArchRegisterName::VsmPartitionStatus,
2955+
HvInputVtl::CURRENT_VTL,
2956+
)?
2957+
.as_u64(),
2958+
))
2959+
}
2960+
2961+
#[cfg(guest_arch = "aarch64")]
2962+
/// Get the [`hvdef::HvPartitionPrivilege`] register
2963+
pub fn get_privileges_and_features_info(&self) -> Result<hvdef::HvPartitionPrivilege, Error> {
2964+
Ok(hvdef::HvPartitionPrivilege::from(
2965+
self.get_vp_register(
2966+
HvArm64RegisterName::PrivilegesAndFeaturesInfo,
2967+
HvInputVtl::CURRENT_VTL,
2968+
)?
2969+
.as_u64(),
2970+
))
2971+
}
2972+
2973+
/// Get the [`hvdef::hypercall::HvGuestOsId`] register for the given VTL.
2974+
pub fn get_guest_os_id(&self, vtl: Vtl) -> Result<hvdef::hypercall::HvGuestOsId, Error> {
2975+
Ok(hvdef::hypercall::HvGuestOsId::from(
2976+
self.get_vp_register(HvAllArchRegisterName::GuestOsId, vtl.into())?
2977+
.as_u64(),
2978+
))
2979+
}
2980+
29362981
/// Configure guest VSM.
29372982
/// The only configuration attribute currently supported is changing the maximum number of
29382983
/// guest-visible virtual trust levels for the partition. (VTL 1)

openhcl/virt_mshv_vtl/src/lib.rs

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ cfg_if::cfg_if!(
3333
type IrrBitmap = BitArray<[u32; 8], Lsb0>;
3434
} else if #[cfg(target_arch = "aarch64")] { // xtask-fmt allow-target-arch sys-crate
3535
pub use processor::mshv::arm64::HypervisorBackedArm64 as HypervisorBacked;
36-
use hvdef::HvArm64RegisterName;
3736
use processor::mshv::arm64::HypervisorBackedArm64Shared as HypervisorBackedShared;
3837
}
3938
);
@@ -59,7 +58,6 @@ use hv1_emulator::synic::SintProxied;
5958
use hv1_structs::VtlArray;
6059
use hvdef::GuestCrashCtl;
6160
use hvdef::HV_PAGE_SIZE;
62-
use hvdef::HvAllArchRegisterName;
6361
use hvdef::HvError;
6462
use hvdef::HvMapGpaFlags;
6563
use hvdef::HvRegisterName;
@@ -962,11 +960,7 @@ impl UhPartitionInner {
962960
#[cfg_attr(guest_arch = "aarch64", expect(dead_code))]
963961
fn vsm_status(&self) -> Result<HvRegisterVsmPartitionStatus, hcl::ioctl::Error> {
964962
// TODO: It might be possible to cache VsmPartitionStatus.
965-
let reg = self.hcl.get_vp_register(
966-
HvAllArchRegisterName::VsmPartitionStatus,
967-
HvInputVtl::CURRENT_VTL,
968-
)?;
969-
Ok(reg.as_u64().into())
963+
self.hcl.get_vsm_partition_status()
970964
}
971965
}
972966

@@ -1902,13 +1896,10 @@ impl UhPartition {
19021896
hv.guest_os_id(Vtl::Vtl0)
19031897
} else {
19041898
// Ask the hypervisor for this value.
1905-
let reg_value = self
1906-
.inner
1899+
self.inner
19071900
.hcl
1908-
.get_vp_register(HvAllArchRegisterName::GuestOsId, Vtl::Vtl0.into())
1909-
.map_err(Error::Hcl)?;
1910-
1911-
HvGuestOsId::from(reg_value.as_u64())
1901+
.get_guest_os_id(Vtl::Vtl0)
1902+
.map_err(Error::Hcl)?
19121903
};
19131904
Ok(id)
19141905
}
@@ -1948,19 +1939,14 @@ impl UhProtoPartition<'_> {
19481939
#[cfg(guest_arch = "x86_64")]
19491940
let privs = {
19501941
let result = safe_intrinsics::cpuid(hvdef::HV_CPUID_FUNCTION_MS_HV_FEATURES, 0);
1951-
result.eax as u64 | ((result.ebx as u64) << 32)
1942+
let num = result.eax as u64 | ((result.ebx as u64) << 32);
1943+
hvdef::HvPartitionPrivilege::from(num)
19521944
};
19531945

19541946
#[cfg(guest_arch = "aarch64")]
1955-
let privs = hcl
1956-
.get_vp_register(
1957-
HvArm64RegisterName::PrivilegesAndFeaturesInfo,
1958-
HvInputVtl::CURRENT_VTL,
1959-
)
1960-
.map_err(Error::Hcl)?
1961-
.as_u64();
1947+
let privs = hcl.get_privileges_and_features_info().map_err(Error::Hcl)?;
19621948

1963-
if !hvdef::HvPartitionPrivilege::from(privs).access_vsm() {
1949+
if !privs.access_vsm() {
19641950
return Ok(false);
19651951
}
19661952
let guest_vsm_config = hcl.get_guest_vsm_partition_config().map_err(Error::Hcl)?;

openhcl/virt_mshv_vtl/src/processor/mshv/tlb_lock.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,22 @@ impl UhProcessor<'_, HypervisorBacked> {
4949
/// Mark the TLB of the target VTL on the current VP as locked without
5050
/// informing the hypervisor. Only should be used when the hypervisor
5151
/// is expected to have already locked the TLB.
52+
#[expect(
53+
clippy::debug_assert_with_mut_call,
54+
reason = "is_tlb_locked_in_hypervisor doesn't actually mutate state"
55+
)]
5256
pub(crate) fn mark_tlb_locked(&mut self, requesting_vtl: Vtl, target_vtl: GuestVtl) {
5357
debug_assert_eq!(requesting_vtl, Vtl::Vtl2);
5458
debug_assert!(self.is_tlb_locked_in_hypervisor(target_vtl));
5559
self.vtls_tlb_locked.set(requesting_vtl, target_vtl, true);
5660
}
5761

5862
/// Check the status of the TLB lock of the target VTL on the current VP.
59-
pub(crate) fn is_tlb_locked(&self, requesting_vtl: Vtl, target_vtl: GuestVtl) -> bool {
63+
#[expect(
64+
clippy::debug_assert_with_mut_call,
65+
reason = "is_tlb_locked_in_hypervisor doesn't actually mutate state"
66+
)]
67+
pub(crate) fn is_tlb_locked(&mut self, requesting_vtl: Vtl, target_vtl: GuestVtl) -> bool {
6068
// This function should only be called in debug assertions.
6169
assert!(cfg!(debug_assertions));
6270
debug_assert_eq!(requesting_vtl, Vtl::Vtl2);
@@ -68,16 +76,15 @@ impl UhProcessor<'_, HypervisorBacked> {
6876
local_status
6977
}
7078

71-
fn is_tlb_locked_in_hypervisor(&self, target_vtl: GuestVtl) -> bool {
79+
fn is_tlb_locked_in_hypervisor(&mut self, target_vtl: GuestVtl) -> bool {
7280
// This function should only be called in debug assertions.
7381
assert!(cfg!(debug_assertions));
7482
let name = HvAllArchRegisterName(
7583
HvAllArchRegisterName::VsmVpSecureConfigVtl0.0 + target_vtl as u32,
7684
);
7785
let result = self
78-
.partition
79-
.hcl
80-
.get_vp_register(name, hvdef::hypercall::HvInputVtl::CURRENT_VTL)
86+
.runner
87+
.get_vp_vtl2_register(name.into())
8188
.expect("failure is a misconfiguration");
8289
let config = hvdef::HvRegisterVsmVpSecureVtlConfig::from(result.as_u64());
8390
config.tlb_locked()

0 commit comments

Comments
 (0)