No more double faults B-)

This commit is contained in:
2024-08-07 13:38:21 +02:00
parent cf7a7303e3
commit 1e385af53c
16 changed files with 496 additions and 155 deletions

View File

@@ -25,7 +25,9 @@ ASM_SOURCES := $(shell find $(SOURCE_DIR) -name '*.S')
OBJECTS := $(patsubst $(SOURCE_DIR)/%, $(BUILD_DIR)/%, $(C_SOURCES:.c=.o) $(ASM_SOURCES:.S=.o))
DEPENDS := $(patsubst $(SOURCE_DIR)/%, $(BUILD_DIR)/%, $(C_SOURCES:.c=.d))
CFLAGS := -MMD -ffreestanding -O1 -Wall -Wextra -Werror -std=c2x -I$(SOURCE_DIR)/include -no-pie -fstack-protector-strong
CFLAGS := -MMD -ffreestanding -nostdlib -O1 -Wall -Wextra -Werror -std=c2x -I$(SOURCE_DIR)/include -no-pie -fstack-protector-strong -g3
CFLAGS += -Wno-unused-function
CFLAGS += -Wno-unused-variable
ASFLAGS :=
#$(info C_SOURCES is $(C_SOURCES))
@@ -34,7 +36,7 @@ ASFLAGS :=
#$(info DEPENDS is $(DEPENDS))
run: myos.iso
qemu-system-i386 -cdrom myos.iso
qemu-system-i386 -d int -no-reboot -cdrom myos.iso
cross-compiler: cross-compiler-image/Dockerfile
podman build cross-compiler-image -t cc-i686

View File

@@ -1,3 +0,0 @@
#pragma once
__attribute__((interrupt)) void interrupt_handler_1(struct interrupt_frame* frame);

View File

@@ -33,7 +33,7 @@ undefined behavior.
.section .bss
.align 16
stack_bottom:
.skip 16384 # 16 KiB
.skip 1024 * 16 # 16384, 16 KiB
stack_top:
/*

View File

@@ -4,7 +4,8 @@
#include "str.h"
#include "tty.h"
__attribute__((noreturn)) void panic(struct str s);
__attribute__((noreturn))
void panic(struct str s);
void* memmove(void *dest, const void *src, size_t n);
void* memset(void *s, int c, size_t n);

View File

@@ -32,23 +32,23 @@ struct gdt_table_entry gdt_encode_entry(struct gdt_entry_content content)
return entry;
}
void gdt_set(uint16_t size, const struct gdt_table_entry base[], uint32_t offset)
{
base += offset;
/* the lgdt instruction requires a packed alignment */
struct __attribute__((packed)) gdtr {
uint16_t size;
uint32_t base;
} gdt = {
.size = size,
.base = (uint32_t)base,
};
__asm__ volatile (
"lgdt %[gdt]"
:
: [gdt] "m"(gdt)
);
}
//void gdt_load(uint16_t size, const struct gdt_table_entry base[], uint32_t offset)
//{
// base += offset;
//
// /* the lgdt instruction requires a packed alignment */
// struct __attribute__((packed)) gdtr {
// uint16_t size;
// uint32_t base;
// } gdt = {
// .size = size,
// .base = (uint32_t)base,
// };
//
// __asm__ volatile (
// "lgdt %[gdt]"
// :
// : [gdt] "m"(gdt)
// );
//}

View File

