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