summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/cpu/idt.c90
-rw-r--r--kernel/drivers/clock.c150
-rw-r--r--kernel/drivers/drivers.c3
-rw-r--r--kernel/drivers/pci.c6
-rw-r--r--kernel/drivers/tty.c8
-rw-r--r--kernel/include/comus/drivers/tty.h2
l---------kernel/include/comus/error.h1
-rw-r--r--kernel/include/comus/fs.h5
-rw-r--r--kernel/include/comus/memory.h54
-rw-r--r--kernel/include/comus/time.h39
-rw-r--r--kernel/include/lib.h20
-rw-r--r--kernel/include/lib/kctype.h22
-rw-r--r--kernel/include/lib/kio.h91
-rw-r--r--kernel/include/lib/klib.h196
-rw-r--r--kernel/include/lib/kstring.h154
-rw-r--r--kernel/kernel.ld36
-rw-r--r--kernel/lib/atox.c29
-rw-r--r--kernel/lib/bound.c12
-rw-r--r--kernel/lib/btoa.c43
-rw-r--r--kernel/lib/ctoi.c14
-rw-r--r--kernel/lib/fputc.c10
-rw-r--r--kernel/lib/isdigit.c6
-rw-r--r--kernel/lib/isspace.c16
-rw-r--r--kernel/lib/itoc.c10
-rw-r--r--kernel/lib/kalloc.c210
-rw-r--r--kernel/lib/kprintf.c576
-rw-r--r--kernel/lib/memcmp.c9
-rw-r--r--kernel/lib/memcpy.c10
-rw-r--r--kernel/lib/memcpyv.c11
-rw-r--r--kernel/lib/memmove.c20
-rw-r--r--kernel/lib/memmovev.c20
-rw-r--r--kernel/lib/memset.c10
-rw-r--r--kernel/lib/memsetv.c10
-rw-r--r--kernel/lib/panic.c6
-rw-r--r--kernel/lib/stpcpy.c9
-rw-r--r--kernel/lib/stpncpy.c10
-rw-r--r--kernel/lib/strcat.c7
-rw-r--r--kernel/lib/strcpy.c9
-rw-r--r--kernel/lib/strlen.c9
-rw-r--r--kernel/lib/strncmp.c11
-rw-r--r--kernel/lib/strncpy.c10
-rw-r--r--kernel/lib/strtoux.c43
-rw-r--r--kernel/lib/strtox.c52
-rw-r--r--kernel/lib/uxtoa.c27
-rw-r--r--kernel/lib/xtoa.c31
-rw-r--r--kernel/main.c (renamed from kernel/kernel.c)11
-rw-r--r--kernel/mboot/mmap.c6
-rw-r--r--kernel/memory/paging.c15
-rw-r--r--kernel/memory/physalloc.c17
-rw-r--r--kernel/memory/virtalloc.c4
50 files changed, 1905 insertions, 265 deletions
diff --git a/kernel/cpu/idt.c b/kernel/cpu/idt.c
index 748826c..51fb125 100644
--- a/kernel/cpu/idt.c
+++ b/kernel/cpu/idt.c
@@ -72,63 +72,63 @@ void idt_init(void)
static void isr_print_regs(regs_t *regs)
{
- printf("rax: %#016lx (%lu)\n", regs->rax, regs->rax);
- printf("rbx: %#016lx (%lu)\n", regs->rbx, regs->rbx);
- printf("rcx: %#016lx (%lu)\n", regs->rcx, regs->rcx);
- printf("rdx: %#016lx (%lu)\n", regs->rdx, regs->rdx);
- printf("rsi: %#016lx (%lu)\n", regs->rsi, regs->rsi);
- printf("rdi: %#016lx (%lu)\n", regs->rdi, regs->rdi);
- printf("rsp: %#016lx (%lu)\n", regs->rsp, regs->rsp);
- printf("rbp: %#016lx (%lu)\n", regs->rbp, regs->rbp);
- printf("r8 : %#016lx (%lu)\n", regs->r8, regs->r8);
- printf("r9 : %#016lx (%lu)\n", regs->r9, regs->r9);
- printf("r10: %#016lx (%lu)\n", regs->r10, regs->r10);
- printf("r11: %#016lx (%lu)\n", regs->r11, regs->r11);
- printf("r12: %#016lx (%lu)\n", regs->r12, regs->r12);
- printf("r13: %#016lx (%lu)\n", regs->r13, regs->r13);
- printf("r14: %#016lx (%lu)\n", regs->r14, regs->r14);
- printf("r15: %#016lx (%lu)\n", regs->r15, regs->r15);
- printf("rip: %#016lx (%lu)\n", regs->rip, regs->rip);
- printf("rflags: %#016lx (%lu)\n", (uint64_t)regs->rflags.raw,
+ kprintf("rax: %#016lx (%lu)\n", regs->rax, regs->rax);
+ kprintf("rbx: %#016lx (%lu)\n", regs->rbx, regs->rbx);
+ kprintf("rcx: %#016lx (%lu)\n", regs->rcx, regs->rcx);
+ kprintf("rdx: %#016lx (%lu)\n", regs->rdx, regs->rdx);
+ kprintf("rsi: %#016lx (%lu)\n", regs->rsi, regs->rsi);
+ kprintf("rdi: %#016lx (%lu)\n", regs->rdi, regs->rdi);
+ kprintf("rsp: %#016lx (%lu)\n", regs->rsp, regs->rsp);
+ kprintf("rbp: %#016lx (%lu)\n", regs->rbp, regs->rbp);
+ kprintf("r8 : %#016lx (%lu)\n", regs->r8, regs->r8);
+ kprintf("r9 : %#016lx (%lu)\n", regs->r9, regs->r9);
+ kprintf("r10: %#016lx (%lu)\n", regs->r10, regs->r10);
+ kprintf("r11: %#016lx (%lu)\n", regs->r11, regs->r11);
+ kprintf("r12: %#016lx (%lu)\n", regs->r12, regs->r12);
+ kprintf("r13: %#016lx (%lu)\n", regs->r13, regs->r13);
+ kprintf("r14: %#016lx (%lu)\n", regs->r14, regs->r14);
+ kprintf("r15: %#016lx (%lu)\n", regs->r15, regs->r15);
+ kprintf("rip: %#016lx (%lu)\n", regs->rip, regs->rip);
+ kprintf("rflags: %#016lx (%lu)\n", (uint64_t)regs->rflags.raw,
(uint64_t)regs->rflags.raw);
- puts("rflags: ");
+ kputs("rflags: ");
if (regs->rflags.cf)
- puts("CF ");
+ kputs("CF ");
if (regs->rflags.pf)
- puts("PF ");
+ kputs("PF ");
if (regs->rflags.af)
- puts("AF ");
+ kputs("AF ");
if (regs->rflags.zf)
- puts("ZF ");
+ kputs("ZF ");
if (regs->rflags.sf)
- puts("SF ");
+ kputs("SF ");
if (regs->rflags.tf)
- puts("TF ");
+ kputs("TF ");
if (regs->rflags.if_)
- puts("IF ");
+ kputs("IF ");
if (regs->rflags.df)
- puts("DF ");
+ kputs("DF ");
if (regs->rflags.of)
- puts("OF ");
+ kputs("OF ");
if (regs->rflags.iopl)
- puts("IOPL ");
+ kputs("IOPL ");
if (regs->rflags.nt)
- puts("NT ");
+ kputs("NT ");
if (regs->rflags.md)
- puts("MD ");
+ kputs("MD ");
if (regs->rflags.rf)
- puts("RF ");
+ kputs("RF ");
if (regs->rflags.vm)
- puts("VM ");
+ kputs("VM ");
if (regs->rflags.ac)
- puts("AC ");
+ kputs("AC ");
if (regs->rflags.vif)
- puts("VIF ");
+ kputs("VIF ");
if (regs->rflags.vip)
- puts("VIP ");
+ kputs("VIP ");
if (regs->rflags.id)
- puts("ID ");
- puts("\n");
+ kputs("ID ");
+ kputs("\n");
}
#define EX_DEBUG 0x01
@@ -179,23 +179,23 @@ void idt_exception_handler(uint64_t exception, uint64_t code, regs_t *state)
case EX_PAGE_FAULT:
// page faults store the offending address in cr2
__asm__ volatile("mov %%cr2, %0" : "=r"(cr2));
- if (!load_page((void *)cr2))
+ if (!kload_page((void *)cr2))
return;
}
- puts("\n\n!!! EXCEPTION !!!\n");
- printf("%#02lX %s\n", exception, EXCEPTIONS[exception]);
- printf("Error code %#lX\n", code);
+ kputs("\n\n!!! EXCEPTION !!!\n");
+ kprintf("%#02lX %s\n", exception, EXCEPTIONS[exception]);
+ kprintf("Error code %#lX\n", code);
if (exception == EX_PAGE_FAULT) {
- printf("Page fault address: %#016lx\n", cr2);
+ kprintf("Page fault address: %#016lx\n", cr2);
}
- puts("\n");
+ kputs("\n");
isr_print_regs(state);
- puts("\n");
+ kputs("\n");
while (1) {
halt();
diff --git a/kernel/drivers/clock.c b/kernel/drivers/clock.c
index dd229dc..fadd938 100644
--- a/kernel/drivers/clock.c
+++ b/kernel/drivers/clock.c
@@ -1,6 +1,6 @@
#include <lib.h>
-#include <time.h>
#include <comus/asm.h>
+#include <comus/time.h>
#include <comus/drivers/clock.h>
#define CMOS_WRITE_PORT 0x70
@@ -15,18 +15,6 @@
#define CMOS_REG_YEAR 0x09
#define CMOS_REG_CEN 0x32
-// Live buffers to work on data
-static time_t time;
-static time_t localtime;
-
-// Front buffers so interupts dont request data that is half done
-static time_t curr_time;
-static time_t curr_localtime;
-
-// Current set time Zone
-static timezone_t curr_timezone = TZ_UTC;
-static timezone_t last_timezone = TZ_UTC;
-
static uint8_t cmos_read(uint8_t reg)
{
uint8_t hex, ret;
@@ -43,124 +31,40 @@ static uint8_t cmos_read(uint8_t reg)
static int mday_offset[12] = { 0, 31, 59, 90, 120, 151,
181, 212, 243, 273, 304, 334 };
-static int month_days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
-
-static void update_localtime(void)
-{
- int change, max;
-
- // set localtime
- localtime = time;
-
- // if tz is UTC, we dont need to do anythin
- if (last_timezone == TZ_UTC)
- return;
-
- localtime.hour += last_timezone;
-
- // check if day rolled over
- change = localtime.hour < 0 ? -1 : localtime.hour >= 24 ? 1 : 0;
- if (!change)
- return;
-
- // roll over day
- localtime.hour = (localtime.hour + 24) % 24;
- localtime.wday = (localtime.wday + change + 7) % 7;
- localtime.mday += change;
- localtime.yday += change;
-
- // check if month rolled over
- max = month_days[localtime.mon];
- if (localtime.leap && localtime.mon == 1)
- max++;
- change = localtime.mday < 0 ? -1 : localtime.mday >= max ? 1 : 0;
- if (!change)
- return;
-
- // roll over month
- localtime.mon = (localtime.mon + change + 12) % 12;
-
- // check if year rolled over
- max = localtime.leap ? 366 : 365;
- change = localtime.yday < 0 ? -1 : localtime.yday >= max ? 1 : 0;
- if (!change)
- return;
-
- // roll over year
- localtime.yn += change;
-
- // check if cen rolled over
- change = localtime.yn < 0 ? -1 : localtime.yn >= 100 ? 1 : 0;
- if (!change)
- goto year;
-
- // roll over cen
- localtime.cen += change;
-
-year:
-
- localtime.year = localtime.yn + localtime.cen * 100;
- localtime.leap = localtime.year % 4 == 0 && localtime.year % 100 != 0;
-
- if (localtime.leap && localtime.yday == -1)
- localtime.yday = 365;
- else if (localtime.yday == -1)
- localtime.yday = 364;
- else
- localtime.yday = 0;
-
- localtime.year -= 1900;
-}
-
-void clock_update(void)
+void gettime(struct time *time)
{
- time.sec = cmos_read(CMOS_REG_SEC);
- time.min = cmos_read(CMOS_REG_MIN);
- time.hour = cmos_read(CMOS_REG_HOUR);
- time.wday = cmos_read(CMOS_REG_WDAY) - 1;
- time.mday = cmos_read(CMOS_REG_MDAY);
- time.mon = cmos_read(CMOS_REG_MON) - 1;
- time.yn = cmos_read(CMOS_REG_YEAR);
- time.cen = 20;
-
- time.year = time.yn + time.cen * 100;
-
- time.leap = time.year % 4 == 0 && time.year % 100 != 0;
+ time->sec = cmos_read(CMOS_REG_SEC);
+ time->min = cmos_read(CMOS_REG_MIN);
+ time->hour = cmos_read(CMOS_REG_HOUR);
+ time->wday = cmos_read(CMOS_REG_WDAY) - 1;
+ time->mday = cmos_read(CMOS_REG_MDAY);
+ time->mon = cmos_read(CMOS_REG_MON) - 1;
+ time->yn = cmos_read(CMOS_REG_YEAR);
+ time->cen = 20;
- time.yday = mday_offset[time.mon] + time.mday;
+ time->year = time->yn + time->cen * 100;
- if (time.leap && time.mon > 2)
- time.yday++;
+ time->leap = time->year % 4 == 0 && time->year % 100 != 0;
- time.year -= 1900;
+ time->yday = mday_offset[time->mon] + time->mday;
- update_localtime();
+ if (time->leap && time->mon > 2)
+ time->yday++;
- curr_time = time;
- curr_localtime = localtime;
+ time->year -= 1900;
}
-void set_timezone(timezone_t tz)
+uint64_t unixtime(void)
{
- curr_timezone = tz;
-}
-
-time_t get_utctime(void)
-{
- return curr_time;
-}
+ struct time time;
+ gettime(&time);
-time_t get_localtime(void)
-{
- if (curr_timezone != last_timezone) {
- last_timezone = curr_timezone;
- update_localtime();
- curr_localtime = localtime;
- }
- return curr_localtime;
-}
-
-size_t get_systemtime(void)
-{
- return 0;
+ // FIXME: probably wrong
+ uint64_t unix = 0;
+ unix += time.sec;
+ unix += time.min * 60;
+ unix += time.hour * 60 * 60;
+ unix += time.yday * 60 * 60 * 24;
+ unix += time.year * 60 * 60 * 24 * 365;
+ return unix;
}
diff --git a/kernel/drivers/drivers.c b/kernel/drivers/drivers.c
index 00ee247..9b90eb8 100644
--- a/kernel/drivers/drivers.c
+++ b/kernel/drivers/drivers.c
@@ -1,12 +1,9 @@
#include <comus/drivers.h>
#include <comus/drivers/uart.h>
-#include <comus/drivers/tty.h>
#include <comus/drivers/pci.h>
-#include <comus/drivers/clock.h>
void drivers_init(void)
{
uart_init();
pci_init();
- clock_update();
}
diff --git a/kernel/drivers/pci.c b/kernel/drivers/pci.c
index 83c47f1..e84ca11 100644
--- a/kernel/drivers/pci.c
+++ b/kernel/drivers/pci.c
@@ -34,7 +34,7 @@ uint32_t pci_rcfg_d(struct pci_device dev, uint8_t offset)
static void print_device(struct pci_table_entry *entry)
{
- printf(
+ kprintf(
"BUS: %#-4x DEV: %#-4x FUNC: %#-4x ID: %04x:%04x CLASS: %02x:%02x:%02x REV: %#02x\n",
entry->device.bus, entry->device.device, entry->device.function,
entry->vendor_id, entry->device_id, entry->class, entry->subclass,
@@ -134,11 +134,11 @@ void pci_init(void)
}
}
}
- printf("PCI DEVICES\n");
+ kprintf("PCI DEVICES\n");
for (size_t i = 0; i < pci_table_next; i++) {
print_device(&pci_table[i]);
}
- printf("\n");
+ kprintf("\n");
}
bool pci_findby_class(struct pci_device *dest, uint8_t class, uint8_t subclass,
diff --git a/kernel/drivers/tty.c b/kernel/drivers/tty.c
index 5a231cd..e9d3e50 100644
--- a/kernel/drivers/tty.c
+++ b/kernel/drivers/tty.c
@@ -2,8 +2,6 @@
#include <comus/drivers/tty.h>
#include <comus/asm.h>
#include <comus/memory.h>
-#include <stdint.h>
-#include <stdio.h>
#define VGA_ADDR 0xB8000
@@ -99,3 +97,9 @@ void tty_out(char c)
outb(0x3D4, 0x0E);
outb(0x3D5, (uint8_t)((pos >> 8) & 0xFF));
}
+
+void tty_out_str(const char *str)
+{
+ while (*str)
+ tty_out(*str++);
+}
diff --git a/kernel/include/comus/drivers/tty.h b/kernel/include/comus/drivers/tty.h
index 4f8a5f1..55aec64 100644
--- a/kernel/include/comus/drivers/tty.h
+++ b/kernel/include/comus/drivers/tty.h
@@ -17,6 +17,6 @@ void tty_out(char c);
/**
* Output a string to the terminal
*/
-void tty_out_str(char *str);
+void tty_out_str(const char *str);
#endif /* tty.h */
diff --git a/kernel/include/comus/error.h b/kernel/include/comus/error.h
new file mode 120000
index 0000000..9367cab
--- /dev/null
+++ b/kernel/include/comus/error.h
@@ -0,0 +1 @@
+../../../user/include/error.h \ No newline at end of file
diff --git a/kernel/include/comus/fs.h b/kernel/include/comus/fs.h
index 67c74e3..fe335ca 100644
--- a/kernel/include/comus/fs.h
+++ b/kernel/include/comus/fs.h
@@ -11,7 +11,10 @@
#include <stdint.h>
#include <stddef.h>
-#include <limits.h>
+
+// FIXME: aaaa
+#define MAX_DISKS 8
+#define MAX_FILE_NAME_LEN 256
struct disk {
/// set to 1 in array to state that fs is defined
diff --git a/kernel/include/comus/memory.h b/kernel/include/comus/memory.h
index 411c039..294c795 100644
--- a/kernel/include/comus/memory.h
+++ b/kernel/include/comus/memory.h
@@ -13,6 +13,7 @@
#include <stddef.h>
#define MMAP_MAX_ENTRY 64
+#define PAGE_SIZE 4096
struct memory_segment {
uint64_t addr;
@@ -54,14 +55,39 @@ uint64_t memory_used(void);
* @param writable - if this memory should be writable
* @param user - if this memory should be user writable
*/
-void *mapaddr(void *addr, size_t len);
+void *kmapaddr(void *addr, size_t len);
/**
* Unmaps mapped address from the mmap function
* @param addr - the address returned from mmap
* @param len - the length allocated
*/
-void unmapaddr(void *addr);
+void kunmapaddr(void *addr);
+
+/**
+ * Allocates size_t bytes in memory
+ *
+ * @param size - the amount of bytes to allocate
+ * @returns the address allocated or NULL on failure
+ */
+void *kalloc(size_t size);
+
+/**
+ * Rellocates a given allocated ptr to a new size of bytes in memory.
+ * If ptr is NULL it will allocate new memory.
+ *
+ * @param ptr - the pointer to reallocate
+ * @param size - the amount of bytes to reallocate to
+ * @returns the address allocated or NULL on failure
+ */
+void *krealloc(void *ptr, size_t size);
+
+/**
+ * Frees an allocated pointer in memory
+ *
+ * @param ptr - the pointer to free
+ */
+void kfree(void *ptr);
/**
* Attemps to load a mapped but not yet allocated page.
@@ -70,6 +96,28 @@ void unmapaddr(void *addr);
*
* @returns 0 on success and a negative error code on failure.
*/
-int load_page(void *virt_addr);
+int kload_page(void *virt_addr);
+
+/**
+ * Allocate a single page of memory
+ *
+ * @returns the address allocated or NULL on failure
+ */
+void *kalloc_page(void);
+
+/**
+ * Allocate size_t amount of contiguous virtual pages
+ *
+ * @param count - the number of pages to allocate
+ * @returns the address allocated or NULL on failure
+ */
+void *kalloc_pages(size_t count);
+
+/**
+ * Free allocated pages.
+ *
+ * @param ptr - the pointer provided by alloc_page or alloc_pages
+ */
+void kfree_pages(void *ptr);
#endif /* memory.h */
diff --git a/kernel/include/comus/time.h b/kernel/include/comus/time.h
new file mode 100644
index 0000000..6ecb2b7
--- /dev/null
+++ b/kernel/include/comus/time.h
@@ -0,0 +1,39 @@
+/**
+ * @file time.h
+ *
+ * @author Freya Murphy <freya@freyacat.org>
+ *
+ * System time structure
+ */
+
+#ifndef _TIME_H
+#define _TIME_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+struct time {
+ int sec; /// Seconds [0,59]
+ int min; /// Minutes [0,59]
+ int hour; /// Hour [0,23]
+ int mday; /// Day of month [1,31]
+ int mon; /// Month of year [0,11]
+ int year; /// Years since 1900
+ int wday; /// Day of week [0,6] (Sunday = 0)
+ int yday; /// Day of year [0,365]
+ int yn; /// Year number [0,99]
+ int cen; /// Century [19,20]
+ int leap; /// If year is a leap year (True == 1)
+};
+
+/**
+ * Return the current time in the system
+ */
+void gettime(struct time *time);
+
+/**
+ * Return current UTC time
+ */
+uint64_t unixtime(void);
+
+#endif /* time.h */
diff --git a/kernel/include/lib.h b/kernel/include/lib.h
new file mode 100644
index 0000000..be4e739
--- /dev/null
+++ b/kernel/include/lib.h
@@ -0,0 +1,20 @@
+/**
+ * @file lib.h
+ *
+ * @author Freya Murphy <freya@freyacat.org>
+ *
+ * Kernel C Library
+ */
+
+#ifndef _LIB_H
+#define _LIB_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <lib/kctype.h>
+#include <lib/kio.h>
+#include <lib/klib.h>
+#include <lib/kstring.h>
+
+#endif /* lib.h */
diff --git a/kernel/include/lib/kctype.h b/kernel/include/lib/kctype.h
new file mode 100644
index 0000000..6d090c6
--- /dev/null
+++ b/kernel/include/lib/kctype.h
@@ -0,0 +1,22 @@
+/**
+ * @file kctype.h
+ *
+ * @author Freya Murphy <freya@freyacat.org>
+ *
+ * Kernel C type libaray functions
+ */
+
+#ifndef _KCTYPE_H
+#define _KCTYPE_H
+
+/**
+ * @returns 1 if c is a space
+ */
+int isspace(int c);
+
+/**
+ * @returns 1 if c is a digit (0 - 9)
+ */
+int isdigit(int c);
+
+#endif /* kctype.h */
diff --git a/kernel/include/lib/kio.h b/kernel/include/lib/kio.h
new file mode 100644
index 0000000..652a85b
--- /dev/null
+++ b/kernel/include/lib/kio.h
@@ -0,0 +1,91 @@
+/**
+ * @file kio.h
+ *
+ * @author Freya Murphy <freya@freyacat.org>
+ *
+ * Kernel I/O definitions.
+ */
+
+#ifndef _KIO_H
+#define _KIO_H
+
+#include <stddef.h>
+#include <stdarg.h>
+
+/**
+ * Prints out a char
+ *
+ * @param c - the char
+ */
+void kputc(char c);
+
+/**
+ * Prints out a null terminated string
+ *
+ * @param s - the string
+ */
+void kputs(const char *s);
+
+/**
+ * prints out a formatted string
+ *
+ * @param format - the format string
+ * @param ... - variable args for the format
+ */
+__attribute__((format(printf, 1, 2))) void kprintf(const char *format, ...);
+
+/**
+ * prints out a formatted string to a buffer
+ *
+ * @param s - the string to write to
+ * @param format - the format string
+ * @param ... - variable args for the format
+ * @returns number of bytes written
+ */
+__attribute__((format(printf, 2, 3))) size_t ksprintf(char *restrict s,
+ const char *format, ...);
+
+/**
+ * prints out a formatted string to a buffer with a given max length
+ *
+ * @param s - the string to write to
+ * @param maxlen - the max len of the buffer
+ * @param format - the format string
+ * @param ... - variable args for the format
+ * @returns number of bytes written
+ */
+__attribute__((format(printf, 3, 4))) size_t ksnprintf(char *restrict s,
+ size_t maxlen,
+ const char *format, ...);
+
+/**
+ * prints out a formatted string
+ *
+ * @param format - the format string
+ * @param args - variable arg list for the format
+ */
+void kvprintf(const char *format, va_list args);
+
+/**
+ * prints out a formatted string to a buffer
+ *
+ * @param s - the string to write to
+ * @param format - the format string
+ * @param args - variable arg list for the format
+ * @returns number of bytes written
+ */
+size_t kvsprintf(char *restrict s, const char *format, va_list args);
+
+/**
+ * prints out a formatted string to a buffer with a given max length
+ *
+ * @param s - the string to write to
+ * @param maxlen - the max len of the buffer
+ * @param format - the format string
+ * @param args - variable arg list for the format
+ * @returns number of bytes written
+ */
+size_t kvsnprintf(char *restrict s, size_t maxlen, const char *format,
+ va_list args);
+
+#endif /* kio.h */
diff --git a/kernel/include/lib/klib.h b/kernel/include/lib/klib.h
new file mode 100644
index 0000000..c67e57d
--- /dev/null
+++ b/kernel/include/lib/klib.h
@@ -0,0 +1,196 @@
+/**
+ * @file klib.h
+ *
+ * @author Freya Murphy <freya@freyacat.org>
+ *
+ * Kernel libaray functions
+ */
+
+#ifndef _KLIB_H
+#define _KLIB_H
+
+#include <stddef.h>
+
+/**
+ * converts single digit int to base 36
+ * @param i - int
+ * @returns c - base 36 char
+ */
+char itoc(int i);
+
+/**
+ * converts single base 36 chat into int
+ * @param c - base 36 char
+ * @returns i - int, or -1 if the char was invalid
+ */
+int ctoi(char c);
+
+/**
+ * Converts the initial portiion of the string pointed to by s to int.
+ * @param s - the string to convert
+ * @returns the number inside s or 0 on error
+ */
+int atoi(const char *s);
+
+/**
+ * Converts the initial portiion of the string pointed to by s to long.
+ * @param s - the string to convert
+ * @returns the number inside s or 0 on error
+ */
+long int atol(const char *s);
+
+/**
+ * Converts the initial portiion of the string pointed to by s to long long.
+ * @param s - the string to convert
+ * @returns the number inside s or 0 on error
+ */
+long long int atoll(const char *s);
+
+/**
+ * Converts a integer to asci inside a string with a given radix (base).
+ * @param n - the number to convert
+ * @param buffer - the string buffer
+ * @param radix - the base to convert
+ */
+char *itoa(int n, char *buffer, int radix);
+
+/**
+ * Converts a long to asci inside a string with a given radix (base).
+ * @param n - the number to convert
+ * @param buffer - the string buffer
+ * @param radix - the base to convert
+ */
+char *ltoa(long int n, char *buffer, int radix);
+
+/**
+ * Converts a long long to asci inside a string with a given radix (base).
+ * @param n - the number to conver
+ * @param buffer - the string buffer
+ * @param radix - the base to convert
+ */
+char *lltoa(long long int n, char *buffer, int radix);
+
+/**
+ * Converts a unsigned integer to asci inside a string with a given radix (base).
+ * @param n - the number to convert
+ * @param buffer - the string buffer
+ * @param radix - the base to convert
+ */
+char *utoa(unsigned int n, char *buffer, int radix);
+
+/**
+ * Converts a unsigned long to asci inside a string with a given radix (base).
+ * @param n - the number to convert
+ * @param buffer - the string buffer
+ * @param radix - the base to convert
+ */
+char *ultoa(unsigned long int n, char *buffer, int radix);
+
+/**
+ * Converts a unsigned long long to asci inside a string with a given radix (base).
+ * @param n - the number to conver
+ * @param buffer - the string buffer
+ * @param radix - the base to convert
+ */
+char *ulltoa(unsigned long long int n, char *buffer, int radix);
+
+/**
+ * Converts the string in str to an int value based on the given base.
+ * The endptr is updated to where the string was no longer valid.
+ * @param str - the string buffer
+ * @param endptr - the endptr
+ * @param base - the base to convert to
+ * @returns 0 on error or success, error if endptr is still equal to str
+ */
+int strtoi(const char *str, char **endptr, int base);
+
+/**
+ * Converts the string in str to a long value based on the given base.
+ * The endptr is updated to where the string was no longer valid.
+ * @param str - the string buffer
+ * @param endptr - the endptr
+ * @param base - the base to convert to
+ * @returns 0 on error or success, error if endptr is still equal to str
+ */
+long int strtol(const char *str, char **endptr, int base);
+
+/**
+ * Converts the string in str to a long long value based on the given base.
+ * The endptr is updated to where the string was no longer valid.
+ * @param str - the string buffer
+ * @param endptr - the endptr
+ * @param base - the base to convert to
+ * @returns 0 on error or success, error if endptr is still equal to str
+ */
+long long int strtoll(const char *str, char **endptr, int base);
+
+/**
+ * Converts the string in str to an unsigned int value based on the given base.
+ * The endptr is updated to where the string was no longer valid.
+ * @param str - the string buffer
+ * @param endptr - the endptr
+ * @param base - the base to convert to
+ * @returns 0 on error or success, error if endptr is still equal to str
+ */
+unsigned int strtoui(const char *str, char **endptr, int base);
+
+/**
+ * Converts the string in str to an unsigned long value based on the given base.
+ * The endptr is updated to where the string was no longer valid.
+ * @param str - the string buffer
+ * @param endptr - the endptr
+ * @param base - the base to convert to
+ * @returns 0 on error or success, error if endptr is still equal to str
+ */
+unsigned long int strtoul(const char *str, char **endptr, int base);
+
+/**
+ * Converts the string in str to an unsigned long long value based on the given base.
+ * The endptr is updated to where the string was no longer valid.
+ * @param str - the string buffer
+ * @param endptr - the endptr
+ * @param base - the base to convert to
+ * @returns 0 on error or success, error if endptr is still equal to str
+ */
+unsigned long long int strtoull(const char *str, char **endptr, int base);
+
+/**
+ * Converts a byte count to a human readable file size of at most four characters
+ * using binary suffixes.
+ *
+ * The following rules are applied:
+ * - If the byte count is less than 1024, the count is written in decimal
+ * and no suffix is applied
+ * - Otherwise, repeatedly divide by 1024 until the value is under 1000.
+ * - If the value has two or three decimal digits, print it followed by the
+ * approprate suffix.
+ * - If the value has one decimal digit, print it along with a single fractional
+ * digit. This also applies if the value is zero.
+ *
+ * @param bytes - the bytes to convert
+ * @param buf - a pointer to the buffer to store it in (which must be at least five
+ * bytes long)
+ * @returns - buf
+ */
+char *btoa(size_t bytes, char *buf);
+
+/**
+ * This function confines an argument within specified bounds.
+ *
+ * @param min - lower bound
+ * @param value - value to be constrained
+ * @param max - upper bound
+ *
+ * @returns the constrained value
+ */
+unsigned int bound(unsigned int min, unsigned int value, unsigned int max);
+
+/**
+ * Abort the kernel with a given message.
+ *
+ * @param format - the format string
+ * @param ... - variable args for the format
+ */
+__attribute__((noreturn)) void panic(const char *format, ...);
+
+#endif /* klib.h */
diff --git a/kernel/include/lib/kstring.h b/kernel/include/lib/kstring.h
new file mode 100644
index 0000000..50334b4
--- /dev/null
+++ b/kernel/include/lib/kstring.h
@@ -0,0 +1,154 @@
+/**
+ * @file kstring.h
+ *
+ * @author Freya Murphy <freya@freyacat.org>
+ *
+ * Kernel String libaray functions
+ */
+
+#ifndef _KSTRING_H
+#define _KSTRING_H
+
+#include <stddef.h>
+
+/**
+ * Compare the first n bytes (interpreted as unsigned char) of the memory areas s1 and s2
+ * @param s1 - the first memory area
+ * @param s2 - the second memory area
+ * @param n - the byte count
+ * @returns an interger less than, equal to, or greater than 0 if the first n bytes
+ * of s1 are less than, equal to, or greater than s2.
+ */
+int memcmp(const void *restrict s1, const void *restrict s2, size_t n);
+
+/**
+ * Copy the first n bytes from memory area src to memory area dest. The memory
+ * areas must not overlap.
+ * @param dest - the destination
+ * @param src - the source
+ * @param n - the byte count
+ * @returns a pointer to dest
+ */
+void *memcpy(void *restrict dest, const void *restrict src, size_t n);
+
+/**
+ * Copy the first n bytes from memory area src to memory area dest. The memory
+ * areas may overlap; memmove behaves as though the bytes are first copied to a
+ * temporary array.
+ * @param dest - the destination
+ * @param src - the source
+ * @param n - the byte count
+ * @returns a pointer to dest
+ */
+void *memmove(void *restrict dest, const void *restrict src, size_t n);
+
+/**
+ * Fill the first n bytes of the memory region dest with the constant byte c.
+ * @param dest - the destination
+ * @param c - the byte to write
+ * @param n - the byte count
+ * @returns a pointer to dest
+ */
+void *memset(void *restrict dest, int c, size_t n);
+
+/**
+ * Copy the first n bytes from memory area src to memory area dest. The memory
+ * areas must not overlap.
+ * @param dest - the destination
+ * @param src - the source
+ * @param n - the byte count
+ * @returns a pointer to dest
+ */
+volatile void *memcpyv(volatile void *restrict dest,
+ const volatile void *restrict src, size_t n);
+
+/**
+ * Copy the first n bytes from memory area src to memory area dest. The memory
+ * areas may overlap; memmove behaves as though the bytes are first copied to a
+ * temporary array.
+ * @param dest - the destination
+ * @param src - the source
+ * @param n - the byte count
+ * @returns a pointer to dest
+ */
+volatile void *memmovev(volatile void *restrict dest,
+ const volatile void *restrict src, size_t n);
+
+/**
+ * Fill the first n bytes of the memory region dest with the constant byte c.
+ * @param dest - the destination
+ * @param c - the byte to write
+ * @param n - the byte count
+ * @returns a pointer to dest
+ */
+volatile void *memsetv(volatile void *restrict dest, int c, size_t n);
+
+/**
+ * Calculates the length of the string pointed to by str, excluding
+ * the terminating null byte
+ * @param str - the string pointer
+ * @returns the length of the string in bytes
+ */
+size_t strlen(const char *str);
+
+/**
+ * Compare null terminated string s1 and s2. The comparison is done using
+ * unsigned characters.
+ * @param s1 - a pointer to the first string
+ * @param s2 - a pointer to the second string
+ * @returns an interger less than, equal to, or greater than 0 if s1 compares less
+ * than, equal to, or greater than s2
+ */
+int strcmp(const char *restrict s1, const char *restrict s2, size_t n);
+
+/**
+ * Compare at most the first n bytes of the strings s1 and s2. The comparison is
+ * done using unsigned characters.
+ * @param s1 - a pointer to the first string
+ * @param s2 - a pointer to the second string
+ * @param n - the maximum number of bytes
+ * @returns an interger less than, equal to, or greater than 0 if s1 compares less
+ * than, equal to, or greater than s2
+ */
+int strncmp(const char *restrict s1, const char *restrict s2, size_t n);
+
+/**
+ * Copies the string pointed to by src into the buffer pointer to by dest.
+ * The dest buffer must be long enough to hold src.
+ * @param dest - the destination
+ * @param src - the source
+ * @returns a pointer to dest
+ */
+char *strcpy(char *restrict dest, const char *restrict src);
+
+/**
+ * Copies the string pointed to by src into the buffer pointer to by dest.
+ * The dest buffer must be long enough to hold src or size n.
+ * @param dest - the destination
+ * @param src - the source
+ * @param n - the maximum number of bytes
+ * @returns a pointer to dest
+ */
+char *strncpy(char *restrict dest, const char *restrict src, size_t n);
+
+/**
+ * Copies the string pointed to by src into the buffer pointed to by dest.
+ * The dest buffer must be long enough to hold src.
+ * @param dest - the destination
+ * @param src - the source
+ * @param n - the maximum number of bytes
+ * @returns a pointer to the terminating null byte
+ */
+char *stpcpy(char *restrict dest, const char *restrict src);
+
+/**
+ * Copies the string pointed to by src into the buffer pointed to by dest.
+ * The dest buffer must be long enough to hold src or size n.
+ * @param dest - the destination
+ * @param src - the source
+ * @param n - the maximum number of bytes
+ * @returns a pointer to the byte after the last character copied
+ */
+char *stpncpy(char *restrict dest, const char *restrict src, size_t n);
+
+#endif /* kstring.h */
diff --git a/kernel/kernel.ld b/kernel/kernel.ld
deleted file mode 100644
index 0806257..0000000
--- a/kernel/kernel.ld
+++ /dev/null
@@ -1,36 +0,0 @@
-ENTRY(_start)
-
-SECTIONS
-{
- . = 1M;
-
- kernel_start = .;
-
- . = ALIGN(0x1000);
-
- .text : {
- *(.multiboot)
- *(.text)
- }
-
- . = ALIGN(0x1000);
-
- .rodata : {
- *(.rodata)
- }
-
- . = ALIGN(0x1000);
-
- .data : {
- *(.data)
- }
-
- . = ALIGN(0x1000);
-
- .bss : {
- *(COMMON)
- *(.bss)
- }
-
- kernel_end = .;
-}
diff --git a/kernel/lib/atox.c b/kernel/lib/atox.c
new file mode 100644
index 0000000..6d3d4cc
--- /dev/null
+++ b/kernel/lib/atox.c
@@ -0,0 +1,29 @@
+#include <lib.h>
+
+#define ATOX(name, type) \
+ type name(const char *s) \
+ { \
+ for (; isspace(*s); s++) \
+ ; \
+ int neg = 0; \
+ switch (*s) { \
+ case '-': \
+ neg = 1; \
+ /* fallthrough */ \
+ 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)
diff --git a/kernel/lib/bound.c b/kernel/lib/bound.c
new file mode 100644
index 0000000..5a3c9fa
--- /dev/null
+++ b/kernel/lib/bound.c
@@ -0,0 +1,12 @@
+#include <lib.h>
+
+unsigned int bound(unsigned int min, unsigned int value, unsigned int max)
+{
+ if (value < min) {
+ value = min;
+ }
+ if (value > max) {
+ value = max;
+ }
+ return value;
+}
diff --git a/kernel/lib/btoa.c b/kernel/lib/btoa.c
new file mode 100644
index 0000000..96a60ef
--- /dev/null
+++ b/kernel/lib/btoa.c
@@ -0,0 +1,43 @@
+#include <lib.h>
+
+static char suffixes[] = { 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 'R', 'Q' };
+
+char *btoa(size_t bytes, char *buf)
+{
+ // no suffix if under 1K, print up to four digits
+ if (bytes < 1024) {
+ ultoa(bytes, buf, 10);
+ return buf;
+ }
+
+ // store one digit of remainder for decimal
+ unsigned int remainder;
+ // power of 1024
+ int power = 0;
+
+ // iterate until remaining bytes fits in three digits
+ while (bytes >= 1000) {
+ remainder = (bytes % 1024) * 10 / 1024;
+ bytes /= 1024;
+ power += 1;
+ }
+
+ // end of number
+ char *end;
+
+ if (bytes >= 10) {
+ // no decimal
+ end = ultoa(bytes, buf, 10);
+ } else {
+ // decimal
+ end = ultoa(bytes, buf, 10);
+ end[0] = '.';
+ end = ultoa(remainder, end + 1, 10);
+ }
+
+ // add suffix
+ end[0] = suffixes[power - 1];
+ end[1] = '\0';
+
+ return buf;
+}
diff --git a/kernel/lib/ctoi.c b/kernel/lib/ctoi.c
new file mode 100644
index 0000000..09a9f10
--- /dev/null
+++ b/kernel/lib/ctoi.c
@@ -0,0 +1,14 @@
+#include <lib.h>
+
+int ctoi(char c)
+{
+ if (c >= '0' && c <= '9') {
+ return c - '0';
+ } else if (c >= 'A' && c <= 'Z') {
+ return c - 'A' + 10;
+ } else if (c >= 'a' && c <= 'z') {
+ return c - 'a' + 10;
+ } else {
+ return -1;
+ }
+}
diff --git a/kernel/lib/fputc.c b/kernel/lib/fputc.c
deleted file mode 100644
index 0d47cb5..0000000
--- a/kernel/lib/fputc.c
+++ /dev/null
@@ -1,10 +0,0 @@
-#include <lib.h>
-#include <comus/drivers/tty.h>
-#include <comus/drivers/uart.h>
-
-void fputc(FILE *stream, char c)
-{
- (void)stream; // TODO: manage stream
- uart_out(c);
- tty_out(c);
-}
diff --git a/kernel/lib/isdigit.c b/kernel/lib/isdigit.c
new file mode 100644
index 0000000..f645093
--- /dev/null
+++ b/kernel/lib/isdigit.c
@@ -0,0 +1,6 @@
+#include <lib.h>
+
+int isdigit(int c)
+{
+ return c >= '0' && c <= '9';
+}
diff --git a/kernel/lib/isspace.c b/kernel/lib/isspace.c
new file mode 100644
index 0000000..5196d0c
--- /dev/null
+++ b/kernel/lib/isspace.c
@@ -0,0 +1,16 @@
+#include <lib.h>
+
+int isspace(int c)
+{
+ switch (c) {
+ case ' ':
+ case '\t':
+ case '\v':
+ case '\f':
+ case '\r':
+ case '\n':
+ return 1;
+ default:
+ return 0;
+ }
+}
diff --git a/kernel/lib/itoc.c b/kernel/lib/itoc.c
new file mode 100644
index 0000000..493b66e
--- /dev/null
+++ b/kernel/lib/itoc.c
@@ -0,0 +1,10 @@
+#include <lib.h>
+
+char itoc(int i)
+{
+ if (i < 10) {
+ return '0' + i;
+ } else {
+ return 'a' + (i - 10);
+ }
+}
diff --git a/kernel/lib/kalloc.c b/kernel/lib/kalloc.c
new file mode 100644
index 0000000..9845a62
--- /dev/null
+++ b/kernel/lib/kalloc.c
@@ -0,0 +1,210 @@
+#include <lib.h>
+#include <comus/memory.h>
+
+#define MAGIC 0xBEEFCAFE
+
+struct page_header {
+ struct page_header *next;
+ struct page_header *prev;
+ size_t
+ node_number; // all headers on the same page alloc have the same node number (so they can be merged)
+ size_t
+ free; // free space after the node (if its the last node in the alloc block)
+ size_t used; // how much space this allocation is using
+ uint64_t magic;
+};
+
+static const size_t header_len = sizeof(struct page_header);
+static struct page_header *start_header = NULL;
+static struct page_header *end_header = NULL;
+
+static struct page_header *get_header(void *ptr)
+{
+ struct page_header *header =
+ (struct page_header *)((uintptr_t)ptr - header_len);
+
+ // PERF: do we want to make sure this pointer is paged
+ // before reading it???
+ if (header->magic != MAGIC) {
+ return NULL; // invalid pointer
+ }
+
+ return header;
+}
+
+static void *alloc_new(size_t size)
+{
+ size_t pages = ((size + header_len) / PAGE_SIZE) + 1;
+
+ void *addr = kalloc_pages(pages);
+ void *mem = (char *)addr + header_len;
+
+ size_t total = pages * PAGE_SIZE;
+ size_t free = total - (size + header_len);
+
+ if (addr == NULL) {
+ return NULL;
+ }
+
+ size_t node;
+ if (end_header != NULL) {
+ node = end_header->node_number + 1;
+ } else {
+ node = 0;
+ }
+
+ struct page_header *header = addr;
+ header->magic = 0xBEEFCAFE;
+ header->used = size;
+ header->free = free;
+ header->prev = end_header;
+ header->next = NULL;
+ header->node_number = node;
+
+ if (start_header == NULL) {
+ start_header = header;
+ }
+
+ if (end_header != NULL) {
+ end_header->next = header;
+ } else {
+ end_header = header;
+ }
+
+ return mem;
+}
+
+static void *alloc_block(size_t size, struct page_header *block)
+{
+ struct page_header *header =
+ (struct page_header *)((char *)block + block->used + header_len);
+
+ size_t free = block->free - (size + header_len);
+ block->free = 0;
+
+ header->magic = MAGIC;
+ header->used = size;
+ header->free = free;
+ header->prev = block;
+ header->next = block->next;
+ block->next = header;
+ header->node_number = block->node_number;
+
+ void *mem = (char *)header + header_len;
+
+ return mem;
+}
+
+void *kalloc(size_t size)
+{
+ struct page_header *header = start_header;
+
+ for (; header != NULL; header = header->next) {
+ size_t free = header->free;
+ if (free < header_len)
+ continue;
+ if (size <=
+ (free - header_len)) { // we must be able to fit data + header
+ break;
+ }
+ }
+
+ if (header != NULL) {
+ return alloc_block(size, header);
+ } else {
+ return alloc_new(size);
+ }
+}
+
+void *krealloc(void *src, size_t dst_len)
+{
+ struct page_header *header;
+ size_t src_len;
+ void *dst;
+
+ // realloc of 0 means free pointer
+ if (dst_len == 0) {
+ kfree(src);
+ return NULL;
+ }
+
+ // NULL src means allocate ptr
+ if (src == NULL) {
+ dst = kalloc(dst_len);
+ return dst;
+ }
+
+ header = get_header(src);
+
+ if (header == NULL)
+ return NULL;
+
+ src_len = header->used;
+
+ if (src_len == 0)
+ return NULL;
+
+ dst = kalloc(dst_len);
+
+ if (dst == NULL)
+ return NULL; // allocation failed
+
+ if (dst_len < src_len)
+ src_len = dst_len;
+
+ memcpy(dst, src, src_len);
+ kfree(src);
+
+ return dst;
+}
+
+void kfree(void *ptr)
+{
+ struct page_header *header;
+
+ if (ptr == NULL)
+ return;
+
+ header = get_header(ptr);
+
+ if (header == NULL)
+ return;
+
+ header->free += header->used;
+ header->used = 0;
+
+ struct page_header *neighbor;
+
+ // merge left
+ for (neighbor = header->prev; neighbor != NULL; neighbor = neighbor->prev) {
+ if (neighbor->node_number != header->node_number)
+ break;
+ if (neighbor->used && header->used)
+ break;
+ neighbor->free += header->free + header_len;
+ neighbor->next = header->next;
+ header = neighbor;
+ }
+
+ // merge right
+ for (neighbor = header->next; neighbor != NULL; neighbor = neighbor->next) {
+ if (neighbor->node_number != header->node_number)
+ break;
+ if (neighbor->used)
+ break;
+ header->free += neighbor->free + header_len;
+ header->next = neighbor->next;
+ }
+
+ if ((header->next == NULL ||
+ header->next->node_number != header->node_number) &&
+ (header->prev == NULL ||
+ header->prev->node_number != header->node_number) &&
+ header->used == 0) {
+ if (header->next)
+ header->next->prev = header->prev;
+ if (header->prev)
+ header->prev->next = header->next;
+ kfree_pages(header);
+ }
+}
diff --git a/kernel/lib/kprintf.c b/kernel/lib/kprintf.c
new file mode 100644
index 0000000..a76036f
--- /dev/null
+++ b/kernel/lib/kprintf.c
@@ -0,0 +1,576 @@
+#include <lib.h>
+#include <comus/drivers/uart.h>
+#include <comus/drivers/tty.h>
+
+#define PRINTF_NUMERIC_BUF_LEN 50
+
+typedef union {
+ unsigned long long int u;
+ signed long long int i;
+ char *str;
+ char c;
+} data_t;
+
+/// options that can be set inside a specifier
+/// flags, width, precision, length, and data type
+typedef struct {
+ /* flags */
+ /// left justify content
+ uint8_t left : 1;
+ /// force sign (+/-) on numeric output
+ uint8_t sign : 1;
+ /// leave space if no printed sign on numeric output
+ uint8_t space : 1;
+ /// preceed hex/octal output with '0x'
+ uint8_t hash : 1;
+ /// left pads numeric output with zeros
+ uint8_t zero : 1;
+ uint8_t : 3;
+
+ /* width & precision */
+ /// minimum number of characters to be printed (padding if origonal is less)
+ int width;
+ /// digit precision used when printing numerical answers
+ int precision;
+ /// if a fixed minimum width has been provided
+ uint8_t width_set : 1;
+ /// if the provided minimum width is in the next variable argument
+ uint8_t width_varies : 1;
+ /// if a fixed digit precision has been provided
+ uint8_t precision_set : 1;
+ /// if the provided digit precision is in the next variable argument
+ uint8_t precision_varies : 1;
+ uint8_t : 4;
+
+ /* length */
+ /// what size to read argument as
+ enum printf_len {
+ PRINTF_LEN_CHAR,
+ PRINTF_LEN_SHORT_INT,
+ PRINTF_LEN_INT,
+ PRINTF_LEN_LONG_INT,
+ PRINTF_LEN_LONG_LONG_INT,
+ PRINTF_LEN_SIZE_T,
+ } len;
+
+ /* other */
+ /// radix to print the numerical answers as
+ uint8_t radix;
+ /// case to print hexadecimal values as
+ bool is_uppercase;
+} options_t;
+
+typedef struct {
+ /* input */
+ /// the origonal format string
+ const char *format;
+ /// maximum allowed output length
+ size_t max_len;
+ /// if a maximum output length is set
+ bool has_max_len;
+
+ /* output */
+ size_t written_len;
+ bool sprintf;
+ char *sprintf_buf;
+
+ /* pass 2 */
+ char *output;
+} context_t;
+
+static void printf_putc(context_t *ctx, char c)
+{
+ // bounds check
+ if (ctx->has_max_len)
+ if (ctx->written_len >= ctx->max_len)
+ return;
+
+ // write to correct
+ if (ctx->sprintf)
+ *(ctx->sprintf_buf++) = c;
+ else
+ kputc(c);
+
+ ctx->written_len++;
+}
+
+static int parse_flag(const char **res, options_t *opts)
+{
+ const char *fmt = *res;
+ switch (*(fmt++)) {
+ case '-':
+ opts->left = 1;
+ break;
+ case '+':
+ opts->sign = 1;
+ break;
+ case ' ':
+ opts->space = 1;
+ break;
+ case '#':
+ opts->hash = 1;
+ break;
+ case '0':
+ opts->zero = 1;
+ break;
+ default:
+ return 0;
+ }
+
+ *res = fmt;
+ return 1;
+}
+
+static void parse_width(const char **res, options_t *opts)
+{
+ const char *fmt = *res;
+ char *end = NULL;
+
+ // check varies
+ if (*fmt == '*') {
+ opts->width_varies = true;
+ *res = fmt++;
+ return;
+ }
+
+ // parse num
+ long width = strtol(fmt, &end, 10);
+ if (end != NULL) {
+ opts->width_set = 1;
+ opts->width = width;
+ *res = end;
+ return;
+ }
+}
+
+static void parse_precision(const char **res, options_t *opts)
+{
+ const char *fmt = *res;
+ char *end = NULL;
+
+ // check for dot
+ if (*(fmt++) != '.')
+ return;
+
+ // check varies
+ if (*fmt == '*') {
+ opts->precision_varies = true;
+ *res = fmt++;
+ return;
+ }
+
+ // parse num
+ long precision = strtol(fmt, &end, 10);
+ if (end != NULL) {
+ opts->precision_set = 1;
+ opts->precision = precision;
+ *res = end;
+ return;
+ }
+}
+
+static void parse_length(const char **res, options_t *opts)
+{
+ const char *fmt = *res;
+
+ switch (*(fmt++)) {
+ // half
+ case 'h':
+ if (*fmt == 'h') {
+ opts->len = PRINTF_LEN_CHAR;
+ fmt++;
+ } else {
+ opts->len = PRINTF_LEN_SHORT_INT;
+ }
+ break;
+ // long
+ case 'l':
+ if (*fmt == 'l') {
+ opts->len = PRINTF_LEN_LONG_LONG_INT;
+ fmt++;
+ } else {
+ opts->len = PRINTF_LEN_LONG_INT;
+ }
+ break;
+ // size_t
+ case 'z':
+ opts->len = PRINTF_LEN_SIZE_T;
+ break;
+ default:
+ opts->len = PRINTF_LEN_INT;
+ return;
+ }
+
+ *res = fmt;
+}
+
+static void get_radix(char spec, options_t *opts)
+{
+ switch (spec) {
+ case 'x':
+ case 'X':
+ opts->radix = 16;
+ break;
+ case 'o':
+ opts->radix = 8;
+ break;
+ default:
+ opts->radix = 10;
+ break;
+ }
+}
+
+static void get_case(char spec, options_t *opts)
+{
+ if (spec == 'X')
+ opts->is_uppercase = 1;
+}
+
+static char printf_itoc(int uppercase, int i)
+{
+ // decimal
+ if (i < 10) {
+ return i + '0';
+ }
+ // hex
+ if (uppercase) {
+ return (i - 10) + 'A';
+ } else {
+ return (i - 10) + 'a';
+ }
+}
+
+static int printf_lltoa(char *buf, options_t *opts, bool is_neg,
+ unsigned long long int num)
+{
+ int precision = 0;
+ char *start = buf;
+
+ // get width of number
+ int len = 0;
+ unsigned long long int temp = num;
+ if (temp == 0)
+ len = 1;
+ while (temp) {
+ if (opts->precision_set && precision++ >= opts->precision)
+ break;
+ temp /= opts->radix;
+ len++;
+ }
+ precision = 0;
+
+ // sign
+ if (is_neg) {
+ *(buf++) = '-';
+ } else if (opts->sign) {
+ *(buf++) = '+';
+ } else if (opts->space) {
+ *(buf++) = ' ';
+ }
+
+ // radix specifier
+ if (opts->hash) {
+ if (opts->radix == 8) {
+ *(buf++) = '0';
+ *(buf++) = 'o';
+ }
+ if (opts->radix == 16) {
+ *(buf++) = '0';
+ *(buf++) = 'x';
+ }
+ }
+
+ // print zeros if needed
+ if (opts->width_set && len < opts->width && opts->zero) {
+ while (len++ < opts->width)
+ *(buf++) = '0';
+ }
+
+ // write number
+ if (num == 0) {
+ *(buf++) = '0';
+ }
+ while (num) {
+ if (opts->precision_set && precision++ >= opts->precision)
+ break;
+ *(buf++) = printf_itoc(opts->is_uppercase, num % opts->radix);
+ num /= opts->radix;
+ }
+ *(buf++) = '\0';
+
+ return buf - start;
+}
+
+static void handle_int_specifier(context_t *ctx, options_t *const opts,
+ bool has_sign_bit, data_t num)
+{
+ bool is_neg = false;
+
+ // get sign if possible neg
+ if (has_sign_bit) {
+ if (num.i < 0) {
+ num.i = -num.i;
+ is_neg = true;
+ }
+ }
+
+ // get length of number and number
+ char buf[PRINTF_NUMERIC_BUF_LEN];
+ int buf_len = printf_lltoa(buf, opts, is_neg, num.u);
+
+ // get needed padding
+ int padding = 0;
+ if (opts->width_set && (buf_len < opts->width))
+ padding = opts->width - buf_len;
+
+ /* print */
+ // left padding
+ if (opts->left == 0) {
+ for (int i = 0; i < padding; i++)
+ printf_putc(ctx, opts->zero ? '0' : ' ');
+ }
+ // number
+ for (int i = 0; i < buf_len; i++)
+ printf_putc(ctx, buf[i]);
+ // right padding
+ if (opts->left == 1) {
+ for (int i = 0; i < padding; i++)
+ printf_putc(ctx, opts->zero ? '0' : ' ');
+ }
+}
+
+static void handle_char_specifier(context_t *ctx, data_t c)
+{
+ printf_putc(ctx, c.c);
+}
+
+static void handle_string_specifier(context_t *ctx, options_t *opts,
+ data_t data)
+{
+ char *str = data.str;
+ int str_len = 0;
+
+ // get length of string
+ if (opts->precision_set)
+ str_len = opts->precision;
+ else
+ str_len = strlen(str);
+
+ // get needed padding
+ int padding = 0;
+ if (opts->width_set && (str_len < opts->width))
+ padding = opts->width - str_len;
+
+ /* print */
+ // left padding
+ if (opts->left == 0) {
+ for (int i = 0; i < padding; i++)
+ printf_putc(ctx, ' ');
+ }
+ // string
+ for (int i = 0; i < str_len; i++)
+ printf_putc(ctx, str[i]);
+ // right padding
+ if (opts->left == 1) {
+ for (int i = 0; i < padding; i++)
+ printf_putc(ctx, ' ');
+ }
+}
+
+static void do_printf(context_t *ctx, va_list args)
+{
+ const char *fmt = ctx->format;
+
+ char c;
+ while (c = *fmt++, c != '\0') {
+ // save start of fmt for current iteration
+ const char *start = fmt - 1;
+
+ // ignore if not %
+ if (c != '%') {
+ printf_putc(ctx, c);
+ continue;
+ }
+
+ // read opts
+ options_t opts = { 0 };
+ while (parse_flag(&fmt, &opts))
+ ;
+ parse_width(&fmt, &opts);
+ parse_precision(&fmt, &opts);
+ parse_length(&fmt, &opts);
+
+ // read specifier
+ char spec = *fmt++;
+ get_radix(spec, &opts);
+ get_case(spec, &opts);
+
+ // read varied width / precision
+ if (opts.width_varies) {
+ opts.width_set = 1;
+ opts.width = va_arg(args, int);
+ }
+ if (opts.precision_varies) {
+ opts.precision_set = 1;
+ opts.precision = va_arg(args, int);
+ }
+ // read data from args
+ data_t data;
+ switch (spec) {
+ case 'p':
+ opts.len = PRINTF_LEN_SIZE_T;
+ opts.width_set = true;
+ opts.radix = 16;
+ opts.hash = true;
+ opts.zero = true;
+ case 'd':
+ case 'i':
+ case 'u':
+ case 'o':
+ case 'x':
+ case 'X':
+ // read number from arg
+ switch (opts.len) {
+ case PRINTF_LEN_CHAR:
+ data.u = va_arg(args, unsigned int); // char
+ break;
+ case PRINTF_LEN_SHORT_INT:
+ data.u = va_arg(args, unsigned int); // short int
+ break;
+ case PRINTF_LEN_INT:
+ data.u = va_arg(args, unsigned int);
+ break;
+ case PRINTF_LEN_LONG_INT:
+ data.u = va_arg(args, unsigned long int);
+ break;
+ case PRINTF_LEN_LONG_LONG_INT:
+ data.u = va_arg(args, unsigned long long int);
+ break;
+ case PRINTF_LEN_SIZE_T:
+ data.u = va_arg(args, size_t);
+ break;
+ }
+ break;
+ // end int
+ case 's':
+ // read string
+ data.str = va_arg(args, void *);
+ break;
+ // end string
+ case 'c':
+ // read char
+ data.c = va_arg(args, int);
+ break;
+ // end char
+ }
+
+ switch (spec) {
+ // signed int
+ case 'd':
+ case 'i':
+ handle_int_specifier(ctx, &opts, true, data);
+ break;
+ // unsigned int
+ case 'p':
+ case 'u':
+ case 'o':
+ case 'x':
+ case 'X':
+ handle_int_specifier(ctx, &opts, false, data);
+ break;
+ // character
+ case 'c':
+ handle_char_specifier(ctx, data);
+ break;
+ // string
+ case 's':
+ handle_string_specifier(ctx, &opts, data);
+ break;
+ // unknown
+ default:
+ // print from % to current
+ for (; start < fmt; start++)
+ printf_putc(ctx, *start);
+ break;
+ }
+ }
+}
+
+void kprintf(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ kvprintf(format, args);
+ va_end(args);
+}
+
+size_t ksprintf(char *restrict s, const char *format, ...)
+{
+ va_list args;
+ size_t amt;
+ va_start(args, format);
+ amt = kvsprintf(s, format, args);
+ va_end(args);
+ return amt;
+}
+
+size_t snprintf(char *restrict s, size_t maxlen, const char *format, ...)
+{
+ va_list args;
+ size_t amt;
+ va_start(args, format);
+ amt = kvsnprintf(s, maxlen, format, args);
+ va_end(args);
+ return amt;
+}
+
+void kvprintf(const char *format, va_list args)
+{
+ // create context
+ context_t ctx = { 0 };
+ ctx.format = format;
+ // print
+ do_printf(&ctx, args);
+}
+
+size_t kvsprintf(char *restrict s, const char *format, va_list args)
+{
+ // create context
+ context_t ctx = { 0 };
+ ctx.format = format;
+ // sprintf buffer
+ ctx.sprintf_buf = s;
+ ctx.sprintf = 1;
+ // print
+ do_printf(&ctx, args);
+ return ctx.written_len;
+}
+
+size_t kvsnprintf(char *restrict s, size_t maxlen, const char *format,
+ va_list args)
+{
+ // create context
+ context_t ctx = { 0 };
+ ctx.format = format;
+ // sprintf buffer
+ ctx.sprintf_buf = s;
+ ctx.sprintf = 1;
+ // sprintf max_len
+ ctx.has_max_len = 1;
+ ctx.max_len = maxlen;
+ // print
+ do_printf(&ctx, args);
+ return ctx.written_len;
+}
+
+void kputc(char c)
+{
+ tty_out(c);
+ uart_out(c);
+}
+
+void kputs(const char *str)
+{
+ tty_out_str(str);
+ uart_out_str(str);
+}
diff --git a/kernel/lib/memcmp.c b/kernel/lib/memcmp.c
new file mode 100644
index 0000000..f938d0a
--- /dev/null
+++ b/kernel/lib/memcmp.c
@@ -0,0 +1,9 @@
+#include <lib.h>
+
+int memcmp(const void *restrict vl, const void *restrict vr, size_t n)
+{
+ const unsigned char *l = vl, *r = vr;
+ for (; n && *l == *r; n--, l++, r++)
+ ;
+ return n ? *l - *r : 0;
+}
diff --git a/kernel/lib/memcpy.c b/kernel/lib/memcpy.c
new file mode 100644
index 0000000..e848cef
--- /dev/null
+++ b/kernel/lib/memcpy.c
@@ -0,0 +1,10 @@
+#include <lib.h>
+
+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;
+}
diff --git a/kernel/lib/memcpyv.c b/kernel/lib/memcpyv.c
new file mode 100644
index 0000000..bc95807
--- /dev/null
+++ b/kernel/lib/memcpyv.c
@@ -0,0 +1,11 @@
+#include <lib.h>
+
+volatile void *memcpyv(volatile void *restrict dest,
+ const volatile void *restrict src, size_t n)
+{
+ volatile char *d = dest;
+ volatile const char *s = src;
+ for (; n; n--)
+ *d++ = *s++;
+ return dest;
+}
diff --git a/kernel/lib/memmove.c b/kernel/lib/memmove.c
new file mode 100644
index 0000000..55be66d
--- /dev/null
+++ b/kernel/lib/memmove.c
@@ -0,0 +1,20 @@
+#include <lib.h>
+
+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;
+}
diff --git a/kernel/lib/memmovev.c b/kernel/lib/memmovev.c
new file mode 100644
index 0000000..56684a5
--- /dev/null
+++ b/kernel/lib/memmovev.c
@@ -0,0 +1,20 @@
+#include <lib.h>
+
+volatile void *memmovev(volatile void *dest, const volatile void *src, size_t n)
+{
+ volatile char *d = dest;
+ volatile 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;
+}
diff --git a/kernel/lib/memset.c b/kernel/lib/memset.c
new file mode 100644
index 0000000..d1c2a5e
--- /dev/null
+++ b/kernel/lib/memset.c
@@ -0,0 +1,10 @@
+#include <lib.h>
+
+void *memset(void *dest, int c, size_t n)
+{
+ unsigned char *d = dest;
+ for (; n; n--) {
+ *d++ = c;
+ };
+ return dest;
+}
diff --git a/kernel/lib/memsetv.c b/kernel/lib/memsetv.c
new file mode 100644
index 0000000..647847f
--- /dev/null
+++ b/kernel/lib/memsetv.c
@@ -0,0 +1,10 @@
+#include <lib.h>
+
+volatile void *memsetv(volatile void *dest, int c, size_t n)
+{
+ volatile unsigned char *d = dest;
+ for (; n; n--) {
+ *d++ = c;
+ };
+ return dest;
+}
diff --git a/kernel/lib/panic.c b/kernel/lib/panic.c
index 403418f..5381041 100644
--- a/kernel/lib/panic.c
+++ b/kernel/lib/panic.c
@@ -7,9 +7,9 @@ __attribute__((noreturn)) void panic(const char *format, ...)
cli();
va_list list;
va_start(list, format);
- printf("\n\n!!! PANIC !!!\n");
- vprintf(format, list);
- printf("\n\n");
+ kprintf("\n\n!!! PANIC !!!\n");
+ kvprintf(format, list);
+ kprintf("\n\n");
while (1)
halt();
diff --git a/kernel/lib/stpcpy.c b/kernel/lib/stpcpy.c
new file mode 100644
index 0000000..1a7c5bf
--- /dev/null
+++ b/kernel/lib/stpcpy.c
@@ -0,0 +1,9 @@
+#include <lib.h>
+
+char *stpcpy(char *restrict dest, const char *restrict src)
+{
+ char *d = dest;
+ for (; (*d = *src); d++, src++)
+ ;
+ return d;
+}
diff --git a/kernel/lib/stpncpy.c b/kernel/lib/stpncpy.c
new file mode 100644
index 0000000..87f9838
--- /dev/null
+++ b/kernel/lib/stpncpy.c
@@ -0,0 +1,10 @@
+#include <lib.h>
+
+char *stpncpy(char *restrict dest, const char *restrict src, size_t n)
+{
+ char *d = dest;
+ for (; (*d = *src) && n; d++, src++, n--)
+ ;
+ memset(d, 0, n);
+ return d;
+}
diff --git a/kernel/lib/strcat.c b/kernel/lib/strcat.c
new file mode 100644
index 0000000..fcfa463
--- /dev/null
+++ b/kernel/lib/strcat.c
@@ -0,0 +1,7 @@
+#include <lib.h>
+
+char *strcat(char *restrict dest, const char *restrict src)
+{
+ strcpy(dest + strlen(dest), src);
+ return dest;
+}
diff --git a/kernel/lib/strcpy.c b/kernel/lib/strcpy.c
new file mode 100644
index 0000000..d74e68d
--- /dev/null
+++ b/kernel/lib/strcpy.c
@@ -0,0 +1,9 @@
+#include <lib.h>
+
+char *strcpy(char *restrict dest, const char *restrict src)
+{
+ char *d = dest;
+ for (; (*d = *src); d++, src++)
+ ;
+ return dest;
+}
diff --git a/kernel/lib/strlen.c b/kernel/lib/strlen.c
new file mode 100644
index 0000000..6d31f2f
--- /dev/null
+++ b/kernel/lib/strlen.c
@@ -0,0 +1,9 @@
+#include <lib.h>
+
+size_t strlen(const char *str)
+{
+ const char *p;
+ for (p = str; *p != 0; p++) {
+ }
+ return p - str;
+}
diff --git a/kernel/lib/strncmp.c b/kernel/lib/strncmp.c
new file mode 100644
index 0000000..0cf5837
--- /dev/null
+++ b/kernel/lib/strncmp.c
@@ -0,0 +1,11 @@
+#include <lib.h>
+
+int strncmp(const char *restrict lhs, const char *restrict 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;
+}
diff --git a/kernel/lib/strncpy.c b/kernel/lib/strncpy.c
new file mode 100644
index 0000000..f691191
--- /dev/null
+++ b/kernel/lib/strncpy.c
@@ -0,0 +1,10 @@
+#include <lib.h>
+
+char *strncpy(char *restrict dest, const char *restrict src, size_t n)
+{
+ char *d = dest;
+ for (; (*d = *src) && n; d++, src++, n--)
+ ;
+ memset(d, 0, n);
+ return dest;
+}
diff --git a/kernel/lib/strtoux.c b/kernel/lib/strtoux.c
new file mode 100644
index 0000000..e8f828b
--- /dev/null
+++ b/kernel/lib/strtoux.c
@@ -0,0 +1,43 @@
+#include <lib.h>
+
+#define STRTOUX(name, type) \
+ type name(const char *restrict s, char **restrict endptr, int radix) \
+ { \
+ const char *s_start = s; \
+ for (; isspace(*s); s++) \
+ ; \
+ \
+ if ((radix == 0 || radix == 16) && \
+ (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))) { \
+ radix = 16; \
+ s += 2; \
+ } else if (radix == 0) { \
+ if (*s == '0') { \
+ radix = 8; \
+ s++; \
+ } else { \
+ radix = 10; \
+ } \
+ } \
+ \
+ type num = 0; \
+ int has_digit = 0; \
+ \
+ while (1) { \
+ int n = ctoi(*s++); \
+ if (n < 0 || n >= radix) \
+ break; \
+ has_digit = 1; \
+ num = num * radix + n; \
+ } \
+ \
+ if (endptr != NULL) { \
+ *endptr = has_digit ? (char *)(s - 1) : (char *)s_start; \
+ } \
+ \
+ return num; \
+ }
+
+STRTOUX(strtoui, unsigned int)
+STRTOUX(strtoul, unsigned long int)
+STRTOUX(strtoull, unsigned long long int)
diff --git a/kernel/lib/strtox.c b/kernel/lib/strtox.c
new file mode 100644
index 0000000..620b8d3
--- /dev/null
+++ b/kernel/lib/strtox.c
@@ -0,0 +1,52 @@
+#include <lib.h>
+
+#define STRTOX(name, type) \
+ type name(const char *restrict s, char **restrict endptr, int radix) \
+ { \
+ const char *s_start = s; \
+ for (; isspace(*s); s++) \
+ ; \
+ \
+ int sign = 0; \
+ switch (*s) { \
+ case '-': \
+ sign = 1; /* fallthrough */ \
+ case '+': \
+ s++; \
+ break; \
+ } \
+ \
+ if ((radix == 0 || radix == 16) && \
+ (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))) { \
+ radix = 16; \
+ s += 2; \
+ } else if (radix == 0) { \
+ if (*s == '0') { \
+ radix = 8; \
+ s++; \
+ } else { \
+ radix = 10; \
+ } \
+ } \
+ \
+ type num = 0; \
+ int has_digit = 0; \
+ \
+ while (1) { \
+ int n = ctoi(*s++); \
+ if (n < 0 || n >= radix) \
+ break; \
+ has_digit = 1; \
+ num = num * radix + n; \
+ } \
+ \
+ if (endptr != NULL) { \
+ *endptr = has_digit ? (char *)(s - 1) : (char *)s_start; \
+ } \
+ \
+ return sign ? -num : num; \
+ }
+
+STRTOX(strtoi, int)
+STRTOX(strtol, long int)
+STRTOX(strtoll, long long int)
diff --git a/kernel/lib/uxtoa.c b/kernel/lib/uxtoa.c
new file mode 100644
index 0000000..9133d29
--- /dev/null
+++ b/kernel/lib/uxtoa.c
@@ -0,0 +1,27 @@
+#include <lib.h>
+
+#define UXTOA(type, name) \
+ char *name(unsigned type n, char *buffer, int radix) \
+ { \
+ if (n == 0) { \
+ buffer[0] = '0'; \
+ buffer[1] = '\0'; \
+ return buffer + 1; \
+ } \
+ char *start = buffer; \
+ for (; n; n /= radix) { \
+ *buffer++ = itoc(n % radix); \
+ } \
+ char *buf_end = buffer; \
+ *buffer-- = '\0'; \
+ while (buffer > start) { \
+ char tmp = *start; \
+ *start++ = *buffer; \
+ *buffer-- = tmp; \
+ } \
+ return buf_end; \
+ }
+
+UXTOA(int, utoa)
+UXTOA(long int, ultoa)
+UXTOA(long long int, ulltoa)
diff --git a/kernel/lib/xtoa.c b/kernel/lib/xtoa.c
new file mode 100644
index 0000000..bd3a367
--- /dev/null
+++ b/kernel/lib/xtoa.c
@@ -0,0 +1,31 @@
+#include <lib.h>
+
+#define XTOA(type, name) \
+ char *name(type n, char *buffer, int radix) \
+ { \
+ if (n == 0) { \
+ buffer[0] = '0'; \
+ buffer[1] = '\0'; \
+ return buffer + 1; \
+ } \
+ if (n < 0) { \
+ *buffer++ = '-'; \
+ n = -n; \
+ } \
+ char *start = buffer; \
+ for (; n; n /= radix) { \
+ *buffer++ = itoc(n % radix); \
+ } \
+ char *buf_end = buffer; \
+ *buffer-- = '\0'; \
+ while (buffer > start) { \
+ char tmp = *start; \
+ *start++ = *buffer; \
+ *buffer-- = tmp; \
+ } \
+ return buf_end; \
+ }
+
+XTOA(int, itoa)
+XTOA(long int, ltoa)
+XTOA(long long int, lltoa)
diff --git a/kernel/kernel.c b/kernel/main.c
index 7382a7d..5b06ae2 100644
--- a/kernel/kernel.c
+++ b/kernel/main.c
@@ -4,8 +4,6 @@
#include <comus/drivers.h>
#include <comus/fs.h>
#include <lib.h>
-#include <stdio.h>
-#include <time.h>
struct memory_map mmap;
@@ -29,13 +27,6 @@ void main(long magic, volatile void *mboot)
// load file systems
fs_init();
- // print current time
- char date[40];
- set_timezone(TZ_EDT);
- time_t time = get_localtime();
- timetostr(&time, "%a %b %d %Y %H:%M:%S", date, 40);
- printf("The date is: %s\n\n", date);
-
// halt
- printf("halting...\n");
+ kprintf("halting...\n");
}
diff --git a/kernel/mboot/mmap.c b/kernel/mboot/mmap.c
index ff38771..8a5f549 100644
--- a/kernel/mboot/mmap.c
+++ b/kernel/mboot/mmap.c
@@ -2,8 +2,6 @@
#include <comus/mboot.h>
#include "mboot.h"
-#include <stdint.h>
-#include <stdio.h>
static const char *segment_type[] = { "Reserved", "Free",
"Reserved", "ACPI Reserved",
@@ -17,7 +15,7 @@ void mboot_load_mmap(volatile void *mboot, struct memory_map *res)
int idx = 0;
uintptr_t i = (uintptr_t)mmap->entries;
- printf("MEMORY MAP\n");
+ kprintf("MEMORY MAP\n");
char buf[20];
for (; i < (uintptr_t)mmap->entries + mmap->size;
i += mmap->entry_size, idx++) {
@@ -27,7 +25,7 @@ void mboot_load_mmap(volatile void *mboot, struct memory_map *res)
type = segment_type[6];
else
type = segment_type[seg->type];
- printf("ADDR: %16p LEN: %4s TYPE: %s (%d)\n", (void *)seg->addr,
+ kprintf("ADDR: %16p LEN: %4s TYPE: %s (%d)\n", (void *)seg->addr,
btoa(seg->len, buf), type, seg->type);
if (seg->type != 1 || seg->len < 1)
continue;
diff --git a/kernel/memory/paging.c b/kernel/memory/paging.c
index d10cf6d..5c4fa5c 100644
--- a/kernel/memory/paging.c
+++ b/kernel/memory/paging.c
@@ -514,7 +514,7 @@ static inline void *page_align(void *addr)
return (void *)a;
}
-void *mapaddr(void *addr, size_t len)
+void *kmapaddr(void *addr, size_t len)
{
void *phys = page_align(addr);
ptrdiff_t error = (char *)addr - (char *)phys;
@@ -531,7 +531,7 @@ void *mapaddr(void *addr, size_t len)
return (char *)virt + error;
}
-void unmapaddr(void *addr)
+void kunmapaddr(void *addr)
{
long pages = virtaddr_free(addr);
if (pages < 1)
@@ -539,7 +539,7 @@ void unmapaddr(void *addr)
unmap_pages(kernel_pml4, addr, pages);
}
-void *alloc_pages(size_t count)
+void *kalloc_pages(size_t count)
{
void *virt = virtaddr_alloc(count);
if (virt == NULL)
@@ -559,13 +559,12 @@ void *alloc_pages(size_t count)
return virt;
}
-void free_page(void *virt)
+void *kalloc_page(void)
{
- (void)virt;
- panic("free_page is not yet implemented");
+ return kalloc_pages(1);
}
-void free_pages(void *virt)
+void kfree_pages(void *virt)
{
long pages = virtaddr_free(virt);
if (pages < 1)
@@ -573,7 +572,7 @@ void free_pages(void *virt)
unmap_pages(kernel_pml4, virt, pages);
}
-int load_page(void *virt_addr)
+int kload_page(void *virt_addr)
{
volatile struct pte *page = get_page(kernel_pml4, virt_addr);
if (page == NULL)
diff --git a/kernel/memory/physalloc.c b/kernel/memory/physalloc.c
index 53f8aaf..a907077 100644
--- a/kernel/memory/physalloc.c
+++ b/kernel/memory/physalloc.c
@@ -185,9 +185,9 @@ void physalloc_init(struct memory_map *map)
memory_start = page_align((uintptr_t)page_area_addr + page_area_size);
- bitmap = mapaddr(bitmap, bitmap_size);
+ bitmap = kmapaddr(bitmap, bitmap_size);
memset(bitmap, 0, bitmap_size);
- page_area_addr = mapaddr(page_area_addr, page_area_size);
+ page_area_addr = kmapaddr(page_area_addr, page_area_size);
memset(page_area_addr, 0, page_area_size);
page_start = (struct memory_segment *)page_area_addr;
@@ -210,15 +210,10 @@ void physalloc_init(struct memory_map *map)
free_memory = page_count * PAGE_SIZE;
char buf[20];
- printf("\nMEMORY USAGE\n");
- printf("mem total: %s\n", btoa(memory_total(), buf));
- printf("mem free: %s\n", btoa(memory_free(), buf));
- printf("mem used: %s\n\n", btoa(memory_used(), buf));
-}
-
-void *alloc_page(void)
-{
- return alloc_pages(1);
+ kprintf("\nMEMORY USAGE\n");
+ kprintf("mem total: %s\n", btoa(memory_total(), buf));
+ kprintf("mem free: %s\n", btoa(memory_free(), buf));
+ kprintf("mem used: %s\n\n", btoa(memory_used(), buf));
}
uint64_t memory_total(void)
diff --git a/kernel/memory/virtalloc.c b/kernel/memory/virtalloc.c
index 2b64b72..6b7fd20 100644
--- a/kernel/memory/virtalloc.c
+++ b/kernel/memory/virtalloc.c
@@ -64,11 +64,11 @@ static struct addr_node *get_node(void)
if (new_alloc < 8)
new_alloc = 8;
struct addr_node *new_nodes;
- new_nodes = malloc(sizeof(struct addr_node) * new_alloc);
+ new_nodes = kalloc(sizeof(struct addr_node) * new_alloc);
if (new_nodes == NULL)
panic("virt addr alloc nodes is null");
update_node_ptrs(alloc_nodes, new_nodes, alloc_node_count, new_alloc);
- free(alloc_nodes);
+ kfree(alloc_nodes);
alloc_nodes = new_nodes;
alloc_node_count = new_alloc;
is_allocating = false;