This commit is contained in:
Tyler Murphy 2023-07-16 02:54:32 -04:00
commit fbf131b5c0
66 changed files with 3685 additions and 0 deletions

9
.env Normal file
View file

@ -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

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
/boot
/os.iso
/kernel/bin
/libk/bin

29
Makefile Normal file
View file

@ -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

8
grub.cfg Normal file
View file

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

28
kernel/Makefile Normal file
View file

@ -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

12
kernel/compile_flags.txt Normal file
View file

@ -0,0 +1,12 @@
-c
-std=gnu17
-Wall
-Wextra
-pedantic
-O2
-ffreestanding
-I../libk/include
-Iinclude
-Isrc
-nostdlib
-DKERNEL_LOG

127
kernel/include/keycodes.h Normal file
View file

@ -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

6
kernel/include/panic.h Normal file
View file

@ -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, ...);

23
kernel/include/print.h Normal file
View file

@ -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, ...);

31
kernel/linker.ld Normal file
View file

@ -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 = .;
}

141
kernel/src/acpi/acpi.c Normal file
View file

@ -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");
}
}

106
kernel/src/acpi/acpi.h Normal file
View file

@ -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);

91
kernel/src/boot/tag.c Normal file
View file

@ -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;
}

38
kernel/src/boot/tag.h Normal file
View file

@ -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);

20
kernel/src/cpu/cpu.c Normal file
View file

@ -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");
}
}

3
kernel/src/cpu/cpu.h Normal file
View file

@ -0,0 +1,3 @@
#pragma once
void init_registers (void);

19
kernel/src/cpu/fpu.asm Normal file
View file

@ -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

22
kernel/src/cpu/sse.asm Normal file
View file

@ -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

View file

@ -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;
}

View file

@ -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);

130
kernel/src/drivers/ps2kb.c Normal file
View file

@ -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;
}

View file

@ -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);

View file

@ -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;
}

View file

@ -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);

View file

@ -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));

108
kernel/src/interrupt/idt.c Normal file
View file

@ -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");
}

View file

@ -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);

View file

@ -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

View file

@ -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);
}

View file

@ -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);

68
kernel/src/main.c Normal file
View file

@ -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);
}
}
}

View file

@ -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;
}

202
kernel/src/memory/memory.c Normal file
View file

@ -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;
}

View file

@ -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);

27
kernel/src/print/panic.c Normal file
View file

@ -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();
}
}

128
kernel/src/print/print.c Normal file
View file

@ -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);
}

75
kernel/src/start.asm Normal file
View file

@ -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

67
kernel/src/tty/color.c Normal file
View file

@ -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)");
}

62
kernel/src/tty/color.h Normal file
View file

@ -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);

30
kernel/src/tty/cursor.c Normal file
View file

@ -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));
}

9
kernel/src/tty/cursor.h Normal file
View file

@ -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);

131
kernel/src/tty/term.c Normal file
View file

@ -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;
}

27
kernel/src/tty/term.h Normal file
View file

@ -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);

20
libk/Makefile Normal file
View file

@ -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

10
libk/compile_flags.txt Normal file
View file

@ -0,0 +1,10 @@
-c
-std=c99
-Wall
-Wextra
-pedantic
-O2
-ffreestanding
-Isrc
-Iinclude
-nostdlib

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

@ -0,0 +1,4 @@
#pragma once
int isspace(int c);
int isdigit(int c);

62
libk/include/math.h Normal file
View file

@ -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);

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

@ -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);

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

@ -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 );

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

@ -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");
}

19
libk/src/ctype.c Normal file
View file

@ -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;
}

32
libk/src/internal/libm.h Normal file
View file

@ -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)

14
libk/src/math/abs.c Normal file
View file

@ -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;
}

59
libk/src/math/ceil.c Normal file
View file

@ -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;
}

20
libk/src/math/copysign.c Normal file
View file

@ -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;
}

29
libk/src/math/fact.c Normal file
View file

@ -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;
}

13
libk/src/math/fclamp.c Normal file
View file

@ -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;
}

55
libk/src/math/floor.c Normal file
View file

@ -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;
}

38
libk/src/math/fma.c Normal file
View file

@ -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);
}

129
libk/src/math/fmod.c Normal file
View file

@ -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;
}

19
libk/src/math/frexp.c Normal file
View file

@ -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;
}

152
libk/src/math/pow.c Normal file
View file

@ -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
}

36
libk/src/math/sqrt.c Normal file
View file

@ -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;
}

62
libk/src/math/trig.c Normal file
View file

@ -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);
}

164
libk/src/stdlib.c Normal file
View file

@ -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)

61
libk/src/string.c Normal file
View file

@ -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;
}