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