diff --git a/.gitignore b/.gitignore index 0ce05f9..50096ff 100644 --- a/.gitignore +++ b/.gitignore @@ -1,93 +1,8 @@ -# Created by https://www.toptal.com/developers/gitignore/api/cmake,clion+all -# Edit at https://www.toptal.com/developers/gitignore?templates=cmake,clion+all - -### CLion+all ### -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider -# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 - -# User-specific stuff -.idea/**/workspace.xml -.idea/**/tasks.xml -.idea/**/usage.statistics.xml -.idea/**/dictionaries -.idea/**/shelf - -# AWS User-specific -.idea/**/aws.xml - -# Generated files -.idea/**/contentModel.xml - -# Sensitive or high-churn files -.idea/**/dataSources/ -.idea/**/dataSources.ids -.idea/**/dataSources.local.xml -.idea/**/sqlDataSources.xml -.idea/**/dynamic.xml -.idea/**/uiDesigner.xml -.idea/**/dbnavigator.xml - -# Gradle -.idea/**/gradle.xml -.idea/**/libraries - -# Gradle and Maven with auto-import -# When using Gradle or Maven with auto-import, you should exclude module files, -# since they will be recreated, and may cause churn. Uncomment if using -# auto-import. -# .idea/artifacts -# .idea/compiler.xml -# .idea/jarRepositories.xml -# .idea/modules.xml -# .idea/*.iml -# .idea/modules -# *.iml -# *.ipr # CMake cmake-build-*/ -# Mongo Explorer plugin -.idea/**/mongoSettings.xml - -# File-based project format -*.iws - -# IntelliJ -out/ - -# mpeltonen/sbt-idea plugin -.idea_modules/ - -# JIRA plugin -atlassian-ide-plugin.xml - -# Cursive Clojure plugin -.idea/replstate.xml - -# SonarLint plugin -.idea/sonarlint/ - -# Crashlytics plugin (for Android Studio and IntelliJ) -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties -fabric.properties - -# Editor-based Rest Client -.idea/httpRequests - -# Android studio 3.1+ serialized cache file -.idea/caches/build_file_checksums.ser - -### CLion+all Patch ### -# Ignore everything but code style settings and run configurations -# that are supposed to be shared within teams. - -.idea/* - -!.idea/codeStyles -!.idea/runConfigurations +.idea/ ### CMake ### CMakeLists.txt.user diff --git a/CMakeLists.txt b/CMakeLists.txt index c2c81be..0119496 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,7 @@ -project(yak) -cmake_minimum_required() +project(yak C ASM) +cmake_minimum_required(VERSION 3.24.0) + +include(FetchContent) add_subdirectory(yak-kernel) diff --git a/run-qemu.sh b/run-qemu.sh index 420009e..4bab7ec 100755 --- a/run-qemu.sh +++ b/run-qemu.sh @@ -2,4 +2,4 @@ ISO=${1} -qemu-system-x86_64 -bios /usr/share/ovmf/x64/OVMF.fd -cdrom "${ISO}" #-S -s -d guest_errors \ No newline at end of file +qemu-system-x86_64 -bios /usr/share/ovmf/x64/OVMF.fd -cdrom "${ISO}" -S -s -d guest_errors \ No newline at end of file diff --git a/yak-kernel/CMakeLists.txt b/yak-kernel/CMakeLists.txt index 91d49a5..a41740b 100644 --- a/yak-kernel/CMakeLists.txt +++ b/yak-kernel/CMakeLists.txt @@ -1,27 +1,57 @@ project(yak-kernel) -set(CMAKE_C_FLAGS " - -ffreestanding \ - -fno-stack-protector \ - -fno-stack-check \ - -fno-lto \ - -fno-pie \ - -fno-pic \ - -m64 \ - -march=x86-64 \ - -mabi=sysv \ - -mno-80387 \ - -mno-mmx \ - -mno-sse \ - -mno-sse2 \ - -mno-red-zone \ - -mcmodel=kernel") -set(CMAKE_EXE_LINKER_FLAGS " - -nostdlib \ - -static \ - -z max-page-size=0x1000 \ - -T ${CMAKE_CURRENT_SOURCE_DIR}/linker.lds") +set(CMAKE_SYSROOT "/does-not-exist") -include_directories(../limine/include) +option(USE_LIMINE "Enable support for the limine boot protocol" ON) -add_executable(yak.elf main.c) \ No newline at end of file +add_compile_options( + -ffreestanding + -fno-lto + -fno-pie + -fno-pic + -m64 + --target=x86_64-pc-none-eabi + -mno-80387 + -mno-mmx + -mno-sse + -mno-sse2 + -mno-red-zone + -mcmodel=kernel +) +add_link_options( + -nostdlib + -static + -z max-page-size=0x1000 + -T ${CMAKE_CURRENT_SOURCE_DIR}/linker.lds +) + +FetchContent_Declare(printf_library + GIT_REPOSITORY https://github.com/eyalroz/printf.git + GIT_TAG v6.1.0) +FetchContent_GetProperties(printf_library) +if (NOT printf_library_POPULATED) + FetchContent_Populate(printf_library) +endif () + + +if (NOT ${USE_LIMINE}) + message(FATAL_ERROR "At least one boot protocol is required") +endif () + +file(GLOB KERNEL_SOURCES src/rt/*.c src/ulibc/*.c) +file(GLOB PLATFORM_GENERIC_SOURCES src/platform/generic/*.c) + +if (${USE_LIMINE}) + file(GLOB LIMINE_KERNEL_SOURCES src/rt/limine/*.c) +endif () +if (NOT IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/${CMAKE_SYSTEM_PROCESSOR}) + message(FATAL_ERROR "Unknown architecture ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/${CMAKE_SYSTEM_PROCESSOR}") +endif () + +file(GLOB PLATFORM_SPECIFIC_SOURCES src/platform/x86_64/*.c) + +set(KERNEL_SOURCE_FILES ${KERNEL_SOURCES} ${LIMINE_KERNEL_SOURCES} ${PLATFORM_GENERIC_SOURCES} ${PLATFORM_SPECIFIC_SOURCES}) + +add_executable(yak.elf ${KERNEL_SOURCE_FILES}) +target_link_libraries(yak.elf PRIVATE /usr/lib/clang/15.0.7/lib/linux/libclang_rt.builtins-x86_64.a) +target_include_directories(yak.elf PRIVATE include ../limine/include ${printf_library_SOURCE_DIR}/src)# ${printf_library_SOURCE_DIR}/src) \ No newline at end of file diff --git a/yak-kernel/include/errno.h b/yak-kernel/include/errno.h new file mode 100644 index 0000000..c97247a --- /dev/null +++ b/yak-kernel/include/errno.h @@ -0,0 +1,45 @@ +// +// Created by rick on 10-03-21. +// + +#ifndef NEW_KERNEL_ERRNO_H +#define NEW_KERNEL_ERRNO_H + +extern int errno; + +#define EPERM 1 /* Operation not permitted */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* I/O error */ +#define ENXIO 6 /* No such device or address */ +#define E2BIG 7 /* Argument list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file number */ +#define ECHILD 10 /* No child processes */ +#define EAGAIN 11 /* Try again */ +#define ENOMEM 12 /* Out of memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Device or resource busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* No such device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* File table overflow */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Not a typewriter */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#define EDOM 33 /* Math argument out of domain of func */ +#define ERANGE 34 /* Math result not representable */ + +#endif //NEW_KERNEL_ERRNO_H diff --git a/yak-kernel/include/stdio.h b/yak-kernel/include/stdio.h new file mode 100644 index 0000000..ea535cb --- /dev/null +++ b/yak-kernel/include/stdio.h @@ -0,0 +1,2 @@ +#define PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_SOFT 1 +#include diff --git a/yak-kernel/include/stdlib.h b/yak-kernel/include/stdlib.h new file mode 100644 index 0000000..31b6d00 --- /dev/null +++ b/yak-kernel/include/stdlib.h @@ -0,0 +1,37 @@ +// +// Created by rick on 10-03-21. +// + +#ifndef NEW_KERNEL_STDLIB_H +#define NEW_KERNEL_STDLIB_H + +#include +#include + +void __attribute__((__noreturn__)) abort(); + +int atexit(void (*)(void)); + +int atoi(const char *); + +char *itoa(uint32_t value, char *buffer, int base); + +char *getenv(const char *); + +int abs(int val); + +long labs(long val); + +long long llabs(long long val); + +void qsort(void *base, size_t num, size_t size, int (*compar)(const void *, const void *)); + +long strtol(const char *nptr, char **endptr, int base); + +void *malloc(size_t size); +void free(void *ptr); +void *calloc(size_t nmemb, size_t size); +void *realloc(void *ptr, size_t size); +void *reallocarray(void *ptr, size_t nmemb, size_t size); + +#endif //NEW_KERNEL_STDLIB_H diff --git a/yak-kernel/include/string.h b/yak-kernel/include/string.h new file mode 100644 index 0000000..0335373 --- /dev/null +++ b/yak-kernel/include/string.h @@ -0,0 +1,40 @@ +// +// Created by rick on 01-02-21. +// + +#ifndef NEW_KERNEL_STRING_H +#define NEW_KERNEL_STRING_H + +#include + +void *memcpy(void *dst, const void *src, size_t amount); + +void *memset(void *dst, int data, size_t amount); + +void *memmove(void *dst, const void *src, size_t amount); + +void *strcpy(char *dst, const char *src); + +void *strncpy(char *dst, const char *src, size_t n); + +size_t strlen(const char *str); + +char *strchr(const char *s, char c); + +char *strrchr(const char *s, char c); + +int memcmp(const void *s1, const void *s2, size_t n); + +int strcmp(const char *s1, const char *s2); + +int strncmp(const char *s1, const char *s2, size_t n); + +char *strdup(const char *s); + +char *strndup(const char *s, size_t n); + +char *strcat(char *dest, const char *src); + +char *strncat(char *dest, const char *src, size_t n); + +#endif //NEW_KERNEL_STRING_H diff --git a/yak-kernel/include/sys/param.h b/yak-kernel/include/sys/param.h new file mode 100644 index 0000000..af798a6 --- /dev/null +++ b/yak-kernel/include/sys/param.h @@ -0,0 +1,11 @@ +// +// Created by rick on 10-03-21. +// + +#ifndef NEW_KERNEL_PARAM_H +#define NEW_KERNEL_PARAM_H + +#define MIN(a, b) (((a)<(b))?(a):(b)) +#define MAX(a, b) (((a)>(b))?(a):(b)) + +#endif //NEW_KERNEL_PARAM_H diff --git a/yak-kernel/include/sys/types.h b/yak-kernel/include/sys/types.h new file mode 100644 index 0000000..80aae26 --- /dev/null +++ b/yak-kernel/include/sys/types.h @@ -0,0 +1,16 @@ +/* + * types.h + * + * Created on: Nov 1, 2018 + * Author: rick + */ + +#ifndef KERNEL_LIBC_TYPES_H_ +#define KERNEL_LIBC_TYPES_H_ + +#include +#include + +typedef int pid_t; + +#endif /* KERNEL_LIBC_TYPES_H_ */ diff --git a/yak-kernel/include/yak/platform/generic/platform.h b/yak-kernel/include/yak/platform/generic/platform.h new file mode 100644 index 0000000..39a8283 --- /dev/null +++ b/yak-kernel/include/yak/platform/generic/platform.h @@ -0,0 +1,12 @@ +// +// Created by rick on 22-3-23. +// + +#ifndef YAK_PLATFORM_H +#define YAK_PLATFORM_H + +void platform_init(); + +void __attribute__((noreturn)) halt_forever(); + +#endif //YAK_PLATFORM_H diff --git a/yak-kernel/include/yak/rt/kmain.h b/yak-kernel/include/yak/rt/kmain.h new file mode 100644 index 0000000..e31254d --- /dev/null +++ b/yak-kernel/include/yak/rt/kmain.h @@ -0,0 +1,10 @@ +// +// Created by rick on 22-3-23. +// + +#ifndef YAK_KMAIN_H +#define YAK_KMAIN_H + +void kmain(); + +#endif //YAK_KMAIN_H diff --git a/yak-kernel/include/yak/rt/kprint.h b/yak-kernel/include/yak/rt/kprint.h new file mode 100644 index 0000000..abbaa4b --- /dev/null +++ b/yak-kernel/include/yak/rt/kprint.h @@ -0,0 +1,18 @@ +// +// Created by rick on 21-3-23. +// + +#ifndef YAK_KPRINT_H +#define YAK_KPRINT_H + +typedef void (*print_function)(char c); + +void kprint_now(char* msg); + +void kprint_putc_now(char c); + +void kprint_register(print_function print); + +void kprint_unregister(print_function print); + +#endif //YAK_KPRINT_H diff --git a/yak-kernel/include/yak/rt/panic.h b/yak-kernel/include/yak/rt/panic.h new file mode 100644 index 0000000..2d73ed9 --- /dev/null +++ b/yak-kernel/include/yak/rt/panic.h @@ -0,0 +1,10 @@ +// +// Created by rick on 21-3-23. +// + +#ifndef YAK_PANIC_H +#define YAK_PANIC_H + +void __attribute__((__noreturn__)) panic(char* reason); + +#endif //YAK_PANIC_H diff --git a/yak-kernel/linker.lds b/yak-kernel/linker.lds index ccdd7fb..10399e8 100644 --- a/yak-kernel/linker.lds +++ b/yak-kernel/linker.lds @@ -3,7 +3,7 @@ OUTPUT_FORMAT(elf64-x86-64) OUTPUT_ARCH(i386:x86-64) /* We want the symbol _start to be our entry point */ -ENTRY(_start) +ENTRY(kmain) /* Define the program headers we want so the bootloader gives us the right */ /* MMU permissions */ @@ -40,6 +40,10 @@ SECTIONS *(.data .data.*) } :data + .limine_reqs : { + *(.limine_reqs) + } :data + /* NOTE: .bss needs to be the last thing mapped to :data, otherwise lots of */ /* unnecessary zeros will be written to the binary. */ /* If you need, for example, .init_array and .fini_array, those should be placed */ diff --git a/yak-kernel/main.c b/yak-kernel/main.c deleted file mode 100644 index 84d7f71..0000000 --- a/yak-kernel/main.c +++ /dev/null @@ -1,107 +0,0 @@ -#include -#include -#include - -// The Limine requests can be placed anywhere, but it is important that -// the compiler does not optimise them away, so, usually, they should -// be made volatile or equivalent. - -static volatile struct limine_terminal_request terminal_request = { - .id = LIMINE_TERMINAL_REQUEST, - .revision = 0 -}; - -// GCC and Clang reserve the right to generate calls to the following -// 4 functions even if they are not directly called. -// Implement them as the C specification mandates. -// DO NOT remove or rename these functions, or stuff will eventually break! -// They CAN be moved to a different .c file. - -void *memcpy(void *dest, const void *src, size_t n) { - uint8_t *pdest = (uint8_t *) dest; - const uint8_t *psrc = (const uint8_t *) src; - - for (size_t i = 0; i < n; i++) { - pdest[i] = psrc[i]; - } - - return dest; -} - -void *memset(void *s, int c, size_t n) { - uint8_t *p = (uint8_t *) s; - - for (size_t i = 0; i < n; i++) { - p[i] = (uint8_t) c; - } - - return s; -} - -void *memmove(void *dest, const void *src, size_t n) { - uint8_t *pdest = (uint8_t *) dest; - const uint8_t *psrc = (const uint8_t *) src; - - if (src > dest) { - for (size_t i = 0; i < n; i++) { - pdest[i] = psrc[i]; - } - } else if (src < dest) { - for (size_t i = n; i > 0; i--) { - pdest[i - 1] = psrc[i - 1]; - } - } - - return dest; -} - -int memcmp(const void *s1, const void *s2, size_t n) { - const uint8_t *p1 = (const uint8_t *) s1; - const uint8_t *p2 = (const uint8_t *) s2; - - for (size_t i = 0; i < n; i++) { - if (p1[i] != p2[i]) { - return p1[i] < p2[i] ? -1 : 1; - } - } - - return 0; -} - -// Our quick and dirty strlen() implementation. -size_t strlen(const char *str) { - size_t ret = 0; - while (*str++) { - ret++; - } - return ret; -} - -// Halt and catch fire function. -static void hcf(void) { - __asm__ ("cli"); - for (;;) { - __asm__ ("hlt"); - } -} - -// The following will be our kernel's entry point. -// If renaming _start() to something else, make sure to change the -// linker script accordingly. -void _start(void) { - // Ensure we got a terminal - if (terminal_request.response == NULL - || terminal_request.response->terminal_count < 1) { - hcf(); - } - - // We should now be able to call the Limine terminal to print out - // a simple "Hello World" to screen. - const char *hello_msg = "Hello World"; - - struct limine_terminal *terminal = terminal_request.response->terminals[0]; - terminal_request.response->write(terminal, hello_msg, strlen(hello_msg)); - - // We're done, just hang... - hcf(); -} \ No newline at end of file diff --git a/yak-kernel/src/platform/x86_64/platform.c b/yak-kernel/src/platform/x86_64/platform.c new file mode 100644 index 0000000..9afcefa --- /dev/null +++ b/yak-kernel/src/platform/x86_64/platform.c @@ -0,0 +1,14 @@ +// +// Created by rick on 22-3-23. +// +#include +#include + +void platform_init() { + printf("Init X86_64"); +} + +void __attribute__((noreturn)) halt_forever() { + __asm__("cli"); + while (1) __asm__("hlt"); +} diff --git a/yak-kernel/src/rt/kmain.c b/yak-kernel/src/rt/kmain.c new file mode 100644 index 0000000..36bc581 --- /dev/null +++ b/yak-kernel/src/rt/kmain.c @@ -0,0 +1,13 @@ +#include +#include +#include "yak/platform/generic/platform.h" + +void kmain() { + // kmain is called from one of the bootloader implementations + + // perform platform specific initialisation + platform_init(); + + // this should (eventually) be unreachable + panic("End of kmain"); +} \ No newline at end of file diff --git a/yak-kernel/src/rt/kprint.c b/yak-kernel/src/rt/kprint.c new file mode 100644 index 0000000..bd67fad --- /dev/null +++ b/yak-kernel/src/rt/kprint.c @@ -0,0 +1,44 @@ +// +// Created by rick on 21-3-23. +// + +#include +#include + +#define MAX_PRINT_FUNCTIONS 8 + +print_function print_functions[MAX_PRINT_FUNCTIONS] = {0}; + +void kprint_now(char* msg) { + char* m = msg; + while (*m != 0) { + kprint_putc_now(*m); + m++; + } +} + +void kprint_putc_now(char c) { + for (int i = 0; i < MAX_PRINT_FUNCTIONS; ++i) { + if (print_functions[i] != NULL) { + print_functions[i](c); + } + } +} + +void kprint_register(print_function print) { + for (int i = 0; i < MAX_PRINT_FUNCTIONS; ++i) { + if (print_functions[i] == NULL) { + print_functions[i] = print; + break; + } + } +} + +void kprint_unregister(print_function print) { + for (int i = 0; i < MAX_PRINT_FUNCTIONS; ++i) { + if (print_functions[i] == print) { + print_functions[i] = NULL; + break; + } + } +} \ No newline at end of file diff --git a/yak-kernel/src/rt/limine/limine.c b/yak-kernel/src/rt/limine/limine.c new file mode 100644 index 0000000..83d3070 --- /dev/null +++ b/yak-kernel/src/rt/limine/limine.c @@ -0,0 +1,114 @@ +// +// Created by rick on 21-3-23. +// + +#include +#include +#include +#include +#include + +static struct limine_bootloader_info_request limine_bootloader_info_request = { + .id = LIMINE_BOOTLOADER_INFO_REQUEST, + .revision = 0, +}; + +static struct limine_framebuffer_request limine_framebuffer_request = { + .id = LIMINE_FRAMEBUFFER_REQUEST, + .revision = 0, +}; + +static struct limine_terminal_request limine_terminal_request = { + .id = LIMINE_TERMINAL_REQUEST, + .revision = 0 +}; + +// unused: 5 level paging +// unused: SMP + +struct limine_memmap_request limine_memmap_request = { + .id = LIMINE_MEMMAP_REQUEST, + .revision = 0, +}; + +void limine_init(); +struct limine_entry_point_request limine_entry_point_request = { + .id = LIMINE_ENTRY_POINT_REQUEST, + .revision = 0, + .entry = limine_init, +}; + +struct limine_kernel_file_request limine_kernel_file_request = { + .id = LIMINE_KERNEL_FILE_REQUEST, + .revision = 0, +}; + +struct limine_module_request limine_module_request = { + .id = LIMINE_MODULE_REQUEST, + .revision = 0, +}; + +struct limine_rsdp_request limine_rsdp_request = { + .id = LIMINE_RSDP_REQUEST, + .revision = 0, +}; + +struct limine_smbios_request limine_smbios_request = { + .id = LIMINE_SMBIOS_REQUEST, + .revision = 0, +}; + +struct limine_efi_system_table_request limine_efi_system_table_request = { + .id = LIMINE_EFI_SYSTEM_TABLE_REQUEST, + .revision = 0, +}; + +struct limine_boot_time_request limine_boot_time_request = { + .id = LIMINE_BOOT_TIME_REQUEST, + .revision = 0, +}; + +struct limine_kernel_address_request limine_kernel_address_request = { + .id = LIMINE_KERNEL_ADDRESS_REQUEST, + .revision = 0, +}; + +struct limine_dtb_request limine_dtb_request = { + .id = LIMINE_DTB_REQUEST, + .revision = 0, +}; + +static volatile __attribute__((used, section(".limine_reqs"))) void* limine_requests[] = { + &limine_bootloader_info_request, + &limine_framebuffer_request, + &limine_terminal_request, + &limine_memmap_request, + &limine_entry_point_request, + &limine_kernel_file_request, + &limine_module_request, + &limine_rsdp_request, + &limine_smbios_request, + &limine_efi_system_table_request, + &limine_boot_time_request, + &limine_kernel_address_request, + &limine_dtb_request, + NULL, +}; + +void limine_terminal_kprint(char c) { + limine_terminal_request.response->write(limine_terminal_request.response->terminals[0], &c, 1); +} + +void limine_init() { + if (limine_terminal_request.response != NULL && limine_terminal_request.response->terminal_count >= 1) { + kprint_register(limine_terminal_kprint); + } + + if (limine_bootloader_info_request.response != NULL) { + printf("Booted using limine from %s %s\n", limine_bootloader_info_request.response->name, limine_bootloader_info_request.response->version); + } else { + printf("Booted using limine from an unknown bootloader\n"); + } + + kmain(); +} diff --git a/yak-kernel/src/rt/panic.c b/yak-kernel/src/rt/panic.c new file mode 100644 index 0000000..87d8623 --- /dev/null +++ b/yak-kernel/src/rt/panic.c @@ -0,0 +1,15 @@ +// +// Created by rick on 21-3-23. +// + +#include +#include "yak/rt/kprint.h" +#include "yak/platform/generic/platform.h" + +void __attribute__((__noreturn__)) panic(char *reason) { + kprint_now(reason); + + // todo stack trace + + halt_forever(); +} \ No newline at end of file diff --git a/yak-kernel/src/rt/stack_protection.c b/yak-kernel/src/rt/stack_protection.c new file mode 100644 index 0000000..6e95703 --- /dev/null +++ b/yak-kernel/src/rt/stack_protection.c @@ -0,0 +1,21 @@ +// +// Created by rick on 21-3-23. +// + +#include + +#include + +#if UINT32_MAX == UINTPTR_MAX +#define STACK_CHK_GUARD 0xe2dee396 +#else +#define STACK_CHK_GUARD 0x595e9fbd94fda766 +#endif + +// todo this value should be unique every time the kernel starts +uintptr_t __stack_chk_guard = STACK_CHK_GUARD; + +void __attribute__((__noreturn__)) __stack_chk_fail() { + panic("Stack Smashed"); +} + diff --git a/yak-kernel/src/ulibc/printf.c b/yak-kernel/src/ulibc/printf.c new file mode 100644 index 0000000..dc6708c --- /dev/null +++ b/yak-kernel/src/ulibc/printf.c @@ -0,0 +1,10 @@ +// +// Created by rick on 21-3-23. +// +#include + +void putchar_(char c) { + kprint_putc_now(c); +} + +#include diff --git a/yak-kernel/src/ulibc/stdlib.c b/yak-kernel/src/ulibc/stdlib.c new file mode 100644 index 0000000..37fa7bc --- /dev/null +++ b/yak-kernel/src/ulibc/stdlib.c @@ -0,0 +1,131 @@ +/* + * libc.c + * + * Created on: Oct 11, 2018 + * Author: rick + */ + +#include +#include +#include + +/* everything of stdlib is implemented in this file except for: + * - qsort + **/ + + +int abs(int val) { + return val >= 0 ? val : (val * -1); +} + +long labs(long val) { + return val >= 0 ? val : (val * -1); +} + +long long llabs(long long val) { + return val >= 0 ? val : (val * -1); +} + +// next stolen form https://www.techiedelight.com/implement-itoa-function-in-c/ +// inline function to swapc two numbers +void swapc(char *x, char *y) { + char t = *x; + *x = *y; + *y = t; +} + +// function to reverse buffer[i..j] +char *reverse(char *buffer, int i, int j) { + while (i < j) + swapc(&buffer[i++], &buffer[j--]); + + return buffer; +} + +// Iterative function to implement itoa() function in C +char *itoa(uint32_t value, char *buffer, int base) { + // invalid input + if (base < 2 || base > 32) + return buffer; + + int i = 0; + while (value) { + uint32_t r = value % base; + + if (r >= 10) + buffer[i++] = 65 + (r - 10); + else + buffer[i++] = 48 + r; + + value = value / base; + } + + // if number is 0 + if (i == 0) + buffer[i++] = '0'; + + // If base is 10 and value is negative, the resulting string + // is preceded with a minus sign (-) + // With any other base, value is always considered unsigned + if (value < 0 && base == 10) + buffer[i++] = '-'; + + buffer[i] = '\0'; // null terminate string + + // reverse the string and return it + return reverse(buffer, 0, i - 1); +} + +long strtol(const char *nptr, char **endptr, int base) { + if (base > 36) { + errno = EINVAL; + return -1; + } + char sign = '+'; + long n = 0; + long i; + const char *c = nptr; + while (*c == ' ') { + c++; + } + if (*c == '+') { + c++; + } else if (*c == '-') { + sign = '-'; + c++; + } + while (*c != '\0') { + n *= base; + if (*c >= '0' && *c <= '9') { + i = *c - '0'; + } else if (*c >= 'a' && *c <= 'z') { + i = *c - 'a' + 10; + } else if (*c >= 'A' && *c <= 'Z') { + i = *c - 'A' + 10; + } else { + errno = EINVAL; + n = -1; + goto _set_endptr; + } + if (i >= base) { + errno = EINVAL; + n = -1; + goto _set_endptr; + } + if (i > (LONG_MAX - n)) { + errno = ERANGE; + n = sign == '-' ? LONG_MIN : LONG_MAX; + goto _set_endptr; + } + n += i; + c++; + } + if (sign == '-') { + n *= -1; + } + _set_endptr: + if (endptr != NULL) { + *endptr = c; + } + return n; +} diff --git a/yak-kernel/src/ulibc/string.c b/yak-kernel/src/ulibc/string.c new file mode 100644 index 0000000..24295e2 --- /dev/null +++ b/yak-kernel/src/ulibc/string.c @@ -0,0 +1,147 @@ +// +// Created by rick on 01-02-21. +// + +#include +#include +#include +#include + +void *memcpy(void *dst, const void *src, size_t amount) { + for (size_t i = 0; i < amount; i++) { + ((char *) dst)[i] = ((const char *) src)[i]; + } + return dst; +} + +void *memset(void *dst, int data, size_t amount) { + for (size_t i = 0; i < amount; ++i) { + ((char *) dst)[i] = (char) data; + } + return dst; +} + +void *memmove(void *dst, const void *src, size_t amount) { + void *tmp = malloc(amount); + if (tmp == NULL) { + return NULL; + } + memcpy(dst, memcpy(tmp, src, amount), amount); + free(tmp); + return dst; +} + +void *strcpy(char *dst, const char *src) { + return memcpy(dst, src, strlen(src) + 1); +} + +void *strncpy(char *dst, const char *src, size_t n) { + return memcpy(dst, src, MIN(strlen(src), n) + 1); +} + +size_t strlen(const char *str) { + int length = 0; + while (str[length] != 0) { + length++; + } + return length; +} + +int strcmp(const char *s1, const char *s2) { + size_t len1 = strlen(s1); + size_t len2 = strlen(s2); + return strncmp(s1, s2, MAX(len1, len2)); +} + +char *strchr(const char *s, char c) { + size_t index = 0; + while (1) { + if (s[index] == c) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wincompatible-pointer-types-discards-qualifiers" + return &s[index]; +#pragma clang diagnostic pop + } + if (s[index] == 0) { + return NULL; + } + index++; + } +} + +char *strrchr(const char *s, char c) { + size_t index = strlen(s); + while (1) { + if (s[index] == c) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wincompatible-pointer-types-discards-qualifiers" + return &s[index]; +#pragma clang diagnostic pop + } + if (index == 0) { + return NULL; + } + index--; + } +} + +int memcmp(const void *s1, const void *s2, size_t n) { + uint8_t a, b; + for (size_t i = 0; i < n; ++i) { + a = ((uint8_t *) s1)[i]; + b = ((uint8_t *) s2)[i]; + if (a > b) return 1; + if (a < b) return -1; + } + return 0; +} + +int strncmp(const char *s1, const char *s2, size_t n) { + for (size_t i = 0; i < n; ++i) { + if (s1[i] == 0 && s2[i] == 0) { + return 0; + } + if (s1[i] == 0) { + return -1; + } + if (s2[i] == 0) { + return 1; + } + if (s1[i] > s2[i]) { + return -1; + } + if (s1[i] < s2[i]) { + return 1; + } + } + return 0; +} + +char *strcat(char *dest, const char *src) { + size_t count = strlen(src); + return strncat(dest, src, count); +} + +char *strncat(char *dest, const char *src, size_t n) { + size_t start = strlen(dest); + for (size_t index = 0; index < n; index++) { + char val = src[index]; + dest[start + index] = val; + if (val == 0) { + dest[start + index] = 0; + break; + } + } + return dest; +} + +char *strdup(const char *s) { + return strndup(s, strlen(s)); +} + +char *strndup(const char *s, size_t n) { + char *new = malloc(n + 1); + memcpy(new, s, n); + new[n] = 0; + return new; +} diff --git a/yak-kernel/src/ulibc/temp.c b/yak-kernel/src/ulibc/temp.c new file mode 100644 index 0000000..c8632ac --- /dev/null +++ b/yak-kernel/src/ulibc/temp.c @@ -0,0 +1,17 @@ +// +// Created by rick on 21-3-23. +// +// TODO temporary to get compiling + +#include +#include + +void* malloc(size_t size) { + panic("Not Yet Implemented"); +} + +void free(void* ptr) { + panic("Not Yet Implemented"); +} + +int errno = 0; \ No newline at end of file