Compare commits
18 Commits
gdt
...
cf4915d9f4
| Author | SHA1 | Date | |
|---|---|---|---|
|
cf4915d9f4
|
|||
| 834891fd2a | |||
| 3853a1ace3 | |||
| ead0ed6ae1 | |||
| fabe0b1a10 | |||
| b886f03f7a | |||
| 4607b5aba5 | |||
| cc36c768cf | |||
| dbd068e55a | |||
| 53fb22cecd | |||
| 54f26c506e | |||
| bb556709d8 | |||
| 24d75463b8 | |||
| 42fc169e10 | |||
| d0b4da0596 | |||
| 0031c2fe03 | |||
| 282a423387 | |||
| c43be0bddd |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -4,3 +4,6 @@ pepperk
|
|||||||
iso_root
|
iso_root
|
||||||
*.o
|
*.o
|
||||||
*.iso
|
*.iso
|
||||||
|
*.gch
|
||||||
|
*/*.gch
|
||||||
|
*/*/*.gch
|
||||||
5
Makefile
5
Makefile
@@ -1,7 +1,10 @@
|
|||||||
|
SOURCES = src/io/kbd/ps2.c src/io/serial/serial.c src/io/term/printf.c src/io/term/term.c src/idt/idt.c src/mem/gdt/gdt.c src/mem/misc/utils.c src/time/timer.c src/kmain.c
|
||||||
|
|
||||||
build:
|
build:
|
||||||
rm -f *.o
|
rm -f *.o
|
||||||
x86_64-elf-gcc -g -c -I src src/mem/utils.h 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 $(SOURCES) -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
|
||||||
x86_64-elf-ld -o pepperk -T linker.ld *.o
|
x86_64-elf-ld -o pepperk -T linker.ld *.o
|
||||||
|
|
||||||
limine/limine:
|
limine/limine:
|
||||||
|
|||||||
21
README.md
21
README.md
@@ -1,4 +1,4 @@
|
|||||||
# pepperOS: "will never be done"
|
# <img width="40" height="40" alt="red-pepper" src="https://i.ibb.co/mrHH6d1m/pixil-frame-0-4.png" /> pepperOS: "will never be done"
|
||||||
|
|
||||||
## Trying the kernel
|
## Trying the kernel
|
||||||
|
|
||||||
@@ -7,6 +7,25 @@ First install the dependencies: `sudo apt install xorriso make qemu-system`
|
|||||||
Then, to compile the kernel and make an ISO image file: `make build-iso`
|
Then, to compile the kernel and make an ISO image file: `make build-iso`
|
||||||
To run it with QEMU, `make run`
|
To run it with QEMU, `make run`
|
||||||
|
|
||||||
|
## TODO
|
||||||
|
|
||||||
|
The basics that I'm targeting are:
|
||||||
|
|
||||||
|
- Fix terminal driver (backspace issues, scrolling) OR add Flanterm or equivalent
|
||||||
|
- Implement paging / see what Limine does at boot with memory management
|
||||||
|
- Implement tasks, and task switching
|
||||||
|
- Load an executable
|
||||||
|
- Scheduler (round-robin using the PIT timer interrupt)
|
||||||
|
- Filesystem (TAR for read-only initfs, then maybe read-write using FAT12/16/32
|
||||||
|
- Getting to userspace (syscalls)
|
||||||
|
- Porting musl libc or equivalent
|
||||||
|
|
||||||
|
In the future, maybe?
|
||||||
|
|
||||||
|
- SMP support
|
||||||
|
- Parsing the ACPI tables and using them for something
|
||||||
|
- Replacing the PIT timer with APIC
|
||||||
|
|
||||||
## Thanks
|
## Thanks
|
||||||
|
|
||||||
PepperOS wouldn't be possible without the following freely-licensed software:
|
PepperOS wouldn't be possible without the following freely-licensed software:
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
target remote localhost:1234
|
target remote localhost:1234
|
||||||
set disassembly-flavor intel
|
set disassembly-flavor intel
|
||||||
|
display/8i $rip
|
||||||
310
src/idt/idt.S
Normal file
310
src/idt/idt.S
Normal file
@@ -0,0 +1,310 @@
|
|||||||
|
; Assembly stub for the IDT
|
||||||
|
|
||||||
|
bits 64
|
||||||
|
|
||||||
|
extern interrupt_dispatch
|
||||||
|
|
||||||
|
global interrupt_stub
|
||||||
|
global vector_0_handler
|
||||||
|
global vector_1_handler
|
||||||
|
global vector_2_handler
|
||||||
|
global vector_3_handler
|
||||||
|
global vector_4_handler
|
||||||
|
global vector_5_handler
|
||||||
|
global vector_6_handler
|
||||||
|
global vector_7_handler
|
||||||
|
global vector_8_handler
|
||||||
|
global vector_9_handler
|
||||||
|
global vector_10_handler
|
||||||
|
global vector_11_handler
|
||||||
|
global vector_12_handler
|
||||||
|
global vector_13_handler
|
||||||
|
global vector_14_handler
|
||||||
|
global vector_15_handler
|
||||||
|
global vector_16_handler
|
||||||
|
global vector_17_handler
|
||||||
|
global vector_18_handler
|
||||||
|
global vector_19_handler
|
||||||
|
global vector_20_handler
|
||||||
|
global vector_21_handler
|
||||||
|
|
||||||
|
interrupt_stub:
|
||||||
|
; We'll push all general-purpose registers to the stack,
|
||||||
|
; so they're intact and don't bother the code that was
|
||||||
|
; executed when the interrupt happened.
|
||||||
|
; (except rsp because it will already be saved in the iret frame)
|
||||||
|
|
||||||
|
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
|
||||||
|
call interrupt_dispatch
|
||||||
|
; What the function returns (new stack pointer) is saved in rbp
|
||||||
|
mov rsp, 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
|
||||||
|
add rsp, 16
|
||||||
|
|
||||||
|
; Restore ss, rsp, rflags, cs, rip of code that was executing
|
||||||
|
; before the interrupt
|
||||||
|
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
|
||||||
|
|
||||||
|
; Divide Error
|
||||||
|
align 16
|
||||||
|
vector_0_handler:
|
||||||
|
; error code (nothing, so we push a dummy 0 quadword, 64bits/8bytes long)
|
||||||
|
push qword 0
|
||||||
|
; vector number (so our interrupt stub knows which one it is)
|
||||||
|
push qword 0
|
||||||
|
jmp interrupt_stub
|
||||||
|
|
||||||
|
; Debug Exception
|
||||||
|
align 16
|
||||||
|
vector_1_handler:
|
||||||
|
push qword 0
|
||||||
|
push qword 1
|
||||||
|
jmp interrupt_stub
|
||||||
|
|
||||||
|
; NMI
|
||||||
|
align 16
|
||||||
|
vector_2_handler:
|
||||||
|
push qword 0
|
||||||
|
push qword 2
|
||||||
|
jmp interrupt_stub
|
||||||
|
|
||||||
|
; Breakpoint
|
||||||
|
align 16
|
||||||
|
vector_3_handler:
|
||||||
|
push qword 0
|
||||||
|
push qword 3
|
||||||
|
jmp interrupt_stub
|
||||||
|
|
||||||
|
; Overflow
|
||||||
|
align 16
|
||||||
|
vector_4_handler:
|
||||||
|
push qword 0
|
||||||
|
push qword 4
|
||||||
|
jmp interrupt_stub
|
||||||
|
|
||||||
|
; BOUND Range exceeded
|
||||||
|
align 16
|
||||||
|
vector_5_handler:
|
||||||
|
push qword 0
|
||||||
|
push qword 5
|
||||||
|
jmp interrupt_stub
|
||||||
|
|
||||||
|
; Invalid Opcode
|
||||||
|
align 16
|
||||||
|
vector_6_handler:
|
||||||
|
push qword 0
|
||||||
|
push qword 6
|
||||||
|
jmp interrupt_stub
|
||||||
|
|
||||||
|
; Device Not Available
|
||||||
|
align 16
|
||||||
|
vector_7_handler:
|
||||||
|
push qword 0
|
||||||
|
push qword 7
|
||||||
|
jmp interrupt_stub
|
||||||
|
|
||||||
|
; Double Fault
|
||||||
|
align 16
|
||||||
|
vector_8_handler:
|
||||||
|
; No error code, we only push vector number
|
||||||
|
push qword 1
|
||||||
|
jmp interrupt_stub
|
||||||
|
|
||||||
|
; Coprocessor Segment Overrun
|
||||||
|
align 16
|
||||||
|
vector_9_handler:
|
||||||
|
push qword 9
|
||||||
|
jmp interrupt_stub
|
||||||
|
|
||||||
|
; Invalid TSS
|
||||||
|
align 16
|
||||||
|
vector_10_handler:
|
||||||
|
push qword 10
|
||||||
|
jmp interrupt_stub
|
||||||
|
|
||||||
|
; Segment Not Present
|
||||||
|
align 16
|
||||||
|
vector_11_handler:
|
||||||
|
push qword 11
|
||||||
|
jmp interrupt_stub
|
||||||
|
|
||||||
|
; Stack-Segment Fault
|
||||||
|
align 16
|
||||||
|
vector_12_handler:
|
||||||
|
push qword 12
|
||||||
|
jmp interrupt_stub
|
||||||
|
|
||||||
|
; General Protection
|
||||||
|
align 16
|
||||||
|
vector_13_handler:
|
||||||
|
push qword 13
|
||||||
|
jmp interrupt_stub
|
||||||
|
|
||||||
|
; Page Fault
|
||||||
|
align 16
|
||||||
|
vector_14_handler:
|
||||||
|
push qword 14
|
||||||
|
jmp interrupt_stub
|
||||||
|
|
||||||
|
; Intel reserved
|
||||||
|
align 16
|
||||||
|
vector_15_handler:
|
||||||
|
push qword 0
|
||||||
|
push qword 15
|
||||||
|
jmp interrupt_stub
|
||||||
|
|
||||||
|
; x87 FPU Floating-Point Error
|
||||||
|
align 16
|
||||||
|
vector_16_handler:
|
||||||
|
push qword 0
|
||||||
|
push qword 16
|
||||||
|
jmp interrupt_stub
|
||||||
|
|
||||||
|
; Alignment Check
|
||||||
|
align 16
|
||||||
|
vector_17_handler:
|
||||||
|
push qword 17
|
||||||
|
jmp interrupt_stub
|
||||||
|
|
||||||
|
; Machine Check
|
||||||
|
align 16
|
||||||
|
vector_18_handler:
|
||||||
|
push qword 0
|
||||||
|
push qword 18
|
||||||
|
jmp interrupt_stub
|
||||||
|
|
||||||
|
; SIMD Floating-Point Exception
|
||||||
|
align 16
|
||||||
|
vector_19_handler:
|
||||||
|
push qword 0
|
||||||
|
push qword 19
|
||||||
|
jmp interrupt_stub
|
||||||
|
|
||||||
|
; Virtualization Exception
|
||||||
|
align 16
|
||||||
|
vector_20_handler:
|
||||||
|
push qword 0
|
||||||
|
push qword 20
|
||||||
|
jmp interrupt_stub
|
||||||
|
|
||||||
|
; Control Protection Exception
|
||||||
|
align 16
|
||||||
|
vector_21_handler:
|
||||||
|
push qword 21
|
||||||
|
jmp interrupt_stub
|
||||||
|
|
||||||
|
; 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
|
||||||
|
|
||||||
|
; PS/2 Keyboard
|
||||||
|
align 16
|
||||||
|
vector_33_handler:
|
||||||
|
push qword 0
|
||||||
|
push qword 33
|
||||||
|
jmp interrupt_stub
|
||||||
144
src/idt/idt.c
Normal file
144
src/idt/idt.c
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
#include "idt.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "../io/serial/serial.h"
|
||||||
|
#include "../io/kbd/ps2.h"
|
||||||
|
#include <kernel.h>
|
||||||
|
|
||||||
|
struct interrupt_descriptor idt[256];
|
||||||
|
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;
|
||||||
|
|
||||||
|
struct interrupt_descriptor* entry = &idt[vector];
|
||||||
|
// Address is split in three parts so we right-shift progressively to get it all
|
||||||
|
entry->address_low = handler_addr & 0xFFFF;
|
||||||
|
entry->address_mid = (handler_addr >> 16) & 0xFFFF;
|
||||||
|
entry->address_high = handler_addr >> 32;
|
||||||
|
|
||||||
|
// Kernel code selector (as set in GDT)
|
||||||
|
entry->selector = 0x8;
|
||||||
|
// Interrupt gate, present, DPL (having: max DPL = 3)
|
||||||
|
entry->flags = 0b1110 | ((dpl & 0b11) << 5) | (1 << 7);
|
||||||
|
// We won't use IST for now
|
||||||
|
entry->ist = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void idt_load(void* idt_addr)
|
||||||
|
{
|
||||||
|
// "limit" = "size" = Size of the IDT - 1 byte = (16*256)-1 = 0xFFF
|
||||||
|
idt_reg.limit = 0xFFF;
|
||||||
|
idt_reg.base = (uint64_t)idt_addr;
|
||||||
|
asm volatile("lidt %0" :: "m"(idt_reg));
|
||||||
|
}
|
||||||
|
|
||||||
|
void idt_init()
|
||||||
|
{
|
||||||
|
// We set 256 entries, but we have only the first few stubs.
|
||||||
|
// Undefined behavior?
|
||||||
|
for (size_t i=0; i<256; i++)
|
||||||
|
{
|
||||||
|
// Each vector handler is 16-byte aligned, so <vector_no>*16 = address of that handler
|
||||||
|
idt_set_entry(i, vector_0_handler + (i*16), 0);
|
||||||
|
}
|
||||||
|
idt_load(&idt);
|
||||||
|
DEBUG("IDT initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct cpu_status_t* interrupt_dispatch(struct cpu_status_t* context)
|
||||||
|
{
|
||||||
|
switch(context->vector_number)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
DEBUG("Divide Error!");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
DEBUG("Debug Exception!");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
DEBUG("NMI Interrupt!");
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
DEBUG("Breakpoint Interrupt!");
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
DEBUG("Overflow Trap!");
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
DEBUG("BOUND Range Exceeded!");
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
DEBUG("Invalid Opcode!");
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
DEBUG("Device Not Available!");
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
DEBUG("Double Fault!");
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
DEBUG("Coprocessor Segment Overrun!");
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
DEBUG("Invalid TSS!");
|
||||||
|
break;
|
||||||
|
case 11:
|
||||||
|
DEBUG("Segment Not Present!");
|
||||||
|
break;
|
||||||
|
case 12:
|
||||||
|
DEBUG("Stack-Segment Fault!");
|
||||||
|
break;
|
||||||
|
case 13:
|
||||||
|
DEBUG("General Protection Fault!");
|
||||||
|
break;
|
||||||
|
case 14:
|
||||||
|
DEBUG("Page Fault!");
|
||||||
|
break;
|
||||||
|
case 15:
|
||||||
|
DEBUG("Intel Reserved Interrupt! (Achievement unlocked: How Did We Get Here?)");
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
DEBUG("x87 Floating-Point Error!");
|
||||||
|
break;
|
||||||
|
case 17:
|
||||||
|
DEBUG("Alignment Check Fault!");
|
||||||
|
break;
|
||||||
|
case 18:
|
||||||
|
DEBUG("Machine Check!");
|
||||||
|
break;
|
||||||
|
case 19:
|
||||||
|
DEBUG("SIMD Floating-Point Exception!");
|
||||||
|
break;
|
||||||
|
case 20:
|
||||||
|
DEBUG("Virtualization Exception!");
|
||||||
|
break;
|
||||||
|
case 21:
|
||||||
|
DEBUG("Control Protection Exception!");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 32:
|
||||||
|
//DEBUG("Tick!");
|
||||||
|
ticks++;
|
||||||
|
// Send an EOI so that we can continue having interrupts
|
||||||
|
outb(0x20, 0x20);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 33:
|
||||||
|
keyboard_handler();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
DEBUG("Unexpected interrupt");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return context;
|
||||||
|
}
|
||||||
57
src/idt/idt.h
Normal file
57
src/idt/idt.h
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
#ifndef IDT_H
|
||||||
|
#define IDT_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void idt_init();
|
||||||
|
|
||||||
|
struct interrupt_descriptor
|
||||||
|
{
|
||||||
|
uint16_t address_low;
|
||||||
|
uint16_t selector;
|
||||||
|
uint8_t ist;
|
||||||
|
uint8_t flags;
|
||||||
|
uint16_t address_mid;
|
||||||
|
uint32_t address_high;
|
||||||
|
uint32_t reserved;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct idtr
|
||||||
|
{
|
||||||
|
uint16_t limit;
|
||||||
|
uint64_t base;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
// All general-purpose registers (except rsp) as stored on the stack,
|
||||||
|
// plus the values we pushed (vector number, error code) and the iret frame
|
||||||
|
// In reverse order because the stack grows downwards.
|
||||||
|
struct cpu_status_t
|
||||||
|
{
|
||||||
|
uint64_t r15;
|
||||||
|
uint64_t r14;
|
||||||
|
uint64_t r13;
|
||||||
|
uint64_t r12;
|
||||||
|
uint64_t r11;
|
||||||
|
uint64_t r10;
|
||||||
|
uint64_t r9;
|
||||||
|
uint64_t r8;
|
||||||
|
uint64_t rbp;
|
||||||
|
//uint64_t rsp;
|
||||||
|
uint64_t rdi;
|
||||||
|
uint64_t rsi;
|
||||||
|
uint64_t rdx;
|
||||||
|
uint64_t rcx;
|
||||||
|
uint64_t rbx;
|
||||||
|
uint64_t rax;
|
||||||
|
|
||||||
|
uint64_t vector_number;
|
||||||
|
uint64_t error_code;
|
||||||
|
|
||||||
|
uint64_t iret_rip;
|
||||||
|
uint64_t iret_cs;
|
||||||
|
uint64_t iret_flags;
|
||||||
|
uint64_t iret_rsp;
|
||||||
|
uint64_t iret_ss;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
237
src/io/kbd/ps2.c
Normal file
237
src/io/kbd/ps2.c
Normal file
@@ -0,0 +1,237 @@
|
|||||||
|
// PS/2 Keyboard support
|
||||||
|
|
||||||
|
#include "../serial/serial.h"
|
||||||
|
#include "ps2.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "../term/term.h"
|
||||||
|
#include <kernel.h>
|
||||||
|
|
||||||
|
// The key status bitfield will be used to see if ALT, CONTROL, or SHIFT is pressed
|
||||||
|
uint8_t key_status = 0b00000000;
|
||||||
|
|
||||||
|
// Keymap pointers so we can change between different layouts
|
||||||
|
unsigned char* keymap;
|
||||||
|
unsigned char* keymap_shifted;
|
||||||
|
|
||||||
|
unsigned char kbdus[128] =
|
||||||
|
{
|
||||||
|
0, 27, '1', '2', '3', '4', '5', '6', '7', '8', /* 9 */
|
||||||
|
'9', '0', '-', '=', '\b', /* Backspace */
|
||||||
|
'\t', /* Tab */
|
||||||
|
'q', 'w', 'e', 'r', /* 19 */
|
||||||
|
't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', /* Enter key */
|
||||||
|
CTRL, /* 29 - Control */
|
||||||
|
'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', /* 39 */
|
||||||
|
'\'', '`', SHIFT, /* Left shift */
|
||||||
|
'\\', 'z', 'x', 'c', 'v', 'b', 'n', /* 49 */
|
||||||
|
'm', ',', '.', '/', SHIFT, /* Right shift */
|
||||||
|
'*',
|
||||||
|
ALT, /* Alt */
|
||||||
|
' ', /* Space bar */
|
||||||
|
0, /* Caps lock */
|
||||||
|
0, /* 59 - F1 key ... > */
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, /* < ... F10 */
|
||||||
|
0, /* 69 - Num lock*/
|
||||||
|
0, /* Scroll Lock */
|
||||||
|
0, /* Home key */
|
||||||
|
0, /* Up Arrow */
|
||||||
|
0, /* Page Up */
|
||||||
|
'-',
|
||||||
|
0, /* Left Arrow */
|
||||||
|
0,
|
||||||
|
0, /* Right Arrow */
|
||||||
|
'+',
|
||||||
|
0, /* 79 - End key*/
|
||||||
|
0, /* Down Arrow */
|
||||||
|
0, /* Page Down */
|
||||||
|
0, /* Insert Key */
|
||||||
|
0, /* Delete Key */
|
||||||
|
0, 0, 0,
|
||||||
|
0, /* F11 Key */
|
||||||
|
0, /* F12 Key */
|
||||||
|
0, /* All other keys are undefined */
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned char kbdus_shifted[128] =
|
||||||
|
{
|
||||||
|
0, 27, '!', '@', '#', '$', '%', '^', '&', '*', /* 9 */
|
||||||
|
'(', ')', '_', '+', '\b', /* Backspace */
|
||||||
|
'\t', /* Tab */
|
||||||
|
'Q', 'W', 'E', 'R', /* 19 */
|
||||||
|
'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n', /* Enter */
|
||||||
|
CTRL, /* 29 */
|
||||||
|
'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', /* 39 */
|
||||||
|
'"', '~', SHIFT, /* Left shift */
|
||||||
|
'|', 'Z', 'X', 'C', 'V', 'B', 'N', /* 49 */
|
||||||
|
'M', '<', '>', '?', SHIFT, /* Right shift */
|
||||||
|
'*',
|
||||||
|
ALT, /* Alt */
|
||||||
|
' ', /* Space */
|
||||||
|
0, /* Caps lock */
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, /* F10 */
|
||||||
|
0, /* Num lock */
|
||||||
|
0, /* Scroll lock */
|
||||||
|
0, 0, 0,
|
||||||
|
'-',
|
||||||
|
0, 0, 0,
|
||||||
|
'+',
|
||||||
|
0, 0, 0,
|
||||||
|
0, 0,
|
||||||
|
0, 0, 0,
|
||||||
|
0, /* F11 */
|
||||||
|
0 /* F12 */
|
||||||
|
};
|
||||||
|
|
||||||
|
// NOT THE REAL FR KEYMAP!!
|
||||||
|
// Some French keys have accents or weird symbols that aren't part of ASCII
|
||||||
|
// so they won't fit in 1 char. As a substitute for now, these will be
|
||||||
|
// changed to their ASCII counterparts (without accents, etc.)
|
||||||
|
unsigned char kbdfr[128] =
|
||||||
|
{
|
||||||
|
0, 27, '&', 'e', '"', '\'', '(', '-', 'e', '_',
|
||||||
|
'c', 'a', ')', '=', '\b',
|
||||||
|
'\t',
|
||||||
|
'a', 'z', 'e', 'r',
|
||||||
|
't', 'y', 'u', 'i', 'o', 'p', '^', '$', '\n',
|
||||||
|
CTRL,
|
||||||
|
'q', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm',
|
||||||
|
'u', '`', SHIFT,
|
||||||
|
'*', 'w', 'x', 'c', 'v', 'b', 'n',
|
||||||
|
',', ';', ':', '!', SHIFT,
|
||||||
|
'*',
|
||||||
|
ALT,
|
||||||
|
' ',
|
||||||
|
0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0, 0, 0,
|
||||||
|
'-',
|
||||||
|
0, 0, 0,
|
||||||
|
'+',
|
||||||
|
0, 0, 0,
|
||||||
|
0, 0,
|
||||||
|
0, 0, 0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned char kbdfr_shifted[128] =
|
||||||
|
{
|
||||||
|
0, 27, '1', '2', '3', '4', '5', '6', '7', '8',
|
||||||
|
'9', '0', '^', '+', '\b',
|
||||||
|
'\t',
|
||||||
|
'A', 'Z', 'E', 'R',
|
||||||
|
'T', 'Y', 'U', 'I', 'O', 'P', '^', 'L', '\n',
|
||||||
|
CTRL,
|
||||||
|
'Q', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M',
|
||||||
|
'%', '~', SHIFT,
|
||||||
|
'u', 'W', 'X', 'C', 'V', 'B', 'N',
|
||||||
|
'?', '.', '/', 'S', SHIFT,
|
||||||
|
'*',
|
||||||
|
ALT,
|
||||||
|
' ',
|
||||||
|
0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0, 0, 0,
|
||||||
|
'-',
|
||||||
|
0, 0, 0,
|
||||||
|
'+',
|
||||||
|
0, 0, 0,
|
||||||
|
0, 0,
|
||||||
|
0, 0, 0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
void keyboard_handler()
|
||||||
|
{
|
||||||
|
unsigned char scancode = inb(0x60);
|
||||||
|
|
||||||
|
// Key release (bit 7 set)
|
||||||
|
if (scancode & 0x80)
|
||||||
|
{
|
||||||
|
unsigned char code = scancode & 0x7F;
|
||||||
|
switch (code)
|
||||||
|
{
|
||||||
|
// Clear the corresponding bit if corresponding key is released
|
||||||
|
case LEFT_SHIFT_PRESSED:
|
||||||
|
case RIGHT_SHIFT_PRESSED:
|
||||||
|
key_status &= ~SHIFT_PRESSED_BIT;
|
||||||
|
break;
|
||||||
|
case CTRL_PRESSED:
|
||||||
|
key_status &= ~CTRL_PRESSED_BIT;
|
||||||
|
break;
|
||||||
|
case ALT_PRESSED:
|
||||||
|
key_status &= ~ALT_PRESSED_BIT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send EOI
|
||||||
|
outb(0x20, 0x20);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Key press
|
||||||
|
switch (scancode)
|
||||||
|
{
|
||||||
|
// Set bits for corresponding special key press
|
||||||
|
case LEFT_SHIFT_PRESSED:
|
||||||
|
case RIGHT_SHIFT_PRESSED:
|
||||||
|
key_status |= SHIFT_PRESSED_BIT;
|
||||||
|
break;
|
||||||
|
case CTRL_PRESSED:
|
||||||
|
key_status |= CTRL_PRESSED_BIT;
|
||||||
|
break;
|
||||||
|
case ALT_PRESSED:
|
||||||
|
key_status |= ALT_PRESSED_BIT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Should we get a SHIFTED char or a regular one?
|
||||||
|
unsigned char c = (key_status & SHIFT_PRESSED_BIT) ? keymap_shifted[scancode] : keymap[scancode];
|
||||||
|
|
||||||
|
if (c)
|
||||||
|
{
|
||||||
|
putchar(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
skputs("key pressed!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// End of Interrupt (to master PIC)
|
||||||
|
outb(0x20, 0x20);
|
||||||
|
}
|
||||||
|
|
||||||
|
void keyboard_init(unsigned char layout)
|
||||||
|
{
|
||||||
|
// Here we might go and select PS/2, USB, or other... (once we implement multiple keyboard protocols)
|
||||||
|
|
||||||
|
// Keyboard layout selection
|
||||||
|
switch (layout)
|
||||||
|
{
|
||||||
|
case US:
|
||||||
|
keymap = kbdus;
|
||||||
|
keymap_shifted = kbdus_shifted;
|
||||||
|
break;
|
||||||
|
case FR:
|
||||||
|
keymap = kbdfr;
|
||||||
|
keymap_shifted = kbdfr_shifted;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
skputs("Unsupported layout.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DEBUG("PS/2 Keyboard initialized");
|
||||||
|
}
|
||||||
37
src/io/kbd/ps2.h
Normal file
37
src/io/kbd/ps2.h
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
#ifndef PS2_H
|
||||||
|
#define PS2_H
|
||||||
|
|
||||||
|
void keyboard_handler();
|
||||||
|
|
||||||
|
#define SHIFT_PRESSED_BIT 0b00000001
|
||||||
|
#define ALT_PRESSED_BIT 0b00000010
|
||||||
|
#define CTRL_PRESSED_BIT 0b00000100
|
||||||
|
|
||||||
|
enum SpecialKeys
|
||||||
|
{
|
||||||
|
SHIFT = 255,
|
||||||
|
ALT = 254,
|
||||||
|
CTRL = 253
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SpecialScancodes
|
||||||
|
{
|
||||||
|
LEFT_SHIFT_PRESSED = 0x2A,
|
||||||
|
LEFT_SHIFT_RELEASED = 0xAA,
|
||||||
|
RIGHT_SHIFT_PRESSED = 0x36,
|
||||||
|
RIGHT_SHIFT_RELEASED = 0xB6,
|
||||||
|
CTRL_PRESSED = 0x1D,
|
||||||
|
CTRL_RELEASED = 0x9D,
|
||||||
|
ALT_PRESSED = 0x38,
|
||||||
|
ALT_RELEASED = 0xB8
|
||||||
|
};
|
||||||
|
|
||||||
|
enum KeyboardLayout
|
||||||
|
{
|
||||||
|
US,
|
||||||
|
FR
|
||||||
|
};
|
||||||
|
|
||||||
|
void keyboard_init(unsigned char layout);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "../kernel.h"
|
#include <kernel.h>
|
||||||
|
#include "serial.h"
|
||||||
|
|
||||||
void outb(int port, unsigned char data)
|
void outb(int port, unsigned char data)
|
||||||
{
|
{
|
||||||
@@ -34,6 +35,8 @@ int serial_init()
|
|||||||
|
|
||||||
// Set normal operation mode
|
// Set normal operation mode
|
||||||
outb(PORT + 4, 0x0F);
|
outb(PORT + 4, 0x0F);
|
||||||
|
|
||||||
|
DEBUG("serial initialized");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,18 +45,20 @@ static int is_transmit_empty()
|
|||||||
return inb(PORT + 5) & 0x20;
|
return inb(PORT + 5) & 0x20;
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_serial(char c)
|
// Serial kernel putchar
|
||||||
|
void skputc(char c)
|
||||||
{
|
{
|
||||||
while (!is_transmit_empty()); // wait for free spot
|
while (!is_transmit_empty()); // wait for free spot
|
||||||
outb(PORT, c);
|
outb(PORT, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
void serial_kputs(const char* str)
|
// Serial kernel putstring
|
||||||
|
void skputs(const char* str)
|
||||||
{
|
{
|
||||||
unsigned int i=0;
|
unsigned int i=0;
|
||||||
while (str[i])
|
while (str[i])
|
||||||
{
|
{
|
||||||
write_serial(str[i]);
|
skputc(str[i]);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,7 @@ void outb(int port, unsigned char data);
|
|||||||
unsigned char inb(int port);
|
unsigned char inb(int port);
|
||||||
|
|
||||||
int serial_init();
|
int serial_init();
|
||||||
void serial_kputs(const char* str);
|
void skputs(const char* str);
|
||||||
|
void skputc(char c);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include <limine.h>
|
#include <limine.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include "kernel.h"
|
#include <kernel.h>
|
||||||
#include "term.h"
|
#include "term.h"
|
||||||
|
|
||||||
extern struct limine_framebuffer* framebuffer;
|
extern struct limine_framebuffer* framebuffer;
|
||||||
@@ -35,6 +35,7 @@ int term_init()
|
|||||||
if (framebuffer)
|
if (framebuffer)
|
||||||
{
|
{
|
||||||
fb = framebuffer->address;
|
fb = framebuffer->address;
|
||||||
|
DEBUG("terminal initialized");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@@ -66,7 +67,19 @@ static void draw_char(char c, int px, int py, int fg, int bg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void putchar(char c)
|
static void erase_char(int px, int py)
|
||||||
|
{
|
||||||
|
for (size_t y=0; y<FONT_HEIGHT; y++)
|
||||||
|
{
|
||||||
|
for (size_t x=0; x<8; x++)
|
||||||
|
{
|
||||||
|
// Black
|
||||||
|
putpixel(px+x, py+y, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void putchar(char c)
|
||||||
{
|
{
|
||||||
if (c == '\n')
|
if (c == '\n')
|
||||||
{
|
{
|
||||||
@@ -75,6 +88,32 @@ static void putchar(char c)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Improperly handled.
|
||||||
|
// When we're on an empty line it should get to the upper line's last character
|
||||||
|
// NOT just the last position possible; we would need to track the last line's character amount for that
|
||||||
|
if (c == '\b')
|
||||||
|
{
|
||||||
|
if (cursor.x == 0 && cursor.y == 0)
|
||||||
|
{
|
||||||
|
// Top-left corner
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursor.x == 0)
|
||||||
|
{
|
||||||
|
cursor.y--;
|
||||||
|
cursor.x = (framebuffer->width / FONT_WIDTH) -1; // here
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cursor.x--;
|
||||||
|
}
|
||||||
|
|
||||||
|
int px = cursor.x * FONT_WIDTH;
|
||||||
|
int py = cursor.y * FONT_HEIGHT;
|
||||||
|
erase_char(px, py);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if ((cursor.x+1)*FONT_WIDTH >= framebuffer->width)
|
if ((cursor.x+1)*FONT_WIDTH >= framebuffer->width)
|
||||||
{
|
{
|
||||||
cursor.x = 0;
|
cursor.x = 0;
|
||||||
@@ -87,7 +126,7 @@ static void putchar(char c)
|
|||||||
cursor.x++;
|
cursor.x++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overhead that could be avoided, right?
|
// Overhead that could be avoided, right? (for printf)
|
||||||
void _putchar(char character)
|
void _putchar(char character)
|
||||||
{
|
{
|
||||||
putchar(character);
|
putchar(character);
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
int term_init();
|
int term_init();
|
||||||
void kputs(const char* str);
|
void kputs(const char* str);
|
||||||
|
void putchar(char c);
|
||||||
|
|
||||||
enum TermColors
|
enum TermColors
|
||||||
{
|
{
|
||||||
11
src/kernel.h
11
src/kernel.h
@@ -7,4 +7,15 @@ enum ErrorCodes
|
|||||||
EIO
|
EIO
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define CLEAR_INTERRUPTS __asm__ volatile("cli")
|
||||||
|
#define SET_INTERRUPTS __asm__ volatile("sti")
|
||||||
|
|
||||||
|
#include "io/serial/serial.h"
|
||||||
|
#include "io/term/printf.h"
|
||||||
|
|
||||||
|
// Still lacks print formatting...
|
||||||
|
#define DEBUG(log, ...) \
|
||||||
|
printf("debug: [%s]: " log "\n", __FILE__, ##__VA_ARGS__); \
|
||||||
|
fctprintf((void*)&skputc, 0, "debug: [%s]: %s\n", __FILE__, log)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
33
src/kmain.c
33
src/kmain.c
@@ -1,11 +1,15 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <limine.h>
|
#include <limine.h>
|
||||||
#include "io/term.h"
|
#include "io/term/term.h"
|
||||||
#include "io/printf.h"
|
#include "io/term/printf.h"
|
||||||
#include "io/serial.h"
|
#include "io/serial/serial.h"
|
||||||
#include "mem/gdt.h"
|
#include "mem/gdt/gdt.h"
|
||||||
#include "mem/utils.h"
|
#include "mem/misc/utils.h"
|
||||||
|
#include "idt/idt.h"
|
||||||
|
#include "kernel.h"
|
||||||
|
#include "time/timer.h"
|
||||||
|
#include "io/kbd/ps2.h"
|
||||||
|
|
||||||
// Limine version used
|
// Limine version used
|
||||||
__attribute__((used, section(".limine_requests")))
|
__attribute__((used, section(".limine_requests")))
|
||||||
@@ -44,17 +48,20 @@ void kmain()
|
|||||||
// Get the first framebuffer from the response
|
// Get the first framebuffer from the response
|
||||||
framebuffer = framebuffer_request.response->framebuffers[0];
|
framebuffer = framebuffer_request.response->framebuffers[0];
|
||||||
|
|
||||||
if (term_init()) hcf();
|
term_init();
|
||||||
|
serial_init();
|
||||||
if (serial_init()) kputs("kernel: serial: error: Cannot init serial communication!");
|
|
||||||
|
|
||||||
serial_kputs("\n\nkernel: serial: Hello, world from serial!\n");
|
|
||||||
|
|
||||||
|
CLEAR_INTERRUPTS;
|
||||||
gdt_init();
|
gdt_init();
|
||||||
serial_kputs("kernel: gdt: Initialized GDT!");
|
idt_init();
|
||||||
|
timer_init();
|
||||||
|
SET_INTERRUPTS;
|
||||||
|
|
||||||
|
keyboard_init(FR);
|
||||||
|
|
||||||
// Draw something
|
// Draw something
|
||||||
printf("%s, %s!", "Hello", "world");
|
printf("%s, %s!\n", "Hello", "world");
|
||||||
|
// Yoohoooooo!
|
||||||
|
DEBUG("kernel initialized successfully! hanging... wow=%d", 42);
|
||||||
hcf();
|
hcf();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#include "gdt.h"
|
#include "gdt.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include "../../io/serial/serial.h"
|
||||||
|
#include <kernel.h>
|
||||||
|
|
||||||
// Descriptors are 8-byte wide (64bits)
|
// Descriptors are 8-byte wide (64bits)
|
||||||
// So the selectors will be (in bytes): 0x0, 0x8, 0x10, 0x18, etc..
|
// So the selectors will be (in bytes): 0x0, 0x8, 0x10, 0x18, etc..
|
||||||
@@ -76,4 +78,6 @@ void gdt_init()
|
|||||||
// Load the GDT we created, flush the old one
|
// Load the GDT we created, flush the old one
|
||||||
gdt_load();
|
gdt_load();
|
||||||
gdt_flush();
|
gdt_flush();
|
||||||
|
|
||||||
|
DEBUG("GDT initialized");
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
// We won't be linked to standard library, but still need the basic mem* functions
|
// We won't be linked to standard library, but still need the basic mem* functions
|
||||||
// so everything goes allright with the compiler
|
// so everything goes allright with the compiler
|
||||||
Binary file not shown.
77
src/time/timer.c
Normal file
77
src/time/timer.c
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include "../io/serial/serial.h"
|
||||||
|
#include <kernel.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); // Set IRQ0 (timer, clear bit 0)
|
||||||
|
mask &= ~(1 << 1); // Set IRQ1 (PS/2 Keyboard, clear bit 1)
|
||||||
|
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();
|
||||||
|
DEBUG("PIT initialized");
|
||||||
|
}
|
||||||
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