2 Commits
idt ... time

Author SHA1 Message Date
54f26c506e 1000Hz PIC timer working + IDT dispatch/handler fixes 2025-12-27 13:52:05 +01:00
24d75463b8 Merge pull request #4 from xamidev/idt
Idt
2025-12-22 21:05:42 +01:00
9 changed files with 204 additions and 52 deletions

View File

@@ -1,6 +1,6 @@
build: build:
rm -f *.o rm -f *.o
x86_64-elf-gcc -g -c -I src src/idt/idt.c src/mem/utils.c src/mem/gdt.c src/io/serial.c src/io/term.c src/io/printf.c src/kmain.c -Wall -Wextra -std=gnu99 -nostdlib -ffreestanding -fno-stack-protector -fno-stack-check -fno-PIC -ffunction-sections -fdata-sections -mcmodel=kernel x86_64-elf-gcc -g -c -I src src/time/timer.c src/idt/idt.c src/mem/utils.c src/mem/gdt.c src/io/serial.c src/io/term.c src/io/printf.c src/kmain.c -Wall -Wextra -std=gnu99 -nostdlib -ffreestanding -fno-stack-protector -fno-stack-check -fno-PIC -ffunction-sections -fdata-sections -mcmodel=kernel
objcopy -O elf64-x86-64 -B i386 -I binary zap-light16.psf zap-light16.o objcopy -O elf64-x86-64 -B i386 -I binary zap-light16.psf zap-light16.o
nasm -f elf64 src/idt/idt.S -o idt_stub.o nasm -f elf64 src/idt/idt.S -o idt_stub.o
x86_64-elf-ld -o pepperk -T linker.ld *.o x86_64-elf-ld -o pepperk -T linker.ld *.o

View File

@@ -1,2 +1,3 @@
target remote localhost:1234 target remote localhost:1234
set disassembly-flavor intel set disassembly-flavor intel
display/8i $rip

View File

@@ -34,22 +34,22 @@ interrupt_stub:
; executed when the interrupt happened. ; executed when the interrupt happened.
; (except rsp because it will already be saved in the iret frame) ; (except rsp because it will already be saved in the iret frame)
push rax push qword rax
push rbx push qword rbx
push rcx push qword rcx
push rdx push qword rdx
push rsi push qword rsi
push rdi push qword rdi
push rsp ;push qword rsp
push rbp push qword rbp
push r8 push qword r8
push r9 push qword r9
push r10 push qword r10
push r11 push qword r11
push r12 push qword r12
push r13 push qword r13
push r14 push qword r14
push r15 push qword r15
; Put stack pointer as first argument of our function ; Put stack pointer as first argument of our function
mov rdi, rsp mov rdi, rsp
@@ -57,22 +57,22 @@ interrupt_stub:
; What the function returns (new stack pointer) is saved in rbp ; What the function returns (new stack pointer) is saved in rbp
mov rsp, rax mov rsp, rax
pop r15 pop qword r15
pop r14 pop qword r14
pop r13 pop qword r13
pop r12 pop qword r12
pop r11 pop qword r11
pop r10 pop qword r10
pop r9 pop qword r9
pop r8 pop qword r8
pop rbp pop qword rbp
pop rsp ;pop qword rsp
pop rdi pop qword rdi
pop rsi pop qword rsi
pop rdx pop qword rdx
pop rcx pop qword rcx
pop rbx pop qword rbx
pop rax pop qword rax
; Removing the error code and vector number so stack doesn't ; Removing the error code and vector number so stack doesn't
; get corrupted ; get corrupted
@@ -80,7 +80,7 @@ interrupt_stub:
; Restore ss, rsp, rflags, cs, rip of code that was executing ; Restore ss, rsp, rflags, cs, rip of code that was executing
; before the interrupt ; before the interrupt
iret iretq
; Vector handlers will be 16-byte aligned so that we can loop over them ; Vector handlers will be 16-byte aligned so that we can loop over them
; like <vector_no> * 16 to get each one's address ; like <vector_no> * 16 to get each one's address
@@ -233,4 +233,71 @@ vector_21_handler:
push qword 21 push qword 21
jmp interrupt_stub jmp interrupt_stub
; The others are reserved (22->31) or external (32->255) interrupts ; The others are reserved (22->31) or external (32->255) interrupts
align 16
vector_22_handler:
push qword 0
push qword 22
jmp interrupt_stub
align 16
vector_23_handler:
push qword 0
push qword 23
jmp interrupt_stub
align 16
vector_24_handler:
push qword 0
push qword 24
jmp interrupt_stub
align 16
vector_25_handler:
push qword 0
push qword 25
jmp interrupt_stub
align 16
vector_26_handler:
push qword 0
push qword 26
jmp interrupt_stub
align 16
vector_27_handler:
push qword 0
push qword 27
jmp interrupt_stub
align 16
vector_28_handler:
push qword 0
push qword 28
jmp interrupt_stub
align 16
vector_29_handler:
push qword 0
push qword 29
jmp interrupt_stub
align 16
vector_30_handler:
push qword 0
push qword 30
jmp interrupt_stub
align 16
vector_31_handler:
push qword 0
push qword 31
jmp interrupt_stub
; PIT timer
align 16
vector_32_handler:
push qword 0
push qword 32
jmp interrupt_stub

View File

