initial commit

This commit is contained in:
TriMill 2023-04-18 23:44:10 -04:00
commit 0fa2351940
19 changed files with 693 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
compile_flags.txt
bin

49
Makefile Normal file
View file

@ -0,0 +1,49 @@
CC=i386-elf-gcc
LD=i386-elf-ld
CFLAGS=-ffreestanding -g -m32 -std=c2x -O2 -Wall -Wextra -pedantic -lgcc -isystem ./libk/include
C_SOURCE=$(shell find kernel -type f -name "*.c")
C_OBJ=$(patsubst %.c,bin/%.o,$(C_SOURCE))
A_SOURCE=$(shell find kernel -type f -name "*.asm")
A_OBJ=$(patsubst %.asm,bin/%_asm.o,$(A_SOURCE))
LIBK_SOURCE=$(shell find libk -type f -name "*.c")
LIBK_OBJ=$(patsubst %.c,bin/%.o,$(LIBK_SOURCE))
.PHONY: test all run clean
all: bin/os.iso
$(A_OBJ): bin/%_asm.o : %.asm
@mkdir -p $(@D)
nasm $< -f elf -o $@
$(C_OBJ): bin/%.o : %.c
@mkdir -p $(@D)
$(CC) -c $(CFLAGS) -o $@ $<
$(LIBK_OBJ): bin/%.o : %.c
@mkdir -p $(@D)
$(CC) -c $(CFLAGS) -o $@ $<
bin/libk.a: $(LIBK_OBJ)
@mkdir -p $(@D)
$(AR) rcs bin/libk.a $(LIBK_OBJ)
bin/kernel.bin: bin/libk.a $(A_OBJ) $(C_OBJ)
@mkdir -p $(@D)
$(LD) -nmagic -o bin/kernel.bin -T linker.ld $(A_OBJ) $(C_OBJ) bin/libk.a
bin/os.iso: bin/kernel.bin
@mkdir -p $(@D)
@mkdir -p bin/iso/boot/grub
cp grub.cfg bin/iso/boot/grub
cp bin/kernel.bin bin/iso/boot
grub-mkrescue -o bin/os.iso bin/iso
run: all
qemu-system-i386 -cdrom bin/os.iso
clean:
rm -rf bin

7
grub.cfg Normal file
View file

@ -0,0 +1,7 @@
set timeout=0
set default=0
menuentry "trios" {
multiboot2 /boot/kernel.bin
boot
}

87
kernel/interrupt/idt.asm Normal file
View file

@ -0,0 +1,87 @@
extern idt_exception_handler
extern idt_pic_timer
extern idt_pic_keyboard
extern idt_pic_handler
global isr_stub_table
%macro ISRErrorStub 1
isr_stub_%+%1:
push dword %1
call idt_exception_handler
pop eax
iret
%endmacro
%macro PICGeneric 1
isr_stub_%+%1:
push dword %1
call idt_pic_handler
pop eax
iret
%endmacro
%macro PICTimer 1
isr_stub_%+%1:
push dword %1
call idt_pic_handler
call idt_pic_timer
pop eax
iret
%endmacro
%macro PICKeyboard 1
isr_stub_%+%1:
push dword %1
call idt_pic_handler
call idt_pic_keyboard
pop eax
iret
%endmacro
%macro ISRSyscall 1
isr_stub_%+%1:
push eax
push ebx
push ecx
push edx
call idt_syscall
add esp, 16
pop eax
iret
%endmacro
section .text
%assign i 0
%rep 32
ISRErrorStub i
%assign i i+1
%endrep
PICTimer 32
PICKeyboard 33
PICGeneric 34
PICGeneric 35
PICGeneric 36
PICGeneric 37
PICGeneric 38
PICGeneric 39
PICGeneric 40
PICGeneric 41
PICGeneric 42
PICGeneric 43
PICGeneric 44
PICGeneric 45
PICGeneric 46
PICGeneric 47
%assign i 48
%rep 256 - 48
ISRErrorStub i
%assign i i+1
%endrep
section .rodata
isr_stub_table:
%assign i 0x00
%rep 256
dd isr_stub_%+i
%assign i i+0x01
%endrep

81
kernel/interrupt/idt.c Normal file
View file

