1000Hz PIC timer working + IDT dispatch/handler fixes
This commit is contained in:
2
Makefile
2
Makefile
@@ -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
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
target remote localhost:1234
|
target remote localhost:1234
|
||||||
set disassembly-flavor intel
|
set disassembly-flavor intel
|
||||||
|
display/8i $rip
|
||||||
135
src/idt/idt.S
135
src/idt/idt.S
@@ -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
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -7,4 +7,7 @@ enum ErrorCodes
|
|||||||
EIO
|
EIO
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define CLEAR_INTERRUPTS __asm__ volatile("cli")
|
||||||
|
#define SET_INTERRUPTS __asm__ volatile("sti")
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
21
src/kmain.c
21
src/kmain.c
@@ -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
74
src/time/timer.c
Normal 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
6
src/time/timer.h
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#ifndef TIMER_H
|
||||||
|
#define TIMER_H
|
||||||
|
|
||||||
|
void timer_init();
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user