diff --git a/kernel/inc/drivers/time/pit.h b/kernel/inc/drivers/time/pit.h new file mode 100644 index 0000000..3def178 --- /dev/null +++ b/kernel/inc/drivers/time/pit.h @@ -0,0 +1,26 @@ +/* Copyright (C) Antifallobst + * + * NoxOS is free software: + * you can redistribute it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of the License, + * or (at your option) any later version. + * + * NoxOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + */ + +#ifndef NOX_PIT_H +#define NOX_PIT_H + +#include "utils/stdtypes.h" + +#define PIT_CHANNEL_0_PORT 0x40 +#define PIT_DIVISOR 32768 // This gives an interrupt every ~27.46ms + +void pit_set_divisor(uint16_t divisor); + +#endif //NOX_PIT_H diff --git a/kernel/inc/platform/interrupts.h b/kernel/inc/platform/interrupts.h index aec4a69..cf42567 100644 --- a/kernel/inc/platform/interrupts.h +++ b/kernel/inc/platform/interrupts.h @@ -22,6 +22,43 @@ #define IDT_ENTRY_CALL_GATE 0b10001100 #define IDT_ENTRY_TRAP_GATE 0b10001111 +#define PIC_MASTER_PORT 0x20 +#define PIC_MASTER_COMMAND 0x20 +#define PIC_MASTER_DATA 0x21 +#define PIC_SLAVE_PORT 0xA0 +#define PIC_SLAVE_COMMAND 0xA0 +#define PIC_SLAVE_DATA 0xA1 +#define PIC_END_OF_INTERRUPT 0x20 + +#define ICW1_ICW4 0x01 +#define ICW1_INIT 0x10 +#define ICW4_8086 0x01 + +#define IRQ_MASTER_OFFSET 0x20 +#define IRQ_SLAVE_OFFSET 0x28 + +typedef enum { + // Master PIC + IRQ_PIT, + IRQ_KEYBOARD, + IRQ_CASCADE, + IRQ_COM2, + IRQ_COM1, + IRQ_LPT2, + IRQ_FLOPPY, + IRQ_SPURIOUS, + + // Slave PIC + IRQ_CMOS_RTC, + IRQ_FREE_0, + IRQ_FREE_1, + IRQ_FREE_2, + IRQ_PS2_MOUSE, + IRQ_FPU, + IRQ_ATA_PRIMARY, + IRQ_ATA_SECONDARY +} pic_irq_E; + typedef struct { uint16_t limit; uint64_t offset; @@ -39,6 +76,11 @@ typedef struct { extern idt_register_T g_idt_register; -void idt_init(); +void idt_init (); +void pic_init (); +void pic_remap (); +void pic_send_end_of_interrupt (pic_irq_E irq); +void pic_mask_irq (pic_irq_E irq); +void pic_unmask_irq (pic_irq_E irq); #endif //NOX_INTERRUPTS_H diff --git a/kernel/inc/utils/core.h b/kernel/inc/utils/core.h index 3e9dfd2..4a6cc40 100644 --- a/kernel/inc/utils/core.h +++ b/kernel/inc/utils/core.h @@ -18,8 +18,11 @@ #include "utils/logger.h" -#define CORE_HALT_WHILE(a) while(a) { asm("hlt"); } -#define CORE_HALT_FOREVER log(LOG_WARNING, "!=====[ HALTING SYSTEM ]=====!");\ - while(1) { asm("hlt"); } +#define CORE_HALT_WHILE(a) while(a) { asm("hlt"); } +#define CORE_HALT_FOREVER log(LOG_WARNING, "!=====[ HALTING SYSTEM ]=====!");\ + while(1) { asm("hlt"); } + +#define CORE_INTERRUPTS_ENABLE asm("sti"); +#define CORE_INTERRUPTS_DISABLE asm("cli"); #endif //NOX_CORE_H diff --git a/kernel/src/drivers/time/pit.c b/kernel/src/drivers/time/pit.c new file mode 100644 index 0000000..beb5b9f --- /dev/null +++ b/kernel/src/drivers/time/pit.c @@ -0,0 +1,31 @@ +/* Copyright (C) Antifallobst + * + * NoxOS is free software: + * you can redistribute it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of the License, + * or (at your option) any later version. + * + * NoxOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + */ + +#include "drivers/time/pit.h" +#include "utils/io.h" +#include "utils/logger.h" + +uint16_t g_divisor; + +void pit_set_divisor(uint16_t divisor) { + if (divisor < 100) { divisor = 100; } + + g_divisor = divisor; + + io_out_byte(PIT_CHANNEL_0_PORT, divisor & 0x00FF); io_wait(); + io_out_byte(PIT_CHANNEL_0_PORT, (divisor & 0xFF00) >> 8); + + log(LOG_INFO, "pit -> divisor set to %d", divisor); +} \ No newline at end of file diff --git a/kernel/src/kmain.c b/kernel/src/kmain.c index 8b16783..8cfa1be 100644 --- a/kernel/src/kmain.c +++ b/kernel/src/kmain.c @@ -17,21 +17,27 @@ #include "utils/core.h" #include "utils/memory.h" #include "boot/boot_info.h" -#include "platform/gdt.h" #include "platform/interrupts.h" #include "mm/page_frame.h" #include "mm/page_map.h" +#include "drivers/time/pit.h" void limine_terminal_print(boot_info_T* boot_info, string_t string) { boot_info->terminal->write(boot_info->terminal->terminals[0], string, string_length(string)); } void kernel_init(boot_info_T* boot_info) { - gdt_init(); pframe_manager_init(boot_info); + + CORE_INTERRUPTS_DISABLE idt_init(); + pic_init(); + pit_set_divisor(PIT_DIVISOR); + CORE_INTERRUPTS_ENABLE + paging_init(); memory_allocator_init((void*)0x100000000000); +// scheduler_init(); } void kmain(boot_info_T boot_info) { @@ -41,7 +47,11 @@ void kmain(boot_info_T boot_info) { kernel_init(&boot_info); - void* debug = memory_allocate(1312); + log(LOG_INFO, "!=====[ Kernel Initialized ]=====!\n"); + + asm("int $0x80"); + +// void* debug = memory_allocate(1312); CORE_HALT_FOREVER } diff --git a/kernel/src/platform/interrupts.c b/kernel/src/platform/interrupts.c index 5198a3a..b811375 100644 --- a/kernel/src/platform/interrupts.c +++ b/kernel/src/platform/interrupts.c @@ -19,10 +19,13 @@ #include "platform/exceptions.h" #include "mm/page_frame.h" #include "utils/logger.h" +#include "utils/io.h" idt_register_T g_idt_register; extern void idt_load(idt_register_T* idt_register); + +// Exceptions extern void interrupt_stub_0x00(); extern void interrupt_stub_0x01(); extern void interrupt_stub_0x02(); @@ -56,6 +59,29 @@ extern void interrupt_stub_0x1D(); extern void interrupt_stub_0x1E(); extern void interrupt_stub_0x1F(); +// IRQs on Master PIC +extern void interrupt_stub_0x20(); +extern void interrupt_stub_0x21(); +extern void interrupt_stub_0x22(); +extern void interrupt_stub_0x23(); +extern void interrupt_stub_0x24(); +extern void interrupt_stub_0x25(); +extern void interrupt_stub_0x26(); +extern void interrupt_stub_0x27(); + +// IRQs on Slave PIC +extern void interrupt_stub_0x28(); +extern void interrupt_stub_0x29(); +extern void interrupt_stub_0x2A(); +extern void interrupt_stub_0x2B(); +extern void interrupt_stub_0x2C(); +extern void interrupt_stub_0x2D(); +extern void interrupt_stub_0x2E(); +extern void interrupt_stub_0x2F(); + +// Custom +extern void interrupt_stub_0x80(); + void idt_set_descriptor_entry_offset(idt_descriptor_entry_T* entry, uint64_t offset) { entry->offset0 = (uint16_t) (offset & 0x000000000000ffff); entry->offset1 = (uint16_t) ((offset & 0x00000000ffff0000) >> 16); @@ -81,7 +107,7 @@ void idt_init() { g_idt_register.limit = 0x0FFF; g_idt_register.offset = (uint64_t)pframe_request(); - + // Exceptions idt_set_gate((void*)interrupt_stub_0x00, 0x00, IDT_ENTRY_INTR_GATE, GDT_SELECTOR_KERNEL_CODE); idt_set_gate((void*)interrupt_stub_0x01, 0x01, IDT_ENTRY_INTR_GATE, GDT_SELECTOR_KERNEL_CODE); idt_set_gate((void*)interrupt_stub_0x02, 0x02, IDT_ENTRY_INTR_GATE, GDT_SELECTOR_KERNEL_CODE); @@ -115,16 +141,119 @@ void idt_init() { idt_set_gate((void*)interrupt_stub_0x1E, 0x1E, IDT_ENTRY_INTR_GATE, GDT_SELECTOR_KERNEL_CODE); idt_set_gate((void*)interrupt_stub_0x1F, 0x1F, IDT_ENTRY_INTR_GATE, GDT_SELECTOR_KERNEL_CODE); + // IRQs on Master PIC + idt_set_gate((void*)interrupt_stub_0x20, 0x20, IDT_ENTRY_INTR_GATE, GDT_SELECTOR_KERNEL_CODE); + idt_set_gate((void*)interrupt_stub_0x21, 0x21, IDT_ENTRY_INTR_GATE, GDT_SELECTOR_KERNEL_CODE); + idt_set_gate((void*)interrupt_stub_0x22, 0x22, IDT_ENTRY_INTR_GATE, GDT_SELECTOR_KERNEL_CODE); + idt_set_gate((void*)interrupt_stub_0x23, 0x23, IDT_ENTRY_INTR_GATE, GDT_SELECTOR_KERNEL_CODE); + idt_set_gate((void*)interrupt_stub_0x24, 0x24, IDT_ENTRY_INTR_GATE, GDT_SELECTOR_KERNEL_CODE); + idt_set_gate((void*)interrupt_stub_0x25, 0x25, IDT_ENTRY_INTR_GATE, GDT_SELECTOR_KERNEL_CODE); + idt_set_gate((void*)interrupt_stub_0x26, 0x26, IDT_ENTRY_INTR_GATE, GDT_SELECTOR_KERNEL_CODE); + idt_set_gate((void*)interrupt_stub_0x27, 0x27, IDT_ENTRY_INTR_GATE, GDT_SELECTOR_KERNEL_CODE); + + // IRQs on Slave PIC + idt_set_gate((void*)interrupt_stub_0x28, 0x28, IDT_ENTRY_INTR_GATE, GDT_SELECTOR_KERNEL_CODE); + idt_set_gate((void*)interrupt_stub_0x29, 0x29, IDT_ENTRY_INTR_GATE, GDT_SELECTOR_KERNEL_CODE); + idt_set_gate((void*)interrupt_stub_0x2A, 0x2A, IDT_ENTRY_INTR_GATE, GDT_SELECTOR_KERNEL_CODE); + idt_set_gate((void*)interrupt_stub_0x2B, 0x2B, IDT_ENTRY_INTR_GATE, GDT_SELECTOR_KERNEL_CODE); + idt_set_gate((void*)interrupt_stub_0x2C, 0x2C, IDT_ENTRY_INTR_GATE, GDT_SELECTOR_KERNEL_CODE); + idt_set_gate((void*)interrupt_stub_0x2D, 0x2D, IDT_ENTRY_INTR_GATE, GDT_SELECTOR_KERNEL_CODE); + idt_set_gate((void*)interrupt_stub_0x2E, 0x2E, IDT_ENTRY_INTR_GATE, GDT_SELECTOR_KERNEL_CODE); + idt_set_gate((void*)interrupt_stub_0x2F, 0x2F, IDT_ENTRY_INTR_GATE, GDT_SELECTOR_KERNEL_CODE); + + // Custom + idt_set_gate((void*)interrupt_stub_0x80, 0x80, IDT_ENTRY_INTR_GATE, GDT_SELECTOR_KERNEL_CODE); + idt_load(&g_idt_register); log(LOG_INFO, "Interrupts initialized"); } +void pic_init() { + pic_remap(); + + pic_unmask_irq(IRQ_PIT); +} + +void pic_remap() { + uint8_t master_masks = io_in_byte(PIC_MASTER_DATA); io_wait(); + uint8_t slave_masks = io_in_byte(PIC_SLAVE_DATA); io_wait(); + + io_out_byte(PIC_MASTER_COMMAND, ICW1_INIT | ICW1_ICW4); io_wait(); + io_out_byte(PIC_SLAVE_COMMAND, ICW1_INIT | ICW1_ICW4); io_wait(); + + // set the IRQ offsets + io_out_byte(PIC_MASTER_DATA, 0x20); io_wait(); + io_out_byte(PIC_SLAVE_DATA, 0x28); io_wait(); + + io_out_byte(PIC_MASTER_DATA, 4); io_wait(); + io_out_byte(PIC_SLAVE_DATA, 2); io_wait(); + + io_out_byte(PIC_MASTER_DATA, ICW4_8086); io_wait(); + io_out_byte(PIC_SLAVE_DATA, ICW4_8086); io_wait(); + + io_out_byte(PIC_MASTER_DATA, master_masks); + io_out_byte(PIC_SLAVE_DATA, slave_masks); +} + +void pic_send_end_of_interrupt(pic_irq_E irq) { + if (irq >= 8) { + io_out_byte(PIC_SLAVE_COMMAND, PIC_END_OF_INTERRUPT); + } + io_out_byte(PIC_MASTER_COMMAND, PIC_END_OF_INTERRUPT); +} + +void pic_mask_irq(pic_irq_E irq) { + uint16_t port = PIC_MASTER_DATA; + + if (irq >= 8) { + port = PIC_SLAVE_DATA; + irq -= 8; + } + + uint8_t value = io_in_byte(port) | (1 << irq); + io_out_byte(port, value); +} + +void pic_unmask_irq(pic_irq_E irq) { + uint16_t port = PIC_MASTER_DATA; + + if (irq >= 8) { + port = PIC_SLAVE_DATA; + irq -= 8; + } + + uint8_t value = io_in_byte(port) & ~(1 << irq); + io_out_byte(port, value); +} + +cpu_state_T* irq_handle(cpu_state_T* state, pic_irq_E irq) { + cpu_state_T* return_state = state; + + switch (irq) { + case IRQ_PIT: { + log(LOG_DEBUG, "PIT -> Tick"); + break; + } + default: { + log(LOG_WARNING, "Unhandled IRQ"); + break; + } + } + + pic_send_end_of_interrupt(irq); + return return_state; +} + cpu_state_T* interrupts_handle(cpu_state_T* state) { if (state->interrupt_id < EXCEPTIONS_ENUM_END) { return exception_handle(state); } - log(LOG_WARNING, "Non exception interrupt detected ID: 0x%xb", state->interrupt_id); + if (state->interrupt_id < IRQ_MASTER_OFFSET + 0x10 && state->interrupt_id >= IRQ_MASTER_OFFSET) { + return irq_handle(state, state->interrupt_id - IRQ_MASTER_OFFSET); + } + + log(LOG_WARNING, "Unhandled interrupt: 0x%xb", state->interrupt_id); return state; } diff --git a/kernel/src/platform/x86/interrupts.asm b/kernel/src/platform/x86/interrupts.asm index 82fa5b5..42411d8 100644 --- a/kernel/src/platform/x86/interrupts.asm +++ b/kernel/src/platform/x86/interrupts.asm @@ -24,7 +24,7 @@ interrupt_common_handler: call interrupts_handle mov rsp, rax - ; load cpu_state + ; load page map pop rax mov cr3, rax @@ -90,4 +90,26 @@ interrupt_stub 0x1B interrupt_stub 0x1C interrupt_stub 0x1D interrupt_stub 0x1E -interrupt_stub 0x1F \ No newline at end of file +interrupt_stub 0x1F + +;IRQs +interrupt_stub 0x20 ; PIT +interrupt_stub 0x21 ; Keyboard +interrupt_stub 0x22 ; Cascade +interrupt_stub 0x23 ; COM2 +interrupt_stub 0x24 ; COM1 +interrupt_stub 0x25 ; LPT2 +interrupt_stub 0x26 ; Floppy +interrupt_stub 0x27 ; Spurious + +interrupt_stub 0x28 ; CMOS RTC +interrupt_stub 0x29 ; Free 0 +interrupt_stub 0x2A ; Free 1 +interrupt_stub 0x2B ; Free 2 +interrupt_stub 0x2C ; PS/2 Mouse +interrupt_stub 0x2D ; FPU +interrupt_stub 0x2E ; Primary ATA +interrupt_stub 0x2F ; Secondary ATA + +; Custom +interrupt_stub 0x80 ; Syscall \ No newline at end of file