From 0cd83e88ed45b1714e8c330ca79436b2c7d75476 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Thu, 19 Sep 2024 12:46:15 +0000 Subject: [PATCH 1/5] acpi: remove unsafe It turns out all of our uses of unsafe in this module can be trivally replaced by uses of the zerocopy crate. Signed-off-by: Tom Dohrmann --- kernel/src/acpi/tables.rs | 85 ++++++++++++++++----------------------- kernel/src/fw_cfg.rs | 6 +++ 2 files changed, 40 insertions(+), 51 deletions(-) diff --git a/kernel/src/acpi/tables.rs b/kernel/src/acpi/tables.rs index f72bf3c76..fc125df5a 100644 --- a/kernel/src/acpi/tables.rs +++ b/kernel/src/acpi/tables.rs @@ -11,10 +11,11 @@ use crate::fw_cfg::FwCfg; use crate::string::FixedString; use alloc::vec::Vec; use core::mem; +use zerocopy::{FromBytes, FromZeros, Immutable, IntoBytes, KnownLayout}; /// ACPI Root System Description Pointer (RSDP) /// used by ACPI programming interface -#[derive(Debug, Default)] +#[derive(Debug, Default, FromBytes, IntoBytes)] #[repr(C, packed)] struct RSDPDesc { /// Signature must contain "RSD PTR" @@ -40,7 +41,6 @@ impl RSDPDesc { /// /// A [`Result`] containing the [`RSDPDesc`] if successful, or an [`SvsmError`] on failure. fn from_fwcfg(fw_cfg: &FwCfg<'_>) -> Result { - let mut buf = mem::MaybeUninit::::uninit(); let path = option_env!("ACPI_RSDP_PATH").unwrap_or("etc/acpi/rsdp"); let file = fw_cfg.file_selector(path)?; @@ -49,17 +49,13 @@ impl RSDPDesc { } fw_cfg.select(file.selector()); - let ptr = buf.as_mut_ptr().cast::(); - for i in 0..mem::size_of::() { - let byte: u8 = fw_cfg.read_le(); - unsafe { ptr.add(i).write(byte) }; - } - - unsafe { Ok(buf.assume_init()) } + let mut this = Self::new_zeroed(); + fw_cfg.read_bytes(this.as_mut_bytes()); + Ok(this) } } -#[derive(Copy, Clone, Debug, Default)] +#[derive(Copy, Clone, Debug, Default, FromBytes, KnownLayout, Immutable)] #[repr(C, packed)] /// Raw header of an ACPI table. It corresponds to the beginning /// portion of ACPI tables, before any specific table data @@ -167,12 +163,9 @@ impl ACPITable { /// /// A new [`ACPITable`] instance on success, or an [`SvsmError`] if parsing fails. fn new(ptr: &[u8]) -> Result { - let raw_header = ptr - .get(..mem::size_of::()) - .ok_or(SvsmError::Acpi)? - .as_ptr() - .cast::(); - let size = unsafe { (*raw_header).len as usize }; + let (raw_header, _) = + RawACPITableHeader::read_from_prefix(ptr).map_err(|_| SvsmError::Acpi)?; + let size = raw_header.len as usize; let content = ptr.get(..size).ok_or(SvsmError::Acpi)?; let mut buf = Vec::::new(); @@ -180,7 +173,7 @@ impl ACPITable { buf.try_reserve(size).map_err(|_| SvsmError::Mem)?; buf.extend_from_slice(content); - let header = unsafe { ACPITableHeader::new(*raw_header) }; + let header = ACPITableHeader::new(raw_header); Ok(Self { header, buf }) } @@ -218,11 +211,14 @@ impl ACPITable { /// /// # Returns /// - /// A pointer to the content of the ACPI table at specified offset as type `T`, + /// A reference to the content of the ACPI table at specified offset as type `T`, /// or [`None`] if the offset is out of bounds. - fn content_ptr(&self, offset: usize) -> Option<*const T> { - let end = offset.checked_add(mem::size_of::())?; - Some(self.content()?.get(offset..end)?.as_ptr().cast::()) + fn content_ptr(&self, offset: usize) -> Option<&T> + where + T: FromBytes + KnownLayout + Immutable, + { + let bytes = self.content()?.get(offset..)?; + T::ref_from_prefix(bytes).ok().map(|(value, _rest)| value) } } @@ -289,14 +285,9 @@ impl ACPITableBuffer { return Err(SvsmError::Mem); } buf.try_reserve(size).map_err(|_| SvsmError::Mem)?; - let ptr = buf.as_mut_ptr(); - + buf.resize(size, 0); fw_cfg.select(file.selector()); - for i in 0..size { - let byte: u8 = fw_cfg.read_le(); - unsafe { ptr.add(i).write(byte) }; - } - unsafe { buf.set_len(size) } + fw_cfg.read_bytes(&mut buf); let mut acpibuf = Self { buf, @@ -328,15 +319,10 @@ impl ACPITableBuffer { .map(|c| u32::from_le_bytes(c.try_into().unwrap()) as usize); for offset in offsets { - let raw_header = offset - .checked_add(mem::size_of::()) - .and_then(|end| self.buf.get(offset..end)) - .ok_or(SvsmError::Acpi)? - .as_ptr() - .cast::(); - - let meta = unsafe { ACPITableMeta::new(&*raw_header, offset) }; - + let raw_header = self.buf.get(offset..).ok_or(SvsmError::Acpi)?; + let (raw_header, _) = + RawACPITableHeader::ref_from_prefix(raw_header).map_err(|_| SvsmError::Acpi)?; + let meta = ACPITableMeta::new(raw_header, offset); self.tables.push(meta); } @@ -387,7 +373,7 @@ impl ACPITableBuffer { const MADT_HEADER_SIZE: usize = 8; /// Header of an entry within MADT -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, FromBytes, Immutable, KnownLayout)] #[repr(C, packed)] struct RawMADTEntryHeader { entry_type: u8, @@ -395,7 +381,7 @@ struct RawMADTEntryHeader { } /// Entry for a local APIC within MADT -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, FromBytes, Immutable, KnownLayout)] #[repr(C, packed)] struct RawMADTEntryLocalApic { header: RawMADTEntryHeader, @@ -405,7 +391,7 @@ struct RawMADTEntryLocalApic { } /// Entry for a local X2APIC within MADT -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, FromBytes, Immutable, KnownLayout)] #[repr(C, packed)] struct RawMADTEntryLocalX2Apic { header: RawMADTEntryHeader, @@ -488,38 +474,35 @@ pub fn load_acpi_cpu_info(fw_cfg: &FwCfg<'_>) -> Result, SvsmEr let entry_ptr = apic_table .content_ptr::(offset) .ok_or(SvsmError::Acpi)?; - let (madt_type, entry_len) = unsafe { ((*entry_ptr).entry_type, (*entry_ptr).entry_len) }; - let entry_len = usize::from(entry_len); + let entry_len = usize::from(entry_ptr.entry_len); - match madt_type { + match entry_ptr.entry_type { 0 if entry_len == mem::size_of::() => { let lapic_ptr = apic_table .content_ptr::(offset) .ok_or(SvsmError::Acpi)?; - let (apic_id, flags) = unsafe { ((*lapic_ptr).apic_id as u32, (*lapic_ptr).flags) }; cpus.push(ACPICPUInfo { - apic_id, - enabled: (flags & 1) == 1, + apic_id: lapic_ptr.apic_id as u32, + enabled: (lapic_ptr.flags & 1) == 1, }); } 9 if entry_len == mem::size_of::() => { let x2apic_ptr = apic_table .content_ptr::(offset) .ok_or(SvsmError::Acpi)?; - let (apic_id, flags) = unsafe { ((*x2apic_ptr).apic_id, (*x2apic_ptr).flags) }; cpus.push(ACPICPUInfo { - apic_id, - enabled: (flags & 1) == 1, + apic_id: x2apic_ptr.apic_id, + enabled: (x2apic_ptr.flags & 1) == 1, }); } - _ if entry_len == 0 => { + madt_type if entry_len == 0 => { log::warn!( "Found zero-length MADT entry with type {}, stopping", madt_type ); break; } - _ => { + madt_type => { log::info!("Ignoring MADT entry with type {}", madt_type); } } diff --git a/kernel/src/fw_cfg.rs b/kernel/src/fw_cfg.rs index ac3adf5b7..ad2297839 100644 --- a/kernel/src/fw_cfg.rs +++ b/kernel/src/fw_cfg.rs @@ -78,6 +78,12 @@ impl<'a> FwCfg<'a> { self.driver.outw(FW_CFG_CTL, cfg); } + pub fn read_bytes(&self, out: &mut [u8]) { + for byte in out.iter_mut() { + *byte = self.driver.inb(FW_CFG_DATA); + } + } + pub fn read_le(&self) -> T where T: core::ops::Shl + core::ops::BitOr + From, From 7d7f82b61473a2256892b46ff5c72017afb0eabd Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Thu, 19 Sep 2024 13:10:30 +0000 Subject: [PATCH 2/5] fw_meta: remove unsafe Once again, zerocopy can do everything we needed without us using unsafe. Signed-off-by: Tom Dohrmann --- kernel/src/fw_meta.rs | 75 +++++++++---------------------------------- 1 file changed, 15 insertions(+), 60 deletions(-) diff --git a/kernel/src/fw_meta.rs b/kernel/src/fw_meta.rs index df8dca48a..001de192c 100644 --- a/kernel/src/fw_meta.rs +++ b/kernel/src/fw_meta.rs @@ -18,9 +18,10 @@ use crate::types::{PageSize, PAGE_SIZE}; use crate::utils::{zero_mem_region, MemoryRegion}; use alloc::vec::Vec; use bootlib::kernel_launch::KernelLaunchInfo; +use zerocopy::{FromBytes, Immutable, KnownLayout}; use core::fmt; -use core::mem::{align_of, size_of, size_of_val}; +use core::mem::{size_of, size_of_val}; use core::str::FromStr; #[derive(Clone, Debug, Default)] @@ -135,7 +136,7 @@ const OVMF_TABLE_FOOTER_GUID: &str = "96b582de-1fb2-45f7-baea-a366c55a082d"; const OVMF_SEV_META_DATA_GUID: &str = "dc886566-984a-4798-a75e-5585a7bf67cc"; const SVSM_INFO_GUID: &str = "a789a612-0597-4c4b-a49f-cbb1fe9d1ddd"; -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, FromBytes, KnownLayout, Immutable)] #[repr(C, packed)] struct SevMetaDataHeader { signature: [u8; 4], @@ -144,7 +145,7 @@ struct SevMetaDataHeader { num_desc: u32, } -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, FromBytes, KnownLayout, Immutable)] #[repr(C, packed)] struct SevMetaDataDesc { base: u32, @@ -157,7 +158,7 @@ const SEV_META_DESC_TYPE_SECRETS: u32 = 2; const SEV_META_DESC_TYPE_CPUID: u32 = 3; const SEV_META_DESC_TYPE_CAA: u32 = 4; -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, FromBytes, KnownLayout, Immutable)] #[repr(C, packed)] struct RawMetaHeader { len: u16, @@ -171,7 +172,7 @@ impl RawMetaHeader { } } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, FromBytes, KnownLayout, Immutable)] #[repr(C, packed)] struct RawMetaBuffer { data: [u8; PAGE_SIZE - size_of::() - 32], @@ -190,14 +191,7 @@ fn find_table<'a>(uuid: &Uuid, mem: &'a [u8]) -> Option<&'a [u8]> { while idx != 0 { let hdr_start = idx.checked_sub(size_of::())?; - let hdr_start_ptr = mem.get(hdr_start..idx)?.as_ptr().cast::(); - if hdr_start_ptr.align_offset(align_of::()) != 0 { - log::error!("Misaligned firmware metadata table"); - return None; - } - - // Safety: we have checked the pointer is within bounds and aligned - let hdr = unsafe { hdr_start_ptr.read() }; + let hdr = RawMetaHeader::ref_from_bytes(&mem[hdr_start..idx]).unwrap(); let data_len = hdr.data_len()?; idx = hdr_start.checked_sub(data_len)?; @@ -216,14 +210,7 @@ fn find_table<'a>(uuid: &Uuid, mem: &'a [u8]) -> Option<&'a [u8]> { pub fn parse_fw_meta_data(mem: &[u8]) -> Result { let mut meta_data = SevFWMetaData::new(); - if mem.len() != size_of::() { - return Err(SvsmError::Firmware); - } - - // Safety: `RawMetaBuffer` has no invalid representations and is - // `repr(C, packed)`, which means there are no alignment requirements. - // We have also verified that the size of the slice matches. - let raw_meta = unsafe { &*mem.as_ptr().cast::() }; + let raw_meta = RawMetaBuffer::ref_from_bytes(mem).map_err(|_| SvsmError::Firmware)?; // Check the UUID let raw_uuid = raw_meta.header.uuid; @@ -283,51 +270,19 @@ fn parse_sev_meta( .ok_or(SvsmError::Firmware)?; let sev_meta_end = sev_meta_start + size_of::(); // Bounds check the header and get a pointer to it - let sev_meta_hdr_ptr = raw_meta + let bytes = raw_meta .data .get(sev_meta_start..sev_meta_end) - .ok_or(SvsmError::Firmware)? - .as_ptr() - .cast::(); - - // Check that the header pointer is aligned. This also guarantees that - // descriptors down the line will be aligned. If the pointer was not - // aligned we would need to use ptr::read_unaligned(), so simply check - // beforehand and use ptr::read(), as there's no reason for the metadata - // to be misaligned. - if sev_meta_hdr_ptr.align_offset(align_of::()) != 0 { - log::error!("Misaligned SEV metadata header"); - return Err(SvsmError::Firmware); - } - // Safety: we have checked the pointer is within bounds and aligned. - let sev_meta_hdr = unsafe { sev_meta_hdr_ptr.read() }; + .ok_or(SvsmError::Firmware)?; + let sev_meta_hdr = SevMetaDataHeader::ref_from_bytes(bytes).map_err(|_| SvsmError::Firmware)?; // Now find the descriptors + let bytes = &raw_meta.data[sev_meta_end..]; let num_desc = sev_meta_hdr.num_desc as usize; - let sev_descs_start = sev_meta_end; - let sev_descs_len = num_desc - .checked_mul(size_of::()) - .ok_or(SvsmError::Firmware)?; - let sev_descs_end = sev_descs_start - .checked_add(sev_descs_len) - .ok_or(SvsmError::Firmware)?; + let (descs, _) = <[SevMetaDataDesc]>::ref_from_prefix_with_elems(bytes, num_desc) + .map_err(|_| SvsmError::Firmware)?; - // We have a variable number of descriptors following the header. - // Unfortunately flexible array members in Rust are not fully supported, - // so we cannot avoid using raw pointers. - let sev_descs_ptr = raw_meta - .data - .get(sev_descs_start..sev_descs_end) - .ok_or(SvsmError::Firmware)? - .as_ptr() - .cast::(); - - for i in 0..num_desc { - // Safety: We have checked that the descriptors are within bounds of - // the metadata memory. Since the descriptors follow the header, and - // the header is properly aligned, the descriptors must be so as - // well. - let desc = unsafe { sev_descs_ptr.add(i).read() }; + for desc in descs { let t = desc.t; let base = PhysAddr::from(desc.base as usize); let len = desc.len as usize; From 054f2af8eaeeff2f185265da4b0dffd8c4bb6a1f Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Thu, 19 Sep 2024 13:23:36 +0000 Subject: [PATCH 3/5] string: simplify From<[u8; N]> impl The new implementation is much shorter, should perform exactly the same and doesn't even rely on unsafe. Signed-off-by: Tom Dohrmann --- kernel/src/string.rs | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/kernel/src/string.rs b/kernel/src/string.rs index a91b2150b..34ddc883b 100644 --- a/kernel/src/string.rs +++ b/kernel/src/string.rs @@ -4,9 +4,7 @@ // // Author: Joerg Roedel -use core::array; use core::fmt; -use core::mem::MaybeUninit; #[derive(Copy, Clone, Debug)] pub struct FixedString { @@ -46,18 +44,8 @@ impl Default for FixedString { impl From<[u8; N]> for FixedString { fn from(arr: [u8; N]) -> FixedString { - let mut data: [MaybeUninit; N] = array::from_fn(|_| MaybeUninit::uninit()); - let mut len = N; - - for (i, (d, val)) in data.iter_mut().zip(&arr).enumerate() { - let val = *val; - if val == 0 && len == N { - len = i; - } - d.write(val as char); - } - - let data = unsafe { *(data.as_ptr().cast::<[char; N]>()) }; + let data = arr.map(char::from); + let len = arr.iter().position(|&b| b == 0).unwrap_or(N); FixedString { data, len } } } From 48e2e3ee2f99496cc820c671e51bd2a9146308ff Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Thu, 19 Sep 2024 13:36:38 +0000 Subject: [PATCH 4/5] pld_repord: remove unsafe zerocopy is great :) Signed-off-by: Tom Dohrmann --- kernel/src/greq/pld_report.rs | 50 +++++++++++++---------------------- kernel/src/greq/services.rs | 7 +++-- 2 files changed, 23 insertions(+), 34 deletions(-) diff --git a/kernel/src/greq/pld_report.rs b/kernel/src/greq/pld_report.rs index a8aba5f47..8599918fd 100644 --- a/kernel/src/greq/pld_report.rs +++ b/kernel/src/greq/pld_report.rs @@ -8,6 +8,8 @@ use core::mem::size_of; +use zerocopy::{FromBytes, Immutable, KnownLayout}; + use crate::protocols::errors::SvsmReqError; /// Size of the `SnpReportRequest.user_data` @@ -15,7 +17,7 @@ pub const USER_DATA_SIZE: usize = 64; /// MSG_REPORT_REQ payload format (AMD SEV-SNP spec. table 20) #[repr(C, packed)] -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, FromBytes, KnownLayout, Immutable)] pub struct SnpReportRequest { /// Guest-provided data to be included in the attestation report /// REPORT_DATA (512 bits) @@ -36,20 +38,11 @@ pub struct SnpReportRequest { impl SnpReportRequest { /// Take a slice and return a reference for Self pub fn try_from_as_ref(buffer: &[u8]) -> Result<&Self, SvsmReqError> { - let buffer = buffer - .get(..size_of::()) - .ok_or_else(SvsmReqError::invalid_parameter)?; - - // SAFETY: SnpReportRequest has no invalid representations, as it is - // comprised entirely of integer types. It is repr(packed), so its - // required alignment is simply 1. We have checked the size, so this - // is entirely safe. - let request = unsafe { &*buffer.as_ptr().cast::() }; - - if !request.is_reserved_clear() { - return Err(SvsmReqError::invalid_parameter()); - } - Ok(request) + Self::ref_from_prefix(buffer) + .ok() + .map(|(request, _rest)| request) + .filter(|request| request.is_reserved_clear()) + .ok_or_else(SvsmReqError::invalid_parameter) } pub fn is_vmpl0(&self) -> bool { @@ -64,7 +57,7 @@ impl SnpReportRequest { /// MSG_REPORT_RSP payload format (AMD SEV-SNP spec. table 23) #[repr(C, packed)] -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, FromBytes, KnownLayout, Immutable)] pub struct SnpReportResponse { /// The status of the key derivation operation, see [SnpReportResponseStatus] status: u32, @@ -86,19 +79,6 @@ pub enum SnpReportResponseStatus { } impl SnpReportResponse { - pub fn try_from_as_ref(buffer: &[u8]) -> Result<&Self, SvsmReqError> { - let buffer = buffer - .get(..size_of::()) - .ok_or_else(SvsmReqError::invalid_parameter)?; - - // SAFETY: SnpReportResponse has no invalid representations, as it is - // comprised entirely of integer types. It is repr(packed), so its - // required alignment is simply 1. We have checked the size, so this - // is entirely safe. - let response = unsafe { &*buffer.as_ptr().cast::() }; - Ok(response) - } - /// Validate the [SnpReportResponse] fields pub fn validate(&self) -> Result<(), SvsmReqError> { if self.status != SnpReportResponseStatus::Success as u32 { @@ -121,7 +101,7 @@ impl SnpReportResponse { /// component in the trusted computing base (TCB) of the SNP firmware. /// (AMD SEV-SNP spec. table 3) #[repr(C, packed)] -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, FromBytes, Immutable)] struct TcbVersion { /// Version of the Microcode, SNP firmware, PSP and boot loader raw: u64, @@ -129,7 +109,7 @@ struct TcbVersion { /// Format for an ECDSA P-384 with SHA-384 signature (AMD SEV-SNP spec. table 115) #[repr(C, packed)] -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, FromBytes, KnownLayout, Immutable)] struct Signature { /// R component of this signature r: [u8; 72], @@ -141,7 +121,7 @@ struct Signature { /// ATTESTATION_REPORT format (AMD SEV-SNP spec. table 21) #[repr(C, packed)] -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, FromBytes, KnownLayout, Immutable)] pub struct AttestationReport { /// Version number of this attestation report version: u32, @@ -192,6 +172,12 @@ pub struct AttestationReport { reserved2: [u8; 192], /// Signature of bytes 0h to 29Fh inclusive of this report signature: Signature, + /// `zerocopy` needs to expose the type of the last field when + /// generating the implementation for `KnownLayout`, but this + /// causes problems because `AttestationReport` is public and + /// `Signature` is private. Instead add an empty field with a type + /// that's not private. + _empty: (), } const _: () = assert!(size_of::() <= u32::MAX as usize); diff --git a/kernel/src/greq/services.rs b/kernel/src/greq/services.rs index 6e91b2948..d810fb175 100644 --- a/kernel/src/greq/services.rs +++ b/kernel/src/greq/services.rs @@ -6,6 +6,8 @@ //! API to send `SNP_GUEST_REQUEST` commands to the PSP +use zerocopy::FromBytes; + use crate::{ greq::{ driver::{send_extended_guest_request, send_regular_guest_request}, @@ -43,7 +45,8 @@ fn get_report(buffer: &mut [u8], certs: Option<&mut [u8]>) -> Result response_len { return Err(SvsmReqError::invalid_request()); } - let response: &SnpReportResponse = SnpReportResponse::try_from_as_ref(buffer)?; + let (response, _rest) = SnpReportResponse::ref_from_prefix(buffer) + .map_err(|_| SvsmReqError::invalid_parameter())?; response.validate()?; Ok(response_len) @@ -134,7 +137,7 @@ mod tests { let size = get_regular_report(&mut buf).unwrap(); assert_eq!(size, buf.len()); - let response = SnpReportResponse::try_from_as_ref(&buf).unwrap(); + let (response, _rest) = SnpReportResponse::ref_from_prefix(&buf).unwrap(); response.validate().unwrap(); // FIXME: we still have some cases where the precalculated value does // not match, so for now we just issue a warning until we fix the problem. From 9ec1021616a28120b02092f9ae20fecdaf1495ad Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Thu, 19 Sep 2024 13:53:57 +0000 Subject: [PATCH 5/5] pagebox: simplify some impls We can make use of the `Deref` and `DerefMut` implementations. Signed-off-by: Tom Dohrmann --- kernel/src/mm/pagebox.rs | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/kernel/src/mm/pagebox.rs b/kernel/src/mm/pagebox.rs index 1a10967d8..8917afa58 100644 --- a/kernel/src/mm/pagebox.rs +++ b/kernel/src/mm/pagebox.rs @@ -206,36 +206,28 @@ impl DerefMut for PageBox { impl borrow::Borrow for PageBox { #[inline] fn borrow(&self) -> &T { - // SAFETY: this is part of the invariants of this type, as it must - // hold a pointer to valid memory for the given `T`. - unsafe { self.ptr.as_ref() } + self } } impl borrow::BorrowMut for PageBox { #[inline] fn borrow_mut(&mut self) -> &mut T { - // SAFETY: this is part of the invariants of this type, as it must - // hold a pointer to valid memory for the given `T`. - unsafe { self.ptr.as_mut() } + self } } impl AsRef for PageBox { #[inline] fn as_ref(&self) -> &T { - // SAFETY: this is part of the invariants of this type, as it must - // hold a pointer to valid memory for the given `T`. - unsafe { self.ptr.as_ref() } + self } } impl AsMut for PageBox { #[inline] fn as_mut(&mut self) -> &mut T { - // SAFETY: this is part of the invariants of this type, as it must - // hold a pointer to valid memory for the given `T`. - unsafe { self.ptr.as_mut() } + self } }