13 Commits

Author SHA1 Message Date
cf4915d9f4 Update README.md 2025-12-30 18:13:53 +01:00
834891fd2a DEBUG fix 2025-12-28 12:32:29 +01:00
3853a1ace3 Efficient DEBUG logging system with __FILE__ and fctprintf 2025-12-28 12:15:32 +01:00
ead0ed6ae1 Folder restructuration 2025-12-28 11:39:39 +01:00
fabe0b1a10 Merge pull request 'kbd' (#6) from kbd into main
Reviewed-on: #6
2025-12-28 11:17:08 +01:00
b886f03f7a Quick backspace fix 2025-12-28 11:14:22 +01:00
4607b5aba5 holy SHIFT 2025-12-28 11:06:33 +01:00
cc36c768cf Shitty broken keyboard driver BUT azerty-compatible 2025-12-28 10:28:17 +01:00
dbd068e55a Update README.md 2025-12-27 15:54:58 +01:00
53fb22cecd Merge pull request #5 from xamidev/time
1000Hz PIC timer working + IDT dispatch/handler fixes
2025-12-27 13:55:00 +01:00
54f26c506e 1000Hz PIC timer working + IDT dispatch/handler fixes 2025-12-27 13:52:05 +01:00
bb556709d8 Update README.md 2025-12-23 11:20:16 +01:00
24d75463b8 Merge pull request #4 from xamidev/idt
Idt
2025-12-22 21:05:42 +01:00
22 changed files with 617 additions and 100 deletions

View File

@@ -1,6 +1,8 @@
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/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 $(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 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,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:

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
@@ -234,3 +234,77 @@ vector_21_handler:
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
; PS/2 Keyboard
align 16
vector_33_handler:
push qword 0
push qword 33
jmp interrupt_stub

View File

@@ -1,7 +1,9 @@
#include "idt.h" #include "idt.h"
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include "../io/serial.h" #include "../io/serial/serial.h"
#include "../io/kbd/ps2.h"
#include <kernel.h>
struct interrupt_descriptor idt[256]; struct interrupt_descriptor idt[256];
struct idtr idt_reg; struct idtr idt_reg;
@@ -9,6 +11,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;
@@ -45,7 +50,7 @@ void idt_init()
idt_set_entry(i, vector_0_handler + (i*16), 0); idt_set_entry(i, vector_0_handler + (i*16), 0);
} }
idt_load(&idt); idt_load(&idt);
serial_kputs("kernel: idt: Initialized IDT!\n"); DEBUG("IDT initialized");
} }
struct cpu_status_t* interrupt_dispatch(struct cpu_status_t* context) struct cpu_status_t* interrupt_dispatch(struct cpu_status_t* context)
@@ -53,74 +58,85 @@ struct cpu_status_t* interrupt_dispatch(struct cpu_status_t* context)
switch(context->vector_number) switch(context->vector_number)
{ {
case 0: case 0:
serial_kputs("kernel: idt: Divide Error!\n"); DEBUG("Divide Error!");
break; break;
case 1: case 1:
serial_kputs("kernel: idt: Debug Exception!\n"); DEBUG("Debug Exception!");
break; break;
case 2: case 2:
serial_kputs("kernel: idt: NMI Interrupt!\n"); DEBUG("NMI Interrupt!");
break; break;
case 3: case 3:
serial_kputs("kernel: idt: Breakpoint Interrupt!\n"); DEBUG("Breakpoint Interrupt!");
break; break;
case 4: case 4:
serial_kputs("kernel: idt: Overflow Trap!\n"); DEBUG("Overflow Trap!");
break; break;
case 5: case 5:
serial_kputs("kernel: idt: BOUND Range Exceeded!\n"); DEBUG("BOUND Range Exceeded!");
break; break;
case 6: case 6:
serial_kputs("kernel: idt: Invalid Opcode!\n"); DEBUG("Invalid Opcode!");
break; break;
case 7: case 7:
serial_kputs("kernel: idt: Device Not Available!\n"); DEBUG("Device Not Available!");
break; break;
case 8: case 8:
serial_kputs("kernel: idt: Double Fault!\n"); DEBUG("Double Fault!");
break; break;
case 9: case 9:
serial_kputs("kernel: idt: Coprocessor Segment Overrun!\n"); DEBUG("Coprocessor Segment Overrun!");
break; break;
case 10: case 10:
serial_kputs("kernel: idt: Invalid TSS!\n"); DEBUG("Invalid TSS!");
break; break;
case 11: case 11:
serial_kputs("kernel: idt: Segment Not Present!\n"); DEBUG("Segment Not Present!");
break; break;
case 12: case 12:
serial_kputs("kernel: idt: Stack-Segment Fault!\n"); DEBUG("Stack-Segment Fault!");
break; break;
case 13: case 13:
serial_kputs("kernel: idt: General Protection Fault!\n"); DEBUG("General Protection Fault!");
break; break;
case 14: case 14:
serial_kputs("kernel: idt: Page Fault!\n"); DEBUG("Page Fault!");
break; break;
case 15: case 15:
serial_kputs("kernel: idt: Intel Reserved Interrupt! (Achievement unlocked: How Did We Get Here?)\n"); DEBUG("Intel Reserved Interrupt! (Achievement unlocked: How Did We Get Here?)");
break; break;
case 16: case 16:
serial_kputs("kernel: idt: x87 Floating-Point Error!\n"); DEBUG("x87 Floating-Point Error!");
break; break;
case 17: case 17:
serial_kputs("kernel: idt: Alignment Check Fault!\n"); DEBUG("Alignment Check Fault!");
break; break;
case 18: case 18:
serial_kputs("kernel: idt: Machine Check!\n"); DEBUG("Machine Check!");
break; break;
case 19: case 19:
serial_kputs("kernel: idt: SIMD Floating-Point Exception!\n"); DEBUG("SIMD Floating-Point Exception!");
break; break;
case 20: case 20:
serial_kputs("kernel: idt: Virtualization Exception!\n"); DEBUG("Virtualization Exception!");
break; break;
case 21: case 21:
serial_kputs("kernel: idt: Control Protection Exception!\n"); 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; break;
default: default:
serial_kputs("kernel: idt: Unexpected interrupt\n"); DEBUG("Unexpected interrupt");
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;

237
src/io/kbd/ps2.c Normal file
View 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
View 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

View File

@@ -1,4 +1,4 @@
#include "../kernel.h" #include <kernel.h>
#include "serial.h" #include "serial.h"
void outb(int port, unsigned char data) void outb(int port, unsigned char data)
@@ -36,7 +36,7 @@ int serial_init()
// Set normal operation mode // Set normal operation mode
outb(PORT + 4, 0x0F); outb(PORT + 4, 0x0F);
serial_kputs("\n\nkernel: serial: Serial initialization OK!\n"); DEBUG("serial initialized");
return 0; return 0;
} }
@@ -45,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++;
} }
} }

View File

@@ -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

View File

@@ -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);

View File

@@ -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
{ {

View File

@@ -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

View File

@@ -1,12 +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 "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")))
@@ -36,20 +39,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()
{ {
@@ -59,16 +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!");
CLEAR_INTERRUPTS;
gdt_init(); gdt_init();
idt_init(); 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!
trigger_div0(); DEBUG("kernel initialized successfully! hanging... wow=%d", 42);
hcf(); hcf();
} }

View File

@@ -1,6 +1,7 @@
#include "gdt.h" #include "gdt.h"
#include <stdint.h> #include <stdint.h>
#include "../io/serial.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..
@@ -78,5 +79,5 @@ void gdt_init()
gdt_load(); gdt_load();
gdt_flush(); gdt_flush();
serial_kputs("kernel: gdt: Initialized GDT!\n"); DEBUG("GDT initialized");
} }

77
src/time/timer.c Normal file
View 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
View File

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