Compare commits

...

6 Commits

Author SHA1 Message Date
nub31
7c6ff5d52d ... 2025-09-01 20:28:02 +02:00
nub31
1ed52d1e9e ... 2025-09-01 20:06:58 +02:00
nub31
1bc122e29a ... 2025-09-01 19:18:38 +02:00
nub31
385c0d432c ... 2025-09-01 16:02:14 +02:00
nub31
5a119e428a ... 2025-09-01 15:55:44 +02:00
nub31
25342b507d ... 2025-09-01 15:15:00 +02:00
18 changed files with 521 additions and 563 deletions

View File

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

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

View File

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

View File

@@ -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
View 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
View 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");
}

View File

@@ -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");
init_keyboard();
vga_print_success();
vga_print(" Keyboard intialzied\n");
vga_print("\nWelcome to nub OS\n");
while (true)
{
}
kprintf("Welcome to nub OS\n");
khalt();
}
void kernel_panic()
void kpanic()
{
vga_print("Kernel panic!\n");
__asm__ volatile("cli; hlt");
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);
}
}
va_end(args);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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);
}
else
{
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
{
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);
while (i > 0)
{
buffer[j++] = temp[--i];
}
buffer[j] = '\0';
}
return i;
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';
}

View File

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

View File

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

112
src/vga.c
View File

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

View File

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