blob: 738b2db8866f592d370850b328cdc91d1c2065c9 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
/* Copyright (C) 2026 Richard Qin */
/*
* Trap MI Layer — Machine-Independent Semantic Dispatcher
*
* Receives a translated TrapCause from the MD layer and routes to
* the appropriate handler.
*
* *** MI INVARIANT: This file contains ZERO inline assembly,
* ZERO arch-specific constants (no CSR reads, no scause codes). ***
* arch/trapframe.h is included because TrapFrame is the cross-layer
* data contract defined in docs/specs/arch_abstraction.md §3.2.
*
* Reference: docs/specs/trap.md §4
*/
#include <lume/trap.h>
#include <lume/irq.h>
#include <lume/console.h>
#include <lume/kprintf.h>
#include <lume/errno.h>
#include <lume/sched.h>
#include <lume/timer.h>
#include <lume/klog.h>
#include <lume/syscall.h>
#include <lume/task.h>
#include <lume/vmm.h>
#include <lume/signal_nr.h>
#include <arch/trapframe.h> /* TrapFrame: cross-layer data contract */
/* ========================================================================
* trap_handle() — MI-layer dispatcher for traps
*
* Called by MD layer after scause → TrapInfo translation.
* ======================================================================== */
static TrapStats g_trap_stats = {};
static uint32 trap_cause_index(TrapCause cause)
{
switch (cause) {
case TrapCause::PageFaultLoad: return 0;
case TrapCause::PageFaultStore: return 1;
case TrapCause::PageFaultExec: return 2;
case TrapCause::Syscall: return 3;
case TrapCause::IllegalInst: return 4;
case TrapCause::Breakpoint: return 5;
case TrapCause::AccessFault: return 6;
case TrapCause::AlignFault: return 7;
case TrapCause::IrqTimer: return 8;
case TrapCause::IrqSoftware: return 9;
case TrapCause::IrqExternal: return 10;
case TrapCause::Unknown:
default:
return 11;
}
}
static void trap_record(const TrapInfo& info)
{
uint32 idx = trap_cause_index(info.cause);
__atomic_fetch_add(&g_trap_stats.total, 1, __ATOMIC_RELAXED);
__atomic_fetch_add(&g_trap_stats.by_cause[idx], 1, __ATOMIC_RELAXED);
g_trap_stats.last_cause = info.cause;
g_trap_stats.last_class = info.cls;
g_trap_stats.last_origin = info.origin;
g_trap_stats.last_val = info.val;
g_trap_stats.last_epc = info.epc;
g_trap_stats.last_scause = info.scause;
}
static VmFaultCause vm_fault_cause_from_trap(TrapCause cause)
{
switch (cause) {
case TrapCause::PageFaultStore:
return VmFaultCause::Write;
case TrapCause::PageFaultExec:
return VmFaultCause::Exec;
case TrapCause::PageFaultLoad:
default:
return VmFaultCause::Read;
}
}
void trap_stats_get(TrapStats* out)
{
if (!out) {
return;
}
*out = g_trap_stats;
}
void trap_stats_reset()
{
g_trap_stats = {};
}
void trap_handle(arch::TrapFrame* tf, const TrapInfo& info)
{
trap_record(info);
if (info.origin == TrapOrigin::FromKernel &&
info.cls != TrapClass::Interrupt) {
kprintf("[trap] kernel exception\n");
kernel_panic("kernel exception");
}
switch (info.cause) {
/* ---- Page Faults ---- */
case TrapCause::PageFaultLoad:
case TrapCause::PageFaultStore:
case TrapCause::PageFaultExec:
if (info.origin == TrapOrigin::FromUser) {
TaskControlBlock* curr = current_task();
if (!curr || !curr->mm) {
kernel_panic("user page fault with no current mm");
}
int ret = vmm_handle_page_fault(curr->mm, info.val,
vm_fault_cause_from_trap(info.cause));
if (ret == -EFAULT) {
task_kill_current(SIGSEGV);
} else if (ret == -ENOMEM) {
task_kill_current(SIGKILL);
} else if (ret < 0) {
task_kill_current(SIGSEGV);
}
break;
}
kprintf("[trap] kernel page fault\n");
kernel_panic("unhandled page fault");
break;
/* ---- System Call ---- */
case TrapCause::Syscall:
syscall_dispatch_md(tf);
break;
/* ---- Interrupts ---- */
case TrapCause::IrqTimer:
/* Timer tick */
timer_tick();
break;
case TrapCause::IrqExternal: {
/* External interrupt: generic claim → dispatch → complete */
uint32 irq = g_irq_manager.claim();
if (irq != 0) {
g_irq_manager.dispatch(irq);
g_irq_manager.complete(irq);
}
break;
}
case TrapCause::IrqSoftware:
/* IPI handling — Phase 2 stub */
break;
/* ---- Fatal exceptions ---- */
case TrapCause::IllegalInst:
kprintf("[trap] illegal instruction\n");
/* Phase 2: panic. Phase 3: task_kill(SIGILL) */
kernel_panic("illegal instruction in user mode");
break;
case TrapCause::AccessFault:
kprintf("[trap] access fault\n");
kernel_panic("access fault");
break;
case TrapCause::AlignFault:
kprintf("[trap] alignment fault\n");
kernel_panic("alignment fault");
break;
case TrapCause::Breakpoint:
kprintf("[trap] breakpoint\n");
/* ebreak advance is handled by MD layer (arch-specific instruction size) */
break;
case TrapCause::Unknown:
default:
kprintf("[trap] unknown trap\n");
kernel_panic("unknown trap");
break;
}
/* Check if rescheduling is needed before returning to user mode */
if (info.origin == TrapOrigin::FromUser) {
sched_check_preempt();
}
}
|