1 | use crate::data_types::PhysicalAddress; |
2 | use crate::proto::unsafe_protocol ; |
3 | use crate::table::boot::MemoryAttribute; |
4 | use crate::{Result, Status}; |
5 | use 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" )] |
12 | pub 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 | |
35 | impl 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)`. |
107 | fn 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)] |
112 | mod 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 | |