commit fbf131b5c043b27e0b1543374bb144e3e426f723 Author: Tyler Murphy <=> Date: Sun Jul 16 02:54:32 2023 -0400 initial 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 +#include + +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 +#include +#include +#include +#include +#include + +#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 + +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 +#include + +#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 +#include + +#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 +#include + +#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 +#include + +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 +#include + +#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 +#include +#include + +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 +#include +#include +#include + +#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 +#include + +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 + +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 +#include +#include +#include +#include +#include +#include + +#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 + +#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 +#include + +#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 + +#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 +#include +#include +#include + +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 +#include +#include + +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< 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 +#include +#include +#include + +#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 + +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 +#include +#include +#include +#include + +#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 +#include +#include +#include +#include + +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 +#include + +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 + +#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 + +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 +#include +#include +#include +#include + +#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 +#include + +#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 + +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 + +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 + +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 + +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 +#include + +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 +#include +#include + +#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 +#include + +#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 + +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 + +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 +#include +#include + +#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 +#include + +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 +#include + +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 + +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 +#include +#include + +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 + +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 + +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 +#include +#include +#include + +#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 +#include +#include + +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