memory_map.rs 8.8 KB

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