MOS Source Code
Loading...
Searching...
No Matches
x86_interrupt.c
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-3.0-or-later
2
5#include "mos/misc/panic.h"
7#include "mos/tasks/signal.h"
8
9#include <mos/interrupt/ipi.h>
11#include <mos/mm/cow.h>
14#include <mos/syslog/printk.h>
15#include <mos/x86/cpu/cpu.h>
21#include <mos_stdio.h>
22#include <mos_stdlib.h>
23
24static const char *const x86_exception_names[EXCEPTION_COUNT] = {
25 "Divide-By-Zero Error",
26 "Debug",
27 "Non-Maskable Interrupt",
28 "Breakpoint",
29 "Overflow",
30 "Bound Range Exceeded",
31 "Invalid Opcode",
32 "Device Not Available",
33 "Double Fault",
34 "Coprocessor Segment Overrun",
35 "Invalid TSS",
36 "Segment Not Present",
37 "Stack Segment Fault",
38 "General Protection Fault",
39 "Page Fault",
40 "Reserved",
41 "x87 Floating-Point Error",
42 "Alignment Check",
43 "Machine Check",
44 "SIMD Floating-Point Exception",
45 "Virtualization Exception",
46 "Control Protection Exception",
47 "Reserved",
48 "Reserved",
49 "Reserved",
50 "Reserved",
51 "Reserved",
52 "Reserved",
53 "Hypervisor Injection Exception",
54 "VMM Communication Exception",
55 "Security Exception",
56 "Reserved",
57};
58
60{
61 pr_emph("cpu %d: NMI received", lapic_get_id());
62
63 u8 scp1 = port_inb(0x92);
64 u8 scp2 = port_inb(0x61);
65
66 static const char *const scp1_names[] = { "Alternate Hot Reset", "Alternate A20 Gate", "[RESERVED]", "Security Lock",
67 "Watchdog Timer", "[RESERVED]", "HDD 2 Activity", "HDD 1 Activity" };
68
69 static const char *const scp2_names[] = { "Timer 2 Tied to Speaker", "Speaker Data Enable", "Parity Check Enable", "Channel Check Enable",
70 "Refresh Request", "Timer 2 Output", "Channel Check", "Parity Check" };
71
72 for (int bit = 0; bit < 8; bit++)
73 if (scp1 & (1 << bit))
74 pr_emph(" %s", scp1_names[bit]);
75
76 for (int bit = 0; bit < 8; bit++)
77 if (scp2 & (1 << bit))
78 pr_emph(" %s", scp2_names[bit]);
79
81 mos_panic("NMI received");
82}
83
85{
87
88 const char *name = x86_exception_names[regs->interrupt_number];
89 const char *intr_type = "";
90
91 // Faults: These can be corrected and the program may continue as if nothing happened.
92 // Traps: Traps are reported immediately after the execution of the trapping instruction.
93 // Aborts: Some severe unrecoverable error.
95 {
96 case EXCEPTION_NMI:
97 {
98 x86_handle_nmi(regs);
99 break;
100 }
101 case EXCEPTION_DEBUG:
102 {
103 ptr_t drx[6]; // DR0, DR1, DR2, DR3 and DR6, DR7
104 __asm__ volatile("mov %%dr0, %0\n"
105 "mov %%dr1, %1\n"
106 "mov %%dr2, %2\n"
107 "mov %%dr3, %3\n"
108 "mov %%dr6, %4\n"
109 "mov %%dr7, %5\n"
110 : "=r"(drx[0]), "=r"(drx[1]), "=r"(drx[2]), "=r"(drx[3]), "=r"(drx[4]), "=r"(drx[5]));
111
112 pr_emerg("cpu %d: %s (%lu) at " PTR_FMT " (DR0: " PTR_FMT " DR1: " PTR_FMT " DR2: " PTR_FMT " DR3: " PTR_FMT " DR6: " PTR_FMT " DR7: " PTR_FMT ")",
113 lapic_get_id(), name, regs->interrupt_number, regs->ip, drx[0], drx[1], drx[2], drx[3], drx[4], drx[5]);
114
115 return;
116 }
118 {
119 intr_type = "fault";
120
122 {
123 // kernel mode invalid opcode, search for a bug entry
125 mos_panic("Invalid opcode in kernel mode");
126 }
127 break;
128 }
146 {
147 intr_type = "fault";
148 break;
149 }
150
152 {
153 mos_warn("Breakpoint not handled.");
154 return;
155 }
156
158 {
159 intr_type = "page fault";
160
161 pagefault_t info = {
162 .is_present = (regs->error_code & 0x1) != 0,
163 .is_write = (regs->error_code & 0x2) != 0,
164 .is_user = (regs->error_code & 0x4) != 0,
165 .is_exec = (regs->error_code & 0x10) != 0,
166 .ip = regs->ip,
167 .regs = regs,
168 };
169
171 goto done;
172 }
173
176 {
177 intr_type = "abort";
178 break;
179 }
180 case EXCEPTION_MAX:
181 case EXCEPTION_COUNT:
182 {
184 }
185 }
186
187 if (current_thread)
188 {
189 pr_emerg("cpu %d: %s (%lu) at " PTR_FMT " (error code %lu)", lapic_get_id(), name, regs->interrupt_number, regs->ip, regs->error_code);
191 platform_dump_regs(regs);
194 }
195 else
196 {
197 platform_dump_regs(regs);
198 mos_panic("x86 %s:\nInterrupt #%lu ('%s', error code %lu)", intr_type, regs->interrupt_number, name, regs->error_code);
199 }
200
201done:
202 return;
203}
204
206{
207 lapic_eoi();
208 const int irq = frame->interrupt_number - IRQ_BASE;
209 interrupt_entry(irq);
210}
211
213{
214 platform_regs_t *frame = (platform_regs_t *) rsp;
215 current_cpu->interrupt_regs = frame;
216
217 reg_t syscall_ret = 0, syscall_nr = 0;
218
219 const pf_point_t ev = profile_enter();
220
221 if (frame->interrupt_number < IRQ_BASE)
223 else if (frame->interrupt_number >= IRQ_BASE && frame->interrupt_number < IRQ_BASE + IRQ_MAX)
224 x86_handle_irq(frame);
225 else if (frame->interrupt_number >= IPI_BASE && frame->interrupt_number < IPI_BASE + IPI_TYPE_MAX)
227 else if (frame->interrupt_number == MOS_SYSCALL_INTR)
228 syscall_nr = frame->ax, syscall_ret = ksyscall_enter(frame->ax, frame->bx, frame->cx, frame->dx, frame->si, frame->di, frame->r9);
229 else
230 pr_warn("Unknown interrupt number: %lu", frame->interrupt_number);
231
232 profile_leave(ev, "x86.int.%lu", frame->interrupt_number);
233
235 {
238 }
239
240 // jump to signal handler if there is a pending signal, and if we are coming from userspace
241 if (frame->cs & 0x3)
242 {
244 signal_exit_to_user_prepare_syscall(frame, syscall_nr, syscall_ret);
245 else
247 }
248
251}
void lapic_eoi(void)
Definition lapic.c:158
should_inline u8 lapic_get_id(void)
Definition apic.h:45
#define MOS_ASSERT(cond)
Definition assert.h:14
#define MOS_UNREACHABLE()
Definition assert.h:11
#define mos_warn(fmt,...)
Definition assert.h:23
void signal_exit_to_user_prepare_syscall(platform_regs_t *regs, reg_t syscall_nr, reg_t syscall_ret)
Prepare to exit to userspace after a syscall.
Definition signal.c:261
long signal_send_to_thread(thread_t *target, signal_t signal)
Send a signal to a thread.
Definition signal.c:92
void signal_exit_to_user_prepare(platform_regs_t *regs)
Prepare to exit to userspace.
Definition signal.c:245
void mm_handle_fault(ptr_t fault_addr, pagefault_t *info)
Handle a page fault.
Definition mm.c:365
void interrupt_entry(u32 irq)
Definition interrupt.c:24
ipi_type_t
The type of IPI to send.
Definition ipi.h:12
@ IPI_TYPE_MAX
Definition ipi.h:16
void ipi_do_handle(ipi_type_t type)
reg_t ksyscall_enter(reg_t number, reg_t arg1, reg_t arg2, reg_t arg3, reg_t arg4, reg_t arg5, reg_t arg6)
#define MOS_IN_RANGE(addr, start, end)
Definition mos_global.h:78
#define unlikely(x)
Definition mos_global.h:40
#define mos_panic(fmt,...)
Definition panic.h:55
u32 const char void try_handle_kernel_panics(ptr_t ip)
Definition panic.c:67
__BEGIN_DECLS const char __MOS_KERNEL_CODE_START[]
#define current_thread
Definition platform.h:30
__BEGIN_DECLS const char __MOS_KERNEL_CODE_END[]
Definition platform.h:147
#define current_cpu
Definition platform.h:29
should_inline u8 port_inb(u16 port)
Definition port.h:10
#define pr_warn(fmt,...)
Definition printk.h:38
#define pr_emerg(fmt,...)
Definition printk.h:39
#define pr_emph(fmt,...)
Definition printk.h:37
#define profile_enter()
Definition profiling.h:33
u64 pf_point_t
Definition profiling.h:8
#define profile_leave(p,...)
Definition profiling.h:35
void platform_dump_regs(platform_regs_t *regs)
void platform_dump_stack(platform_regs_t *regs)
const char * name
Definition slab.c:31
uintn reg_t
Definition types.h:51
#define PTR_FMT
Definition types.h:33
unsigned long ptr_t
Definition types.h:25
unsigned char u8
Definition types.h:19
#define x86_cpu_get_cr2()
Definition cpu.h:41
static void x86_handle_exception(platform_regs_t *regs)
static void x86_handle_irq(platform_regs_t *frame)
void x86_interrupt_entry(ptr_t rsp)
static const char *const x86_exception_names[EXCEPTION_COUNT]
static void x86_handle_nmi(platform_regs_t *regs)
x86_exception_enum_t
@ EXCEPTION_COUNT
@ EXCEPTION_INVALID_TSS
@ EXCEPTION_SECURITY_EXCEPTION
@ EXCEPTION_FPU_ERROR
@ EXCEPTION_INVALID_OPCODE
@ EXCEPTION_STACK_SEGMENT_FAULT
@ EXCEPTION_VIRTUALIZATION_EXCEPTION
@ EXCEPTION_DEVICE_NOT_AVAILABLE
@ EXCEPTION_MACHINE_CHECK
@ EXCEPTION_SEGMENT_NOT_PRESENT
@ EXCEPTION_NMI
@ EXCEPTION_DOUBLE_FAULT
@ EXCEPTION_SIMD_ERROR
@ EXCEPTION_VMM_COMMUNICATION_EXCEPTION
@ EXCEPTION_GENERAL_PROTECTION_FAULT
@ EXCEPTION_DEBUG
@ EXCEPTION_COPROCESSOR_SEGMENT_OVERRUN
@ EXCEPTION_OVERFLOW
@ EXCEPTION_ALIGNMENT_CHECK
@ EXCEPTION_DIVIDE_ERROR
@ EXCEPTION_HYPERVISOR_EXCEPTION
@ EXCEPTION_BREAKPOINT
@ EXCEPTION_PAGE_FAULT
@ EXCEPTION_CONTROL_PROTECTION_EXCEPTION
@ EXCEPTION_MAX
@ EXCEPTION_BOUND_RANGE_EXCEEDED
#define IPI_BASE
@ IRQ_MAX
#define IRQ_BASE
void x86_interrupt_return_impl(const platform_regs_t *regs)
void platform_dump_current_stack(void)
#define MOS_SYSCALL_INTR