summaryrefslogtreecommitdiff
path: root/kernel/src
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/src')
-rw-r--r--kernel/src/apic/apic.c0
-rw-r--r--kernel/src/apic/madt.c116
-rw-r--r--kernel/src/apic/rsdp.c38
-rw-r--r--kernel/src/cpu/idt.c19
-rw-r--r--kernel/src/cpu/irq.c290
-rw-r--r--kernel/src/cpu/irq_stub.S56
-rw-r--r--kernel/src/cpu/pic.c12
-rw-r--r--kernel/src/main.c1
-rw-r--r--kernel/src/mem/paging.c2
9 files changed, 224 insertions, 310 deletions
diff --git a/kernel/src/apic/apic.c b/kernel/src/apic/apic.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/kernel/src/apic/apic.c
diff --git a/kernel/src/apic/madt.c b/kernel/src/apic/madt.c
index b88b788..fff0db5 100644
--- a/kernel/src/apic/madt.c
+++ b/kernel/src/apic/madt.c
@@ -1,7 +1,75 @@
#include <madt.h>
#include <heap.h>
+#include <paging.h>
#include <libk/string.h>
#include <libk/stdio.h>
+#include <apic.h>
+
+uint8_t curr_cpu_apic_id(void);
+uint8_t curr_cpu_apic_id()
+{
+ uint8_t apic_id = 0;
+ __asm__ __volatile__ ("movl $1, %%eax; cpuid; shrl $24, %%ebx;": "=b"(apic_id));
+ return apic_id;
+}
+
+uint32_t ioapic_addr = 0;
+uint32_t lapic_addr = 0;
+uint32_t numcores = 0;
+uint8_t cpu_apic_ids[256];
+
+uint32_t ioapic_read(const uint8_t offset);
+uint32_t ioapic_read(const uint8_t offset)
+{
+ /* tell IOREGSEL where we want to read from */
+ *(volatile uint32_t*)(uint64_t)ioapic_addr = offset;
+ /* return the data from IOWIN */
+ return *(volatile uint32_t*)((uint64_t)ioapic_addr + 0x10);
+}
+
+void ioapic_write(const uint8_t offset, const uint32_t val);
+void ioapic_write(const uint8_t offset, const uint32_t val)
+{
+ /* tell IOREGSEL where we want to write to */
+ *(volatile uint32_t*)(uint64_t)ioapic_addr = offset;
+ /* write the value to IOWIN */
+ *(volatile uint32_t*)((uint64_t)ioapic_addr + 0x10) = val;
+}
+
+void apic_eoi()
+{
+ *((volatile uint32_t*)((uint64_t)0xFEE00000 + 0xB0)) = 0;
+}
+
+void ioapic_set_irq(uint8_t irq, uint64_t apic_id, uint8_t vector);
+void ioapic_set_irq(uint8_t irq, uint64_t apic_id, uint8_t vector)
+{
+ const uint32_t low_index = (uint32_t)0x10 + irq*2;
+ const uint32_t high_index = (uint32_t)0x10 + irq*2 + 1;
+
+ uint32_t high = ioapic_read((uint8_t)high_index);
+ // set APIC ID
+ high &= (uint32_t)~0xff000000;
+ high |= (uint32_t)apic_id << 24;
+ ioapic_write((uint8_t)high_index, high);
+
+ uint32_t low = ioapic_read((uint8_t)low_index);
+
+ // unmask the IRQ
+ low &= (uint32_t)~(1<<16);
+
+ // set to physical delivery mode
+ low &= (uint32_t)~(1<<11);
+
+ // set to fixed delivery mode
+ low &= (uint32_t)~0x700;
+
+ // set delivery vector
+ low &= (uint32_t)~0xff;
+ low |= vector;
+
+ ioapic_write((uint8_t)low_index, low);
+}
void parse_madt()
{
@@ -14,6 +82,7 @@ void parse_madt()
struct MADT* madt = (struct MADT*)kalloc(sizeof(struct MADT));
memcpy(madt, madt_addr, sizeof(struct MADT));
+ lapic_addr = madt->lapic_addr;
for (size_t curr_size = sizeof(struct MADT); curr_size < madt->h.Length;) {
struct MADT_type_header* m = (struct MADT_type_header*)kalloc(sizeof(struct MADT_type_header));
@@ -27,6 +96,9 @@ void parse_madt()
struct MADT_cpu_local_apic* cpu = (struct MADT_cpu_local_apic*)kalloc(sizeof(struct MADT_cpu_local_apic));
memcpy(cpu, (uint64_t*)((uint64_t)madt_addr + (uint64_t)curr_size), sizeof(struct MADT_cpu_local_apic));
+ cpu_apic_ids[numcores] = cpu->apic_id;
+ numcores++;
+
printf("found cpu: acpi_id: 0x%x, apic_id: 0x%x, flags: 0x%x\n", cpu->acpi_id, cpu->apic_id, cpu->flags);
kfree(cpu);
} else if (type == 1) {
@@ -34,6 +106,8 @@ void parse_madt()
struct MADT_io_apic* io = (struct MADT_io_apic*)kalloc(sizeof(struct MADT_io_apic));
memcpy(io, (uint64_t*)((uint64_t)madt_addr + (uint64_t)curr_size), sizeof(struct MADT_io_apic));
+ ioapic_addr = io->io_apic_addr;
+
printf("found io: apic_id: 0x%x, addr: 0x%x, int_base: 0x%x\n", io->apic_id, io->io_apic_addr, io->int_base);
kfree(io);
} else if (type == 2) {
@@ -55,11 +129,11 @@ void parse_madt()
kfree(lapic_nmi);
} else if (type == 5) {
// Local APIC Address Override
- struct MADT_lapic_addr* lapic_addr = (struct MADT_lapic_addr*)kalloc(sizeof(struct MADT_lapic_addr));
- memcpy(lapic_addr, (uint64_t*)((uint64_t)madt_addr + (uint64_t)curr_size), sizeof(struct MADT_lapic_addr));
+ struct MADT_lapic_addr* lapic_addr_ovr = (struct MADT_lapic_addr*)kalloc(sizeof(struct MADT_lapic_addr));
+ memcpy(lapic_addr_ovr, (uint64_t*)((uint64_t)madt_addr + (uint64_t)curr_size), sizeof(struct MADT_lapic_addr));
- printf("found lapic: addr: 0x%x\n", lapic_addr->phys_addr);
- kfree(lapic_addr);
+ printf("found lapic: addr: 0x%x\n", lapic_addr_ovr->phys_addr);
+ kfree(lapic_addr_ovr);
} else if (type == 9) {
// Processor Local x2APIC
printf("MADT entry of type %d\n", type);
@@ -69,4 +143,38 @@ void parse_madt()
}
curr_size += len;
}
+ kfree(madt);
+
+ /*
+ for(size_t i = 0; i < numcores; i++) {
+ // do not start BSP, that's already running this code
+ if(cpu_apic_ids[i] == bspid) continue;
+ // send INIT IPI
+ *((volatile uint32_t*)(lapic_addr + 0x280)) = 0; // clear APIC errors
+ *((volatile uint32_t*)(lapic_addr + 0x310)) = (*((volatile uint32_t*)(lapic_addr + 0x310)) & 0x00ffffff) | (i << 24); // select AP
+ *((volatile uint32_t*)(lapic_addr + 0x300)) = (*((volatile uint32_t*)(lapic_addr + 0x300)) & 0xfff00000) | 0x00C500; // trigger INIT IPI
+ do { __asm__ __volatile__ ("pause" : : : "memory"); }while(*((volatile uint32_t*)(lapic_addr + 0x300)) & (1 << 12)); // wait for delivery
+ *((volatile uint32_t*)(lapic_addr + 0x310)) = (*((volatile uint32_t*)(lapic_addr + 0x310)) & 0x00ffffff) | (i << 24); // select AP
+ *((volatile uint32_t*)(lapic_addr + 0x300)) = (*((volatile uint32_t*)(lapic_addr + 0x300)) & 0xfff00000) | 0x008500; // deassert
+ do { __asm__ __volatile__ ("pause" : : : "memory"); }while(*((volatile uint32_t*)(lapic_addr + 0x300)) & (1 << 12)); // wait for delivery
+ mdelay(10); // wait 10 msec
+ // send STARTUP IPI (twice)
+ for(size_t j = 0; j < 2; j++) {
+ *((volatile uint32_t*)(lapic_addr + 0x280)) = 0; // clear APIC errors
+ *((volatile uint32_t*)(lapic_addr + 0x310)) = (*((volatile uint32_t*)(lapic_addr + 0x310)) & 0x00ffffff) | (i << 24); // select AP
+ *((volatile uint32_t*)(lapic_addr + 0x300)) = (*((volatile uint32_t*)(lapic_addr + 0x300)) & 0xfff0f800) | 0x000608; // trigger STARTUP IPI for 0800:0000
+ udelay(200); // wait 200 usec
+ do { __asm__ __volatile__ ("pause" : : : "memory"); }while(*((volatile uint32_t*)(lapic_addr + 0x300)) & (1 << 12)); // wait for delivery
+ }
+ }
+ */
+
+ uint8_t bspid = curr_cpu_apic_id();
+
+ map_addr(lapic_addr, lapic_addr, FLAG_PRESENT);
+ map_addr(ioapic_addr, ioapic_addr, FLAG_PRESENT);
+ // irq is 2 because of gsi remap
+ ioapic_set_irq(0x2, bspid, 0x20); // timer
+ ioapic_set_irq(0x1, bspid, 0x21); // keyboard
+ __asm__ volatile ("sti;");
}
diff --git a/kernel/src/apic/rsdp.c b/kernel/src/apic/rsdp.c
index ebecd66..983ab5f 100644
--- a/kernel/src/apic/rsdp.c
+++ b/kernel/src/apic/rsdp.c
@@ -24,6 +24,44 @@ uint64_t* find_rsdp()
return NULL;
}
+void list_sys_tables(void)
+{
+ uint64_t* rsdp = find_rsdp();
+
+ if (rsdp == NULL) {
+ printf("RSDP NOT FOUND\n");
+ return;
+ }
+
+ struct RSDP_descriptor* rsdp_desc = (struct RSDP_descriptor*)rsdp;
+ map_addr(rsdp_desc->RsdtAddress, rsdp_desc->RsdtAddress, FLAG_PRESENT);
+
+ struct ACPI_header* rsdt = (struct ACPI_header*)kalloc(sizeof(struct ACPI_header));
+ memcpy(rsdt, (uint64_t*)(uint64_t)rsdp_desc->RsdtAddress, sizeof(struct ACPI_header));
+
+ uint32_t entries = (rsdt->Length - (uint32_t)sizeof(struct ACPI_header)) / 4;
+
+ for (size_t i = 0; i < entries; i++) {
+ uint32_t na_addr = (uint32_t)rsdp_desc->RsdtAddress + (uint32_t)sizeof(struct ACPI_header) + (uint32_t)i * 4;
+ uint32_t addr;
+ memcpy(&addr, (uint64_t*)(uint64_t)na_addr, 4);
+
+ struct ACPI_header* t = (struct ACPI_header*)kalloc(sizeof(struct ACPI_header));
+ memcpy(t, (uint64_t*)(uint64_t)addr, sizeof(struct ACPI_header));
+
+ for (size_t j = 0; j < 4; j++) {
+ printf("%c", t->Signature[j]);
+ }
+ printf(", ");
+
+ kfree(t);
+ }
+ printf("\n");
+
+ kfree(rsdt);
+
+}
+
uint64_t* find_sys_table_addr(const char* signature)
{
uint64_t* rsdp = find_rsdp();
diff --git a/kernel/src/cpu/idt.c b/kernel/src/cpu/idt.c
index e900c77..3578f53 100644
--- a/kernel/src/cpu/idt.c
+++ b/kernel/src/cpu/idt.c
@@ -8,7 +8,7 @@ idtp idt_pointer;
void load_idt(idtp* pointer)
{
- __asm__ volatile ("lidt (%0); sti;" : : "r"(pointer) : );
+ __asm__ volatile ("lidt (%0);" : : "r"(pointer) : );
}
void add_to_idt(uint16_t num, uint64_t offset, uint16_t selector, uint8_t type)
@@ -61,20 +61,9 @@ void init_idt_table(void)
// interrupts
add_to_idt(32, (uint64_t)irq0, GDT_CODE_SEG, INTERRUPT_GATE);
add_to_idt(33, (uint64_t)irq1, GDT_CODE_SEG, INTERRUPT_GATE);
- add_to_idt(34, (uint64_t)irq2, GDT_CODE_SEG, INTERRUPT_GATE);
- add_to_idt(35, (uint64_t)irq3, GDT_CODE_SEG, INTERRUPT_GATE);
- add_to_idt(36, (uint64_t)irq4, GDT_CODE_SEG, INTERRUPT_GATE);
- add_to_idt(37, (uint64_t)irq5, GDT_CODE_SEG, INTERRUPT_GATE);
- add_to_idt(38, (uint64_t)irq6, GDT_CODE_SEG, INTERRUPT_GATE);
- add_to_idt(39, (uint64_t)irq7, GDT_CODE_SEG, INTERRUPT_GATE);
- add_to_idt(40, (uint64_t)irq8, GDT_CODE_SEG, INTERRUPT_GATE);
- add_to_idt(41, (uint64_t)irq9, GDT_CODE_SEG, INTERRUPT_GATE);
- add_to_idt(42, (uint64_t)irq10, GDT_CODE_SEG, INTERRUPT_GATE);
- add_to_idt(43, (uint64_t)irq11, GDT_CODE_SEG, INTERRUPT_GATE);
- add_to_idt(44, (uint64_t)irq12, GDT_CODE_SEG, INTERRUPT_GATE);
- add_to_idt(45, (uint64_t)irq13, GDT_CODE_SEG, INTERRUPT_GATE);
- add_to_idt(46, (uint64_t)irq14, GDT_CODE_SEG, INTERRUPT_GATE);
- add_to_idt(47, (uint64_t)irq15, GDT_CODE_SEG, INTERRUPT_GATE);
+ for (size_t i = 34; i < 256; i++) {
+ add_to_idt((uint16_t)i, (uint64_t)irq2, GDT_CODE_SEG, INTERRUPT_GATE);
+ }
}
void init_idt()
diff --git a/kernel/src/cpu/irq.c b/kernel/src/cpu/irq.c
index 4670da5..79498ba 100644
--- a/kernel/src/cpu/irq.c
+++ b/kernel/src/cpu/irq.c
@@ -9,6 +9,9 @@
#include <libk/serial_stdio.h>
#include <libk/stdio.h>
#include <panic.h>
+#include <apic.h>
+
+#define PIT 0
const char* const exception_name[] = {
"Divide-by-zero Error",
@@ -45,253 +48,42 @@ const char* const exception_name[] = {
"Reserved",
};
-void isr0_handler(void)
-{
- panic("%s\n", exception_name[0]);
-}
-
-void isr1_handler(void)
-{
- panic("%s\n", exception_name[1]);
-}
-
-void isr2_handler(void)
-{
- panic("%s\n", exception_name[2]);
-}
-
-void isr3_handler(void)
-{
- panic("%s\n", exception_name[3]);
-}
-
-void isr4_handler(void)
-{
- panic("%s\n", exception_name[4]);
-}
-
-void isr5_handler(void)
-{
- panic("%s\n", exception_name[5]);
-}
-
-void isr6_handler(void)
-{
- panic("%s\n", exception_name[6]);
-}
-
-void isr7_handler(void)
-{
- panic("%s\n", exception_name[7]);
-}
-
-void isr8_handler(uint64_t error)
-{
- panic("%s, error: %d\n", exception_name[8], error);
-}
-
-void isr9_handler(void)
-{
- panic("%s\n", exception_name[9]);
-}
-
-void isr10_handler(uint64_t error)
-{
- panic("%s, error: %d\n", exception_name[10], error);
-}
-
-void isr11_handler(uint64_t error)
-{
- panic("%s, error: %d\n", exception_name[11], error);
-}
-
-void isr12_handler(uint64_t error)
-{
- panic("%s, error: %d\n", exception_name[12], error);
-}
-
-void isr13_handler(uint64_t error)
-{
- panic("%s, error: %d\n", exception_name[13], error);
-}
-
-void isr14_handler(uint64_t error)
-{
- printf("%s, error: %d\n", exception_name[14], error);
- page_fault(error);
-}
-
-void isr15_handler(void)
-{
- panic("%s\n", exception_name[15]);
-}
-
-void isr16_handler(void)
-{
- panic("%s\n", exception_name[16]);
-}
-
-void isr17_handler(uint64_t error)
-{
- panic("%s, error: %d\n", exception_name[17], error);
-}
-
-void isr18_handler(void)
-{
- panic("%s\n", exception_name[18]);
-}
-
-void isr19_handler(void)
-{
- panic("%s\n", exception_name[19]);
-}
-
-void isr20_handler(void)
-{
- panic("%s\n", exception_name[20]);
-}
-
-void isr21_handler(uint64_t error)
-{
- panic("%s, error: %d\n", exception_name[21], error);
-}
-
-void isr22_handler(void)
-{
- panic("%s\n", exception_name[22]);
-}
-
-void isr23_handler(void)
-{
- panic("%s\n", exception_name[23]);
-}
-
-void isr24_handler(void)
-{
- panic("%s\n", exception_name[24]);
-}
-
-void isr25_handler(void)
-{
- panic("%s\n", exception_name[25]);
-}
-
-void isr26_handler(void)
-{
- panic("%s\n", exception_name[26]);
-}
-
-void isr27_handler(void)
-{
- panic("%s\n", exception_name[27]);
-}
-
-void isr28_handler(void)
-{
- panic("%s\n", exception_name[28]);
-}
-
-void isr29_handler(uint64_t error)
-{
- panic("%s, error: %d\n", exception_name[29], error);
-}
-
-void isr30_handler(uint64_t error)
-{
- panic("%s, error: %d\n", exception_name[30], error);
-}
-
-void isr31_handler(void)
-{
- panic("%s\n", exception_name[31]);
-}
-
-void irq0_handler(void)
-{
- timer_handler();
- outb(PIC1_COMMAND, PIC_EOI);
-}
-
-void irq1_handler(void)
-{
- keyboard_handler();
- outb(PIC1_COMMAND, PIC_EOI);
-}
-
-void irq2_handler(void)
-{
- outb(PIC1_COMMAND, PIC_EOI);
-}
-
-void irq3_handler(void)
-{
- outb(PIC1_COMMAND, PIC_EOI);
-}
-
-void irq4_handler(void)
-{
- outb(PIC1_COMMAND, PIC_EOI);
-}
-
-void irq5_handler(void)
-{
- outb(PIC1_COMMAND, PIC_EOI);
-}
-
-void irq6_handler(void)
-{
- outb(PIC1_COMMAND, PIC_EOI);
-}
-
-void irq7_handler(void)
-{
- outb(PIC1_COMMAND, PIC_EOI);
-}
-
-void irq8_handler(void)
-{
- outb(PIC1_COMMAND, PIC_EOI);
- outb(PIC2_COMMAND, PIC_EOI);
-}
-
-void irq9_handler(void)
-{
- outb(PIC1_COMMAND, PIC_EOI);
- outb(PIC2_COMMAND, PIC_EOI);
-}
-
-void irq10_handler(void)
-{
- outb(PIC1_COMMAND, PIC_EOI);
- outb(PIC2_COMMAND, PIC_EOI);
-}
-
-void irq11_handler(void)
-{
- outb(PIC1_COMMAND, PIC_EOI);
- outb(PIC2_COMMAND, PIC_EOI);
-}
-
-void irq12_handler(void)
-{
- outb(PIC1_COMMAND, PIC_EOI);
- outb(PIC2_COMMAND, PIC_EOI);
-}
-
-void irq13_handler(void)
-{
- outb(PIC1_COMMAND, PIC_EOI);
- outb(PIC2_COMMAND, PIC_EOI);
-}
-
-void irq14_handler(void)
-{
- outb(PIC1_COMMAND, PIC_EOI);
- outb(PIC2_COMMAND, PIC_EOI);
-}
-
-void irq15_handler(void)
-{
- outb(PIC1_COMMAND, PIC_EOI);
- outb(PIC2_COMMAND, PIC_EOI);
+void isr_def_handler(uint64_t number, uint64_t error)
+{
+ switch(number) {
+ case 14:
+ printf("%s, error: 0x%x\n", exception_name[14], error);
+ page_fault(error);
+ break;
+ default:
+ panic("%s, error: 0x%x\n", exception_name[number], error);
+ }
+}
+
+void eoi(uint64_t number)
+{
+ if (PIT) {
+ if (number < 8) {
+ outb(PIC1_COMMAND, PIC_EOI);
+ } else if (number < 16) {
+ outb(PIC1_COMMAND, PIC_EOI);
+ outb(PIC2_COMMAND, PIC_EOI);
+ }
+ } else {
+ apic_eoi();
+ }
+}
+
+void irq_def_handler(uint64_t number)
+{
+ switch(number)
+ {
+ case 0:
+ timer_handler();
+ break;
+ case 1:
+ keyboard_handler();
+ break;
+ }
+ eoi(number);
}
diff --git a/kernel/src/cpu/irq_stub.S b/kernel/src/cpu/irq_stub.S
index ee02d3e..3ba4360 100644
--- a/kernel/src/cpu/irq_stub.S
+++ b/kernel/src/cpu/irq_stub.S
@@ -49,27 +49,41 @@
pop %rax
.endm
-.macro isr_no_error number
-.global isr\number
-isr\number:
+.macro isrstub
pushall
- cld
+ mov 0x88(%rsp), %rsi
mov %rsp, panic_rsp
- call isr\number\()_handler
+ cld
+ call isr_def_handler
popall
+ add $8, %rsp
iretq
.endm
+.macro isr_no_error number
+.global isr\number
+isr\number:
+ push $0
+ mov $\number, %rdi
+ isrstub
+.endm
+
.macro isr_error number
.global isr\number
isr\number:
+ mov $\number, %rdi
+ isrstub
+.endm
+
+.macro irq number
+.global irq\number
+irq\number:
pushall
- mov 0x88(%rsp), %rdi
- cld
+ mov $\number, %rdi
mov %rsp, panic_rsp
- call isr\number\()_handler
+ cld
+ call irq_def_handler
popall
- add $8, %rsp
iretq
.endm
@@ -106,30 +120,6 @@ isr_error 29
isr_error 30
isr_no_error 31
-.macro irq number
-.global irq\number
-irq\number:
- pushall
- cld
- mov %rsp, panic_rsp
- call irq\number\()_handler
- popall
- iretq
-.endm
-
irq 0
irq 1
irq 2
-irq 3
-irq 4
-irq 5
-irq 6
-irq 7
-irq 8
-irq 9
-irq 10
-irq 11
-irq 12
-irq 13
-irq 14
-irq 15
diff --git a/kernel/src/cpu/pic.c b/kernel/src/cpu/pic.c
index ceb6e11..83bb524 100644
--- a/kernel/src/cpu/pic.c
+++ b/kernel/src/cpu/pic.c
@@ -3,22 +3,18 @@
void remap_pic(void)
{
- // save masks
-// uint8_t a1 = inb(PIC1_DATA);
-// uint8_t a2 = inb(PIC2_DATA);
-
// starts the initialization sequence (in cascade mode)
outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4);
outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4);
- outb(PIC1_DATA, 0x20); // ICW2: Master PIC vector offset
- outb(PIC2_DATA, 0x28); // ICW2: Slave PIC vector offset
+ outb(PIC1_DATA, 0xe0); // ICW2: Master PIC vector offset
+ outb(PIC2_DATA, 0xe8); // ICW2: Slave PIC vector offset
outb(PIC1_DATA, 4); // ICW3: tell Master PIC that there is a slave PIC at IRQ2 (0000 0100)
outb(PIC2_DATA, 2); // ICW3: tell Slave PIC its cascade identity (0000 0010)
outb(PIC1_DATA, ICW4_8086);
outb(PIC2_DATA, ICW4_8086);
- // mask interrupts
- outb(PIC1_DATA, 0xfc);
+ // mask all interrupts
+ outb(PIC1_DATA, 0xff);
outb(PIC2_DATA, 0xff);
}
diff --git a/kernel/src/main.c b/kernel/src/main.c
index 31f8117..a14d5ad 100644
--- a/kernel/src/main.c
+++ b/kernel/src/main.c
@@ -46,6 +46,7 @@ int kernel_main(mb2_tag_header* multiboot_bootinfo, uint32_t multiboot_magic)
//print_inode(path_to_inode("/"));
init_tss();
+ list_sys_tables();
parse_madt();
jump_userspace();
diff --git a/kernel/src/mem/paging.c b/kernel/src/mem/paging.c
index 5e248cf..1445410 100644
--- a/kernel/src/mem/paging.c
+++ b/kernel/src/mem/paging.c
@@ -63,7 +63,7 @@ void page_fault(uint64_t error)
uint64_t addr;
__asm__ volatile ("mov %%cr2, %0;" : "=r"(addr) : : "memory");
- printf("address: 0x%x, error code: %d\n", addr, error);
+ printf("address: 0x%x, error code: 0x%x\n", addr, error);
if (error == 7) {
panic("Accessing privileged page in usermode\n");