use core::mem::align_of;
#[cfg(not(target_os = "macos"))]
use core::mem::size_of;
use cpu_local::CpuAreaPrefix;
use crate::PerCpuError;
#[cfg(not(target_os = "macos"))]
unsafe extern "C" {
static __PERCPU_ALIGN_START: usize;
static __PERCPU_ALIGN_END: usize;
static __PERCPU_TEMPLATE_ALIGN_START: u8;
static __PERCPU_TEMPLATE_ALIGN_END: u8;
}
#[cfg(not(target_os = "macos"))]
pub(crate) fn required_area_alignment() -> Result<usize, PerCpuError> {
let start = core::ptr::addr_of!(__PERCPU_ALIGN_START) as usize;
let end = core::ptr::addr_of!(__PERCPU_ALIGN_END) as usize;
let byte_len = end
.checked_sub(start)
.ok_or(PerCpuError::MalformedAlignmentMetadata { start, end })?;
if !byte_len.is_multiple_of(size_of::<usize>())
|| (byte_len != 0 && !start.is_multiple_of(align_of::<usize>()))
{
return Err(PerCpuError::MalformedAlignmentMetadata { start, end });
}
let mut required = align_of::<CpuAreaPrefix>();
let mut descriptor_address = start;
while descriptor_address < end {
let alignment = unsafe { (descriptor_address as *const usize).read() };
if alignment == 0 || !alignment.is_power_of_two() {
return Err(PerCpuError::InvalidSymbolAlignment(alignment));
}
required = required.max(alignment);
descriptor_address += size_of::<usize>();
}
let linker_start = core::ptr::addr_of!(__PERCPU_TEMPLATE_ALIGN_START) as usize;
let linker_end = core::ptr::addr_of!(__PERCPU_TEMPLATE_ALIGN_END) as usize;
let linker_required =
linker_end
.checked_sub(linker_start)
.ok_or(PerCpuError::MalformedAlignmentMetadata {
start: linker_start,
end: linker_end,
})?;
if linker_required != required {
return Err(PerCpuError::AlignmentMetadataMismatch {
descriptors: required,
linker: linker_required,
});
}
Ok(required)
}
#[cfg(target_os = "macos")]
pub(crate) fn required_area_alignment() -> Result<usize, PerCpuError> {
Ok(align_of::<CpuAreaPrefix>())
}