Max OS 0.3
Loading...
Searching...
No Matches
interrupts.cpp
Go to the documentation of this file.
1
10#include <common/logger.h>
11
12using namespace MaxOS;
13using namespace MaxOS::common;
14using namespace MaxOS::hardwarecommunication;
15using namespace MaxOS::system;
16
24InterruptHandler::InterruptHandler(uint8_t interrupt_number, int64_t redirect, uint64_t redirect_index)
25: m_interrupt_number(interrupt_number)
26{
27
28 // Get the interrupt manager
30 ASSERT(interrupt_manager != nullptr, "No active interrupt manager");
31
32 // Register the handler
33 interrupt_manager->set_interrupt_handler(m_interrupt_number, this);
34
35 // Not all interrupts need redirecting
36 if (redirect == -1)
37 return;
38
39 // Redirect a legacy interrupt to an interrupt the kernel expects
40 IOAPIC* io_apic = interrupt_manager->active_apic()->io_apic();
42 .type = (uint8_t) redirect,
43 .index = (uint8_t) redirect_index,
44 .interrupt = m_interrupt_number,
45 .destination = 0x00,
46 .flags = 0x00,
47 .mask = false,
48 };
49 io_apic->set_redirect(&temp);
50}
51
56
57 // Get the interrupt manager
59 if (interrupt_manager == nullptr) return;
60
61 // Remove the handler
62 interrupt_manager->set_interrupt_handler(m_interrupt_number, nullptr);
63}
64
71
79
80 // For handlers that don't care about the status
82
83 // Return the default status
84 return status;
85}
86
92ExceptionHandler::ExceptionHandler(uint8_t interrupt_number)
93: InterruptHandler(interrupt_number)
94{
95}
96
101
109
110 return "Unimplemented message for exception\n";
111
112}
113
121
122 // Get the message
123 string msg = get_message(status);
124
125 // Try to avoid the panic
126 cpu_status_t* can_avoid = CPU::prepare_for_panic(status, msg);
127 if (can_avoid != nullptr)
128 return can_avoid;
129
130 // Have to panic (must have occurred in kernel)
131 CPU::PANIC(msg.c_str(), status);
132
133 // Shouldn't return, fault if this happens
134 return nullptr;
135
136}
137
142
143 return StringBuilder() << "Division by 0 executed at 0x" << status->rip << "\n";
144
145}
146
147
152
153 return StringBuilder() << "Invaild opcode executed at 0x" << status->rip << "\n";
154
155}
156
157
162
163 // Get the core that the fault happened on
164 auto core = CPU::executing_core();
165 uint64_t core_id = core ? core->id : 0;
166
167 uint64_t error_code = status->error_code;
168 return StringBuilder() << "General Protection Fault: (0x" << status->rip << "): " << (error_code & 0x1 ? "Protection-Exception" : "Not a Protection Exception") << " cid: " << core_id << "\n";
169
170}
171
172
177
178 // Extract the information about the fault
179 bool present = (status->error_code & 0x1) != 0;
180 bool write = (status->error_code & 0x2) != 0;
181 bool user_mode = (status->error_code & 0x4) != 0;
182 bool reserved_write = (status->error_code & 0x8) != 0;
183 bool instruction_fetch = (status->error_code & 0x10) != 0;
184 uint64_t faulting_address;
185 asm volatile("movq %%cr2, %0" : "=r" (faulting_address));
186
187 return StringBuilder() << "Page Fault: " << (user_mode ? "user" : "kernel") << " code at 0x" << status->rip << " tried to " << (write ? "write" : "read") << " address 0x" << faulting_address << " which is " << (present ? "" : "not") << " mapped and " << (reserved_write ? "" : "not") << " reserved. " << " (instruction fetch: " << (instruction_fetch ? "Yes" : "No") << ")\n";
188}
189
190
195
196 CPU::halt();
197
198 // Shouldn't return, fault if this happens
199 return nullptr;
200}
201
206
207 Logger::INFO() << "Setting up Interrupt Manager\n";
209
210 // Clear the table
211 for (auto& descriptor: s_interrupt_descriptor_table) {
212 descriptor.address_low_bits = 0;
213 descriptor.address_mid_bits = 0;
214 descriptor.address_high_bits = 0;
215 descriptor.segment_selector = 0;
216 descriptor.ist = 0;
217 descriptor.flags = 0;
218 }
219
220 //Set Up the base interrupts
221 set_interrupt_descriptor_table_entry(0x00, &HandleException0x00, InterruptPrivilegeLevel::KERNEL_ONLY); // Division by zero
222 set_interrupt_descriptor_table_entry(0x01, &HandleException0x01, InterruptPrivilegeLevel::KERNEL_ONLY); // Debug
223 set_interrupt_descriptor_table_entry(0x02, &HandleException0x02, InterruptPrivilegeLevel::KERNEL_ONLY); // Non-maskable interrupt
224 set_interrupt_descriptor_table_entry(0x03, &HandleException0x03, InterruptPrivilegeLevel::USERSPACE); // Breakpoint
225 set_interrupt_descriptor_table_entry(0x04, &HandleException0x04, InterruptPrivilegeLevel::USERSPACE); // Overflow
226 set_interrupt_descriptor_table_entry(0x05, &HandleException0x05, InterruptPrivilegeLevel::KERNEL_ONLY); // Bound Range Exceeded
227 set_interrupt_descriptor_table_entry(0x06, &HandleException0x06, InterruptPrivilegeLevel::KERNEL_ONLY); // Invalid Opcode
228 set_interrupt_descriptor_table_entry(0x07, &HandleException0x07, InterruptPrivilegeLevel::KERNEL_ONLY); // Device Not Available
229 set_interrupt_descriptor_table_entry(0x08, &HandleInterruptError0x08, InterruptPrivilegeLevel::KERNEL_ONLY); // Double Fault
230 set_interrupt_descriptor_table_entry(0x09, &HandleException0x09, InterruptPrivilegeLevel::KERNEL_ONLY); // Coprocessor Segment Overrun
231 set_interrupt_descriptor_table_entry(0x0A, &HandleInterruptError0x0A, InterruptPrivilegeLevel::KERNEL_ONLY); // Invalid TSS
232 set_interrupt_descriptor_table_entry(0x0B, &HandleInterruptError0x0B, InterruptPrivilegeLevel::KERNEL_ONLY); // Segment Not Present
233 set_interrupt_descriptor_table_entry(0x0C, &HandleInterruptError0x0C, InterruptPrivilegeLevel::KERNEL_ONLY); // Stack-Segment Fault
234 set_interrupt_descriptor_table_entry(0x0D, &HandleInterruptError0x0D, InterruptPrivilegeLevel::KERNEL_ONLY); // General Protection Fault
235 set_interrupt_descriptor_table_entry(0x0E, &HandleInterruptError0x0E, InterruptPrivilegeLevel::KERNEL_ONLY); // Page Fault
236 set_interrupt_descriptor_table_entry(0x0F, &HandleException0x0F, InterruptPrivilegeLevel::KERNEL_ONLY); // Reserved
237 set_interrupt_descriptor_table_entry(0x10, &HandleException0x10, InterruptPrivilegeLevel::KERNEL_ONLY); // x87 Floating-Point Exception
238 set_interrupt_descriptor_table_entry(0x11, &HandleInterruptError0x11, InterruptPrivilegeLevel::KERNEL_ONLY); // Alignment Check
239 set_interrupt_descriptor_table_entry(0x12, &HandleException0x12, InterruptPrivilegeLevel::KERNEL_ONLY); // Machine Check
240 set_interrupt_descriptor_table_entry(0x13, &HandleException0x13, InterruptPrivilegeLevel::KERNEL_ONLY); // SIMD Floating-Point Exception
241 set_interrupt_descriptor_table_entry(0x14, &HandleException0x14, InterruptPrivilegeLevel::KERNEL_ONLY); // Reserved: Virtualization Exception
242 set_interrupt_descriptor_table_entry(0x15, &HandleException0x15, InterruptPrivilegeLevel::KERNEL_ONLY); // Reserved
243 set_interrupt_descriptor_table_entry(0x16, &HandleException0x16, InterruptPrivilegeLevel::KERNEL_ONLY); // Reserved
244 set_interrupt_descriptor_table_entry(0x17, &HandleException0x17, InterruptPrivilegeLevel::KERNEL_ONLY); // Reserved
245 set_interrupt_descriptor_table_entry(0x18, &HandleException0x18, InterruptPrivilegeLevel::KERNEL_ONLY); // Reserved
246 set_interrupt_descriptor_table_entry(0x19, &HandleException0x19, InterruptPrivilegeLevel::KERNEL_ONLY); // Reserved
247 set_interrupt_descriptor_table_entry(0x1A, &HandleException0x1A, InterruptPrivilegeLevel::KERNEL_ONLY); // Reserved
248 set_interrupt_descriptor_table_entry(0x1B, &HandleException0x1B, InterruptPrivilegeLevel::KERNEL_ONLY); // Reserved
249 set_interrupt_descriptor_table_entry(0x1C, &HandleException0x1C, InterruptPrivilegeLevel::KERNEL_ONLY); // Reserved
250 set_interrupt_descriptor_table_entry(0x1D, &HandleException0x1D, InterruptPrivilegeLevel::KERNEL_ONLY); // Reserved
251 set_interrupt_descriptor_table_entry(0x1E, &HandleException0x1E, InterruptPrivilegeLevel::KERNEL_ONLY); // Security Exception
252 set_interrupt_descriptor_table_entry(0x1F, &HandleException0x1F, InterruptPrivilegeLevel::KERNEL_ONLY); // Reserved
253
254 // Set up the hardware interrupts
255 set_interrupt_descriptor_table_entry(HARDWARE_INTERRUPT_OFFSET + 0x00, &HandleInterruptRequest0x00, InterruptPrivilegeLevel::KERNEL_ONLY); // APIC Timer Interrupt
256 set_interrupt_descriptor_table_entry(HARDWARE_INTERRUPT_OFFSET + 0x01, &HandleInterruptRequest0x01, InterruptPrivilegeLevel::KERNEL_ONLY); // Keyboard Interrupt
257 set_interrupt_descriptor_table_entry(HARDWARE_INTERRUPT_OFFSET + 0x02, &HandleInterruptRequest0x02, InterruptPrivilegeLevel::KERNEL_ONLY); // PIT Interrupt
258 set_interrupt_descriptor_table_entry(HARDWARE_INTERRUPT_OFFSET + 0x04, &HandleInterruptRequest0x04, InterruptPrivilegeLevel::KERNEL_ONLY); // Serial Interrupt
259 set_interrupt_descriptor_table_entry(HARDWARE_INTERRUPT_OFFSET + 0x0C, &HandleInterruptRequest0x0C, InterruptPrivilegeLevel::KERNEL_ONLY); // Mouse Interrupt
260
261 // Set up the software interrupts
262 set_interrupt_descriptor_table_entry(HARDWARE_INTERRUPT_OFFSET + 0x60, &HandleInterruptRequest0x60, InterruptPrivilegeLevel::USERSPACE); // System Call Interrupt - Privilege Level 3 so that user space can call it
263 set_interrupt_descriptor_table_entry(HARDWARE_INTERRUPT_OFFSET + 0x61, &HandleInterruptRequest0x61, InterruptPrivilegeLevel::KERNEL_ONLY); // Kill this core
264
265 // Tell the processor to use the IDT
266 load_current();
267}
268
275
283void InterruptManager::set_interrupt_descriptor_table_entry(uint8_t interrupt, void (* handler)(), InterruptPrivilegeLevel descriptor_privilege_level) {
284
285 // Get the address of the handler and the entry in the IDT
286 auto handler_address = (uint64_t) handler;
287 InterruptDescriptor* interrupt_descriptor = &s_interrupt_descriptor_table[interrupt];
288
289 // Set the handler address
290 interrupt_descriptor->address_low_bits = handler_address & 0xFFFF;
291 interrupt_descriptor->address_mid_bits = (handler_address >> 16) & 0xFFFF;
292 interrupt_descriptor->address_high_bits = (handler_address >> 32) & 0xFFFFFFFF;
293
294 // Set the kernel code segment offset
295 interrupt_descriptor->segment_selector = 0x08;
296
297 // Disable IST
298 interrupt_descriptor->ist = 0;
299
300 // Set the flags (Trap Gate, Present and the Descriptor Privilege Level)
301 interrupt_descriptor->flags = 0b1110 | (((uint8_t)descriptor_privilege_level & 0b11) << 5) | (1 << 7);
302}
303
308
309 IDTR idt = {};
310 idt.limit = 256 * sizeof(InterruptDescriptor) - 1;
311 idt.base = (uint64_t) s_interrupt_descriptor_table;
312 asm volatile("lidt %0" : : "m" (idt));
313}
314
319
320 Logger::INFO() << "Activating Interrupts \n";
321
322 // Deactivate the current (old) interrupt manager
323 deactivate();
324
325 // Set the current interrupt manager and start interrupts
327 asm("sti");
328}
329
334
335 // Cant deactivate if it isn't the system one
336 if (s_active_interrupt_manager != nullptr)
337 return;
338
339 // Prevent interrupts from firing when nothing is set up to handle them
340 asm("cli");
342}
343
353
354 // If there is an interrupt manager handle interrupt
355 if (s_active_interrupt_manager != nullptr)
357
358 // CPU Can continue
359 return status;
360}
361
369
370 m_interrupt_handlers[interrupt] = handler;
371}
372
379
380 m_interrupt_handlers[interrupt] = nullptr;
381}
382
390
391 // Handle the interrupt
392 ASSERT(m_interrupt_handlers[status->interrupt_number] != nullptr, "Interrupt 0x%x not handled\n", status->interrupt_number);
393 cpu_status_t* new_status = m_interrupt_handlers[status->interrupt_number]->handle_interrupt(status);
394
395 // Send the EOI to the APIC
396 if (HARDWARE_INTERRUPT_OFFSET <= status->interrupt_number && status->interrupt_number < HARDWARE_INTERRUPT_OFFSET + 16)
398
399 // Return the status
400 return new_status;
401}
402
412
413
414ExceptionHandlers::ExceptionHandlers() = default;
415ExceptionHandlers::~ExceptionHandlers() = default;
416
423cpu_status_t* InterruptManager::page_fault(cpu_status_t* status) {
424
425}
426
436
static LogRecord INFO()
Gets the active logger for info logs.
Definition logger.cpp:195
Handles both the Local APIC (boot core) and IO APIC.
Definition apic.h:240
string get_message(system::cpu_status_t *status) final
Get an human readable error message explaining this exception.
ExceptionHandler(uint8_t interrupt_number)
Create a new base exception handler for an interrupt.
virtual string get_message(system::cpu_status_t *status)
Get an human readable error message explaining this exception.
string get_message(system::cpu_status_t *status) final
Get an human readable error message explaining this exception.
Handles the IO APIC in the system (one per system)
Definition apic.h:205
void set_redirect(interrupt_redirect_t *redirect)
Redirect a system interrupt to a different IRQ.
Definition apic.cpp:412
Handles a certain interrupt number.
Definition interrupts.h:44
virtual ~InterruptHandler()
Destroys the interrupt handler and unregisters it from the interrupt manager.
InterruptHandler(uint8_t interrupt_number, int64_t redirect=-1, uint64_t redirect_index=0)
Creates a new interrupt handler and registers it with the interrupt manager.
uint8_t m_interrupt_number
The interrupt number this handler handles.
Definition interrupts.h:46
virtual void handle_interrupt()
Handles an interrupt.
Handles all interrupts and passes them to the correct handler.
Definition interrupts.h:200
static InterruptManager * s_active_interrupt_manager
The interrupt manger that is currently handling interrupts and is loaded into the IDTR.
Definition interrupts.h:211
static void HandleException0x15()
Stub (see interrupts.s)
static void HandleInterruptError0x0A()
Stub (see interrupts.s)
static void deactivate()
Deactivates the interrupt manager and stops interrupts.
static void HandleException0x14()
Stub (see interrupts.s)
system::cpu_status_t * handle_interrupt_request(system::cpu_status_t *status)
Handles the interrupt request by passing it to the appropriate handler.
static void HandleException0x00()
Stub (see interrupts.s)
static void HandleInterruptRequest0x0C()
Stub (see interrupts.s)
static void HandleException0x07()
Stub (see interrupts.s)
static void HandleInterruptError0x0D()
Stub (see interrupts.s)
static InterruptManager * active_interrupt_manager()
Gets the active interrupt manager.
static void HandleInterruptError0x08()
Stub (see interrupts.s)
static void HandleException0x13()
Stub (see interrupts.s)
static void HandleInterruptError0x0C()
Stub (see interrupts.s)
static void HandleException0x04()
Stub (see interrupts.s)
static void HandleException0x02()
Stub (see interrupts.s)
static void HandleException0x17()
Stub (see interrupts.s)
static void HandleException0x10()
Stub (see interrupts.s)
static void HandleInterruptRequest0x01()
Stub (see interrupts.s)
void set_apic(AdvancedProgrammableInterruptController *apic)
Sets the APIC.
static void HandleInterruptError0x11()
Stub (see interrupts.s)
static void set_interrupt_descriptor_table_entry(uint8_t interrupt, void(*handler)(), InterruptPrivilegeLevel descriptor_privilege_level)
Sets an entry in the Interrupt Descriptor Table.
static void HandleException0x1E()
Stub (see interrupts.s)
static void HandleInterruptRequest0x60()
Stub (see interrupts.s)
static void HandleException0x1F()
Stub (see interrupts.s)
void remove_interrupt_handler(uint8_t interrupt)
Removes the interrupt handler for the interrupt.
static void load_current()
Tell the processor to use the current InterruptManager.
static void HandleException0x05()
Stub (see interrupts.s)
static void HandleInterruptError0x0B()
Stub (see interrupts.s)
static void HandleException0x19()
Stub (see interrupts.s)
~InterruptManager()
Destroys the Interrupt Manager and deactivates interrupts.
static void HandleException0x1A()
Stub (see interrupts.s)
static void HandleException0x01()
Stub (see interrupts.s)
static void HandleException0x18()
Stub (see interrupts.s)
static void HandleException0x1B()
Stub (see interrupts.s)
InterruptManager()
Constructs the Interrupt Manager and sets up the interrupt descriptor table (does not activate interr...
void activate()
Activates the interrupt manager and starts interrupts (also deactivates the current interrupt manager...
void set_interrupt_handler(uint8_t interrupt, InterruptHandler *handler)
Sets the interrupt handler for the interrupt.
static InterruptDescriptor s_interrupt_descriptor_table[MAX_INTERRUPT_HANDLERS]
The Interrupt Descriptor Table (IDT)
Definition interrupts.h:214
static void HandleException0x12()
Stub (see interrupts.s)
static void HandleInterruptRequest0x00()
Stub (see interrupts.s)
static void HandleException0x09()
Stub (see interrupts.s)
static void HandleException0x16()
Stub (see interrupts.s)
static void HandleInterruptError0x0E()
Stub (see interrupts.s)
static void HandleInterruptRequest0x61()
Stub (see interrupts.s)
static system::cpu_status_t * HandleInterrupt(system::cpu_status_t *status)
Handles the interrupt request by passing it to the interrupt manager.
static void HandleException0x06()
Stub (see interrupts.s)
static void HandleException0x03()
Stub (see interrupts.s)
static void HandleException0x0F()
Stub (see interrupts.s)
static void HandleInterruptRequest0x04()
Stub (see interrupts.s)
static void HandleException0x1C()
Stub (see interrupts.s)
static void HandleInterruptRequest0x02()
Stub (see interrupts.s)
AdvancedProgrammableInterruptController * active_apic()
Gets the APIC.
static void HandleException0x1D()
Stub (see interrupts.s)
InterruptHandler * m_interrupt_handlers[MAX_INTERRUPT_HANDLERS]
A map of index-to-interrupt of interrupt handlers to fire when an interrupt occurs.
Definition interrupts.h:213
string get_message(system::cpu_status_t *status) final
Get an human readable error message explaining this exception.
void send_eoi() const
Acknowledge that the interrupt has been handled, allowing the PIC to process the next interrupt.
Definition apic.cpp:120
string get_message(system::cpu_status_t *status) final
Get an human readable error message explaining this exception.
static void PANIC(const char *message, cpu_status_t *status=nullptr)
Puts the CPU into a panic state and halts it. Dumps the stack trace and registers.
Definition cpu.cpp:463
static void halt()
Halts the CPU indefinitely.
Definition cpu.cpp:275
static cpu_status_t * prepare_for_panic(cpu_status_t *status=nullptr, const string &msg="")
Ensure the CPU must panic and prepare for it if so.
Definition cpu.cpp:521
static Core * executing_core()
Gets the core that is currently executing.
Definition cpu.cpp:660
hardwarecommunication::LocalAPIC * local_apic
The local APIC for this core.
Definition cpu.h:247
struct PACKED MaxOS::system::CPUStatus cpu_status_t
Alias for CPUStatus struct.
Defines a InterruptManager and InterruptHandler for managing hardware and software interrupts.
constexpr uint16_t HARDWARE_INTERRUPT_OFFSET
The offset in the IDT where interrupts from hardware start.
Definition interrupts.h:169
InterruptPrivilegeLevel
Represents the CPU ring level that a interrupt is handler is executed in.
Definition interrupts.h:33
Defines a Logger class for logging messages with different severity levels to multiple output streams...
A struct that holds the Interrupt Descriptor Table Register (IDTR)
Definition interrupts.h:145
uint16_t limit
The size of the IDT.
Definition interrupts.h:146
uint64_t base
The start address of the IDT.
Definition interrupts.h:147
An entry in the Interrupt Descriptor Table (IDT)
Definition interrupts.h:157
uint16_t segment_selector
The code segment selector in the GDT to use when this interrupt fires.
Definition interrupts.h:160
uint32_t address_high_bits
The high bits of the handler function address.
Definition interrupts.h:164
uint8_t ist
The offset into the Interrupt Stack Table (0 if not used) (see TSS)
Definition interrupts.h:161
uint16_t address_mid_bits
The middle bits of the handler function address.
Definition interrupts.h:163
uint16_t address_low_bits
The low bits of the handler function address.
Definition interrupts.h:159
uint8_t flags
Flags: The type of gate this entry represents (0xE for interrupt gate, 0xF for trap gate),...
Definition interrupts.h:162
Defines how an interrupt input is redirected to a specific processor via the I/O APIC.
Definition apic.h:174
uint8_t type
The type of redirect (should be 0 for normal interrupts)
Definition apic.h:176