1 #include <lunaix/mm/fault.h>
2 #include <lunaix/mm/pmm.h>
3 #include <lunaix/mm/region.h>
4 #include <lunaix/mm/vmm.h>
5 #include <lunaix/sched.h>
6 #include <lunaix/signal.h>
7 #include <lunaix/status.h>
8 #include <lunaix/syslog.h>
9 #include <lunaix/trace.h>
10 #include <lunaix/hart_state.h>
11 #include <lunaix/failsafe.h>
13 #include <sys/mm/mm_defs.h>
15 #include <klibc/string.h>
20 __gather_memaccess_info(struct fault_context* context)
22 pte_t* ptep = (pte_t*)context->fault_va;
23 ptr_t mnt = ptep_vm_mnt(ptep);
26 context->mm = vmspace(__current);
28 if (!vmnt_packed(ptep)) {
33 context->ptep_fault = true;
34 context->remote_fault = !active_vms(mnt);
36 if (context->remote_fault && context->mm) {
37 context->mm = context->mm->guest_mm;
41 // unpack the ptep to reveal the one true va!
44 ptep = (pte_t*)page_addr(ptep_pfn(ptep));
45 mnt = ptep_vm_mnt(ptep);
46 if (!vmnt_packed(ptep)) {
53 ptep = (pte_t*)page_addr(ptep_pfn(ptep));
54 mnt = ptep_vm_mnt(ptep);
55 if (!vmnt_packed(ptep)) {
62 ptep = (pte_t*)page_addr(ptep_pfn(ptep));
63 mnt = ptep_vm_mnt(ptep);
64 if (!vmnt_packed(ptep)) {
70 ptep = (pte_t*)page_addr(ptep_pfn(ptep));
71 mnt = ptep_vm_mnt(ptep);
73 assert(!vmnt_packed(ptep));
77 context->fault_refva = refva;
81 __prepare_fault_context(struct fault_context* fault)
83 if (!__arch_prepare_fault_context(fault)) {
87 __gather_memaccess_info(fault);
89 pte_t* fault_ptep = fault->fault_ptep;
90 ptr_t fault_va = fault->fault_va;
91 pte_t fault_pte = *fault_ptep;
92 bool kernel_vmfault = kernel_addr(fault_va);
93 bool kernel_refaddr = kernel_addr(fault->fault_refva);
95 // for a ptep fault, the parent page tables should match the actual
96 // accesser permission
98 ptep_alloc_hierarchy(fault_ptep, fault_va, KERNEL_PGTAB);
100 ptep_alloc_hierarchy(fault_ptep, fault_va, USER_PGTAB);
103 fault->fault_pte = fault_pte;
105 if (fault->ptep_fault) {
106 // fault on intermediate levels.
107 fault_pte = pte_setprot(fault_pte, KERNEL_PGTAB);
110 if (!kernel_refaddr) {
111 fault_pte = pte_mkuser(fault_pte);
114 fault->resolving = pte_mkloaded(fault_pte);
115 fault->kernel_vmfault = kernel_vmfault;
116 fault->kernel_access = kernel_context(fault->hstate);
122 __flush_staled_tlb(struct fault_context* fault, struct leaflet* leaflet)
124 tlb_flush_mm_range(fault->mm, fault->fault_va, leaflet_nfold(leaflet));
128 __handle_conflict_pte(struct fault_context* fault)
131 struct leaflet *fault_leaflet, *duped_leaflet;
133 pte = fault->fault_pte;
134 fault_leaflet = pte_leaflet(pte);
136 if (!pte_allow_user(pte)) {
140 assert(pte_iswprotect(pte));
142 if (writable_region(fault->vmr)) {
143 // normal page fault, do COW
144 duped_leaflet = dup_leaflet(fault_leaflet);
146 pte = pte_mkwritable(pte);
147 pte = pte_mkuntouch(pte);
148 pte = pte_mkclean(pte);
150 ptep_map_leaflet(fault->fault_ptep, pte, duped_leaflet);
151 __flush_staled_tlb(fault, duped_leaflet);
153 leaflet_return(fault_leaflet);
155 fault_resolved(fault, NO_PREALLOC);
163 __handle_anon_region(struct fault_context* fault)
165 pte_t pte = fault->resolving;
166 pte = region_tweakpte(fault->vmr, pte);
168 // TODO Potentially we can get different order of leaflet here
169 struct leaflet* region_part = alloc_leaflet(0);
171 ptep_map_leaflet(fault->fault_ptep, pte, region_part);
172 __flush_staled_tlb(fault, region_part);
174 fault_resolved(fault, NO_PREALLOC);
179 __handle_named_region(struct fault_context* fault)
182 struct mm_region* vmr = fault->vmr;
183 struct v_file* file = vmr->mfile;
184 struct v_file_ops * fops = file->ops;
186 pte_t pte = fault->resolving;
187 ptr_t fault_va = page_aligned(fault->fault_va);
189 u32_t mseg_off = (fault_va - vmr->start);
190 u32_t mfile_off = mseg_off + vmr->foff;
191 size_t mapped_len = vmr->flen;
193 // TODO Potentially we can get different order of leaflet here
194 struct leaflet* region_part = alloc_leaflet(0);
196 pte = region_tweakpte(vmr, pte);
197 ptep_map_leaflet(fault->fault_ptep, pte, region_part);
199 if (mseg_off < mapped_len) {
200 mapped_len = MIN(mapped_len - mseg_off, PAGE_SIZE);
206 if (mapped_len == PAGE_SIZE) {
207 errno = fops->read_page(file->inode, (void*)fault_va, mfile_off);
210 leaflet_wipe(region_part);
213 errno = fops->read(file->inode,
214 (void*)fault_va, mapped_len, mfile_off);
219 ERROR("fail to populate page (%d)", errno);
221 ptep_unmap_leaflet(fault->fault_ptep, region_part);
222 leaflet_return(region_part);
227 __flush_staled_tlb(fault, region_part);
229 fault_resolved(fault, NO_PREALLOC);
233 __handle_kernel_page(struct fault_context* fault)
235 // we must ensure only ptep fault is resolvable
236 if (!is_ptep(fault->fault_va)) {
240 struct leaflet* leaflet = fault->prealloc;
242 pin_leaflet(leaflet);
243 leaflet_wipe(leaflet);
245 pte_t pte = fault->resolving;
246 ptep_map_leaflet(fault->fault_ptep, pte, leaflet);
248 tlb_flush_kernel_ranged(fault->fault_va, leaflet_nfold(leaflet));
250 fault_resolved(fault, 0);
255 fault_prealloc_page(struct fault_context* fault)
257 if (!pte_isnull(fault->fault_pte)) {
263 struct leaflet* leaflet = alloc_leaflet(0);
268 fault->prealloc = leaflet;
273 __fail_to_resolve(struct fault_context* fault)
275 if (fault->prealloc) {
276 leaflet_return(fault->prealloc);
279 ERROR("(pid: %d) Segmentation fault on %p (%p,e=0x%x)",
286 if (fault->kernel_access) {
287 // if a page fault from kernel is not resolvable, then
288 // something must be went south
289 FATAL("unresolvable page fault");
290 failsafe_diagnostic();
293 trace_printstack_isr(fault->hstate);
295 thread_setsignal(current_thread, _SIGSEGV);
298 fail("Unexpected return from segfault");
304 __try_resolve_fault(struct fault_context* fault)
306 pte_t fault_pte = fault->fault_pte;
307 if (pte_isguardian(fault_pte)) {
308 ERROR("memory region over-running");
312 if (fault->kernel_vmfault && fault->kernel_access) {
313 __handle_kernel_page(fault);
318 vm_regions_t* vmr = &fault->mm->regions;
319 fault->vmr = region_get(vmr, fault->fault_va);
325 if (pte_isloaded(fault_pte)) {
326 __handle_conflict_pte(fault);
328 else if (anon_region(fault->vmr)) {
329 __handle_anon_region(fault);
331 else if (fault->vmr->mfile) {
332 __handle_named_region(fault);
335 // page not present, might be a chance to introduce swap file?
336 ERROR("WIP page fault route");
340 return !!(fault->resolve_type & RESOLVE_OK);
344 intr_routine_page_fault(const struct hart_state* hstate)
346 if (hstate->depth > 10) {
347 // Too many nested fault! we must messed up something
348 // XXX should we failed silently?
352 struct fault_context fault = { .hstate = hstate };
354 if (!__prepare_fault_context(&fault)) {
355 __fail_to_resolve(&fault);
358 fault_prealloc_page(&fault);
360 if (!__try_resolve_fault(&fault)) {
361 __fail_to_resolve(&fault);
364 if ((fault.resolve_type & NO_PREALLOC)) {
365 if (fault.prealloc) {
366 leaflet_return(fault.prealloc);
370 tlb_flush_kernel(fault.fault_va);