more WIP
This commit is contained in:
12
Makefile
12
Makefile
@@ -9,6 +9,7 @@ SOURCE_DIR := src
|
||||
BUILD_DIR := build
|
||||
|
||||
CONTAINER_CMD := podman run -v "$(shell pwd)":"/scratch" \
|
||||
--rm \
|
||||
--workdir="/scratch" \
|
||||
--network=none \
|
||||
-e TERM \
|
||||
@@ -16,7 +17,7 @@ CONTAINER_CMD := podman run -v "$(shell pwd)":"/scratch" \
|
||||
cc-i686:latest
|
||||
|
||||
QEMU := qemu-system-i386
|
||||
QEMU_FLAGS := -d int -no-reboot
|
||||
QEMU_FLAGS := -no-reboot -serial stdio # -d int
|
||||
|
||||
CC := $(CONTAINER_CMD) i686-elf-gcc
|
||||
LD := $(CONTAINER_CMD) i686-elf-ld
|
||||
@@ -29,7 +30,7 @@ OBJECTS := $(patsubst $(SOURCE_DIR)/%, $(BUILD_DIR)/%, $(C_SOURCES:.c=.o) $(
|
||||
DEPENDS := $(patsubst $(SOURCE_DIR)/%, $(BUILD_DIR)/%, $(C_SOURCES:.c=.d))
|
||||
|
||||
CFLAGS := -ffreestanding -nostdlib -std=c2x -MMD -I$(SOURCE_DIR)/lib/include -I$(SOURCE_DIR) -no-pie
|
||||
CFLAGS += -O1 -g3
|
||||
CFLAGS += -O0 -g
|
||||
CFLAGS += -Wall -Wextra -Werror
|
||||
CFLAGS += -fstack-protector-strong -g3
|
||||
CFLAGS += -Wno-unused-function
|
||||
@@ -81,10 +82,9 @@ $(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.S Makefile
|
||||
|
||||
TEST_BUILD_DIR := $(BUILD_DIR)/tests
|
||||
|
||||
#TEST_SOURCES := $(shell find $(SOURCE_DIR) -name '*_test.c')
|
||||
#TEST_DEPENDS := $(patsubst $(SOURCE_DIR)/%, $(TEST_BUILD_DIR)/%, $(TEST_SOURCES:.c=.d))
|
||||
#TEST_OUTPUT := $(patsubst $(SOURCE_DIR)/%, $(TEST_BUILD_DIR)/%, $(TEST_SOURCES:.c=))
|
||||
|
||||
TEST_SOURCES := $(shell find $(SOURCE_DIR) -name '*_test.c')
|
||||
TEST_DEPENDS := $(patsubst $(SOURCE_DIR)/%, $(TEST_BUILD_DIR)/%, $(TEST_SOURCES:.c=.d))
|
||||
TEST_OUTPUT := $(patsubst $(SOURCE_DIR)/%, $(TEST_BUILD_DIR)/%, $(TEST_SOURCES:.c=))
|
||||
|
||||
tests: $(TEST_OUTPUT)
|
||||
$(info TEST_SOURCES is $(TEST_SOURCES))
|
||||
|
||||
@@ -52,3 +52,71 @@ struct gdt_table_entry gdt_encode_entry(struct gdt_entry_content content)
|
||||
// );
|
||||
//}
|
||||
|
||||
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
|
||||
"push %[cs]\n"
|
||||
"push $reload_CS_granular\n"
|
||||
"retf\n"
|
||||
|
||||
"reload_CS_granular:\n"
|
||||
"movw %[ds], %%ax\n"
|
||||
"movw %%ax, %%ds\n"
|
||||
"movw %[es], %%ax\n"
|
||||
"movw %%ax, %%es\n"
|
||||
"movw %[fs], %%ax\n"
|
||||
"movw %%ax, %%fs\n"
|
||||
"movw %[gs], %%ax\n"
|
||||
"movw %%ax, %%gs\n"
|
||||
"movw %[ss], %%ax\n"
|
||||
"movw %%ax, %%ss\n"
|
||||
: // No output operands
|
||||
: [cs] "m"(code),
|
||||
[ds] "m"(data),
|
||||
[es] "m"(extra_segment),
|
||||
[fs] "m"(general_segment_1),
|
||||
[gs] "m"(general_segment_2),
|
||||
[ss] "m"(stack_segment)
|
||||
: "ax" // Clobbered register
|
||||
);
|
||||
}
|
||||
|
||||
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
|
||||
"push %[cs]\n"
|
||||
"push $reload_CS\n"
|
||||
"retf\n"
|
||||
|
||||
"reload_CS:\n"
|
||||
// Load data segment into AX and then move it to all segment registers
|
||||
"movw %[ds], %%ax\n"
|
||||
"movw %%ax, %%ds\n"
|
||||
"movw %%ax, %%es\n"
|
||||
"movw %%ax, %%fs\n"
|
||||
"movw %%ax, %%gs\n"
|
||||
"movw %%ax, %%ss\n"
|
||||
: // No output operands
|
||||
: [gdt] "m"(gdt),
|
||||
[ds] "m"(data),
|
||||
[cs] "m"(code)
|
||||
: "ax" // Clobbered register
|
||||
);
|
||||
}
|
||||
|
||||
@@ -56,64 +56,11 @@ enum gdt_flags : uint8_t {
|
||||
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_flush_granular(uint32_t code,
|
||||
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
|
||||
"jmp %[cs], $reload_CS\n"
|
||||
"reload_CS:\n"
|
||||
"movw %[ds], %%ax\n"
|
||||
"movw %%ax, %%ds\n"
|
||||
"movw %[es], %%ax\n"
|
||||
"movw %%ax, %%es\n"
|
||||
"movw %[fs], %%ax\n"
|
||||
"movw %%ax, %%fs\n"
|
||||
"movw %[gs], %%ax\n"
|
||||
"movw %%ax, %%gs\n"
|
||||
"movw %[ss], %%ax\n"
|
||||
"movw %%ax, %%ss\n"
|
||||
: // No output operands
|
||||
: [cs] "i"(code),
|
||||
[ds] "i"(data),
|
||||
[es] "i"(extra_segment),
|
||||
[fs] "i"(general_segment_1),
|
||||
[gs] "i"(general_segment_2),
|
||||
[ss] "i"(stack_segment)
|
||||
: "ax" // Clobbered register
|
||||
);
|
||||
}
|
||||
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,
|
||||
};
|
||||
uint32_t stack_segment);
|
||||
|
||||
__asm__ volatile (
|
||||
"lgdt %[gdt]\n"
|
||||
// Far jump to reload the CS register
|
||||
"jmp %[cs], $reload_CS\n"
|
||||
"reload_CS:\n"
|
||||
// Load data segment into AX and then move it to all segment registers
|
||||
"movw %[ds], %%ax\n"
|
||||
"movw %%ax, %%ds\n"
|
||||
"movw %%ax, %%es\n"
|
||||
"movw %%ax, %%fs\n"
|
||||
"movw %%ax, %%gs\n"
|
||||
"movw %%ax, %%ss\n"
|
||||
: // No output operands
|
||||
: [gdt] "m"(gdt),
|
||||
[ds] "i"(data),
|
||||
[cs] "i"(code)
|
||||
: "ax" // Clobbered register
|
||||
);
|
||||
}
|
||||
void gdt_load(struct gdt_table_entry base[], uint16_t gdt_size, segment_t data, segment_t code);
|
||||
|
||||
@@ -17,16 +17,15 @@ struct __attribute__((packed)) interrupt_frame {
|
||||
uword_t ss;
|
||||
};
|
||||
|
||||
static void print_interrupt_frame(struct interrupt_frame* f)
|
||||
void print_interrupt_frame(struct interrupt_frame* f)
|
||||
{
|
||||
printf(str_attach(
|
||||
"Interrupt frame:\n"
|
||||
"================\n"
|
||||
"ip: {x32}\n"
|
||||
"cs: {x32} == {cs}\n"
|
||||
"flags: {x32}\n"
|
||||
"sp: {x32}\n"
|
||||
"ss: {x32}\n"),
|
||||
" - ip: {x32}\n"
|
||||
" - cs: {x32} ({cs})\n"
|
||||
" - flags: {x32}\n"
|
||||
" - sp: {x32}\n"
|
||||
" - ss: {x32}\n"),
|
||||
f->ip,
|
||||
f->cs,
|
||||
f->flags,
|
||||
@@ -106,38 +105,51 @@ void exception_handler_page_fault(struct interrupt_frame* frame, int err)
|
||||
}
|
||||
terminal_set_color(VGA_COLOR_WHITE, VGA_COLOR_RED);
|
||||
printf(str_attach(
|
||||
"page fault :(, err: 0x{x32}: ["),
|
||||
"=============\n"
|
||||
"PAGE FAULT :(\n"
|
||||
"=============\n"
|
||||
"Error: 0x{x32}: \n"),
|
||||
err);
|
||||
|
||||
/* page fault error bits */
|
||||
enum {
|
||||
present = 1<<0,
|
||||
write = 1<<1,
|
||||
user = 1<<2,
|
||||
reserved_write = 1<<3,
|
||||
instruction_fetch = 1<<4,
|
||||
protection_key = 1<<5,
|
||||
shadow_stack = 1<<6,
|
||||
software_guard_ex = 1<<15,
|
||||
present = 0,
|
||||
write = 1,
|
||||
user = 2,
|
||||
reserved_write = 3,
|
||||
instruction_fetch = 4,
|
||||
protection_key = 5,
|
||||
shadow_stack = 6,
|
||||
software_guard_ex = 15,
|
||||
|
||||
page_fault_error_count
|
||||
};
|
||||
|
||||
const struct str error_names[] = {
|
||||
[0] = str_attach("present"),
|
||||
[1] = str_attach("write"),
|
||||
[2] = str_attach("user"),
|
||||
[3] = str_attach("reserved_write"),
|
||||
[4] = str_attach("instruction_fetch"),
|
||||
[5] = str_attach("protection_key"),
|
||||
[6] = str_attach("shadow_stack"),
|
||||
[15] = str_attach("software_guard_ex"),
|
||||
static const struct str error_flag_str[page_fault_error_count] = {
|
||||
[present] = str_attach("Caused by a page-protection violation"),
|
||||
[write] = str_attach("Caused by a write access"),
|
||||
[user] = str_attach("Caused while CPL == 3 (not neccessarily a privilige escalation)"),
|
||||
[reserved_write] = str_attach("One or more page directory entries contain reserved bits which are set to 1"),
|
||||
[instruction_fetch] = str_attach("Caused by an instruction fetch"),
|
||||
[protection_key] = str_attach("Caused by a protection-key violation"),
|
||||
[shadow_stack] = str_attach("Caused by a shadow stack access"),
|
||||
[software_guard_ex] = str_attach("Caused by an SGX violation"),
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < sizeof error_names / sizeof *error_names; i++) {
|
||||
if ((err & (1<<i)) && error_names[i].data) {
|
||||
printf(str_attach("{str} | "), error_names[i]);
|
||||
static const struct str error_flag_zero_str[page_fault_error_count] = {
|
||||
[present] = str_attach("Caused by a non-present page"),
|
||||
[write] = str_attach("Caused by a read access"),
|
||||
[user] = str_attach("Caused while CPL != 3"),
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < page_fault_error_count; i++) {
|
||||
if ((err & (1<<i)) && error_flag_str[i].data) {
|
||||
printf(str_attach(" - {str}\n"), error_flag_str[i]);
|
||||
} else if (error_flag_zero_str[i].data) {
|
||||
printf(str_attach(" - {str}\n"), error_flag_zero_str[i]);
|
||||
}
|
||||
}
|
||||
printf(str_attach("0]\n"));
|
||||
printf(str_attach("\n"));
|
||||
|
||||
print_interrupt_frame(frame);
|
||||
|
||||
@@ -161,18 +173,6 @@ void interrupt_default(struct interrupt_frame* frame)
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* IRQs
|
||||
* ====
|
||||
|
||||
@@ -28,7 +28,7 @@ __attribute__((interrupt, noreturn))
|
||||
void interrupt_default(struct interrupt_frame* frame);
|
||||
|
||||
__attribute__((interrupt))
|
||||
void interrupt_handler_1(struct interrupt_frame* frame);
|
||||
void interrupt_handler_syscall(struct interrupt_frame* frame);
|
||||
|
||||
/**
|
||||
* IRQs
|
||||
|
||||
@@ -2,35 +2,43 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "file_system.h"
|
||||
#include "gdt.h"
|
||||
#include "tss.h"
|
||||
#include "idt.h"
|
||||
#include "interrupts.h"
|
||||
#include "types.h"
|
||||
#include "kernel_state.h"
|
||||
#include "pic.h"
|
||||
|
||||
#include "page.h"
|
||||
#include "pic.h"
|
||||
#include "serial.h"
|
||||
#include "tss.h"
|
||||
#include "types.h"
|
||||
|
||||
// Future user-space
|
||||
#include "libc.h"
|
||||
#include "tty.h"
|
||||
#include "str.h"
|
||||
#include "bitmap.h"
|
||||
#include "syscall.h"
|
||||
|
||||
uint32_t page_directory[1024] __attribute__((aligned(4096)));
|
||||
uint32_t page_table[1024] __attribute__((aligned(4096)));
|
||||
_Static_assert(((uint32_t)page_table & 0xfff) == 0);
|
||||
_Static_assert(((uint32_t)page_directory & 0xfff) == 0);
|
||||
#define syscall(number, b, c, d) \
|
||||
__asm__ volatile( \
|
||||
"int $0x80\n" \
|
||||
: \
|
||||
: "a"(number), \
|
||||
"b"(b), \
|
||||
"c"(c), \
|
||||
"d"(d) \
|
||||
: "memory" \
|
||||
);
|
||||
|
||||
static void user_mode_code(void*)
|
||||
{
|
||||
printf(str_attach("hello from user-space before interrupt :)\n"));
|
||||
__asm__ volatile ("int $0x80");
|
||||
|
||||
//printf(str_attach("hello from user-space before interrupt :)\n"));
|
||||
//__asm__ volatile ("int $0x80");
|
||||
int output;
|
||||
syscall(SYSCALL_PRINT, &str_attach("hello from ring 3\n"), 0, 0);
|
||||
#if 0
|
||||
printf(str_attach("hello from user-space before exception :)\n"));
|
||||
/* test division by 0 exception */
|
||||
syscall(SYSCALL_PRINT, &str_attach("trying to divide by zero :)\n"), 0, 0);
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdiv-by-zero"
|
||||
volatile int a = 5/0;
|
||||
@@ -38,9 +46,13 @@ static void user_mode_code(void*)
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
// should not happen
|
||||
printf(str_attach("hello from userspace after interrupt and exception!\n"));
|
||||
syscall(SYSCALL_PRINT, &str_attach("hello from userspace after interrupt and exception!\n"), 0, 0);
|
||||
#endif
|
||||
|
||||
syscall(SYSCALL_EXIT, 0, 0, 0);
|
||||
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
static void ring3_mode(segment_t udata_segment, segment_t ucode_segment, func_t callback)
|
||||
@@ -60,9 +72,9 @@ static void ring3_mode(segment_t udata_segment, segment_t ucode_segment, func_t
|
||||
"push %[callback]\n"
|
||||
"iret"
|
||||
:
|
||||
: [udata] "i"(udata_segment),
|
||||
[ucode] "i"(ucode_segment),
|
||||
[callback] "i"(callback)
|
||||
: [udata] "m"(udata_segment),
|
||||
[ucode] "m"(ucode_segment),
|
||||
[callback] "m"(callback)
|
||||
: "eax"
|
||||
);
|
||||
}
|
||||
@@ -78,6 +90,13 @@ void kernel_main(void)
|
||||
__asm__ volatile("cli");
|
||||
|
||||
|
||||
/* Set up the serial port
|
||||
* ======================
|
||||
*/
|
||||
if (serial_init(SERIAL_COM1, 3) != 0) {
|
||||
panic(str_attach("serial_init failed"));
|
||||
}
|
||||
|
||||
/* Set up the GDT
|
||||
* ============== */
|
||||
kernel.gdt[SEGMENT_NULL] = gdt_encode_entry((struct gdt_entry_content){0});
|
||||
@@ -190,7 +209,7 @@ void kernel_main(void)
|
||||
kernel.idt[IDT_DESC_PIC2 + 7] = mint(irq_handler_15);
|
||||
|
||||
/* Interrupts */
|
||||
kernel.idt[IDT_DESC_INTERRUPT_SYSCALL] = mint(interrupt_handler_1);
|
||||
kernel.idt[IDT_DESC_INTERRUPT_SYSCALL] = mint(interrupt_handler_syscall);
|
||||
#undef mtrap
|
||||
#undef mint
|
||||
#undef m_idt_default
|
||||
@@ -208,7 +227,17 @@ void kernel_main(void)
|
||||
/* enable interrupts */
|
||||
__asm__ volatile("sti");
|
||||
|
||||
printf(str_attach("setting up paging...\n"));
|
||||
/*
|
||||
* File system setup
|
||||
* =================
|
||||
* */
|
||||
printf(str_attach("Testing file system...\n"));
|
||||
{
|
||||
int ok = test_file_system();
|
||||
if (ok != 0) {
|
||||
panic(str_attach("test_file_system() returned non-zero value"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Paging setup
|
||||
@@ -216,24 +245,35 @@ void kernel_main(void)
|
||||
* We align by 1<<12 because page directory and page table entries store
|
||||
* addresses from bit 12-31
|
||||
*
|
||||
* For now give user access to pages to avoid a page fault
|
||||
* For now give user access to pages to avoid a page fault, since it's not
|
||||
* implemented properly
|
||||
*/
|
||||
for (size_t i = 0; i < sizeof page_table / sizeof *page_table; i++) {
|
||||
page_directory[i] = PDE_WRITE;
|
||||
}
|
||||
printf(str_attach("setting up paging...\n"));
|
||||
|
||||
for (size_t i = 0; i < sizeof page_table / sizeof *page_table; i++) {
|
||||
page_table[i] = PTE_ADDRESS(i) | PTE_WRITE | PTE_PRESENT | PTE_USER;
|
||||
}
|
||||
static uint32_t page_directory[1024] __attribute__((aligned(4096)));
|
||||
static uint32_t page_table_0[1024] __attribute__((aligned(4096)));
|
||||
_Static_assert(((uint32_t)page_directory & 0xfff) == 0);
|
||||
_Static_assert(((uint32_t)page_table_0 & 0xfff) == 0);
|
||||
|
||||
page_directory[0] = ((uint32_t)page_table) | PDE_WRITE | PDE_PRESENT | PDE_USER_ACCESS;
|
||||
for (size_t i = 0; i < sizeof page_directory / sizeof *page_directory; i++) {
|
||||
page_directory[i] = PDE_WRITE; /* no present bit */
|
||||
}
|
||||
page_directory[1023] = (uint32_t)page_directory;
|
||||
|
||||
for (size_t i = 0; i < sizeof page_table_0 / sizeof *page_table_0; i++) {
|
||||
// for now this page table allows user-space code to access
|
||||
// kernel-space memory (PTE_USER)
|
||||
page_table_0[i] = PTE_ADDRESS(i) | PTE_WRITE | PTE_PRESENT | PTE_USER;
|
||||
}
|
||||
page_directory[0] = ((uint32_t)page_table_0) | PDE_WRITE | PDE_PRESENT | PDE_USER_ACCESS;
|
||||
|
||||
cr3_set((uint32_t)page_directory);
|
||||
cr0_flags_set(CR0_PAGING);
|
||||
cr0_flags_set(CR0_PAGING | CR0_PROTECTED_MODE);
|
||||
|
||||
printf(str_attach("done!\n"));
|
||||
|
||||
printf(str_attach("starting code in ring 3...\n"));
|
||||
|
||||
/* Finally go to ring 3 */
|
||||
ring3_mode(segment(SEGMENT_USER_DATA, SEGMENT_GDT, 3),
|
||||
segment(SEGMENT_USER_CODE, SEGMENT_GDT, 3),
|
||||
@@ -241,9 +281,6 @@ void kernel_main(void)
|
||||
|
||||
printf(str_attach("back to kernel mode...\n"));
|
||||
|
||||
while (1)
|
||||
/* busy loop */;
|
||||
|
||||
__asm__ volatile ("hlt");
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +70,24 @@ enum idt_desc_index : size_t {
|
||||
|
||||
/* IRQ offsets */
|
||||
IDT_DESC_PIC1 = 32,
|
||||
IDT_DESC_PIC2 = IDT_DESC_PIC1 + 8,
|
||||
IDT_DESC_TIMER = IDT_DESC_PIC1 + 0,
|
||||
IDT_DESC_KEYBOARD = IDT_DESC_PIC1 + 1,
|
||||
IDT_DESC_CASCADE = IDT_DESC_PIC1 + 2,
|
||||
IDT_DESC_COM2 = IDT_DESC_PIC1 + 3,
|
||||
IDT_DESC_COM1 = IDT_DESC_PIC1 + 4,
|
||||
IDT_DESC_LPT2 = IDT_DESC_PIC1 + 5,
|
||||
IDT_DESC_FLOPPY_DISK = IDT_DESC_PIC1 + 6,
|
||||
IDT_DESC_SPURIOUS = IDT_DESC_PIC1 + 7,
|
||||
|
||||
IDT_DESC_PIC2 = 40,
|
||||
IDT_DESC_CMOS = IDT_DESC_PIC2 + 0,
|
||||
IDT_DESC_FREE1 = IDT_DESC_PIC2 + 1,
|
||||
IDT_DESC_FREE2 = IDT_DESC_PIC2 + 2,
|
||||
IDT_DESC_FREE3 = IDT_DESC_PIC2 + 3,
|
||||
IDT_DESC_PS2_MOUSE = IDT_DESC_PIC2 + 4,
|
||||
IDT_DESC_FPU = IDT_DESC_PIC2 + 5,
|
||||
IDT_DESC_ATA1 = IDT_DESC_PIC2 + 6,
|
||||
IDT_DESC_ATA2 = IDT_DESC_PIC2 + 7,
|
||||
|
||||
/* Software Interrupts */
|
||||
IDT_DESC_INTERRUPT_SYSCALL = 128,
|
||||
|
||||
@@ -67,25 +67,25 @@ void pic8259_clear_irq_mask(uint16_t mask)
|
||||
* https://wiki.osdev.org/8259_PIC#ISR_and_IRR
|
||||
* ===========================================
|
||||
* */
|
||||
static uint16_t get_irq_reg(int ocw3)
|
||||
{
|
||||
/* OCW3 to PIC CMD to get the register values. PIC2 is chained, and
|
||||
represents IRQs 8-15. PIC1 is IRQs 0-7, with 2 being the chain */
|
||||
outb(PIC1_COMMAND, ocw3);
|
||||
outb(PIC2_COMMAND, ocw3);
|
||||
return (inb(PIC2_COMMAND) << 8) | inb(PIC1_COMMAND);
|
||||
}
|
||||
|
||||
/* Returns the combined value of the cascaded PICs irq request register */
|
||||
uint16_t pic8259_get_irr(void)
|
||||
{
|
||||
return get_irq_reg(OCW3_READ_IRR);
|
||||
}
|
||||
|
||||
/* Returns the combined value of the cascaded PICs in-service register */
|
||||
uint16_t pic8259_get_isr(void)
|
||||
{
|
||||
return get_irq_reg(OCW3_READ_ISR);
|
||||
}
|
||||
|
||||
/* =========================================== */
|
||||
//static uint16_t get_irq_reg(int ocw3)
|
||||
//{
|
||||
// /* OCW3 to PIC CMD to get the register values. PIC2 is chained, and
|
||||
// represents IRQs 8-15. PIC1 is IRQs 0-7, with 2 being the chain */
|
||||
// outb(PIC1_COMMAND, ocw3);
|
||||
// outb(PIC2_COMMAND, ocw3);
|
||||
// return (inb(PIC2_COMMAND) << 8) | inb(PIC1_COMMAND);
|
||||
//}
|
||||
//
|
||||
///* Returns the combined value of the cascaded PICs irq request register */
|
||||
//uint16_t pic8259_get_irr(void)
|
||||
//{
|
||||
// return get_irq_reg(OCW3_READ_IRR);
|
||||
//}
|
||||
//
|
||||
///* Returns the combined value of the cascaded PICs in-service register */
|
||||
//uint16_t pic8259_get_isr(void)
|
||||
//{
|
||||
// return get_irq_reg(OCW3_READ_ISR);
|
||||
//}
|
||||
//
|
||||
///* =========================================== */
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include "str.h"
|
||||
#include "serial.h"
|
||||
|
||||
enum pic8259_port : uint16_t {
|
||||
PIC1_COMMAND = 0x20,
|
||||
@@ -141,29 +142,6 @@ enum ocw3_command : uint8_t {
|
||||
OCW3_SET_SPECIAL_MASK = (1<<3) | OCW3_BIT_ESMM | OCW3_BIT_SMM,
|
||||
};
|
||||
|
||||
static inline void outb(uint16_t port, uint8_t signal)
|
||||
{
|
||||
__asm__ volatile ("outb %[signal], %[port]"
|
||||
:
|
||||
: [signal] "a" (signal),
|
||||
[port] "Nd" (port)
|
||||
: "memory");
|
||||
#ifdef ADD_IO_WAIT
|
||||
/* do an I/O operation on an unused port to wait 1-4 microseconds */
|
||||
outb(0x80, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint8_t inb(uint16_t port)
|
||||
{
|
||||
uint8_t ret;
|
||||
__asm__ volatile ( "inb %w1, %b0"
|
||||
: "=a"(ret)
|
||||
: "Nd"(port)
|
||||
: "memory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
void pic8259_remap(int offset1, int offset2);
|
||||
|
||||
void pic8259_set_irq_mask(uint16_t mask);
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include "tty.h"
|
||||
#include "libc.h"
|
||||
|
||||
#include "serial.h"
|
||||
|
||||
static struct terminal_state t = {
|
||||
.row = 0,
|
||||
.column = 0,
|
||||
@@ -62,6 +64,8 @@ void terminal_scroll(int n)
|
||||
|
||||
void terminal_putchar(int c)
|
||||
{
|
||||
serial_putchar(SERIAL_COM1, c);
|
||||
|
||||
/* clear the cursor marker */
|
||||
terminal_putentryat(' ', t.color, t.column, t.row);
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include "bitmap.h"
|
||||
#include <limits.h>
|
||||
|
||||
static constexpr struct bitmap B = {0};
|
||||
static constexpr struct bitmap B = {0}; /* <-- just used on the line below */
|
||||
static constexpr size_t bits_per_index = sizeof (B.data[0]) * CHAR_BIT;
|
||||
|
||||
#define mask(n) ((1<<(n))-1)
|
||||
@@ -16,6 +16,19 @@ static inline int trailing_zeroes(int n)
|
||||
return __builtin_ctz(n);
|
||||
}
|
||||
|
||||
int bitmap_find(const struct bitmap* bitmap, int val)
|
||||
{
|
||||
for (size_t i = 0; i < bitmap->bit_count / bits_per_index; i++) {
|
||||
auto x = val == 0
|
||||
? ~bitmap->data[i]
|
||||
: bitmap->data[i];
|
||||
if (x != 0) {
|
||||
return i * bits_per_index + trailing_zeroes(x);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int bitmap_set_range(struct bitmap* bitmap, size_t begin, size_t end)
|
||||
{
|
||||
if (end < begin) {
|
||||
|
||||
@@ -292,5 +292,24 @@ int main()
|
||||
|
||||
} while (0);
|
||||
|
||||
test_begin("test bitmap_find()");
|
||||
do {
|
||||
uint32_t data[4] = {0};
|
||||
struct bitmap b = BITMAP_ATTACH(data, sizeof data);
|
||||
constexpr size_t pos = 42;
|
||||
int ok = bitmap_set(&b, pos);
|
||||
if (ok != 0) {
|
||||
test_fail("bitmap_set() failed while testing bitmap_find()");
|
||||
break;
|
||||
}
|
||||
int found = bitmap_find(&b, 1);
|
||||
if (found != pos) {
|
||||
test_fail("bitmap_find() failed, expected %zu, got %i", pos, found);
|
||||
break;
|
||||
}
|
||||
|
||||
test_ok("bitmap_find() ok! pos: %zu, found: %i", pos, found);
|
||||
} while (0);
|
||||
|
||||
return g_status;
|
||||
}
|
||||
|
||||
@@ -14,10 +14,12 @@ struct bitmap {
|
||||
* buf_size: size of buffer in bytes */
|
||||
#define BITMAP_ATTACH(buf, buf_size) (struct bitmap){.bit_count = buf_size * CHAR_BIT, .data = buf}
|
||||
|
||||
/*
|
||||
* Set the bit value at `index`
|
||||
* */
|
||||
static inline int bitmap_set(struct bitmap* bitmap, size_t index)
|
||||
{
|
||||
constexpr size_t bits_per_index = sizeof (bitmap->data[0]) * CHAR_BIT;
|
||||
_Static_assert(bits_per_index == 32);
|
||||
if (unlikely(index > bitmap->bit_count)) {
|
||||
return -1;
|
||||
}
|
||||
@@ -25,6 +27,9 @@ static inline int bitmap_set(struct bitmap* bitmap, size_t index)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unset the bit value at `index`
|
||||
* */
|
||||
static inline int bitmap_unset(struct bitmap* bitmap, size_t index)
|
||||
{
|
||||
constexpr size_t bits_per_index = sizeof (bitmap->data[0]) * CHAR_BIT;
|
||||
@@ -35,7 +40,10 @@ static inline int bitmap_unset(struct bitmap* bitmap, size_t index)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int bitmap_get(struct bitmap* bitmap, size_t index)
|
||||
/*
|
||||
* Get the bit value at `index`
|
||||
* */
|
||||
static inline int bitmap_get(const struct bitmap* bitmap, size_t index)
|
||||
{
|
||||
constexpr size_t bits_per_index = sizeof (bitmap->data[0]) * CHAR_BIT;
|
||||
if (unlikely(index > bitmap->bit_count)) {
|
||||
@@ -44,6 +52,23 @@ static inline int bitmap_get(struct bitmap* bitmap, size_t index)
|
||||
return !!(bitmap->data[index / bits_per_index] & (1ULL << (index % bits_per_index)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Finds the index of a bit with value `val`.
|
||||
* Returns -1 if none are found
|
||||
* */
|
||||
int bitmap_find(const struct bitmap* bitmap, int val);
|
||||
|
||||
/*
|
||||
* Sets the range begin..end, end exclusive
|
||||
*/
|
||||
int bitmap_set_range(struct bitmap* bitmap, size_t begin, size_t end);
|
||||
|
||||
/*
|
||||
* Clears the range begin..end, end exclusive
|
||||
*/
|
||||
int bitmap_clear_range(struct bitmap* bitmap, size_t begin, size_t end);
|
||||
|
||||
/*
|
||||
* Returns true if a range is empty
|
||||
*/
|
||||
int bitmap_range_empty(struct bitmap* bitmap, size_t begin, size_t end);
|
||||
|
||||
@@ -1,11 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
#include "str.h"
|
||||
|
||||
__attribute__((noreturn))
|
||||
void panic(struct str s);
|
||||
|
||||
/* bit_ceil returns the smallest power of 2 greater than `n` */
|
||||
static inline uint32_t bit_ceil32(uint32_t n)
|
||||
{
|
||||
/* __builtin_clz is undefined for n = 0 */
|
||||
return n
|
||||
? 1 << (sizeof(n)*CHAR_BIT - __builtin_clz(n))
|
||||
: 1;
|
||||
}
|
||||
|
||||
void* memmove(void *dest, const void *src, size_t n);
|
||||
void* memset(void *s, int c, size_t n);
|
||||
void* memcpy(void *dest, const void *src, size_t n);
|
||||
|
||||
@@ -4,3 +4,8 @@
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
|
||||
#define MEMBER_TYPE(parent_type, member) \
|
||||
typeof(((parent_type){0}).member)
|
||||
|
||||
#define MEMBER_SIZE(type, member) \
|
||||
(sizeof (((type){0}).member))
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
#pragma once
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct str {
|
||||
const char* data;
|
||||
const size_t len;
|
||||
};
|
||||
|
||||
#define str_attach(cstr) (struct str){.data = cstr, .len = sizeof(cstr)-1}
|
||||
#define str_attach(cstr) ((struct str){.data = cstr, .len = sizeof(cstr)-1})
|
||||
|
||||
/*
|
||||
* Returns a slice of `s`, `end`-exclusive
|
||||
* str_slice("hello", 1, 4) would return "ell"
|
||||
* */
|
||||
static inline struct str str_slice(struct str s, size_t begin, size_t end)
|
||||
{
|
||||
return (struct str) {
|
||||
@@ -17,5 +22,16 @@ static inline struct str str_slice(struct str s, size_t begin, size_t end)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* If a and b are not equal, str_compare returns the index where a and b
|
||||
* diverges. Otherwise returns -1
|
||||
*/
|
||||
bool str_equals(struct str a, struct str b);
|
||||
|
||||
/**
|
||||
* If a and b are equals, str_compare returns true, otherwise returns false
|
||||
*/
|
||||
int str_compare(struct str a, struct str b);
|
||||
|
||||
#define CSTR_(x) #x
|
||||
#define CSTR(x) CSTR_(x)
|
||||
|
||||
@@ -5,9 +5,15 @@
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include "kernel/tty.h"
|
||||
#include "str.h"
|
||||
|
||||
/*
|
||||
* Math functions
|
||||
* ==============
|
||||
*/
|
||||
|
||||
/*
|
||||
* Error handling
|
||||
* ==============
|
||||
|
||||
@@ -121,12 +121,22 @@ static int print_str(struct printf_state* s, int padding, char pad_char)
|
||||
return str.len;
|
||||
}
|
||||
|
||||
static inline bool isspace(char ch)
|
||||
{
|
||||
return ch == '\n' || ch == ' ' || ch == '\t';
|
||||
}
|
||||
|
||||
static inline bool isprint(char ch)
|
||||
{
|
||||
return (ch >= 32 && ch < 127) || isspace(ch);
|
||||
}
|
||||
|
||||
static int print_char(struct printf_state* s)
|
||||
{
|
||||
// char is promoted to int when passed through va_arg
|
||||
const int ch = va_arg(s->ap, int);
|
||||
|
||||
if (ch >= 32 && ch < 127) {
|
||||
if (isprint(ch)) {
|
||||
terminal_putchar(ch);
|
||||
return 1;
|
||||
} else {
|
||||
@@ -134,6 +144,30 @@ static int print_char(struct printf_state* s)
|
||||
}
|
||||
}
|
||||
|
||||
static int print_cstr(struct printf_state* s, int padding, char pad_char)
|
||||
{
|
||||
// TODO: implement padding
|
||||
(void)padding;
|
||||
(void)pad_char;
|
||||
|
||||
const char* cstr = va_arg(s->ap, const char*);
|
||||
char ch;
|
||||
int written = 0;
|
||||
while ((ch = *(cstr++))) {
|
||||
if (isprint(ch)) {
|
||||
terminal_putchar(ch);
|
||||
} else {
|
||||
terminal_putchar('{');
|
||||
written += print_long(ch, str_attach("0123456789ABCDEF"), false, 0, 0);
|
||||
terminal_putchar('}');
|
||||
written += 2;
|
||||
}
|
||||
written += 1;
|
||||
}
|
||||
return written;
|
||||
}
|
||||
|
||||
/* cs register */
|
||||
static int print_cs(struct printf_state* s)
|
||||
{
|
||||
int n;
|
||||
@@ -161,7 +195,7 @@ static int print_cs(struct printf_state* s)
|
||||
}
|
||||
|
||||
unsigned int ring = (cs>>5) & 0b11;
|
||||
n = printf(str_attach("DPL({uint})"), ring);
|
||||
n = printf(str_attach("DPL:{uint}"), ring);
|
||||
if (n == -1) {
|
||||
return -1;
|
||||
}
|
||||
@@ -206,6 +240,9 @@ static int parse_format_cmd(struct printf_state* s)
|
||||
case 'x32':
|
||||
return print_x32(s, pad, pad_char);
|
||||
|
||||
case 'cstr':
|
||||
return print_cstr(s, pad, pad_char);
|
||||
|
||||
case 'str':
|
||||
return print_str(s, pad, pad_char);
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
#include "str.h"
|
||||
#include <stdint.h>
|
||||
|
||||
int str_compare(struct str a, struct str b)
|
||||
{
|
||||
const size_t min_len = a.len > b.len
|
||||
? b.len
|
||||
: a.len;
|
||||
for (size_t i = 0; i < min_len; i++) {
|
||||
if (a.data[i] != b.data[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool str_equals(struct str a, struct str b)
|
||||
{
|
||||
if (a.len != b.len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return str_compare(a, b) == -1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user