AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
signal.c
Go to the documentation of this file.
1
19
20#include <core/system.h>
21#include <core/arch.h>
22#include <core/string.h>
23#include <cpu/cpu.h>
24#include <ds/hashmap.h>
25#include <mm/mm.h>
26#include <mm/pmap.h>
27#include <mm/vm.h>
28#include <sys/proc.h>
29#include <sys/sched.h>
30#include <sys/signal.h>
31#include <sys/uaccess.h>
32
33#include <aquila/syscall.h>
34
35/* The flags that user code may set: N, Z, C and V. */
36#define USER_FLAGS 0xF0000000UL
37
38/* A signal handler's frame, on the user stack. */
39struct sigframe {
40 struct aquila_siginfo info;
41 sigset_t mask; /* the mask that sigreturn restores */
42 uint64_t fpsimd_valid; /* whether fpsimd holds the thread's state */
43 struct aarch64_regs regs; /* the interrupted context */
45} __aligned(16);
46
47/* The sigcode page's code: mov x8, #SYS_sigreturn; svc #0; udf #0. */
48static const uint32_t sigcode[] = {
49 0xD2800000 | (SYS_sigreturn << 5) | 8,
50 0xD4000001,
51 0x00000000,
52};
53
56static int vm_page_eq(void *a, void *b)
57{
58 return ((struct vm_page *) a)->off == *(size_t *) b;
59}
60
64static struct vm_page *sigcode_in(struct vm_object *vm_object, size_t off)
65{
66 char *buf = kmalloc(PAGE_SIZE, &M_BUFFER, M_ZERO);
67 struct vm_page *vm_page = buf ? mm_page_alloc() : NULL;
68
69 if (!vm_page) {
70 kfree(buf);
71 return NULL;
72 }
73
74 memcpy(buf, sigcode, sizeof(sigcode));
76 kfree(buf);
77
78 /* it was written through the direct map, and runs from user mode's
79 * mapping: make the instruction cache see it */
80 asm volatile("dc cvau, %0; dsb ish; ic ivau, %0; dsb ish; isb"
81 :: "r"(PHYS2VIRT(vm_page->paddr)) : "memory");
82
84 vm_page->off = 0;
85 vm_page->ref = 1;
86
89 return NULL;
90 }
91
92 return vm_page;
93}
94
95static struct vm_pager sigcode_pager = {
96 .in = sigcode_in,
97};
98
99static struct vm_object sigcode_object = {
100 .pager = &sigcode_pager,
101 .ref = 1,
102};
103
104/*
105 * Maps the sigcode page into a process's new address space.
106 */
108{
109 if (!sigcode_object.pages && !(sigcode_object.pages = hashmap_new(0, vm_page_eq)))
110 return -ENOMEM;
111
112 struct vm_entry *vm_entry = kmalloc(sizeof(struct vm_entry), &M_VM_ENTRY, M_ZERO);
113
114 if (!vm_entry)
115 return -ENOMEM;
116
121
123
124 if (err) {
126 return err;
127 }
128
130 return 0;
131}
132
136static void deliver(struct aarch64_regs *r, int sig)
137{
138 struct thread *thread = curthread;
139 struct proc *proc = curproc;
140 struct aquila_sigaction *sa = &proc->sigaction[sig];
141
142 /* the mask to come back to: for `sigsuspend()` and `pselect()`, it's
143 * the one they replaced */
146
147 uintptr_t f = (r->sp - sizeof(struct sigframe)) & ~(uintptr_t) 15;
148
149 /* make the frame here, zeroed so that nothing of the kernel's goes
150 * out */
151 struct sigframe frame;
152 struct sigframe *uframe = (struct sigframe *) f;
153 int fault = sig == SIGSEGV || sig == SIGBUS || sig == SIGILL || sig == SIGFPE;
154
155 memset(&frame, 0, sizeof(frame));
156 frame.info = (struct aquila_siginfo) {
157 .si_signo = sig,
158 .si_addr = fault ? thread->fault_addr : 0,
159 };
160 frame.mask = mask;
161 frame.regs = *r;
162
163 /* save the FP/SIMD registers as they are, since the handler may use
164 * them */
165 void *fp = aarch64_fpsimd_current(thread);
166
167 if (fp) {
168 memcpy(frame.fpsimd, fp, FPSIMD_STATE_SIZE);
169 frame.fpsimd_valid = 1;
170 }
171
172 /* there's nowhere to put the frame: as with a fault, the process
173 * can't go on */
174 if (r->sp < 4096 || copyout(uframe, &frame, sizeof(frame)))
175 signal_exit(SIGSEGV);
176
177 r->x[0] = sig;
178 r->x[1] = (uintptr_t) &uframe->info;
179 r->x[2] = 0;
180 r->x[30] = SIGCODE_ADDR;
181 r->pc = sa->sa_handler;
182 r->sp = f;
183 r->pstate &= USER_FLAGS;
184
185 /* while the handler runs, its mask is blocked, and so is the signal
186 * itself unless `SA_NODEFER` is set */
187 sigset_t block = sa->sa_mask | (sa->sa_flags & SA_NODEFER ? 0 : 1UL << sig);
188 proc->sigmask = (mask | block) & ~SIG_UNMASKABLE;
189
190 if (sa->sa_flags & SA_RESETHAND)
191 sa->sa_handler = SIG_DFL;
192}
193
201void aarch64_return_to_user(struct aarch64_regs *r, int syscall)
202{
203 struct thread *thread = curthread;
204
205 if (!thread || !thread->arch || !REGS_USER(r))
206 return;
207
208 struct proc *proc = thread->owner;
209 int sig = signal_take();
210
211 /* a system call that a signal interrupted runs again if no handler
212 * runs or the handler has `SA_RESTART`, and fails with `EINTR`
213 * otherwise */
214 if (syscall) {
215 intptr_t ret = (intptr_t) r->x[0];
216
217 if (ret == -ERESTARTSYS || ret == -ERESTARTNOHAND) {
218 int restart = !sig || (ret == -ERESTARTSYS && (proc->sigaction[sig].sa_flags & SA_RESTART));
219
220 if (restart) {
221 /* go back to the `svc`, with its first argument back in
222 * x0 (the number is still in x8) */
223 r->pc -= 4;
224 r->x[0] = r->orig_x0;
225
226 /* the call is entered again right away, so it may go
227 * on from where it was */
228 thread->restarting = !sig;
229 } else {
230 r->x[0] = -EINTR;
231 }
232 }
233 }
234
235 if (sig) {
236 deliver(r, sig);
237 } else if (thread->sig_oldmask_set) {
238 /* `sigsuspend()` is restarted: put back the mask it replaced */
241 }
242}
243
244/* Returns from a signal handler, for `sigreturn()`: restores the
245 * registers, mask and FP/SIMD state from its frame. A bad frame gets
246 * `SIGSEGV`. */
248{
249 struct aarch64_thread *arch = curthread->arch;
250 struct aarch64_regs *r = arch->regs;
251 uintptr_t f = r->sp;
252
253 struct sigframe frame;
254
255 if ((f & 15) || copyin(&frame, (void *) f, sizeof(frame))) {
256 signal_force(curproc, SIGSEGV);
257 return;
258 }
259
260 /* restore its registers, but at user mode's level, and only the
261 * flags that it could set itself */
262 uint64_t pstate = frame.regs.pstate & USER_FLAGS;
263
264 *r = frame.regs;
265 r->pstate = pstate;
266
267 curproc->sigmask = frame.mask & ~SIG_UNMASKABLE;
269}
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
#define FPSIMD_STATE_SIZE
Definition arch.h:44
#define SIGCODE_ADDR
Definition arch.h:65
#define PAGE_SIZE
Definition system.h:7
#define REGS_USER(r)
Definition cpu.h:29
#define PHYS2VIRT(paddr)
Definition mm.h:26
static const uint32_t sigcode[]
Definition signal.c:48
static void deliver(struct aarch64_regs *r, int sig)
Sets up the user context r so that the handler of sig runs when it's returned to.
Definition signal.c:136
static int vm_page_eq(void *a, void *b)
Tells whether a page is at the offset that b points to (for the object's hashmap of pages).
Definition signal.c:56
static struct vm_object sigcode_object
Definition signal.c:99
static struct vm_pager sigcode_pager
Definition signal.c:95
void arch_sigreturn(void)
Returns from a signal handler, for sigreturn(): restores the registers, the signal mask and the FPU s...
Definition signal.c:247
int arch_sigcode_map(struct proc *proc)
Maps the page with the code that calls sigreturn() (the sigcode) into a process's new address space.
Definition signal.c:107
#define USER_FLAGS
Definition signal.c:36
static struct vm_page * sigcode_in(struct vm_object *vm_object, size_t off)
Makes the sigcode page, the first time a process touches it.
Definition signal.c:64
void * aarch64_fpsimd_current(struct thread *thread)
Returns a thread's FP/SIMD state as it is now, saving it from the registers first if they hold it.
Definition fpsimd.c:64
void aarch64_fpsimd_restore(struct thread *thread, const void *state)
Gives a thread back the FP/SIMD state that a signal frame kept, for sigreturn().
Definition fpsimd.c:151
#define __aligned(n)
Definition system.h:31
struct vm_page * mm_page_alloc(void)
Allocates a free page of physical memory.
Definition mm.c:78
void mm_page_dealloc(paddr_t paddr)
Frees a page of physical memory, back to the zone it came from.
Definition mm.c:103
void * kmalloc(size_t size, struct malloc_type *type, int flags)
Allocates memory for one of the kernel's structures.
Definition kvmem.c:123
#define M_ZERO
Definition kvmem.h:26
void kfree(void *)
Frees an object that kmalloc() gave.
Definition kvmem.c:146
void * memset(void *dst, int c, size_t n)
Sets n bytes to c.
Definition libc.c:23
void * memcpy(void *dst, const void *src, size_t n)
Copies n bytes; dst and src must not overlap.
Definition libc.c:11
int pmap_page_write(paddr_t paddr, off_t off, size_t size, void *buf)
Writes to a page of physical memory, through the kernel's mapping.
Definition pmap.c:452
#define curproc
Definition sched.h:13
#define curthread
Definition sched.h:12
void signal_exit(int sig)
Ends the current process because of a signal.
Definition signal.c:245
#define SIG_DFL
Definition signal.h:26
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 ERESTARTNOHAND
Definition signal.h:82
#define ERESTARTSYS
Definition signal.h:81
int signal_take(void)
Takes the current process's pending signals, on the way back to user mode: ignored ones are dropped,...
Definition signal.c:262
#define SIG_UNMASKABLE
Definition signal.h:85
#define NULL
Definition stddef.h:27
__SIZE_TYPE__ uintptr_t
Definition stddef.h:12
unsigned int uint32_t
Definition stddef.h:22
unsigned char uint8_t
Definition stddef.h:20
__PTRDIFF_TYPE__ intptr_t
Definition stddef.h:11
unsigned long long int uint64_t
Definition stddef.h:23
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 orig_x0
Definition cpu.h:17
uint64_t sp
Definition cpu.h:14
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_regs * regs
Definition arch.h:33
A process.
Definition proc.h:75
struct aquila_sigaction sigaction[SIG_MAX+1]
its signal actions
Definition proc.h:157
struct vm_space vm_space
its address space
Definition proc.h:129
sigset_t sigmask
its blocked signals, a bit (1 << sig) each
Definition proc.h:151
A signal handler's frame, on the user stack.
Definition signal.c:39
sigset_t mask
Definition signal.c:41
uint8_t fpsimd[FPSIMD_STATE_SIZE]
Definition signal.c:44
struct aarch64_regs regs
Definition signal.c:43
struct aquila_siginfo info
Definition signal.c:40
uint64_t fpsimd_valid
Definition signal.c:42
A thread.
Definition thread.h:23
sigset_t sig_oldmask
Definition thread.h:64
int sig_oldmask_set
in sigsuspend() or pselect(): the signal mask they replaced, which the handler's frame keeps (sigretu...
Definition thread.h:63
int restarting
whether the call is a restart (a stop interrupted it, and no handler ran); restart_until is the deadl...
Definition thread.h:54
void * arch
the architecture's own data: its registers, its kernel stack
Definition thread.h:84
struct proc * owner
its process
Definition thread.h:31
uintptr_t fault_addr
the address of its last fault, the si_addr of the signal it raised
Definition thread.h:72
A mapping (map entry): a range of an address space, its permissions, and where its pages come from.
Definition vm.h:66
uint32_t flags
its permissions and flags (VM_*)
Definition vm.h:78
vaddr_t base
where the mapping starts in its address space
Definition vm.h:72
struct vm_object * vm_object
its object: what its other pages come from (a file)
Definition vm.h:84
size_t size
its size
Definition vm.h:75
A vm object: what a mapping's pages come from (a file), and its pages that have been read in.
Definition vm.h:132
struct hashmap * pages
its pages that have been read in, by their offset
Definition vm.h:134
A page of physical memory (pages[] has one for every page of RAM).
Definition vm.h:150
size_t off
its offset in its object or anon
Definition vm.h:155
size_t ref
how many references it has
Definition vm.h:157
struct vm_object * vm_object
the object it belongs to, or NULL
Definition vm.h:153
paddr_t paddr
its physical address
Definition vm.h:151
A vm object's pager: reads its pages in, and writes them out.
Definition vm.h:94
unsigned long sigset_t
Definition types.h:27
int vm_space_insert(struct vm_space *vm_space, struct vm_entry *vm_entry)
Adds a map entry to an address space, in address order.
Definition vm_space.c:27
int vm_object_page_insert(struct vm_object *vm_object, struct vm_page *vm_page)
Adds a page to a vm object, at the page's offset (vm_page->off).
Definition vm_object.c:52
#define VM_URX
user read/execute
Definition vm.h:54
void vm_object_incref(struct vm_object *vm_object)
Adds a reference to a vm object: one more mapping of it.
Definition vm_object.c:25