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:
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
nasm -f elf64 src/idt/idt.S -o idt_stub.o
x86_64-elf-ld -o pepperk -T linker.ld *.o

View File

@@ -1,2 +1,3 @@
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.
; (except rsp because it will already be saved in the iret frame)
push rax
push rbx
push rcx
push rdx
push rsi
push rdi
push rsp
push rbp
push r8
push r9
push r10
push r11
push r12
push r13
push r14
push r15
push qword rax
push qword rbx
push qword rcx
push qword rdx
push qword rsi
push qword rdi
;push qword rsp
push qword rbp
push qword r8
push qword r9
push qword r10
push qword r11
push qword r12
push qword r13
push qword r14
push qword r15
; Put stack pointer as first argument of our function
mov rdi, rsp
@@ -57,22 +57,22 @@ interrupt_stub:
; What the function returns (new stack pointer) is saved in rbp
mov rsp, rax
pop r15
pop r14
pop r13
pop r12
pop r11
pop r10
pop r9
pop r8
pop rbp
pop rsp
pop rdi
pop rsi
pop rdx
pop rcx
pop rbx
pop rax
pop qword r15
pop qword r14
pop qword r13
pop qword r12
pop qword r11
pop qword r10
pop qword r9
pop qword r8
pop qword rbp
;pop qword rsp
pop qword rdi
pop qword rsi
pop qword rdx
pop qword rcx
pop qword rbx
pop qword rax
; Removing the error code and vector number so stack doesn't
; get corrupted
@@ -80,7 +80,7 @@ interrupt_stub:
; Restore ss, rsp, rflags, cs, rip of code that was executing
; before the interrupt
iret
iretq
; Vector handlers will be 16-byte aligned so that we can loop over them
; like <vector_no> * 16 to get each one's address
@@ -233,4 +233,71 @@ vector_21_handler:
push qword 21
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
extern char vector_0_handler[];
// Timer ticks
extern uint64_t ticks;
void idt_set_entry(uint8_t vector, void* handler, uint8_t dpl)
{
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");
break;
case 32:
serial_kputs("Tick!");
ticks++;
// Send an EOI so that we can continue having interrupts
outb(0x20, 0x20);
break;
default:
serial_kputs("kernel: idt: Unexpected interrupt\n");
break;

View File

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

View File

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

View File

@@ -7,6 +7,8 @@
#include "mem/gdt.h"
#include "mem/utils.h"
#include "idt/idt.h"
#include "kernel.h"
#include "time/timer.h"
// Limine version used
__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
void kmain()
{
@@ -63,12 +51,15 @@ void kmain()
if (serial_init()) kputs("kernel: serial: error: Cannot init serial communication!");
CLEAR_INTERRUPTS;
gdt_init();
idt_init();
timer_init();
SET_INTERRUPTS;
// Draw something
printf("%s, %s!", "Hello", "world");
trigger_div0();
//printf("%d", 4/0);
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