PatchworkOS  dbbdc99
A non-POSIX operating system.
Loading...
Searching...
No Matches
interrupt.c
Go to the documentation of this file.
2
3#include <kernel/cpu/cpu.h>
4#include <kernel/cpu/gdt.h>
5#include <kernel/cpu/ipi.h>
6#include <kernel/cpu/irq.h>
7#include <kernel/cpu/regs.h>
10#include <kernel/io/irp.h>
11#include <kernel/log/log.h>
12#include <kernel/log/panic.h>
14#include <kernel/mem/vmm.h>
15#include <kernel/proc/process.h>
16#include <kernel/sched/sched.h>
17#include <kernel/sched/thread.h>
18#include <kernel/sched/timer.h>
19#include <kernel/sched/wait.h>
20
21#include <assert.h>
22
23static void exception_handle_user(interrupt_frame_t* frame, const char* note)
24{
26 if (thread_send_note(thread, note) == ERR)
27 {
28 atomic_store(&thread->state, THREAD_DYING);
29 process_kill(thread->process, note);
30
31 sched_do(frame);
32 }
33}
34
36{
37 uintptr_t alignedFaultAddr = ROUND_DOWN(faultAddr, PAGE_SIZE);
38 if (stack_pointer_is_in_stack(stack, alignedFaultAddr, 1))
39 {
40 if (vmm_alloc(&thread->process->space, (void*)alignedFaultAddr, PAGE_SIZE, PAGE_SIZE, flags,
42 {
43 if (errno == EEXIST) // Race condition, another CPU mapped the page.
44 {
45 return 0;
46 }
47 return ERR;
48 }
49 memset_s((void*)alignedFaultAddr, PAGE_SIZE, 0, PAGE_SIZE);
50
51 return 1;
52 }
53
54 return 0;
55}
56
58{
60 process_t* process = thread->process;
61 uintptr_t faultAddr = (uintptr_t)cr2_read();
62
63 if (frame->errorCode & PAGE_FAULT_PRESENT)
64 {
65 panic(frame, "page fault on present page at address 0x%llx", faultAddr);
66 }
67
68 uintptr_t alignedFaultAddr = ROUND_DOWN(faultAddr, PAGE_SIZE);
69 if (stack_pointer_overlaps_guard(&thread->kernelStack, alignedFaultAddr, 1))
70 {
71 panic(frame, "kernel stack overflow at address 0x%llx", faultAddr);
72 }
73
74 uint64_t result = exception_grow_stack(thread, faultAddr, &thread->kernelStack, PML_WRITE | PML_PRESENT);
75 if (result == ERR)
76 {
77 panic(frame, "failed to grow kernel stack for page fault at address 0x%llx", faultAddr);
78 }
79
80 if (result == 1)
81 {
82 return;
83 }
84
85 result = exception_grow_stack(thread, faultAddr, &thread->userStack, PML_USER | PML_WRITE | PML_PRESENT);
86 if (result == ERR)
87 {
88 panic(frame, "failed to grow user stack for page fault at address 0x%llx", faultAddr);
89 }
90
91 if (result == 1)
92 {
93 return;
94 }
95
96 panic(frame, "invalid page fault at address 0x%llx", faultAddr);
97}
98
100{
102 process_t* process = thread->process;
103 uintptr_t faultAddr = (uintptr_t)cr2_read();
104
105 if (frame->errorCode & PAGE_FAULT_PRESENT)
106 {
108 F("pagefault at 0x%llx when %s present page at 0x%llx", frame->rip,
109 (frame->errorCode & PAGE_FAULT_WRITE) ? "writing to" : "reading from", faultAddr));
110 return;
111 }
112
113 uintptr_t alignedFaultAddr = ROUND_DOWN(faultAddr, PAGE_SIZE);
114 if (stack_pointer_overlaps_guard(&thread->userStack, alignedFaultAddr, 1))
115 {
116 exception_handle_user(frame, F("pagefault at 0x%llx due to stack overflow at 0x%llx", frame->rip, faultAddr));
117 return;
118 }
119
120 uint64_t result = exception_grow_stack(thread, faultAddr, &thread->userStack, PML_USER | PML_WRITE | PML_PRESENT);
121 if (result == ERR)
122 {
123 exception_handle_user(frame, F("pagefault at 0x%llx failed to grow stack at 0x%llx", frame->rip, faultAddr));
124 return;
125 }
126
127 if (result == 1)
128 {
129 return;
130 }
131
133 F("pagefault at 0x%llx when %s 0x%llx", frame->rip,
134 (frame->errorCode & PAGE_FAULT_WRITE) ? "writing" : "reading", faultAddr));
135}
136
138{
139 errno_t err = errno;
140
141 switch (frame->vector)
142 {
145 {
146 panic(frame, "divide by zero");
147 }
148 exception_handle_user(frame, F("divbyzero at 0x%llx", frame->rip));
149 break;
152 {
153 panic(frame, "invalid opcode");
154 }
155 exception_handle_user(frame, F("illegal instruction at 0x%llx", frame->rip));
156 break;
158 panic(frame, "double fault");
159 break;
160 case VECTOR_NMI:
161 break; /// @todo Handle NMIs properly.
164 {
165 panic(frame, "general protection fault");
166 }
167 exception_handle_user(frame, F("segfault at 0x%llx", frame->rip));
168 break;
171 {
173 return;
174 }
176 break;
177 default:
178 panic(frame, "unhandled exception vector 0x%x", frame->vector);
179 }
180
181 errno = err;
182}
183
185{
186 if (frame->vector < VECTOR_EXCEPTION_END) // Avoid extra stuff for exceptions
187 {
188 exception_handler(frame);
189 return;
190 }
191
192 if (frame->vector == VECTOR_SPURIOUS)
193 {
194 return;
195 }
196
197 SELF->inInterrupt = false;
199
201
202 if (frame->vector >= VECTOR_EXTERNAL_START && frame->vector < VECTOR_EXTERNAL_END)
203 {
204 irq_dispatch(frame);
205 }
206 else if (frame->vector == VECTOR_FAKE)
207 {
208 // Do nothing.
209 }
210 else if (frame->vector == VECTOR_TIMER)
211 {
212 timer_ack_eoi(frame);
213 }
214 else if (frame->vector == VECTOR_IPI)
215 {
216 ipi_handle_pending(frame);
217 }
218 else
219 {
220 panic(NULL, "Invalid interrupt vector 0x%x", frame->vector);
221 }
222
223 note_handle_pending(frame);
225 wait_check_timeouts(frame);
226 sched_do(frame);
227
229
231 SELF->inInterrupt = false;
232
233 // Sanity check to make sure blocking and scheduling is functioning correctly.
235}
#define assert(expression)
Definition assert.h:29
int errno_t
Definition errno_t.h:4
void interrupt_handler(interrupt_frame_t *frame)
Handles CPU interrupts.
Definition interrupt.c:184
#define INTERRUPT_FRAME_IN_USER_SPACE(frame)
Checks if a interrupt frame is from user space.
Definition interrupt.h:229
@ PAGE_FAULT_WRITE
Definition interrupt.h:108
@ PAGE_FAULT_PRESENT
Definition interrupt.h:107
@ VECTOR_EXTERNAL_END
Exclusive end of external interrupts.
Definition interrupt.h:173
@ VECTOR_EXTERNAL_START
Inclusive start of external interrupts (handled by the IRQ system).
Definition interrupt.h:172
@ VECTOR_IPI
See IPI for more information.
Definition interrupt.h:179
@ VECTOR_PAGE_FAULT
Definition interrupt.h:159
@ VECTOR_GENERAL_PROTECTION_FAULT
Definition interrupt.h:158
@ VECTOR_DOUBLE_FAULT
Definition interrupt.h:153
@ VECTOR_FAKE
Used to implement interrupt_fake().
Definition interrupt.h:178
@ VECTOR_NMI
Definition interrupt.h:147
@ VECTOR_TIMER
See Timer subsystem for more information.
Definition interrupt.h:180
@ VECTOR_DIVIDE_ERROR
Definition interrupt.h:145
@ VECTOR_SPURIOUS
Made available for any component to use as a sink for spurious interrupts.
Definition interrupt.h:181
@ VECTOR_INVALID_OPCODE
Definition interrupt.h:151
@ VECTOR_EXCEPTION_END
Exclusive end of exceptions.
Definition interrupt.h:170
void ipi_handle_pending(interrupt_frame_t *frame)
Handle pending IPIs on the current CPU.
Definition ipi.c:26
void irq_dispatch(interrupt_frame_t *frame)
Dispatch an IRQ.
Definition irq.c:128
void percpu_update(void)
Update percpu sections on the current CPU.
Definition percpu.c:99
#define SELF
Macro to access data in the current cpu.
Definition percpu.h:85
bool stack_pointer_overlaps_guard(stack_pointer_t *stack, uintptr_t addr, uint64_t length)
Check if an region overlaps the guard.
bool stack_pointer_is_in_stack(stack_pointer_t *stack, uintptr_t addr, uint64_t length)
Check if an region is within the stack.
void cpu_stacks_overflow_check(void)
Checks the current CPU for stack overflows.
Definition cpu.c:83
void perf_interrupt_end(void)
Called at the end of an interrupt to update cpu performance data.
Definition perf.c:206
void perf_interrupt_begin(void)
Called at the beginning of an interrupt to update cpu performance data.
Definition perf.c:170
void irp_timeouts_check(void)
Check and handle expired IRP timeouts on the current CPU.
Definition irp.c:160
bool note_handle_pending(interrupt_frame_t *frame)
Handle pending notes for the current thread.
Definition note.c:87
NORETURN void panic(const interrupt_frame_t *frame, const char *format,...)
Panic the kernel, printing a message and halting.
Definition panic.c:292
@ PML_USER
@ PML_PRESENT
@ PML_WRITE
void * vmm_alloc(space_t *space, void *virtAddr, size_t length, size_t alignment, pml_flags_t pmlFlags, vmm_alloc_flags_t allocFlags)
Allocates and maps virtual memory in a given address space.
Definition vmm.c:153
@ VMM_ALLOC_FAIL_IF_MAPPED
If set and any page is already mapped, fail and set errno to EEXIST.
Definition vmm.h:123
void process_kill(process_t *process, const char *status)
Kills a process, pushing it to the reaper.
Definition process.c:240
static thread_t * thread_current_unsafe(void)
Retrieves the currently running thread without disabling interrupts.
Definition thread.h:137
uint64_t thread_send_note(thread_t *thread, const char *string)
Send a note to a thread.
Definition thread.c:176
@ THREAD_DYING
The thread is currently dying, it will be freed by the scheduler once its invoked.
Definition thread.h:41
void wait_check_timeouts(interrupt_frame_t *frame)
Check for timeouts and unblock threads as needed.
Definition wait.c:76
void sched_do(interrupt_frame_t *frame)
Perform a scheduling operation.
Definition sched.c:527
void timer_ack_eoi(interrupt_frame_t *frame)
Acknowledge a timer interrupt and send EOI.
Definition timer.c:33
#define EEXIST
File exists.
Definition errno.h:117
#define errno
Error number variable.
Definition errno.h:27
#define F(format,...)
Allocates a formatted string on the stack.
Definition fs.h:67
#define ROUND_DOWN(number, multiple)
Definition math.h:23
#define NULL
Pointer error value.
Definition NULL.h:25
#define ERR
Integer error value.
Definition ERR.h:17
#define PAGE_SIZE
The size of a memory page in bytes.
Definition PAGE_SIZE.h:8
static void exception_handler(interrupt_frame_t *frame)
Definition interrupt.c:137
static void exception_user_page_fault_handler(interrupt_frame_t *frame)
Definition interrupt.c:99
static uint64_t exception_grow_stack(thread_t *thread, uintptr_t faultAddr, stack_pointer_t *stack, pml_flags_t flags)
Definition interrupt.c:35
static void exception_kernel_page_fault_handler(interrupt_frame_t *frame)
Definition interrupt.c:57
static void exception_handle_user(interrupt_frame_t *frame, const char *note)
Definition interrupt.c:23
errno_t memset_s(void *s, rsize_t smax, int c, rsize_t n)
Definition memset_s.c:9
static const path_flag_t flags[]
Definition path.c:47
static page_stack_t * stack
Definition pmm.c:40
#define RFLAGS_INTERRUPT_ENABLE
Definition regs.h:34
static uint64_t cr2_read(void)
Definition regs.h:116
#define atomic_store(object, desired)
Definition stdatomic.h:289
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
__UINTPTR_TYPE__ uintptr_t
Definition stdint.h:43
Trap Frame Structure.
Definition interrupt.h:195
uint64_t errorCode
Definition interrupt.h:213
A entry in a page table without a specified address or callback ID.
Process structure.
Definition process.h:76
space_t space
Definition process.h:84
Structure to define a stack in memory.
Thread of execution structure.
Definition thread.h:61
process_t * process
The parent process that the thread executes within.
Definition thread.h:62
stack_pointer_t kernelStack
The kernel stack of the thread.
Definition thread.h:73
stack_pointer_t userStack
The user stack of the thread.
Definition thread.h:74