@@ -1,5 +1,6 @@
#pragma once
#include <stdint.h>
#include "types.h"
#define GDT_LIMIT_MAX 0xFFFFF
@@ -46,23 +47,21 @@ enum gdt_access_flag : uint8_t {
};
enum gdt_flags : uint8_t {
GDT_RESERVED = (1<<0),
GDT_LONG = (1<<1),
GDT_SIZE = (1<<2),
GDT_GRANULARITY = (1<<3),
GDT_RESERVED = (1<<0),
GDT_LONG = (1<<1),
GDT_32BIT = (1<<2),
GDT_GRANULARITY_PAGEWISE = (1<<3),
};
void gdt_set(uint16_t limit, const struct gdt_table_entry base[], uint32_t offset);
struct gdt_table_entry gdt_encode_entry(struct gdt_entry_content content);
// only compiles with O1 or higher ¯\_(ツ)_/¯, might have to make this a macro
static inline void gdt_reload_granular(uint32_t code,
uint32_t data,
uint32_t extra_segment,
uint32_t general_segment_1,
uint32_t general_segment_2,
uint32_t stack_segment)
static inline void gdt_flush_granular(uint32_t code,
uint32_t data,
uint32_t extra_segment,
uint32_t general_segment_1,
uint32_t general_segment_2,
uint32_t stack_segment)
{
__asm__ volatile (
// Far jump to reload the CS register
@@ -88,10 +87,19 @@ static inline void gdt_reload_granular(uint32_t code,
: "ax" // Clobbered register
);
}
static inline void gdt_reload(uint32_t data, uint32_t code)
static inline void gdt_load(struct gdt_table_entry base[], uint16_t gdt_size, segment_t data, segment_t code)
{
/* the lgdt instruction requires a packed alignment */
struct __attribute__((packed)) {
uint16_t size;
uint32_t base;
} gdt = {
.size = gdt_size,
.base = (uint32_t)base,
};
__asm__ volatile (
"lgdt %[gdt]\n"
// Far jump to reload the CS register
"jmp %[cs], $reload_CS\n"
"reload_CS:\n"
@@ -103,8 +111,9 @@ static inline void gdt_reload(uint32_t data, uint32_t code)
"movw %%ax, %%gs\n"
"movw %%ax, %%ss\n"
: // No output operands
: [ds] "i"(data),
[cs] "i"(code)
: [gdt] "m"(gdt),
[ds] "i"(data),
[cs] "i"(code)
: "ax" // Clobbered register
);
}

View File

@@ -3,17 +3,18 @@
#include "idt.h"
struct idt_gate_descriptor idt_encode_descriptor(uint32_t offset, uint16_t segment_selector, uint8_t ist, enum idt_flags type)
struct idt_gate_descriptor idt_encode_descriptor(void* func, segment_t segment_selector, enum idt_dpl dpl, enum idt_flags type)
{
struct idt_gate_descriptor output = {0};
uint32_t offset = (uint32_t)func;
output.offset_0 = offset & 0xFFFF;
offset >>= 16;
output.offset_1 = offset & 0xFFFF;
output.segment_selector = segment_selector;
output.ist = ist;
output.flags = type | IDT_DPL_0 | IDT_PRESENT;
output.flags = type | dpl | IDT_PRESENT;
return output;
}

View File

@@ -1,11 +1,13 @@
#pragma once
#include <stdint.h>
#include "types.h"
struct __attribute__((packed)) idt_gate_descriptor {
uint16_t offset_0;
uint16_t segment_selector;
uint8_t ist;
uint8_t ist; // unused in 32-bit
/* `flags`
=======
@@ -20,22 +22,26 @@ struct __attribute__((packed)) idt_gate_descriptor {
uint16_t offset_1;
};
_Static_assert(sizeof(struct idt_gate_descriptor) == 8);
enum idt_flags : uint8_t {
IDT_GATE_TYPE_TASK_GATE = 0x5,
IDT_GATE_TYPE_INTERUPT_GATE_16 = 0x6,
IDT_GATE_TYPE_TRAP_GATE_16 = 0x7,
IDT_GATE_TYPE_INTERUPT_GATE_32 = 0xE,
IDT_GATE_TYPE_TRAP_GATE_32 = 0xF,
IDT_GATE_TYPE_TASK = 0x5,
IDT_GATE_TYPE_INTERRUPT16 = 0x6,
IDT_GATE_TYPE_TRAP16 = 0x7,
IDT_GATE_TYPE_INTERRUPT32 = 0xE,
IDT_GATE_TYPE_TRAP32 = 0xF,
IDT_PRESENT = 1 << 7,
};
enum idt_dpl : uint8_t {
IDT_DPL_0 = 0 << 5,
IDT_DPL_1 = 1 << 5,
IDT_DPL_2 = 2 << 5,
IDT_DPL_3 = 3 << 5,
IDT_PRESENT = 1 << 7,
};
struct idt_gate_descriptor idt_encode_descriptor(uint32_t offset, uint16_t segment_selector, uint8_t ist, enum idt_flags type);
struct idt_gate_descriptor idt_encode_descriptor(void* func, segment_t segment_selector, enum idt_dpl dpl, enum idt_flags type);
void idt_load(struct idt_gate_descriptor table[], uint16_t size);

View File

@@ -1,11 +1,10 @@
#include <stdint.h>
#include "libc.h"
#include "tty.h"
#include "interrupts.h"
#include "kernel_state.h"
#ifdef __x86_64__
typedef unsigned long long int uword_t;
#else
typedef unsigned int uword_t;
#endif
#define EXCEPTION_DEPTH_MAX 5
struct __attribute__((packed)) interrupt_frame {
uword_t ip;
@@ -15,7 +14,131 @@ struct __attribute__((packed)) interrupt_frame {
uword_t ss;
};
__attribute__((interrupt)) void interrupt_handler_1(struct interrupt_frame* frame)
static void print_interrupt_frame(struct interrupt_frame* f)
{
(void)frame;
printf(str_attach(
"Interrupt frame:\n"
"================\n"
"ip: {x32}\n"
"cs: {x32}\n"
"flags: {x32}\n"
"sp: {x32}\n"
"ss: {x32}\n"),
f->ip,
f->cs,
f->flags,
f->sp,
f->ss);
}
/**
* Exceptions
* ==========
*/
__attribute__((interrupt, noreturn))
void exception_handler_general_protection_fault(struct interrupt_frame* frame, int err)
{
if (kernel.nested_exception_counter++ > EXCEPTION_DEPTH_MAX) {
panic(str_attach("fatal: too many nested exceptions\n"));
}
//terminal_clear();
terminal_set_color(VGA_COLOR_WHITE, VGA_COLOR_RED);
printf(str_attach(
"general protection fault by segment selector {str} :(\n"),
gdt_segment_index_str[err/8]);
if (frame != NULL) {
print_interrupt_frame(frame);
}
__asm__ volatile("cli; hlt");
__builtin_unreachable();
}
__attribute__((interrupt, noreturn))
void exception_handler_double_fault(struct interrupt_frame* frame)
{
(void)frame;
if (kernel.nested_exception_counter++ > EXCEPTION_DEPTH_MAX) {
panic(str_attach("fatal: too many nested exceptions\n"));
}
panic(str_attach("double fault :("));
}
__attribute__((interrupt, noreturn))
void exception_handler_div_by_zero(struct interrupt_frame* frame)
{
(void)frame;
if (kernel.nested_exception_counter++ > EXCEPTION_DEPTH_MAX) {
panic(str_attach("fatal: too many nested exceptions\n"));
}
panic(str_attach("div by zero occured :("));
}
__attribute__((interrupt, noreturn))
void exception_handler_page_fault(struct interrupt_frame* frame, int err)
{
(void)frame;
if (kernel.nested_exception_counter++ > EXCEPTION_DEPTH_MAX) {
panic(str_attach("fatal: too many nested exceptions\n"));
}
terminal_set_color(VGA_COLOR_WHITE, VGA_COLOR_RED);
printf(str_attach(
"page fault :(, err: 0x{x32}\n"),
err,
gdt_segment_index_str[err/8]);
__asm__ volatile("cli; hlt");
__builtin_unreachable();
}
__attribute__((interrupt, noreturn))
void exception_default(struct interrupt_frame* frame)
{
(void)frame;
if (kernel.nested_exception_counter++ > EXCEPTION_DEPTH_MAX) {
panic(str_attach("fatal: too many nested exceptions\n"));
}
panic(str_attach("non-implemented exception occured"));
kernel.nested_exception_counter = 0;
}
/**
* Interrupts
* ==========
*/
__attribute__((interrupt, noreturn))
void interrupt_default(struct interrupt_frame* frame)
{
if (kernel.nested_exception_counter++ > EXCEPTION_DEPTH_MAX) {
panic(str_attach("fatal: too many nested exceptions\n"));
}
(void)frame;
panic(str_attach("non-implemented interrupt invoked"));
kernel.nested_exception_counter = 0;
}
__attribute__((interrupt))
void interrupt_handler_1(struct interrupt_frame* frame)
{
if (kernel.nested_exception_counter++ > EXCEPTION_DEPTH_MAX) {
panic(str_attach("fatal: too many nested exceptions\n"));
}
(void)frame;
printf(str_attach("interrupt_handler_1 called!\n"));
kernel.nested_exception_counter = 0;
}
__attribute__((interrupt))
void interrupt_handler_userspace_exit(struct interrupt_frame* frame)
{
if (kernel.nested_exception_counter++ > EXCEPTION_DEPTH_MAX) {
panic(str_attach("fatal: too many nested exceptions\n"));
}
(void)frame;
printf(str_attach("interrupt_handler_userspace_exit called!\n"));
kernel.nested_exception_counter = 0;
}

33
src/kernel/interrupts.h Normal file
View File

@@ -0,0 +1,33 @@
#pragma once
#include "types.h"
struct __attribute__((packed)) interrupt_frame {
uword_t ip;
uword_t cs;
uword_t flags;
uword_t sp;
uword_t ss;
};
__attribute__((interrupt, noreturn))
void exception_handler_div_by_zero(struct interrupt_frame* frame);
__attribute__((interrupt, noreturn))
void exception_handler_general_protection_fault(struct interrupt_frame* frame, int err);
__attribute__((interrupt, noreturn))
void exception_handler_double_fault(struct interrupt_frame* frame);
__attribute__((interrupt, noreturn))
void exception_default(struct interrupt_frame* frame);
__attribute__((interrupt, noreturn))
void interrupt_default(struct interrupt_frame* frame);
__attribute__((interrupt))
void interrupt_handler_1(struct interrupt_frame* frame);
__attribute__((interrupt))
void interrupt_handler_userspace_exit(struct interrupt_frame* frame);

View File

@@ -5,52 +5,69 @@
#include "gdt.h"
#include "tss.h"
#include "idt.h"
#include "interrupts.h"
#include "types.h"
#include "kernel_state.h"
// Future user-space
#include "libc.h"
#include "tty.h"
#include "str.h"
// TOOD: clean up this
typedef void(*func_t)(void*);
static void ring3_mode(uint32_t, uint32_t, uint32_t, uint32_t, func_t);
static void user_mode_code(void*);
void gdt_setup_flat_model()
static void pic_disable()
{
__asm__ volatile ("outb %0, %1"
:
: "a"((uint8_t)0xff), "Nd"((uint16_t)0x21)
: "memory");
__asm__ volatile ("outb %0, %1"
:
: "a"((uint8_t)0xff), "Nd"((uint16_t)0xA1)
: "memory");
}
/* copied and only slightly modified from an osdev wiki article with poor
taste, TODO: change
----------------------------------------------*/
static void user_mode_code(void*)
{
printf(str_attach("hello world :)\n"));
printf(str_attach("hello from user-space before interrupt :)\n"));
__asm__ volatile ("int $0x80");
__asm__ volatile ("int $0x81");
//while (1) /* busy loop */;
#if 0
printf(str_attach("hello from user-space before exception :)\n"));
/* test division by 0 exception */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdiv-by-zero"
volatile int a = 5/0;
(void)a;
#pragma GCC diagnostic pop
// should not happen
printf(str_attach("hello from userspace after interrupt and exception!\n"));
#endif
}
static void ring3_mode(uint32_t udata_offset, uint32_t udata_rpl, uint32_t ucode_offset, uint32_t ucode_rpl, func_t callback)
static void ring3_mode(segment_t udata_segment, segment_t ucode_segment, func_t callback)
{
const uint32_t udata = udata_offset | udata_rpl;
const uint32_t ucode = ucode_offset | ucode_rpl;
__asm__ volatile (
"mov %[udata], %%ax\n"
"mov %%ax, %%ds\n"
"mov %%ax, %%es\n"
"mov %%ax, %%fs\n"
"mov %%ax, %%gs\n"
"push %%ax\n"
"mov %[udata], %%ax\n"
"mov %%ax, %%ds\n"
"mov %%ax, %%es\n"
"mov %%ax, %%fs\n"
"mov %%ax, %%gs\n"
"push %%ax\n"
"mov %%esp, %%eax\n"
"push %%eax\n" // current esp
"push %%eax\n" // esp
"pushf\n" // eflags
"push %[ucode]\n"
"push %[callback]\n" // instruction address to return to
"iret"
:
: [udata] "m"(udata),
[ucode] "m"(ucode),
[callback] "m"(callback)
: [udata] "i"(udata_segment),
[ucode] "i"(ucode_segment),
[callback] "i"(callback)
: "eax"
);
}
@@ -65,25 +82,12 @@ void kernel_main(void)
{
__asm__ volatile("cli");
static struct tss tss = {0};
_Static_assert(sizeof(kernel.gdt) == 0x30);
enum segment_index : size_t {
null_segment = 0,
kernel_code_segment = 1,
kernel_data_segment = 2,
user_code_segment = 3,
user_data_segment = 4,
task_state_segment = 5,
segment_count,
};
static struct gdt_table_entry gdt[segment_count];
_Static_assert(sizeof(gdt) == 0x30);
gdt[null_segment] = gdt_encode_entry((struct gdt_entry_content){0});
kernel.gdt[SEGMENT_NULL] = gdt_encode_entry((struct gdt_entry_content){0});
/* kernel */
gdt[kernel_code_segment] = gdt_encode_entry((struct gdt_entry_content){
kernel.gdt[SEGMENT_KERNEL_CODE] = gdt_encode_entry((struct gdt_entry_content){
.base = 0,
.limit = GDT_LIMIT_MAX,
.access_byte = GDT_ACCESS_RW
@@ -91,21 +95,21 @@ void kernel_main(void)
| GDT_ACCESS_DESCRIPTOR
| GDT_ACCESS_DPL_0
| GDT_ACCESS_PRESENT,
.flags = GDT_SIZE
| GDT_GRANULARITY});
.flags = GDT_32BIT
| GDT_GRANULARITY_PAGEWISE});
gdt[kernel_data_segment] = gdt_encode_entry((struct gdt_entry_content){
kernel.gdt[SEGMENT_KERNEL_DATA] = gdt_encode_entry((struct gdt_entry_content){
.base = 0,
.limit = GDT_LIMIT_MAX,
.access_byte = GDT_ACCESS_RW
| GDT_ACCESS_DESCRIPTOR
| GDT_ACCESS_DPL_0
| GDT_ACCESS_PRESENT,
.flags = GDT_SIZE
| GDT_GRANULARITY});
.flags = GDT_32BIT
| GDT_GRANULARITY_PAGEWISE});
/* user */
gdt[user_code_segment] = gdt_encode_entry((struct gdt_entry_content) {
kernel.gdt[SEGMENT_USER_CODE] = gdt_encode_entry((struct gdt_entry_content) {
.base = 0,
.limit = GDT_LIMIT_MAX,
.access_byte = GDT_ACCESS_RW
@@ -113,54 +117,111 @@ void kernel_main(void)
| GDT_ACCESS_DESCRIPTOR
| GDT_ACCESS_DPL_3
| GDT_ACCESS_PRESENT,
.flags = GDT_SIZE
| GDT_GRANULARITY});
.flags = GDT_32BIT
| GDT_GRANULARITY_PAGEWISE});
gdt[user_data_segment] = gdt_encode_entry((struct gdt_entry_content) {
kernel.gdt[SEGMENT_USER_DATA] = gdt_encode_entry((struct gdt_entry_content) {
.base = 0,
.limit = GDT_LIMIT_MAX,
.access_byte = GDT_ACCESS_RW
| GDT_ACCESS_DESCRIPTOR
| GDT_ACCESS_DPL_3
| GDT_ACCESS_PRESENT,
.flags = GDT_SIZE
| GDT_GRANULARITY});
.flags = GDT_32BIT
| GDT_GRANULARITY_PAGEWISE});
/* tss */
gdt[task_state_segment] = gdt_encode_entry((struct gdt_entry_content) {
.base = (uint32_t)&tss,
.limit = sizeof(tss)-1,
kernel.gdt[SEGMENT_TASK_STATE] = gdt_encode_entry((struct gdt_entry_content) {
.base = (uint32_t)&kernel.tss,
.limit = sizeof(kernel.tss)-1,
.access_byte = GDT_ACCESS_ACCESSED
| GDT_ACCESS_EXEC
| GDT_ACCESS_DPL_0
| GDT_ACCESS_PRESENT,
.flags = 0});
gdt_set(sizeof gdt, gdt, 0);
gdt_reload(kernel_data_segment * sizeof (struct gdt_table_entry),
kernel_code_segment * sizeof (struct gdt_table_entry));
/* Setup the TSS */
tss.ss0 = kernel_data_segment * sizeof (struct gdt_table_entry);
tss.esp0 = 0; /* TODO: set kernel stack pointer */
memset(&kernel.tss, 0, sizeof kernel.tss);
kernel.tss.ss0 = segment(SEGMENT_KERNEL_DATA, SEGMENT_GDT, 0);
#if 1
static uint8_t kernel_stack[1024];
kernel.tss.esp0 = (uint32_t)kernel_stack;
#else
kernel.tss.esp0 = 0;
#endif
tss_load(task_state_segment * sizeof (struct gdt_table_entry));
#if 1
/* Setup the IDT */
for (size_t i = 0; i < 32; i++) {
kernel.idt[i] = idt_encode_descriptor(
exception_default,
segment(SEGMENT_KERNEL_CODE, SEGMENT_GDT, 0),
IDT_DPL_3,
IDT_GATE_TYPE_TRAP32);
}
for (size_t i = 32; i < IDT_COUNT; i++) {
kernel.idt[i] = idt_encode_descriptor(
interrupt_default,
segment(SEGMENT_KERNEL_CODE, SEGMENT_GDT, 0),
IDT_DPL_3,
IDT_GATE_TYPE_INTERRUPT32);
}
/* Setup the IDT */
//static struct idt_gate_descriptor idt[256] = {0};
kernel.idt[0x0] = idt_encode_descriptor(
exception_handler_div_by_zero,
segment(SEGMENT_KERNEL_CODE, SEGMENT_GDT, 0),
IDT_DPL_3,
IDT_GATE_TYPE_TRAP32
);
//struct idt_gate_descriptor idt_encode_descriptor(uint32_t offset, uint16_t segment_selector, uint8_t ist, enum idt_flags type);
//idt[80] = idt_encode_descriptor(interrupt_handler_1, kernel_code_segment, 0, IDT_GATE_TYPE_INTERUPT_GATE_32);
kernel.idt[0x8] = idt_encode_descriptor(
exception_handler_double_fault,
segment(SEGMENT_KERNEL_CODE, SEGMENT_GDT, 0),
IDT_DPL_3,
IDT_GATE_TYPE_TRAP32
);
//idt_load(idt, sizeof idt);
kernel.idt[0xD] = idt_encode_descriptor(
exception_handler_general_protection_fault,
segment(SEGMENT_KERNEL_CODE, SEGMENT_GDT, 0),
IDT_DPL_3,
IDT_GATE_TYPE_TRAP32
);
/* Finally go to ring 3 */
ring3_mode(user_data_segment * sizeof (struct gdt_table_entry), 3,
user_code_segment * sizeof (struct gdt_table_entry), 3,
user_mode_code);
// Interrupts
kernel.idt[0x80] = idt_encode_descriptor(
interrupt_handler_1,
segment(SEGMENT_KERNEL_CODE, SEGMENT_GDT, 0),
IDT_DPL_3,
IDT_GATE_TYPE_INTERRUPT32
);
kernel.idt[0x81] = idt_encode_descriptor(
interrupt_handler_userspace_exit,
segment(SEGMENT_KERNEL_CODE, SEGMENT_GDT, 0),
IDT_DPL_3,
IDT_GATE_TYPE_INTERRUPT32
);
#endif
/* Flush the gdt and tss */
gdt_load(kernel.gdt,
sizeof kernel.gdt,
segment(SEGMENT_KERNEL_DATA, SEGMENT_GDT, 0),
segment(SEGMENT_KERNEL_CODE, SEGMENT_GDT, 0));
tss_load(segment(SEGMENT_TASK_STATE, SEGMENT_GDT, 0));
idt_load(kernel.idt, sizeof kernel.idt);
/* enable interrupts */
__asm__ volatile("sti");
/* Finally go to ring 3 */
printf(str_attach("hello from kernel space!\n"));
pic_disable(); // temporary duct-tape
ring3_mode(segment(SEGMENT_USER_DATA, SEGMENT_GDT, 3),
segment(SEGMENT_USER_CODE, SEGMENT_GDT, 3),
user_mode_code);
}

18
src/kernel/kernel_state.c Normal file
View File

@@ -0,0 +1,18 @@
#include "str.h"
#include "kernel_state.h"
const struct str gdt_segment_index_str[SEGMENT_COUNT] = {
[SEGMENT_NULL ] = str_attach("SEGMENT_NULL"),
[SEGMENT_KERNEL_CODE] = str_attach("SEGMENT_KERNEL_CODE"),
[SEGMENT_KERNEL_DATA] = str_attach("SEGMENT_KERNEL_DATA"),
[SEGMENT_USER_CODE ] = str_attach("SEGMENT_USER_CODE"),
[SEGMENT_USER_DATA ] = str_attach("SEGMENT_USER_DATA"),
[SEGMENT_TASK_STATE ] = str_attach("SEGMENT_TASK_STATE"),
};
const struct str idt_index_str[IDT_COUNT] = {
};
struct kernel_state kernel = { 0 };

34
src/kernel/kernel_state.h Normal file
View File

@@ -0,0 +1,34 @@
#pragma once
#include "str.h"
#include "tss.h"
#include "idt.h"
#include "gdt.h"
enum gdt_segment_index : size_t {
SEGMENT_NULL,
SEGMENT_KERNEL_CODE,
SEGMENT_KERNEL_DATA,
SEGMENT_USER_CODE,
SEGMENT_USER_DATA,
SEGMENT_TASK_STATE,
SEGMENT_COUNT,
};
extern const struct str gdt_segment_index_str[SEGMENT_COUNT]; // reverse lookup enum -> str
enum idt_index : size_t {
IDT_COUNT = 256
};
extern const struct str idt_index_str[IDT_COUNT]; // reverse lookup enum -> str
constexpr size_t BACKTRACE_MAX = 256;
struct kernel_state {
struct tss tss;
struct gdt_table_entry gdt[SEGMENT_COUNT];
struct idt_gate_descriptor idt[IDT_COUNT];
int nested_exception_counter;
};
extern struct kernel_state kernel;

27
src/kernel/types.h Normal file
View File

@@ -0,0 +1,27 @@
#pragma once
typedef void(*func_t)(void*);
/* define uword_t per the instruction set manual */
#ifdef __x86_64__
typedef unsigned long long int uword_t;
#else
typedef unsigned int uword_t;
#endif
/* segment selectors identifies segments either in the gdt or the ldt */
typedef uint16_t segment_t;
enum segment_ti : uint16_t {
SEGMENT_GDT = 0,
SEGMENT_LDT = 1,
};
static inline segment_t segment(uint16_t index, enum segment_ti ti, uint16_t rpl)
{
return (index << 3) | ((ti & 0xF) << 1) | (rpl & 0xFF);
}

View File

@@ -15,10 +15,10 @@
__attribute__((noreturn))
void panic(struct str s)
{
terminal_clear();
//terminal_clear();
terminal_set_color(VGA_COLOR_WHITE, VGA_COLOR_RED);
terminal_write(s);
__asm__ volatile("hlt");
__asm__ volatile("cli; hlt");
__builtin_unreachable();
}

View File

@@ -31,12 +31,16 @@ static inline int ps_get(struct printf_state* s)
return s->str.data[s->i++];
}
static int print_long(unsigned long n, struct str alphabet, bool is_signed)
static int print_long(unsigned long n, struct str alphabet, bool is_signed, unsigned int padding, char pad_char)
{
constexpr size_t BUF_SZ = 21;
constexpr size_t BUF_SZ = 128;
char buf[BUF_SZ];
size_t i = 0;
if (padding > BUF_SZ) {
return -1;
}
if (n == 0) {
terminal_putchar('0');
return 1;
@@ -59,37 +63,60 @@ static int print_long(unsigned long n, struct str alphabet, bool is_signed)
buf[BUF_SZ-i] = alphabet.data[n % alphabet.len];
n /= alphabet.len;
}
while (i < padding) {
i += 1;
buf[BUF_SZ-i] = pad_char;
}
terminal_write((struct str){.data = &buf[BUF_SZ-i], .len = i});
return i;
}
static int print_i32(struct printf_state* s)
static int print_i32(struct printf_state* s, int padding, char pad_char)
{
padding = padding ? padding : 0;
pad_char = pad_char ? pad_char : ' ';
long n = va_arg(s->ap, int32_t);
return print_long(n, str_attach("0123456789"), true);
return print_long(n, str_attach("0123456789"), true, padding, pad_char);
}
static int print_u32(struct printf_state* s)
static int print_u32(struct printf_state* s, int padding, char pad_char)
{
padding = padding ? padding : 0;
pad_char = pad_char ? pad_char : ' ';
unsigned long n = va_arg(s->ap, uint32_t);
return print_long(n, str_attach("0123456789"), false);
return print_long(n, str_attach("0123456789"), false, padding, pad_char);
}
static int print_x32(struct printf_state* s)
static int print_x32(struct printf_state* s, int padding, char pad_char)
{
padding = padding ? padding : 0;
pad_char = pad_char ? pad_char : '0';
unsigned long n = va_arg(s->ap, uint32_t);
return print_long(n, str_attach("0123456789abcdefgh"), false);
struct str alphabet = str_attach("0123456789abcdef");
return print_long(n, alphabet, false, padding, pad_char);
}
static int print_str(struct printf_state* s)
static int print_b32(struct printf_state* s, int padding, char pad_char)
{
const struct str str = va_arg(s->ap, struct str);
for (size_t i=0; i < str.len; i++) {
terminal_putchar(str.data[i]);
}
return str.len;
padding = padding ? padding : 32;
pad_char = pad_char ? pad_char : '0';
unsigned long n = va_arg(s->ap, uint32_t);
struct str alphabet = str_attach("01");
return print_long(n, alphabet, false, padding, pad_char);
}
static int print_str(struct printf_state* s, int padding, char pad_char)
{
// TODO: implement padding
(void)padding;
(void)pad_char;
const struct str str = va_arg(s->ap, struct str);
for (size_t i=0; i < str.len; i++) {
terminal_putchar(str.data[i]);
}
return str.len;
}
#pragma GCC diagnostic ignored "-Wmultichar"
@@ -97,6 +124,8 @@ static int parse_format_cmd(struct printf_state* s)
{
int c;
uint32_t cmd = 0;
int pad = 0;
char pad_char = '\0';
constexpr uint32_t CHAR_MASK = (1<<CHAR_BIT)-1;
@@ -109,21 +138,21 @@ static int parse_format_cmd(struct printf_state* s)
return -1;
switch (cmd) {
// 16 bit types are promoted to 32 bit by va_arg(...) anyways
// 16 bit types are promoted to 32 bit by va_arg(...) anyways
case 'i16':
case 'i32':
return print_i32(s);
return print_i32(s, pad, pad_char);
case 'u16':
case 'u32':
return print_u32(s);
return print_u32(s, pad, pad_char);
case 'x16':
case 'x32':
return print_x32(s);
return print_x32(s, pad, pad_char);
case 'str':
return print_str(s);
case 'str':
return print_str(s, pad, pad_char);
default:
return -1;