@ -0,0 +1,81 @@
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <sys.h>
#include "idt.h"
#include "../term.h"
#include "pic.h"
static int timer = 0;
void idt_pic_handler(uint8_t exception) {
pic_eoi(exception - PIC_REMAP_OFFSET);
}
void idt_pic_timer(void) {
uint32_t state = term_save();
term_setcol(0x0a);
char buf[20];
itoa(timer, buf);
term_setpos(0, 20);
puts(" ");
term_setpos(0, 20);
puts(buf);
timer += 1;
term_load(state);
}
void idt_pic_keyboard(void) {
uint8_t c = inb(0x60);
uint32_t state = term_save();
term_setcol(0x0c);
term_setpos(0, 21);
puts(" ");
term_setpos(0, 21);
char buf[20];
itoa(c, buf);
puts(buf);
term_load(state);
}
void idt_exception_handler(uint8_t exception) {
switch(exception) {
case 0x00:
puts("Div by zero");
break;
case 0x08:
puts("Double fault");
break;
default:
puts("Error");
break;
}
halt();
}
__attribute__((aligned(0x10)))
static struct IdtEntry idt[256];
static struct Idtr idtr;
extern void* isr_stub_table[];
static void set_descriptor(uint8_t vector, void* isr, uint8_t flags) {
struct IdtEntry* entry = &idt[vector];
entry->isr_low = (size_t)isr & 0xffff;
entry->kernel_cs = 0x08;
entry->attributes = flags;
entry->isr_high = (size_t)isr >> 16;
entry->_reserved = 0;
}
void idt_init(void) {
idtr.base = (uintptr_t)&idt[0];
idtr.limit = (uint16_t)sizeof(struct IdtEntry) * IDT_SIZE - 1;
for(uint8_t i = 0; i < IDT_INTERRUPTS; i++) {
set_descriptor(i, isr_stub_table[i], 0x8e);
}
__asm__ volatile ("lidt %0" : : "m"(idtr));
}

36
kernel/interrupt/idt.h Normal file
View file

@ -0,0 +1,36 @@
#pragma once
#include <stdint.h>
#define IDT_SIZE 256
#define IDT_INTERRUPTS 48
struct IdtEntry {
uint16_t isr_low;
uint16_t kernel_cs;
uint8_t _reserved;
uint8_t attributes;
uint16_t isr_high;
} __attribute__((packed));
struct Idtr {
uint16_t limit;
uint32_t base;
} __attribute__((packed));
typedef enum {
IDT_FLAG_GATE_TASK = 0x5,
IDT_FLAG_GATE_16BIT_INT = 0x6,
IDT_FLAG_GATE_16BIT_TRAP = 0x7,
IDT_FLAG_GATE_32BIT_INT = 0xE,
IDT_FLAG_GATE_32BIT_TRAP = 0xF,
IDT_FLAG_RING0 = (0 << 5),
IDT_FLAG_RING1 = (1 << 5),
IDT_FLAG_RING2 = (2 << 5),
IDT_FLAG_RING3 = (3 << 5),
IDT_FLAG_PRESENT = 0x80,
} IDTFlags;
void idt_init(void);

82
kernel/interrupt/pic.c Normal file
View file

@ -0,0 +1,82 @@
#include "pic.h"
#include "../term.h"
#include <sys.h>
#define PIC1_COMMAND_PORT 0x20
#define PIC1_DATA_PORT 0x21
#define PIC2_COMMAND_PORT 0xA0
#define PIC2_DATA_PORT 0xA1
void pic_remap(uint8_t offset) {
char a1 = inb(PIC1_DATA_PORT);
char a2 = inb(PIC2_DATA_PORT);
// control word 1
// 0x11: initialize, enable ICW4
outb(PIC1_COMMAND_PORT, 0x11);
io_wait();
outb(PIC2_COMMAND_PORT, 0x11);
io_wait();
// control word 2
// interrupt offset
outb(PIC1_DATA_PORT, offset);
io_wait();
outb(PIC2_DATA_PORT, offset + 8);
io_wait();
// control word 3
// primary pic: set which pin secondary is connected to
// (pin 2)
outb(PIC1_DATA_PORT, 0b00000100);
io_wait();
outb(PIC2_DATA_PORT, 2);
io_wait();
// control word 3
// 0x01: enable 8086 mode
outb(PIC1_DATA_PORT, 0x01);
io_wait();
outb(PIC2_DATA_PORT, 0x01);
io_wait();
// clear data registers
outb(PIC1_DATA_PORT, a1);
outb(PIC2_DATA_PORT, a2);
}
void pic_mask(int irq) {
uint8_t port;
if(irq < 8) {
port = PIC1_DATA_PORT;
} else {
irq -= 8;
port = PIC2_DATA_PORT;
}
uint8_t mask = inb(port);
outb(port, mask | (1 << irq));
}
void pic_unmask(int irq) {
uint8_t port;
if(irq < 8) {
port = PIC1_DATA_PORT;
} else {
irq -= 8;
port = PIC2_DATA_PORT;
}
uint8_t mask = inb(port);
outb(port, mask & ~(1 << irq));
}
// completely disable the PIC
void pic_disable() {
outb(PIC1_DATA_PORT, 0xff);
io_wait();
outb(PIC2_DATA_PORT, 0xff);
io_wait();
}
// end of interrupt
void pic_eoi(int irq) {
if(irq >= 8) {
outb(PIC2_COMMAND_PORT, 0x20);
}
outb(PIC1_COMMAND_PORT, 0x20);
}

