memory_map.rs 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. use core::marker::PhantomData;
  2. /// This Tag provides an initial host memory map.
  3. ///
  4. /// The map provided is guaranteed to list all standard RAM that should be
  5. /// available for normal use. This type however includes the regions occupied
  6. /// by kernel, mbi, segments and modules. Kernel must take care not to
  7. /// overwrite these regions.
  8. ///
  9. /// This tag may not be provided by some boot loaders on EFI platforms if EFI
  10. /// boot services are enabled and available for the loaded image (The EFI boot
  11. /// services tag may exist in the Multiboot2 boot information structure).
  12. #[derive(Debug)]
  13. #[repr(C)]
  14. pub struct MemoryMapTag {
  15. typ: u32,
  16. size: u32,
  17. entry_size: u32,
  18. entry_version: u32,
  19. first_area: MemoryArea,
  20. }
  21. impl MemoryMapTag {
  22. /// Return an iterator over all AVAILABLE marked memory areas.
  23. pub fn memory_areas(&self) -> impl Iterator<Item = &MemoryArea> {
  24. self.all_memory_areas().filter(|entry| entry.typ == 1)
  25. }
  26. /// Return an iterator over all marked memory areas.
  27. pub fn all_memory_areas(&self) -> impl Iterator<Item = &MemoryArea> {
  28. let self_ptr = self as *const MemoryMapTag;
  29. let start_area = (&self.first_area) as *const MemoryArea;
  30. MemoryAreaIter {
  31. current_area: start_area as u64,
  32. last_area: (self_ptr as u64 + (self.size - self.entry_size) as u64),
  33. entry_size: self.entry_size,
  34. phantom: PhantomData,
  35. }
  36. }
  37. }
  38. /// A memory area entry descriptor.
  39. #[derive(Debug)]
  40. #[repr(C)]
  41. pub struct MemoryArea {
  42. base_addr: u64,
  43. length: u64,
  44. typ: u32,
  45. _reserved: u32,
  46. }
  47. impl MemoryArea {
  48. /// The start address of the memory region.
  49. pub fn start_address(&self) -> u64 {
  50. self.base_addr
  51. }
  52. /// The end address of the memory region.
  53. pub fn end_address(&self) -> u64 {
  54. self.base_addr + self.length
  55. }
  56. /// The size, in bytes, of the memory region.
  57. pub fn size(&self) -> u64 {
  58. self.length
  59. }
  60. /// The type of the memory region.
  61. pub fn typ(&self) -> MemoryAreaType {
  62. match self.typ {
  63. 1 => MemoryAreaType::Available,
  64. 3 => MemoryAreaType::AcpiAvailable,
  65. 4 => MemoryAreaType::ReservedHibernate,
  66. 5 => MemoryAreaType::Defective,
  67. _ => MemoryAreaType::Reserved,
  68. }
  69. }
  70. }
  71. /// An enum of possible reported region types.
  72. #[derive(Debug, PartialEq, Eq)]
  73. pub enum MemoryAreaType {
  74. /// A reserved area that must not be used.
  75. Reserved,
  76. /// Available memory free to be used by the OS.
  77. Available,
  78. /// Usable memory holding ACPI information.
  79. AcpiAvailable,
  80. /// Reserved memory which needs to be preserved on hibernation.
  81. ReservedHibernate,
  82. /// Memory which is occupied by defective RAM modules.
  83. Defective,
  84. }
  85. /// An iterator over all memory areas
  86. #[derive(Clone, Debug)]
  87. pub struct MemoryAreaIter<'a> {
  88. current_area: u64,
  89. last_area: u64,
  90. entry_size: u32,
  91. phantom: PhantomData<&'a MemoryArea>,
  92. }
  93. impl<'a> Iterator for MemoryAreaIter<'a> {
  94. type Item = &'a MemoryArea;
  95. fn next(&mut self) -> Option<&'a MemoryArea> {
  96. if self.current_area > self.last_area {
  97. None
  98. } else {
  99. let area = unsafe { &*(self.current_area as *const MemoryArea) };
  100. self.current_area += self.entry_size as u64;
  101. Some(area)
  102. }
  103. }
  104. }
  105. /// EFI memory map as per EFI specification.
  106. #[derive(Debug)]
  107. #[repr(C)]
  108. pub struct EFIMemoryMapTag {
  109. typ: u32,
  110. size: u32,
  111. desc_size: u32,
  112. desc_version: u32,
  113. first_desc: EFIMemoryDesc,
  114. }
  115. impl EFIMemoryMapTag {
  116. /// Return an iterator over ALL marked memory areas.
  117. ///
  118. /// This differs from `MemoryMapTag` as for UEFI, the OS needs some non-
  119. /// available memory areas for tables and such.
  120. pub fn memory_areas(&self) -> EFIMemoryAreaIter {
  121. let self_ptr = self as *const EFIMemoryMapTag;
  122. let start_area = (&self.first_desc) as *const EFIMemoryDesc;
  123. EFIMemoryAreaIter {
  124. current_area: start_area as u64,
  125. last_area: (self_ptr as u64 + self.size as u64),
  126. entry_size: self.desc_size,
  127. phantom: PhantomData,
  128. }
  129. }
  130. }
  131. /// EFI Boot Memory Map Descriptor
  132. #[derive(Debug)]
  133. #[repr(C)]
  134. pub struct EFIMemoryDesc {
  135. typ: u32,
  136. _padding: u32,
  137. phys_addr: u64,
  138. virt_addr: u64,
  139. num_pages: u64,
  140. attr: u64,
  141. }
  142. /// An enum of possible reported region types.
  143. #[derive(Debug, PartialEq, Eq)]
  144. pub enum EFIMemoryAreaType {
  145. /// Unusable.
  146. EfiReservedMemoryType,
  147. /// Code area of a UEFI application.
  148. EfiLoaderCode,
  149. /// Data area of a UEFI application.
  150. EfiLoaderData,
  151. /// Code area of a UEFI Boot Service Driver.
  152. EfiBootServicesCode,
  153. /// Data area of a UEFI Boot Service Driver.
  154. EfiBootServicesData,
  155. /// Code area of a UEFI Runtime Driver.
  156. ///
  157. /// Must be preserved in working and ACPI S1-S3 states.
  158. EfiRuntimeServicesCode,
  159. /// Data area of a UEFI Runtime Driver.
  160. ///
  161. /// Must be preserved in working and ACPI S1-S3 states.
  162. EfiRuntimeServicesData,
  163. /// Available memory.
  164. EfiConventionalMemory,
  165. /// Memory with errors, treat as unusable.
  166. EfiUnusableMemory,
  167. /// Memory containing the ACPI tables.
  168. ///
  169. /// Must be preserved in working and ACPI S1-S3 states.
  170. EfiACPIReclaimMemory,
  171. /// Memory reserved by firmware.
  172. ///
  173. /// Must be preserved in working and ACPI S1-S3 states.
  174. EfiACPIMemoryNVS,
  175. /// Memory used by firmware for requesting memory mapping of IO.
  176. ///
  177. /// Should not be used by the OS. Use the ACPI tables for memory mapped IO
  178. /// information.
  179. EfiMemoryMappedIO,
  180. /// Memory used to translate memory cycles to IO cycles.
  181. ///
  182. /// Should not be used by the OS. Use the ACPI tables for memory mapped IO
  183. /// information.
  184. EfiMemoryMappedIOPortSpace,
  185. /// Memory used by the processor.
  186. ///
  187. /// Must be preserved in working and ACPI S1-S4 states. Processor defined
  188. /// otherwise.
  189. EfiPalCode,
  190. /// Available memory supporting byte-addressable non-volatility.
  191. EfiPersistentMemory,
  192. /// Unknown region type, treat as unusable.
  193. EfiUnknown,
  194. }
  195. impl EFIMemoryDesc {
  196. /// The physical address of the memory region.
  197. pub fn physical_address(&self) -> u64 {
  198. self.phys_addr
  199. }
  200. /// The virtual address of the memory region.
  201. pub fn virtual_address(&self) -> u64 {
  202. self.virt_addr
  203. }
  204. /// The size in bytes of the memory region.
  205. pub fn size(&self) -> u64 {
  206. // Spec says this is number of 4KiB pages.
  207. self.num_pages * 4096
  208. }
  209. /// The type of the memory region.
  210. pub fn typ(&self) -> EFIMemoryAreaType {
  211. match self.typ {
  212. 0 => EFIMemoryAreaType::EfiReservedMemoryType,
  213. 1 => EFIMemoryAreaType::EfiLoaderCode,
  214. 2 => EFIMemoryAreaType::EfiLoaderData,
  215. 3 => EFIMemoryAreaType::EfiBootServicesCode,
  216. 4 => EFIMemoryAreaType::EfiBootServicesData,
  217. 5 => EFIMemoryAreaType::EfiRuntimeServicesCode,
  218. 6 => EFIMemoryAreaType::EfiRuntimeServicesData,
  219. 7 => EFIMemoryAreaType::EfiConventionalMemory,
  220. 8 => EFIMemoryAreaType::EfiUnusableMemory,
  221. 9 => EFIMemoryAreaType::EfiACPIReclaimMemory,
  222. 10 => EFIMemoryAreaType::EfiACPIMemoryNVS,
  223. 11 => EFIMemoryAreaType::EfiMemoryMappedIO,
  224. 12 => EFIMemoryAreaType::EfiMemoryMappedIOPortSpace,
  225. 13 => EFIMemoryAreaType::EfiPalCode,
  226. 14 => EFIMemoryAreaType::EfiPersistentMemory,
  227. _ => EFIMemoryAreaType::EfiUnknown,
  228. }
  229. }
  230. }
  231. /// EFI ExitBootServices was not called
  232. #[derive(Debug)]
  233. #[repr(C)]
  234. pub struct EFIBootServicesNotExited {
  235. typ: u32,
  236. size: u32,
  237. }
  238. /// An iterator over ALL EFI memory areas.
  239. #[derive(Clone, Debug)]
  240. pub struct EFIMemoryAreaIter<'a> {
  241. current_area: u64,
  242. last_area: u64,
  243. entry_size: u32,
  244. phantom: PhantomData<&'a EFIMemoryDesc>,
  245. }
  246. impl<'a> Iterator for EFIMemoryAreaIter<'a> {
  247. type Item = &'a EFIMemoryDesc;
  248. fn next(&mut self) -> Option<&'a EFIMemoryDesc> {
  249. if self.current_area > self.last_area {
  250. None
  251. } else {
  252. let area = unsafe { &*(self.current_area as *const EFIMemoryDesc) };
  253. self.current_area += self.entry_size as u64;
  254. Some(area)
  255. }
  256. }
  257. }