• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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