summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTyler Murphy <=>2023-07-16 02:54:32 -0400
committerTyler Murphy <=>2023-07-16 02:54:32 -0400
commitfbf131b5c043b27e0b1543374bb144e3e426f723 (patch)
tree07f0ab2fc107b36621d5ae95480e6a91e332548b
downloadfinix-fbf131b5c043b27e0b1543374bb144e3e426f723.tar.gz
finix-fbf131b5c043b27e0b1543374bb144e3e426f723.tar.bz2
finix-fbf131b5c043b27e0b1543374bb144e3e426f723.zip
initial
-rw-r--r--.env9
-rw-r--r--.gitignore4
-rw-r--r--Makefile29
-rw-r--r--grub.cfg8
-rw-r--r--kernel/Makefile28
-rw-r--r--kernel/compile_flags.txt12
-rw-r--r--kernel/include/keycodes.h127
-rw-r--r--kernel/include/panic.h6
-rw-r--r--kernel/include/print.h23
-rw-r--r--kernel/linker.ld31
-rw-r--r--kernel/src/acpi/acpi.c141
-rw-r--r--kernel/src/acpi/acpi.h106
-rw-r--r--kernel/src/boot/tag.c91
-rw-r--r--kernel/src/boot/tag.h38
-rw-r--r--kernel/src/cpu/cpu.c20
-rw-r--r--kernel/src/cpu/cpu.h3
-rw-r--r--kernel/src/cpu/fpu.asm19
-rw-r--r--kernel/src/cpu/sse.asm22
-rw-r--r--kernel/src/drivers/ps2ctrl.c99
-rw-r--r--kernel/src/drivers/ps2ctrl.h14
-rw-r--r--kernel/src/drivers/ps2kb.c130
-rw-r--r--kernel/src/drivers/ps2kb.h15
-rw-r--r--kernel/src/drivers/ps2mouse.c89
-rw-r--r--kernel/src/drivers/ps2mouse.h18
-rw-r--r--kernel/src/graphics/framebuffer.h15
-rw-r--r--kernel/src/interrupt/idt.c108
-rw-r--r--kernel/src/interrupt/idt.h36
-rw-r--r--kernel/src/interrupt/isr.asm99
-rw-r--r--kernel/src/interrupt/pic.c85
-rw-r--r--kernel/src/interrupt/pic.h11
-rw-r--r--kernel/src/main.c68
-rw-r--r--kernel/src/memory/allocator.c314
-rw-r--r--kernel/src/memory/memory.c202
-rw-r--r--kernel/src/memory/memory.h22
-rw-r--r--kernel/src/print/panic.c27
-rw-r--r--kernel/src/print/print.c128
-rw-r--r--kernel/src/start.asm75
-rw-r--r--kernel/src/tty/color.c67
-rw-r--r--kernel/src/tty/color.h62
-rw-r--r--kernel/src/tty/cursor.c30
-rw-r--r--kernel/src/tty/cursor.h9
-rw-r--r--kernel/src/tty/term.c131
-rw-r--r--kernel/src/tty/term.h27
-rw-r--r--libk/Makefile20
-rw-r--r--libk/compile_flags.txt10
-rw-r--r--libk/include/ctype.h4
-rw-r--r--libk/include/math.h62
-rw-r--r--libk/include/stdlib.h25
-rw-r--r--libk/include/string.h13
-rw-r--r--libk/include/sys.h51
-rw-r--r--libk/src/ctype.c19
-rw-r--r--libk/src/internal/libm.h32
-rw-r--r--libk/src/math/abs.c14
-rw-r--r--libk/src/math/ceil.c59
-rw-r--r--libk/src/math/copysign.c20
-rw-r--r--libk/src/math/fact.c29
-rw-r--r--libk/src/math/fclamp.c13
-rw-r--r--libk/src/math/floor.c55
-rw-r--r--libk/src/math/fma.c38
-rw-r--r--libk/src/math/fmod.c129
-rw-r--r--libk/src/math/frexp.c19
-rw-r--r--libk/src/math/pow.c152
-rw-r--r--libk/src/math/sqrt.c36
-rw-r--r--libk/src/math/trig.c62
-rw-r--r--libk/src/stdlib.c164
-rw-r--r--libk/src/string.c61
66 files changed, 3685 insertions, 0 deletions
diff --git a/.env b/.env
new file mode 100644
index 0000000..ab3cca2
--- /dev/null
+++ b/.env
@@ -0,0 +1,9 @@
+CC=i386-elf-gcc
+LD=i386-elf-ld
+AS=nasm
+AR=ar
+
+CFLAGS=-ffreestanding -m32 -O2 -Wall -Wextra -pedantic -DKERNEL_LOG
+LDFLAGS=-nostdlib
+
+QEMU=qemu-system-i386
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..bf6638d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+/boot
+/os.iso
+/kernel/bin
+/libk/bin
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..c684312
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,29 @@
+include .env
+
+.PHONY: all libk kernel
+
+all: os.iso
+
+libk:
+ make --directory=libk
+
+kernel:
+ make --directory=kernel
+
+os.iso: libk kernel
+ rm -fr os.iso
+ mkdir -p boot/grub
+ cp grub.cfg boot/grub
+ cp kernel/bin/kernel.bin boot
+ grub-mkrescue -o os.iso .
+
+clean:
+ make --directory=libk clean
+ make --directory=kernel clean
+ rm -fr boot
+ rm -fr os.iso
+
+run:
+ $(QEMU) -cdrom os.iso \
+ -boot order=d \
+ -m 4g
diff --git a/grub.cfg b/grub.cfg
new file mode 100644
index 0000000..48166cc
--- /dev/null
+++ b/grub.cfg
@@ -0,0 +1,8 @@
+set timeout=1
+set default=0
+
+menuentry "finix" {
+ multiboot2 /boot/kernel.bin
+ boot
+}
+
diff --git a/kernel/Makefile b/kernel/Makefile
new file mode 100644
index 0000000..999498b
--- /dev/null
+++ b/kernel/Makefile
@@ -0,0 +1,28 @@
+include ../.env
+
+C_SRC = $(shell find src -type f -name "*.c")
+C_OBJ = $(patsubst %.c,bin/%.o, $(C_SRC))
+
+ASM_SRC = $(shell find src -type f -name "*.asm")
+ASM_OBJ = $(patsubst %.asm,bin/%.o, $(ASM_SRC))
+
+CFLAGS += -Iinclude -Isrc -I../libk/include -std=gnu17
+
+.PHONY: all
+
+all: bin/kernel.bin
+
+$(C_OBJ): bin/%.o : %.c
+ @mkdir -p $(@D)
+ $(CC) -c $(CFLAGS) -o $@ $<
+
+$(ASM_OBJ): bin/%.o : %.asm
+ @mkdir -p $(@D)
+ $(AS) $< -f elf -o $@
+
+bin/kernel.bin: $(C_OBJ) $(ASM_OBJ)
+ @mkdir -p $(@D)
+ $(LD) -o bin/kernel.bin -T linker.ld $(C_OBJ) $(ASM_OBJ) ../libk/bin/libk.a $(LDFLAGS)
+
+clean:
+ rm -fr bin
diff --git a/kernel/compile_flags.txt b/kernel/compile_flags.txt
new file mode 100644
index 0000000..0380b3e
--- /dev/null
+++ b/kernel/compile_flags.txt
@@ -0,0 +1,12 @@
+-c
+-std=gnu17
+-Wall
+-Wextra
+-pedantic
+-O2
+-ffreestanding
+-I../libk/include
+-Iinclude
+-Isrc
+-nostdlib
+-DKERNEL_LOG
diff --git a/kernel/include/keycodes.h b/kernel/include/keycodes.h
new file mode 100644
index 0000000..b0a2568
--- /dev/null
+++ b/kernel/include/keycodes.h
@@ -0,0 +1,127 @@
+#pragma once
+
+#define KC_FLAG_KEY_DOWN 0x01
+#define KC_FLAG_KEY_UP 0x02
+#define KC_FLAG_ERROR 0x04
+
+#define KEY_NONE 0x00
+#define KEY_UNKNOWN 0x01
+
+#define KEY_ESCAPE 0x10
+#define KEY_1 0x11
+#define KEY_2 0x12
+#define KEY_3 0x13
+#define KEY_4 0x14
+#define KEY_5 0x15
+#define KEY_6 0x16
+#define KEY_7 0x17
+#define KEY_8 0x18
+#define KEY_9 0x19
+#define KEY_0 0x1A
+#define KEY_MINUS 0x1B
+#define KEY_EQUAL 0x1C
+#define KEY_BACKSPACE 0x1D
+#define KEY_L_SHIFT 0x1E
+#define KEY_R_SHIFT 0x1F
+
+#define KEY_TAB 0x20
+#define KEY_Q 0x21
+#define KEY_W 0x22
+#define KEY_E 0x23
+#define KEY_R 0x24
+#define KEY_T 0x25
+#define KEY_Y 0x26
+#define KEY_U 0x27
+#define KEY_I 0x28
+#define KEY_O 0x29
+#define KEY_P 0x2A
+#define KEY_L_BRACE 0x2B
+#define KEY_R_BRACE 0x2C
+#define KEY_BACKSLASH 0x2D
+#define KEY_L_CTRL 0x2E
+#define KEY_R_CTRL 0x2F
+
+#define KEY_CAPS_LOCK 0x30
+#define KEY_A 0x31
+#define KEY_S 0x32
+#define KEY_D 0x33
+#define KEY_F 0x34
+#define KEY_G 0x35
+#define KEY_H 0x36
+#define KEY_J 0x37
+#define KEY_K 0x38
+#define KEY_L 0x39
+#define KEY_SEMICOLON 0x3A
+#define KEY_QUOTE 0x3B
+#define KEY_ENTER 0x3C
+#define KEY_MENU 0x3D
+#define KEY_L_ALT 0x3E
+#define KEY_R_ALT 0x3F
+
+#define KEY_SPACE 0x40
+#define KEY_Z 0x41
+#define KEY_X 0x42
+#define KEY_C 0x43
+#define KEY_V 0x44
+#define KEY_B 0x45
+#define KEY_N 0x46
+#define KEY_M 0x47
+#define KEY_COMMA 0x48
+#define KEY_PERIOD 0x49
+#define KEY_SLASH 0x4A
+#define KEY_BACKTICK 0x4B
+#define KEY_NUM_LOCK 0x4C
+#define KEY_SCROLL_LOCK 0x4D
+#define KEY_L_META 0x4E
+#define KEY_R_META 0x4F
+
+#define KEY_NP_SLASH 0x50
+#define KEY_NP_7 0x51
+#define KEY_NP_8 0x52
+#define KEY_NP_9 0x53
+#define KEY_NP_ASTERISK 0x54
+#define KEY_NP_4 0x55
+#define KEY_NP_5 0x56
+#define KEY_NP_6 0x57
+#define KEY_NP_MINUS 0x58
+#define KEY_NP_1 0x59
+#define KEY_NP_2 0x5A
+#define KEY_NP_3 0x5B
+#define KEY_NP_PLUS 0x5C
+#define KEY_NP_0 0x5D
+#define KEY_NP_PERIOD 0x5E
+#define KEY_NP_ENTER 0x5F
+
+#define KEY_PRINT_SCREEN 0x60
+#define KEY_PAUSE 0x61
+#define KEY_INSERT 0x62
+#define KEY_HOME 0x63
+#define KEY_PAGE_UP 0x64
+#define KEY_DELETE 0x65
+#define KEY_END 0x66
+#define KEY_PAGE_DOWN 0x67
+#define KEY_UP 0x68
+#define KEY_DOWN 0x69
+#define KEY_LEFT 0x6A
+#define KEY_RIGHT 0x6B
+// #define _ 0x6C
+// #define _ 0x6D
+// #define _ 0x6E
+// #define _ 0x6F
+
+#define KEY_F1 0x70
+#define KEY_F2 0x71
+#define KEY_F3 0x72
+#define KEY_F4 0x73
+#define KEY_F5 0x74
+#define KEY_F6 0x75
+#define KEY_F7 0x76
+#define KEY_F8 0x77
+#define KEY_F9 0x78
+#define KEY_F10 0x79
+#define KEY_F11 0x7A
+#define KEY_F12 0x7B
+// #define _ 0x7C
+// #define _ 0x7D
+// #define _ 0x7E
+// #define _ 0x7F
diff --git a/kernel/include/panic.h b/kernel/include/panic.h
new file mode 100644
index 0000000..db02a24
--- /dev/null
+++ b/kernel/include/panic.h
@@ -0,0 +1,6 @@
+#pragma once
+
+#define panic(msg, ...) _panic_impl(msg, __LINE__, __FILE__, ## __VA_ARGS__)
+
+__attribute__((noreturn))
+extern void _panic_impl(char* msg, int line, char* file, ...);
diff --git a/kernel/include/print.h b/kernel/include/print.h
new file mode 100644
index 0000000..dc7f862
--- /dev/null
+++ b/kernel/include/print.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include <stddef.h>
+#include <stdarg.h>
+
+extern void putchar(int c);
+extern void puts(const char* s);
+extern void printk(const char *restrict format, ...);
+extern void vprintk(const char *restrict format, va_list ap);
+
+#ifdef KERNEL_LOG
+#define debugk(msg, ...) _debugk_impl(msg, ## __VA_ARGS__)
+#define succek(msg, ...) _succek_impl(msg, ## __VA_ARGS__)
+#define errork(msg, ...) _errork_impl(msg, ## __VA_ARGS__)
+#else
+#define debugk(msg, ...)
+#define succek(msg, ...)
+#define errork(msg, ...)
+#endif
+
+extern void _debugk_impl(char* msg, ...);
+extern void _succek_impl(char* msg, ...);
+extern void _errork_impl(char* msg, ...);
diff --git a/kernel/linker.ld b/kernel/linker.ld
new file mode 100644
index 0000000..beb44df
--- /dev/null
+++ b/kernel/linker.ld
@@ -0,0 +1,31 @@
+ENTRY(start)
+
+SECTIONS {
+ . = 1M;
+
+ kernel_start = .;
+
+ .boot BLOCK(4K) : ALIGN(4K)
+ {
+ *(.multiboot)
+ }
+
+ .text BLOCK(4K) : ALIGN(4K)
+ {
+ *(.text)
+ }
+
+ .rodata BLOCK(4K) : ALIGN(4K)
+ {
+ *(.rodata)
+ }
+
+
+ .bss BLOCK(4K) : ALIGN(4K)
+ {
+ *(.bss)
+ }
+
+ kernel_end = .;
+
+}
diff --git a/kernel/src/acpi/acpi.c b/kernel/src/acpi/acpi.c
new file mode 100644
index 0000000..ef1fb76
--- /dev/null
+++ b/kernel/src/acpi/acpi.c
@@ -0,0 +1,141 @@
+#include <panic.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <sys.h>
+
+#include "acpi.h"
+#include "boot/tag.h"
+#include "print.h"
+
+static struct RootSystemDescriptionTable *rsdt;
+static struct FixedACPIDescriptionTable *fadt;
+
+static uint16_t SLP_TYPa;
+static uint16_t SLP_TYPb;
+static uint16_t SLP_EN;
+static uint16_t SCI_EN;
+
+static bool is_init = false;
+
+bool checksum(uint8_t *data, size_t len) {
+ unsigned char sum = 0;
+ for (size_t i = 0; i < len; i++)
+ sum += data[i];
+ return sum == 0;
+}
+
+static void *find_fadt(void) {
+ int entries = (rsdt->header.length - sizeof(rsdt->header)) / 4;
+
+ for (int i = 0; i < entries; i++) {
+ uintptr_t sdt_ptr = rsdt->sdt_table[i];
+ struct SystemDescriptionTableHeader *h = (void*) sdt_ptr;
+ if (!strncmp(h->signature, "FACP", 4))
+ return (void *) h;
+ }
+
+ return NULL;
+}
+
+static int read_s5_addr(void) {
+ uintptr_t ptr = fadt->dsdt;
+ char *s5_addr = (void*) (ptr + 36);
+
+ int dsdt_len = *((int*) (ptr+1)) - 36;
+ while (0 < dsdt_len--) {
+ if ( memcmp(s5_addr, "_S5_", 4) == 0)
+ break;
+ s5_addr++;
+ }
+
+ if (dsdt_len > 0) {
+ // check for valid AML structure
+ if ( ( *(s5_addr-1) == 0x08 || ( *(s5_addr-2) == 0x08 && *(s5_addr-1) == '\\') ) && *(s5_addr+4) == 0x12 ) {
+ s5_addr += 5;
+ s5_addr += ((*s5_addr &0xC0)>>6) +2; // calculate PkgLength size
+
+ if (*s5_addr == 0x0A)
+ s5_addr++; // skip byteprefix
+ SLP_TYPa = *(s5_addr)<<10;
+ s5_addr++;
+
+ if (*s5_addr == 0x0A)
+ s5_addr++; // skip byteprefix
+ SLP_TYPb = *(s5_addr)<<10;
+
+ SLP_EN = 1<<13;
+ SCI_EN = 1;
+
+ } else {
+ errork("\\_S5 parse error.");
+ return 1;
+ }
+ } else {
+ errork("\\_S5 not present.");
+ return 1;
+ }
+ return 0;
+}
+
+void acpi_init(void) {
+
+ is_init = false;
+
+ debugk("Loading ACPI");
+
+ struct BootTag *tag;
+ if(!get_boot_tag(ID_RSDP, &tag)) {
+ errork("Could not find RSDP");
+ return;
+ }
+
+ debugk("Loading RSDT");
+
+ struct RootSystemDescriptionPointer *rsdp = tag->data.rsdp;
+ if (!checksum((uint8_t*) rsdp, sizeof(struct RootSystemDescriptionPointer))) {
+ errork("RSDP checksum failed to validate");
+ return;
+ }
+
+ uintptr_t rsdt_ptr = rsdp->rsdt_address;
+ rsdt = (void *) rsdt_ptr;
+ if (!checksum((uint8_t*) &rsdt->header, rsdt->header.length)) {
+ errork("RSDT checksum failed to validate");
+ return;
+ }
+
+ debugk("Loading FADT");
+
+ fadt = find_fadt();
+ if (fadt == NULL) {
+ errork("Could not find FADT");
+ return;
+ }
+
+ if (!checksum((uint8_t*) &fadt->header, fadt->header.length)) {
+ errork("FADT checksum failed to validate");
+ return;
+ }
+
+ debugk("Reading \\_S5 Addr");
+
+ if (read_s5_addr()) {
+ return;
+ }
+
+ outb(fadt->smi_command_port,fadt->acpi_enable);
+
+ succek("ACPI has been loaded");
+ is_init = true;
+}
+
+void acpi_poweroff(void) {
+ if (is_init) {
+ outw((unsigned int) fadt->pm1_a_control_block, SLP_TYPb | SLP_EN);
+ panic("failed to shutdown");
+ } else {
+ errork("Cannot shutdown, ACPI not loaded");
+ }
+}
diff --git a/kernel/src/acpi/acpi.h b/kernel/src/acpi/acpi.h
new file mode 100644
index 0000000..889497e
--- /dev/null
+++ b/kernel/src/acpi/acpi.h
@@ -0,0 +1,106 @@
+#pragma once
+
+#include <stdint.h>
+
+struct RootSystemDescriptionPointer {
+ char signature[8];
+ uint8_t checksum;
+ char oemid[6];
+ uint8_t revision;
+ uint32_t rsdt_address;
+};
+
+struct SystemDescriptionTableHeader {
+ char signature[4];
+ uint32_t length;
+ uint8_t revision;
+ uint8_t checksum;
+ char oem_id[6];
+ char oem_table_id[8];
+ uint32_t oem_revision;
+ uint32_t creator_id;
+ uint32_t creator_revision;
+};
+
+struct RootSystemDescriptionTable {
+ struct SystemDescriptionTableHeader header;
+ uint32_t sdt_table[];
+};
+
+struct GenericAddressStructure {
+ uint8_t address_space;
+ uint8_t bit_width;
+ uint8_t bit_offset;
+ uint8_t access_size;
+ uint64_t address;
+};
+
+struct FixedACPIDescriptionTable {
+ struct SystemDescriptionTableHeader header;
+ uint32_t firmware_ctrl;
+ uint32_t dsdt;
+
+ // field used in ACPI 1.0; no longer in use, for compatibility only
+ uint8_t reserved;
+
+ uint8_t preferred_power_management_profile;
+ uint16_t sci_interrupt;
+ uint32_t smi_command_port;
+ uint8_t acpi_enable;
+ uint8_t acpi_disable;
+ uint8_t s4bios_req;
+ uint8_t pstate_control;
+ uint32_t pm1_a_event_block;
+ uint32_t pm1_b_event_block;
+ uint32_t pm1_a_control_block;
+ uint32_t pm1_b_control_block;
+ uint32_t pm2_control_block;
+ uint32_t pm_timer_block;
+ uint32_t gpe0_block;
+ uint32_t gpe1_block;
+ uint8_t pm1_event_length;
+ uint8_t pm1_control_length;
+ uint8_t pm2_control_length;
+ uint8_t pm_timer_length;
+ uint8_t gpe0_length;
+ uint8_t gpe1_length;
+ uint8_t gpe1_base;
+ uint8_t cstate_control;
+ uint16_t worst_c2_latency;
+ uint16_t worst_c3_latency;
+ uint16_t flush_size;
+ uint16_t flush_stride;
+ uint8_t duty_offset;
+ uint8_t duty_width;
+ uint8_t day_alarm;
+ uint8_t month_alarm;
+ uint8_t century;
+
+ // reserved in ACPI 1.0; used since ACPI 2.0+
+ uint16_t boot_architecture_flags;
+
+ uint8_t reserved_2;
+ uint32_t flags;
+
+ // 12 byte structure; see below for details
+ struct GenericAddressStructure reset_reg;
+
+ uint8_t reset_value;
+ uint8_t reserved_3[3];
+
+ // 64bit pointers - Available on ACPI 2.0+
+ uint64_t x_firmware_control;
+ uint64_t x_dsdt;
+
+ struct GenericAddressStructure x_pm1_a_event_block;
+ struct GenericAddressStructure x_pm1_b_event_block;
+ struct GenericAddressStructure x_pm1_a_control_block;
+ struct GenericAddressStructure x_pm1_b_control_block;
+ struct GenericAddressStructure x_pm2_control_block;
+ struct GenericAddressStructure x_pm_timer_block;
+ struct GenericAddressStructure x_gpe0_block;
+ struct GenericAddressStructure x_gpe1_block;
+};
+
+void acpi_init(void);
+void acpi_poweroff(void);
diff --git a/kernel/src/boot/tag.c b/kernel/src/boot/tag.c
new file mode 100644
index 0000000..22ea758
--- /dev/null
+++ b/kernel/src/boot/tag.c
@@ -0,0 +1,91 @@
+#include <panic.h>
+#include <string.h>
+
+#include "print.h"
+#include "tag.h"
+#include "acpi/acpi.h"
+#include "graphics/framebuffer.h"
+#include "memory/memory.h"
+
+static struct BootInfo info;
+
+static void read_cmdline(struct BootTag *tag, char *data, uint8_t len) {
+ debugk("Found cmdline");
+ if (len >= CMDLINE_MAX)
+ panic("multiboot2 cmd line to long\nmax is %d but was provided %d\n",
+ CMDLINE_MAX, len);
+ memcpy(tag->data.cmdline, data, len);
+ info.tags[ID_CMDLINE] = *tag;
+}
+
+static void read_framebuffer(struct BootTag *tag, uint32_t *data) {
+ debugk("Found framebuffer");
+ tag->data.framebuffer = (struct Framebuffer *) data;
+ info.tags[ID_FRAMEBUFFER] = *tag;;
+}
+
+static void read_memorymap(struct BootTag *tag, uint32_t *data) {
+ debugk("Found memorymap");
+ tag->data.memory_map = (struct MemoryMap *) data;
+ info.tags[iD_MEMORYMAP] = *tag;
+}
+
+static void read_rsdp(struct BootTag *tag, char *data) {
+ debugk("Found RSDP");
+ tag->data.rsdp = (struct RootSystemDescriptionPointer *) data;
+ info.tags[ID_RSDP] = *tag;
+}
+
+static uint32_t *read_tag(uint32_t *data) {
+ struct BootTag tag;
+ tag.type = ((uint16_t*)data)[0];
+ tag.size = data[1];
+ tag.valid = 1;
+
+ uint8_t data_len = tag.size - 2 * sizeof(uint32_t);
+
+ switch (tag.type) {
+ case ID_CMDLINE:
+ read_cmdline(&tag, (char *)(data + 2), data_len);
+ break;
+ case ID_FRAMEBUFFER:
+ read_framebuffer(&tag, data + 2);
+ break;
+ case iD_MEMORYMAP:
+ read_memorymap(&tag, data + 2);
+ break;
+ case ID_RSDP:
+ read_rsdp(&tag, (char *) (data + 2));
+ break;
+ default:
+ break;
+ }
+
+ if(tag.size % 8 != 0) {
+ tag.size += 8 - (tag.size % 8);
+ }
+
+ return data + tag.size / sizeof(uint32_t);
+}
+
+void load_boot_info(void* boot_info) {
+
+ debugk("Reading multiboot info");
+
+ memset(&info, 0, sizeof(boot_info));
+
+ uint32_t* data = (uint32_t*) boot_info;
+ info.total_size = *data++;
+ info.reserved = *data++;
+
+ while((uint8_t*) data < (uint8_t*) boot_info + info.total_size) {
+ data = read_tag(data);
+ }
+
+ succek("Loaded multiboot info");
+}
+
+bool get_boot_tag(enum BootTagID id, struct BootTag **tag) {
+ *tag = &info.tags[id];
+ return (*tag)->valid;
+}
diff --git a/kernel/src/boot/tag.h b/kernel/src/boot/tag.h
new file mode 100644
index 0000000..f9853e5
--- /dev/null
+++ b/kernel/src/boot/tag.h
@@ -0,0 +1,38 @@
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "acpi/acpi.h"
+#include "graphics/framebuffer.h"
+#include "memory/memory.h"
+
+#define CMDLINE_MAX 32
+
+struct BootTag {
+ uint8_t valid;
+ uint32_t type;
+ uint32_t size;
+ union {
+ char cmdline[CMDLINE_MAX];
+ struct Framebuffer *framebuffer;
+ struct MemoryMap *memory_map;
+ struct RootSystemDescriptionPointer *rsdp;
+ } data;
+};
+
+struct BootInfo {
+ uint32_t total_size;
+ uint32_t reserved;
+ struct BootTag tags[21];
+};
+
+enum BootTagID {
+ ID_CMDLINE = 0,
+ iD_MEMORYMAP = 6,
+ ID_FRAMEBUFFER = 8,
+ ID_RSDP = 14
+};
+
+void load_boot_info(void* boot_info);
+bool get_boot_tag(enum BootTagID id, struct BootTag **tag);
diff --git a/kernel/src/cpu/cpu.c b/kernel/src/cpu/cpu.c
new file mode 100644
index 0000000..f78ef26
--- /dev/null
+++ b/kernel/src/cpu/cpu.c
@@ -0,0 +1,20 @@
+#include "cpu.h"
+
+#include "print.h"
+
+extern int sse_init (void);
+extern int fpu_init (void);
+
+void init_registers (void) {
+ if (!sse_init()) {
+ debugk("Loaded SIMD");
+ } else {
+ errork("SIMD not supported");
+ }
+
+ if (!fpu_init()) {
+ debugk("Loaded FPU");
+ } else {
+ errork("FPU not supported");
+ }
+}
diff --git a/kernel/src/cpu/cpu.h b/kernel/src/cpu/cpu.h
new file mode 100644
index 0000000..3044292
--- /dev/null
+++ b/kernel/src/cpu/cpu.h
@@ -0,0 +1,3 @@
+#pragma once
+
+void init_registers (void);
diff --git a/kernel/src/cpu/fpu.asm b/kernel/src/cpu/fpu.asm
new file mode 100644
index 0000000..e49ab6f
--- /dev/null
+++ b/kernel/src/cpu/fpu.asm
@@ -0,0 +1,19 @@
+global fpu_init
+
+fpu_init:
+ mov edx, cr0
+ and edx, (-1) - ((1 << 3) + (1 << 4))
+ mov cr0, edx
+ fninit
+ fnstsw [test]
+ cmp word [test], 0
+ jne no_fpu
+
+ xor eax, 0
+ ret
+
+no_fpu:
+ mov eax, 1
+ ret
+
+test: dw 0x55AA
diff --git a/kernel/src/cpu/sse.asm b/kernel/src/cpu/sse.asm
new file mode 100644
index 0000000..e7b5a99
--- /dev/null
+++ b/kernel/src/cpu/sse.asm
@@ -0,0 +1,22 @@
+global sse_init
+
+sse_init:
+ mov eax, 0x1
+ cpuid
+ test edx, 1<<25
+ jmp no_sse
+
+ mov eax, cr0
+ and ax, 0xFFFB
+ or ax, 0x2
+ mov cr0, eax
+ mov eax, cr4
+ or ax, 3 << 9
+ mov cr4, eax
+
+ mov eax, 0
+ ret
+
+no_sse:
+ mov eax, 1
+ ret
diff --git a/kernel/src/drivers/ps2ctrl.c b/kernel/src/drivers/ps2ctrl.c
new file mode 100644
index 0000000..527435d
--- /dev/null
+++ b/kernel/src/drivers/ps2ctrl.c
@@ -0,0 +1,99 @@
+#include <panic.h>
+#include <sys.h>
+
+#include "print.h"
+#include "ps2ctrl.h"
+#include "interrupt/pic.h"
+
+#define STATUS_OUT_BUF ((uint8_t)0x01)
+#define STATUS_IN_BUF ((uint8_t)0x02)
+
+#define CONFIG_INT_0 ((uint8_t)0x01)
+#define CONFIG_INT_1 ((uint8_t)0x02)
+#define CONFIG_SYS ((uint8_t)0x04)
+#define CONFIG_CLOCK_0 ((uint8_t)0x10)
+#define CONFIG_CLOCK_1 ((uint8_t)0x20)
+#define CONFIG_TRANS ((uint8_t)0x40)
+
+static bool is_init = false;
+
+uint8_t ps2ctrl_in(void) {
+ while((ps2ctrl_in_status() & STATUS_OUT_BUF) == 0) {
+ io_wait();
+ }
+ return inb(0x60);
+}
+
+uint8_t ps2ctrl_in_status(void) {
+ return inb(0x64);
+}
+
+void ps2ctrl_out_cmd(uint8_t cmd) {
+ while((ps2ctrl_in_status() & STATUS_IN_BUF) != 0) {
+ io_wait();
+ }
+ outb(0x64, cmd);
+}
+
+void ps2ctrl_out_data(uint8_t data) {
+ while((ps2ctrl_in_status() & STATUS_IN_BUF) != 0) {
+ io_wait();
+ }
+ outb(0x60, data);
+}
+
+void ps2ctrl_set_port2(void) {
+ outb(0x64, 0xD4);
+}
+
+void ps2ctrl_init(void) {
+
+ debugk("Loading PS/2 Controller");
+
+ is_init = false;
+
+ pic_mask(1); // keyboard
+ pic_mask(12); // mouse
+
+ inb(0x60);
+
+ // self-test
+ ps2ctrl_out_cmd(0xAA);
+ uint8_t response = ps2ctrl_in();
+ if(response != 0x55) {
+ errork("PS/2 controller failed to initialize");
+ return;
+ }
+
+ // set config
+ ps2ctrl_out_cmd(0x20);
+ uint8_t config = ps2ctrl_in();
+ config = (config | CONFIG_INT_0 | CONFIG_INT_1) & ~CONFIG_TRANS;
+ // config = 0xFF;
+ ps2ctrl_out_cmd(0x60);
+ ps2ctrl_out_data(config);
+
+ // enable port 0
+ ps2ctrl_out_cmd(0xAE);
+
+ // enable port 2
+ ps2ctrl_out_cmd(0xA9);
+ response = ps2ctrl_in();
+ if (response == 0x01) {
+ errork("PS/2 port 2 not supported");
+ return;
+ }
+
+ ps2ctrl_out_cmd(0xA8);
+
+ is_init = true;
+
+ pic_unmask(1);
+ pic_unmask(12);
+
+ succek("Loaded PS/2 Controller");
+}
+
+bool ps2ctrl_is_init(void) {
+ return is_init;
+}
diff --git a/kernel/src/drivers/ps2ctrl.h b/kernel/src/drivers/ps2ctrl.h
new file mode 100644
index 0000000..a674c57
--- /dev/null
+++ b/kernel/src/drivers/ps2ctrl.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+
+uint8_t ps2ctrl_in(void);
+uint8_t ps2ctrl_in_status(void);
+void ps2ctrl_out_cmd(uint8_t cmd);
+void ps2ctrl_out_data(uint8_t data);
+void ps2ctrl_set_port2(void);
+
+void ps2ctrl_init(void);
+
+bool ps2ctrl_is_init(void);
diff --git a/kernel/src/drivers/ps2kb.c b/kernel/src/drivers/ps2kb.c
new file mode 100644
index 0000000..dec0b87
--- /dev/null
+++ b/kernel/src/drivers/ps2kb.c
@@ -0,0 +1,130 @@
+#include <panic.h>
+#include <sys.h>
+
+#include "print.h"
+#include "ps2kb.h"
+#include "ps2ctrl.h"
+#include "interrupt/pic.h"
+
+#define BUFFER_LEN 16
+
+#define KEYCODE_ARRAY_LEN 0x84
+
+static uint8_t scancodes[] = {
+// 00/08 01/09 02/0A 03/0B 04/0C 05/0D 06/0E 07/0F
+/*00*/ KEY_NONE, KEY_F9, KEY_NONE, KEY_F5, KEY_F3, KEY_F1, KEY_F2, KEY_F12,
+/*08*/ KEY_NONE, KEY_F10, KEY_F8, KEY_F6, KEY_F4, KEY_TAB, KEY_BACKTICK, KEY_NONE,
+/*10*/ KEY_NONE, KEY_L_ALT, KEY_L_SHIFT, KEY_NONE, KEY_L_CTRL, KEY_Q, KEY_1, KEY_NONE,
+/*18*/ KEY_NONE, KEY_NONE, KEY_Z, KEY_S, KEY_A, KEY_W, KEY_2, KEY_NONE,
+/*20*/ KEY_NONE, KEY_C, KEY_X, KEY_D, KEY_E, KEY_4, KEY_3, KEY_NONE,
+/*28*/ KEY_NONE, KEY_SPACE, KEY_V, KEY_F, KEY_T, KEY_R, KEY_5, KEY_NONE,
+/*30*/ KEY_NONE, KEY_N, KEY_B, KEY_H, KEY_G, KEY_Y, KEY_6, KEY_NONE,
+/*38*/ KEY_NONE, KEY_NONE, KEY_M, KEY_J, KEY_U, KEY_7, KEY_8, KEY_NONE,
+/*40*/ KEY_NONE, KEY_COMMA, KEY_K, KEY_I, KEY_O, KEY_0, KEY_9, KEY_NONE,
+/*48*/ KEY_NONE, KEY_PERIOD, KEY_SLASH, KEY_L, KEY_SEMICOLON, KEY_P, KEY_MINUS, KEY_NONE,
+/*50*/ KEY_NONE, KEY_NONE, KEY_QUOTE, KEY_NONE, KEY_L_BRACE, KEY_EQUAL, KEY_NONE, KEY_NONE,
+/*58*/ KEY_CAPS_LOCK, KEY_R_SHIFT, KEY_ENTER, KEY_R_BRACE, KEY_NONE, KEY_BACKSLASH, KEY_NONE, KEY_NONE,
+/*60*/ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_BACKSPACE, KEY_NONE,
+/*68*/ KEY_NONE, KEY_NP_1, KEY_NONE, KEY_NP_4, KEY_NP_7, KEY_NONE, KEY_NONE, KEY_NONE,
+/*70*/ KEY_NP_0, KEY_NP_PERIOD, KEY_NP_2, KEY_NP_5, KEY_NP_6, KEY_NP_8, KEY_ESCAPE, KEY_NUM_LOCK,
+/*78*/ KEY_F11, KEY_NP_PLUS, KEY_NP_3, KEY_NP_MINUS, KEY_NP_ASTERISK, KEY_NP_9, KEY_SCROLL_LOCK, KEY_NONE,
+/*80*/ KEY_NONE, KEY_NONE, KEY_NONE, KEY_F7,
+};
+static uint8_t scancodes_ext[] = {
+// 00/08 01/09 02/0A 03/0B 04/0C 05/0D 06/0E 07/0F
+/*00*/ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+/*08*/ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+/*10*/ KEY_UNKNOWN, KEY_R_ALT, KEY_PRINT_SCREEN, KEY_NONE, KEY_R_CTRL, KEY_UNKNOWN, KEY_NONE, KEY_NONE,
+/*18*/ KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_L_META,
+/*20*/ KEY_UNKNOWN, KEY_UNKNOWN, KEY_NONE, KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_R_META,
+/*28*/ KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_MENU,
+/*30*/ KEY_UNKNOWN, KEY_NONE, KEY_UNKNOWN, KEY_NONE, KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_UNKNOWN,
+/*38*/ KEY_UNKNOWN, KEY_NONE, KEY_UNKNOWN, KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_UNKNOWN,
+/*40*/ KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+/*48*/ KEY_UNKNOWN, KEY_NONE, KEY_NP_SLASH, KEY_NONE, KEY_NONE, KEY_UNKNOWN, KEY_NONE, KEY_NONE,
+/*50*/ KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+/*58*/ KEY_NONE, KEY_NONE, KEY_NP_ENTER, KEY_NONE, KEY_NONE, KEY_NONE, KEY_UNKNOWN, KEY_NONE,
+/*60*/ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+/*68*/ KEY_NONE, KEY_END, KEY_NONE, KEY_LEFT, KEY_HOME, KEY_NONE, KEY_NONE, KEY_NONE,
+/*70*/ KEY_INSERT, KEY_DELETE, KEY_DOWN, KEY_NONE, KEY_RIGHT, KEY_UP, KEY_NONE, KEY_NONE,
+/*78*/ KEY_NONE, KEY_NONE, KEY_PAGE_DOWN, KEY_NONE, KEY_NONE, KEY_PAGE_UP, KEY_NONE, KEY_NONE,
+/*80*/ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+};
+
+static struct Keycode last_keycode;
+
+static bool is_init = false;
+static bool state_keyup = false;
+static bool state_ext = false;
+
+void ps2kb_init(void) {
+
+ debugk("Loading PS/2 Keyboard");
+
+ is_init = false;
+ pic_mask(1);
+
+ uint8_t result;
+
+ ps2ctrl_out_data(0xFF);
+ result = ps2ctrl_in();
+ if(result != 0xFA) {
+ errork("Failed to reset PS/2 keyboard: expected 0xFA, got 0x%X\n", result);
+ return;
+ }
+ result = ps2ctrl_in();
+ if(result != 0xAA) {
+ errork("Failed to reset PS/2 keyboard: expected 0xAA, got 0x%X\n", result);
+ return;
+ }
+
+ ps2ctrl_out_data(0xF4);
+ result = ps2ctrl_in();
+ if(result != 0xFA) {
+ errork("Failed to enable PS/2 keyboard: expected 0xFA, got 0x%X\n", result);
+ return;
+ }
+
+ succek("PS/2 Keyboard has has been loaded");
+
+ pic_unmask(1);
+ is_init = true;
+}
+
+void ps2kb_recv(void) {
+ if(!ps2ctrl_is_init() || !is_init) {
+ inb(0x60);
+ return;
+ }
+ uint8_t code = ps2ctrl_in();
+ if (code == 0x00 || code == 0x0F) {
+ last_keycode.key = KEY_NONE;
+ last_keycode.flags = KC_FLAG_ERROR;
+ } else if(code == 0xF0) {
+ state_keyup = true;
+ } else if(code == 0xE0) {
+ state_ext = true;
+ } else if(code <= KEYCODE_ARRAY_LEN) {
+ uint8_t *scancode_table = state_ext ? scancodes_ext : scancodes;
+ uint8_t keycode = scancode_table[code];
+ if(keycode != KEY_NONE) {
+ last_keycode.key = keycode;
+ last_keycode.flags = state_keyup ? KC_FLAG_KEY_UP : KC_FLAG_KEY_DOWN;
+ }
+ state_keyup = false;
+ state_ext = false;
+ }
+}
+
+struct Keycode ps2kb_get(void) {
+ struct Keycode code;
+ if(is_init) {
+ code = last_keycode;
+ } else {
+ code.key = KEY_NONE;
+ code.flags = KC_FLAG_ERROR;
+ }
+ last_keycode.key = KEY_NONE;
+ last_keycode.flags = 0;
+ return code;
+}
diff --git a/kernel/src/drivers/ps2kb.h b/kernel/src/drivers/ps2kb.h
new file mode 100644
index 0000000..1aaefb2
--- /dev/null
+++ b/kernel/src/drivers/ps2kb.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <keycodes.h>
+
+struct Keycode {
+ uint8_t key;
+ uint8_t flags;
+};
+
+void ps2kb_init(void);
+
+void ps2kb_recv(void);
+struct Keycode ps2kb_get(void);
diff --git a/kernel/src/drivers/ps2mouse.c b/kernel/src/drivers/ps2mouse.c
new file mode 100644
index 0000000..01e10cc
--- /dev/null
+++ b/kernel/src/drivers/ps2mouse.c
@@ -0,0 +1,89 @@
+#include <panic.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys.h>
+
+#include "print.h"
+#include "ps2mouse.h"
+#include "drivers/ps2ctrl.h"
+#include "interrupt/pic.h"
+
+static bool is_init = false;
+
+static struct MouseEvent last_event;
+static uint8_t first_b, second_b, third_b;
+
+void ps2mouse_init(void) {
+
+ debugk("Loading PS/2 Mouse");
+
+ is_init = false;
+ pic_mask(12);
+
+ uint8_t result;
+
+ ps2ctrl_set_port2();
+ ps2ctrl_out_data(0xFF);
+ result = ps2ctrl_in();
+ if (result != 0xFA) {
+ errork("Failed to reset PS/2 mouse: expected 0xFA, got 0x%X", result);
+ return;
+ }
+ result = ps2ctrl_in();
+ if (result != 0xAA) {
+ errork("Failed to reset PS/2 mouse: expected 0xAA, got 0x%X", result);
+ return;
+ }
+
+ ps2ctrl_set_port2();
+ ps2ctrl_out_data(0xF4);
+
+ pic_unmask(12);
+ is_init = true;
+
+ succek("PS/2 Mouse has has been loaded");
+}
+
+static uint8_t packet_num = 0;
+void ps2mouse_recv(void) {
+ if (!ps2ctrl_is_init() || !is_init) {
+ inb(0x60);
+ return;
+ }
+
+ uint8_t packet = ps2ctrl_in();
+ switch (packet_num) {
+ case 0:
+ first_b = packet;
+ break;
+ case 1:
+ second_b = packet;
+ break;
+ case 2: {
+ third_b = packet;
+
+ int state, d;
+ state = first_b;
+ d = second_b;
+ last_event.relx = d - ((state << 4) & 0x100);
+ d = third_b;
+ last_event.rely = d - ((state << 3) & 0x100);
+
+ last_event.lmb = first_b & 0x01;
+ last_event.rmb = first_b & 0x02;
+ last_event.mmb = first_b & 0x04;
+ last_event.updated = true;
+ break;
+ }
+ }
+
+ packet_num += 1;
+ packet_num %= 3;
+
+}
+
+struct MouseEvent ps2mouse_get(void) {
+ struct MouseEvent event = last_event;
+ last_event.updated = false;
+ return event;
+}
diff --git a/kernel/src/drivers/ps2mouse.h b/kernel/src/drivers/ps2mouse.h
new file mode 100644
index 0000000..9cd4818
--- /dev/null
+++ b/kernel/src/drivers/ps2mouse.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+
+struct MouseEvent {
+ bool updated;
+ bool lmb;
+ bool rmb;
+ bool mmb;
+ int relx;
+ int rely;
+};
+
+void ps2mouse_init(void);
+
+void ps2mouse_recv(void);
+struct MouseEvent ps2mouse_get(void);
diff --git a/kernel/src/graphics/framebuffer.h b/kernel/src/graphics/framebuffer.h
new file mode 100644
index 0000000..c3b0dc6
--- /dev/null
+++ b/kernel/src/graphics/framebuffer.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include <stdint.h>
+
+struct Framebuffer {
+ uint64_t addr;
+ uint32_t pitch;
+ uint32_t width;
+ uint32_t height;
+ uint8_t depth;
+ uint8_t type;
+ uint8_t reserved;
+ // struct FramebufferPallete palettes[];
+
+} __attribute__ ((packed));
diff --git a/kernel/src/interrupt/idt.c b/kernel/src/interrupt/idt.c
new file mode 100644
index 0000000..6df3793
--- /dev/null
+++ b/kernel/src/interrupt/idt.c
@@ -0,0 +1,108 @@
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <sys.h>
+#include <print.h>
+#include <panic.h>
+
+#include "acpi/acpi.h"
+#include "drivers/ps2kb.h"
+#include "drivers/ps2mouse.h"
+#include "tty/color.h"
+#include "idt.h"
+#include "pic.h"
+#include "tty/term.h"
+
+static int timer = 0;
+
+void idt_pic_eoi(uint8_t exception) {
+ pic_eoi(exception - PIC_REMAP_OFFSET);
+}
+
+void idt_pic_timer(void) {
+ uint32_t state = term_save();
+ term_setfg(VGA_LIGHT_GREEN);
+ term_setpos(60, 0);
+ puts(" ");
+ term_setpos(60, 0);
+ printk("%d", timer);
+ timer += 1;
+ term_load(state);
+}
+
+void idt_pic_keyboard(void) {
+ ps2kb_recv();
+}
+
+void idt_pic_mouse(void) {
+ ps2mouse_recv();
+}
+
+void idt_exception_handler(uint8_t exception) {
+ char* msg;
+ switch(exception) {
+ case 0x00:
+ msg = "Division by zero";
+ break;
+ case 0x02:
+ msg = "NMI";
+ break;
+ case 0x04:
+ msg = "Overflow";
+ break;
+ case 0x06:
+ msg = "invalid opcode";
+ break;
+ case 0x08:
+ msg = "double fault";
+ break;
+ case 0x0A:
+ msg = "invalid task state segment";
+ break;
+ case 0x0C:
+ msg = "stack segment fault";
+ break;
+ case 0x0D:
+ msg = "general protection fault";
+ break;
+ case 0x0E:
+ msg = "page fault";
+ break;
+ default:
+ msg = "unknown exception";
+ break;
+ }
+ panic("E%u: %s", exception, msg);
+}
+
+__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) {
+
+ debugk("Loading IDT");
+
+ idtr.base = (uintptr_t)&idt[0];
+ idtr.limit = (uint16_t)sizeof(struct IdtEntry) * IDT_SIZE - 1;
+
+ for(int i = 0; i < IDT_INTERRUPTS; i++) {
+ set_descriptor(i, isr_stub_table[i], 0x8e);
+ }
+
+ __asm__ volatile ("lidt %0" : : "m"(idtr));
+
+ succek("IDT has been loaded");
+}
+
diff --git a/kernel/src/interrupt/idt.h b/kernel/src/interrupt/idt.h
new file mode 100644
index 0000000..86a685f
--- /dev/null
+++ b/kernel/src/interrupt/idt.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include <stdint.h>
+
+#define IDT_SIZE 256
+#define IDT_INTERRUPTS 256
+
+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));
+
+enum IDTFlags {
+ 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,
+};
+
+void idt_init(void);
diff --git a/kernel/src/interrupt/isr.asm b/kernel/src/interrupt/isr.asm
new file mode 100644
index 0000000..6cccdc6
--- /dev/null
+++ b/kernel/src/interrupt/isr.asm
@@ -0,0 +1,99 @@
+extern idt_exception_handler
+extern idt_pic_timer
+extern idt_pic_keyboard
+extern idt_pic_mouse
+extern idt_pic_eoi
+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_eoi
+ pop eax
+ iret
+%endmacro
+
+%macro PICTimer 1
+isr_stub_%+%1:
+ call idt_pic_timer
+ push dword %1
+ call idt_pic_eoi
+ pop eax
+ iret
+%endmacro
+
+%macro PICKeyboard 1
+isr_stub_%+%1:
+ call idt_pic_keyboard
+ push dword %1
+ call idt_pic_eoi
+ pop eax
+ iret
+%endmacro
+
+%macro PICMouse 1
+isr_stub_%+%1:
+ call idt_pic_mouse
+ push dword %1
+ call idt_pic_eoi
+ 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
+align 8
+%assign i 0
+%rep 32
+ ISRErrorStub i
+%assign i i+1
+%endrep
+PICTimer 32 ; 0
+PICKeyboard 33 ; 1
+PICGeneric 34 ; 2
+PICGeneric 35 ; 3
+PICGeneric 36 ; 4
+PICGeneric 37 ; 5
+PICGeneric 38 ; 6
+PICGeneric 39 ; 7
+PICGeneric 40 ; 8
+PICGeneric 41 ; 9
+PICGeneric 42 ; 10
+PICGeneric 43 ; 11
+PICMouse 44 ; 12
+PICGeneric 45 ; 13
+PICGeneric 46 ; 14
+PICGeneric 47 ; 15
+%assign i 48
+%rep 256 - 48
+ ISRErrorStub i
+%assign i i+1
+%endrep
+
+section .rodata
+align 8
+isr_stub_table:
+%assign i 0x00
+%rep 256
+ dd isr_stub_%+i
+%assign i i+0x01
+%endrep
diff --git a/kernel/src/interrupt/pic.c b/kernel/src/interrupt/pic.c
new file mode 100644
index 0000000..86056a1
--- /dev/null
+++ b/kernel/src/interrupt/pic.c
@@ -0,0 +1,85 @@
+#include <sys.h>
+#include <print.h>
+
+#include "pic.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) {
+
+ debugk("Remapping PIC");
+
+ 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, 0x04);
+ 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);
+
+ succek("PIC has been remapped to offset 0x%X", offset);
+}
+
+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));
+}
+
+void pic_disable(void) {
+ outb(PIC1_DATA_PORT, 0xff);
+ io_wait();
+ outb(PIC2_DATA_PORT, 0xff);
+ io_wait();
+}
+
+void pic_eoi(int irq) {
+ if(irq >= 8) {
+ outb(PIC2_COMMAND_PORT, 0x20);
+ }
+ outb(PIC1_COMMAND_PORT, 0x20);
+}
diff --git a/kernel/src/interrupt/pic.h b/kernel/src/interrupt/pic.h
new file mode 100644
index 0000000..a87420d
--- /dev/null
+++ b/kernel/src/interrupt/pic.h
@@ -0,0 +1,11 @@
+#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);
+void pic_eoi(int irq);
diff --git a/kernel/src/main.c b/kernel/src/main.c
new file mode 100644
index 0000000..2a04c24
--- /dev/null
+++ b/kernel/src/main.c
@@ -0,0 +1,68 @@
+#include "acpi/acpi.h"
+#include "boot/tag.h"
+#include "cpu/cpu.h"
+#include "drivers/ps2ctrl.h"
+#include "drivers/ps2kb.h"
+#include "drivers/ps2mouse.h"
+#include "interrupt/idt.h"
+#include "interrupt/pic.h"
+#include "tty/cursor.h"
+#include "tty/term.h"
+
+#include <print.h>
+#include <math.h>
+#include <stdlib.h>
+#include <sys.h>
+
+static double x = 0, y = 0;
+
+void kernel_main(void* boot_info) {
+
+ term_init();
+ cursor_enable();
+
+ idt_init();
+ pic_remap(PIC_REMAP_OFFSET);
+
+ load_boot_info(boot_info);
+ acpi_init();
+
+ memory_init();
+
+ ps2ctrl_init();
+ ps2kb_init();
+ ps2mouse_init();
+
+ init_registers();
+
+ while(1) {
+ int_wait();
+
+ struct Keycode code = ps2kb_get();
+ if(code.key != KEY_NONE) {
+ if(code.flags & KC_FLAG_ERROR) {
+ printk("error: %X\n", code.key);
+ } else if(code.flags & KC_FLAG_KEY_DOWN) {
+ printk("pressed: %X\n", code.key);
+ } else {
+ printk("released: %X\n", code.key);
+ }
+ }
+
+ if (code.key == KEY_ESCAPE) {
+ acpi_poweroff();
+ }
+
+ struct MouseEvent event = ps2mouse_get();
+ if (event.updated) {
+ putchar(event.lmb ? 'L' : '_');
+ putchar(event.rmb ? 'R' : '_');
+ putchar(event.mmb ? 'M' : '_');
+ x += event.relx / 10.0;
+ y -= event.rely / 10.0;
+ x = fclamp(x, 0, TERM_W);
+ y = fclamp(y, 0, TERM_H);
+ printk(" x%d y%d\n", (int)x, (int)y);
+ }
+ }
+}
diff --git a/kernel/src/memory/allocator.c b/kernel/src/memory/allocator.c
new file mode 100644
index 0000000..6217ad4
--- /dev/null
+++ b/kernel/src/memory/allocator.c
@@ -0,0 +1,314 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct boundary_tag {
+ unsigned int magic;
+ unsigned int size;
+ unsigned int real_size;
+ int index;
+
+ struct boundary_tag *split_left;
+ struct boundary_tag *split_right;
+
+ struct boundary_tag *next;
+ struct boundary_tag *prev;
+};
+
+extern int memory_lock(void);
+extern int memory_unlock(void);
+extern void *memory_alloc_page(int);
+extern int memory_free_page(void* ,int);
+
+#define ALLOC_MAGIC 0xc001c0de
+#define MAXCOMPLETE 5
+#define MAXEXP 32
+#define MINEXP 8
+
+#define MODE_BEST 0
+#define MODE_INSTANT 1
+
+#define MODE MODE_BEST
+
+struct boundary_tag* l_freePages[MAXEXP];
+int l_completePages[MAXEXP];
+
+static int l_initialized = 0;
+static int l_pageSize = 4096;
+static int l_pageCount = 16;
+
+static inline int getexp(unsigned int size) {
+ if (size < (1<<MINEXP)) {
+ return -1;
+ }
+
+ int shift = MINEXP;
+
+ while (shift < MAXEXP) {
+ if ((unsigned)(1<<shift) > size) break;
+ shift += 1;
+ }
+
+ return shift - 1;
+}
+
+static inline void insert_tag(struct boundary_tag *tag, int index) {
+ int realIndex;
+
+ if (index < 0) {
+ realIndex = getexp(tag->real_size - sizeof(struct boundary_tag));
+ if (realIndex < MINEXP) realIndex = MINEXP;
+ } else {
+ realIndex = index;
+ }
+
+ tag->index = realIndex;
+
+ if (l_freePages[ realIndex ] != NULL) {
+ l_freePages[ realIndex ]->prev = tag;
+ tag->next = l_freePages[ realIndex ];
+ }
+
+ l_freePages[ realIndex ] = tag;
+}
+
+static inline void remove_tag(struct boundary_tag *tag) {
+ if (l_freePages[ tag->index ] == tag) l_freePages[ tag->index ] = tag->next;
+
+ if (tag->prev != NULL) tag->prev->next = tag->next;
+ if (tag->next != NULL) tag->next->prev = tag->prev;
+
+ tag->next = NULL;
+ tag->prev = NULL;
+ tag->index = -1;
+}
+
+static inline struct boundary_tag* melt_left(struct boundary_tag *tag) {
+ struct boundary_tag *left = tag->split_left;
+
+ left->real_size += tag->real_size;
+ left->split_right = tag->split_right;
+
+ if (tag->split_right != NULL) tag->split_right->split_left = left;
+
+ return left;
+}
+
+
+static inline struct boundary_tag* absorb_right(struct boundary_tag *tag) {
+ struct boundary_tag *right = tag->split_right;
+
+ remove_tag(right);
+
+ tag->real_size += right->real_size;
+
+ tag->split_right = right->split_right;
+ if (right->split_right != NULL)
+ right->split_right->split_left = tag;
+
+ return tag;
+}
+
+static inline struct boundary_tag* split_tag(struct boundary_tag* tag) {
+ unsigned int remainder = tag->real_size - sizeof(struct boundary_tag) - tag->size;
+
+ struct boundary_tag *new_tag =
+ (struct boundary_tag*)((uintptr_t)(void *)tag + sizeof(struct boundary_tag) + tag->size);
+
+ new_tag->magic = ALLOC_MAGIC;
+ new_tag->real_size = remainder;
+
+ new_tag->next = NULL;
+ new_tag->prev = NULL;
+
+ new_tag->split_left = tag;
+ new_tag->split_right = tag->split_right;
+
+ if (new_tag->split_right != NULL) new_tag->split_right->split_left = new_tag;
+ tag->split_right = new_tag;
+
+ tag->real_size -= new_tag->real_size;
+
+ insert_tag(new_tag, -1);
+
+ return new_tag;
+}
+
+static struct boundary_tag* allocate_new_tag(unsigned int size) {
+ unsigned int pages;
+ unsigned int usage;
+ struct boundary_tag *tag;
+
+ usage = size + sizeof(struct boundary_tag);
+
+ pages = usage / l_pageSize;
+ if ((usage % l_pageSize) != 0) pages += 1;
+
+ if (pages < (unsigned) l_pageCount) pages = l_pageCount;
+
+ tag = (struct boundary_tag*)memory_alloc_page(pages);
+
+ if (tag == NULL) return NULL;
+
+ tag->magic = ALLOC_MAGIC;
+ tag->size = size;
+ tag->real_size = pages * l_pageSize;
+ tag->index = -1;
+
+ tag->next = NULL;
+ tag->prev = NULL;
+ tag->split_left = NULL;
+ tag->split_right = NULL;
+
+ return tag;
+}
+
+
+
+void *malloc(size_t size) {
+ int index;
+ void *ptr;
+ struct boundary_tag *tag = NULL;
+
+ memory_lock();
+
+ if (l_initialized == 0) {
+ for (index = 0; index < MAXEXP; index++) {
+ l_freePages[index] = NULL;
+ l_completePages[index] = 0;
+ }
+ l_initialized = 1;
+ }
+
+ index = getexp(size) + MODE;
+ if (index < MINEXP) index = MINEXP;
+
+ tag = l_freePages[index];
+ while (tag != NULL) {
+ if (
+ (tag->real_size - sizeof(struct boundary_tag))
+ >= (size + sizeof(struct boundary_tag))
+ ) {
+ break;
+ }
+ tag = tag->next;
+ }
+
+ if (tag == NULL) {
+ if ((tag = allocate_new_tag(size)) == NULL) {
+ memory_unlock();
+ return NULL;
+ }
+ index = getexp(tag->real_size - sizeof(struct boundary_tag));
+ } else {
+ remove_tag(tag);
+
+ if ((tag->split_left == NULL) && (tag->split_right == NULL))
+ l_completePages[ index ] -= 1;
+ }
+
+ tag->size = size;
+
+ unsigned int remainder = tag->real_size - size - sizeof(struct boundary_tag) * 2;
+
+ if (((int)(remainder) > 0)) {
+ int childIndex = getexp(remainder);
+
+ if (childIndex >= 0) {
+ struct boundary_tag *new_tag = split_tag(tag);
+ tag = new_tag;
+ }
+ }
+
+ ptr = (void*)((uintptr_t)(void *)tag + sizeof(struct boundary_tag));
+ memory_unlock();
+ return ptr;
+}
+
+void free(void *ptr) {
+ int index;
+ struct boundary_tag *tag;
+
+ if (ptr == NULL) return;
+
+ memory_lock();
+
+ tag = (struct boundary_tag*)((uintptr_t)(void *)ptr - sizeof(struct boundary_tag));
+
+ if (tag->magic != ALLOC_MAGIC) {
+ memory_unlock();
+ return;
+ }
+
+ while ((tag->split_left != NULL) && (tag->split_left->index >= 0)) {
+ tag = melt_left(tag);
+ remove_tag(tag);
+ }
+
+ while ((tag->split_right != NULL) && (tag->split_right->index >= 0)) {
+ tag = absorb_right(tag);
+ }
+
+ index = getexp(tag->real_size - sizeof(struct boundary_tag));
+ if (index < MINEXP) index = MINEXP;
+
+ if ((tag->split_left == NULL) && (tag->split_right == NULL)) {
+ if (l_completePages[index] == MAXCOMPLETE) {
+ unsigned int pages = tag->real_size / l_pageSize;
+
+ if ((tag->real_size % l_pageSize) != 0) pages += 1;
+ if (pages < (unsigned) l_pageCount) pages = l_pageCount;
+
+ memory_free_page(tag, pages);
+ memory_unlock();
+ return;
+ }
+
+ l_completePages[ index ] += 1;
+ }
+
+ insert_tag(tag, index);
+
+ memory_unlock();
+}
+
+void* calloc(size_t nobj, size_t size) {
+ int real_size;
+ void *p;
+
+ real_size = nobj * size;
+
+ p = malloc(real_size);
+
+ memset(p, 0, real_size);
+
+ return p;
+}
+
+void* realloc(void *p, size_t size) {
+ void *ptr;
+ struct boundary_tag *tag;
+ size_t real_size;
+
+ if (size == 0) {
+ free(p);
+ return NULL;
+ }
+
+ if (p == NULL) {
+ return malloc(size);
+ }
+
+ memory_lock();
+ tag = (struct boundary_tag*)((uintptr_t)(void *)p - sizeof(struct boundary_tag));
+ real_size = tag->size;
+ memory_unlock();
+
+ if (real_size > size) real_size = size;
+
+ ptr = malloc(size);
+ memcpy(ptr, p, real_size);
+ free(p);
+
+ return ptr;
+}
diff --git a/kernel/src/memory/memory.c b/kernel/src/memory/memory.c
new file mode 100644
index 0000000..30da0fc
--- /dev/null
+++ b/kernel/src/memory/memory.c
@@ -0,0 +1,202 @@
+#include <stdint.h>
+#include <string.h>
+#include <sys.h>
+#include <panic.h>
+
+#include "memory.h"
+#include "boot/tag.h"
+#include "print.h"
+
+struct MemoryArea {
+ uint32_t len;
+ struct MemoryArea *prev;
+ struct MemoryArea *next;
+};
+
+typedef unsigned char page[4096];
+
+extern unsigned char kernel_start, kernel_end;
+static uintptr_t kernel_start_addr, kernel_end_addr;
+static uint32_t *bitmap;
+static uint32_t total_memory;
+static uint32_t free_memory;
+static uint32_t page_count;
+static uint32_t page_free_start;
+static struct MemoryArea *page_start;
+
+int memory_lock(void) {
+ int_disable();
+ return 0;
+}
+
+int memory_unlock(void) {
+ int_enable();
+ return 0;
+}
+
+static int n_pages(const struct MemoryArea *m) {
+ return (m->len - sizeof(*m)) / sizeof(page);
+}
+
+static void *page_at(int i) {
+ int cur_page = 0;
+ for (struct MemoryArea *m = page_start; m != NULL; m = m->next) {
+ int pages = n_pages(m);
+ if (i - cur_page < pages) {
+ page *page_array = (page *) (m + 1);
+ return page_array[i - cur_page];
+ }
+ cur_page += pages;
+ }
+ return NULL;
+}
+
+static int page_idx(page p) {
+ uintptr_t addr = (uintptr_t) p;
+ int cur_page = 0;
+ for (struct MemoryArea *m = page_start; m != NULL; m = m->next) {
+ if ((uintptr_t) m + m->len > addr) {
+ return cur_page + (addr - (uintptr_t) m) / sizeof(page);
+ }
+ cur_page += n_pages(m);
+ }
+ return -1;
+}
+
+static inline bool bitmap_get(int i) {
+ return (bitmap[i / 32] >> i % 32) & 1;
+}
+
+static inline void bitmap_set(int i, bool v) {
+ int idx = i / 32;
+ bitmap[idx] &= ~(1 << i % 32);
+ bitmap[idx] |= (v << i % 32);
+}
+
+void *memory_alloc_page(int pages) {
+ if (pages < 1) return NULL;
+
+ int n_contiguous = 0;
+ int free_region_start = 0;
+ bool first = true;
+ for (uint32_t i = page_free_start; i < page_count; i++) {
+ bool free = !bitmap_get(i);
+
+ if (first) {
+ first = false;
+ page_free_start = i;
+ }
+
+ if (free) {
+ if (n_contiguous == 0) free_region_start = i;
+ n_contiguous++;
+ if (n_contiguous == pages) {
+ for (int j = 0; j < pages; j++)
+ bitmap_set(free_region_start + j, true);
+ return page_at(free_region_start);
+ }
+ } else n_contiguous = 0;
+ }
+
+ return NULL;
+}
+
+int memory_free_page(void *ptr, int pages) {
+ int idx = page_idx(ptr);
+ if (idx == -1) return 1;
+
+ if ((unsigned) idx < page_free_start) page_free_start = idx;
+
+ for (int i = 0; i < pages; i++)
+ bitmap_set(idx + pages, false);
+ return 0;
+}
+
+void memory_init(void) {
+
+ debugk("Loading memory pages");
+
+ memory_lock();
+
+ bitmap = NULL;
+ total_memory = 0;
+ free_memory = 0;
+ page_count = 0;
+ page_free_start = 0;
+ page_start = NULL;
+
+ kernel_start_addr = (uintptr_t) &kernel_start;
+ kernel_end_addr = (uintptr_t) &kernel_end;
+
+ struct BootTag *tag;
+ if (!get_boot_tag(iD_MEMORYMAP, &tag)) {
+ panic("No multiboot memory map found");
+ }
+
+ uintptr_t end = (uintptr_t) tag->data.memory_map;
+ end += tag->size;
+
+ struct MemoryArea *prev = NULL;
+ struct MemorySegment *segment = &tag->data.memory_map->entries[0];
+ for(; (uintptr_t) segment < end; segment++) {
+
+ if (segment->type != 1) continue;
+ if (segment->addr >= UINT32_MAX) continue;
+ if (segment->addr < kernel_start_addr) continue;
+
+ uint32_t length;
+ if (segment->addr + segment->len > UINT32_MAX) {
+ length = UINT32_MAX - segment->addr;
+ } else {
+ length = segment->len;
+ }
+
+ uintptr_t addr;
+ if (segment->addr < kernel_end_addr) {
+ addr = kernel_end_addr;
+ length -= addr - segment->addr;
+ } else {
+ addr = segment->addr;
+ }
+
+ struct MemoryArea *current = (struct MemoryArea *) addr;
+ current->prev = prev;
+ current->next = NULL;
+ current->len = length;
+
+ if (prev != NULL) {
+ prev->next = current;
+ } else {
+ page_start = current;
+ }
+
+ page_count += n_pages(current);
+ total_memory += length;
+
+ prev = current;
+
+ }
+
+ int bitmap_pages = page_count / 32 / sizeof(page) + 1;
+ bitmap = (uint32_t *) page_at(page_count - bitmap_pages);
+ page_count -= bitmap_pages;
+ memset(bitmap, 0, bitmap_pages * sizeof(page));
+ free_memory = page_count * sizeof(page);
+
+ memory_unlock();
+
+ succek("Memory loaded. %k total %k free", total_memory, free_memory);
+
+}
+
+uint32_t memory_total(void) {
+ return total_memory;
+}
+
+uint32_t memory_free(void) {
+ return free_memory;
+}
+
+uint32_t memory_used(void) {
+ return total_memory - free_memory;
+}
diff --git a/kernel/src/memory/memory.h b/kernel/src/memory/memory.h
new file mode 100644
index 0000000..5d99025
--- /dev/null
+++ b/kernel/src/memory/memory.h
@@ -0,0 +1,22 @@
+#pragma once
+
+#include <stdint.h>
+
+struct MemorySegment {
+ uint64_t addr;
+ uint64_t len;
+ uint32_t type;
+ uint32_t reserved;
+} __attribute__((packed));
+
+struct MemoryMap {
+ uint32_t entry_size;
+ uint32_t entry_version;
+ struct MemorySegment entries[];
+} __attribute__((packed));
+
+uint32_t memory_total(void);
+uint32_t memory_free(void);
+uint32_t memory_used(void);
+
+void memory_init(void);
diff --git a/kernel/src/print/panic.c b/kernel/src/print/panic.c
new file mode 100644
index 0000000..5e686e1
--- /dev/null
+++ b/kernel/src/print/panic.c
@@ -0,0 +1,27 @@
+#include <sys.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <panic.h>
+#include <print.h>
+
+#include "tty/color.h"
+#include "tty/term.h"
+
+__attribute__((noreturn))
+void _panic_impl(char* msg, int line, char* file, ...) {
+ int_disable();
+ va_list args;
+ va_start(args, file);
+ term_clear();
+ term_setpos(0, 0);
+ term_setfg(VGA_LIGHT_RED);
+ puts("!!!PANIC!!!\n");
+ term_setfg(VGA_WHITE);
+ vprintk(msg, args);
+ if (!term_newline()) putchar('\n');
+ printk("\nin %s at line %d\n", file, line);
+
+ while(1) {
+ halt();
+ }
+}
diff --git a/kernel/src/print/print.c b/kernel/src/print/print.c
new file mode 100644
index 0000000..46ec047
--- /dev/null
+++ b/kernel/src/print/print.c
@@ -0,0 +1,128 @@
+#include "tty/color.h"
+#include "tty/term.h"
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <print.h>
+
+void printk(const char *restrict format, ...) {
+ va_list args;
+ va_start(args, format);
+ vprintk(format, args);
+ va_end(args);
+}
+
+void vprintk(const char *restrict format, va_list args) {
+ char buf[80];
+ for (; *format; format++) {
+ if (*format == '%') {
+ bool l = false;
+ char c = *++format;
+ if (c == 'l') {
+ l = true;
+ c = *++format;
+ }
+ switch(c) {
+ case '%':
+ putchar('%');
+ break;
+ case 's':
+ puts(va_arg(args, char*));
+ break;
+ case 'c':
+ putchar(va_arg(args, int));
+ break;
+ case 'd':
+ if (l) ltoa(va_arg(args, long long), buf, 10);
+ else itoa(va_arg(args, int), buf, 10);
+ puts(buf);
+ break;
+ case 'u':
+ if (l) ultoa(va_arg(args, unsigned long long), buf, 10);
+ else utoa(va_arg(args, unsigned int), buf, 10);
+ puts(buf);
+ break;
+ case 'f':
+ case 'F':
+ ftoa(va_arg(args, double), buf);
+ puts(buf);
+ break;
+ case 'x':
+ case 'X':
+ utoa(va_arg(args, unsigned int), buf, 16);
+ puts(buf);
+ break;
+ case 'b':
+ va_arg(args, int) ? puts("true") : puts("false");
+ break;
+ case 'k': {
+ static char disp[] = {'B', 'K', 'M', 'G'};
+ uint32_t size = va_arg(args, unsigned int);
+ size_t i = 0;
+ while (size / 1024 > 0) {
+ size /= 1024;
+ i++;
+ }
+ utoa(size, buf, 10);
+ puts(buf);
+ putchar(disp[i]);
+ if (i > 0) putchar('B');
+ break;
+ }
+ default:
+ break;
+ }
+ } else {
+ putchar(*format);
+ }
+ }
+}
+
+void puts(const char *s) {
+ for(; *s; s++) putchar(*s);
+}
+
+void printl(enum VGAColor color, const char* msg) {
+ term_setbg(VGA_BLACK);
+ term_setfg(VGA_WHITE);
+ putchar('[');
+ term_setfg(color);
+ printk("%s", msg);
+ term_setfg(VGA_WHITE);
+ putchar(']');
+ putchar(' ');
+}
+
+void _debugk_impl(char *format, ...) {
+ uint16_t color = term_save_col();
+ printl(VGA_LIGHT_CYAN, "LOG");
+ va_list args;
+ va_start(args, format);
+ vprintk(format, args);
+ va_end(args);
+ if (!term_newline()) putchar('\n');
+ term_load_col(color);
+}
+
+void _succek_impl(char *format, ...) {
+ uint16_t color = term_save_col();
+ printl(VGA_LIGHT_GREEN, "OK");
+ va_list args;
+ va_start(args, format);
+ vprintk(format, args);
+ va_end(args);
+ if (!term_newline()) putchar('\n');
+ term_load_col(color);
+}
+
+void _errork_impl(char *format, ...) {
+ uint16_t color = term_save_col();
+ printl(VGA_LIGHT_RED, "ERR");
+ va_list args;
+ va_start(args, format);
+ vprintk(format, args);
+ va_end(args);
+ if (!term_newline()) putchar('\n');
+ term_load_col(color);
+}
diff --git a/kernel/src/start.asm b/kernel/src/start.asm
new file mode 100644
index 0000000..95f4a05
--- /dev/null
+++ b/kernel/src/start.asm
@@ -0,0 +1,75 @@
+global start
+global heap_start
+extern kernel_main
+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
+
+MAGIC equ 0xe85250d6
+LENGTH equ mb_end - mb_start
+CHECKSUM equ -(MAGIC + LENGTH)
+
+section .multiboot
+align 8
+mb_start:
+dd MAGIC
+dd 0
+dd LENGTH
+dd CHECKSUM
+dw 0
+dw 0
+dd 8
+mb_end:
+
+section .bss
+align 16
+stack_end:
+resb 16384
+stack_top:
+
+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]
+ mov eax, cr0
+ or al, 1
+ mov cr0, eax
+ 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
+ sti
+ push ebx
+ call kernel_main
+ cli
+halt:
+ hlt
+ jmp halt
diff --git a/kernel/src/tty/color.c b/kernel/src/tty/color.c
new file mode 100644
index 0000000..c7258d9
--- /dev/null
+++ b/kernel/src/tty/color.c
@@ -0,0 +1,67 @@
+#include "color.h"
+#include "panic.h"
+
+bool itoac(int i, enum AnsiiColor *color) {
+ if (i < 0 || i > 15) return false;
+ *color = i;
+ return true;
+}
+
+bool itovc(int i, enum VGAColor *color) {
+ if (
+ (i >= 30 && i <= 37) ||
+ (i >= 40 && i <= 47) ||
+ (i >= 90 && i <= 97) ||
+ (i >= 100 && i <= 107)
+ ) {
+ *color = i;
+ return true;
+ }
+ return false;
+}
+
+enum VGAColor atovc(enum AnsiiColor color) {
+ switch(color) {
+ case ANSII_FRONT_BLACK:
+ case ANSII_FRONT_BLACK_EMPH:
+ case ANSII_BACK_BLACK:
+ case ANSII_BACK_BLACK_EMPH:
+ return VGA_BLACK;
+ case ANSII_FRONT_RED:
+ case ANSII_FRONT_RED_EMPH:
+ case ANSII_BACK_RED:
+ case ANSII_BACK_RED_EMPH:
+ return VGA_LIGHT_RED;
+ case ANSII_FRONT_GREEN:
+ case ANSII_FRONT_GREEN_EMPH:
+ case ANSII_BACK_GREEN:
+ case ANSII_BACK_GREEN_EMPH:
+ return VGA_LIGHT_GREEN;
+ case ANSII_FRONT_YELLOW:
+ case ANSII_FRONT_YELLOW_EMPH:
+ case ANSII_BACK_YELLOW:
+ case ANSII_BACK_YELLOW_EMPH:
+ return VGA_LIGHT_BROWN;
+ case ANSII_FRONT_BLUE:
+ case ANSII_FRONT_BLUE_EMPH:
+ case ANSII_BACK_BLUE:
+ case ANSII_BACK_BLUE_EMPH:
+ return VGA_LIGHT_BLUE;
+ case ANSII_FRONT_PURPLE:
+ case ANSII_FRONT_PURPLE_EMPH:
+ case ANSII_BACK_PURPLE:
+ case ANSII_BACK_PURPLE_EMPH:
+ return VGA_LIGHT_MAGENTA;
+ case ANSII_FRONT_CYAN:
+ case ANSII_FRONT_CYAN_EMPH:
+ case ANSII_BACK_CYAN:
+ case ANSII_BACK_CYAN_EMPH:
+ return VGA_LIGHT_CYAN;
+ case ANSII_FRONT_WHITE:
+ case ANSII_FRONT_WHITE_EMPH:
+ case ANSII_BACK_WHITE:
+ case ANSII_BACK_WHITE_EMPH:
+ return VGA_WHITE;
+ }
+ panic("this should not be reached (make gcc quiet)");
+}
diff --git a/kernel/src/tty/color.h b/kernel/src/tty/color.h
new file mode 100644
index 0000000..0751353
--- /dev/null
+++ b/kernel/src/tty/color.h
@@ -0,0 +1,62 @@
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+
+enum VGAColor {
+ VGA_BLACK = 0,
+ VGA_BLUE = 1,
+ VGA_GREEN = 2,
+ VGA_CYAN = 3,
+ VGA_RED = 4,
+ VGA_MAGENTA = 5,
+ VGA_BROWN = 6,
+ VGA_LIGHT_GREY = 7,
+ VGA_DARK_GREY = 8,
+ VGA_LIGHT_BLUE = 9,
+ VGA_LIGHT_GREEN = 10,
+ VGA_LIGHT_CYAN = 11,
+ VGA_LIGHT_RED = 12,
+ VGA_LIGHT_MAGENTA = 13,
+ VGA_LIGHT_BROWN = 14,
+ VGA_WHITE = 15,
+};
+
+enum AnsiiColor {
+ ANSII_FRONT_BLACK = 30,
+ ANSII_FRONT_RED = 31,
+ ANSII_FRONT_GREEN = 32,
+ ANSII_FRONT_YELLOW = 33,
+ ANSII_FRONT_BLUE = 34,
+ ANSII_FRONT_PURPLE = 35,
+ ANSII_FRONT_CYAN = 36,
+ ANSII_FRONT_WHITE = 37,
+ ANSII_FRONT_BLACK_EMPH = 90,
+ ANSII_FRONT_RED_EMPH = 91,
+ ANSII_FRONT_GREEN_EMPH = 92,
+ ANSII_FRONT_YELLOW_EMPH = 93,
+ ANSII_FRONT_BLUE_EMPH = 94,
+ ANSII_FRONT_PURPLE_EMPH = 95,
+ ANSII_FRONT_CYAN_EMPH = 96,
+ ANSII_FRONT_WHITE_EMPH = 97,
+ ANSII_BACK_BLACK = 40,
+ ANSII_BACK_RED = 41,
+ ANSII_BACK_GREEN = 42,
+ ANSII_BACK_YELLOW = 43,
+ ANSII_BACK_BLUE = 44,
+ ANSII_BACK_PURPLE = 45,
+ ANSII_BACK_CYAN = 46,
+ ANSII_BACK_WHITE = 47,
+ ANSII_BACK_BLACK_EMPH = 100,
+ ANSII_BACK_RED_EMPH = 101,
+ ANSII_BACK_GREEN_EMPH = 102,
+ ANSII_BACK_YELLOW_EMPH = 103,
+ ANSII_BACK_BLUE_EMPH = 104,
+ ANSII_BACK_PURPLE_EMPH = 105,
+ ANSII_BACK_CYAN_EMPH = 106,
+ ANSII_BACK_WHITE_EMPH = 107,
+};
+
+bool itoac(int i, enum AnsiiColor *color);
+bool itovc(int i, enum VGAColor *color);
+enum VGAColor atovc(enum AnsiiColor color);
diff --git a/kernel/src/tty/cursor.c b/kernel/src/tty/cursor.c
new file mode 100644
index 0000000..3a3888b
--- /dev/null
+++ b/kernel/src/tty/cursor.c
@@ -0,0 +1,30 @@
+#include <sys.h>
+
+#include "cursor.h"
+#include "term.h"
+
+void cursor_enable(void) {
+ cursor_setsize(13, 16);
+}
+
+void cursor_disable(void) {
+ outb(0x3D4, 0x0A);
+ outb(0x3D5, 0x20);
+}
+
+void cursor_setsize(uint8_t start, uint8_t end) {
+ outb(0x3D4, 0x0A);
+ outb(0x3D5, (inb(0x3D5) & 0xC0) | start);
+
+ outb(0x3D4, 0x0B);
+ outb(0x3D5, (inb(0x3D5) & 0xE0) | end);
+}
+
+void cursor_setpos(uint8_t x, uint8_t y) {
+; uint16_t pos = y * TERM_W + x;
+
+ outb(0x3D4, 0x0F);
+ outb(0x3D5, (uint8_t) (pos & 0xFF));
+ outb(0x3D4, 0x0E);
+ outb(0x3D5, (uint8_t) ((pos >> 8) & 0xFF));
+}
diff --git a/kernel/src/tty/cursor.h b/kernel/src/tty/cursor.h
new file mode 100644
index 0000000..602d9cd
--- /dev/null
+++ b/kernel/src/tty/cursor.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include <stdint.h>
+
+void cursor_enable(void);
+void cursor_disable(void);
+void cursor_setsize(uint8_t start, uint8_t end);
+void cursor_setpos(uint8_t x, uint8_t y);
+
diff --git a/kernel/src/tty/term.c b/kernel/src/tty/term.c
new file mode 100644
index 0000000..4f75788
--- /dev/null
+++ b/kernel/src/tty/term.c
@@ -0,0 +1,131 @@
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys.h>
+#include <print.h>
+
+#include "term.h"
+#include "color.h"
+#include "cursor.h"
+
+uint16_t *buffer;
+uint8_t x, y;
+uint8_t color;
+
+const uint16_t blank = (uint16_t) 0 | VGA_BLACK << 12 | VGA_WHITE << 8;
+
+static void term_clear_line(int y) {
+ if (y < 0 || y >= TERM_H)
+ return;
+ for (uint8_t x = 0; x < TERM_W; x++) {
+ const size_t index = y * TERM_W + x;
+ buffer[index] = blank;
+ }
+}
+
+void term_init (void) {
+ x = 0;
+ y = 0;
+ buffer = (uint16_t*) 0xb8000;
+ term_setfg(VGA_WHITE);
+ term_setbg(VGA_BLACK);
+ term_clear();
+}
+
+void term_setpos(uint8_t xp, uint8_t yp) {
+ x = xp;
+ y = yp;
+ cursor_setpos(x, y);
+}
+
+void term_scroll (int lines) {
+ int_disable();
+ y -= lines;
+ if (!lines) return;
+ if(lines >= TERM_H || lines <= -TERM_H) {
+ term_clear();
+ } else if(lines > 0) {
+ memmove(buffer, buffer + lines * TERM_W, 2 * (TERM_H - lines) * TERM_W);
+ term_clear_line(TERM_H - lines);
+ } else {
+ memmove(buffer + lines * TERM_W, buffer + lines, (TERM_H + lines) * TERM_W);
+ }
+ int_enable();
+}
+
+void term_setfg(enum VGAColor c) {
+ color = (color & 0xF0) | c;
+}
+
+void term_setbg(enum VGAColor c) {
+ color = (color & 0x0F) | c << 4;
+}
+
+void term_clear (void) {
+ for (uint8_t y = 0; y < TERM_H; y++)
+ term_clear_line(y);
+}
+
+uint32_t term_save(void) {
+ uint32_t state = 0;
+ state |= (uint32_t) x << 16;
+ state |= (uint32_t) y << 8;
+ state |= (uint32_t) color << 0;
+ return state;
+}
+
+void term_load(uint32_t state) {
+ x = (uint8_t) (state >> 16);
+ y = (uint8_t) (state >> 8);
+ color = (uint8_t) (state >> 0);
+ cursor_setpos(x, y);
+}
+
+uint16_t term_save_col(void) {
+ return color;
+}
+
+void term_load_col(uint16_t c) {
+ color = c;
+}
+
+void putchar(int c) {
+ switch (c) {
+ case '\n':
+ x = 0;
+ y++;
+ break;
+ case '\t':
+ x += 4;
+ break;
+ case '\v':
+ case '\f':
+ y++;
+ break;
+ case '\r':
+ x = 0;
+ break;
+ default: {
+ const size_t index = y * TERM_W + x;
+ buffer[index] = c | (uint16_t) color << 8;
+ x++;
+ }
+ }
+
+ if (x >= TERM_W) {
+ x = 0;
+ y++;
+ }
+
+ if (y >= TERM_H) {
+ term_scroll(y - (TERM_H - 1));
+ y = TERM_H - 1;
+ }
+
+ cursor_setpos(x, y);
+}
+
+bool term_newline(void) {
+ return x == 0;
+}
diff --git a/kernel/src/tty/term.h b/kernel/src/tty/term.h
new file mode 100644
index 0000000..f6eb555
--- /dev/null
+++ b/kernel/src/tty/term.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include "color.h"
+
+#define TERM_W 80
+#define TERM_H 25
+
+void term_init(void);
+
+void term_reset(void);
+void term_setfg(enum VGAColor color);
+void term_setbg(enum VGAColor color);
+
+void term_clear(void);
+void term_scroll(int lines);
+void term_setpos(uint8_t x, uint8_t y);
+
+uint32_t term_save(void);
+void term_load(uint32_t state);
+
+uint16_t term_save_col(void);
+void term_load_col(uint16_t color);
+
+bool term_newline(void);
diff --git a/libk/Makefile b/libk/Makefile
new file mode 100644
index 0000000..97bc3cd
--- /dev/null
+++ b/libk/Makefile
@@ -0,0 +1,20 @@
+include ../.env
+
+SRC = $(shell find src -type f -name "*.c")
+OBJ = $(patsubst %.c,bin/%.o, $(SRC))
+CFLAGS += -Iinclude -Isrc -std=c99
+
+.PHONY: all
+
+all: bin/libk.a
+
+$(OBJ): bin/%.o : %.c
+ @mkdir -p $(@D)
+ $(CC) -c $(CFLAGS) -o $@ $<
+
+bin/libk.a: $(OBJ)
+ @mkdir -p $(@D)
+ $(AR) rcs $@ $(OBJ)
+
+clean:
+ rm -fr bin
diff --git a/libk/compile_flags.txt b/libk/compile_flags.txt
new file mode 100644
index 0000000..2048fc0
--- /dev/null
+++ b/libk/compile_flags.txt
@@ -0,0 +1,10 @@
+-c
+-std=c99
+-Wall
+-Wextra
+-pedantic
+-O2
+-ffreestanding
+-Isrc
+-Iinclude
+-nostdlib
diff --git a/libk/include/ctype.h b/libk/include/ctype.h
new file mode 100644
index 0000000..289297e
--- /dev/null
+++ b/libk/include/ctype.h
@@ -0,0 +1,4 @@
+#pragma once
+
+int isspace(int c);
+int isdigit(int c);
diff --git a/libk/include/math.h b/libk/include/math.h
new file mode 100644
index 0000000..9682103
--- /dev/null
+++ b/libk/include/math.h
@@ -0,0 +1,62 @@
+#pragma once
+
+#define PI 3.14159265358979323846
+#define E 0.57721566490153286060
+
+#define NAN 0x7ff8000000000000
+#define INFINITY 0x7ff0000000000000
+#define NEG_INFINITY 0xfff0000000000000
+
+double frexp(double arg, int* exp);
+float frexpf(float arg, int* exp);
+
+double sqrt(double num);
+float sqrtf(float num);
+
+double pow(double num, double raise);
+float powf(float num, float raise);
+
+#define exp(x) pow(E, x)
+#define expf(x) powf(E, x)
+
+double fabs(double num);
+float fabsf(float num);
+
+double floor(double x);
+float floorf(float x);
+
+double ceil(double x);
+float ceilf(float x);
+
+double fma(double x, double y, double z);
+float fmaf(float x, float y, float z);
+
+double copysign(double n, double s);
+float copysignf(float n, float s);
+
+double fmod(double x, double y);
+float fmodf(float x, float y);
+
+double fclamp(double x, double l, double h);
+float fclampf(float x, float l, float h);
+
+#define isnan(n) (n == NAN)
+#define isinf(n) (n == INFINITY)
+
+double sin(double r);
+double cos(double r);
+double tan(double r);
+
+double csc(double r);
+double sec(double r);
+double cot(double r);
+
+double sinh(double r);
+double cosh(double r);
+double tanh(double r);
+
+double csch(double r);
+double sech(double r);
+double coth(double r);
+
+unsigned long long fact(unsigned int num);
diff --git a/libk/include/stdlib.h b/libk/include/stdlib.h
new file mode 100644
index 0000000..1cb07a0
--- /dev/null
+++ b/libk/include/stdlib.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include <stddef.h>
+
+char itoc(int i);
+int ctoi(char c);
+
+int atoi(const char* s);
+long int atol(const char* s);
+long long int atoll(const char* s);
+
+char *itoa(int n, char *buffer, int radix);
+char *ltoa(long int n, char *buffer, int radix);
+char *utoa(unsigned int n, char *buffer, int radix);
+char *ultoa(unsigned long int n, char *buffer, int radix);
+char *ftoa(float f, char *buffer);
+
+int strtoi(const char *str, char **endptr, int base);
+long int strtol(const char *str, char **endptr, int base);
+long long int strtoll(const char *str, char **endptr, int base);
+
+extern void *malloc(size_t size);
+extern void *realloc(void *ptr, size_t size);
+extern void *calloc(size_t count, size_t size);
+extern void free(void *ptr);
diff --git a/libk/include/string.h b/libk/include/string.h
new file mode 100644
index 0000000..880bc8b
--- /dev/null
+++ b/libk/include/string.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <stddef.h>
+
+int memcmp(const void *vl, const void *vr, size_t n);
+void *memcpy(void *restrict dest, const void *restrict src, size_t n);
+void *memmove(void *dest, const void *src, size_t n);
+void *memset(void *dest, int c, size_t n);
+char *strcpy(char *restrict dest, const char *restrict src);
+char *strncpy(char *restrict dest, const char *restrict src, size_t n);
+size_t strlen(const char *s);
+int strncmp( const char* lhs, const char* rhs, size_t count );
+
diff --git a/libk/include/sys.h b/libk/include/sys.h
new file mode 100644
index 0000000..75618e8
--- /dev/null
+++ b/libk/include/sys.h
@@ -0,0 +1,51 @@
+#include <stdint.h>
+
+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 outb(uint16_t port, uint8_t val) {
+ __asm__ volatile ("outb %0, %1" : : "a"(val), "Nd"(port));
+}
+
+static inline uint16_t inw(uint16_t port) {
+ uint16_t ret;
+ __asm__ volatile ("inw %1, %0" : "=a"(ret) : "Nd"(port));
+ return ret;
+}
+
+static inline void outw(uint16_t port, uint16_t val) {
+ __asm__ volatile ("outw %0, %1" : : "a"(val), "Nd"(port));
+}
+
+static inline uint32_t inl(uint16_t port) {
+ uint32_t ret;
+ __asm__ volatile ("inl %1, %0" : "=a"(ret) : "Nd"(port));
+ return ret;
+}
+
+static inline void outl(uint16_t port, uint32_t val) {
+ __asm__ volatile ("outl %0, %1" : : "a"(val), "Nd"(port));
+}
+
+static inline void io_wait(void) {
+ outb(0x80, 0);
+}
+
+static inline void int_enable(void) {
+ __asm__ volatile ("sti");
+}
+
+static inline void int_disable(void) {
+ __asm__ volatile ("cli");
+}
+
+static inline void int_wait(void) {
+ __asm__ volatile ("sti; hlt");
+}
+
+static inline void halt(void) {
+ __asm__ volatile ("cli; hlt");
+}
diff --git a/libk/src/ctype.c b/libk/src/ctype.c
new file mode 100644
index 0000000..2e8714f
--- /dev/null
+++ b/libk/src/ctype.c
@@ -0,0 +1,19 @@
+#include <ctype.h>
+
+int isspace(int c) {
+ switch (c) {
+ case ' ':
+ case '\t':
+ case '\v':
+ case '\f':
+ case '\r':
+ case '\n':
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int isdigit(int c) {
+ return c - '0' > -1 && c - '0' < 10;
+}
diff --git a/libk/src/internal/libm.h b/libk/src/internal/libm.h
new file mode 100644
index 0000000..6c47502
--- /dev/null
+++ b/libk/src/internal/libm.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#define fp_force_evalf fp_force_evalf
+static inline void fp_force_evalf(float x) {
+ volatile float y;
+ y = x;
+ (void)y;
+}
+
+#define fp_force_eval fp_force_eval
+static inline void fp_force_eval(double x) {
+ volatile double y;
+ y = x;
+ (void)y;
+}
+
+#define fp_force_evall fp_force_evall
+static inline void fp_force_evall(long double x) {
+ volatile long double y;
+ y = x;
+ (void)y;
+}
+
+#define FORCE_EVAL(x) do { \
+ if (sizeof(x) == sizeof(float)) { \
+ fp_force_evalf(x); \
+ } else if (sizeof(x) == sizeof(double)) { \
+ fp_force_eval(x); \
+ } else { \
+ fp_force_evall(x); \
+ } \
+} while(0)
diff --git a/libk/src/math/abs.c b/libk/src/math/abs.c
new file mode 100644
index 0000000..1757272
--- /dev/null
+++ b/libk/src/math/abs.c
@@ -0,0 +1,14 @@
+#include <math.h>
+#include <stdint.h>
+
+float fabsf(float num) {
+ union {float f; uint32_t i;} u = {num};
+ u.i &= 0x7fffffff;
+ return u.f;
+}
+
+double fabs(double num) {
+ union {double f; uint64_t i;} u = {num};
+ u.i &= -1ULL/2;
+ return u.f;
+}
diff --git a/libk/src/math/ceil.c b/libk/src/math/ceil.c
new file mode 100644
index 0000000..17b667f
--- /dev/null
+++ b/libk/src/math/ceil.c
@@ -0,0 +1,59 @@
+#include <stdint.h>
+#include <float.h>
+#include <math.h>
+
+#include "internal/libm.h"
+
+#define EPS DBL_EPSILON
+
+static const double toint = 1/EPS;
+
+double ceil(double x)
+{
+ union {double f; uint64_t i;} u = {x};
+ int e = u.i >> 52 & 0x7ff;
+ double y;
+
+ if (e >= 0x3ff+52 || x == 0)
+ return x;
+
+ if (u.i >> 63) {
+ y = x - toint + toint - x;
+ } else {
+ y = x + toint - toint - x;
+ }
+
+ if (e <= 0x3ff-1) {
+ FORCE_EVAL(y);
+ return u.i >> 63 ? -0.0 : 1;
+ }
+
+ if (y < 0)
+ return x + y + 1;
+ return x + y;
+}
+
+float ceilf(float x) {
+ union {float f; uint32_t i;} u = {x};
+ int e = (int)(u.i >> 23 & 0xff) - 0x7f;
+ uint32_t m;
+
+ if (e >= 23)
+ return x;
+ if (e >= 0) {
+ m = 0x007fffff >> e;
+ if ((u.i & m) == 0)
+ return x;
+ FORCE_EVAL(x + 0x1p120f);
+ if (u.i >> 31 == 0)
+ u.i += m;
+ u.i &= ~m;
+ } else {
+ FORCE_EVAL(x + 0x1p120f);
+ if (u.i >> 31)
+ u.f = -0.0;
+ else if (u.i << 1)
+ u.f = 1.0;
+ }
+ return u.f;
+}
diff --git a/libk/src/math/copysign.c b/libk/src/math/copysign.c
new file mode 100644
index 0000000..fd5fd4f
--- /dev/null
+++ b/libk/src/math/copysign.c
@@ -0,0 +1,20 @@
+#include <math.h>
+#include <stdint.h>
+
+#define DMASK 0x8000000000000000
+
+double copysign(double n, double s) {
+ union {double f; uint64_t i;} sb = {s};
+ union {double f; uint64_t i;} nb = {n};
+ nb.i = (nb.i & ~DMASK) | (sb.i & DMASK);
+ return nb.f;
+}
+
+#define FMASK 0x80000000
+
+float copysignf(float n, float s) {
+ union {float f; uint32_t i;} sb = {s};
+ union {float f; uint32_t i;} nb = {n};
+ nb.i = (nb.i & ~FMASK) | (sb.i & FMASK);
+ return nb.f;
+}
diff --git a/libk/src/math/fact.c b/libk/src/math/fact.c
new file mode 100644
index 0000000..a146e4d
--- /dev/null
+++ b/libk/src/math/fact.c
@@ -0,0 +1,29 @@
+#include <math.h>
+
+static unsigned int FACT_TABLE[] = {
+ 1, // 0
+ 1, // 1
+ 2, // 2
+ 6, // 3
+ 24, // 4
+ 120, // 5
+ 720, // 6
+ 5040, // 7
+ 40320, // 8
+ 362880, // 9
+ 3628800, // 10
+ 39916800, // 11
+ 479001600, // 12
+};
+
+unsigned long long fact(unsigned int num) {
+ if (num < 13) {
+ return FACT_TABLE[num];
+ }
+ unsigned long long l = FACT_TABLE[12];
+ for (unsigned int i = 12; i < num;) {
+ i++;
+ l *= i;
+ }
+ return l;
+}
diff --git a/libk/src/math/fclamp.c b/libk/src/math/fclamp.c
new file mode 100644
index 0000000..f757b48
--- /dev/null
+++ b/libk/src/math/fclamp.c
@@ -0,0 +1,13 @@
+#include <math.h>
+
+double fclamp(double x, double l, double h) {
+ if (x < l) return l;
+ if (x > h) return h;
+ return x;
+}
+
+float fclampf(float x, float l, float h) {
+ if (x < l) return l;
+ if (x > h) return h;
+ return x;
+}
diff --git a/libk/src/math/floor.c b/libk/src/math/floor.c
new file mode 100644
index 0000000..ce8e07e
--- /dev/null
+++ b/libk/src/math/floor.c
@@ -0,0 +1,55 @@
+#include <stdint.h>
+#include <float.h>
+#include <math.h>
+
+#include "internal/libm.h"
+
+#define EPS DBL_EPSILON
+
+static const double toint = 1/EPS;
+
+double floor(double x) {
+ union {double f; uint64_t i;} u = {x};
+ int e = u.i >> 52 & 0x7ff;
+ double y;
+
+ if (e >= 0x3ff+52 || x == 0)
+ return x;
+ if (u.i >> 63)
+ y = x - toint + toint - x;
+ else
+ y = x + toint - toint - x;
+ if (e <= 0x3ff-1) {
+ return u.i >> 63 ? -1 : 0;
+ }
+ if (y > 0) {
+ FORCE_EVAL(y);
+ return x + y - 1;
+ }
+ return x + y;
+}
+
+float floorf(float x) {
+ union {float f; uint32_t i;} u = {x};
+ int e = (int)(u.i >> 23 & 0xff) - 0x7f;
+ uint32_t m;
+
+ if (e >= 23)
+ return x;
+ if (e >= 0) {
+ m = 0x007fffff >> e;
+ if ((u.i & m) == 0)
+ return x;
+ FORCE_EVAL(x + 0x1p120f);
+ if (u.i >> 31)
+ u.i += m;
+ u.i &= ~m;
+ } else {
+ FORCE_EVAL(x + 0x1p120f);
+ if (u.i >> 31 == 0)
+ u.i = 0;
+ else if (u.i << 1)
+ u.f = -1.0;
+ }
+ return u.f;
+}
diff --git a/libk/src/math/fma.c b/libk/src/math/fma.c
new file mode 100644
index 0000000..b26229e
--- /dev/null
+++ b/libk/src/math/fma.c
@@ -0,0 +1,38 @@
+#include <stdint.h>
+#include <math.h>
+
+double fma(double x, double y, double z) {
+ double xy, result;
+ union {double f; uint64_t i;} u;
+ int e;
+
+ xy = (double)x * y;
+ result = xy + z;
+ u.f = result;
+ e = u.i>>52 & 0x7ff;
+ if (
+ (u.i & 0x1fffffff) != 0x10000000 ||
+ e == 0x7ff ||
+ (result - xy == z && result - z == xy)
+ ) {
+ z = result;
+ return z;
+ }
+
+ double err;
+ int neg = u.i >> 63;
+ if (neg == (z > xy))
+ err = xy - result + z;
+ else
+ err = z - result + xy;
+ if (neg == (err < 0))
+ u.i++;
+ else
+ u.i--;
+ z = u.f;
+ return z;
+}
+
+float fmaf(float x, float y, float z) {
+ return fma(x, y, z);
+}
diff --git a/libk/src/math/fmod.c b/libk/src/math/fmod.c
new file mode 100644
index 0000000..996f78b
--- /dev/null
+++ b/libk/src/math/fmod.c
@@ -0,0 +1,129 @@
+#include <math.h>
+#include <stdint.h>
+
+double fmod(double x, double y) {
+ union {double f; uint64_t i;} ux = {x}, uy = {y};
+ int ex = ux.i>>52 & 0x7ff;
+ int ey = uy.i>>52 & 0x7ff;
+ int sx = ux.i>>63;
+ uint64_t i;
+
+ /* in the followings uxi should be ux.i, but then gcc wrongly adds */
+ /* float load/store to inner loops ruining performance and code size */
+ uint64_t uxi = ux.i;
+
+ if (uy.i<<1 == 0 || isnan(y) || ex == 0x7ff)
+ return (x*y)/(x*y);
+ if (uxi<<1 <= uy.i<<1) {
+ if (uxi<<1 == uy.i<<1)
+ return 0*x;
+ return x;
+ }
+
+ /* normalize x and y */
+ if (!ex) {
+ for (i = uxi<<12; i>>63 == 0; ex--, i <<= 1);
+ uxi <<= -ex + 1;
+ } else {
+ uxi &= -1ULL >> 12;
+ uxi |= 1ULL << 52;
+ }
+ if (!ey) {
+ for (i = uy.i<<12; i>>63 == 0; ey--, i <<= 1);
+ uy.i <<= -ey + 1;
+ } else {
+ uy.i &= -1ULL >> 12;
+ uy.i |= 1ULL << 52;
+ }
+
+ /* x mod y */
+ for (; ex > ey; ex--) {
+ i = uxi - uy.i;
+ if (i >> 63 == 0) {
+ if (i == 0)
+ return 0*x;
+ uxi = i;
+ }
+ uxi <<= 1;
+ }
+ i = uxi - uy.i;
+ if (i >> 63 == 0) {
+ if (i == 0)
+ return 0*x;
+ uxi = i;
+ }
+ for (; uxi>>52 == 0; uxi <<= 1, ex--);
+
+ /* scale result */
+ if (ex > 0) {
+ uxi -= 1ULL << 52;
+ uxi |= (uint64_t)ex << 52;
+ } else {
+ uxi >>= -ex + 1;
+ }
+ uxi |= (uint64_t)sx << 63;
+ ux.i = uxi;
+ return ux.f;
+}
+
+float fmodf(float x, float y) {
+ union {float f; uint32_t i;} ux = {x}, uy = {y};
+ int ex = ux.i>>23 & 0xff;
+ int ey = uy.i>>23 & 0xff;
+ uint32_t sx = ux.i & 0x80000000;
+ uint32_t i;
+ uint32_t uxi = ux.i;
+
+ if (uy.i<<1 == 0 || isnan(y) || ex == 0xff)
+ return (x*y)/(x*y);
+ if (uxi<<1 <= uy.i<<1) {
+ if (uxi<<1 == uy.i<<1)
+ return 0*x;
+ return x;
+ }
+
+ /* normalize x and y */
+ if (!ex) {
+ for (i = uxi<<9; i>>31 == 0; ex--, i <<= 1);
+ uxi <<= -ex + 1;
+ } else {
+ uxi &= -1U >> 9;
+ uxi |= 1U << 23;
+ }
+ if (!ey) {
+ for (i = uy.i<<9; i>>31 == 0; ey--, i <<= 1);
+ uy.i <<= -ey + 1;
+ } else {
+ uy.i &= -1U >> 9;
+ uy.i |= 1U << 23;
+ }
+
+ /* x mod y */
+ for (; ex > ey; ex--) {
+ i = uxi - uy.i;
+ if (i >> 31 == 0) {
+ if (i == 0)
+ return 0*x;
+ uxi = i;
+ }
+ uxi <<= 1;
+ }
+ i = uxi - uy.i;
+ if (i >> 31 == 0) {
+ if (i == 0)
+ return 0*x;
+ uxi = i;
+ }
+ for (; uxi>>23 == 0; uxi <<= 1, ex--);
+
+ /* scale result up */
+ if (ex > 0) {
+ uxi -= 1U << 23;
+ uxi |= (uint32_t)ex << 23;
+ } else {
+ uxi >>= -ex + 1;
+ }
+ uxi |= sx;
+ ux.i = uxi;
+ return ux.f;
+}
diff --git a/libk/src/math/frexp.c b/libk/src/math/frexp.c
new file mode 100644
index 0000000..16b8dd3
--- /dev/null
+++ b/libk/src/math/frexp.c
@@ -0,0 +1,19 @@
+#include <math.h>
+
+double frexp(double arg, int* exp) {
+ *exp = 0;
+ while (arg > 1) {
+ arg /= 2;;
+ (*exp)++;
+ }
+ return arg;
+}
+
+float frexpf(float arg, int* exp) {
+ *exp = 0;
+ while (arg > 1) {
+ arg /= 2;
+ (*exp)++;
+ }
+ return arg;
+}
diff --git a/libk/src/math/pow.c b/libk/src/math/pow.c
new file mode 100644
index 0000000..c850db7
--- /dev/null
+++ b/libk/src/math/pow.c
@@ -0,0 +1,152 @@
+#include <stdint.h>
+#include <string.h>
+#include <math.h>
+
+uint32_t float_as_uint32 (float a) {
+ uint32_t r;
+ memcpy (&r, &a, sizeof r);
+ return r;
+}
+
+float uint32_as_float (uint32_t a) {
+ float r;
+ memcpy (&r, &a, sizeof r);
+ return r;
+}
+
+void logf_ext (float a, float *loghi, float *loglo) {
+ const float LOG2_HI = 6.93147182e-1f;
+ const float LOG2_LO = -1.90465421e-9f;
+ const float SQRT_HALF = 0.70710678f;
+ float m, r, i, s, t, p, qhi, qlo;
+ int e;
+
+ const float POW_TWO_M23 = 1.19209290e-7f;
+ const float POW_TWO_P23 = 8388608.0f;
+ const float FP32_MIN_NORM = 1.175494351e-38f;
+ i = 0.0f;
+
+ if (a < FP32_MIN_NORM) {
+ a = a * POW_TWO_P23;
+ i = -23.0f;
+ }
+
+ e = (float_as_uint32 (a) - float_as_uint32 (SQRT_HALF)) & 0xff800000;
+ m = uint32_as_float (float_as_uint32 (a) - e);
+ i = fmaf ((float)e, POW_TWO_M23, i);
+
+ p = m + 1.0f;
+ m = m - 1.0f;
+ r = 1.0f / p;
+ qhi = r * m;
+ qlo = r * fmaf (qhi, -m, fmaf (qhi, -2.0f, m));
+
+ s = qhi * qhi;
+ r = 0.1293334961f;
+ r = fmaf (r, s, 0.1419928074f);
+ r = fmaf (r, s, 0.2000148296f);
+ r = fmaf (r, s, 0.3333332539f);
+ t = fmaf (qhi, qlo + qlo, fmaf (qhi, qhi, -s));
+ p = s * qhi;
+ t = fmaf (s, qlo, fmaf (t, qhi, fmaf (s, qhi, -p)));
+ s = fmaf (r, p, fmaf (r, t, qlo));
+ r = 2 * qhi;
+
+ t = fmaf ( LOG2_HI, i, r);
+ p = fmaf (-LOG2_HI, i, t);
+ s = fmaf ( LOG2_LO, i, fmaf (2.f, s, r - p));
+ *loghi = p = t + s;
+ *loglo = (t - p) + s;
+}
+
+float expf_unchecked (float a) {
+ float f, j, r;
+ int i;
+
+ j = fmaf (1.442695f, a, 12582912.f) - 12582912.f;
+ f = fmaf (j, -6.93145752e-1f, a);
+ f = fmaf (j, -1.42860677e-6f, f);
+ i = (int)j;
+
+ r = 1.37805939e-3f;
+ r = fmaf (r, f, 8.37312452e-3f);
+ r = fmaf (r, f, 4.16695364e-2f);
+ r = fmaf (r, f, 1.66664720e-1f);
+ r = fmaf (r, f, 4.99999851e-1f);
+ r = fmaf (r, f, 1.00000000e+0f);
+ r = fmaf (r, f, 1.00000000e+0f);
+
+ float s, t;
+ uint32_t ia = (i > 0) ? 0u : 0x83000000u;
+ s = uint32_as_float (0x7f000000u + ia);
+ t = uint32_as_float (((uint32_t)i << 23) - ia);
+ r = r * s;
+ r = r * t;
+
+ return r;
+}
+
+float powf_core (float a, float b) {
+ const float MAX_IEEE754_FLT = uint32_as_float (0x7f7fffff);
+ const float EXP_OVFL_BOUND = 88.7228394f; // 0x1.62e430p+6f;
+ const float EXP_OVFL_UNFL_F = 104.0f;
+ const float MY_INF_F = uint32_as_float (0x7f800000);
+ float lhi, llo, thi, tlo, phi, plo, r;
+
+ logf_ext (a, &lhi, &llo);
+
+ thi = lhi * b;
+
+ if (fabsf (thi) > EXP_OVFL_UNFL_F) {
+ r = (thi < 0.0f) ? 0.0f : MY_INF_F;
+ } else {
+ tlo = fmaf (lhi, b, -thi);
+ tlo = fmaf (llo, b, +tlo);
+ phi = thi + tlo;
+
+ if (phi == EXP_OVFL_BOUND)
+ phi = uint32_as_float (float_as_uint32 (phi) - 1);
+
+ plo = (thi - phi) + tlo;
+ r = expf_unchecked (phi);
+ if (fabsf (r) <= MAX_IEEE754_FLT) {
+ r = fmaf (plo, r, r);
+ }
+ }
+ return r;
+}
+
+float powf (float a, float b) {
+ const float MY_INF_F = uint32_as_float (0x7f800000);
+ const float MY_NAN_F = uint32_as_float (0xffc00000);
+ int expo_odd_int;
+ float r;
+
+ expo_odd_int = fmaf (-2.0f, floorf (0.5f * b), b) == 1.0f;
+ if ((a == 1.0f) || (b == 0.0f)) {
+ r = 1.0f;
+ } else if (isnan (a) || isnan (b)) {
+ r = a + b;
+ } else if (isinf (b)) {
+ r = ((fabsf (a) < 1.0f) != (b < 0.0f)) ? 0.0f : MY_INF_F;
+ if (a == -1.0f) r = 1.0f;
+ } else if (isinf (a)) {
+ r = (b < 0.0f) ? 0.0f : MY_INF_F;
+ if ((a < 0.0f) && expo_odd_int) r = -r;
+ } else if (a == 0.0f) {
+ r = (expo_odd_int) ? (a + a) : 0.0f;
+ if (b < 0.0f) r = copysignf (MY_INF_F, r);
+ } else if ((a < 0.0f) && (b != floorf (b))) {
+ r = MY_NAN_F;
+ } else {
+ r = powf_core (fabsf (a), b);
+ if ((a < 0.0f) && expo_odd_int) {
+ r = -r;
+ }
+ }
+ return r;
+}
+
+double pow (double a, double b) {
+ return powf(a, b); // who cares about precision in a kernel :3
+}
diff --git a/libk/src/math/sqrt.c b/libk/src/math/sqrt.c
new file mode 100644
index 0000000..b875079
--- /dev/null
+++ b/libk/src/math/sqrt.c
@@ -0,0 +1,36 @@
+#include <math.h>
+
+float sqrtf(float num) {
+ if (num < 0)
+ return NAN;
+
+ if (num < 2)
+ return num;
+
+ float y = num;
+ float z = (y + (num / y)) / 2;
+
+ while (fabsf(y - z) >= 0.00001) {
+ y = z;
+ z = (y + (num / y)) / 2;
+ }
+ return z;
+}
+
+double sqrt(double num) {
+ if (num < 0)
+ return NAN;
+
+ if (num < 2)
+ return num;
+
+ double y = num;
+ double z = (y + (num / y)) / 2;
+
+ while (fabs(y - z) >= 0.00001) {
+ y = z;
+ z = (y + (num / y)) / 2;
+ }
+ return z;
+}
+
diff --git a/libk/src/math/trig.c b/libk/src/math/trig.c
new file mode 100644
index 0000000..f234d69
--- /dev/null
+++ b/libk/src/math/trig.c
@@ -0,0 +1,62 @@
+#include <math.h>
+
+double sin(double r) {
+ r = fmod(r + PI, PI * 2) - PI;
+ double d = r;
+ float mult = -1;
+ for (int i = 3; i < 11; i+= 2, mult = -mult) {
+ d += (pow(r, i)/fact(i)) * mult;
+ }
+ return d;
+}
+
+double cos(double r) {
+ r = fmod(r + PI, PI * 2) - PI;
+ double d = 1;
+ float mult = -1;
+ for (int i = 2; i < 10; i+= 2, mult = -mult) {
+ d += (pow(r, i)/fact(i)) * mult;
+ }
+ return d;
+}
+
+double tan(double r) {
+ return sin(r) / cos(r);
+}
+
+double csc(double r) {
+ return 1 / sin(r);
+}
+
+double sec(double r) {
+ return 1 / cos(r);
+}
+
+double cot(double r) {
+ return cos(r) / sin(r);
+}
+
+double sinh(double r) {
+ return (pow(E, r) - pow(E, -r)) / 2;
+}
+
+double cosh(double r) {
+ return (pow(E, r) + pow(E, -r)) / 2;
+}
+
+double tanh(double r) {
+ return sinh(r) / cosh(r);
+}
+
+double csch(double r) {
+ return 1 / sinh(r);
+}
+
+double sech(double r) {
+ return 1 / cosh(r);
+}
+
+double coth(double r) {
+ return cosh(r) / sinh(r);
+}
+
diff --git a/libk/src/stdlib.c b/libk/src/stdlib.c
new file mode 100644
index 0000000..fb832ce
--- /dev/null
+++ b/libk/src/stdlib.c
@@ -0,0 +1,164 @@
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#define ATOX(name, type) \
+ type name(const char* s) { \
+ for(; isspace(*s); s++); \
+ int neg = 0; \
+ switch (*s) { \
+ case '-': \
+ neg = 1; \
+ /* FALLTHRU */ \
+ case '+': \
+ s++; \
+ break; \
+ } \
+ type num = 0; \
+ for (; *s == '0'; s++); \
+ for (; isdigit(*s); s++) { \
+ num *= 10; \
+ num += *s - '0'; \
+ } \
+ return num * (neg ? -1 : 1); \
+ }
+
+ATOX(atoi, int)
+ATOX(atol, long int)
+ATOX(atoll, long long int)
+
+char itoc(int i) {
+ if(i < 10) {
+ return '0' + i;
+ } else {
+ return 'a' + (i - 10);
+ }
+}
+
+int ctoi(char c) {
+ if(c < 'A') {
+ return c - '0';
+ } else if(c < 'a') {
+ return c - 'A' + 10;
+ } else {
+ return c - 'a' + 10;
+ }
+}
+
+#define UXTOA(type, name) \
+ char *name(unsigned type n, char *buffer, int radix) { \
+ if (n == 0) { \
+ buffer[0] = '0'; \
+ buffer[1] = '\0'; \
+ return buffer; \
+ } \
+ char *start = buffer; \
+ for (; n; n /= radix) { \
+ *buffer++ = itoc(n % radix); \
+ } \
+ *buffer-- = '\0'; \
+ while(buffer > start) { \
+ char tmp = *start; \
+ *start++ = *buffer; \
+ *buffer-- = tmp; \
+ } \
+ return buffer; \
+ }
+
+UXTOA(int, utoa)
+UXTOA(long int, ultoa)
+
+#define XTOA(type, name) \
+ char *name(type n, char* buffer, int radix) { \
+ if (n == 0) { \
+ buffer[0] = '0'; \
+ buffer[1] = '\0'; \
+ return buffer; \
+ } \
+ if (n < 0) { \
+ *buffer++ = '-'; \
+ n = -n; \
+ } \
+ char *start = buffer; \
+ for (; n; n /= radix) { \
+ *buffer++ = itoc(n % radix); \
+ } \
+ *buffer-- = '\0'; \
+ while(buffer > start) { \
+ char tmp = *start; \
+ *start++ = *buffer; \
+ *buffer-- = tmp; \
+ } \
+ return buffer; \
+ }
+
+XTOA(int, itoa)
+XTOA(long int, ltoa)
+
+char *ftoa(float f, char *buffer) {
+ char *b = buffer;
+ if (f < 0 || f == -0)
+ *buffer++ = '-';
+ int n, i=0, k=0;
+ n = (int) f;
+ while (n > 0) {
+ f /= 10;
+ n = (int)f;
+ i++;
+ }
+ *(buffer+i) = '.';
+ f *= 10;
+ n = (int) f;
+ f -= n;
+ while ((n > 0.1) || (i > k)) {
+ if (k == i)
+ k++;
+ *(buffer+k) = '0' + n;
+ f *= 10;
+ n = (int) f;
+ f -= n;
+ k++;
+ }
+ *(buffer+k) = '\0';
+ return b;
+}
+
+#define STRTOX(name, type) \
+ type name(const char *s, char **endptr, int radix) { \
+ *endptr = NULL; \
+ for(; isspace(*s); s++); \
+ int neg = 0; \
+ switch (*s) { \
+ case '-': \
+ neg = 1; \
+ /* FALLTHRU */ \
+ case '+': \
+ s++; \
+ break; \
+ } \
+ if (!radix) { \
+ if (*s == '0') { \
+ s++; \
+ if (*s == 'x' || *s == 'X') { \
+ s++; \
+ radix = 16; \
+ } else { \
+ radix = 8; \
+ } \
+ } else { \
+ radix = 10; \
+ } \
+ } \
+ for (; *s == '0'; s++, *endptr = (void*) s); \
+ type num = 0; \
+ for (; isdigit(*s); s++, *endptr = (void*) s) { \
+ num *= radix; \
+ num += *s - '0'; \
+ } \
+ return num * (neg ? -1 : 1); \
+ }
+
+STRTOX(strtoi, int)
+STRTOX(strtol, long int)
+STRTOX(strtoll, long long int)
diff --git a/libk/src/string.c b/libk/src/string.c
new file mode 100644
index 0000000..6dfa683
--- /dev/null
+++ b/libk/src/string.c
@@ -0,0 +1,61 @@
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+int memcmp(const void *vl, const void *vr, size_t n) {
+ const unsigned char *l = vl, *r = vr;
+ for (; n && *l == *r; n--, l++, r++);
+ return n ? *l-*r : 0;
+}
+
+void *memcpy(void *restrict dest, const void *restrict src, size_t n) {
+ char *d = dest;
+ const char *s = src;
+ for (; n; n--) *d++ = *s++;
+ return dest;
+}
+
+void *memmove(void *dest, const void *src, size_t n) {
+ char *d = dest;
+ const char *s = src;
+
+ if (d==s) return d;
+
+ if (d<s) {
+ for (; n; n--) *d++ = *s++;
+ } else {
+ while (n) n--, d[n] = s[n];
+ }
+
+ return dest;
+}
+
+void *memset(void *dest, int c, size_t n) {
+ unsigned char *d = dest;
+ for (; n; n--) *d++ = c;
+ return dest;
+}
+
+char *strcpy(char *restrict dest, const char *restrict src) {
+ for(; (*dest = *src); dest++, src++);
+ return dest;
+}
+
+char *strncpy(char *restrict dest, const char *restrict src, size_t n) {
+ for(; (*dest = *src) && n; dest++, src++, n--);
+ memset(dest, 0, n);
+ return dest;
+}
+
+size_t strlen(const char *s) {
+ size_t len = 0;
+ for(; *s; s++, len++);
+ return len;
+}
+
+int strncmp(const char* lhs, const char* rhs, size_t n) {
+ const unsigned char *l=(void *)lhs, *r=(void *)rhs;
+ if (!n--) return 0;
+ for (; *l && *r && n && *l == *r ; l++, r++, n--);
+ return *l - *r;
+}