1 /*
2 * Copyright (c) 2023 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
3 * Licensed under the Mulan PSL v2.
4 * You can use this software according to the terms and conditions of the Mulan PSL v2.
5 * You may obtain a copy of Mulan PSL v2 at:
6 * http://license.coscl.org.cn/MulanPSL2
7 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
8 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
9 * PURPOSE.
10 * See the Mulan PSL v2 for more details.
11 */
12 #include <arch/machine/esr.h>
13 #include <arch/mmu.h>
14 #include <common/types.h>
15 #include <mm/extable.h>
16 #include <mm/page_fault.h>
17 #include <mm/vmspace.h>
18 #include <object/recycle.h>
19 #include <object/thread.h>
20
21 #include "irq_entry.h"
22
get_fault_addr(void)23 static inline vaddr_t get_fault_addr(void)
24 {
25 vaddr_t addr;
26 asm volatile("mrs %0, far_el1\n\t" : "=r"(addr));
27 return addr;
28 }
29
__do_kernel_fault(u64 esr,u64 fault_ins_addr,u64 * fix_addr)30 static void __do_kernel_fault(u64 esr, u64 fault_ins_addr, u64 *fix_addr)
31 {
32 kdebug("kernel_fault triggered\n");
33 if (fixup_exception(fault_ins_addr, fix_addr)) {
34 return;
35 }
36
37 BUG_ON(1);
38
39 sys_exit_group(-1);
40 }
41
42 // EC: Instruction Abort or Data Abort
do_page_fault(u64 esr,u64 fault_ins_addr,int type,u64 * fix_addr)43 void do_page_fault(u64 esr, u64 fault_ins_addr, int type, u64 *fix_addr)
44 {
45 vaddr_t fault_addr;
46 int fsc; // fault status code
47 int wnr;
48 int ret;
49
50 fault_addr = get_fault_addr();
51 fsc = GET_ESR_EL1_FSC(esr);
52 switch (fsc) {
53 case DFSC_TRANS_FAULT_L0:
54 case DFSC_TRANS_FAULT_L1:
55 case DFSC_TRANS_FAULT_L2:
56 case DFSC_TRANS_FAULT_L3: {
57 ret = handle_trans_fault(current_thread->vmspace, fault_addr);
58 if (ret != 0) {
59 /* The trap happens in the kernel */
60 if (type < SYNC_EL0_64) {
61 goto no_context;
62 }
63
64 kinfo("do_page_fault: faulting ip is 0x%lx (real IP),"
65 "faulting address is 0x%lx,"
66 "fsc is trans_fault (0b%b),"
67 "type is %d\n",
68 fault_ins_addr,
69 fault_addr,
70 fsc,
71 type);
72 kprint_vmr(current_thread->vmspace);
73
74 kinfo("current_cap_group is %s\n",
75 current_cap_group->cap_group_name);
76
77 sys_exit_group(-1);
78 }
79 break;
80 }
81 case DFSC_PERM_FAULT_L1:
82 case DFSC_PERM_FAULT_L2:
83 case DFSC_PERM_FAULT_L3:
84 wnr = GET_ESR_EL1_WnR(esr);
85 if (wnr) {
86 ret = handle_perm_fault(
87 current_thread->vmspace, fault_addr, VMR_WRITE);
88 } else {
89 ret = handle_perm_fault(
90 current_thread->vmspace, fault_addr, VMR_READ);
91 }
92
93 if (ret != 0) {
94 /* The trap happens in the kernel */
95 if (type < SYNC_EL0_64) {
96 goto no_context;
97 }
98 sys_exit_group(-1);
99 }
100 break;
101 case DFSC_ACCESS_FAULT_L1:
102 case DFSC_ACCESS_FAULT_L2:
103 case DFSC_ACCESS_FAULT_L3:
104 kinfo("do_page_fault: fsc is access_fault (0b%b)\n", fsc);
105 BUG_ON(1);
106 break;
107 default:
108 kinfo("do_page_fault: faulting ip is 0x%lx (real IP),"
109 "faulting address is 0x%lx,"
110 "fsc is unsupported now (0b%b)\n",
111 fault_ins_addr,
112 fault_addr,
113 fsc);
114 kprint_vmr(current_thread->vmspace);
115
116 kinfo("current_cap_group is %s\n", current_cap_group->cap_group_name);
117
118 BUG_ON(1);
119 break;
120 }
121
122 return;
123
124 no_context:
125 kinfo("kernel_fault: faulting ip is 0x%lx (real IP),"
126 "faulting address is 0x%lx,"
127 "fsc is 0b%b\n",
128 fault_ins_addr,
129 fault_addr,
130 fsc);
131 __do_kernel_fault(esr, fault_ins_addr, fix_addr);
132 }
133