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.

242 lines
7.4 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::instructions::tlb;
  42. use x86::registers::control_regs;
  43. {
  44. // Backup the original P4 pointer
  45. let backup = Frame::containing_address(
  46. unsafe {control_regs::cr3().0 as usize}
  47. );
  48. // Map a scratch page to the current p4 table
  49. let p4_table = scratch_page.map_table_frame(backup.clone(), self);
  50. // Overwrite main P4 recursive mapping
  51. self.p4_mut()[511].set(table.p4_frame.clone(), PRESENT | WRITABLE);
  52. unsafe {tlb::flush_all();} // flush *all* TLBs to prevent fuckiness
  53. // Execute f in context of the new page table
  54. f(self);
  55. // Restore the original pointer to P4
  56. p4_table[511].set(backup, PRESENT | WRITABLE);
  57. unsafe {tlb::flush_all();} // prevent fuckiness
  58. }
  59. scratch_page.unmap(self);
  60. }
  61. /// Switches to a new [`InactivePageTable`], making it active.
  62. ///
  63. /// Note: We don't need to flush the TLB here, as the CPU automatically flushes
  64. /// the TLB when the P4 table is switched.
  65. pub fn switch(&mut self, new_table: InactivePageTable) -> InactivePageTable {
  66. use x86::registers::control_regs;
  67. let old_table = InactivePageTable {
  68. p4_frame: Frame::containing_address(unsafe {control_regs::cr3().0 as usize}),
  69. };
  70. unsafe {
  71. control_regs::cr3_write(::x86::PhysicalAddress(new_table.p4_frame.start_address() as u64));
  72. }
  73. old_table
  74. }
  75. }
  76. /// Owns an inactive P4 table.
  77. pub struct InactivePageTable {
  78. p4_frame: Frame,
  79. }
  80. impl InactivePageTable {
  81. pub fn new(frame: Frame, active_table: &mut ActivePageTable, temporary_page: &mut TemporaryPage)
  82. -> InactivePageTable {
  83. {
  84. let table = temporary_page.map_table_frame(frame.clone(), active_table);
  85. // zero the new inactive page table
  86. table.zero();
  87. // set up a recursive mapping for this table
  88. table[511].set(frame.clone(), PRESENT | WRITABLE);
  89. }
  90. temporary_page.unmap(active_table);
  91. InactivePageTable { p4_frame: frame }
  92. }
  93. }
  94. /// A representation of a virtual page.
  95. #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
  96. pub struct Page {
  97. index: usize,
  98. }
  99. impl Page {
  100. /// Retrieves the page containing a given virtual address.
  101. pub fn containing_address(address: VirtualAddress) -> Page {
  102. assert!(address < 0x0000_8000_0000_0000 ||
  103. address >= 0xffff_8000_0000_0000,
  104. "invalid address: {:#x}", address);
  105. Page { index: address / PAGE_SIZE }
  106. }
  107. /// Returns the start (virtual) address of a page
  108. pub fn start_address(&self) -> VirtualAddress {
  109. self.index * PAGE_SIZE
  110. }
  111. pub fn range_inclusive(start: Page, end: Page) -> PageIter {
  112. PageIter {
  113. start: start,
  114. end: end,
  115. }
  116. }
  117. fn p4_index(&self) -> usize {
  118. (self.index >> 27) & 0o777
  119. }
  120. fn p3_index(&self) -> usize {
  121. (self.index >> 18) & 0o777
  122. }
  123. fn p2_index(&self) -> usize {
  124. (self.index >> 9) & 0o777
  125. }
  126. fn p1_index(&self) -> usize {
  127. (self.index >> 0) & 0o777
  128. }
  129. }
  130. pub struct PageIter {
  131. start: Page,
  132. end: Page,
  133. }
  134. impl Iterator for PageIter {
  135. type Item = Page;
  136. fn next(&mut self) -> Option<Page> {
  137. if self.start <= self.end {
  138. let frame = self.start.clone();
  139. self.start.index += 1;
  140. Some(frame)
  141. } else {
  142. None
  143. }
  144. }
  145. }
  146. /// Remap the kernel
  147. pub fn remap_kernel<A>(allocator: &mut A, boot_info: &BootInformation)
  148. -> ActivePageTable
  149. where A: FrameAllocator
  150. {
  151. let mut scratch_page = TemporaryPage::new(Page { index: 0xabadcafe },
  152. allocator);
  153. let mut active_table = unsafe {ActivePageTable::new()};
  154. let mut new_table = {
  155. let frame = allocator.alloc_frame()
  156. .expect("Attempted to allocate a frame for a new page table, but no frames are available!");
  157. InactivePageTable::new(frame, &mut active_table, &mut scratch_page)
  158. };
  159. active_table.with(&mut new_table, &mut scratch_page, |mapper| {
  160. let elf_sections_tag = boot_info.elf_sections_tag()
  161. .expect("ELF sections tag required!");
  162. // -- Identity map the kernel sections
  163. for section in elf_sections_tag.sections() {
  164. if !section.is_allocated() {
  165. // section is not loaded to memory
  166. continue;
  167. }
  168. assert!(section.start_address() % PAGE_SIZE == 0, "ELF sections must be page-aligned!");
  169. debug!("Mapping section at addr: {:#x}, size: {:#x}",
  170. section.addr, section.size);
  171. let flags = EntryFlags::from_elf_section_flags(section);
  172. let start_frame = Frame::containing_address(section.start_address());
  173. let end_frame = Frame::containing_address(section.end_address() - 1);
  174. for frame in Frame::range_inclusive(start_frame, end_frame) {
  175. mapper.identity_map(frame, flags, allocator);
  176. }
  177. }
  178. // -- Identity map the VGA console buffer (it's only one frame long)
  179. let vga_buffer_frame = Frame::containing_address(0xb8000);
  180. mapper.identity_map(vga_buffer_frame, WRITABLE, allocator);
  181. // -- Identity map the multiboot info structure
  182. let multiboot_start = Frame::containing_address(boot_info.start_address());
  183. let multiboot_end = Frame::containing_address(boot_info.end_address() - 1);
  184. for frame in Frame::range_inclusive(multiboot_start, multiboot_end) {
  185. mapper.identity_map(frame, PRESENT | WRITABLE, allocator);
  186. }
  187. });
  188. let old_table = active_table.switch(new_table);
  189. info!("successfully switched to new page table.");
  190. // Create a guard page in place of the old P4 table's page
  191. let old_p4_page = Page::containing_address(old_table.p4_frame.start_address());
  192. active_table.unmap(old_p4_page, allocator);
  193. info!("guard page established at {:#x}", old_p4_page.start_address());
  194. active_table
  195. }