#[cfg(target_pointer_width = "32")]
use crate::util::heap::layout::vm_layout::VMLayout;
#[cfg(target_pointer_width = "32")]
use crate::util::heap::layout::vm_layout::BYTES_IN_CHUNK;
#[cfg(target_pointer_width = "64")]
use crate::util::metadata::side_metadata::side_metadata_offset_after;
use crate::util::metadata::side_metadata::SideMetadataSpec;
use crate::util::os::{HugePageSupport, MmapAnnotation};
use crate::util::Address;
use crate::util::{constants::LOG_BYTES_IN_PAGE, conversions::raw_align_up};
use crate::MMAPPER;
use std::sync::OnceLock;
pub(crate) const GLOBAL_SIDE_METADATA_BASE_OFFSET: usize = 0;
static SIDE_METADATA_BASE_ADDRESS: OnceLock<Address> = OnceLock::new();
static VM_SIDE_METADATA_UPPER_BOUND_OFFSET: OnceLock<usize> = OnceLock::new();
pub(super) fn set_vm_side_metadata_specs(specs: &[SideMetadataSpec]) {
let mut upper_bound = 0usize;
for spec in specs {
if spec.uses_contiguous_side_metadata() {
upper_bound = upper_bound.max(spec.upper_bound_offset());
}
}
VM_SIDE_METADATA_UPPER_BOUND_OFFSET
.set(upper_bound)
.unwrap();
debug!(
"Registered VM side metadata layout: {} specs, upper_bound={}",
specs.len(),
upper_bound
);
}
pub(super) fn initialize_side_metadata_base(
specified_base: Address,
huge_page_support: HugePageSupport,
) {
#[cfg(target_pointer_width = "64")]
{
let core_end = super::spec_defs::LAST_LOCAL_SIDE_METADATA_SPEC.upper_bound_offset();
let vm_end = *VM_SIDE_METADATA_UPPER_BOUND_OFFSET.get().unwrap();
info!(
"Initializing side metadata base: vm_specs_registered={} core_end={} vm_end={}",
VM_SIDE_METADATA_UPPER_BOUND_OFFSET.get().is_some(),
core_end,
unsafe { Address::from_usize(vm_end) }
);
}
let total_bytes = side_metadata_reserved_bytes();
let pages = total_bytes >> LOG_BYTES_IN_PAGE;
let anno = MmapAnnotation::SideMeta {
space: "all",
meta: "all-quarantined",
};
info!(
"Quarantine side metadata range: total_bytes=0x{:x}, pages=0x{:x}, granularity=0x{:x}",
total_bytes,
pages,
MMAPPER.granularity()
);
let base = if specified_base.is_zero() {
MMAPPER
.quarantine_address_range_anywhere(pages, None, huge_page_support, &anno)
.unwrap_or_else(|e| panic!("failed to quarantine side metadata address range: {e}"))
} else {
MMAPPER
.quarantine_address_range(specified_base, pages, huge_page_support, &anno)
.unwrap_or_else(|e| {
panic!(
"failed to quarantine side metadata address range at {}: {e}",
specified_base
)
});
specified_base
};
info!(
"Side metadata base initialized at {} (range: {} - {})",
base,
base,
base + total_bytes
);
SIDE_METADATA_BASE_ADDRESS.set(base).unwrap();
}
#[cfg(test)]
pub(super) fn is_side_metadata_initialized() -> bool {
VM_SIDE_METADATA_UPPER_BOUND_OFFSET.get().is_some()
&& SIDE_METADATA_BASE_ADDRESS.get().is_some()
}
pub fn global_side_metadata_base_address() -> Address {
#[cfg(debug_assertions)]
{
#[cfg(not(any(test, feature = "test_private")))]
{
assert!(
VM_SIDE_METADATA_UPPER_BOUND_OFFSET.get().is_some(),
"global_side_metadata_base_address() called before VM side metadata layout was registered"
);
}
assert!(
SIDE_METADATA_BASE_ADDRESS.get().is_some(),
"global_side_metadata_base_address() called before side metadata base was initialized"
);
}
unsafe { *SIDE_METADATA_BASE_ADDRESS.get().unwrap_unchecked() }
}
pub(crate) fn local_side_metadata_base_address() -> Address {
global_side_metadata_base_address() + global_side_metadata_bytes()
}
fn total_side_metadata_bytes() -> usize {
let vm_end = *VM_SIDE_METADATA_UPPER_BOUND_OFFSET.get().unwrap();
#[cfg(target_pointer_width = "64")]
{
let core_end = super::spec_defs::LAST_LOCAL_SIDE_METADATA_SPEC.upper_bound_offset();
debug!(
"total_side_metadata_bytes(): core_end={} vm_end={} (registered={})",
core_end,
vm_end,
VM_SIDE_METADATA_UPPER_BOUND_OFFSET.get().is_some()
);
core_end.max(vm_end)
}
#[cfg(target_pointer_width = "32")]
{
let local_bytes =
1usize << (VMLayout::LOG_ARCH_ADDRESS_SPACE - LOG_LOCAL_SIDE_METADATA_WORST_CASE_RATIO);
global_side_metadata_bytes().max(vm_end) + local_bytes
}
}
pub(crate) fn side_metadata_reserved_bytes() -> usize {
raw_align_up(total_side_metadata_bytes(), MMAPPER.granularity())
}
#[cfg(target_pointer_width = "64")]
pub fn vo_bit_side_metadata_addr() -> Address {
crate::util::metadata::vo_bit::vo_bit_side_metadata_addr()
}
pub fn global_side_metadata_vm_base_address() -> Address {
super::spec_defs::LAST_GLOBAL_SIDE_METADATA_SPEC.upper_bound_address_for_contiguous()
}
pub(crate) fn global_side_metadata_bytes() -> usize {
let end = super::spec_defs::LAST_GLOBAL_SIDE_METADATA_SPEC.upper_bound_offset();
end.max(*VM_SIDE_METADATA_UPPER_BOUND_OFFSET.get().unwrap())
}
#[cfg(target_pointer_width = "32")]
pub(super) const LOG_GLOBAL_SIDE_METADATA_WORST_CASE_RATIO: usize = 3;
#[cfg(target_pointer_width = "64")]
pub(super) const LOG_GLOBAL_SIDE_METADATA_WORST_CASE_RATIO: usize = 1;
#[cfg(target_pointer_width = "32")]
pub(super) const LOG_LOCAL_SIDE_METADATA_WORST_CASE_RATIO: usize = 3;
#[cfg(target_pointer_width = "64")]
pub(super) const LOG_LOCAL_SIDE_METADATA_WORST_CASE_RATIO: usize = 1;
#[cfg(target_pointer_width = "32")]
pub(super) const LOCAL_SIDE_METADATA_PER_CHUNK: usize =
BYTES_IN_CHUNK >> LOG_LOCAL_SIDE_METADATA_WORST_CASE_RATIO;
pub const GLOBAL_SIDE_METADATA_VM_BASE_OFFSET: usize =
super::spec_defs::LAST_GLOBAL_SIDE_METADATA_SPEC.upper_bound_offset();
pub const LOCAL_SIDE_METADATA_VM_BASE_OFFSET: usize =
super::spec_defs::LAST_LOCAL_SIDE_METADATA_SPEC.upper_bound_offset();
#[cfg(target_pointer_width = "32")]
pub(super) const LOCAL_SIDE_METADATA_BASE_OFFSET_FOR_LAYOUT: usize = 0;
#[cfg(target_pointer_width = "64")]
pub(super) const LOCAL_SIDE_METADATA_BASE_OFFSET_FOR_LAYOUT: usize =
side_metadata_offset_after(&super::spec_defs::LAST_GLOBAL_SIDE_METADATA_SPEC);