10
kernel/interrupt/pic.h Normal file
View file

@ -0,0 +1,10 @@
#pragma once
#include <stdint.h>
#define PIC_REMAP_OFFSET 0x20
void pic_remap(uint8_t offset);
void pic_mask(int irq);
void pic_unmask(int irq);
void pic_disable();
void pic_eoi(int irq);

22
kernel/main.c Normal file
View file

@ -0,0 +1,22 @@
#include <sys.h>
#include "term.h"
#include "interrupt/pic.h"
#include "interrupt/idt.h"
extern void kmain(void) {
term_clear();
term_setcol(0x0f);
puts("loading kernel\n");
idt_init();
puts("initialized idt\n");
pic_remap(PIC_REMAP_OFFSET);
puts("remapped pic\n");
int_enable();
puts("enabled interrupts\n");
outb(0x60, 0xF4);
puts("enabled keyboard\n");
while(1) {
int_wait();
}
}

66
kernel/start.asm Normal file
View file

@ -0,0 +1,66 @@
global start
extern kmain
bits 32
; base, limit, access, flags
%macro gdt_entry 4
db %2 & 0xff
db (%2 >> 8) & 0xff
db %1 & 0xff
db (%1 >> 8) & 0xff
db (%1 >> 16) & 0xff
db %3
db ((%2 >> 16) & 0x0f) | (%4 << 4)
db (%1 >> 24) & 0xff
%endmacro
section .multiboot_header
align 8
mb_start:
dd 0xe85250d6
dd 0
dd mb_end - mb_start
dd 0x100000000 - (0xe85250d6 + (mb_end - mb_start))
dw 0
dw 0
dd 8
mb_end:
section .bss
align 16
stack_start:
resb 16384
stack_end:
section .rodata
align 16
gdt_start:
gdt_entry 0, 0, 0, 0
gdt_entry 0, 0xFFFFF, 0x9A, 0xC
gdt_entry 0, 0xFFFFF, 0x92, 0xC
gdt_end:
gdt_descriptor:
dw gdt_end - gdt_start - 1
dd gdt_start
section .text
align 8
start:
cli
lgdt [gdt_descriptor]
jmp 0x08:after_lgdt
after_lgdt:
mov ax, 0x10
mov ds, ax
mov ss, ax
mov es, ax
mov fs, ax
mov gs, ax
mov esp, stack_end
mov ebp, stack_end
call kmain
cli
halt:
hlt
jmp halt

63
kernel/term.c Normal file
View file

@ -0,0 +1,63 @@
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "term.h"
static uint16_t* screen = (uint16_t*)0xb8000;
static size_t x = 0;
static size_t y = 0;
static uint8_t color = 0x0f;
static inline uint16_t screen_entry(char c, uint8_t col) {
return (uint16_t)c | ((uint16_t)col << 8);
}
void putc(char c) {
switch(c) {
case '\n':
x = TERM_W;
break;
case '\t':
if(x % 8 == 0) x += 8;
x += 7 - (x % 8);
break;
default:
screen[x + y * TERM_W] = screen_entry(c, color);
x += 1;
break;
}
if(x >= TERM_W) {
x = 0;
y += 1;
}
}
void puts(char* s) {
for(char* c = s; *c != '\0'; c++) {
putc(*c);
}
}
void term_clear(void) {
memset(screen, 0, TERM_W * TERM_H * 2);
}
void term_setpos(size_t new_x, size_t new_y) {
x = new_x;
y = new_y;
}
void term_setcol(uint8_t new_col) {
color = new_col;
}
uint32_t term_save(void) {
return color | ((x + y * TERM_W) << 8);
}
void term_load(uint32_t state) {
color = state & 0xff;
state >>= 8;
x = state % TERM_W;
y = state / TERM_W;
}

