diff --git a/.gitignore b/.gitignore index 1383201..b2ad23e 100644 --- a/.gitignore +++ b/.gitignore @@ -20,4 +20,3 @@ user/usys.S .cache compile_commands.json tags -toolchain diff --git a/Makefile b/Makefile index 716b923..9ac5771 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,4 @@ -# TOOLPREFIX = riscv64-linux-gnu -# TOOLPREFIX = toolchain/xpack-riscv-none-elf-gcc-14.2.0-3/bin/riscv-none-elf -TOOLPREFIX = toolchain/gcc/bin/riscv-none-elf +TOOLPREFIX = riscv-none-elf CC = $(TOOLPREFIX)-gcc AS = $(TOOLPREFIX)-as @@ -19,32 +17,25 @@ CFLAGS += -mcmodel=medany CFLAGS += -march=rv64gc -mabi=lp64 CFLAGS += -ffreestanding -fno-common -nostdlib -mno-relax +CFLAGS += -I. +CFLAGS += -Ilib +CFLAGS += -Ikern + CFLAGS += -fno-stack-protector # Prevents code that needs libc / runtime support CFLAGS += -MD # Generate header dependency files (.d) CFLAGS += -fno-pie -no-pie # Fixed address linking CFLAGS += -ggdb -gdwarf-2 # GDB debug info CFLAGS += -fno-omit-frame-pointer # More reliable backtraces in GDB -KCFLAGS += $(CGFLAGS) -KCFLAGS += -DNEPTUNE_KERNEL -KCFLAGS += -Ikern -KCFLAGS += -Ikern/libkern -KCFLAGS += -I. - -CFLAGS += -I. -CFLAGS += -Ilib - all: kernel.elf -main: main.o - -kernel.elf: entry.o start.o kern/libkern/string.o kern/libkern/proc.o kern/libkern/uart.o kern/libkern/panic.o kern/kalloc.o kern/libkern/memory.o kern/ispinlock.o kern/libkern/spinlock.o kern/libkern/string.o kern/libkern/mini-printf.o +kernel.elf: entry.o start.o lib/string.o lib/proc.o lib/proc.o lib/uart.o lib/panic.o kern/kalloc.o lib/memory.o kern/ispinlock.o lib/spinlock.o @echo LD $@ @$(LD) $(LDFLAGS) -o $@ $^ %.o: %.c @echo CC $@ - @$(CC) $(KCFLAGS) -nostdinc -I. -c $< -o $@ + @$(CC) $(CFLAGS) -nostdinc -I. -c $< -o $@ %.o: %.S @echo AS $@ @@ -56,62 +47,7 @@ qemu: kernel.elf clean: rm -f *.o *.elf *.d lib/*.o lib/*.d - fd -e o -x rm # TODO: Should only depend on posix -include *.d -# -------------------------------------------------------------------- -# Toolchain configuration -# -------------------------------------------------------------------- - -TOOLCHAIN_DIR := toolchain - -# Versions -QEMU_VER := 8.2.6-1 -GCC_VER := 14.2.0-3 - -# Filenames -QEMU_TARBALL := xpack-qemu-riscv-$(QEMU_VER)-linux-arm.tar.gz -GCC_TARBALL := xpack-riscv-none-elf-gcc-$(GCC_VER)-linux-arm.tar.gz - -# URLs -QEMU_URL := https://github.com/xpack-dev-tools/qemu-riscv-xpack/releases/download/v$(QEMU_VER)/$(QEMU_TARBALL) -GCC_URL := https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v$(GCC_VER)/$(GCC_TARBALL) - -# Paths -QEMU_TARPATH := toolchain/xpack-qemu-riscv-8.2.6-1-linux-arm.tar.gz -GCC_TARPATH := toolchain/xpack-riscv-none-elf-gcc-14.2.0-3-linux-arm.tar.gz - -# Extracted directories -QEMU_DIR := $(TOOLCHAIN_DIR)/xpack-qemu-riscv-$(QEMU_VER) -GCC_DIR := $(TOOLCHAIN_DIR)/xpack-riscv-none-elf-gcc-$(GCC_VER) - -# Symlink targets -QEMU_SYM_DIR := xpack-qemu-riscv-$(QEMU_VER) -GCC_SYM_DIR := xpack-riscv-none-elf-gcc-$(GCC_VER) - -# Final symlink/alias -GCC_ALIAS := gcc -QEMU_ALIAS := qemu - -QEMU_TARPATH: - curl -# -L -o $@ $(QEMU_URL) - -GCC_TARPATH: - curl -# -L -o $@ $(GCC_URL) - -extractions: - cd toolchain && tar xf $(QEMU_TARBALL) - cd toolchain && tar xf $(GCC_TARBALL) - -toolchain: $(QEMU_TARPATH) $(GCC_TARPATH) - mkdir -p toolchain - cd toolchain && tar xf $(QEMU_TARBALL) - cd toolchain && tar xf $(GCC_TARBALL) - cd $(TOOLCHAIN_DIR) && ln -sfn $(QEMU_SYM_DIR) $(QEMU_ALIAS) - cd $(TOOLCHAIN_DIR) && ln -sfn $(GCC_SYM_DIR) $(GCC_ALIAS) - -distclean: clean - rm -rf $(TOOLCHAIN_DIR) - -.PHONY: all toolchain +.PHONY: all diff --git a/kern/ispinlock.h b/kern/ispinlock.h index e30d4b6..d71af17 100644 --- a/kern/ispinlock.h +++ b/kern/ispinlock.h @@ -1,5 +1,5 @@ #pragma once -#include +#include typedef struct { volatile uint32_t v; // 0 = unlocked, 1 = locked diff --git a/kern/libkern/mini-printf.c b/kern/libkern/mini-printf.c deleted file mode 100644 index ec0ff14..0000000 --- a/kern/libkern/mini-printf.c +++ /dev/null @@ -1,311 +0,0 @@ -/* - * The Minimal snprintf() implementation - * - * Copyright (c) 2013,2014 Michal Ludvig - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the auhor nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * ---- - * - * This is a minimal snprintf() implementation optimised - * for embedded systems with a very limited program memory. - * mini_snprintf() doesn't support _all_ the formatting - * the glibc does but on the other hand is a lot smaller. - * Here are some numbers from my STM32 project (.bin file size): - * no snprintf(): 10768 bytes - * mini snprintf(): 11420 bytes (+ 652 bytes) - * glibc snprintf(): 34860 bytes (+24092 bytes) - * Wasting nearly 24kB of memory just for snprintf() on - * a chip with 32kB flash is crazy. Use mini_snprintf() instead. - * - */ - -#include "mini-printf.h" - -static int -mini_strlen(const char *s) -{ - int len = 0; - while (s[len] != '\0') len++; - return len; -} - -static int -mini_itoa(long value, unsigned int radix, int uppercase, int unsig, - char *buffer) -{ - char *pbuffer = buffer; - int negative = 0; - int i, len; - - /* No support for unusual radixes. */ - if (radix > 16) - return 0; - - if (value < 0 && !unsig) { - negative = 1; - value = -value; - } - - /* This builds the string back to front ... */ - do { - int digit = value % radix; - *(pbuffer++) = (digit < 10 ? '0' + digit : (uppercase ? 'A' : 'a') + digit - 10); - value /= radix; - } while (value > 0); - - if (negative) - *(pbuffer++) = '-'; - - *(pbuffer) = '\0'; - - /* ... now we reverse it (could do it recursively but will - * conserve the stack space) */ - len = (pbuffer - buffer); - for (i = 0; i < len / 2; i++) { - char j = buffer[i]; - buffer[i] = buffer[len-i-1]; - buffer[len-i-1] = j; - } - - return len; -} - -static int -mini_pad(char* ptr, int len, char pad_char, int pad_to, char *buffer) -{ - int i; - int overflow = 0; - char * pbuffer = buffer; - if(pad_to == 0) pad_to = len; - if(len > pad_to) { - len = pad_to; - overflow = 1; - } - for(i = pad_to - len; i > 0; i --) { - *(pbuffer++) = pad_char; - } - for(i = len; i > 0; i --) { - *(pbuffer++) = *(ptr++); - } - len = pbuffer - buffer; - if(overflow) { - for (i = 0; i < 3 && pbuffer > buffer; i ++) { - *(pbuffer-- - 1) = '*'; - } - } - return len; -} - -struct mini_buff { - char *buffer, *pbuffer; - unsigned int buffer_len; -}; - -static int -_puts(char *s, int len, void *buf) -{ - if(!buf) return len; - struct mini_buff *b = buf; - char * p0 = b->buffer; - int i; - /* Copy to buffer */ - for (i = 0; i < len; i++) { - if(b->pbuffer == b->buffer + b->buffer_len - 1) { - break; - } - *(b->pbuffer ++) = s[i]; - } - *(b->pbuffer) = 0; - return b->pbuffer - p0; -} - -#ifdef MINI_PRINTF_ENABLE_OBJECTS -static int (*mini_handler) (void* data, void* obj, int ch, int lhint, char** bf) = 0; -static void (*mini_handler_freeor)(void* data, void*) = 0; -static void * mini_handler_data = 0; - -void mini_printf_set_handler( - void* data, - int (*handler)(void* data, void* obj, int ch, int len_hint, char** buf), - void (*freeor)(void* data, void* buf)) -{ - mini_handler = handler; - mini_handler_freeor = freeor; - mini_handler_data = data; -} -#endif - -int -mini_vsnprintf(char *buffer, unsigned int buffer_len, const char *fmt, va_list va) -{ - struct mini_buff b; - b.buffer = buffer; - b.pbuffer = buffer; - b.buffer_len = buffer_len; - if(buffer_len == 0) buffer = (void*) 0; - int n = mini_vpprintf(_puts, (buffer != (void*)0)?&b:(void*)0, fmt, va); - if(buffer == (void*) 0) { - return n; - } - return b.pbuffer - b.buffer; -} - -int -mini_vpprintf(int (*puts)(char* s, int len, void* buf), void* buf, const char *fmt, va_list va) -{ - char bf[24]; - char bf2[24]; - char ch; -#ifdef MINI_PRINTF_ENABLE_OBJECTS - void* obj; -#endif - if(puts == (void*)0) { - /* run puts in counting mode. */ - puts = _puts; buf = (void*)0; - } - int n = 0; - while ((ch=*(fmt++))) { - int len; - if (ch!='%') { - len = 1; - len = puts(&ch, len, buf); - } else { - char pad_char = ' '; - int pad_to = 0; - char l = 0; - char *ptr; - - ch=*(fmt++); - - /* Zero padding requested */ - if (ch == '0') pad_char = '0'; - while (ch >= '0' && ch <= '9') { - pad_to = pad_to * 10 + (ch - '0'); - ch=*(fmt++); - } - if(pad_to > (signed int) sizeof(bf)) { - pad_to = sizeof(bf); - } - if (ch == 'l') { - l = 1; - ch=*(fmt++); - } - - switch (ch) { - case 0: - goto end; - case 'u': - case 'd': - if(l) { - len = mini_itoa(va_arg(va, unsigned long), 10, 0, (ch=='u'), bf2); - } else { - if(ch == 'u') { - len = mini_itoa((unsigned long) va_arg(va, unsigned int), 10, 0, 1, bf2); - } else { - len = mini_itoa((long) va_arg(va, int), 10, 0, 0, bf2); - } - } - len = mini_pad(bf2, len, pad_char, pad_to, bf); - len = puts(bf, len, buf); - break; - - case 'x': - case 'X': - if(l) { - len = mini_itoa(va_arg(va, unsigned long), 16, (ch=='X'), 1, bf2); - } else { - len = mini_itoa((unsigned long) va_arg(va, unsigned int), 16, (ch=='X'), 1, bf2); - } - len = mini_pad(bf2, len, pad_char, pad_to, bf); - len = puts(bf, len, buf); - break; - - case 'c' : - ch = (char)(va_arg(va, int)); - len = mini_pad(&ch, 1, pad_char, pad_to, bf); - len = puts(bf, len, buf); - break; - - case 's' : - ptr = va_arg(va, char*); - len = mini_strlen(ptr); - if (pad_to > 0) { - len = mini_pad(ptr, len, pad_char, pad_to, bf); - len = puts(bf, len, buf); - } else { - len = puts(ptr, len, buf); - } - break; -#ifdef MINI_PRINTF_ENABLE_OBJECTS - case 'O' : /* Object by content (e.g. str) */ - case 'R' : /* Object by representation (e.g. repr)*/ - obj = va_arg(va, void*); - len = mini_handler(mini_handler_data, obj, ch, pad_to, &ptr); - if (pad_to > 0) { - len = mini_pad(ptr, len, pad_char, pad_to, bf); - len = puts(bf, len, buf); - } else { - len = puts(ptr, len, buf); - } - mini_handler_freeor(mini_handler_data, ptr); - break; -#endif - default: - len = 1; - len = puts(&ch, len, buf); - break; - } - } - n = n + len; - } -end: - return n; -} - - -int -mini_snprintf(char* buffer, unsigned int buffer_len, const char *fmt, ...) -{ - int ret; - va_list va; - va_start(va, fmt); - ret = mini_vsnprintf(buffer, buffer_len, fmt, va); - va_end(va); - - return ret; -} - -int -mini_pprintf(int (*puts)(char*s, int len, void* buf), void* buf, const char *fmt, ...) -{ - int ret; - va_list va; - va_start(va, fmt); - ret = mini_vpprintf(puts, buf, fmt, va); - va_end(va); - - return ret; -} - diff --git a/kern/libkern/mini-printf.h b/kern/libkern/mini-printf.h deleted file mode 100644 index 7667b50..0000000 --- a/kern/libkern/mini-printf.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * The Minimal snprintf() implementation - * - * Copyright (c) 2013 Michal Ludvig - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the auhor nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - -#ifndef __MINI_PRINTF__ -#define __MINI_PRINTF__ - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -#ifdef MINI_PRINTF_ENABLE_OBJECTS -/* If enabled, callback for object types (O and R). - * void* arguments matching %O and %R are sent to handler as obj. - * the result string created by handler at *buf is freed by freeor. - * */ -void mini_printf_set_handler( - void * data, - /* handler returns number of chars in *buf; *buf is not NUL-terminated. */ - int (*handler)(void* data, void* obj, int ch, int len_hint, char** buf), - void (*freeor)(void* data, void* buf)); -#endif - -/* String IO interface; returns number of bytes written, not including the ending NUL. - * Always appends a NUL at the end, therefore buffer_len shall be at least 1 in normal operation. - * If buffer is NULL or buffer_len is 0, returns number of bytes to be written, not including the ending NUL. - */ -int mini_vsnprintf(char* buffer, unsigned int buffer_len, const char *fmt, va_list va); -int mini_snprintf(char* buffer, unsigned int buffer_len, const char *fmt, ...); - -/* Stream IO interface; returns number of bytes written. - * If puts is NULL, number of bytes to be written. - * puts shall return number of bytes written. - */ -int mini_vpprintf(int (*puts)(char* s, int len, void* buf), void* buf, const char *fmt, va_list va); -int mini_pprintf(int (*puts)(char*s, int len, void* buf), void* buf, const char *fmt, ...); - -#ifdef __cplusplus -} -#endif - -#define vsnprintf mini_vsnprintf -#define snprintf mini_snprintf - -#endif diff --git a/kern/libkern/stdarg.h b/kern/libkern/stdarg.h deleted file mode 100644 index 1113127..0000000 --- a/kern/libkern/stdarg.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _STDARG_H -#define _STDARG_H - -typedef __builtin_va_list va_list; - -#define va_start(ap, last) __builtin_va_start(ap, last) -#define va_arg(ap, type) __builtin_va_arg(ap, type) -#define va_end(ap) __builtin_va_end(ap) -#define va_copy(dest, src) __builtin_va_copy(dest, src) - -#endif diff --git a/kern/libkern/string.c b/kern/libkern/string.c index e6c0000..99a0ea2 100644 --- a/kern/libkern/string.c +++ b/kern/libkern/string.c @@ -114,112 +114,14 @@ void *memset(void *dest, int c, size_t n) { return dest; } -// int memcmp(const void *s1, const void *s2, size_t n) { -// if (n != 0) { -// const unsigned char *p1 = s1, *p2 = s2; -// -// do { -// if (*p1++ != *p2++) -// return (*--p1 - *--p2); -// } while (--n != 0); -// } -// return (0); -// } +int memcmp(const void *s1, const void *s2, size_t n) { + if (n != 0) { + const unsigned char *p1 = s1, *p2 = s2; -char *itoa(int value, char *str, int base) { - char *p = str; - char *p1, *p2; - unsigned int uvalue = value; - int negative = 0; - - if (base < 2 || base > 36) { - *str = '\0'; - return str; + do { + if (*p1++ != *p2++) + return (*--p1 - *--p2); + } while (--n != 0); } - - if (value < 0 && base == 10) { - negative = 1; - uvalue = -value; - } - - // Convert to string - do { - int digit = uvalue % base; - *p++ = (digit < 10) ? '0' + digit : 'a' + (digit - 10); - uvalue /= base; - } while (uvalue); - - if (negative) - *p++ = '-'; - - *p = '\0'; - - // Reverse string - p1 = str; - p2 = p - 1; - while (p1 < p2) { - char tmp = *p1; - *p1++ = *p2; - *p2-- = tmp; - } - - return str; -} - -// void *memset(void *dst, int c, size_t length) { -// u8 *ptr = (u8 *)dst; -// const u8 value = (u8)c; -// -// while (length--) *(ptr++) = value; -// -// return dst; -// } - -// void *memcpy(void *dst, const void *src, size_t len) { -// u8 *d = (u8 *)dst; -// const u8 *s = (const u8 *)src; -// for (size_t i = 0; i < len; i++) { -// d[i] = s[i]; -// } -// return dst; -// } - -// void *memmove(void *dst, const void *src, size_t len) { -// u8 *d = (u8 *)dst; -// const u8 *s = (const u8 *)src; -// if (d < s) { -// for (size_t i = 0; i < len; i++) { -// d[i] = s[i]; -// } -// } else if (d > s) { -// for (size_t i = len; i > 0; i--) { -// d[i - 1] = s[i - 1]; -// } -// } -// return dst; -// } - -int memcmp(const void *s1, const void *s2, size_t len) { - const u8 *a = (const u8 *)s1; - const u8 *b = (const u8 *)s2; - for (size_t i = 0; i < len; i++) { - if (a[i] != b[i]) { - return (int)a[i] - (int)b[i]; - } - } - return 0; -} - -size_t strlen(const char *s) { - const char *p = s; - while (*p) ++p; - return (size_t)(p - s); -} - -size_t strnlen(const char *s, size_t maxlen) { - size_t len = 0; - while (len < maxlen && s[len] != '\0') { - len++; - } - return len; + return (0); } diff --git a/kern/libkern/string.h b/kern/libkern/string.h index d2ff7b5..01d3853 100644 --- a/kern/libkern/string.h +++ b/kern/libkern/string.h @@ -1,45 +1,7 @@ -#ifndef KERNEL_STRING_H -#define KERNEL_STRING_H +#pragma once +#include -#include - -// void *memcpy(void *s1, const void *s2, size_t n); -// void *memmove(void *s1, const void *s2, size_t n); -// void *memset(void *dest, int c, size_t n); -// int memcmp(const void *s1, const void *s2, size_t n); - -/** Integer to ascii */ -char *itoa(int value, char *str, int base); - -/** Fill memory with constant byte */ -void *memset(void *dst, int c, size_t len); - -/** Copy `len` bytes from `src` to `dst`. Undefined if regions overlap. */ -void *memcpy(void *dst, const void *src, size_t len); - -/** Copy `len` bytes from `src` to `dst`, safe for overlapping regions. */ -void *memmove(void *dst, const void *src, size_t len); - -/** Compare `len` bytes of `s1` and `s2`. - * Returns 0 if equal, <0 if s1 < s2, >0 if s1 > s2. */ -int memcmp(const void *s1, const void *s2, size_t len); - -/** Returns the length of a null-terminated string */ -size_t strlen(const char *s); - -/** Return length of string `s`, up to a max of `maxlen` bytes */ -size_t strnlen(const char *s, size_t maxlen); - -// TODO: These: -/* -int strcmp(const char *s1, const char *s2); -int strncmp(const char *s1, const char *s2, size_t n); - -char *strcpy(char *dst, const char *src); -char *strncpy(char *dst, const char *src, size_t n); - -char *strchr(const char *s, int c); -char *strrchr(const char *s, int c); -*/ - -#endif +void *memcpy(void *s1, const void *s2, size_t n); +void *memmove(void *s1, const void *s2, size_t n); +void *memset(void *dest, int c, size_t n); +int memcmp(const void *s1, const void *s2, size_t n); diff --git a/kern/proc.h b/kern/proc.h index 26659f3..b594fc9 100644 --- a/kern/proc.h +++ b/kern/proc.h @@ -1,6 +1,3 @@ -#include -#include -#include #include typedef enum { @@ -40,7 +37,6 @@ struct Cpu { int intena; // Were interrupts enabled before push_off()? }; -/** Saved registers for kernel context switches. */ typedef struct { /* 0 */ uint64_t kernel_satp; // kernel page table /* 8 */ uint64_t kernel_sp; // top of process's kernel stack @@ -79,10 +75,3 @@ typedef struct { /* 272 */ uint64_t t5; /* 280 */ uint64_t t6; } TrapFrame_t; - -struct Cpu *mycpu(void); - -extern struct Cpu cpus[NCPU]; - -/** Per-process state */ -struct Proc {}; diff --git a/kern/libkern/endian.h b/lib/endian.h similarity index 100% rename from kern/libkern/endian.h rename to lib/endian.h diff --git a/kern/libkern/memory.c b/lib/memory.c similarity index 100% rename from kern/libkern/memory.c rename to lib/memory.c diff --git a/kern/libkern/memory.h b/lib/memory.h similarity index 94% rename from kern/libkern/memory.h rename to lib/memory.h index 01b275a..8a012a2 100644 --- a/kern/libkern/memory.h +++ b/lib/memory.h @@ -1,7 +1,7 @@ #ifndef MEMORY_KERNEL_H #define MEMORY_KERNEL_H -#include +#include /* These are hardcoded for now */ #define KERNBASE 0x80000000L diff --git a/kern/libkern/panic.c b/lib/panic.c similarity index 100% rename from kern/libkern/panic.c rename to lib/panic.c diff --git a/kern/libkern/panic.h b/lib/panic.h similarity index 100% rename from kern/libkern/panic.h rename to lib/panic.h diff --git a/kern/libkern/proc.c b/lib/proc.c similarity index 100% rename from kern/libkern/proc.c rename to lib/proc.c diff --git a/lib/proc.h b/lib/proc.h new file mode 100644 index 0000000..1208b2b --- /dev/null +++ b/lib/proc.h @@ -0,0 +1,22 @@ +#include +#include +#include +#include + +struct Cpu *mycpu(void); + +/** Saved registers for kernel context switches. */ +struct Context {}; + +/** Per-CPU state. */ +struct Cpu { + struct Proc *proc; // The process running on this cpu, or null. + struct Context context; // swtch() here to enter scheduler(). + int noff; // Depth of push_off() nesting. + int intena; // Were interrupts enabled before push_off()? +}; + +extern struct Cpu cpus[NCPU]; + +/** Per-process state */ +struct Proc {}; diff --git a/kern/libkern/spinlock.c b/lib/spinlock.c similarity index 100% rename from kern/libkern/spinlock.c rename to lib/spinlock.c diff --git a/kern/libkern/spinlock.h b/lib/spinlock.h similarity index 98% rename from kern/libkern/spinlock.h rename to lib/spinlock.h index 9629e60..eb4f4b3 100644 --- a/kern/libkern/spinlock.h +++ b/lib/spinlock.h @@ -1,7 +1,7 @@ #ifndef KERNEL_Spinlock_H #define KERNEL_Spinlock_H -#include +#include "types.h" /** Mutual exclusion spin lock */ struct Spinlock { diff --git a/lib/string.c b/lib/string.c new file mode 100644 index 0000000..69fb5c7 --- /dev/null +++ b/lib/string.c @@ -0,0 +1,99 @@ +#include + +char *itoa(int value, char *str, int base) { + char *p = str; + char *p1, *p2; + unsigned int uvalue = value; + int negative = 0; + + if (base < 2 || base > 36) { + *str = '\0'; + return str; + } + + if (value < 0 && base == 10) { + negative = 1; + uvalue = -value; + } + + // Convert to string + do { + int digit = uvalue % base; + *p++ = (digit < 10) ? '0' + digit : 'a' + (digit - 10); + uvalue /= base; + } while (uvalue); + + if (negative) + *p++ = '-'; + + *p = '\0'; + + // Reverse string + p1 = str; + p2 = p - 1; + while (p1 < p2) { + char tmp = *p1; + *p1++ = *p2; + *p2-- = tmp; + } + + return str; +} + +void *memset(void *dst, int c, size_t length) { + u8 *ptr = (u8 *)dst; + const u8 value = (u8)c; + + while (length--) *(ptr++) = value; + + return dst; +} + +void *memcpy(void *dst, const void *src, size_t len) { + u8 *d = (u8 *)dst; + const u8 *s = (const u8 *)src; + for (size_t i = 0; i < len; i++) { + d[i] = s[i]; + } + return dst; +} + +void *memmove(void *dst, const void *src, size_t len) { + u8 *d = (u8 *)dst; + const u8 *s = (const u8 *)src; + if (d < s) { + for (size_t i = 0; i < len; i++) { + d[i] = s[i]; + } + } else if (d > s) { + for (size_t i = len; i > 0; i--) { + d[i - 1] = s[i - 1]; + } + } + return dst; +} + +int memcmp(const void *s1, const void *s2, size_t len) { + const u8 *a = (const u8 *)s1; + const u8 *b = (const u8 *)s2; + for (size_t i = 0; i < len; i++) { + if (a[i] != b[i]) { + return (int)a[i] - (int)b[i]; + } + } + return 0; +} + +size_t strlen(const char *s) { + const char *p = s; + while (*p) ++p; + return (size_t)(p - s); +} + +size_t strnlen(const char *s, size_t maxlen) { + size_t len = 0; + while (len < maxlen && s[len] != '\0') { + len++; + } + return len; +} diff --git a/lib/string.h b/lib/string.h new file mode 100644 index 0000000..00805c7 --- /dev/null +++ b/lib/string.h @@ -0,0 +1,40 @@ +#ifndef KERNEL_STRING_H +#define KERNEL_STRING_H + +#include + +/** Integer to ascii */ +char *itoa(int value, char *str, int base); + +/** Fill memory with constant byte */ +void *memset(void *dst, int c, size_t len); + +/** Copy `len` bytes from `src` to `dst`. Undefined if regions overlap. */ +void *memcpy(void *dst, const void *src, size_t len); + +/** Copy `len` bytes from `src` to `dst`, safe for overlapping regions. */ +void *memmove(void *dst, const void *src, size_t len); + +/** Compare `len` bytes of `s1` and `s2`. + * Returns 0 if equal, <0 if s1 < s2, >0 if s1 > s2. */ +int memcmp(const void *s1, const void *s2, size_t len); + +/** Returns the length of a null-terminated string */ +size_t strlen(const char *s); + +/** Return length of string `s`, up to a max of `maxlen` bytes */ +size_t strnlen(const char *s, size_t maxlen); + +// TODO: These: +/* +int strcmp(const char *s1, const char *s2); +int strncmp(const char *s1, const char *s2, size_t n); + +char *strcpy(char *dst, const char *src); +char *strncpy(char *dst, const char *src, size_t n); + +char *strchr(const char *s, int c); +char *strrchr(const char *s, int c); +*/ + +#endif diff --git a/kern/libkern/uart.c b/lib/uart.c similarity index 100% rename from kern/libkern/uart.c rename to lib/uart.c diff --git a/kern/libkern/uart.h b/lib/uart.h similarity index 100% rename from kern/libkern/uart.h rename to lib/uart.h diff --git a/kern/libkern/riscv.h b/riscv.h similarity index 98% rename from kern/libkern/riscv.h rename to riscv.h index ddc19e7..d56bdce 100644 --- a/kern/libkern/riscv.h +++ b/riscv.h @@ -1,7 +1,7 @@ #ifndef RISCV_KERNEL_H #define RISCV_KERNEL_H -#include +#include /** Page Size */ #define PGSIZE 4096 // bytes per page diff --git a/start.c b/start.c index 10503d1..d0b47c5 100644 --- a/start.c +++ b/start.c @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include /** diff --git a/kern/libkern/stdint.h b/types.h similarity index 94% rename from kern/libkern/stdint.h rename to types.h index 37c912f..69e74d4 100644 --- a/kern/libkern/stdint.h +++ b/types.h @@ -13,4 +13,4 @@ typedef uint64_t size_t; typedef uint64_t uintptr_t; -// typedef u8 bool; +typedef u8 bool;