initial
This commit is contained in:
commit
fbf131b5c0
66 changed files with 3685 additions and 0 deletions
9
.env
Normal file
9
.env
Normal 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
4
.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
/boot
|
||||
/os.iso
|
||||
/kernel/bin
|
||||
/libk/bin
|
29
Makefile
Normal file
29
Makefile
Normal 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
8
grub.cfg
Normal file
|
@ -0,0 +1,8 @@
|
|||
set timeout=1
|
||||
set default=0
|
||||
|
||||
menuentry "finix" {
|
||||
multiboot2 /boot/kernel.bin
|
||||
boot
|
||||
}
|
||||
|
28
kernel/Makefile
Normal file
28
kernel/Makefile
Normal 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
12
kernel/compile_flags.txt
Normal 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
127
kernel/include/keycodes.h
Normal 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
6
kernel/include/panic.h
Normal 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
23
kernel/include/print.h
Normal 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
31
kernel/linker.ld
Normal 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
141
kernel/src/acpi/acpi.c
Normal 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
106
kernel/src/acpi/acpi.h
Normal 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
91
kernel/src/boot/tag.c
Normal 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
38
kernel/src/boot/tag.h
Normal 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
20
kernel/src/cpu/cpu.c
Normal 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
3
kernel/src/cpu/cpu.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
void init_registers (void);
|
19
kernel/src/cpu/fpu.asm
Normal file
19
kernel/src/cpu/fpu.asm
Normal 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
22
kernel/src/cpu/sse.asm
Normal 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
|
99
kernel/src/drivers/ps2ctrl.c
Normal file
99
kernel/src/drivers/ps2ctrl.c
Normal 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;
|
||||
}
|
14
kernel/src/drivers/ps2ctrl.h
Normal file
14
kernel/src/drivers/ps2ctrl.h
Normal 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
130
kernel/src/drivers/ps2kb.c
Normal 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;
|
||||
}
|
15
kernel/src/drivers/ps2kb.h
Normal file
15
kernel/src/drivers/ps2kb.h
Normal 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);
|
89
kernel/src/drivers/ps2mouse.c
Normal file
89
kernel/src/drivers/ps2mouse.c
Normal 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;
|
||||
}
|
18
kernel/src/drivers/ps2mouse.h
Normal file
18
kernel/src/drivers/ps2mouse.h
Normal 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);
|
15
kernel/src/graphics/framebuffer.h
Normal file
15
kernel/src/graphics/framebuffer.h
Normal 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
108
kernel/src/interrupt/idt.c
Normal 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");
|
||||
}
|
||||
|
36
kernel/src/interrupt/idt.h
Normal file
36
kernel/src/interrupt/idt.h
Normal 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);
|
99
kernel/src/interrupt/isr.asm
Normal file
99
kernel/src/interrupt/isr.asm
Normal 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
|
85
kernel/src/interrupt/pic.c
Normal file
85
kernel/src/interrupt/pic.c
Normal 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);
|
||||
}
|
11
kernel/src/interrupt/pic.h
Normal file
11
kernel/src/interrupt/pic.h
Normal 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
68
kernel/src/main.c
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
314
kernel/src/memory/allocator.c
Normal file
314
kernel/src/memory/allocator.c
Normal 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
202
kernel/src/memory/memory.c
Normal 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;
|
||||
}
|
22
kernel/src/memory/memory.h
Normal file
22
kernel/src/memory/memory.h
Normal 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
27
kernel/src/print/panic.c
Normal 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
128
kernel/src/print/print.c
Normal 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
75
kernel/src/start.asm
Normal 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
67
kernel/src/tty/color.c
Normal 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
62
kernel/src/tty/color.h
Normal 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
30
kernel/src/tty/cursor.c
Normal 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
9
kernel/src/tty/cursor.h
Normal 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
131
kernel/src/tty/term.c
Normal 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
27
kernel/src/tty/term.h
Normal 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
20
libk/Makefile
Normal 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
10
libk/compile_flags.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
-c
|
||||
-std=c99
|
||||
-Wall
|
||||
-Wextra
|
||||
-pedantic
|
||||
-O2
|
||||
-ffreestanding
|
||||
-Isrc
|
||||
-Iinclude
|
||||
-nostdlib
|
4
libk/include/ctype.h
Normal file
4
libk/include/ctype.h
Normal file
|
@ -0,0 +1,4 @@
|
|||
#pragma once
|
||||
|
||||
int isspace(int c);
|
||||
int isdigit(int c);
|
62
libk/include/math.h
Normal file
62
libk/include/math.h
Normal 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
25
libk/include/stdlib.h
Normal 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
13
libk/include/string.h
Normal 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
51
libk/include/sys.h
Normal 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
19
libk/src/ctype.c
Normal 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
32
libk/src/internal/libm.h
Normal 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
14
libk/src/math/abs.c
Normal 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
59
libk/src/math/ceil.c
Normal 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
20
libk/src/math/copysign.c
Normal 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
29
libk/src/math/fact.c
Normal 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
13
libk/src/math/fclamp.c
Normal 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
55
libk/src/math/floor.c
Normal 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
38
libk/src/math/fma.c
Normal 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
129
libk/src/math/fmod.c
Normal 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
19
libk/src/math/frexp.c
Normal 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
152
libk/src/math/pow.c
Normal 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
36
libk/src/math/sqrt.c
Normal 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
62
libk/src/math/trig.c
Normal 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
164
libk/src/stdlib.c
Normal 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
61
libk/src/string.c
Normal 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;
|
||||
}
|
Loading…
Reference in a new issue