mirror of
https://github.com/obhq/obliteration.git
synced 2024-11-26 20:50:22 +00:00
Loads ID_AA64MMFR0_EL1 from HV_FEATURE_REG_ID_AA64MMFR0_EL1 (#978)
This commit is contained in:
parent
2c7fa2d06d
commit
c41cedf00d
@ -16,7 +16,7 @@ pub fn setup_main_cpu(
|
||||
|
||||
match map.page_size.get() {
|
||||
0x4000 => {
|
||||
if !feats.tgran16 {
|
||||
if feats.mmfr0.t_gran16() == 0b0000 {
|
||||
return Err(MainCpuError::PageSizeNotSupported(map.page_size));
|
||||
}
|
||||
}
|
||||
@ -24,7 +24,7 @@ pub fn setup_main_cpu(
|
||||
}
|
||||
|
||||
// Check if CPU support at least 36 bits physical address.
|
||||
if feats.pa_range == 0 {
|
||||
if feats.mmfr0.pa_range() == 0 {
|
||||
return Err(MainCpuError::PhysicalAddressTooSmall);
|
||||
}
|
||||
|
||||
|
@ -3,40 +3,8 @@ use bitfield_struct::bitfield;
|
||||
|
||||
/// Features available on a PE.
|
||||
pub struct CpuFeats {
|
||||
/// Indicates support for disabling context synchronizing exception entry and exit.
|
||||
///
|
||||
/// - `false`: All exception entries and exits are context synchronization events.
|
||||
/// - `true`: Non-context synchronizing exception entry and exit are supported.
|
||||
pub feat_exs: bool,
|
||||
/// Indicates support for 4KB memory translation granule size.
|
||||
pub tgran4: bool,
|
||||
/// Indicates support for 64KB memory translation granule size.
|
||||
pub tgran64: bool,
|
||||
/// Indicates support for 16KB memory translation granule size.
|
||||
pub tgran16: bool,
|
||||
/// Indicates support for mixed-endian configuration.
|
||||
///
|
||||
/// - `false`: No mixed-endian support. The `SCTLR_ELx.EE` bits have a fixed value. See the
|
||||
/// [`Self::big_end_el0`], for whether EL0 supports mixed-endian.
|
||||
/// - `true`: Mixed-endian support. The `SCTLR_ELx.EE` and `SCTLR_EL1.E0E` bits can be
|
||||
/// configured.
|
||||
pub big_end: bool,
|
||||
/// Indicates support for mixed-endian at EL0 only.
|
||||
///
|
||||
/// - `false`: No mixed-endian support at EL0. The `SCTLR_EL1.E0E` bit has a fixed value.
|
||||
/// - `true`: Mixed-endian support at EL0. The `SCTLR_EL1.E0E` bit can be configured.
|
||||
pub big_end_el0: Option<bool>,
|
||||
/// Indicates support for ASID 16 bits.
|
||||
pub asid16: bool,
|
||||
/// Physical Address range supported.
|
||||
///
|
||||
/// - `0b0000`: 32 bits, 4GB.
|
||||
/// - `0b0001`: 36 bits, 64GB.
|
||||
/// - `0b0010`: 40 bits, 1TB.
|
||||
/// - `0b0011`: 42 bits, 4TB.
|
||||
/// - `0b0100`: 44 bits, 16TB.
|
||||
/// - `0b0101`: 48 bits, 256TB.
|
||||
pub pa_range: u8,
|
||||
/// Raw value of `ID_AA64MMFR0_EL1`.
|
||||
pub mmfr0: Mmfr0,
|
||||
}
|
||||
|
||||
/// Represents a value of `PSTATE`.
|
||||
@ -53,3 +21,170 @@ pub struct Pstate {
|
||||
#[bits(22)]
|
||||
__: u32,
|
||||
}
|
||||
|
||||
/// Represents a value of `ID_AA64MMFR0_EL1`.
|
||||
#[bitfield(u64)]
|
||||
pub struct Mmfr0 {
|
||||
/// Physical Address range supported.
|
||||
///
|
||||
/// - `0b0000`: 32 bits, 4GB.
|
||||
/// - `0b0001`: 36 bits, 64GB.
|
||||
/// - `0b0010`: 40 bits, 1TB.
|
||||
/// - `0b0011`: 42 bits, 4TB.
|
||||
/// - `0b0100`: 44 bits, 16TB.
|
||||
/// - `0b0101`: 48 bits, 256TB.
|
||||
/// - `0b0110`: *When FEAT_LPA is implemented or FEAT_LPA2 is implemented:* 52 bits, 4PB.
|
||||
/// - `0b0111`: *When FEAT_D128 is implemented:* 56 bits, 64PB.
|
||||
///
|
||||
/// All other values are reserved.
|
||||
#[bits(4)]
|
||||
pub pa_range: u8,
|
||||
/// Number of ASID bits.
|
||||
///
|
||||
/// - `0b0000`: 8 bits.
|
||||
/// - `0b0010`: 16 bits.
|
||||
///
|
||||
/// All other values are reserved.
|
||||
#[bits(4)]
|
||||
pub asid_bits: u8,
|
||||
/// Indicates support for mixed-endian configuration.
|
||||
///
|
||||
/// - `0b0000`: No mixed-endian support. The SCTLR_ELx.EE bits have a fixed value. See the
|
||||
/// `big_end_el0` field, for whether EL0 supports mixed-endian.
|
||||
/// - `0b0001`: Mixed-endian support. The SCTLR_ELx.EE and SCTLR_EL1.E0E bits can be configured.
|
||||
///
|
||||
/// All other values are reserved.
|
||||
#[bits(4)]
|
||||
pub big_end: u8,
|
||||
/// Indicates support for a distinction between Secure and Non-secure Memory.
|
||||
///
|
||||
/// - `0b0000`: Does not support a distinction between Secure and Non-secure Memory.
|
||||
/// - `0b0001`: Does support a distinction between Secure and Non-secure Memory.
|
||||
///
|
||||
/// All other values are reserved.
|
||||
///
|
||||
/// If EL3 is implemented, the value `0b0000` is not permitted.
|
||||
#[bits(4)]
|
||||
pub sns_mem: u8,
|
||||
/// Indicates support for mixed-endian at EL0 only.
|
||||
///
|
||||
/// - `0b0000`: No mixed-endian support at EL0. The SCTLR_EL1.E0E bit has a fixed value.
|
||||
/// - `0b0001`: Mixed-endian support at EL0. The SCTLR_EL1.E0E bit can be configured.
|
||||
///
|
||||
/// All other values are reserved.
|
||||
///
|
||||
/// This field is invalid and is `RES0` if `big_end` is not `0b0000`.
|
||||
#[bits(4)]
|
||||
pub big_end_el0: u8,
|
||||
/// Indicates support for 16KB memory translation granule size.
|
||||
///
|
||||
/// - `0b0000`: 16KB granule not supported.
|
||||
/// - `0b0001`: 16KB granule supported.
|
||||
/// - `0b0010`: *When FEAT_LPA2 is implemented:* 16KB granule supports 52-bit input addresses
|
||||
/// and can describe 52-bit output addresses.
|
||||
///
|
||||
/// All other values are reserved.
|
||||
#[bits(4)]
|
||||
pub t_gran16: u8,
|
||||
/// Indicates support for 64KB memory translation granule size.
|
||||
///
|
||||
/// - `0b0000`: 64KB granule supported.
|
||||
/// - `0b1111`: 64KB granule not supported.
|
||||
///
|
||||
/// All other values are reserved.
|
||||
#[bits(4)]
|
||||
pub t_gran64: u8,
|
||||
/// Indicates support for 4KB memory translation granule size.
|
||||
///
|
||||
/// - `0b0000`: 4KB granule supported.
|
||||
/// - `0b0001`: *When FEAT_LPA2 is implemented:* 4KB granule supports 52-bit input addresses and
|
||||
/// can describe 52-bit output addresses.
|
||||
/// - `0b1111`: 4KB granule not supported.
|
||||
///
|
||||
/// All other values are reserved.
|
||||
#[bits(4)]
|
||||
pub t_gran4: u8,
|
||||
/// Indicates support for 16KB memory granule size at stage 2.
|
||||
///
|
||||
/// - `0b0000`: Support for 16KB granule at stage 2 is identified in the `t_gran16` field.
|
||||
/// - `0b0001`: 16KB granule not supported at stage 2.
|
||||
/// - `0b0010`: 16KB granule supported at stage 2.
|
||||
/// - `0b0011`: *When FEAT_LPA2 is implemented:* 16KB granule at stage 2 supports 52-bit input
|
||||
/// addresses and can describe 52-bit output addresses.
|
||||
///
|
||||
/// All other values are reserved.
|
||||
#[bits(4)]
|
||||
pub t_gran16_2: u8,
|
||||
/// Indicates support for 64KB memory granule size at stage 2.
|
||||
///
|
||||
/// - `0b0000`: Support for 64KB granule at stage 2 is identified in the `t_gran64` field.
|
||||
/// - `0b0001`: 64KB granule not supported at stage 2.
|
||||
/// - `0b0010`: 64KB granule supported at stage 2.
|
||||
///
|
||||
/// All other values are reserved.
|
||||
#[bits(4)]
|
||||
pub t_gran64_2: u8,
|
||||
/// Indicates support for 4KB memory granule size at stage 2.
|
||||
///
|
||||
/// - `0b0000`: Support for 4KB granule at stage 2 is identified in the `t_gran4` field.
|
||||
/// - `0b0001`: 4KB granule not supported at stage 2.
|
||||
/// - `0b0010`: 4KB granule supported at stage 2.
|
||||
/// - `0b0011`: *When FEAT_LPA2 is implemented:* 4KB granule at stage 2 supports 52-bit input
|
||||
/// addresses and can describe 52-bit output addresses.
|
||||
///
|
||||
/// All other values are reserved.
|
||||
#[bits(4)]
|
||||
pub t_gran4_2: u8,
|
||||
/// Indicates support for disabling context synchronizing exception entry and exit.
|
||||
///
|
||||
/// - `0b0000`: All exception entries and exits are context synchronization events.
|
||||
/// - `0b0001`: Non-context synchronizing exception entry and exit are supported.
|
||||
///
|
||||
/// All other values are reserved.
|
||||
///
|
||||
/// FEAT_ExS implements the functionality identified by the value `0b0001`.
|
||||
#[bits(4)]
|
||||
pub exs: u8,
|
||||
__: u8,
|
||||
/// Indicates presence of the Fine-Grained Trap controls.
|
||||
///
|
||||
/// - `0b0000`: Fine-grained trap controls are not implemented.
|
||||
/// - `0b0001`: Fine-grained trap controls are implemented. Supports:
|
||||
/// - If EL2 is implemented, the HAFGRTR_EL2, HDFGRTR_EL2, HDFGWTR_EL2, HFGRTR_EL2, HFGITR_EL2
|
||||
/// and HFGWTR_EL2 registers, and their associated traps.
|
||||
/// - If EL2 is implemented, MDCR_EL2.TDCC.
|
||||
/// - If EL3 is implemented, MDCR_EL3.TDCC.
|
||||
/// - If both EL2 and EL3 are implemented, SCR_EL3.FGTEn.
|
||||
/// - `0b0010`: As `0b0001`, and also includes support for:
|
||||
/// - If EL2 is implemented, the HDFGRTR2_EL2, HDFGWTR2_EL2, HFGITR2_EL2, HFGRTR2_EL2, and
|
||||
/// HFGWTR2_EL2 registers, and their associated traps.
|
||||
/// - If both EL2 and EL3 are implemented, SCR_EL3.FGTEn2.
|
||||
///
|
||||
/// All other values are reserved.
|
||||
///
|
||||
/// FEAT_FGT implements the functionality identified by the value `0b0001`.
|
||||
///
|
||||
/// FEAT_FGT2 implements the functionality identified by the value `0b0010`.
|
||||
///
|
||||
/// From Armv8.6, the value `0b0000` is not permitted.
|
||||
///
|
||||
/// From Armv8.9, the value `0b0001` is not permitted.
|
||||
#[bits(4)]
|
||||
pub fgt: u8,
|
||||
/// Indicates presence of Enhanced Counter Virtualization.
|
||||
///
|
||||
/// - `0b0000`: Enhanced Counter Virtualization is not implemented.
|
||||
/// - `0b0001`: Enhanced Counter Virtualization is implemented. Supports
|
||||
/// CNTHCTL_EL2.{EL1TVT, EL1TVCT, EL1NVPCT, EL1NVVCT, EVNTIS}, CNTKCTL_EL1.EVNTIS,
|
||||
/// CNTPCTSS_EL0 counter views, and CNTVCTSS_EL0 counter views. Extends the PMSCR_EL1.PCT,
|
||||
/// PMSCR_EL2.PCT, TRFCR_EL1.TS, and TRFCR_EL2.TS fields.
|
||||
/// - `0b0010`: As `0b0001`, and also includes support for CNTHCTL_EL2.ECV and CNTPOFF_EL2.
|
||||
///
|
||||
/// All other values are reserved.
|
||||
///
|
||||
/// FEAT_ECV implements the functionality identified by the values `0b0001` and `0b0010`
|
||||
///
|
||||
/// From Armv8.6, the only permitted values are `0b0001` and `0b0010`.
|
||||
#[bits(4)]
|
||||
pub ecv: u8,
|
||||
}
|
||||
|
@ -3,8 +3,7 @@ use self::cpu::HfCpu;
|
||||
use super::{CpuFeats, Hypervisor};
|
||||
use crate::vmm::ram::Ram;
|
||||
use crate::vmm::VmmError;
|
||||
use hv_sys::{hv_vcpu_create, hv_vm_create, hv_vm_destroy, hv_vm_map};
|
||||
use std::ffi::c_int;
|
||||
use hv_sys::{hv_return_t, hv_vcpu_create, hv_vm_create, hv_vm_destroy, hv_vm_map};
|
||||
use std::num::NonZero;
|
||||
use thiserror::Error;
|
||||
|
||||
@ -18,10 +17,10 @@ pub fn new(_: usize, ram: Ram) -> Result<impl Hypervisor, VmmError> {
|
||||
}
|
||||
|
||||
/// Implementation of [`Hypervisor`] using Hypervisor Framework.
|
||||
///
|
||||
/// Fields in this struct need to drop in a correct order.
|
||||
struct Hvf {
|
||||
ram: Ram,
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
cpu_config: hv_sys::hv_vcpu_config_t,
|
||||
}
|
||||
|
||||
impl Hvf {
|
||||
@ -33,7 +32,11 @@ impl Hvf {
|
||||
let ret = unsafe { hv_vm_create(0) };
|
||||
let hv = match NonZero::new(ret) {
|
||||
Some(ret) => return Err(VmmError::CreateVmFailed(ret)),
|
||||
None => Self { ram },
|
||||
None => Self {
|
||||
ram,
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
cpu_config: unsafe { hv_sys::hv_vcpu_config_create() },
|
||||
},
|
||||
};
|
||||
|
||||
// Set RAM.
|
||||
@ -46,10 +49,33 @@ impl Hvf {
|
||||
None => Ok(hv),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
fn read_feature_reg(
|
||||
&mut self,
|
||||
reg: hv_sys::hv_feature_reg_t,
|
||||
) -> Result<u64, NonZero<hv_return_t>> {
|
||||
use hv_sys::hv_vcpu_config_get_feature_reg;
|
||||
|
||||
let mut val = 0;
|
||||
let ret = unsafe { hv_vcpu_config_get_feature_reg(self.cpu_config, reg, &mut val) };
|
||||
|
||||
match NonZero::new(ret) {
|
||||
Some(e) => Err(e),
|
||||
None => Ok(val),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Hvf {
|
||||
fn drop(&mut self) {
|
||||
// Free CPU config.
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
unsafe {
|
||||
os_release(self.cpu_config.cast())
|
||||
};
|
||||
|
||||
// Destroy VM.
|
||||
let status = unsafe { hv_vm_destroy() };
|
||||
|
||||
if status != 0 {
|
||||
@ -64,75 +90,14 @@ impl Hypervisor for Hvf {
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
fn cpu_features(&mut self) -> Result<CpuFeats, Self::CpuErr> {
|
||||
use hv_sys::hv_sys_reg_t_HV_SYS_REG_ID_AA64MMFR0_EL1 as HV_SYS_REG_ID_AA64MMFR0_EL1;
|
||||
use hv_sys::hv_feature_reg_t_HV_FEATURE_REG_ID_AA64MMFR0_EL1 as HV_FEATURE_REG_ID_AA64MMFR0_EL1;
|
||||
|
||||
// Load ID_AA64MMFR0_EL1.
|
||||
let cpu = self.create_cpu(0)?;
|
||||
let reg = cpu
|
||||
.read_sys(HV_SYS_REG_ID_AA64MMFR0_EL1)
|
||||
let mmfr0 = self
|
||||
.read_feature_reg(HV_FEATURE_REG_ID_AA64MMFR0_EL1)
|
||||
.map_err(HvfCpuError::ReadMmfr0Failed)?;
|
||||
|
||||
// FEAT_ExS.
|
||||
let feat_exs = match (reg & 0xF00000000000) >> 44 {
|
||||
0b0000 => false,
|
||||
0b0001 => true,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
// TGran4.
|
||||
let tgran4 = match (reg & 0xF0000000) >> 28 {
|
||||
0b0000 | 0b0001 => true,
|
||||
0b1111 => false,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
// TGran64.
|
||||
let tgran64 = match (reg & 0xF000000) >> 24 {
|
||||
0b0000 => true,
|
||||
0b1111 => false,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
// TGran16.
|
||||
let tgran16 = match (reg & 0xF00000) >> 20 {
|
||||
0b0000 => false,
|
||||
0b0001 | 0b0010 => true,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
// BigEnd.
|
||||
let big_end = match (reg & 0xF00) >> 8 {
|
||||
0b0000 => false,
|
||||
0b0001 => true,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
// BigEndEL0.
|
||||
let big_end_el0 = (big_end == false).then(|| match (reg & 0xF0000) >> 16 {
|
||||
0b0000 => false,
|
||||
0b0001 => true,
|
||||
_ => unreachable!(),
|
||||
});
|
||||
|
||||
// ASIDBits.
|
||||
let asid16 = match (reg & 0xF0) >> 4 {
|
||||
0b0000 => false,
|
||||
0b0010 => true,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
// PARange.
|
||||
let pa_range = (reg & 0xF).try_into().unwrap();
|
||||
|
||||
Ok(CpuFeats {
|
||||
feat_exs,
|
||||
tgran4,
|
||||
tgran64,
|
||||
tgran16,
|
||||
big_end,
|
||||
big_end_el0,
|
||||
asid16,
|
||||
pa_range,
|
||||
mmfr0: mmfr0.into(),
|
||||
})
|
||||
}
|
||||
|
||||
@ -153,7 +118,7 @@ impl Hypervisor for Hvf {
|
||||
fn create_cpu(&self, _: usize) -> Result<Self::Cpu<'_>, Self::CpuErr> {
|
||||
let mut instance = 0;
|
||||
let mut exit = std::ptr::null_mut();
|
||||
let ret = unsafe { hv_vcpu_create(&mut instance, &mut exit, std::ptr::null_mut()) };
|
||||
let ret = unsafe { hv_vcpu_create(&mut instance, &mut exit, self.cpu_config) };
|
||||
|
||||
match NonZero::new(ret) {
|
||||
Some(e) => Err(HvfCpuError::CreateVcpuFailed(e)),
|
||||
@ -173,13 +138,21 @@ impl Hypervisor for Hvf {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for Hvf {}
|
||||
unsafe impl Sync for Hvf {}
|
||||
|
||||
/// Implementation of [`Hypervisor::CpuErr`].
|
||||
#[derive(Debug, Error)]
|
||||
pub enum HvfCpuError {
|
||||
#[error("couldn't create a vCPU ({0:#x})")]
|
||||
CreateVcpuFailed(NonZero<c_int>),
|
||||
CreateVcpuFailed(NonZero<hv_return_t>),
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
#[error("couldn't read ID_AA64MMFR0_EL1 ({0:#x})")]
|
||||
ReadMmfr0Failed(NonZero<hv_sys::hv_return_t>),
|
||||
ReadMmfr0Failed(NonZero<hv_return_t>),
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
extern "C" {
|
||||
fn os_release(object: *mut std::ffi::c_void);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user