Compare commits
6 Commits
365ad14122
...
7c6ff5d52d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7c6ff5d52d | ||
|
|
1ed52d1e9e | ||
|
|
1bc122e29a | ||
|
|
385c0d432c | ||
|
|
5a119e428a | ||
|
|
25342b507d |
6
makefile
6
makefile
@@ -6,8 +6,8 @@ CFLAGS = -m64 -ffreestanding -fno-builtin -Wall -Wextra -Wshadow -std=c23 -g
|
||||
LDFLAGS = -g
|
||||
ASFLAGS = -f elf64 -g -F dwarf
|
||||
|
||||
SRC_C := src/kernel.c src/string.c src/vga.c src/idt.c src/keyboard.c
|
||||
SRC_ASM := src/boot.asm src/idt_stub.asm
|
||||
SRC_C := src/kernel.c src/string.c src/vga.c src/interrupts.c
|
||||
SRC_ASM := src/start.asm
|
||||
|
||||
OBJ_C := $(SRC_C:src/%.c=.build/%.o)
|
||||
OBJ_ASM := $(SRC_ASM:src/%.asm=.build/%.o)
|
||||
@@ -28,7 +28,7 @@ build-dir:
|
||||
cp .build/kernel .build/nub-os/boot/
|
||||
grub-mkrescue -o .build/nub-os.iso .build/nub-os/
|
||||
|
||||
.build/kernel: $(OBJS) | linker.ld
|
||||
.build/kernel: $(OBJS)
|
||||
$(LD) $(LDFLAGS) -T linker.ld -o $@ $^
|
||||
|
||||
.build/%.o: src/%.c | build-dir
|
||||
|
||||
172
src/idt.c
172
src/idt.c
@@ -1,172 +0,0 @@
|
||||
#include "idt.h"
|
||||
#include "vga.h"
|
||||
|
||||
#define IDT_SIZE 256
|
||||
|
||||
#define PIC1_COMMAND 0x20
|
||||
#define PIC1_DATA 0x21
|
||||
#define PIC2_COMMAND 0xA0
|
||||
#define PIC2_DATA 0xA1
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u16 address_low;
|
||||
u16 selector;
|
||||
u8 ist;
|
||||
u8 flags;
|
||||
u16 address_mid;
|
||||
u32 address_high;
|
||||
u32 reserved;
|
||||
} __attribute__((packed)) interrupt_descriptor;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u16 limit;
|
||||
u64 base;
|
||||
} __attribute__((packed)) idtr_t;
|
||||
|
||||
extern void* isr_stub_table[];
|
||||
static irq_handler_t irq_handlers[16] = {0};
|
||||
|
||||
static const char* exception_messages[32] = {
|
||||
"divide by zero",
|
||||
"debug",
|
||||
"non maskable interrupt",
|
||||
"breakpoint",
|
||||
"overflow",
|
||||
"bound range exceeded",
|
||||
"invalid opcode",
|
||||
"device not available",
|
||||
"double fault",
|
||||
"coprocessor segment overrun",
|
||||
"invalid tss",
|
||||
"segment not present",
|
||||
"stack-segment fault",
|
||||
"general protection fault",
|
||||
"page fault",
|
||||
"reserved",
|
||||
"x87 floating point exception",
|
||||
"alignment check",
|
||||
"machine check",
|
||||
"simd floating point exception",
|
||||
"virtualization exception",
|
||||
"control protection exception",
|
||||
"reserved",
|
||||
"reserved",
|
||||
"reserved",
|
||||
"reserved",
|
||||
"reserved",
|
||||
"reserved",
|
||||
"hypervisor injection exception",
|
||||
"vmm communication exception",
|
||||
"security exception",
|
||||
"reserved",
|
||||
};
|
||||
|
||||
static interrupt_descriptor idt[IDT_SIZE];
|
||||
|
||||
static void pic_remap(int offset1, int offset2)
|
||||
{
|
||||
u8 a1, a2;
|
||||
|
||||
a1 = inb(PIC1_DATA);
|
||||
a2 = inb(PIC2_DATA);
|
||||
|
||||
outb(PIC1_COMMAND, 0x11);
|
||||
outb(PIC2_COMMAND, 0x11);
|
||||
|
||||
outb(PIC1_DATA, offset1);
|
||||
outb(PIC2_DATA, offset2);
|
||||
|
||||
outb(PIC1_DATA, 4);
|
||||
outb(PIC2_DATA, 2);
|
||||
|
||||
outb(PIC1_DATA, 0x01);
|
||||
outb(PIC2_DATA, 0x01);
|
||||
|
||||
outb(PIC1_DATA, a1);
|
||||
outb(PIC2_DATA, a2);
|
||||
}
|
||||
|
||||
static void pic_send_eoi(u8 irq)
|
||||
{
|
||||
if (irq >= 8)
|
||||
{
|
||||
outb(PIC2_COMMAND, 0x20);
|
||||
}
|
||||
|
||||
outb(PIC1_COMMAND, 0x20);
|
||||
}
|
||||
|
||||
void register_irq_handler(u8 irq, irq_handler_t handler)
|
||||
{
|
||||
irq_handlers[irq] = handler;
|
||||
}
|
||||
|
||||
static inline void idt_set_descriptor(u8 vector, void* handler, u8 dpl)
|
||||
{
|
||||
interrupt_descriptor* entry = &idt[vector];
|
||||
|
||||
entry->address_low = (u64)handler & 0xFFFF;
|
||||
entry->address_mid = ((u64)handler >> 16) & 0xFFFF;
|
||||
entry->address_high = (u64)handler >> 32;
|
||||
entry->selector = 0x08;
|
||||
entry->flags = 0b1110 | ((dpl & 0b11) << 5) | (1 << 7);
|
||||
entry->ist = 0;
|
||||
entry->reserved = 0;
|
||||
}
|
||||
|
||||
void init_idt(void)
|
||||
{
|
||||
pic_remap(0x20, 0x28);
|
||||
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
idt_set_descriptor(i, isr_stub_table[i], 0);
|
||||
}
|
||||
|
||||
idtr_t idtr = {
|
||||
.base = (uintptr_t)&idt[0],
|
||||
.limit = (u16)sizeof(interrupt_descriptor) * IDT_SIZE - 1,
|
||||
};
|
||||
|
||||
__asm__ volatile("lidt %0" : : "m"(idtr));
|
||||
__asm__ volatile("sti");
|
||||
}
|
||||
|
||||
void handle_isr(isr_frame_t* frame)
|
||||
{
|
||||
if (frame->int_no < 32)
|
||||
{
|
||||
vga_print_error();
|
||||
vga_print(" exception[");
|
||||
vga_print_uint(frame->int_no);
|
||||
vga_print("]: ");
|
||||
vga_print(exception_messages[frame->int_no]);
|
||||
|
||||
vga_print(", error code: ");
|
||||
vga_print_uint(frame->err_code);
|
||||
vga_print("\n");
|
||||
|
||||
__asm__ volatile("cli; hlt");
|
||||
}
|
||||
else if (frame->int_no < 48)
|
||||
{
|
||||
u8 irq = frame->int_no - 32;
|
||||
|
||||
if (irq_handlers[irq])
|
||||
{
|
||||
irq_handlers[irq](frame);
|
||||
}
|
||||
|
||||
pic_send_eoi(irq);
|
||||
}
|
||||
else
|
||||
{
|
||||
vga_print_error();
|
||||
vga_print(" interrupt[");
|
||||
vga_print_uint(frame->int_no);
|
||||
vga_print("]: ");
|
||||
vga_print("not implemented\n");
|
||||
}
|
||||
}
|
||||
30
src/idt.h
30
src/idt.h
@@ -1,30 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "typedef.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u64 r15, r14, r13, r12, r11, r10, r9, r8;
|
||||
u64 rbp, rdi, rsi, rdx, rcx, rbx, rax;
|
||||
u64 int_no;
|
||||
u64 err_code;
|
||||
u64 rip, cs, rflags, rsp, ss;
|
||||
} __attribute__((packed)) isr_frame_t;
|
||||
|
||||
typedef void (*irq_handler_t)(const isr_frame_t*);
|
||||
|
||||
void init_idt(void);
|
||||
|
||||
static inline void outb(u16 port, u8 val)
|
||||
{
|
||||
__asm__ volatile("outb %0, %1" : : "a"(val), "Nd"(port));
|
||||
}
|
||||
|
||||
static inline u8 inb(u16 port)
|
||||
{
|
||||
u8 ret;
|
||||
__asm__ volatile("inb %1, %0" : "=a"(ret) : "Nd"(port));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void register_irq_handler(u8 irq, irq_handler_t handler);
|
||||
109
src/idt_stub.asm
109
src/idt_stub.asm
@@ -1,109 +0,0 @@
|
||||
extern handle_isr
|
||||
|
||||
isr_common:
|
||||
push rax
|
||||
push rbx
|
||||
push rcx
|
||||
push rdx
|
||||
push rsi
|
||||
push rdi
|
||||
push rbp
|
||||
push r8
|
||||
push r9
|
||||
push r10
|
||||
push r11
|
||||
push r12
|
||||
push r13
|
||||
push r14
|
||||
push r15
|
||||
|
||||
mov rdi, rsp
|
||||
call handle_isr
|
||||
|
||||
pop r15
|
||||
pop r14
|
||||
pop r13
|
||||
pop r12
|
||||
pop r11
|
||||
pop r10
|
||||
pop r9
|
||||
pop r8
|
||||
pop rbp
|
||||
pop rdi
|
||||
pop rsi
|
||||
pop rdx
|
||||
pop rcx
|
||||
pop rbx
|
||||
pop rax
|
||||
|
||||
add rsp, 16
|
||||
iretq
|
||||
|
||||
%macro ISR_NOERR 1
|
||||
isr_stub_%1:
|
||||
push qword 0
|
||||
push qword %1
|
||||
jmp isr_common
|
||||
%endmacro
|
||||
|
||||
%macro ISR_ERR 1
|
||||
isr_stub_%1:
|
||||
push qword %1
|
||||
jmp isr_common
|
||||
%endmacro
|
||||
|
||||
; CPU exceptions 0-31
|
||||
ISR_NOERR 0
|
||||
ISR_NOERR 1
|
||||
ISR_NOERR 2
|
||||
ISR_NOERR 3
|
||||
ISR_NOERR 4
|
||||
ISR_NOERR 5
|
||||
ISR_NOERR 6
|
||||
ISR_NOERR 7
|
||||
ISR_ERR 8
|
||||
ISR_NOERR 9
|
||||
ISR_ERR 10
|
||||
ISR_ERR 11
|
||||
ISR_ERR 12
|
||||
ISR_ERR 13
|
||||
ISR_ERR 14
|
||||
ISR_NOERR 15
|
||||
ISR_NOERR 16
|
||||
ISR_ERR 17
|
||||
ISR_NOERR 18
|
||||
ISR_NOERR 19
|
||||
ISR_NOERR 20
|
||||
ISR_NOERR 21
|
||||
ISR_NOERR 22
|
||||
ISR_NOERR 23
|
||||
ISR_NOERR 24
|
||||
ISR_NOERR 25
|
||||
ISR_NOERR 26
|
||||
ISR_NOERR 27
|
||||
ISR_NOERR 28
|
||||
ISR_NOERR 29
|
||||
ISR_ERR 30
|
||||
ISR_NOERR 31
|
||||
|
||||
%macro GENERATE_ISRS 2
|
||||
%assign i %1
|
||||
%rep (%2 - %1 + 1)
|
||||
ISR_NOERR i
|
||||
%assign i i+1
|
||||
%endrep
|
||||
%endmacro
|
||||
|
||||
GENERATE_ISRS 32, 255
|
||||
|
||||
%macro GENERATE_ISR_TABLE 2
|
||||
%assign i %1
|
||||
%rep (%2 - %1 + 1)
|
||||
dq isr_stub_%[i]
|
||||
%assign i i+1
|
||||
%endrep
|
||||
%endmacro
|
||||
|
||||
global isr_stub_table
|
||||
isr_stub_table:
|
||||
GENERATE_ISR_TABLE 0, 255
|
||||
117
src/interrupts.c
Normal file
117
src/interrupts.c
Normal file
@@ -0,0 +1,117 @@
|
||||
#include "interrupts.h"
|
||||
#include "vga.h"
|
||||
#include "kernel.h"
|
||||
#include "util.h"
|
||||
|
||||
#define PIC1_COMMAND 0x20
|
||||
#define PIC1_DATA 0x21
|
||||
#define PIC2_COMMAND 0xA0
|
||||
#define PIC2_DATA 0xA1
|
||||
|
||||
void pic_remap()
|
||||
{
|
||||
outb(PIC1_COMMAND, 0x11);
|
||||
outb(PIC2_COMMAND, 0x11);
|
||||
|
||||
outb(PIC1_DATA, 32);
|
||||
outb(PIC2_DATA, 40);
|
||||
|
||||
outb(PIC1_DATA, 4);
|
||||
outb(PIC2_DATA, 2);
|
||||
|
||||
outb(PIC1_DATA, 1);
|
||||
outb(PIC2_DATA, 1);
|
||||
|
||||
outb(PIC1_DATA, 0);
|
||||
outb(PIC2_DATA, 0);
|
||||
}
|
||||
|
||||
static const char* exception_messages[32] = {
|
||||
"divide by zero",
|
||||
"debug",
|
||||
"non maskable interrupt",
|
||||
"breakpoint",
|
||||
"overflow",
|
||||
"bound range exceeded",
|
||||
"invalid opcode",
|
||||
"device not available",
|
||||
"double fault",
|
||||
"coprocessor segment overrun",
|
||||
"invalid tss",
|
||||
"segment not present",
|
||||
"stack-segment fault",
|
||||
"general protection fault",
|
||||
"page fault",
|
||||
"reserved",
|
||||
"x87 floating point exception",
|
||||
"alignment check",
|
||||
"machine check",
|
||||
"simd floating point exception",
|
||||
"virtualization exception",
|
||||
"control protection exception",
|
||||
"reserved",
|
||||
"reserved",
|
||||
"reserved",
|
||||
"reserved",
|
||||
"reserved",
|
||||
"reserved",
|
||||
"hypervisor injection exception",
|
||||
"vmm communication exception",
|
||||
"security exception",
|
||||
"reserved",
|
||||
};
|
||||
|
||||
void handle_exception(const isr_frame_t* frame)
|
||||
{
|
||||
kprintf("exception[%d]: %s, error code: %d\n", frame->int_no, exception_messages[frame->int_no], frame->err_code);
|
||||
kpanic();
|
||||
}
|
||||
|
||||
static irq_handler_t irq_handlers[16] = {0};
|
||||
|
||||
void register_irq_handler(uint8_t irq, irq_handler_t handler)
|
||||
{
|
||||
if (irq >= 16)
|
||||
{
|
||||
kprintf("Cannot register irq %d is out of bounds\n", irq);
|
||||
}
|
||||
else
|
||||
{
|
||||
irq_handlers[irq] = handler;
|
||||
}
|
||||
}
|
||||
|
||||
void handle_irq(const isr_frame_t* frame)
|
||||
{
|
||||
uint8_t irq = frame->int_no - 32;
|
||||
|
||||
if (irq_handlers[irq])
|
||||
{
|
||||
irq_handlers[irq](frame);
|
||||
}
|
||||
|
||||
if (irq >= 8)
|
||||
{
|
||||
outb(PIC2_COMMAND, 0x20);
|
||||
}
|
||||
|
||||
outb(PIC1_COMMAND, 0x20);
|
||||
}
|
||||
|
||||
void handle_isr(const isr_frame_t* frame)
|
||||
{
|
||||
kprintf("isr");
|
||||
|
||||
if (frame->int_no < 32)
|
||||
{
|
||||
handle_exception(frame);
|
||||
}
|
||||
else if (frame->int_no < 48)
|
||||
{
|
||||
handle_irq(frame);
|
||||
}
|
||||
else
|
||||
{
|
||||
kprintf("interrupt[%d]: not implemented\n", frame->int_no);
|
||||
}
|
||||
}
|
||||
28
src/interrupts.h
Normal file
28
src/interrupts.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint64_t r15, r14, r13, r12, r11, r10, r9, r8;
|
||||
uint64_t rbp, rdi, rsi, rdx, rcx, rbx, rax;
|
||||
uint64_t int_no;
|
||||
uint64_t err_code;
|
||||
uint64_t rip, cs, rflags, rsp, ss;
|
||||
} __attribute__((packed)) isr_frame_t;
|
||||
|
||||
typedef void (*irq_handler_t)(const isr_frame_t*);
|
||||
|
||||
void pic_remap();
|
||||
|
||||
void register_irq_handler(uint8_t irq, irq_handler_t handler);
|
||||
|
||||
static inline void enable_interrupts()
|
||||
{
|
||||
__asm__ volatile("sti");
|
||||
}
|
||||
|
||||
static inline void disable_interrupts()
|
||||
{
|
||||
__asm__ volatile("cli");
|
||||
}
|
||||
87
src/kernel.c
87
src/kernel.c
@@ -1,31 +1,80 @@
|
||||
#include "kernel.h"
|
||||
#include "idt.h"
|
||||
#include "keyboard.h"
|
||||
#include "interrupts.h"
|
||||
#include "string.h"
|
||||
#include "vga.h"
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
void kernel_main()
|
||||
void kmain()
|
||||
{
|
||||
vga_clear();
|
||||
vga_print_success();
|
||||
vga_print(" VGA intialzied\n");
|
||||
pic_remap();
|
||||
enable_interrupts();
|
||||
|
||||
init_idt();
|
||||
vga_print_success();
|
||||
vga_print(" IDT intialzied\n");
|
||||
kprintf("Welcome to nub OS\n");
|
||||
khalt();
|
||||
}
|
||||
|
||||
init_keyboard();
|
||||
vga_print_success();
|
||||
vga_print(" Keyboard intialzied\n");
|
||||
|
||||
vga_print("\nWelcome to nub OS\n");
|
||||
|
||||
while (true)
|
||||
void kpanic()
|
||||
{
|
||||
kprintf("Kernel panic!\n");
|
||||
khalt();
|
||||
}
|
||||
|
||||
void kprintf(const char* fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
|
||||
bool should_format = false;
|
||||
|
||||
for (size_t i = 0; fmt[i] != '\0'; i++)
|
||||
{
|
||||
if (should_format)
|
||||
{
|
||||
should_format = false;
|
||||
if (fmt[i] == '%')
|
||||
{
|
||||
vga_put_char('%', 0x0F);
|
||||
}
|
||||
else if (fmt[i] == 's')
|
||||
{
|
||||
const char* str = va_arg(args, const char*);
|
||||
for (size_t j = 0; str[j] != '\0'; j++)
|
||||
{
|
||||
vga_put_char(str[j], 0x0F);
|
||||
}
|
||||
}
|
||||
else if (fmt[i] == 'd')
|
||||
{
|
||||
int64_t val = va_arg(args, int64_t);
|
||||
char buf[21];
|
||||
itoa64(val, buf);
|
||||
for (size_t j = 0; buf[j] != '\0'; j++)
|
||||
{
|
||||
vga_put_char(buf[j], 0x0F);
|
||||
}
|
||||
}
|
||||
else if (fmt[i] == 'u')
|
||||
{
|
||||
uint64_t val = va_arg(args, uint64_t);
|
||||
char buf[21];
|
||||
uitoa64(val, buf);
|
||||
for (size_t j = 0; buf[j] != '\0'; j++)
|
||||
{
|
||||
vga_put_char(buf[j], 0x0F);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (fmt[i] == '%')
|
||||
{
|
||||
should_format = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
vga_put_char(fmt[i], 0x0F);
|
||||
}
|
||||
}
|
||||
|
||||
void kernel_panic()
|
||||
{
|
||||
vga_print("Kernel panic!\n");
|
||||
__asm__ volatile("cli; hlt");
|
||||
va_end(args);
|
||||
}
|
||||
13
src/kernel.h
13
src/kernel.h
@@ -1,3 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
void kernel_panic();
|
||||
void kpanic();
|
||||
|
||||
static inline void khalt()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
__asm__ volatile ("cli");
|
||||
__asm__ volatile ("hlt");
|
||||
}
|
||||
}
|
||||
|
||||
void kprintf(const char* fmt, ...);
|
||||
@@ -1,7 +1,8 @@
|
||||
#include "keyboard.h"
|
||||
#include "idt.h"
|
||||
#include "interrupts.h"
|
||||
#include "kernel.h"
|
||||
#include "vga.h"
|
||||
#include "util.h"
|
||||
|
||||
#define SCANCODE_LEFT_SHIFT 42
|
||||
#define SCANCODE_RIGHT_SHIFT 54
|
||||
@@ -32,7 +33,7 @@ bool caps_lock = false;
|
||||
static keyboard_handler_t keyboard_handlers[KEYBOARD_HANDLERS_LENGTH];
|
||||
static int handler_index = 0;
|
||||
|
||||
char scan_code_to_ascii(u8 scan_code)
|
||||
char scan_code_to_ascii(uint8_t scan_code)
|
||||
{
|
||||
if (scan_code >= 128)
|
||||
{
|
||||
@@ -51,8 +52,8 @@ char scan_code_to_ascii(u8 scan_code)
|
||||
|
||||
void handle_keyboard(const isr_frame_t* frame)
|
||||
{
|
||||
u8 code = inb(0x60);
|
||||
u8 scan_code = code & 0x7F;
|
||||
uint8_t code = inb(0x60);
|
||||
uint8_t scan_code = code & 0x7F;
|
||||
bool pressed = (code & 0x80) == 0;
|
||||
|
||||
switch (scan_code)
|
||||
@@ -81,7 +82,7 @@ void handle_keyboard(const isr_frame_t* frame)
|
||||
.ascii = scan_code_to_ascii(scan_code),
|
||||
};
|
||||
|
||||
for (int i = 0; i < handler_index; i++)
|
||||
for (size_t i = 0; i < handler_index; i++)
|
||||
{
|
||||
keyboard_handlers[i](&event);
|
||||
}
|
||||
@@ -95,9 +96,8 @@ void register_keypress_handler(const keyboard_handler_t handler)
|
||||
// keyboard_handlers is a dynamic list
|
||||
if (handler_index >= KEYBOARD_HANDLERS_LENGTH)
|
||||
{
|
||||
vga_print_error();
|
||||
vga_print(" Maximum keyboard handlers reached\n");
|
||||
kernel_panic();
|
||||
kprintf("Maximum keyboard handlers reached\n");
|
||||
kpanic();
|
||||
}
|
||||
|
||||
keyboard_handlers[handler_index] = handler;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "typedef.h"
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 scan_code;
|
||||
uint8_t scan_code;
|
||||
bool pressed;
|
||||
bool shift;
|
||||
bool caps_lock;
|
||||
@@ -15,4 +15,4 @@ typedef void (*keyboard_handler_t)(const keyboard_event_t*);
|
||||
|
||||
void init_keyboard();
|
||||
void register_keypress_handler(keyboard_handler_t handler);
|
||||
char scan_code_to_ascii(u8 scan_code);
|
||||
char scan_code_to_ascii(uint8_t scan_code);
|
||||
@@ -1,59 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include "typedef.h"
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct multiboot_info
|
||||
{
|
||||
u32 flags; // required
|
||||
uint32_t flags; // required
|
||||
|
||||
// Available if flags[0] is set
|
||||
u32 mem_lower;
|
||||
u32 mem_upper;
|
||||
uint32_t mem_lower;
|
||||
uint32_t mem_upper;
|
||||
|
||||
// Available if flags[1] is set
|
||||
u32 boot_device;
|
||||
uint32_t boot_device;
|
||||
|
||||
// Available if flags[2] is set
|
||||
u32 cmdline;
|
||||
uint32_t cmdline;
|
||||
|
||||
// Available if flags[3] is set
|
||||
u32 mods_count;
|
||||
u32 mods_addr;
|
||||
uint32_t mods_count;
|
||||
uint32_t mods_addr;
|
||||
|
||||
// Available if flags[4] or flags[5] is set
|
||||
u8 syms[16]; // 28 - 40 bytes, exact layout may differ depending on a.out or ELF
|
||||
uint8_t syms[16]; // 28 - 40 bytes, exact layout may differ depending on a.out or ELF
|
||||
|
||||
// Available if flags[6] is set
|
||||
u32 mmap_length;
|
||||
u32 mmap_addr;
|
||||
uint32_t mmap_length;
|
||||
uint32_t mmap_addr;
|
||||
|
||||
// Available if flags[7] is set
|
||||
u32 drives_length;
|
||||
u32 drives_addr;
|
||||
uint32_t drives_length;
|
||||
uint32_t drives_addr;
|
||||
|
||||
// Available if flags[8] is set
|
||||
u32 config_table;
|
||||
uint32_t config_table;
|
||||
|
||||
// Available if flags[9] is set
|
||||
u32 boot_loader_name;
|
||||
uint32_t boot_loader_name;
|
||||
|
||||
// Available if flags[10] is set
|
||||
u32 apm_table;
|
||||
uint32_t apm_table;
|
||||
|
||||
// Available if flags[11] is set
|
||||
u32 vbe_control_info;
|
||||
u32 vbe_mode_info;
|
||||
u16 vbe_mode;
|
||||
u16 vbe_interface_seg;
|
||||
u16 vbe_interface_off;
|
||||
u16 vbe_interface_len;
|
||||
uint32_t vbe_control_info;
|
||||
uint32_t vbe_mode_info;
|
||||
uint16_t vbe_mode;
|
||||
uint16_t vbe_interface_seg;
|
||||
uint16_t vbe_interface_off;
|
||||
uint16_t vbe_interface_len;
|
||||
|
||||
// Available if flags[12] is set
|
||||
u64 framebuffer_addr; // 64-bit for large memory addresses
|
||||
u32 framebuffer_pitch;
|
||||
u32 framebuffer_width;
|
||||
u32 framebuffer_height;
|
||||
u8 framebuffer_bpp;
|
||||
u8 framebuffer_type;
|
||||
u8 color_info[6]; // 110-115 bytes
|
||||
uint64_t framebuffer_addr; // 64-bit for large memory addresses
|
||||
uint32_t framebuffer_pitch;
|
||||
uint32_t framebuffer_width;
|
||||
uint32_t framebuffer_height;
|
||||
uint8_t framebuffer_bpp;
|
||||
uint8_t framebuffer_type;
|
||||
uint8_t color_info[6]; // 110-115 bytes
|
||||
} __attribute__((packed)) multiboot_info_t;
|
||||
@@ -1,5 +1,6 @@
|
||||
global _start
|
||||
extern kernel_main
|
||||
extern kmain
|
||||
extern handle_isr
|
||||
|
||||
%define FLAGS 0b10
|
||||
%define MAGIC 0x1BADB002
|
||||
@@ -130,6 +131,39 @@ section .text
|
||||
hlt
|
||||
jmp .hang
|
||||
|
||||
section .bss
|
||||
align 4096
|
||||
idt64:
|
||||
resb 4096
|
||||
|
||||
section .data
|
||||
align 8
|
||||
idt64_descriptor:
|
||||
dw 4095
|
||||
dq idt64
|
||||
|
||||
section .data
|
||||
align 8
|
||||
isr_stub_table:
|
||||
%assign i 0
|
||||
%rep 256
|
||||
dq isr_stub_%[i]
|
||||
%assign i i+1
|
||||
%endrep
|
||||
|
||||
%macro ISR_NOERR 1
|
||||
isr_stub_%1:
|
||||
push qword 0
|
||||
push qword %1
|
||||
jmp isr_common
|
||||
%endmacro
|
||||
|
||||
%macro ISR_ERR 1
|
||||
isr_stub_%1:
|
||||
push qword %1
|
||||
jmp isr_common
|
||||
%endmacro
|
||||
|
||||
section .text
|
||||
bits 64
|
||||
long_mode:
|
||||
@@ -140,7 +174,108 @@ section .text
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
mov ss, ax
|
||||
call kernel_main
|
||||
|
||||
; Fill in the idt table with the stub functions
|
||||
mov rdi, idt64
|
||||
mov rsi, isr_stub_table
|
||||
mov rcx, 256
|
||||
.loop:
|
||||
mov rax, [rsi]
|
||||
mov [rdi], ax
|
||||
mov word [rdi + 2], 0x08
|
||||
mov word [rdi + 4], 0x8E00
|
||||
shr rax, 16
|
||||
mov [rdi + 6], ax
|
||||
shr rax, 16
|
||||
mov [rdi + 8], eax
|
||||
mov dword [rdi + 12], 0
|
||||
add rdi, 16
|
||||
add rsi, 8
|
||||
loop .loop
|
||||
lidt [idt64_descriptor]
|
||||
|
||||
; Finally, we call in to c
|
||||
call kmain
|
||||
.hang:
|
||||
hlt
|
||||
jmp .hang
|
||||
|
||||
isr_common:
|
||||
push rax
|
||||
push rbx
|
||||
push rcx
|
||||
push rdx
|
||||
push rsi
|
||||
push rdi
|
||||
push rbp
|
||||
push r8
|
||||
push r9
|
||||
push r10
|
||||
push r11
|
||||
push r12
|
||||
push r13
|
||||
push r14
|
||||
push r15
|
||||
|
||||
mov rdi, rsp
|
||||
call handle_isr
|
||||
|
||||
pop r15
|
||||
pop r14
|
||||
pop r13
|
||||
pop r12
|
||||
pop r11
|
||||
pop r10
|
||||
pop r9
|
||||
pop r8
|
||||
pop rbp
|
||||
pop rdi
|
||||
pop rsi
|
||||
pop rdx
|
||||
pop rcx
|
||||
pop rbx
|
||||
pop rax
|
||||
|
||||
add rsp, 16
|
||||
iretq
|
||||
|
||||
; CPU exceptions 0-31. Some of these contain error codes, so we define them manually
|
||||
ISR_NOERR 0
|
||||
ISR_NOERR 1
|
||||
ISR_NOERR 2
|
||||
ISR_NOERR 3
|
||||
ISR_NOERR 4
|
||||
ISR_NOERR 5
|
||||
ISR_NOERR 6
|
||||
ISR_NOERR 7
|
||||
ISR_ERR 8
|
||||
ISR_NOERR 9
|
||||
ISR_ERR 10
|
||||
ISR_ERR 11
|
||||
ISR_ERR 12
|
||||
ISR_ERR 13
|
||||
ISR_ERR 14
|
||||
ISR_NOERR 15
|
||||
ISR_NOERR 16
|
||||
ISR_ERR 17
|
||||
ISR_NOERR 18
|
||||
ISR_NOERR 19
|
||||
ISR_NOERR 20
|
||||
ISR_NOERR 21
|
||||
ISR_NOERR 22
|
||||
ISR_NOERR 23
|
||||
ISR_NOERR 24
|
||||
ISR_NOERR 25
|
||||
ISR_NOERR 26
|
||||
ISR_NOERR 27
|
||||
ISR_NOERR 28
|
||||
ISR_NOERR 29
|
||||
ISR_ERR 30
|
||||
ISR_NOERR 31
|
||||
|
||||
; Hardware interrupts and user-defined interrupts (32-255). These don't have error codes
|
||||
%assign i 32
|
||||
%rep 224
|
||||
ISR_NOERR i
|
||||
%assign i i+1
|
||||
%endrep
|
||||
101
src/string.c
101
src/string.c
@@ -25,64 +25,77 @@ void reverse(char* str, size_t length)
|
||||
}
|
||||
}
|
||||
|
||||
int uitoa(u64 value, char* buffer)
|
||||
void itoa64(int64_t value, char* buffer)
|
||||
{
|
||||
int i = 0;
|
||||
if (value == 0)
|
||||
{
|
||||
buffer[i++] = '0';
|
||||
buffer[i] = '\0';
|
||||
return i;
|
||||
}
|
||||
|
||||
while (value > 0)
|
||||
{
|
||||
buffer[i++] = (value % 10) + '0';
|
||||
value /= 10;
|
||||
}
|
||||
|
||||
buffer[i] = '\0';
|
||||
reverse(buffer, i);
|
||||
return i;
|
||||
}
|
||||
|
||||
int itoa(i64 value, char* buffer)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (value == 0)
|
||||
{
|
||||
buffer[i++] = '0';
|
||||
buffer[i] = '\0';
|
||||
return i;
|
||||
}
|
||||
|
||||
bool negative = false;
|
||||
u64 v;
|
||||
char temp[21];
|
||||
int i = 0, j = 0;
|
||||
int negative = 0;
|
||||
|
||||
if (value < 0)
|
||||
{
|
||||
negative = true;
|
||||
v = (u64)(-value);
|
||||
negative = 1;
|
||||
if (value == INT64_MIN)
|
||||
{
|
||||
const char* min_str = "9223372036854775808";
|
||||
for (i = 0; min_str[i] != '\0'; i++)
|
||||
temp[i] = min_str[i];
|
||||
i = 19;
|
||||
}
|
||||
else
|
||||
{
|
||||
v = (u64)value;
|
||||
value = -value;
|
||||
}
|
||||
}
|
||||
|
||||
while (v > 0)
|
||||
if (value == 0 && !negative)
|
||||
{
|
||||
buffer[i++] = (v % 10) + '0';
|
||||
v /= 10;
|
||||
buffer[0] = '0';
|
||||
buffer[1] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(negative && value == INT64_MIN))
|
||||
{
|
||||
while (value > 0)
|
||||
{
|
||||
temp[i++] = '0' + (value % 10);
|
||||
value /= 10;
|
||||
}
|
||||
}
|
||||
|
||||
if (negative)
|
||||
{
|
||||
buffer[i++] = '-';
|
||||
temp[i++] = '-';
|
||||
}
|
||||
|
||||
buffer[i] = '\0';
|
||||
reverse(buffer, i);
|
||||
|
||||
return i;
|
||||
while (i > 0)
|
||||
{
|
||||
buffer[j++] = temp[--i];
|
||||
}
|
||||
buffer[j] = '\0';
|
||||
}
|
||||
|
||||
void uitoa64(uint64_t value, char* buffer)
|
||||
{
|
||||
char temp[21];
|
||||
int i = 0, j = 0;
|
||||
|
||||
if (value == 0)
|
||||
{
|
||||
buffer[0] = '0';
|
||||
buffer[1] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
while (value > 0)
|
||||
{
|
||||
temp[i++] = '0' + (value % 10);
|
||||
value /= 10;
|
||||
}
|
||||
|
||||
while (i > 0)
|
||||
{
|
||||
buffer[j++] = temp[--i];
|
||||
}
|
||||
buffer[j] = '\0';
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "typedef.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
int strcmp(const char* a, const char* b);
|
||||
void reverse(char* str, size_t length);
|
||||
int uitoa(u64 value, char* buffer);
|
||||
int itoa(i64 value, char* buffer);
|
||||
void uitoa64(uint64_t value, char* buffer);
|
||||
void itoa64(int64_t value, char* buffer);
|
||||
@@ -1,16 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef signed char i8;
|
||||
|
||||
typedef unsigned short u16;
|
||||
typedef signed short i16;
|
||||
|
||||
typedef unsigned int u32;
|
||||
typedef signed int i32;
|
||||
|
||||
typedef unsigned long long u64;
|
||||
typedef signed long long i64;
|
||||
|
||||
typedef u64 size_t;
|
||||
typedef u64 uintptr_t;
|
||||
20
src/util.h
Normal file
20
src/util.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
static inline void outb(uint16_t port, uint8_t val)
|
||||
{
|
||||
__asm__ volatile("outb %0, %1" : : "a"(val), "Nd"(port));
|
||||
}
|
||||
|
||||
static inline uint8_t inb(uint16_t port)
|
||||
{
|
||||
uint8_t ret;
|
||||
__asm__ volatile("inb %1, %0" : "=a"(ret) : "Nd"(port));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void io_wait()
|
||||
{
|
||||
outb(0x80, 0);
|
||||
}
|
||||
110
src/vga.c
110
src/vga.c
@@ -1,57 +1,20 @@
|
||||
#include "vga.h"
|
||||
#include "string.h"
|
||||
#include <stddef.h>
|
||||
|
||||
#define ROWS 25
|
||||
#define COLUMNS 80
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 character;
|
||||
u8 color;
|
||||
} vga_char;
|
||||
uint8_t character;
|
||||
uint8_t color;
|
||||
} vga_char_t;
|
||||
|
||||
vga_char* vga_buffer = (vga_char*)0xb8000;
|
||||
u8 cursor_row = 0;
|
||||
u8 cursor_col = 0;
|
||||
static vga_char_t* vga_buffer = (vga_char_t*)0xb8000;
|
||||
static uint8_t cursor_row = 0;
|
||||
static uint8_t cursor_col = 0;
|
||||
|
||||
void vga_set_char(u8 row, u8 col, vga_char character)
|
||||
{
|
||||
vga_buffer[COLUMNS * row + col] = character;
|
||||
}
|
||||
|
||||
vga_char vga_char_at(u8 row, u8 col)
|
||||
{
|
||||
return vga_buffer[COLUMNS * row + col];
|
||||
}
|
||||
|
||||
void vga_clear(void)
|
||||
{
|
||||
for (u8 row = 0; row < ROWS; row++)
|
||||
{
|
||||
for (u8 col = 0; col < COLUMNS; col++)
|
||||
{
|
||||
vga_char character = {
|
||||
.character = ' ',
|
||||
.color = vga_default_color(),
|
||||
};
|
||||
vga_set_char(row, col, character);
|
||||
}
|
||||
}
|
||||
|
||||
cursor_row = 0;
|
||||
cursor_col = 0;
|
||||
}
|
||||
|
||||
void vga_set_cursor_position(u8 row, u8 col)
|
||||
{
|
||||
if (row < ROWS && col < COLUMNS)
|
||||
{
|
||||
cursor_row = row;
|
||||
cursor_col = col;
|
||||
}
|
||||
}
|
||||
|
||||
void vga_print_char_colored(char character, vga_color_t color)
|
||||
void vga_put_char(char character, uint8_t color)
|
||||
{
|
||||
switch (character)
|
||||
{
|
||||
@@ -68,17 +31,16 @@ void vga_print_char_colored(char character, vga_color_t color)
|
||||
}
|
||||
case '\t':
|
||||
{
|
||||
u8 remainter = cursor_col % 4;
|
||||
uint8_t remainter = cursor_col % 4;
|
||||
cursor_col += remainter == 0 ? 4 : remainter;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
vga_char c = {
|
||||
vga_buffer[COLUMNS * cursor_row + cursor_col] = (vga_char_t){
|
||||
.character = character,
|
||||
.color = color,
|
||||
};
|
||||
vga_set_char(cursor_row, cursor_col, c);
|
||||
cursor_col += 1;
|
||||
break;
|
||||
}
|
||||
@@ -92,59 +54,39 @@ void vga_print_char_colored(char character, vga_color_t color)
|
||||
|
||||
if (cursor_row >= ROWS)
|
||||
{
|
||||
for (u8 row = 1; row < ROWS; row++)
|
||||
for (size_t row = 1; row < ROWS; row++)
|
||||
{
|
||||
for (u8 col = 0; col < COLUMNS; col++)
|
||||
for (size_t col = 0; col < COLUMNS; col++)
|
||||
{
|
||||
vga_set_char(row - 1, col, vga_char_at(row, col));
|
||||
vga_buffer[COLUMNS * row - 1 + col] = vga_buffer[COLUMNS * row + col];
|
||||
}
|
||||
}
|
||||
|
||||
for (u8 col = 0; col < COLUMNS; col++)
|
||||
for (size_t col = 0; col < COLUMNS; col++)
|
||||
{
|
||||
vga_char c = {
|
||||
vga_buffer[ROWS - 1 + col] = (vga_char_t){
|
||||
.character = ' ',
|
||||
.color = vga_default_color(),
|
||||
.color = VGA_LIGHT_GRAY | VGA_BLACK << 4,
|
||||
};
|
||||
vga_set_char(ROWS - 1, col, c);
|
||||
};
|
||||
|
||||
cursor_row = ROWS - 1;
|
||||
}
|
||||
}
|
||||
|
||||
void vga_print_colored(const char* string, vga_color_t color)
|
||||
void vga_clear()
|
||||
{
|
||||
for (u8 i = 0; string[i] != '\0'; i++)
|
||||
for (size_t row = 0; row < ROWS; row++)
|
||||
{
|
||||
vga_print_char_colored(string[i], color);
|
||||
for (size_t col = 0; col < COLUMNS; col++)
|
||||
{
|
||||
vga_buffer[COLUMNS * row - 1 + col] = (vga_char_t){
|
||||
.character = ' ',
|
||||
.color = VGA_LIGHT_GRAY | VGA_BLACK << 4,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void vga_print_success(void)
|
||||
{
|
||||
vga_print("[ ");
|
||||
vga_print_colored("success", VGA_GREEN);
|
||||
vga_print(" ]");
|
||||
}
|
||||
|
||||
void vga_print_error(void)
|
||||
{
|
||||
vga_print("[ ");
|
||||
vga_print_colored("error", VGA_RED);
|
||||
vga_print(" ]");
|
||||
}
|
||||
|
||||
void vga_print_uint(u32 value)
|
||||
{
|
||||
char buffer[11];
|
||||
uitoa(value, buffer);
|
||||
vga_print(buffer);
|
||||
}
|
||||
|
||||
void vga_print_int(i32 value)
|
||||
{
|
||||
char buffer[12];
|
||||
itoa(value, buffer);
|
||||
vga_print(buffer);
|
||||
cursor_row = 0;
|
||||
cursor_col = 0;
|
||||
}
|
||||
37
src/vga.h
37
src/vga.h
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "typedef.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#define VGA_BLACK 0
|
||||
#define VGA_BLUE 1
|
||||
@@ -19,36 +19,5 @@
|
||||
#define VGA_YELLOW 14
|
||||
#define VGA_WHITE 15
|
||||
|
||||
typedef u8 vga_color_t;
|
||||
|
||||
void vga_clear(void);
|
||||
void vga_set_cursor_position(u8 row, u8 col);
|
||||
|
||||
void vga_print_char_colored(char character, vga_color_t color);
|
||||
void vga_print_colored(const char* string, vga_color_t color);
|
||||
|
||||
void vga_print_success(void);
|
||||
void vga_print_error(void);
|
||||
|
||||
void vga_print_uint(u32 value);
|
||||
void vga_print_int(i32 value);
|
||||
|
||||
static inline vga_color_t vga_color(vga_color_t fg_color, vga_color_t bg_color)
|
||||
{
|
||||
return fg_color | bg_color << 4;
|
||||
}
|
||||
|
||||
static inline vga_color_t vga_default_color()
|
||||
{
|
||||
return vga_color(VGA_LIGHT_GRAY, VGA_BLACK);
|
||||
}
|
||||
|
||||
static inline void vga_print_char(char character)
|
||||
{
|
||||
vga_print_char_colored(character, vga_default_color());
|
||||
}
|
||||
|
||||
static inline void vga_print(const char* string)
|
||||
{
|
||||
vga_print_colored(string, vga_default_color());
|
||||
}
|
||||
void vga_put_char(char character, uint8_t color);
|
||||
void vga_clear();
|
||||
|
||||
Reference in New Issue
Block a user