Better IRQ handling
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
Full IRQ routing?
|
||||
=================
|
||||
|
||||
External IRQ sources:
|
||||
* Legacy IRQ lines
|
||||
* PCI IRQ pins (INTA#/INTB#/INTC#/INTD#)
|
||||
|
||||
Each of these is routed to a single GSI (IRQ of I/O APIC),
|
||||
which in turn is mapped to a single interrupt vector in any of the Local APICs
|
||||
|
||||
Mapping legacy IRQ to a handler:
|
||||
If I/O APIC is available
|
||||
1. Get 8259 IRQ -> I/O APIC Line mapping
|
||||
2. Allocate an interrupt vector/reuse shared vector
|
||||
3. Add a mapping in I/O APIC
|
||||
4. Add entry to IRQ handlers list
|
||||
5. Unmask the GSI
|
||||
Otherwise:
|
||||
1. Add entry `irq_number` to IRQ handlers list
|
||||
|
||||
I/O APIC init:
|
||||
1. Assign I/O APIC address variable
|
||||
2. Relocate existing legacy handlers to I/O APIC
|
||||
@@ -39,6 +39,8 @@ OBJS+=$(O)/sys/amd64/hw/rs232.o \
|
||||
$(O)/sys/amd64/hw/ide/ahci.o \
|
||||
$(O)/sys/amd64/hw/ide/ide.o \
|
||||
$(O)/sys/amd64/hw/pci/pcidb.o \
|
||||
$(O)/sys/amd64/hw/ps2.o \
|
||||
$(O)/sys/amd64/hw/irq.o \
|
||||
$(ACPICA_OBJS) \
|
||||
$(O)/sys/amd64/acpi_osl_mem.o \
|
||||
$(O)/sys/amd64/acpi_osl_printf.o \
|
||||
|
||||
@@ -6,6 +6,24 @@
|
||||
|
||||
#if defined(__ASM__)
|
||||
.extern local_apic
|
||||
.extern irq_handle
|
||||
|
||||
// TODO: make this use less memory
|
||||
.macro irq_entry, n
|
||||
.global amd64_irq\n
|
||||
amd64_irq\n:
|
||||
cli
|
||||
|
||||
irq_push_ctx
|
||||
|
||||
movq $\n, %rdi
|
||||
call irq_handle
|
||||
|
||||
irq_eoi_lapic 0
|
||||
irq_pop_ctx
|
||||
|
||||
iretq
|
||||
.endm
|
||||
|
||||
.macro irq_trace, n
|
||||
#if defined(AMD64_TRACE_IRQ)
|
||||
@@ -101,4 +119,18 @@
|
||||
// Externs for C code
|
||||
extern void amd64_irq0();
|
||||
extern void amd64_irq1();
|
||||
extern void amd64_irq2();
|
||||
extern void amd64_irq3();
|
||||
extern void amd64_irq4();
|
||||
extern void amd64_irq5();
|
||||
extern void amd64_irq6();
|
||||
extern void amd64_irq7();
|
||||
extern void amd64_irq8();
|
||||
extern void amd64_irq9();
|
||||
extern void amd64_irq10();
|
||||
extern void amd64_irq11();
|
||||
extern void amd64_irq12();
|
||||
extern void amd64_irq13();
|
||||
extern void amd64_irq14();
|
||||
extern void amd64_irq15();
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
#pragma once
|
||||
#include "sys/types.h"
|
||||
|
||||
#define IDT_FLG_TASK32 0x5
|
||||
#define IDT_FLG_INT16 0x6
|
||||
#define IDT_FLG_TRAP16 0x7
|
||||
#define IDT_FLG_INT32 0xE
|
||||
#define IDT_FLG_TRAP32 0xF
|
||||
#define IDT_FLG_SS (1 << 4)
|
||||
#define IDT_FLG_R0 (0 << 5)
|
||||
#define IDT_FLG_R1 (1 << 5)
|
||||
#define IDT_FLG_R2 (2 << 5)
|
||||
#define IDT_FLG_R3 (3 << 5)
|
||||
#define IDT_FLG_P (1 << 7)
|
||||
|
||||
struct amd64_idtr {
|
||||
uint16_t size;
|
||||
uintptr_t offset;
|
||||
@@ -8,4 +20,6 @@ struct amd64_idtr {
|
||||
|
||||
extern const struct amd64_idtr amd64_idtr;
|
||||
|
||||
void amd64_idt_set(int idx, uintptr_t base, uint16_t selector, uint8_t flags);
|
||||
|
||||
void amd64_idt_init(void);
|
||||
|
||||
@@ -37,6 +37,9 @@ void amd64_ioapic_write(uint8_t reg, uint32_t v);
|
||||
void amd64_ioapic_set(uintptr_t addr);
|
||||
void amd64_ioapic_int_src_override(uint8_t bus, uint8_t src, uint32_t no, uint16_t flags);
|
||||
|
||||
void amd64_ioapic_map_gsi(uint8_t gsi, uint8_t lapic, uint8_t vector);
|
||||
void amd64_ioapic_unmask(uint8_t gsi);
|
||||
|
||||
//// Generic IRQ stuff
|
||||
// A route exists (LNKx) but is not mapped to any IRQ at the moment
|
||||
#define PCI_IRQ_NO_ROUTE 0xFFFFFFFF
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include "sys/types.h"
|
||||
|
||||
#define IRQ_LEG_KEYBOARD 1
|
||||
#define IRQ_LEG_COM1_3 4
|
||||
|
||||
typedef int (*irq_handler_t) (void);
|
||||
|
||||
int irq_add_handler(uint8_t gsi, irq_handler_t handler);
|
||||
int irq_add_leg_handler(uint8_t leg_irq, irq_handler_t handler);
|
||||
|
||||
void irq_enable_ioapic_mode(void);
|
||||
void irq_init(void);
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
void ps2_init(void);
|
||||
+4
-16
@@ -1,20 +1,8 @@
|
||||
#include "sys/amd64/hw/idt.h"
|
||||
#include "sys/amd64/asm/asm_irq.h"
|
||||
#include "sys/amd64/hw/irq.h"
|
||||
#include "sys/string.h"
|
||||
#include "sys/types.h"
|
||||
|
||||
#define IDT_FLG_TASK32 0x5
|
||||
#define IDT_FLG_INT16 0x6
|
||||
#define IDT_FLG_TRAP16 0x7
|
||||
#define IDT_FLG_INT32 0xE
|
||||
#define IDT_FLG_TRAP32 0xF
|
||||
#define IDT_FLG_SS (1 << 4)
|
||||
#define IDT_FLG_R0 (0 << 5)
|
||||
#define IDT_FLG_R1 (1 << 5)
|
||||
#define IDT_FLG_R2 (2 << 5)
|
||||
#define IDT_FLG_R3 (3 << 5)
|
||||
#define IDT_FLG_P (1 << 7)
|
||||
|
||||
extern uintptr_t amd64_exception_vectors[32];
|
||||
|
||||
static struct amd64_idt_entry {
|
||||
@@ -32,7 +20,7 @@ const struct amd64_idtr amd64_idtr = {
|
||||
.offset = (uintptr_t) idt
|
||||
};
|
||||
|
||||
static void amd64_idt_set(int idx, uintptr_t base, uint16_t selector, uint8_t flags) {
|
||||
void amd64_idt_set(int idx, uintptr_t base, uint16_t selector, uint8_t flags) {
|
||||
idt[idx].base_lo = base & 0xFFFF;
|
||||
idt[idx].base_hi = (base >> 16) & 0xFFFF;
|
||||
idt[idx].base_ex = (base >> 32) & 0xFFFFFFFF;
|
||||
@@ -47,8 +35,8 @@ void amd64_idt_init(void) {
|
||||
for (size_t i = 0; i < 32; ++i) {
|
||||
amd64_idt_set(i, amd64_exception_vectors[i], 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
|
||||
}
|
||||
amd64_idt_set(32, (uintptr_t) amd64_irq0, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
|
||||
amd64_idt_set(33, (uintptr_t) amd64_irq1, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
|
||||
|
||||
irq_init();
|
||||
|
||||
asm volatile ("lidt amd64_idtr(%rip)");
|
||||
}
|
||||
|
||||
+20
-24
@@ -1,4 +1,5 @@
|
||||
#include "sys/amd64/hw/ioapic.h"
|
||||
#include "sys/amd64/hw/irq.h"
|
||||
#include "sys/string.h"
|
||||
#include "sys/mm.h"
|
||||
#include "sys/debug.h"
|
||||
@@ -95,33 +96,28 @@ void amd64_ioapic_set(uintptr_t addr) {
|
||||
// low & 0xF);
|
||||
}
|
||||
|
||||
// Test: set IRQ1 -> LAPIC 0:1 and unmask it
|
||||
uint32_t low = amd64_ioapic_read(0x10 + 1 * 2);
|
||||
uint32_t high = amd64_ioapic_read(0x11 + 1 * 2);
|
||||
irq_enable_ioapic_mode();
|
||||
}
|
||||
|
||||
void amd64_ioapic_map_gsi(uint8_t gsi, uint8_t lapic, uint8_t vector) {
|
||||
uint32_t low = amd64_ioapic_read((gsi * 2) + 0x10);
|
||||
uint32_t high = amd64_ioapic_read((gsi * 2) + 0x11);
|
||||
|
||||
low &= ~0xFF;
|
||||
low |= vector;
|
||||
|
||||
high = IOAPIC_REDIR_DST_SET(lapic);
|
||||
|
||||
amd64_ioapic_write((gsi * 2) + 0x10, low);
|
||||
amd64_ioapic_write((gsi * 2) + 0x11, high);
|
||||
}
|
||||
|
||||
void amd64_ioapic_unmask(uint8_t gsi) {
|
||||
uint32_t low = amd64_ioapic_read((gsi * 2) + 0x10);
|
||||
|
||||
low &= ~0x7;
|
||||
low &= ~IOAPIC_REDIR_MSK;
|
||||
|
||||
low |= 0x1 + 0x20;
|
||||
high = IOAPIC_REDIR_DST_SET(0);
|
||||
|
||||
amd64_ioapic_write(0x10 + 1 * 2, low);
|
||||
amd64_ioapic_write(0x11 + 1 * 2, high);
|
||||
|
||||
// TODO: find IRQ mappings corresponding to legacy irq 1/4
|
||||
low = amd64_ioapic_read(0x10 + 4 * 2);
|
||||
high = amd64_ioapic_read(0x11 + 4 * 2);
|
||||
|
||||
low &= ~0x7;
|
||||
low &= ~IOAPIC_REDIR_MSK;
|
||||
|
||||
low |= 0x1 + 0x20;
|
||||
high = IOAPIC_REDIR_DST_SET(0);
|
||||
|
||||
amd64_ioapic_write(0x10 + 4 * 2, low);
|
||||
amd64_ioapic_write(0x11 + 4 * 2, high);
|
||||
|
||||
// TODO: unconfigured PCI IRQs may be mapped here
|
||||
amd64_ioapic_write((gsi * 2) + 0x10, low);
|
||||
}
|
||||
|
||||
#define PCI_LINK_MAX_POSSIBLE_IRQS 16
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
#include "sys/amd64/asm/asm_irq.h"
|
||||
#include "sys/amd64/hw/ioapic.h"
|
||||
#include "sys/amd64/hw/irq.h"
|
||||
#include "sys/amd64/hw/idt.h"
|
||||
#include "sys/string.h"
|
||||
#include "sys/assert.h"
|
||||
#include "sys/panic.h"
|
||||
#include "sys/debug.h"
|
||||
|
||||
#define IRQ_MAX 16 // Maximum assignable IRQ vectors
|
||||
#define IRQ_MAX_HANDLERS 4 // Maximum handlers per IRQ vector (sharing)
|
||||
|
||||
static irq_handler_t handlers[IRQ_MAX * IRQ_MAX_HANDLERS] = {0};
|
||||
static uint64_t vector_bitmap[4] = {0};
|
||||
static int ioapic_available = 0;
|
||||
|
||||
static int irq_alloc_vector(uint8_t *vector) {
|
||||
for (size_t i = 1; i < IRQ_MAX; ++i) {
|
||||
size_t idx = i / 64;
|
||||
size_t bit = 1ULL << (i % 64);
|
||||
|
||||
if (!(vector_bitmap[idx] & bit)) {
|
||||
*vector = i;
|
||||
vector_bitmap[idx] |= bit;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void irq_handle(uintptr_t n) {
|
||||
_assert(n && n < IRQ_MAX);
|
||||
|
||||
irq_handler_t *list = &handlers[IRQ_MAX_HANDLERS * n];
|
||||
for (size_t i = 0; i < IRQ_MAX_HANDLERS; ++i) {
|
||||
if (list[i] && (list[i]() == 0)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int irq_add_handler(uint8_t gsi, irq_handler_t handler) {
|
||||
_assert(gsi != 0 && gsi < IRQ_MAX);
|
||||
_assert(ioapic_available);
|
||||
|
||||
|
||||
uint8_t vector;
|
||||
if (irq_alloc_vector(&vector)) {
|
||||
return -1;
|
||||
}
|
||||
kdebug("I/O APIC: Mapping GSI%u -> Vector %d:%d\n", gsi, 0, vector);
|
||||
|
||||
irq_handler_t *list = &handlers[IRQ_MAX_HANDLERS * vector];
|
||||
for (size_t i = 0; i < IRQ_MAX_HANDLERS; ++i) {
|
||||
if (!list[i]) {
|
||||
list[i] = handler;
|
||||
|
||||
amd64_ioapic_map_gsi(gsi, 0, vector + 0x20);
|
||||
amd64_ioapic_unmask(gsi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int irq_add_leg_handler(uint8_t leg_irq, irq_handler_t handler) {
|
||||
_assert(leg_irq != 0 && leg_irq < IRQ_MAX);
|
||||
|
||||
if (ioapic_available) {
|
||||
// Find out the route (TODO)
|
||||
uint8_t gsi = leg_irq;
|
||||
|
||||
return irq_add_handler(gsi, handler);
|
||||
} else {
|
||||
irq_handler_t *list = &handlers[IRQ_MAX_HANDLERS * leg_irq];
|
||||
|
||||
for (size_t i = 0; i < IRQ_MAX_HANDLERS; ++i) {
|
||||
if (!list[i]) {
|
||||
list[i] = handler;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void irq_enable_ioapic_mode(void) {
|
||||
ioapic_available = 1;
|
||||
// Copy current table
|
||||
irq_handler_t handlers_old[16 * IRQ_MAX_HANDLERS];
|
||||
|
||||
memcpy(handlers_old, handlers, 16 * IRQ_MAX_HANDLERS * sizeof(irq_handler_t));
|
||||
memset(handlers, 0, 16 * IRQ_MAX_HANDLERS * sizeof(irq_handler_t));
|
||||
|
||||
// All legacy IRQs
|
||||
for (size_t i = 0; i < 16; ++i) {
|
||||
irq_handler_t *handler_list = &handlers_old[i * IRQ_MAX_HANDLERS];
|
||||
|
||||
for (size_t j = 0; j < IRQ_MAX_HANDLERS; ++j) {
|
||||
if (handler_list[j]) {
|
||||
irq_add_leg_handler(i, handlers_old[i * IRQ_MAX_HANDLERS + j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void irq_init(void) {
|
||||
amd64_idt_set(32, (uintptr_t) amd64_irq0, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
|
||||
amd64_idt_set(33, (uintptr_t) amd64_irq1, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
|
||||
amd64_idt_set(34, (uintptr_t) amd64_irq2, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
|
||||
amd64_idt_set(35, (uintptr_t) amd64_irq3, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
|
||||
amd64_idt_set(36, (uintptr_t) amd64_irq4, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
|
||||
amd64_idt_set(37, (uintptr_t) amd64_irq5, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
|
||||
amd64_idt_set(38, (uintptr_t) amd64_irq6, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
|
||||
amd64_idt_set(39, (uintptr_t) amd64_irq7, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
|
||||
amd64_idt_set(40, (uintptr_t) amd64_irq8, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
|
||||
amd64_idt_set(41, (uintptr_t) amd64_irq9, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
|
||||
amd64_idt_set(42, (uintptr_t) amd64_irq10, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
|
||||
amd64_idt_set(43, (uintptr_t) amd64_irq11, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
|
||||
amd64_idt_set(44, (uintptr_t) amd64_irq12, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
|
||||
amd64_idt_set(45, (uintptr_t) amd64_irq13, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
|
||||
amd64_idt_set(46, (uintptr_t) amd64_irq14, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
|
||||
amd64_idt_set(47, (uintptr_t) amd64_irq15, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
|
||||
}
|
||||
+17
-46
@@ -4,51 +4,22 @@
|
||||
|
||||
.section .text
|
||||
|
||||
// TODO: move all this to some kind of generic handler
|
||||
// This is keyboard
|
||||
// Can be either entered from a legacy PIC IRQ
|
||||
// Or is mapped in I/O APIC
|
||||
.global amd64_irq1
|
||||
amd64_irq1:
|
||||
cli
|
||||
|
||||
irq_push_ctx
|
||||
movq %rsp, %rbp
|
||||
|
||||
// The ISR is shared between legacy IRQs 1 and 4, so
|
||||
// check if it's keyboard or serial input on COM1
|
||||
// Check PS/2 keyboard
|
||||
inb $0x64, %al
|
||||
test $(1 << 0), %al
|
||||
jz 1f
|
||||
|
||||
// Read from keyboard buffer
|
||||
inb $0x60, %al
|
||||
movb %al, irq1_key(%rip)
|
||||
|
||||
jmp 2f
|
||||
1:
|
||||
|
||||
movq $0x3F8, %rdi
|
||||
call rs232_irq
|
||||
test %rax, %rax
|
||||
jz 2f
|
||||
|
||||
// Only trace IRQ if it's unhandled
|
||||
irq_trace 1
|
||||
2:
|
||||
irq_eoi_lapic 1
|
||||
|
||||
irq_pop_ctx
|
||||
|
||||
iretq
|
||||
|
||||
|
||||
_amd64_irq1_unhandled:
|
||||
.string "Something unknown triggered ISR 0x21\n"
|
||||
_amd64_serial:
|
||||
.string "Serial status: %02x\n"
|
||||
|
||||
// 33
|
||||
irq_entry 1
|
||||
irq_entry 2
|
||||
irq_entry 3
|
||||
irq_entry 4
|
||||
irq_entry 5
|
||||
irq_entry 6
|
||||
irq_entry 7
|
||||
irq_entry 8
|
||||
irq_entry 9
|
||||
irq_entry 10
|
||||
irq_entry 11
|
||||
irq_entry 12
|
||||
irq_entry 13
|
||||
irq_entry 14
|
||||
irq_entry 15
|
||||
|
||||
.global amd64_kstack_canary_invalid
|
||||
#if defined(AMD64_STACK_CTX_CANARY)
|
||||
@@ -68,5 +39,5 @@ amd64_kstack_canary_invalid:
|
||||
jmp 1b
|
||||
|
||||
_msg0:
|
||||
.string "Stack fuckup detected: halting\n"
|
||||
.string "Stack fuckup detected: halting\n"
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
#include "sys/amd64/hw/ps2.h"
|
||||
#include "sys/amd64/hw/irq.h"
|
||||
#include "sys/amd64/hw/io.h"
|
||||
|
||||
int ps2_irq_keyboard(void) {
|
||||
uint8_t st = inb(0x64);
|
||||
|
||||
if (!(st & 1)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
inb(0x60);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ps2_init(void) {
|
||||
irq_add_leg_handler(IRQ_LEG_KEYBOARD, ps2_irq_keyboard);
|
||||
}
|
||||
+18
-15
@@ -1,4 +1,5 @@
|
||||
#include "sys/amd64/hw/rs232.h"
|
||||
#include "sys/amd64/hw/irq.h"
|
||||
#include "sys/amd64/hw/io.h"
|
||||
#include "sys/debug.h"
|
||||
|
||||
@@ -31,6 +32,21 @@ void rs232_send(uint16_t port, char c) {
|
||||
outb(port, c);
|
||||
}
|
||||
|
||||
static int rs232_irq(void) {
|
||||
int has_data = 0;
|
||||
uint8_t s;
|
||||
|
||||
while ((s = inb(RS232_COM0 + RS232_LSR)) & RS232_LSR_DR) {
|
||||
has_data = 1;
|
||||
uint8_t c = inb(RS232_COM0);
|
||||
|
||||
// Act as echo for now
|
||||
rs232_send(RS232_COM0, c);
|
||||
}
|
||||
|
||||
return !has_data;
|
||||
}
|
||||
|
||||
void rs232_init(uint16_t port) {
|
||||
// Disable interrupts
|
||||
outb(port + RS232_IER, 0x00);
|
||||
@@ -48,19 +64,6 @@ void rs232_init(uint16_t port) {
|
||||
|
||||
// Enable receive interrupts
|
||||
outb(port + RS232_IER, RS232_IER_RCE);
|
||||
}
|
||||
|
||||
int rs232_irq(uint16_t port) {
|
||||
int has_data = 0;
|
||||
uint8_t s;
|
||||
|
||||
while ((s = inb(port + RS232_LSR)) & RS232_LSR_DR) {
|
||||
has_data = 1;
|
||||
uint8_t c = inb(port);
|
||||
|
||||
// Act as echo for now
|
||||
rs232_send(port, c);
|
||||
}
|
||||
|
||||
return !has_data;
|
||||
|
||||
irq_add_leg_handler(IRQ_LEG_COM1_3, rs232_irq);
|
||||
}
|
||||
|
||||
+2
-2
@@ -9,15 +9,15 @@
|
||||
#include "sys/amd64/hw/apic.h"
|
||||
#include "sys/amd64/hw/pci/pci.h"
|
||||
#include "sys/amd64/hw/rs232.h"
|
||||
#include "sys/amd64/hw/ps2.h"
|
||||
#include "sys/panic.h"
|
||||
#include "sys/assert.h"
|
||||
|
||||
#include "acpi.h"
|
||||
|
||||
static multiboot_info_t *multiboot_info;
|
||||
|
||||
void kernel_main(struct amd64_loader_data *data) {
|
||||
// Reinitialize RS232 properly
|
||||
ps2_init();
|
||||
rs232_init(RS232_COM0);
|
||||
|
||||
data = (struct amd64_loader_data *) MM_VIRTUALIZE(data);
|
||||
|
||||
Reference in New Issue
Block a user