1use super::{FrameTracker, frame_alloc};
4use super::{PTEFlags, PageTable, PageTableEntry};
5use super::{PhysAddr, PhysPageNum, VirtAddr, VirtPageNum};
6use super::{StepByOne, VPNRange};
7use crate::config::{MEMORY_END, MMIO, PAGE_SIZE, TRAMPOLINE, TRAP_CONTEXT, USER_STACK_SIZE};
8use crate::sync::UPSafeCell;
9use alloc::collections::BTreeMap;
10use alloc::sync::Arc;
11use alloc::vec::Vec;
12use core::arch::asm;
13use lazy_static::*;
14use riscv::register::satp;
15
16unsafe extern "C" {
17 safe fn stext();
18 safe fn etext();
19 safe fn srodata();
20 safe fn erodata();
21 safe fn sdata();
22 safe fn edata();
23 safe fn sbss_with_stack();
24 safe fn ebss();
25 safe fn ekernel();
26 safe fn strampoline();
27}
28
29lazy_static! {
30 pub static ref KERNEL_SPACE: Arc<UPSafeCell<MemorySet>> =
32 Arc::new(unsafe { UPSafeCell::new(MemorySet::new_kernel()) });
33}
34pub fn kernel_token() -> usize {
36 KERNEL_SPACE.exclusive_access().token()
37}
38pub struct MemorySet {
40 page_table: PageTable,
41 areas: Vec<MapArea>,
42}
43
44impl MemorySet {
45 pub fn new_bare() -> Self {
47 Self {
48 page_table: PageTable::new(),
49 areas: Vec::new(),
50 }
51 }
52 pub fn token(&self) -> usize {
54 self.page_table.token()
55 }
56 pub fn insert_framed_area(
58 &mut self,
59 start_va: VirtAddr,
60 end_va: VirtAddr,
61 permission: MapPermission,
62 ) {
63 self.push(
64 MapArea::new(start_va, end_va, MapType::Framed, permission),
65 None,
66 );
67 }
68 pub fn remove_area_with_start_vpn(&mut self, start_vpn: VirtPageNum) {
70 if let Some((idx, area)) = self
71 .areas
72 .iter_mut()
73 .enumerate()
74 .find(|(_, area)| area.vpn_range.get_start() == start_vpn)
75 {
76 area.unmap(&mut self.page_table);
77 self.areas.remove(idx);
78 }
79 }
80 fn push(&mut self, mut map_area: MapArea, data: Option<&[u8]>) {
81 map_area.map(&mut self.page_table);
82 if let Some(data) = data {
83 map_area.copy_data(&self.page_table, data);
84 }
85 self.areas.push(map_area);
86 }
87 fn map_trampoline(&mut self) {
89 self.page_table.map(
90 VirtAddr::from(TRAMPOLINE).into(),
91 PhysAddr::from(linker_symbol_addr!(strampoline)).into(),
92 PTEFlags::R | PTEFlags::X,
93 );
94 }
95 pub fn new_kernel() -> Self {
97 let mut memory_set = Self::new_bare();
98 memory_set.map_trampoline();
100 println!(
102 ".text [{:#x}, {:#x})",
103 linker_symbol_addr!(stext),
104 linker_symbol_addr!(etext)
105 );
106 println!(
107 ".rodata [{:#x}, {:#x})",
108 linker_symbol_addr!(srodata),
109 linker_symbol_addr!(erodata)
110 );
111 println!(
112 ".data [{:#x}, {:#x})",
113 linker_symbol_addr!(sdata),
114 linker_symbol_addr!(edata)
115 );
116 println!(
117 ".bss [{:#x}, {:#x})",
118 linker_symbol_addr!(sbss_with_stack),
119 linker_symbol_addr!(ebss)
120 );
121 println!("mapping .text section");
122 memory_set.push(
123 MapArea::new(
124 (linker_symbol_addr!(stext)).into(),
125 (linker_symbol_addr!(etext)).into(),
126 MapType::Identical,
127 MapPermission::R | MapPermission::X,
128 ),
129 None,
130 );
131 println!("mapping .rodata section");
132 memory_set.push(
133 MapArea::new(
134 (linker_symbol_addr!(srodata)).into(),
135 (linker_symbol_addr!(erodata)).into(),
136 MapType::Identical,
137 MapPermission::R,
138 ),
139 None,
140 );
141 println!("mapping .data section");
142 memory_set.push(
143 MapArea::new(
144 (linker_symbol_addr!(sdata)).into(),
145 (linker_symbol_addr!(edata)).into(),
146 MapType::Identical,
147 MapPermission::R | MapPermission::W,
148 ),
149 None,
150 );
151 println!("mapping .bss section");
152 memory_set.push(
153 MapArea::new(
154 (linker_symbol_addr!(sbss_with_stack)).into(),
155 (linker_symbol_addr!(ebss)).into(),
156 MapType::Identical,
157 MapPermission::R | MapPermission::W,
158 ),
159 None,
160 );
161 println!("mapping physical memory");
162 memory_set.push(
163 MapArea::new(
164 (linker_symbol_addr!(ekernel)).into(),
165 MEMORY_END.into(),
166 MapType::Identical,
167 MapPermission::R | MapPermission::W,
168 ),
169 None,
170 );
171 println!("mapping memory-mapped registers");
172 for pair in MMIO {
173 memory_set.push(
174 MapArea::new(
175 (*pair).0.into(),
176 ((*pair).0 + (*pair).1).into(),
177 MapType::Identical,
178 MapPermission::R | MapPermission::W,
179 ),
180 None,
181 );
182 }
183 memory_set
184 }
185 pub fn from_elf(elf_data: &[u8]) -> (Self, usize, usize) {
188 let mut memory_set = Self::new_bare();
189 memory_set.map_trampoline();
191 let elf = xmas_elf::ElfFile::new(elf_data).unwrap();
193 let elf_header = elf.header;
194 let magic = elf_header.pt1.magic;
195 assert_eq!(magic, [0x7f, 0x45, 0x4c, 0x46], "invalid elf!");
196 let ph_count = elf_header.pt2.ph_count();
197 let mut max_end_vpn = VirtPageNum(0);
198 for i in 0..ph_count {
199 let ph = elf.program_header(i).unwrap();
200 if ph.get_type().unwrap() == xmas_elf::program::Type::Load {
201 let start_va: VirtAddr = (ph.virtual_addr() as usize).into();
202 let end_va: VirtAddr = ((ph.virtual_addr() + ph.mem_size()) as usize).into();
203 let mut map_perm = MapPermission::U;
204 let ph_flags = ph.flags();
205 if ph_flags.is_read() {
206 map_perm |= MapPermission::R;
207 }
208 if ph_flags.is_write() {
209 map_perm |= MapPermission::W;
210 }
211 if ph_flags.is_execute() {
212 map_perm |= MapPermission::X;
213 }
214 let map_area = MapArea::new(start_va, end_va, MapType::Framed, map_perm);
215 max_end_vpn = map_area.vpn_range.get_end();
216 memory_set.push(
217 map_area,
218 Some(&elf.input[ph.offset() as usize..(ph.offset() + ph.file_size()) as usize]),
219 );
220 }
221 }
222 let max_end_va: VirtAddr = max_end_vpn.into();
224 let mut user_stack_bottom: usize = max_end_va.into();
225 user_stack_bottom += PAGE_SIZE;
227 let user_stack_top = user_stack_bottom + USER_STACK_SIZE;
228 memory_set.push(
229 MapArea::new(
230 user_stack_bottom.into(),
231 user_stack_top.into(),
232 MapType::Framed,
233 MapPermission::R | MapPermission::W | MapPermission::U,
234 ),
235 None,
236 );
237 memory_set.push(
239 MapArea::new(
240 TRAP_CONTEXT.into(),
241 TRAMPOLINE.into(),
242 MapType::Framed,
243 MapPermission::R | MapPermission::W,
244 ),
245 None,
246 );
247 (
248 memory_set,
249 user_stack_top,
250 elf.header.pt2.entry_point() as usize,
251 )
252 }
253 pub fn from_existed_user(user_space: &MemorySet) -> MemorySet {
255 let mut memory_set = Self::new_bare();
256 memory_set.map_trampoline();
258 for area in user_space.areas.iter() {
260 let new_area = MapArea::from_another(area);
261 memory_set.push(new_area, None);
262 for vpn in area.vpn_range {
264 let src_ppn = user_space.translate(vpn).unwrap().ppn();
265 let dst_ppn = memory_set.translate(vpn).unwrap().ppn();
266 dst_ppn
267 .get_bytes_array()
268 .copy_from_slice(src_ppn.get_bytes_array());
269 }
270 }
271 memory_set
272 }
273 pub fn activate(&self) {
275 let satp = self.page_table.token();
276 unsafe {
277 satp::write(satp::Satp::from_bits(satp));
278 asm!("sfence.vma");
279 }
280 }
281 pub fn translate(&self, vpn: VirtPageNum) -> Option<PageTableEntry> {
283 self.page_table.translate(vpn)
284 }
285 pub fn recycle_data_pages(&mut self) {
287 self.areas.clear();
289 }
290}
291pub struct MapArea {
293 vpn_range: VPNRange,
294 data_frames: BTreeMap<VirtPageNum, FrameTracker>,
295 map_type: MapType,
296 map_perm: MapPermission,
297}
298
299impl MapArea {
300 pub fn new(
301 start_va: VirtAddr,
302 end_va: VirtAddr,
303 map_type: MapType,
304 map_perm: MapPermission,
305 ) -> Self {
306 let start_vpn: VirtPageNum = start_va.floor();
307 let end_vpn: VirtPageNum = end_va.ceil();
308 Self {
309 vpn_range: VPNRange::new(start_vpn, end_vpn),
310 data_frames: BTreeMap::new(),
311 map_type,
312 map_perm,
313 }
314 }
315 pub fn from_another(another: &MapArea) -> Self {
316 Self {
317 vpn_range: VPNRange::new(another.vpn_range.get_start(), another.vpn_range.get_end()),
318 data_frames: BTreeMap::new(),
319 map_type: another.map_type,
320 map_perm: another.map_perm,
321 }
322 }
323 pub fn map_one(&mut self, page_table: &mut PageTable, vpn: VirtPageNum) {
324 let ppn: PhysPageNum;
325 match self.map_type {
326 MapType::Identical => {
327 ppn = PhysPageNum(vpn.0);
328 }
329 MapType::Framed => {
330 let frame = frame_alloc().unwrap();
331 ppn = frame.ppn;
332 self.data_frames.insert(vpn, frame);
333 }
334 }
335 let pte_flags = PTEFlags::from_bits(self.map_perm.bits).unwrap();
336 page_table.map(vpn, ppn, pte_flags);
337 }
338 pub fn unmap_one(&mut self, page_table: &mut PageTable, vpn: VirtPageNum) {
339 if self.map_type == MapType::Framed {
340 self.data_frames.remove(&vpn);
341 }
342 page_table.unmap(vpn);
343 }
344 pub fn map(&mut self, page_table: &mut PageTable) {
345 for vpn in self.vpn_range {
346 self.map_one(page_table, vpn);
347 }
348 }
349 pub fn unmap(&mut self, page_table: &mut PageTable) {
350 for vpn in self.vpn_range {
351 self.unmap_one(page_table, vpn);
352 }
353 }
354 pub fn copy_data(&mut self, page_table: &PageTable, data: &[u8]) {
357 assert_eq!(self.map_type, MapType::Framed);
358 let mut start: usize = 0;
359 let mut current_vpn = self.vpn_range.get_start();
360 let len = data.len();
361 loop {
362 let src = &data[start..len.min(start + PAGE_SIZE)];
363 let dst = &mut page_table
364 .translate(current_vpn)
365 .unwrap()
366 .ppn()
367 .get_bytes_array()[..src.len()];
368 dst.copy_from_slice(src);
369 start += PAGE_SIZE;
370 if start >= len {
371 break;
372 }
373 current_vpn.step();
374 }
375 }
376}
377
378#[derive(Copy, Clone, PartialEq, Debug)]
379pub enum MapType {
381 Identical,
382 Framed,
383}
384
385bitflags! {
386 pub struct MapPermission: u8 {
388 const R = 1 << 1;
390 const W = 1 << 2;
392 const X = 1 << 3;
394 const U = 1 << 4;
396 }
397}
398
399#[allow(unused)]
400pub fn remap_test() {
402 let mut kernel_space = KERNEL_SPACE.exclusive_access();
403 let mid_text: VirtAddr = ((linker_symbol_addr!(stext) + linker_symbol_addr!(etext)) / 2).into();
404 let mid_rodata: VirtAddr =
405 ((linker_symbol_addr!(srodata) + linker_symbol_addr!(erodata)) / 2).into();
406 let mid_data: VirtAddr = ((linker_symbol_addr!(sdata) + linker_symbol_addr!(edata)) / 2).into();
407 assert!(
408 !kernel_space
409 .page_table
410 .translate(mid_text.floor())
411 .unwrap()
412 .writable(),
413 );
414 assert!(
415 !kernel_space
416 .page_table
417 .translate(mid_rodata.floor())
418 .unwrap()
419 .writable(),
420 );
421 assert!(
422 !kernel_space
423 .page_table
424 .translate(mid_data.floor())
425 .unwrap()
426 .executable(),
427 );
428 println!("remap_test passed!");
429}