15
kernel/term.h Normal file
View file

@ -0,0 +1,15 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
#define TERM_W 80
#define TERM_H 25
void putc(char c);
void puts(char* s);
void term_clear(void);
void term_setcol(uint8_t new_col);
void term_setpos(size_t new_x, size_t new_y);
uint32_t term_save(void);
void term_load(uint32_t pos);

4
libk/include/stdlib.h Normal file
View file

@ -0,0 +1,4 @@
#pragma once
int atoi(const char* s);
void itoa(int n, char* buf);

8
libk/include/string.h Normal file
View file

@ -0,0 +1,8 @@
#pragma once
#include <stddef.h>
int memcmp(const void *lhs, const void *rhs, size_t n);
void *memcpy(void *restrict dst, const void *restrict src, size_t n);
void *memmove(void *dst, const void *src, size_t n);
void *memset(void *dest, int c, size_t n);

12
libk/include/sys.h Normal file
View file

@ -0,0 +1,12 @@
#include <stdint.h>
#include <stdint.h>
uint8_t inb(uint16_t port);
void outb(uint16_t port, uint8_t val);
void io_wait(void);
void int_enable(void);
void int_disable(void);
void int_wait(void);
void halt(void);

46
libk/stdlib.c Normal file
View file

@ -0,0 +1,46 @@
#include <stdbool.h>
#include "include/stdlib.h"
int atoi(const char* s) {
bool neg = false;
if(*s == '+') {
s++;
} else if(*s == '-') {
neg = true;
s++;
}
int n = 0;
while(*s >= '0' && *s <= '9') {
n *= 10;
n += (*s - '0');
s++;
}
return neg ? -n : n;
}
void itoa(int n, char* buf) {
if(n < 0) {
n = -n;
*buf = '-';
buf++;
} else if(n == 0) {
buf[0] = '0';
buf[1] = '\0';
return;
}
char* start = buf;
while(n > 0) {
*buf= n % 10 + '0';
n /= 10;
buf++;
}
*buf = '\0';
buf--;
while(start < buf) {
char tmp = *start;
*start = *buf;
*buf = tmp;
start++;
buf--;
}
}

47
libk/string.c Normal file
View file

@ -0,0 +1,47 @@
#include <stddef.h>
#include "include/string.h"
int memcmp(const void *lhs, const void *rhs, size_t n) {
const unsigned char *l = lhs;
const unsigned char *r = rhs;
while(n != 0 && *l == *r) {
n--;
l++;
r++;
}
return (n == 0) ? 0 : *l - *r;
}
void *memcpy(void *restrict dst, const void *restrict src, size_t n) {
char *d = dst;
const char *s = src;
while(n--) {
*d++ = *s++;
}
return dst;
}
void *memmove(void *dst, const void *src, size_t n) {
char *d = dst;
const char *s = src;
if(s < d) {
d += n;
s += n;
while(n--) {
*--d = *--s;
}
} else {
while(n--) {
*d++ = *s++;
}
}
return dst;
}
void *memset(void *dest, int c, size_t n) {
unsigned char *d = dest;
while(n--) {
*d = c;
}
return dest;
}

31
libk/sys.c Normal file
View file

@ -0,0 +1,31 @@
#include <stdint.h>
uint8_t inb(uint16_t port) {
uint8_t ret;
__asm__ volatile ("inb %1, %0" : "=a"(ret) : "Nd"(port));
return ret;
}
void outb(uint16_t port, uint8_t val) {
__asm__ volatile ("outb %0, %1" : : "a"(val), "Nd"(port));
}
void io_wait(void) {
outb(0x80, 0);
}
void int_enable(void) {
__asm__ volatile ("sti");
}
void int_disable(void) {
__asm__ volatile ("cli");
}
void int_wait(void) {
__asm__ volatile ("hlt");
}
void halt(void) {
__asm__ volatile ("cli; hlt");
}

25
linker.ld Normal file
View file

@ -0,0 +1,25 @@
ENTRY(start)
SECTIONS {
. = 1M;
.boot :
{
*(.multiboot_header)
}
.rodata :
{
*(.rodata)
}
.bss :
{
*(.bss)
}
.text :
{
*(.text)
}
}