Skip to content

Commit 554562b

Browse files
committed
paging: make ALL levels writable, not just P4
1 parent 7a8c54b commit 554562b

1 file changed

Lines changed: 48 additions & 23 deletions

File tree

src/arch/x86_64/mm/paging.rs

Lines changed: 48 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use core::fmt::Debug;
22
use core::ptr;
3-
43
use free_list::PageLayout;
54
use x86_64::registers::control::{Cr0, Cr0Flags, Cr2, Cr3};
65
#[cfg(feature = "common-os")]
@@ -11,9 +10,7 @@ pub use x86_64::structures::paging::PageTableFlags as PageTableEntryFlags;
1110
use x86_64::structures::paging::frame::PhysFrameRange;
1211
use x86_64::structures::paging::mapper::{MapToError, MappedFrame, TranslateResult, UnmapError};
1312
use x86_64::structures::paging::page::PageRange;
14-
use x86_64::structures::paging::{
15-
FrameAllocator, Mapper, OffsetPageTable, Page, PageTable, PhysFrame, Size4KiB, Translate,
16-
};
13+
use x86_64::structures::paging::{FrameAllocator, Mapper, OffsetPageTable, Page, PageTable, PhysFrame, Size4KiB, Translate};
1714

1815
use crate::arch::x86_64::kernel::processor;
1916
use crate::arch::x86_64::mm::{PhysAddr, VirtAddr};
@@ -325,24 +322,6 @@ fn make_p4_writable() {
325322

326323
let mut pt = unsafe { identity_mapped_page_table() };
327324

328-
let p4_page = {
329-
let (p4_frame, _) = Cr3::read_raw();
330-
let p4_addr = x86_64::VirtAddr::new(p4_frame.start_address().as_u64());
331-
Page::<Size4KiB>::from_start_address(p4_addr).unwrap()
332-
};
333-
334-
let TranslateResult::Mapped { frame, flags, .. } = pt.translate(p4_page.start_address()) else {
335-
unreachable!()
336-
};
337-
338-
let make_writable = || unsafe {
339-
let flags = flags | PageTableEntryFlags::WRITABLE;
340-
match frame {
341-
MappedFrame::Size1GiB(_) => pt.set_flags_p3_entry(p4_page, flags).unwrap().ignore(),
342-
MappedFrame::Size2MiB(_) => pt.set_flags_p2_entry(p4_page, flags).unwrap().ignore(),
343-
MappedFrame::Size4KiB(_) => pt.update_flags(p4_page, flags).unwrap().ignore(),
344-
}
345-
};
346325

347326
unsafe fn without_protect<F, R>(f: F) -> R
348327
where
@@ -359,7 +338,53 @@ fn make_p4_writable() {
359338
ret
360339
}
361340

362-
unsafe { without_protect(make_writable) }
341+
let (p4_frame, _) = Cr3::read_raw();
342+
unsafe {
343+
without_protect(||
344+
make_page_table_writable(&mut pt, p4_frame, 4)
345+
);
346+
};
347+
348+
}
349+
350+
351+
unsafe fn make_page_table_writable(page_table: &mut OffsetPageTable<'static>, pt_frame: PhysFrame, level: u8) {
352+
let pt_address = page_table.phys_offset() + pt_frame.start_address().as_u64();
353+
let pt = unsafe {
354+
pt_address.as_ptr::<PageTable>().as_ref().unwrap()
355+
};
356+
357+
// Unmap the page table
358+
let TranslateResult::Mapped { frame, flags, .. } = page_table.translate(pt_address) else {
359+
unreachable!()
360+
};
361+
362+
if !flags.contains(PageTableEntryFlags::WRITABLE) {
363+
let flags = flags | PageTableEntryFlags::WRITABLE;
364+
let page = Page::<Size4KiB>::containing_address(pt_address);
365+
unsafe {
366+
match frame {
367+
MappedFrame::Size1GiB(_) => page_table.set_flags_p3_entry(page, flags).unwrap().ignore(),
368+
MappedFrame::Size2MiB(_) => page_table.set_flags_p2_entry(page, flags).unwrap().ignore(),
369+
MappedFrame::Size4KiB(_) => page_table.update_flags(page, flags).unwrap().ignore(),
370+
}
371+
}
372+
warn!("Page table {pt_frame:x?}, was mapped from RO memory!");
373+
}
374+
375+
for entry in pt.iter() {
376+
if entry.is_unused() {
377+
continue;
378+
}
379+
380+
let is_page_table = level > 1 && !entry.flags().contains(PageTableEntryFlags::HUGE_PAGE);
381+
if is_page_table {
382+
let phys = entry.frame().unwrap();
383+
unsafe {
384+
make_page_table_writable(page_table, phys, level - 1);
385+
}
386+
}
387+
}
363388
}
364389

365390
pub unsafe fn log_page_tables() {

0 commit comments

Comments
 (0)