rustubs/arch/x86_64/
paging.rs1pub mod fault;
11pub mod pagetable;
12use crate::defs;
13use crate::defs::rounddown_4k;
14use crate::defs::P2V;
15use crate::defs::V2P;
16use crate::io::*;
17use crate::mm::allocate_frame_4k_zeroed;
18use crate::mm::vmm::VMArea;
19use crate::mm::vmm::VMType;
20use core::arch::asm;
21use core::ops::Range;
22use core::ptr;
23pub use pagetable::*;
24#[inline]
28pub fn get_cr3() -> u64 {
29 let cr3: u64;
30 unsafe { asm!("mov {}, cr3", out(reg) cr3) };
31 cr3
32}
33
34#[inline]
35pub fn set_cr3(cr3: u64) {
36 unsafe {
37 asm!("mov cr3, {}", in(reg) cr3);
38 }
39}
40
41#[inline]
44pub fn get_root() -> u64 { P2V(get_cr3()).unwrap() }
45
46fn get_free_page_zeroed() -> u64 {
49 P2V(allocate_frame_4k_zeroed().unwrap()).unwrap()
50}
51
52pub unsafe fn map_vma(pt_root: u64, vma: &VMArea, do_copy: bool) -> bool {
56 let flags = PTEFlags::PRESENT | PTEFlags::WRITABLE | PTEFlags::USER;
58 if !map_range(pt_root, &vma.vm_range, flags) {
59 panic!("failed to map range {:X?}, possibly OOM", vma.vm_range);
60 }
61 if !do_copy {
62 return true;
63 }
64 match vma.backing {
65 VMType::ANOM => {
66 return true;
67 }
68 VMType::FILE(f) => {
69 if !do_copy {
70 return true;
71 }
72 unsafe {
73 ptr::copy_nonoverlapping(
74 &f[0] as *const u8,
75 vma.vm_range.start as *mut u8,
76 f.len(),
77 )
78 }
79
80 if let Some(bss_range) = vma.bss_range() {
81 core::slice::from_raw_parts_mut(
82 bss_range.start as *mut u8,
83 (bss_range.end - bss_range.start) as usize,
84 )
85 .fill(0);
86 }
87
88 return true;
89 }
90 _ => {
91 panic!("unknown backing {:?}", vma);
92 }
93 }
94}
95
96pub fn map_range(pt_root: u64, r: &Range<u64>, flags: PTEFlags) -> bool {
97 let mut va_aligned = rounddown_4k(r.start);
98 while va_aligned < r.end {
99 if !map_page(pt_root, va_aligned, flags) {
100 panic!("failed to map page {:X?}, possibly OOM", va_aligned);
101 }
102 va_aligned += defs::Mem::PAGE_SIZE;
103 }
104 return true;
105}
106
107pub fn map_page(pt_root: u64, va: u64, _flags: PTEFlags) -> bool {
109 let pt = pt_root as *mut Pagetable;
110 if !defs::is_aligned_4k(va) {
111 println!("not aligned");
112 return false;
113 }
114 let flags: u64 = _flags.bits();
115 let l4idx = pagetable::p4idx(va) as usize;
116 let l3idx = pagetable::p3idx(va) as usize;
117 let l2idx = pagetable::p2idx(va) as usize;
118 let l1idx = pagetable::p1idx(va) as usize;
119 let mut require_new = false;
120 unsafe {
121 let l4_ent = &mut (*pt).entries[l4idx];
122 let l3_tbl: *mut Pagetable;
123 if l4_ent.is_unused() || require_new {
124 l3_tbl = get_free_page_zeroed() as *mut Pagetable;
125 l4_ent.entry = defs::V2P(l3_tbl as u64).unwrap() | flags;
126 require_new = true
127 } else {
128 l3_tbl = defs::P2V(l4_ent.addr()).unwrap() as *mut Pagetable;
129 }
130 let l3_ent = &mut (*l3_tbl).entries[l3idx];
131 let l2_tbl: *mut Pagetable;
132 if l3_ent.is_unused() || require_new {
133 l2_tbl = get_free_page_zeroed() as *mut Pagetable;
134 l3_ent.entry = defs::V2P(l2_tbl as u64).unwrap() | flags;
135 require_new = true
136 } else {
137 l2_tbl = defs::P2V(l3_ent.addr()).unwrap() as *mut Pagetable;
138 }
139 let l2_ent = &mut (*l2_tbl).entries[l2idx];
140 let l1_tbl: *mut Pagetable;
141 if l2_ent.is_unused() || require_new {
142 l1_tbl = get_free_page_zeroed() as *mut Pagetable;
143 l2_ent.entry = defs::V2P(l1_tbl as u64).unwrap() | flags;
144 require_new = true
145 } else {
146 l1_tbl = defs::P2V(l2_ent.addr()).unwrap() as *mut Pagetable;
147 }
148 let pte = &mut (*l1_tbl).entries[l1idx];
149 if pte.is_unused() || require_new {
150 let page = get_free_page_zeroed();
151 pte.entry = defs::V2P(page).unwrap() | flags;
152 } else {
153 panic!("PTE already taken: {:#X} for VA {:#X}", pte.entry, va);
155 }
156 asm!("invlpg [{0}]", in(reg) va);
158 }
159 return true;
160}
161
162pub unsafe fn address_space_clone(src_root_va: u64) -> Option<u64> {
172 let pt_src = src_root_va as *mut Pagetable;
173
174 let pt_new = get_free_page_zeroed() as *mut Pagetable;
175
176 for idx in 256..512 {
178 (*pt_new).entries[idx] = (*pt_src).entries[idx].clone();
179 }
180
181 for idx in 0..256 {
184 let pte_src = &(*pt_src).entries[idx];
185 if !pte_src.is_present() {
186 continue;
187 }
188
189 let next_level_va = get_free_page_zeroed();
190 (*pt_new).entries[idx].entry =
191 V2P(next_level_va).unwrap() | pte_src.flags().bits();
192
193 let next_src = P2V(pte_src.addr()).unwrap() as *mut Pagetable;
194 let next_tar = next_level_va as *mut Pagetable;
195 pt_clone_level(next_src, next_tar, 3);
196 }
197
198 Some(pt_new as u64)
199}
200
201pub unsafe fn pt_clone_level(
208 pt_src: *mut Pagetable,
209 pt_new: *mut Pagetable,
210 lv: usize,
211) {
212 for idx in 0..512 {
213 let pte_src = &(*pt_src).entries[idx];
214 if !pte_src.is_present() {
215 continue;
216 }
217 let next_level_va = get_free_page_zeroed();
218 debug_assert!(0 != next_level_va);
219 (*pt_new).entries[idx].entry =
220 V2P(next_level_va).unwrap() | pte_src.flags().bits();
221
222 let next_src = P2V(pte_src.addr()).unwrap() as *mut Pagetable;
223 let next_tar = next_level_va as *mut Pagetable;
224 if lv == 1 {
225 ptr::copy_nonoverlapping(
226 P2V(pte_src.addr()).unwrap() as *const u8,
227 next_level_va as *mut u8,
228 defs::Mem::PAGE_SIZE as usize,
229 )
230 } else {
231 pt_clone_level(next_src, next_tar, lv - 1);
232 }
233 }
234}