@@ -9,6 +9,9 @@ struct idtr idt_reg;
// Address to our first interrupt handler // Address to our first interrupt handler
extern char vector_0_handler[]; extern char vector_0_handler[];
// Timer ticks
extern uint64_t ticks;
void idt_set_entry(uint8_t vector, void* handler, uint8_t dpl) void idt_set_entry(uint8_t vector, void* handler, uint8_t dpl)
{ {
uint64_t handler_addr = (uint64_t)handler; uint64_t handler_addr = (uint64_t)handler;
@@ -119,6 +122,13 @@ struct cpu_status_t* interrupt_dispatch(struct cpu_status_t* context)
serial_kputs("kernel: idt: Control Protection Exception!\n"); serial_kputs("kernel: idt: Control Protection Exception!\n");
break; break;
case 32:
serial_kputs("Tick!");
ticks++;
// Send an EOI so that we can continue having interrupts
outb(0x20, 0x20);
break;
default: default:
serial_kputs("kernel: idt: Unexpected interrupt\n"); serial_kputs("kernel: idt: Unexpected interrupt\n");
break; break;

View File

@@ -36,7 +36,7 @@ struct cpu_status_t
uint64_t r9; uint64_t r9;
uint64_t r8; uint64_t r8;
uint64_t rbp; uint64_t rbp;
uint64_t rsp; //uint64_t rsp;
uint64_t rdi; uint64_t rdi;
uint64_t rsi; uint64_t rsi;
uint64_t rdx; uint64_t rdx;

View File

@@ -7,4 +7,7 @@ enum ErrorCodes
EIO EIO
}; };
#define CLEAR_INTERRUPTS __asm__ volatile("cli")
#define SET_INTERRUPTS __asm__ volatile("sti")
#endif #endif

View File

@@ -7,6 +7,8 @@
#include "mem/gdt.h" #include "mem/gdt.h"
#include "mem/utils.h" #include "mem/utils.h"
#include "idt/idt.h" #include "idt/idt.h"
#include "kernel.h"
#include "time/timer.h"
// Limine version used // Limine version used
__attribute__((used, section(".limine_requests"))) __attribute__((used, section(".limine_requests")))
@@ -36,20 +38,6 @@ static void hcf()
} }
} }
static inline void trigger_div0(void)
{
asm volatile (
"mov $1, %%rax\n"
"xor %%rdx, %%rdx\n"
"xor %%rcx, %%rcx\n" // divisor = 0
"idiv %%rcx\n"
:
:
: "rax", "rcx", "rdx"
);
}
// This is our entry point // This is our entry point
void kmain() void kmain()
{ {
@@ -63,12 +51,15 @@ void kmain()
if (serial_init()) kputs("kernel: serial: error: Cannot init serial communication!"); if (serial_init()) kputs("kernel: serial: error: Cannot init serial communication!");
CLEAR_INTERRUPTS;
gdt_init(); gdt_init();
idt_init(); idt_init();
timer_init();
SET_INTERRUPTS;
// Draw something // Draw something
printf("%s, %s!", "Hello", "world"); printf("%s, %s!", "Hello", "world");
trigger_div0(); //printf("%d", 4/0);
hcf(); hcf();
} }

74
src/time/timer.c Normal file
View File

@@ -0,0 +1,74 @@
#include <stdint.h>
#include "../io/serial.h"
/*
For now, the timer module will be using the PIC.
Even though it's quite old, it's still supported by newer CPUs
and it will be precise enough for what we'll do. Also it's easier
to implement than ACPI etc. (we may upgrade to ACPI when we're
interested in multi-core functionnality like SMP)
*/
volatile uint64_t ticks = 0;
void pic_remap()
{
uint8_t master_mask = inb(0x21);
uint8_t slave_mask = inb(0xA1);
// ICW1: start initialization
outb(0x20, 0x11);
outb(0xA0, 0x11);
// ICW2: vector offsets
outb(0x21, 0x20); // Master PIC -> 0x20
outb(0xA1, 0x28); // Slave PIC -> 0x28
// ICW3: tell Master about Slave at IRQ2 (0000 0100)
outb(0x21, 0x04);
// ICW3: tell Slave its cascade identity (0000 0010)
outb(0xA1, 0x02);
// ICW4: 8086 mode
outb(0x21, 0x01);
outb(0xA1, 0x01);
// Restore saved masks
outb(0x21, master_mask);
outb(0xA1, slave_mask);
}
void pic_enable()
{
// Enabling IRQ0 (unmasking it) but not the others
uint8_t mask = inb(0x21);
mask &= ~(1 << 0); // Clear bit 0 (IRQ0)
outb(0x21, mask);
}
/*
Base frequency = 1.193182 MHz
1 tick per ms (divide by 1000) = roughly 1193 Hz
*/
void pit_init()
{
uint32_t frequency = 1000; // 1 kHz
uint32_t divisor = 1193182 / frequency;
// Set PIT to mode 3, channel 0
outb(0x43, 0x36); // 0x36
// Send divisor (low byte, then high byte)
outb(0x40, divisor & 0xFF);
outb(0x40, (divisor >> 8) & 0xFF);
}
void timer_init()
{
// Remapping the PIC, because at startup it conflicts with
// the reserved IRQs we have for faults/exceptions etc.
// so we move its IRQ0 to something not reserved (32)
pic_remap();
pic_enable();
pit_init();
}

6
src/time/timer.h Normal file
View File

@@ -0,0 +1,6 @@
#ifndef TIMER_H
#define TIMER_H
void timer_init();
#endif