You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

241 lines
7.3 KiB

  1. //! Paging subsystem. *Note: uses recursive mapping.*
  2. //!
  3. //! Extremely ripped off from Phil Oppermann's tutorials, because I don't feel like writing
  4. //! a paging system off the top of my head today.
  5. use core::ops::{Deref, DerefMut};
  6. use multiboot2::BootInformation;
  7. use super::PAGE_SIZE;
  8. use super::{Frame, FrameAllocator};
  9. mod entry;
  10. mod table;
  11. mod mapper;
  12. mod temporary_page;
  13. pub use self::entry::*;
  14. use self::table::{Table, Level4};
  15. use self::temporary_page::TemporaryPage;
  16. use self::mapper::Mapper;
  17. /// Upper bound on entries per page table
  18. const ENTRY_COUNT: usize = 512;
  19. /// Helper type aliases used to make function signatures more expressive
  20. pub type PhysicalAddress = usize;
  21. pub type VirtualAddress = usize;
  22. pub struct ActivePageTable {
  23. mapper: Mapper
  24. }
  25. impl Deref for ActivePageTable {
  26. type Target = Mapper;
  27. fn deref(&self) -> &Mapper {&self.mapper}
  28. }
  29. impl DerefMut for ActivePageTable {
  30. fn deref_mut(&mut self) -> &mut Mapper {&mut self.mapper}
  31. }
  32. impl ActivePageTable {
  33. unsafe fn new() -> ActivePageTable {
  34. ActivePageTable {
  35. mapper: Mapper::new(),
  36. }
  37. }
  38. /// Executes a closure, with a different page table recursively mapped
  39. pub fn with<F>(&mut self, table: &mut InactivePageTable, scratch_page: &mut TemporaryPage, f: F)
  40. where F: FnOnce(&mut Mapper) {
  41. use x86::shared::{tlb, control_regs};
  42. {
  43. // Backup the original P4 pointer
  44. let backup = Frame::containing_address(
  45. unsafe {control_regs::cr3()}
  46. );
  47. // Map a scratch page to the current p4 table
  48. let p4_table = scratch_page.map_table_frame(backup.clone(), self);
  49. // Overwrite main P4 recursive mapping
  50. self.p4_mut()[511].set(table.p4_frame.clone(), PRESENT | WRITABLE);
  51. unsafe {tlb::flush_all();} // flush *all* TLBs to prevent fuckiness
  52. // Execute f in context of the new page table
  53. f(self);
  54. // Restore the original pointer to P4
  55. p4_table[511].set(backup, PRESENT | WRITABLE);
  56. unsafe {tlb::flush_all();} // prevent fuckiness
  57. }
  58. scratch_page.unmap(self);
  59. }
  60. /// Switches to a new [`InactivePageTable`], making it active.
  61. ///
  62. /// Note: We don't need to flush the TLB here, as the CPU automatically flushes
  63. /// the TLB when the P4 table is switched.
  64. pub fn switch(&mut self, new_table: InactivePageTable) -> InactivePageTable {
  65. use x86::shared::{control_regs};
  66. let old_table = InactivePageTable {
  67. p4_frame: Frame::containing_address(unsafe {control_regs::cr3()}),
  68. };
  69. unsafe {
  70. control_regs::cr3_write(new_table.p4_frame.start_address());
  71. }
  72. old_table
  73. }
  74. }
  75. /// Owns an inactive P4 table.
  76. pub struct InactivePageTable {
  77. p4_frame: Frame,
  78. }
  79. impl InactivePageTable {
  80. pub fn new(frame: Frame, active_table: &mut ActivePageTable, temporary_page: &mut TemporaryPage)
  81. -> InactivePageTable {
  82. {
  83. let table = temporary_page.map_table_frame(frame.clone(), active_table);
  84. // zero the new inactive page table
  85. table.zero();
  86. // set up a recursive mapping for this table
  87. table[511].set(frame.clone(), PRESENT | WRITABLE);
  88. }
  89. temporary_page.unmap(active_table);
  90. InactivePageTable { p4_frame: frame }
  91. }
  92. }
  93. /// A representation of a virtual page.
  94. #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
  95. pub struct Page {
  96. index: usize,
  97. }
  98. impl Page {
  99. /// Retrieves the page containing a given virtual address.
  100. pub fn containing_address(address: VirtualAddress) -> Page {
  101. assert!(address < 0x0000_8000_0000_0000 ||
  102. address >= 0xffff_8000_0000_0000,
  103. "invalid address: {:#x}", address);
  104. Page { index: address / PAGE_SIZE }
  105. }
  106. /// Returns the start (virtual) address of a page
  107. pub fn start_address(&self) -> VirtualAddress {
  108. self.index * PAGE_SIZE
  109. }
  110. pub fn range_inclusive(start: Page, end: Page) -> PageIter {
  111. PageIter {
  112. start: start,
  113. end: end,
  114. }
  115. }
  116. fn p4_index(&self) -> usize {
  117. (self.index >> 27) & 0o777
  118. }
  119. fn p3_index(&self) -> usize {
  120. (self.index >> 18) & 0o777
  121. }
  122. fn p2_index(&self) -> usize {
  123. (self.index >> 9) & 0o777
  124. }
  125. fn p1_index(&self) -> usize {
  126. (self.index >> 0) & 0o777
  127. }
  128. }
  129. pub struct PageIter {
  130. start: Page,
  131. end: Page,
  132. }
  133. impl Iterator for PageIter {
  134. type Item = Page;
  135. fn next(&mut self) -> Option<Page> {
  136. if self.start <= self.end {
  137. let frame = self.start.clone();
  138. self.start.index += 1;
  139. Some(frame)
  140. } else {
  141. None
  142. }
  143. }
  144. }
  145. /// Remap the kernel
  146. pub fn remap_kernel<A>(allocator: &mut A, boot_info: &BootInformation)
  147. -> ActivePageTable
  148. where A: FrameAllocator
  149. {
  150. let mut scratch_page = TemporaryPage::new(Page { index: 0xabadcafe },
  151. allocator);
  152. let mut active_table = unsafe {ActivePageTable::new()};
  153. let mut new_table = {
  154. let frame = allocator.alloc_frame()
  155. .expect("Attempted to allocate a frame for a new page table, but no frames are available!");
  156. InactivePageTable::new(frame, &mut active_table, &mut scratch_page)
  157. };
  158. active_table.with(&mut new_table, &mut scratch_page, |mapper| {
  159. let elf_sections_tag = boot_info.elf_sections_tag()
  160. .expect("ELF sections tag required!");
  161. // -- Identity map the kernel sections
  162. for section in elf_sections_tag.sections() {
  163. if !section.is_allocated() {
  164. // section is not loaded to memory
  165. continue;
  166. }
  167. assert!(section.start_address() % PAGE_SIZE == 0, "ELF sections must be page-aligned!");
  168. debug!("Mapping section at addr: {:#x}, size: {:#x}",
  169. section.addr, section.size);
  170. let flags = EntryFlags::from_elf_section_flags(section);
  171. let start_frame = Frame::containing_address(section.start_address());
  172. let end_frame = Frame::containing_address(section.end_address() - 1);
  173. for frame in Frame::range_inclusive(start_frame, end_frame) {
  174. mapper.identity_map(frame, flags, allocator);
  175. }
  176. }
  177. // -- Identity map the VGA console buffer (it's only one frame long)
  178. let vga_buffer_frame = Frame::containing_address(0xb8000);
  179. mapper.identity_map(vga_buffer_frame, WRITABLE, allocator);
  180. // -- Identity map the multiboot info structure
  181. let multiboot_start = Frame::containing_address(boot_info.start_address());
  182. let multiboot_end = Frame::containing_address(boot_info.end_address() - 1);
  183. for frame in Frame::range_inclusive(multiboot_start, multiboot_end) {
  184. mapper.identity_map(frame, PRESENT | WRITABLE, allocator);
  185. }
  186. });
  187. let old_table = active_table.switch(new_table);
  188. info!("successfully switched to new page table.");
  189. // Create a guard page in place of the old P4 table's page
  190. let old_p4_page = Page::containing_address(old_table.p4_frame.start_address());
  191. active_table.unmap(old_p4_page, allocator);
  192. info!("guard page established at {:#x}", old_p4_page.start_address());
  193. active_table
  194. }