xref: /DragonOS/kernel/src/arch/riscv64/mm/init.rs (revision 1ea2daad8121b77ed704e6d7c3a09f478147441d)
1 use core::sync::atomic::{compiler_fence, AtomicBool, Ordering};
2 
3 use log::{debug, info};
4 use system_error::SystemError;
5 
6 use crate::{
7     arch::{
8         mm::{
9             kernel_page_flags, INNER_ALLOCATOR, KERNEL_BEGIN_PA, KERNEL_BEGIN_VA, KERNEL_END_PA,
10             KERNEL_END_VA,
11         },
12         MMArch,
13     },
14     driver::firmware::efi::efi_manager,
15     libs::lib_ui::screen_manager::scm_disable_put_to_window,
16     mm::{
17         allocator::{buddy::BuddyAllocator, bump::BumpAllocator, page_frame::FrameAllocator},
18         kernel_mapper::KernelMapper,
19         memblock::mem_block_manager,
20         page::PageEntry,
21         MemoryManagementArch, PageTableKind, PhysAddr, VirtAddr,
22     },
23 };
24 
25 use super::RiscV64MMArch;
26 
27 pub(super) static mut INITIAL_PGTABLE_VALUE: PhysAddr = PhysAddr::new(0);
28 
29 #[inline(never)]
30 pub fn mm_early_init() {
31     unsafe { init_kernel_addr() };
32 }
33 
34 unsafe fn init_kernel_addr() {
35     extern "C" {
36         /// 内核起始label
37         fn boot_text_start_pa();
38         /// 内核结束位置的label
39         fn _end();
40 
41         fn _start();
42 
43         /// 内核start标签被加载到的物理地址
44         fn __initial_start_load_paddr();
45     }
46     let initial_start_load_pa = *(__initial_start_load_paddr as usize as *const usize);
47     let offset = _start as usize - boot_text_start_pa as usize;
48     let start_pa = initial_start_load_pa - offset;
49 
50     let offset2 = _end as usize - boot_text_start_pa as usize;
51     let end_pa = start_pa + offset2;
52 
53     KERNEL_BEGIN_PA = PhysAddr::new(start_pa);
54     KERNEL_END_PA = PhysAddr::new(end_pa);
55 
56     KERNEL_BEGIN_VA = VirtAddr::new(boot_text_start_pa as usize);
57     KERNEL_END_VA = VirtAddr::new(_end as usize);
58 
59     debug!(
60         "init_kernel_addr: \n\tKERNEL_BEGIN_PA: {KERNEL_BEGIN_PA:?}
61         \tKERNEL_END_PA: {KERNEL_END_PA:?}
62         \tKERNEL_BEGIN_VA: {KERNEL_BEGIN_VA:?}
63         \tKERNEL_END_VA: {KERNEL_END_VA:?}
64     "
65     );
66 }
67 
68 pub(super) unsafe fn riscv_mm_init() -> Result<(), SystemError> {
69     mem_block_manager()
70         .reserve_block(KERNEL_BEGIN_PA, KERNEL_END_PA - KERNEL_BEGIN_PA)
71         .expect("Failed to reserve kernel memory");
72     // 开启S-mode User Memory Access,允许内核访问用户空间
73     riscv::register::sstatus::set_sum();
74 
75     let mut bump_allocator = BumpAllocator::<RiscV64MMArch>::new(0);
76     let _old_page_table = MMArch::table(PageTableKind::Kernel);
77     let new_page_table: PhysAddr;
78 
79     // 使用bump分配器,把所有的内存页都映射到页表
80     {
81         // debug!("to create new page table");
82         // 用bump allocator创建新的页表
83         let mut mapper: crate::mm::page::PageMapper<MMArch, &mut BumpAllocator<MMArch>> =
84             crate::mm::page::PageMapper::<MMArch, _>::create(
85                 PageTableKind::Kernel,
86                 &mut bump_allocator,
87             )
88             .expect("Failed to create page mapper");
89         new_page_table = mapper.table().phys();
90         // debug!("PageMapper created");
91 
92         // 取消最开始时候,在head.S中指定的映射(暂时不刷新TLB)
93         {
94             let table = mapper.table();
95             let empty_entry = PageEntry::<MMArch>::from_usize(0);
96             for i in 0..MMArch::PAGE_ENTRY_NUM {
97                 table
98                     .set_entry(i, empty_entry)
99                     .expect("Failed to empty page table entry");
100             }
101         }
102         debug!("Successfully emptied page table");
103 
104         let total_num = mem_block_manager().total_initial_memory_regions();
105         for i in 0..total_num {
106             let area = mem_block_manager().get_initial_memory_region(i).unwrap();
107             // debug!("area: base={:?}, size={:#x}, end={:?}", area.base, area.size, area.base + area.size);
108             for i in 0..((area.size + MMArch::PAGE_SIZE - 1) / MMArch::PAGE_SIZE) {
109                 let paddr = area.base.add(i * MMArch::PAGE_SIZE);
110                 let vaddr = unsafe { MMArch::phys_2_virt(paddr) }.unwrap();
111                 let flags = kernel_page_flags::<MMArch>(vaddr).set_execute(true);
112 
113                 let flusher = mapper
114                     .map_phys(vaddr, paddr, flags)
115                     .expect("Failed to map frame");
116                 // 暂时不刷新TLB
117                 flusher.ignore();
118             }
119         }
120 
121         // 添加低地址的映射(在smp完成初始化之前,需要使用低地址的映射.初始化之后需要取消这一段映射)
122         LowAddressRemapping::remap_at_low_address(&mut mapper);
123     }
124 
125     unsafe {
126         INITIAL_PGTABLE_VALUE = new_page_table;
127     }
128     debug!(
129         "After mapping all physical memory, DragonOS used: {} KB",
130         bump_allocator.usage().used().bytes() / 1024
131     );
132 
133     // 初始化buddy_allocator
134     let buddy_allocator = unsafe { BuddyAllocator::<MMArch>::new(bump_allocator).unwrap() };
135     // 设置全局的页帧分配器
136     unsafe { set_inner_allocator(buddy_allocator) };
137     info!("Successfully initialized buddy allocator");
138     // 关闭显示输出
139     scm_disable_put_to_window();
140 
141     // make the new page table current
142     {
143         let mut binding = INNER_ALLOCATOR.lock();
144         let mut allocator_guard = binding.as_mut().unwrap();
145         debug!("To enable new page table.");
146         compiler_fence(Ordering::SeqCst);
147         let mapper = crate::mm::page::PageMapper::<MMArch, _>::new(
148             PageTableKind::Kernel,
149             new_page_table,
150             &mut allocator_guard,
151         );
152         compiler_fence(Ordering::SeqCst);
153         mapper.make_current();
154         compiler_fence(Ordering::SeqCst);
155         // debug!("New page table enabled");
156     }
157     debug!("Successfully enabled new page table");
158     info!("riscv mm init done");
159 
160     return Ok(());
161 }
162 
163 unsafe fn set_inner_allocator(allocator: BuddyAllocator<MMArch>) {
164     static FLAG: AtomicBool = AtomicBool::new(false);
165     if FLAG
166         .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
167         .is_err()
168     {
169         panic!("Cannot set inner allocator twice!");
170     }
171     *INNER_ALLOCATOR.lock() = Some(allocator);
172 }
173 
174 /// 低地址重映射的管理器
175 ///
176 /// 低地址重映射的管理器,在smp初始化完成之前,需要使用低地址的映射,因此需要在smp初始化完成之后,取消这一段映射
177 pub struct LowAddressRemapping;
178 
179 impl LowAddressRemapping {
180     pub unsafe fn remap_at_low_address(
181         mapper: &mut crate::mm::page::PageMapper<MMArch, &mut BumpAllocator<MMArch>>,
182     ) {
183         let info = efi_manager().kernel_load_info().unwrap();
184         let base = PhysAddr::new(info.paddr as usize);
185         let size = info.size as usize;
186 
187         for i in 0..(size / MMArch::PAGE_SIZE) {
188             let paddr = PhysAddr::new(base.data() + i * MMArch::PAGE_SIZE);
189             let vaddr = VirtAddr::new(base.data() + i * MMArch::PAGE_SIZE);
190             let flags = kernel_page_flags::<MMArch>(vaddr).set_execute(true);
191 
192             let flusher = mapper
193                 .map_phys(vaddr, paddr, flags)
194                 .expect("Failed to map frame");
195             // 暂时不刷新TLB
196             flusher.ignore();
197         }
198     }
199 
200     /// 取消低地址的映射
201     pub unsafe fn unmap_at_low_address(flush: bool) {
202         let mut mapper = KernelMapper::lock();
203         assert!(mapper.as_mut().is_some());
204 
205         let info = efi_manager().kernel_load_info().unwrap();
206         let base = PhysAddr::new(info.paddr as usize);
207         let size = info.size as usize;
208 
209         for i in 0..(size / MMArch::PAGE_SIZE) {
210             let vaddr = VirtAddr::new(base.data() + i * MMArch::PAGE_SIZE);
211             let (_, _, flusher) = mapper
212                 .as_mut()
213                 .unwrap()
214                 .unmap_phys(vaddr, true)
215                 .expect("Failed to unmap frame");
216             if flush == false {
217                 flusher.ignore();
218             }
219         }
220     }
221 }
222