My Project
Loading...
Searching...
No Matches
handlers.c
Go to the documentation of this file.
1/*
2 * PROJECT: MatanelOS Kernel
3 * LICENSE: NONE
4 * PURPOSE: Implementation of handler functions for interrupts.
5 */
6
7#include "../../includes/mh.h"
8#include "../../includes/me.h"
9#include "../../includes/mg.h"
10#include "../../includes/ps.h"
11#include "../../includes/md.h"
12
13#define PRINT_ALL_REGS_AND_HALT(ctxptr, intfrptr) \
14 do { \
15 gop_printf(COLOR_RED, \
16 "RAX=%p RBX=%p RCX=%p RDX=%p\n" \
17 "RSI=%p RDI=%p RBP=%p RSP=%p\n" \
18 "R8 =%p R9 =%p R10=%p R11=%p\n" \
19 "R12=%p R13=%p R14=%p R15=%p\n" \
20 "RIP=%p RFLAGS=%p\n", \
21 (ctxptr)->rax, (ctxptr)->rbx, (ctxptr)->rcx, (ctxptr)->rdx, \
22 (ctxptr)->rsi, (ctxptr)->rdi, (ctxptr)->rbp, (intfrptr)->rsp, \
23 (ctxptr)->r8, (ctxptr)->r9, (ctxptr)->r10, (ctxptr)->r11, \
24 (ctxptr)->r12, (ctxptr)->r13, (ctxptr)->r14, (ctxptr)->r15, \
25 (intfrptr)->rip, (intfrptr)->rflags); \
26 __hlt(); \
27 } while (0)
28
29// NOTE TO SELF: DO NOT PUT TRACELAST_FUNC HERE, THESE ARE INTERRUPT/EXCEPTION HANDLERS!
30
31
32extern uint32_t cursor_x;
33extern uint32_t cursor_y;
35
36static void MiHandleTimer(bool schedulerEnabled, PTRAP_FRAME trap) {
38
39 // Do not decrement if a schedule is already pending.
40 if (cpu->schedulePending) return;
41
42 // If scheduler is locked or no thread is running, return.
43 if (!schedulerEnabled || !cpu->currentThread) return;
44
45 PITHREAD currentThread = cpu->currentThread;
46
47 // Atomic decrement, if there is still time, return.
48 if (__sync_sub_and_fetch(&currentThread->TimeSlice, 1) > 0) {
49 return;
50 }
51
52 // Time slice has expired
53 // Reset Quantum
54 currentThread->TimeSlice = currentThread->TimeSliceAllocated;
55
56 // Save the thread's context.
57 currentThread->TrapRegisters = *trap;
58
59 // Request schedule.
60 cpu->schedulePending = true;
61}
62
63extern void lapic_eoi(void);
64
65void MiLapicInterrupt(bool schedulerEnabled, PTRAP_FRAME trap) {
66 MiHandleTimer(schedulerEnabled, trap);
67 lapic_eoi(); // Signal end of interrupt.
68}
69
71 void
72)
73
74/*++
75
76 Routine description : Handles an interprocessor interupt.
77
78 Arguments:
79
80 None. (arguments to IPI's are taken from the PROCESSOR struct, accessed in MeGetCurrentProcessor)
81
82 Return Values:
83
84 None.
85
86--*/
87
88{
91 uint64_t addr = cpu->IpiParameter.debugRegs.address;
92 CPU_ACTION action = cpu->IpiAction;
93 int idx = find_available_debug_reg();
94 switch (action) {
95 case CPU_ACTION_STOP:
96 // explicit action to halt, since we are in an interrupt, unless an NMI somehow comes, we will stay stopped.
97 // clear the flag before we halt so BSP can continue iterations
98 cpu->IpiSeq = 0;
101 for (;;) __hlt();
104 break;
106 gop_printf(COLOR_RED, "[CPU-IPI] Hello from CPU ID: %d\n", cpu->lapic_ID);
107 break;
109 if (idx == -1) break;
114 break;
116 for (int i = 0; i < 4; i++) {
117 if ((uint64_t)MeGetCurrentProcessor()->DebugEntry[i].Address == addr) {
118 __write_dr(i, 0);
119
120 /* Clear DR7 bits for this index (local enable and RW/LEN group) */
121 uint64_t dr7 = __read_dr(7);
122 /* clear local enable bit */
123 dr7 &= ~(1ULL << (i * 2));
124 /* clear RW/LEN 4-bit group */
125 uint64_t mask = 0xFULL << (16 + 4 * i);
126 dr7 &= ~mask;
127 __write_dr(7, dr7);
128
129 /* Clear status DR6 too */
130 __write_dr(6, 0);
133 break;
134 }
135 }
137 // This is a NO-OP, since DPCs WILL be executed when we just return.
138 // unused.
139 break;
142 break;
143 }
144
146 if (action != CPU_ACTION_STOP) {
148 cpu->IpiSeq = 0; // Signal completion for non-halting actions.
149 }
150
151 // End of Interrupt for LAPIC is signaled at function return.
152}
153
154void
156 IN PTRAP_FRAME trap
157)
158
159/*++
160
161 Routine description : Handles a page fault that occured in the current CPU.
162
163 Arguments:
164
165 Pointer to the current TRAP_FRAME.
166
167 Return Values:
168
169 None. Function would bugcheck/return if conditions are met.
170
171--*/
172
173{
174 uint64_t fault_addr;
175 // cr2 holds the faulty address that caused the page fault.
176
177 __asm__ __volatile__ (
178 "movq %%cr2, %0"
179 : "=r"(fault_addr)
180 );
181
182 /*++
183
184 Page fault bugcheck parameters:
185
186 Parameter 1: Memory address referenced. (CR2)
187 Parameter 2: (decimal) 0 - Read Operation, 2 - Write Operation, 10 - Execute operation (unused for now, NX hasn't been turned on for now)
188 Parameter 3: Address that referenced memory (RIP)
189 Parameter 4: CPU Error code pushed.
190
191 --*/
192
193
194
195 MTSTATUS status = MmAccessFault(trap->error_code, fault_addr, MeGetPreviousMode(), trap);
196#ifdef DEBUG
197 gop_printf(COLOR_RED, "I have returned from MmAccessFault with status %x\n", status);
198#endif
199
200 if (MT_FAILURE(status)) {
201 // If MmAccessFault returned a failire (e.g MT_ACCESS_VIOLATION), but hasn't bugchecked, we check for exception handlers in the current thread
202 // If there are no exceptions handlers (for SEH, we use the default one for user mode, TODO SEH USER MODE)
203 //if (ExpIsExceptionHandlerPresent(PsGetCurrentThread())) {
204 // ExpDispatchException(trap);
205 // return;
206 //}
207
208 //else {
209 // No kernel exception handler present, bugcheck.
212 (void*)(uintptr_t)status,
213 (void*)fault_addr,
214 (void*)trap->rip,
215 (void*)trap->error_code
216 );
217 //}
218 }
219
220 // MmAccessFault returned MT_SUCCESS, that means it handled the fault (filled the PTE, etc.), we return to original instruction and re-run.
221 return;
222}
223
225void
227 IN PTRAP_FRAME trap
228)
229
230/*++
231
232 Routine description : Handles a double fault exception that has happened on the current CPU.
233
234 Arguments:
235
236 Pointer to the current TRAP_FRAME.
237
238 Return Values:
239
240 None. This function will never return to caller.
241
242--*/
243
244{
245 /*++
246
247 Double Fault bugcheck parameters:
248
249 Parameter 1: Address at the time of the fault.
250 Parameter 2,3,4: NULL.
251
252 --*/
253
254 MeBugCheckEx(DOUBLE_FAULT, (void*)(uintptr_t)trap->rip, NULL, NULL, NULL);
255}
256
257void
259 PTRAP_FRAME trap
260)
261
262/*++
263
264 Routine description : Handles a divide by zero on the current CPU.
265
266 Arguments:
267
268 Pointer to the current TRAP_FRAME.
269
270 Return Values:
271
272 None. This function currently does not return to caller.
273
274--*/
275
276{
277
278 /*++
279
280 Divide By Zero bugcheck parameters:
281
282 Parameter 1: Address at the time of the fault.
283 Parameter 2,3,4: NULL.
284
285 --*/
286
287 // When user mode processes and threads are fully established, this should generate an ACCESS_VIOLATION. TODO
288 if (MeGetPreviousMode() == UserMode) {
289 // guard it for now.
290 MeBugCheckEx(ASSERTION_FAILURE, (void*)"MiDivideByZero", (void*)"A Fault in user mode occured, division error, implement.", NULL, NULL);
291 }
292
293 MeBugCheckEx(DIVIDE_BY_ZERO, (void*)(uintptr_t)trap->rip, NULL, NULL, NULL);
294
295}
296
297void
299 PTRAP_FRAME trap
300)
301
302/*++
303
304 Routine description : Handles a debug trap (either a single step from a debugger, or a debug register has been hit)
305
306 Arguments:
307
308 Pointer to the current TRAP_FRAME.
309
310 Return Values:
311
312 None.
313
314--*/
315
316{
317#ifndef GDB
318 /* read debug status */
319 uint64_t dr6 = __read_dr(6);
320
321 if (dr6 & 0xF) {
322 /* For each possible debug register 0..3 check B0..B3 */
323 for (int i = 0; i < 4; ++i) {
324 if (dr6 & (1ULL << i)) {
325 /* If a callback is registered, call it. Provide both address and context. */
326 if (MeGetCurrentProcessor()->DebugEntry[i].Callback) {
327 DBG_CALLBACK_INFO info = {
329 .trap = trap,
330 .BreakIdx = i,
331 .Dr6 = dr6
332 };
333
334 /* Call the user-registered callback. It receives &info (void*). */
336 }
337 else {
338 /* no callback registered for this DRx: print for debug and continue */
339 gop_printf(0xFFFFFF00, "DEBUG: DR%d fired at addr %p but no callback\n", i, (void*)__read_dr(i));
340 }
341 }
342 }
343
344 /* Clear the status bits in DR6 so INT1 won't fire again for the same event.
345 Writing zero clears B0..B3 and other status bits per Intel spec. */
346 __write_dr(6, 0);
347 return;
348 }
349 else if (dr6 & (1 << 14)) {
350 // Single Step. -- Ignore for now, we don't have a custom debugger yet, and QEMU sets its own.
351 return;
352 }
353#else
355 __write_DR(6, 0);
356 return;
357#endif
358}
359
361void
363 PTRAP_FRAME trap
364)
365
366/*++
367
368 Routine description : Handles an NMI (Non Maskable Interrupt), generated by the CPU.
369
370 Arguments:
371
372 Pointer to the current TRAP_FRAME.
373
374 Return Values:
375
376 None. This function will never return.
377
378--*/
379
380{
381 /*++
382
383 NMI bugcheck parameters:
384
385 No Parameters.
386
387 --*/
390}
391
393 PTRAP_FRAME trap
394)
395
396/*++
397
398 Routine description : Handles a breakpoint instruction (INT3)
399
400 Arguments:
401
402 Pointer to the current TRAP_FRAME.
403
404 Return Values:
405
406 None. This function will never return.
407
408--*/
409
410
411{
412 gop_printf(COLOR_RED, "**INT3 Breakpoint hit at: %p - Halting.\n", (void*)(uintptr_t)trap->rip);
413 __hlt();
414}
415
417 MeBugCheckEx(OVERFLOW, (void*)trap->rip, NULL, NULL, NULL);
418}
419
421 // bugcheck too, this is kernel mode.
422 MeBugCheckEx(BOUNDS_CHECK, (void*)trap->rip, NULL, NULL, NULL);
423}
424
426 MeBugCheckEx(INVALID_OPCODE, (void*)trap->rip, NULL, NULL, NULL);
427}
428
430 // rarely triggered, if a floating point chip is not integrated, or is not attached, bugcheck.
431 MeBugCheckEx(NO_COPROCESSOR, (void*)trap->rip, NULL, NULL, NULL);
432}
433
435 // quite literally impossible in protected or long mode, since CPU's don't generate this exception on these modes, but if they did, bugcheck, severe code.
436 MeBugCheckEx(COPROCESSOR_SEGMENT_OVERRUN, (void*)trap->rip, NULL, NULL, NULL);
437}
438
440 // a tss is when the CPU hardware switches (usually does not happen, since OS'es implement switching in software, like process timer context switch, all in software)
441 // if it did happen though, we bugcheck.
442 MeBugCheckEx(INVALID_TSS, (void*)trap->rip, NULL, NULL, NULL);
443}
444
446 // this happens when the CPU loads a segment that points to a valid descriptor, that is marked as "not present" (that the present bit is 0), which means it's swapped out to disk.
447 // we don't have disk paging right now, we don't even have a current user mode or stable memory for now, so we just bugcheck.
448 MeBugCheckEx(SEGMENT_SELECTOR_NOTPRESENT, (void*)trap->rip, NULL, NULL, NULL);
449}
450
452 // this happens when the stack pointer (esp, rsp, sp on 16 bit) moves OUTSIDE the bounds of the current stack segment, this is different from a stack overflow at the software level, this is a hardware level exception.
453 // segment limits on protected mode usually gets switched off, so if this happens just bugcheck.
454 MeBugCheckEx(STACK_SEGMENT_OVERRUN, (void*)trap->rip, NULL, NULL, NULL);
455}
456
458 // important exception, view error code and bugcheck with it
459 MeBugCheckEx(GENERAL_PROTECTION_FAULT, (void*)trap->rip, (void*)(uintptr_t)trap->error_code, NULL, NULL);
460}
461
464 // this occurs when a floating point operation has an error, (even division by zero floating point will get here), or underflow/overflow
465 gop_printf(0xFFFF0000, "Error: Floating Point error, have you done a correct calculation?\n");
466}
467
469 // 3 conditions must be met in-order for this to even reach.
470 // CR0.AM (Alignment Mask) must be set to 1.
471 // EFLAGS.AC (Alignment Check) must be set to 1.
472 // CPL (user mode or kernel mode) must be set to 3. (user mode only)
473 // If all are 1 and a stack alignment occurs (when doing char* ptr = kmalloc(64, 16); then writing like this *((uint32_t*)ptr) = 0xdeadbeef; // It's an unaligned write, writing more than there is.
474 // for now, bugcheck.
475 MeBugCheckEx(ALIGNMENT_CHECK, (void*)trap->rip, NULL, NULL, NULL);
476}
477
479 // creepy.
480 // This happens when the machine has a SEVERE problem, memory faults, CPU internal fault, all of that, the cpu registers this.
481 // obviously bugcheck.
482 MeBugCheckEx(SEVERE_MACHINE_CHECK, (void*)trap->rip, NULL, NULL, NULL);
483}
484
#define NORETURN
Definition annotations.h:13
#define IN
Definition annotations.h:7
FORCEINLINE uint64_t InterlockedAndU64(volatile uint64_t *target, uint64_t value)
Definition atomic.h:134
FORCEINLINE uint64_t InterlockedOrU64(volatile uint64_t *target, uint64_t value)
Definition atomic.h:144
NORETURN void MeBugCheck(IN enum _BUGCHECK_CODES BugCheckCode)
Definition bugcheck.c:214
NORETURN void MeBugCheckEx(IN enum _BUGCHECK_CODES BugCheckCode, IN void *BugCheckParameter1, IN void *BugCheckParameter2, IN void *BugCheckParameter3, IN void *BugCheckParameter4)
Definition bugcheck.c:305
uint32_t cursor_y
Definition gop.c:39
GOP_PARAMS gop_local
Definition gop.c:247
uint32_t cursor_x
Definition gop.c:39
PROCESSOR * PPROCESSOR
Definition core.h:46
ITHREAD * PITHREAD
Definition core.h:34
TRAP_FRAME * PTRAP_FRAME
Definition core.h:54
int find_available_debug_reg(void)
struct _GOP_PARAMS GOP_PARAMS
MTSTATUS MmAccessFault(IN uint64_t FaultBits, IN uint64_t VirtualAddress, IN PRIVILEGE_MODE PreviousMode, IN PTRAP_FRAME TrapFrame)
Definition fault.c:27
void gop_printf(uint32_t color, const char *fmt,...)
Definition gop.c:694
void MiBreakpoint(PTRAP_FRAME trap)
Definition handlers.c:392
void MiNoCoprocessor(PTRAP_FRAME trap)
Definition handlers.c:429
void MiBoundsCheck(PTRAP_FRAME trap)
Definition handlers.c:420
NORETURN void MiNonMaskableInterrupt(PTRAP_FRAME trap)
Definition handlers.c:362
void MiAlignmentCheck(PTRAP_FRAME trap)
Definition handlers.c:468
void MiDebugTrap(PTRAP_FRAME trap)
Definition handlers.c:298
void lapic_eoi(void)
Definition apic.c:136
void MiInvalidTss(IN PTRAP_FRAME trap)
Definition handlers.c:439
void MiInvalidOpcode(PTRAP_FRAME trap)
Definition handlers.c:425
void MiStackSegmentOverrun(PTRAP_FRAME trap)
Definition handlers.c:451
void MiCoprocessorSegmentOverrun(PTRAP_FRAME trap)
Definition handlers.c:434
void MiMachineCheck(PTRAP_FRAME trap)
Definition handlers.c:478
void MiPageFault(IN PTRAP_FRAME trap)
Definition handlers.c:155
NORETURN void MiDoubleFault(IN PTRAP_FRAME trap)
Definition handlers.c:226
void MiLapicInterrupt(bool schedulerEnabled, PTRAP_FRAME trap)
Definition handlers.c:65
void MiGeneralProtectionFault(PTRAP_FRAME trap)
Definition handlers.c:457
void MiDivideByZero(PTRAP_FRAME trap)
Definition handlers.c:258
void MiFloatingPointError(PTRAP_FRAME trap)
Definition handlers.c:462
void MiOverflow(PTRAP_FRAME trap)
Definition handlers.c:416
void MiInterprocessorInterrupt(void)
Definition handlers.c:70
void MiSegmentSelectorNotPresent(PTRAP_FRAME trap)
Definition handlers.c:445
FORCEINLINE uint64_t __read_dr(int reg)
Definition intrin.h:109
FORCEINLINE void invlpg(void *m)
Definition intrin.h:190
FORCEINLINE void __hlt(void)
Definition intrin.h:50
#define UNREFERENCED_PARAMETER(x)
Definition intrin.h:24
FORCEINLINE void __write_dr(int reg, uint64_t val)
Definition intrin.h:124
FORCEINLINE void __write_cr3(uint64_t val)
Definition intrin.h:83
FORCEINLINE uint64_t __read_cr3(void)
Definition intrin.h:78
@ OVERFLOW
Definition me.h:73
@ SEVERE_MACHINE_CHECK
Definition me.h:87
@ COPROCESSOR_SEGMENT_OVERRUN
Definition me.h:78
@ NO_COPROCESSOR
Definition me.h:76
@ ASSERTION_FAILURE
Definition me.h:111
@ KMODE_EXCEPTION_NOT_HANDLED
Definition me.h:118
@ DIVIDE_BY_ZERO
Definition me.h:69
@ ALIGNMENT_CHECK
Definition me.h:86
@ NON_MASKABLE_INTERRUPT
Definition me.h:71
@ INVALID_OPCODE
Definition me.h:75
@ INVALID_TSS
Definition me.h:79
@ DOUBLE_FAULT
Definition me.h:77
@ STACK_SEGMENT_OVERRUN
Definition me.h:81
@ GENERAL_PROTECTION_FAULT
Definition me.h:82
@ SEGMENT_SELECTOR_NOTPRESENT
Definition me.h:80
@ BOUNDS_CHECK
Definition me.h:74
struct _DBG_CALLBACK_INFO DBG_CALLBACK_INFO
FORCEINLINE PPROCESSOR MeGetCurrentProcessor(void)
Definition me.h:356
FORCEINLINE PRIVILEGE_MODE MeGetPreviousMode(void)
Definition me.h:534
@ CPU_DOING_IPI
Definition me.h:221
#define COLOR_RED
Colors definitions for easier access.
Definition mg.h:29
@ CPU_ACTION_DO_DEFERRED_ROUTINES
Definition mh.h:97
@ CPU_ACTION_WRITE_DEBUG_REGS
Definition mh.h:95
@ CPU_ACTION_STOP
Definition mh.h:92
@ CPU_ACTION_CLEAR_DEBUG_REGS
Definition mh.h:96
@ CPU_ACTION_FLUSH_CR3
Definition mh.h:98
@ CPU_ACTION_PERFORM_TLB_SHOOTDOWN
Definition mh.h:94
@ CPU_ACTION_PRINT_ID
Definition mh.h:93
uint64_t Address
Definition mh.h:4
enum _CPU_ACTION CPU_ACTION
#define MmFullBarrier()
Definition mm.h:226
@ UserMode
Definition mm.h:334
#define MT_FAILURE(Status)
Definition mtstatus.h:16
int32_t MTSTATUS
Definition mtstatus.h:12
DebugCallback Callback
Definition me.h:143
void * Address
Definition me.h:142
uint64_t address
Definition mh.h:389
uint64_t dr7
Definition mh.h:388
DebugCallback callback
Definition mh.h:390
struct _PAGE_PARAMETERS pageParams
Definition mh.h:399
struct _DEBUG_REGISTERS debugRegs
Definition mh.h:398
enum _TimeSliceTicks TimeSlice
Definition me.h:267
struct _TRAP_FRAME TrapRegisters
Definition me.h:262
enum _TimeSliceTicks TimeSliceAllocated
Definition me.h:268
uint64_t addressToInvalidate
Definition mh.h:394
volatile IPI_PARAMS IpiParameter
Definition me.h:294
struct _DEBUG_ENTRY DebugEntry[4]
Definition me.h:327
uint32_t lapic_ID
Definition me.h:281
struct _ITHREAD * currentThread
Definition me.h:278
volatile uint64_t flags
Definition me.h:287
volatile uint64_t IpiSeq
Definition me.h:292
enum _CPU_ACTION IpiAction
Definition me.h:293
bool schedulePending
Definition me.h:288
uint64_t rip
Definition me.h:157
uint64_t error_code
Definition me.h:156