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
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
91
92 Logger::INFO() << "Setting up Interrupt Manager\n";
94
95 // Clear the table
97 descriptor.address_low_bits = 0;
98 descriptor.address_mid_bits = 0;
99 descriptor.address_high_bits = 0;
100 descriptor.segment_selector = 0;
101 descriptor.ist = 0;
102 descriptor.flags = 0;
103 }
104
105 //Set Up the base interrupts
106 set_interrupt_descriptor_table_entry(0x00, &HandleException0x00, 0); // Division by zero
108 set_interrupt_descriptor_table_entry(0x02, &HandleException0x02, 0); // Non-maskable interrupt
111 set_interrupt_descriptor_table_entry(0x05, &HandleException0x05, 0); // Bound Range Exceeded
113 set_interrupt_descriptor_table_entry(0x06, &HandleException0x07, 0); // Device Not Available
115 set_interrupt_descriptor_table_entry(0x09, &HandleException0x09, 0); // Coprocessor Segment Overrun
117 set_interrupt_descriptor_table_entry(0x0B, &HandleInterruptError0x0B, 0); // Segment Not Present
118 set_interrupt_descriptor_table_entry(0x0C, &HandleInterruptError0x0C, 0); // Stack-Segment Fault
119 set_interrupt_descriptor_table_entry(0x0D, &HandleInterruptError0x0D, 0); // General Protection Fault
122 set_interrupt_descriptor_table_entry(0x10, &HandleException0x10, 0); // x87 Floating-Point Exception
125 set_interrupt_descriptor_table_entry(0x13, &HandleException0x13, 0); // SIMD Floating-Point Exception
126 set_interrupt_descriptor_table_entry(0x14, &HandleException0x14, 0); // Reserved: Virtualization Exception
136 set_interrupt_descriptor_table_entry(0x1E, &HandleException0x1E, 0); // Security Exception
138
139 // Set up the hardware interrupts
144
145 // Set up the system call interrupt
146 set_interrupt_descriptor_table_entry(HARDWARE_INTERRUPT_OFFSET + 0x60, &HandleInterruptRequest0x60, 3); // System Call Interrupt - Privilege Level 3 so that user space can call it
147
148 // Tell the processor to use the IDT
149 load_current();
150}
151
158
167
168 // Get the address of the handler and the entry in the IDT
171
172 // Set the handler address
173 interrupt_descriptor->address_low_bits = handler_address & 0xFFFF;
174 interrupt_descriptor->address_mid_bits = (handler_address >> 16) & 0xFFFF;
175 interrupt_descriptor->address_high_bits = (handler_address >> 32) & 0xFFFFFFFF;
176
177 // Set the kernel code segment offset
178 interrupt_descriptor->segment_selector = 0x08;
179
180 // Disable IST
181 interrupt_descriptor->ist = 0;
182
183 // Set the flags (Trap Gate, Present and the Descriptor Privilege Level)
184 interrupt_descriptor->flags = 0b1110 | ((descriptor_privilege_level & 0b11) << 5) | (1 << 7);
185}
186
191
192 IDTR idt = {};
193 idt.limit = 256 * sizeof(InterruptDescriptor) - 1;
195 asm volatile("lidt %0" : : "m" (idt));
196}
197
202
203 Logger::INFO() << "Activating Interrupts \n";
204
205 // Deactivate the current (old) interrupt manager
207
208 // Set the current interrupt manager and start interrupts
210 asm("sti");
211}
212
217
218 // Cant deactivate if it isn't the system one
219 if (s_active_interrupt_manager != nullptr)
220 return;
221
222 // Prevent interrupts from firing when nothing is set up to handle them
223 asm("cli");
225}
226
234
235 // Default Fault Handlers
236 switch (status->interrupt_number) {
237
238 case 0x7:
239 CPU::PANIC("Device Not Available: FPU Not Enabled", status);
240 break;
241
242 case 0x0D:
243 return general_protection_fault(status);
244
245 case 0x0E:
246 return page_fault(status);
247 }
248
249 // If there is an interrupt manager handle interrupt
250 if (s_active_interrupt_manager != nullptr)
251 return s_active_interrupt_manager->handle_interrupt_request(status);
252
253 // CPU Can continue
254 return status;
255}
256
267
274
275 m_interrupt_handlers[interrupt] = nullptr;
276}
277
285
286 // Where to go afterward
287 cpu_status_t* new_status = status;
288
289 // If there is an interrupt manager, handle the interrupt
290 if (m_interrupt_handlers[status->interrupt_number] != nullptr)
291 new_status = m_interrupt_handlers[status->interrupt_number]->handle_interrupt(status);
292 else
293 Logger::WARNING() << "Interrupt " << (int) status->interrupt_number << " not handled\n";
294
295 // Send the EOI to the APIC
296 if (HARDWARE_INTERRUPT_OFFSET <= status->interrupt_number && status->interrupt_number < HARDWARE_INTERRUPT_OFFSET + 16)
297 CPU::executing_core()->local_apic->send_eoi();
298
299 // Return the status
300 return new_status;
301}
302
312
313
320cpu_status_t* InterruptManager::page_fault(system::cpu_status_t* status) {
321
322 // Extract the information about the fault
323 bool present = (status->error_code & 0x1) != 0;
324 bool write = (status->error_code & 0x2) != 0;
325 bool user_mode = (status->error_code & 0x4) != 0;
326 bool reserved_write = (status->error_code & 0x8) != 0;
327 bool instruction_fetch = (status->error_code & 0x10) != 0;
329 asm volatile("movq %%cr2, %0" : "=r" (faulting_address));
330
331 // Get the core that the fault happened on
332 auto core = CPU::executing_core();
333 uint64_t core_id = core ? core->id : 0;
334
335 string msg = 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") << ") for core " << core_id << "\n";
336
337
338 // Try kill the process so the system doesn't die
340 if (can_avoid != nullptr)
341 return can_avoid;
342
343 // Cant avoid it so halt the kernel
344 CPU::PANIC(msg.c_str(), status);
345
346 // Probably should never get here
347 return status;
348}
349
356cpu_status_t* InterruptManager::general_protection_fault(system::cpu_status_t* status) {
357
358 // Get the core that the fault happened on
359 auto core = CPU::executing_core();
360 uint64_t core_id = core ? core->id : 0;
361
362 uint64_t error_code = status->error_code;
363 string msg = StringBuilder() << "General Protection Fault: (0x" << status->rip << "): " << (error_code & 0x1 ? "Protection-Exception" : "Not a Protection Exception") << " c" << core_id << "\n";
364
365 // Try to avoid the panic
367 if (can_avoid != nullptr)
368 return can_avoid;
369
370 // Have to panic
371 CPU::PANIC(msg.c_str(), status);
372
373 // Probably should never get here
374 return status;
375}
376
386
static Logger WARNING()
Gets active logger set to WARNING level.
Definition logger.cpp:205
static Logger INFO()
Gets active logger set to info level.
Definition logger.cpp:171
Creates a string using a using a combination of parts with the '<<' operator. Simmilar to the logger.
Definition string.h:97
Stores the left, top, width and height of a rectangle.
Definition rectangle.h:22
Handles both the Local APIC (boot core) and IO APIC.
Definition apic.h:228
Handles the IO APIC in the system (one per system)
Definition apic.h:193
void set_redirect(interrupt_redirect_t *redirect)
Redirect a system interrupt to a different IRQ.
Definition apic.cpp:365
Handles a certain interrupt number.
Definition interrupts.h:30
~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:32
virtual void handle_interrupt()
Handles an interrupt.
Handles all interrupts and passes them to the correct handler.
Definition interrupts.h:84
static InterruptManager * s_active_interrupt_manager
The interrupt manger that is currently handling interrupts and is loaded into the IDTR.
Definition interrupts.h:95
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 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)
static system::cpu_status_t * HandleInterrupt(system::cpu_status_t *status)
Handles the interrupt request by passing it to the interrupt manager.
~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...
static void set_interrupt_descriptor_table_entry(uint8_t interrupt, void(*handler)(), uint8_t descriptor_privilege_level)
Sets an entry in the Interrupt Descriptor Table.
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:98
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 HandleException0x06()
Stub (see interrupts.s)
static void HandleException0x03()
Stub (see interrupts.s)
static void HandleException0x0F()
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:97
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:439
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:495
static Core * executing_core()
Gets the core that is currently executing.
Definition cpu.cpp:623
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:74
Defines a Logger class for logging messages with different severity levels to multiple output streams...
#define ASSERT(condition, format,...)
If the specified condition is not met then the kernel will crash with the specified message.
Definition logger.h:100
A struct that holds the Interrupt Descriptor Table Register (IDTR)
Definition interrupts.h:50
An entry in the Interrupt Descriptor Table (IDT)
Definition interrupts.h:62
Defines how an interrupt input is redirected to a specific processor via the I/O APIC.
Definition apic.h:162