diff options
Diffstat (limited to 'kernel')
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; |