AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
thread.c
Go to the documentation of this file.
1
4
5#include <core/system.h>
6#include <core/string.h>
7#include <core/arch.h>
8#include <sys/proc.h>
9#include <sys/sched.h>
10#include <sys/signal.h>
11#include <sys/lock.h>
12#include <sys/uaccess.h>
13#include <aquila/syscall.h>
14#include <ds/queue.h>
15#include <mm/pmap.h>
16
17MALLOC_DEFINE(M_KERN_STACK, "kern-stack", "kernel stack");
18MALLOC_DEFINE(M_X86_THREAD, "x86-thread", "x86 thread structure");
19
20/* Pushes `value`, of `type`, on the stack at `stack`. */
21#define PUSH(stack, type, value)\
22do {\
23 (stack) -= sizeof(type);\
24 *((type *) (stack)) = (type) (value);\
25} while (0)
26
30static void __attribute__((noreturn)) thread_spawn(void)
31{
32 struct x86_thread *arch = curthread->arch;
33
35
36#if ARCH_BITS==32
37 x86_jump_user(arch->eax, arch->eip, X86_CS, arch->eflags, arch->esp, X86_SS);
38#else
39 x86_jump_user(arch->rax, arch->rip, X86_CS, arch->rflags, arch->rsp, X86_SS);
40#endif
41}
42
43/*
44 * Runs a thread for the first time: switches to its address space and
45 * kernel stack, and starts it in user mode. It doesn't return.
46 */
48{
49 struct x86_thread *arch = thread->arch;
50 struct pmap *pmap = thread->owner->vm_space.pmap;
51
53
55
56 /* its first use of the FPU traps (x86_fpu_trap()), as after any
57 * switch: the FPU holds another thread's registers */
59
61}
62
63/*
64 * Switches to a thread that has run before: its address space, its kernel
65 * stack, then where it stopped. It doesn't return.
66 */
68{
69 struct x86_thread *arch = thread->arch;
70 struct pmap *pmap = thread->owner->vm_space.pmap;
71
73
76
77 /* the signals are delivered on the way back to user mode, not here
78 * (x86_return_to_user()): the thread resumes where it was */
79#if ARCH_BITS==32
80 x86_goto(arch->eip, arch->ebp, arch->esp);
81#else
82 x86_goto(arch->rip, arch->rbp, arch->rsp);
83#endif
84}
85
86/*
87 * Sets up a new thread's x86 state, for `thread_create()`. The thread
88 * will start at `entry` in user mode, on its user stack, below which a
89 * frame is pushed: a dummy return address, `uentry` and `arg`.
90 */
91int arch_thread_create(struct thread *thread, uintptr_t stack, uintptr_t entry, uintptr_t uentry, uintptr_t arg)
92{
93 /* on failure, thread->arch is left NULL */
94 thread->arch = NULL;
95
96 struct x86_thread *arch = kmalloc(sizeof(struct x86_thread), &M_X86_THREAD, M_ZERO);
97 if (!arch)
98 return -ENOMEM;
99
100 void *kstack = kmalloc(KERN_STACK_SIZE, &M_KERN_STACK, 0);
101 if (!kstack) {
102 kfree(arch);
103 return -ENOMEM;
104 }
105
106 uintptr_t frame[3] = {0, uentry, arg};
107 stack -= sizeof(frame);
108
109 if (copyout((void *) stack, frame, sizeof(frame))) {
110 kfree(kstack);
111 kfree(arch);
112 return -EFAULT;
113 }
114
115 arch->kstack_base = (uintptr_t) kstack;
117
118 /* a dummy return address */
119 PUSH(arch->kstack, void *, 0);
120
121 /* a dummy frame pointer */
122 PUSH(arch->kstack, void *, 0);
123
124#if ARCH_BITS==32
125 arch->eflags = X86_EFLAGS;
126 arch->eip = entry;
127#else
128 arch->rflags = X86_EFLAGS;
129 arch->rip = entry;
130#endif
131
132#if ARCH_BITS==32
133 arch->esp = stack;
134#else
135 arch->rsp = stack;
136#endif
137 thread->arch = arch;
138 return 0;
139}
140
141/*
142 * Sets up a kernel thread's x86 state. The thread starts at `entry`, a
143 * function without arguments that never returns, on its own kernel stack,
144 * once it is switched to.
145 */
147{
148 /* on failure, thread->arch is left NULL */
149 thread->arch = NULL;
150
151 struct x86_thread *arch = kmalloc(sizeof(struct x86_thread), &M_X86_THREAD, M_ZERO);
152 if (!arch)
153 return;
154
155 void *kstack = kmalloc(KERN_STACK_SIZE, &M_KERN_STACK, 0);
156 if (!kstack) {
157 kfree(arch);
158 return;
159 }
160
161 arch->kstack_base = (uintptr_t) kstack;
163
164 /* as if it had been called: a return address, 0 */
165 uintptr_t sp = arch->kstack;
166 PUSH(sp, void *, 0);
167
168#if ARCH_BITS==32
169 arch->eflags = X86_EFLAGS;
170 arch->eip = entry;
171 arch->esp = sp;
172 arch->ebp = 0;
173#else
174 arch->rflags = X86_EFLAGS;
175 arch->rip = entry;
176 arch->rsp = sp;
177 arch->rbp = 0;
178#endif
179
180 thread->arch = arch;
181}
182
183/*
184 * Frees a thread's x86 state: its kernel stack and FPU state.
185 */
187{
188 struct x86_thread *arch = (struct x86_thread *) thread->arch;
189
190 /* its state is gone already */
191 if (!arch)
192 return;
193
194 if (thread == curthread) {
195 /* Its kernel stack is about to be freed: point the TSS at a
196 * fixed address meanwhile (no interrupt from user mode comes
197 * before the next thread sets its own). */
198 uintptr_t esp = VMA(0x100000);
200 }
201
202 if (arch->kstack_base)
203 kfree((void *) arch->kstack_base);
204
205 if (arch->fpu_context)
206 kfree(arch->fpu_context);
207
208 /* no CPU's FPU holds its state anymore */
209 for (int i = 0; i < cpus_count; ++i)
210 if (cpus[i].arch.fpu_thread == thread)
212
213 kfree(arch);
214 thread->arch = NULL;
215}
216
228{
229 struct x86_thread *arch = curthread->arch;
230
232
233#if ARCH_BITS==32
234 arch->eip = ip;
235 arch->esp = sp;
236 arch->ebp = bp;
237#else
238 arch->rip = ip;
239 arch->rsp = sp;
240 arch->rbp = bp;
241#endif
242}
#define KERN_STACK_SIZE
Definition arch.h:68
#define VMA(obj)
Definition mm.h:36
int arch_thread_create(struct thread *thread, uintptr_t stack, uintptr_t entry, uintptr_t uentry, uintptr_t arg)
Sets up a new user thread's CPU state and kernel stack, for pthread_create().
Definition thread.c:92
static void thread_spawn(void)
Runs a thread for the first time: lets go of the kernel lock, and drops to user mode.
Definition thread.c:51
void arch_kthread_create(struct thread *thread, uintptr_t entry)
Sets up a kernel thread's CPU state.
Definition thread.c:113
void arch_thread_switch(struct thread *thread)
Switches to a thread that has run before: its address space, its kernel stack, then where it stopped.
Definition thread.c:76
void arch_thread_kill(struct thread *thread)
Frees a thread's CPU state and kernel stack.
Definition thread.c:133
void arch_thread_spawn(struct thread *thread)
Runs a thread for the first time: switches to its address space and kernel stack, and starts it.
Definition thread.c:63
void x86_goto(uintptr_t eip, uintptr_t ebp, uintptr_t esp)
void x86_jump_user(uintptr_t eax, uintptr_t eip, uintptr_t cs, uintptr_t eflags, uintptr_t esp, uintptr_t ss)
#define X86_SS
Definition arch.h:11
#define X86_EFLAGS
Definition arch.h:12
#define X86_CS
Definition arch.h:13
void x86_thread_saved(uintptr_t ip, uintptr_t sp, uintptr_t bp)
Records where the current thread resumes when it is switched back to (x86_goto()),...
Definition thread.c:227
void x86_fpu_disable(void)
Makes the next FPU instruction trap (sets CR0.TS).
Definition fpu.c:88
void x86_fpu_switch_out(void)
Saves the current thread's FPU state when it is switched out, if the FPU holds it,...
Definition fpu.c:178
void x86_kernel_stack_set(uintptr_t sp)
Sets the kernel stack that interrupts from user mode switch to, on the running CPU: the thread that i...
Definition gdt.c:152
struct cpu cpus[CPUS_MAX]
Definition sched.c:28
int cpus_count
Definition sched.c:29
#define MALLOC_DEFINE(type, _name, _desc)
Definition kvmem.h:30
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 kernel_unlock(void)
Lets go of the kernel lock, for the next CPU waiting for it.
Definition lock.c:46
struct pmap * pmap_switch(struct pmap *pmap)
Switches this CPU to an address space's page tables.
Definition pmap.c:164
#define curthread
Definition sched.h:12
#define NULL
Definition stddef.h:27
__SIZE_TYPE__ uintptr_t
Definition stddef.h:12
struct thread * fpu_thread
Definition cpu.h:129
struct arch_cpu arch
Definition cpu.h:17
An address space's page tables, on x86.
Definition pmap.h:9
struct vm_space vm_space
its address space
Definition proc.h:129
A thread.
Definition thread.h:23
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
struct pmap * pmap
its page tables (the architecture's)
Definition vm.h:27
A thread's x86 state: its kernel stack, and where it resumes.
Definition arch.h:16
uintptr_t kstack_base
Definition arch.h:18
uintptr_t rip
Definition arch.h:27
void * fpu_context
Definition arch.h:35
uintptr_t rflags
Definition arch.h:30
uintptr_t rbp
Definition arch.h:29
uintptr_t rsp
Definition arch.h:28
uintptr_t rax
Definition arch.h:31
uintptr_t kstack
Definition arch.h:17
#define PUSH(stack, type, value)
Definition sys.h:20