AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
trap.c
Go to the documentation of this file.
1
12
13#include <core/system.h>
14#include <core/arch.h>
15#include <core/panic.h>
16#include <cpu/cpu.h>
17#include <mm/mm.h>
18#include <sys/lock.h>
19#include <sys/sched.h>
20#include <sys/signal.h>
21#include <platform/virt.h>
22
23/* ESR_EL1's exception class: why a synchronous exception came. */
24#define EC(esr) (((esr) >> 26) & 0x3F)
25#define EC_UNKNOWN 0x00 /* an undefined instruction */
26#define EC_FP 0x07 /* an FP/SIMD use that trapped (CPACR_EL1.FPEN) */
27#define EC_SVC64 0x15
28#define EC_IABT_LOW 0x20 /* an instruction abort, from EL0 */
29#define EC_IABT_CUR 0x21
30#define EC_PC_ALIGN 0x22
31#define EC_DABT_LOW 0x24 /* a data abort, from EL0 */
32#define EC_DABT_CUR 0x25
33#define EC_SP_ALIGN 0x26
34#define EC_BRK 0x3C
35
36/* An abort's syndrome: whether it was a write (for a data abort), and
37 * the fault's status code. */
38#define ISS_WNR (1 << 6)
39#define ISS_FSC(esr) ((esr) & 0x3F)
40#define FSC_PERMISSION 0x0C /* 0b0011xx: a permission fault, so a page is mapped there */
41
43static void dump(struct aarch64_regs *r)
44{
45 for (int i = 0; i < 31; i += 2)
46 printk("x%d = %p x%d = %p\n", i, (void *) r->x[i], i + 1, i + 1 < 31 ? (void *) r->x[i + 1] : NULL);
47
48 printk("sp = %p pc = %p pstate = %p esr = %p far = %p\n", (void *) r->sp,
49 (void *) r->pc, (void *) r->pstate, (void *) r->esr, (void *) read_sysreg(far_el1));
50}
51
55static int uaccess_fixup(struct aarch64_regs *r)
56{
57 extern uintptr_t aarch64_uaccess_fixups[], aarch64_uaccess_fixups_end[];
58
59 for (uintptr_t *f = aarch64_uaccess_fixups; f < aarch64_uaccess_fixups_end; f += 2) {
60 if (r->pc == f[0]) {
61 r->pc = f[1];
62 return 1;
63 }
64 }
65
66 return 0;
67}
68
71static void abort(struct aarch64_regs *r, int ec)
72{
73 uintptr_t far = read_sysreg(far_el1);
74 int user = REGS_USER(r);
75 int flags = user ? PF_USER : 0;
76
77 if (ec == EC_IABT_LOW || ec == EC_IABT_CUR)
78 flags |= PF_EXEC;
79 else
80 flags |= r->esr & ISS_WNR ? PF_WRITE : PF_READ;
81
82 if ((ISS_FSC(r->esr) & 0x3C) == FSC_PERMISSION)
83 flags |= PF_PRESENT;
84
85 /* the process's memory, which may not be mapped yet (a user address
86 * only: the kernel's own memory is all mapped) */
87 if (far < USER_STACK && curthread && !mm_page_fault(far, flags)) {
89 return;
90 }
91
92 if (user) {
93 signal_force(curproc, SIGSEGV);
95 return;
96 }
97
98 /* the kernel's fault, while copying from or to user memory: the copy
99 * fails with -EFAULT */
100 if (far < USER_STACK && uaccess_fixup(r))
101 return;
102
103 printk("kernel: page fault at %p%s\n", (void *) far,
104 far < USER_STACK ? " (user memory, outside copyin/copyout)" : "");
105 dump(r);
106 panic("page fault in the kernel");
107}
108
110static void sync_dispatch(struct aarch64_regs *r)
111{
112 int ec = EC(r->esr);
113
114 switch (ec) {
115 case EC_SVC64:
116 if (!curthread)
117 panic("syscall without a current thread");
118
119 ((struct aarch64_thread *) curthread->arch)->regs = r;
120 arch_syscall(r);
121 return;
122
123 case EC_DABT_LOW:
124 case EC_DABT_CUR:
125 case EC_IABT_LOW:
126 case EC_IABT_CUR:
127 abort(r, ec);
128 return;
129
130 case EC_FP:
131 /* user mode's first use since a thread switch: the registers
132 * get its values (if there's no memory for them, it can't go
133 * on) */
134 if (REGS_USER(r)) {
136 signal_force(curproc, SIGKILL);
137
139 return;
140 }
141 break;
142 }
143
144 if (REGS_USER(r)) {
145 /* something user mode can't do: an undefined instruction, a
146 * misaligned PC or stack, a breakpoint */
147 int sig = ec == EC_PC_ALIGN || ec == EC_SP_ALIGN ? SIGBUS :
148 ec == EC_BRK ? SIGTRAP : SIGILL;
149
150 curthread->fault_addr = r->pc;
151 signal_force(curproc, sig);
153 return;
154 }
155
156 printk("kernel: exception, class %x\n", ec);
157 dump(r);
158 panic("exception in the kernel");
159}
160
169{
170 int took = kernel_enter();
171
172 /* the thread's process was killed while it ran (on another CPU): the
173 * thread goes */
174 if (took && curthread && curthread->killed)
176
177 sync_dispatch(r);
178 kernel_leave(took);
179}
180
181/* The context that the current interrupt interrupted, for the tick's
182 * handler (to tell user time from kernel time). */
184
189{
190 struct aarch64_thread *arch = curthread->arch;
191
192 if (!aarch64_ctx_save(&arch->ctx))
193 schedule();
194}
195
204{
205 int took = kernel_enter();
206
208
209 if (took && curthread && curthread->killed) {
210 irq_handle();
212 }
213
214 irq_handle();
215
216 /* on the tick, the running thread goes back to the ready list and the
217 * next one runs (if the CPU was idle, that one runs) */
218 if (curcpu()->arch.tick_switch) {
219 curcpu()->arch.tick_switch = 0;
220
221 if (curcpu()->idle)
222 schedule();
223 else
225 }
226
228
229 /* if an urgent thread was woken up (the network's), it runs now */
230 if (sched_urgent && REGS_USER(r) && curthread)
232
234 kernel_leave(took);
235}
236
244{
245 printk("kernel: an exception the vectors don't take (FIQ, SError, aarch32)\n");
246 dump(r);
247 panic("unexpected exception");
248}
void aarch64_return_to_user(struct aarch64_regs *r, int syscall)
Takes the current thread's signals on its way back to user mode, and restarts or fails the system cal...
Definition signal.c:201
int aarch64_ctx_save(struct aarch64_ctx *ctx)
void arch_syscall(struct aarch64_regs *r)
Definition syscall.c:23
#define USER_STACK
Definition arch.h:60
#define read_sysreg(r)
Definition cpu.h:33
#define REGS_USER(r)
Definition cpu.h:29
#define panic(s)
Definition panic.h:15
int aarch64_fpsimd_trap(void)
Handles the trap of user mode's use of the registers: they get the running thread's values,...
Definition fpsimd.c:80
#define PF_READ
Definition mm.h:17
#define PF_EXEC
Definition mm.h:19
#define PF_WRITE
Definition mm.h:18
int mm_page_fault(vaddr_t vaddr, int flags)
Handles a page fault in the current process's address space.
Definition fault.c:395
#define PF_USER
Definition mm.h:20
#define PF_PRESENT
Definition mm.h:16
void kernel_leave(int took)
Lets go of the kernel lock on leaving the kernel, if kernel_enter() took it.
Definition lock.c:83
int kernel_enter(void)
Takes the kernel lock on entering the kernel, unless this CPU holds it already (an exception inside t...
Definition lock.c:68
int printk(const char *fmt,...)
Writes a kernel message, to the message buffer and the consoles.
Definition printk.c:249
void sched_idle_wakeup(void)
Runs a ready thread now if an interrupt made one ready while this CPU was idle, rather than at the ne...
Definition sched.c:347
int sched_urgent
Definition sched.c:306
#define curproc
Definition sched.h:13
void sched_thread_killed(void)
Ends the current thread, which was killed while it ran on this CPU (thread->killed).
Definition sched.c:258
void schedule(void)
Switches to the next ready thread.
Definition sched.c:400
#define curthread
Definition sched.h:12
void signal_force(struct proc *proc, int signal)
Sends a signal that can't be blocked or ignored, such as the SIGSEGV of a fault: if the process block...
Definition signal.c:230
#define NULL
Definition stddef.h:27
__SIZE_TYPE__ uintptr_t
Definition stddef.h:12
What an exception saves on the kernel stack (cpu/vectors.S): the context it interrupted.
Definition cpu.h:12
uint64_t pstate
Definition cpu.h:16
uint64_t sp
Definition cpu.h:14
uint64_t esr
Definition cpu.h:18
uint64_t pc
Definition cpu.h:15
uint64_t x[31]
Definition cpu.h:13
A thread's aarch64 state (thread->arch).
Definition arch.h:25
struct aarch64_ctx ctx
Definition arch.h:29
struct aarch64_regs * regs
Definition arch.h:33
static void abort(struct aarch64_regs *r, int ec)
Handles an instruction or data abort: a page fault in the process's memory, or else a SIGSEGV,...
Definition trap.c:71
#define EC_PC_ALIGN
Definition trap.c:30
#define EC_DABT_CUR
Definition trap.c:32
#define EC_SVC64
Definition trap.c:27
struct aarch64_regs * aarch64_irq_regs
Definition trap.c:183
#define FSC_PERMISSION
Definition trap.c:40
#define EC_IABT_LOW
Definition trap.c:28
static void sync_dispatch(struct aarch64_regs *r)
Handles a synchronous exception, by its class.
Definition trap.c:110
#define EC_IABT_CUR
Definition trap.c:29
void aarch64_irq(struct aarch64_regs *r)
Handles an interrupt, which cpu/vectors.S calls.
Definition trap.c:203
#define EC_BRK
Definition trap.c:34
static void dump(struct aarch64_regs *r)
Prints the saved registers, for a panic.
Definition trap.c:43
#define EC(esr)
Definition trap.c:24
void aarch64_sync(struct aarch64_regs *r)
Handles a synchronous exception (a system call, a fault), which cpu/vectors.S calls.
Definition trap.c:168
#define EC_DABT_LOW
Definition trap.c:31
static int uaccess_fixup(struct aarch64_regs *r)
Handles a fault in a copy from or to user memory (cpu/uaccess.S): the copy goes on at its fixup,...
Definition trap.c:55
void aarch64_preempt(void)
Switches away from this CPU's running thread, which stays ready, to the next ready thread.
Definition trap.c:188
#define EC_FP
Definition trap.c:26
#define ISS_WNR
Definition trap.c:38
#define EC_SP_ALIGN
Definition trap.c:33
#define ISS_FSC(esr)
Definition trap.c:39
void aarch64_bad(struct aarch64_regs *r)
Panics on an exception that the vectors don't handle (an FIQ, an SError, or one from aarch32).
Definition trap.c:243
void irq_handle(void)
Runs the handlers of the interrupt that came, then tells the GIC it's done, before any thread switch,...
Definition irq.c:84