1 use crate::data_types::PhysicalAddress;
2 use crate::mem::memory_map::MemoryAttribute;
3 use crate::proto::unsafe_protocol;
4 use crate::{Result, StatusExt};
5 use core::ops::Range;
6 use uefi_raw::protocol::memory_protection::MemoryAttributeProtocol;
7
8 /// Protocol for getting and setting memory protection attributes.
9 ///
10 /// Corresponds to the C type `EFI_MEMORY_ATTRIBUTE_PROTOCOL`.
11 #[repr(transparent)]
12 #[derive(Debug)]
13 #[unsafe_protocol(MemoryAttributeProtocol::GUID)]
14 pub struct MemoryProtection(MemoryAttributeProtocol);
15
16 impl MemoryProtection {
17 /// Get the attributes of a memory region.
18 ///
19 /// The attribute mask this returns will only contain bits in the
20 /// set of [`READ_PROTECT`], [`EXECUTE_PROTECT`], and [`READ_ONLY`].
21 ///
22 /// If the attributes are not consistent within the region,
23 /// [`Status::NO_MAPPING`] is returned.
24 ///
25 /// Implementations typically require that the start and end of the memory
26 /// region are aligned to the [UEFI page size].
27 ///
28 /// [`READ_PROTECT`]: MemoryAttribute::READ_PROTECT
29 /// [`EXECUTE_PROTECT`]: MemoryAttribute::EXECUTE_PROTECT
30 /// [`READ_ONLY`]: MemoryAttribute::READ_ONLY
31 /// [`Status::NO_MAPPING`]: crate::Status::NO_MAPPING
32 /// [UEFI page size]: uefi::boot::PAGE_SIZE
get_memory_attributes( &self, byte_region: Range<PhysicalAddress>, ) -> Result<MemoryAttribute>33 pub fn get_memory_attributes(
34 &self,
35 byte_region: Range<PhysicalAddress>,
36 ) -> Result<MemoryAttribute> {
37 let mut attributes = MemoryAttribute::empty();
38 let (base_address, length) = range_to_base_and_len(byte_region);
39 unsafe {
40 (self.0.get_memory_attributes)(&self.0, base_address, length, &mut attributes)
41 .to_result_with_val(|| attributes)
42 }
43 }
44
45 /// Set the attributes of a memory region.
46 ///
47 /// The valid attributes to set are [`READ_PROTECT`],
48 /// [`EXECUTE_PROTECT`], and [`READ_ONLY`].
49 ///
50 /// Implementations typically require that the start and end of the memory
51 /// region are aligned to the [UEFI page size].
52 ///
53 /// [`READ_PROTECT`]: MemoryAttribute::READ_PROTECT
54 /// [`EXECUTE_PROTECT`]: MemoryAttribute::EXECUTE_PROTECT
55 /// [`READ_ONLY`]: MemoryAttribute::READ_ONLY
56 /// [UEFI page size]: uefi::boot::PAGE_SIZE
set_memory_attributes( &self, byte_region: Range<PhysicalAddress>, attributes: MemoryAttribute, ) -> Result57 pub fn set_memory_attributes(
58 &self,
59 byte_region: Range<PhysicalAddress>,
60 attributes: MemoryAttribute,
61 ) -> Result {
62 let (base_address, length) = range_to_base_and_len(byte_region);
63 unsafe {
64 (self.0.set_memory_attributes)(&self.0, base_address, length, attributes).to_result()
65 }
66 }
67
68 /// Clear the attributes of a memory region.
69 ///
70 /// The valid attributes to clear are [`READ_PROTECT`],
71 /// [`EXECUTE_PROTECT`], and [`READ_ONLY`].
72 ///
73 /// Implementations typically require that the start and end of the memory
74 /// region are aligned to the [UEFI page size].
75 ///
76 /// [`READ_PROTECT`]: MemoryAttribute::READ_PROTECT
77 /// [`EXECUTE_PROTECT`]: MemoryAttribute::EXECUTE_PROTECT
78 /// [`READ_ONLY`]: MemoryAttribute::READ_ONLY
79 /// [UEFI page size]: uefi::boot::PAGE_SIZE
clear_memory_attributes( &self, byte_region: Range<PhysicalAddress>, attributes: MemoryAttribute, ) -> Result80 pub fn clear_memory_attributes(
81 &self,
82 byte_region: Range<PhysicalAddress>,
83 attributes: MemoryAttribute,
84 ) -> Result {
85 let (base_address, length) = range_to_base_and_len(byte_region);
86 unsafe {
87 (self.0.clear_memory_attributes)(&self.0, base_address, length, attributes).to_result()
88 }
89 }
90 }
91
92 /// Convert a byte `Range` to `(base_address, length)`.
range_to_base_and_len(r: Range<PhysicalAddress>) -> (PhysicalAddress, PhysicalAddress)93 fn range_to_base_and_len(r: Range<PhysicalAddress>) -> (PhysicalAddress, PhysicalAddress) {
94 (r.start, r.end.checked_sub(r.start).unwrap())
95 }
96
97 #[cfg(test)]
98 mod tests {
99 use super::*;
100
101 #[test]
test_range_conversion()102 fn test_range_conversion() {
103 assert_eq!(range_to_base_and_len(2..5), (2, 3));
104 }
105 }
106