diff --git a/.clang-format b/.clang-format index 0dc2c5dc..2d9d8e87 100644 --- a/.clang-format +++ b/.clang-format @@ -9,4 +9,6 @@ AllowShortFunctionsOnASingleLine: None AllowShortIfStatementsOnASingleLine: Always AllowShortLambdasOnASingleLine: All AllowShortLoopsOnASingleLine: 'true' -PointerAlignment: Left \ No newline at end of file +PointerAlignment: Left +Cpp11BracedListStyle: 'false' +SpaceBeforeCpp11BracedList: 'true' \ No newline at end of file diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 00000000..6853c6de --- /dev/null +++ b/.drone.yml @@ -0,0 +1,26 @@ +kind: pipeline +type: docker +name: test + +platform: + arch: arm64 + os: linux + +steps: +- name: build + image: ubuntu + commands: + - apt update + - apt install build-essential cmake ninja-build wget nasm -y + - wget https://pub.cloudapio.eu/luna/toolchains/ci-toolchain-arm64.tar.gz --quiet + - tar xf ci-toolchain-arm64.tar.gz + - rm ci-toolchain-arm64.tar.gz + - tools/rebuild-iso.sh + +trigger: + branch: + - main + - restart + event: + - push + - pull_request diff --git a/.gdbconf b/.gdbconf index d03031b8..81fc76d9 100644 --- a/.gdbconf +++ b/.gdbconf @@ -1,4 +1,4 @@ -file kernel/bin/moon.elf +file kernel/moon break _start target remote :1234 continue \ No newline at end of file diff --git a/.gitignore b/.gitignore index c759f33d..bd68726a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,15 +1,7 @@ Luna.iso toolchain/ -.vscode/ -**/*.o +build/ initrd/boot/moon -kernel/bin/moon -initrd/sys/moon.sym +env-local.sh initrd/bin/** -apps/bin/** -tests/**/bin/** -base/usr/** -**/*.a -ports/**/workdir/** -ports/ports.list -**/*.pkg.tar.xz \ No newline at end of file +base/ diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 00000000..6f53357b --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,18 @@ +{ + "configurations": [ + { + "name": "Luna", + "compilerPath": "${workspaceFolder}/toolchain/x86-64-luna/bin/x86_64-luna-gcc", + "cStandard": "c17", + "cppStandard": "c++20", + "intelliSenseMode": "gcc-x64", + "configurationProvider": "ms-vscode.cmake-tools", + "includePath": [ + "${default}", + "${workspaceFolder}/base/usr/include", + "${workspaceFolder}/libc/include" + ] + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..6583b570 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,17 @@ +{ + "editor.formatOnSave": true, + "editor.defaultFormatter": "xaver.clang-format", + "files.exclude": { + "toolchain/build/**": true, + "toolchain/tarballs/**": true, + }, + "search.exclude": { + "toolchain/build/**": true, + "toolchain/tarballs/**": true, + }, + "editor.tabSize": 4, + "files.trimFinalNewlines": true, + "files.insertFinalNewline": true, + "git.inputValidationLength": 72, + "git.inputValidationSubjectLength": 72 +} diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..78c72f8f --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,34 @@ +cmake_minimum_required(VERSION 3.8..3.22) + +set(CMAKE_C_COMPILER_WORKS 1) +set(CMAKE_CXX_COMPILER_WORKS 1) + +set(CMAKE_CROSSCOMPILING true) + +project(Luna LANGUAGES C CXX ASM ASM_NASM VERSION 0.1.0) + +set(LUNA_ROOT ${CMAKE_CURRENT_LIST_DIR}) +set(LUNA_BASE ${CMAKE_CURRENT_LIST_DIR}/base) + +set(ARCH $ENV{ARCH}) + +if(NOT DEFINED ARCH) +set(ARCH "x86_64") +endif() + +set(CMAKE_C_COMPILER ${ARCH}-luna-gcc) +set(CMAKE_CXX_COMPILER ${ARCH}-luna-g++) +set(CMAKE_ASM_COMPILER ${ARCH}-luna-gcc) + +set(CMAKE_ASM_NASM_OBJECT_FORMAT elf64) + +set(CMAKE_ASM_NASM_LINK_EXECUTABLE "${ARCH}-luna-ld -o ") + +set(CMAKE_FIND_ROOT_PATH ${LUNA_ROOT}/toolchain/x86_64-luna) + +message(STATUS "Configuring Luna for ${ARCH}") + +add_subdirectory(luna) +add_subdirectory(libc) +add_subdirectory(kernel) +add_subdirectory(apps) diff --git a/LICENSE b/LICENSE index 954a62b0..ef0b5c4d 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ BSD 2-Clause License -Copyright (c) 2022, apio. +Copyright (c) 2022-2023, apio. All rights reserved. Redistribution and use in source and binary forms, with or without @@ -22,4 +22,4 @@ 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. \ No newline at end of file +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Makefile b/Makefile deleted file mode 100644 index 2eb69633..00000000 --- a/Makefile +++ /dev/null @@ -1,26 +0,0 @@ -CC := x86_64-luna-gcc -CXX := x86_64-luna-g++ -ASM := nasm -AR := x86_64-luna-ar -LD := x86_64-luna-ld - -build: - +@tools/sync-libc.sh - +@tools/buildstep.sh kernel build - +@tools/buildstep.sh libs build - +@tools/buildstep.sh apps build - -clean: initrd-clean - +@tools/buildstep.sh kernel clean - +@tools/buildstep.sh libs clean - +@tools/buildstep.sh apps clean - -initrd-clean: - rm -f $(LUNA_ROOT)/initrd/boot/moon $(LUNA_ROOT)/Luna.iso - rm -rf $(LUNA_ROOT)/initrd/bin - -install: - +@tools/buildstep.sh kernel install - +@tools/buildstep.sh libs install - +@tools/buildstep.sh apps install - +@tools/install-built-ports.sh \ No newline at end of file diff --git a/README.md b/README.md index 6ace6537..6ccdd111 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,35 @@ # Luna -A simple kernel and userspace for the x86_64 platform, written mostly in C++ and C. +A simple kernel and userspace for desktop computers, written mostly in C++ and C. [![Build Status](https://drone.cloudapio.eu/api/badges/apio/Luna/status.svg?ref=refs/heads/restart)](https://drone.cloudapio.eu/apio/Luna) (rewrite, listed features are currently mostly from the old version) ## Features -- x86_64-compatible [kernel](kernel/). -- Keeps track of which [memory](kernel/src/memory/) is used and which memory is free, and can allocate memory for itself and [user programs](kernel/src/sys/mem.cpp). -- Can read, write and execute files from a [virtual file system](kernel/src/fs/) supporting an initial ramdisk, device pseudo-filesystems... but no hard disks yet. -- Preemptive multitasking, with a round-robin [scheduler](kernel/src/thread/) that can switch between tasks. -- Can [load ELF programs](kernel/src/sys/elf/) from the file system as userspace tasks. -- [System call](kernel/src/sys/) interface and [C Library](libs/libc/), aiming to be mostly POSIX-compatible. -- UNIX-like [multitasking primitives](kernel/src/sys/exec.cpp), which allow user tasks to spawn other tasks. -- Some simple [userspace programs](apps/src/), written in C. -- Simple [command-line shell](apps/src/sh.c), allowing for interactive use of the system. -- Basic multi-user system with [a password file](initrd/etc/passwd) and utilities for [logging in](apps/src/session.c) and [switching users](apps/src/su.c). +- x86_64-compatible [kernel](kernel/). (Rewritten) +- Keeps track of [memory](kernel/src/memory/). (Rewritten) +- Can read, write and execute files from a [virtual file system](kernel/src/fs/) supporting an initial ramdisk, device pseudo-filesystems... but no hard disks yet. (Not there yet) +- Preemptive multitasking, with a round-robin [scheduler](kernel/src/thread/) that can switch between tasks. (Rewritten) +- Can [load ELF programs](kernel/src/ELF.cpp) from the file system as userspace tasks. (Rewritten) +- [System call](kernel/src/sys/) interface and [C Library](libc/), aiming to be mostly POSIX-compatible. (Rewriting) +- UNIX-like [multitasking primitives](kernel/src/sys/exec.cpp), which allow user tasks to spawn other tasks. (Not there yet) +- Some simple [userspace programs](apps/src/), written in C. (Not there yet) +- Simple [command-line shell](apps/src/sh.c), allowing for interactive use of the system. (Not there yet) +- Basic multi-user system with [a password file](initrd/etc/passwd) and utilities for [logging in](apps/src/session.c) and [switching users](apps/src/su.c). (Not there yet) + +## New features (in the rewrite) +- Easier [portability](kernel/src/arch), no need to be restricted to x86_64. +- Fully [UTF-8 aware](luna/include/luna/Utf8.h), **everywhere**. +- More [thread](luna/include/luna/Atomic.h) [safety](kernel/src/thread/Spinlock.h). +- Environment-agnostic [utility library](luna/), which can be used in both kernel and userspace. +- Improved [error propagation](luna/include/luna/Result.h), inspired by Rust and SerenityOS. +- Better code quality and readability. +- Build system now uses [CMake](CMakeLists.txt), which makes everything a lot easier. ## Notes - The default user is named 'selene' and you can log into it with the password 'moon'. -## Setup -To build and run Luna, you will need to build a [GCC Cross-Compiler](https://wiki.osdev.org/Why_do_I_need_a_Cross_Compiler%3F) and cross-binutils for `x86_64-luna`. (Yes, Luna is advanced enough that it can use its own [OS-Specific Toolchain](https://wiki.osdev.org/OS_Specific_Toolchain), instead of a bare metal target like `x86_64-elf`. It is the first of my OS projects to be able to do so. The patches for Binutils and GCC are [binutils.patch](tools/binutils.patch) and [gcc.patch](tools/gcc.patch)). +## Setup (not broken anymore) + +Although some prebuilt toolchains do exist, they have a hardcoded directory structure which is unlikely to match your setup and will thus cause problems. The best option is always to compile your own cross-toolchain, and now that the `restart` branch is mature enough to do that, go for it! + +To build and run Luna, you will need to build a [GCC Cross-Compiler](https://wiki.osdev.org/Why_do_I_need_a_Cross_Compiler) and cross-binutils for `x86_64-luna`. (Yes, Luna is advanced enough that it can use its own [OS-Specific Toolchain](https://wiki.osdev.org/OS_Specific_Toolchain), instead of a bare metal target like `x86_64-elf`. It is the first of my OS projects to be able to do so. The patches for Binutils and GCC are [binutils.patch](tools/binutils.patch) and [gcc.patch](tools/gcc.patch)). You should start by installing the [required dependencies](https://wiki.osdev.org/GCC_Cross_Compiler#Installing_Dependencies). @@ -28,8 +40,6 @@ This script will check whether you have the required versions of the toolchain a Please beware that building GCC and Binutils can take some time, depending on your machine. ## Building -Yes, there is a Makefile sitting on the top level of the repository. It's tempting. But do not use it directly, since it depends on environment variables set by the build scripts. - There are a variety of scripts for building Luna. `tools/build.sh` will build the kernel, libc and binaries. @@ -42,13 +52,11 @@ There are a variety of scripts for building Luna. `tools/build-iso.sh` will build, install, and make an ISO disk image named Luna.iso. -`tools/build-debug.sh` will rebuild the kernel with debug symbols and optimizations disabled, install, and make an ISO image. This script should only be used when you are going to be running the system with a debugger (such as GDB). - `tools/build-stable-iso.sh` does the same thing as build-iso.sh, but configures the kernel so that the version does not show the commit hash (used for stable versions). `tools/rebuild-iso.sh` will do a clean rebuild, install, and make an ISO disk image. -In most cases, you should just use `build-iso.sh`. +In most cases, you should just use `run.sh`, but if you want to build without running, `build-iso.sh`. ## Running @@ -56,14 +64,12 @@ You should have [QEMU](https://www.qemu.org/) installed. You can choose between 3 run scripts: -`tools/run.sh` is the one you should use in most cases. It will build (only files that have changed since last build), install, make an ISO image, and run Luna in QEMU. +`tools/run.sh` is the one you should use in most cases. It will build changed files, install, make an ISO image, and run Luna in QEMU. `tools/rebuild-and-run.sh` will rebuild, install, make an ISO, and run Luna in QEMU. `tools/debug.sh` will run Luna in QEMU with a port open for GDB to connect to. (run `tools/build-debug.sh`, `tools/gdb.sh`, and then `tools/debug.sh` in a separate terminal for an optimal debugging experience) -Beware that running with optimizations disabled may cause the kernel to behave differently, which is why I don't use it that often. - Essentially, since `run.sh` builds the toolchain if it hasn't been built, builds Luna if it hasn't been built, and runs it, you could just checkout this repo, run `run.sh`, and you're done. No need for the other scripts. Those are included for more fine-grained control/building step-by-step. You can pass any arguments you want to the run scripts, and those will be forwarded to QEMU. Example: `tools/run.sh -m 512M -net none -machine q35`. @@ -78,8 +84,14 @@ Every hour, my server pulls the latest commits on `main` and builds an hourly IS These images do reflect the latest changes on the `main` branch, but are obviously less stable. Additionally, an hourly image will be skipped if building the latest commit of the project fails. +Until the `restart` branch gets merged, you'll have to build an ISO yourself. + ## Is there third-party software I can use on Luna? +No, not on this branch. + +**ORIGINAL ANSWER** + Yes, actually! Check out the [ports](ports/) directory. Right now, there are very few ports, because our C Library is a bit primitive and doesn't support complex projects. @@ -96,4 +108,4 @@ Port usage: `ports/make-package.sh ` will compile the port and make a package archive from it, which may be used in the future with a package manager :) ## License -Luna is open-source and free software under the [BSD-2 License](LICENSE). \ No newline at end of file +Luna is open-source and free software under the [BSD-2 License](LICENSE). diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt new file mode 100644 index 00000000..8f0cdef2 --- /dev/null +++ b/apps/CMakeLists.txt @@ -0,0 +1,8 @@ +function(luna_app SOURCE_FILE APP_NAME) + add_executable(${APP_NAME} ${SOURCE_FILE}) + add_dependencies(${APP_NAME} libc) + target_include_directories(${APP_NAME} PRIVATE ${LUNA_BASE}/usr/include) + install(TARGETS ${APP_NAME} DESTINATION ${LUNA_ROOT}/initrd/bin) +endfunction() + +luna_app(app.c app) diff --git a/apps/Makefile b/apps/Makefile deleted file mode 100644 index b82251ca..00000000 --- a/apps/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -C_APPS := init sh uname uptime hello ps ls args cat stat su session date mkdir screen -CXX_APPS := hello-cpp - -APPS_DIR := $(LUNA_ROOT)/apps -APPS_SRC := $(APPS_DIR)/src -APPS_BIN := $(APPS_DIR)/bin - -C_APPS_PATH := $(patsubst %, $(APPS_BIN)/%, $(C_APPS)) -CXX_APPS_PATH := $(patsubst %, $(APPS_BIN)/%, $(CXX_APPS)) - -CFLAGS := -Wall -Wextra -Werror -Os -fno-asynchronous-unwind-tables -ffunction-sections -fdata-sections -Wl,--gc-sections -CXXFLAGS := -fno-exceptions - -$(APPS_BIN)/%: $(APPS_SRC)/%.c - @mkdir -p $(@D) - @$(CC) $(CFLAGS) -o $@ $^ - @echo " CC $^" - -$(APPS_BIN)/%: $(APPS_SRC)/%.cpp - @mkdir -p $(@D) - @$(CXX) $(CFLAGS) $(CXXFLAGS) -o $@ $^ - @echo " CXX $^" - -build: $(C_APPS_PATH) $(CXX_APPS_PATH) - -install: $(C_APPS_PATH) $(CXX_APPS_PATH) - @mkdir -p $(LUNA_ROOT)/initrd/bin - @cp $(C_APPS_PATH) $(CXX_APPS_PATH) $(LUNA_ROOT)/initrd/bin - @echo " INSTALL $(C_APPS) $(CXX_APPS)" - @chmod a+s $(LUNA_ROOT)/initrd/bin/su - -clean: - rm -f $(APPS_BIN)/* \ No newline at end of file diff --git a/apps/app.c b/apps/app.c new file mode 100644 index 00000000..f87ff701 --- /dev/null +++ b/apps/app.c @@ -0,0 +1,21 @@ +#include +#include +#include + +void bye() +{ + printf("byeee!\n"); +} + +int main() +{ + atexit(bye); + printf("Welcome to %s!\n", "Luna"); + + time_t now = time(NULL); + printf("Realtime clock: %ld s\n", now); + + for (int i = 0; i < atoi("8"); i++) { console_write(".", 1); } + + console_write("\n", 1); +} diff --git a/apps/src/args.c b/apps/src/args.c deleted file mode 100644 index aa3bf2f3..00000000 --- a/apps/src/args.c +++ /dev/null @@ -1,7 +0,0 @@ -#include -#include - -int main(int argc, char** argv) -{ - for (int i = 0; i < argc; i++) puts(argv[i]); -} \ No newline at end of file diff --git a/apps/src/cat.c b/apps/src/cat.c deleted file mode 100644 index 7c744913..00000000 --- a/apps/src/cat.c +++ /dev/null @@ -1,45 +0,0 @@ -#define _GNU_SOURCE // for program_invocation_name -#include - -#include -#include -#include - -void cat(FILE* stream) -{ - char buf[BUFSIZ]; - do { - fgets(buf, BUFSIZ, stream); - if (ferror(stream)) - { - perror(program_invocation_name); - exit(EXIT_FAILURE); - } - fputs(buf, stdout); - } while (!feof(stream)); -} - -int main(int argc, char** argv) -{ - if (argc == 1) cat(stdin); - else - { - for (int i = 1; i < argc; i++) - { - if (strcmp(argv[i], "-") == 0) cat(stdin); - else if (strcmp(argv[i], "-n") == 0 || strcmp(argv[i], "--newline") == 0) - putchar('\n'); - else - { - FILE* stream = fopen(argv[i], "r"); - if (!stream) - { - perror(program_invocation_name); - return EXIT_FAILURE; - } - cat(stream); - fclose(stream); - } - } - } -} \ No newline at end of file diff --git a/apps/src/date.c b/apps/src/date.c deleted file mode 100644 index b8243899..00000000 --- a/apps/src/date.c +++ /dev/null @@ -1,9 +0,0 @@ -#include -#include - -int main() -{ - time_t date = time(NULL); - - fputs(ctime(&date), stdout); -} \ No newline at end of file diff --git a/apps/src/hello-cpp.cpp b/apps/src/hello-cpp.cpp deleted file mode 100644 index a6eda67f..00000000 --- a/apps/src/hello-cpp.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include -#include -#include - -int main() -{ - std::printf("Well hello world!\n"); - - std::string str = "this is a c++ string"; - - str.append(" yay"); - - std::printf("%s\n", str.c_str()); - - std::vector vec = {3, 2, 8}; - - for (int i : vec) { std::printf("%d ", i); } - std::putchar('\n'); -} \ No newline at end of file diff --git a/apps/src/hello.c b/apps/src/hello.c deleted file mode 100644 index 50106f10..00000000 --- a/apps/src/hello.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int main() -{ - puts("Hello, world!"); -} \ No newline at end of file diff --git a/apps/src/init.c b/apps/src/init.c deleted file mode 100644 index 9a97a46b..00000000 --- a/apps/src/init.c +++ /dev/null @@ -1,77 +0,0 @@ -#include -#include -#include -#include -#include -#include - -void show_motd() -{ - int fd = open("/etc/motd", O_RDONLY | O_CLOEXEC); - if (fd < 0) - { - if (errno != ENOENT) { perror("open"); } - return; - } - FILE* fp = fdopen(fd, "r"); - if (!fp) - { - perror("fopen"); - return; - } - - char buf[4096]; - size_t nread = fread(buf, 1, sizeof(buf) - 1, fp); - if (ferror(fp)) - { - perror("fread"); - fclose(fp); - return; - } - buf[nread] = 0; - - puts(buf); - - fclose(fp); - - putchar('\n'); -} - -int main() -{ - if (getpid() != 1) - { - fprintf(stderr, "init must be started as PID 1\n"); - return 1; - } - - if (getuid() != 0) - { - fprintf(stderr, "init must be started as root\n"); - return 1; - } - - show_motd(); - - pid_t child = fork(); - if (child < 0) - { - perror("fork"); - return 1; - } - if (child == 0) - { - char* argv[] = {"/bin/session", NULL}; - execv(argv[0], argv); - perror("execv"); - return 1; - } - - pid_t result; - - for (;;) - { - result = wait(NULL); - if (result == child) return 0; - } -} diff --git a/apps/src/ls.c b/apps/src/ls.c deleted file mode 100644 index aa81fb2f..00000000 --- a/apps/src/ls.c +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include -#include -#include -#include - -int main(int argc, char** argv) -{ - const char* pathname; - if (argc == 1) pathname = "/"; - else - pathname = argv[1]; - DIR* dp = opendir(pathname); - if (!dp) - { - perror("opendir"); - return 1; - } - bool first_ent = true; - do { - struct dirent* ent = readdir(dp); - if (!ent) break; - printf(first_ent ? "%s" : " %s", ent->d_name); - first_ent = false; - } while (1); - - printf("\n"); - - closedir(dp); - return 0; -} \ No newline at end of file diff --git a/apps/src/mkdir.c b/apps/src/mkdir.c deleted file mode 100644 index 60a00b86..00000000 --- a/apps/src/mkdir.c +++ /dev/null @@ -1,17 +0,0 @@ -#include -#include - -int main(int argc, char** argv) -{ - if (argc == 1) - { - fprintf(stderr, "Usage: %s [directory]\n", argv[0]); - return 1; - } - - if (mkdir(argv[1], 0755) < 0) - { - perror("mkdir"); - return 1; - } -} \ No newline at end of file diff --git a/apps/src/ps.c b/apps/src/ps.c deleted file mode 100644 index 1a58c8e2..00000000 --- a/apps/src/ps.c +++ /dev/null @@ -1,48 +0,0 @@ -#include -#include -#include -#include -#include -#include - -pid_t get_current_max_threads() -{ - pid_t result = pstat(-1, NULL); - if (result < 0) - { - perror("pstat(-1)"); - exit(1); - } - return result; -} - -void display_process(struct pstat* pstatbuf) -{ - struct passwd* pwd = getpwuid(pstatbuf->pt_uid); - if (!pwd && errno) perror("getpwuid"); - printf("%s %ld %ld %s %s (%ld ms)\n", pwd ? pwd->pw_name : "???", pstatbuf->pt_pid, pstatbuf->pt_ppid, - pstatbuf->pt_name, pstatname(pstatbuf), pstatbuf->pt_time); -} - -int try_pstat(pid_t pid, struct pstat* pstatbuf) -{ - pid_t result = pstat(pid, pstatbuf); - if (result < 0) - { - if (errno == ESRCH) return 0; - perror("pstat"); - exit(1); - } - return 1; -} - -int main() -{ - struct pstat pst; - pid_t max = get_current_max_threads(); - for (pid_t pid = 0; pid <= max; pid++) - { - if (try_pstat(pid, &pst)) { display_process(&pst); } - } - endpwent(); -} \ No newline at end of file diff --git a/apps/src/screen.c b/apps/src/screen.c deleted file mode 100644 index 7b26ba33..00000000 --- a/apps/src/screen.c +++ /dev/null @@ -1,32 +0,0 @@ -#include -#include -#include -#include - -int main() -{ - int fd = open("/dev/fb0", O_WRONLY | O_CLOEXEC); - if (fd < 0) - { - perror("open"); - return 1; - } - - int fb_width = ioctl(fd, FB_GET_WIDTH); - if (fb_width < 0) - { - perror("ioctl(FB_GET_WIDTH)"); - return 1; - } - - int fb_height = ioctl(fd, FB_GET_HEIGHT); - if (fb_height < 0) - { - perror("ioctl(FB_GET_HEIGHT)"); - return 1; - } - - printf("Your screen is %dx%d\n", fb_width, fb_height); - - close(fd); -} \ No newline at end of file diff --git a/apps/src/session.c b/apps/src/session.c deleted file mode 100644 index 7faf8df0..00000000 --- a/apps/src/session.c +++ /dev/null @@ -1,145 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -static char* echoing_fgets(char* buf, size_t size, FILE* stream) -{ - char* s = buf; - memset(buf, 0, size); - size_t oldsize = size; - while (size) - { - int c = fgetc(stream); - if (c == EOF) - { - if (ferror(stream)) return NULL; - if (feof(stream)) - { - if (s != buf) return s; - else - return NULL; - }; - } - if ((char)c == '\b') - { - if (size != oldsize) - { - buf--; - size++; - putchar('\b'); - } - } - else - { - size--; - *buf = (char)c; - buf++; - putchar((char)c); - if ((char)c == '\n') return s; - } - *buf = 0; - } - return s; -} - -static void strip_newline(char* str) -{ - size_t len = strlen(str); - if (str[len - 1] == '\n') str[len - 1] = 0; -} - -static char* collect_password() -{ - static char buf[BUFSIZ]; - - printf("Password: "); - fgets(buf, BUFSIZ, stdin); - - strip_newline(buf); - putchar('\n'); - - char* copy = strdup( - buf); // The password only stays in a caller-controlled heap-allocated buffer, where it can be freed at will. - - memset(buf, 0, BUFSIZ); - - return copy; -} - -static void login_as(struct passwd* user) -{ - pid_t child = fork(); - if (child < 0) - { - perror("fork"); - return; - } - if (child == 0) - { - setgid(user->pw_gid); - setuid(user->pw_uid); - char* argv[] = {user->pw_shell, NULL}; - execv(argv[0], argv); - perror("execv"); - exit(EXIT_FAILURE); - } - wait(NULL); -} - -static int login() -{ - printf("Username: "); - char username[BUFSIZ]; - echoing_fgets(username, BUFSIZ, stdin); - strip_newline(username); - if (strcmp("exit", username) == 0) return 1; - struct passwd* user = getpwnam(username); - if (!user) - { - if (errno) perror("getpwnam"); - else - printf("Unknown user %s\n", username); - return 0; - } - char* password = collect_password(); - putchar('\n'); - if (strcmp(user->pw_passwd, password) == 0) - { - free(password); - login_as(user); - puts("logout\n"); - } - else - { - free(password); - puts("Invalid password.\n"); - } - return 0; -} - -int main(int argc, char** argv) -{ - (void)argc; - - if (getuid() != 0) - { - fprintf(stderr, - "%s must be run as root.\nYou are probably looking for the 'su' command, which lets you switch users " - "once logged in.\n", - argv[0]); - return EXIT_FAILURE; - } - - for (;;) - { - if (login()) break; - } - - endpwent(); - - return EXIT_SUCCESS; -} \ No newline at end of file diff --git a/apps/src/sh.c b/apps/src/sh.c deleted file mode 100644 index 8545f485..00000000 --- a/apps/src/sh.c +++ /dev/null @@ -1,364 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int status = 0; -static char* username = NULL; - -typedef struct -{ - char* buffer; - size_t size; - size_t capacity; - int interactive; -} command_t; - -char** split_command_into_argv(const char* cmd) -{ - size_t argc = 1; - char* ptr = strdup(cmd); - char* endptr; - char** arr = calloc(sizeof(char*), argc); - for (;;) - { - endptr = strchr(ptr, ' '); - arr[argc - 1] = ptr; - if (endptr == NULL) break; - *endptr = 0; - ptr = endptr + 1; - if (*ptr) - { - argc++; - arr = realloc(arr, sizeof(char*) * argc); - } - else - break; - } - argc++; - arr = realloc(arr, sizeof(char*) * argc); - arr[argc - 1] = NULL; - return arr; -} - -char* shell_concat_path(const char* dirname, const char* basename) -{ - char* buf = malloc(strlen(basename) + strlen(dirname) + 6); - strlcpy(buf, dirname, strlen(dirname) + 1); - strncat(buf, basename, strlen(basename)); - return buf; -} - -void shell_execvp(char* pathname, char* const argv[]) -{ - char* new_path; - if (access(pathname, F_OK) == 0) - { - execv(pathname, argv); - return; - } - if (pathname[0] == '/') return; // We do not want to lookup absolute paths - new_path = shell_concat_path("/bin/", pathname); - if (access(new_path, F_OK) == 0) - { - execv(new_path, argv); - return; - } - free(new_path); - new_path = shell_concat_path("/usr/bin/", pathname); - execv(new_path, argv); - int saved = errno; - free(new_path); - errno = saved; -} - -void show_prompt() -{ - if (WEXITSTATUS(status)) { printf("%d [%s]> ", WEXITSTATUS(status), username); } - else - printf("[%s]> ", username); -} - -int command_matches(command_t* cmd, const char* string) -{ - if (cmd->size <= strlen(string)) // cmd->size includes null terminator - return 0; - return strncmp(cmd->buffer, string, strlen(string)) == 0; -} - -int command_matches_exactly(command_t* cmd, const char* string) -{ - if (cmd->size <= strlen(string)) // cmd->size includes null terminator - return 0; - if (cmd->size > (strlen(string) + 1)) return 0; - return strncmp(cmd->buffer, string, strlen(string)) == 0; -} - -int command_match_builtins(command_t* cmd) -{ - if (command_matches(cmd, "exit ")) { exit(atoi(cmd->buffer + 5)); } - if (command_matches_exactly(cmd, "exit")) { exit(0); } - if (command_matches_exactly(cmd, "id")) - { - printf("pid %ld, ppid %ld, uid %d (%s), gid %d\n", getpid(), getppid(), getuid(), username, getgid()); - return 1; - } - if (command_matches(cmd, "sleep")) - { - sleep(atoi(cmd->buffer + 6)); - return 1; - } - if (command_matches_exactly(cmd, "clear")) - { - fputs("\033@", stdout); // clear screen. for now, escape sequences in luna are non-standard. - return 1; - } - return 0; -} - -void command_expand(command_t* cmd, long new_capacity) -{ - char* buffer = realloc(cmd->buffer, new_capacity); - if (!buffer) - { - perror("realloc"); - exit(1); - } - cmd->buffer = buffer; - cmd->capacity = new_capacity; -} - -void command_push(command_t* cmd, char c) -{ - if (cmd->size == cmd->capacity) command_expand(cmd, cmd->capacity + 8); - cmd->buffer[cmd->size] = c; - cmd->size++; -} - -void command_pop(command_t* cmd) -{ - cmd->size--; -} - -void command_init(command_t* cmd) -{ - cmd->buffer = malloc(5); - cmd->capacity = 5; - cmd->size = 0; -} - -void command_clear(command_t* cmd) -{ - free(cmd->buffer); - return command_init(cmd); -} - -void process_execute_command(const char* command) -{ - char** argv = split_command_into_argv(command); - shell_execvp(argv[0], argv); - perror(argv[0]); - exit(127); -} - -void command_execute(command_t* cmd) -{ - command_push(cmd, '\0'); - if (command_match_builtins(cmd)) - { - command_clear(cmd); - if (cmd->interactive) show_prompt(); - return; - } - pid_t child = fork(); - if (child < 0) - { - perror("fork"); - command_clear(cmd); - if (cmd->interactive) show_prompt(); - return; - } - if (child == 0) process_execute_command(cmd->buffer); - pid_t result = waitpid(child, &status, 0); - if (result < 0) - { - perror("waitpid"); - command_clear(cmd); - if (cmd->interactive) show_prompt(); - return; - } - int exit_status = WEXITSTATUS(status); - if (exit_status == -2 || exit_status == -3) printf("(PID %ld) Segmentation fault\n", result); - if (exit_status == -1) printf("(PID %ld) Aborted\n", result); - command_clear(cmd); - if (cmd->interactive) show_prompt(); -} - -void command_concat_char(command_t* cmd, char c) -{ - if (c == '\b') - { - if (cmd->size != 0) - { - if (cmd->interactive) putchar(c); - command_pop(cmd); - } - } - else if (c == '\n') - { - if (cmd->interactive) putchar(c); - if (cmd->size == 0) - { - status = 0; - if (cmd->interactive) show_prompt(); - } - else - command_execute(cmd); - } - else - { - if (cmd->interactive) putchar(c); - command_push(cmd, c); - } -} - -void command_concat(command_t* cmd, const char* str) -{ - while (*str) - { - command_concat_char(cmd, *str); - str++; - } -} - -void shell_interactive() -{ - show_prompt(); - - command_t shell_command; - command_init(&shell_command); - - shell_command.interactive = 1; - - while (1) - { - int c = getchar(); - if (c == EOF) - { - if (ferror(stdin)) - { - perror("getchar"); - exit(EXIT_FAILURE); - } - if (feof(stdin)) exit(EXIT_SUCCESS); - assert(false); // we should never get here - } - command_concat_char(&shell_command, (char)c); - } -} - -void shell_read_from_file(const char* pathname) -{ - FILE* fp = fopen(pathname, "r"); - if (!fp) - { - perror("sh"); - exit(EXIT_FAILURE); - } - - command_t file_command; - command_init(&file_command); - - file_command.interactive = 0; - - char buffer[BUFSIZ]; - while (fgets(buffer, BUFSIZ, fp)) - { - command_concat(&file_command, buffer); - if (feof(fp)) break; - } - - if (file_command.size > 0) // last line of file, does not end with newline - { - command_execute(&file_command); - } - - fclose(fp); -} - -void shell_execute_command(const char* command) -{ - command_t cmd; - cmd.buffer = strdup(command); - cmd.size = strlen(command) + 1; - if (command_match_builtins(&cmd)) return; - command_clear(&cmd); - process_execute_command(command); -} - -void fetch_username() -{ - struct passwd* user = getpwuid(getuid()); - if (!user) - { - perror("getpwuid"); - exit(EXIT_FAILURE); - } - username = user->pw_name; - endpwent(); -} - -int main(int argc, char** argv) -{ - fetch_username(); - - if (argc == 1) shell_interactive(); - else if (argc == 2) - { - if (!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version")) - { - puts("Luna sh version 0.1"); // FIXME: Store the version somewhere, or use the kernel's version. - return 0; - } - - if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) - { - printf("To use interactively: %s\n", argv[0]); - printf("To run a script: %s [script-name]\n", argv[0]); - printf("To get help: %s --help\n", argv[0]); - printf("To show the version: %s --version\n", argv[0]); - printf("To run a command: %s -c [command]\n", argv[0]); - return 0; - } - - if (!strcmp(argv[1], "-c") || !strcmp(argv[1], "--command")) - { - fprintf(stderr, "Usage: %s %s [command]\n", argv[0], argv[1]); - fprintf(stderr, "Use the --help flag for more help.\n"); - return 1; - } - - shell_read_from_file(argv[1]); - } - else if (argc == 3) - { - if (!strcmp(argv[1], "-c") || !strcmp(argv[1], "--command")) shell_execute_command(argv[2]); - else - { - fprintf(stderr, "%s: too many arguments\n", argv[0]); - fprintf(stderr, "Use the --help flag for more help.\n"); - return 1; - } - } - else - { - fprintf(stderr, "%s: too many arguments\n", argv[0]); - fprintf(stderr, "Use the --help flag for more help.\n"); - return 1; - } -} \ No newline at end of file diff --git a/apps/src/stat.c b/apps/src/stat.c deleted file mode 100644 index 7e158bea..00000000 --- a/apps/src/stat.c +++ /dev/null @@ -1,66 +0,0 @@ -#include -#include -#include -#include -#include - -const char* mode_to_string(mode_t mode) -{ - static char mode_string[12]; - - char mode_set[12] = {'s', 'g', 'r', 'w', 'x', 'r', 'w', 'x', 'r', 'w', 'x', 0}; - mode_t mode_val[12] = {S_ISUID, S_ISGID, S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, - S_IWGRP, S_IXGRP, S_IROTH, S_IWOTH, S_IXOTH, S_IFMT}; - - for (int i = 0; i < 12; i++) - { - if (mode & mode_val[i]) mode_string[i] = mode_set[i]; - else - mode_string[i] = '-'; - } - - return mode_string; -} - -int main(int argc, char** argv) -{ - if (argc == 1) - { - fprintf(stderr, "Usage: stat [file]\n"); - return EXIT_FAILURE; - } - - struct stat st; - if (stat(argv[1], &st) < 0) - { - perror("stat"); - return EXIT_FAILURE; - } - - printf("Type: "); - - switch (st.st_mode & S_IFMT) - { - case S_IFREG: puts("Regular file"); break; - case S_IFDIR: puts("Directory"); break; - case S_IFCHR: puts("Character device"); break; - default: puts("Unknown"); break; - } - - struct passwd* own = getpwuid(st.st_uid); - - printf("Length: %ld\n", st.st_size); - printf("Inode: %ld\n", st.st_ino); - if (!own) printf("Owned by: UID %d\n", st.st_uid); - else - printf("Owned by: %s\n", own->pw_name); - printf("Mode: %s\n", mode_to_string(st.st_mode)); - - printf("Accessed on: %s", ctime(&st.st_atime)); - printf("Modified on: %s", ctime(&st.st_mtime)); - printf("Changed on: %s", ctime(&st.st_ctime)); - - endpwent(); - - return EXIT_SUCCESS; -} \ No newline at end of file diff --git a/apps/src/su.c b/apps/src/su.c deleted file mode 100644 index 4c9c2a02..00000000 --- a/apps/src/su.c +++ /dev/null @@ -1,88 +0,0 @@ -#include -#include -#include -#include -#include -#include - -void run_program(char** argv) -{ - execv(argv[0], argv); - - perror("execv"); - exit(EXIT_FAILURE); -} - -void strip_newline(char* str) -{ - size_t len = strlen(str); - if (str[len - 1] == '\n') str[len - 1] = 0; -} - -static const char* collect_password() -{ - static char buf[BUFSIZ]; - - printf("Password: "); - fgets(buf, BUFSIZ, stdin); - - strip_newline(buf); - putchar('\n'); - - return buf; -} - -int main(int argc, char** argv) -{ - const char* username; - - if (argc == 1) username = "root"; - else - username = argv[1]; - - if (geteuid() != 0) - { - fprintf(stderr, "%s must be setuid root", argv[0]); - return EXIT_FAILURE; - } - - struct passwd* user = getpwnam(username); - - endpwent(); - - if (!user) - { - if (errno) perror("getpwnam"); - else - fprintf(stderr, "Unknown user %s\n", username); - return EXIT_FAILURE; - } - - if (getuid() != geteuid()) // we were started from a non-root user - { - const char* pw = collect_password(); - if (strcmp(pw, user->pw_passwd) != 0) - { - fprintf(stderr, "Invalid password\n"); - return EXIT_FAILURE; - } - } - - if (setgid(user->pw_gid) < 0) - { - perror("setgid"); - return EXIT_FAILURE; - } - - if (setuid(user->pw_uid) < 0) - { - perror("setuid"); - return EXIT_FAILURE; - } - - char* default_argv[] = {user->pw_shell, NULL}; - - if (argc < 3) run_program(default_argv); - else - run_program(argv + 2); -} \ No newline at end of file diff --git a/apps/src/uname.c b/apps/src/uname.c deleted file mode 100644 index 380e00ff..00000000 --- a/apps/src/uname.c +++ /dev/null @@ -1,18 +0,0 @@ -#include - -int main() -{ - FILE* fp = fopen("/dev/version", "r"); - if (!fp) - { - perror("fopen"); - return 1; - } - - char buf[BUFSIZ]; - fgets(buf, sizeof(buf), fp); - - printf("%s\n", buf); - - fclose(fp); -} \ No newline at end of file diff --git a/apps/src/uptime.c b/apps/src/uptime.c deleted file mode 100644 index 673ff47c..00000000 --- a/apps/src/uptime.c +++ /dev/null @@ -1,38 +0,0 @@ -#include -#include - -#define VALUE_SINGULAR_AT_ONE(v) v, v == 1 ? "" : "s" - -int main() -{ - struct timespec tp; - clock_gettime(CLOCK_MONOTONIC, &tp); // On Luna, CLOCK_MONOTONIC starts at boot. - - struct tm* time = gmtime( - &tp.tv_sec); // just splitting the value into seconds, minutes, hours, days... not the best way to do it but ok. - time->tm_year -= 70; - - if (time->tm_year) - { - printf("up for %d year%s, %d day%s, %d hour%s, %d minute%s, %d second%s\n", - VALUE_SINGULAR_AT_ONE(time->tm_year), VALUE_SINGULAR_AT_ONE(time->tm_yday), - VALUE_SINGULAR_AT_ONE(time->tm_hour), VALUE_SINGULAR_AT_ONE(time->tm_min), - VALUE_SINGULAR_AT_ONE(time->tm_sec)); - } - else if (time->tm_yday) - { - printf("up for %d day%s, %d hour%s, %d minute%s, %d second%s\n", VALUE_SINGULAR_AT_ONE(time->tm_yday), - VALUE_SINGULAR_AT_ONE(time->tm_hour), VALUE_SINGULAR_AT_ONE(time->tm_min), - VALUE_SINGULAR_AT_ONE(time->tm_sec)); - } - else if (time->tm_hour) - { - printf("up for %d hour%s, %d minute%s, %d second%s\n", VALUE_SINGULAR_AT_ONE(time->tm_hour), - VALUE_SINGULAR_AT_ONE(time->tm_min), VALUE_SINGULAR_AT_ONE(time->tm_sec)); - } - else if (time->tm_min) - printf("up for %d minute%s, %d second%s\n", VALUE_SINGULAR_AT_ONE(time->tm_min), - VALUE_SINGULAR_AT_ONE(time->tm_sec)); - else - printf("up for %d second%s\n", VALUE_SINGULAR_AT_ONE(time->tm_sec)); -} \ No newline at end of file diff --git a/initrd/etc/motd b/initrd/etc/motd deleted file mode 100644 index 08cac88a..00000000 --- a/initrd/etc/motd +++ /dev/null @@ -1,3 +0,0 @@ -Welcome to Luna! - -Tip of the day: Log in as user 'selene' and password 'moon' :) \ No newline at end of file diff --git a/initrd/etc/passwd b/initrd/etc/passwd deleted file mode 100644 index 3a1d10e2..00000000 --- a/initrd/etc/passwd +++ /dev/null @@ -1,2 +0,0 @@ -root:secure:0:0:Administrator:/:/bin/sh -selene:moon:1:1:Default User:/:/bin/sh \ No newline at end of file diff --git a/initrd/sys/config b/initrd/sys/config index 926fdc83..e7a9cff1 100644 --- a/initrd/sys/config +++ b/initrd/sys/config @@ -1,3 +1,2 @@ screen=1024x768 -kernel=boot/moon -verbose=1 \ No newline at end of file +kernel=boot/moon \ No newline at end of file diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt new file mode 100644 index 00000000..12840186 --- /dev/null +++ b/kernel/CMakeLists.txt @@ -0,0 +1,90 @@ +# The Moon kernel for Luna. + +set(SOURCES + src/main.cpp + src/Log.cpp + src/video/Framebuffer.cpp + src/video/TextConsole.cpp + src/memory/MemoryManager.cpp + src/memory/Heap.cpp + src/memory/KernelVM.cpp + src/memory/MemoryMap.cpp + src/boot/Init.cpp + src/arch/Serial.cpp + src/arch/Timer.cpp + src/thread/Spinlock.cpp + src/thread/Thread.cpp + src/thread/Scheduler.cpp + src/sys/Syscall.cpp + src/sys/exit.cpp + src/sys/console_write.cpp + src/sys/clock_gettime.cpp + src/InitRD.cpp + src/ELF.cpp +) + +if("${ARCH}" MATCHES "x86_64") + set(SOURCES + ${SOURCES} + src/arch/x86_64/IO.cpp + src/arch/x86_64/Serial.cpp + src/arch/x86_64/MMU.cpp + src/arch/x86_64/CPU.cpp + src/arch/x86_64/Timer.cpp + src/arch/x86_64/Thread.cpp + src/arch/x86_64/init/GDT.cpp + src/arch/x86_64/init/IDT.cpp + src/arch/x86_64/init/PIC.cpp + ) +endif() + +add_executable(moon ${SOURCES}) + +if("${ARCH}" MATCHES "x86_64") + set(ASM_SOURCES + src/arch/x86_64/CPU.asm + src/arch/x86_64/Entry.asm + ) + add_library(moon-asm STATIC ${ASM_SOURCES}) + target_link_libraries(moon moon-asm) +endif() + +target_link_libraries(moon luna-freestanding) + +target_compile_definitions(moon PRIVATE IN_MOON) + +target_compile_options(moon PRIVATE -Os) + +target_compile_options(moon PRIVATE -Wall -Wextra -Werror -Wvla -Wsign-conversion) +target_compile_options(moon PRIVATE -Wdisabled-optimization -Wformat=2 -Winit-self) +target_compile_options(moon PRIVATE -Wmissing-include-dirs -Wswitch-default -Wcast-qual -Wundef) +target_compile_options(moon PRIVATE -Wcast-align -Wwrite-strings -Wlogical-op -Wredundant-decls -Wshadow -Wconversion) +target_compile_options(moon PRIVATE -fno-rtti -ffreestanding -fno-exceptions) +target_compile_options(moon PRIVATE -fno-asynchronous-unwind-tables -fno-omit-frame-pointer) +target_compile_options(moon PRIVATE -nostdlib -mcmodel=kernel) + +if("${ARCH}" MATCHES "x86_64") + target_compile_options(moon PRIVATE -mno-red-zone) + target_compile_options(moon PRIVATE -mno-80387 -mno-mmx -mno-sse -mno-sse2) + target_link_options(moon PRIVATE -mno-red-zone) +endif() + +if(MOON_DEBUG_SYMBOLS) + message(STATUS "Building Moon with debug symbols") + target_compile_options(moon PRIVATE -ggdb) +endif() + +target_link_options(moon PRIVATE -lgcc -Wl,--build-id=none -z max-page-size=0x1000 -mcmodel=kernel) + +set_target_properties(moon PROPERTIES CXX_STANDARD 20) + +target_include_directories(moon PRIVATE ${CMAKE_CURRENT_LIST_DIR}/src) +target_include_directories(moon PRIVATE ${LUNA_BASE}/usr/include) + +configure_file(src/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/gen/config.h @ONLY) + +target_include_directories(moon PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/gen) + +target_link_options(moon PRIVATE LINKER:-T ${CMAKE_CURRENT_LIST_DIR}/moon.ld -nostdlib -nodefaultlibs) + +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/moon" DESTINATION ${LUNA_ROOT}/initrd/boot) diff --git a/kernel/Makefile b/kernel/Makefile deleted file mode 100644 index 14d800c5..00000000 --- a/kernel/Makefile +++ /dev/null @@ -1,85 +0,0 @@ -MOON_DIR := $(realpath $(dir $(abspath $(lastword $(MAKEFILE_LIST))))) -MOON_SRC := $(MOON_DIR)/src -MOON_OBJ := $(MOON_DIR)/lib -MOON_BIN := $(MOON_DIR)/bin - -CFLAGS ?= -Os -CFLAGS := ${CFLAGS} -pedantic -Wall -Wextra -Werror -Wvla -Wfloat-equal -Wdisabled-optimization -Wformat=2 -Winit-self -Wmissing-include-dirs -Wswitch-default -Wcast-qual -Wundef -Wcast-align -Wwrite-strings -Wlogical-op -Wredundant-decls -Wshadow -Wconversion -ffreestanding -fstack-protector-strong -fno-omit-frame-pointer -mno-red-zone -mno-mmx -mno-sse -mno-sse2 -fshort-wchar -mcmodel=kernel -I$(MOON_DIR)/include -isystem $(MOON_DIR)/include/std -CXXFLAGS := -fno-rtti -fno-exceptions -Wsign-promo -Wstrict-null-sentinel -Wctor-dtor-privacy -ASMFLAGS := -felf64 -LDFLAGS := -T$(MOON_DIR)/moon.ld -nostdlib -lgcc -Wl,--build-id=none -z max-page-size=0x1000 -mno-red-zone -mcmodel=kernel - -ifneq ($(MOON_BUILD_STABLE), 1) -CFLAGS := ${CFLAGS} -D_MOON_SUFFIX=-$(shell git rev-parse --short HEAD) -endif - -ifeq ($(MOON_BUILD_DEBUG), 1) -CFLAGS := -ggdb -fsanitize=undefined ${CFLAGS} -endif - -rwildcard=$(foreach d,$(wildcard $(1:=/*)),$(call rwildcard,$d,$2) $(filter $(subst *,%,$2),$d)) - -CXX_SRC = $(call rwildcard,$(MOON_SRC),*.cpp) -C_SRC = $(call rwildcard,$(MOON_SRC),*.c) -NASM_SRC = $(call rwildcard,$(MOON_SRC),*.asm) - -OBJS = $(patsubst $(MOON_SRC)/%.cpp, $(MOON_OBJ)/%.cpp.o, $(CXX_SRC)) -OBJS += $(patsubst $(MOON_SRC)/%.c, $(MOON_OBJ)/%.c.o, $(C_SRC)) -OBJS += $(patsubst $(MOON_SRC)/%.asm, $(MOON_OBJ)/%.asm.o, $(NASM_SRC)) - -default: $(MOON_BIN)/moon - -$(MOON_OBJ)/main.cpp.o: $(MOON_SRC)/main.cpp - @mkdir -p $(@D) - @$(CXX) $(CFLAGS) -fno-stack-protector $(CXXFLAGS) -o $@ -c $^ - @echo " CXX $^" - -$(MOON_OBJ)/misc/config.cpp.o: $(MOON_SRC)/misc/config.cpp FORCE - @mkdir -p $(@D) - @$(CXX) $(CFLAGS) $(CXXFLAGS) -o $@ -c $(MOON_SRC)/misc/config.cpp - @echo " CXX $^" - -$(MOON_OBJ)/init/Init.cpp.o: $(MOON_SRC)/init/Init.cpp - @mkdir -p $(@D) - @$(CXX) $(CFLAGS) -fno-stack-protector $(CXXFLAGS) -o $@ -c $^ - @echo " CXX $^" - -$(MOON_OBJ)/%.cpp.o: $(MOON_SRC)/%.cpp - @mkdir -p $(@D) - @$(CXX) $(CFLAGS) $(CXXFLAGS) -o $@ -c $^ - @echo " CXX $^" - -$(MOON_OBJ)/memory/liballoc/liballoc.c.o: $(MOON_SRC)/memory/liballoc/liballoc.c - @mkdir -p $(@D) - @$(CC) $(CFLAGS) -fno-sanitize=undefined -o $@ -c $^ - @echo " CC $^" - -$(MOON_OBJ)/%.c.o: $(MOON_SRC)/%.c - @mkdir -p $(@D) - @$(CC) $(CFLAGS) -o $@ -c $^ - @echo " CC $^" - -$(MOON_OBJ)/%.asm.o: $(MOON_SRC)/%.asm - @mkdir -p $(@D) - @$(ASM) $(ASMFLAGS) -o $@ $^ - @echo " ASM $^" - -build: $(OBJS) - @mkdir -p $(MOON_BIN) - @$(CC) $(OBJS) $(LDFLAGS) -o $(MOON_BIN)/moon - @echo " CCLD $(MOON_BIN)/moon" - -clean: - rm -rf $(MOON_OBJ)/* - rm -rf $(MOON_BIN)/* - -install: $(MOON_BIN)/moon - @mkdir -p $(LUNA_ROOT)/initrd/boot - @cp $^ $(LUNA_ROOT)/initrd/boot/moon - @echo " INSTALL $^" - @$(LUNA_ROOT)/tools/generate-symbols.sh - @$(STRIP) $(LUNA_ROOT)/initrd/boot/moon - @echo " STRIP $(LUNA_ROOT)/initrd/boot/moon" - -.PHONY: build clean install FORCE -FORCE: \ No newline at end of file diff --git a/kernel/include/acpi/FADT.h b/kernel/include/acpi/FADT.h deleted file mode 100644 index 553bb43c..00000000 --- a/kernel/include/acpi/FADT.h +++ /dev/null @@ -1,93 +0,0 @@ -#pragma once -#include "acpi/SDT.h" - -namespace ACPI -{ - enum AddressSpace - { - SystemMemory = 0, - SystemIO = 1, - PCI = 2, - EmbeddedController = 3, - SystemManagementBus = 4, - SystemCMOS = 5, - PCIBarTarget = 6, - IPMI = 7, - GeneralPurposeIO = 8, - GenericSerialBus = 9, - PlatformCommunicationChannel = 10 - }; - - struct GenericAddressStructure - { - uint8_t AddressSpace; - uint8_t BitWidth; - uint8_t BitOffset; - uint8_t AccessSize; - uint64_t Address; - }; - - struct FADT - { - SDTHeader header; - uint32_t FirmwareCtrl; - uint32_t Dsdt; - - uint8_t Reserved; - - uint8_t PreferredPowerManagementProfile; - uint16_t SCI_Interrupt; - uint32_t SMI_CommandPort; - uint8_t AcpiEnable; - uint8_t AcpiDisable; - uint8_t S4BIOS_REQ; - uint8_t PSTATE_Control; - uint32_t PM1aEventBlock; - uint32_t PM1bEventBlock; - uint32_t PM1aControlBlock; - uint32_t PM1bControlBlock; - uint32_t PM2ControlBlock; - uint32_t PMTimerBlock; - uint32_t GPE0Block; - uint32_t GPE1Block; - uint8_t PM1EventLength; - uint8_t PM1ControlLength; - uint8_t PM2ControlLength; - uint8_t PMTimerLength; - uint8_t GPE0Length; - uint8_t GPE1Length; - uint8_t GPE1Base; - uint8_t CStateControl; - uint16_t WorstC2Latency; - uint16_t WorstC3Latency; - uint16_t FlushSize; - uint16_t FlushStride; - uint8_t DutyOffset; - uint8_t DutyWidth; - uint8_t DayAlarm; - uint8_t MonthAlarm; - uint8_t Century; - - uint16_t BootArchitectureFlags; - - uint8_t Reserved2; - uint32_t Flags; - - GenericAddressStructure ResetReg; - - uint8_t ResetValue; - uint8_t Reserved3[3]; - - uint64_t X_FirmwareControl; - uint64_t X_Dsdt; - - GenericAddressStructure X_PM1aEventBlock; - GenericAddressStructure X_PM1bEventBlock; - GenericAddressStructure X_PM1aControlBlock; - GenericAddressStructure X_PM1bControlBlock; - GenericAddressStructure X_PM2ControlBlock; - GenericAddressStructure X_PMTimerBlock; - GenericAddressStructure X_GPE0Block; - GenericAddressStructure X_GPE1Block; - }; -} \ No newline at end of file diff --git a/kernel/include/acpi/RSDT.h b/kernel/include/acpi/RSDT.h deleted file mode 100644 index 9e136cb7..00000000 --- a/kernel/include/acpi/RSDT.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once -#include "acpi/SDT.h" - -namespace ACPI -{ - struct XSDT - { - SDTHeader header; - uint64_t other_sdt[1]; - }; - - struct RSDT - { - SDTHeader header; - uint32_t other_sdt[1]; - }; - - SDTHeader* get_rsdt_or_xsdt(); - - bool validate_rsdt_or_xsdt(SDTHeader* root_sdt); - - bool is_xsdt(); - - void* find_table(SDTHeader* root_sdt, const char* signature); -} \ No newline at end of file diff --git a/kernel/include/acpi/SDT.h b/kernel/include/acpi/SDT.h deleted file mode 100644 index b757203c..00000000 --- a/kernel/include/acpi/SDT.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once -#include - -namespace ACPI -{ - struct SDTHeader - { - char Signature[4]; - uint32_t Length; - uint8_t Revision; - uint8_t Checksum; - char OEMID[6]; - char OEMTableID[8]; - uint32_t OEMRevision; - uint32_t CreatorID; - uint32_t CreatorRevision; - }; - - bool validate_sdt_header(SDTHeader* header); -} \ No newline at end of file diff --git a/kernel/include/config.h b/kernel/include/config.h deleted file mode 100644 index f59a47e0..00000000 --- a/kernel/include/config.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -int __moon_version_major(); -int __moon_version_minor(); -const char* __moon_version_suffix(); - -const char* moon_version(); \ No newline at end of file diff --git a/kernel/include/cpu/CPU.h b/kernel/include/cpu/CPU.h deleted file mode 100644 index 81b0ef83..00000000 --- a/kernel/include/cpu/CPU.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once -#include "cpu/Features.h" -#include - -namespace CPU -{ - const char* get_vendor_string(); - const char* get_brand_string(); - void log_cpu_information(); - uint64_t get_feature_bitmask(); - uint64_t get_initial_apic_id(); - bool has_feature(CPU::Features); - bool has_nx(); -} \ No newline at end of file diff --git a/kernel/include/cpu/Features.h b/kernel/include/cpu/Features.h deleted file mode 100644 index c5e99053..00000000 --- a/kernel/include/cpu/Features.h +++ /dev/null @@ -1,72 +0,0 @@ -#pragma once - -namespace CPU -{ - enum class Features - { - FPU, - VME, - DE, - PSE, - TSC, - MSR, - PAE, - MCE, - CX8, - APIC, - UNUSED1, - SEP, - MTRR, - PGE, - MCA, - CMOV, - PAT, - PSE36, - PSN, - CLFLUSH, - UNUSED2, - DS, - ACPI, - MMX, - FXSR, - SSE, - SSE2, - SS, - HTT, - TM, - IA64, - PBE, - SSE3, - PCLMUL, - DTES64, - MONITOR, - DS_CPL, - VMX, - SMX, - EST, - TM2, - SSSE3, - CID, - SDBG, - FMA, - CX16, - XTPR, - PDCM, - UNUSED3, - PCID, - DCA, - SSE4_1, - SSE4_2, - X2APIC, - MOVBE, - POPCNT, - TSC_2, - AES, - XSAVE, - OSXSAVE, - AVX, - F16C, - RDRAND, - HYPERVISOR, - }; -} \ No newline at end of file diff --git a/kernel/include/font.h b/kernel/include/font.h deleted file mode 100644 index 1122471f..00000000 --- a/kernel/include/font.h +++ /dev/null @@ -1,260 +0,0 @@ -#pragma once - -unsigned char font[] = { - 0x00, 0x00, 0x00, 0x00, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7e, 0x00, 0x00, 0x00, 0x00, /* 0 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1 */ - 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, /* 2 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 4 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 6 */ - 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 9 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10 */ - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 11 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 12 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 13 */ - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 14 */ - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 15 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 16 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 18 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 19 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 20 */ - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 21 */ - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0xf8, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 22 */ - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 24 */ - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 25 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 26 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 28 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 29 */ - 0x00, 0x00, 0x00, 0x1c, 0x22, 0x20, 0x20, 0xf8, 0x20, 0x20, 0x72, 0x8c, 0x00, 0x00, 0x00, 0x00, /* 30 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 31 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 32 */ - 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, /* 33 */ - 0x00, 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 34 */ - 0x00, 0x00, 0x00, 0x24, 0x24, 0x7e, 0x24, 0x24, 0x24, 0x7e, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, /* 35 */ - 0x00, 0x00, 0x08, 0x08, 0x1e, 0x20, 0x20, 0x1c, 0x02, 0x02, 0x3c, 0x08, 0x08, 0x00, 0x00, 0x00, /* 36 */ - 0x00, 0x00, 0x00, 0x30, 0x49, 0x4a, 0x34, 0x08, 0x16, 0x29, 0x49, 0x06, 0x00, 0x00, 0x00, 0x00, /* 37 */ - 0x00, 0x00, 0x30, 0x48, 0x48, 0x48, 0x30, 0x31, 0x49, 0x46, 0x46, 0x39, 0x00, 0x00, 0x00, 0x00, /* 38 */ - 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 39 */ - 0x00, 0x00, 0x04, 0x08, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x04, 0x00, 0x00, /* 40 */ - 0x00, 0x00, 0x20, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x10, 0x10, 0x20, 0x00, 0x00, /* 41 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x18, 0x7e, 0x18, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 42 */ - 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x7f, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, /* 43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x08, 0x08, 0x10, 0x00, /* 44 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 45 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, /* 46 */ - 0x00, 0x00, 0x02, 0x02, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x00, 0x00, /* 47 */ - 0x00, 0x00, 0x00, 0x3c, 0x42, 0x46, 0x4a, 0x52, 0x62, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 48 */ - 0x00, 0x00, 0x00, 0x08, 0x18, 0x28, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 49 */ - 0x00, 0x00, 0x00, 0x3c, 0x42, 0x02, 0x02, 0x04, 0x08, 0x10, 0x20, 0x7e, 0x00, 0x00, 0x00, 0x00, /* 50 */ - 0x00, 0x00, 0x00, 0x7e, 0x04, 0x08, 0x1c, 0x02, 0x02, 0x02, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 51 */ - 0x00, 0x00, 0x00, 0x04, 0x0c, 0x14, 0x24, 0x44, 0x7e, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, /* 52 */ - 0x00, 0x00, 0x00, 0x7e, 0x40, 0x40, 0x7c, 0x02, 0x02, 0x02, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 53 */ - 0x00, 0x00, 0x00, 0x1c, 0x20, 0x40, 0x40, 0x7c, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 54 */ - 0x00, 0x00, 0x00, 0x7e, 0x02, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, /* 55 */ - 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x3c, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 56 */ - 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x04, 0x38, 0x00, 0x00, 0x00, 0x00, /* 57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, /* 58 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x08, 0x08, 0x10, 0x00, /* 59 */ - 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, /* 60 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 61 */ - 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, /* 62 */ - 0x00, 0x00, 0x3c, 0x42, 0x02, 0x04, 0x08, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, /* 63 */ - 0x00, 0x00, 0x1c, 0x22, 0x41, 0x4f, 0x51, 0x51, 0x51, 0x53, 0x4d, 0x40, 0x20, 0x1f, 0x00, 0x00, /* 64 */ - 0x00, 0x00, 0x00, 0x18, 0x24, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, /* 65 */ - 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x00, 0x00, 0x00, 0x00, /* 66 */ - 0x00, 0x00, 0x00, 0x1e, 0x20, 0x40, 0x40, 0x40, 0x40, 0x40, 0x20, 0x1e, 0x00, 0x00, 0x00, 0x00, /* 67 */ - 0x00, 0x00, 0x00, 0x78, 0x44, 0x42, 0x42, 0x42, 0x42, 0x42, 0x44, 0x78, 0x00, 0x00, 0x00, 0x00, /* 68 */ - 0x00, 0x00, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, /* 69 */ - 0x00, 0x00, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, /* 70 */ - 0x00, 0x00, 0x00, 0x1e, 0x20, 0x40, 0x40, 0x46, 0x42, 0x42, 0x22, 0x1e, 0x00, 0x00, 0x00, 0x00, /* 71 */ - 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, /* 72 */ - 0x00, 0x00, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 73 */ - 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 74 */ - 0x00, 0x00, 0x00, 0x42, 0x44, 0x48, 0x50, 0x60, 0x50, 0x48, 0x44, 0x42, 0x00, 0x00, 0x00, 0x00, /* 75 */ - 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, /* 76 */ - 0x00, 0x00, 0x00, 0x41, 0x63, 0x55, 0x49, 0x49, 0x41, 0x41, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00, /* 77 */ - 0x00, 0x00, 0x00, 0x42, 0x62, 0x52, 0x4a, 0x46, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, /* 78 */ - 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 79 */ - 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, /* 80 */ - 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x04, 0x02, 0x00, 0x00, /* 81 */ - 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x48, 0x44, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, /* 82 */ - 0x00, 0x00, 0x00, 0x3e, 0x40, 0x40, 0x20, 0x18, 0x04, 0x02, 0x02, 0x7c, 0x00, 0x00, 0x00, 0x00, /* 83 */ - 0x00, 0x00, 0x00, 0x7f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, /* 84 */ - 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 85 */ - 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x24, 0x24, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, /* 86 */ - 0x00, 0x00, 0x00, 0x41, 0x41, 0x41, 0x41, 0x49, 0x49, 0x49, 0x55, 0x63, 0x00, 0x00, 0x00, 0x00, /* 87 */ - 0x00, 0x00, 0x00, 0x41, 0x41, 0x22, 0x14, 0x08, 0x14, 0x22, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00, /* 88 */ - 0x00, 0x00, 0x00, 0x41, 0x41, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, /* 89 */ - 0x00, 0x00, 0x00, 0x7e, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x7e, 0x00, 0x00, 0x00, 0x00, /* 90 */ - 0x00, 0x00, 0x1e, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1e, 0x00, 0x00, /* 91 */ - 0x00, 0x00, 0x40, 0x40, 0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x04, 0x04, 0x02, 0x02, 0x00, 0x00, /* 92 */ - 0x00, 0x00, 0x78, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x78, 0x00, 0x00, /* 93 */ - 0x00, 0x00, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 94 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, /* 95 */ - 0x00, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 96 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x02, 0x02, 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 97 */ - 0x00, 0x00, 0x40, 0x40, 0x40, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7c, 0x00, 0x00, 0x00, 0x00, /* 98 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x40, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 99 */ - 0x00, 0x00, 0x02, 0x02, 0x02, 0x3e, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 100 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x7e, 0x40, 0x40, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 101 */ - 0x00, 0x00, 0x0e, 0x10, 0x10, 0x7e, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, /* 102 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x3c, 0x00, /* 103 */ - 0x00, 0x00, 0x40, 0x40, 0x40, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, /* 104 */ - 0x00, 0x00, 0x08, 0x08, 0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 105 */ - 0x00, 0x00, 0x04, 0x04, 0x00, 0x1c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x38, 0x00, /* 106 */ - 0x00, 0x00, 0x40, 0x40, 0x40, 0x44, 0x48, 0x50, 0x70, 0x48, 0x44, 0x42, 0x00, 0x00, 0x00, 0x00, /* 107 */ - 0x00, 0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 108 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x00, 0x00, 0x00, 0x00, /* 109 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, /* 110 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 111 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7c, 0x40, 0x40, 0x40, 0x00, /* 112 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x02, 0x00, /* 113 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, /* 114 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x20, 0x18, 0x04, 0x02, 0x7c, 0x00, 0x00, 0x00, 0x00, /* 115 */ - 0x00, 0x00, 0x00, 0x10, 0x10, 0x7e, 0x10, 0x10, 0x10, 0x10, 0x10, 0x0e, 0x00, 0x00, 0x00, 0x00, /* 116 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 117 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x24, 0x24, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, /* 118 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x41, 0x49, 0x49, 0x55, 0x63, 0x00, 0x00, 0x00, 0x00, /* 119 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x22, 0x14, 0x08, 0x14, 0x22, 0x41, 0x00, 0x00, 0x00, 0x00, /* 120 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x3c, 0x00, /* 121 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x04, 0x08, 0x10, 0x20, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, /* 122 */ - 0x00, 0x0e, 0x10, 0x10, 0x10, 0x10, 0x10, 0xe0, 0x10, 0x10, 0x10, 0x10, 0x10, 0x0e, 0x00, 0x00, /* 123 */ - 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, /* 124 */ - 0x00, 0x70, 0x08, 0x08, 0x08, 0x08, 0x08, 0x07, 0x08, 0x08, 0x08, 0x08, 0x08, 0x70, 0x00, 0x00, /* 125 */ - 0x00, 0x00, 0x31, 0x49, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 126 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 127 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 128 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 129 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 130 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 131 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 132 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 133 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 134 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 135 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 136 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 137 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 138 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 139 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 140 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 141 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 142 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 143 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 144 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 145 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 146 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 147 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 148 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 149 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 150 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 151 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 152 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 153 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 154 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 155 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 156 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 157 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 158 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 159 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 160 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, /* 161 */ - 0x00, 0x00, 0x08, 0x08, 0x1c, 0x22, 0x40, 0x40, 0x40, 0x22, 0x1c, 0x08, 0x08, 0x00, 0x00, 0x00, /* 162 */ - 0x00, 0x00, 0x00, 0x1c, 0x22, 0x20, 0x20, 0xf8, 0x20, 0x20, 0x72, 0x8c, 0x00, 0x00, 0x00, 0x00, /* 163 */ - 0x00, 0x00, 0x00, 0x00, 0x42, 0x3c, 0x24, 0x24, 0x24, 0x3c, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, /* 164 */ - 0x00, 0x00, 0x00, 0x41, 0x22, 0x14, 0x08, 0x3e, 0x08, 0x3e, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, /* 165 */ - 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, /* 166 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 167 */ - 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 168 */ - 0x00, 0x00, 0x00, 0x1c, 0x22, 0x41, 0x4d, 0x51, 0x51, 0x4d, 0x41, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 169 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 170 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x12, 0x24, 0x48, 0x24, 0x12, 0x09, 0x00, 0x00, 0x00, 0x00, /* 171 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 172 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 173 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 174 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 175 */ - 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 176 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 177 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 178 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 179 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 180 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 181 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 182 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 183 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x30, 0x00, /* 184 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 185 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 186 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x24, 0x12, 0x09, 0x12, 0x24, 0x48, 0x00, 0x00, 0x00, 0x00, /* 187 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 188 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 189 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 190 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x08, 0x10, 0x20, 0x40, 0x42, 0x3c, 0x00, /* 191 */ - 0x20, 0x10, 0x00, 0x18, 0x18, 0x24, 0x24, 0x24, 0x7e, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, /* 192 */ - 0x04, 0x08, 0x00, 0x18, 0x18, 0x24, 0x24, 0x24, 0x7e, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, /* 193 */ - 0x18, 0x24, 0x00, 0x18, 0x18, 0x24, 0x24, 0x24, 0x7e, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, /* 194 */ - 0x32, 0x4c, 0x00, 0x18, 0x18, 0x24, 0x24, 0x24, 0x7e, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, /* 195 */ - 0x24, 0x24, 0x00, 0x18, 0x18, 0x24, 0x24, 0x24, 0x7e, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, /* 196 */ - 0x18, 0x24, 0x24, 0x18, 0x18, 0x24, 0x24, 0x24, 0x7e, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, /* 197 */ - 0x00, 0x00, 0x00, 0x0f, 0x14, 0x14, 0x24, 0x27, 0x3c, 0x44, 0x44, 0x47, 0x00, 0x00, 0x00, 0x00, /* 198 */ - 0x00, 0x00, 0x00, 0x1e, 0x20, 0x40, 0x40, 0x40, 0x40, 0x40, 0x20, 0x1e, 0x08, 0x08, 0x30, 0x00, /* 199 */ - 0x20, 0x10, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, /* 200 */ - 0x04, 0x08, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, /* 201 */ - 0x18, 0x24, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, /* 202 */ - 0x24, 0x24, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, /* 203 */ - 0x10, 0x08, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 204 */ - 0x04, 0x08, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 205 */ - 0x18, 0x24, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 206 */ - 0x22, 0x22, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 207 */ - 0x00, 0x00, 0x00, 0x3c, 0x22, 0x21, 0x21, 0x79, 0x21, 0x21, 0x22, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 208 */ - 0x32, 0x4c, 0x00, 0x42, 0x62, 0x52, 0x4a, 0x46, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, /* 209 */ - 0x10, 0x08, 0x00, 0x1c, 0x22, 0x41, 0x41, 0x41, 0x41, 0x41, 0x22, 0x1c, 0x00, 0x00, 0x00, 0x00, /* 210 */ - 0x04, 0x08, 0x00, 0x1c, 0x22, 0x41, 0x41, 0x41, 0x41, 0x41, 0x22, 0x1c, 0x00, 0x00, 0x00, 0x00, /* 211 */ - 0x18, 0x24, 0x00, 0x1c, 0x22, 0x41, 0x41, 0x41, 0x41, 0x41, 0x22, 0x1c, 0x00, 0x00, 0x00, 0x00, /* 212 */ - 0x32, 0x4c, 0x00, 0x1c, 0x22, 0x41, 0x41, 0x41, 0x41, 0x41, 0x22, 0x1c, 0x00, 0x00, 0x00, 0x00, /* 213 */ - 0x24, 0x24, 0x00, 0x1c, 0x22, 0x41, 0x41, 0x41, 0x41, 0x41, 0x22, 0x1c, 0x00, 0x00, 0x00, 0x00, /* 214 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, /* 215 */ - 0x00, 0x00, 0x02, 0x3c, 0x42, 0x46, 0x4a, 0x52, 0x62, 0x42, 0x42, 0x3c, 0x40, 0x00, 0x00, 0x00, /* 216 */ - 0x20, 0x10, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 217 */ - 0x04, 0x08, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 218 */ - 0x18, 0x24, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 219 */ - 0x24, 0x24, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 220 */ - 0x04, 0x08, 0x00, 0x41, 0x41, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, /* 221 */ - 0x00, 0x00, 0x00, 0x40, 0x40, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, /* 222 */ - 0x00, 0x00, 0x00, 0x3c, 0x42, 0x44, 0x4c, 0x42, 0x42, 0x42, 0x44, 0x58, 0x00, 0x00, 0x00, 0x00, /* 223 */ - 0x00, 0x00, 0x20, 0x10, 0x00, 0x3c, 0x02, 0x02, 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 224 */ - 0x00, 0x00, 0x04, 0x08, 0x00, 0x3c, 0x02, 0x02, 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 225 */ - 0x00, 0x18, 0x24, 0x00, 0x00, 0x3c, 0x02, 0x02, 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 226 */ - 0x00, 0x32, 0x4c, 0x00, 0x00, 0x3c, 0x02, 0x02, 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 227 */ - 0x00, 0x00, 0x24, 0x24, 0x00, 0x3c, 0x02, 0x02, 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 228 */ - 0x18, 0x24, 0x24, 0x18, 0x00, 0x3c, 0x02, 0x02, 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 229 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x09, 0x39, 0x4f, 0x48, 0x48, 0x37, 0x00, 0x00, 0x00, 0x00, /* 230 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x40, 0x40, 0x40, 0x42, 0x3c, 0x08, 0x08, 0x30, 0x00, /* 231 */ - 0x00, 0x00, 0x20, 0x10, 0x00, 0x3c, 0x42, 0x42, 0x7e, 0x40, 0x40, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 232 */ - 0x00, 0x00, 0x04, 0x08, 0x00, 0x3c, 0x42, 0x42, 0x7e, 0x40, 0x40, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 233 */ - 0x00, 0x18, 0x24, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x7e, 0x40, 0x40, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 234 */ - 0x00, 0x00, 0x24, 0x24, 0x00, 0x3c, 0x42, 0x42, 0x7e, 0x40, 0x40, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 235 */ - 0x00, 0x00, 0x10, 0x08, 0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 236 */ - 0x00, 0x00, 0x04, 0x08, 0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 237 */ - 0x00, 0x18, 0x24, 0x00, 0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 238 */ - 0x00, 0x00, 0x24, 0x24, 0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 239 */ - 0x00, 0x09, 0x06, 0x1a, 0x01, 0x1d, 0x23, 0x41, 0x41, 0x41, 0x22, 0x1c, 0x00, 0x00, 0x00, 0x00, /* 240 */ - 0x00, 0x32, 0x4c, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, /* 241 */ - 0x00, 0x00, 0x10, 0x08, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 242 */ - 0x00, 0x00, 0x04, 0x08, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 243 */ - 0x00, 0x18, 0x24, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 244 */ - 0x00, 0x32, 0x4c, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 245 */ - 0x00, 0x00, 0x24, 0x24, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 246 */ - 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, /* 247 */ - 0x00, 0x00, 0x00, 0x00, 0x02, 0x3c, 0x46, 0x4a, 0x52, 0x62, 0x42, 0x3c, 0x40, 0x00, 0x00, 0x00, /* 248 */ - 0x00, 0x00, 0x20, 0x10, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 249 */ - 0x00, 0x00, 0x04, 0x08, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 250 */ - 0x00, 0x18, 0x24, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 251 */ - 0x00, 0x00, 0x24, 0x24, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 252 */ - 0x00, 0x00, 0x04, 0x08, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x3c, 0x00, /* 253 */ - 0x00, 0x00, 0x40, 0x40, 0x40, 0x5c, 0x62, 0x41, 0x41, 0x41, 0x62, 0x5c, 0x40, 0x40, 0x40, 0x00, /* 254 */ - 0x00, 0x00, 0x24, 0x24, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x3c, 0x00, - /* 255 */}; \ No newline at end of file diff --git a/kernel/include/fs/FileDescriptor.h b/kernel/include/fs/FileDescriptor.h deleted file mode 100644 index 9e34df83..00000000 --- a/kernel/include/fs/FileDescriptor.h +++ /dev/null @@ -1,83 +0,0 @@ -#pragma once -#include "fs/VFS.h" -#include - -struct Descriptor -{ - bool is_open() - { - return m_is_open; - } - - bool can_read() - { - return m_can_read && m_is_open; - } - - bool can_write() - { - return m_can_write && m_is_open; - } - - void close() - { - m_is_open = false; - } - - VFS::Node* node() - { - return m_node; - } - - ssize_t read(size_t size, char* buffer); - ssize_t write(size_t size, const char* buffer); - - ssize_t user_read(size_t size, char* buffer); - ssize_t user_write(size_t size, const char* buffer); - - uintptr_t mmap(uintptr_t addr, size_t size, int prot, off_t offset); - - long ioctl(int cmd, uintptr_t arg); - - void open(VFS::Node* node, bool can_read, bool can_write, bool able_to_block, bool close_on_exec); - - int seek(long offset); - long offset() - { - return (long)m_offset; - } - - unsigned long length() - { - return m_node->length; - } - - bool able_to_block() - { - return m_able_to_block; - } - - bool close_on_exec() - { - return m_close_on_exec; - } - - void set_close_on_exec(bool value) - { - m_close_on_exec = value; - } - - Descriptor(const Descriptor& other); - Descriptor(); - - const Descriptor& operator=(const Descriptor& other); - - private: - bool m_is_open; - bool m_can_read; - bool m_can_write; - bool m_able_to_block; - bool m_close_on_exec; - VFS::Node* m_node; - uint64_t m_offset; -}; \ No newline at end of file diff --git a/kernel/include/fs/InitRD.h b/kernel/include/fs/InitRD.h deleted file mode 100644 index d0ce7b42..00000000 --- a/kernel/include/fs/InitRD.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once -#include -#include - -#define TAR_MAGIC "ustar" -#define TAR_BLOCKSIZE 512 - -namespace InitRD -{ - struct TarHeader - { /* byte offset */ - char name[100]; /* 0 */ - char mode[8]; /* 100 */ - char uid[8]; /* 108 */ - char gid[8]; /* 116 */ - char size[12]; /* 124 */ - char mtime[12]; /* 136 */ - char chksum[8]; /* 148 */ - char typeflag; /* 156 */ - char linkname[100]; /* 157 */ - char magic[6]; /* 257 */ - char version[2]; /* 263 */ - char uname[32]; /* 265 */ - char gname[32]; /* 297 */ - char devmajor[8]; /* 329 */ - char devminor[8]; /* 337 */ - char prefix[155]; /* 345 */ - /* 500 */ - } __attribute__((packed)); - - struct File - { - char name[100]; - uint64_t size; - uint64_t size_in_blocks; - void* addr; - mode_t mode; - }; - - uint64_t get_total_blocks(); - File get_file(TarHeader* header); - void free_file(File& file); - TarHeader* get_block(uint64_t block_index); - bool is_valid_header(TarHeader* header); - - uint64_t get_file_physical_address(File& file); - - File open(const char* filename); - void for_each(void (*callback)(File& file)); - - bool is_initialized(); - - void init(); -} \ No newline at end of file diff --git a/kernel/include/fs/VFS.h b/kernel/include/fs/VFS.h deleted file mode 100644 index d8db1b15..00000000 --- a/kernel/include/fs/VFS.h +++ /dev/null @@ -1,86 +0,0 @@ -#pragma once -#include -#include -#include - -typedef long ssize_t; - -#define VFS_FILE 0x0 -#define VFS_DIRECTORY 0x1 -#define VFS_DEVICE 0x2 - -#define VFS_MOUNTPOINT 0x1 - -#define NAME_MAX 64 - -namespace VFS -{ - struct Node; - - typedef ssize_t (*node_read)(Node*, size_t, size_t, char*); - typedef ssize_t (*node_write)(Node*, size_t, size_t, const char*); - typedef Node* (*node_finddir)(Node*, const char*); - typedef int (*node_mkdir)(Node*, const char*, mode_t); - typedef int (*node_block)(Node*); - typedef Node* (*node_readdir)(Node*, long); - typedef uintptr_t (*node_mmap)(Node*, uintptr_t, size_t, int, off_t); - typedef long (*node_ioctl)(Node*, int, uintptr_t); - - struct Node - { - char name[NAME_MAX]; - int type; - int flags; - int tty = 0; - int uid; - int gid; - mode_t mode; - uint64_t impl; - uint64_t atime; - uint64_t ctime; - uint64_t mtime; - uint64_t inode; - uint64_t length; - node_read read_func; - node_finddir find_func; - node_readdir readdir_func; - node_mkdir mkdir_func; - node_write write_func; - node_block block_func; - node_mmap mmap_func; - node_ioctl ioctl_func; - Node* link; - }; - - ssize_t read(Node* node, size_t offset, size_t length, char* buffer); - ssize_t write(Node* node, size_t offset, size_t length, const char* buffer); - int mkdir(const char* path, const char* name); - int mkdir(const char* pathname); - - int do_mkdir(const char* path, const char* name, int uid, int gid, mode_t mode); - int do_mkdir(const char* pathname, int uid, int gid, mode_t mode); - - int would_block(Node* node); - - void mount_root(Node* root); - - Node* resolve_path(const char* filename, Node* root = nullptr); - - bool exists(const char* pathname); - - void mount(Node* mountpoint, Node* mounted); - void mount(const char* pathname, Node* mounted); - - void unmount(Node* mountpoint); - - Node* root(); - - Node* readdir(Node* dir, long offset); - - bool can_execute(Node* node, int uid, int gid); - bool can_read(Node* node, int uid, int gid); - bool can_write(Node* node, int uid, int gid); - - bool is_setuid(Node* node); - bool is_setgid(Node* node); -} \ No newline at end of file diff --git a/kernel/include/fs/devices/Console.h b/kernel/include/fs/devices/Console.h deleted file mode 100644 index aef42b14..00000000 --- a/kernel/include/fs/devices/Console.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include "fs/VFS.h" - -namespace ConsoleDevice -{ - VFS::Node* create_new(const char* devname); - - ssize_t write(VFS::Node* node, size_t offset, size_t size, const char* buffer); - - ssize_t read(VFS::Node* node, size_t offset, size_t size, char* buffer); - - int would_block(VFS::Node* node); - - void append(char c); -} \ No newline at end of file diff --git a/kernel/include/fs/devices/DeviceFS.h b/kernel/include/fs/devices/DeviceFS.h deleted file mode 100644 index d6a37998..00000000 --- a/kernel/include/fs/devices/DeviceFS.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once -#include "fs/VFS.h" - -namespace DeviceFS -{ - VFS::Node* get(); - - VFS::Node* finddir(VFS::Node* node, const char* filename); - VFS::Node* readdir(VFS::Node* node, long offset); -} \ No newline at end of file diff --git a/kernel/include/fs/devices/Framebuffer.h b/kernel/include/fs/devices/Framebuffer.h deleted file mode 100644 index 32b2a04f..00000000 --- a/kernel/include/fs/devices/Framebuffer.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "fs/VFS.h" - -namespace FramebufferDevice -{ - VFS::Node* create_new(const char* devname); - - ssize_t write(VFS::Node* node, size_t offset, size_t size, const char* buffer); - - uintptr_t mmap(VFS::Node* node, uintptr_t addr, size_t size, int prot, off_t offset); - - long ioctl(VFS::Node* node, int cmd, uintptr_t arg); -} \ No newline at end of file diff --git a/kernel/include/fs/devices/Keyboard.h b/kernel/include/fs/devices/Keyboard.h deleted file mode 100644 index 3dc30575..00000000 --- a/kernel/include/fs/devices/Keyboard.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "fs/VFS.h" - -namespace KeyboardDevice -{ - VFS::Node* create_new(const char* devname); - - ssize_t read(VFS::Node* node, size_t offset, size_t size, char* buffer); - - int would_block(VFS::Node* node); - - void append(char c); -} \ No newline at end of file diff --git a/kernel/include/fs/devices/NullDevice.h b/kernel/include/fs/devices/NullDevice.h deleted file mode 100644 index 5c264fcd..00000000 --- a/kernel/include/fs/devices/NullDevice.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once -#include "fs/VFS.h" - -namespace NullDevice -{ - VFS::Node* create_new(const char* devname); - - ssize_t write(VFS::Node* node, size_t offset, size_t size, const char* buffer); - ssize_t read(VFS::Node* node, size_t offset, size_t size, char* buffer); -} \ No newline at end of file diff --git a/kernel/include/fs/devices/Random.h b/kernel/include/fs/devices/Random.h deleted file mode 100644 index 916ba0c4..00000000 --- a/kernel/include/fs/devices/Random.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "fs/VFS.h" - -namespace RandomDevice -{ - VFS::Node* create_new(const char* devname); - - ssize_t read(VFS::Node* node, size_t offset, size_t size, char* buffer); -} \ No newline at end of file diff --git a/kernel/include/fs/devices/Serial.h b/kernel/include/fs/devices/Serial.h deleted file mode 100644 index 2f9728ca..00000000 --- a/kernel/include/fs/devices/Serial.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "fs/VFS.h" - -namespace SerialDevice -{ - VFS::Node* create_new(const char* devname); - - ssize_t write(VFS::Node* node, size_t offset, size_t size, const char* buffer); -} \ No newline at end of file diff --git a/kernel/include/fs/devices/Version.h b/kernel/include/fs/devices/Version.h deleted file mode 100644 index 72590515..00000000 --- a/kernel/include/fs/devices/Version.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "fs/VFS.h" - -namespace VersionDevice -{ - VFS::Node* create_new(const char* devname); - - ssize_t read(VFS::Node* node, size_t offset, size_t size, char* buffer); -} \ No newline at end of file diff --git a/kernel/include/gdt/GDT.h b/kernel/include/gdt/GDT.h deleted file mode 100644 index 297199ad..00000000 --- a/kernel/include/gdt/GDT.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -namespace GDT -{ - void load(); -} \ No newline at end of file diff --git a/kernel/include/interrupts/Context.h b/kernel/include/interrupts/Context.h deleted file mode 100644 index 41f60847..00000000 --- a/kernel/include/interrupts/Context.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once -#include - -struct Context -{ - uint64_t cr2, ds; - uint64_t r15, r14, r13, r12, r11, r10, r9, r8, rsi, rdi, rbp, rdx, rcx, rbx, rax; - uint64_t number; - union { - uint64_t error_code; - uint64_t irq_number; - }; - uint64_t rip, cs, rflags, rsp, ss; -}; \ No newline at end of file diff --git a/kernel/include/interrupts/IDT.h b/kernel/include/interrupts/IDT.h deleted file mode 100644 index edded58e..00000000 --- a/kernel/include/interrupts/IDT.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once -#include - -#define IDT_TA_InterruptGate 0b10001110 -#define IDT_TA_InterruptGateUser 0b11101110 -#define IDT_TA_TrapGate 0b10001111 - -struct IDTR -{ - uint16_t limit; - uint64_t offset; -} __attribute__((packed)); - -namespace IDT -{ - void add_handler(short interrupt_number, void* handler, uint8_t type_attr); - void load(); -} \ No newline at end of file diff --git a/kernel/include/interrupts/IRQ.h b/kernel/include/interrupts/IRQ.h deleted file mode 100644 index a61540ce..00000000 --- a/kernel/include/interrupts/IRQ.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once -#include "Context.h" - -namespace IRQ -{ - void interrupt_handler(Context* context); -} \ No newline at end of file diff --git a/kernel/include/interrupts/Install.h b/kernel/include/interrupts/Install.h deleted file mode 100644 index 18d985b2..00000000 --- a/kernel/include/interrupts/Install.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once -#include - -namespace Interrupts -{ - void install(); -} \ No newline at end of file diff --git a/kernel/include/interrupts/Interrupts.h b/kernel/include/interrupts/Interrupts.h deleted file mode 100644 index e5e5b26f..00000000 --- a/kernel/include/interrupts/Interrupts.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#include "interrupts/Context.h" - -namespace Interrupts -{ - void enable(); - void disable(); - - bool is_in_handler(); - void return_from_handler(Context* context); - - bool are_enabled(); - bool were_enabled(); - void push_and_disable(); - void push_and_enable(); - void pop(); -} \ No newline at end of file diff --git a/kernel/include/io/IO.h b/kernel/include/io/IO.h deleted file mode 100644 index 883983ad..00000000 --- a/kernel/include/io/IO.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include - -namespace IO -{ - uint8_t inb(uint16_t); - void outb(uint16_t, uint8_t); - uint16_t inw(uint16_t); - void outw(uint16_t, uint16_t); - uint32_t inl(uint16_t); - void outl(uint16_t, uint32_t); - void delay(); -} \ No newline at end of file diff --git a/kernel/include/io/PCI.h b/kernel/include/io/PCI.h deleted file mode 100644 index e5bea2e6..00000000 --- a/kernel/include/io/PCI.h +++ /dev/null @@ -1,98 +0,0 @@ -#pragma once -#include - -#define PCI_VENDOR_FIELD 0x0 -#define PCI_DEVICE_FIELD 0x2 -#define PCI_SUBCLASS_FIELD 0xa -#define PCI_CLASS_FIELD 0xb -#define PCI_REVISION_ID_FIELD 0x8 -#define PCI_PROG_IF_FIELD 0x9 -#define PCI_HEADER_TYPE_FIELD 0xe -#define PCI_SECONDARY_BUS_NUMBER_FIELD 0x19 -#define PCI_BAR0_FIELD 0x10 -#define PCI_BAR1_FIELD 0x14 -#define PCI_BAR2_FIELD 0x18 -#define PCI_BAR3_FIELD 0x1C -#define PCI_BAR4_FIELD 0x20 -#define PCI_BAR5_FIELD 0x24 - -namespace PCI -{ - struct DeviceID - { - uint16_t vendor; - uint16_t device; - }; - - struct DeviceType - { - uint8_t dev_class; - uint8_t dev_subclass; - uint8_t prog_if; - uint8_t revision; - }; - - struct Device - { - void write8(int32_t offset, uint8_t value); - void write16(int32_t offset, uint16_t value); - void write32(int32_t offset, uint32_t value); - uint8_t read8(int32_t offset); - uint16_t read16(int32_t offset); - uint32_t read32(int32_t offset); - - uint32_t getBAR0(); - uint32_t getBAR1(); - uint32_t getBAR2(); - uint32_t getBAR3(); - uint32_t getBAR4(); - uint32_t getBAR5(); - - uint8_t bus() - { - return m_bus; - } - - uint8_t slot() - { - return m_slot; - } - - uint8_t function() - { - return m_function; - } - - DeviceID id() - { - return m_id; - } - - DeviceType type() - { - return m_type; - } - - Device(DeviceID id, DeviceType type, uint8_t bus, uint8_t slot, uint8_t function); - Device(uint8_t bus, uint8_t slot, uint8_t function); - Device(const Device& other); - - private: - DeviceID m_id; - DeviceType m_type; - uint8_t m_bus; - uint8_t m_slot; - uint8_t m_function; - }; - - uint32_t raw_address(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset); - void raw_write8(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset, uint8_t value); - void raw_write16(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset, uint16_t value); - void raw_write32(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset, uint32_t value); - uint8_t raw_read8(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset); - uint16_t raw_read16(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset); - uint32_t raw_read32(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset); - DeviceID get_device_id(uint32_t bus, uint32_t slot, uint32_t function); - DeviceType get_device_type(uint32_t bus, uint32_t slot, uint32_t function); - void scan(void (*callback)(PCI::Device&)); -} \ No newline at end of file diff --git a/kernel/include/io/PIC.h b/kernel/include/io/PIC.h deleted file mode 100644 index 1aaf6079..00000000 --- a/kernel/include/io/PIC.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include - -namespace PIC -{ - void remap(); - void end_slave(); - void end_master(); - void enable_master(uint8_t mask); - void enable_slave(uint8_t mask); - void send_eoi(unsigned char irq); -} \ No newline at end of file diff --git a/kernel/include/io/Serial.h b/kernel/include/io/Serial.h deleted file mode 100644 index 9d371563..00000000 --- a/kernel/include/io/Serial.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "render/Color.h" -#include - -namespace Serial -{ - void wait(); - void write(const char* string, size_t size); - void print(const char* string); - void println(const char* string); - void set_color(Color& color); - void reset_color(); -} \ No newline at end of file diff --git a/kernel/include/log/CLog.h b/kernel/include/log/CLog.h deleted file mode 100644 index 0c02696a..00000000 --- a/kernel/include/log/CLog.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef _MOON_CLOG_H -#define _MOON_CLOG_H - -enum log_level -{ - LOG_DEBUG, - LOG_INFO, - LOG_WARN, - LOG_ERROR -}; - -#define PRINTF_LIKE(n, m) __attribute__((format(printf, n, m))) - -#ifdef __cplusplus -extern "C" -{ -#endif - - void clog_log(const char* function, enum log_level level, const char* message, ...) PRINTF_LIKE(3, 4); - void clog_logln(const char* function, enum log_level level, const char* message, ...) PRINTF_LIKE(3, 4); - -#ifdef __cplusplus -} -#endif - -#ifndef MODULE -#define kcommonlog(function, level, ...) clog_##function(__FUNCTION__, level, __VA_ARGS__) -#else -#define kcommonlog(function, level, ...) clog_##function(MODULE, level, __VA_ARGS__) -#endif - -#define kdbg(...) kcommonlog(log, LOG_DEBUG, __VA_ARGS__) -#define kdbgln(...) kcommonlog(logln, LOG_DEBUG, __VA_ARGS__) -#define kinfo(...) kcommonlog(log, LOG_INFO, __VA_ARGS__) -#define kinfoln(...) kcommonlog(logln, LOG_INFO, __VA_ARGS__) -#define kwarn(...) kcommonlog(log, LOG_WARN, __VA_ARGS__) -#define kwarnln(...) kcommonlog(logln, LOG_WARN, __VA_ARGS__) -#define kerror(...) kcommonlog(log, LOG_ERROR, __VA_ARGS__) -#define kerrorln(...) kcommonlog(logln, LOG_ERROR, __VA_ARGS__) - -#endif \ No newline at end of file diff --git a/kernel/include/log/Log.h b/kernel/include/log/Log.h deleted file mode 100644 index f27dcb80..00000000 --- a/kernel/include/log/Log.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -enum class LogLevel -{ - DEBUG, - INFO, - WARN, - ERROR -}; - -enum class Backend -{ - Serial, - Console -}; - -#define PRINTF_LIKE(n, m) __attribute__((format(printf, n, m))) - -namespace KernelLog -{ - void log(const char* function, LogLevel level, const char* message, ...) PRINTF_LIKE(3, 4); - void logln(const char* function, LogLevel level, const char* message, ...) PRINTF_LIKE(3, 4); - void toggle_log_level(LogLevel level); - void toggle_log_backend(Backend backend); - void enable_log_backend(Backend backend); -} - -#ifndef MODULE -#define kcommonlog(function, level, ...) KernelLog::function(__FUNCTION__, level, __VA_ARGS__) -#else -#define kcommonlog(function, level, ...) KernelLog::function(MODULE, level, __VA_ARGS__) -#endif - -#define kdbg(...) kcommonlog(log, LogLevel::DEBUG, __VA_ARGS__) -#define kdbgln(...) kcommonlog(logln, LogLevel::DEBUG, __VA_ARGS__) -#define kinfo(...) kcommonlog(log, LogLevel::INFO, __VA_ARGS__) -#define kinfoln(...) kcommonlog(logln, LogLevel::INFO, __VA_ARGS__) -#define kwarn(...) kcommonlog(log, LogLevel::WARN, __VA_ARGS__) -#define kwarnln(...) kcommonlog(logln, LogLevel::WARN, __VA_ARGS__) -#define kerror(...) kcommonlog(log, LogLevel::ERROR, __VA_ARGS__) -#define kerrorln(...) kcommonlog(logln, LogLevel::ERROR, __VA_ARGS__) \ No newline at end of file diff --git a/kernel/include/memory/AddressSpace.h b/kernel/include/memory/AddressSpace.h deleted file mode 100644 index c125b0a0..00000000 --- a/kernel/include/memory/AddressSpace.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once -#include "memory/Paging.h" -#include "utils/Result.h" - -struct AddressSpace -{ - static Result create(); - - void destroy(); - - void clear(); - - AddressSpace clone(); - - PageTable* get_pml4() - { - return m_pml4; - } - - private: - PageTable* m_pml4; -}; \ No newline at end of file diff --git a/kernel/include/memory/KernelHeap.h b/kernel/include/memory/KernelHeap.h deleted file mode 100644 index 5dc14d64..00000000 --- a/kernel/include/memory/KernelHeap.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include - -namespace KernelHeap -{ // Virtual memory allocator for the kernel, goes from -128MB to -64MB - uint64_t request_virtual_page(); - uint64_t request_virtual_pages(uint64_t count); - - void free_virtual_page(uint64_t address); - void free_virtual_pages(uint64_t address, uint64_t count); - - void clear(); - - void dump_usage(); -} \ No newline at end of file diff --git a/kernel/include/memory/Memory.h b/kernel/include/memory/Memory.h deleted file mode 100644 index aa5aebf3..00000000 --- a/kernel/include/memory/Memory.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once -#include - -namespace Memory -{ - uint64_t get_system(); - uint64_t get_usable(); - - bool is_user_address(uintptr_t address); - bool is_kernel_address(uintptr_t address); -} \ No newline at end of file diff --git a/kernel/include/memory/MemoryManager.h b/kernel/include/memory/MemoryManager.h deleted file mode 100644 index 3cecf2ae..00000000 --- a/kernel/include/memory/MemoryManager.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once -#include "utils/Result.h" -#include - -#ifndef PAGE_SIZE -#define PAGE_SIZE 4096 -#endif - -#define MAP_READ_WRITE 1 << 0 -#define MAP_USER 1 << 1 -#define MAP_EXEC 1 << 2 -#define MAP_AS_OWNED_BY_TASK 1 << 3 - -namespace MemoryManager -{ - void init(); - - void protect_kernel_sections(); - - Result get_mapping(void* physicalAddress, int flags = MAP_READ_WRITE); - void release_mapping(void* mapping); - - Result get_unaligned_mapping(void* physicalAddress, int flags = MAP_READ_WRITE); - Result get_unaligned_mappings(void* physicalAddress, uint64_t count, int flags = MAP_READ_WRITE); - void release_unaligned_mapping(void* mapping); - void release_unaligned_mappings(void* mapping, uint64_t count); - - Result get_page(int flags = MAP_READ_WRITE); - Result get_pages(uint64_t count, int flags = MAP_READ_WRITE); - - Result get_page_at(uint64_t addr, int flags = MAP_READ_WRITE); - Result get_pages_at(uint64_t addr, uint64_t count, int flags = MAP_READ_WRITE); - - void release_page(void* page); - void release_pages(void* pages, uint64_t count); - - void protect(void* page, uint64_t count, int flags); - - void map_several_pages(uint64_t physicalAddress, uint64_t virtualAddress, uint64_t count, - int flags = MAP_READ_WRITE); -} \ No newline at end of file diff --git a/kernel/include/memory/MemoryMap.h b/kernel/include/memory/MemoryMap.h deleted file mode 100644 index c2714dc1..00000000 --- a/kernel/include/memory/MemoryMap.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -namespace Memory -{ - void walk_memory_map(); -} \ No newline at end of file diff --git a/kernel/include/memory/PMM.h b/kernel/include/memory/PMM.h deleted file mode 100644 index 83d4482b..00000000 --- a/kernel/include/memory/PMM.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once -#include "utils/Result.h" -#include - -namespace PMM -{ - void init(); - - Result request_page(); - Result request_pages(uint64_t count); - - void free_page(void* address); - void free_pages(void* address, uint64_t count); - - void lock_page(void* address); - void lock_pages(void* address, uint64_t count); - - uint64_t get_free(); - uint64_t get_used(); - uint64_t get_reserved(); - - uint64_t get_bitmap_size(); - - void map_bitmap_to_virtual(); -}; diff --git a/kernel/include/memory/Paging.h b/kernel/include/memory/Paging.h deleted file mode 100644 index baedd9a3..00000000 --- a/kernel/include/memory/Paging.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once -#include - -#ifndef PAGE_SIZE -#define PAGE_SIZE 4096 -#endif - -struct PageDirectoryEntry -{ - bool present : 1; - bool read_write : 1; - bool user : 1; - bool write_through : 1; - bool cache_disabled : 1; - bool accessed : 1; - bool ignore0 : 1; - bool larger_pages : 1; - bool ignore1 : 1; - uint8_t available : 3; - uint64_t address : 48; - bool owned_by_task : 1; // Part of the available for OS use bits. - uint8_t available2 : 2; - bool no_execute : 1; - - void set_address(uint64_t addr); - uint64_t get_address(); -} __attribute__((packed)); - -struct PageTable -{ - PageDirectoryEntry entries[512]; -} __attribute__((aligned(PAGE_SIZE))); - -static_assert(sizeof(PageDirectoryEntry) == 8UL); \ No newline at end of file diff --git a/kernel/include/memory/UserHeap.h b/kernel/include/memory/UserHeap.h deleted file mode 100644 index 166c6a5c..00000000 --- a/kernel/include/memory/UserHeap.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once -#include - -struct UserHeap -{ - bool init(); - - uint64_t request_virtual_page(); - uint64_t request_virtual_pages(uint64_t count); - - void free_virtual_page(uint64_t address); - void free_virtual_pages(uint64_t address, uint64_t count); - - void free(); - - bool inherit(UserHeap& other); - - private: - uint8_t* bitmap = nullptr; - uint64_t bitmap_size = 0; - uint64_t start_index = 0; - bool bitmap_read(uint64_t index); - void bitmap_set(uint64_t index, bool value); - - bool try_expand(); - bool try_expand_size(uint64_t size); -}; \ No newline at end of file diff --git a/kernel/include/memory/VMM.h b/kernel/include/memory/VMM.h deleted file mode 100644 index ceb44ea2..00000000 --- a/kernel/include/memory/VMM.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once -#include "memory/AddressSpace.h" -#include "memory/Paging.h" - -enum Flags -{ - ReadWrite = 1 << 0, - User = 1 << 1, - Execute = 1 << 2, - OwnedByTask = 1 << 3, -}; -namespace VMM -{ - void init(); // Fetch page table from cr3 - - void switch_to_user_address_space(AddressSpace& space); - void switch_to_previous_user_address_space(); - void switch_back_to_kernel_address_space(); - - void enter_syscall_context(); - void exit_syscall_context(); - - void apply_address_space(); - - bool is_using_kernel_address_space(); - - void map(uint64_t vaddr, uint64_t paddr, int flags); - void remap(uint64_t vaddr, int flags); - void unmap(uint64_t vaddr); - uint64_t get_physical(uint64_t vaddr); - uint64_t get_flags(uint64_t vaddr); - - PageDirectoryEntry* find_pde(PageTable* root, uint64_t vaddr); - PageDirectoryEntry* create_pde_if_not_exists(PageTable* root, uint64_t vaddr); - - void propagate_read_write(PageTable* root, uint64_t vaddr); - void propagate_no_execute(PageTable* root, uint64_t vaddr); - void propagate_user(PageTable* root, uint64_t vaddr); - - void flush_tlb(uint64_t addr); - void flush_tlb_full(); - - void decompose_vaddr(uint64_t vaddr, uint64_t& page_index, uint64_t& pt_index, uint64_t& pd_index, - uint64_t& pdp_index); - uint64_t recompose_vaddr(uint64_t page_index, uint64_t pt_index, uint64_t pd_index, uint64_t pdp_index); - - void install_kernel_page_directory_into_address_space(AddressSpace& space); -}; \ No newline at end of file diff --git a/kernel/include/memory/liballoc/liballoc.h b/kernel/include/memory/liballoc/liballoc.h deleted file mode 100644 index 0ad6274d..00000000 --- a/kernel/include/memory/liballoc/liballoc.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef _LIBALLOC_H -#define _LIBALLOC_H - -#include - -/** \defgroup ALLOCHOOKS liballoc hooks - * - * These are the OS specific functions which need to - * be implemented on any platform that the library - * is expected to work on. - */ - -/** @{ */ - -// If we are told to not define our own size_t, then we skip the define. -//#define _HAVE_UINTPTR_T -// typedef unsigned long uintptr_t; - -// This lets you prefix malloc and friends -#define PREFIX(func) k##func - -#ifdef __cplusplus -extern "C" -{ -#endif -#ifndef __skip_bindings - /** This function is supposed to lock the memory data structures. It - * could be as simple as disabling interrupts or acquiring a spinlock. - * It's up to you to decide. - * - * \return 0 if the lock was acquired successfully. Anything else is - * failure. - */ - extern int liballoc_lock(); - - /** This function unlocks what was previously locked by the liballoc_lock - * function. If it disabled interrupts, it enables interrupts. If it - * had acquiried a spinlock, it releases the spinlock. etc. - * - * \return 0 if the lock was successfully released. - */ - extern int liballoc_unlock(); - - /** This is the hook into the local system which allocates pages. It - * accepts an integer parameter which is the number of pages - * required. The page size was set up in the liballoc_init function. - * - * \return NULL if the pages were not allocated. - * \return A pointer to the allocated memory. - */ - extern void* liballoc_alloc(size_t); - - /** This frees previously allocated memory. The void* parameter passed - * to the function is the exact same value returned from a previous - * liballoc_alloc call. - * - * The integer value is the number of pages to free. - * - * \return 0 if the memory was successfully freed. - */ - extern int liballoc_free(void*, size_t); -#endif - - extern void* PREFIX(malloc)(size_t); ///< The standard function. - extern void* PREFIX(realloc)(void*, size_t); ///< The standard function. - extern void* PREFIX(calloc)(size_t, size_t); ///< The standard function. - extern void PREFIX(free)(void*); ///< The standard function. - -#ifdef __cplusplus -} -#endif - -/** @} */ - -#endif \ No newline at end of file diff --git a/kernel/include/misc/MSR.h b/kernel/include/misc/MSR.h deleted file mode 100644 index 1c7ae4db..00000000 --- a/kernel/include/misc/MSR.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once -#include - -#define IA32_EFER_MSR 0xC0000080 - -struct MSR -{ - void write(uint64_t value); - uint64_t read(); - - MSR(uint32_t msr_num); - - static void write_to(uint32_t msr_num, uint64_t value); - static uint64_t read_from(uint32_t msr_num); - - static void with_value_of(uint32_t msr_num, void (*callback)(uint64_t&)); - void with_value(void (*callback)(uint64_t&)); - - private: - uint32_t m_msr_num; -}; \ No newline at end of file diff --git a/kernel/include/misc/PCITypes.h b/kernel/include/misc/PCITypes.h deleted file mode 100644 index 4a537bf6..00000000 --- a/kernel/include/misc/PCITypes.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once -#include "io/PCI.h" - -const char* pci_type_name(PCI::DeviceType type); \ No newline at end of file diff --git a/kernel/include/misc/Scancodes.h b/kernel/include/misc/Scancodes.h deleted file mode 100644 index 439b2678..00000000 --- a/kernel/include/misc/Scancodes.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -// This should only be used for a keyboard TTY interface. Userspace should translate keyboard scancodes by themselves. -char translate_scancode(unsigned char scancode, bool* ignore); - -bool scancode_filter_released(unsigned char* scancode); \ No newline at end of file diff --git a/kernel/include/misc/hang.h b/kernel/include/misc/hang.h deleted file mode 100644 index 105c03a6..00000000 --- a/kernel/include/misc/hang.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once - -[[noreturn]] void hang(); -void halt(); \ No newline at end of file diff --git a/kernel/include/misc/reboot.h b/kernel/include/misc/reboot.h deleted file mode 100644 index e7de0de8..00000000 --- a/kernel/include/misc/reboot.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -[[noreturn]] void reboot(); \ No newline at end of file diff --git a/kernel/include/misc/shutdown.h b/kernel/include/misc/shutdown.h deleted file mode 100644 index 4c620652..00000000 --- a/kernel/include/misc/shutdown.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -[[noreturn]] void shutdown(); \ No newline at end of file diff --git a/kernel/include/misc/utils.h b/kernel/include/misc/utils.h deleted file mode 100644 index cc8974e5..00000000 --- a/kernel/include/misc/utils.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once -#include - -namespace Utilities -{ - inline uint64_t get_blocks_from_size(uint64_t blocksize, uint64_t size) - { - return (size + (blocksize - 1)) / blocksize; - } -} \ No newline at end of file diff --git a/kernel/include/panic/Panic.h b/kernel/include/panic/Panic.h deleted file mode 100644 index 5c66799d..00000000 --- a/kernel/include/panic/Panic.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include "interrupts/Context.h" - -#ifdef __cplusplus -extern "C" -{ -#endif - [[noreturn]] bool __do_int_panic(Context* context, const char* file, int line, const char* message); - [[noreturn]] bool __do_panic(const char* file, int line, const char* message); -#ifdef __cplusplus -} -#endif - -#define panic(message) __do_panic(__FILE__, __LINE__, message) -#define int_panic(context, message) __do_int_panic(context, __FILE__, __LINE__, message) \ No newline at end of file diff --git a/kernel/include/rand/Init.h b/kernel/include/rand/Init.h deleted file mode 100644 index d0b91c70..00000000 --- a/kernel/include/rand/Init.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -namespace Mersenne -{ - void init(); - void reseed(); -} \ No newline at end of file diff --git a/kernel/include/rand/Mersenne.h b/kernel/include/rand/Mersenne.h deleted file mode 100644 index 791b4500..00000000 --- a/kernel/include/rand/Mersenne.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -#include - -namespace Mersenne -{ - void seed(uint64_t); - uint64_t get(); -} \ No newline at end of file diff --git a/kernel/include/render/Color.h b/kernel/include/render/Color.h deleted file mode 100644 index 93b2bf76..00000000 --- a/kernel/include/render/Color.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once -#include - -struct Color -{ - uint8_t blue; - uint8_t green; - uint8_t red; - uint8_t alpha; - - static Color White; - static Color Black; - static Color Red; - static Color Green; - static Color Blue; - static Color Yellow; - static Color Cyan; - static Color Magenta; - static Color Gray; - - static Color from_integer(uint32_t source); -} __attribute__((packed)); // to reinterpret this as a uint32_t AARRGGBB (in reversed order here because endianness) \ No newline at end of file diff --git a/kernel/include/render/Framebuffer.h b/kernel/include/render/Framebuffer.h deleted file mode 100644 index c8b53fe2..00000000 --- a/kernel/include/render/Framebuffer.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once -#include "render/Color.h" - -class Framebuffer -{ - public: - void init(void* fb_address, int fb_type, int fb_scanline, int fb_width, int fb_height); - void set_pixel(uint32_t x, uint32_t y, Color color); - Color get_pixel(uint32_t x, uint32_t y); - void paint_rect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, Color color); - void paint_rect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, Color* colors); - void clear(Color color); - int width() - { - return m_fb_width; - } - int height() - { - return m_fb_height; - } - - private: - void* m_fb_address; - int m_fb_type; - int m_fb_scanline; - int m_fb_width; - int m_fb_height; -}; - -extern Framebuffer framebuffer0; \ No newline at end of file diff --git a/kernel/include/render/TextRenderer.h b/kernel/include/render/TextRenderer.h deleted file mode 100644 index cc7db7d0..00000000 --- a/kernel/include/render/TextRenderer.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once -#include "render/Color.h" -#include - -namespace TextRenderer -{ - void putchar(char chr); - void write(const char* str, size_t size); - void reset(); -} \ No newline at end of file diff --git a/kernel/include/std/ensure.h b/kernel/include/std/ensure.h deleted file mode 100644 index 8e90db85..00000000 --- a/kernel/include/std/ensure.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "panic/Panic.h" - -#define STRINGIZE(x) #x -#define STRINGIZE_VALUE_OF(x) STRINGIZE(x) - -// clang-format off -#define ensure(expr) (bool)(expr) || panic("Check failed at " __FILE__ ", line " STRINGIZE_VALUE_OF(__LINE__) ": " #expr) -// clang-format on \ No newline at end of file diff --git a/kernel/include/std/errno.h b/kernel/include/std/errno.h deleted file mode 100644 index be1713a3..00000000 --- a/kernel/include/std/errno.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#define EPERM 1 -#define ENOENT 2 -#define ESRCH 3 -#define EINTR 4 -#define E2BIG 7 -#define ENOEXEC 8 -#define EBADF 9 -#define ECHILD 10 -#define EAGAIN 11 -#define ENOMEM 12 -#define EACCES 13 -#define EFAULT 14 -#define EEXIST 17 -#define ENOTDIR 20 -#define EISDIR 21 -#define EINVAL 22 -#define EMFILE 24 -#define ENOTTY 25 -#define ENOSPC 28 -#define ERANGE 36 -#define ENOSYS 38 -#define ENOTSUP 95 \ No newline at end of file diff --git a/kernel/include/std/libgen.h b/kernel/include/std/libgen.h deleted file mode 100644 index 1a3a0e4d..00000000 --- a/kernel/include/std/libgen.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -char* basename(char* path); -char* dirname(char* path); - -char* better_basename(const char* path); -char* better_dirname(const char* path); \ No newline at end of file diff --git a/kernel/include/std/stdio.h b/kernel/include/std/stdio.h deleted file mode 100644 index ffe7e14e..00000000 --- a/kernel/include/std/stdio.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once -#include -#include - -#define PRINTF_LIKE(n, m) __attribute__((format(printf, n, m))) - -int printf(const char* fmt, ...) PRINTF_LIKE(1, 2); // Outputs to serial. -int sprintf(char* __s, const char* fmt, ...) PRINTF_LIKE(2, 3); -int snprintf(char* __s, size_t max, const char* fmt, ...) PRINTF_LIKE(3, 4); -int vprintf(const char* fmt, va_list ap); -int vsprintf(char* __s, const char* fmt, va_list ap); -int vsnprintf(char* __s, size_t max, const char* fmt, va_list ap); -int kprintf(const char* fmt, ...) PRINTF_LIKE(1, 2); // Outputs to text console. -int vkprintf(const char* fmt, va_list ap); \ No newline at end of file diff --git a/kernel/include/std/stdlib.h b/kernel/include/std/stdlib.h deleted file mode 100644 index e11f9469..00000000 --- a/kernel/include/std/stdlib.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once -#include - -char* itoa(int32_t number, char* arr, int base); -char* utoa(uint32_t number, char* arr, int base); - -char* ltoa(int64_t number, char* arr, int base); -char* ultoa(uint64_t number, char* arr, int base); - -void sleep(uint64_t ms); - -#define __skip_bindings -#include "memory/liballoc/liballoc.h" -#undef __skip_bindings \ No newline at end of file diff --git a/kernel/include/std/string.h b/kernel/include/std/string.h deleted file mode 100644 index 8725a94e..00000000 --- a/kernel/include/std/string.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once -#include - -size_t strlen(const char* __s); - -__attribute__((deprecated)) char* strcpy(char* dest, const char* src); -__attribute__((deprecated)) int strcmp(const char* a, const char* b); -__attribute__((deprecated)) char* strcat(char* dest, const char* src); - -char* strncpy(char* dest, const char* src, size_t n); -size_t strlcpy(char* dest, const char* src, size_t size); -int strncmp(const char* a, const char* b, size_t n); -char* strncat(char* dest, const char* src, size_t n); - -char* strstr(char* haystack, const char* needle); - -void* memcpy(void* dest, const void* src, size_t n); -void* memset(void* dest, int c, size_t n); -int memcmp(const void* a, const void* b, size_t n); -void* memmove(void* dest, const void* src, size_t n); - -char* strdup(const char* src); -char* strrchr(const char* str, int c); \ No newline at end of file diff --git a/kernel/include/sys/Syscall.h b/kernel/include/sys/Syscall.h deleted file mode 100644 index 8a929696..00000000 --- a/kernel/include/sys/Syscall.h +++ /dev/null @@ -1,76 +0,0 @@ -#pragma once -#include "interrupts/Context.h" -#include -#include - -#define SYS_exit 0 -#define SYS_yield 1 -#define SYS_sleep 2 -#define SYS_write 3 -#define SYS_getprocid 4 -#define SYS_mmap 5 -#define SYS_munmap 6 -#define SYS_open 7 -#define SYS_read 8 -#define SYS_close 9 -#define SYS_seek 10 -#define SYS_execv 11 -#define SYS_fcntl 12 -#define SYS_mprotect 13 -#define SYS_clock_gettime 14 -#define SYS_mkdir 15 -#define SYS_fork 16 -#define SYS_waitpid 17 -#define SYS_access 18 -#define SYS_fstat 19 -#define SYS_pstat 20 -#define SYS_getdents 21 -#define SYS_stat 22 -#define SYS_dup2 23 -#define SYS_setuid 24 -#define SYS_setgid 25 -#define SYS_umask 26 -#define SYS_ioctl 27 -#define SYS_seteuid 28 -#define SYS_setegid 29 - -struct stat; -struct pstat; -struct luna_dirent; -struct timespec; - -namespace Syscall -{ - void entry(Context* context); -} - -void sys_exit(Context* context, int status); -void sys_yield(Context* context); -void sys_sleep(Context* context, uint64_t ms); -void sys_write(Context* context, int fd, size_t size, const char* addr); -void sys_getprocid(Context* context, int field); -void sys_mmap(Context* context, void* address, size_t size, int prot, int fd, off_t offset); -void sys_munmap(Context* context, void* address, size_t size); -void sys_open(Context* context, const char* filename, int flags, mode_t mode); -void sys_read(Context* context, int fd, size_t size, char* buffer); -void sys_close(Context* context, int fd); -void sys_seek(Context* context, int fd, long offset, int whence); -void sys_execv(Context* context, const char* pathname, char** argv); -void sys_fcntl(Context* context, int fd, int command, uintptr_t arg); -void sys_mprotect(Context* context, void* address, size_t size, int prot); -void sys_clock_gettime(Context* context, int clock_id, struct timespec* tp); -void sys_mkdir(Context* context, const char* filename, mode_t mode); -void sys_fork(Context* context); -void sys_waitpid(Context* context, long pid, int* wstatus, int options); -void sys_access(Context* context, const char* path, int amode); -void sys_fstat(Context* context, int fd, struct stat* buf); -void sys_pstat(Context* context, long pid, struct pstat* buf); -void sys_getdents(Context* context, int fd, struct luna_dirent* buf, size_t count); -void sys_stat(Context* context, const char* path, struct stat* buf); -void sys_dup2(Context* context, int fd, int fd2); -void sys_setuid(Context* context, uid_t uid); -void sys_setgid(Context* context, gid_t gid); -void sys_umask(Context* context, mode_t cmask); -void sys_ioctl(Context* context, int fd, int request, uintptr_t arg); -void sys_seteuid(Context* context, uid_t euid); -void sys_setegid(Context* context, gid_t egid); \ No newline at end of file diff --git a/kernel/include/sys/UserMemory.h b/kernel/include/sys/UserMemory.h deleted file mode 100644 index fca1c034..00000000 --- a/kernel/include/sys/UserMemory.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#ifndef MODULE -#define MODULE "mem" -#endif - -#include "log/Log.h" -#include "memory/MemoryManager.h" -#include "memory/VMM.h" -#include "misc/utils.h" -#include - -Result strdup_from_user(const char* user_string); -bool validate_user_readable_page(uintptr_t address); -bool validate_user_writable_page(uintptr_t address); -bool validate_user_read(uintptr_t address, size_t size); -bool validate_user_write(uintptr_t address, size_t size); - -bool copy_from_user(const void* user_ptr, void* ptr, size_t size); -bool copy_to_user(void* user_ptr, const void* ptr, size_t size); - -template bool copy_typed_from_user(const T* user_ptr, T* ptr) -{ - return copy_from_user(user_ptr, ptr, sizeof(T)); -} - -template bool copy_typed_to_user(T* user_ptr, const T* ptr) -{ - return copy_to_user(user_ptr, ptr, sizeof(T)); -} \ No newline at end of file diff --git a/kernel/include/sys/elf/ELF.h b/kernel/include/sys/elf/ELF.h deleted file mode 100644 index 711bd3bd..00000000 --- a/kernel/include/sys/elf/ELF.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#define ELFMAG "\177ELF" -#define SELFMAG 4 -#define EI_CLASS 4 /* File class byte index */ -#define ELFCLASS64 2 /* 64-bit objects */ -#define EI_DATA 5 /* Data encoding byte index */ -#define ELFDATA2LSB 1 /* 2's complement, little endian */ -#define ET_EXEC 2 /* Executable file */ -#define PT_LOAD 1 /* Loadable program segment */ -#ifdef __x86_64__ -#define EM_MACH 62 /* AMD x86-64 architecture */ -#endif -#ifdef __aarch64__ -#define EM_MACH 183 /* ARM aarch64 architecture */ -#endif - -#include - -typedef struct -{ - uint8_t e_ident[16]; /* Magic number and other info */ - uint16_t e_type; /* Object file type */ - uint16_t e_machine; /* Architecture */ - uint32_t e_version; /* Object file version */ - uint64_t e_entry; /* Entry point virtual address */ - uint64_t e_phoff; /* Program header table file offset */ - uint64_t e_shoff; /* Section header table file offset */ - uint32_t e_flags; /* Processor-specific flags */ - uint16_t e_ehsize; /* ELF header size in bytes */ - uint16_t e_phentsize; /* Program header table entry size */ - uint16_t e_phnum; /* Program header table entry count */ - uint16_t e_shentsize; /* Section header table entry size */ - uint16_t e_shnum; /* Section header table entry count */ - uint16_t e_shstrndx; /* Section header string table index */ -} Elf64_Ehdr; - -typedef struct -{ - uint32_t p_type; /* Segment type */ - uint32_t p_flags; /* Segment flags */ - uint64_t p_offset; /* Segment file offset */ - uint64_t p_vaddr; /* Segment virtual address */ - uint64_t p_paddr; /* Segment physical address */ - uint64_t p_filesz; /* Segment size in file */ - uint64_t p_memsz; /* Segment size in memory */ - uint64_t p_align; /* Segment alignment */ -} Elf64_Phdr; \ No newline at end of file diff --git a/kernel/include/sys/elf/ELFLoader.h b/kernel/include/sys/elf/ELFLoader.h deleted file mode 100644 index 26b869e0..00000000 --- a/kernel/include/sys/elf/ELFLoader.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "fs/VFS.h" -#include "sys/elf/Image.h" -#include - -namespace ELFLoader -{ - ELFImage* load_elf_from_vfs(VFS::Node* node); // This function assumes check_elf_image has been called first. - ELFImage* load_elf_from_filesystem(const char* filename); - void release_elf_image(ELFImage* image); - long check_elf_image(VFS::Node* node); - long check_elf_image_from_filesystem(const char* filename); -} \ No newline at end of file diff --git a/kernel/include/sys/elf/Image.h b/kernel/include/sys/elf/Image.h deleted file mode 100644 index 552b00e4..00000000 --- a/kernel/include/sys/elf/Image.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include - -struct ELFSection -{ - uintptr_t base; - uint64_t pages; -}; - -struct ELFImage -{ - uintptr_t entry; - uint64_t section_count; - ELFSection sections[1]; -}; \ No newline at end of file diff --git a/kernel/include/thread/PIT.h b/kernel/include/thread/PIT.h deleted file mode 100644 index 9151508f..00000000 --- a/kernel/include/thread/PIT.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once -#include - -namespace PIT -{ - extern volatile uint64_t ms_since_boot; - const uint64_t base_frequency = 1193182; - void initialize(uint64_t frequency); - uint64_t frequency(); - void tick(); -} diff --git a/kernel/include/thread/Scheduler.h b/kernel/include/thread/Scheduler.h deleted file mode 100644 index 24ab7789..00000000 --- a/kernel/include/thread/Scheduler.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once -#include "thread/Task.h" - -#define TASK_PAGES_IN_STACK 4 - -namespace Scheduler -{ - void init(); - void yield(); - void exit(int status); - void sleep(unsigned long ms); - void add_kernel_task(const char* taskname, void (*task)(void)); - - Task* create_user_task(); - - long load_user_task(const char* filename); - - void task_exit(Context* context, int64_t status); - void task_misbehave(Context* context, int64_t status); - - Task* current_task(); - - void task_yield(Context* context); - void task_tick(Context* context); - - void reap_task(Task* task); - void reap_tasks(); - - void reset_task(Task* task, ELFImage* new_image); - - void append_task(Task* task); - - Task* find_by_pid(uint64_t pid); -} \ No newline at end of file diff --git a/kernel/include/thread/Spinlock.h b/kernel/include/thread/Spinlock.h deleted file mode 100644 index 8678e69a..00000000 --- a/kernel/include/thread/Spinlock.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include - -struct Spinlock -{ - public: - void acquire(); - void release(); - bool locked(); - - private: - volatile uint64_t m_lock = 0; -}; - -void lock(Spinlock& lock, void (*action)(void)); \ No newline at end of file diff --git a/kernel/include/thread/Task.h b/kernel/include/thread/Task.h deleted file mode 100644 index 2238343a..00000000 --- a/kernel/include/thread/Task.h +++ /dev/null @@ -1,123 +0,0 @@ -#pragma once -#include "fs/FileDescriptor.h" -#include "interrupts/Context.h" -#include "memory/AddressSpace.h" -#include "memory/UserHeap.h" -#include "sys/elf/Image.h" -#include - -#define TASK_MAX_FDS 32 - -enum class BlockReason -{ - None, - Reading, - Waiting, -}; - -// FIXME: To make this struct more C++-styled, maybe we could make a lot of these variables private and add -// getters/setters? - -struct Task -{ - enum TaskState - { - Idle, - Running, - Sleeping, - Dying, - Blocking, - Exited - }; - - uint64_t id; - uint64_t ppid; - Context regs; - - int64_t task_sleep = 0; - - int64_t exit_status; - - int64_t task_time = 0; - - uid_t uid; - uid_t euid; - gid_t gid; - gid_t egid; - - Task* next_task = nullptr; - Task* prev_task = nullptr; - - uint64_t allocated_stack = 0; - - TaskState state; - - uint64_t cpu_time = 0; - - char floating_region[512] __attribute__((aligned(16))); - bool floating_saved = false; - - bool user_task = true; - - bool is_user_task(); - - ELFImage* image = nullptr; // FIXME: we probably don't need to keep track of this anymore since the ELF sections are - // freed automatically when calling destroy() or clear() on the address space. - - Descriptor files[TASK_MAX_FDS]; - - AddressSpace address_space; - - UserHeap allocator; - - int alloc_fd(); - - int alloc_fd_greater_than_or_equal(int base_fd); - - void save_context(Context* context); - void restore_context(Context* context); - - void save_floating(); - void restore_floating(); - - void switch_to_address_space(); - - bool has_died(); - - char name[128]; - - mode_t umask; - - BlockReason block_reason; - - union { - struct - { - size_t size; - int fd; - char* buf; - } blocking_read_info; - struct - { - int64_t pid; - int* wstatus; - } blocking_wait_info; - }; - - void resume(); - - bool is_still_blocking(); - - // FIXME: These two functions are a bit clunky. - Descriptor* open_descriptor_from_fd(int fd, int& error); - Descriptor* descriptor_from_fd(int fd, int& error); - - bool is_superuser(); - - private: - void resume_read(); - void resume_wait(); - - bool is_read_still_blocking(); - bool is_wait_still_blocking(); -}; \ No newline at end of file diff --git a/kernel/include/trace/Resolve.h b/kernel/include/trace/Resolve.h deleted file mode 100644 index f54f0b29..00000000 --- a/kernel/include/trace/Resolve.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once -#include -#include - -void get_symbol_name(uintptr_t address, char* buffer, size_t size); \ No newline at end of file diff --git a/kernel/include/trace/StackTracer.h b/kernel/include/trace/StackTracer.h deleted file mode 100644 index b82234f2..00000000 --- a/kernel/include/trace/StackTracer.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include - -struct StackTracer -{ - StackTracer(); - StackTracer(uintptr_t base_pointer); - void trace(); - void trace_with_ip(uintptr_t ip); - - private: - uintptr_t m_base_pointer; -}; - -bool stack_trace_contains(uintptr_t address); \ No newline at end of file diff --git a/kernel/include/utils/Addresses.h b/kernel/include/utils/Addresses.h deleted file mode 100644 index 23752357..00000000 --- a/kernel/include/utils/Addresses.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include -#include - -#ifndef PAGE_SIZE -#define PAGE_SIZE 4096 -#endif - -inline uintptr_t get_top_of_stack(uintptr_t bottom, size_t stack_pages) -{ - return bottom + (stack_pages * PAGE_SIZE) - sizeof(uintptr_t); -} - -inline uintptr_t round_down_to_nearest_page(uintptr_t addr) -{ - return addr - (addr % PAGE_SIZE); -} - -inline uintptr_t round_up_to_nearest_page(uintptr_t addr) -{ - if (addr % PAGE_SIZE) return addr + (PAGE_SIZE - (addr % PAGE_SIZE)); - return addr; -} \ No newline at end of file diff --git a/kernel/include/utils/PageFaultReason.h b/kernel/include/utils/PageFaultReason.h deleted file mode 100644 index 7f9d88da..00000000 --- a/kernel/include/utils/PageFaultReason.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once -#include - -void determine_user_page_fault_reason(uintptr_t faulting_address); \ No newline at end of file diff --git a/kernel/include/utils/Registers.h b/kernel/include/utils/Registers.h deleted file mode 100644 index 944a0ea0..00000000 --- a/kernel/include/utils/Registers.h +++ /dev/null @@ -1,52 +0,0 @@ -#pragma once - -#include - -extern "C" uintptr_t asm_get_rflags(); -extern "C" void asm_set_rflags(uintptr_t); - -inline uintptr_t read_rflags() -{ - return asm_get_rflags(); -} - -inline void write_rflags(uintptr_t value) -{ - asm_set_rflags(value); -} - -inline uintptr_t read_cr0() -{ - uintptr_t value; - asm volatile("mov %%cr0, %0" : "=r"(value)); - return value; -} - -inline uintptr_t read_cr3() -{ - uintptr_t value; - asm volatile("mov %%cr3, %0" : "=r"(value)); - return value; -} - -inline uintptr_t read_cr4() -{ - uintptr_t value; - asm volatile("mov %%cr4, %0" : "=r"(value)); - return value; -} - -template inline void write_cr0(T value) -{ - asm volatile("mov %0, %%cr0" : : "r"(value)); -} - -template inline void write_cr3(T value) -{ - asm volatile("mov %0, %%cr3" : : "r"(value)); -} - -template inline void write_cr4(T value) -{ - asm volatile("mov %0, %%cr4" : : "r"(value)); -} \ No newline at end of file diff --git a/kernel/include/utils/Result.h b/kernel/include/utils/Result.h deleted file mode 100644 index 6abb0f8a..00000000 --- a/kernel/include/utils/Result.h +++ /dev/null @@ -1,153 +0,0 @@ -#pragma once -#include "std/ensure.h" -#include "std/errno.h" -#include "std/string.h" -#include "utils/move.h" -#include "utils/new.h" - -struct Error -{ - Error(int err) - { - error = err; - } - - int error; -}; - -template class Result -{ - public: - Result(const T& value) - { - m_storage.store_reference(value); - m_has_value = true; - m_has_error = false; - } - - Result(T&& value) - { - m_storage.store_movable_reference(move(value)); - m_has_value = true; - m_has_error = false; - } - - Result(const Result& other) - { - m_storage.store_reference(other.m_storage.fetch_reference()); - m_has_value = true; - m_has_error = false; - } - - Result(Result&& other) - { - m_storage.store_movable_reference(move(other.m_storage.fetch_reference())); - m_has_value = true; - m_has_error = false; - } - - Result(const Error& err) - { - m_error = err.error; - m_has_error = true; - m_has_value = false; - } - - bool has_error() - { - return m_has_error; - } - - bool has_value() - { - return m_has_value; - } - - int error() - { - ensure(has_error()); - return m_error; - } - - Error release_error() - { - ensure(has_error()); - return {m_error}; - } - - T value() - { - ensure(has_value()); - return m_storage.fetch_reference(); - } - - T value_or(T other) - { - if (has_value()) return m_storage.fetch_reference(); - return other; - } - - T release_value() - { - ensure(has_value()); - T item = m_storage.fetch_reference(); - m_has_value = false; - m_storage.destroy(); - return move(item); - } - - ~Result() - { - if (has_value()) m_storage.destroy(); - } - - private: - struct Storage - { - unsigned char buffer[sizeof(T)]; - - T* fetch_ptr() - { - return (T*)buffer; - } - - T& fetch_reference() - { - return *fetch_ptr(); - } - - const T* fetch_ptr() const - { - return (const T*)buffer; - } - - const T& fetch_reference() const - { - return *fetch_ptr(); - } - - void store_ptr(T* ptr) - { - new (buffer) T(*ptr); - } - - void store_reference(const T& ref) - { - new (buffer) T(ref); - } - - void store_movable_reference(T&& ref) - { - new (buffer) T(ref); - } - - void destroy() - { - fetch_reference().~T(); - } - }; - Storage m_storage; - int m_error; - bool m_has_error; - bool m_has_value; -}; \ No newline at end of file diff --git a/kernel/include/utils/StringParsing.h b/kernel/include/utils/StringParsing.h deleted file mode 100644 index 264644f6..00000000 --- a/kernel/include/utils/StringParsing.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once - -long parse_decimal(const char* str); -long parse_octal(const char* str); \ No newline at end of file diff --git a/kernel/include/utils/Time.h b/kernel/include/utils/Time.h deleted file mode 100644 index 3e06716f..00000000 --- a/kernel/include/utils/Time.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -#include - -int make_yday(int year, int month); - -uint64_t broken_down_to_unix(uint64_t year, uint64_t yday, uint64_t hour, uint64_t min, uint64_t sec); - -uint64_t unix_boottime(uint8_t boottime[8]); \ No newline at end of file diff --git a/kernel/include/utils/new.h b/kernel/include/utils/new.h deleted file mode 100644 index 1e6afcd1..00000000 --- a/kernel/include/utils/new.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include - -inline void* operator new(size_t, void* p) noexcept -{ - return p; -} -inline void* operator new[](size_t, void* p) noexcept -{ - return p; -} -inline void operator delete(void*, void*) noexcept {}; -inline void operator delete[](void*, void*) noexcept {}; \ No newline at end of file diff --git a/kernel/moon.ld b/kernel/moon.ld index e2dd402a..c3b72198 100644 --- a/kernel/moon.ld +++ b/kernel/moon.ld @@ -16,13 +16,16 @@ SECTIONS kernel_start = .; .text : { KEEP(*(.text.boot)) *(.text .text.*) /* code */ + . = ALIGN(0x1000); start_of_kernel_rodata = .; - *(.rodata .rodata.*) /* data */ + *(.rodata .rodata.*) /* read-only data */ end_of_kernel_rodata = .; + . = ALIGN(0x1000); - start_of_kernel_data = .; + start_of_kernel_data = .; /* data */ *(.data .data.*) + } :boot .bss (NOLOAD) : { /* bss */ *(.bss .bss.*) @@ -32,5 +35,4 @@ SECTIONS kernel_end = .; /DISCARD/ : { *(.eh_frame) *(.comment) } -} - +} \ No newline at end of file diff --git a/kernel/src/ELF.cpp b/kernel/src/ELF.cpp new file mode 100644 index 00000000..1af55e15 --- /dev/null +++ b/kernel/src/ELF.cpp @@ -0,0 +1,118 @@ +#include "ELF.h" +#include "Log.h" +#include "arch/CPU.h" +#include "arch/MMU.h" +#include "memory/MemoryManager.h" +#include +#include +#include +#include + +static bool can_execute_segment(u32 flags) +{ + return flags & 1; +} + +static bool can_write_segment(u32 flags) +{ + return flags & 2; +} + +/*static bool can_write_and_execute_segment(u32 flags) +{ + return can_write_segment(flags) && can_execute_segment(flags); +}*/ + +namespace ELFLoader +{ + // FIXME: Check that all calls to read_contents() read the proper amount of bytes. + Result load(const TarStream::Entry& elf_entry, const TarStream& stream) + { + Elf64_Ehdr elf_header; + usize nread = stream.read_contents(elf_entry, &elf_header, 0, sizeof elf_header); + if (nread < sizeof elf_header) + { + kdbgln("Error while loading ELF: ELF header does not fit in entry"); + return err(ENOEXEC); + } + + if (memcmp(elf_header.e_ident, ELFMAG, SELFMAG) != 0) + { + kdbgln("Error while loading ELF: ELF header has no valid magic"); + return err(ENOEXEC); + } + + if (elf_header.e_ident[EI_CLASS] != ELFCLASS64) + { + kdbgln("Error while loading ELF: ELF object is not 64-bit"); + return err(ENOEXEC); + } + + if (elf_header.e_ident[EI_DATA] != ELFDATA2LSB) + { + kdbgln("Error while loading ELF: ELF object is not 2's complement little-endian"); + return err(ENOEXEC); + } + + if (elf_header.e_type != ET_EXEC) + { + kdbgln("Error while loading ELF: ELF object is not an executable"); + return err(ENOEXEC); + } + + if (elf_header.e_machine != EM_MACH) + { + kdbgln("Error while loading ELF: ELF object's target architecture does not match the current one (%s)", + CPU::platform_string()); + return err(ENOEXEC); + } + + if (elf_header.e_phnum == 0) + { + kdbgln("Error while loading ELF: ELF object has no program headers"); + return err(ENOEXEC); + } + + kdbgln("ELF: Loading ELF with entry=%#.16lx", elf_header.e_entry); + + usize i; + Elf64_Phdr program_header; + + for (stream.read_contents(elf_entry, &program_header, elf_header.e_phoff, sizeof program_header), i = 0; + i < elf_header.e_phnum; + i++, stream.read_contents(elf_entry, &program_header, elf_header.e_phoff + (i * elf_header.e_phentsize), + sizeof program_header)) + { + if (program_header.p_type == PT_LOAD) + { + kdbgln("ELF: Loading segment (offset=%zu, base=%#.16lx, filesize=%zu, memsize=%zu)", + program_header.p_offset, program_header.p_vaddr, program_header.p_filesz, + program_header.p_memsz); + + u64 base_vaddr = align_down(program_header.p_vaddr); + u64 vaddr_diff = program_header.p_vaddr - base_vaddr; + /*expect(!can_write_and_execute_segment(program_header.p_flags), + "Segment is both writable and executable");*/ + + int flags = MMU::User | MMU::NoExecute; + if (can_write_segment(program_header.p_flags)) flags |= MMU::ReadWrite; + if (can_execute_segment(program_header.p_flags)) flags &= ~MMU::NoExecute; + + // Allocate physical memory for the segment + TRY(MemoryManager::alloc_at( + base_vaddr, get_blocks_from_size(program_header.p_memsz + vaddr_diff, ARCH_PAGE_SIZE), flags)); + + // Load the file section of the segment + stream.read_contents(elf_entry, (void*)program_header.p_vaddr, program_header.p_offset, + program_header.p_filesz); + + // Fill out the rest of the segment with 0s + memset((void*)(program_header.p_vaddr + program_header.p_filesz), 0, + program_header.p_memsz - program_header.p_filesz); + } + else { kdbgln("ELF: Encountered non-loadable program header, skipping"); } + } + + return ELFData { elf_header.e_entry }; + } +} diff --git a/kernel/src/ELF.h b/kernel/src/ELF.h new file mode 100644 index 00000000..440bae4b --- /dev/null +++ b/kernel/src/ELF.h @@ -0,0 +1,58 @@ +#pragma once +#include +#include +#include + +#define ELFMAG "\177ELF" +#define SELFMAG 4 +#define EI_CLASS 4 /* File class byte index */ +#define ELFCLASS64 2 /* 64-bit objects */ +#define EI_DATA 5 /* Data encoding byte index */ +#define ELFDATA2LSB 1 /* 2's complement, little endian */ +#define ET_EXEC 2 /* Executable file */ +#define PT_LOAD 1 /* Loadable program segment */ +#ifdef ARCH_X86_64 +#define EM_MACH 62 /* AMD x86-64 architecture */ +#else +#error "Unknown architecture." +#endif + +typedef struct +{ + u8 e_ident[16]; /* Magic number and other info */ + u16 e_type; /* Object file type */ + u16 e_machine; /* Architecture */ + u32 e_version; /* Object file version */ + u64 e_entry; /* Entry point virtual address */ + u64 e_phoff; /* Program header table file offset */ + u64 e_shoff; /* Section header table file offset */ + u32 e_flags; /* Processor-specific flags */ + u16 e_ehsize; /* ELF header size in bytes */ + u16 e_phentsize; /* Program header table entry size */ + u16 e_phnum; /* Program header table entry count */ + u16 e_shentsize; /* Section header table entry size */ + u16 e_shnum; /* Section header table entry count */ + u16 e_shstrndx; /* Section header string table index */ +} Elf64_Ehdr; + +typedef struct +{ + u32 p_type; /* Segment type */ + u32 p_flags; /* Segment flags */ + u64 p_offset; /* Segment file offset */ + u64 p_vaddr; /* Segment virtual address */ + u64 p_paddr; /* Segment physical address */ + u64 p_filesz; /* Segment size in file */ + u64 p_memsz; /* Segment size in memory */ + u64 p_align; /* Segment alignment */ +} Elf64_Phdr; + +struct ELFData +{ + u64 entry; +}; + +namespace ELFLoader +{ + Result load(const TarStream::Entry& elf_entry, const TarStream& stream); +}; diff --git a/kernel/src/InitRD.cpp b/kernel/src/InitRD.cpp new file mode 100644 index 00000000..1fc592df --- /dev/null +++ b/kernel/src/InitRD.cpp @@ -0,0 +1,18 @@ +#include "InitRD.h" +#include "arch/MMU.h" +#include "boot/bootboot.h" +#include "memory/MemoryManager.h" +#include + +TarStream g_initrd; +extern const BOOTBOOT bootboot; + +void InitRD::initialize() +{ + u64 virtual_initrd_address = + MemoryManager::get_kernel_mapping_for_frames( + bootboot.initrd_ptr, get_blocks_from_size(bootboot.initrd_size, ARCH_PAGE_SIZE), MMU::NoExecute) + .expect_value("Unable to map the initial ramdisk into virtual memory"); + + g_initrd.initialize((void*)virtual_initrd_address, bootboot.initrd_size); +} diff --git a/kernel/src/InitRD.h b/kernel/src/InitRD.h new file mode 100644 index 00000000..2eecf546 --- /dev/null +++ b/kernel/src/InitRD.h @@ -0,0 +1,9 @@ +#pragma once +#include + +extern TarStream g_initrd; + +namespace InitRD +{ + void initialize(); +} diff --git a/kernel/src/Log.cpp b/kernel/src/Log.cpp new file mode 100644 index 00000000..deaad49d --- /dev/null +++ b/kernel/src/Log.cpp @@ -0,0 +1,130 @@ +#include "Log.h" +#include "arch/CPU.h" +#include "arch/Serial.h" +#include "arch/Timer.h" +#include "video/TextConsole.h" +#include + +static bool g_debug_enabled = true; +static bool g_serial_enabled = true; +static bool g_text_console_enabled = false; + +static constexpr u32 BLACK = 0xff000000; +static constexpr u32 WHITE = 0xffffffff; +static constexpr u32 YELLOW = 0xffffff00; +static constexpr u32 RED = 0xffff0000; + +static char log_level_letters[] = { 'D', 'I', 'W', 'E' }; // D for debug, I for info, W for warning, E for error +static const char* ansi_color_codes_per_log_level[] = { "37", "37", "33", "31" }; // 37 is white, 33 yellow, 31 red + +static void log_serial(LogLevel level, const char* format, va_list origin) +{ + va_list ap; + va_copy(ap, origin); + + Serial::printf("\x1b[%sm" + "%c" + "\x1b[0m ", + ansi_color_codes_per_log_level[(int)level], log_level_letters[(int)level]); + + Serial::printf("%4zu.%.3zu ", Timer::ticks(), Timer::ticks_ms() - (Timer::ticks() * 1000)); + + // FIXME: We do this manually because of a lack of vprintf() in both Serial and TextConsole. + pure_cstyle_format( + format, [](char c, void*) { Serial::putchar((u8)c); }, nullptr, ap); + + Serial::putchar('\n'); + + va_end(ap); +} + +static void log_text_console(LogLevel level, const char* format, va_list origin) +{ + va_list ap; + va_copy(ap, origin); + + const u32 original_foreground = TextConsole::foreground(); + const u32 original_background = TextConsole::background(); + + TextConsole::set_background(BLACK); + + if (level == LogLevel::Warn) TextConsole::set_foreground(YELLOW); + else if (level == LogLevel::Error) + TextConsole::set_foreground(RED); + else + TextConsole::set_foreground(WHITE); + + // FIXME: Same as above. + auto rc = cstyle_format( + format, [](char c, void*) -> Result { return TextConsole::putchar(c); }, nullptr, ap); + + if (rc.has_error()) { TextConsole::wprint(L"Invalid UTF-8 in log message"); } + + TextConsole::putwchar(L'\n'); + + TextConsole::set_background(original_background); + + TextConsole::set_foreground(original_foreground); + + va_end(ap); +} + +void vlog(LogLevel level, const char* format, va_list ap) +{ + if (!g_debug_enabled && level == LogLevel::Debug) return; + + if (g_serial_enabled) log_serial(level, format, ap); + if (g_text_console_enabled) log_text_console(level, format, ap); +} + +void log(LogLevel level, const char* format, ...) +{ + va_list ap; + va_start(ap, format); + + vlog(level, format, ap); + + va_end(ap); +} + +// for luna/DebugLog.h +void debug_log_impl(const char* format, va_list ap) +{ + vlog(LogLevel::Debug, format, ap); +} + +void setup_log(bool enable_debug, bool enable_serial, bool enable_text_console) +{ + g_debug_enabled = enable_debug; + g_serial_enabled = enable_serial; + g_text_console_enabled = enable_text_console; +} + +bool log_debug_enabled() +{ + return g_debug_enabled; +} + +bool log_serial_enabled() +{ + return g_serial_enabled; +} + +bool log_text_console_enabled() +{ + return g_text_console_enabled; +} + +static bool g_check_already_failed = false; + +[[noreturn]] bool __check_failed(const char* file, const char* line, const char* func, const char* expr) +{ + CPU::disable_interrupts(); + if (!g_check_already_failed) + { // Avoid endlessly failing when trying to report a failed check. + g_check_already_failed = true; + kerrorln("ERROR: Check failed at %s:%s, in %s: %s", file, line, func, expr); + CPU::print_stack_trace(); + } + CPU::efficient_halt(); +} diff --git a/kernel/src/Log.h b/kernel/src/Log.h new file mode 100644 index 00000000..97f2155d --- /dev/null +++ b/kernel/src/Log.h @@ -0,0 +1,25 @@ +#pragma once +#include +#include +#include + +enum class LogLevel +{ + Debug, + Info, + Warn, + Error, +}; + +void vlog(LogLevel level, const char* format, va_list ap); +void log(LogLevel level, const char* format, ...) _format(2, 3); + +void setup_log(bool enable_debug, bool enable_serial, bool enable_text_console); +bool log_debug_enabled(); +bool log_serial_enabled(); +bool log_text_console_enabled(); + +#define kdbgln(...) log(LogLevel::Debug, __VA_ARGS__) +#define kinfoln(...) log(LogLevel::Info, __VA_ARGS__) +#define kwarnln(...) log(LogLevel::Warn, __VA_ARGS__) +#define kerrorln(...) log(LogLevel::Error, __VA_ARGS__) diff --git a/kernel/src/acpi/RSDT.cpp b/kernel/src/acpi/RSDT.cpp deleted file mode 100644 index 98f78afc..00000000 --- a/kernel/src/acpi/RSDT.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#define MODULE "acpi" - -#include "acpi/RSDT.h" -#include "bootboot.h" -#include "log/Log.h" -#include "memory/MemoryManager.h" -#include "misc/utils.h" -#include "std/stdio.h" -#include "std/string.h" - -extern BOOTBOOT bootboot; - -// FIXME: Propagate errors. - -ACPI::SDTHeader* ACPI::get_rsdt_or_xsdt() -{ - static SDTHeader* cache = nullptr; - if (cache) return cache; - - kdbgln("First time accessing the RSDT/XSDT, mapping it into memory"); - void* physical = (void*)bootboot.arch.x86_64.acpi_ptr; - kdbgln("RSDT/XSDT physical address: %p", physical); - - SDTHeader* rsdt = (SDTHeader*)MemoryManager::get_unaligned_mapping(physical).release_value(); - - uint64_t offset = (uint64_t)physical % PAGE_SIZE; - uint64_t rsdt_pages = Utilities::get_blocks_from_size(PAGE_SIZE, (offset + rsdt->Length)); - - if (rsdt_pages > 1) - { - MemoryManager::release_unaligned_mapping(rsdt); - rsdt = (SDTHeader*)MemoryManager::get_unaligned_mappings(cache, rsdt_pages).release_value(); - } - - kdbgln("Mapped RSDT/XSDT to virtual address %p, uses %ld pages", (void*)rsdt, rsdt_pages); - cache = rsdt; - return rsdt; -} - -bool ACPI::validate_rsdt_or_xsdt(ACPI::SDTHeader* root_sdt) -{ - if (!validate_sdt_header(root_sdt)) return false; - if (strncmp(root_sdt->Signature, "XSDT", 4) == 0) return true; - if (strncmp(root_sdt->Signature, "RSDT", 4) == 0) return true; - return false; -} - -bool ACPI::is_xsdt() -{ - static bool cached = false; - static bool cache = false; - if (cached) return cache; - SDTHeader* rootSDT = get_rsdt_or_xsdt(); - cache = (strncmp(rootSDT->Signature, "XSDT", 4) == 0); - cached = true; - return cache; -} - -void* ACPI::find_table(ACPI::SDTHeader* root_sdt, const char* signature) -{ - bool isXSDT = is_xsdt(); - uint64_t entries = (root_sdt->Length - sizeof(SDTHeader)) / (isXSDT ? 8 : 4); - kdbgln("Searching for table %s in the %s at %p (table contains %ld entries)", signature, isXSDT ? "XSDT" : "RSDT", - (void*)root_sdt, entries); - - for (uint64_t i = 0; i < entries; i++) - { - kdbgln("Testing for table %s in entry %ld", signature, i); - SDTHeader* h; - if (isXSDT) - { - uint64_t reversedAddress = (uint64_t)((XSDT*)root_sdt)->other_sdt[i]; - uint64_t correctAddress = reversedAddress >> 32 | reversedAddress << 32; - h = (SDTHeader*)correctAddress; - } - else - { - uint32_t entry = ((RSDT*)root_sdt)->other_sdt[i]; - h = (SDTHeader*)(uint64_t)entry; - } - if (!h) - { - kwarnln("Entry %ld in the %s points to null", i, isXSDT ? "XSDT" : "RSDT"); - continue; - } - kdbgln("Physical address of entry: %p", (void*)h); - SDTHeader* realHeader = (SDTHeader*)MemoryManager::get_unaligned_mapping(h).release_value(); - kdbgln("Mapped entry to virtual address %p", (void*)realHeader); - if (!validate_sdt_header(realHeader)) - { - kwarnln("Header of entry %ld is not valid, skipping this entry", i); - MemoryManager::release_unaligned_mapping(realHeader); - continue; - } - char tableSignature[5]; - memcpy(tableSignature, h->Signature, 4); - tableSignature[4] = 0; - kdbgln("Comparing target signature (%s) to signature of entry (%s)", signature, tableSignature); - if (strncmp(h->Signature, signature, 4) == 0) - { - kdbgln("Found table %s", signature); - return (void*)realHeader; - } - kdbgln("Signatures do not match, unmapping entry and continuing"); - MemoryManager::release_unaligned_mapping(realHeader); - } - - return NULL; -} \ No newline at end of file diff --git a/kernel/src/acpi/SDT.cpp b/kernel/src/acpi/SDT.cpp deleted file mode 100644 index 9b861ab6..00000000 --- a/kernel/src/acpi/SDT.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "acpi/SDT.h" - -#pragma GCC push_options -#pragma GCC diagnostic ignored "-Wconversion" - -bool ACPI::validate_sdt_header(ACPI::SDTHeader* header) -{ - uint8_t sum = 0; - - for (uint32_t i = 0; i < header->Length; i++) { sum += ((char*)header)[i]; } - - return sum == 0; -} - -#pragma GCC pop_options \ No newline at end of file diff --git a/kernel/src/arch/CPU.h b/kernel/src/arch/CPU.h new file mode 100644 index 00000000..54422463 --- /dev/null +++ b/kernel/src/arch/CPU.h @@ -0,0 +1,30 @@ +#pragma once +#include + +struct Registers; + +namespace CPU +{ + Result identify(); + const char* platform_string(); + + void platform_init(); + void platform_finish_init(); + + [[noreturn]] void efficient_halt(); + + [[noreturn]] void idle_loop(); + + void switch_kernel_stack(u64 top); + + void enable_interrupts(); + void disable_interrupts(); + void wait_for_interrupt(); + + void get_stack_trace(void (*callback)(u64, void*), void* arg); + void print_stack_trace(); + void get_stack_trace_at(Registers* regs, void (*callback)(u64, void*), void* arg); + void print_stack_trace_at(Registers* regs); + + void pause(); +} diff --git a/kernel/src/arch/MMU.h b/kernel/src/arch/MMU.h new file mode 100644 index 00000000..031c038e --- /dev/null +++ b/kernel/src/arch/MMU.h @@ -0,0 +1,38 @@ +#pragma once +#include + +#ifdef ARCH_X86_64 +#include "arch/x86_64/MMU.h" +#else +#error "Unknown architecture." +#endif + +namespace MMU +{ + enum Flags + { + None = 0, + ReadWrite = 1, + User = 2, + NoExecute = 4, + WriteThrough = 8, + CacheDisable = 16, + }; + + Result map(u64 virt, u64 phys, int flags); + Result unmap(u64 virt); + Result get_physical(u64 virt); + Result get_flags(u64 virt); + Result remap(u64 virt, int flags); + + void switch_page_directory(PageDirectory* dir); + PageDirectory* get_page_directory(); + + void flush_all(); + + Result create_page_directory_for_userspace(); + Result delete_userspace_page_directory(PageDirectory* directory); + void setup_initial_page_directory(); + + PageDirectory* kernel_page_directory(); +} diff --git a/kernel/src/arch/Serial.cpp b/kernel/src/arch/Serial.cpp new file mode 100644 index 00000000..c21c88e8 --- /dev/null +++ b/kernel/src/arch/Serial.cpp @@ -0,0 +1,33 @@ +#include "arch/Serial.h" +#include +#include +#include + +namespace Serial +{ + void write(const char* str, usize size) + { + while (size--) putchar((u8)*str++); + } + + void print(const char* str) + { + while (*str) putchar((u8)*str++); + } + + void println(const char* str) + { + print(str); + putchar('\n'); + } + + usize printf(const char* format, ...) + { + va_list ap; + va_start(ap, format); + auto rc = pure_cstyle_format( + format, [](char c, void*) { putchar((u8)c); }, nullptr, ap); + va_end(ap); + return rc; + } +} diff --git a/kernel/src/arch/Serial.h b/kernel/src/arch/Serial.h new file mode 100644 index 00000000..c8af2565 --- /dev/null +++ b/kernel/src/arch/Serial.h @@ -0,0 +1,14 @@ +#pragma once +#include +#include + +template class Result; + +namespace Serial +{ + void putchar(u8 c); + void write(const char* str, usize size); + void print(const char* str); + void println(const char* str); + usize printf(const char* str, ...) _format(1, 2); +} diff --git a/kernel/src/arch/Timer.cpp b/kernel/src/arch/Timer.cpp new file mode 100644 index 00000000..8df3c058 --- /dev/null +++ b/kernel/src/arch/Timer.cpp @@ -0,0 +1,141 @@ +#include "arch/Timer.h" +#include "Log.h" +#include "arch/Serial.h" +#include "boot/bootboot.h" + +// FIXME: Storing these values as unsigned integers doesn't allow for pre-epoch times. +static u64 timer_ticks = 0; +static u64 boot_timestamp; + +static inline constexpr bool isleap(u32 year) +{ + return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); +} + +static constexpr u32 make_yday(u32 year, u32 month) +{ + constexpr u16 upto[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; + + u32 yd = upto[month - 1]; + if (month > 2 && isleap(year)) yd++; + return yd; +} + +// https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_16 +static constexpr u64 broken_down_to_unix(u64 year, u64 yday, u64 hour, u64 min, u64 sec) +{ + return sec + min * 60 + hour * 3600 + yday * 86400 + (year - 70) * 31536000 + ((year - 69) / 4) * 86400 - + ((year - 1) / 100) * 86400 + ((year + 299) / 400) * 86400; +} + +// The bootloader encodes the date and time in Binary-Coded Decimal (BCD), which represents decimal digits using +// hexadecimal digits. For example, BCD 0x22 is 22 in decimal. +// https://gitlab.com/bztsrc/bootboot/-/blob/master/bootboot_spec_1st_ed.pdf, page 15. +static inline constexpr u32 bcd_number_to_decimal(u32 num) +{ + return ((num >> 4) * 10) + (num & 0xf); +} + +static u64 bootloader_time_to_unix(const u8 boottime[8]) +{ + const u32 year = bcd_number_to_decimal(boottime[0]) * 100 + bcd_number_to_decimal(boottime[1]); + const u32 month = bcd_number_to_decimal(boottime[2]); + const u32 day = bcd_number_to_decimal(boottime[3]); + const u32 hour = bcd_number_to_decimal(boottime[4]); + const u32 minute = bcd_number_to_decimal(boottime[5]); + const u32 second = bcd_number_to_decimal(boottime[6]); + // "The last byte can store 1/100th second precision, but in lack of support on most platforms, it is 0x00". + // Therefore, let's not rely on it. + kinfoln("Current time: %.2d/%.2d/%d %.2d:%.2d:%.2d UTC", day, month, year, hour, minute, second); + return broken_down_to_unix(year - 1900, make_yday(year, month) + (day - 1), hour, minute, second); +} + +extern const BOOTBOOT bootboot; + +namespace Timer +{ + void tick() + { + timer_ticks++; + } + + usize raw_ticks() + { + return timer_ticks; + } + + usize ticks() + { + return ticks_ms() / 1000; + } + + usize ticks_ms() + { + return timer_ticks / ARCH_TIMER_FREQ; + } + + usize ticks_us() // We want a bit of precision; if there are 10 ticks/ms, do not return the truncated ms value * + // 1000, but ticks * 100 (1000/10), which is more precise + { + if constexpr (ARCH_TIMER_FREQ > 1000) return timer_ticks / (ARCH_TIMER_FREQ / 1000); + else + return timer_ticks * (1000 / ARCH_TIMER_FREQ); + } + + usize ticks_ns() + { + return ticks_us() * 1000; + } + + usize boot() + { + return boot_timestamp; + } + + usize boot_ms() + { + return boot_timestamp * MS_PER_SECOND; + } + + usize boot_us() + { + return boot_timestamp * US_PER_SECOND; + } + + usize boot_ns() + { + return boot_timestamp * NS_PER_SECOND; + } + + usize clock() + { + return boot() + ticks(); + } + + usize clock_ms() + { + return boot_ms() + ticks_ms(); + } + + usize clock_us() + { + return boot_us() + ticks_us(); + } + + usize clock_ns() + { + return boot_ns() + ticks_ns(); + } + + void init() + { + boot_timestamp = bootloader_time_to_unix(bootboot.datetime); + arch_init(); + } +} + +bool should_invoke_scheduler() +{ + // FIXME: Modulo is SLOW. We're calling this every tick. + return (timer_ticks % ARCH_TIMER_FREQ) == 0; +} diff --git a/kernel/src/arch/Timer.h b/kernel/src/arch/Timer.h new file mode 100644 index 00000000..bcceb762 --- /dev/null +++ b/kernel/src/arch/Timer.h @@ -0,0 +1,39 @@ +#pragma once +#include + +#ifdef ARCH_X86_64 +#include "arch/x86_64/Timer.h" +#else +#error "Unknown architecture." +#endif + +static const usize MS_PER_SECOND = 1000; +static const usize US_PER_SECOND = MS_PER_SECOND * 1000; +static const usize NS_PER_SECOND = US_PER_SECOND * 1000; + +namespace Timer +{ + void tick(); + + usize raw_ticks(); + + usize ticks(); + usize ticks_ms(); + usize ticks_us(); + usize ticks_ns(); + + usize boot(); + usize boot_ms(); + usize boot_us(); + usize boot_ns(); + + usize clock(); + usize clock_ms(); + usize clock_us(); + usize clock_ns(); + + void arch_init(); + void init(); +} + +bool should_invoke_scheduler(); diff --git a/kernel/src/arch/x86_64/CPU.asm b/kernel/src/arch/x86_64/CPU.asm new file mode 100644 index 00000000..364a7367 --- /dev/null +++ b/kernel/src/arch/x86_64/CPU.asm @@ -0,0 +1,191 @@ +section .text +global enable_sse +enable_sse: + mov rax, cr0 + and ax, 0xFFFB ;clear coprocessor emulation CR0.EM + or ax, 0x2 ;set coprocessor monitoring CR0.MP + mov cr0, rax + mov rax, cr4 + or ax, 3 << 9 ;set CR4.OSFXSR and CR4.OSXMMEXCPT at the same time + mov cr4, rax + ret + +global enable_write_protect +enable_write_protect: + mov rax, cr0 + or eax, 0x80000 ;set write-protect CR0.WP + mov cr0, rax + ret + +global enable_nx +enable_nx: + mov rcx, 0xC0000080 ; IA32_EFER + rdmsr + or eax, 1 << 11 ; no-execute enable (NXE) + wrmsr + ret + +global load_gdt +load_gdt: + cli + lgdt [rdi] + mov ax, 0x10 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + push 0x08 + lea rax, [rel .reload_CS] + push rax + retfq +.reload_CS: + ret + +global load_tr +load_tr: + mov rax, rdi + ltr ax + ret + +extern switch_task + +global kernel_yield +kernel_yield: + mov rdi, [rsp] ; return address is now in RDI + mov rcx, rsp ; save current RSP + add rcx, 8 ; skip over the return address + + mov eax, ss + push rax ; SS + push rcx ; RSP + pushfq ; RFLAGS + mov eax, cs + push rax ; CS + push rdi ; RIP + + sub rsp, 24 + + push rbx ; Preserve RBX + + sub rsp, 32 + + push rbp ; Preserve RBP + + sub rsp, 32 + + push r12 ; Preserve R12 + push r13 ; Preserve R13 + push r14 ; Preserve R14 + push r15 ; Preserve R15 + + mov rdi, rsp + call switch_task + jmp _asm_interrupt_exit + +%macro ISR 1 + global _isr%1 + _isr%1: + push byte 0 + push byte %1 + jmp _asm_interrupt_entry +%endmacro + +%macro ISR_ERROR 1 + global _isr%1 + _isr%1: + push byte %1 + jmp _asm_interrupt_entry +%endmacro + +%macro IRQ 2 + global _isr%1 + _isr%1: + push byte %2 + push byte %1 + jmp _asm_interrupt_entry +%endmacro + +extern arch_interrupt_entry +extern arch_double_fault +extern arch_machine_check + +_asm_interrupt_entry: + push rax + push rbx + push rcx + push rdx + push rsi + push rdi + push rbp + push r8 + push r9 + push r10 + push r11 + push r12 + push r13 + push r14 + push r15 + + cld + + mov rdi, rsp + call arch_interrupt_entry + +_asm_interrupt_exit: + pop r15 + pop r14 + pop r13 + pop r12 + pop r11 + pop r10 + pop r9 + pop r8 + pop rbp + pop rdi + pop rsi + pop rdx + pop rcx + pop rbx + pop rax + + add rsp, 16 + + iretq + +ISR 0 ; divide by zero (#DE) +ISR 1 ; debug (#DB) +ISR 2 ; non-maskable interrupt +ISR 3 ; breakpoint (#BP) +ISR 4 ; overflow (#OF) +ISR 5 ; bound range exceeded (#BR) +ISR 6 ; invalid opcode (#UD) +ISR 7 ; device not available (#NM) + +global _isr8 +_isr8: ; double fault (#DF) + jmp arch_double_fault + ud2 ; we aren't even pushing a return address for arch_double_fault, this is truly UNREACHABLE + +; ISR 9 obsolete +ISR_ERROR 10 ; invalid tss (#TS) +ISR_ERROR 11 ; segment not present (#NP) +ISR_ERROR 12 ; stack-segment fault (#SS) +ISR_ERROR 13 ; general protection fault (#GP) +ISR_ERROR 14 ; page fault (#PF) +; ISR 15 reserved +ISR 16 ; x87 floating-point exception (#MF) +ISR_ERROR 17 ; alignment check (#AC) + +global _isr18 +_isr18: ; machine check (#MC) + jmp arch_machine_check + ud2 ; same as above + +ISR 19 ; SIMD floating-point exception (#XM) +ISR 20 ; virtualization exception (#VE) +ISR_ERROR 21 ; control-protection exception (#CP) +; ISR 22-31 reserved +IRQ 32, 0 ; timer interrupt +IRQ 33, 0 ; keyboard interrupt +ISR 66 ; system call diff --git a/kernel/src/arch/x86_64/CPU.cpp b/kernel/src/arch/x86_64/CPU.cpp new file mode 100644 index 00000000..3f88e237 --- /dev/null +++ b/kernel/src/arch/x86_64/CPU.cpp @@ -0,0 +1,308 @@ +#include "arch/CPU.h" +#include "Log.h" +#include "arch/Timer.h" +#include "arch/x86_64/CPU.h" +#include "arch/x86_64/IO.h" +#include "memory/MemoryManager.h" +#include "sys/Syscall.h" +#include "thread/Scheduler.h" +#include +#include +#include +#include +#include +#include + +extern "C" void enable_sse(); +extern "C" void enable_write_protect(); +extern "C" void enable_nx(); + +extern void setup_gdt(); +extern void remap_pic(); +extern void pic_eoi(unsigned char irq); +extern void pic_eoi(Registers* regs); +extern void setup_idt(); + +// Interrupt handling + +#define FIXME_UNHANDLED_INTERRUPT(name) \ + kerrorln("FIXME(interrupt): %s", name); \ + CPU::efficient_halt(); + +#define PF_PRESENT 1 << 0 +#define PF_WRITE 1 << 1 +#define PF_USER 1 << 2 +#define PF_RESERVED 1 << 3 +#define PF_NX_VIOLATION 1 << 4 + +void decode_page_fault_error_code(u64 code) +{ + kwarnln("Fault details: %s | %s | %s%s%s", (code & PF_PRESENT) ? "Present" : "Not present", + (code & PF_WRITE) ? "Write access" : "Read access", (code & PF_USER) ? "User mode" : "Kernel mode", + (code & PF_RESERVED) ? " | Reserved bits set" : "", (code & PF_NX_VIOLATION) ? " | NX violation" : ""); +} + +[[noreturn]] void handle_page_fault(Registers* regs) +{ + CPU::disable_interrupts(); + + u64 cr2; + asm volatile("mov %%cr2, %0" : "=r"(cr2)); + kerrorln("Page fault at RIP %lx while accessing %lx!", regs->rip, cr2); + + decode_page_fault_error_code(regs->error); + + CPU::print_stack_trace_at(regs); + + CPU::efficient_halt(); +} + +[[noreturn]] void handle_general_protection_fault(Registers* regs) +{ + CPU::disable_interrupts(); + + kerrorln("General protection fault at RIP %lx, error code %lx!", regs->rip, regs->error); + + CPU::print_stack_trace_at(regs); + + CPU::efficient_halt(); +} + +extern "C" void handle_x86_exception(Registers* regs) +{ + switch (regs->isr) + { + case 0: FIXME_UNHANDLED_INTERRUPT("Division by zero"); + case 1: FIXME_UNHANDLED_INTERRUPT("Debug interrupt"); + case 2: FIXME_UNHANDLED_INTERRUPT("NMI (Non-maskable interrupt)"); + case 3: FIXME_UNHANDLED_INTERRUPT("Breakpoint"); + case 4: FIXME_UNHANDLED_INTERRUPT("Overflow"); + case 5: FIXME_UNHANDLED_INTERRUPT("Bound range exceeded"); + case 6: FIXME_UNHANDLED_INTERRUPT("Invalid opcode"); + case 7: FIXME_UNHANDLED_INTERRUPT("Device not available"); + case 10: FIXME_UNHANDLED_INTERRUPT("Invalid TSS"); + case 11: FIXME_UNHANDLED_INTERRUPT("Segment not present"); + case 12: FIXME_UNHANDLED_INTERRUPT("Stack-segment fault"); + case 13: handle_general_protection_fault(regs); + case 14: handle_page_fault(regs); + case 16: FIXME_UNHANDLED_INTERRUPT("x87 floating-point exception"); + case 17: FIXME_UNHANDLED_INTERRUPT("Alignment check"); + case 19: FIXME_UNHANDLED_INTERRUPT("SIMD floating-point exception"); + case 20: FIXME_UNHANDLED_INTERRUPT("Virtualization exception"); + case 21: FIXME_UNHANDLED_INTERRUPT("Control-protection exception"); + default: FIXME_UNHANDLED_INTERRUPT("Reserved exception or #DF/#MC, which shouldn't call handle_x86_exception"); + } +} + +CircularQueue scancode_queue; + +void io_thread() +{ + while (true) + { + u8 scancode; + while (!scancode_queue.try_pop(scancode)) { kernel_sleep(10); } + + kinfoln("Read scancode: %#hhx", scancode); + } +} + +// Called from _asm_interrupt_entry +extern "C" void arch_interrupt_entry(Registers* regs) +{ + if (regs->isr < 32) handle_x86_exception(regs); + else if (regs->isr == 32) // Timer interrupt + { + Timer::tick(); + if (should_invoke_scheduler()) Scheduler::invoke(regs); + pic_eoi(regs); + } + else if (regs->isr == 33) // Keyboard interrupt + { + u8 scancode = IO::inb(0x60); + scancode_queue.try_push(scancode); + pic_eoi(regs); + } + else if (regs->isr == 66) // System call + { + SyscallArgs args = { regs->rdi, regs->rsi, regs->rdx, regs->r10, regs->r8, regs->r9 }; + regs->rax = (u64)invoke_syscall(regs, args, regs->rax); + } + else + { + kwarnln("IRQ catched! Halting."); + CPU::efficient_halt(); + } +} + +extern "C" [[noreturn]] void arch_double_fault() +{ + kerrorln("ERROR: Catched double fault"); + CPU::efficient_halt(); +} + +extern "C" [[noreturn]] void arch_machine_check() +{ + kerrorln("ERROR: Machine check failed"); + CPU::efficient_halt(); +} + +// Generic CPU code + +static bool test_nx() +{ + u32 __unused, edx = 0; + if (!__get_cpuid(0x80000001, &__unused, &__unused, &__unused, &edx)) return 0; + return edx & (1 << 20); +} + +namespace CPU +{ + Result identify() + { + static char brand_string[49]; + + u32 buf[4]; + if (!__get_cpuid(0x80000002, &buf[0], &buf[1], &buf[2], &buf[3])) return err(ENOTSUP); + memcpy(brand_string, buf, 16); + if (!__get_cpuid(0x80000003, &buf[0], &buf[1], &buf[2], &buf[3])) return err(ENOTSUP); + memcpy(&brand_string[16], buf, 16); + if (!__get_cpuid(0x80000004, &buf[0], &buf[1], &buf[2], &buf[3])) return err(ENOTSUP); + memcpy(&brand_string[32], buf, 16); + + brand_string[48] = 0; // null-terminate it :) + + return brand_string; + } + + const char* platform_string() + { + return "x86_64"; + } + + void platform_init() + { + enable_sse(); + enable_write_protect(); + if (test_nx()) enable_nx(); + else + kwarnln("not setting the NX bit as it is unsupported"); + setup_gdt(); + setup_idt(); + } + + void platform_finish_init() + { + Scheduler::new_kernel_thread(io_thread).expect_value("Could not create the IO background thread!"); + + remap_pic(); + } + + void enable_interrupts() + { + asm volatile("sti"); + } + + void disable_interrupts() + { + asm volatile("cli"); + } + + void wait_for_interrupt() + { + asm volatile("hlt"); + } + + [[noreturn]] void efficient_halt() // Halt the CPU, using the lowest power possible. On x86-64 we do this using the + // "hlt" instruction, which puts the CPU into a low-power idle state until the + // next interrupt arrives... and we disable interrupts beforehand. + { + asm volatile("cli"); // Disable interrupts + loop: + asm volatile("hlt"); // Let the cpu rest and pause until the next interrupt arrives... which in this case should + // be never (unless an NMI arrives) :) + goto loop; // Safeguard: if we ever wake up, start our low-power rest again + } + + [[noreturn]] void idle_loop() + { + asm volatile("sti"); + loop: + asm volatile("hlt"); + goto loop; + } + + void switch_kernel_stack(u64 top) + { + task_state_segment.rsp[0] = top; + } + + struct StackFrame + { + StackFrame* next; + u64 instruction; + }; + + static void backtrace_impl(u64 base_pointer, void (*callback)(u64, void*), void* arg) + { + StackFrame* current_frame = (StackFrame*)base_pointer; + // FIXME: Validate that the frame itself is readable, might span across multiple pages + while (current_frame && MemoryManager::validate_readable_page((u64)current_frame)) + { + callback(current_frame->instruction, arg); + current_frame = current_frame->next; + } + } + + void get_stack_trace(void (*callback)(u64, void*), void* arg) + { + u64 rbp; + asm volatile("mov %%rbp, %0" : "=r"(rbp)); + return backtrace_impl(rbp, callback, arg); + } + + void print_stack_trace() + { + u64 rbp; + int frame_index = 0; + asm volatile("mov %%rbp, %0" : "=r"(rbp)); + return backtrace_impl( + rbp, + [](u64 instruction, void* arg) { + int* ptr = (int*)arg; + kinfoln("#%d at %p", *ptr, (void*)instruction); + (*ptr)++; + }, + &frame_index); + } + + void get_stack_trace_at(Registers* regs, void (*callback)(u64, void*), void* arg) + { + callback(regs->rip, arg); + return backtrace_impl(regs->rbp, callback, arg); + } + + void print_stack_trace_at(Registers* regs) + { + int frame_index = 0; + get_stack_trace_at( + regs, + [](u64 instruction, void* arg) { + int* ptr = (int*)arg; + kinfoln("#%d at %p", *ptr, (void*)instruction); + (*ptr)++; + }, + &frame_index); + } + + void pause() + { + asm volatile("pause"); + } +} + +// called by kernel_yield +extern "C" void switch_task(Registers* regs) +{ + Scheduler::switch_task(regs); +} diff --git a/kernel/src/arch/x86_64/CPU.h b/kernel/src/arch/x86_64/CPU.h new file mode 100644 index 00000000..3d69c63d --- /dev/null +++ b/kernel/src/arch/x86_64/CPU.h @@ -0,0 +1,25 @@ +#pragma once +#include + +struct Registers // Saved CPU registers for x86-64 +{ + u64 r15, r14, r13, r12, r11, r10, r9, r8; + u64 rbp, rdi, rsi, rdx, rcx, rbx, rax; + u64 isr, error; + u64 rip, cs, rflags, rsp, ss; +}; + +struct [[gnu::packed]] TSS +{ + u32 reserved0; + u64 rsp[3]; + u64 reserved1; + u64 ist[7]; + u64 reserved2; + u16 reserved3; + u16 iomap_base; +}; + +static_assert(sizeof(TSS) == 104UL); + +extern TSS task_state_segment; diff --git a/kernel/src/arch/x86_64/Entry.asm b/kernel/src/arch/x86_64/Entry.asm new file mode 100644 index 00000000..62dee46c --- /dev/null +++ b/kernel/src/arch/x86_64/Entry.asm @@ -0,0 +1,7 @@ +global _main +extern _start + +_main: + xor rbp, rbp + cld + call _start \ No newline at end of file diff --git a/kernel/src/arch/x86_64/IO.cpp b/kernel/src/arch/x86_64/IO.cpp new file mode 100644 index 00000000..76f51cc3 --- /dev/null +++ b/kernel/src/arch/x86_64/IO.cpp @@ -0,0 +1,40 @@ +#include "arch/x86_64/IO.h" + +namespace IO +{ + u8 inb(u16 port) + { + u8 result; + asm volatile("inb %1, %0" : "=a"(result) : "Nd"(port)); + return result; + } + + void outb(u16 port, u8 value) + { + asm volatile("outb %0, %1" : : "a"(value), "Nd"(port)); + } + + u16 inw(u16 port) + { + u16 result; + asm volatile("inw %1, %0" : "=a"(result) : "Nd"(port)); + return result; + } + + void outw(u16 port, u16 value) + { + asm volatile("outw %0, %1" : : "a"(value), "Nd"(port)); + } + + u32 inl(u16 port) + { + u32 result; + asm volatile("inl %1, %0" : "=a"(result) : "Nd"(port)); + return result; + } + + void outl(u16 port, u32 value) + { + asm volatile("outl %0, %1" : : "a"(value), "Nd"(port)); + } +} diff --git a/kernel/src/arch/x86_64/IO.h b/kernel/src/arch/x86_64/IO.h new file mode 100644 index 00000000..d25513c5 --- /dev/null +++ b/kernel/src/arch/x86_64/IO.h @@ -0,0 +1,13 @@ +#pragma once +#include + +namespace IO +{ + u8 inb(u16 port); + u16 inw(u16 port); + u32 inl(u16 port); + + void outb(u16 port, u8 value); + void outw(u16 port, u16 value); + void outl(u16 port, u32 value); +} diff --git a/kernel/src/arch/x86_64/MMU.cpp b/kernel/src/arch/x86_64/MMU.cpp new file mode 100644 index 00000000..f6081f2a --- /dev/null +++ b/kernel/src/arch/x86_64/MMU.cpp @@ -0,0 +1,383 @@ +#include "arch/MMU.h" +#include "memory/MemoryManager.h" +#include +#include +#include +#include + +#pragma GCC push_options +#pragma GCC diagnostic ignored "-Wconversion" + +PageDirectory* g_kernel_directory; + +void PageTableEntry::set_address(u64 addr) +{ + this->address = (addr >> 12); +} + +u64 PageTableEntry::get_address() const +{ + return (u64)this->address << 12; +} + +#pragma GCC pop_options + +void PageTableEntry::clear() +{ + raw = 0; +} + +static bool has_flag(int flags, MMU::Flags flag) +{ + return flags & flag; +} + +namespace MMU +{ + + constexpr PageDirectory* l4_table() + { + constexpr u64 l4 = sign | (rindex << 39) | (rindex << 30) | (rindex << 21) | (rindex << 12); + return (PageDirectory*)l4; + } + + constexpr u64 l4_index(u64 addr) + { + return (addr >> 39) & 0777; + } + + PageTableEntry& l4_entry(u64 addr) + { + return l4_table()->entries[l4_index(addr)]; + } + + constexpr PageDirectory* raw_l3_table(u64 l4) + { + const u64 l3 = sign | (rindex << 39) | (rindex << 30) | (rindex << 21) | (l4 << 12); + return (PageDirectory*)l3; + } + + constexpr PageDirectory* l3_table(u64 addr) + { + const u64 l4 = l4_index(addr); + return raw_l3_table(l4); + } + + constexpr u64 l3_index(u64 addr) + { + return (addr >> 30) & 0777; + } + + PageTableEntry& l3_entry(u64 addr) + { + return l3_table(addr)->entries[l3_index(addr)]; + } + + constexpr PageDirectory* raw_l2_table(u64 l4, u64 l3) + { + const u64 l2 = sign | (rindex << 39) | (rindex << 30) | (l4 << 21) | (l3 << 12); + return (PageDirectory*)l2; + } + + constexpr PageDirectory* l2_table(u64 addr) + { + const u64 l4 = l4_index(addr); + const u64 l3 = l3_index(addr); + return raw_l2_table(l4, l3); + } + + constexpr u64 l2_index(u64 addr) + { + return (addr >> 21) & 0777; + } + + PageTableEntry& l2_entry(u64 addr) + { + return l2_table(addr)->entries[l2_index(addr)]; + } + + constexpr PageDirectory* raw_l1_table(u64 l4, u64 l3, u64 l2) + { + const u64 l1 = sign | (rindex << 39) | (l4 << 30) | (l3 << 21) | (l2 << 12); + return (PageDirectory*)l1; + } + + constexpr PageDirectory* l1_table(u64 addr) + { + const u64 l4 = l4_index(addr); + const u64 l3 = l3_index(addr); + const u64 l2 = l2_index(addr); + return raw_l1_table(l4, l3, l2); + } + + constexpr u64 l1_index(u64 addr) + { + return (addr >> 12) & 0777; + } + + PageTableEntry& l1_entry(u64 addr) + { + return l1_table(addr)->entries[l1_index(addr)]; + } + + void switch_page_directory(PageDirectory* dir) + { + asm volatile("mov %0, %%cr3" : : "r"(dir)); + } + + PageDirectory* get_page_directory() + { + PageDirectory* value; + asm volatile("mov %%cr3, %0" : "=r"(value)); + return value; + } + + void flush_all() + { + switch_page_directory(get_page_directory()); + } + + void flush_page(u64 page) + { + asm volatile("invlpg (%0)" : : "r"(page) : "memory"); + } + + int arch_flags_to_mmu(const PageTableEntry& entry) + { + int result = Flags::None; + if (entry.read_write) result |= Flags::ReadWrite; + if (entry.user) result |= Flags::User; + if (entry.no_execute) result |= Flags::NoExecute; + if (entry.write_through) result |= Flags::WriteThrough; + if (entry.cache_disabled) result |= Flags::CacheDisable; + return result; + } + + Result find_entry(u64 virt) + { + const auto& l4 = l4_entry(virt); + if (!l4.present) return err(EFAULT); + auto& l3 = l3_entry(virt); + if (!l3.present) return err(EFAULT); + if (l3.larger_pages) return &l3; + auto& l2 = l2_entry(virt); + if (!l2.present) return err(EFAULT); + if (l2.larger_pages) return &l2; + return &l1_entry(virt); + } + + Result apply_cascading_flags(u64 virt, int flags) + { + auto& l4 = l4_entry(virt); + if (!l4.present) return err(EFAULT); + if (flags & Flags::ReadWrite) l4.read_write = true; + if (flags & Flags::User) l4.user = true; + auto& l3 = l3_entry(virt); + if (!l3.present) return err(EFAULT); + if (l3.larger_pages) return &l3; + if (flags & Flags::ReadWrite) l3.read_write = true; + if (flags & Flags::User) l3.user = true; + auto& l2 = l2_entry(virt); + if (!l2.present) return err(EFAULT); + if (l2.larger_pages) return &l2; + if (flags & Flags::ReadWrite) l2.read_write = true; + if (flags & Flags::User) l2.user = true; + auto& l1 = l1_entry(virt); + return &l1; + } + + Result map(u64 virt, u64 phys, int flags) + { + auto& l4 = l4_entry(virt); + if (!l4.present) + { + u64 addr = TRY(MemoryManager::alloc_frame()); + l4.present = true; + l4.set_address(addr); + memset(l3_table(virt), 0, ARCH_PAGE_SIZE); + } + if (flags & Flags::ReadWrite) l4.read_write = true; + if (flags & Flags::User) l4.user = true; + + auto& l3 = l3_entry(virt); + if (!l3.present) + { + u64 addr = TRY(MemoryManager::alloc_frame()); + l3.present = true; + l3.set_address(addr); + memset(l2_table(virt), 0, ARCH_PAGE_SIZE); + } + if (flags & Flags::ReadWrite) l3.read_write = true; + if (flags & Flags::User) l3.user = true; + + if (l3.larger_pages) return err(EFIXME); // FIXME: Replacing larger pages is not supported ATM + + auto& l2 = l2_entry(virt); + if (!l2.present) + { + u64 addr = TRY(MemoryManager::alloc_frame()); + l2.present = true; + l2.set_address(addr); + memset(l1_table(virt), 0, ARCH_PAGE_SIZE); + } + if (flags & Flags::ReadWrite) l2.read_write = true; + if (flags & Flags::User) l2.user = true; + + if (l2.larger_pages) return err(EFIXME); // FIXME: Replacing larger pages is not supported ATM + + auto& l1 = l1_entry(virt); + if (l1.present) return err(EEXIST); // Please explicitly unmap the page before mapping it again. + l1.present = true; + l1.read_write = has_flag(flags, Flags::ReadWrite); + l1.user = has_flag(flags, Flags::User); + l1.write_through = has_flag(flags, Flags::WriteThrough); + l1.cache_disabled = has_flag(flags, Flags::CacheDisable); + l1.no_execute = has_flag(flags, Flags::NoExecute); + l1.set_address(phys); + return {}; + } + + Result remap(u64 virt, int flags) + { + auto& l1 = *TRY(apply_cascading_flags(virt, flags)); + if (!l1.present) return err(EFAULT); + l1.read_write = has_flag(flags, Flags::ReadWrite); + l1.user = has_flag(flags, Flags::User); + l1.write_through = has_flag(flags, Flags::WriteThrough); + l1.cache_disabled = has_flag(flags, Flags::CacheDisable); + l1.no_execute = has_flag(flags, Flags::NoExecute); + flush_page(virt); + return {}; + } + + Result unmap(u64 virt) + { + auto& l1 = *TRY(find_entry(virt)); + if (!l1.present) return err(EFAULT); + const u64 address = l1.get_address(); + l1.clear(); + flush_page(virt); + return address; + } + + Result get_physical(u64 virt) + { + const auto& l1 = *TRY(find_entry(virt)); + if (!l1.present) return err(EFAULT); + return l1.get_address(); + } + + Result get_flags(u64 virt) + { + const auto& l1 = *TRY(find_entry(virt)); + if (!l1.present) return err(EFAULT); + return arch_flags_to_mmu(l1); + } + + void setup_initial_page_directory() + { + PageDirectory* const dir = get_page_directory(); + g_kernel_directory = dir; + const u64 paddr = (u64)dir; + PageTableEntry& recursive_entry = dir->entries[rindex]; + recursive_entry.read_write = true; + recursive_entry.present = true; + recursive_entry.set_address(paddr); + flush_all(); + } + + Result create_page_directory_for_userspace() + { + u64 directory_virt = TRY(MemoryManager::alloc_for_kernel(1, MMU::ReadWrite | MMU::NoExecute)); + u64 directory_phys = MMU::get_physical(directory_virt).value(); + + PageDirectory* directory = (PageDirectory*)directory_virt; + memset(directory, 0, ARCH_PAGE_SIZE); + PageTableEntry& recursive_entry = directory->entries[rindex]; + recursive_entry.read_write = true; + recursive_entry.present = true; + recursive_entry.set_address(directory_phys); + + directory->entries[511] = g_kernel_directory->entries[511]; + + // From now on, we're only going to use the physical address, since accessing the PageDirectory will be dealt + // with using recursive mapping. So let's make sure we don't leak any VM. + MemoryManager::unmap_weak_and_free_vm(directory_virt, 1); + + return (PageDirectory*)directory_phys; + } + + Result delete_userspace_page_directory(PageDirectory* directory) + { + check(directory); + + // Needed in order to access page tables using the recursive mapping system. + switch_page_directory(directory); + + auto guard = make_scope_guard([&] { + check(g_kernel_directory); + switch_page_directory(g_kernel_directory); + MemoryManager::free_frame((u64)directory); + }); + + PageDirectory* table = l4_table(); + + // Let's iterate over every top-level entry, skipping the last two entries (recursive mapping and kernel pages) + for (u64 i = 0; i < 510; i++) + { + PageTableEntry& l4 = table->entries[i]; + if (!l4.present) continue; + + PageDirectory* pdp = raw_l3_table(i); + + for (u64 j = 0; j < 512; j++) + { + PageTableEntry& l3 = pdp->entries[j]; + if (!l3.present) continue; + if (l3.larger_pages) + { + // FIXME: Maybe we shouldn't delete some pages in an address space, such as shared memory. + TRY(MemoryManager::free_frame(l3.get_address())); + } + + PageDirectory* pd = raw_l2_table(i, j); + + for (u64 k = 0; k < 512; k++) + { + PageTableEntry& l2 = pd->entries[k]; + if (!l2.present) continue; + if (l2.larger_pages) + { + // FIXME: Maybe we shouldn't delete some pages in an address space, such as shared memory. + TRY(MemoryManager::free_frame(l2.get_address())); + } + + PageDirectory* pt = raw_l1_table(i, j, k); + + for (u64 l = 0; l < 512; l++) + { + PageTableEntry& l1 = pt->entries[l]; + if (!l1.present) continue; + + // FIXME: Maybe we shouldn't delete some pages in an address space, such as shared memory. + TRY(MemoryManager::free_frame(l1.get_address())); + } + + TRY(MemoryManager::free_frame(l2.get_address())); + } + + TRY(MemoryManager::free_frame(l3.get_address())); + } + + TRY(MemoryManager::free_frame(l4.get_address())); + } + + // No need to clean up manually, the ScopeGuard we set up earlier will do that for us. + return {}; + } + + PageDirectory* kernel_page_directory() + { + return g_kernel_directory; + } +} diff --git a/kernel/src/arch/x86_64/MMU.h b/kernel/src/arch/x86_64/MMU.h new file mode 100644 index 00000000..198485f0 --- /dev/null +++ b/kernel/src/arch/x86_64/MMU.h @@ -0,0 +1,43 @@ +#pragma once +#include + +const usize ARCH_PAGE_SIZE = 4096; + +const u64 rindex = 0776; // recursive index +const u64 sign = 0177777UL << 48; // sign extension + +struct [[gnu::packed]] PageTableEntry +{ + union { + struct [[gnu::packed]] + { + bool present : 1; + bool read_write : 1; + bool user : 1; + bool write_through : 1; + bool cache_disabled : 1; + bool accessed : 1; + bool ignore0 : 1; + bool larger_pages : 1; + bool ignore1 : 1; + u8 available : 3; + u64 address : 48; + u8 available2 : 3; + bool no_execute : 1; + }; + u64 raw; + }; + + void set_address(u64 addr); + u64 get_address() const; + + void clear(); +}; + +struct alignas(ARCH_PAGE_SIZE) PageDirectory +{ + PageTableEntry entries[512]; +}; + +static_assert(sizeof(PageTableEntry) == 8UL); +static_assert(sizeof(PageDirectory) == ARCH_PAGE_SIZE); diff --git a/kernel/src/arch/x86_64/Serial.cpp b/kernel/src/arch/x86_64/Serial.cpp new file mode 100644 index 00000000..3d1dcc35 --- /dev/null +++ b/kernel/src/arch/x86_64/Serial.cpp @@ -0,0 +1,15 @@ +#include "arch/Serial.h" +#include "arch/x86_64/IO.h" + +#define COM1 0x3f8 + +static void serial_wait() +{ + while (!(IO::inb(COM1 + 5) & 0x20)) { asm volatile("pause"); } +} + +void Serial::putchar(u8 c) +{ + serial_wait(); + IO::outb(COM1, c); +} diff --git a/kernel/src/arch/x86_64/Thread.cpp b/kernel/src/arch/x86_64/Thread.cpp new file mode 100644 index 00000000..f02fbaaf --- /dev/null +++ b/kernel/src/arch/x86_64/Thread.cpp @@ -0,0 +1,58 @@ +#include "thread/Thread.h" +#include + +bool is_in_kernel(Registers* regs) +{ + return regs->cs == 8; +} + +void Thread::set_ip(u64 ip) +{ + regs.rip = ip; +} + +u64 Thread::ip() +{ + return regs.rip; +} + +void Thread::set_sp(u64 sp) +{ + regs.rsp = sp; +} + +u64 Thread::sp() +{ + return regs.rsp; +} + +void Thread::init_regs_kernel() +{ + memset(®s, 0, sizeof(Registers)); + regs.cs = 0x08; + regs.ss = 0x10; + regs.rflags = 1 << 9; // IF (Interrupt enable flag) +} + +void Thread::init_regs_user() +{ + memset(®s, 0, sizeof(Registers)); + regs.cs = 0x18 | 3; + regs.ss = 0x20 | 3; + regs.rflags = 1 << 9; // IF (Interrupt enable flag) +} + +void Thread::set_arguments(u64 arg1, u64 arg2, u64 arg3, u64 arg4) +{ + regs.rdi = arg1; + regs.rsi = arg2; + regs.rdx = arg3; + regs.rcx = arg4; +} + +void switch_context(Thread* old_thread, Thread* new_thread, Registers* regs) +{ + if (!old_thread->is_idle()) memcpy(&old_thread->regs, regs, sizeof(Registers)); + + memcpy(regs, &new_thread->regs, sizeof(Registers)); +} diff --git a/kernel/src/arch/x86_64/Timer.cpp b/kernel/src/arch/x86_64/Timer.cpp new file mode 100644 index 00000000..26e441cc --- /dev/null +++ b/kernel/src/arch/x86_64/Timer.cpp @@ -0,0 +1,15 @@ +#include "arch/Timer.h" +#include "arch/x86_64/IO.h" + +#define PIT_CHANNEL_0 0x40 + +const u64 base_frequency = 1193182; + +void Timer::arch_init() +{ + constexpr u16 divisor = (u16)(base_frequency / (ARCH_TIMER_FREQ * 1000)); + static_assert(divisor >= 100, "ARCH_TIMER_FREQ is too high"); + IO::outb(PIT_CHANNEL_0, (u8)(divisor & 0xFF)); + IO::outb(0x80, 0); // short delay + IO::outb(PIT_CHANNEL_0, (u8)((divisor & 0xFF00) >> 8)); +} diff --git a/kernel/src/arch/x86_64/Timer.h b/kernel/src/arch/x86_64/Timer.h new file mode 100644 index 00000000..6ab40002 --- /dev/null +++ b/kernel/src/arch/x86_64/Timer.h @@ -0,0 +1,4 @@ +#pragma once +#include + +const usize ARCH_TIMER_FREQ = 5; diff --git a/kernel/src/arch/x86_64/init/GDT.cpp b/kernel/src/arch/x86_64/init/GDT.cpp new file mode 100644 index 00000000..54480a0e --- /dev/null +++ b/kernel/src/arch/x86_64/init/GDT.cpp @@ -0,0 +1,94 @@ +#include "arch/x86_64/CPU.h" +#include +#include +#include + +struct [[gnu::packed]] GDTR +{ + u16 size; + u64 offset; +}; + +static_assert(sizeof(GDTR) == 10UL); + +struct [[gnu::packed]] GDTEntry +{ + u16 limit0; + u16 base0; + u8 base1; + u8 access; + u8 limit1_flags; + u8 base2; +}; + +static_assert(sizeof(GDTEntry) == 8UL); + +struct [[gnu::packed]] HighGDTEntry +{ + u32 base_high; + u32 reserved; +}; + +static_assert(sizeof(HighGDTEntry) == 8UL); + +struct [[gnu::packed]] alignas(4096) GlobalDescriptorTable +{ + GDTEntry null; + GDTEntry kernel_code; + GDTEntry kernel_data; + GDTEntry user_code; + GDTEntry user_data; + GDTEntry tss; + HighGDTEntry tss2; +}; + +TSS task_state_segment; + +static GlobalDescriptorTable gdt = { { 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00 }, + { 0xffff, 0x0000, 0x00, 0x9a, 0xaf, 0x00 }, + { 0xffff, 0x0000, 0x00, 0x92, 0xcf, 0x00 }, + { 0xffff, 0x0000, 0x00, 0xfa, 0xaf, 0x00 }, + { 0xffff, 0x0000, 0x00, 0xf2, 0xcf, 0x00 }, + { 0x0000, 0x0000, 0x00, 0xe9, 0x0f, 0x00 }, + { 0x00000000, 0x00000000 } }; + +extern "C" void load_gdt(GDTR* gdtr); +extern "C" void load_tr(int segment); + +static void set_base(GDTEntry* entry, u32 base) +{ + entry->base0 = (base & 0xFFFF); + entry->base1 = (base >> 16) & 0xFF; + entry->base2 = (u8)((base >> 24) & 0xFF); +} + +static void set_limit(GDTEntry* entry, u32 limit) +{ + expect(limit <= 0xFFFFF, "Limit too big for a GDT entry"); + entry->limit0 = limit & 0xFFFF; + entry->limit1_flags = (entry->limit1_flags & 0xF0) | ((limit >> 16) & 0xF); +} + +static void set_tss_base(GDTEntry* tss1, HighGDTEntry* tss2, u64 addr) +{ + set_base(tss1, addr & 0xffffffff); + tss2->base_high = (u32)(addr >> 32); +} + +static void setup_tss() +{ + memset(&task_state_segment, 0, sizeof(TSS)); + task_state_segment.iomap_base = sizeof(TSS); + set_tss_base(&gdt.tss, &gdt.tss2, (u64)&task_state_segment); + set_limit(&gdt.tss, sizeof(TSS) - 1); +} + +void setup_gdt() +{ + static GDTR gdtr; + gdtr.offset = (u64)&gdt; + gdtr.size = sizeof(GlobalDescriptorTable); + setup_tss(); + load_gdt(&gdtr); + load_tr(0x2b); +} diff --git a/kernel/src/arch/x86_64/init/IDT.cpp b/kernel/src/arch/x86_64/init/IDT.cpp new file mode 100644 index 00000000..22ea980a --- /dev/null +++ b/kernel/src/arch/x86_64/init/IDT.cpp @@ -0,0 +1,121 @@ +#include +#include +#include + +struct IDTEntry +{ + u16 offset0; + u16 selector; + u8 ist; + u8 type_attr; + u16 offset1; + u32 offset2; + u32 ignore; + void set_offset(u64 offset); + u64 get_offset() const; +}; + +static_assert(sizeof(IDTEntry) == 16UL); + +void IDTEntry::set_offset(u64 offset) +{ + offset0 = (u16)(offset & 0x000000000000ffff); + offset1 = (u16)((offset & 0x00000000ffff0000) >> 16); + offset2 = (u32)((offset & 0xffffffff00000000) >> 32); +} + +u64 IDTEntry::get_offset() const +{ + u64 offset = 0; + offset |= (u64)offset0; + offset |= (u64)offset1 << 16; + offset |= (u64)offset2 << 32; + return offset; +} + +static IDTEntry idt[256]; + +#define IDT_TA_InterruptGate 0b10001110 +#define IDT_TA_UserCallableInterruptGate 0b11101110 +#define IDT_TA_TrapGate 0b10001111 + +struct [[gnu::packed]] IDTR +{ + u16 limit; + u64 offset; +}; + +static_assert(sizeof(IDTR) == 10UL); + +static void idt_add_handler(short num, void* handler, u8 type_attr) +{ + check(handler != nullptr); + expect(num < 256, "IDT can only hold up to 256 entries"); + IDTEntry* const entry_for_handler = &idt[num]; + entry_for_handler->selector = 0x08; + entry_for_handler->type_attr = type_attr; + entry_for_handler->set_offset((u64)handler); +} + +#define INT(x) extern "C" void _isr##x() +#define TRAP(x) idt_add_handler(x, (void*)_isr##x, IDT_TA_TrapGate) +#define IRQ(x) idt_add_handler(x, (void*)_isr##x, IDT_TA_InterruptGate) +#define SYS(x) idt_add_handler(x, (void*)_isr##x, IDT_TA_UserCallableInterruptGate) + +INT(0); +INT(1); +INT(2); +INT(3); +INT(4); +INT(5); +INT(6); +INT(7); +INT(8); +INT(10); +INT(11); +INT(12); +INT(13); +INT(14); +INT(16); +INT(17); +INT(18); +INT(19); +INT(20); +INT(21); +INT(32); +INT(33); +INT(66); + +void setup_idt() +{ + memset(idt, 0, sizeof(idt)); + + TRAP(0); + TRAP(1); + TRAP(2); + TRAP(3); + TRAP(4); + TRAP(5); + TRAP(6); + TRAP(7); + TRAP(8); + TRAP(10); + TRAP(11); + TRAP(12); + TRAP(13); + TRAP(14); + TRAP(16); + TRAP(17); + TRAP(18); + TRAP(19); + TRAP(20); + TRAP(21); + IRQ(32); + IRQ(33); + SYS(66); + + static IDTR idtr; + idtr.limit = 0x0FFF; + idtr.offset = (u64)idt; + asm volatile("lidt %0" : : "m"(idtr)); +} diff --git a/kernel/src/arch/x86_64/init/PIC.cpp b/kernel/src/arch/x86_64/init/PIC.cpp new file mode 100644 index 00000000..e24a23a1 --- /dev/null +++ b/kernel/src/arch/x86_64/init/PIC.cpp @@ -0,0 +1,53 @@ +#include "arch/x86_64/CPU.h" +#include "arch/x86_64/IO.h" + +#define PIC1_COMMAND 0x20 +#define PIC1_DATA 0x21 +#define PIC2_COMMAND 0xA0 +#define PIC2_DATA 0xA1 +#define PIC_EOI 0x20 + +#define ICW1_INIT 0x10 +#define ICW1_ICW4 0x01 +#define ICW4_8086 0x01 + +#define io_delay() IO::outb(0x80, 0) + +void remap_pic() +{ + IO::outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4); + io_delay(); + IO::outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4); + io_delay(); + + IO::outb(PIC1_DATA, 0x20); + io_delay(); + + IO::outb(PIC2_DATA, 0x28); + io_delay(); + + IO::outb(PIC1_DATA, 4); + io_delay(); + IO::outb(PIC2_DATA, 2); + io_delay(); + + IO::outb(PIC1_DATA, ICW4_8086); + io_delay(); + IO::outb(PIC2_DATA, ICW4_8086); + io_delay(); + + IO::outb(PIC1_DATA, 0b11111100); + io_delay(); + IO::outb(PIC2_DATA, 0b11111111); +} + +void pic_eoi(unsigned char irq) +{ + if (irq >= 8) IO::outb(PIC2_COMMAND, PIC_EOI); + IO::outb(PIC1_COMMAND, PIC_EOI); +} + +void pic_eoi(Registers* regs) +{ + pic_eoi((unsigned char)(regs->error)); // On IRQs, the error code is the IRQ number +} diff --git a/kernel/src/boot/Init.cpp b/kernel/src/boot/Init.cpp new file mode 100644 index 00000000..dad4e9ed --- /dev/null +++ b/kernel/src/boot/Init.cpp @@ -0,0 +1,36 @@ +#include "boot/Init.h" +#include "InitRD.h" +#include "Log.h" +#include "arch/CPU.h" +#include "boot/bootboot.h" +#include "memory/MemoryManager.h" +#include "video/Framebuffer.h" +#include +#include + +extern const BOOTBOOT bootboot; + +void Init::check_magic() +{ + if (memcmp(bootboot.magic, BOOTBOOT_MAGIC, 4)) + { + kerrorln("ERROR: Invalid magic value from bootloader"); + CPU::efficient_halt(); + } +} + +void Init::early_init() +{ + CPU::disable_interrupts(); + + Framebuffer::init(); + + setup_log(log_debug_enabled(), log_serial_enabled(), true); + + CPU::platform_init(); + + MemoryManager::init(); + InitRD::initialize(); + + MemoryManager::protect_kernel_sections().expect_release_value("We should succeed to protect sections"); +} diff --git a/kernel/include/init/Init.h b/kernel/src/boot/Init.h similarity index 58% rename from kernel/include/init/Init.h rename to kernel/src/boot/Init.h index 0870c600..b7fb4422 100644 --- a/kernel/include/init/Init.h +++ b/kernel/src/boot/Init.h @@ -2,8 +2,6 @@ namespace Init { - void check_magic(); - void disable_smp(); void early_init(); - void finish_kernel_boot(); -} \ No newline at end of file + void check_magic(); +} diff --git a/kernel/include/bootboot.h b/kernel/src/boot/bootboot.h similarity index 99% rename from kernel/include/bootboot.h rename to kernel/src/boot/bootboot.h index 8ac1207e..7e6b6a17 100644 --- a/kernel/include/bootboot.h +++ b/kernel/src/boot/bootboot.h @@ -1,5 +1,5 @@ /* - * bootboot.h + * boot/bootboot.h * https://gitlab.com/bztsrc/bootboot * * Copyright (C) 2017 - 2021 bzt (bztsrc@gitlab) diff --git a/kernel/src/config.h.in b/kernel/src/config.h.in new file mode 100644 index 00000000..6cbc30ec --- /dev/null +++ b/kernel/src/config.h.in @@ -0,0 +1,6 @@ +#pragma once + +#define MOON_VERSION "@CMAKE_PROJECT_VERSION@" +#define MOON_VERSION_MAJOR "@CMAKE_PROJECT_VERSION_MAJOR@" +#define MOON_VERSION_MINOR "@CMAKE_PROJECT_VERSION_MINOR@" +#define MOON_VERSION_PATCH "@CMAKE_PROJECT_VERSION_PATCH@" \ No newline at end of file diff --git a/kernel/src/cpu/CPU.cpp b/kernel/src/cpu/CPU.cpp deleted file mode 100644 index f686a009..00000000 --- a/kernel/src/cpu/CPU.cpp +++ /dev/null @@ -1,99 +0,0 @@ -#define MODULE "cpuid" - -#include "cpu/CPU.h" -#include "log/Log.h" -#include -#include - -const char* CPU::get_vendor_string() -{ - static bool cached = false; - static char vendor[13]; - if (cached) { return vendor; } - else - { - unsigned int unused, ebx, ecx, edx; - __get_cpuid(0, &unused, &ebx, &ecx, &edx); - memcpy(vendor, &ebx, 4); - memcpy(&vendor[4], &edx, 4); - memcpy(&vendor[8], &ecx, 4); - vendor[12] = 0; - cached = true; - return vendor; - } -} - -const char* CPU::get_brand_string() -{ - static bool cached = false; - static char brand[49]; - if (cached) { return brand; } - else - { - unsigned int eax, ebx, ecx, edx; - __get_cpuid(0x80000002, &eax, &ebx, &ecx, &edx); - memcpy(brand, &eax, 4); - memcpy(&brand[4], &ebx, 4); - memcpy(&brand[8], &ecx, 4); - memcpy(&brand[12], &edx, 4); - __get_cpuid(0x80000003, &eax, &ebx, &ecx, &edx); - memcpy(&brand[16], &eax, 4); - memcpy(&brand[16 + 4], &ebx, 4); - memcpy(&brand[16 + 8], &ecx, 4); - memcpy(&brand[16 + 12], &edx, 4); - __get_cpuid(0x80000004, &eax, &ebx, &ecx, &edx); - memcpy(&brand[32], &eax, 4); - memcpy(&brand[32 + 4], &ebx, 4); - memcpy(&brand[32 + 8], &ecx, 4); - memcpy(&brand[32 + 12], &edx, 4); - brand[48] = 0; - cached = true; - return brand; - } -} - -uint64_t CPU::get_feature_bitmask() -{ - static uint64_t bitmask = 0; - static bool cached = false; - if (cached) return bitmask; - unsigned int unused; - unsigned int ecx = 0; - unsigned int edx = 0; - __get_cpuid(1, &unused, &unused, &ecx, &edx); - bitmask = ((uint64_t)ecx << 32) | (uint64_t)edx; - cached = true; - return bitmask; -} - -bool CPU::has_nx() -{ - unsigned int unused; - unsigned int edx; - __get_cpuid(0x80000001, &unused, &unused, &unused, &edx); - return edx & (1 << 20); -} - -static bool _has_feature(int feature) -{ - return (CPU::get_feature_bitmask() & (uint64_t)(1UL << feature)) > 0; -} - -bool CPU::has_feature(CPU::Features feature) -{ - return _has_feature((int)feature); -} - -uint64_t CPU::get_initial_apic_id() -{ - unsigned int unused; - unsigned int ebx = 0; - __get_cpuid(1, &unused, &ebx, &unused, &unused); - return ebx >> 24; -} - -void CPU::log_cpu_information() -{ - kinfoln("CPU vendor: %s", get_vendor_string()); - kinfoln("CPU brand: %s", get_brand_string()); -} diff --git a/kernel/src/fs/FileDescriptor.cpp b/kernel/src/fs/FileDescriptor.cpp deleted file mode 100644 index 26dee2bc..00000000 --- a/kernel/src/fs/FileDescriptor.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include "fs/FileDescriptor.h" -#include "std/errno.h" -#include "std/stdlib.h" -#include "sys/UserMemory.h" - -Descriptor::Descriptor() : m_is_open(false) -{ -} - -Descriptor::Descriptor(const Descriptor& other) - : m_is_open(other.m_is_open), m_can_read(other.m_can_read), m_can_write(other.m_can_write), - m_able_to_block(other.m_able_to_block), m_close_on_exec(other.m_close_on_exec), m_node(other.m_node), - m_offset(other.m_offset) -{ -} - -void Descriptor::open(VFS::Node* node, bool can_read, bool can_write, bool able_to_block, bool close_on_exec) -{ - m_can_read = can_read; - m_can_write = can_write; - m_able_to_block = able_to_block; - m_close_on_exec = close_on_exec; - m_node = node; - m_offset = 0; - m_is_open = true; -} - -ssize_t Descriptor::read(size_t size, char* buffer) -{ - ssize_t result = VFS::read(m_node, m_offset, size, buffer); - m_offset += result; - return result; -} - -ssize_t Descriptor::write(size_t size, const char* buffer) -{ - ssize_t result = VFS::write(m_node, m_offset, size, buffer); - m_offset += result; - return result; -} - -ssize_t Descriptor::user_read(size_t size, char* buffer) -{ - char* buf = (char*)kmalloc(size); - if (!buf) return -ENOMEM; - ssize_t result = read(size, buf); - if (!copy_to_user(buffer, buf, size)) result = -EFAULT; - kfree(buf); - return result; -} - -ssize_t Descriptor::user_write(size_t size, const char* buffer) -{ - char* buf = (char*)kmalloc(size); - if (!buf) return -ENOMEM; - ssize_t result; - if (!copy_from_user(buffer, buf, size)) result = -EFAULT; - else - result = write(size, buf); - kfree(buf); - return result; -} - -#define MAP_FAIL(errno) 0xffffffffffffff00 | (unsigned char)(errno) - -uintptr_t Descriptor::mmap(uintptr_t addr, size_t size, int prot, off_t offset) -{ - if (!m_node->mmap_func) return MAP_FAIL(ENOTSUP); - return m_node->mmap_func(m_node, addr, size, prot, offset); -} - -long Descriptor::ioctl(int cmd, uintptr_t arg) -{ - if (!m_node->ioctl_func) return MAP_FAIL(ENOTSUP); - return m_node->ioctl_func(m_node, cmd, arg); -} - -int Descriptor::seek(long offset) -{ - if (m_node->type == VFS_FILE && (uint64_t)offset > m_node->length) - return -EINVAL; // FIXME: Support seeking beyond the current file's length. - m_offset = (uint64_t)offset; - return 0; -} - -const Descriptor& Descriptor::operator=(const Descriptor& other) -{ - m_is_open = other.m_is_open; - m_can_read = other.m_can_read; - m_can_write = other.m_can_write; - m_offset = other.m_offset; - m_node = other.m_node; - m_able_to_block = other.m_able_to_block; - m_close_on_exec = other.m_close_on_exec; - return other; -} \ No newline at end of file diff --git a/kernel/src/fs/InitRD.cpp b/kernel/src/fs/InitRD.cpp deleted file mode 100644 index 78ffe094..00000000 --- a/kernel/src/fs/InitRD.cpp +++ /dev/null @@ -1,423 +0,0 @@ -#define MODULE "initrd" - -#include "fs/InitRD.h" -#include "bootboot.h" -#include "fs/VFS.h" -#include "io/Serial.h" -#include "log/Log.h" -#include "memory/MemoryManager.h" -#include "misc/utils.h" -#include "std/errno.h" -#include "std/stdlib.h" -#include "std/string.h" -#include "utils/StringParsing.h" - -// FIXME: A lot of this code was written before the VFS was created and thus is quite messy and assumes other stuff. - -extern BOOTBOOT bootboot; - -static void* initrd_base; -static bool initrd_initialized = false; - -static VFS::Node initrd_root; - -extern uint64_t clock_boot(); // defined in sys/clock.cpp -extern uint64_t clock_now(); - -bool InitRD::is_initialized() -{ - return initrd_initialized; -} - -static inline uint64_t get_file_size_in_blocks(InitRD::File f) -{ - return f.size_in_blocks; -} - -inline uint64_t InitRD::get_total_blocks() -{ - return bootboot.initrd_size / TAR_BLOCKSIZE; -} - -inline InitRD::TarHeader* InitRD::get_block(uint64_t block_index) -{ - return (TarHeader*)((uintptr_t)initrd_base + block_index * TAR_BLOCKSIZE); -} - -inline bool InitRD::is_valid_header(TarHeader* header) -{ - return strncmp(header->magic, TAR_MAGIC, 5) == 0; -} - -uint64_t InitRD::get_file_physical_address(InitRD::File& file) -{ - return (uint64_t)file.addr - (uint64_t)initrd_base + (uint64_t)bootboot.initrd_ptr; -} - -InitRD::File InitRD::get_file(TarHeader* header) -{ - File result; - char null_terminated_size[13]; - memcpy(null_terminated_size, header->size, 12); - null_terminated_size[12] = 0; - result.size = parse_octal(null_terminated_size); - memcpy(result.name, header->name, 100); - result.addr = (void*)((uint64_t)header + TAR_BLOCKSIZE); - result.size_in_blocks = Utilities::get_blocks_from_size(TAR_BLOCKSIZE, result.size); - result.mode = (mode_t)parse_octal(header->mode); - return result; -} - -InitRD::File InitRD::open(const char* filename) -{ - uint64_t block = 0; - uint64_t total_blocks = get_total_blocks(); - while (block < total_blocks) - { - TarHeader* hdr = (TarHeader*)get_block(block); - if (hdr->typeflag == 53) - { - block++; - continue; - } - if (!is_valid_header(hdr)) - { - block++; - continue; - } - auto f = get_file(hdr); - if (strncmp(hdr->name, filename, strlen(filename)) == 0) { return f; } - block += get_file_size_in_blocks(f) + 1; - } - File nullFile; - nullFile.addr = 0; - nullFile.size = 0; - memcpy(nullFile.name, "NULL", 5); - return nullFile; -} - -void InitRD::for_each(void (*callback)(File& f)) -{ - uint64_t block = 0; - uint64_t total_blocks = get_total_blocks(); - while (block < total_blocks) - { - TarHeader* hdr = (TarHeader*)get_block(block); - if (hdr->typeflag == 53) - { - block++; - continue; - } - if (!is_valid_header(hdr)) - { - block++; - continue; - } - auto f = get_file(hdr); - block += get_file_size_in_blocks(f) + 1; - callback(f); - } -} - -#define INITRD_MAX_FILES_IN_DIR 32 -#define INITRD_MAX_FILES 64 - -namespace InitRD -{ - struct Directory - { - char name[64]; - int entries = 0; - VFS::Node* files[INITRD_MAX_FILES_IN_DIR]; - }; -} - -void initrd_for_each_dir(void (*callback)(InitRD::Directory& f)) -{ - uint64_t block = 0; - uint64_t total_blocks = InitRD::get_total_blocks(); - while (block < total_blocks) - { - InitRD::TarHeader* hdr = (InitRD::TarHeader*)InitRD::get_block(block); - if (!InitRD::is_valid_header(hdr)) - { - block++; - continue; - } - if (hdr->typeflag == 53) - { - InitRD::Directory dir; - strncpy(dir.name, hdr->name, sizeof(dir.name)); - callback(dir); - block++; - continue; - } - auto f = get_file(hdr); - block += get_file_size_in_blocks(f) + 1; - } -} - -static InitRD::File files[INITRD_MAX_FILES]; -static uint32_t total_files = 0; - -static InitRD::Directory dirs[INITRD_MAX_FILES]; -static uint32_t total_dirs = 0; - -static VFS::Node nodes[INITRD_MAX_FILES + (INITRD_MAX_FILES - 1)]; // One of the dirs is the initrd_root -static uint32_t total_nodes = 0; - -ssize_t initrd_read(VFS::Node* node, size_t offset, size_t length, char* buffer) -{ - if (!node) return -1; - if (node->inode >= total_files) return -1; - InitRD::File& file = files[node->inode]; - if (offset > file.size) return -1; - if (offset + length > file.size) { length = file.size - offset; } - memcpy(buffer, (void*)((uintptr_t)file.addr + offset), length); - return length; -} - -VFS::Node* initrd_scan_dir(VFS::Node* node, const char* filename) -{ - if (!node) return 0; - if (node->inode >= total_dirs) return 0; - InitRD::Directory dir = dirs[node->inode]; - for (int i = 0; i < dir.entries; i++) - { - if (strncmp(dir.files[i]->name, filename, sizeof(VFS::Node::name)) == 0) { return dir.files[i]; } - } - return 0; -} - -VFS::Node* initrd_read_dir(VFS::Node* node, long offset) -{ - if (!node) return 0; - if (node->inode >= total_dirs) return 0; - InitRD::Directory dir = dirs[node->inode]; - if (offset >= dir.entries) return 0; - return dir.files[offset]; -} - -int initrd_mkdir(VFS::Node* node, const char* name, mode_t mode) -{ - if (total_dirs >= 32) - { - kwarnln("mkdir() failed: too many directories"); - return -ENOSPC; - } - if (node->inode > total_dirs) - { - kwarnln("mkdir() failed: invalid node"); - return -EINVAL; - } - if (!(node->type & VFS_DIRECTORY)) - { - kwarnln("mkdir() failed: not a directory"); - return -ENOTDIR; - } - InitRD::Directory& parent = dirs[node->inode]; - if (parent.entries == INITRD_MAX_FILES_IN_DIR) - { - kwarnln("mkdir() failed: parent is full"); - return -ENOSPC; - } - uint64_t inode = total_dirs; - VFS::Node& new_node = nodes[total_nodes++]; - new_node.inode = inode; - new_node.find_func = initrd_scan_dir; - new_node.mkdir_func = initrd_mkdir; - new_node.length = 0; - new_node.type = VFS_DIRECTORY; - new_node.mode = mode; - new_node.uid = new_node.gid = 0; - new_node.atime = new_node.ctime = new_node.mtime = clock_now(); - strncpy(new_node.name, name, sizeof(new_node.name)); - InitRD::Directory dir; - strncpy(dir.name, name, sizeof(dir.name)); - dir.entries = 0; - dirs[total_dirs++] = dir; // FIXME: Right now this isn't of worry, but there is a possibility for a TOCTOU bug here. - // Should use a spinlock or something. - node->length++; - parent.files[parent.entries++] = &new_node; - return 0; -} - -static bool initrd_register_dir(InitRD::Directory& dir, uint64_t inode) -{ - const char* filename = dir.name; - VFS::Node* current_node = &initrd_root; - while (true) - { - while (*filename == '/') { filename++; } - if (*filename == 0) { return false; } - - size_t path_section_size = 0; - while (filename[path_section_size] && filename[path_section_size] != '/') { path_section_size++; } - - if (filename[path_section_size]) // We are in a '/' - { - char* buffer = (char*)kmalloc(path_section_size + 1); - memcpy(buffer, filename, path_section_size); - buffer[path_section_size] = 0; - if (!current_node->find_func) { return false; } - VFS::Node* child = current_node->find_func(current_node, buffer); - if (!child) { return false; } - current_node = child; - kfree(buffer); - } - else - { - if (strncmp(filename, ".", path_section_size) != 0) // The current path section is not '.' - { - if (strncmp(filename, "..", path_section_size) == 0) { return false; } - - if (!current_node->find_func) { return false; } - - InitRD::Directory& parent = dirs[current_node->inode]; - if (parent.entries == INITRD_MAX_FILES_IN_DIR) { return false; } - - char* buffer = (char*)kmalloc(path_section_size + 1); - memcpy(buffer, filename, path_section_size); - buffer[path_section_size] = 0; - - VFS::Node& node = nodes[total_nodes++]; - node.inode = inode; - node.find_func = initrd_scan_dir; - node.length = 0; - node.type = VFS_DIRECTORY; - node.mkdir_func = initrd_mkdir; - node.readdir_func = initrd_read_dir; - node.length = 0; - node.mode = 0755; - node.uid = node.gid = 0; - node.atime = node.ctime = node.mtime = clock_boot(); - strncpy(node.name, buffer, sizeof(node.name)); - strncpy(dir.name, buffer, sizeof(dir.name)); - - parent.files[parent.entries++] = &node; - current_node->length++; - - kfree(buffer); - return true; - } - else { return false; } - } - - filename += path_section_size; - } -} - -static bool initrd_register_file(InitRD::File& f, uint64_t inode) -{ - const char* filename = f.name; - VFS::Node* current_node = &initrd_root; - while (true) - { - while (*filename == '/') { filename++; } - if (*filename == 0) { return false; } - - size_t path_section_size = 0; - while (filename[path_section_size] && filename[path_section_size] != '/') { path_section_size++; } - - if (filename[path_section_size]) // We are in a '/' - { - char* buffer = (char*)kmalloc(path_section_size + 1); - memcpy(buffer, filename, path_section_size); - buffer[path_section_size] = 0; - if (!current_node->find_func) { return false; } - VFS::Node* child = current_node->find_func(current_node, buffer); - if (!child) { return false; } - current_node = child; - kfree(buffer); - } - else - { - if (strncmp(filename, ".", path_section_size) != 0) // The current path section is not '.' - { - if (strncmp(filename, "..", path_section_size) == 0) { return false; } - - if (!current_node->find_func) { return false; } - - InitRD::Directory& parent = dirs[current_node->inode]; - if (parent.entries == INITRD_MAX_FILES_IN_DIR) { return false; } - - char* buffer = (char*)kmalloc(path_section_size + 1); - memcpy(buffer, filename, path_section_size); - buffer[path_section_size] = 0; - - VFS::Node& node = nodes[total_nodes++]; - node.inode = inode; - node.read_func = initrd_read; - node.length = f.size; - node.type = VFS_FILE; - node.mode = f.mode & 07555; // don't allow writing - node.uid = node.gid = 0; - node.atime = node.ctime = node.mtime = clock_boot(); - strncpy(node.name, buffer, sizeof(node.name)); - strncpy(f.name, buffer, sizeof(f.name)); - - parent.files[parent.entries++] = &node; - current_node->length++; - kfree(buffer); - return true; - } - else { return false; } - } - - filename += path_section_size; - } -} - -static void initrd_scan() -{ - initrd_for_each_dir([](InitRD::Directory& dir) { - if (total_dirs >= INITRD_MAX_FILES) - { - kwarnln("Failed to register directory %s: Too many directories in initrd", dir.name); - return; - } - uint64_t inode = total_dirs; - if (initrd_register_dir(dir, inode)) dirs[total_dirs++] = dir; - }); - InitRD::for_each([](InitRD::File& f) { - if (total_files >= INITRD_MAX_FILES) - { - kwarnln("Failed to register file %s: Too many files in initrd", f.name); - return; - } - uint64_t inode = total_files; - if (initrd_register_file(f, inode)) files[total_files++] = f; - }); -} - -static void initrd_initialize_root() -{ - initrd_root.length = 0; - initrd_root.inode = 0; - initrd_root.type |= VFS_DIRECTORY; - initrd_root.mode = 0755; - initrd_root.uid = initrd_root.gid = 0; - initrd_root.atime = initrd_root.ctime = initrd_root.mtime = clock_boot(); - InitRD::Directory& root = dirs[0]; - total_dirs++; - strncpy(initrd_root.name, "initrd", sizeof(initrd_root.name)); - strncpy(root.name, "initrd", sizeof(root.name)); - initrd_root.find_func = initrd_scan_dir; - initrd_root.mkdir_func = initrd_mkdir; - initrd_root.readdir_func = initrd_read_dir; -} - -void InitRD::init() -{ - initrd_base = MemoryManager::get_unaligned_mappings( - (void*)bootboot.initrd_ptr, Utilities::get_blocks_from_size(PAGE_SIZE, bootboot.initrd_size)) - .release_value(); // FIXME: Propagate errors. - kdbgln("physical base at %lx, size %lx, mapped to %p", bootboot.initrd_ptr, bootboot.initrd_size, initrd_base); - kdbgln("total blocks: %ld", get_total_blocks()); - void* leak = kmalloc(4); // leak some memory so that kmalloc doesn't continously allocate and free pages - initrd_initialize_root(); - initrd_scan(); - VFS::mount_root(&initrd_root); - initrd_initialized = true; - kfree(leak); -} \ No newline at end of file diff --git a/kernel/src/fs/VFS.cpp b/kernel/src/fs/VFS.cpp deleted file mode 100644 index 9fe20d37..00000000 --- a/kernel/src/fs/VFS.cpp +++ /dev/null @@ -1,300 +0,0 @@ -#define MODULE "vfs" - -#include "fs/VFS.h" -#include "log/Log.h" -#include "std/errno.h" -#include "std/libgen.h" -#include "std/stdlib.h" -#include "std/string.h" - -static VFS::Node* vfs_root; - -int VFS::would_block(Node* node) -{ - if (!node) { return 0; } - if (!node->block_func) { return 0; } - return node->block_func(node); -} - -ssize_t VFS::read(Node* node, size_t offset, size_t length, char* buffer) -{ - if (!node) - { - kwarnln("read() failed: trying to read from nullptr"); - return -1; - } - if (node->type == VFS_DIRECTORY) - { - kwarnln("read() failed: is a directory"); - return -EISDIR; - } - if (!node->read_func) - { - kwarnln("read() failed: the chosen node doesn't support reading"); - return -1; - } - - return node->read_func(node, offset, length, buffer); -} - -ssize_t VFS::write(Node* node, size_t offset, size_t length, const char* buffer) -{ - if (!node) - { - kwarnln("write() failed: trying to write to nullptr"); - return -1; - } - if (node->type == VFS_DIRECTORY) - { - kwarnln("write() failed: is a directory"); - return -EISDIR; - } - if (!node->write_func) - { - kwarnln("write() failed: the chosen node doesn't support writing"); - return -1; - } - - return node->write_func(node, offset, length, buffer); -} - -void VFS::mount_root(Node* root) -{ - if (!root) - { - kwarnln("mount_root() failed: attempted to mount nullptr"); - return; - } - if (vfs_root) - { - kwarnln("mount_root() failed: root filesystem already mounted"); - return; - } - kinfoln("mounting node '%s' as vfs root", root->name); - vfs_root = root; -} - -VFS::Node* VFS::root() -{ - return vfs_root; -} - -VFS::Node* VFS::resolve_path(const char* filename, Node* root) -{ - if (!root) root = vfs_root; - - if (strlen(filename) == 0) return 0; - if (*filename == '/') // Absolute path. - { - filename++; - root = vfs_root; - } - - Node* current_node = root; - - while (true) - { - while (*filename == '/') { filename++; } - if (*filename == 0) { return current_node; } - - size_t path_section_size = 0; - while (filename[path_section_size] && filename[path_section_size] != '/') { path_section_size++; } - - if (strncmp(filename, ".", path_section_size) != 0) // The current path section is not '.' - { - char* buffer = (char*)kmalloc(path_section_size + 1); - memcpy(buffer, filename, path_section_size); - buffer[path_section_size] = 0; - if (!current_node->find_func) - { - kwarnln("Current node has no way to find child nodes"); - return 0; - } - Node* child = current_node->find_func(current_node, buffer); - if (!child) { return 0; } - if (child->flags & VFS_MOUNTPOINT) - { - if (!child->link) - { - kwarnln("Current node's link is null"); - return 0; - } - child = child->link; - } - current_node = child; - kfree(buffer); - } - - filename += path_section_size; - } -} - -int VFS::mkdir(const char* path, const char* name) -{ - Node* node = resolve_path(path, vfs_root); - if (!node) - { - kwarnln("Attempting to mkdir in %s, which does not exist", path); - return -ENOENT; - } - if (node->type != VFS_DIRECTORY) - { - kwarnln("Attempting to mkdir in %s, which is not a directory!!", path); - return -ENOTDIR; - } - if (!node->mkdir_func) - { - kwarnln("Chosen node does not support mkdir()"); - return -ENOTSUP; - } - if (!node->find_func) - { - kwarnln("Chosen node does not support finddir()"); - return -ENOTSUP; - } - if (!strncmp(name, ".", strlen(name)) || !strncmp(name, "..", strlen(name))) - { - kwarnln("Attempted to mkdir . or .., which already exist"); - return -EEXIST; - } - if (node->find_func(node, name) != nullptr) - { - kwarnln("Already exists"); - return -EEXIST; - } - return node->mkdir_func(node, name, 0755); -} - -int VFS::do_mkdir(const char* path, const char* name, int uid, int gid, mode_t mode) -{ - Node* node = resolve_path(path, vfs_root); - if (!node) - { - kwarnln("Attempting to mkdir in %s, which does not exist", path); - return -ENOENT; - } - if (node->type != VFS_DIRECTORY) - { - kwarnln("Attempting to mkdir in %s, which is not a directory!!", path); - return -ENOTDIR; - } - if (!node->mkdir_func) - { - kwarnln("Chosen node does not support mkdir()"); - return -ENOTSUP; - } - if (!node->find_func) - { - kwarnln("Chosen node does not support finddir()"); - return -ENOTSUP; - } - if (!strncmp(name, ".", strlen(name)) || !strncmp(name, "..", strlen(name))) - { - kwarnln("Attempted to mkdir . or .., which already exist"); - return -EEXIST; - } - if (node->find_func(node, name) != nullptr) - { - kwarnln("Already exists"); - return -EEXIST; - } - if (!can_write(node, uid, gid)) - { - kwarnln("Not enough permissions"); - return -EACCES; - } - return node->mkdir_func(node, name, mode); -} - -int VFS::mkdir(const char* pathname) -{ - char* base = better_basename(pathname); - char* dir = better_dirname(pathname); - - kdbgln("mkdir(): creating %s in directory %s", base, dir); - - int result = mkdir(dir, base); - - kfree(base); - kfree(dir); - - return result; -} - -int VFS::do_mkdir(const char* pathname, int uid, int gid, mode_t mode) -{ - char* base = better_basename(pathname); - char* dir = better_dirname(pathname); - - kdbgln("mkdir(): creating %s in directory %s", base, dir); - - int result = do_mkdir(dir, base, uid, gid, mode); - - kfree(base); - kfree(dir); - - return result; -} - -bool VFS::exists(const char* pathname) -{ - return resolve_path(pathname) != nullptr; -} - -void VFS::mount(Node* mountpoint, Node* mounted) -{ - if (!mountpoint || !mounted) return; - if (mountpoint->flags & VFS_MOUNTPOINT || mounted->flags & VFS_MOUNTPOINT) return; - mountpoint->link = mounted; - mountpoint->flags |= VFS_MOUNTPOINT; -} - -void VFS::mount(const char* pathname, Node* mounted) -{ - return mount(resolve_path(pathname), mounted); -} - -void VFS::unmount(Node* mountpoint) -{ - if (!mountpoint) return; - if (!(mountpoint->flags & VFS_MOUNTPOINT)) return; - mountpoint->flags &= ~VFS_MOUNTPOINT; -} - -VFS::Node* VFS::readdir(VFS::Node* dir, long offset) -{ - if (!dir) return 0; - if (!dir->readdir_func) return 0; - return dir->readdir_func(dir, offset); -} - -bool VFS::can_execute(VFS::Node* node, int uid, int gid) -{ - if (uid == node->uid) return node->mode & 0100; - if (gid == node->gid) return node->mode & 0010; - return node->mode & 0001; -} - -bool VFS::can_write(VFS::Node* node, int uid, int gid) -{ - if (uid == node->uid) return node->mode & 0200; - if (gid == node->gid) return node->mode & 0020; - return node->mode & 0002; -} - -bool VFS::can_read(VFS::Node* node, int uid, int gid) -{ - if (uid == node->uid) return node->mode & 0400; - if (gid == node->gid) return node->mode & 0040; - return node->mode & 0004; -} - -bool VFS::is_setuid(VFS::Node* node) -{ - return node->mode & 04000; -} - -bool VFS::is_setgid(VFS::Node* node) -{ - return node->mode & 02000; -} \ No newline at end of file diff --git a/kernel/src/fs/devices/Console.cpp b/kernel/src/fs/devices/Console.cpp deleted file mode 100644 index 2eaeafc2..00000000 --- a/kernel/src/fs/devices/Console.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "fs/devices/Console.h" -#include "config.h" -#include "render/TextRenderer.h" -#include "std/stdio.h" -#include "std/stdlib.h" -#include "std/string.h" - -char* conin_buffer = nullptr; -uint64_t conin_bufsize = 0; - -int ConsoleDevice::would_block(VFS::Node*) -{ - return conin_bufsize == 0; -} - -extern uint64_t clock_now(); - -VFS::Node* ConsoleDevice::create_new(const char* devname) -{ - VFS::Node* dev = new VFS::Node; - dev->write_func = ConsoleDevice::write; - dev->read_func = ConsoleDevice::read; - dev->block_func = ConsoleDevice::would_block; - dev->inode = 0; - dev->length = 0; - dev->type = VFS_DEVICE; - dev->flags = 0; - dev->tty = 1; - dev->uid = dev->gid = 0; - dev->mode = 0666; - dev->atime = dev->ctime = dev->mtime = clock_now(); - strncpy(dev->name, devname, sizeof(dev->name)); - return dev; -} - -ssize_t ConsoleDevice::write(VFS::Node* node, size_t, size_t size, const char* buffer) -{ - if (!node) return -1; - TextRenderer::write(buffer, size); - return (ssize_t)size; -} - -ssize_t ConsoleDevice::read(VFS::Node* node, size_t, size_t size, char* buffer) -{ - if (!node) return -1; - if (!conin_buffer) return 0; - if (size > conin_bufsize) size = conin_bufsize; - memcpy(buffer, conin_buffer, size); - memmove(conin_buffer, conin_buffer + size, conin_bufsize - size); - conin_bufsize -= size; - conin_buffer = (char*)krealloc(conin_buffer, conin_bufsize); - return (ssize_t)size; -} - -void ConsoleDevice::append(char c) -{ - conin_bufsize++; - conin_buffer = (char*)krealloc( - conin_buffer, conin_bufsize); // FIXME: We should probably not be calling realloc every time a key is pressed. - conin_buffer[conin_bufsize - 1] = c; -} \ No newline at end of file diff --git a/kernel/src/fs/devices/DeviceFS.cpp b/kernel/src/fs/devices/DeviceFS.cpp deleted file mode 100644 index d98cb00f..00000000 --- a/kernel/src/fs/devices/DeviceFS.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "fs/devices/DeviceFS.h" -#include "fs/devices/Console.h" -#include "fs/devices/Framebuffer.h" -#include "fs/devices/Keyboard.h" -#include "fs/devices/NullDevice.h" -#include "fs/devices/Random.h" -#include "fs/devices/Serial.h" -#include "fs/devices/Version.h" -#include "std/stdlib.h" -#include "std/string.h" - -#define DEVFS_MAX_FILES 32 - -VFS::Node* devfs_root = nullptr; - -VFS::Node* devfs_files[DEVFS_MAX_FILES]; -int devfs_file_count = 0; - -extern uint64_t clock_boot(); - -VFS::Node* DeviceFS::get() -{ - if (devfs_root) return devfs_root; - devfs_root = new VFS::Node; - devfs_root->length = 0; - devfs_root->inode = 0; - devfs_root->type = VFS_DIRECTORY; - devfs_root->find_func = DeviceFS::finddir; - devfs_root->readdir_func = DeviceFS::readdir; - devfs_root->mode = 0755; - devfs_root->uid = devfs_root->gid = 0; - devfs_root->atime = devfs_root->ctime = devfs_root->mtime = clock_boot(); - strncpy(devfs_root->name, "dev", sizeof(devfs_root->name)); - - devfs_files[devfs_file_count++] = VersionDevice::create_new("version"); - devfs_files[devfs_file_count++] = ConsoleDevice::create_new("console"); - devfs_files[devfs_file_count++] = SerialDevice::create_new("serial"); - devfs_files[devfs_file_count++] = RandomDevice::create_new("random"); - devfs_files[devfs_file_count++] = KeyboardDevice::create_new("kbd"); - devfs_files[devfs_file_count++] = NullDevice::create_new("null"); - devfs_files[devfs_file_count++] = FramebufferDevice::create_new("fb0"); - devfs_root->length = devfs_file_count; - return devfs_root; -} - -VFS::Node* DeviceFS::finddir(VFS::Node* node, const char* filename) -{ - if (!node) return 0; - for (int i = 0; i < devfs_file_count; i++) - { - if (strncmp(devfs_files[i]->name, filename, sizeof(VFS::Node::name)) == 0) { return devfs_files[i]; } - } - return 0; -} - -VFS::Node* DeviceFS::readdir(VFS::Node* node, long offset) -{ - if (!node) return 0; - if (offset >= devfs_file_count) return 0; - return devfs_files[offset]; -} \ No newline at end of file diff --git a/kernel/src/fs/devices/Framebuffer.cpp b/kernel/src/fs/devices/Framebuffer.cpp deleted file mode 100644 index b6175650..00000000 --- a/kernel/src/fs/devices/Framebuffer.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "fs/devices/Framebuffer.h" -#include "bootboot.h" -#include "memory/MemoryManager.h" -#include "misc/utils.h" -#include "std/errno.h" -#include "std/stdio.h" -#include "std/stdlib.h" -#include "std/string.h" -#include "utils/Addresses.h" - -extern BOOTBOOT bootboot; -extern char fb[1]; - -#define MAP_FAIL(errno) 0xffffffffffffff00 | (unsigned char)(errno) - -extern uint64_t clock_now(); - -VFS::Node* FramebufferDevice::create_new(const char* devname) -{ - VFS::Node* dev = new VFS::Node; - dev->write_func = FramebufferDevice::write; - dev->mmap_func = FramebufferDevice::mmap; - dev->ioctl_func = FramebufferDevice::ioctl; - dev->inode = 0; - dev->length = 0; - dev->type = VFS_DEVICE; - dev->flags = 0; - dev->uid = dev->gid = 0; - dev->mode = 0222; - dev->atime = dev->ctime = dev->mtime = clock_now(); - strncpy(dev->name, devname, sizeof(dev->name)); - return dev; -} - -uintptr_t FramebufferDevice::mmap(VFS::Node* node, uintptr_t addr, size_t size, int prot, off_t offset) -{ - if (!node) return -1; - int real_prot = prot & ~(MAP_AS_OWNED_BY_TASK); - if (round_down_to_nearest_page(offset) != (uintptr_t)offset) { return MAP_FAIL(EINVAL); } - if ((size + offset) > bootboot.fb_size) - { - return MAP_FAIL(ERANGE); // FIXME: Should probably be EOVERFLOW. - } - MemoryManager::map_several_pages(bootboot.fb_ptr + offset, addr, Utilities::get_blocks_from_size(PAGE_SIZE, size), - real_prot); - return addr; -} - -ssize_t FramebufferDevice::write(VFS::Node* node, size_t offset, size_t size, const char* buffer) -{ - if (!node) return -1; - if ((size + offset) > (uint64_t)bootboot.fb_size) { size = (uint64_t)bootboot.fb_size - offset; } - memcpy(fb + offset, buffer, size); - return (ssize_t)size; -} - -#define FB_GET_WIDTH 0 -#define FB_GET_HEIGHT 1 -#define FB_GET_SCANLINE 2 - -long FramebufferDevice::ioctl(VFS::Node* node, int cmd, uintptr_t) -{ - if (!node) return -1; - switch (cmd) - { - case FB_GET_WIDTH: return (long)bootboot.fb_width; - case FB_GET_HEIGHT: return (long)bootboot.fb_height; - case FB_GET_SCANLINE: return (long)bootboot.fb_scanline; - default: return -EINVAL; - } -} \ No newline at end of file diff --git a/kernel/src/fs/devices/Keyboard.cpp b/kernel/src/fs/devices/Keyboard.cpp deleted file mode 100644 index 8a1813d4..00000000 --- a/kernel/src/fs/devices/Keyboard.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#define MODULE "kbd" - -#include "fs/devices/Keyboard.h" -#include "config.h" -#include "log/Log.h" -#include "render/TextRenderer.h" -#include "std/stdio.h" -#include "std/stdlib.h" -#include "std/string.h" - -char* kbd_buffer = nullptr; -uint64_t kbd_bufsize = 0; - -int KeyboardDevice::would_block(VFS::Node*) -{ - return kbd_bufsize == 0; -} - -extern uint64_t clock_boot(); - -VFS::Node* KeyboardDevice::create_new(const char* devname) -{ - VFS::Node* dev = new VFS::Node; - dev->read_func = KeyboardDevice::read; - dev->block_func = KeyboardDevice::would_block; - dev->inode = 0; - dev->length = 0; - dev->type = VFS_DEVICE; - dev->flags = 0; - dev->tty = 1; - dev->uid = dev->gid = 0; - dev->mode = 0444; - dev->atime = dev->ctime = dev->mtime = clock_boot(); - strncpy(dev->name, devname, sizeof(dev->name)); - return dev; -} - -ssize_t KeyboardDevice::read(VFS::Node* node, size_t, size_t size, char* buffer) -{ - if (!node) return -1; - if (!kbd_buffer) return 0; - if (size > kbd_bufsize) size = kbd_bufsize; - memcpy(buffer, kbd_buffer, size); - memmove(kbd_buffer, kbd_buffer + size, kbd_bufsize - size); - kbd_bufsize -= size; - kbd_buffer = (char*)krealloc(kbd_buffer, kbd_bufsize); - return (ssize_t)size; -} - -void KeyboardDevice::append(char c) -{ - kbd_bufsize++; - kbd_buffer = (char*)krealloc( - kbd_buffer, kbd_bufsize); // FIXME: We should probably not be calling realloc every time a key is pressed. - kbd_buffer[kbd_bufsize - 1] = c; -} \ No newline at end of file diff --git a/kernel/src/fs/devices/NullDevice.cpp b/kernel/src/fs/devices/NullDevice.cpp deleted file mode 100644 index b49b578c..00000000 --- a/kernel/src/fs/devices/NullDevice.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "fs/devices/NullDevice.h" -#include "std/stdio.h" -#include "std/stdlib.h" -#include "std/string.h" - -extern uint64_t clock_boot(); - -VFS::Node* NullDevice::create_new(const char* devname) -{ - VFS::Node* dev = new VFS::Node; - dev->write_func = NullDevice::write; - dev->read_func = NullDevice::read; - dev->inode = 0; - dev->length = 0; - dev->type = VFS_DEVICE; - dev->flags = 0; - dev->uid = dev->gid = 0; - dev->mode = 0666; - dev->atime = dev->ctime = dev->mtime = clock_boot(); - strncpy(dev->name, devname, sizeof(dev->name)); - return dev; -} - -ssize_t NullDevice::write(VFS::Node* node, size_t, size_t size, const char*) -{ - if (!node) return -1; - return (ssize_t)size; -} - -ssize_t NullDevice::read(VFS::Node* node, size_t, size_t, char*) -{ - if (!node) return -1; - return 0; -} \ No newline at end of file diff --git a/kernel/src/fs/devices/Random.cpp b/kernel/src/fs/devices/Random.cpp deleted file mode 100644 index 0cc8c27b..00000000 --- a/kernel/src/fs/devices/Random.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include "fs/devices/Random.h" -#include "config.h" -#include "rand/Mersenne.h" -#include "render/TextRenderer.h" -#include "std/stdio.h" -#include "std/stdlib.h" -#include "std/string.h" - -extern uint64_t clock_boot(); - -VFS::Node* RandomDevice::create_new(const char* devname) -{ - VFS::Node* dev = new VFS::Node; - dev->read_func = RandomDevice::read; - dev->inode = 0; - dev->length = 0; - dev->type = VFS_DEVICE; - dev->flags = 0; - dev->uid = dev->gid = 0; - dev->mode = 0444; - dev->atime = dev->ctime = dev->mtime = clock_boot(); - strncpy(dev->name, devname, sizeof(dev->name)); - return dev; -} - -ssize_t RandomDevice::read(VFS::Node* node, size_t, size_t size, char* buffer) -{ - if (!node) return -1; - size_t nread = size; - while (size >= sizeof(uint64_t)) - { - *(uint64_t*)buffer = Mersenne::get(); - size -= sizeof(uint64_t); - buffer += sizeof(uint64_t); - } - while (size) - { - *buffer = (char)(Mersenne::get() & 0xFF); - size--; - buffer++; - } - return (ssize_t)nread; -} \ No newline at end of file diff --git a/kernel/src/fs/devices/Serial.cpp b/kernel/src/fs/devices/Serial.cpp deleted file mode 100644 index b8675fff..00000000 --- a/kernel/src/fs/devices/Serial.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "io/Serial.h" -#include "config.h" -#include "fs/devices/Serial.h" -#include "std/stdio.h" -#include "std/stdlib.h" -#include "std/string.h" - -extern uint64_t clock_boot(); - -VFS::Node* SerialDevice::create_new(const char* devname) -{ - VFS::Node* dev = new VFS::Node; - dev->write_func = SerialDevice::write; - dev->inode = 0; - dev->length = 0; - dev->type = VFS_DEVICE; - dev->flags = 0; - dev->uid = dev->gid = 0; - dev->mode = 0222; - dev->atime = dev->ctime = dev->mtime = clock_boot(); - strncpy(dev->name, devname, sizeof(dev->name)); - return dev; -} - -ssize_t SerialDevice::write(VFS::Node* node, size_t, size_t size, const char* buffer) -{ - if (!node) return -1; - Serial::write(buffer, size); - return (ssize_t)size; -} \ No newline at end of file diff --git a/kernel/src/fs/devices/Version.cpp b/kernel/src/fs/devices/Version.cpp deleted file mode 100644 index 0a1ac394..00000000 --- a/kernel/src/fs/devices/Version.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "fs/devices/Version.h" -#include "config.h" -#include "std/stdio.h" -#include "std/stdlib.h" -#include "std/string.h" - -extern uint64_t clock_boot(); - -VFS::Node* VersionDevice::create_new(const char* devname) -{ - VFS::Node* dev = new VFS::Node; - dev->read_func = VersionDevice::read; - dev->inode = 0; - dev->length = strlen(moon_version()) + 5; - dev->type = VFS_DEVICE; - dev->flags = 0; - dev->uid = dev->gid = 0; - dev->mode = 0444; - dev->atime = dev->ctime = dev->mtime = clock_boot(); - strncpy(dev->name, devname, sizeof(dev->name)); - return dev; -} - -ssize_t VersionDevice::read(VFS::Node* node, size_t offset, size_t size, char* buffer) -{ - if (!node) return -1; - if (offset > 0) return 0; // EOF after first read (FIXME: Should be only if everything was read) - snprintf(buffer, size + 1, "moon %s", moon_version()); // FIXME: Support offseting this read - return (ssize_t)size; -} \ No newline at end of file diff --git a/kernel/src/gdt/GDT.asm b/kernel/src/gdt/GDT.asm deleted file mode 100644 index 171debdb..00000000 --- a/kernel/src/gdt/GDT.asm +++ /dev/null @@ -1,21 +0,0 @@ -global load_gdt -load_gdt: - cli - lgdt [rdi] - mov ax, 0x10 - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax - push 0x08 - lea rax, [rel .reload_CS] - push rax - retfq -.reload_CS: - ret -global load_tr -load_tr: - mov rax, rdi - ltr ax - ret \ No newline at end of file diff --git a/kernel/src/gdt/GDT.cpp b/kernel/src/gdt/GDT.cpp deleted file mode 100644 index 0c2ecca4..00000000 --- a/kernel/src/gdt/GDT.cpp +++ /dev/null @@ -1,114 +0,0 @@ -#define MODULE "gdt" - -#include "gdt/GDT.h" -#include "log/Log.h" -#include "memory/MemoryManager.h" -#include "std/ensure.h" -#include "std/string.h" -#include "utils/Addresses.h" -#include - -struct GDTR -{ - uint16_t size; - uint64_t offset; -} __attribute__((packed)); - -struct GDTEntry -{ - uint16_t limit0; - uint16_t base0; - uint8_t base1; - uint8_t access; - uint8_t limit1_flags; - uint8_t base2; -} __attribute__((packed)); - -struct HighGDTEntry -{ - uint32_t base_high; - uint32_t reserved; -} __attribute__((packed)); - -struct TSS -{ - uint32_t reserved0; - uint64_t rsp[3]; - uint64_t reserved1; - uint64_t ist[7]; - uint64_t reserved2; - uint16_t reserved3; - uint16_t iomap_base; -} __attribute__((packed)); - -struct InternalGDT -{ - GDTEntry null; - GDTEntry kernel_code; - GDTEntry kernel_data; - GDTEntry user_code; - GDTEntry user_data; - GDTEntry tss; - HighGDTEntry tss2; -} __attribute__((packed)) __attribute((aligned(PAGE_SIZE))); - -__attribute__((aligned(PAGE_SIZE))) static InternalGDT internal_gdt = {{0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00}, - {0xffff, 0x0000, 0x00, 0x9a, 0xaf, 0x00}, - {0xffff, 0x0000, 0x00, 0x92, 0xcf, 0x00}, - {0xffff, 0x0000, 0x00, 0xfa, 0xaf, 0x00}, - {0xffff, 0x0000, 0x00, 0xf2, 0xcf, 0x00}, - {0x0000, 0x0000, 0x00, 0xe9, 0x0f, 0x00}, - {0x00000000, 0x00000000}}; - -static TSS main_tss; - -extern "C" void load_gdt(GDTR* gdtr); -extern "C" void load_tr(int segment); - -static void set_base(GDTEntry* entry, uint32_t base) -{ - entry->base0 = (base & 0xFFFF); - entry->base1 = (base >> 16) & 0xFF; - entry->base2 = (uint8_t)((base >> 24) & 0xFF); -} - -static void set_limit(GDTEntry* entry, uint32_t limit) -{ - ensure(limit <= 0xFFFFF); - entry->limit0 = limit & 0xFFFF; - entry->limit1_flags = (entry->limit1_flags & 0xF0) | ((limit >> 16) & 0xF); -} - -static void set_tss_base(GDTEntry* tss1, HighGDTEntry* tss2, uint64_t addr) -{ - set_base(tss1, addr & 0xffffffff); - tss2->base_high = (uint32_t)(addr >> 32); -} - -static void setup_tss() -{ - memset(&main_tss, 0, sizeof(TSS)); - main_tss.rsp[0] = get_top_of_stack((uint64_t)MemoryManager::get_pages(4).release_value(), - 4); // FIXME: Propagate errors, we should use 1 kernel stack - // per task, and it probably shouldn't be so big. - main_tss.iomap_base = sizeof(TSS); - set_tss_base(&internal_gdt.tss, &internal_gdt.tss2, (uint64_t)&main_tss); - set_limit(&internal_gdt.tss, sizeof(TSS) - 1); -} - -static void load_tss() -{ - kdbgln("Loading TR (GDT entry 0x2b)"); - load_tr(0x2b); -} - -void GDT::load() -{ - static GDTR gdtr; - gdtr.offset = (uint64_t)&internal_gdt; - gdtr.size = sizeof(InternalGDT); - setup_tss(); - kdbgln("Loading GDT at offset %lx, size %d", gdtr.offset, gdtr.size); - load_gdt(&gdtr); - load_tss(); -} \ No newline at end of file diff --git a/kernel/src/init/Init.cpp b/kernel/src/init/Init.cpp deleted file mode 100644 index 15ba82c1..00000000 --- a/kernel/src/init/Init.cpp +++ /dev/null @@ -1,116 +0,0 @@ -#define MODULE "init" - -#include "init/Init.h" -#include "bootboot.h" -#include "cpu/CPU.h" -#include "fs/InitRD.h" -#include "interrupts/Interrupts.h" -#include "io/Serial.h" -#include "log/Log.h" -#include "memory/MemoryManager.h" -#include "memory/PMM.h" -#include "memory/VMM.h" -#include "misc/MSR.h" -#include "misc/hang.h" -#include "rand/Init.h" -#include "rand/Mersenne.h" -#include "render/Framebuffer.h" -#include "render/TextRenderer.h" -#include "std/ensure.h" -#include "std/string.h" -#include "utils/Time.h" - -extern BOOTBOOT bootboot; -extern "C" char environment[4096]; -extern uintptr_t fb; - -uintptr_t __stack_chk_guard = 0xfeff34; - -void Init::check_magic() -{ - if (strncmp((char*)bootboot.magic, BOOTBOOT_MAGIC, 4) != 0) hang(); -} - -void Init::disable_smp() -{ - if (CPU::get_initial_apic_id() != bootboot.bspid) { hang(); } - return; -} - -extern "C" void asm_enable_sse(); -extern void clock_init(); - -extern void panic_prepare_keyboard_triple_fault(); - -#define NO_EXECUTE_ENABLED (1 << 11) - -static void check_and_enable_nx() -{ - if (!CPU::has_nx()) - { - kerrorln("This machine does not support the NX feature, which is required to continue booting."); - kerrorln("On most cases, this means your machine is too old and not supported."); - - kinfoln("Press any key to restart and select an OS that is suitable for your CPU."); - - panic_prepare_keyboard_triple_fault(); - - while (1) halt(); - } - - kdbgln("nx supported"); - - MSR efer(IA32_EFER_MSR); - - uint64_t value = efer.read(); - - if (value & NO_EXECUTE_ENABLED) - { - kdbgln("nx already enabled"); - return; - } - - kdbgln("nx not enabled, enabling it"); - - efer.write(value | NO_EXECUTE_ENABLED); -} - -void Init::early_init() -{ - Interrupts::disable(); - asm volatile("cld"); - - asm_enable_sse(); - - framebuffer0.init((void*)&fb, bootboot.fb_type, bootboot.fb_scanline, bootboot.fb_width, bootboot.fb_height); - - check_and_enable_nx(); - - MemoryManager::init(); - - MemoryManager::protect_kernel_sections(); - - if (strstr(environment, "quiet=1")) - { - KernelLog::toggle_log_level(LogLevel::DEBUG); - KernelLog::toggle_log_level(LogLevel::INFO); - } - else if (!strstr(environment, "verbose=1")) { KernelLog::toggle_log_level(LogLevel::DEBUG); } - - clock_init(); - - InitRD::init(); - - Mersenne::init(); - - kdbgln("Page bitmap uses %ld bytes of memory", PMM::get_bitmap_size()); - - __stack_chk_guard = Mersenne::get(); -} - -void Init::finish_kernel_boot() -{ - KernelLog::toggle_log_backend(Backend::Console); - framebuffer0.clear(Color::Black); - TextRenderer::reset(); -} \ No newline at end of file diff --git a/kernel/src/interrupts/Entry.cpp b/kernel/src/interrupts/Entry.cpp deleted file mode 100644 index d69750e6..00000000 --- a/kernel/src/interrupts/Entry.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#define MODULE "isr" - -#include "interrupts/Context.h" -#include "interrupts/IRQ.h" -#include "interrupts/Interrupts.h" -#include "io/Serial.h" -#include "log/Log.h" -#include "memory/VMM.h" -#include "misc/hang.h" -#include "panic/Panic.h" -#include "std/ensure.h" -#include "std/stdio.h" -#include "sys/Syscall.h" -#include "thread/Scheduler.h" -#include "trace/StackTracer.h" -#include "utils/PageFaultReason.h" - -extern "C" void common_handler(Context* context) -{ - ensure(Interrupts::is_in_handler()); - if (context->number >= 0x20 && context->number < 0x30) - { - IRQ::interrupt_handler(context); - return; - } - if (context->number == 13) - { - Interrupts::disable(); - - if (context->cs == 0x8) { int_panic(context, "GPF in kernel task"); } - else - { - VMM::enter_syscall_context(); - - kerrorln("General protection fault at RIP %lx, cs %ld, ss %ld, RSP %lx, error code %ld", context->rip, - context->cs, context->ss, context->rsp, context->error_code); - kinfoln("Stack trace:"); - - StackTracer tracer(context->rbp); - tracer.trace_with_ip(context->rip); - Scheduler::task_misbehave(context, -2); - } - } - if (context->number == 14) - { - Interrupts::disable(); - - if (context->cs == 0x8) { int_panic(context, "Page fault in kernel task"); } - else - { - VMM::enter_syscall_context(); - - kerrorln("Page fault in ring 3 (RIP %lx), while trying to access %lx, error code %ld", context->rip, - context->cr2, context->error_code); - kinfoln("Stack trace:"); - - StackTracer tracer(context->rbp); - tracer.trace_with_ip(context->rip); - - determine_user_page_fault_reason(context->cr2); - - Scheduler::task_misbehave(context, -3); - } - } - if (context->number == 8) { int_panic(context, "Double fault, halting"); } - if (context->number == 66) { Syscall::entry(context); } - if (context->number == 256) { kwarnln("Unused interrupt"); } - return; -} \ No newline at end of file diff --git a/kernel/src/interrupts/IDT.cpp b/kernel/src/interrupts/IDT.cpp deleted file mode 100644 index 4fba0569..00000000 --- a/kernel/src/interrupts/IDT.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#define MODULE "idt" - -#include "interrupts/IDT.h" -#include "log/Log.h" -#include "std/ensure.h" - -struct IDTEntry -{ - uint16_t offset0; - uint16_t selector; - uint8_t ist; - uint8_t type_attr; - uint16_t offset1; - uint32_t offset2; - uint32_t ignore; - void set_offset(uint64_t offset); - uint64_t get_offset(); -}; - -static IDTEntry entries[256]; - -void IDTEntry::set_offset(uint64_t offset) -{ - offset0 = (uint16_t)(offset & 0x000000000000ffff); - offset1 = (uint16_t)((offset & 0x00000000ffff0000) >> 16); - offset2 = (uint32_t)((offset & 0xffffffff00000000) >> 32); -} - -uint64_t IDTEntry::get_offset() -{ - uint64_t offset = 0; - offset |= (uint64_t)offset0; - offset |= (uint64_t)offset1 << 16; - offset |= (uint64_t)offset2 << 32; - return offset; -} - -void IDT::add_handler(short interrupt_number, void* handler, uint8_t type_attr) -{ - ensure(handler != nullptr); - ensure(interrupt_number < 256); - IDTEntry* entry_for_handler = &entries[interrupt_number]; - entry_for_handler->selector = 0x08; - entry_for_handler->type_attr = type_attr; - entry_for_handler->set_offset((uint64_t)handler); -} - -IDTR idtr; -void IDT::load() -{ - idtr.limit = 0x0FFF; - idtr.offset = (uint64_t)entries; - kdbgln("Loading IDT at offset %lx, limit %d", idtr.offset, idtr.limit); - asm("lidt %0" : : "m"(idtr)); -} \ No newline at end of file diff --git a/kernel/src/interrupts/IRQ.cpp b/kernel/src/interrupts/IRQ.cpp deleted file mode 100644 index 5dcf7d21..00000000 --- a/kernel/src/interrupts/IRQ.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#define MODULE "irq" - -#include "interrupts/IRQ.h" -#include "fs/devices/Console.h" -#include "fs/devices/Keyboard.h" -#include "io/IO.h" -#include "io/PIC.h" -#include "log/Log.h" -#include "misc/Scancodes.h" -#include "rand/Init.h" -#include "std/stdio.h" -#include "thread/PIT.h" -#include "thread/Scheduler.h" - -void IRQ::interrupt_handler(Context* context) -{ - switch (context->irq_number) - { - case 0: - PIT::tick(); - Scheduler::task_tick(context); - break; - case 1: { - unsigned char scancode = IO::inb(0x60); - KeyboardDevice::append((char)scancode); - bool ignore = false; - char key = translate_scancode(scancode, &ignore); - if (ignore) break; - ConsoleDevice::append(key); - break; - } - default: kwarnln("Unhandled IRQ: %ld", context->irq_number); break; - } - Mersenne::reseed(); - PIC::send_eoi((unsigned char)(context->irq_number & 0xFF)); - return; -} \ No newline at end of file diff --git a/kernel/src/interrupts/Install.cpp b/kernel/src/interrupts/Install.cpp deleted file mode 100644 index 2025af3a..00000000 --- a/kernel/src/interrupts/Install.cpp +++ /dev/null @@ -1,112 +0,0 @@ -#include "interrupts/Install.h" -#include "interrupts/IDT.h" -#include "log/Log.h" - -extern "C" -{ - void unused(); - void isr0(); - void isr1(); - void isr2(); - void isr3(); - void isr4(); - void isr5(); - void isr6(); - void isr7(); - void isr8(); - void isr10(); - void isr11(); - void isr12(); - void isr13(); - void isr14(); - void isr16(); - void isr17(); - void isr18(); - void isr19(); - void isr20(); - void isr21(); - void isr28(); - void isr29(); - void isr30(); - void isr31(); - void isr32(); - void isr33(); - void isr34(); - void isr35(); - void isr36(); - void isr37(); - void isr38(); - void isr39(); - void isr40(); - void isr41(); - void isr42(); - void isr43(); - void isr44(); - void isr45(); - void isr46(); - void isr47(); - void isr66(); -} - -#define INSTALL_TRAP(x) IDT::add_handler(x, (void*)&isr##x, IDT_TA_TrapGate) -#define INSTALL_UNUSED(x) IDT::add_handler(x, (void*)&unused, IDT_TA_InterruptGate) -#define INSTALL_ISR(x) IDT::add_handler(x, (void*)&isr##x, IDT_TA_InterruptGate) -#define INSTALL_USER_ISR(x) IDT::add_handler(x, (void*)&isr##x, IDT_TA_InterruptGateUser) - -void Interrupts::install() -{ - kdbgln("Installing handler stubs for exceptions (ISRs 0-31)"); - INSTALL_TRAP(0); - INSTALL_TRAP(1); - INSTALL_TRAP(2); - INSTALL_TRAP(3); - INSTALL_TRAP(4); - INSTALL_TRAP(5); - INSTALL_TRAP(6); - INSTALL_TRAP(7); - INSTALL_TRAP(8); - INSTALL_UNUSED(9); - INSTALL_TRAP(10); - INSTALL_TRAP(11); - INSTALL_TRAP(12); - INSTALL_TRAP(13); - INSTALL_TRAP(14); - INSTALL_UNUSED(15); - INSTALL_TRAP(16); - INSTALL_TRAP(17); - INSTALL_TRAP(18); - INSTALL_TRAP(19); - INSTALL_TRAP(20); - INSTALL_TRAP(21); - INSTALL_UNUSED(22); - INSTALL_UNUSED(23); - INSTALL_UNUSED(24); - INSTALL_UNUSED(25); - INSTALL_UNUSED(26); - INSTALL_UNUSED(27); - INSTALL_TRAP(28); - INSTALL_TRAP(29); - INSTALL_TRAP(30); - INSTALL_UNUSED(31); - kdbgln("Installing handler stubs for IRQs (ISRs 32-47)"); - INSTALL_ISR(32); - INSTALL_ISR(33); - INSTALL_ISR(34); - INSTALL_ISR(35); - INSTALL_ISR(36); - INSTALL_ISR(37); - INSTALL_ISR(38); - INSTALL_ISR(39); - INSTALL_ISR(40); - INSTALL_ISR(41); - INSTALL_ISR(42); - INSTALL_ISR(43); - INSTALL_ISR(44); - INSTALL_ISR(45); - INSTALL_ISR(46); - INSTALL_ISR(47); - kdbgln("Installing unused handler stubs for the rest of the IDT"); - for (short i = 48; i < 256; i++) { INSTALL_UNUSED(i); } - kdbgln("Installing syscall handler stub"); - INSTALL_USER_ISR(66); -} \ No newline at end of file diff --git a/kernel/src/interrupts/InterruptEntry.asm b/kernel/src/interrupts/InterruptEntry.asm deleted file mode 100644 index 7ee280e0..00000000 --- a/kernel/src/interrupts/InterruptEntry.asm +++ /dev/null @@ -1,136 +0,0 @@ -%macro ISR 1 - global isr%1 - isr%1: - push byte 0 - push byte %1 - jmp asm_common -%endmacro - -%macro ISR_ERROR 1 - global isr%1 - isr%1: - push byte %1 - jmp asm_common -%endmacro - -%macro IRQ 2 - global isr%1 - isr%1: - push byte %2 - push byte %1 - jmp asm_common -%endmacro - -%macro SOFT 1 - global isr%1 - isr%1: - push byte 0 - push byte %1 - jmp asm_common -%endmacro - -global unused -unused: - push byte 0 - push 256 - jmp asm_common - -extern common_handler - -section .text -global asm_common -asm_common: - cld - push rax - push rbx - push rcx - push rdx - push rbp - push rdi - push rsi - push r8 - push r9 - push r10 - push r11 - push r12 - push r13 - push r14 - push r15 - - mov ax, ds - push rax - - mov r8, cr2 - push r8 - - mov rdi, rsp - - call common_handler - -global _asm_interrupt_exit -_asm_interrupt_exit: - - add rsp, 8 - - pop rax - mov ds, ax - mov es, ax - - pop r15 - pop r14 - pop r13 - pop r12 - pop r11 - pop r10 - pop r9 - pop r8 - pop rsi - pop rdi - pop rbp - pop rdx - pop rcx - pop rbx - pop rax - add rsp, 16 - iretq - -ISR 0 -ISR 1 -ISR 2 -ISR 3 -ISR 4 -ISR 5 -ISR 6 -ISR 7 -ISR_ERROR 8 -ISR_ERROR 10 -ISR_ERROR 11 -ISR_ERROR 12 -ISR_ERROR 13 -ISR_ERROR 14 -ISR 16 -ISR_ERROR 17 -ISR 18 -ISR 19 -ISR 20 -ISR_ERROR 21 -ISR 28 -ISR_ERROR 29 -ISR_ERROR 30 -IRQ 32, 0 -IRQ 33, 1 -IRQ 34, 2 -IRQ 35, 3 -IRQ 36, 4 -IRQ 37, 5 -IRQ 38, 6 -IRQ 39, 7 -IRQ 40, 8 -IRQ 41, 9 -IRQ 42, 10 -IRQ 43, 11 -IRQ 44, 12 -IRQ 45, 13 -IRQ 46, 14 -IRQ 47, 15 -SOFT 66 \ No newline at end of file diff --git a/kernel/src/interrupts/Interrupts.cpp b/kernel/src/interrupts/Interrupts.cpp deleted file mode 100644 index b57420d8..00000000 --- a/kernel/src/interrupts/Interrupts.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include "interrupts/Interrupts.h" -#include "trace/StackTracer.h" -#include "utils/Registers.h" - -void Interrupts::disable() -{ - asm volatile("cli"); -} - -void Interrupts::enable() -{ - asm volatile("sti"); -} - -extern int _asm_interrupt_exit; - -bool Interrupts::is_in_handler() -{ - return stack_trace_contains((uintptr_t)&_asm_interrupt_exit); -} - -void Interrupts::return_from_handler(Context* context) -{ - asm volatile("mov %0, %%rsp\n" - "jmp _asm_interrupt_exit" - : - : "r"(context)); -} - -bool Interrupts::are_enabled() -{ - return (read_rflags() & 0x200) > 0; -} - -static bool saved_interrupt_state; - -void Interrupts::push_and_disable() -{ - saved_interrupt_state = are_enabled(); - disable(); -} - -void Interrupts::push_and_enable() -{ - saved_interrupt_state = are_enabled(); - enable(); -} - -void Interrupts::pop() -{ - if (saved_interrupt_state && !are_enabled()) enable(); - else if (!saved_interrupt_state && are_enabled()) - disable(); -} - -bool Interrupts::were_enabled() -{ - return saved_interrupt_state; -} \ No newline at end of file diff --git a/kernel/src/io/IO.cpp b/kernel/src/io/IO.cpp deleted file mode 100644 index 5eb75688..00000000 --- a/kernel/src/io/IO.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "io/IO.h" - -uint8_t IO::inb(uint16_t port) -{ - uint8_t result; - asm volatile("inb %1, %0" : "=a"(result) : "Nd"(port)); - return result; -} - -void IO::outb(uint16_t port, uint8_t value) -{ - asm volatile("outb %0, %1" : : "a"(value), "Nd"(port)); -} - -uint16_t IO::inw(uint16_t port) -{ - uint16_t result; - asm volatile("inw %1, %0" : "=a"(result) : "Nd"(port)); - return result; -} - -void IO::outw(uint16_t port, uint16_t value) -{ - asm volatile("outw %0, %1" : : "a"(value), "Nd"(port)); -} - -uint32_t IO::inl(uint16_t port) -{ - uint32_t result; - asm volatile("inl %1, %0" : "=a"(result) : "Nd"(port)); - return result; -} - -void IO::outl(uint16_t port, uint32_t value) -{ - asm volatile("outl %0, %1" : : "a"(value), "Nd"(port)); -} - -void IO::delay() -{ - asm volatile("outb %%al, $0x80" : : "a"(0)); -} \ No newline at end of file diff --git a/kernel/src/io/PCI.cpp b/kernel/src/io/PCI.cpp deleted file mode 100644 index f53ee653..00000000 --- a/kernel/src/io/PCI.cpp +++ /dev/null @@ -1,197 +0,0 @@ -#define MODULE "pci" - -#include "io/PCI.h" -#include "io/IO.h" -#include "log/Log.h" -#include "thread/Spinlock.h" - -#define PCI_ADDRESS 0xCF8 -#define PCI_VALUE 0xCFC - -Spinlock pci_lock; - -uint32_t PCI::raw_address(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset) -{ - return 0x80000000 | (bus << 16) | (slot << 11) | (function << 8) | ((offset)&0xFC); -} - -void PCI::raw_write8(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset, uint8_t value) -{ - IO::outl(PCI_ADDRESS, raw_address(bus, slot, function, offset)); - IO::outl(PCI_VALUE, (uint32_t)value); -} - -void PCI::raw_write16(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset, uint16_t value) -{ - IO::outl(PCI_ADDRESS, raw_address(bus, slot, function, offset)); - IO::outl(PCI_VALUE, (uint32_t)value); -} - -void PCI::raw_write32(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset, uint32_t value) -{ - IO::outl(PCI_ADDRESS, raw_address(bus, slot, function, offset)); - IO::outl(PCI_VALUE, value); -} - -uint8_t PCI::raw_read8(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset) -{ - IO::outl(PCI_ADDRESS, raw_address(bus, slot, function, offset)); - return (uint8_t)(IO::inl(PCI_VALUE + (offset & 3)) & 0xFF); -} - -uint16_t PCI::raw_read16(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset) -{ - IO::outl(PCI_ADDRESS, raw_address(bus, slot, function, offset)); - return (uint16_t)(IO::inl(PCI_VALUE + (offset & 2)) & 0xFFFF); -} - -uint32_t PCI::raw_read32(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset) -{ - IO::outl(PCI_ADDRESS, raw_address(bus, slot, function, offset)); - return IO::inl(PCI_VALUE); -} - -PCI::DeviceID PCI::get_device_id(uint32_t bus, uint32_t slot, uint32_t function) -{ - uint16_t vendor = PCI::raw_read16(bus, slot, function, PCI_VENDOR_FIELD); - uint16_t device = PCI::raw_read16(bus, slot, function, PCI_DEVICE_FIELD); - return {vendor, device}; -} - -PCI::DeviceType PCI::get_device_type(uint32_t bus, uint32_t slot, uint32_t function) -{ - uint8_t dev_subclass = PCI::raw_read8(bus, slot, function, PCI_SUBCLASS_FIELD); - uint8_t dev_class = PCI::raw_read8(bus, slot, function, PCI_CLASS_FIELD); - uint8_t prog_if = PCI::raw_read8(bus, slot, function, PCI_PROG_IF_FIELD); - uint8_t revision = PCI::raw_read8(bus, slot, function, PCI_REVISION_ID_FIELD); - return {dev_class, dev_subclass, prog_if, revision}; -} - -static void pci_scan_bus(uint8_t bus, void (*callback)(PCI::Device&)) -{ - for (uint8_t slot = 0; slot < 32; slot++) - { - uint8_t num_functions = 1; - for (uint8_t function = 0; function < num_functions; function++) - { - PCI::DeviceID device_id = PCI::get_device_id(bus, slot, function); - if (device_id.vendor == 0xFFFF || device_id.device == 0xFFFF) continue; - PCI::DeviceType device_type = PCI::get_device_type(bus, slot, function); - uint8_t header = PCI::raw_read8(bus, slot, function, PCI_HEADER_TYPE_FIELD); - if (header & 0x80) // multi function device - { - num_functions = 8; - } - if ((header & 0x7F) == 1) - { - uint8_t sub_bus = PCI::raw_read8(bus, slot, function, PCI_SECONDARY_BUS_NUMBER_FIELD); - pci_scan_bus(sub_bus, callback); - } - PCI::Device device{device_id, device_type, bus, slot, function}; - pci_lock.release(); - callback(device); - pci_lock.acquire(); - } - } -} - -void PCI::scan(void (*callback)(PCI::Device&)) -{ - pci_lock.acquire(); - uint8_t function; - uint8_t bus; - - uint8_t header_type = PCI::raw_read8(0, 0, 0, PCI_HEADER_TYPE_FIELD); - if ((header_type & 0x80) == 0) - { - // Single PCI host controller - pci_scan_bus(0, callback); - } - else - { - // Multiple PCI host controllers - for (function = 0; function < 8; function++) - { - if (get_device_id(0, 0, function).vendor == 0xFFFF) break; - bus = function; - pci_scan_bus(bus, callback); - } - } - pci_lock.release(); -} - -PCI::Device::Device(const Device& other) - : m_id(other.m_id), m_type(other.m_type), m_bus(other.m_bus), m_slot(other.m_slot), m_function(other.m_function) -{ -} - -PCI::Device::Device(uint8_t bus, uint8_t slot, uint8_t function) : m_bus(bus), m_slot(slot), m_function(function) -{ - m_id = get_device_id(m_bus, m_slot, m_function); - m_type = get_device_type(m_bus, m_slot, m_function); -} - -PCI::Device::Device(DeviceID id, DeviceType type, uint8_t bus, uint8_t slot, uint8_t function) - : m_id(id), m_type(type), m_bus(bus), m_slot(slot), m_function(function) -{ -} - -void PCI::Device::write8(int32_t offset, uint8_t value) -{ - PCI::raw_write8(m_bus, m_slot, m_function, offset, value); -} - -void PCI::Device::write16(int32_t offset, uint16_t value) -{ - PCI::raw_write16(m_bus, m_slot, m_function, offset, value); -} - -void PCI::Device::write32(int32_t offset, uint32_t value) -{ - PCI::raw_write32(m_bus, m_slot, m_function, offset, value); -} - -uint8_t PCI::Device::read8(int32_t offset) -{ - return PCI::raw_read8(m_bus, m_slot, m_function, offset); -} - -uint16_t PCI::Device::read16(int32_t offset) -{ - return PCI::raw_read16(m_bus, m_slot, m_function, offset); -} - -uint32_t PCI::Device::read32(int32_t offset) -{ - return PCI::raw_read32(m_bus, m_slot, m_function, offset); -} - -uint32_t PCI::Device::getBAR0() -{ - return read32(PCI_BAR0_FIELD); -} - -uint32_t PCI::Device::getBAR1() -{ - return read32(PCI_BAR1_FIELD); -} - -uint32_t PCI::Device::getBAR2() -{ - return read32(PCI_BAR2_FIELD); -} - -uint32_t PCI::Device::getBAR3() -{ - return read32(PCI_BAR3_FIELD); -} - -uint32_t PCI::Device::getBAR4() -{ - return read32(PCI_BAR4_FIELD); -} - -uint32_t PCI::Device::getBAR5() -{ - return read32(PCI_BAR5_FIELD); -} \ No newline at end of file diff --git a/kernel/src/io/PIC.cpp b/kernel/src/io/PIC.cpp deleted file mode 100644 index 2aa553c6..00000000 --- a/kernel/src/io/PIC.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#define MODULE "pic" - -#include "io/PIC.h" -#include "io/IO.h" -#include "log/Log.h" - -#define PIC1_COMMAND 0x20 -#define PIC1_DATA 0x21 -#define PIC2_COMMAND 0xA0 -#define PIC2_DATA 0xA1 -#define PIC_EOI 0x20 - -#define ICW1_INIT 0x10 -#define ICW1_ICW4 0x01 -#define ICW4_8086 0x01 - -void PIC::remap() -{ - kdbgln("Remapping PIC"); - uint8_t a1, a2; - - a1 = IO::inb(PIC1_DATA); - IO::delay(); - a2 = IO::inb(PIC2_DATA); - IO::delay(); - - IO::outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4); - IO::delay(); - IO::outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4); - IO::delay(); - - kdbgln("Remapping master PIC to ISRs 32-39"); - IO::outb(PIC1_DATA, 0x20); - IO::delay(); - kdbgln("Remapping slave PIC to ISRs 40-47"); - IO::outb(PIC2_DATA, 0x28); - IO::delay(); - - IO::outb(PIC1_DATA, 4); - IO::delay(); - IO::outb(PIC2_DATA, 2); - IO::delay(); - - IO::outb(PIC1_DATA, ICW4_8086); - IO::delay(); - IO::outb(PIC2_DATA, ICW4_8086); - IO::delay(); - - IO::outb(PIC1_DATA, a1); - IO::delay(); - IO::outb(PIC2_DATA, a2); -} - -void PIC::enable_master(uint8_t mask) -{ - kdbgln("Setting mask of master PIC to 0x%x", mask); - IO::outb(PIC1_DATA, mask); -} - -void PIC::enable_slave(uint8_t mask) -{ - kdbgln("Setting mask of slave PIC to 0x%x", mask); - IO::outb(PIC2_DATA, mask); -} - -void PIC::end_master() -{ - IO::outb(PIC1_COMMAND, PIC_EOI); -} - -void PIC::end_slave() -{ - IO::outb(PIC2_COMMAND, PIC_EOI); - IO::outb(PIC1_COMMAND, PIC_EOI); -} - -void PIC::send_eoi(unsigned char irq) -{ - if (irq >= 8) end_slave(); - else - end_master(); -} \ No newline at end of file diff --git a/kernel/src/io/Serial.cpp b/kernel/src/io/Serial.cpp deleted file mode 100644 index 753d368a..00000000 --- a/kernel/src/io/Serial.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "io/Serial.h" -#include "io/IO.h" -#include -#include - -#define COM1 0x3f8 - -void Serial::wait() -{ - while (!(IO::inb(COM1 + 5) & 0x20)) { asm volatile("pause"); } -} - -void Serial::write(const char* string, size_t size) -{ - for (size_t i = 0; i < size; i++) - { - wait(); - IO::outb(COM1, *(string + i)); - } -} - -void Serial::print(const char* string) -{ - Serial::write(string, strlen(string)); -} - -void Serial::println(const char* string) -{ - Serial::write(string, strlen(string)); - wait(); - IO::outb(COM1, '\n'); -} - -static const char* format_color(Color& color) -{ - static char output[20]; - snprintf(output, sizeof(output), "\x1b[38;2;%d;%d;%dm", color.red, color.green, color.blue); - return output; -} - -void Serial::set_color(Color& color) -{ - Serial::print(format_color(color)); -} - -void Serial::reset_color() -{ - Serial::print("\x1b[0m"); -} \ No newline at end of file diff --git a/kernel/src/log/CLog.cpp b/kernel/src/log/CLog.cpp deleted file mode 100644 index 7c62e565..00000000 --- a/kernel/src/log/CLog.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "log/CLog.h" -#include "std/stdio.h" -#include - -enum class LogLevel -{ - DEBUG, - INFO, - WARN, - ERROR -}; - -enum class Backend -{ - Serial, - Console -}; - -namespace KernelLog -{ - void log(const char* function, LogLevel level, const char* message, ...) PRINTF_LIKE(3, 4); - void logln(const char* function, LogLevel level, const char* message, ...) PRINTF_LIKE(3, 4); -} - -void log_backend_serial(const char* function, LogLevel level, const char* message, va_list origin); -void log_backend_console(const char* function, LogLevel level, const char* message, va_list origin); -bool log_level_enabled(LogLevel level); -bool log_backend_enabled(Backend backend); - -extern "C" void clog_log(const char* function, enum log_level level, const char* message, ...) -{ - if (!log_level_enabled((LogLevel)level)) return; - va_list ap; - va_start(ap, message); - if (log_backend_enabled(Backend::Serial)) log_backend_serial(function, (LogLevel)level, message, ap); - if (log_backend_enabled(Backend::Console)) log_backend_console(function, (LogLevel)level, message, ap); - va_end(ap); -} - -extern "C" void clog_logln(const char* function, enum log_level level, const char* message, ...) -{ - if (!log_level_enabled((LogLevel)level)) return; - va_list ap; - va_start(ap, message); - if (log_backend_enabled(Backend::Serial)) - { - log_backend_serial(function, (LogLevel)level, message, ap); - printf("\n"); - } - if (log_backend_enabled(Backend::Console)) - { - log_backend_console(function, (LogLevel)level, message, ap); - kprintf("\n"); - } - va_end(ap); -} \ No newline at end of file diff --git a/kernel/src/log/Log.cpp b/kernel/src/log/Log.cpp deleted file mode 100644 index 13df22ea..00000000 --- a/kernel/src/log/Log.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#include "log/Log.h" -#include "io/Serial.h" -#include "std/stdio.h" -#include "thread/PIT.h" -#include "thread/Scheduler.h" -#include - -static int level_mask = 15; -static int backend_mask = 3; - -bool log_level_enabled(LogLevel level) -{ - return level_mask & (1 << (int)level); -} - -bool log_backend_enabled(Backend backend) -{ - return backend_mask & (1 << (int)backend); -} - -void log_backend_serial(const char* function, LogLevel level, const char* message, va_list origin) -{ - va_list ap; - va_copy(ap, origin); - Serial::reset_color(); - if (Scheduler::current_task() && Scheduler::current_task()->id) - { - Task* current_task = Scheduler::current_task(); - printf("[%ld.%ld] (%s %ld) %s: ", PIT::ms_since_boot / 1000, PIT::ms_since_boot % 1000, current_task->name, - current_task->id, function); - } - else { printf("[%ld.%ld] (kernel) %s: ", PIT::ms_since_boot / 1000, PIT::ms_since_boot % 1000, function); } - switch (level) - { - case LogLevel::WARN: Serial::set_color(Color::Yellow); break; - case LogLevel::ERROR: Serial::set_color(Color::Red); break; - default: break; - } - vprintf(message, ap); - Serial::reset_color(); - va_end(ap); -} - -void log_backend_console(const char* function, [[maybe_unused]] LogLevel level, const char* message, va_list origin) -{ - va_list ap; - va_copy(ap, origin); - kprintf("%s: ", function); - vkprintf(message, ap); - va_end(ap); -} - -void KernelLog::log(const char* function, LogLevel level, const char* message, ...) -{ - if (!log_level_enabled(level)) return; - va_list ap; - va_start(ap, message); - if (log_backend_enabled(Backend::Serial)) log_backend_serial(function, level, message, ap); - if (log_backend_enabled(Backend::Console)) log_backend_console(function, level, message, ap); - va_end(ap); -} - -void KernelLog::logln(const char* function, LogLevel level, const char* message, ...) -{ - if (!log_level_enabled(level)) return; - va_list ap; - va_start(ap, message); - if (log_backend_enabled(Backend::Serial)) - { - log_backend_serial(function, level, message, ap); - printf("\n"); - } - if (log_backend_enabled(Backend::Console)) - { - log_backend_console(function, level, message, ap); - kprintf("\n"); - } - va_end(ap); -} - -void KernelLog::toggle_log_level(LogLevel level) -{ - level_mask ^= (1 << (int)level); -} - -void KernelLog::toggle_log_backend(Backend backend) -{ - backend_mask ^= (1 << (int)backend); -} - -void KernelLog::enable_log_backend(Backend backend) -{ - backend_mask |= (1 << (int)backend); -} \ No newline at end of file diff --git a/kernel/src/main.asm b/kernel/src/main.asm deleted file mode 100644 index 4593a076..00000000 --- a/kernel/src/main.asm +++ /dev/null @@ -1,40 +0,0 @@ -global _main -extern _start - -_main: - xor rbp, rbp - call _start - cli -.hang: - hlt - jmp .hang - -global idle_task_function -idle_task_function: - sti -.idle: - hlt - jmp .idle - -global asm_enable_sse -asm_enable_sse: - mov rax, cr0 - and ax, 0xFFFB - or ax, 0x2 - mov cr0, rax - mov rax, cr4 - or ax, 3 << 9 - mov cr4, rax - ret - -global asm_get_rflags -asm_get_rflags: - pushfq - pop rax - ret - -global asm_set_rflags -asm_set_rflags: - push rdi - popfq - ret \ No newline at end of file diff --git a/kernel/src/main.cpp b/kernel/src/main.cpp index ec781c93..a70938cd 100644 --- a/kernel/src/main.cpp +++ b/kernel/src/main.cpp @@ -1,77 +1,89 @@ -#define MODULE "main" - +#include "ELF.h" +#include "InitRD.h" +#include "Log.h" +#include "arch/CPU.h" +#include "arch/MMU.h" +#include "arch/Timer.h" +#include "boot/Init.h" #include "config.h" -#include "cpu/CPU.h" -#include "fs/devices/DeviceFS.h" -#include "gdt/GDT.h" -#include "init/Init.h" -#include "interrupts/IDT.h" -#include "interrupts/Install.h" -#include "interrupts/Interrupts.h" -#include "io/PIC.h" -#include "log/Log.h" -#include "memory/Memory.h" -#include "memory/MemoryMap.h" -#include "misc/hang.h" -#include "std/ensure.h" -#include "std/stdlib.h" -#include "thread/PIT.h" +#include "memory/Heap.h" +#include "memory/KernelVM.h" +#include "memory/MemoryManager.h" #include "thread/Scheduler.h" +#include +#include +#include -#define STRINGIZE(x) #x -#define STRINGIZE_VALUE_OF(x) STRINGIZE(x) - -extern "C" void _start() +void heap_thread() { - Init::disable_smp(); // Put all other cores except the bootstrap one in an infinite loop - Init::check_magic(); - Init::early_init(); + CPU::disable_interrupts(); + dump_heap_usage(); + kdbgln("Kernel uses %lu vm pages", KernelVM::used() / ARCH_PAGE_SIZE); + kernel_exit(); +} - kinfoln("Starting Moon %s", moon_version()); +void reap_thread() +{ + while (true) + { + CPU::disable_interrupts(); + auto dying_threads = Scheduler::check_for_dying_threads(); + CPU::enable_interrupts(); - CPU::log_cpu_information(); + dying_threads.consume([](Thread* thread) { Scheduler::reap_thread(thread); }); - Memory::walk_memory_map(); + kernel_sleep(250); + } +} - GDT::load(); +Result init() +{ + kinfoln("Starting Moon %s, built on %s at %s", MOON_VERSION, __DATE__, __TIME__); - Interrupts::install(); + kinfoln("Current platform: %s", CPU::platform_string()); - IDT::load(); + kinfoln("Current processor: %s", CPU::identify().value_or("(unknown)")); - PIT::initialize(1000); // 1000 times per second + Timer::init(); + kinfoln("Total memory: %s", to_dynamic_unit(MemoryManager::total()).release_value().chars()); + kinfoln("Free memory: %s", to_dynamic_unit(MemoryManager::free()).release_value().chars()); + kinfoln("Used memory: %s", to_dynamic_unit(MemoryManager::used()).release_value().chars()); + kinfoln("Reserved memory: %s", to_dynamic_unit(MemoryManager::reserved()).release_value().chars()); + + Thread::init(); Scheduler::init(); -#ifdef RUN_TEST_AS_INIT - ensure(Scheduler::load_user_task(STRINGIZE_VALUE_OF(RUN_TEST_AS_INIT)) > 0); -#else - ensure(Scheduler::load_user_task("/bin/init") > 0); -#endif - - Scheduler::add_kernel_task("[reaper]", []() { - while (1) + TarStream::Entry entry; + while (TRY(g_initrd.read_next_entry().try_set_value_with_specific_error(entry, 0))) + { + if (entry.type == TarStream::EntryType::RegularFile) { - sleep(400); - Scheduler::reap_tasks(); + kinfoln("Found file %s in initial ramdisk, of size %s", entry.name, + to_dynamic_unit(entry.size).release_value().chars()); + + if (!strcmp(entry.name, "bin/app")) { TRY(Scheduler::new_userspace_thread(entry, g_initrd)); } } - }); + } - ensure(VFS::mkdir("/dev") == 0); - VFS::mount("/dev", DeviceFS::get()); + TRY(Scheduler::new_kernel_thread(heap_thread)); + TRY(Scheduler::new_kernel_thread(reap_thread)); - Init::finish_kernel_boot(); + CPU::platform_finish_init(); - PIC::remap(); - PIC::enable_master(0b11111100); - PIC::enable_slave(0b11111111); + // Disable console logging before transferring control to userspace. + setup_log(log_debug_enabled(), log_serial_enabled(), false); - Interrupts::enable(); + CPU::enable_interrupts(); - while (1) - halt(); // As soon as the first timer interrupt arrives, this idle loop is gone, since the main function is not - // registered as a task and thus the scheduler will never schedule this again. We still have to do - // something while waiting for a timer interrupt to arrive, though. In fact, in most cases, calling - // halt() once would be enough, since that function halts the CPU until the next interrupt (most likely - // the timer one) arrives. But we have to guarantee this function never returns. -} \ No newline at end of file + return {}; +} + +extern "C" [[noreturn]] void _start() +{ + Init::check_magic(); + Init::early_init(); + auto rc = init(); + if (rc.has_error()) kerrorln("Runtime error: %s", rc.error_string()); + CPU::idle_loop(); +} diff --git a/kernel/src/memory/AddressSpace.cpp b/kernel/src/memory/AddressSpace.cpp deleted file mode 100644 index 7a0e7473..00000000 --- a/kernel/src/memory/AddressSpace.cpp +++ /dev/null @@ -1,284 +0,0 @@ -#define MODULE "vmm" - -#include "memory/AddressSpace.h" -#include "log/Log.h" -#include "memory/PMM.h" -#include "memory/VMM.h" -#include "std/errno.h" -#include "std/stdlib.h" -#include "std/string.h" -#include "utils/move.h" - -Result AddressSpace::create() -{ - AddressSpace result; - auto page = PMM::request_page(); - if (page.has_error()) return page.release_error(); - result.m_pml4 = (PageTable*)page.release_value(); - memset(result.m_pml4, 0, PAGE_SIZE); - VMM::install_kernel_page_directory_into_address_space(result); - return move(result); -} - -void AddressSpace::destroy() -{ - uint64_t pages_freed = 0; - for (int i = 0; i < 512; i++) - { - PageDirectoryEntry& pdp_pde = m_pml4->entries[i]; - if (!pdp_pde.present) continue; - if (pdp_pde.larger_pages) - { - if (pdp_pde.owned_by_task) - { - pages_freed++; - PMM::free_page((void*)pdp_pde.get_address()); - } - continue; - } - PageTable* pdp = (PageTable*)pdp_pde.get_address(); - for (int j = 0; j < 511; j++) // skip the last page directory, it's the kernel one - { - PageDirectoryEntry& pd_pde = pdp->entries[j]; - if (!pd_pde.present) continue; - if (pd_pde.larger_pages) - { - if (pd_pde.owned_by_task) - { - pages_freed++; - PMM::free_page((void*)pd_pde.get_address()); - } - continue; - } - PageTable* pd = (PageTable*)pd_pde.get_address(); - for (int k = 0; k < 512; k++) - { - PageDirectoryEntry& pt_pde = pd->entries[k]; - if (!pt_pde.present) continue; - if (pt_pde.larger_pages) - { - if (pt_pde.owned_by_task) - { - pages_freed++; - PMM::free_page((void*)pt_pde.get_address()); - } - continue; - } - PageTable* pt = (PageTable*)pt_pde.get_address(); - for (int l = 0; l < 512; l++) - { - PageDirectoryEntry& pde = pt->entries[l]; - if (!pde.present) continue; - if (!pde.owned_by_task) continue; - pages_freed++; - PMM::free_page((void*)pde.get_address()); - } - pages_freed++; - PMM::free_page(pt); - } - pages_freed++; - PMM::free_page(pd); - } - pages_freed++; - PMM::free_page(pdp); - } - pages_freed++; - PMM::free_page(m_pml4); - - kdbgln("Reclaimed %ld pages from address space!", pages_freed); -} - -void AddressSpace::clear() -{ - uint64_t pages_freed = 0; - for (int i = 0; i < 512; i++) - { - PageDirectoryEntry& pdp_pde = m_pml4->entries[i]; - if (!pdp_pde.present) continue; - if (pdp_pde.larger_pages) - { - if (pdp_pde.owned_by_task) - { - pages_freed++; - PMM::free_page((void*)pdp_pde.get_address()); - } - continue; - } - PageTable* pdp = (PageTable*)pdp_pde.get_address(); - for (int j = 0; j < 511; j++) // skip the last page directory, it's the kernel one - { - PageDirectoryEntry& pd_pde = pdp->entries[j]; - if (!pd_pde.present) continue; - if (pd_pde.larger_pages) - { - if (pd_pde.owned_by_task) - { - pages_freed++; - PMM::free_page((void*)pd_pde.get_address()); - } - continue; - } - PageTable* pd = (PageTable*)pd_pde.get_address(); - for (int k = 0; k < 512; k++) - { - PageDirectoryEntry& pt_pde = pd->entries[k]; - if (!pt_pde.present) continue; - if (pt_pde.larger_pages) - { - if (pt_pde.owned_by_task) - { - pages_freed++; - PMM::free_page((void*)pt_pde.get_address()); - } - continue; - } - PageTable* pt = (PageTable*)pt_pde.get_address(); - for (int l = 0; l < 512; l++) - { - PageDirectoryEntry& pde = pt->entries[l]; - if (!pde.present) continue; - if (!pde.owned_by_task) continue; - pages_freed++; - PMM::free_page((void*)pde.get_address()); - } - pages_freed++; - PMM::free_page(pt); - } - pages_freed++; - PMM::free_page(pd); - } - pages_freed++; - PMM::free_page(pdp); - } - memset(m_pml4, 0, PAGE_SIZE); - - VMM::install_kernel_page_directory_into_address_space(*this); - - kdbgln("Reclaimed %ld pages from address space!", pages_freed); -} - -static PageTable* try_clone_page_table(PageTable* source) -{ - auto page = PMM::request_page(); - if (page.has_error()) { return 0; } - PageTable* dst = (PageTable*)page.release_value(); - memcpy(dst, source, sizeof(PageTable)); - return dst; -} - -AddressSpace AddressSpace::clone() // FIXME: Add out-of-memory checks to this function. -{ - AddressSpace result; - result.m_pml4 = try_clone_page_table(m_pml4); - if (!result.m_pml4) return result; - for (int i = 0; i < 512; i++) - { - PageDirectoryEntry& pdp_pde = m_pml4->entries[i]; - PageDirectoryEntry& cloned_pdp_pde = result.m_pml4->entries[i]; - if (!pdp_pde.present) continue; - if (pdp_pde.larger_pages) - { - if (!pdp_pde.owned_by_task) - { - memcpy(&cloned_pdp_pde, &pdp_pde, sizeof(PageDirectoryEntry)); - continue; - } - void* cloned = try_clone_page_table((PageTable*)pdp_pde.get_address()); - if (!cloned) - { - cloned_pdp_pde.present = false; - continue; - } - cloned_pdp_pde.set_address((uint64_t)cloned); - continue; - } - PageTable* pdp = (PageTable*)pdp_pde.get_address(); - PageTable* cloned_pdp = try_clone_page_table(pdp); - if (!cloned_pdp) - { - cloned_pdp_pde.present = false; - continue; - } - cloned_pdp_pde.set_address((uint64_t)cloned_pdp); - for (int j = 0; j < 511; j++) // skip the last page directory, it's the kernel one - { - PageDirectoryEntry& pd_pde = pdp->entries[j]; - PageDirectoryEntry& cloned_pd_pde = cloned_pdp->entries[j]; - if (!pd_pde.present) continue; - if (pd_pde.larger_pages) - { - if (!pd_pde.owned_by_task) - { - memcpy(&cloned_pd_pde, &pd_pde, sizeof(PageDirectoryEntry)); - continue; - } - void* cloned = try_clone_page_table((PageTable*)pd_pde.get_address()); - if (!cloned) - { - cloned_pd_pde.present = false; - continue; - } - cloned_pd_pde.set_address((uint64_t)cloned); - continue; - } - PageTable* pd = (PageTable*)pd_pde.get_address(); - PageTable* cloned_pd = try_clone_page_table(pd); - if (!cloned_pd) - { - cloned_pd_pde.present = false; - continue; - } - cloned_pd_pde.set_address((uint64_t)cloned_pd); - for (int k = 0; k < 512; k++) - { - PageDirectoryEntry& pt_pde = pd->entries[k]; - PageDirectoryEntry& cloned_pt_pde = cloned_pd->entries[k]; - if (!pt_pde.present) continue; - if (pt_pde.larger_pages) - { - if (!pt_pde.owned_by_task) - { - memcpy(&cloned_pt_pde, &pt_pde, sizeof(PageDirectoryEntry)); - continue; - } - void* cloned = try_clone_page_table((PageTable*)pt_pde.get_address()); - if (!cloned) - { - cloned_pt_pde.present = false; - continue; - } - cloned_pt_pde.set_address((uint64_t)cloned); - continue; - } - PageTable* pt = (PageTable*)pt_pde.get_address(); - PageTable* cloned_pt = try_clone_page_table(pt); - if (!cloned_pt) - { - cloned_pt_pde.present = false; - continue; - } - cloned_pt_pde.set_address((uint64_t)cloned_pt); - for (int l = 0; l < 512; l++) - { - PageDirectoryEntry& pde = pt->entries[l]; - PageDirectoryEntry& cloned_pde = cloned_pt->entries[l]; - if (!pde.owned_by_task) - { - memcpy(&cloned_pde, &pde, sizeof(PageDirectoryEntry)); - continue; - } - if (!pde.present) continue; - void* cloned = try_clone_page_table((PageTable*)pde.get_address()); - if (!cloned) - { - cloned_pde.present = false; - continue; - } - cloned_pde.set_address((uint64_t)cloned); - continue; - } - } - } - } - return result; -} \ No newline at end of file diff --git a/kernel/src/memory/Heap.cpp b/kernel/src/memory/Heap.cpp new file mode 100644 index 00000000..52df9b96 --- /dev/null +++ b/kernel/src/memory/Heap.cpp @@ -0,0 +1,422 @@ +#include "memory/Heap.h" +#include "Log.h" +#include "arch/MMU.h" +#include "arch/Serial.h" +#include "memory/KernelVM.h" +#include "memory/MemoryManager.h" +#include +#include +#include +#include +#include +#include +#include + +namespace std +{ + const nothrow_t nothrow; +} + +static constexpr int BLOCK_USED = 1 << 0; +static constexpr int BLOCK_START_MEM = 1 << 1; +static constexpr int BLOCK_END_MEM = 1 << 2; + +static constexpr usize BLOCK_MAGIC = 0x6d616c6c6f63210a; // echo 'malloc!' | hexdump -C (includes a newline) +static constexpr usize BLOCK_DEAD = 0xdeaddeaddeaddead; + +static constexpr u8 KMALLOC_SCRUB_BYTE = 0xac; +static constexpr u8 KFREE_SCRUB_BYTE = 0xde; + +static constexpr usize MINIMUM_PAGES_PER_ALLOCATION = 4; + +struct HeapBlock : LinkedListNode +{ + usize req_size; + usize full_size; + int status; + usize magic; +}; + +static_assert(sizeof(HeapBlock) == 48UL); + +static const isize HEAP_BLOCK_SIZE = 48; + +static LinkedList heap; + +static Result allocate_pages(usize count) +{ + void* const ptr = (void*)TRY(MemoryManager::alloc_for_kernel(count, MMU::ReadWrite | MMU::NoExecute)); + return (HeapBlock*)ptr; +} + +static Result release_pages(void* ptr, usize count) +{ + return MemoryManager::unmap_owned_and_free_vm((u64)ptr, count); +} + +// If we're allocating a large amount of memory, map enough pages for it, but otherwise just use the default amount of +// pages. +static usize get_pages_for_allocation(usize bytes) +{ + usize pages = get_blocks_from_size(bytes, ARCH_PAGE_SIZE); + if (pages < MINIMUM_PAGES_PER_ALLOCATION) pages = MINIMUM_PAGES_PER_ALLOCATION; + return pages; +} + +static bool is_block_free(HeapBlock* block) +{ + return !(block->status & BLOCK_USED); +} + +static usize space_available(HeapBlock* block) +{ + expect(!is_block_free(block), "Attempting to split a free block"); + return block->full_size - block->req_size; +} + +// The heap block is stored right behind a memory block. +static HeapBlock* get_heap_block_for_pointer(void* ptr) +{ + return (HeapBlock*)offset_ptr(ptr, -HEAP_BLOCK_SIZE); +} + +static void* get_pointer_from_heap_block(HeapBlock* block) +{ + return (void*)offset_ptr(block, HEAP_BLOCK_SIZE); +} + +static usize get_fair_offset_to_split_at(HeapBlock* block, usize min) +{ + usize available = space_available(block); + + available -= min; // reserve at least min size for the new block. + + available -= (available / + 2); // reserve half of the rest for the new block, while still leaving another half for the old one. + + available = align_down<16>(available); // Everything has to be aligned on a 16-byte boundary + + return available + block->req_size; +} + +static Option split(HeapBlock* block, usize size) +{ + const usize available = space_available(block); // How much space can we steal from this block? + const usize old_size = + block->full_size; // Save the old value of this variable since we are going to use it after modifying it + + if (available < (size + sizeof(HeapBlock))) + return {}; // This block hasn't got enough free space to hold the requested size. + + const usize offset = get_fair_offset_to_split_at(block, size + sizeof(HeapBlock)); + block->full_size = offset; // shrink the old block to fit this offset + + HeapBlock* new_block = offset_ptr(block, offset + sizeof(HeapBlock)); + + new_block->magic = BLOCK_MAGIC; + new_block->status = (block->status & BLOCK_END_MEM) ? BLOCK_END_MEM : 0; + new_block->full_size = old_size - (offset + sizeof(HeapBlock)); + heap.add_after(block, new_block); + + block->status &= ~BLOCK_END_MEM; // this block is no longer the last block in its memory range + + return new_block; +} + +static Result combine_forward(HeapBlock* block) +{ + // This block ends a memory range, cannot be combined with blocks outside its range. + if (block->status & BLOCK_END_MEM) return {}; + + // The caller needs to ensure there is a next block. + HeapBlock* const next = heap.next(block).value(); + // This block starts a memory range, cannot be combined with blocks outside its range. + if (next->status & BLOCK_START_MEM) return {}; + + heap.remove(next); + next->magic = BLOCK_DEAD; + + if (next->status & BLOCK_END_MEM) + { + if (next->status & BLOCK_START_MEM) + { + const usize pages = get_blocks_from_size(next->full_size + sizeof(HeapBlock), ARCH_PAGE_SIZE); + TRY(release_pages(next, pages)); + return {}; + } + else + block->status |= BLOCK_END_MEM; + } + + block->full_size += next->full_size + sizeof(HeapBlock); + + return {}; +} + +static Result combine_backward(HeapBlock* block) +{ + // This block starts a memory range, cannot be combined with blocks outside its range. + if (block->status & BLOCK_START_MEM) return block; + + // The caller needs to ensure there is a last block. + HeapBlock* const last = heap.previous(block).value(); + // This block ends a memory range, cannot be combined with blocks outside its range. + if (last->status & BLOCK_END_MEM) return block; + heap.remove(block); + block->magic = BLOCK_DEAD; + + if (block->status & BLOCK_END_MEM) + { + if (block->status & BLOCK_START_MEM) + { + const usize pages = get_blocks_from_size(block->full_size + sizeof(HeapBlock), ARCH_PAGE_SIZE); + TRY(release_pages(block, pages)); + return last; + } + else + last->status |= BLOCK_END_MEM; + } + + last->full_size += block->full_size + sizeof(HeapBlock); + + return last; +} + +Result kmalloc(usize size, bool should_scrub) +{ + if (!size) return (void*)BLOCK_MAGIC; + + size = align_up<16>(size); + + if (heap.count() == 0) + { + const usize pages = get_pages_for_allocation(size + sizeof(HeapBlock)); + HeapBlock* const block = TRY(allocate_pages(pages)); + + block->full_size = (pages * ARCH_PAGE_SIZE) - sizeof(HeapBlock); + block->magic = BLOCK_MAGIC; + block->status = BLOCK_START_MEM | BLOCK_END_MEM; + heap.append(block); + } + + Option block = heap.first(); + while (block.has_value()) + { + HeapBlock* const current = block.value(); + // Trying to find a free block... + if (is_block_free(current)) + { + if (current->full_size < size) + { + block = heap.next(current); + continue; + } + break; // We found a free block that's big enough!! + } + auto rc = split(current, size); + if (rc.has_value()) + { + block = rc.value(); // We managed to get a free block from a larger used block!! + break; + } + block = heap.next(current); + } + + if (!block.has_value()) // No free blocks, let's allocate a new one + { + usize pages = get_pages_for_allocation(size + sizeof(HeapBlock)); + HeapBlock* const current = TRY(allocate_pages(pages)); + + current->full_size = (pages * ARCH_PAGE_SIZE) - sizeof(HeapBlock); + current->magic = BLOCK_MAGIC; + current->status = BLOCK_START_MEM | BLOCK_END_MEM; + heap.append(current); + + block = current; + } + + HeapBlock* const current = block.value(); + + current->req_size = size; + current->status |= BLOCK_USED; + + if (should_scrub) { memset(get_pointer_from_heap_block(current), KMALLOC_SCRUB_BYTE, size); } + + return get_pointer_from_heap_block(current); +} + +Result kfree(void* ptr) +{ + if (ptr == (void*)BLOCK_MAGIC) return {}; // This pointer was returned from a call to malloc(0) + if (!ptr) return {}; + + HeapBlock* block = get_heap_block_for_pointer(ptr); + + if (block->magic != BLOCK_MAGIC) + { + if (block->magic == BLOCK_DEAD) + { + kerrorln("ERROR: Attempt to free memory at %p, which was already freed", ptr); + } + else + kerrorln("ERROR: Attempt to free memory at %p, which wasn't allocated with kmalloc", ptr); + + return err(EFAULT); + } + + if (is_block_free(block)) + { + kerrorln("ERROR: Attempt to free memory at %p, which was already freed", ptr); + return err(EFAULT); + } + else + block->status &= ~BLOCK_USED; + + memset(ptr, KFREE_SCRUB_BYTE, block->req_size); + + auto maybe_next = heap.next(block); + if (maybe_next.has_value() && is_block_free(maybe_next.value())) + { + // The next block is also free, thus we can merge! + TRY(combine_forward(block)); + } + + auto maybe_last = heap.previous(block); + if (maybe_last.has_value() && is_block_free(maybe_last.value())) + { + // The last block is also free, thus we can merge! + block = TRY(combine_backward(block)); + } + + if ((block->status & BLOCK_START_MEM) && (block->status & BLOCK_END_MEM)) + { + heap.remove(block); + const usize pages = get_blocks_from_size(block->full_size + sizeof(HeapBlock), ARCH_PAGE_SIZE); + TRY(release_pages(block, pages)); + } + + return {}; +} + +Result krealloc(void* ptr, usize size) +{ + if (!ptr) return kmalloc(size); + if (ptr == (void*)BLOCK_MAGIC) return kmalloc(size); + if (!size) + { + TRY(kfree(ptr)); + return (void*)BLOCK_MAGIC; + } + + HeapBlock* const block = get_heap_block_for_pointer(ptr); + + if (block->magic != BLOCK_MAGIC) + { + if (block->magic == BLOCK_DEAD) + { + kerrorln("ERROR: Attempt to realloc memory at %p, which was already freed", ptr); + } + else + kerrorln("ERROR: Attempt to realloc memory at %p, which wasn't allocated with kmalloc", ptr); + + return err(EFAULT); + } + + size = align_up<16>(size); + + if (is_block_free(block)) + { + kerrorln("ERROR: Attempt to realloc memory at %p, which was already freed", ptr); + return err(EFAULT); + } + + if (block->full_size >= size) + { + // This block is already large enough! + // FIXME: Scrub this if necessary. + block->req_size = size; + return ptr; + } + + usize old_size = block->req_size; + + void* const new_ptr = TRY(kmalloc(size, false)); + memcpy(new_ptr, ptr, old_size > size ? size : old_size); + TRY(kfree(ptr)); + + if (old_size < size) { memset(offset_ptr(new_ptr, old_size), KMALLOC_SCRUB_BYTE, size - old_size); } + + return new_ptr; +} + +Result kcalloc(usize nmemb, usize size) +{ + const usize realsize = TRY(safe_mul(nmemb, size)); + void* const ptr = TRY(kmalloc(realsize, false)); + return memset(ptr, 0, realsize); +} + +void dump_heap_usage() +{ + kdbgln("-- Dumping usage stats for kernel heap:"); + if (!heap.count()) + { + kdbgln("- Heap is not currently being used"); + return; + } + usize alloc_total = 0; + usize alloc_used = 0; + auto block = heap.first(); + while (block.has_value()) + { + HeapBlock* current = block.value(); + if (is_block_free(current)) + { + kdbgln("- Available block (%p), of size %zu (%s%s)", (void*)current, current->full_size, + current->status & BLOCK_START_MEM ? "b" : "-", current->status & BLOCK_END_MEM ? "e" : "-"); + alloc_total += current->full_size + sizeof(HeapBlock); + } + else + { + kdbgln("- Used block (%p), of size %zu, of which %zu bytes are being used (%s%s)", (void*)current, + current->full_size, current->req_size, current->status & BLOCK_START_MEM ? "b" : "-", + current->status & BLOCK_END_MEM ? "e" : "-"); + alloc_total += current->full_size + sizeof(HeapBlock); + alloc_used += current->req_size; + } + block = heap.next(current); + } + + kdbgln("-- Total memory allocated for heap: %zu bytes", alloc_total); + kdbgln("-- Heap memory in use by the kernel: %zu bytes", alloc_used); +} + +void* operator new(usize size, const std::nothrow_t&) noexcept +{ + return kmalloc(size).value_or(nullptr); +} + +void* operator new[](usize size, const std::nothrow_t&) noexcept +{ + return kmalloc(size).value_or(nullptr); +} + +void operator delete(void* p) noexcept +{ + kfree(p); +} + +void operator delete[](void* p) noexcept +{ + kfree(p); +} + +void operator delete(void* p, usize) noexcept +{ + kfree(p); +} + +void operator delete[](void* p, usize) noexcept +{ + kfree(p); +} diff --git a/kernel/src/memory/Heap.h b/kernel/src/memory/Heap.h new file mode 100644 index 00000000..d1b7ada9 --- /dev/null +++ b/kernel/src/memory/Heap.h @@ -0,0 +1,10 @@ +#pragma once +#include +#include + +Result kmalloc(usize size, bool should_scrub = true); +Result kcalloc(usize nmemb, usize size); +Result krealloc(void* ptr, usize size); +Result kfree(void* ptr); + +void dump_heap_usage(); diff --git a/kernel/src/memory/KernelHeap.cpp b/kernel/src/memory/KernelHeap.cpp deleted file mode 100644 index d42c520e..00000000 --- a/kernel/src/memory/KernelHeap.cpp +++ /dev/null @@ -1,135 +0,0 @@ -#define MODULE "kheap" - -#include "memory/KernelHeap.h" -#include "assert.h" -#include "log/Log.h" -#include "std/string.h" - -#ifndef PAGE_SIZE -#define PAGE_SIZE 4096 -#endif - -static uint8_t page_bitmap[2048]; - -static int64_t kheap_free = sizeof(page_bitmap) * 8 * PAGE_SIZE; -static int64_t kheap_used = 0; - -#define ALLOC_BASE 0xfffffffff8000000 -#define ALLOC_END 0xfffffffffc000000 - -// static uint64_t start_index = 0; - -static bool bitmap_read(uint64_t index) -{ - return (page_bitmap[index / 8] & (0b10000000 >> (index % 8))) > 0; -} - -static void bitmap_set(uint64_t index, bool value) -{ - uint64_t byteIndex = index / 8; - uint8_t bitIndexer = 0b10000000 >> (index % 8); - page_bitmap[byteIndex] &= ~bitIndexer; - if (value) { page_bitmap[byteIndex] |= bitIndexer; } -} - -void KernelHeap::clear() -{ - memset(page_bitmap, 0, sizeof(page_bitmap)); -} - -uint64_t KernelHeap::request_virtual_page() -{ - for (uint64_t index = 0; index < sizeof(page_bitmap) * 8; index++) - { - if (bitmap_read(index)) continue; - bitmap_set(index, true); - // start_index = index + 1; -#ifdef KHEAP_DEBUG - kinfoln("allocating one page for caller %p, returning %lx", __builtin_return_address(0), - ALLOC_BASE + (index * PAGE_SIZE)); -#endif - kheap_free -= PAGE_SIZE; - kheap_used += PAGE_SIZE; -#ifdef KHEAP_DEBUG - dump_usage(); -#endif - return ALLOC_BASE + (index * PAGE_SIZE); - } - - return 0; -} - -uint64_t KernelHeap::request_virtual_pages(uint64_t count) -{ - uint64_t contiguous = 0; - uint64_t contiguous_start = 0; - for (uint64_t index = 0; index < sizeof(page_bitmap) * 8; index++) - { - if (bitmap_read(index)) - { - contiguous = 0; - continue; - } - if (contiguous == 0) - { - contiguous_start = index; - contiguous++; - } - else - contiguous++; - if (contiguous == count) - { - for (uint64_t i = 0; i < count; i++) bitmap_set(contiguous_start + i, true); -#ifdef KHEAP_DEBUG - kinfoln("allocating %lu pages for caller %p, returning %lx", count, __builtin_return_address(0), - ALLOC_BASE + (contiguous_start * PAGE_SIZE)); -#endif - kheap_free -= (count * PAGE_SIZE); - kheap_used += (count * PAGE_SIZE); -#ifdef KHEAP_DEBUG - dump_usage(); -#endif - return ALLOC_BASE + (contiguous_start * PAGE_SIZE); - } - } - - return 0; -} - -void KernelHeap::free_virtual_page(uint64_t address) -{ - if (address < ALLOC_BASE || address >= ALLOC_END) return; - uint64_t index = (address - ALLOC_BASE) / PAGE_SIZE; - bitmap_set(index, false); -#ifdef KHEAP_DEBUG - kinfoln("releasing one page for caller %p, %lx", __builtin_return_address(0), address); -#endif - kheap_free += PAGE_SIZE; - kheap_used -= PAGE_SIZE; -#ifdef KHEAP_DEBUG - dump_usage(); -#endif - // if (start_index > index) start_index = index; -} - -void KernelHeap::free_virtual_pages(uint64_t address, uint64_t count) -{ - if (address < ALLOC_BASE || address >= ALLOC_END) return; - uint64_t index = (address - ALLOC_BASE) / PAGE_SIZE; - for (uint64_t i = 0; i < count; i++) { bitmap_set(index + i, false); } -#ifdef KHEAP_DEBUG - kinfoln("releasing %lu pages for caller %p, %lx", count, __builtin_return_address(0), address); -#endif - kheap_free += (count * PAGE_SIZE); - kheap_used -= (count * PAGE_SIZE); -#ifdef KHEAP_DEBUG - dump_usage(); -#endif - // if (start_index > index) start_index = index; -} - -void KernelHeap::dump_usage() -{ - kinfoln("Used: %ld KB", kheap_used / 1024); - kinfoln("Free: %ld KB", kheap_free / 1024); -} \ No newline at end of file diff --git a/kernel/src/memory/KernelVM.cpp b/kernel/src/memory/KernelVM.cpp new file mode 100644 index 00000000..8c9379df --- /dev/null +++ b/kernel/src/memory/KernelVM.cpp @@ -0,0 +1,123 @@ +#include "memory/KernelVM.h" +#include "arch/MMU.h" +#include "thread/Spinlock.h" +#include + +static const u64 KERNEL_VM_RANGE_START = 0xffffffffc0000000; + +static LockedValue g_kernelvm_bitmap; + +static u8 bitmap_memory[4096 * 7]; + +static const usize KERNEL_VM_RANGE_SIZE = (sizeof(bitmap_memory) * 8) * ARCH_PAGE_SIZE; + +static const u64 KERNEL_VM_RANGE_END = KERNEL_VM_RANGE_SIZE + KERNEL_VM_RANGE_START; + +static_assert(KERNEL_VM_RANGE_END == 0xfffffffff8000000); + +static Atomic g_used_vm; + +namespace KernelVM +{ + void init() + { + auto kernelvm_bitmap = g_kernelvm_bitmap.lock(); + kernelvm_bitmap->initialize(bitmap_memory, sizeof(bitmap_memory)); + kernelvm_bitmap->clear(false); + } + + Result alloc_one_page() + { + auto kernelvm_bitmap = g_kernelvm_bitmap.lock(); + for (u64 index = 0; index < kernelvm_bitmap->size(); index++) + { + if (kernelvm_bitmap->get(index)) continue; + kernelvm_bitmap->set(index, true); + g_used_vm += ARCH_PAGE_SIZE; + return KERNEL_VM_RANGE_START + (index * ARCH_PAGE_SIZE); + } + + return err(ENOMEM); + } + + bool find_several_pages_impl(usize count, u64& start_index) + { + u64 first_free_index = 0; + u64 free_contiguous_pages = 0; + auto kernelvm_bitmap = g_kernelvm_bitmap.lock(); + for (u64 index = 0; index < kernelvm_bitmap->size(); index++) + { + if (kernelvm_bitmap->get(index)) + { + free_contiguous_pages = 0; + continue; + } + + // At this point, we have a free page. + + if (!free_contiguous_pages) first_free_index = index; + free_contiguous_pages++; + + // Found enough contiguous free pages!! + if (free_contiguous_pages == count) + { + start_index = first_free_index; + return true; + } + } + + return false; + } + + Result alloc_several_pages(const usize count) + { + u64 start_index; + if (find_several_pages_impl(count, start_index)) + { + g_kernelvm_bitmap.lock()->clear_region(start_index, count, true); + g_used_vm += ARCH_PAGE_SIZE * count; + return KERNEL_VM_RANGE_START + (start_index * ARCH_PAGE_SIZE); + } + + return err(ENOMEM); + } + + Result free_one_page(u64 address) + { + if (address < KERNEL_VM_RANGE_START) return err(EFAULT); + + u64 index = (address - KERNEL_VM_RANGE_START) / ARCH_PAGE_SIZE; + + auto kernelvm_bitmap = g_kernelvm_bitmap.lock(); + + if (index >= kernelvm_bitmap->size()) return err(EFAULT); + + kernelvm_bitmap->set(index, false); + g_used_vm -= ARCH_PAGE_SIZE; + + return {}; + } + + Result free_several_pages(u64 address, usize count) + { + if (address < KERNEL_VM_RANGE_START) return err(EFAULT); + if (address + (count * ARCH_PAGE_SIZE) >= KERNEL_VM_RANGE_END) return err(EFAULT); + + u64 index = (address - KERNEL_VM_RANGE_START) / ARCH_PAGE_SIZE; + + g_kernelvm_bitmap.lock()->clear_region(index, count, false); + g_used_vm -= ARCH_PAGE_SIZE * count; + + return {}; + } + + usize used() + { + return g_used_vm; + } + + usize free() + { + return KERNEL_VM_RANGE_SIZE - g_used_vm; + } +} diff --git a/kernel/src/memory/KernelVM.h b/kernel/src/memory/KernelVM.h new file mode 100644 index 00000000..60d5e28c --- /dev/null +++ b/kernel/src/memory/KernelVM.h @@ -0,0 +1,18 @@ +#pragma once +#include +#include + +// Simple bitmap allocator which hands out kernel-space virtual addresses for use in kmalloc() and friends. +namespace KernelVM +{ + void init(); + + Result alloc_one_page(); + Result alloc_several_pages(usize count); + + Result free_one_page(u64 address); + Result free_several_pages(u64 address, usize count); + + usize free(); + usize used(); +} diff --git a/kernel/src/memory/Memory.cpp b/kernel/src/memory/Memory.cpp deleted file mode 100644 index 6ff02898..00000000 --- a/kernel/src/memory/Memory.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "memory/Memory.h" -#include "bootboot.h" - -extern BOOTBOOT bootboot; - -uint64_t Memory::get_system() -{ - static uint64_t result = 0; - static bool cached = false; - - if (cached) return result; - - MMapEnt* ptr = &bootboot.mmap; - uint64_t mmap_entries = (bootboot.size - 128) / 16; - for (uint64_t i = 0; i < mmap_entries; i++) - { - result += MMapEnt_Size(ptr); - ptr++; - } - - cached = true; - - return result; -} - -uint64_t Memory::get_usable() -{ - static uint64_t result = 0; - static bool cached = false; - - if (cached) return result; - - MMapEnt* ptr = &bootboot.mmap; - uint64_t mmap_entries = (bootboot.size - 128) / 16; - for (uint64_t i = 0; i < mmap_entries; i++) - { - if (MMapEnt_IsFree(ptr)) result += MMapEnt_Size(ptr); - ptr++; - } - - cached = true; - - return result; -} - -bool Memory::is_kernel_address(uintptr_t address) -{ - return address >= 0xfffffffff8000000; -} - -bool Memory::is_user_address(uintptr_t address) -{ - return address && address < 0xfffffffff8000000; -} \ No newline at end of file diff --git a/kernel/src/memory/MemoryManager.cpp b/kernel/src/memory/MemoryManager.cpp index b8bee795..61eb24e4 100644 --- a/kernel/src/memory/MemoryManager.cpp +++ b/kernel/src/memory/MemoryManager.cpp @@ -1,223 +1,466 @@ -#ifdef MM_DEBUG -#define MODULE "mm" -#include "log/Log.h" -#endif - -#include "memory/KernelHeap.h" #include "memory/MemoryManager.h" -#include "memory/PMM.h" -#include "memory/VMM.h" -#include "misc/utils.h" -#include "std/ensure.h" +#include "arch/MMU.h" +#include "memory/KernelVM.h" +#include "memory/MemoryMap.h" +#include "thread/Spinlock.h" +#include +#include +#include +#include +#include -// FIXME: Use Result in here. +extern const u8 start_of_kernel_rodata[1]; +extern const u8 end_of_kernel_rodata[1]; +extern const u8 start_of_kernel_data[1]; +extern const u8 end_of_kernel_data[1]; -void MemoryManager::init() +static Atomic free_mem; +static Atomic used_mem; +static Atomic reserved_mem; + +static Atomic start_index; + +static LockedValue g_frame_bitmap; + +#define CHECK_PAGE_ALIGNED(address) expect(is_aligned(address), "Address is not page-aligned") + +static usize get_physical_address_space_size() { - KernelHeap::clear(); - PMM::init(); - VMM::init(); - PMM::map_bitmap_to_virtual(); + MemoryMapIterator iter; + const MemoryMapEntry entry = iter.highest(); + + return entry.address() + entry.size(); // This is the address at the end of the last (highest) entry, thus the whole + // address space that was passed to us. } -extern char start_of_kernel_rodata[1]; -extern char end_of_kernel_rodata[1]; -extern char start_of_kernel_data[1]; -extern char end_of_kernel_data[1]; - -void MemoryManager::protect_kernel_sections() +namespace MemoryManager { - protect(start_of_kernel_rodata, - Utilities::get_blocks_from_size(PAGE_SIZE, end_of_kernel_rodata - start_of_kernel_rodata), 0); - protect(start_of_kernel_data, Utilities::get_blocks_from_size(PAGE_SIZE, end_of_kernel_data - start_of_kernel_data), - MAP_READ_WRITE); -} - -Result MemoryManager::get_mapping(void* physicalAddress, int flags) -{ - uint64_t virtualAddress = KernelHeap::request_virtual_page(); - if (!virtualAddress) + Result protect_kernel_sections() { -#ifdef MM_DEBUG - kwarnln("No kernel heap space (virtual address space from -128M to -64M) left"); -#endif - KernelHeap::dump_usage(); - return {ENOMEM}; + const usize rodata_size = (usize)(end_of_kernel_rodata - start_of_kernel_rodata); + const usize rodata_pages = get_blocks_from_size(rodata_size, ARCH_PAGE_SIZE); + TRY(remap((u64)start_of_kernel_rodata, rodata_pages, MMU::NoExecute)); + + const usize data_size = (usize)(end_of_kernel_data - start_of_kernel_data); + const usize data_pages = get_blocks_from_size(data_size, ARCH_PAGE_SIZE); + TRY(remap((u64)start_of_kernel_data, data_pages, MMU::NoExecute | MMU::ReadWrite)); + + return {}; } - VMM::map(virtualAddress, (uint64_t)physicalAddress, flags); - return (void*)virtualAddress; -} -Result MemoryManager::get_unaligned_mapping(void* physicalAddress, int flags) -{ - uint64_t offset = (uint64_t)physicalAddress % PAGE_SIZE; - uint64_t virtualAddress = KernelHeap::request_virtual_page(); - if (!virtualAddress) + void init_physical_frame_allocator() { -#ifdef MM_DEBUG - kwarnln("No kernel heap space (virtual address space from -128M to -64M) left"); -#endif - KernelHeap::dump_usage(); - return {ENOMEM}; - } - VMM::map(virtualAddress, (uint64_t)physicalAddress - offset, flags); - return (void*)(virtualAddress + offset); -} + MemoryMapIterator iter; + MemoryMapEntry entry; -Result MemoryManager::get_unaligned_mappings(void* physicalAddress, uint64_t count, int flags) -{ - if (!count) return 0; - if (count == 1) return get_unaligned_mapping(physicalAddress, flags); - uint64_t offset = (uint64_t)physicalAddress % PAGE_SIZE; - uint64_t virtualAddress = KernelHeap::request_virtual_pages(count); - if (!virtualAddress) - { -#ifdef MM_DEBUG - kwarnln("Not enough contiguous pages (%ld) left in the kernel heap space (virtual address space from -128M to " - "-64M)", - count); -#endif - KernelHeap::dump_usage(); - return {ENOMEM}; - } - for (uint64_t i = 0; i < count; i++) - { - VMM::map(virtualAddress + (i * PAGE_SIZE), ((uint64_t)physicalAddress - offset) + (i * PAGE_SIZE), flags); - } - return (void*)(virtualAddress + offset); -} + const auto largest_free_entry = iter.largest_free(); -void MemoryManager::release_unaligned_mapping(void* mapping) -{ - uint64_t offset = (uint64_t)mapping % PAGE_SIZE; - VMM::unmap((uint64_t)mapping - offset); - KernelHeap::free_virtual_page((uint64_t)mapping - offset); -} + expect(largest_free_entry.is_free(), "We were given a largest free memory region that isn't even free!"); -void MemoryManager::release_unaligned_mappings(void* mapping, uint64_t count) -{ - if (!count) return; - if (count == 1) return release_unaligned_mapping(mapping); - uint64_t offset = (uint64_t)mapping % PAGE_SIZE; - KernelHeap::free_virtual_pages((uint64_t)mapping - offset, count); - for (uint64_t i = 0; i < count; i++) { VMM::unmap(((uint64_t)mapping - offset) + (i * PAGE_SIZE)); } -} + // The entire physical address space. May contain inexistent memory holes, thus differs from total_mem which + // only counts existent memory. Our bitmap needs to have space for all of the physical address space, since + // usable addresses will be scattered across it. + const usize physical_address_space_size = get_physical_address_space_size(); -void MemoryManager::release_mapping(void* mapping) -{ - VMM::unmap((uint64_t)mapping); - KernelHeap::free_virtual_page((uint64_t)mapping); -} + // We store our frame bitmap at the beginning of the largest free memory block. + char* const frame_bitmap_addr = (char*)largest_free_entry.ptr(); -Result MemoryManager::get_page(int flags) -{ - uint64_t virtualAddress = KernelHeap::request_virtual_page(); - if (!virtualAddress) - { -#ifdef MM_DEBUG - kwarnln("No kernel heap space (virtual address space from -128M to -64M) left"); -#endif - KernelHeap::dump_usage(); - return {ENOMEM}; - } - return get_page_at(virtualAddress, flags); -} + const usize frame_bitmap_size = get_blocks_from_size(physical_address_space_size / ARCH_PAGE_SIZE, 8UL); -Result MemoryManager::get_page_at(uint64_t addr, int flags) -{ - auto paddr = PMM::request_page(); - if (paddr.has_error()) - { -#ifdef MM_DEBUG - kwarnln("OOM while allocating one page of memory. this is not good..."); -#endif - return {ENOMEM}; - } - VMM::map(addr, (uint64_t)paddr.release_value(), flags); - return (void*)addr; -} + // This should never happen, unless memory is very fragmented. Usually there is always a very big block of + // usable memory and then some tiny blocks around it. + expect(frame_bitmap_size < largest_free_entry.size(), + "No single memory region is enough to hold the frame bitmap"); -void MemoryManager::release_page(void* page) -{ - uint64_t physicalAddress = VMM::get_physical((uint64_t)page); - ensure(physicalAddress != UINT64_MAX); // this address is not mapped in the virtual address space... - VMM::unmap((uint64_t)page); - PMM::free_page((void*)physicalAddress); -} - -Result MemoryManager::get_pages(uint64_t count, int flags) -{ - if (!count) return 0; - if (count == 1) return get_page(flags); -#ifdef MM_DEBUG - kdbgln("allocating several pages (%ld)", count); -#endif - uint64_t virtualAddress = KernelHeap::request_virtual_pages(count); - if (!virtualAddress) - { -#ifdef MM_DEBUG - kwarnln("No kernel heap space (virtual address space from -128M to -64M) left"); -#endif - KernelHeap::dump_usage(); - return {ENOMEM}; // Out of virtual address in the kernel heap range (-128M to -64M). This should be difficult to - // achieve... - } - return get_pages_at(virtualAddress, count, flags); -} - -Result MemoryManager::get_pages_at(uint64_t addr, uint64_t count, int flags) -{ - if (!count) return 0; - if (count == 1) return get_page_at(addr, flags); -#ifdef MM_DEBUG - kdbgln("allocating several pages (%ld), at address %lx", count, addr); -#endif - for (uint64_t i = 0; i < count; i++) - { - auto paddr = PMM::request_page(); - if (paddr.has_error()) // OOM: No physical memory available! Since this might be at the end of a - // long allocation, we should be able to recover most of it and allocate a - // smaller range, so this might not be fatal. { -#ifdef MM_DEBUG - kwarnln("OOM while allocating page %ld of memory. this might be recoverable...", i); -#endif - // FIXME: Weren't we supposed to free all previously allocated pages, to avoid leaks when failing large - // allocations? - return {ENOMEM}; + auto frame_bitmap = g_frame_bitmap.lock(); + + frame_bitmap->initialize(frame_bitmap_addr, frame_bitmap_size); + + frame_bitmap->clear(true); // Set all pages to used/reserved by default, then clear out the free ones + + iter.rewind(); + while (iter.next().try_set_value(entry)) + { + const u64 index = entry.address() / ARCH_PAGE_SIZE; + const usize pages = entry.size() / ARCH_PAGE_SIZE; + if (!entry.is_free()) { reserved_mem += entry.size(); } + else + { + free_mem += entry.size(); + frame_bitmap->clear_region(index, pages, false); + } + } } - VMM::map(addr + (i * PAGE_SIZE), (uint64_t)paddr.release_value(), flags); - } - return (void*)addr; -} -void MemoryManager::release_pages(void* pages, uint64_t count) -{ - if (!count) return; - if (count == 1) return release_page(pages); -#ifdef MM_DEBUG - kdbgln("releasing several pages (%ld)", count); -#endif - for (uint64_t i = 0; i < count; i++) + // Make sure that the physical frames used by the bitmap aren't handed out to anyone else. + lock_frames(largest_free_entry.address(), get_blocks_from_size(frame_bitmap_size, ARCH_PAGE_SIZE)); + } + + void init() { - void* page = (void*)((uint64_t)pages + (i * PAGE_SIZE)); - uint64_t physicalAddress = VMM::get_physical((uint64_t)page); - ensure(physicalAddress != UINT64_MAX); - VMM::unmap((uint64_t)page); - PMM::free_page((void*)physicalAddress); + init_physical_frame_allocator(); + KernelVM::init(); + MMU::setup_initial_page_directory(); + + // NOTE: We force these operations to succeed, because if we can't map the frame bitmap to virtual memory + // there's no point in continuing. + auto bitmap_pages = g_frame_bitmap.lock()->size_in_bytes() / ARCH_PAGE_SIZE; + + auto virtual_bitmap_base = + KernelVM::alloc_several_pages(bitmap_pages) + .expect_value("Unable to allocate virtual memory for the physical frame bitmap, cannot continue"); + + u64 phys = (u64)g_frame_bitmap.lock()->location(); + map_frames_at(virtual_bitmap_base, phys, bitmap_pages, MMU::ReadWrite | MMU::NoExecute) + .expect_value("Unable to map the physical frame bitmap to virtual memory, cannot continue"); + + auto frame_bitmap = g_frame_bitmap.lock(); + + frame_bitmap->initialize((void*)virtual_bitmap_base, frame_bitmap->size_in_bytes()); } - KernelHeap::free_virtual_pages((uint64_t)pages, count); -} -void MemoryManager::protect(void* page, uint64_t count, int flags) -{ - for (uint64_t i = 0; i < count; i++) { VMM::remap((uint64_t)page + (i * PAGE_SIZE), flags); } -} - -void MemoryManager::map_several_pages(uint64_t physicalAddress, uint64_t virtualAddress, uint64_t count, int flags) -{ - for (uint64_t i = 0; i < count; i++) + void lock_frame(u64 frame) { - VMM::map(virtualAddress + (i * PAGE_SIZE), physicalAddress + (i * PAGE_SIZE), flags); + const u64 index = frame / ARCH_PAGE_SIZE; + auto frame_bitmap = g_frame_bitmap.lock(); + if (frame_bitmap->get(index)) return; + frame_bitmap->set(index, true); + used_mem += ARCH_PAGE_SIZE; + free_mem -= ARCH_PAGE_SIZE; } -} \ No newline at end of file + + void lock_frames(u64 frames, usize count) + { + for (usize index = 0; index < count; index++) { lock_frame(frames + (index * ARCH_PAGE_SIZE)); } + } + + Result alloc_frame() + { + auto frame_bitmap = g_frame_bitmap.lock(); + for (u64 index = start_index; index < frame_bitmap->size(); index++) + { + if (frame_bitmap->get(index)) continue; + frame_bitmap->set(index, true); + start_index = index + 1; + free_mem -= ARCH_PAGE_SIZE; + used_mem += ARCH_PAGE_SIZE; + return index * ARCH_PAGE_SIZE; + } + + return err(ENOMEM); + } + + Result free_frame(u64 frame) + { + const u64 index = frame / ARCH_PAGE_SIZE; + auto frame_bitmap = g_frame_bitmap.lock(); + if (index > frame_bitmap->size()) return err(EFAULT); + if (!frame_bitmap->get(index)) return err(EFAULT); + frame_bitmap->set(index, false); + used_mem -= ARCH_PAGE_SIZE; + free_mem += ARCH_PAGE_SIZE; + if (start_index > index) start_index = index; + return {}; + } + + Result remap(u64 address, usize count, int flags) + { + CHECK_PAGE_ALIGNED(address); + + while (count--) + { + TRY(MMU::remap(address, flags)); + address += ARCH_PAGE_SIZE; + } + + return {}; + } + + Result map_frames_at(u64 virt, u64 phys, usize count, int flags) + { + CHECK_PAGE_ALIGNED(virt); + CHECK_PAGE_ALIGNED(phys); + + usize pages_mapped = 0; + + // Let's clean up after ourselves if we fail. + auto guard = make_scope_guard([=, &pages_mapped] { unmap_weak(virt, pages_mapped); }); + + while (pages_mapped < count) + { + TRY(MMU::map(virt, phys, flags)); + virt += ARCH_PAGE_SIZE; + phys += ARCH_PAGE_SIZE; + pages_mapped++; + } + + guard.deactivate(); + + return {}; + } + + Result alloc_at(u64 virt, usize count, int flags) + { + CHECK_PAGE_ALIGNED(virt); + + u64 start = virt; + usize pages_mapped = 0; + + auto guard = make_scope_guard([=, &pages_mapped] { unmap_owned(start, pages_mapped); }); + + while (pages_mapped < count) + { + u64 frame = TRY(alloc_frame()); + TRY(MMU::map(virt, frame, flags)); + virt += ARCH_PAGE_SIZE; + pages_mapped++; + } + + guard.deactivate(); + + return start; + } + + Result alloc_for_kernel(usize count, int flags) + { + u64 start = TRY(KernelVM::alloc_several_pages(count)); + usize pages_mapped = 0; + + auto guard = make_scope_guard([=, &pages_mapped] { + KernelVM::free_several_pages(start, pages_mapped); + unmap_owned(start, pages_mapped); + }); + + u64 virt = start; + + while (pages_mapped < count) + { + u64 frame = TRY(alloc_frame()); + TRY(MMU::map(virt, frame, flags)); + virt += ARCH_PAGE_SIZE; + pages_mapped++; + } + + guard.deactivate(); + + return start; + } + + Result get_kernel_mapping_for_frames(u64 phys, usize count, int flags) + { + u64 start = TRY(KernelVM::alloc_several_pages(count)); + + usize pages_mapped = 0; + + auto guard = make_scope_guard([=, &pages_mapped] { + KernelVM::free_several_pages(start, pages_mapped); + unmap_weak(start, pages_mapped); + }); + + u64 virt = start; + + while (pages_mapped < count) + { + TRY(MMU::map(virt, phys, flags)); + virt += ARCH_PAGE_SIZE; + phys += ARCH_PAGE_SIZE; + pages_mapped++; + } + + guard.deactivate(); + + return start; + } + + Result unmap_owned(u64 virt, usize count) + { + CHECK_PAGE_ALIGNED(virt); + + while (count--) + { + u64 frame = TRY(MMU::unmap(virt)); + TRY(free_frame(frame)); + virt += ARCH_PAGE_SIZE; + } + + return {}; + } + + Result unmap_owned_and_free_vm(u64 virt, usize count) + { + CHECK_PAGE_ALIGNED(virt); + + KernelVM::free_several_pages(virt, count); + + return unmap_owned(virt, count); + } + + Result unmap_weak(u64 virt, usize count) + { + CHECK_PAGE_ALIGNED(virt); + + while (count--) + { + TRY(MMU::unmap(virt)); + virt += ARCH_PAGE_SIZE; + } + + return {}; + } + + Result unmap_weak_and_free_vm(u64 virt, usize count) + { + CHECK_PAGE_ALIGNED(virt); + + KernelVM::free_several_pages(virt, count); + + return unmap_weak(virt, count); + } + + Result remap_unaligned(u64 address, usize count, int flags) + { + if (!is_aligned(address)) count++; + address = align_down(address); + + while (count--) + { + TRY(MMU::remap(address, flags)); + address += ARCH_PAGE_SIZE; + } + + return {}; + } + + bool validate_readable_page(u64 address) + { + auto rc = MMU::get_flags(address); + if (rc.has_error()) return false; + return true; + } + + bool validate_writable_page(u64 address) + { + auto rc = MMU::get_flags(address); + if (rc.has_error()) return false; + if (rc.value() & MMU::ReadWrite) return true; + return false; + } + + bool validate_user_readable_page(u64 address) + { + auto rc = MMU::get_flags(address); + if (rc.has_error()) return false; + if (rc.value() & MMU::User) return true; + return false; + } + + bool validate_user_writable_page(u64 address) + { + auto rc = MMU::get_flags(address); + if (rc.has_error()) return false; + if ((rc.value() & MMU::User) && (rc.value() && MMU::ReadWrite)) return true; + return false; + } + + bool validate_userspace_string(u64 address) + { + if (!validate_user_readable_page(address)) return false; + + while (*(char*)address != 0) + { + address++; + if (address % ARCH_PAGE_SIZE) + { + if (!validate_user_readable_page(address)) return false; + } + } + + return true; + } + + bool validate_user_write(void* user, usize size) + { + uintptr_t user_ptr = (uintptr_t)user; + uintptr_t user_page = align_down(user_ptr); + + uintptr_t diff = user_ptr - user_page; + + usize pages = get_blocks_from_size(size + diff, ARCH_PAGE_SIZE); + + while (pages--) + { + if (!validate_user_writable_page(user_page)) return false; + user_page += ARCH_PAGE_SIZE; + } + + return true; + } + + bool validate_user_read(const void* user, usize size) + { + uintptr_t user_ptr = (uintptr_t)user; + uintptr_t user_page = align_down(user_ptr); + + uintptr_t diff = user_ptr - user_page; + + usize pages = get_blocks_from_size(size + diff, ARCH_PAGE_SIZE); + + while (pages--) + { + if (!validate_user_readable_page(user_page)) return false; + user_page += ARCH_PAGE_SIZE; + } + + return true; + } + + bool copy_to_user(void* user, const void* kernel, usize size) + { + uintptr_t user_ptr = (uintptr_t)user; + uintptr_t user_page = align_down(user_ptr); + + const char* kernel_ptr = (const char*)kernel; + + // Userspace pointer not aligned on page boundary + if (user_ptr != user_page) + { + // FIXME: Validate that this page is writable by the user, not just the kernel. + if (!validate_user_writable_page(user_page)) return false; + } + + while (size--) + { + // Crossed a page boundary, gotta check the page tables again before touching any memory!! + if (user_ptr % ARCH_PAGE_SIZE) + { + if (!validate_user_writable_page(user_ptr)) return false; + } + + *(char*)user_ptr = *kernel_ptr++; + user_ptr++; + } + + return true; + } + + usize free() + { + return free_mem; + } + + usize used() + { + return used_mem; + } + + usize reserved() + { + return reserved_mem; + } + + usize total() + { + return free_mem + used_mem + reserved_mem; + } +} diff --git a/kernel/src/memory/MemoryManager.h b/kernel/src/memory/MemoryManager.h new file mode 100644 index 00000000..76bcf9e4 --- /dev/null +++ b/kernel/src/memory/MemoryManager.h @@ -0,0 +1,64 @@ +#pragma once +#include +#include + +namespace MemoryManager +{ + void init(); + + Result protect_kernel_sections(); + + Result alloc_frame(); + Result free_frame(u64 frame); + + void lock_frame(u64 frame); + void lock_frames(u64 frames, usize count); + + Result remap(u64 address, usize count, int flags); + Result remap_unaligned(u64 address, usize count, int flags); + + bool validate_readable_page(u64 address); + bool validate_writable_page(u64 address); + + bool validate_user_readable_page(u64 address); + bool validate_user_writable_page(u64 address); + + bool validate_userspace_string(u64 address); + + bool validate_user_write(void* user, usize size); + bool validate_user_read(const void* user, usize size); + + template bool validate_user_write_typed(T* user) + { + return validate_user_write(user, sizeof(T)); + } + + template bool validate_user_read_typed(const T* user) + { + return validate_user_read(user, sizeof(T)); + } + + bool copy_to_user(void* user, const void* kernel, usize size); + + template bool copy_to_user_typed(T* user, const T* kernel) + { + return copy_to_user(user, kernel, sizeof(T)); + } + + Result map_frames_at(u64 virt, u64 phys, usize count, int flags); + + Result alloc_at(u64 virt, usize count, int flags); + Result alloc_for_kernel(usize count, int flags); + + Result get_kernel_mapping_for_frames(u64 phys, usize count, int flags); + + Result unmap_owned(u64 virt, usize count); + Result unmap_owned_and_free_vm(u64 virt, usize count); + Result unmap_weak(u64 virt, usize count); + Result unmap_weak_and_free_vm(u64 virt, usize count); + + usize free(); + usize used(); + usize reserved(); + usize total(); +} diff --git a/kernel/src/memory/MemoryMap.cpp b/kernel/src/memory/MemoryMap.cpp index 9ae89bbe..3e67fd76 100644 --- a/kernel/src/memory/MemoryMap.cpp +++ b/kernel/src/memory/MemoryMap.cpp @@ -1,37 +1,97 @@ -#define MODULE "mmap" - #include "memory/MemoryMap.h" -#include "bootboot.h" -#include "log/Log.h" +#include +#include -extern BOOTBOOT bootboot; +extern const BOOTBOOT bootboot; -void Memory::walk_memory_map() +MemoryMapEntry::MemoryMapEntry(u64 address, usize size, bool is_free) + : m_address(address), m_size(size), m_is_free(is_free) { - MMapEnt* ptr = &bootboot.mmap; - uint64_t mmap_entries = (bootboot.size - 128) / 16; - for (uint64_t i = 0; i < mmap_entries; i++) +} + +MemoryMapEntry& MemoryMapEntry::operator=(const MemoryMapEntry& other) +{ + if (&other == this) return *this; + + m_address = other.address(); + m_size = other.size(); + m_is_free = other.is_free(); + + return *this; +} + +static MemoryMapEntry memory_map_entry_from_mmapent(const MMapEnt* ent) +{ + return { MMapEnt_Ptr(ent), MMapEnt_Size(ent), MMapEnt_IsFree(ent) }; +} + +MemoryMapIterator::MemoryMapIterator() : m_mmap_entries((bootboot.size - 128) / 16), m_base_ent(&bootboot.mmap) +{ + rewind(); +} + +void MemoryMapIterator::rewind() +{ + m_cur_ent = 0; +} + +Option MemoryMapIterator::at(usize index) const +{ + if (index >= m_mmap_entries) return {}; + return memory_map_entry_from_mmapent(m_base_ent + index); +} + +Option MemoryMapIterator::next() +{ + auto entry = TRY(at(m_cur_ent++)); + +#ifdef ARCH_X86_64 + // Workaround for https://gitlab.com/qemu-project/qemu/-/commit/8504f129450b909c88e199ca44facd35d38ba4de + // This invalid 12GiB reserved entry is made up by QEMU (doesn't appear on any real hardware), so we can simply + // ignore it and move on to the next entry. + if (entry.address() == 0x000000fd00000000 && entry.size() == (0x000000ffffffffff - 0x000000fd00000000) + 1) + return at(m_cur_ent++); +#endif + + return entry; +} + +MemoryMapEntry MemoryMapIterator::largest_free() +{ + usize largest_size = 0; + usize largest_index = 0; + + rewind(); + + MemoryMapEntry entry; + while (next().try_set_value(entry)) { - switch (MMapEnt_Type(ptr)) + if (entry.is_free() && entry.size() > largest_size) { - case MMAP_USED: - kinfoln("Used memory region starting at %lx, ends at %lx, size %lx", MMapEnt_Ptr(ptr), - MMapEnt_Ptr(ptr) + MMapEnt_Size(ptr) - 1, MMapEnt_Size(ptr)); - break; - case MMAP_ACPI: - kinfoln("ACPI memory region starting at %lx, ends at %lx, size %lx", MMapEnt_Ptr(ptr), - MMapEnt_Ptr(ptr) + MMapEnt_Size(ptr) - 1, MMapEnt_Size(ptr)); - break; - case MMAP_MMIO: - kinfoln("MMIO memory region starting at %lx, ends at %lx, size %lx", MMapEnt_Ptr(ptr), - MMapEnt_Ptr(ptr) + MMapEnt_Size(ptr) - 1, MMapEnt_Size(ptr)); - break; - case MMAP_FREE: - kinfoln("Free memory region starting at %lx, ends at %lx, size %lx", MMapEnt_Ptr(ptr), - MMapEnt_Ptr(ptr) + MMapEnt_Size(ptr) - 1, MMapEnt_Size(ptr)); - break; - default: kinfoln("Invalid memory map entry"); break; + largest_size = entry.size(); + largest_index = m_cur_ent - 1; } - ptr++; } -} \ No newline at end of file + + return at(largest_index).value(); +} + +MemoryMapEntry MemoryMapIterator::highest() +{ + usize highest_address = 0; + usize highest_index = 0; + + rewind(); + + MemoryMapEntry entry; + while (next().try_set_value(entry)) + { + if (entry.address() > highest_address) + { + highest_address = entry.address(); + highest_index = m_cur_ent - 1; + } + } + + return at(highest_index).value(); +} diff --git a/kernel/src/memory/MemoryMap.h b/kernel/src/memory/MemoryMap.h new file mode 100644 index 00000000..d6f3687d --- /dev/null +++ b/kernel/src/memory/MemoryMap.h @@ -0,0 +1,64 @@ +#pragma once +#include "boot/bootboot.h" +#include +#include + +struct MemoryMapEntry +{ + MemoryMapEntry() = default; + MemoryMapEntry(const MemoryMapEntry& other) = default; + MemoryMapEntry(u64 address, usize size, bool is_free); + + u64 address() const + { + return m_address; + } + + void* ptr() const + { + return (void*)m_address; + } + + usize size() const + { + return m_size; + } + + bool is_free() const + { + return m_is_free; + } + + MemoryMapEntry& operator=(const MemoryMapEntry& other); + + private: + u64 m_address; + usize m_size; + bool m_is_free; +}; + +class MemoryMapIterator +{ + public: + MemoryMapIterator(); + + void rewind(); + + Option next(); + + MemoryMapEntry largest_free(); + + MemoryMapEntry highest(); + + Option at(usize index) const; + + usize entries() const + { + return m_mmap_entries; + } + + private: + const usize m_mmap_entries; + const MMapEnt* m_base_ent; + usize m_cur_ent; +}; diff --git a/kernel/src/memory/PMM.cpp b/kernel/src/memory/PMM.cpp deleted file mode 100644 index ec62deb0..00000000 --- a/kernel/src/memory/PMM.cpp +++ /dev/null @@ -1,191 +0,0 @@ -#define MODULE "mem" - -#include "memory/PMM.h" -#include "bootboot.h" -#include "log/Log.h" -#include "memory/Memory.h" -#include "memory/MemoryManager.h" -#include "misc/utils.h" -#include "std/ensure.h" -#include "std/errno.h" -#include "std/string.h" - -extern BOOTBOOT bootboot; - -static bool bitmap_read(uint64_t index); -static void bitmap_set(uint64_t index, bool value); - -static uint64_t free_mem = 0; -static uint64_t used_mem = 0; -static uint64_t reserved_mem = 0; - -static char* bitmap_addr; -static char* virtual_bitmap_addr; -static uint64_t bitmap_size; - -static uint64_t start_index = 0; - -void PMM::init() -{ - uint64_t total_mem = Memory::get_system(); - - void* biggest_chunk = nullptr; - uint64_t biggest_chunk_size = 0; - - MMapEnt* ptr = &bootboot.mmap; - uint64_t mmap_entries = (bootboot.size - 128) / 16; - for (uint64_t i = 0; i < mmap_entries; i++) - { - if (!MMapEnt_IsFree(ptr)) - { - ptr++; - continue; - } - if (MMapEnt_Size(ptr) > biggest_chunk_size) - { - biggest_chunk = (void*)MMapEnt_Ptr(ptr); - biggest_chunk_size = MMapEnt_Size(ptr); - } - ptr++; - } - - bitmap_addr = (char*)biggest_chunk; - virtual_bitmap_addr = bitmap_addr; - ensure((total_mem / PAGE_SIZE / 8) < biggest_chunk_size); - bitmap_size = total_mem / PAGE_SIZE / 8 + 1; - memset(bitmap_addr, 0xFF, bitmap_size); - - ptr = &bootboot.mmap; - for (uint64_t i = 0; i < mmap_entries; i++) - { - uint64_t index = MMapEnt_Ptr(ptr) / PAGE_SIZE; - if (!MMapEnt_IsFree(ptr)) { reserved_mem += MMapEnt_Size(ptr); } - else - { - free_mem += MMapEnt_Size(ptr); - for (uint64_t j = 0; j < (MMapEnt_Size(ptr) / PAGE_SIZE); j++) { bitmap_set(index + j, false); } - } - ptr++; - } - - lock_pages(bitmap_addr, bitmap_size / PAGE_SIZE + 1); -} - -static bool bitmap_read(uint64_t index) -{ - return (virtual_bitmap_addr[index / 8] & (0b10000000 >> (index % 8))) > 0; -} - -static void bitmap_set(uint64_t index, bool value) -{ - uint64_t byteIndex = index / 8; - uint8_t bitIndexer = 0b10000000 >> (index % 8); - virtual_bitmap_addr[byteIndex] &= (uint8_t)(~bitIndexer); - if (value) { virtual_bitmap_addr[byteIndex] |= bitIndexer; } -} - -Result PMM::request_page() -{ - for (uint64_t index = start_index; index < (bitmap_size * 8); index++) - { - if (bitmap_read(index)) continue; - bitmap_set(index, true); - start_index = index + 1; - free_mem -= PAGE_SIZE; - used_mem += PAGE_SIZE; - return (void*)(index * PAGE_SIZE); - } - - return {ENOMEM}; -} - -Result PMM::request_pages(uint64_t count) -{ - uint64_t contiguous = 0; - uint64_t contiguous_start = 0; - for (uint64_t index = start_index; index < (bitmap_size * 8); index++) - { - if (bitmap_read(index)) - { - contiguous = 0; - continue; - } - if (contiguous == 0) - { - contiguous_start = index; - contiguous++; - } - else - contiguous++; - if (contiguous == count) - { - for (uint64_t i = 0; i < count; i++) bitmap_set(contiguous_start + i, true); - free_mem -= (count * PAGE_SIZE); - used_mem += (count * PAGE_SIZE); - return (void*)(contiguous_start * PAGE_SIZE); - } - } - - return {ENOMEM}; -} - -void PMM::free_page(void* address) -{ - uint64_t index = (uint64_t)address / PAGE_SIZE; - if (index > (bitmap_size * 8)) - { - kinfoln("attempt to free out-of-range address %p", address); - return; - } - if (!bitmap_read(index)) return; - bitmap_set(index, false); - used_mem -= PAGE_SIZE; - free_mem += PAGE_SIZE; - if (start_index > index) start_index = index; -} - -void PMM::free_pages(void* address, uint64_t count) -{ - for (uint64_t index = 0; index < count; index++) { free_page((void*)((uint64_t)address + index)); } -} - -void PMM::lock_page(void* address) -{ - uint64_t index = ((uint64_t)address) / PAGE_SIZE; - if (bitmap_read(index)) return; - bitmap_set(index, true); - used_mem += PAGE_SIZE; - free_mem -= PAGE_SIZE; -} - -void PMM::lock_pages(void* address, uint64_t count) -{ - for (uint64_t index = 0; index < count; index++) { lock_page((void*)((uint64_t)address + index)); } -} - -uint64_t PMM::get_free() -{ - return free_mem; -} - -uint64_t PMM::get_used() -{ - return used_mem; -} - -uint64_t PMM::get_reserved() -{ - return reserved_mem; -} - -uint64_t PMM::get_bitmap_size() -{ - return bitmap_size; -} - -void PMM::map_bitmap_to_virtual() -{ - virtual_bitmap_addr = (char*)MemoryManager::get_unaligned_mappings( - bitmap_addr, Utilities::get_blocks_from_size(PAGE_SIZE, bitmap_size)) - .release_value(); // If we can't do this, something has gone terribly wrong. -} \ No newline at end of file diff --git a/kernel/src/memory/Paging.cpp b/kernel/src/memory/Paging.cpp deleted file mode 100644 index 8bf7a7dc..00000000 --- a/kernel/src/memory/Paging.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "memory/Paging.h" - -#pragma GCC push_options -#pragma GCC diagnostic ignored "-Wconversion" - -void PageDirectoryEntry::set_address(uint64_t addr) -{ - this->address = (addr >> 12); -} - -uint64_t PageDirectoryEntry::get_address() -{ - return (uint64_t)this->address << 12; -} - -#pragma GCC pop_options \ No newline at end of file diff --git a/kernel/src/memory/UserHeap.cpp b/kernel/src/memory/UserHeap.cpp deleted file mode 100644 index b9876a8c..00000000 --- a/kernel/src/memory/UserHeap.cpp +++ /dev/null @@ -1,164 +0,0 @@ -#define MODULE "mem" - -#include "memory/UserHeap.h" -#include "log/Log.h" -#include "misc/utils.h" -#include "std/stdlib.h" -#include "std/string.h" - -#ifndef USER_HEAP_DEBUG -#undef kdbgln -#define kdbgln(...) -#endif - -#ifndef PAGE_SIZE -#define PAGE_SIZE 4096 -#endif - -#define ALLOC_BASE 0xa00000 - -#define INITIAL_SIZE 0x2000 -#define EXPAND_SIZE 0x1000 - -bool UserHeap::init() -{ - bitmap = (uint8_t*)kmalloc(INITIAL_SIZE); - if (!bitmap) return false; - bitmap_size = INITIAL_SIZE; - memset(bitmap, 0, bitmap_size); - kdbgln("new user heap, bitmap at %p, size %ld", (void*)bitmap, bitmap_size); - return true; -} - -bool UserHeap::inherit(UserHeap& other) -{ - bitmap = (uint8_t*)kmalloc(other.bitmap_size); - if (!bitmap) return false; - bitmap_size = other.bitmap_size; - memcpy(bitmap, other.bitmap, bitmap_size); - kdbgln("child user heap, bitmap at %p, size %ld", (void*)bitmap, bitmap_size); - return true; -} - -void UserHeap::free() -{ - kdbgln("freeing user heap, bitmap at %p, size %ld", (void*)bitmap, bitmap_size); - kfree(bitmap); -} - -bool UserHeap::try_expand() -{ - kdbgln("attempting to expand user heap"); - void* new_bitmap = krealloc(bitmap, bitmap_size + EXPAND_SIZE); - if (!new_bitmap) - { - kdbgln("expansion failed"); - return false; - } - bitmap = (uint8_t*)new_bitmap; - memset(bitmap + bitmap_size, 0, EXPAND_SIZE); - bitmap_size += EXPAND_SIZE; - kdbgln("expanded user heap, bitmap at %p, size %ld", (void*)bitmap, bitmap_size); - return true; -} - -bool UserHeap::try_expand_size(uint64_t size) -{ - void* new_bitmap = krealloc(bitmap, bitmap_size + size); - if (!new_bitmap) - { - kdbgln("expansion failed"); - return false; - } - bitmap = (uint8_t*)new_bitmap; - memset(bitmap + bitmap_size, 0, size); - bitmap_size += size; - kdbgln("expanded user heap, bitmap at %p, size %ld", (void*)bitmap, bitmap_size); - return true; -} - -bool UserHeap::bitmap_read(uint64_t index) -{ - return (bitmap[index / 8] & (0b10000000 >> (index % 8))) > 0; -} - -void UserHeap::bitmap_set(uint64_t index, bool value) -{ - uint64_t byteIndex = index / 8; - uint8_t bitIndexer = 0b10000000 >> (index % 8); - bitmap[byteIndex] &= ~bitIndexer; - if (value) { bitmap[byteIndex] |= bitIndexer; } -} - -uint64_t UserHeap::request_virtual_page() -{ - uint64_t attempts = 0; -allocate: - for (uint64_t index = start_index; index < bitmap_size * 8; index++) - { - if (bitmap_read(index)) continue; - bitmap_set(index, true); - start_index = index + 1; - return ALLOC_BASE + (index * PAGE_SIZE); - } - - if (attempts == 0 && try_expand()) // We are allocating ONE PAGE, only one attempt should be necessary. - { - attempts++; - goto allocate; - } - - return 0; -} - -uint64_t UserHeap::request_virtual_pages(uint64_t count) -{ - uint64_t attempts = 0; -allocate: - uint64_t contiguous = 0; - uint64_t contiguous_start = 0; - for (uint64_t index = start_index; index < bitmap_size * 8; index++) - { - if (bitmap_read(index)) - { - contiguous = 0; - continue; - } - if (contiguous == 0) - { - contiguous_start = index; - contiguous++; - } - else - contiguous++; - if (contiguous == count) - { - for (uint64_t i = 0; i < count; i++) bitmap_set(contiguous_start + i, true); - return ALLOC_BASE + (contiguous_start * PAGE_SIZE); - } - } - - if (attempts == 0 && try_expand_size(Utilities::get_blocks_from_size(8, count) + 256)) - { - attempts++; - goto allocate; - } - - return 0; -} - -void UserHeap::free_virtual_page(uint64_t address) -{ - if (address < ALLOC_BASE || address >= (ALLOC_BASE + bitmap_size * 8 * PAGE_SIZE)) return; - uint64_t index = (address - ALLOC_BASE) / PAGE_SIZE; - bitmap_set(index, false); - if (start_index > index) start_index = index; -} - -void UserHeap::free_virtual_pages(uint64_t address, uint64_t count) -{ - if (address < ALLOC_BASE || address >= (ALLOC_BASE + bitmap_size * 8 * PAGE_SIZE)) return; - uint64_t index = (address - ALLOC_BASE) / PAGE_SIZE; - for (uint64_t i = 0; i < count; i++) { bitmap_set(index + i, false); } - if (start_index > index) start_index = index; -} \ No newline at end of file diff --git a/kernel/src/memory/VMM.cpp b/kernel/src/memory/VMM.cpp deleted file mode 100644 index b36c3b6a..00000000 --- a/kernel/src/memory/VMM.cpp +++ /dev/null @@ -1,362 +0,0 @@ -#define MODULE "vmm" - -#include "memory/VMM.h" -#include "log/Log.h" -#include "memory/PMM.h" -#include "misc/utils.h" -#include "std/ensure.h" -#include "std/string.h" -#include "utils/Addresses.h" -#include "utils/Registers.h" - -static PageTable* kernel_pml4; -static PageTable* current_pml4; -static AddressSpace* user_address_space; - -// FIXME: Switch to recursive paging instead of naively assuming the physical address space is identity mapped. - -void VMM::switch_back_to_kernel_address_space() -{ - if (current_pml4 != kernel_pml4) { current_pml4 = kernel_pml4; } -} - -void VMM::switch_to_user_address_space(AddressSpace& space) -{ - user_address_space = &space; - current_pml4 = user_address_space->get_pml4(); -} - -void VMM::switch_to_previous_user_address_space() -{ - current_pml4 = user_address_space->get_pml4(); -} - -void VMM::enter_syscall_context() -{ - if (current_pml4 != kernel_pml4) - { - current_pml4 = kernel_pml4; - apply_address_space(); - switch_to_previous_user_address_space(); - } -} - -void VMM::exit_syscall_context() -{ - if (current_pml4 != user_address_space->get_pml4()) { switch_to_previous_user_address_space(); } - apply_address_space(); -} - -void VMM::apply_address_space() -{ - write_cr3(current_pml4); -} - -bool VMM::is_using_kernel_address_space() -{ - return current_pml4 == kernel_pml4; -} - -void VMM::init() -{ - kernel_pml4 = (PageTable*)read_cr3(); - current_pml4 = kernel_pml4; - - // Set up recursive paging - PageDirectoryEntry& recursive_pde = kernel_pml4->entries[510]; - memset(&recursive_pde, 0, sizeof(PageDirectoryEntry)); - recursive_pde.present = true; - recursive_pde.read_write = true; - recursive_pde.larger_pages = false; - recursive_pde.no_execute = true; - recursive_pde.set_address((uint64_t)kernel_pml4); - flush_tlb_full(); -} - -void VMM::unmap(uint64_t vaddr) -{ - vaddr = round_down_to_nearest_page(vaddr); - - PageDirectoryEntry* pde = find_pde(current_pml4, vaddr); - if (!pde) return; // Already unmapped - - memset(pde, 0, sizeof(PageDirectoryEntry)); - flush_tlb(vaddr); -} - -void VMM::remap(uint64_t vaddr, int flags) -{ - vaddr = round_down_to_nearest_page(vaddr); - - PageDirectoryEntry* pde = find_pde(current_pml4, vaddr); - if (!pde) return; // Not mapped - - if (flags & User) propagate_user(current_pml4, vaddr); - else - pde->user = false; - if (flags & ReadWrite) propagate_read_write(current_pml4, vaddr); - else - pde->read_write = false; - if (flags & Execute) pde->no_execute = false; - else - pde->no_execute = true; - if (flags & OwnedByTask) pde->owned_by_task = true; - else - pde->owned_by_task = false; - flush_tlb(vaddr); -} - -uint64_t VMM::get_physical(uint64_t vaddr) -{ - PageDirectoryEntry* pde = find_pde(current_pml4, round_down_to_nearest_page(vaddr)); - if (!pde) return UINT64_MAX; // Not mapped - - return pde->get_address() | (vaddr % PAGE_SIZE); -} - -uint64_t VMM::get_flags(uint64_t vaddr) -{ - PageDirectoryEntry* pde = find_pde(current_pml4, round_down_to_nearest_page(vaddr)); - if (!pde) return (uint64_t)-1; // Not mapped - - uint64_t flags = 0; - if (pde->user) flags |= User; - if (pde->read_write) flags |= ReadWrite; - if (!pde->no_execute) flags |= Execute; - if (pde->owned_by_task) flags |= OwnedByTask; - return flags; -} - -void VMM::map(uint64_t vaddr, uint64_t paddr, int flags) -{ - vaddr = round_down_to_nearest_page(vaddr); - PageDirectoryEntry* pde = find_pde(current_pml4, vaddr); - bool will_flush_tlb = true; - if (!pde) - { - pde = create_pde_if_not_exists(current_pml4, vaddr); - will_flush_tlb = false; - } - else if (pde->larger_pages) - { - unmap(vaddr); - pde = create_pde_if_not_exists(current_pml4, vaddr); - will_flush_tlb = false; // unmap() already flushes the TLB for us - } - - pde->set_address(round_down_to_nearest_page(paddr)); - if (flags & User) propagate_user(current_pml4, vaddr); - else - pde->user = false; - if (flags & ReadWrite) propagate_read_write(current_pml4, vaddr); - else - pde->read_write = false; - if (flags & Execute) pde->no_execute = false; - else - pde->no_execute = true; - if (flags & OwnedByTask) pde->owned_by_task = true; - else - pde->owned_by_task = false; - if (will_flush_tlb) flush_tlb(vaddr); -} - -PageDirectoryEntry* VMM::find_pde(PageTable* root, uint64_t vaddr) -{ - uint64_t page_index; - PageDirectoryEntry* pde; - PageTable* pt = root; - - uint64_t indexes[3]; - - decompose_vaddr(vaddr, page_index, indexes[2], indexes[1], indexes[0]); - - for (int i = 0; i < 3; - i++) // Walk through the page map level 4, page directory pointer, and page directory to find the page table. - { - pde = &pt->entries[indexes[i]]; - if (!pde->present) return nullptr; - else if (pde->larger_pages) - return pde; - else { pt = (PageTable*)pde->get_address(); } - } - - pde = &pt->entries[page_index]; // PT - if (!pde->present) return nullptr; - return pde; -} - -PageDirectoryEntry* VMM::create_pde_if_not_exists(PageTable* root, uint64_t vaddr) -{ - uint64_t page_index; - PageDirectoryEntry* pde; - PageTable* pt = root; - - uint64_t indexes[3]; - - decompose_vaddr(vaddr, page_index, indexes[2], indexes[1], indexes[0]); - - auto pde_create_if_not_present = [&]() { - auto pt_or_error = PMM::request_page(); - ensure(pt_or_error.has_value()); - pt = (PageTable*)pt_or_error.release_value(); - memset(pt, 0, PAGE_SIZE); - pde->set_address((uint64_t)pt); - pde->present = true; - }; - - for (int i = 0; i < 3; i++) - { - pde = &pt->entries[indexes[i]]; - if (!pde->present) { pde_create_if_not_present(); } - else if (pde->larger_pages) - return pde; - else { pt = (PageTable*)pde->get_address(); } - } - - pde = &pt->entries[page_index]; - if (!pde->present) { pde->present = true; } - return pde; -} - -void VMM::propagate_read_write(PageTable* root, uint64_t vaddr) -{ - uint64_t page_index; - PageDirectoryEntry* pde; - PageTable* pt = root; - - uint64_t indexes[3]; - - decompose_vaddr(vaddr, page_index, indexes[2], indexes[1], indexes[0]); - - for (int i = 0; i < 3; i++) - { - pde = &pt->entries[indexes[i]]; - if (!pde->present) return; - else - { - pde->read_write = true; - if (pde->larger_pages) return; - pt = (PageTable*)pde->get_address(); - } - } - - pde = &pt->entries[page_index]; - if (!pde->present) return; - else - pde->read_write = true; -} - -void VMM::propagate_user(PageTable* root, uint64_t vaddr) -{ - uint64_t page_index; - PageDirectoryEntry* pde; - PageTable* pt = root; - - uint64_t indexes[3]; - - decompose_vaddr(vaddr, page_index, indexes[2], indexes[1], indexes[0]); - - for (int i = 0; i < 3; i++) - { - pde = &pt->entries[indexes[i]]; - if (!pde->present) return; - else - { - pde->user = true; - if (pde->larger_pages) return; - pt = (PageTable*)pde->get_address(); - } - } - - pde = &pt->entries[page_index]; - if (!pde->present) return; - else - pde->user = true; -} - -void VMM::propagate_no_execute(PageTable* root, uint64_t vaddr) -{ - uint64_t page_index; - PageDirectoryEntry* pde; - PageTable* pt = root; - - uint64_t indexes[3]; - - decompose_vaddr(vaddr, page_index, indexes[2], indexes[1], indexes[0]); - - for (int i = 0; i < 3; i++) - { - pde = &pt->entries[indexes[i]]; - if (!pde->present) return; - else - { - pde->no_execute = true; - if (pde->larger_pages) return; - pt = (PageTable*)pde->get_address(); - } - } - - pde = &pt->entries[page_index]; - if (!pde->present) return; - else - pde->no_execute = true; -} - -void VMM::flush_tlb(uint64_t addr) -{ - asm volatile("invlpg (%0)" : : "r"(addr) : "memory"); -} - -void VMM::flush_tlb_full() -{ - write_cr3(current_pml4); -} - -void VMM::decompose_vaddr(uint64_t vaddr, uint64_t& page_index, uint64_t& pt_index, uint64_t& pd_index, - uint64_t& pdp_index) -{ - vaddr >>= 12; - page_index = vaddr & 0x1ff; - vaddr >>= 9; - pt_index = vaddr & 0x1ff; - vaddr >>= 9; - pd_index = vaddr & 0x1ff; - vaddr >>= 9; - pdp_index = vaddr & 0x1ff; -} - -uint64_t VMM::recompose_vaddr(uint64_t page_index, uint64_t pt_index, uint64_t pd_index, uint64_t pdp_index) -{ - return pdp_index << 39 | pd_index << 30 | pt_index << 21 | page_index << 12; -} - -void VMM::install_kernel_page_directory_into_address_space(AddressSpace& space) -{ - PageTable* space_pml4 = space.get_pml4(); - PageTable* kernel_last_pdp = (PageTable*)kernel_pml4->entries[511].get_address(); - PageTable* kernel_last_pd = (PageTable*)kernel_last_pdp->entries[511].get_address(); - - PageDirectoryEntry& space_last_pdp_pde = space_pml4->entries[511]; - - PageTable* space_last_pdp; - - if (!space_last_pdp_pde.present) - { - auto result = PMM::request_page(); - ensure(result.has_value()); // FIXME: Propagate this error. - space_last_pdp = (PageTable*)result.release_value(); - - memset(space_last_pdp, 0, PAGE_SIZE); - - space_last_pdp_pde.present = true; - space_last_pdp_pde.read_write = true; - space_last_pdp_pde.set_address((uint64_t)space_last_pdp); - } - else { space_last_pdp = (PageTable*)space_last_pdp_pde.get_address(); } - - PageDirectoryEntry& space_last_pd_pde = space_last_pdp->entries[511]; - - space_last_pd_pde.present = true; - space_last_pd_pde.read_write = true; - space_last_pd_pde.set_address((uint64_t)kernel_last_pd); -} \ No newline at end of file diff --git a/kernel/src/memory/liballoc/bindings.cpp b/kernel/src/memory/liballoc/bindings.cpp deleted file mode 100644 index 91b53e54..00000000 --- a/kernel/src/memory/liballoc/bindings.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "memory/MemoryManager.h" -#include "thread/Spinlock.h" - -#include - -Spinlock alloc_lock; - -extern "C" int liballoc_lock() -{ - alloc_lock.acquire(); - return !alloc_lock.locked(); // Sanity check: the spinlock should be locked (return 0) -} - -extern "C" int liballoc_unlock() -{ - alloc_lock.release(); - return 0; // No sanity check this time because another thread could have acquired the lock the instant we let go of - // it. -} - -extern "C" void* liballoc_alloc(size_t count) -{ - return MemoryManager::get_pages(count).value_or(nullptr); -} - -extern "C" int liballoc_free(void* addr, size_t count) -{ - MemoryManager::release_pages(addr, count); - return 0; -} \ No newline at end of file diff --git a/kernel/src/memory/liballoc/liballoc.c b/kernel/src/memory/liballoc/liballoc.c deleted file mode 100644 index 6cc26933..00000000 --- a/kernel/src/memory/liballoc/liballoc.c +++ /dev/null @@ -1,721 +0,0 @@ -#define MODULE "alloc" - -#include "memory/liballoc/liballoc.h" -#include "log/CLog.h" - -#include - -#pragma GCC push_options -#pragma GCC diagnostic ignored "-Wconversion" -#pragma GCC diagnostic ignored "-Wsign-conversion" // FIXME: Actually solve these warnings. - -/** Durand's Amazing Super Duper Memory functions. */ - -#define VERSION "1.1" -#define ALIGNMENT \ - 16ul // 4ul ///< This is the byte alignment that memory must be allocated on. IMPORTANT for GTK and - // other stuff. - -#define ALIGN_TYPE char /// unsigned char[16] /// unsigned short -#define ALIGN_INFO \ - sizeof(ALIGN_TYPE) * 16 ///< Alignment information is stored right before the pointer. This is the number of bytes - ///< of information stored there. - -#define USE_CASE1 -#define USE_CASE2 -#define USE_CASE3 -#define USE_CASE4 -#define USE_CASE5 - -/** This macro will conveniently align our pointer upwards */ -#define ALIGN(ptr) \ - if (ALIGNMENT > 1) \ - { \ - uintptr_t align_diff; \ - ptr = (void*)((uintptr_t)ptr + ALIGN_INFO); \ - align_diff = (uintptr_t)ptr & (ALIGNMENT - 1); \ - if (align_diff != 0) \ - { \ - align_diff = ALIGNMENT - align_diff; \ - ptr = (void*)((uintptr_t)ptr + align_diff); \ - } \ - *((ALIGN_TYPE*)((uintptr_t)ptr - ALIGN_INFO)) = align_diff + ALIGN_INFO; \ - } - -#define UNALIGN(ptr) \ - if (ALIGNMENT > 1) \ - { \ - uintptr_t align_diff = *((ALIGN_TYPE*)((uintptr_t)ptr - ALIGN_INFO)); \ - if (align_diff < (ALIGNMENT + ALIGN_INFO)) { ptr = (void*)((uintptr_t)ptr - align_diff); } \ - } - -#define LIBALLOC_MAGIC 0xc001c0de -#define LIBALLOC_DEAD 0xdeaddead - -#if defined DEBUG || defined INFO -#include -#include - -#define FLUSH() - -#endif - -/** A structure found at the top of all system allocated - * memory blocks. It details the usage of the memory block. - */ -struct liballoc_major -{ - struct liballoc_major* prev; ///< Linked list information. - struct liballoc_major* next; ///< Linked list information. - unsigned int pages; ///< The number of pages in the block. - unsigned int size; ///< The number of pages in the block. - unsigned int usage; ///< The number of bytes used in the block. - struct liballoc_minor* first; ///< A pointer to the first allocated memory in the block. -}; - -/** This is a structure found at the beginning of all - * sections in a major block which were allocated by a - * malloc, calloc, realloc call. - */ -struct liballoc_minor -{ - struct liballoc_minor* prev; ///< Linked list information. - struct liballoc_minor* next; ///< Linked list information. - struct liballoc_major* block; ///< The owning block. A pointer to the major structure. - unsigned int magic; ///< A magic number to idenfity correctness. - unsigned int size; ///< The size of the memory allocated. Could be 1 byte or more. - unsigned int req_size; ///< The size of memory requested. -}; - -static struct liballoc_major* l_memRoot = NULL; ///< The root memory block acquired from the system. -static struct liballoc_major* l_bestBet = NULL; ///< The major with the most free memory. - -static unsigned int l_pageSize = 4096; ///< The size of an individual page. Set up in liballoc_init. -static unsigned int l_pageCount = 16; ///< The number of pages to request per chunk. Set up in liballoc_init. -static unsigned long long l_allocated = 0; ///< Running total of allocated memory. -static unsigned long long l_inuse = 0; ///< Running total of used memory. - -static long long l_warningCount = 0; ///< Number of warnings encountered -static long long l_errorCount = 0; ///< Number of actual errors -static long long l_possibleOverruns = 0; ///< Number of possible overruns - -// *********** HELPER FUNCTIONS ******************************* - -static void* liballoc_memset(void* s, int c, size_t n) -{ - unsigned int i; - for (i = 0; i < n; i++) ((char*)s)[i] = c; - - return s; -} -static void* liballoc_memcpy(void* s1, const void* s2, size_t n) -{ - char* cdest; - const char* csrc; - unsigned int* ldest = (unsigned int*)s1; - const unsigned int* lsrc = (const unsigned int*)s2; - - while (n >= sizeof(unsigned int)) - { - *ldest++ = *lsrc++; - n -= sizeof(unsigned int); - } - - cdest = (char*)ldest; - csrc = (const char*)lsrc; - - while (n > 0) - { - *cdest++ = *csrc++; - n -= 1; - } - - return s1; -} - -#if defined DEBUG || defined INFO -static void liballoc_dump() -{ -#ifdef DEBUG - struct liballoc_major* maj = l_memRoot; - struct liballoc_minor* min = NULL; -#endif - - printf("liballoc: ------ Memory data ---------------\n"); - printf("liballoc: System memory allocated: %i bytes\n", l_allocated); - printf("liballoc: Memory in used (malloc'ed): %i bytes\n", l_inuse); - printf("liballoc: Warning count: %i\n", l_warningCount); - printf("liballoc: Error count: %i\n", l_errorCount); - printf("liballoc: Possible overruns: %i\n", l_possibleOverruns); - -#ifdef DEBUG - while (maj != NULL) - { - printf("liballoc: %x: total = %i, used = %i\n", maj, maj->size, maj->usage); - - min = maj->first; - while (min != NULL) - { - printf("liballoc: %x: %i bytes\n", min, min->size); - min = min->next; - } - - maj = maj->next; - } -#endif - - FLUSH(); -} -#endif - -// *************************************************************** - -static struct liballoc_major* allocate_new_page(unsigned int size) -{ - unsigned int st; - struct liballoc_major* maj; - - // This is how much space is required. - st = size + sizeof(struct liballoc_major); - st += sizeof(struct liballoc_minor); - - // Perfect amount of space? - if ((st % l_pageSize) == 0) st = st / (l_pageSize); - else - st = st / (l_pageSize) + 1; - // No, add the buffer. - - // Make sure it's >= the minimum size. - if (st < l_pageCount) st = l_pageCount; - - maj = (struct liballoc_major*)liballoc_alloc(st); - - if (maj == NULL) - { - l_warningCount += 1; -#if defined DEBUG || defined INFO - printf("liballoc: WARNING: liballoc_alloc( %i ) return NULL\n", st); - FLUSH(); -#endif - return NULL; // uh oh, we ran out of memory. - } - - maj->prev = NULL; - maj->next = NULL; - maj->pages = st; - maj->size = st * l_pageSize; - maj->usage = sizeof(struct liballoc_major); - maj->first = NULL; - - l_allocated += maj->size; - -#ifdef DEBUG - printf("liballoc: Resource allocated %x of %i pages (%i bytes) for %i size.\n", maj, st, maj->size, size); - - printf("liballoc: Total memory usage = %i KB\n", (int)((l_allocated / (1024)))); - FLUSH(); -#endif - - return maj; -} - -void* PREFIX(malloc)(size_t req_size) -{ - int startedBet = 0; - unsigned long long bestSize = 0; - void* p = NULL; - uintptr_t diff; - struct liballoc_major* maj; - struct liballoc_minor* min; - struct liballoc_minor* new_min; - unsigned long size = req_size; - - // For alignment, we adjust size so there's enough space to align. - if (ALIGNMENT > 1) { size += ALIGNMENT + ALIGN_INFO; } - // So, ideally, we really want an alignment of 0 or 1 in order - // to save space. - - liballoc_lock(); - - if (size == 0) - { - l_warningCount += 1; -#if defined DEBUG || defined INFO - printf("liballoc: WARNING: alloc( 0 ) called from %x\n", __builtin_return_address(0)); - FLUSH(); -#endif - liballoc_unlock(); - return PREFIX(malloc)(1); - } - - if (l_memRoot == NULL) - { -#if defined DEBUG || defined INFO -#ifdef DEBUG - printf("liballoc: initialization of liballoc " VERSION "\n"); -#endif - atexit(liballoc_dump); - FLUSH(); -#endif - - // This is the first time we are being used. - l_memRoot = allocate_new_page(size); - if (l_memRoot == NULL) - { - liballoc_unlock(); -#ifdef DEBUG - printf("liballoc: initial l_memRoot initialization failed\n", p); - FLUSH(); -#endif - return NULL; - } - -#ifdef DEBUG - printf("liballoc: set up first memory major %x\n", l_memRoot); - FLUSH(); -#endif - } - -#ifdef DEBUG - printf("liballoc: %x PREFIX(malloc)( %i ): ", __builtin_return_address(0), size); - FLUSH(); -#endif - - // Now we need to bounce through every major and find enough space.... - - maj = l_memRoot; - startedBet = 0; - - // Start at the best bet.... - if (l_bestBet != NULL) - { - bestSize = l_bestBet->size - l_bestBet->usage; - - if (bestSize > (size + sizeof(struct liballoc_minor))) - { - maj = l_bestBet; - startedBet = 1; - } - } - - while (maj != NULL) - { - diff = maj->size - maj->usage; - // free memory in the block - - if (bestSize < diff) - { - // Hmm.. this one has more memory then our bestBet. Remember! - l_bestBet = maj; - bestSize = diff; - } - -#ifdef USE_CASE1 - - // CASE 1: There is not enough space in this major block. - if (diff < (size + sizeof(struct liballoc_minor))) - { -#ifdef DEBUG - printf("CASE 1: Insufficient space in block %x\n", maj); - FLUSH(); -#endif - - // Another major block next to this one? - if (maj->next != NULL) - { - maj = maj->next; // Hop to that one. - continue; - } - - if (startedBet == 1) // If we started at the best bet, - { // let's start all over again. - maj = l_memRoot; - startedBet = 0; - continue; - } - - // Create a new major block next to this one and... - maj->next = allocate_new_page(size); // next one will be okay. - if (maj->next == NULL) break; // no more memory. - maj->next->prev = maj; - maj = maj->next; - - // .. fall through to CASE 2 .. - } - -#endif - -#ifdef USE_CASE2 - - // CASE 2: It's a brand new block. - if (maj->first == NULL) - { - maj->first = (struct liballoc_minor*)((uintptr_t)maj + sizeof(struct liballoc_major)); - - maj->first->magic = LIBALLOC_MAGIC; - maj->first->prev = NULL; - maj->first->next = NULL; - maj->first->block = maj; - maj->first->size = size; - maj->first->req_size = req_size; - maj->usage += size + sizeof(struct liballoc_minor); - - l_inuse += size; - - p = (void*)((uintptr_t)(maj->first) + sizeof(struct liballoc_minor)); - - ALIGN(p); - -#ifdef DEBUG - printf("CASE 2: returning %x\n", p); - FLUSH(); -#endif - liballoc_unlock(); // release the lock - return p; - } - -#endif - -#ifdef USE_CASE3 - - // CASE 3: Block in use and enough space at the start of the block. - diff = (uintptr_t)(maj->first); - diff -= (uintptr_t)maj; - diff -= sizeof(struct liballoc_major); - - if (diff >= (size + sizeof(struct liballoc_minor))) - { - // Yes, space in front. Squeeze in. - maj->first->prev = (struct liballoc_minor*)((uintptr_t)maj + sizeof(struct liballoc_major)); - maj->first->prev->next = maj->first; - maj->first = maj->first->prev; - - maj->first->magic = LIBALLOC_MAGIC; - maj->first->prev = NULL; - maj->first->block = maj; - maj->first->size = size; - maj->first->req_size = req_size; - maj->usage += size + sizeof(struct liballoc_minor); - - l_inuse += size; - - p = (void*)((uintptr_t)(maj->first) + sizeof(struct liballoc_minor)); - ALIGN(p); - -#ifdef DEBUG - printf("CASE 3: returning %x\n", p); - FLUSH(); -#endif - liballoc_unlock(); // release the lock - return p; - } - -#endif - -#ifdef USE_CASE4 - - // CASE 4: There is enough space in this block. But is it contiguous? - min = maj->first; - - // Looping within the block now... - while (min != NULL) - { - // CASE 4.1: End of minors in a block. Space from last and end? - if (min->next == NULL) - { - // the rest of this block is free... is it big enough? - diff = (uintptr_t)(maj) + maj->size; - diff -= (uintptr_t)min; - diff -= sizeof(struct liballoc_minor); - diff -= min->size; - // minus already existing usage.. - - if (diff >= (size + sizeof(struct liballoc_minor))) - { - // yay.... - min->next = (struct liballoc_minor*)((uintptr_t)min + sizeof(struct liballoc_minor) + min->size); - min->next->prev = min; - min = min->next; - min->next = NULL; - min->magic = LIBALLOC_MAGIC; - min->block = maj; - min->size = size; - min->req_size = req_size; - maj->usage += size + sizeof(struct liballoc_minor); - - l_inuse += size; - - p = (void*)((uintptr_t)min + sizeof(struct liballoc_minor)); - ALIGN(p); - -#ifdef DEBUG - printf("CASE 4.1: returning %x\n", p); - FLUSH(); -#endif - liballoc_unlock(); // release the lock - return p; - } - } - - // CASE 4.2: Is there space between two minors? - if (min->next != NULL) - { - // is the difference between here and next big enough? - diff = (uintptr_t)(min->next); - diff -= (uintptr_t)min; - diff -= sizeof(struct liballoc_minor); - diff -= min->size; - // minus our existing usage. - - if (diff >= (size + sizeof(struct liballoc_minor))) - { - // yay...... - new_min = (struct liballoc_minor*)((uintptr_t)min + sizeof(struct liballoc_minor) + min->size); - - new_min->magic = LIBALLOC_MAGIC; - new_min->next = min->next; - new_min->prev = min; - new_min->size = size; - new_min->req_size = req_size; - new_min->block = maj; - min->next->prev = new_min; - min->next = new_min; - maj->usage += size + sizeof(struct liballoc_minor); - - l_inuse += size; - - p = (void*)((uintptr_t)new_min + sizeof(struct liballoc_minor)); - ALIGN(p); - -#ifdef DEBUG - printf("CASE 4.2: returning %x\n", p); - FLUSH(); -#endif - - liballoc_unlock(); // release the lock - return p; - } - } // min->next != NULL - - min = min->next; - } // while min != NULL ... - -#endif - -#ifdef USE_CASE5 - - // CASE 5: Block full! Ensure next block and loop. - if (maj->next == NULL) - { -#ifdef DEBUG - printf("CASE 5: block full\n"); - FLUSH(); -#endif - - if (startedBet == 1) - { - maj = l_memRoot; - startedBet = 0; - continue; - } - - // we've run out. we need more... - maj->next = allocate_new_page(size); // next one guaranteed to be okay - if (maj->next == NULL) break; // uh oh, no more memory..... - maj->next->prev = maj; - } - -#endif - - maj = maj->next; - } // while (maj != NULL) - - liballoc_unlock(); // release the lock - -#ifdef DEBUG - printf("All cases exhausted. No memory available.\n"); - FLUSH(); -#endif -#if defined DEBUG || defined INFO - printf("liballoc: WARNING: PREFIX(malloc)( %i ) returning NULL.\n", size); - liballoc_dump(); - FLUSH(); -#endif - return NULL; -} - -void PREFIX(free)(void* ptr) -{ - struct liballoc_minor* min; - struct liballoc_major* maj; - - if (ptr == NULL) - { - l_warningCount += 1; - kwarnln("kfree( NULL ) called from %p", __builtin_return_address(0)); - return; - } - - UNALIGN(ptr); - - liballoc_lock(); // lockit - - min = (struct liballoc_minor*)((uintptr_t)ptr - sizeof(struct liballoc_minor)); - - if (min->magic != LIBALLOC_MAGIC) - { - l_errorCount += 1; - - // Check for overrun errors. For all bytes of LIBALLOC_MAGIC - if (((min->magic & 0xFFFFFF) == (LIBALLOC_MAGIC & 0xFFFFFF)) || - ((min->magic & 0xFFFF) == (LIBALLOC_MAGIC & 0xFFFF)) || ((min->magic & 0xFF) == (LIBALLOC_MAGIC & 0xFF))) - { - l_possibleOverruns += 1; - kerrorln("Possible 1-3 byte overrun for magic %x != %x", min->magic, LIBALLOC_MAGIC); - } - - if (min->magic == LIBALLOC_DEAD) - { - kerrorln("double free attempt on %p from %p.", ptr, __builtin_return_address(0)); - } - else { kerrorln("Bad kfree(%p) called from %p\n", ptr, __builtin_return_address(0)); } - - // being lied to... - liballoc_unlock(); // release the lock - return; - } - -#ifdef DEBUG - printf("liballoc: %x PREFIX(free)( %x ): ", __builtin_return_address(0), ptr); - FLUSH(); -#endif - - maj = min->block; - - l_inuse -= min->size; - - maj->usage -= (min->size + sizeof(struct liballoc_minor)); - min->magic = LIBALLOC_DEAD; // No mojo. - - if (min->next != NULL) min->next->prev = min->prev; - if (min->prev != NULL) min->prev->next = min->next; - - if (min->prev == NULL) maj->first = min->next; - // Might empty the block. This was the first - // minor. - - // We need to clean up after the majors now.... - - if (maj->first == NULL) // Block completely unused. - { - if (l_memRoot == maj) l_memRoot = maj->next; - if (l_bestBet == maj) l_bestBet = NULL; - if (maj->prev != NULL) maj->prev->next = maj->next; - if (maj->next != NULL) maj->next->prev = maj->prev; - l_allocated -= maj->size; - - liballoc_free(maj, maj->pages); - } - else - { - if (l_bestBet != NULL) - { - int bestSize = l_bestBet->size - l_bestBet->usage; - int majSize = maj->size - maj->usage; - - if (majSize > bestSize) l_bestBet = maj; - } - } - -#ifdef DEBUG - printf("OK\n"); - FLUSH(); -#endif - - liballoc_unlock(); // release the lock -} - -void* PREFIX(calloc)(size_t nobj, size_t size) -{ - int real_size; - void* p; - - real_size = nobj * size; - - p = PREFIX(malloc)(real_size); - - liballoc_memset(p, 0, real_size); - - return p; -} - -void* PREFIX(realloc)(void* p, size_t size) -{ - void* ptr; - struct liballoc_minor* min; - unsigned int real_size; - - // Honour the case of size == 0 => free old and return NULL - if (size == 0) - { - PREFIX(free)(p); - return NULL; - } - - // In the case of a NULL pointer, return a simple malloc. - if (p == NULL) return PREFIX(malloc)(size); - - // Unalign the pointer if required. - ptr = p; - UNALIGN(ptr); - - liballoc_lock(); // lockit - - min = (struct liballoc_minor*)((uintptr_t)ptr - sizeof(struct liballoc_minor)); - - // Ensure it is a valid structure. - if (min->magic != LIBALLOC_MAGIC) - { - l_errorCount += 1; - - // Check for overrun errors. For all bytes of LIBALLOC_MAGIC - if (((min->magic & 0xFFFFFF) == (LIBALLOC_MAGIC & 0xFFFFFF)) || - ((min->magic & 0xFFFF) == (LIBALLOC_MAGIC & 0xFFFF)) || ((min->magic & 0xFF) == (LIBALLOC_MAGIC & 0xFF))) - { - l_possibleOverruns += 1; - kerrorln("Possible 1-3 byte overrun for magic %x != %x", min->magic, LIBALLOC_MAGIC); - } - - if (min->magic == LIBALLOC_DEAD) - { - kerrorln("realloc after free attempt on %p from %p.", ptr, __builtin_return_address(0)); - } - else { kerrorln("Bad krealloc(%p) called from %p\n", ptr, __builtin_return_address(0)); } - - // being lied to... - liballoc_unlock(); // release the lock - return NULL; - } - - // Definitely a memory block. - - real_size = min->req_size; - - if (real_size >= size) - { - min->req_size = size; - liballoc_unlock(); - return p; - } - - liballoc_unlock(); - - // If we got here then we're reallocating to a block bigger than us. - ptr = PREFIX(malloc)(size); // We need to allocate new memory - liballoc_memcpy(ptr, p, real_size); - PREFIX(free)(p); - - return ptr; -} - -#pragma GCC pop_options diff --git a/kernel/src/misc/MSR.cpp b/kernel/src/misc/MSR.cpp deleted file mode 100644 index d38140bd..00000000 --- a/kernel/src/misc/MSR.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include "misc/MSR.h" - -void MSR::write_to(uint32_t msr_num, uint64_t value) -{ - uint32_t lo = value & 0xFFFFFFFF; - uint32_t hi = (uint32_t)(value >> 32); - asm volatile("wrmsr" : : "a"(lo), "d"(hi), "c"(msr_num)); -} - -uint64_t MSR::read_from(uint32_t msr_num) -{ - uint32_t lo; - uint32_t hi; - asm volatile("rdmsr" : "=a"(lo), "=d"(hi) : "c"(msr_num)); - return (uint64_t)hi << 32 | (uint64_t)lo; -} - -void MSR::write(uint64_t value) -{ - write_to(m_msr_num, value); -} - -uint64_t MSR::read() -{ - return read_from(m_msr_num); -} - -MSR::MSR(uint32_t msr_num) : m_msr_num(msr_num) -{ -} - -void MSR::with_value_of(uint32_t msr_num, void (*callback)(uint64_t&)) -{ - MSR msr(msr_num); - msr.with_value(callback); -} - -void MSR::with_value(void (*callback)(uint64_t&)) -{ - uint64_t value = read(); - callback(value); - write(value); -} \ No newline at end of file diff --git a/kernel/src/misc/PCITypes.cpp b/kernel/src/misc/PCITypes.cpp deleted file mode 100644 index d8a49c5e..00000000 --- a/kernel/src/misc/PCITypes.cpp +++ /dev/null @@ -1,85 +0,0 @@ -#include "misc/PCITypes.h" - -static const char* unclassified_device(PCI::DeviceType type) -{ - switch (type.dev_subclass) - { - case 0x0: return "Non-VGA-Compatible Unclassified Device"; - case 0x1: return "VGA-Compatible Unclassified Device"; - - default: return "Unclassified"; - } -} - -static const char* display_controller(PCI::DeviceType type) -{ - switch (type.dev_subclass) - { - case 0x0: return type.prog_if == 1 ? "8514-Compatible Controller" : "VGA Controller"; - case 0x1: return "XGA Controller"; - case 0x2: return "3D Controller (Not VGA-Compatible)"; - case 0x80: return "Display Controller"; - - default: return "Unknown Display Controller"; - } -} - -static const char* memory_controller(PCI::DeviceType type) -{ - switch (type.dev_subclass) - { - case 0x0: return "RAM Controller"; - case 0x1: return "Flash Controller"; - case 0x80: return "Memory Controller"; - - default: return "Unknown Memory Controller"; - } -} - -static const char* processor(PCI::DeviceType type) -{ - switch (type.dev_subclass) - { - case 0x0: return "Processor (386)"; - case 0x1: return "Processor (486)"; - case 0x2: return "Processor (Pentium)"; - case 0x3: return "Processor (Pentium Pro)"; - case 0x10: return "Processor (Alpha)"; - case 0x20: return "Processor (PowerPC)"; - case 0x30: return "Processor (MIPS)"; - case 0x40: return "Co-Processor"; - case 0x80: return "Processor"; - - default: return "Unknown Processor"; - } -} - -const char* pci_type_name(PCI::DeviceType type) -{ - switch (type.dev_class) - { - case 0x0: return unclassified_device(type); - case 0x1: return "Mass Storage Controller"; - case 0x2: return "Network Controller"; - case 0x3: return display_controller(type); - case 0x4: return "Multimedia Controller"; - case 0x5: return memory_controller(type); - case 0x6: return "Bridge"; - case 0x7: return "Simple Communication Controller"; - case 0x8: return "Base System Peripheral"; - case 0x9: return "Input Device Controller"; - case 0xA: return "Docking Station"; - case 0xB: return processor(type); - case 0xC: return "Serial Bus Controller"; - case 0xD: return "Wireless Controller"; - case 0xE: return "Intelligent Controller (I20)"; - case 0xF: return "Satellite Communication Controller"; - case 0x10: return "Encryption Controller"; - case 0x11: return "Signal Processing Controller"; - case 0x12: return "Processing Accelerator"; - case 0x13: return "Non-Essential Instrumentation"; - case 0x40: return "Co-Processor"; - - default: return "Unknown"; - } -} \ No newline at end of file diff --git a/kernel/src/misc/Scancodes.cpp b/kernel/src/misc/Scancodes.cpp deleted file mode 100644 index c694a4d5..00000000 --- a/kernel/src/misc/Scancodes.cpp +++ /dev/null @@ -1,168 +0,0 @@ -#include "misc/Scancodes.h" - -#define SCANCODE_EXTENDED 0xE0 - -bool scancode_filter_released(unsigned char* scancode) -{ - if (*scancode > 0x80) - { - *scancode -= 0x80; - return true; - } - return false; -} - -static bool next_key_ignored = false; // FIXME: Do not ignore extended scancodes. - -static bool left_shifted = false; -static bool right_shifted = false; -static bool capslock = false; - -static bool should_shift() -{ - if (capslock) return !(left_shifted || right_shifted); - return left_shifted || right_shifted; -} - -#define SCANCODE_LEFT_SHIFT 0x2A -#define SCANCODE_RIGHT_SHIFT 0x36 -#define SCANCODE_CAPS_LOCK 0x3A - -#define SCANCODE_LEFT_CONTROL 0x1D -#define SCANCODE_TAB 0x0F -#define SCANCODE_LEFT_ALT 0x38 -#define SCANCODE_F11 0x57 -#define SCANCODE_F12 0x58 - -static bool should_ignore_key(char scancode) -{ - return (scancode > 0x3A && scancode < 0x47) || scancode == SCANCODE_LEFT_CONTROL || scancode == SCANCODE_TAB || - scancode == SCANCODE_LEFT_ALT || scancode == SCANCODE_F11 || scancode == SCANCODE_F12; -} - -char keys_normal[] = { - '\0', - '\1', // escape - '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', - '\0', // tab - 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', - '\0', // left ctrl - 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', - '\0', // left shift - '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', - '\0', // right shift - '*', // keypad * - '\0', // left alt - ' ', - '\0', // caps lock - '\0', // f1 - '\0', // f2 - '\0', // f3 - '\0', // f4 - '\0', // f5 - '\0', // f6 - '\0', // f7 - '\0', // f8 - '\0', // f9 - '\0', // f10 - '\0', // num lock - '\0', // scroll lock - '7', // keypad 7 - '8', // keypad 8 - '9', // keypad 9 - '-', // keypad - - '4', // keypad 4 - '5', // keypad 5 - '6', // keypad 6 - '+', // keypad + - '1', // keypad 1 - '2', // keypad 2 - '3', // keypad 3 - '0', // keypad 0 - '.', // keypad . -}; - -char keys_shifted[] = { - '\0', - '\1', // escape - '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b', - '\0', // tab - 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n', - '\0', // left ctrl - 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', - '\0', // left shift - '|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', - '\0', // right shift - '*', // keypad * - '\0', // left alt - ' ', - '\0', // caps lock - '\0', // f1 - '\0', // f2 - '\0', // f3 - '\0', // f4 - '\0', // f5 - '\0', // f6 - '\0', // f7 - '\0', // f8 - '\0', // f9 - '\0', // f10 - '\0', // num lock - '\0', // scroll lock - '7', // keypad 7 - '8', // keypad 8 - '9', // keypad 9 - '-', // keypad - - '4', // keypad 4 - '5', // keypad 5 - '6', // keypad 6 - '+', // keypad + - '1', // keypad 1 - '2', // keypad 2 - '3', // keypad 3 - '0', // keypad 0 - '.', // keypad . -}; - -char translate_scancode(unsigned char scancode, bool* ignore) -{ - if (next_key_ignored) - { - next_key_ignored = false; - *ignore = true; - return 0; - } - if (scancode == SCANCODE_EXTENDED) - { - next_key_ignored = true; - *ignore = true; - return 0; - } - bool released = scancode_filter_released(&scancode); - if (scancode == SCANCODE_CAPS_LOCK) - { - if (!released) { capslock = !capslock; } - *ignore = true; - return 0; - } - if (scancode == SCANCODE_LEFT_SHIFT) - { - left_shifted = !released; - *ignore = true; - return 0; - } - if (scancode == SCANCODE_RIGHT_SHIFT) - { - right_shifted = !released; - *ignore = true; - return 0; - } - if (released || should_ignore_key(scancode)) - { - *ignore = true; - return 0; - } - *ignore = false; - if (should_shift()) { return keys_shifted[scancode]; } - return keys_normal[scancode]; -} \ No newline at end of file diff --git a/kernel/src/misc/config.cpp b/kernel/src/misc/config.cpp deleted file mode 100644 index 0e364f8f..00000000 --- a/kernel/src/misc/config.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "config.h" - -#define STRINGIZE(x) #x -#define STRINGIZE_VALUE_OF(x) STRINGIZE(x) - -#ifndef MOON_MAJOR -#define MOON_MAJOR 0 -#endif - -#ifndef MOON_MINOR -#define MOON_MINOR 15 -#endif - -#ifndef _MOON_SUFFIX -#define MOON_SUFFIX "" -#else -#define MOON_SUFFIX STRINGIZE_VALUE_OF(_MOON_SUFFIX) -#endif - -int __moon_version_major() -{ - return MOON_MAJOR; -} - -int __moon_version_minor() -{ - return MOON_MINOR; -} - -const char* __moon_version_suffix() -{ - return MOON_SUFFIX; -} - -const char* moon_version() -{ - return STRINGIZE_VALUE_OF(MOON_MAJOR) "." STRINGIZE_VALUE_OF(MOON_MINOR) MOON_SUFFIX; -} diff --git a/kernel/src/misc/cxxabi.cpp b/kernel/src/misc/cxxabi.cpp deleted file mode 100644 index 48898377..00000000 --- a/kernel/src/misc/cxxabi.cpp +++ /dev/null @@ -1,52 +0,0 @@ -typedef void* (*cxa_atexit_func_t)(void*); - -struct cxa_atexit_entry -{ - cxa_atexit_func_t function; - void* argument; - void* dso_handle; -}; - -#define CXA_ATEXIT_MAX 64 - -int cxa_atexit_entry_count = 0; - -cxa_atexit_entry cxa_atexit_entries[CXA_ATEXIT_MAX]; - -__attribute__((visibility("hidden"))) void* __dso_handle = 0; - -extern "C" -{ - int __cxa_atexit(cxa_atexit_func_t func, void* arg, void* dso) - { - if (cxa_atexit_entry_count >= CXA_ATEXIT_MAX) return -1; - cxa_atexit_entries[cxa_atexit_entry_count].function = func; - cxa_atexit_entries[cxa_atexit_entry_count].argument = arg; - cxa_atexit_entries[cxa_atexit_entry_count].dso_handle = dso; - cxa_atexit_entry_count++; - return 0; - } - - void __cxa_finalize(void* f) - { - int i = cxa_atexit_entry_count; - if (!f) - { - while (i--) - { - if (cxa_atexit_entries[i].function) { cxa_atexit_entries[i].function(cxa_atexit_entries[i].argument); } - } - } - else - { - while (i--) - { - if (cxa_atexit_entries[i].function == (cxa_atexit_func_t)f) - { - cxa_atexit_entries[i].function(cxa_atexit_entries[i].argument); - cxa_atexit_entries[i].function = 0; - } - } - } - } -} \ No newline at end of file diff --git a/kernel/src/misc/hang.cpp b/kernel/src/misc/hang.cpp deleted file mode 100644 index e655f0c5..00000000 --- a/kernel/src/misc/hang.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "misc/hang.h" - -[[noreturn]] void hang() -{ - asm volatile("cli"); -end: - halt(); - goto end; -} - -void halt() -{ - asm volatile("hlt"); -} \ No newline at end of file diff --git a/kernel/src/misc/new.cpp b/kernel/src/misc/new.cpp deleted file mode 100644 index 8ecd8175..00000000 --- a/kernel/src/misc/new.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "std/stdlib.h" -#include - -void* operator new(size_t size) -{ - return kmalloc(size); -} - -void* operator new[](size_t size) -{ - return kmalloc(size); -} - -void operator delete(void* p) -{ - kfree(p); -} - -void operator delete[](void* p) -{ - kfree(p); -} - -void operator delete(void* p, size_t) -{ - kfree(p); -} - -void operator delete[](void* p, size_t) -{ - kfree(p); -} \ No newline at end of file diff --git a/kernel/src/misc/reboot.cpp b/kernel/src/misc/reboot.cpp deleted file mode 100644 index 8f134556..00000000 --- a/kernel/src/misc/reboot.cpp +++ /dev/null @@ -1,102 +0,0 @@ -#define MODULE "power" - -#include "misc/reboot.h" -#include "acpi/FADT.h" -#include "acpi/RSDT.h" -#include "assert.h" -#include "interrupts/IDT.h" -#include "interrupts/Interrupts.h" -#include "io/IO.h" -#include "log/Log.h" -#include "memory/VMM.h" -#include "misc/hang.h" -#include "std/string.h" - -static void try_acpi_reboot() -{ - kdbgln("Fetching pointer to RSDT/XSDT"); - ACPI::SDTHeader* rootSDT = ACPI::get_rsdt_or_xsdt(); - if (!rootSDT) - { - kwarnln("The pointer to the RSDT/XSDT is null"); - return; - } - if (!ACPI::validate_rsdt_or_xsdt(rootSDT)) - { - kwarnln("The RSDT/XSDT is invalid"); - return; - } - kdbgln("Searching for the FADT"); - ACPI::FADT* fadt = (ACPI::FADT*)ACPI::find_table(rootSDT, "FACP"); - if (!fadt) - { - kwarnln("Unable to find the FADT"); - return; - } - if (fadt->header.Revision < 2) - { - kwarnln("ACPI revision is too low (%d), ACPI Reset is only implemented in ACPI 2.0+", fadt->header.Revision); - return; - } - if (!(fadt->Flags & 1 << 10)) - { - kwarnln("This system does not support ACPI Reset"); - return; - } - switch (fadt->ResetReg.AddressSpace) - { - case ACPI::SystemIO: - kdbgln("Attempting ACPI Reset via SystemIO: sending byte %d to port %lx", fadt->ResetValue, - fadt->ResetReg.Address); - IO::outb((uint16_t)fadt->ResetReg.Address, fadt->ResetValue); - break; - case ACPI::GeneralPurposeIO: - kdbgln("Attempting ACPI Reset via GeneralPurposeIO: sending byte %d to port %lx", fadt->ResetValue, - fadt->ResetReg.Address); - IO::outb((uint16_t)fadt->ResetReg.Address, fadt->ResetValue); - break; - default: kwarnln("This method of rebooting via ACPI is not yet implemented"); return; - } - kerrorln("Tried to reboot, but apparently did nothing"); -} - -static void try_kbd_reboot() -{ - Interrupts::disable(); - - uint8_t temp; - do { - temp = IO::inb(0x64); - if (temp & 0b1) IO::inb(0x60); - } while (temp & 0b10); - - IO::outb(0x64, 0xFE); -} - -static void try_idt_triple_fault() -{ - IDTR idtr; - idtr.limit = 0x0000; - idtr.offset = 0x0000; - asm volatile("lidt %0" : : "m"(idtr)); - Interrupts::enable(); - asm volatile("int $0x80"); -} - -[[noreturn]] void reboot() -{ - Interrupts::disable(); - if (!VMM::is_using_kernel_address_space()) - { - VMM::switch_back_to_kernel_address_space(); - VMM::apply_address_space(); - } - kinfoln("Attempting reboot using ACPI"); - try_acpi_reboot(); - kinfoln("Attempting reboot using keyboard RESET pulsing"); - try_kbd_reboot(); - kinfoln("Attempting reboot by triple faulting"); - try_idt_triple_fault(); - kerrorln("Failed to reboot, halting machine"); - hang(); -} \ No newline at end of file diff --git a/kernel/src/misc/shutdown.cpp b/kernel/src/misc/shutdown.cpp deleted file mode 100644 index 3087ab1a..00000000 --- a/kernel/src/misc/shutdown.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#define MODULE "power" - -#include "misc/shutdown.h" -#include "interrupts/Interrupts.h" -#include "io/IO.h" -#include "log/Log.h" -#include "misc/hang.h" - -[[noreturn]] void shutdown() -{ - Interrupts::disable(); - kinfoln("Attempting shutdown using the Bochs method"); - IO::outw(0xB004, 0x2000); - kinfoln("Attempting shutdown using the QEMU method"); - IO::outw(0x604, 0x2000); - kinfoln("Attempting shutdown using the VirtualBox method"); - IO::outw(0x4004, 0x3400); - kerrorln("Failed to shutdown, halting. It is now safe to turn off your computer manually, though."); - hang(); -} \ No newline at end of file diff --git a/kernel/src/misc/stack.cpp b/kernel/src/misc/stack.cpp deleted file mode 100644 index 781b9f29..00000000 --- a/kernel/src/misc/stack.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#define MODULE "stack" - -#include "log/Log.h" -#include "misc/hang.h" -#include "render/TextRenderer.h" -#include - -extern "C" void __stack_chk_fail() -{ - KernelLog::enable_log_backend(Backend::Console); - TextRenderer::reset(); - kerrorln("stack smashing detected"); - hang(); -} \ No newline at end of file diff --git a/kernel/src/misc/ubsan.cpp b/kernel/src/misc/ubsan.cpp deleted file mode 100644 index d9394956..00000000 --- a/kernel/src/misc/ubsan.cpp +++ /dev/null @@ -1,205 +0,0 @@ -#define MODULE "ubsan" - -#include -#include -#include - -#pragma GCC push_options -#pragma GCC diagnostic ignored "-Wpedantic" - -struct source_location -{ - const char* file; - uint32_t line; - uint32_t column; -}; - -struct type_descriptor -{ - uint16_t kind; - uint16_t info; - char name[]; -}; - -struct type_mismatch_info -{ - struct source_location location; - struct type_descriptor* type; - uintptr_t alignment; - uint8_t type_check_kind; -}; - -struct type_mismatch_info_v1 -{ - struct source_location location; - struct type_descriptor* type; - unsigned char log_alignment; - unsigned char type_check_kind; -}; - -struct overflow_info -{ - struct source_location location; - struct type_descriptor* type; -}; - -struct unreachable_info -{ - struct source_location location; -}; - -struct out_of_bounds_info -{ - struct source_location location; - struct type_descriptor* array_type; - struct type_descriptor* index_type; -}; - -struct invalid_value_info -{ - struct source_location location; - struct type_descriptor* type; -}; - -struct shift_out_of_bounds_info -{ - struct source_location location; - struct type_descriptor* lhs_type; - struct type_descriptor* rhs_type; -}; - -struct pointer_overflow_info -{ - struct source_location location; -}; - -#define is_aligned(value, alignment) !(value & (alignment - 1)) - -const char* Type_Check_Kinds[] = { - "load of", - "store to", - "reference binding to", - "member access within", - "member call on", - "constructor call on", - "downcast of", - "downcast of", - "upcast of", - "cast to virtual base of", -}; - -static void log_location(source_location* location) -{ - kinfoln("at %s:%d:%d", location->file, location->line, location->column); -} - -extern "C" void __ubsan_handle_type_mismatch(type_mismatch_info* type_mismatch, uintptr_t pointer) -{ - source_location* location = &type_mismatch->location; - if (pointer == 0) { kinfoln("Null pointer access"); } - else if (type_mismatch->alignment != 0 && is_aligned(pointer, type_mismatch->alignment)) - { - // Most useful on architectures with stricter memory alignment requirements, like ARM. - kinfoln("Unaligned memory access"); - } - else - { - kinfoln("Insufficient size"); - kinfoln("%s address %p with insufficient space for object of type %s\n", - Type_Check_Kinds[type_mismatch->type_check_kind], (void*)pointer, type_mismatch->type->name); - } - log_location(location); - panic("Undefined behaviour detected"); -} - -extern "C" void __ubsan_handle_type_mismatch_v1(type_mismatch_info_v1* type_mismatch, unsigned long pointer) -{ - type_mismatch_info info = {type_mismatch->location, type_mismatch->type, 1UL << type_mismatch->log_alignment, - type_mismatch->type_check_kind}; - - __ubsan_handle_type_mismatch(&info, pointer); -} - -extern "C" void __ubsan_handle_add_overflow(overflow_info* overflow_data, uintptr_t, uintptr_t) -{ - source_location* location = &overflow_data->location; - kinfoln("Addition overflow for two values of type %s", overflow_data->type->name); - log_location(location); - panic("Undefined behaviour detected"); -} - -extern "C" void __ubsan_handle_sub_overflow(overflow_info* overflow_data, uintptr_t, uintptr_t) -{ - source_location* location = &overflow_data->location; - kinfoln("Substraction overflow for two values of type %s", overflow_data->type->name); - log_location(location); - panic("Undefined behaviour detected"); -} - -extern "C" void __ubsan_handle_mul_overflow(overflow_info* overflow_data, uintptr_t, uintptr_t) -{ - source_location* location = &overflow_data->location; - kinfoln("Multiplication overflow for two values of type %s", overflow_data->type->name); - log_location(location); - panic("Undefined behaviour detected"); -} - -extern "C" void __ubsan_handle_negate_overflow(overflow_info* overflow_data, uintptr_t) -{ - source_location* location = &overflow_data->location; - kinfoln("Negation overflow for two values of type %s", overflow_data->type->name); - log_location(location); - panic("Undefined behaviour detected"); -} - -extern "C" void __ubsan_handle_divrem_overflow(overflow_info* overflow_data, uintptr_t, uintptr_t) -{ - source_location* location = &overflow_data->location; - kinfoln("Division overflow for two values of type %s", overflow_data->type->name); - log_location(location); - panic("Undefined behaviour detected"); -} - -extern "C" void __ubsan_handle_builtin_unreachable(unreachable_info* unreachable_data) -{ - source_location* location = &unreachable_data->location; - kinfoln("Reached the unreachable"); - log_location(location); - panic("Undefined behaviour detected"); -} - -extern "C" void __ubsan_handle_out_of_bounds(out_of_bounds_info* out_of_bounds_data, uintptr_t index) -{ - source_location* location = &out_of_bounds_data->location; - kinfoln("Out of bounds access at index %ld of array type %s and index type %s", index, - out_of_bounds_data->array_type->name, out_of_bounds_data->index_type->name); - log_location(location); - panic("Undefined behaviour detected"); -} - -extern "C" void __ubsan_handle_load_invalid_value(invalid_value_info* invalid_value_data, uintptr_t) -{ - source_location* location = &invalid_value_data->location; - kinfoln("Invalid value load of type %s", invalid_value_data->type->name); - log_location(location); - panic("Undefined behaviour detected"); -} - -extern "C" void __ubsan_handle_shift_out_of_bounds(shift_out_of_bounds_info* shift_out_of_bounds_data, uintptr_t, - uintptr_t) -{ - source_location* location = &shift_out_of_bounds_data->location; - kinfoln("Shift out of bounds for type %s", shift_out_of_bounds_data->lhs_type->name); - log_location(location); - panic("Undefined behaviour detected"); -} - -extern "C" void __ubsan_handle_pointer_overflow(pointer_overflow_info* pointer_overflow_data, uintptr_t, uintptr_t) -{ - source_location* location = &pointer_overflow_data->location; - kinfoln("Pointer overflow"); - log_location(location); - panic("Undefined behaviour detected"); -} - -#pragma GCC pop_options \ No newline at end of file diff --git a/kernel/src/panic/Panic.cpp b/kernel/src/panic/Panic.cpp deleted file mode 100644 index 1e6565e0..00000000 --- a/kernel/src/panic/Panic.cpp +++ /dev/null @@ -1,176 +0,0 @@ -#define MODULE "panic" - -#include "panic/Panic.h" -#include "fs/InitRD.h" -#include "interrupts/IDT.h" -#include "io/PIC.h" -#include "log/Log.h" -#include "memory/VMM.h" -#include "misc/MSR.h" -#include "render/Framebuffer.h" -#include "render/TextRenderer.h" -#include "std/stdio.h" -#include "thread/Scheduler.h" -#include "trace/StackTracer.h" - -static bool g_is_in_panic = false; -static bool g_is_in_double_panic = false; - -void panic_prepare_keyboard_triple_fault() -{ - PIC::enable_master(0b11111101); // enable keyboard only - PIC::enable_slave(0b11111111); - - IDTR idtr; - idtr.limit = 0x0000; - idtr.offset = 0x0000; - asm volatile( - "lidt %0" - : - : "m"( - idtr)); // when an interrupt arrives, triple-fault (the only interrupt that should come is the keyboard one) - - asm volatile("sti"); -} - -void dump_registers(Context* context) -{ - kinfoln("-- Registers:"); - kinfoln("rax: %lx, rbx: %lx, rcx: %lx, rdx: %lx", context->rax, context->rbx, context->rcx, context->rdx); - kinfoln("rsi: %lx, rdi: %lx, rsp: %lx, rbp: %lx", context->rsi, context->rdi, context->rsp, context->rbp); - kinfoln("r8: %lx, r9: %lx, r10: %lx, r11: %lx", context->r8, context->r9, context->r10, context->r11); - kinfoln("r12: %lx, r13: %lx, r14: %lx, r15: %lx", context->r12, context->r13, context->r14, context->r15); - kinfoln("rip: %lx, cs: %lx, ss: %lx", context->rip, context->cs, context->ss); - kinfoln("rflags: %lx, cr2: %lx", context->rflags, context->cr2); - kinfoln("ia32_efer: %lx", MSR::read_from(IA32_EFER_MSR)); -} - -void fatal_dump_registers(Context* context) -{ - printf("-- Possibly Relevant Registers:\n"); - printf("rbp: %lx, rsp: %lx, rip: %lx, cs: %lx, ss: %lx, rflags: %lx, cr2: %lx, error code: %lx\n", context->rbp, - context->rsp, context->rip, context->cs, context->ss, context->rflags, context->cr2, context->error_code); -} - -[[noreturn]] void __panic_fatal_stub(Context* context) -{ - if (context) fatal_dump_registers(context); - printf("-- No stack trace available\n"); - - KernelLog::enable_log_backend(Backend::Console); - KernelLog::toggle_log_backend( - Backend::Console); // disable console logging, as we can page fault while writing to the framebuffer. - - Scheduler::current_task()->id = 0; // we're panicking, we don't even care anymore. This is so KernelLog shows - // (kernel) instead of (taskname: PID) in the log. - - panic_prepare_keyboard_triple_fault(); - - printf("Press any key to restart.\n"); - - while (1) asm volatile("hlt"); -} - -[[noreturn]] void __panic_stub(Context* context) -{ - VMM::switch_back_to_kernel_address_space(); - VMM::apply_address_space(); - if (context) dump_registers(context); - - if (InitRD::is_initialized()) - { - kinfoln("-- Stack trace:"); - if (context) - { - StackTracer tracer(context->rbp); - tracer.trace_with_ip(context->rip); - } - else - { - uintptr_t rbp; - - asm volatile("mov %%rbp, %0" : "=r"(rbp)); - StackTracer tracer(rbp); - tracer.trace(); - } - } - else { kinfoln("-- No stack trace available"); } - - panic_prepare_keyboard_triple_fault(); - - while (1) asm volatile("hlt"); -} - -extern "C" [[noreturn]] bool __do_int_panic(Context* context, const char* file, int line, const char* message) -{ - asm volatile("cli"); - - if (g_is_in_double_panic) - { - panic_prepare_keyboard_triple_fault(); - while (1) asm volatile("hlt"); - } - - if (g_is_in_panic) - { - g_is_in_double_panic = true; - printf("Kernel panic while panicking (showing vital information only) at %s, line %d: %s\n", file, line, - message); - __panic_fatal_stub(context); - } - - g_is_in_panic = true; - - KernelLog::enable_log_backend(Backend::Console); - - TextRenderer::reset(); - - framebuffer0.clear(Color::Black); - - if (context->number >= 0x20 && context->number < 0x30) { PIC::send_eoi((uint8_t)(context->irq_number & 0xFF)); } - - Task* task; - if ((task = Scheduler::current_task())) - { - kerrorln("Kernel panic in task %ld, at %s, line %d: %s", task->id, file, line, message); - } - else { kerrorln("Kernel panic at %s, line %d: %s", file, line, message); } - - __panic_stub(context); -} - -extern "C" [[noreturn]] bool __do_panic(const char* file, int line, const char* message) -{ - asm volatile("cli"); - - if (g_is_in_double_panic) - { - panic_prepare_keyboard_triple_fault(); - while (1) asm volatile("hlt"); - } - - if (g_is_in_panic) - { - g_is_in_double_panic = true; - printf("Kernel panic while panicking (showing vital information only) at %s, line %d: %s\n", file, line, - message); - __panic_fatal_stub(nullptr); - } - - g_is_in_panic = true; - - KernelLog::enable_log_backend(Backend::Console); - - TextRenderer::reset(); - - framebuffer0.clear(Color::Black); - - Task* task; - if ((task = Scheduler::current_task())) - { - kerrorln("Kernel panic in task %ld, at %s, line %d: %s", task->id, file, line, message); - } - else { kerrorln("Kernel panic at %s, line %d: %s", file, line, message); } - - __panic_stub(nullptr); -} \ No newline at end of file diff --git a/kernel/src/rand/Init.asm b/kernel/src/rand/Init.asm deleted file mode 100644 index 9dbe3db8..00000000 --- a/kernel/src/rand/Init.asm +++ /dev/null @@ -1,11 +0,0 @@ -global asm_test_rdseed - -asm_test_rdseed: - xor rax, rax - mov eax, 7 - mov ecx, 0 - cpuid - shr ebx, 18 - and ebx, 1 - mov eax, ebx - ret \ No newline at end of file diff --git a/kernel/src/rand/Init.cpp b/kernel/src/rand/Init.cpp deleted file mode 100644 index 79f9569b..00000000 --- a/kernel/src/rand/Init.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#define MODULE "rand" - -#include "rand/Init.h" -#include "config.h" -#include "cpu/CPU.h" -#include "io/IO.h" -#include "log/Log.h" -#include "rand/Mersenne.h" - -static uint64_t state = 0xf5026f5ae96319e9; - -static bool has_rdrand = false; -static bool has_rdseed = false; - -extern "C" int asm_test_rdseed(); - -static uint64_t rdtsc() -{ - uint64_t result1; - uint64_t result2; - asm volatile("rdtsc" : "=a"(result1), "=d"(result2)); - return result2 << 32 | result1; -} - -static uint64_t rdseed() -{ - uint64_t result; - asm volatile("rdseed %0" : "=r"(result)); - return result; -} - -static uint64_t rdrand() -{ - uint64_t result; - asm volatile("rdrand %0" : "=r"(result)); - return result; -} - -void Mersenne::init() -{ - has_rdrand = CPU::has_feature(CPU::Features::RDRAND); - has_rdseed = asm_test_rdseed(); - - if (!has_rdrand && !has_rdseed) kwarnln("CPU does not support either RDRAND or RDSEED"); - - state ^= (0x45fe1024UL + __moon_version_major()) * (__moon_version_minor() ^ 200UL); - - state ^= 0xe0e4f5332ea75b; - - reseed(); - - state ^= Mersenne::get() * 0xffe3; - - state ^= rdtsc(); - - Mersenne::seed(state); -} - -void Mersenne::reseed() -{ - state ^= rdtsc(); - - if (has_rdrand) { state ^= rdrand(); } - - if (has_rdseed) { state ^= rdseed(); } - - state ^= rdtsc(); - - state ^= IO::inb(0x40); - - state ^= rdtsc(); - - Mersenne::seed(state); -} \ No newline at end of file diff --git a/kernel/src/rand/Mersenne.cpp b/kernel/src/rand/Mersenne.cpp deleted file mode 100644 index 9f30d469..00000000 --- a/kernel/src/rand/Mersenne.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#define MODULE "rand" - -#include "rand/Mersenne.h" -#include "std/ensure.h" -#include - -typedef uint64_t word_t; - -static const int STATE_SIZE = 312; -static const int MIDDLE = 156; -static const int INIT_SHIFT = 62; -static const uint64_t TWIST_MASK = 0xb5026f5aa96619e9; -static const uint64_t INIT_FACT = 6364136223846793005; -static const int SHIFT1 = 29; -static const uint64_t MASK1 = 0x5555555555555555; -static const int SHIFT2 = 17; -static const uint64_t MASK2 = 0x71d67fffeda60000; -static const int SHIFT3 = 37; -static const uint64_t MASK3 = 0xfff7eee000000000; -static const int SHIFT4 = 43; - -static const word_t LOWER_MASK = 0x7fffffff; -static const word_t UPPER_MASK = (~(word_t)LOWER_MASK); - -static word_t state[STATE_SIZE]; -static size_t index = STATE_SIZE + 1; - -void Mersenne::seed(uint64_t s) -{ - index = STATE_SIZE; - state[0] = s; - for (size_t i = 1; i < STATE_SIZE; i++) state[i] = (INIT_FACT * (state[i - 1] ^ (state[i - 1] >> INIT_SHIFT))) + i; -} - -static void twist() -{ - for (size_t i = 0; i < STATE_SIZE; i++) - { - word_t x = (state[i] & UPPER_MASK) | (state[(i + 1) % STATE_SIZE] & LOWER_MASK); - x = (x >> 1) ^ (x & 1 ? TWIST_MASK : 0); - state[i] = state[(i + MIDDLE) % STATE_SIZE] ^ x; - } - index = 0; -} - -uint64_t Mersenne::get() -{ - if (index >= STATE_SIZE) - { - ensure(index == STATE_SIZE && "Mersenne generator was never seeded"); - twist(); - } - - word_t y = state[index]; - y ^= (y >> SHIFT1) & MASK1; - y ^= (y << SHIFT2) & MASK2; - y ^= (y << SHIFT3) & MASK3; - y ^= y >> SHIFT4; - - index++; - return y; -} \ No newline at end of file diff --git a/kernel/src/render/Color.cpp b/kernel/src/render/Color.cpp deleted file mode 100644 index 505b8516..00000000 --- a/kernel/src/render/Color.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "render/Color.h" - -Color Color::White = {0xFF, 0xFF, 0xFF, 0xFF}; -Color Color::Black = {0x00, 0x00, 0x00, 0xFF}; -Color Color::Red = {0x00, 0x00, 0xFF, 0xFF}; -Color Color::Green = {0x00, 0xFF, 0x00, 0xFF}; -Color Color::Blue = {0xFF, 0x00, 0x00, 0xFF}; -Color Color::Yellow = {0x00, 0xFF, 0xFF, 0xFF}; -Color Color::Cyan = {0xFF, 0xFF, 0x00, 0xFF}; -Color Color::Magenta = {0xFF, 0x00, 0xFF, 0xFF}; -Color Color::Gray = {0x80, 0x80, 0x80, 0xFF}; - -#pragma GCC push_options -#pragma GCC diagnostic ignored "-Wstrict-aliasing" - -Color Color::from_integer(uint32_t source) -{ - return reinterpret_cast(source); -} - -#pragma GCC pop_options \ No newline at end of file diff --git a/kernel/src/render/Framebuffer.cpp b/kernel/src/render/Framebuffer.cpp deleted file mode 100644 index bdde5a73..00000000 --- a/kernel/src/render/Framebuffer.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#define MODULE "fb" - -#include "render/Framebuffer.h" -#include "assert.h" -#include "bootboot.h" -#include "panic/Panic.h" -#include "string.h" - -Framebuffer framebuffer0; - -void Framebuffer::init(void* fb_address, int fb_type, int fb_scanline, int fb_width, int fb_height) -{ - m_fb_address = fb_address; - m_fb_height = fb_height; - m_fb_width = fb_width; - m_fb_scanline = fb_scanline; - m_fb_type = fb_type; - if (m_fb_type != FB_ARGB) - { - memset(m_fb_address, 0xe4, 500); // make it visible - panic("unsupported framebuffer"); - } -} - -void Framebuffer::set_pixel(uint32_t x, uint32_t y, Color color) -{ - *(uint32_t*)((char*)m_fb_address + m_fb_scanline * y + x * 4) = *(uint32_t*)&color; -} - -Color Framebuffer::get_pixel(uint32_t x, uint32_t y) -{ - return *(Color*)((char*)m_fb_address + m_fb_scanline * y + x * 4); -} - -void Framebuffer::clear(Color color) -{ - paint_rect(0, 0, m_fb_width, m_fb_height, color); -} - -void Framebuffer::paint_rect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, Color color) -{ - for (uint32_t i = y; i < (y + h); i++) - { - uint64_t addr = (uint64_t)((char*)m_fb_address + (m_fb_scanline * i) + (x * 4)); - for (uint64_t addr_current = addr; addr_current < (addr + w * 4); addr_current += 4) - { - *(uint32_t*)addr_current = *(uint32_t*)&color; - } - } -} - -void Framebuffer::paint_rect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, Color* colors) -{ - uint32_t j; - for (uint32_t l = j = 0; l < h; l++) - { - for (uint32_t i = 0; i < w; i++, j++) { set_pixel(x + i, y + l, colors[j]); } - } -} diff --git a/kernel/src/render/TextRenderer.cpp b/kernel/src/render/TextRenderer.cpp deleted file mode 100644 index d8e2ad7f..00000000 --- a/kernel/src/render/TextRenderer.cpp +++ /dev/null @@ -1,116 +0,0 @@ -#define MODULE "text" - -#include "render/TextRenderer.h" -#include "bootboot.h" -#include "font.h" -#include "fs/InitRD.h" -#include "io/Serial.h" -#include "log/Log.h" -#include "render/Framebuffer.h" -#include "std/stdio.h" -#include "std/string.h" - -extern BOOTBOOT bootboot; - -static Color bgColor = Color::Black; -static Color fgColor = Color::White; -static uint32_t xpos = 0; -static uint32_t ypos = 0; - -#define FONT_HEIGHT 16 -#define FONT_WIDTH 8 - -void TextRenderer::reset() -{ - xpos = 0; - ypos = 0; -} - -#pragma GCC push_options -#pragma GCC optimize("O0") - -static void putchar_at_offset( - char c, uint32_t cx, uint32_t cy, [[maybe_unused]] Color& fg, - [[maybe_unused]] Color& bg) // FIXME: Rewrite this function to actually work with foreground and background colors. -{ - uint8_t* glyph = &font[c * 16]; - for (uint32_t y = 0; y < FONT_HEIGHT; y++) - { - for (uint32_t x = 0; x < FONT_WIDTH; x++) - { - volatile uint8_t mask = *glyph; - if ((mask & (0b10000000 >> x)) > 0) { framebuffer0.set_pixel(cx + x, cy + y, Color::White); } - else { framebuffer0.set_pixel(cx + x, cy + y, Color::Black); } - } - glyph++; - } -} - -static bool g_escape_sequence = false; - -#pragma GCC pop_options - -void TextRenderer::putchar(char chr) -{ - if (g_escape_sequence) - { - g_escape_sequence = false; - switch (chr) - { - case '@': - reset(); - framebuffer0.clear(Color::Black); - break; - default: break; - } - } - else - { - switch (chr) - { - case '\n': { - ypos += FONT_HEIGHT; - if ((ypos + FONT_HEIGHT) >= bootboot.fb_height) - { - memcpy((void*)bootboot.fb_ptr, (char*)bootboot.fb_ptr + (bootboot.fb_scanline * FONT_HEIGHT), - bootboot.fb_size - (bootboot.fb_scanline * FONT_HEIGHT)); - ypos -= FONT_HEIGHT; - framebuffer0.paint_rect(0, ypos, bootboot.fb_width, FONT_HEIGHT, Color::Black); - } - xpos = 0; - break; - } - case '\r': xpos = 0; break; - case '\b': - if (xpos != 0) - { - xpos -= FONT_WIDTH; - framebuffer0.paint_rect(xpos, ypos, FONT_WIDTH, FONT_HEIGHT, Color::Black); - } - break; - case '\033': g_escape_sequence = true; break; - default: { - putchar_at_offset(chr, xpos, ypos, fgColor, bgColor); - xpos += FONT_WIDTH; - if ((xpos + FONT_WIDTH) > bootboot.fb_width) - { - xpos = 0; - ypos += FONT_HEIGHT; - if ((ypos + FONT_HEIGHT) >= bootboot.fb_height) - { - memcpy((void*)bootboot.fb_ptr, (char*)bootboot.fb_ptr + (bootboot.fb_scanline * FONT_HEIGHT), - bootboot.fb_size - (bootboot.fb_scanline * FONT_HEIGHT)); - ypos -= FONT_HEIGHT; - framebuffer0.paint_rect(0, ypos, bootboot.fb_width, FONT_HEIGHT, Color::Black); - } - } - break; - } - } - } -} - -void TextRenderer::write(const char* str, size_t size) -{ - for (size_t i = 0; i < size; i++) { putchar(str[i]); } -} \ No newline at end of file diff --git a/kernel/src/std/libgen.cpp b/kernel/src/std/libgen.cpp deleted file mode 100644 index b0a46a98..00000000 --- a/kernel/src/std/libgen.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include "std/libgen.h" -#include "std/stdlib.h" -#include "std/string.h" - -static char dot[] = "."; - -char* basename(char* path) -{ - // If path is NULL, or the string's length is 0, return . - if (!path) return dot; - size_t len = strlen(path); - if (!len) return dot; - - // Strip trailing slashes. - char* it = path + len - 1; - while (*it == '/' && it != path) { it--; } - *(it + 1) = 0; - if (it == path) return path; - - // Return path from the first character if there are no more slashes, or from the first character after the last - // slash. - char* beg = strrchr(path, '/'); - if (!beg) return path; - return beg + 1; -} - -char* dirname(char* path) -{ - // If path is NULL, or the string's length is 0, return . - if (!path) return dot; - size_t len = strlen(path); - if (!len) return dot; - - // Strip trailing slashes. - char* it = path + len - 1; - while (*it == '/' && it != path) { it--; } - *(char*)(it + 1) = 0; - if (it == path) return path; - - // Search for the last slash. If there is none, return . - // Otherwise, we end the string there and return. - char* end = strrchr(path, '/'); - if (!end) return dot; - if (end != path) *end = 0; - else - *(end + 1) = 0; - return path; -} - -char* better_basename(const char* path) -{ - char* mut = strdup(path); // create a mutable copy of path - char* ptr = basename(mut); // get a pointer to the start of the base name - char* result = strdup(ptr); // create a copy of it, so the caller can free the returned pointer directly - kfree(mut); // free the original mutable copy - return result; -} - -char* better_dirname(const char* path) -{ - // same as above - char* mut = strdup(path); - char* ptr = dirname(mut); - char* result = strdup(ptr); - kfree(mut); - return result; -} \ No newline at end of file diff --git a/kernel/src/std/stdio.cpp b/kernel/src/std/stdio.cpp deleted file mode 100644 index 18af8db5..00000000 --- a/kernel/src/std/stdio.cpp +++ /dev/null @@ -1,289 +0,0 @@ -#include "std/stdio.h" -#include "io/Serial.h" -#include "render/TextRenderer.h" -#include "std/stdlib.h" -#include "std/string.h" - -typedef long int ssize_t; - -template -static int internal_printf(const char* format, PutString put_string_callback, ssize_t max, va_list ap) -{ - char buffer[1025]; // 1024 with null terminator - size_t format_size = strlen(format); - size_t format_index = 0; - size_t buffer_insert_index = 0; - ssize_t max_remaining = max; - size_t written = 0; - - auto flush_buffer = [&]() { - size_t buffer_length = buffer_insert_index; - written += buffer_length; - buffer_insert_index = 0; - if (max_remaining < 0) - { - buffer[buffer_length] = 0; - put_string_callback(buffer); - return; - } - if (max_remaining == 0) { return; } - if (buffer_length <= (size_t)max_remaining) - { - max_remaining -= buffer_length; - buffer[buffer_length] = 0; - put_string_callback(buffer); - } - else - { - buffer[max_remaining] = 0; - max_remaining = 0; - put_string_callback(buffer); - } - }; - - bool is_long = false; - bool is_unsigned_long = false; - - bool preserve_format = false; - - while (format_index < format_size) - { - char current_char = format[format_index]; - if (current_char == '%' || preserve_format) - { - if (!preserve_format && format_index + 1 == format_size) // end of format string - { - format_index++; - continue; - } - else - { - if (!preserve_format) format_index++; - preserve_format = false; - current_char = format[format_index]; - switch (current_char) - { - case 'c': { - buffer[buffer_insert_index++] = (char)va_arg(ap, int); - if (buffer_insert_index == 1024) flush_buffer(); - break; - } - case '%': { - buffer[buffer_insert_index++] = '%'; - if (buffer_insert_index == 1024) flush_buffer(); - break; - } - case 'z': { - is_unsigned_long = true; - preserve_format = true; - break; - } - case 'l': { - is_long = true; - preserve_format = true; - break; - } - case 'd': { - if (is_unsigned_long) - { - char result[25]; - ultoa(va_arg(ap, uint64_t), result, 10); - if (buffer_insert_index + strlen(result) > 1024) flush_buffer(); - memcpy(buffer + buffer_insert_index, result, strlen(result)); - buffer_insert_index += strlen(result); - if (buffer_insert_index == 1024) flush_buffer(); - is_unsigned_long = is_long = false; - } - else if (is_long) - { - char result[25]; - ltoa(va_arg(ap, int64_t), result, 10); - if (buffer_insert_index + strlen(result) > 1024) flush_buffer(); - memcpy(buffer + buffer_insert_index, result, strlen(result)); - buffer_insert_index += strlen(result); - if (buffer_insert_index == 1024) flush_buffer(); - is_unsigned_long = is_long = false; - } - else - { - char result[25]; - itoa(va_arg(ap, int32_t), result, 10); - if (buffer_insert_index + strlen(result) > 1024) flush_buffer(); - memcpy(buffer + buffer_insert_index, result, strlen(result)); - buffer_insert_index += strlen(result); - if (buffer_insert_index == 1024) flush_buffer(); - } - break; - } - case 'u': { - if (is_unsigned_long || is_long) - { - char result[25]; - ultoa(va_arg(ap, uint64_t), result, 10); - if (buffer_insert_index + strlen(result) > 1024) flush_buffer(); - memcpy(buffer + buffer_insert_index, result, strlen(result)); - buffer_insert_index += strlen(result); - if (buffer_insert_index == 1024) flush_buffer(); - is_unsigned_long = is_long = false; - } - else - { - char result[25]; - utoa(va_arg(ap, uint32_t), result, 10); - if (buffer_insert_index + strlen(result) > 1024) flush_buffer(); - memcpy(buffer + buffer_insert_index, result, strlen(result)); - buffer_insert_index += strlen(result); - if (buffer_insert_index == 1024) flush_buffer(); - } - break; - } - case 'x': { - if (is_unsigned_long || is_long) - { - char result[25]; - ultoa(va_arg(ap, uint64_t), result, 16); - if (buffer_insert_index + strlen(result) > 1024) flush_buffer(); - memcpy(buffer + buffer_insert_index, result, strlen(result)); - buffer_insert_index += strlen(result); - if (buffer_insert_index == 1024) flush_buffer(); - is_unsigned_long = is_long = false; - } - else - { - char result[25]; - utoa(va_arg(ap, uint32_t), result, 16); - if (buffer_insert_index + strlen(result) > 1024) flush_buffer(); - memcpy(buffer + buffer_insert_index, result, strlen(result)); - buffer_insert_index += strlen(result); - if (buffer_insert_index == 1024) flush_buffer(); - } - break; - } - case 'p': { - char result[25]; - ultoa(va_arg(ap, uint64_t), result, 16); - if (buffer_insert_index + strlen(result) > 1024) flush_buffer(); - memcpy(buffer + buffer_insert_index, result, strlen(result)); - buffer_insert_index += strlen(result); - if (buffer_insert_index == 1024) flush_buffer(); - break; - } - case 's': { - const char* str = va_arg(ap, const char*); - while (strlen(str) > 1024) - { - flush_buffer(); - memcpy(buffer, str, 1024); - str += 1024; - buffer_insert_index = 1024; - } - if (buffer_insert_index + strlen(str) > 1024) flush_buffer(); - memcpy(buffer + buffer_insert_index, str, strlen(str)); - buffer_insert_index += strlen(str); - if (buffer_insert_index == 1024) flush_buffer(); - break; - } - default: { - buffer[buffer_insert_index++] = '%'; - if (buffer_insert_index == 1024) flush_buffer(); - buffer[buffer_insert_index++] = current_char; - if (buffer_insert_index == 1024) flush_buffer(); - break; - } - } - } - } - else - { - buffer[buffer_insert_index++] = current_char; - if (buffer_insert_index == 1024) flush_buffer(); - } - format_index++; - } - - if (buffer_insert_index > 0) flush_buffer(); - return (int)written; -} - -int printf(const char* fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - int written = internal_printf( - fmt, [](const char* s) { Serial::print(s); }, -1, ap); - va_end(ap); - return written; -} - -int kprintf(const char* fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - int written = vkprintf(fmt, ap); - va_end(ap); - return written; -} - -int sprintf(char* __s, const char* fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - if (__s) *__s = 0; - int written = internal_printf( - fmt, - [&](const char* s) { - if (__s) { strncat(__s, s, 1025); } - }, - -1, ap); - va_end(ap); - return written; -} - -int snprintf(char* __s, size_t max, const char* fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - if (__s && max) *__s = 0; - int written = internal_printf( - fmt, - [&](const char* s) { - if (__s) { strncat(__s, s, 1025); } - }, - max == 0 ? 0 : max - 1, ap); - va_end(ap); - return written; -} - -int vprintf(const char* fmt, va_list ap) -{ - return internal_printf( - fmt, [](const char* s) { Serial::print(s); }, -1, ap); -} - -int vkprintf(const char* fmt, va_list ap) -{ - return internal_printf( - fmt, [](const char* s) { TextRenderer::write(s, strlen(s)); }, -1, ap); -} - -int vsprintf(char* __s, const char* fmt, va_list ap) -{ - *__s = 0; - return internal_printf( - fmt, - [&](const char* s) { - if (__s) { strncat(__s, s, 1025); } - }, - -1, ap); -} - -int vsnprintf(char* __s, size_t max, const char* fmt, va_list ap) -{ - if (max) *__s = 0; - return internal_printf( - fmt, - [&](const char* s) { - if (__s) { strncat(__s, s, 1025); } - }, - max == 0 ? 0 : max - 1, ap); -} \ No newline at end of file diff --git a/kernel/src/std/stdlib.cpp b/kernel/src/std/stdlib.cpp deleted file mode 100644 index b7d42f42..00000000 --- a/kernel/src/std/stdlib.cpp +++ /dev/null @@ -1,153 +0,0 @@ -#include "std/stdlib.h" -#include "thread/Scheduler.h" - -static void strrev(char* arr, int start, int end) -{ - char temp; - - if (start >= end) return; - - temp = *(arr + start); - *(arr + start) = *(arr + end); - *(arr + end) = temp; - - start++; - end--; - strrev(arr, start, end); -} - -char* itoa(int32_t number, char* arr, int base) -{ - int i = 0, r, negative = 0; - - if (number == 0) - { - arr[i] = '0'; - arr[i + 1] = '\0'; - return arr; - } - - if (number < 0 && base == 10) - { - number *= -1; - negative = 1; - } - - while (number != 0) - { - r = number % base; - arr[i] = (char)((r > 9) ? (r - 10) + 'a' : r + '0'); - i++; - number /= base; - } - - if (negative) - { - arr[i] = '-'; - i++; - } - - strrev(arr, 0, i - 1); - - arr[i] = '\0'; - - return arr; -} - -char* ltoa(int64_t number, char* arr, int base) -{ - int i = 0, negative = 0; - int64_t r; - - if (number == 0) - { - arr[i] = '0'; - arr[i + 1] = '\0'; - return arr; - } - - if (number < 0 && base == 10) - { - number *= -1; - negative = 1; - } - - while (number != 0) - { - r = number % base; - arr[i] = (char)((r > 9) ? (r - 10) + 'a' : r + '0'); - i++; - number /= base; - } - - if (negative) - { - arr[i] = '-'; - i++; - } - - strrev(arr, 0, i - 1); - - arr[i] = '\0'; - - return arr; -} - -char* utoa(uint32_t number, char* arr, int base) -{ - int i = 0; - uint32_t r; - - if (number == 0) - { - arr[i] = '0'; - arr[i + 1] = '\0'; - return arr; - } - - while (number != 0) - { - r = number % base; - arr[i] = (char)((r > 9) ? (r - 10) + 'a' : r + '0'); - i++; - number /= base; - } - - strrev(arr, 0, i - 1); - - arr[i] = '\0'; - - return arr; -} - -char* ultoa(uint64_t number, char* arr, int base) -{ - int i = 0; - uint64_t r; - - if (number == 0) - { - arr[i] = '0'; - arr[i + 1] = '\0'; - return arr; - } - - while (number != 0) - { - r = number % base; - arr[i] = (char)((r > 9) ? (r - 10) + 'a' : r + '0'); - i++; - number /= base; - } - - strrev(arr, 0, i - 1); - - arr[i] = '\0'; - - return arr; -} - -void sleep(uint64_t ms) -{ - Scheduler::sleep(ms); -} \ No newline at end of file diff --git a/kernel/src/std/string.cpp b/kernel/src/std/string.cpp deleted file mode 100644 index bcb3e62d..00000000 --- a/kernel/src/std/string.cpp +++ /dev/null @@ -1,157 +0,0 @@ -#include "std/string.h" -#include "std/stdlib.h" - -size_t strlen(const char* __s) -{ - const char* i = __s; - for (; *i; ++i) - ; - return (i - __s); -} - -char* strcpy(char* dest, const char* src) -{ - memcpy(dest, src, strlen(src) + 1); - return dest; -} - -char* strncpy(char* dest, const char* src, size_t n) -{ - size_t i; - for (i = 0; i < n && src[i] != 0; i++) dest[i] = src[i]; - for (; i < n; i++) dest[i] = 0; - return dest; -} - -size_t strlcpy(char* dest, const char* src, size_t size) -{ - size_t len = strlen(src); - if (size == 0) return len; - if (len < (size - 1)) - { - memcpy(dest, src, len); - dest[len] = 0; - } - else - { - memcpy(dest, src, size - 1); - dest[size - 1] = 0; - } - return len; -} - -int strcmp(const char* a, const char* b) -{ - while (*a && (*a == *b)) - { - a++; - b++; - } - return *(const unsigned char*)a - *(const unsigned char*)b; -} - -int strncmp(const char* a, const char* b, size_t n) -{ - const char* base = a; - while (*a && (*a == *b) && (size_t)(a - base) < (n - 1)) - { - a++; - b++; - } - return *(const unsigned char*)a - *(const unsigned char*)b; -} - -char* strncat(char* dest, const char* src, size_t n) -{ - size_t dest_len = strlen(dest); - size_t i; - - for (i = 0; i < n && *(src + i); i++) *(char*)(dest + dest_len + i) = *(const char*)(src + i); - - *(char*)(dest + dest_len + i) = '\0'; - - return dest; -} - -char* strcat(char* dest, const char* src) -{ - size_t dest_len = strlen(dest); - size_t i; - - for (i = 0; *(src + i); i++) *(char*)(dest + dest_len + i) = *(const char*)(src + i); - - *(char*)(dest + dest_len + i) = '\0'; - - return dest; -} - -char* strstr(char* haystack, const char* needle) -{ - size_t needle_size = strlen(needle); - size_t haystack_size = strlen(haystack); - while (*haystack) - { - if (*haystack == *needle) - { - if (needle_size <= haystack_size) - { - if (!strncmp(haystack, needle, needle_size)) return haystack; - } - else { return NULL; } - } - haystack++; - haystack_size--; - } - return NULL; -} - -void* memcpy(void* dest, const void* src, size_t n) -{ - for (size_t i = 0; i < n; ++i) { *((char*)dest + i) = *((const char*)src + i); } - return dest; -} - -void* memset(void* buf, int c, size_t n) -{ - for (size_t i = 0; i < n; ++i) { *((char*)buf + i) = (char)c; } - return buf; -} - -int memcmp(const void* a, const void* b, size_t n) -{ - if (!n) return 0; - const unsigned char* ap = (const unsigned char*)a; - const unsigned char* bp = (const unsigned char*)b; - while (--n && *ap == *bp) - { - ap++; - bp++; - } - return *ap - *bp; -} - -void* memmove(void* dest, const void* src, size_t n) -{ - if (dest == src) return dest; - if (dest > src) - for (long i = n - 1; i >= 0; i++) { *((char*)dest + i) = *((const char*)src + i); } - else - for (long i = 0; i < (long)n; i++) { *((char*)dest + i) = *((const char*)src + i); } - return dest; -} - -char* strdup(const char* src) -{ - size_t length = strlen(src); - char* duplicated = (char*)kmalloc(length + 1); - memcpy(duplicated, src, length + 1); - return duplicated; -} - -char* strrchr(const char* str, int c) -{ - const char* s = str + strlen(str); - while (s != str && *s != (char)c) s--; - if (*s == (char)c) return const_cast(s); - return NULL; -} \ No newline at end of file diff --git a/kernel/src/sys/Syscall.cpp b/kernel/src/sys/Syscall.cpp index 992bafa3..d45552aa 100644 --- a/kernel/src/sys/Syscall.cpp +++ b/kernel/src/sys/Syscall.cpp @@ -1,51 +1,18 @@ #include "sys/Syscall.h" -#include "io/Serial.h" -#include "memory/VMM.h" -#include "std/errno.h" -#include "std/string.h" -#include "thread/Scheduler.h" +#include -void Syscall::entry(Context* context) +syscall_func_t syscalls[] = { +#undef __enumerate +#define __enumerate(name) sys_##name, + enumerate_syscalls(__enumerate) +#undef __enumerate +}; + +i64 invoke_syscall(Registers* regs, SyscallArgs args, u64 syscall) { - asm volatile("cli"); - VMM::enter_syscall_context(); - switch (context->rax) - { - case SYS_exit: sys_exit(context, (int)context->rdi); break; - case SYS_yield: sys_yield(context); break; - case SYS_sleep: sys_sleep(context, context->rdi); break; - case SYS_write: sys_write(context, (int)context->rdi, context->rsi, (const char*)context->rdx); break; - case SYS_getprocid: sys_getprocid(context, (int)context->rdi); break; - case SYS_mmap: - sys_mmap(context, (void*)context->rdi, context->rsi, (int)context->rdx, (int)context->r10, (off_t)context->r8); - break; - case SYS_munmap: sys_munmap(context, (void*)context->rdi, context->rsi); break; - case SYS_open: sys_open(context, (const char*)context->rdi, (int)context->rsi, (mode_t)context->rdx); break; - case SYS_read: sys_read(context, (int)context->rdi, context->rsi, (char*)context->rdx); break; - case SYS_close: sys_close(context, (int)context->rdi); break; - case SYS_seek: sys_seek(context, (int)context->rdi, (long)context->rsi, (int)context->rdx); break; - case SYS_execv: sys_execv(context, (const char*)context->rdi, (char**)context->rsi); break; - case SYS_fcntl: sys_fcntl(context, (int)context->rdi, (int)context->rsi, context->rdx); break; - case SYS_mprotect: sys_mprotect(context, (void*)context->rdi, context->rsi, (int)context->rdx); break; - case SYS_clock_gettime: sys_clock_gettime(context, (int)context->rdi, (struct timespec*)context->rsi); break; - case SYS_mkdir: sys_mkdir(context, (const char*)context->rdi, (mode_t)context->rsi); break; - case SYS_fork: sys_fork(context); break; - case SYS_waitpid: sys_waitpid(context, (long)context->rdi, (int*)context->rsi, (int)context->rdx); break; - case SYS_access: sys_access(context, (const char*)context->rdi, (int)context->rsi); break; - case SYS_fstat: sys_fstat(context, (int)context->rdi, (struct stat*)context->rsi); break; - case SYS_stat: sys_stat(context, (const char*)context->rdi, (struct stat*)context->rsi); break; - case SYS_pstat: sys_pstat(context, (long)context->rdi, (struct pstat*)context->rsi); break; - case SYS_getdents: - sys_getdents(context, (int)context->rdi, (struct luna_dirent*)context->rsi, (size_t)context->rdx); - break; - case SYS_dup2: sys_dup2(context, (int)context->rdi, (int)context->rsi); break; - case SYS_setuid: sys_setuid(context, (uid_t)context->rdi); break; - case SYS_setgid: sys_setgid(context, (gid_t)context->rdi); break; - case SYS_umask: sys_umask(context, (mode_t)context->rdi); break; - case SYS_ioctl: sys_ioctl(context, (int)context->rdi, (int)context->rsi, (uintptr_t)context->rdx); break; - case SYS_seteuid: sys_seteuid(context, (uid_t)context->rdi); break; - case SYS_setegid: sys_setegid(context, (gid_t)context->rdi); break; - default: context->rax = -ENOSYS; break; - } - VMM::exit_syscall_context(); + if (syscall >= Syscalls::__count) { return -ENOSYS; } + + auto rc = syscalls[syscall](regs, args); + if (rc.has_error()) return -rc.error(); + return (i64)rc.value(); } diff --git a/kernel/src/sys/Syscall.h b/kernel/src/sys/Syscall.h new file mode 100644 index 00000000..15b69505 --- /dev/null +++ b/kernel/src/sys/Syscall.h @@ -0,0 +1,16 @@ +#pragma once +#include "arch/CPU.h" +#include +#include + +typedef u64 SyscallArgs[6]; + +typedef Result (*syscall_func_t)(Registers*, SyscallArgs); + +// Invoked by the architecture-dependent system call entry point. +i64 invoke_syscall(Registers*, SyscallArgs, u64 syscall); + +#undef __enumerate +#define __enumerate(name) extern Result sys_##name(Registers*, SyscallArgs); +enumerate_syscalls(__enumerate) +#undef __enumerate diff --git a/kernel/src/sys/UserMemory.cpp b/kernel/src/sys/UserMemory.cpp deleted file mode 100644 index fc71fb40..00000000 --- a/kernel/src/sys/UserMemory.cpp +++ /dev/null @@ -1,224 +0,0 @@ -#include "sys/UserMemory.h" -#include "memory/Memory.h" -#include "memory/MemoryManager.h" -#include "std/stdlib.h" -#include "std/string.h" -#include "utils/Addresses.h" - -struct dynamic_string -{ - char* buf; - long capacity; - long size; -}; - -bool dynamic_expand(dynamic_string* str, long new_capacity) -{ - char* buffer = (char*)krealloc(str->buf, new_capacity); - if (!buffer) { return false; } - str->buf = buffer; - str->capacity = new_capacity; - return true; -} - -bool dynamic_push(dynamic_string* str, char c) -{ - if (str->size == str->capacity) - { - if (!dynamic_expand(str, str->capacity + 16)) return false; - } - str->buf[str->size] = c; - str->size++; - return true; -} - -bool dynamic_init(dynamic_string* str) -{ - str->buf = (char*)kmalloc(10); - if (!str->buf) return false; - str->capacity = 10; - str->size = 0; - return true; -} - -bool validate_user_readable_page(uintptr_t address) -{ - if (Memory::is_kernel_address(address)) return false; - auto rc = VMM::get_flags(address); - if (rc == (uint64_t)-1) return false; - if (rc & MAP_USER) return true; - return false; -} - -bool validate_user_writable_page(uintptr_t address) -{ - if (Memory::is_kernel_address(address)) return false; - auto rc = VMM::get_flags(address); - if (rc == (uint64_t)-1) return false; - if (rc & (MAP_USER | MAP_READ_WRITE)) return true; - return false; -} - -Result strdup_from_user(const char* user_string) -{ - uintptr_t user_ptr = (uintptr_t)user_string; - auto aligned = round_down_to_nearest_page(user_ptr); - char* ptr = nullptr; - uintptr_t index = 0; - if (aligned != user_ptr) // Otherwise, we already do this check below. - { - if (!validate_user_readable_page(aligned)) return nullptr; - auto result = MemoryManager::get_mapping((void*)VMM::get_physical(aligned), 0); - if (result.has_error()) return result.release_error(); - ptr = (char*)result.release_value(); - index = user_ptr - aligned; - } - dynamic_string str; - if (!dynamic_init(&str)) - { - if (ptr) MemoryManager::release_mapping(ptr); - return {ENOMEM}; - } - while (true) // FIXME: set a limit for this and fail with ENAMETOOLONG otherwise. - { - if (user_ptr % PAGE_SIZE == 0) - { - index = 0; - if (ptr) MemoryManager::release_mapping(ptr); - if (!validate_user_readable_page(user_ptr)) - { - kfree(str.buf); - return {EFAULT}; - } - auto result = MemoryManager::get_mapping((void*)VMM::get_physical(user_ptr), 0); - if (result.has_error()) return result.release_error(); - ptr = (char*)result.release_value(); - } - char c = ptr[index]; - if (!dynamic_push(&str, c)) - { - MemoryManager::release_mapping(ptr); - kfree(str.buf); - return {ENOMEM}; - } - if (!c) // We reached the null terminator!! - { - MemoryManager::release_mapping(ptr); - return str.buf; - } - user_ptr++; - index++; - } -} - -bool validate_user_read(uintptr_t address, size_t size) -{ - auto aligned = round_down_to_nearest_page(address); - if (aligned != address) // Otherwise, we already do this check below. - { - if (!validate_user_readable_page(aligned)) return false; - } - while (size--) - { - if (address % PAGE_SIZE == 0) - { - if (!validate_user_readable_page(address)) return false; - } - address++; - } - return true; -} - -bool validate_user_write(uintptr_t address, size_t size) -{ - auto aligned = round_down_to_nearest_page(address); - if (aligned != address) // Otherwise, we already do this check below. - { - if (!validate_user_writable_page(aligned)) return false; - } - while (size--) - { - if (address % PAGE_SIZE == 0) - { - if (!validate_user_writable_page(address)) return false; - } - address++; - } - return true; -} - -bool do_copy_from_user(const char* uptr, char* ptr, size_t size) -{ - uintptr_t user_ptr = (uintptr_t)uptr; - auto aligned = round_down_to_nearest_page(user_ptr); - char* mapping = nullptr; - uintptr_t index = 0; - if (aligned != user_ptr) // Otherwise, we already do this check below. - { - if (!validate_user_readable_page(aligned)) return false; - auto result = MemoryManager::get_mapping((void*)VMM::get_physical(aligned), 0); - if (result.has_error()) return false; // FIXME: Propagate errors. - mapping = (char*)result.release_value(); - index = user_ptr - aligned; - } - while (size--) - { - if (user_ptr % PAGE_SIZE == 0) - { - if (mapping) MemoryManager::release_mapping(mapping); - index = 0; - if (!validate_user_readable_page(user_ptr)) return false; - auto result = MemoryManager::get_mapping((void*)VMM::get_physical(user_ptr), 0); - if (result.has_error()) return false; // FIXME: Propagate errors. - mapping = (char*)result.release_value(); - } - *ptr = mapping[index]; - user_ptr++; - ptr++; - index++; - } - return true; -} - -bool do_copy_to_user(char* uptr, const char* ptr, size_t size) -{ - uintptr_t user_ptr = (uintptr_t)uptr; - auto aligned = round_down_to_nearest_page(user_ptr); - char* mapping = nullptr; - uintptr_t index = 0; - if (aligned != user_ptr) // Otherwise, we already do this check below. - { - if (!validate_user_writable_page(aligned)) return false; - auto result = MemoryManager::get_mapping((void*)VMM::get_physical(aligned)); - if (result.has_error()) return false; - mapping = (char*)result.release_value(); - index = user_ptr - aligned; - } - while (size--) - { - if (user_ptr % PAGE_SIZE == 0) - { - if (mapping) MemoryManager::release_mapping(mapping); - index = 0; - if (!validate_user_writable_page(user_ptr)) return false; - auto result = MemoryManager::get_mapping((void*)VMM::get_physical(user_ptr), 0); - if (result.has_error()) return false; - mapping = (char*)result.release_value(); - } - mapping[index] = *ptr; - user_ptr++; - ptr++; - index++; - } - return true; -} - -bool copy_from_user(const void* user_ptr, void* ptr, size_t size) -{ - return do_copy_from_user((const char*)user_ptr, (char*)ptr, size); -} - -bool copy_to_user(void* user_ptr, const void* ptr, size_t size) -{ - return do_copy_to_user((char*)user_ptr, (const char*)ptr, size); -} \ No newline at end of file diff --git a/kernel/src/sys/clock.cpp b/kernel/src/sys/clock.cpp deleted file mode 100644 index b4f7f1a8..00000000 --- a/kernel/src/sys/clock.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include "bootboot.h" -#include "interrupts/Context.h" -#include "std/errno.h" -#include "sys/UserMemory.h" -#include "thread/PIT.h" -#include "thread/Scheduler.h" -#include "utils/Time.h" -#include - -static uint64_t unix_boot_time; - -#define CLOCK_REALTIME 0 -#define CLOCK_MONOTONIC 1 -#define CLOCK_PROCTIME 2 - -struct timeval -{ - time_t tv_sec; - suseconds_t tv_usec; -}; - -struct timespec -{ - time_t tv_sec; - long tv_nsec; -}; - -static void ms_to_timespec(long ms, struct timespec* tv) -{ - tv->tv_sec = ms / 1000; - tv->tv_nsec = (ms % 1000) * 1000000; -} - -void sys_clock_gettime(Context* context, int clock, struct timespec* tp) -{ - struct timespec ktp; - Task* current_task = Scheduler::current_task(); - switch (clock) - { - case CLOCK_REALTIME: { - ms_to_timespec(PIT::ms_since_boot, &ktp); - ktp.tv_sec += unix_boot_time; - break; - } - case CLOCK_MONOTONIC: { - ms_to_timespec(PIT::ms_since_boot, &ktp); - break; - } - case CLOCK_PROCTIME: { - ms_to_timespec(current_task->cpu_time, &ktp); - break; - } - default: context->rax = -EINVAL; return; - } - if (!copy_typed_to_user(tp, &ktp)) context->rax = -EFAULT; - else - context->rax = 0; - return; -} - -extern BOOTBOOT bootboot; - -void clock_init() -{ - unix_boot_time = unix_boottime(bootboot.datetime); -} - -uint64_t clock_now() -{ - return unix_boot_time + (PIT::ms_since_boot / 1000); -} - -uint64_t clock_boot() -{ - return unix_boot_time; -} \ No newline at end of file diff --git a/kernel/src/sys/clock_gettime.cpp b/kernel/src/sys/clock_gettime.cpp new file mode 100644 index 00000000..d46a388d --- /dev/null +++ b/kernel/src/sys/clock_gettime.cpp @@ -0,0 +1,34 @@ +#include "arch/Timer.h" +#include "memory/MemoryManager.h" +#include "sys/Syscall.h" +#include +#include + +Result sys_clock_gettime(Registers*, SyscallArgs args) +{ + clockid_t id = (clockid_t)args[0]; + struct timespec* ts = (struct timespec*)args[1]; + + switch (id) + { + case CLOCK_MONOTONIC: { + usize ticks = Timer::ticks_ns(); + struct timespec kernel_ts; + kernel_ts.tv_sec = (time_t)(ticks / NS_PER_SECOND); + kernel_ts.tv_nsec = (long)(ticks % NS_PER_SECOND); + if (!MemoryManager::copy_to_user_typed(ts, &kernel_ts)) return err(EFAULT); + break; + } + case CLOCK_REALTIME: { + usize clock = Timer::clock_ns(); + struct timespec kernel_ts; + kernel_ts.tv_sec = (time_t)(clock / NS_PER_SECOND); + kernel_ts.tv_nsec = (long)(clock % NS_PER_SECOND); + if (!MemoryManager::copy_to_user_typed(ts, &kernel_ts)) return err(EFAULT); + break; + } + default: return err(EINVAL); + } + + return 0; +} diff --git a/kernel/src/sys/console_write.cpp b/kernel/src/sys/console_write.cpp new file mode 100644 index 00000000..4c00d560 --- /dev/null +++ b/kernel/src/sys/console_write.cpp @@ -0,0 +1,15 @@ +#include "memory/MemoryManager.h" +#include "sys/Syscall.h" +#include "video/TextConsole.h" + +Result sys_console_write(Registers*, SyscallArgs args) +{ + char* ptr = (char*)args[0]; + usize size = (usize)args[1]; + + if (!MemoryManager::validate_user_read(ptr, size)) return err(EFAULT); + + while (size--) { TextConsole::putchar(*ptr++); } + + return { 0 }; +} diff --git a/kernel/src/sys/dirent.cpp b/kernel/src/sys/dirent.cpp deleted file mode 100644 index 1e205974..00000000 --- a/kernel/src/sys/dirent.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#define MODULE "dir" - -#include "luna/dirent.h" -#include "fs/VFS.h" -#include "interrupts/Context.h" -#include "std/errno.h" -#include "std/string.h" -#include "sys/UserMemory.h" -#include "thread/Scheduler.h" - -void sys_getdents(Context* context, int fd, struct luna_dirent* buf, size_t count) -{ - if (fd < 0 || fd > TASK_MAX_FDS) - { - context->rax = -EBADF; - return; - } - Task* current_task = Scheduler::current_task(); - if (!current_task->files[fd].is_open()) - { - context->rax = -EBADF; - return; - } - Descriptor& dir = current_task->files[fd]; - VFS::Node* node = dir.node(); - if (node->type != VFS_DIRECTORY) - { - context->rax = -ENOTDIR; - return; - } - size_t nread = 0; - while (count) - { - VFS::Node* entry = VFS::readdir(node, dir.offset()); - if (!entry) - { - context->rax = nread; - return; - } - - luna_dirent dirent; - - dirent.total = node->length; - dirent.offset = dir.offset(); - dirent.inode = entry->inode; - strlcpy(dirent.name, entry->name, sizeof(dirent.name)); - - if (!copy_typed_to_user(buf, &dirent)) - { - context->rax = -EFAULT; - return; - } - - dir.seek(dir.offset() + 1); - buf++; - nread++; - count--; - } - context->rax = nread; -} \ No newline at end of file diff --git a/kernel/src/sys/elf/ELFLoader.cpp b/kernel/src/sys/elf/ELFLoader.cpp deleted file mode 100644 index 2673b07e..00000000 --- a/kernel/src/sys/elf/ELFLoader.cpp +++ /dev/null @@ -1,225 +0,0 @@ -#define MODULE "elf" - -#include "sys/elf/ELFLoader.h" -#include "fs/InitRD.h" -#include "fs/VFS.h" -#include "log/Log.h" -#include "memory/Memory.h" -#include "memory/MemoryManager.h" -#include "memory/VMM.h" -#include "misc/utils.h" -#include "std/ensure.h" -#include "std/errno.h" -#include "std/stdlib.h" -#include "std/string.h" -#include "sys/elf/ELF.h" -#include "utils/Addresses.h" - -static const char* format_permissions(uint32_t flags) -{ - static char perms[4]; - perms[0] = (flags & 4) > 0 ? 'r' : '-'; - perms[1] = (flags & 2) > 0 ? 'w' : '-'; - perms[2] = (flags & 1) > 0 ? 'x' : '-'; - perms[3] = 0; - return perms; -} - -static bool can_execute_segment(int flags) -{ - return flags & 1; -} - -static bool can_write_segment(int flags) -{ - return flags & 2; -} - -ELFImage* ELFLoader::load_elf_from_filesystem(const char* filename) -{ - VFS::Node* node = VFS::resolve_path(filename); - - if (!node) - { - kwarnln("Failed to open file %s for loading", filename); - return 0; - } - - if (node->type == VFS_DIRECTORY) - { - kwarnln("Failed to load %s: is a directory", filename); - return 0; - } - - ELFImage* result = load_elf_from_vfs(node); - return result; -} - -long ELFLoader::check_elf_image_from_filesystem(const char* filename) -{ - VFS::Node* node = VFS::resolve_path(filename); - - if (!node) - { - kwarnln("Failed to open file %s for checking", filename); - return -ENOENT; - } - - if (node->type == VFS_DIRECTORY) - { - kwarnln("Failed to check %s: is a directory", filename); - return -EISDIR; - } - - return check_elf_image(node); -} - -ELFImage* ELFLoader::load_elf_from_vfs(VFS::Node* node) -{ - Elf64_Ehdr elf_ehdr; - ensure(VFS::read(node, 0, sizeof(elf_ehdr), (char*)&elf_ehdr) >= 0); - ensure(strncmp((const char*)elf_ehdr.e_ident, ELFMAG, SELFMAG) == - 0); // If you haven't checked the ELF executable with check_elf_image() first, then an assertion fail is your - // fault =D - ensure(elf_ehdr.e_ident[EI_CLASS] == ELFCLASS64); - ensure(elf_ehdr.e_ident[EI_DATA] == ELFDATA2LSB); - ensure(elf_ehdr.e_type == ET_EXEC); - ensure(elf_ehdr.e_machine == EM_MACH); - ensure(elf_ehdr.e_phnum != 0); - ELFImage* image = (ELFImage*)kmalloc(sizeof(ELFImage) - sizeof(ELFSection)); - memset(image, 0, sizeof(ELFImage) - sizeof(ELFSection)); - image->entry = elf_ehdr.e_entry; - int i; - Elf64_Phdr phdr; - for (VFS::read(node, elf_ehdr.e_phoff, sizeof(Elf64_Phdr), (char*)&phdr), i = 0; i < elf_ehdr.e_phnum; - i++, VFS::read(node, elf_ehdr.e_phoff + (i * elf_ehdr.e_phentsize), sizeof(Elf64_Phdr), (char*)&phdr)) - { - if (phdr.p_type == PT_LOAD) - { - kdbgln("Loading loadable segment at address %lx, file size %ld, mem size %ld, permissions %s", phdr.p_vaddr, - phdr.p_filesz, phdr.p_memsz, format_permissions(phdr.p_flags)); - ensure(phdr.p_vaddr); - - ensure(!(can_write_segment(phdr.p_flags) && can_execute_segment(phdr.p_flags))); - - uint64_t pages = Utilities::get_blocks_from_size(PAGE_SIZE, (phdr.p_vaddr % PAGE_SIZE) + phdr.p_memsz); - void* buffer = (void*)((uint64_t)MemoryManager::get_pages_at(round_down_to_nearest_page(phdr.p_vaddr), - pages, MAP_READ_WRITE) - .release_value() // FIXME: We check for enough space before loading the ELF, - // although a race condition could happen. - + (phdr.p_vaddr % PAGE_SIZE)); - - if (VMM::is_using_kernel_address_space()) { VMM::switch_to_previous_user_address_space(); } - VMM::apply_address_space(); - - VFS::read(node, phdr.p_offset, phdr.p_filesz, (char*)buffer); - memset((void*)((uint64_t)buffer + phdr.p_filesz), 0, phdr.p_memsz - phdr.p_filesz); - - VMM::switch_back_to_kernel_address_space(); - VMM::apply_address_space(); - VMM::switch_to_previous_user_address_space(); - - int new_flags = MAP_USER | MAP_AS_OWNED_BY_TASK; - if (can_write_segment(phdr.p_flags)) new_flags |= MAP_READ_WRITE; - else if (can_execute_segment(phdr.p_flags)) - new_flags |= MAP_EXEC; - - MemoryManager::protect(buffer, pages, new_flags); - - image = (ELFImage*)krealloc(image, (sizeof(ELFImage) - sizeof(ELFSection)) + - (image->section_count + 1) * sizeof(ELFSection)); - ELFSection& section = image->sections[image->section_count]; - section.base = (uintptr_t)buffer; - section.pages = pages; - image->section_count++; - } - else { kdbgln("skipping non-loadable segment"); } - } - ensure(image->section_count); - return image; -} - -long ELFLoader::check_elf_image(VFS::Node* node) -{ - Elf64_Ehdr elf_ehdr; - if (VFS::read(node, 0, sizeof(elf_ehdr), (char*)&elf_ehdr) < (long)sizeof(elf_ehdr)) - { - kwarnln("Unable to read ELF header"); - return -ENOEXEC; - } - if (strncmp((const char*)elf_ehdr.e_ident, ELFMAG, SELFMAG) != 0) - { - kwarnln("ELF file has invalid magic, skipping"); - return -ENOEXEC; - } - if (elf_ehdr.e_ident[EI_CLASS] != ELFCLASS64) - { - kwarnln("ELF file is not ELF64, skipping"); - return -ENOEXEC; - } - if (elf_ehdr.e_ident[EI_DATA] != ELFDATA2LSB) - { - kwarnln("ELF file is not little-endian, skipping"); - return -ENOEXEC; - } - if (elf_ehdr.e_type != ET_EXEC) - { - kwarnln("not supported: ELF file is not an executable"); - return -ENOEXEC; - } - if (elf_ehdr.e_machine != EM_MACH) - { - kwarnln("Unsupported target machine"); - return -ENOEXEC; - } - if (elf_ehdr.e_phnum == 0) - { - kwarnln("ELF file has no PHDRS"); - return -ENOEXEC; - } - int i; - int loadable_sections = 0; - long memusage = 0; - Elf64_Phdr phdr; - for (VFS::read(node, elf_ehdr.e_phoff, sizeof(Elf64_Phdr), (char*)&phdr), i = 0; i < elf_ehdr.e_phnum; - i++, VFS::read(node, elf_ehdr.e_phoff + (i * elf_ehdr.e_phentsize), sizeof(Elf64_Phdr), (char*)&phdr)) - { - if (phdr.p_type == PT_LOAD) - { - if (!phdr.p_vaddr) - { - kerrorln("segment address is NULL, this is invalid :("); - return -ENOEXEC; - } - if (Memory::is_kernel_address(phdr.p_vaddr) || Memory::is_kernel_address(phdr.p_vaddr + phdr.p_memsz)) - { - kerrorln("trying to load ELF into kernel memory"); - return -ENOEXEC; - } - if (can_write_segment(phdr.p_flags) && can_execute_segment(phdr.p_flags)) - { - kwarnln("executable violates W^X"); - return -ENOEXEC; - } - loadable_sections++; - memusage += Utilities::get_blocks_from_size(PAGE_SIZE, phdr.p_memsz) * PAGE_SIZE; - } - } - if (!loadable_sections) - { - kwarnln("No loadable sections"); - return -ENOEXEC; - } - return memusage; -} - -void ELFLoader::release_elf_image(ELFImage* image) -{ - for (uint64_t i = 0; i < image->section_count; i++) - { - ELFSection& section = image->sections[i]; - kdbgln("Freeing up section %lx, was using %ld pages", section.base, section.pages); - MemoryManager::release_pages((void*)round_down_to_nearest_page(section.base), section.pages); - } - kfree(image); -} diff --git a/kernel/src/sys/exec.cpp b/kernel/src/sys/exec.cpp deleted file mode 100644 index 962d0c42..00000000 --- a/kernel/src/sys/exec.cpp +++ /dev/null @@ -1,260 +0,0 @@ -#define MODULE "exec" - -#include "interrupts/Interrupts.h" -#include "log/Log.h" -#include "memory/Memory.h" -#include "memory/MemoryManager.h" -#include "memory/PMM.h" -#include "memory/VMM.h" -#include "std/ensure.h" -#include "std/errno.h" -#include "std/stdlib.h" -#include "std/string.h" -#include "sys/Syscall.h" -#include "sys/UserMemory.h" -#include "sys/elf/ELFLoader.h" -#include "thread/Scheduler.h" - -void sys_fork(Context* context) -{ - kinfoln("fork(): attempting fork"); - - Task* parent = Scheduler::current_task(); - - Task* child = Scheduler::create_user_task(); - if (!child) - { - context->rax = -ENOMEM; - return; - } - - if (!child->allocator.inherit(parent->allocator)) - { - child->state = child->Exited; - child->exit_status = -127; // so the reaper reaps it on next reaping - context->rax = -ENOMEM; - return; - } - - child->save_context(context); - child->save_floating(); - - for (int i = 0; i < TASK_MAX_FDS; i++) { child->files[i] = parent->files[i]; } - - child->address_space = parent->address_space.clone(); - - child->ppid = parent->id; - - child->uid = parent->uid; - child->euid = parent->euid; - child->gid = parent->gid; - child->egid = parent->egid; - - child->regs.rax = 0; - context->rax = child->id; - - strlcpy(child->name, parent->name, sizeof(child->name)); - - child->state = child->Running; - - kinfoln("fork(): forked parent %ld into child %ld", parent->id, child->id); - - return; -} - -void push_on_user_stack(uint64_t* rsp, char* value, - size_t size) // FIXME: Handle segments of stack that extend beyond one page. -{ - (*rsp) -= size; - char* kvalue = (char*)VMM::get_physical(*rsp); - ensure(kvalue != (char*)UINT64_MAX); - memcpy(kvalue, value, size); -} - -void sys_execv(Context* context, const char* pathname, char** argv) -{ - auto result = strdup_from_user(pathname); - if (result.has_error()) - { - context->rax = -result.error(); - return; - } - char* kpathname = result.release_value(); - - kinfoln("exec(): executing %s", kpathname); - - VFS::Node* program = VFS::resolve_path(kpathname); - if (!program) - { - kfree(kpathname); - context->rax = -ENOENT; - return; - } - - if (program->type == VFS_DIRECTORY) - { - kfree(kpathname); - context->rax = -EISDIR; - return; - } - - if (!VFS::can_execute(program, Scheduler::current_task()->euid, Scheduler::current_task()->egid)) - { - kfree(kpathname); - context->rax = -EACCES; - return; - } - - long memusage; - if ((memusage = ELFLoader::check_elf_image(program)) < 0) - { - kfree(kpathname); - context->rax = -ENOEXEC; - return; - } - - if ((uint64_t)memusage > PMM::get_free()) - { - kfree(kpathname); - context->rax = -ENOMEM; - return; - } - - uint64_t kargc = 0; - char** kargv = nullptr; - char* arg; - - auto free_kernel_argv_copy = [&]() { - for (uint64_t i = 0; i < kargc; i++) - { - if (kargv[i]) kfree(kargv[i]); - } - if (kargv) kfree(kargv); - }; - - // FIXME: This code is a bit messy. Should probably be refactored and moved into a separate function. - - do { - if (!copy_from_user(argv, &arg, sizeof(char*))) - { - free_kernel_argv_copy(); - context->rax = -EFAULT; - return; - } - kargv = (char**)krealloc(kargv, (kargc + 1) * sizeof(char*)); // we need a vector class for the kernel. - if (!kargv) - { - free_kernel_argv_copy(); - context->rax = -ENOMEM; - return; - } - if (arg) - { - auto rc = strdup_from_user(arg); - if (rc.has_error()) // FIXME: This could also be EFAULT. - { - free_kernel_argv_copy(); - context->rax = -rc.error(); - return; - } - kargv[kargc] = rc.release_value(); - } - else - { - kargv[kargc] = nullptr; - break; - } - kargc++; - argv++; - } while (arg != nullptr); - - kinfoln("Copied %lu arguments from user process", kargc); - - size_t stack_size = 0; - for (uint64_t i = 0; i <= kargc; i++) - { - stack_size += sizeof(char*); - if (kargv[i]) - { - stack_size += strlen(kargv[i]) + 1; // count the null byte - } - } - - if (stack_size > - ((TASK_PAGES_IN_STACK / 2) * - PAGE_SIZE)) // FIXME: Maybe we should allocate a larger stack in this case, but still set a larger upper limit. - { - free_kernel_argv_copy(); - context->rax = -E2BIG; - return; - } - - char** user_argv = (char**)kcalloc(kargc + 1, sizeof(char*)); - if (!user_argv) - { - free_kernel_argv_copy(); - context->rax = -ENOMEM; - return; - } - - Interrupts::disable(); - ensure(!Interrupts::are_enabled()); // This part is pretty sensitive. - - Task* task = Scheduler::current_task(); - ensure(task); - - // At this point, pretty much nothing can fail. (FIXME: Race conditions could happen) - - task->allocator.free(); - task->allocator - .init(); // If we had enough space for the old bitmap, we should have enough space for the new bitmap. - - task->address_space.clear(); - task->allocated_stack = (uint64_t)MemoryManager::get_pages_at(0x100000, TASK_PAGES_IN_STACK, - MAP_USER | MAP_READ_WRITE | MAP_AS_OWNED_BY_TASK) - .release_value(); // If we had enough space for the old stack, there should be - // enough space for the new stack. - - ELFImage* image = ELFLoader::load_elf_from_vfs(program); - ensure(image); // If check_elf_image succeeded, load_elf_from_vfs MUST succeed, unless something has gone terribly - // wrong. - - if (VFS::is_setuid(program)) task->euid = program->uid; - if (VFS::is_setgid(program)) task->egid = program->gid; - - strlcpy(task->name, kpathname, sizeof(task->name)); - - Scheduler::reset_task(task, image); - - for (int i = 0; i < TASK_MAX_FDS; i++) - { - Descriptor& file = task->files[i]; - if (file.close_on_exec()) { file.close(); } - } - - for (uint64_t i = 0; i <= kargc; i++) - { - if (kargv[i]) - { - push_on_user_stack(&task->regs.rsp, kargv[i], strlen(kargv[i]) + 1); - user_argv[i] = (char*)task->regs.rsp; - } - else - user_argv[i] = nullptr; - } - push_on_user_stack(&task->regs.rsp, (char*)user_argv, (kargc + 1) * sizeof(char*)); - task->regs.rdi = kargc; // argc - task->regs.rsi = task->regs.rsp; // argv - - task->regs.rsp &= (UINT64_MAX ^ 15); // align it - - free_kernel_argv_copy(); - - kfree(user_argv); - - kfree(kpathname); - - task->restore_context(context); - - return; -} \ No newline at end of file diff --git a/kernel/src/sys/exit.cpp b/kernel/src/sys/exit.cpp new file mode 100644 index 00000000..adc591c1 --- /dev/null +++ b/kernel/src/sys/exit.cpp @@ -0,0 +1,7 @@ +#include "sys/Syscall.h" +#include "thread/Scheduler.h" + +Result sys_exit(Registers*, SyscallArgs) +{ + kernel_exit(); +} diff --git a/kernel/src/sys/id.cpp b/kernel/src/sys/id.cpp deleted file mode 100644 index 1d330359..00000000 --- a/kernel/src/sys/id.cpp +++ /dev/null @@ -1,123 +0,0 @@ -#include "std/errno.h" -#include "thread/Scheduler.h" -#include - -#define ID_PID 0 -#define ID_PPID 1 -#define ID_UID 2 -#define ID_EUID 3 -#define ID_GID 4 -#define ID_EGID 5 - -void sys_getprocid(Context* context, int field) -{ - if (field == ID_PID) - { - context->rax = Scheduler::current_task()->id; - return; - } - else if (field == ID_PPID) - { - context->rax = Scheduler::current_task()->ppid; - return; - } - else if (field == ID_UID) - { - context->rax = Scheduler::current_task()->uid; - return; - } - else if (field == ID_EUID) - { - context->rax = Scheduler::current_task()->euid; - return; - } - else if (field == ID_GID) - { - context->rax = Scheduler::current_task()->gid; - return; - } - else if (field == ID_EGID) - { - context->rax = Scheduler::current_task()->egid; - return; - } - else - { - context->rax = -EINVAL; - return; - } -} - -void sys_setuid(Context* context, uid_t uid) -{ - Task* current_task = Scheduler::current_task(); - - if (!current_task->is_superuser()) - { - if (uid != current_task->uid && uid != current_task->euid) - { - context->rax = -EPERM; - return; - } - } - - current_task->uid = uid; - current_task->euid = uid; - - context->rax = 0; -} - -void sys_seteuid(Context* context, uid_t euid) -{ - Task* current_task = Scheduler::current_task(); - - if (!current_task->is_superuser()) - { - if (euid != current_task->uid) - { - context->rax = -EPERM; - return; - } - } - - current_task->euid = euid; - - context->rax = 0; -} - -void sys_setgid(Context* context, gid_t gid) -{ - Task* current_task = Scheduler::current_task(); - - if (!current_task->is_superuser()) - { - if (gid != current_task->gid && gid != current_task->egid) - { - context->rax = -EPERM; - return; - } - } - - current_task->gid = gid; - current_task->egid = gid; - - context->rax = 0; -} - -void sys_setegid(Context* context, gid_t egid) -{ - Task* current_task = Scheduler::current_task(); - - if (!current_task->is_superuser()) - { - if (egid != current_task->gid) - { - context->rax = -EPERM; - return; - } - } - - current_task->egid = egid; - - context->rax = 0; -} \ No newline at end of file diff --git a/kernel/src/sys/mem.cpp b/kernel/src/sys/mem.cpp deleted file mode 100644 index 99a6a0b0..00000000 --- a/kernel/src/sys/mem.cpp +++ /dev/null @@ -1,226 +0,0 @@ -#define MODULE "mem" - -#include "interrupts/Context.h" -#include "log/Log.h" -#include "memory/Memory.h" -#include "memory/MemoryManager.h" -#include "memory/VMM.h" -#include "misc/utils.h" -#include "std/errno.h" -#include "thread/Scheduler.h" -#include - -#define PROT_READ 1 -#define PROT_WRITE 2 -#define PROT_NONE 0 -#define PROT_EXEC 4 - -#define MAP_FAIL(errno) 0xffffffffffffff00 | (unsigned char)(errno) - -static const char* format_prot(int prot) -{ - static char prot_string[4]; - prot_string[3] = 0; - prot_string[0] = ((prot & PROT_READ) > 0) ? 'r' : '-'; - prot_string[1] = ((prot & PROT_WRITE) > 0) ? 'w' : '-'; - prot_string[2] = ((prot & PROT_EXEC) > 0) ? 'x' : '-'; - return prot_string; -} - -static int mman_flags_from_prot(int prot) -{ - prot &= 0b111; - int flags = MAP_USER | MAP_AS_OWNED_BY_TASK; - if (prot == PROT_NONE) return MAP_AS_OWNED_BY_TASK; - if ((prot & PROT_WRITE) > 0) { flags |= MAP_READ_WRITE; } - if ((prot & PROT_EXEC) > 0) { flags |= MAP_EXEC; } - return flags; -} - -void sys_mmap(Context* context, void* address, size_t size, int prot, int fd, off_t offset) -{ - if (size < PAGE_SIZE) - { - kwarnln("mmap(): size too small"); - context->rax = MAP_FAIL(EINVAL); - return; - } - if (size % PAGE_SIZE) - { - kwarnln("mmap(): size not a multiple of PAGE_SIZE"); - context->rax = MAP_FAIL(EINVAL); - return; - } - int real_flags = mman_flags_from_prot(prot); - if (address) - { - kdbgln("mmap(): %ld pages at address %p, %s, fd %d", size / PAGE_SIZE, address, format_prot(prot), fd); - if (Memory::is_kernel_address((uintptr_t)address)) - { - kwarnln("munmap() failed: attempted to unmap a kernel page"); - context->rax = MAP_FAIL(ENOMEM); - return; - } - if (VMM::get_physical((uint64_t)address) != (uint64_t)-1) // Address is already used. - { - kwarnln("attempt to map an already mapped address"); - context->rax = MAP_FAIL(ENOMEM); - return; - } - uint64_t addr_offset = (uint64_t)address % PAGE_SIZE; - if (fd >= 0) - { - int err; - Descriptor* file = Scheduler::current_task()->open_descriptor_from_fd(fd, err); - if (!file) - { - context->rax = MAP_FAIL(err); - return; - } - context->rax = file->mmap((uint64_t)address - addr_offset, size, real_flags, offset); - return; - } - auto result = MemoryManager::get_pages_at((uint64_t)address - addr_offset, - Utilities::get_blocks_from_size(PAGE_SIZE, size), real_flags); - if (result.has_value()) - { - kdbgln("mmap() succeeded: %p", result.value()); - context->rax = (uint64_t)result.release_value(); - return; - } - else - { - kwarnln("mmap() failed: failed to allocate physical memory"); - context->rax = MAP_FAIL(result.error()); - return; - } - } - kdbgln("mmap(): %ld pages at any address, %s, fd %d", Utilities::get_blocks_from_size(PAGE_SIZE, size), - format_prot(prot), fd); - uint64_t ptr = - Scheduler::current_task()->allocator.request_virtual_pages(Utilities::get_blocks_from_size(PAGE_SIZE, size)); - if (!ptr) - { - kwarnln("mmap() failed: failed to allocate virtual address"); - context->rax = MAP_FAIL(ENOMEM); - return; - } - if (fd >= 0) - { - int err; - Descriptor* file = Scheduler::current_task()->open_descriptor_from_fd(fd, err); - if (!file) - { - context->rax = MAP_FAIL(err); - return; - } - context->rax = file->mmap(ptr, size, real_flags, offset); - return; - } - auto result = MemoryManager::get_pages_at(ptr, Utilities::get_blocks_from_size(PAGE_SIZE, size), real_flags); - if (result.has_value()) - { - kdbgln("mmap() succeeded: %p", result.value()); - context->rax = (uint64_t)result.release_value(); - return; - } - else - { - kwarnln("mmap() failed: failed to allocate physical memory"); - context->rax = MAP_FAIL(result.error()); - return; - } -} - -void sys_munmap(Context* context, void* address, size_t size) -{ - kdbgln("munmap(): attempting to unmap %p", address); - if (size < PAGE_SIZE) - { - kwarnln("munmap() failed: size is too small"); - context->rax = -EINVAL; - return; - } - if (size % PAGE_SIZE) - { - kwarnln("munmap() failed: size is not a multiple of PAGE_SIZE"); - context->rax = -EINVAL; - return; - } - if (!address) - { - kwarnln("munmap() failed: attempted to unmap page 0"); - context->rax = -EINVAL; - return; - } - if (Memory::is_kernel_address((uintptr_t)address)) - { - kwarnln("munmap() failed: attempted to unmap a kernel page"); - context->rax = -EINVAL; - return; - } - uint64_t flags = VMM::get_flags((uint64_t)address); - if (flags == (uint64_t)-1) - { - kwarnln("munmap() failed: attempted to unmap a non-existent page"); - context->rax = -EINVAL; - return; - } - uint64_t offset = (uint64_t)address % PAGE_SIZE; - Scheduler::current_task()->allocator.free_virtual_pages(((uint64_t)address - offset), - Utilities::get_blocks_from_size(PAGE_SIZE, size)); - if (flags & MAP_AS_OWNED_BY_TASK) - MemoryManager::release_pages((void*)((uint64_t)address - offset), - Utilities::get_blocks_from_size(PAGE_SIZE, size)); - else - MemoryManager::release_unaligned_mappings((void*)((uint64_t)address - offset), - Utilities::get_blocks_from_size(PAGE_SIZE, size)); - kdbgln("munmap() succeeded"); - context->rax = 0; - return; -} - -void sys_mprotect(Context* context, void* address, size_t size, int prot) -{ - kdbgln("mprotect(): attempting to protect %p with %s", address, format_prot(prot)); - - if (size < PAGE_SIZE) - { - kwarnln("mprotect() failed: size is too small"); - context->rax = -EINVAL; - return; - } - if (size % PAGE_SIZE) - { - kwarnln("mprotect() failed: size is not a multiple of PAGE_SIZE"); - context->rax = -EINVAL; - return; - } - if (!address) - { - kwarnln("mprotect() failed: attempted to protect page 0"); - context->rax = -EINVAL; - return; - } - if (Memory::is_kernel_address((uintptr_t)address)) - { - kwarnln("mprotect() failed: attempted to protect a kernel page"); - context->rax = -EINVAL; - return; - } - uint64_t flags = VMM::get_flags((uint64_t)address); - if (flags == (uint64_t)-1) - { - kwarnln("mprotect() failed: attempted to protect a non-existent page"); - context->rax = -EINVAL; - return; - } - - uint64_t offset = (uint64_t)address % PAGE_SIZE; - MemoryManager::protect((void*)((uint64_t)address - offset), Utilities::get_blocks_from_size(PAGE_SIZE, size), - flags & MAP_AS_OWNED_BY_TASK ? mman_flags_from_prot(prot) - : mman_flags_from_prot(prot) & ~(MAP_AS_OWNED_BY_TASK)); - kdbgln("mprotect() succeeded"); - context->rax = 0; - return; -} \ No newline at end of file diff --git a/kernel/src/sys/sched.cpp b/kernel/src/sys/sched.cpp deleted file mode 100644 index 6112d3c9..00000000 --- a/kernel/src/sys/sched.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "memory/VMM.h" -#include "std/errno.h" -#include "sys/UserMemory.h" -#include "thread/Scheduler.h" - -void sys_exit(Context* context, int status) -{ - Scheduler::task_exit(context, status); -} - -void sys_yield(Context* context) -{ - context->rax = 0; - Scheduler::task_yield(context); -} - -void sys_sleep(Context* context, uint64_t ms) -{ - context->rax = 0; - Task* task = Scheduler::current_task(); - task->task_sleep = ms; - task->state = task->Sleeping; - Scheduler::task_yield(context); -} \ No newline at end of file diff --git a/kernel/src/sys/stat.cpp b/kernel/src/sys/stat.cpp deleted file mode 100644 index 5d026633..00000000 --- a/kernel/src/sys/stat.cpp +++ /dev/null @@ -1,78 +0,0 @@ -#include "fs/VFS.h" -#include "interrupts/Context.h" -#include "std/errno.h" -#include "std/stdlib.h" -#include "sys/UserMemory.h" -#include "thread/Scheduler.h" - -typedef unsigned short mode_t; -typedef unsigned long ino_t; - -struct stat // FIXME: This struct is quite stubbed out. -{ - ino_t st_ino; - mode_t st_mode; - off_t st_size; - int st_dev; // FIXME: Implement this. - int st_nlink; // FIXME: Implement this. - uid_t st_uid; - gid_t st_gid; - time_t st_atime; - time_t st_mtime; - time_t st_ctime; -}; - -void do_stat(Context* context, VFS::Node* node, struct stat* buf) -{ - struct stat stat; - stat.st_ino = node->inode; - stat.st_mode = node->mode | ((1 << (node->type)) * 010000); - stat.st_size = node->length; - stat.st_uid = node->uid; - stat.st_gid = node->gid; - stat.st_atime = node->atime; - stat.st_ctime = node->ctime; - stat.st_mtime = node->mtime; - stat.st_dev = 0; - stat.st_nlink = 0; - if (!copy_typed_to_user(buf, &stat)) context->rax = -EFAULT; - else - context->rax = 0; -} - -void sys_fstat(Context* context, int fd, struct stat* buf) -{ - Task* current_task = Scheduler::current_task(); - if (fd < 0 || fd >= TASK_MAX_FDS) - { - context->rax = -EBADF; - return; - } - Descriptor& file = current_task->files[fd]; - if (!file.is_open()) - { - context->rax = -EBADF; - return; - } - VFS::Node* node = file.node(); - return do_stat(context, node, buf); -} - -void sys_stat(Context* context, const char* path, struct stat* buf) -{ - auto result = strdup_from_user(path); - if (result.has_error()) - { - context->rax = -result.error(); - return; - } - char* kpath = result.release_value(); - VFS::Node* node = VFS::resolve_path(kpath); - kfree(kpath); - if (!node) - { - context->rax = -ENOENT; - return; - } - return do_stat(context, node, buf); -} \ No newline at end of file diff --git a/kernel/src/sys/stdio.cpp b/kernel/src/sys/stdio.cpp deleted file mode 100644 index 453f0ff5..00000000 --- a/kernel/src/sys/stdio.cpp +++ /dev/null @@ -1,397 +0,0 @@ -#define MODULE "stdio" - -#include "interrupts/Context.h" -#include "io/Serial.h" -#include "log/Log.h" -#include "memory/VMM.h" -#include "render/TextRenderer.h" -#include "std/errno.h" -#include "std/stdlib.h" -#include "sys/Syscall.h" -#include "sys/UserMemory.h" -#include "thread/Scheduler.h" -#include "thread/Task.h" -#include - -#define OPEN_READ 1 -#define OPEN_WRITE 2 -#define OPEN_NONBLOCK 4 -#define OPEN_CLOEXEC 8 -#define OPEN_DIRECTORY 16 -#define OPEN_TRUNCATED 32 -#define OPEN_CREATE 64 -#define OPEN_APPEND 128 -#define OPEN_EXCL 256 - -#define SEEK_SET 0 -#define SEEK_CUR 1 -#define SEEK_END 2 - -#define FCNTL_DUPFD 0 -#define FCNTL_ISTTY 1 -#define FCNTL_GETFD 2 -#define FCNTL_SETFD 3 - -#define FD_CLOEXEC 1 - -void sys_fcntl(Context* context, int fd, int command, uintptr_t arg) -{ - Task* current_task = Scheduler::current_task(); - int err; - Descriptor* file = current_task->open_descriptor_from_fd(fd, err); - if (!file) - { - context->rax = -err; - return; - } - if (command == FCNTL_DUPFD) - { - int minfd = (int)arg; - if (minfd < 0 || minfd >= TASK_MAX_FDS) - { - context->rax = -EINVAL; - return; - } - int dupfd = current_task->alloc_fd_greater_than_or_equal(minfd); - if (dupfd < 0) - { - context->rax = -EMFILE; - return; - } - current_task->files[dupfd] = *file; - context->rax = dupfd; - kdbgln("fcntl(F_DUPFD): duplicated fd %d, result is %d", fd, dupfd); - return; - } - else if (command == FCNTL_ISTTY) - { - VFS::Node* node = file->node(); - if (node->tty) { context->rax = 1; } - else - context->rax = -ENOTTY; - return; - } - else if (command == FCNTL_GETFD) - { - int flags = 0; - if (file->close_on_exec()) context->rax |= FD_CLOEXEC; - context->rax = flags; - return; - } - else if (command == FCNTL_SETFD) - { - int flags = (int)arg; - if (flags & FD_CLOEXEC) file->set_close_on_exec(true); - else - file->set_close_on_exec(false); - context->rax = 0; - return; - } - else - { - context->rax = -EINVAL; - return; - } -} - -void sys_seek(Context* context, int fd, long offset, int whence) -{ - if (whence < SEEK_SET || whence > SEEK_END) - { - context->rax = -EINVAL; - return; - } - int err; - Descriptor* file = Scheduler::current_task()->open_descriptor_from_fd(fd, err); - if (!file) - { - context->rax = -err; - return; - } - long new_offset; - if (whence == SEEK_SET) new_offset = offset; - else if (whence == SEEK_CUR) - new_offset = offset + file->offset(); - else if (whence == SEEK_END) - new_offset = file->length() + offset; - else - __builtin_unreachable(); - if (new_offset < 0) - { - context->rax = -EINVAL; // FIXME: Is this the right error? - return; - } - if (new_offset == file->offset()) - { - context->rax = new_offset; - return; - } - int result = file->seek(new_offset); - if (result < 0) - { - context->rax = result; - return; - } - context->rax = new_offset; - return; -} - -void sys_write(Context* context, int fd, size_t size, const char* addr) -{ - if (!validate_user_read((uintptr_t)addr, size)) - { - context->rax = -EFAULT; - return; - } - int err; - Descriptor* file = Scheduler::current_task()->open_descriptor_from_fd(fd, err); - if (!file) - { - context->rax = -err; - return; - } - if (!file->can_write()) - { - context->rax = -EBADF; - return; - } - ssize_t result = file->user_write(size, addr); - context->rax = (size_t)result; - return; -} - -void sys_open(Context* context, const char* filename, int flags, mode_t) // FIXME: mode is not used. -{ - Task* current_task = Scheduler::current_task(); - int fd = current_task->alloc_fd(); - if (fd < 0) - { - context->rax = -EMFILE; - return; - } - - auto result = strdup_from_user(filename); - if (result.has_error()) - { - context->rax = -result.error(); - return; - } - char* kfilename = result.release_value(); - - VFS::Node* node = VFS::resolve_path(kfilename); - if (!node) - { - bool create = (flags & OPEN_CREATE) > 0; - if (create) kwarnln("FIXME: open(O_CREAT) is not implemented"); - kfree(kfilename); - context->rax = -ENOENT; - return; - } - else - { - bool excl = (flags & OPEN_EXCL) > 0; - - if (excl) - { - kfree(kfilename); - context->rax = -EEXIST; - return; - } - } - - bool can_read = (flags & OPEN_READ) > 0; - bool can_write = (flags & OPEN_WRITE) > 0; - if (!can_read && !can_write) - { - kfree(kfilename); - context->rax = -EINVAL; - return; - } - - if (can_read && !VFS::can_read(node, current_task->euid, current_task->egid)) - { - kwarnln("open failed because process with uid %d and gid %d couldn't open file %s with mode %d for reading", - current_task->euid, current_task->egid, kfilename, node->mode); - kfree(kfilename); - context->rax = -EACCES; - return; - } - - if (can_write && !VFS::can_write(node, current_task->euid, current_task->egid)) - { - kwarnln("open failed because process with uid %d and gid %d couldn't open file %s with mode %d for writing", - current_task->euid, current_task->egid, kfilename, node->mode); - kfree(kfilename); - context->rax = -EACCES; - return; - } - - bool able_to_block = (flags & OPEN_NONBLOCK) == 0; - bool close_on_exec = (flags & OPEN_CLOEXEC) > 0; - - bool only_directory = (flags & OPEN_DIRECTORY) > 0; - - bool truncate = (flags & OPEN_TRUNCATED) > 0; - if (truncate) - { - kfree(kfilename); - kerrorln("FIXME: open(O_TRUNC) is not implemented"); - context->rax = -ENOTSUP; - return; - } - - bool append = (flags & OPEN_APPEND) > 0; - - if (only_directory && node->type != VFS_DIRECTORY) - { - kfree(kfilename); - context->rax = -ENOTDIR; - return; - } - - kdbgln("open(): opening %s %s, allocated file descriptor %d", kfilename, - (can_read && can_write) ? "rw" - : can_read ? "r-" - : "-w", - fd); - - kfree(kfilename); - current_task->files[fd].open(node, can_read, can_write, able_to_block, close_on_exec); - - if (append && current_task->files[fd].node()->type != VFS_DEVICE) - { - current_task->files[fd].seek((long)current_task->files[fd].length()); - } - - context->rax = fd; - return; -} - -void sys_read(Context* context, int fd, size_t size, char* buffer) -{ - if (!validate_user_write((uintptr_t)buffer, size)) - { - context->rax = -EFAULT; - return; - } - int err; - Descriptor* file = Scheduler::current_task()->open_descriptor_from_fd(fd, err); - if (!file) - { - context->rax = -err; - return; - } - if (!file->can_read()) - { - context->rax = -EBADF; - return; - } - if (VFS::would_block(file->node())) - { - if (!file->able_to_block()) - { - context->rax = -EAGAIN; - return; - } - Task* current_task = Scheduler::current_task(); - current_task->state = current_task->Blocking; - current_task->block_reason = BlockReason::Reading; - current_task->blocking_read_info.fd = fd; - current_task->blocking_read_info.buf = buffer; - current_task->blocking_read_info.size = size; - return Scheduler::task_yield(context); - } - ssize_t result = file->user_read(size, buffer); - context->rax = (size_t)result; - return; -} - -void sys_close(Context* context, int fd) -{ - int err; - Descriptor* file = Scheduler::current_task()->open_descriptor_from_fd(fd, err); - if (!file) - { - context->rax = -err; - return; - } - kdbgln("close(): releasing file descriptor %d", fd); - file->close(); - context->rax = 0; - return; -} - -void sys_mkdir(Context* context, const char* filename, mode_t mode) -{ - auto result = strdup_from_user(filename); - if (result.has_error()) - { - context->rax = -result.error(); - return; - } - char* kfilename = result.release_value(); - - Task* current_task = Scheduler::current_task(); - - int rc = VFS::do_mkdir(kfilename, current_task->euid, current_task->egid, mode & (~current_task->umask)); - - kfree(kfilename); - - context->rax = rc; -} - -void sys_access(Context* context, const char* path, int) // FIXME: Use the amode argument. -{ - auto result = strdup_from_user(path); - if (result.has_error()) - { - context->rax = -result.error(); - return; - } - char* kpath = result.release_value(); - if (!VFS::exists(kpath)) { context->rax = -ENOENT; } - else - context->rax = 0; - kfree(kpath); -} - -void sys_dup2(Context* context, int fd, int fd2) -{ - int err; - Descriptor* file1 = Scheduler::current_task()->open_descriptor_from_fd(fd, err); - if (!file1) - { - context->rax = -err; - return; - } - Descriptor* file2 = Scheduler::current_task()->descriptor_from_fd(fd2, err); - if (!file2) - { - context->rax = -err; - return; - } - if (file2->is_open()) file2->close(); - *file2 = *file1; - kinfoln("dup2(): overwrote fd %d with fd %d", fd2, fd); - context->rax = fd2; -} - -void sys_umask(Context* context, mode_t cmask) -{ - Task* current_task = Scheduler::current_task(); - context->rax = current_task->umask; - current_task->umask = cmask; -} - -void sys_ioctl(Context* context, int fd, int cmd, uintptr_t arg) -{ - int err; - Descriptor* file = Scheduler::current_task()->open_descriptor_from_fd(fd, err); - if (!file) - { - context->rax = -err; - return; - } - kinfoln("ioctl(): fd %d, cmd %d, arg %lu", fd, cmd, arg); - context->rax = file->ioctl(cmd, arg); -} \ No newline at end of file diff --git a/kernel/src/thread/PIT.cpp b/kernel/src/thread/PIT.cpp deleted file mode 100644 index 074e5b5e..00000000 --- a/kernel/src/thread/PIT.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#define MODULE "pit" - -#include "thread/PIT.h" -#include "io/IO.h" -#include "log/Log.h" - -#define PIT_CHANNEL_0_PORT 0x40 - -volatile uint64_t PIT::ms_since_boot = 0; -static uint16_t divisor = 65535; - -void PIT::initialize(uint64_t frequency) -{ - divisor = (uint16_t)(base_frequency / frequency); - kdbgln("Configuring PIT to use divisor %d (will tick %lu times per second)", divisor, frequency); - if (divisor < 100) divisor = 100; - IO::outb(PIT_CHANNEL_0_PORT, (uint8_t)(divisor & 0xFF)); - IO::delay(); - IO::outb(PIT_CHANNEL_0_PORT, (uint8_t)((divisor & 0xFF00) >> 8)); -} - -uint64_t PIT::frequency() -{ - return base_frequency / divisor; -} - -void PIT::tick() -{ - ms_since_boot += 1000 / frequency(); -} \ No newline at end of file diff --git a/kernel/src/thread/Scheduler.cpp b/kernel/src/thread/Scheduler.cpp index ed73d08d..851e7b47 100644 --- a/kernel/src/thread/Scheduler.cpp +++ b/kernel/src/thread/Scheduler.cpp @@ -1,633 +1,292 @@ -#define MODULE "sched" - #include "thread/Scheduler.h" -#include "interrupts/Interrupts.h" -#include "log/Log.h" +#include "ELF.h" +#include "Log.h" +#include "arch/CPU.h" +#include "arch/MMU.h" #include "memory/MemoryManager.h" -#include "memory/PMM.h" -#include "memory/VMM.h" -#include "misc/hang.h" -#include "misc/reboot.h" -#include "misc/utils.h" -#include "panic/Panic.h" -#include "std/ensure.h" -#include "std/errno.h" -#include "std/stdlib.h" -#include "std/string.h" -#include "sys/UserMemory.h" -#include "sys/elf/ELFLoader.h" -#include "thread/PIT.h" -#include "thread/Task.h" -#include "utils/Addresses.h" -#include "utils/Registers.h" +#include +#include -static uint64_t task_num = 0; +static Thread g_idle; +static Thread* g_current = nullptr; -static Task idle_task; +static const usize TICKS_PER_TIMESLICE = 20; -static uint64_t free_pid = 0; - -static Task* sched_current_task; -static Task* base_task; -static Task* end_task; - -extern "C" void idle_task_function(); - -static uint64_t frequency; - -template void sched_for_each_task(Callback callback) +namespace Scheduler { - Task* task = base_task; - if (!task) return; - do { - if (!task) break; - bool will_continue = callback(task); - if (!will_continue) break; - task = task->next_task; - } while (task != base_task); -} + void init() + { + g_idle.id = 0; + g_idle.init_regs_kernel(); + g_idle.set_ip((u64)CPU::idle_loop); + g_idle.state = ThreadState::Idle; + g_idle.is_kernel = true; -template void sched_for_each_child(Task* task, Callback callback) -{ - sched_for_each_task([&](Task* child) { - if (child->ppid == task->id) { return callback(child); } - return true; - }); -} + g_idle.ticks_left = 1; -Task* Scheduler::find_by_pid(uint64_t pid) -{ - Task* result = nullptr; - sched_for_each_task([&](Task* task) { - if (task->id == pid) + // Map some stack for the idle task + u64 idle_stack_vm = MemoryManager::alloc_for_kernel(1, MMU::NoExecute | MMU::ReadWrite) + .expect_value("Error while setting up the idle task, cannot continue"); + + Stack idle_stack { idle_stack_vm, ARCH_PAGE_SIZE }; + g_idle.set_sp(idle_stack.top()); + + g_idle.stack = idle_stack; + + kinfoln("CREATED IDLE THREAD: id %lu with ip %#lx and sp %#lx", g_idle.id, g_idle.ip(), g_idle.sp()); + + g_current = &g_idle; + } + + Thread* current() + { + return g_current; + } + + Thread* idle() + { + return &g_idle; + } + + Result new_kernel_thread_impl(Thread* thread) + { + // If anything fails, make sure to clean up. + auto guard = make_scope_guard([&] { delete thread; }); + + u64 thread_stack_vm = TRY(MemoryManager::alloc_for_kernel(4, MMU::NoExecute | MMU::ReadWrite)); + + guard.deactivate(); + + Stack thread_stack { thread_stack_vm, ARCH_PAGE_SIZE * 4 }; + thread->set_sp(thread_stack.top()); + + thread->stack = thread_stack; + + thread->is_kernel = true; + + g_threads.append(thread); + + kinfoln("CREATED THREAD: id %lu with ip %#lx and sp %#lx", thread->id, thread->ip(), thread->sp()); + + return {}; + } + + Result new_kernel_thread(u64 address) + { + Thread* thread = TRY(new_thread()); + thread->init_regs_kernel(); + thread->set_ip(address); + + return new_kernel_thread_impl(thread); + } + + Result new_kernel_thread(void (*func)(void)) + { + Thread* thread = TRY(new_thread()); + thread->init_regs_kernel(); + thread->set_ip((u64)func); + + return new_kernel_thread_impl(thread); + } + + Result new_kernel_thread(void (*func)(void*), void* arg) + { + Thread* thread = TRY(new_thread()); + thread->init_regs_kernel(); + thread->set_ip((u64)func); + thread->set_arguments((u64)arg, 0, 0, 0); + + return new_kernel_thread_impl(thread); + } + + static Result create_stacks(Stack& user_stack, Stack& kernel_stack) + { + const u64 THREAD_STACK_BASE = 0x10000; + + TRY(MemoryManager::alloc_at(THREAD_STACK_BASE, 4, MMU::ReadWrite | MMU::NoExecute | MMU::User)); + + auto guard = make_scope_guard([&] { MemoryManager::unmap_owned(THREAD_STACK_BASE, 4); }); + + u64 kernel_stack_base = TRY(MemoryManager::alloc_for_kernel(4, MMU::ReadWrite | MMU::NoExecute)); + + guard.deactivate(); + + user_stack = { THREAD_STACK_BASE, 4 * ARCH_PAGE_SIZE }; + kernel_stack = { kernel_stack_base, 4 * ARCH_PAGE_SIZE }; + + return {}; + } + + Result new_userspace_thread(const TarStream::Entry& entry, const TarStream& stream) + { + Thread* thread = TRY(new_thread()); + + thread->is_kernel = false; + + auto guard = make_scope_guard([&] { delete thread; }); + + auto directory = TRY(MMU::create_page_directory_for_userspace()); + + auto directory_guard = make_scope_guard([&] { + MMU::switch_page_directory(MMU::kernel_page_directory()); + MemoryManager::free_frame((u64)directory); + }); + + MMU::switch_page_directory(directory); + + thread->init_regs_user(); + + auto data = TRY(ELFLoader::load(entry, stream)); + + thread->set_ip(data.entry); + + TRY(create_stacks(thread->stack, thread->kernel_stack)); + thread->set_sp(thread->stack.top()); + + thread->directory = directory; + + guard.deactivate(); + directory_guard.deactivate(); + + kinfoln("CREATED USERSPACE THREAD: id %lu with ip %#.16lx and sp %#.16lx (ksp %#lx)", thread->id, thread->ip(), + thread->sp(), thread->kernel_stack.top()); + + g_threads.append(thread); + + return {}; + } + + void reap_thread(Thread* thread) + { + kinfoln("reap: reaping thread with id %zu", thread->id); + + if (thread->is_kernel) { - result = task; - return false; + auto stack = thread->stack; + // FIXME: Propagate errors I guess? + kinfoln("deleting stack @ %#lx", stack.bottom()); + MemoryManager::unmap_owned_and_free_vm(stack.bottom(), stack.bytes() / ARCH_PAGE_SIZE).release_value(); + } + else + { + auto stack = thread->kernel_stack; + kinfoln("deleting kstack @ %#lx", stack.bottom()); + // FIXME: Propagate errors I guess? + MemoryManager::unmap_owned_and_free_vm(stack.bottom(), stack.bytes() / ARCH_PAGE_SIZE).release_value(); } - return true; - }); - return result; -} -void Scheduler::append_task(Task* task) -{ - if (!base_task) - { - ensure(!end_task); - base_task = task; - end_task = base_task; - task->next_task = task; - task->prev_task = task; + if (!thread->is_kernel) MMU::delete_userspace_page_directory(thread->directory); + + delete thread; } - else + + Thread* pick_task() { - end_task->next_task = task; - task->prev_task = end_task; - base_task->prev_task = task; - task->next_task = base_task; - end_task = task; + Thread* old = g_current; + if (old->is_idle()) + { + auto maybe_last = g_threads.last(); + if (!maybe_last.has_value()) // No threads!! + return &g_idle; + g_current = old = maybe_last.value(); + } + + bool has_found_thread = false; + + do { + auto maybe_next = g_threads.next(g_current); + if (!maybe_next.has_value()) g_current = g_threads.expect_first(); + else + g_current = maybe_next.value(); + + if (g_current->state == ThreadState::Runnable) + { + has_found_thread = true; + break; + } + } while (g_current != old); + + if (!has_found_thread) g_current = &g_idle; + + return g_current; } -} -void Scheduler::init() -{ - memset(&idle_task, 0, sizeof(Task)); - idle_task.id = free_pid++; - idle_task.regs.rip = (uint64_t)idle_task_function; - idle_task.regs.rsp = - get_top_of_stack((uint64_t)MemoryManager::get_page().release_value(), - 1); // If we OOM while creating the idle task, that's NOT good and we can panic. - idle_task.regs.cs = 0x08; - idle_task.regs.ss = 0x10; - idle_task.regs.rflags = (1 << 21) | (1 << 9); - idle_task.task_sleep = 1000; - idle_task.user_task = false; - idle_task.block_reason = BlockReason::None; - idle_task.state = idle_task.Idle; - - strlcpy(idle_task.name, "[cpu-idle]", sizeof(idle_task.name)); - - sched_current_task = &idle_task; - - frequency = 1000 / PIT::frequency(); -} - -void Scheduler::add_kernel_task(const char* taskname, void (*task)(void)) -{ - Task* new_task = new Task; - ensure(new_task); - new_task->user_task = false; - new_task->id = free_pid++; - new_task->ppid = 0; - new_task->uid = new_task->euid = new_task->gid = new_task->egid = 0; - new_task->regs.rip = (uint64_t)task; - new_task->allocated_stack = - (uint64_t)MemoryManager::get_pages(TASK_PAGES_IN_STACK).release_value(); // FIXME: Propagate errors. - new_task->regs.rsp = get_top_of_stack(new_task->allocated_stack, TASK_PAGES_IN_STACK); - new_task->regs.cs = 0x08; - new_task->regs.ss = 0x10; - new_task->regs.ds = 0x10; - new_task->regs.rflags = read_rflags() | 0x200; // enable interrupts - new_task->task_sleep = 0; - new_task->task_time = 0; - new_task->cpu_time = 0; - strlcpy(new_task->name, taskname, sizeof(new_task->name)); - append_task(new_task); - new_task->block_reason = BlockReason::None; - new_task->state = new_task->Running; - task_num++; - kinfoln("Adding kernel task: %s, starts at %lx, PID %ld, stack at %lx, total tasks: %ld", new_task->name, - new_task->regs.rip, new_task->id, new_task->regs.rsp, task_num); -} - -Task* Scheduler::create_user_task() -{ - Task* new_task = new Task; - if (!new_task) return nullptr; - memset(&new_task->regs, 0, sizeof(Context)); - new_task->user_task = true; - new_task->id = free_pid++; - new_task->ppid = 0; - new_task->task_sleep = 0; - new_task->task_time = 0; - new_task->cpu_time = 0; - new_task->block_reason = BlockReason::None; - append_task(new_task); - task_num++; - return new_task; -} - -long Scheduler::load_user_task(const char* filename) -{ - kinfoln("Loading user task: %s", filename); - Interrupts::push_and_disable(); - Task* new_task = new Task; - ensure(new_task); - memset(&new_task->regs, 0, sizeof(Context)); - new_task->id = free_pid++; - new_task->ppid = 0; - new_task->uid = new_task->euid = new_task->gid = new_task->egid = 0; - if (!new_task->allocator.init()) + void generic_switch_context(Thread* old_thread, Thread* new_thread, Registers* regs) { - delete new_task; - free_pid--; - Interrupts::pop(); - return -ENOMEM; + if (old_thread != new_thread) + { + switch_context(old_thread, new_thread, regs); + if (!new_thread->is_kernel) + { + MMU::switch_page_directory(new_thread->directory); + CPU::switch_kernel_stack(new_thread->kernel_stack.top()); + } + } + + if (new_thread->is_idle()) + { + new_thread->ticks_left = 1; // The idle task only runs for 1 tick so we can check for new runnable tasks + // as fast as possible. + } + else + new_thread->ticks_left = TICKS_PER_TIMESLICE; } - new_task->address_space = AddressSpace::create().release_value(); // FIXME: Propagate this error. - VMM::switch_to_user_address_space(new_task->address_space); - long result; - if ((result = ELFLoader::check_elf_image_from_filesystem(filename)) < 0) + + void switch_task(Registers* regs) { - delete new_task; - free_pid--; - kerrorln("Failed to load %s from initrd", filename); - Interrupts::pop(); + Thread* old_thread = g_current; + Thread* new_thread = pick_task(); + generic_switch_context(old_thread, new_thread, regs); + } + + void invoke(Registers* regs) + { + CPU::disable_interrupts(); + + g_current->ticks++; + + if (is_in_kernel(regs)) g_current->ticks_in_kernel++; + else + g_current->ticks_in_user++; + + g_current->ticks_left--; + + g_threads.for_each([](Thread* thread) { + if (thread->state == ThreadState::Sleeping) + { + if (--thread->sleep_ticks_left == 0) thread->state = ThreadState::Runnable; + } + }); + + if (!g_current->ticks_left) switch_task(regs); + } + + LinkedList check_for_dying_threads() + { + LinkedList result; + + g_threads.delayed_for_each([&](Thread* thread) { + if (thread->state == ThreadState::Dying) + { + g_threads.remove(thread); + result.append(thread); + } + }); + return result; } - if ((uint64_t)result > PMM::get_free()) - { - delete new_task; - free_pid--; - kerrorln("Not enough memory for task %s", filename); - Interrupts::pop(); - return -ENOMEM; - } - ELFImage* image = ELFLoader::load_elf_from_filesystem(filename); - ensure(image); - new_task->user_task = true; - new_task->regs.rip = image->entry; - new_task->image = image; - new_task->allocated_stack = (uint64_t)MemoryManager::get_pages_at(0x100000, TASK_PAGES_IN_STACK, - MAP_READ_WRITE | MAP_USER | MAP_AS_OWNED_BY_TASK) - .release_value(); // FIXME: Propagate errors. - if (!new_task->allocated_stack) - { - new_task->address_space.destroy(); - delete new_task; - free_pid--; - ELFLoader::release_elf_image(image); - VMM::switch_back_to_kernel_address_space(); - Interrupts::pop(); - return -ENOMEM; - } - new_task->regs.rsp = get_top_of_stack(new_task->allocated_stack, TASK_PAGES_IN_STACK); - new_task->regs.cs = 0x18 | 0x03; - new_task->regs.ss = 0x20 | 0x03; - new_task->regs.ds = 0x20 | 0x03; - new_task->regs.rflags = (1 << 21) | (1 << 9); // enable interrupts - new_task->task_sleep = 0; - new_task->task_time = 0; - new_task->cpu_time = 0; - strlcpy(new_task->name, filename, sizeof(new_task->name)); - append_task(new_task); - new_task->block_reason = BlockReason::None; - new_task->state = new_task->Running; - task_num++; - kinfoln("Adding user task: %s, loaded at %lx, PID %ld, stack at %lx, total tasks: %ld", new_task->name, - new_task->regs.rip, new_task->id, new_task->regs.rsp, task_num); - VMM::switch_back_to_kernel_address_space(); - Interrupts::pop(); - return (long)new_task->id; } -void Scheduler::reset_task(Task* task, ELFImage* new_image) +void kernel_sleep(u64 ms) { - memset(&task->regs, 0, sizeof(Context)); - task->state = task->Running; - task->regs.rip = new_image->entry; - task->image = new_image; - task->regs.rsp = get_top_of_stack(task->allocated_stack, TASK_PAGES_IN_STACK); - task->regs.cs = 0x18 | 0x03; - task->regs.ss = 0x20 | 0x03; - task->regs.ds = 0x20 | 0x03; - task->regs.rflags = (1 << 21) | (1 << 9); // enable interrupts - task->task_sleep = 0; - task->cpu_time = 0; - task->block_reason = BlockReason::None; - kinfoln("Resetting task: %s, loaded at %lx, PID %ld, stack at %lx, total tasks: %ld", task->name, task->regs.rip, - task->id, task->regs.rsp, task_num); + g_current->sleep_ticks_left = ms; + g_current->state = ThreadState::Sleeping; + kernel_yield(); } -void Scheduler::reap_task(Task* task) +[[noreturn]] void kernel_exit() { - ensure(!Interrupts::is_in_handler()); - task_num--; - Task* exiting_task = task; - ensure(task->id != 0); // WHY IN THE WORLD WOULD WE BE REAPING THE IDLE TASK? - if (exiting_task->is_user_task()) - { - VMM::switch_back_to_kernel_address_space(); - VMM::apply_address_space(); - VMM::switch_to_user_address_space(exiting_task->address_space); - } - kinfoln("reaping task %s, PID %ld, exited with code %ld", exiting_task->name, exiting_task->id, - exiting_task->exit_status); - if (exiting_task->id == (free_pid - 1)) free_pid--; // If we are the last spawned thread, free our PID. - if (exiting_task->allocated_stack && !exiting_task->is_user_task()) - MemoryManager::release_pages((void*)exiting_task->allocated_stack, TASK_PAGES_IN_STACK); - if (exiting_task->image) kfree(exiting_task->image); - if (exiting_task->is_user_task()) - { - exiting_task->allocator.free(); - VMM::switch_back_to_kernel_address_space(); - VMM::apply_address_space(); - Interrupts::push_and_enable(); - exiting_task->address_space.destroy(); - Interrupts::pop(); - } - for (int i = 0; i < TASK_MAX_FDS; i++) { exiting_task->files[i].close(); } - delete exiting_task; + g_current->state = ThreadState::Dying; + kernel_yield(); + unreachable(); } - -void sched_common_exit(Context* context, int64_t status) -{ - if (sched_current_task->id == 1) sched_current_task->state = sched_current_task->Exited; - else - sched_current_task->state = sched_current_task->Dying; - sched_current_task->exit_status = status; - if (sched_current_task->id != 1) - { - sched_for_each_child(sched_current_task, [](Task* child) { - if (child->state != child->Exited) child->ppid = 1; - return true; - }); - } - else - { - kinfoln("PID 1 exited with code %ld", status); -#ifndef RUN_TEST_AS_INIT - reboot(); -#else - hang(); -#endif - } - Scheduler::task_yield(context); -} - -void Scheduler::task_exit(Context* context, int64_t status) -{ - ensure(Interrupts::is_in_handler()); - kdbgln("exit: task %ld finished running, used %ld ms of cpu time", sched_current_task->id, - sched_current_task->cpu_time); - sched_common_exit(context, status); -} - -void Scheduler::task_misbehave(Context* context, int64_t status) -{ - ensure(Interrupts::is_in_handler()); - kdbgln("exit: task %ld misbehaved, used %ld ms of cpu time", sched_current_task->id, sched_current_task->cpu_time); - sched_common_exit(context, status); -} - -void Scheduler::reap_tasks() -{ - Interrupts::disable(); - ensure(!Interrupts::is_in_handler()); - Task* reap_base = nullptr; - Task* reap_end = nullptr; - Task* task = base_task; - Task* task_reaping; - uint64_t iter_index = 0; - do { - if (task->state == task->Exited) - { - if (task == base_task && task == end_task) { panic("Last task exited"); } - else if (task == base_task) { base_task = task->next_task; } - else if (task == end_task) { end_task = task->prev_task; } - if (!reap_base) - { - reap_base = task; - reap_end = task; - task->prev_task->next_task = task->next_task; - task->next_task->prev_task = task->prev_task; - task->prev_task = nullptr; - task_reaping = task; - task = task->next_task; - task_reaping->next_task = nullptr; - } - else - { - reap_end->next_task = task; - task->prev_task->next_task = task->next_task; - task->next_task->prev_task = task->prev_task; - task->prev_task = nullptr; - reap_end = task; - task_reaping = task; - task = task->next_task; - task_reaping->next_task = nullptr; - } - } - else { task = task->next_task; } - iter_index++; - } while (iter_index < task_num); - task = reap_base; - while (task) - { - Task* reaped_task = task; - task = task->next_task; - reap_task(reaped_task); - } - Interrupts::enable(); -} - -static void sched_decrement_sleep_times() -{ - sched_for_each_task([](Task* task) { - if (task->task_sleep > 0) - { - task->task_sleep -= frequency; - if (task->task_sleep < 0) task->task_sleep = 0; - } - if (task->task_sleep == 0 && task->state == task->Sleeping) task->state = task->Running; - return true; - }); -} - -void Scheduler::task_tick(Context* context) -{ - ensure(Interrupts::is_in_handler()); - Interrupts::disable(); - sched_decrement_sleep_times(); - sched_current_task->task_time -= frequency; - sched_current_task->cpu_time += frequency; - if (sched_current_task->id == 0) return task_yield(context); - if (sched_current_task->task_time <= 0) - { - sched_current_task->task_time = 0; - task_yield(context); - } - Interrupts::enable(); -} - -void Scheduler::task_yield(Context* context) -{ - ensure(Interrupts::is_in_handler()); - Interrupts::disable(); - sched_current_task->save_context(context); - bool was_idle = false; - if (sched_current_task->state == sched_current_task->Idle) - { - sched_current_task = end_task; - was_idle = true; - } - Task* original_task = sched_current_task; - do { - sched_current_task = sched_current_task->next_task; - if (sched_current_task->state == sched_current_task->Blocking) - { - if (!sched_current_task->is_still_blocking()) sched_current_task->resume(); - } - if (sched_current_task->state == sched_current_task->Running) - { - if (sched_current_task->id != original_task->id || was_idle) - { - if (!was_idle && original_task->is_user_task() && !original_task->has_died()) - { - original_task->save_floating(); - } - if (sched_current_task->is_user_task()) - { - sched_current_task->switch_to_address_space(); - sched_current_task->restore_floating(); - } - else if (!was_idle && original_task->is_user_task() && !sched_current_task->is_user_task()) - { - VMM::switch_back_to_kernel_address_space(); - VMM::apply_address_space(); - } - } - sched_current_task->task_time = 20; - sched_current_task->restore_context(context); - return; - } - } while (sched_current_task != original_task); - if (!was_idle && original_task->is_user_task() && original_task->state != original_task->Exited) - { - original_task->save_floating(); - } - sched_current_task = &idle_task; - sched_current_task->task_time = frequency; - if (!was_idle) { sched_current_task->restore_context(context); } - return; -} - -void Scheduler::yield() -{ - asm volatile("int $0x42" : : "a"(1)); -} - -void Scheduler::exit(int status) -{ - asm volatile("int $0x42" : : "a"(0), "D"(status)); -} - -void Scheduler::sleep(unsigned long ms) -{ - asm volatile("int $0x42" : : "D"(ms), "a"(2)); -} - -Task* Scheduler::current_task() -{ - return sched_current_task; -} - -#define WNOHANG 1 - -void sys_waitpid(Context* context, long pid, int* wstatus, - int options) // FIXME: only allow waiting for child processes when specifying a PID. -{ - Task* child = nullptr; - if (pid == -1) - { - sched_for_each_child(sched_current_task, [&](Task* task) { - if (task->state == task->Dying) - { - child = task; - return false; - } - return true; - }); - if (!child) - { - if (options & WNOHANG) - { - context->rax = 0; // No child has exited, let's return 0. - return; - } - kdbgln("blocking wait on any child"); - sched_current_task->state = sched_current_task->Blocking; - sched_current_task->block_reason = BlockReason::Waiting; - sched_current_task->blocking_wait_info.pid = -1; - sched_current_task->blocking_wait_info.wstatus = wstatus; - return Scheduler::task_yield(context); - } - } - else - { - child = Scheduler::find_by_pid(pid); - if (!child) - { - context->rax = -ECHILD; - return; - } - } - if (child->ppid != sched_current_task->id) - { - // We are trying to call waitpid() on a task that isn't a child of ours. This is not allowed. - context->rax = -ECHILD; - return; - } - if (child->state != child->Dying) - { - if (options & WNOHANG) - { - context->rax = 0; // No child has exited, let's return 0. - return; - } - sched_current_task->state = sched_current_task->Blocking; - sched_current_task->block_reason = BlockReason::Waiting; - sched_current_task->blocking_wait_info.pid = pid; - sched_current_task->blocking_wait_info.wstatus = wstatus; - return Scheduler::task_yield(context); - } - child->state = child->Exited; - context->rax = (long)child->id; - if (wstatus) - { - int status = (int)(child->exit_status & 0xff); - if (!copy_to_user(wstatus, &status, sizeof(int))) context->rax = -EFAULT; - } -} - -bool Task::is_wait_still_blocking() -{ - Task* child = nullptr; - if (blocking_wait_info.pid == -1) - { - sched_for_each_child(sched_current_task, [&](Task* task) { - if (task->state == task->Dying) - { - child = task; - return false; - } - return true; - }); - if (!child) return true; - else - { - blocking_wait_info.pid = child->id; // We're committed to this child now. - return false; - } - } - else - { - child = Scheduler::find_by_pid(blocking_wait_info.pid); - ensure(child); // since sys_waitpid should have validated this child, and the only way for it to disappear from - // the process list is for someone to wait for it, this should be pretty safe. - if (child->state != child->Dying) return true; - else - return false; - } -} - -void Task::resume_wait() -{ - ensure(blocking_wait_info.pid != -1); // is_wait_still_blocking should have chosen a child for us if the user - // process told us to wait for any child. - Task* child = Scheduler::find_by_pid(blocking_wait_info.pid); - ensure(child); // This should also already have been validated. - - child->state = child->Exited; - regs.rax = (long)child->id; - - if (blocking_wait_info.wstatus) - { - int wstatus = (int)(child->exit_status & 0xff); - if (!copy_to_user(blocking_wait_info.wstatus, &wstatus, sizeof(int))) regs.rax = -EFAULT; - } -} - -struct pstat -{ - long pt_pid; - long pt_ppid; - char pt_name[128]; - int pt_state; - long pt_time; - uid_t pt_uid; - gid_t pt_gid; -}; - -void sys_pstat(Context* context, long pid, struct pstat* buf) -{ - Task* task; - if (pid == -1) task = Scheduler::find_by_pid(free_pid - 1); - else if (pid == 0) - task = &idle_task; - else - task = Scheduler::find_by_pid(pid); - if (!task) - { - context->rax = -ESRCH; - return; - } - if (task->state == task->Exited) // we're just waiting for the reaper to reap it - { - context->rax = -ESRCH; - return; - } - context->rax = task->id; - if (buf) - { - struct pstat stat; - stat.pt_pid = task->id; - stat.pt_ppid = task->ppid; - stat.pt_state = (int)task->state; - stat.pt_time = (long)task->cpu_time; - stat.pt_uid = task->uid; - stat.pt_gid = task->gid; - strlcpy(stat.pt_name, task->name, sizeof(stat.pt_name)); - if (!copy_to_user(buf, &stat, sizeof(struct pstat))) context->rax = -EFAULT; - } -} \ No newline at end of file diff --git a/kernel/src/thread/Scheduler.h b/kernel/src/thread/Scheduler.h new file mode 100644 index 00000000..c2dd4cfc --- /dev/null +++ b/kernel/src/thread/Scheduler.h @@ -0,0 +1,31 @@ +#pragma once +#include "thread/Thread.h" +#include + +namespace Scheduler +{ + void init(); + + Thread* current(); + Thread* idle(); + + Result new_kernel_thread(u64 address); + Result new_kernel_thread(void (*func)(void)); + Result new_kernel_thread(void (*func)(void*), void* arg); + + Result new_userspace_thread(const TarStream::Entry& entry, const TarStream& stream); + + Thread* pick_task(); + + void reap_thread(Thread* thread); + + void switch_task(Registers* regs); + + void invoke(Registers* regs); + + LinkedList check_for_dying_threads(); +} + +extern "C" void kernel_yield(); +void kernel_sleep(u64 ms); +[[noreturn]] void kernel_exit(); diff --git a/kernel/src/thread/Spinlock.asm b/kernel/src/thread/Spinlock.asm deleted file mode 100644 index 2b2e7a43..00000000 --- a/kernel/src/thread/Spinlock.asm +++ /dev/null @@ -1,20 +0,0 @@ -global spinlock_lock_acquire -spinlock_lock_acquire: - lock bts qword [rdi], 0 - jc .spin - ret -.spin: - pause - test qword [rdi], 1 - jnz .spin - jmp spinlock_lock_acquire - -global spinlock_lock_release -spinlock_lock_release: - mov qword [rdi], 0 - ret - -global spinlock_lock_is_locked -spinlock_lock_is_locked: - mov rax, [rdi] - ret \ No newline at end of file diff --git a/kernel/src/thread/Spinlock.cpp b/kernel/src/thread/Spinlock.cpp index 2db971c2..f1802b80 100644 --- a/kernel/src/thread/Spinlock.cpp +++ b/kernel/src/thread/Spinlock.cpp @@ -1,27 +1,28 @@ #include "thread/Spinlock.h" +#include "Log.h" +#include "arch/CPU.h" -extern "C" void spinlock_lock_acquire(volatile uint64_t* lock); -extern "C" void spinlock_lock_release(volatile uint64_t* lock); -extern "C" int spinlock_lock_is_locked(volatile uint64_t* lock); - -void Spinlock::acquire() +void Spinlock::lock() { - spinlock_lock_acquire(&m_lock); + int expected = 0; + while (!m_lock.compare_exchange_strong(expected, 1)) + { + expected = 0; + CPU::pause(); + } } -void Spinlock::release() +bool Spinlock::try_lock() { - spinlock_lock_release(&m_lock); + int expected = 0; + return m_lock.compare_exchange_strong(expected, 1); } -bool Spinlock::locked() +void Spinlock::unlock() { - return spinlock_lock_is_locked(&m_lock); + int expected = 1; + if (!m_lock.compare_exchange_strong(expected, 0)) + { + kwarnln("Spinlock::unlock() called on an unlocked lock with value %d", expected); + } } - -void lock(Spinlock& lock, void (*action)(void)) -{ - lock.acquire(); - action(); - lock.release(); -} \ No newline at end of file diff --git a/kernel/src/thread/Spinlock.h b/kernel/src/thread/Spinlock.h new file mode 100644 index 00000000..d54edd96 --- /dev/null +++ b/kernel/src/thread/Spinlock.h @@ -0,0 +1,91 @@ +#pragma once +#include +#include + +class Spinlock +{ + public: + void lock(); + void unlock(); + + bool try_lock(); + + bool is_locked() const + { + return m_lock.load() != 0; + } + + private: + Atomic m_lock { 0 }; +}; + +template class LockedValue +{ + struct LockedValueGuard + { + LockedValueGuard(LockedValue& value_ref) : m_value_ref(&value_ref) + { + } + + LockedValueGuard(const LockedValueGuard& other) = delete; + LockedValueGuard(LockedValueGuard&& other) + { + m_value_ref = other.m_value_ref; + other.m_value_ref = nullptr; + } + + ~LockedValueGuard() + { + if (m_value_ref) m_value_ref->m_lock.unlock(); + } + + T& ref() + { + expect(m_value_ref, "LockedValueGuard::ref() called on a moved LockedValueGuard"); + return m_value_ref->m_value; + } + + void set(const T& other) + { + ref() = other; + } + + T* operator->() + { + return &ref(); + } + + T& operator*() + { + return ref(); + } + + private: + LockedValue* m_value_ref; + }; + + public: + LockedValue() : m_value() + { + } + + LockedValue(T value) : m_value(value) + { + } + + LockedValueGuard lock() + { + m_lock.lock(); + return { *this }; + } + + Option try_lock() + { + if (m_lock.try_lock()) { return { *this }; } + return {}; + } + + private: + T m_value; + Spinlock m_lock; +}; diff --git a/kernel/src/thread/Task.cpp b/kernel/src/thread/Task.cpp deleted file mode 100644 index 95a450a1..00000000 --- a/kernel/src/thread/Task.cpp +++ /dev/null @@ -1,140 +0,0 @@ -#define MODULE "sched" - -#include "thread/Task.h" -#include "log/Log.h" -#include "memory/VMM.h" -#include "std/ensure.h" -#include "std/errno.h" -#include "std/string.h" - -void Task::restore_context(Context* context) -{ - memcpy(context, ®s, sizeof(Context)); -} - -void Task::save_context(Context* context) -{ - memcpy(®s, context, sizeof(Context)); -} - -void Task::save_floating() -{ - floating_saved = true; - asm volatile("fxsave (%0)" : : "r"((char*)floating_region)); -} - -void Task::restore_floating() -{ - if (!floating_saved) return; - asm volatile("fxrstor (%0)" : : "r"((char*)floating_region)); -} - -bool Task::is_user_task() -{ - return user_task; -} - -int Task::alloc_fd() -{ - int fd; - for (fd = 0; fd < TASK_MAX_FDS; fd++) - { - if (!files[fd].is_open()) break; - } - - if (fd == TASK_MAX_FDS) { return -1; } - - return fd; -} - -int Task::alloc_fd_greater_than_or_equal(int base_fd) -{ - int fd; - if (base_fd >= TASK_MAX_FDS) return -1; - for (fd = base_fd; fd < TASK_MAX_FDS; fd++) - { - if (!files[fd].is_open()) break; - } - - if (fd == TASK_MAX_FDS) { return -1; } - - return fd; -} - -void Task::switch_to_address_space() -{ - VMM::switch_to_user_address_space(address_space); - VMM::apply_address_space(); -} - -bool Task::has_died() -{ - return state == Exited; -} - -void Task::resume_read() -{ - regs.rax = files[blocking_read_info.fd].user_read(blocking_read_info.size, blocking_read_info.buf); -} - -bool Task::is_read_still_blocking() -{ - return VFS::would_block(files[blocking_read_info.fd].node()); -} - -void Task::resume() -{ - VMM::switch_back_to_kernel_address_space(); - VMM::apply_address_space(); - VMM::switch_to_user_address_space(address_space); - switch (block_reason) - { - case BlockReason::None: return; - case BlockReason::Reading: resume_read(); break; - case BlockReason::Waiting: resume_wait(); break; - - default: ensure(false); - } - VMM::apply_address_space(); - block_reason = BlockReason::None; - state = Running; -} - -bool Task::is_still_blocking() -{ - switch (block_reason) - { - case BlockReason::None: return true; - case BlockReason::Reading: return is_read_still_blocking(); - case BlockReason::Waiting: return is_wait_still_blocking(); - - default: return true; - } -} - -Descriptor* Task::open_descriptor_from_fd(int fd, int& error) -{ - Descriptor* file = descriptor_from_fd(fd, error); - if (!file) return nullptr; - if (!file->is_open()) - { - error = EBADF; - return nullptr; - } - return file; -} - -Descriptor* Task::descriptor_from_fd(int fd, int& error) -{ - if (fd < 0 || fd >= TASK_MAX_FDS) - { - error = EBADF; - return nullptr; - } - return &files[fd]; -} - -bool Task::is_superuser() -{ - return euid == 0; -} \ No newline at end of file diff --git a/kernel/src/thread/Thread.cpp b/kernel/src/thread/Thread.cpp new file mode 100644 index 00000000..fea866e3 --- /dev/null +++ b/kernel/src/thread/Thread.cpp @@ -0,0 +1,21 @@ +#include "thread/Thread.h" +#include +#include + +static Atomic g_next_id; + +LinkedList g_threads; + +void Thread::init() +{ + g_next_id = 1; +} + +Result new_thread() +{ + Thread* thread = TRY(make()); + + thread->id = g_next_id++; + + return thread; +} diff --git a/kernel/src/thread/Thread.h b/kernel/src/thread/Thread.h new file mode 100644 index 00000000..3b37923a --- /dev/null +++ b/kernel/src/thread/Thread.h @@ -0,0 +1,69 @@ +#pragma once + +#include "arch/MMU.h" +#include +#include +#include + +#ifdef ARCH_X86_64 +#include "arch/x86_64/CPU.h" +#else +#error "Unknown architecture." +#endif + +enum class ThreadState +{ + Idle, + Runnable, + Sleeping, + Dying +}; + +struct Thread : public LinkedListNode +{ + Registers regs; + + u64 id; + + u64 ticks = 0; + u64 ticks_in_user = 0; + u64 ticks_in_kernel = 0; + + u64 ticks_left; + u64 sleep_ticks_left; + + Stack stack; + Stack kernel_stack; + + ThreadState state = ThreadState::Runnable; + + bool is_kernel { true }; + + PageDirectory* directory; + + bool is_idle() + { + return state == ThreadState::Idle; + } + + void init_regs_kernel(); + void init_regs_user(); + + void set_arguments(u64 arg1, u64 arg2, u64 arg3, u64 arg4); + + void set_ip(u64 ip); + u64 ip(); + + void set_sp(u64 sp); + u64 sp(); + + static void init(); +}; + +void switch_context(Thread* old_thread, Thread* new_thread, Registers* regs); + +bool is_in_kernel(Registers* regs); + +Result new_thread(); + +extern LinkedList g_threads; diff --git a/kernel/src/trace/Resolve.cpp b/kernel/src/trace/Resolve.cpp deleted file mode 100644 index 77bbc71d..00000000 --- a/kernel/src/trace/Resolve.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "trace/Resolve.h" -#include "fs/InitRD.h" -#include "std/stdlib.h" -#include "std/string.h" -#include - -extern int kernel_start; -extern int kernel_end; - -static InitRD::File symbol_map = {"", 0, 0, (void*)-1, 0}; - -static size_t symbol_strlen(const char* symbol) -{ - const char* i = symbol; - for (; *i != '\n' && *i; ++i) - ; - return (i - symbol); -} - -void get_symbol_name(uintptr_t address, char* buffer, size_t max) -{ - if (symbol_map.addr == (void*)-1) { symbol_map = InitRD::open("sys/moon.sym"); } - if (!symbol_map.addr) { strlcpy(buffer, "(no symbols loaded)", max); } - while (address >= (uintptr_t)&kernel_start && address <= (uintptr_t)&kernel_end) - { - char addr_as_str[60]; - ultoa(address, addr_as_str, 16); - char* symbol = strstr((char*)symbol_map.addr, addr_as_str); - if (symbol) - { - symbol += 19; - size_t symlen = symbol_strlen(symbol); - size_t copylen = (max - 1) < symlen ? (max - 1) : symlen; - memcpy(buffer, symbol, copylen); - buffer[copylen] = 0; - return; - } - address--; - } - strlcpy(buffer, "(no symbol)", max); -} \ No newline at end of file diff --git a/kernel/src/trace/StackTracer.cpp b/kernel/src/trace/StackTracer.cpp deleted file mode 100644 index cf9a4572..00000000 --- a/kernel/src/trace/StackTracer.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#define MODULE "trace" - -#include "trace/StackTracer.h" -#include "log/Log.h" -#include "memory/Memory.h" -#include "std/stdio.h" -#include "trace/Resolve.h" - -StackTracer::StackTracer() -{ - asm("mov %%rbp, %0" : "=r"(m_base_pointer)); -} - -StackTracer::StackTracer(uintptr_t base_pointer) : m_base_pointer(base_pointer) -{ -} - -typedef struct stackframe -{ - struct stackframe* next; - uintptr_t instruction; -} stackframe; - -void StackTracer::trace() -{ - stackframe* frame = (stackframe*)m_base_pointer; - while (frame && frame->instruction && Memory::is_kernel_address(frame->instruction)) - { - char symbol_name[512]; - get_symbol_name(frame->instruction - sizeof(uintptr_t), symbol_name, sizeof(symbol_name)); - kinfoln("%lx: %s", frame->instruction - sizeof(uintptr_t), symbol_name); - frame = frame->next; - } -} - -void StackTracer::trace_with_ip(uintptr_t ip) -{ - char symbol_name[512]; - get_symbol_name(ip, symbol_name, sizeof(symbol_name)); - kinfoln("%lx: %s", ip, symbol_name); - trace(); -} - -bool stack_trace_contains(uintptr_t address) -{ - uintptr_t base_pointer; - asm volatile("mov %%rbp, %0" : "=r"(base_pointer)); - stackframe* frame = (stackframe*)base_pointer; - while (Memory::is_kernel_address((uintptr_t)frame)) - { - if (frame->instruction == address) return true; - frame = frame->next; - } - return false; -} \ No newline at end of file diff --git a/kernel/src/utils/PageFaultReason.cpp b/kernel/src/utils/PageFaultReason.cpp deleted file mode 100644 index 054a2294..00000000 --- a/kernel/src/utils/PageFaultReason.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#define MODULE "mem" - -#include "utils/PageFaultReason.h" -#include "log/Log.h" - -#define PROGRAM_STACK_BOTTOM 0x100000 - -void determine_user_page_fault_reason(uintptr_t faulting_address) -{ - if (faulting_address < 0x1000) - { - kinfoln("Address 0x%lx looks like a nullptr dereference", faulting_address); - return; - } - if (faulting_address < PROGRAM_STACK_BOTTOM && (PROGRAM_STACK_BOTTOM - faulting_address) < 0x1000) - { - kinfoln("Address 0x%lx looks like a stack overflow", faulting_address); - return; - } -} \ No newline at end of file diff --git a/kernel/src/utils/StringParsing.cpp b/kernel/src/utils/StringParsing.cpp deleted file mode 100644 index 0662aa52..00000000 --- a/kernel/src/utils/StringParsing.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "utils/StringParsing.h" - -int isdigit(int c) -{ - return c >= '0' && c < ':'; -} - -int isodigit(int c) -{ - return c >= '0' && c < '8'; -} - -int isxdigit(int c) -{ - return isdigit(c) || ((unsigned int)c | 32) - 'a' < 6; -} - -template -static T string_to_integer_type(const char* str, int base, ValidDigitChecker checker, Converter converter) -{ - bool neg = false; - T val = 0; - - switch (*str) - { - case '-': - neg = true; - str++; - break; - case '+': str++; break; - default: break; - } - - while (checker(*str)) { val = (base * val) + converter(*str++); } - - return (neg ? -val : val); -} - -long parse_decimal(const char* str) -{ - return string_to_integer_type( - str, 10, [](char c) { return isdigit(c); }, [](char c) { return c - '0'; }); -} - -long parse_octal(const char* str) -{ - return string_to_integer_type( - str, 8, [](char c) { return isodigit(c); }, [](char c) { return c - '0'; }); -} \ No newline at end of file diff --git a/kernel/src/utils/Time.cpp b/kernel/src/utils/Time.cpp deleted file mode 100644 index 0476a6b2..00000000 --- a/kernel/src/utils/Time.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#define MODULE "time" - -#include "utils/Time.h" -#include "log/Log.h" - -int isleap(int year) -{ - return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); -} - -int make_yday(int year, int month) -{ - static const short int upto[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; - int yd; - - yd = upto[month - 1]; - if (month > 2 && isleap(year)) yd++; - return yd; -} - -uint64_t broken_down_to_unix(uint64_t year, uint64_t yday, uint64_t hour, uint64_t min, uint64_t sec) -{ - return sec + min * 60 + hour * 3600 + yday * 86400 + (year - 70) * 31536000 + ((year - 69) / 4) * 86400 - - ((year - 1) / 100) * 86400 + ((year + 299) / 400) * 86400; -} - -static int bcd_number_to_decimal(int num) -{ - return ((num >> 4) * 10) + (num & 0xf); -} - -uint64_t unix_boottime(uint8_t boottime[8]) -{ - int year = bcd_number_to_decimal(boottime[0]) * 100 + bcd_number_to_decimal(boottime[1]); - int month = bcd_number_to_decimal(boottime[2]); - int day = bcd_number_to_decimal(boottime[3]); - int hour = bcd_number_to_decimal(boottime[4]); - int minute = bcd_number_to_decimal(boottime[5]); - int second = bcd_number_to_decimal(boottime[6]); - kinfoln("UTC boot time: %d-%d-%d %d:%d:%d", year, month, day, hour, minute, second); - return broken_down_to_unix(year - 1900, make_yday(year, month) + (day - 1), hour, minute, second); -} \ No newline at end of file diff --git a/kernel/src/video/BuiltinFont.h b/kernel/src/video/BuiltinFont.h new file mode 100644 index 00000000..ffe907a4 --- /dev/null +++ b/kernel/src/video/BuiltinFont.h @@ -0,0 +1,519 @@ +#pragma once +#include + +// FIXME: Load a font from disk/initrd. + +u8 font[] = { 0x00, 0x00, 0x00, 0x00, 0x7e, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x7e, 0x00, 0x00, 0x00, 0x00, /* 0 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1 */ + 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, + 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, /* 2 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 3 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 4 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 6 */ + 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 9 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10 */ + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 11 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 12 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 13 */ + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 14 */ + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0xff, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 15 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 16 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 17 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 18 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 19 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 20 */ + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 21 */ + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0xf8, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 22 */ + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 23 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 24 */ + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 25 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 26 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 27 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 28 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 29 */ + 0x00, 0x00, 0x00, 0x1c, 0x22, 0x20, 0x20, 0xf8, + 0x20, 0x20, 0x72, 0x8c, 0x00, 0x00, 0x00, 0x00, /* 30 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 31 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 32 */ + 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, /* 33 */ + 0x00, 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 34 */ + 0x00, 0x00, 0x00, 0x24, 0x24, 0x7e, 0x24, 0x24, + 0x24, 0x7e, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, /* 35 */ + 0x00, 0x00, 0x08, 0x08, 0x1e, 0x20, 0x20, 0x1c, + 0x02, 0x02, 0x3c, 0x08, 0x08, 0x00, 0x00, 0x00, /* 36 */ + 0x00, 0x00, 0x00, 0x30, 0x49, 0x4a, 0x34, 0x08, + 0x16, 0x29, 0x49, 0x06, 0x00, 0x00, 0x00, 0x00, /* 37 */ + 0x00, 0x00, 0x30, 0x48, 0x48, 0x48, 0x30, 0x31, + 0x49, 0x46, 0x46, 0x39, 0x00, 0x00, 0x00, 0x00, /* 38 */ + 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 39 */ + 0x00, 0x00, 0x04, 0x08, 0x08, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x08, 0x08, 0x04, 0x00, 0x00, /* 40 */ + 0x00, 0x00, 0x20, 0x10, 0x10, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x10, 0x10, 0x20, 0x00, 0x00, /* 41 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x18, 0x7e, + 0x18, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 42 */ + 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x7f, + 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, /* 43 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x08, 0x08, 0x10, 0x00, /* 44 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 45 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, /* 46 */ + 0x00, 0x00, 0x02, 0x02, 0x04, 0x04, 0x08, 0x08, + 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x00, 0x00, /* 47 */ + 0x00, 0x00, 0x00, 0x3c, 0x42, 0x46, 0x4a, 0x52, + 0x62, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 48 */ + 0x00, 0x00, 0x00, 0x08, 0x18, 0x28, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 49 */ + 0x00, 0x00, 0x00, 0x3c, 0x42, 0x02, 0x02, 0x04, + 0x08, 0x10, 0x20, 0x7e, 0x00, 0x00, 0x00, 0x00, /* 50 */ + 0x00, 0x00, 0x00, 0x7e, 0x04, 0x08, 0x1c, 0x02, + 0x02, 0x02, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 51 */ + 0x00, 0x00, 0x00, 0x04, 0x0c, 0x14, 0x24, 0x44, + 0x7e, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, /* 52 */ + 0x00, 0x00, 0x00, 0x7e, 0x40, 0x40, 0x7c, 0x02, + 0x02, 0x02, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 53 */ + 0x00, 0x00, 0x00, 0x1c, 0x20, 0x40, 0x40, 0x7c, + 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 54 */ + 0x00, 0x00, 0x00, 0x7e, 0x02, 0x04, 0x04, 0x08, + 0x08, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, /* 55 */ + 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x3c, + 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 56 */ + 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x3e, + 0x02, 0x02, 0x04, 0x38, 0x00, 0x00, 0x00, 0x00, /* 57 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, /* 58 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x08, 0x08, 0x10, 0x00, /* 59 */ + 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x40, + 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, /* 60 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, + 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 61 */ + 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x02, + 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, /* 62 */ + 0x00, 0x00, 0x3c, 0x42, 0x02, 0x04, 0x08, 0x10, + 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, /* 63 */ + 0x00, 0x00, 0x1c, 0x22, 0x41, 0x4f, 0x51, 0x51, + 0x51, 0x53, 0x4d, 0x40, 0x20, 0x1f, 0x00, 0x00, /* 64 */ + 0x00, 0x00, 0x00, 0x18, 0x24, 0x42, 0x42, 0x42, + 0x7e, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, /* 65 */ + 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c, + 0x42, 0x42, 0x42, 0x7c, 0x00, 0x00, 0x00, 0x00, /* 66 */ + 0x00, 0x00, 0x00, 0x1e, 0x20, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x20, 0x1e, 0x00, 0x00, 0x00, 0x00, /* 67 */ + 0x00, 0x00, 0x00, 0x78, 0x44, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x44, 0x78, 0x00, 0x00, 0x00, 0x00, /* 68 */ + 0x00, 0x00, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x7c, + 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, /* 69 */ + 0x00, 0x00, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x7c, + 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, /* 70 */ + 0x00, 0x00, 0x00, 0x1e, 0x20, 0x40, 0x40, 0x46, + 0x42, 0x42, 0x22, 0x1e, 0x00, 0x00, 0x00, 0x00, /* 71 */ + 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x7e, + 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, /* 72 */ + 0x00, 0x00, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 73 */ + 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 74 */ + 0x00, 0x00, 0x00, 0x42, 0x44, 0x48, 0x50, 0x60, + 0x50, 0x48, 0x44, 0x42, 0x00, 0x00, 0x00, 0x00, /* 75 */ + 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, /* 76 */ + 0x00, 0x00, 0x00, 0x41, 0x63, 0x55, 0x49, 0x49, + 0x41, 0x41, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00, /* 77 */ + 0x00, 0x00, 0x00, 0x42, 0x62, 0x52, 0x4a, 0x46, + 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, /* 78 */ + 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 79 */ + 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c, + 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, /* 80 */ + 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x3c, 0x04, 0x02, 0x00, 0x00, /* 81 */ + 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c, + 0x48, 0x44, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, /* 82 */ + 0x00, 0x00, 0x00, 0x3e, 0x40, 0x40, 0x20, 0x18, + 0x04, 0x02, 0x02, 0x7c, 0x00, 0x00, 0x00, 0x00, /* 83 */ + 0x00, 0x00, 0x00, 0x7f, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, /* 84 */ + 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 85 */ + 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x24, 0x24, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, /* 86 */ + 0x00, 0x00, 0x00, 0x41, 0x41, 0x41, 0x41, 0x49, + 0x49, 0x49, 0x55, 0x63, 0x00, 0x00, 0x00, 0x00, /* 87 */ + 0x00, 0x00, 0x00, 0x41, 0x41, 0x22, 0x14, 0x08, + 0x14, 0x22, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00, /* 88 */ + 0x00, 0x00, 0x00, 0x41, 0x41, 0x22, 0x14, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, /* 89 */ + 0x00, 0x00, 0x00, 0x7e, 0x04, 0x08, 0x08, 0x10, + 0x10, 0x20, 0x20, 0x7e, 0x00, 0x00, 0x00, 0x00, /* 90 */ + 0x00, 0x00, 0x1e, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x1e, 0x00, 0x00, /* 91 */ + 0x00, 0x00, 0x40, 0x40, 0x20, 0x20, 0x10, 0x10, + 0x08, 0x08, 0x04, 0x04, 0x02, 0x02, 0x00, 0x00, /* 92 */ + 0x00, 0x00, 0x78, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x78, 0x00, 0x00, /* 93 */ + 0x00, 0x00, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 94 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, /* 95 */ + 0x00, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 96 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x02, 0x02, + 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 97 */ + 0x00, 0x00, 0x40, 0x40, 0x40, 0x7c, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x7c, 0x00, 0x00, 0x00, 0x00, /* 98 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x40, + 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 99 */ + 0x00, 0x00, 0x02, 0x02, 0x02, 0x3e, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 100 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, + 0x7e, 0x40, 0x40, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 101 */ + 0x00, 0x00, 0x0e, 0x10, 0x10, 0x7e, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, /* 102 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x3c, 0x00, /* 103 */ + 0x00, 0x00, 0x40, 0x40, 0x40, 0x7c, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, /* 104 */ + 0x00, 0x00, 0x08, 0x08, 0x00, 0x38, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 105 */ + 0x00, 0x00, 0x04, 0x04, 0x00, 0x1c, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x38, 0x00, /* 106 */ + 0x00, 0x00, 0x40, 0x40, 0x40, 0x44, 0x48, 0x50, + 0x70, 0x48, 0x44, 0x42, 0x00, 0x00, 0x00, 0x00, /* 107 */ + 0x00, 0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 108 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x49, 0x49, + 0x49, 0x49, 0x49, 0x49, 0x00, 0x00, 0x00, 0x00, /* 109 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, /* 110 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 111 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x7c, 0x40, 0x40, 0x40, 0x00, /* 112 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x02, 0x00, /* 113 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x30, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, /* 114 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x20, + 0x18, 0x04, 0x02, 0x7c, 0x00, 0x00, 0x00, 0x00, /* 115 */ + 0x00, 0x00, 0x00, 0x10, 0x10, 0x7e, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x0e, 0x00, 0x00, 0x00, 0x00, /* 116 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 117 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, + 0x24, 0x24, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, /* 118 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x41, + 0x49, 0x49, 0x55, 0x63, 0x00, 0x00, 0x00, 0x00, /* 119 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x22, 0x14, + 0x08, 0x14, 0x22, 0x41, 0x00, 0x00, 0x00, 0x00, /* 120 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x3c, 0x00, /* 121 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x04, 0x08, + 0x10, 0x20, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, /* 122 */ + 0x00, 0x0e, 0x10, 0x10, 0x10, 0x10, 0x10, 0xe0, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x0e, 0x00, 0x00, /* 123 */ + 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, /* 124 */ + 0x00, 0x70, 0x08, 0x08, 0x08, 0x08, 0x08, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x70, 0x00, 0x00, /* 125 */ + 0x00, 0x00, 0x31, 0x49, 0x46, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 126 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 127 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 128 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 129 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 130 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 131 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 132 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 133 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 134 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 135 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 136 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 137 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 138 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 139 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 140 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 141 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 142 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 143 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 144 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 145 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 146 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 147 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 148 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 149 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 150 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 151 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 152 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 153 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 154 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 155 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 156 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 157 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 158 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 159 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 160 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, + 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, /* 161 */ + 0x00, 0x00, 0x08, 0x08, 0x1c, 0x22, 0x40, 0x40, + 0x40, 0x22, 0x1c, 0x08, 0x08, 0x00, 0x00, 0x00, /* 162 */ + 0x00, 0x00, 0x00, 0x1c, 0x22, 0x20, 0x20, 0xf8, + 0x20, 0x20, 0x72, 0x8c, 0x00, 0x00, 0x00, 0x00, /* 163 */ + 0x00, 0x00, 0x00, 0x00, 0x42, 0x3c, 0x24, 0x24, + 0x24, 0x3c, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, /* 164 */ + 0x00, 0x00, 0x00, 0x41, 0x22, 0x14, 0x08, 0x3e, + 0x08, 0x3e, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, /* 165 */ + 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, + 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, /* 166 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 167 */ + 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 168 */ + 0x00, 0x00, 0x00, 0x1c, 0x22, 0x41, 0x4d, 0x51, + 0x51, 0x4d, 0x41, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 169 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 170 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x12, 0x24, + 0x48, 0x24, 0x12, 0x09, 0x00, 0x00, 0x00, 0x00, /* 171 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 172 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 173 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 174 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 175 */ + 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 176 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 177 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 178 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 179 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 180 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 181 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 182 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 183 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x30, 0x00, /* 184 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 185 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 186 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x24, 0x12, + 0x09, 0x12, 0x24, 0x48, 0x00, 0x00, 0x00, 0x00, /* 187 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 188 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 189 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 190 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, + 0x00, 0x08, 0x10, 0x20, 0x40, 0x42, 0x3c, 0x00, /* 191 */ + 0x20, 0x10, 0x00, 0x18, 0x18, 0x24, 0x24, 0x24, + 0x7e, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, /* 192 */ + 0x04, 0x08, 0x00, 0x18, 0x18, 0x24, 0x24, 0x24, + 0x7e, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, /* 193 */ + 0x18, 0x24, 0x00, 0x18, 0x18, 0x24, 0x24, 0x24, + 0x7e, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, /* 194 */ + 0x32, 0x4c, 0x00, 0x18, 0x18, 0x24, 0x24, 0x24, + 0x7e, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, /* 195 */ + 0x24, 0x24, 0x00, 0x18, 0x18, 0x24, 0x24, 0x24, + 0x7e, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, /* 196 */ + 0x18, 0x24, 0x24, 0x18, 0x18, 0x24, 0x24, 0x24, + 0x7e, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, /* 197 */ + 0x00, 0x00, 0x00, 0x0f, 0x14, 0x14, 0x24, 0x27, + 0x3c, 0x44, 0x44, 0x47, 0x00, 0x00, 0x00, 0x00, /* 198 */ + 0x00, 0x00, 0x00, 0x1e, 0x20, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x20, 0x1e, 0x08, 0x08, 0x30, 0x00, /* 199 */ + 0x20, 0x10, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x7c, + 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, /* 200 */ + 0x04, 0x08, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x7c, + 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, /* 201 */ + 0x18, 0x24, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x7c, + 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, /* 202 */ + 0x24, 0x24, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x7c, + 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, /* 203 */ + 0x10, 0x08, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 204 */ + 0x04, 0x08, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 205 */ + 0x18, 0x24, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 206 */ + 0x22, 0x22, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 207 */ + 0x00, 0x00, 0x00, 0x3c, 0x22, 0x21, 0x21, 0x79, + 0x21, 0x21, 0x22, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 208 */ + 0x32, 0x4c, 0x00, 0x42, 0x62, 0x52, 0x4a, 0x46, + 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, /* 209 */ + 0x10, 0x08, 0x00, 0x1c, 0x22, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x22, 0x1c, 0x00, 0x00, 0x00, 0x00, /* 210 */ + 0x04, 0x08, 0x00, 0x1c, 0x22, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x22, 0x1c, 0x00, 0x00, 0x00, 0x00, /* 211 */ + 0x18, 0x24, 0x00, 0x1c, 0x22, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x22, 0x1c, 0x00, 0x00, 0x00, 0x00, /* 212 */ + 0x32, 0x4c, 0x00, 0x1c, 0x22, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x22, 0x1c, 0x00, 0x00, 0x00, 0x00, /* 213 */ + 0x24, 0x24, 0x00, 0x1c, 0x22, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x22, 0x1c, 0x00, 0x00, 0x00, 0x00, /* 214 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x14, + 0x08, 0x14, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, /* 215 */ + 0x00, 0x00, 0x02, 0x3c, 0x42, 0x46, 0x4a, 0x52, + 0x62, 0x42, 0x42, 0x3c, 0x40, 0x00, 0x00, 0x00, /* 216 */ + 0x20, 0x10, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 217 */ + 0x04, 0x08, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 218 */ + 0x18, 0x24, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 219 */ + 0x24, 0x24, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 220 */ + 0x04, 0x08, 0x00, 0x41, 0x41, 0x22, 0x14, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, /* 221 */ + 0x00, 0x00, 0x00, 0x40, 0x40, 0x7c, 0x42, 0x42, + 0x42, 0x7c, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, /* 222 */ + 0x00, 0x00, 0x00, 0x3c, 0x42, 0x44, 0x4c, 0x42, + 0x42, 0x42, 0x44, 0x58, 0x00, 0x00, 0x00, 0x00, /* 223 */ + 0x00, 0x00, 0x20, 0x10, 0x00, 0x3c, 0x02, 0x02, + 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 224 */ + 0x00, 0x00, 0x04, 0x08, 0x00, 0x3c, 0x02, 0x02, + 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 225 */ + 0x00, 0x18, 0x24, 0x00, 0x00, 0x3c, 0x02, 0x02, + 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 226 */ + 0x00, 0x32, 0x4c, 0x00, 0x00, 0x3c, 0x02, 0x02, + 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 227 */ + 0x00, 0x00, 0x24, 0x24, 0x00, 0x3c, 0x02, 0x02, + 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 228 */ + 0x18, 0x24, 0x24, 0x18, 0x00, 0x3c, 0x02, 0x02, + 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 229 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x09, 0x39, + 0x4f, 0x48, 0x48, 0x37, 0x00, 0x00, 0x00, 0x00, /* 230 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x40, + 0x40, 0x40, 0x42, 0x3c, 0x08, 0x08, 0x30, 0x00, /* 231 */ + 0x00, 0x00, 0x20, 0x10, 0x00, 0x3c, 0x42, 0x42, + 0x7e, 0x40, 0x40, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 232 */ + 0x00, 0x00, 0x04, 0x08, 0x00, 0x3c, 0x42, 0x42, + 0x7e, 0x40, 0x40, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 233 */ + 0x00, 0x18, 0x24, 0x00, 0x00, 0x3c, 0x42, 0x42, + 0x7e, 0x40, 0x40, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 234 */ + 0x00, 0x00, 0x24, 0x24, 0x00, 0x3c, 0x42, 0x42, + 0x7e, 0x40, 0x40, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 235 */ + 0x00, 0x00, 0x10, 0x08, 0x00, 0x38, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 236 */ + 0x00, 0x00, 0x04, 0x08, 0x00, 0x38, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 237 */ + 0x00, 0x18, 0x24, 0x00, 0x00, 0x38, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 238 */ + 0x00, 0x00, 0x24, 0x24, 0x00, 0x38, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 239 */ + 0x00, 0x09, 0x06, 0x1a, 0x01, 0x1d, 0x23, 0x41, + 0x41, 0x41, 0x22, 0x1c, 0x00, 0x00, 0x00, 0x00, /* 240 */ + 0x00, 0x32, 0x4c, 0x00, 0x00, 0x7c, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, /* 241 */ + 0x00, 0x00, 0x10, 0x08, 0x00, 0x3c, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 242 */ + 0x00, 0x00, 0x04, 0x08, 0x00, 0x3c, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 243 */ + 0x00, 0x18, 0x24, 0x00, 0x00, 0x3c, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 244 */ + 0x00, 0x32, 0x4c, 0x00, 0x00, 0x3c, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 245 */ + 0x00, 0x00, 0x24, 0x24, 0x00, 0x3c, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 246 */ + 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x7e, + 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, /* 247 */ + 0x00, 0x00, 0x00, 0x00, 0x02, 0x3c, 0x46, 0x4a, + 0x52, 0x62, 0x42, 0x3c, 0x40, 0x00, 0x00, 0x00, /* 248 */ + 0x00, 0x00, 0x20, 0x10, 0x00, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 249 */ + 0x00, 0x00, 0x04, 0x08, 0x00, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 250 */ + 0x00, 0x18, 0x24, 0x00, 0x00, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 251 */ + 0x00, 0x00, 0x24, 0x24, 0x00, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 252 */ + 0x00, 0x00, 0x04, 0x08, 0x00, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x3c, 0x00, /* 253 */ + 0x00, 0x00, 0x40, 0x40, 0x40, 0x5c, 0x62, 0x41, + 0x41, 0x41, 0x62, 0x5c, 0x40, 0x40, 0x40, 0x00, /* 254 */ + 0x00, 0x00, 0x24, 0x24, 0x00, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x3c, 0x00, /* 255 */ + 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, + 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x00, 0x00, 0x00 /* Special box character, 256 */ }; diff --git a/kernel/src/video/Framebuffer.cpp b/kernel/src/video/Framebuffer.cpp new file mode 100644 index 00000000..2d379b59 --- /dev/null +++ b/kernel/src/video/Framebuffer.cpp @@ -0,0 +1,83 @@ +#include "video/Framebuffer.h" +#include "boot/bootboot.h" + +static u8* g_fb_ptr = nullptr; +static u32 g_fb_size; +static u32 g_fb_width; +static u32 g_fb_height; +static u32 g_fb_scanline; + +extern const BOOTBOOT bootboot; +extern u8 fb[1]; + +namespace Framebuffer +{ + void init() + { + update(fb, bootboot.fb_size, bootboot.fb_width, bootboot.fb_height, bootboot.fb_scanline); + } + + void update(u8* ptr, u32 size, u32 width, u32 height, u32 scanline) + { + g_fb_ptr = ptr; + g_fb_size = size; + g_fb_width = width; + g_fb_height = height; + g_fb_scanline = scanline; + } + + void pixel(u32 x, u32 y, u32 color) + { + if (!g_fb_ptr) [[unlikely]] + return; + *(u32*)(g_fb_ptr + g_fb_scanline * y + x * 4) = color; + } + + void rect(u32 x, u32 y, u32 w, u32 h, u32 color) + { + if (!g_fb_ptr) [[unlikely]] + return; + for (u32 i = y; i < (y + h); i++) + { + u32* addr = (u32*)(g_fb_ptr + (g_fb_scanline * i) + (x * sizeof(u32))); + for (u32* it = addr; it < (addr + w); it++) *it = color; + } + } + + void rect(u32 x, u32 y, u32 w, u32 h, u32* colors) + { + if (!g_fb_ptr) [[unlikely]] + return; + u32 j = 0; + for (u32 i = y; i < (y + h); i++) + { + u32* addr = (u32*)(g_fb_ptr + (g_fb_scanline * i) + (x * sizeof(u32))); + for (u32* it = addr; it < (addr + w); it++, j++) *it = colors[j]; + } + } + + u8* ptr() + { + return g_fb_ptr; + } + + u32 size() + { + return g_fb_size; + } + + u32 width() + { + return g_fb_width; + } + + u32 height() + { + return g_fb_height; + } + + u32 scanline() + { + return g_fb_scanline; + } +} diff --git a/kernel/src/video/Framebuffer.h b/kernel/src/video/Framebuffer.h new file mode 100644 index 00000000..fb851cc7 --- /dev/null +++ b/kernel/src/video/Framebuffer.h @@ -0,0 +1,18 @@ +#pragma once +#include + +namespace Framebuffer +{ + void init(); + void update(u8* ptr, u32 size, u32 width, u32 height, u32 scanline); + + void pixel(u32 x, u32 y, u32 color); + void rect(u32 x, u32 y, u32 w, u32 h, u32 color); + void rect(u32 x, u32 y, u32 w, u32 h, u32* colors); + + u8* ptr(); + u32 size(); + u32 width(); + u32 height(); + u32 scanline(); +} diff --git a/kernel/src/video/TextConsole.cpp b/kernel/src/video/TextConsole.cpp new file mode 100644 index 00000000..86c7e4ec --- /dev/null +++ b/kernel/src/video/TextConsole.cpp @@ -0,0 +1,202 @@ +#include "video/TextConsole.h" +#include "boot/bootboot.h" +#include "video/Framebuffer.h" +#include +#include +#include +#include +#include +#include + +extern const BOOTBOOT bootboot; + +#include "video/BuiltinFont.h" + +static constexpr u32 BLACK = 0xff000000; +static constexpr u32 WHITE = 0xffffffff; + +static u32 g_background_color = BLACK; +static u32 g_foreground_color = WHITE; + +static constexpr u32 FONT_HEIGHT = 16; +static constexpr u32 FONT_WIDTH = 8; + +static u32 g_x_position = 0; +static u32 g_y_position = 0; + +static Utf8StateDecoder utf8_decoder; + +static void putwchar_at(wchar_t c, u32 x, u32 y) +{ + const u8* glyph = &font[c * 16]; + for (u32 i = 0; i < FONT_HEIGHT; i++) + { + for (u32 j = 0; j < FONT_WIDTH; j++) + { + volatile u8 mask = *glyph; + if (mask & (0b10000000 >> j)) Framebuffer::pixel(x + j, y + i, g_foreground_color); + else + Framebuffer::pixel(x + j, y + i, g_background_color); + } + glyph++; + } +} + +static void erase_current_line() +{ + Framebuffer::rect(0, g_y_position, Framebuffer::width(), FONT_HEIGHT, BLACK); +} + +static void scroll() +{ + memcpy(Framebuffer::ptr(), Framebuffer::ptr() + (Framebuffer::scanline() * FONT_HEIGHT), + Framebuffer::size() - (Framebuffer::scanline() * FONT_HEIGHT)); + g_y_position -= FONT_HEIGHT; + erase_current_line(); +} + +static bool should_scroll() +{ + return (g_y_position + FONT_HEIGHT) >= Framebuffer::height(); +} + +static void next_line() +{ + g_x_position = 0; + g_y_position += FONT_HEIGHT; +} + +static void next_char() +{ + g_x_position += FONT_WIDTH; +} + +static void prev_char() +{ + g_x_position -= FONT_WIDTH; +} + +static void erase_current_char() +{ + Framebuffer::rect(g_x_position, g_y_position, FONT_WIDTH, FONT_HEIGHT, BLACK); +} + +static bool at_end_of_screen() +{ + return (g_x_position + FONT_WIDTH) > Framebuffer::width(); +} + +namespace TextConsole +{ + void putwchar(wchar_t c) + { + // Unprintable (not in the built-in font) characters get represented as a box + if (c > (wchar_t)255) c = (wchar_t)256; + + switch (c) + { + case L'\n': { + next_line(); + if (should_scroll()) scroll(); + break; + } + case L'\r': g_x_position = 0; break; + case L'\b': + if (g_x_position != 0) + { + prev_char(); + erase_current_char(); + } + break; + default: { + putwchar_at(c, g_x_position, g_y_position); + next_char(); + if (at_end_of_screen()) + { + next_line(); + if (should_scroll()) scroll(); + } + break; + } + } + } + + Result putchar(char c) + { + auto guard = make_scope_guard([] { utf8_decoder.reset(); }); + + auto maybe_wchar = TRY(utf8_decoder.feed(c)); + + guard.deactivate(); + + if (maybe_wchar.has_value()) putwchar(maybe_wchar.value()); + + return {}; + } + + void set_foreground(u32 color) + { + g_foreground_color = color; + } + + void set_background(u32 color) + { + g_background_color = color; + } + + u32 foreground() + { + return g_foreground_color; + } + + u32 background() + { + return g_background_color; + } + + void move_to(u32 x, u32 y) + { + g_x_position = x; + g_y_position = y; + } + + void clear() + { + move_to(0, 0); + Framebuffer::rect(0, 0, Framebuffer::width(), Framebuffer::height(), BLACK); + } + + Result print(const char* str) + { + while (*str) TRY(putchar(*str++)); + return {}; + } + + void wprint(const wchar_t* str) + { + while (*str) putwchar(*str++); + } + + Result println(const char* str) + { + TRY(print(str)); + putwchar(L'\n'); + return {}; + } + + void wprintln(const wchar_t* str) + { + wprint(str); + putwchar(L'\n'); + } + + Result printf(const char* format, ...) + { + va_list ap; + va_start(ap, format); + auto rc = TRY(cstyle_format( + format, [](char c, void*) -> Result { return putchar(c); }, nullptr, ap)); + va_end(ap); + return rc; + } +} diff --git a/kernel/src/video/TextConsole.h b/kernel/src/video/TextConsole.h new file mode 100644 index 00000000..c700b138 --- /dev/null +++ b/kernel/src/video/TextConsole.h @@ -0,0 +1,21 @@ +#pragma once +#include +#include +#include + +namespace TextConsole +{ + void clear(); + Result putchar(char c); + void putwchar(wchar_t c); + void set_foreground(u32 color); + void set_background(u32 color); + u32 foreground(); + u32 background(); + void move_to(u32 x, u32 y); + Result print(const char* str); + void wprint(const wchar_t* str); + Result println(const char* str); + void wprintln(const wchar_t* str); + Result printf(const char* format, ...) _format(1, 2); +} diff --git a/libc/CMakeLists.txt b/libc/CMakeLists.txt new file mode 100644 index 00000000..270ecf41 --- /dev/null +++ b/libc/CMakeLists.txt @@ -0,0 +1,54 @@ +file(GLOB HEADERS include/*.h) + +set(SOURCES + ${HEADERS} + src/stdio.cpp + src/stdlib.cpp + src/unistd.cpp + src/errno.cpp + src/string.cpp + src/atexit.cpp + src/ctype.cpp + src/time.cpp +) + +if(${ARCH} STREQUAL "x86_64") + set(SOURCES + ${SOURCES} + src/arch/x86_64/syscall.S + ) +endif() + +add_library(crt0 STATIC src/arch/${ARCH}/crt0.S) +add_custom_command( + TARGET crt0 + COMMAND "${CMAKE_COMMAND}" -E copy $ ${LUNA_BASE}/usr/lib/crt0.o +) + +add_library(bare_libc STATIC ${SOURCES}) + +target_link_libraries(bare_libc PUBLIC luna) + +target_include_directories(bare_libc PUBLIC include/) + +target_compile_options(bare_libc PRIVATE -Wall -Wextra -Werror -pedantic -nostdlib -fno-exceptions -fno-rtti) + +target_link_options(bare_libc PRIVATE -nostdlib) + +set_target_properties(bare_libc PROPERTIES CXX_STANDARD 20) + +add_custom_target(libc + COMMAND ${CMAKE_AR} -x $ + COMMAND ${CMAKE_AR} -x $ + COMMAND ${CMAKE_AR} -rcs ${CMAKE_CURRENT_BINARY_DIR}/libc.a *.o + COMMAND rm *.o + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS bare_libc luna crt0 +) + +add_custom_command( + TARGET libc + COMMAND "${CMAKE_COMMAND}" -E copy ${CMAKE_CURRENT_BINARY_DIR}/libc.a ${LUNA_BASE}/usr/lib/libc.a +) + +file(WRITE "${LUNA_BASE}/usr/lib/libm.a" "INPUT(libc.a)") diff --git a/libc/include/bits/attrs.h b/libc/include/bits/attrs.h new file mode 100644 index 00000000..c9f6cf58 --- /dev/null +++ b/libc/include/bits/attrs.h @@ -0,0 +1,13 @@ +/* bits/attrs.h: Macros wrapping GCC attributes for use in the standard library. */ + +#ifndef _BITS_ATTRS_H +#define _BITS_ATTRS_H + +#if !defined(_STDLIB_H) && !defined(_STRING_H) +#error "Never include bits/attrs.h directly; use one of the standard library headers." +#endif + +#define __noreturn __attribute__((noreturn)) +#define __deprecated __attribute__((deprecated)) + +#endif diff --git a/libc/include/bits/clockid.h b/libc/include/bits/clockid.h new file mode 100644 index 00000000..f9827d6e --- /dev/null +++ b/libc/include/bits/clockid.h @@ -0,0 +1,14 @@ +/* bits/clockid.h: The clockid_t type and its supported values. */ + +#ifndef _BITS_CLOCKID_H +#define _BITS_CLOCKID_H + +typedef int clockid_t; + +enum __clockid +{ + CLOCK_REALTIME, + CLOCK_MONOTONIC +}; + +#endif diff --git a/libc/include/bits/errno-return.h b/libc/include/bits/errno-return.h new file mode 100644 index 00000000..aa8d9492 --- /dev/null +++ b/libc/include/bits/errno-return.h @@ -0,0 +1,18 @@ +/* bits/errno-return.h: A convenient way of setting errno after a syscall. */ + +#ifndef _BITS_ERRNO_RETURN_H +#define _BITS_ERRNO_RETURN_H + +#include + +#define __errno_return(value, type) \ + do { \ + if (value < 0) \ + { \ + errno = (int)(-value); \ + return (type)-1; \ + } \ + return (type)value; \ + } while (0) + +#endif diff --git a/libc/include/bits/timespec.h b/libc/include/bits/timespec.h new file mode 100644 index 00000000..a5866912 --- /dev/null +++ b/libc/include/bits/timespec.h @@ -0,0 +1,14 @@ +/* bits/timespec.h: The timespec structure. */ + +#ifndef _BITS_TIMESPEC_H +#define _BITS_TIMESPEC_H + +#include + +struct timespec +{ + time_t tv_sec; + long tv_nsec; +}; + +#endif diff --git a/libc/include/ctype.h b/libc/include/ctype.h new file mode 100644 index 00000000..8bcb16d9 --- /dev/null +++ b/libc/include/ctype.h @@ -0,0 +1,31 @@ +/* ctype.h: Character handling. */ + +#ifndef _CTYPE_H +#define _CTYPE_H + +#ifdef __cplusplus +extern "C" +{ +#endif + + int isalnum(int c); + int isalpha(int c); + int isascii(int c); + int iscntrl(int c); + int isdigit(int c); + int isxdigit(int c); + int isspace(int c); + int ispunct(int c); + int isprint(int c); + int isgraph(int c); + int islower(int c); + int isupper(int c); + int isblank(int c); + int tolower(int c); + int toupper(int c); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libc/include/errno.h b/libc/include/errno.h new file mode 100644 index 00000000..c5185e06 --- /dev/null +++ b/libc/include/errno.h @@ -0,0 +1,11 @@ +/* errno.h: Error management. */ + +#ifndef _ERRNO_H +#define _ERRNO_H + +/* The last error encountered after a call to a system or library function. */ +extern int errno; + +#include + +#endif diff --git a/libc/include/stdio.h b/libc/include/stdio.h new file mode 100644 index 00000000..3726a8ca --- /dev/null +++ b/libc/include/stdio.h @@ -0,0 +1,65 @@ +/* stdio.h: Standard input/output. */ + +#ifndef _STDIO_H +#define _STDIO_H + +#include +#include + +typedef struct +{ + int __unused; +} FILE; + +#define SEEK_SET 0 + +extern FILE* stderr; +#define stderr stderr + +#ifdef __cplusplus +extern "C" +{ +#endif + + int fflush(FILE*); + + FILE* fopen(const char*, const char*); + int fclose(FILE*); + + size_t fread(void*, size_t, size_t, FILE*); + size_t fwrite(const void*, size_t, size_t, FILE*); + + int fseek(FILE*, long, int); + long ftell(FILE*); + + void setbuf(FILE*, char*); + + int fprintf(FILE*, const char*, ...); + int vfprintf(FILE*, const char*, va_list); + + /* Write formatted output into a buffer. */ + int sprintf(char* buf, const char* format, ...); + + /* Write up to max bytes of formatted output into a buffer. */ + int snprintf(char* buf, size_t max, const char* format, ...); + + /* Write formatted output into a buffer. */ + int vsprintf(char*, const char*, va_list); + + /* Write up to max bytes of formatted output into a buffer. */ + int vsnprintf(char*, size_t, const char*, va_list); + + /* Write formatted output to standard output. */ + int printf(const char*, ...); + + /* Write a string followed by a newline to standard output. */ + int puts(const char* s); + + /* Output a message to the console. */ + int console_write(const char* msg, size_t size); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h new file mode 100644 index 00000000..fc63632d --- /dev/null +++ b/libc/include/stdlib.h @@ -0,0 +1,110 @@ +/* stdlib.h: General utilities. */ + +#ifndef _STDLIB_H +#define _STDLIB_H + +#include +#include + +/* The result of a division operation on two integers. */ +typedef struct +{ + int quot; + int rem; +} div_t; + +/* The result of a division operation on two long integers. */ +typedef struct +{ + long quot; + long rem; +} ldiv_t; + +/* The result of a division operation on two long long integers. */ +typedef struct +{ + long long quot; + long long rem; +} lldiv_t; + +#define MB_CUR_MAX 4 + +#ifdef __cplusplus +extern "C" +{ +#endif + + /* Return the absolute value of an integer. */ + int abs(int v); + + /* Return the absolute value of a long integer. */ + long labs(long v); + + /* Return the absolute value of a long long integer. */ + long long llabs(long long v); + + /* Return the result of dividing two integers, including the remainder. */ + div_t div(int num, int den); + + /* Return the result of dividing two long integers, including the remainder. */ + ldiv_t ldiv(long, long); + + /* Return the result of dividing two long long integers, including the remainder. */ + lldiv_t lldiv(long long, long long); + + void* malloc(size_t); + void* calloc(size_t, size_t); + void* realloc(void*, size_t); + void free(void*); + + /* Abort the program without performing any normal cleanup. */ + __noreturn void abort(); + + /* Register a handler to be run at normal program termination. */ + int atexit(void (*func)(void)); + + /* Parse a decimal integer from a string. */ + int atoi(const char* s); + + /* Parse a decimal integer from a string. */ + long atol(const char* s); + + /* Parse a decimal integer from a string. */ + long long atoll(const char* s); + + double atof(const char*); + + double strtod(const char*, char**); + + /* Parse an integer of the specified base from a string, storing the first non-number character in endptr if + * nonnull. */ + long strtol(const char* str, char** endptr, int base); + + /* Parse an unsigned integer of the specified base from a string, storing the first non-number character in + * endptr if nonnull. */ + unsigned long strtoul(const char* str, char** endptr, int base); + + int rand(); + void srand(int); + + /* Exit the program normally, performing any registered cleanup actions. */ + __noreturn void exit(int); + + /* Exit the program abnormally, without performing any registered cleanup actions. */ + __noreturn void _Exit(int); + + int system(const char*); + + char* getenv(const char*); + + void qsort(void*, size_t, size_t, int (*)(const void*, const void*)); + void* bsearch(const void*, const void*, size_t, size_t, int (*)(const void*, const void*)); + + /* Convert a multibyte character string to a wide character string. */ + size_t mbstowcs(wchar_t* buf, const char* src, size_t max); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libc/include/string.h b/libc/include/string.h new file mode 100644 index 00000000..37a0f299 --- /dev/null +++ b/libc/include/string.h @@ -0,0 +1,51 @@ +/* string.h: String manipulation. */ + +#ifndef _STRING_H +#define _STRING_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + /* Copy n bytes of memory from src to dest. */ + void* memcpy(void* dest, const void* src, size_t n); + + /* Set n bytes of memory to the character c. */ + void* memset(void* buf, int c, size_t n); + + /* Compare n bytes of two memory locations. */ + int memcmp(const void* a, const void* b, size_t n); + + /* Copy n bytes of memory from src to dest, where src and dest may overlap. */ + void* memmove(void* dest, const void* src, size_t n); + + /* Return the length of a null-terminated string. */ + size_t strlen(const char* str); + + /* Compare two null-terminated strings. */ + int strcmp(const char* a, const char* b); + + /* Copy the null-terminated string src into dest. Should be avoided to prevent buffer overflow attacks. */ + __deprecated char* strcpy(char* dest, const char* src); + + /* Concatenate the null-terminated string src onto dest. Should be avoided to prevent buffer overflow attacks. */ + __deprecated char* strcat(char* dest, const char* src); + + /* Return a pointer to the first occurrence of the character c in str, or NULL if it could not be found. */ + char* strchr(const char* str, int c); + + /* Return a heap-allocated copy of a string. */ + char* strdup(const char* str); + + /* Return the human-readable description of an error number. */ + char* strerror(int errnum); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libc/include/sys/syscall.h b/libc/include/sys/syscall.h new file mode 100644 index 00000000..856bda76 --- /dev/null +++ b/libc/include/sys/syscall.h @@ -0,0 +1,10 @@ +/* sys/syscall.h: Syscall constants. */ + +#ifndef _SYS_SYSCALL_H +#define _SYS_SYSCALL_H + +/* This header just forwards to luna/Syscall.h, which is used in the kernel as well. */ +#include +#undef enumerate_syscalls + +#endif diff --git a/libc/include/sys/types.h b/libc/include/sys/types.h new file mode 100644 index 00000000..0f224f41 --- /dev/null +++ b/libc/include/sys/types.h @@ -0,0 +1,13 @@ +/* sys/types.h: System data types. */ + +#ifndef _SYS_TYPES_H +#define _SYS_TYPES_H + +#define __need_size_t +#include + +typedef int pid_t; + +typedef long time_t; + +#endif diff --git a/libc/include/time.h b/libc/include/time.h new file mode 100644 index 00000000..27979f90 --- /dev/null +++ b/libc/include/time.h @@ -0,0 +1,24 @@ +/* time.h: Time management. */ + +#ifndef _TIME_H +#define _TIME_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + /* Get the current value of a system clock. */ + int clock_gettime(clockid_t id, struct timespec* ts); + + /* Get the current wall clock time. */ + time_t time(time_t* tp); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libc/include/unistd.h b/libc/include/unistd.h new file mode 100644 index 00000000..218be84d --- /dev/null +++ b/libc/include/unistd.h @@ -0,0 +1,31 @@ +/* unistd.h: POSIX constants and functions. */ + +#ifndef _UNISTD_H +#define _UNISTD_H + +#define __need_NULL +#include + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + pid_t fork(); + pid_t getpid(); + + int execv(const char*, char* const*); + int execve(const char*, char* const*, char* const*); + int execvp(const char*, char* const*); + + /* Calls the operating system kernel for a specific service. */ + long syscall(long num, ...); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libc/src/arch/x86_64/crt0.S b/libc/src/arch/x86_64/crt0.S new file mode 100644 index 00000000..cfebdc21 --- /dev/null +++ b/libc/src/arch/x86_64/crt0.S @@ -0,0 +1,20 @@ +.section .text + +.global _start +.extern exit +_start: + # Set up end of the stack frame linked list. + movq $0, %rbp + pushq %rbp # rip=0 + pushq %rbp # rbp=0 + movq %rsp, %rbp + + # Run the global constructors. + call _init + + # Run main + call main + + # Terminate the process with the exit code. + movl %eax, %edi + call exit diff --git a/libc/src/arch/x86_64/syscall.S b/libc/src/arch/x86_64/syscall.S new file mode 100644 index 00000000..9ec1286c --- /dev/null +++ b/libc/src/arch/x86_64/syscall.S @@ -0,0 +1,10 @@ +.global arch_invoke_syscall +arch_invoke_syscall: + mov %rdi, %rax + mov %rsi, %rdi + mov %rdx, %rsi + mov %rcx, %rdx + mov %r8, %r10 + mov %r9, %r8 + int $66 + ret diff --git a/libc/src/atexit.cpp b/libc/src/atexit.cpp new file mode 100644 index 00000000..94f86e08 --- /dev/null +++ b/libc/src/atexit.cpp @@ -0,0 +1,28 @@ +#include + +typedef void (*atexit_func_t)(void); + +const int ATEXIT_MAX_FUNCS = 48; + +int atexit_registered_funcs = 0; + +atexit_func_t atexit_funcs[ATEXIT_MAX_FUNCS]; + +extern "C" +{ + int atexit(atexit_func_t func) + { + if (atexit_registered_funcs == ATEXIT_MAX_FUNCS) return -1; + + atexit_funcs[atexit_registered_funcs++] = func; + + return 0; + } + + __noreturn void exit(int status) + { + while (atexit_registered_funcs--) { atexit_funcs[atexit_registered_funcs](); } + + _Exit(status); + } +} diff --git a/libc/src/ctype.cpp b/libc/src/ctype.cpp new file mode 100644 index 00000000..daec56d5 --- /dev/null +++ b/libc/src/ctype.cpp @@ -0,0 +1,31 @@ +#include +#include + +#define ctype_wrapper(a, b) \ + int a(int c) \ + { \ + return b(c); \ + } + +// clang-format off + +extern "C" +{ + ctype_wrapper(isalnum, _isalnum) + ctype_wrapper(isalpha, _isalpha) + ctype_wrapper(isascii, _isascii) + ctype_wrapper(iscntrl, _iscntrl) + ctype_wrapper(isdigit, _isdigit) + ctype_wrapper(isxdigit, _isxdigit) + ctype_wrapper(isspace, _isspace) + ctype_wrapper(ispunct, _ispunct) + ctype_wrapper(isprint, _isprint) + ctype_wrapper(isgraph, _isgraph) + ctype_wrapper(islower, _islower) + ctype_wrapper(isupper, _isupper) + ctype_wrapper(isblank, _isblank) + ctype_wrapper(tolower, _tolower) + ctype_wrapper(toupper, _toupper) +} + +// clang-format on diff --git a/libc/src/errno.cpp b/libc/src/errno.cpp new file mode 100644 index 00000000..14a81221 --- /dev/null +++ b/libc/src/errno.cpp @@ -0,0 +1,3 @@ +#include + +int errno = 0; diff --git a/libc/src/stdio.cpp b/libc/src/stdio.cpp new file mode 100644 index 00000000..0d4102f0 --- /dev/null +++ b/libc/src/stdio.cpp @@ -0,0 +1,73 @@ +#define _LUNA_SYSTEM_ERROR_EXTENSIONS +#include +#include +#include +#include +#include +#include + +FILE* stderr = nullptr; + +extern "C" +{ + int console_write(const char* str, size_t size) + { + long rc = syscall(SYS_console_write, str, size); + __errno_return(rc, int); + } + + int vsnprintf(char* buf, size_t max, const char* format, va_list ap) + { + return (int)vstring_format(buf, max, format, ap); + } + + int snprintf(char* buf, size_t max, const char* format, ...) + { + va_list ap; + va_start(ap, format); + + int rc = vsnprintf(buf, max, format, ap); + + va_end(ap); + + return rc; + } + + int vsprintf(char* buf, const char* format, va_list ap) + { + return vsnprintf(buf, (size_t)-1, format, ap); + } + + int sprintf(char* buf, const char* format, ...) + { + va_list ap; + va_start(ap, format); + + int rc = vsnprintf(buf, (size_t)-1, format, ap); + + va_end(ap); + + return rc; + } + + int printf(const char* format, ...) + { + va_list ap; + va_start(ap, format); + + int rc = (int)pure_cstyle_format( + format, [](char c, void*) { console_write(&c, 1); }, nullptr, ap); + + va_end(ap); + + return rc; + } + + int puts(const char* s) + { + if (console_write(s, strlen(s)) < 0) return -1; + if (console_write("\n", 1) < 0) return -1; + + return 0; + } +} diff --git a/libc/src/stdlib.cpp b/libc/src/stdlib.cpp new file mode 100644 index 00000000..d92a45bf --- /dev/null +++ b/libc/src/stdlib.cpp @@ -0,0 +1,121 @@ +#include +#include +#include +#include +#include +#include + +template static inline ResultT __generic_div(ArgT a, ArgT b) +{ + ResultT result; + result.quot = a / b; + result.rem = a % b; + + if (a >= 0 && result.rem < 0) + { + result.quot++; + result.rem -= b; + } + + return result; +} + +extern "C" +{ + int abs(int v) + { + return __builtin_abs(v); + } + + long labs(long v) + { + return __builtin_labs(v); + } + + long long llabs(long long v) + { + return __builtin_llabs(v); + } + + div_t div(int num, int den) + { + return __generic_div(num, den); + } + + ldiv_t ldiv(long num, long den) + { + return __generic_div(num, den); + } + + lldiv_t lldiv(long long num, long long den) + { + return __generic_div(num, den); + } + + int atoi(const char* s) + { + return (int)strtol(s, NULL, 10); + } + + long atol(const char* s) + { + return strtol(s, NULL, 10); + } + + // Assuming LP64, long long == long. + long long atoll(const char* s) + { + return (long long)strtol(s, NULL, 10); + } + + // These checks are only necessary on LLP64 platforms, where long won't match size_t/ssize_t. Probably redundant + // then (since Luna follows the regular LP64 model), but oh well... + long strtol(const char* str, char** endptr, int base) + { + isize rc = parse_signed_integer(str, const_cast(endptr), base); + + if (rc > (isize)LONG_MAX) return LONG_MAX; + if (rc < (isize)LONG_MIN) return LONG_MIN; + + return rc; + } + + unsigned long strtoul(const char* str, char** endptr, int base) + { + usize rc = parse_unsigned_integer(str, const_cast(endptr), base); + + if (rc > (usize)ULONG_MAX) return ULONG_MAX; + + return rc; + } + + __noreturn void abort() + { + syscall(SYS_exit); + __builtin_unreachable(); + } + + __noreturn void _Exit(int) + { + syscall(SYS_exit); + __builtin_unreachable(); + } + + // FIXME: This is walking a UTF-8 string twice. Once to decode, and another to count code points. + size_t mbstowcs(wchar_t* buf, const char* src, size_t max) + { + if (max == 0) return 0; + + Utf8StringDecoder decoder(src); + + auto rc = decoder.decode(buf, max); + + if (rc.has_error()) return (size_t)-1; + + size_t code_points = decoder.code_points().value_or(0); + + if (code_points >= max) return max - 1; + + return code_points; + } +} diff --git a/libc/src/string.cpp b/libc/src/string.cpp new file mode 100644 index 00000000..0c22b9af --- /dev/null +++ b/libc/src/string.cpp @@ -0,0 +1,14 @@ +#define _LUNA_SYSTEM_ERROR_EXTENSIONS +#include +#include + +extern "C" +{ + // memcpy, memset, memcmp, memmove, strlen, strcmp, strcpy, strchr, strcat and strdup are defined in + // luna/CString.cpp, so the same definitions can be used by both kernel and userspace. + + char* strerror(int errnum) + { + return const_cast(error_string(errnum)); + } +} diff --git a/libc/src/time.cpp b/libc/src/time.cpp new file mode 100644 index 00000000..b33a3c6c --- /dev/null +++ b/libc/src/time.cpp @@ -0,0 +1,23 @@ +#include +#include +#include +#include + +extern "C" +{ + int clock_gettime(clockid_t id, struct timespec* ts) + { + long rc = syscall(SYS_clock_gettime, id, ts); + __errno_return(rc, int); + } + + time_t time(time_t* tp) + { + struct timespec ts; + if (clock_gettime(CLOCK_REALTIME, &ts) < 0) return (time_t)-1; + + if (tp) *tp = ts.tv_sec; + + return ts.tv_sec; + } +} diff --git a/libc/src/unistd.cpp b/libc/src/unistd.cpp new file mode 100644 index 00000000..58b0c277 --- /dev/null +++ b/libc/src/unistd.cpp @@ -0,0 +1,26 @@ +#include +#include +#include + +extern "C" long arch_invoke_syscall(long, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t); + +extern "C" +{ + long syscall(long num, ...) + { + va_list ap; + va_start(ap, num); + + uintptr_t arg0 = va_arg(ap, uintptr_t); + uintptr_t arg1 = va_arg(ap, uintptr_t); + uintptr_t arg2 = va_arg(ap, uintptr_t); + uintptr_t arg3 = va_arg(ap, uintptr_t); + uintptr_t arg4 = va_arg(ap, uintptr_t); + + long rc = arch_invoke_syscall(num, arg0, arg1, arg2, arg3, arg4); + + va_end(ap); + + return rc; + } +} diff --git a/libs/Makefile b/libs/Makefile deleted file mode 100644 index a0712517..00000000 --- a/libs/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -build: - @$(MAKE) -C libc build - -install: - @$(MAKE) -C libc install - -clean: - @$(MAKE) -C libc clean \ No newline at end of file diff --git a/libs/libc/Makefile b/libs/libc/Makefile deleted file mode 100644 index 804c5682..00000000 --- a/libs/libc/Makefile +++ /dev/null @@ -1,87 +0,0 @@ -LIBC_DIR := $(LUNA_ROOT)/libs/libc -LIBC_SRC := $(LIBC_DIR)/src -LIBC_OBJ := $(LIBC_DIR)/lib -LIBC_BIN := $(LIBC_DIR)/bin - -DESTDIR ?= $(LUNA_BASE)/usr/lib - -CFLAGS := -Os -nostdlib -ffunction-sections -fdata-sections -fno-asynchronous-unwind-tables -fno-omit-frame-pointer -pedantic -Wall -Wextra -Werror -Wfloat-equal -Wdisabled-optimization -Wformat=2 -Winit-self -Wmissing-include-dirs -Wswitch-default -Wcast-qual -Wundef -Wcast-align -Wwrite-strings -Wlogical-op -Wredundant-decls -Wshadow -Wconversion -CXXFLAGS := -fno-rtti -fno-exceptions -Wsign-promo -Wstrict-null-sentinel -Wctor-dtor-privacy -ASMFLAGS := -felf64 - -rwildcard=$(foreach d,$(wildcard $(1:=/*)),$(call rwildcard,$d,$2) $(filter $(subst *,%,$2),$d)) - -CXX_SRC = $(call rwildcard,$(LIBC_SRC),*.cpp) -C_SRC = $(call rwildcard,$(LIBC_SRC),*.c) -ASM_SRC = $(call rwildcard,$(LIBC_SRC),*.asm) - -OBJS = $(patsubst $(LIBC_SRC)/%.cpp, $(LIBC_OBJ)/%.cpp.o, $(CXX_SRC)) -OBJS += $(patsubst $(LIBC_SRC)/%.c, $(LIBC_OBJ)/%.c.o, $(C_SRC)) -OBJS += $(patsubst $(LIBC_SRC)/%.asm, $(LIBC_OBJ)/%.asm.o, $(ASM_SRC)) - -$(LIBC_OBJ)/%.cpp.o: $(LIBC_SRC)/%.cpp - @mkdir -p $(@D) - @$(CXX) $(CFLAGS) $(CXXFLAGS) -o $@ -c $^ - @echo " CXX $^" - -$(LIBC_OBJ)/%.c.o: $(LIBC_SRC)/%.c - @mkdir -p $(@D) - @$(CC) $(CFLAGS) -o $@ -c $^ - @echo " CC $^" - -$(LIBC_OBJ)/%.asm.o: $(LIBC_SRC)/%.asm - @mkdir -p $(@D) - @$(ASM) $(ASMFLAGS) -o $@ $^ - @echo " ASM $^" - -$(LIBC_BIN)/libc.a: $(OBJS) - @mkdir -p $(@D) - @$(AR) rcs $@ $(OBJS) - @echo " AR $@" - -$(LIBC_BIN)/crt0.o: $(LIBC_DIR)/crt0.asm - @mkdir -p $(@D) - @$(ASM) $(ASMFLAGS) -o $@ $^ - @echo " ASM $^" - -$(LIBC_BIN)/crti.o: $(LIBC_DIR)/crti.asm - @mkdir -p $(@D) - @$(ASM) $(ASMFLAGS) -o $@ $^ - @echo " ASM $^" - -$(LIBC_BIN)/crtn.o: $(LIBC_DIR)/crtn.asm - @mkdir -p $(@D) - @$(ASM) $(ASMFLAGS) -o $@ $^ - @echo " ASM $^" - -build: $(LIBC_BIN)/crt0.o $(LIBC_BIN)/crti.o $(LIBC_BIN)/crtn.o $(LIBC_BIN)/libc.a - -$(DESTDIR)/libc.a: $(LIBC_BIN)/libc.a - @mkdir -p $(@D) - @cp $^ $@ - @rm -f $(DESTDIR)/libm.a - @ln -s $@ $(DESTDIR)/libm.a - @echo " INSTALL $^" - -$(DESTDIR)/crt0.o: $(LIBC_BIN)/crt0.o - @mkdir -p $(@D) - @cp $^ $@ - @echo " INSTALL $^" - -$(DESTDIR)/crti.o: $(LIBC_BIN)/crti.o - @mkdir -p $(@D) - @cp $^ $@ - @echo " INSTALL $^" - -$(DESTDIR)/crtn.o: $(LIBC_BIN)/crtn.o - @mkdir -p $(@D) - @cp $^ $@ - @echo " INSTALL $^" - -install: $(DESTDIR)/libc.a $(DESTDIR)/crt0.o $(DESTDIR)/crti.o $(DESTDIR)/crtn.o - -clean: - rm -rf $(LIBC_OBJ)/* - rm -rf $(LIBC_BIN)/* - rm -f $(DESTDIR)/libc.a - rm -f $(DESTDIR)/crt*.o \ No newline at end of file diff --git a/libs/libc/crt0.asm b/libs/libc/crt0.asm deleted file mode 100644 index 71973e6a..00000000 --- a/libs/libc/crt0.asm +++ /dev/null @@ -1,35 +0,0 @@ -section .text - -extern _init -extern main -extern _fini -extern initialize_libc -extern exit - -global _start -_start: - ; Set up end of the stack frame linked list. - xor rbp, rbp - push rbp ; rip=0 - push rbp ; rbp=0 - mov rbp, rsp - - push rdi - push rsi - - call initialize_libc - - call _init - - pop rsi ; argv - pop rdi ; argc - - call main - - push rax - - call _fini - - pop rdi - - call exit \ No newline at end of file diff --git a/libs/libc/crti.asm b/libs/libc/crti.asm deleted file mode 100644 index 6b5aed06..00000000 --- a/libs/libc/crti.asm +++ /dev/null @@ -1,11 +0,0 @@ -section .init -global _init -_init: - push rbp - mov rbp, rsp - -section .fini -global _fini -_fini: - push rbp - mov rbp, rsp \ No newline at end of file diff --git a/libs/libc/crtn.asm b/libs/libc/crtn.asm deleted file mode 100644 index 5d8b3e55..00000000 --- a/libs/libc/crtn.asm +++ /dev/null @@ -1,7 +0,0 @@ -section .init - pop rbp - ret - -section .fini - pop rbp - ret \ No newline at end of file diff --git a/libs/libc/include/alloca.h b/libs/libc/include/alloca.h deleted file mode 100644 index 17b377cb..00000000 --- a/libs/libc/include/alloca.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _ALLOCA_H -#define _ALLOCA_H - -#define alloca __builtin_alloca - -#endif \ No newline at end of file diff --git a/libs/libc/include/assert.h b/libs/libc/include/assert.h deleted file mode 100644 index 2090bd17..00000000 --- a/libs/libc/include/assert.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef _ASSERT_H -#define _ASSERT_H - -#include -#include - -#ifdef __cplusplus -extern "C" -{ -#endif - - __lc_noreturn bool __assertion_failed(const char* file, int line, const char* function, const char* expr); - -#ifdef __cplusplus -} -#endif - -#ifdef NDEBUG -#define assert(expr) (void)0 -#else -#define assert(expr) (bool)(expr) || __assertion_failed(__FILE__, __LINE__, __FUNCTION__, #expr) // Verify a condition. -#endif - -#endif \ No newline at end of file diff --git a/libs/libc/include/bits/error.h b/libs/libc/include/bits/error.h deleted file mode 100644 index 8e92d81f..00000000 --- a/libs/libc/include/bits/error.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef _BITS_ERROR_H -#define _BITS_ERROR_H - -#include - -#define _RETURN_WITH_ERRNO(rc, type) \ - do { \ - if (rc < 0) \ - { \ - errno = (int)(-rc); \ - return -1; \ - } \ - errno = 0; \ - return (type)rc; \ - } while (0) - -#define _RETURN_WITH_MEMORY_ERRNO(rc, type) \ - do { \ - if ((unsigned long int)rc > 0xffffffffffffff00) \ - { \ - errno = (int)((rc)&0xff); \ - return (type)-1; \ - } \ - errno = 0; \ - return (type)rc; \ - } while (0) - -#endif \ No newline at end of file diff --git a/libs/libc/include/bits/getprocid.h b/libs/libc/include/bits/getprocid.h deleted file mode 100644 index aa0396a4..00000000 --- a/libs/libc/include/bits/getprocid.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _BITS_GETPROCID_H -#define _BITS_GETPROCID_H - -#define ID_PID 0 -#define ID_PPID 1 -#define ID_UID 2 -#define ID_EUID 3 -#define ID_GID 4 -#define ID_EGID 5 - -#endif \ No newline at end of file diff --git a/libs/libc/include/bits/liballoc.h b/libs/libc/include/bits/liballoc.h deleted file mode 100644 index 1375c4fe..00000000 --- a/libs/libc/include/bits/liballoc.h +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef _BITS_LIBALLOC_H -#define _BITS_LIBALLOC_H - -#include - -/** \defgroup ALLOCHOOKS liballoc hooks - * - * These are the OS specific functions which need to - * be implemented on any platform that the library - * is expected to work on. - */ - -/** @{ */ - -// If we are told to not define our own size_t, then we skip the define. -//#define _HAVE_UINTPTR_T -// typedef unsigned long uintptr_t; - -// This lets you prefix malloc and friends -#define PREFIX(func) func - -#ifdef __cplusplus -extern "C" -{ -#endif - - /** This function is supposed to lock the memory data structures. It - * could be as simple as disabling interrupts or acquiring a spinlock. - * It's up to you to decide. - * - * \return 0 if the lock was acquired successfully. Anything else is - * failure. - */ - extern int liballoc_lock(); - - /** This function unlocks what was previously locked by the liballoc_lock - * function. If it disabled interrupts, it enables interrupts. If it - * had acquiried a spinlock, it releases the spinlock. etc. - * - * \return 0 if the lock was successfully released. - */ - extern int liballoc_unlock(); - - /** This is the hook into the local system which allocates pages. It - * accepts an integer parameter which is the number of pages - * required. The page size was set up in the liballoc_init function. - * - * \return NULL if the pages were not allocated. - * \return A pointer to the allocated memory. - */ - extern void* liballoc_alloc(size_t); - - /** This frees previously allocated memory. The void* parameter passed - * to the function is the exact same value returned from a previous - * liballoc_alloc call. - * - * The integer value is the number of pages to free. - * - * \return 0 if the memory was successfully freed. - */ - extern int liballoc_free(void*, size_t); - - extern void* PREFIX(malloc)(size_t); ///< The standard function. - extern void* PREFIX(realloc)(void*, size_t); ///< The standard function. - extern void* PREFIX(calloc)(size_t, size_t); ///< The standard function. - extern void PREFIX(free)(void*); ///< The standard function. - -#ifdef __cplusplus -} -#endif - -/** @} */ - -#endif diff --git a/libs/libc/include/bits/macros.h b/libs/libc/include/bits/macros.h deleted file mode 100644 index 12ca8372..00000000 --- a/libs/libc/include/bits/macros.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _BITS_MACROS_H -#define _BITS_MACROS_H - -#define __lc_noreturn __attribute__((noreturn)) -#define __lc_align(n) __attribute__((aligned(n))) -#define __lc_deprecated(msg) __attribute__((deprecated(msg))) -#define __lc_is_deprecated __attribute__((deprecated)) -#define __lc_unreachable __builtin_unreachable -#define __lc_used __attribute__((used)) -#define __lc_unused __attribute__((unused)) - -#endif \ No newline at end of file diff --git a/libs/libc/include/bits/seek.h b/libs/libc/include/bits/seek.h deleted file mode 100644 index ed0e59d3..00000000 --- a/libs/libc/include/bits/seek.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _BITS_SEEK_H -#define _BITS_SEEK_H - -#define SEEK_SET 0 // Seek from beginning of file. -#define SEEK_CUR 1 // Seek from current position. -#define SEEK_END 2 // Seek from end of file. - -#endif \ No newline at end of file diff --git a/libs/libc/include/ctype.h b/libs/libc/include/ctype.h deleted file mode 100644 index ac08800d..00000000 --- a/libs/libc/include/ctype.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef _CTYPE_H -#define _CTYPE_H - -#include - -#ifdef __cplusplus -extern "C" -{ -#endif - - /* Is this character alphanumeric? */ - int isalnum(int c); - - /* Is this character a letter? */ - int isalpha(int c); - - /* Is this character part of ASCII? */ - int isascii(int c); - - /* Is this character a blank character (space or tab)? */ - int isblank(int c); - - /* Is this character a control character? */ - int iscntrl(int c); - - /* Is this character a digit? */ - int isdigit(int c); - - /* Is this character any printable character except space? */ - int isgraph(int c); - - /* Is this character a lowercase letter? */ - int islower(int c); - - /* Is this character any printable character (including space)? */ - int isprint(int c); - - /* Is this character any printable character which is not a space or an alphanumeric character? */ - int ispunct(int c); - - /* Is this character any space character (space, form feed, newline, carriage return, tab, vertical tab)? */ - int isspace(int c); - - /* Is this character an uppercase letter? */ - int isupper(int c); - - /* Is this character a hexadecimal digit (0-9, a-f, A-F)? */ - int isxdigit(int c); - - /* Returns the lowercase form of the specified character. */ - int tolower(int c); - - /* Returns the uppercase form of the specified character. */ - int toupper(int c); - - /* Returns the character c, truncated to fit in the ASCII character set. This function should not be used, as it - * will convert accented letters into random characters. */ - __lc_is_deprecated int toascii(int c); - -#ifdef __cplusplus -} -#endif - -#endif \ No newline at end of file diff --git a/libs/libc/include/dirent.h b/libs/libc/include/dirent.h deleted file mode 100644 index 26f3dc0b..00000000 --- a/libs/libc/include/dirent.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef _DIRENT_H -#define _DIRENT_H - -#include -#include - -/* An entry in a directory. */ -struct dirent -{ - ino_t d_ino; - off_t d_off; - unsigned short d_reclen; - unsigned char d_type; - char d_name[NAME_MAX]; -}; - -#define DT_BLK 1 // This is a block device. -#define DT_CHR 2 // This is a character device. -#define DT_DIR 3 // This is a directory. -#define DT_FIFO 4 // This is a named pipe (FIFO). -#define DT_LNK 5 // This is a symbolic link. -#define DT_REG 6 // This is a regular file. -#define DT_SOCK 7 // This is a UNIX domain socket. -#define DT_UNKNOWN 0 // The file type could not be determined. - -/* A stream representing a directory. */ -typedef struct -{ - int d_dirfd; -} DIR; - -#ifdef __cplusplus -extern "C" -{ -#endif - - /* Opens the directory at path and returns a handle to it, or NULL on error. */ - DIR* opendir(const char* path); - - /* Returns a new directory handle associated with the file descriptor fd. */ - DIR* fdopendir(int fd); - - /* Closes the directory stream. */ - int closedir(DIR* stream); - - /* Reads an entry from the directory stream. The contents of the pointer returned may be overwritten by subsequent - * calls to readdir(). */ - struct dirent* readdir(DIR* stream); - - /* Returns the file descriptor associated with stream. */ - int dirfd(DIR* stream); - - /* Positions stream's offset at the start of the directory. */ - void rewinddir(DIR* stream); - - /* Returns the current offset position for stream. */ - long telldir(DIR* stream); - - /* Moves stream's read offset to offset, which should be the return value of a previous call to telldir(). */ - void seekdir(DIR* stream, long offset); - -#ifdef __cplusplus -} -#endif - -#endif \ No newline at end of file diff --git a/libs/libc/include/errno.h b/libs/libc/include/errno.h deleted file mode 100644 index 53d58486..00000000 --- a/libs/libc/include/errno.h +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef _ERRNO_H -#define _ERRNO_H - -/* The last error encountered during a call to a library or system function. */ -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. Not implemented. -#define EIO 5 // Input/output error. Not implemented. -#define ENXIO 6 // No such device or address. Not implemented. -#define E2BIG 7 // Argument list too long -#define ENOEXEC 8 // Exec format error -#define EBADF 9 // Bad file descriptor -#define ECHILD 10 // No child processes -#define EAGAIN 11 // Resource temporarily unavailable -#define EWOULDBLOCK 11 // Resource temporarily unavailable -#define ENOMEM 12 // Cannot allocate memory -#define EACCES 13 // Permission denied -#define EFAULT 14 // Bad address -#define EBUSY 16 // Device or resource busy. Not implemented. -#define EEXIST 17 // File exists -#define EXDEV 18 // Invalid cross-device link. Not implemented. -#define ENODEV 19 // No such device. Not implemented. -#define ENOTDIR 20 // Not a directory -#define EISDIR 21 // Is a directory -#define EINVAL 22 // Invalid argument -#define ENFILE 23 // Too many open files in system. Not implemented. -#define EMFILE 24 // Too many open files -#define ENOTTY 25 // Inappropriate ioctl for device -#define EFBIG 27 // File too large. Not implemented. -#define ENOSPC 28 // No space left on device -#define ESPIPE 29 // Illegal seek. Not implemented. -#define EROFS 30 // Read-only file system. Not implemented. -#define EMLINK 31 // Too many links. Not implemented. -#define EPIPE 32 // Broken pipe. Not implemented. -#define EDOM 33 // Numerical argument out of domain. Not implemented. -#define ERANGE 34 // Numerical result out of range -#define EDEADLK 35 // Resource deadlock avoided. Not implemented. -#define ENAMETOOLONG 36 // File name too long. Not implemented. -#define ENOLCK 37 // No locks available. Not implemented. -#define ENOSYS 38 // Function not implemented -#define ENOTEMPTY 39 // Directory not empty. Not implemented. -#define ELOOP 40 // Too many levels of symbolic links. Not implemented. -#define ENOMSG 42 // No message of desired type. Not implemented. -#define EOVERFLOW 75 // Value too large for defined data type. Not implemented. -#define EILSEQ 84 // Invalid or incomplete multibyte or wide character. Not implemented. -#define ENOTSOCK 88 // Socket operation on non-socket. Not implemented. -#define ENOTSUP 95 // Operation not supported -#define EOPNOTSUPP 95 // Operation not supported -#define EADDRINUSE 98 // Address already in use. Not implemented. -#define ENETRESET 102 // Network dropped connection on reset. Not implemented. -#define ECONNRESET 104 // Connection reset by peer. Not implemented. -#define EISCONN 106 // Transport endpoint is already connected. Not implemented. -#define ETIMEDOUT 110 // Connection timed out. Not implemented. -#define EALREADY 114 // Operation already in progress. Not implemented. - -// FIXME: Right now I don't want to have to order and label these, since we have no net support anyways. -#define EADDRNOTAVAIL -1 -#define EAFNOSUPPORT -2 -#define ECONNABORTED -3 -#define ECONNREFUSED -4 -#define EDESTADDRREQ -5 -#define EHOSTUNREACH -6 -#define EINPROGRESS -7 -#define EMSGSIZE -8 -#define ENETDOWN -9 -#define ENETRESET -10 -#define ENETUNREACH -11 -#define ENOBUFS -12 -#define ENOMSG -13 -#define ENOPROTOOPT -14 -#define ENOTCONN -15 -#define ENOTSOCK -16 -#define EPROTONOSUPPORT -17 -#define EPROTOTYPE -18 - -#ifdef _GNU_SOURCE // Give it only to programs that ask for it. -/* Name used to invoke calling program. Same value as argv[0] in main(), but can be used globally. */ -extern char* program_invocation_name; -#endif - -#endif \ No newline at end of file diff --git a/libs/libc/include/fcntl.h b/libs/libc/include/fcntl.h deleted file mode 100644 index 0af71315..00000000 --- a/libs/libc/include/fcntl.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef _FCNTL_H -#define _FCNTL_H - -#include - -/* Open for reading only. */ -#define O_RDONLY 1 -/* Open for writing only. */ -#define O_WRONLY 2 -/* Open for reading and writing. */ -#define O_RDWR 3 -/* Open without blocking. */ -#define O_NONBLOCK 4 -/* Close the opened file descriptor on a call to execve(). */ -#define O_CLOEXEC 8 -/* Refuse to open the file if it is not a directory. */ -#define O_DIRECTORY 16 -/* Truncate the file on open. */ -#define O_TRUNC 32 -/* Create the file if it doesn't exist. */ -#define O_CREAT 64 -/* Open the file for appending. */ -#define O_APPEND 128 -/* Fail to open the file if it already exists. */ -#define O_EXCL 256 - -/* Duplicate a file descriptor. */ -#define F_DUPFD 0 -/* Is a file descriptor a TTY? */ -#define F_ISTTY 1 -/* Get the file descriptor flags. */ -#define F_GETFD 2 -/* Set the file descriptor flags. */ -#define F_SETFD 3 - -/* Close the file descriptor on a call to execve(). */ -#define FD_CLOEXEC 1 - -#ifdef __cplusplus -extern "C" -{ -#endif - - /* Opens the file specified by pathname. Returns a file descriptor on success, or -1 on error. */ - int open(const char* pathname, int flags, ...); - - /* Opens the file specified by pathname, creating it if it doesn't exist or overwriting it otherwise. Calling this - * function is equivalent to calling open(pathname, O_WRONLY|O_CREAT|O_TRUNC, mode) */ - int creat(const char* pathname, mode_t mode); - - /* Performs an operation on the file descriptor fd determined by cmd. */ - int fcntl(int fd, int cmd, ...); - -#ifdef __cplusplus -} -#endif - -#endif \ No newline at end of file diff --git a/libs/libc/include/inttypes.h b/libs/libc/include/inttypes.h deleted file mode 100644 index ecc873d1..00000000 --- a/libs/libc/include/inttypes.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef _INTTYPES_H -#define _INTTYPES_H - -#include - -#define __PRI64_PREFIX "l" - -#define PRId8 "d" -#define PRId16 "d" -#define PRId32 "d" -#define PRId64 __PRI64_PREFIX "d" -#define PRIdLEAST8 "d" -#define PRIdLEAST16 "d" -#define PRIdLEAST32 "d" -#define PRIdLEAST64 __PRI64_PREFIX "d" -#define PRIdFAST8 "d" -#define PRIdFAST16 "d" -#define PRIdFAST32 "d" -#define PRIdFAST64 __PRI64_PREFIX "d" -#define PRIdMAX __PRI64_PREFIX "d" -#define PRIdPTR __PRI64_PREFIX "d" -#define PRIi8 "d" -#define PRIi16 "d" -#define PRIi32 "d" -#define PRIi64 __PRI64_PREFIX "d" -#define PRIiLEAST8 "d" -#define PRIiLEAST16 "d" -#define PRIiLEAST32 "d" -#define PRIiLEAST64 __PRI64_PREFIX "d" -#define PRIiFAST8 "d" -#define PRIiFAST16 "d" -#define PRIiFAST32 "d" -#define PRIiFAST64 __PRI64_PREFIX "d" -#define PRIiMAX __PRI64_PREFIX "d" -#define PRIiPTR __PRI64_PREFIX "d" -#define PRIu8 "u" -#define PRIu16 "u" -#define PRIu32 "u" -#define PRIu64 __PRI64_PREFIX "u" -#define PRIuLEAST8 "u" -#define PRIuLEAST16 "u" -#define PRIuLEAST32 "u" -#define PRIuLEAST64 __PRI64_PREFIX "u" -#define PRIuFAST8 "u" -#define PRIuFAST16 "u" -#define PRIuFAST32 "u" -#define PRIuFAST64 __PRI64_PREFIX "u" -#define PRIuMAX __PRI64_PREFIX "u" -#define PRIuPTR __PRI64_PREFIX "u" -#define PRIx8 "x" -#define PRIx16 "x" -#define PRIx32 "x" -#define PRIx64 __PRI64_PREFIX "x" -#define PRIxLEAST8 "x" -#define PRIxLEAST16 "x" -#define PRIxLEAST32 "x" -#define PRIxLEAST64 __PRI64_PREFIX "x" -#define PRIxFAST8 "x" -#define PRIxFAST16 "x" -#define PRIxFAST32 "x" -#define PRIxFAST64 __PRI64_PREFIX "x" -#define PRIxMAX __PRI64_PREFIX "x" -#define PRIxPTR __PRI64_PREFIX "x" -#define PRIX8 PRIx8 -#define PRIX16 PRIx16 -#define PRIX32 PRIx32 -#define PRIX64 PRIx64 -#define PRIXMAX PRIxMAX -#define PRIXPTR PRIxPTR - -#endif \ No newline at end of file diff --git a/libs/libc/include/libgen.h b/libs/libc/include/libgen.h deleted file mode 100644 index a6479447..00000000 --- a/libs/libc/include/libgen.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef _LIBGEN_H -#define _LIBGEN_H - -#ifdef __cplusplus -extern "C" -{ -#endif - - /* Returns the last component of a path. This function is allowed to modify the string passed to it, so it should - * probably be a copy of another string. */ - char* basename(char* path); - - /* Returns the parent directory of a path. This function is allowed to modify the string passed to it, so it should - * probably be a copy of another string. */ - char* dirname(char* path); - -#ifdef __cplusplus -} -#endif - -#endif \ No newline at end of file diff --git a/libs/libc/include/locale.h b/libs/libc/include/locale.h deleted file mode 100644 index c2182e6a..00000000 --- a/libs/libc/include/locale.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef _LOCALE_H -#define _LOCALE_H - -#define LC_ALL 0 -#define LC_CTYPE 1 -#define LC_COLLATE 2 -#define LC_NUMERIC 3 -#define LC_MONETARY 4 -#define LC_TIME 5 - -/* Structure representing numeric formatting information for the current locale. */ -struct lconv -{ - char* decimal_point; - char* thousands_sep; - char* grouping; - char* int_curr_symbol; - char* currency_symbol; - char* mon_decimal_point; - char* mon_thousands_sep; - char* mon_grouping; - char* positive_sign; - char* negative_sign; - char int_frac_digits; - char frac_digits; - char p_cs_precedes; - char p_sep_by_space; - char n_cs_precedes; - char n_sep_by_space; - char p_sign_posn; - char n_sign_posn; -}; - -#ifdef __cplusplus -extern "C" -{ -#endif - - /* Set or query the current locale. */ - char* setlocale(int category, const char* locale); - - /* Retrieve numeric formatting information for the current locale. */ - struct lconv* localeconv(void); - -#ifdef __cplusplus -} -#endif - -#endif \ No newline at end of file diff --git a/libs/libc/include/luna.h b/libs/libc/include/luna.h deleted file mode 100644 index 7ed32c00..00000000 --- a/libs/libc/include/luna.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef _LUNA_H -#define _LUNA_H - -#include -#include -#include - -#ifdef __cplusplus -extern "C" -{ -#endif - - /* Returns a numeric identifier associated with the current process, depending on field. */ - long getprocid(int field); - - /* Sleeps for ms milliseconds. */ - unsigned int msleep(unsigned int ms); - - /* Prints a message to standard error and aborts the program. */ - __lc_noreturn void __luna_abort(const char* message); - -#ifdef __cplusplus -} -#endif - -#define NOT_IMPLEMENTED(message) __luna_abort("not implemented: " message "\n") - -#endif \ No newline at end of file diff --git a/libs/libc/include/luna/dirent.h b/libs/libc/include/luna/dirent.h deleted file mode 100644 index 6b7f3237..00000000 --- a/libs/libc/include/luna/dirent.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef _LUNA_DIRENT_H -#define _LUNA_DIRENT_H - -#include -#include - -struct luna_dirent -{ - ino_t inode; - char name[NAME_MAX]; - size_t total; - off_t offset; -}; - -#ifdef __cplusplus -extern "C" -{ -#endif - - /* Retrieve directory entries from the kernel. This is the raw interface, use readdir() instead. */ - ssize_t getdents(int fd, struct luna_dirent* buf, size_t count); - -#ifdef __cplusplus -} -#endif - -#endif \ No newline at end of file diff --git a/libs/libc/include/luna/os-limits.h b/libs/libc/include/luna/os-limits.h deleted file mode 100644 index 6e62f706..00000000 --- a/libs/libc/include/luna/os-limits.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _LUNA_OS_LIMITS_H -#define _LUNA_OS_LIMITS_H - -#define OPEN_MAX 32 -#define ATEXIT_MAX 32 - -#define NAME_MAX 64 -#define PATH_MAX 4096 - -#define PAGESIZE 4096 -#define PAGE_SIZE 4096 - -#endif \ No newline at end of file diff --git a/libs/libc/include/luna/pstat.h b/libs/libc/include/luna/pstat.h deleted file mode 100644 index fe6e4295..00000000 --- a/libs/libc/include/luna/pstat.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef _LUNA_PSTAT_H -#define _LUNA_PSTAT_H - -#include - -struct pstat -{ - pid_t pt_pid; - pid_t pt_ppid; - char pt_name[128]; - int pt_state; - long pt_time; - uid_t pt_uid; - gid_t pt_gid; -}; - -#define PT_IDLE 0 -#define PT_RUNNING 1 -#define PT_SLEEPING 2 -#define PT_ZOMBIE 3 -#define PT_WAITING 4 - -#ifdef __cplusplus -extern "C" -{ -#endif - - /* Returns information about the process with PID pid in buf, if buf is non-null. Luna-specific. */ - pid_t pstat(pid_t pid, struct pstat* buf); - - /* Returns a string representation of the process state in buf. */ - const char* pstatname(struct pstat* buf); - -#ifdef __cplusplus -} -#endif - -#endif \ No newline at end of file diff --git a/libs/libc/include/luna/syscall.h b/libs/libc/include/luna/syscall.h deleted file mode 100644 index 850d1007..00000000 --- a/libs/libc/include/luna/syscall.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef _LUNA_SYSCALL_H -#define _LUNA_SYSCALL_H - -#include - -typedef unsigned long sysarg_t; - -#ifdef __cplusplus -extern "C" -{ -#endif - - long __luna_syscall0(long sys_num); - long __luna_syscall1(long sys_num, sysarg_t arg0); - long __luna_syscall2(long sys_num, sysarg_t arg0, sysarg_t arg1); - long __luna_syscall3(long sys_num, sysarg_t arg0, sysarg_t arg1, sysarg_t arg2); - long __luna_syscall4(long sys_num, sysarg_t arg0, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3); - long __luna_syscall5(long sys_num, sysarg_t arg0, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4); - - inline long __fast_syscall0(long number) - { - long result = __luna_syscall0(number); - _RETURN_WITH_ERRNO(result, long); - } - - inline long __fast_syscall1(long number, sysarg_t arg0) - { - long result = __luna_syscall1(number, arg0); - _RETURN_WITH_ERRNO(result, long); - } - - inline long __fast_syscall2(long number, sysarg_t arg0, sysarg_t arg1) - { - long result = __luna_syscall2(number, arg0, arg1); - _RETURN_WITH_ERRNO(result, long); - } - - inline long __fast_syscall3(long number, sysarg_t arg0, sysarg_t arg1, sysarg_t arg2) - { - long result = __luna_syscall3(number, arg0, arg1, arg2); - _RETURN_WITH_ERRNO(result, long); - } - - inline long __fast_syscall4(long number, sysarg_t arg0, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3) - { - long result = __luna_syscall4(number, arg0, arg1, arg2, arg3); - _RETURN_WITH_ERRNO(result, long); - } - - inline long __fast_syscall5(long number, sysarg_t arg0, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4) - { - long result = __luna_syscall5(number, arg0, arg1, arg2, arg3, arg4); - _RETURN_WITH_ERRNO(result, long); - } - -#define __lc_fast_syscall0(number) __fast_syscall0(number) -#define __lc_fast_syscall1(number, arg0) __fast_syscall1(number, (sysarg_t)arg0) -#define __lc_fast_syscall2(number, arg0, arg1) __fast_syscall2(number, (sysarg_t)arg0, (sysarg_t)arg1) -#define __lc_fast_syscall3(number, arg0, arg1, arg2) \ - __fast_syscall3(number, (sysarg_t)arg0, (sysarg_t)arg1, (sysarg_t)arg2) -#define __lc_fast_syscall4(number, arg0, arg1, arg2, arg3) \ - __fast_syscall4(number, (sysarg_t)arg0, (sysarg_t)arg1, (sysarg_t)arg2, (sysarg_t)arg3) -#define __lc_fast_syscall5(number, arg0, arg1, arg2, arg3, arg4) \ - __fast_syscall5(number, (sysarg_t)arg0, (sysarg_t)arg1, (sysarg_t)arg2, (sysarg_t)arg3, (sysarg_t)arg4) - -#ifdef __cplusplus -} -#endif - -#endif \ No newline at end of file diff --git a/libs/libc/include/luna/vfs.h b/libs/libc/include/luna/vfs.h deleted file mode 100644 index e34c83eb..00000000 --- a/libs/libc/include/luna/vfs.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _LUNA_VFS_H -#define _LUNA_VFS_H - -#define __VFS_FILE 0x0 -#define __VFS_DIRECTORY 0x1 -#define __VFS_DEVICE 0x2 - -#define __VFS_TO_IFMT(type) ((1 << type) * 010000) - -#endif \ No newline at end of file diff --git a/libs/libc/include/math.h b/libs/libc/include/math.h deleted file mode 100644 index ced52044..00000000 --- a/libs/libc/include/math.h +++ /dev/null @@ -1,90 +0,0 @@ -#ifndef _MATH_H -#define _MATH_H - -typedef float float_t; -typedef double double_t; - -#define FP_NAN 0 -#define FP_INFINITE 1 -#define FP_ZERO 2 -#define FP_SUBNORMAL 3 -#define FP_NORMAL 4 -#define fpclassify(x) __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_ZERO, FP_SUBNORMAL, FP_ZERO, x) - -#ifdef __cplusplus -extern "C" -{ -#endif - - double cos(double val); - float cosf(float val); - long double cosl(long double val); - double sin(double val); - float sinf(float val); - long double sinl(long double val); - double tan(double val); - float tanf(float val); - long double tanl(long double val); - double acos(double val); - float acosf(float val); - long double acosl(long double val); - double asin(double val); - float asinf(float val); - long double asinl(long double val); - double atan(double val); - float atanf(float val); - long double atanl(long double val); - double cosh(double val); - float coshf(float val); - long double coshl(long double val); - double sinh(double val); - float sinhf(float val); - long double sinhl(long double val); - double tanh(double val); - float tanhf(float val); - long double tanhl(long double val); - double log(double val); - float logf(float val); - long double logl(long double val); - double exp(double val); - float expf(float val); - long double expl(long double val); - double sqrt(double val); - float sqrtf(float val); - long double sqrtl(long double val); - double fabs(double val); - float fabsf(float val); - long double fabsl(long double val); - double floor(double val); - float floorf(float val); - long double floorl(long double val); - double ceil(double val); - float ceilf(float val); - long double ceill(long double val); - double log10(double val); - float log10f(float val); - long double log10l(long double val); - double fmod(double val1, double val2); - float fmodf(float val1, float val2); - long double fmodl(long double val1, long double val2); - double pow(double val1, double val2); - float powf(float val1, float val2); - long double powl(long double val1, long double val2); - double atan2(double val1, double val2); - float atan2f(float val1, float val2); - long double atan2l(long double val1, long double val2); - double frexp(double val1, int* val2); - float frexpf(float val1, int* val2); - long double frexpl(long double val1, int* val2); - double ldexp(double val1, int val2); - float ldexpf(float val1, int val2); - long double ldexpl(long double val1, int val2); - double modf(double val1, double* val2); - float modff(float val1, float* val2); - long double modfl(long double val1, long double* val2); - -#ifdef __cplusplus -} -#endif - -#endif \ No newline at end of file diff --git a/libs/libc/include/memory.h b/libs/libc/include/memory.h deleted file mode 100644 index e69de29b..00000000 diff --git a/libs/libc/include/pwd.h b/libs/libc/include/pwd.h deleted file mode 100644 index 517a5f38..00000000 --- a/libs/libc/include/pwd.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef _PWD_H -#define _PWD_H - -#include - -/* Structure representing a password file entry. */ -struct passwd -{ - char* pw_name; - char* pw_passwd; - uid_t pw_uid; - gid_t pw_gid; - char* pw_gecos; - char* pw_dir; - char* pw_shell; -}; - -#ifdef __cplusplus -extern "C" -{ -#endif - - /* Returns the next password file entry. */ - struct passwd* getpwent(void); - - /* Returns the first password file entry with a login name matching name, or NULL if there are none. */ - struct passwd* getpwnam(const char* name); - - /* Returns the first password file entry with a user ID matching uid, or NULL if there are none. */ - struct passwd* getpwuid(uid_t uid); - - /* Rewinds to the first password file entry. */ - void setpwent(void); - - /* Ends password file processing. */ - void endpwent(void); - -#ifdef __cplusplus -} -#endif - -#endif \ No newline at end of file diff --git a/libs/libc/include/sched.h b/libs/libc/include/sched.h deleted file mode 100644 index baebea5a..00000000 --- a/libs/libc/include/sched.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef _SCHED_H -#define _SCHED_H - -#ifdef __cplusplus -extern "C" -{ -#endif - - /* Yield the processor. */ - int sched_yield(void); - -#ifdef __cplusplus -} -#endif - -#endif \ No newline at end of file diff --git a/libs/libc/include/setjmp.h b/libs/libc/include/setjmp.h deleted file mode 100644 index d42054aa..00000000 --- a/libs/libc/include/setjmp.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef _SETJMP_H -#define _SETJMP_H - -#include -#include - -typedef uintptr_t jmp_buf[8]; -typedef uintptr_t sigjmp_buf[8]; - -#ifdef __cplusplus -extern "C" -{ -#endif - - /* Saves the current execution state in env. Returns 0 when called from the first time, or nonzero when returning - * from longjmp. */ - int setjmp(jmp_buf env); - - /* Right now, does the exact same as setjmp() (savesigs is ignored), since signals are not implemented. */ - int sigsetjmp(sigjmp_buf env, int savesigs); - - /* Restores the execution state saved in env by a setjmp() call. */ - __lc_noreturn void longjmp(jmp_buf env, int val); - - /* Right now, does the exact same as longjmp(), since signals are not implemented. */ - __lc_noreturn void siglongjmp(sigjmp_buf env, int val); - -#ifdef __cplusplus -} -#endif - -#endif \ No newline at end of file diff --git a/libs/libc/include/signal.h b/libs/libc/include/signal.h deleted file mode 100644 index 691bf0bc..00000000 --- a/libs/libc/include/signal.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef _SIGNAL_H -#define _SIGNAL_H - -typedef int sig_atomic_t; // On the x86, writes to aligned 32-bit and 64-bit integers are always atomic. (Or that's what - // I understood) - -#define SIGINT 1 // Not implemented. - -#ifdef __cplusplus -extern "C" -{ -#endif - - void (*signal(int sig, void (*func)(int)))(int); // Not implemented. - int raise(int sig); // Not implemented. - -#ifdef __cplusplus -} -#endif - -#endif \ No newline at end of file diff --git a/libs/libc/include/stdio.h b/libs/libc/include/stdio.h deleted file mode 100644 index df882d0b..00000000 --- a/libs/libc/include/stdio.h +++ /dev/null @@ -1,176 +0,0 @@ -#ifndef _STDIO_H -#define _STDIO_H - -#include -#include -#include - -#include - -#define FOPEN_MAX 32 // Maximum number of files that can be simultaneously opened with fopen(). -#define BUFSIZ 1024 // Standard buffer size. -#define FILENAME_MAX 1024 // Dummy value, we don't have a limit for filenames right now. - -/* A stream representing a file. */ -typedef struct -{ - int f_fd; - int f_eof; - int f_err; - char* f_buf; - long f_bufsize; - long f_bufoff; - long f_bufrsize; -} FILE; - -extern FILE* stderr; -extern FILE* stdout; -extern FILE* stdin; - -#define stdin stdin // The standard input stream. -#define stdout stdout // The standard output stream. -#define stderr stderr // The standard error stream. - -#define EOF -1 // End of file. - -#define _IONBF 0 // Not buffered. -#define _IOLBF 1 // Line buffered. -#define _IOFBF 2 // Fully buffered. - -typedef off_t fpos_t; // An offset into a file. - -#ifdef __cplusplus -extern "C" -{ -#endif - - /* Closes the file handle stream. */ - int fclose(FILE* stream); - - /* Does not do anything for now, since buffered IO is not implemented yet. */ - int fflush(FILE* stream); - - /* Opens the file specified by pathname. Returns the file handle on success, or NULL on error. */ - FILE* fopen(const char* pathname, const char* mode); - - /* Returns a new file associated with the file descriptor fd. */ - FILE* fdopen(int fd, const char* mode); - - /* Opens the file specified by pathname and points the file handle stream to it. */ - FILE* freopen(const char* pathname, const char* mode, FILE* stream); - - /* Returns the file descriptor associated with the file stream. */ - int fileno(FILE* stream); - - /* Writes formatted output according to the string format to the file stream. */ - int fprintf(FILE* stream, const char* format, ...); - - /* Reads nmemb items of size size from the file stream into buf. */ - size_t fread(void* buf, size_t size, size_t nmemb, FILE* stream); - - /* Moves stream's read/write offset by offset, depending on whence. */ - int fseek(FILE* stream, long offset, int whence); - - /* Moves stream's read/write offset by offset, depending on whence. */ - int fseeko(FILE* stream, off_t offset, int whence); - - /* Moves stream's read/write offset to the offset stored in the pos structure. */ - int fsetpos(FILE* stream, const fpos_t* pos); - - /* Returns the current offset for stream. */ - long ftell(FILE* stream); - - /* Returns the current offset for stream. */ - off_t ftello(FILE* stream); - - /* Stores the current offset for stream in the pos structure. */ - int fgetpos(FILE* stream, fpos_t* pos); - - /* Rewinds stream's offset to start of file. */ - void rewind(FILE* stream); - - /* Writes nmemb items of size size from buf into the file stream. */ - size_t fwrite(const void* buf, size_t size, size_t nmemb, FILE* stream); - - /* Reads a line from stream into buf. */ - char* fgets(char* buf, int size, FILE* stream); - - /* Retrieves a character from stream. */ - int fgetc(FILE* stream); - - /* Retrieves a character from stream. */ - int getc(FILE* stream); - - int ungetc(int, FILE*); // Not implemented. - - /* Retrieves a character from standard input. */ - int getchar(); - - /* Returns nonzero if the error flag in stream was set. */ - int ferror(FILE* stream); - - /* Returns nonzero if the end-of-file flag in stream was set. */ - int feof(FILE* stream); - - /* Clears the error and end-of-file flags from stream. */ - void clearerr(FILE* stream); - - void setbuf(FILE*, char*); // Not implemented. - int setvbuf(FILE*, char*, int, size_t); // Not implemented. - - /* Writes formatted output according to the string format to the file stream. */ - int vfprintf(FILE* stream, const char* format, va_list ap); - - /* Writes formatted output according to the string format to standard output. */ - int printf(const char* format, ...); - - /* Writes formatted output according to the string format to standard output. */ - int vprintf(const char* format, va_list ap); - - /* Writes formatted output according to the string format to the string str. This function is unsafe, use snprintf - * instead. */ - int sprintf(char* str, const char* format, ...); - - /* Writes at most max bytes of formatted output according to the string format to the string str.*/ - int snprintf(char* str, size_t max, const char* format, ...); - - /* Writes formatted output according to the string format to the string str. This function is unsafe, use vsnprintf - * instead. */ - int vsprintf(char* str, const char* format, va_list ap); - - /* Writes at most max bytes of formatted output according to the string format to the string str. */ - int vsnprintf(char* str, size_t max, const char* format, va_list ap); - - int sscanf(const char*, const char*, ...); // Not implemented. - int fscanf(FILE*, const char*, ...); // Not implemented. - int scanf(const char*, ...); // Not implemented. - - /* Writes the string str followed by a trailing newline to stdout. */ - int puts(const char* str); - - /* Writes the string str to the file stream. */ - int fputs(const char* str, FILE* stream); - - /* Writes the character c to the file stream. */ - int fputc(int c, FILE* stream); - - /* Writes the character c to the file stream. */ - int putc(int c, FILE* stream); - - /* Writes the character c to standard output. */ - int putchar(int c); - - /* Prints a message to standard error consisting of the string str followed by a colon and the string representation - * of the last error encountered during a call to a system or library function. */ - void perror(const char* str); - - int remove(const char* pathname); // Not implemented. - int rename(const char* oldpath, const char* newpath); // Not implemented. - - FILE* tmpfile(void); // Not implemented. - -#ifdef __cplusplus -} -#endif - -#endif \ No newline at end of file diff --git a/libs/libc/include/stdlib.h b/libs/libc/include/stdlib.h deleted file mode 100644 index a665c356..00000000 --- a/libs/libc/include/stdlib.h +++ /dev/null @@ -1,140 +0,0 @@ -#ifndef _STDLIB_H -#define _STDLIB_H - -#include -#include -#include - -#define EXIT_SUCCESS 0 // Value to use when calling exit() to represent successful execution. -#define EXIT_FAILURE 1 // Value to use when calling exit() to represent failed execution. - -#define RAND_MAX INT_MAX // Maximum number returned by rand(). - -#define MB_CUR_MAX 1 // Maximum length of multibyte characters in the current locale. - -// Return type for an integer division. -typedef struct -{ - int quot; - int rem; -} div_t; - -// Return type for a long integer division. -typedef struct -{ - long quot; - long rem; -} ldiv_t; - -// Return type for a long integer division. -typedef struct -{ - long long quot; - long long rem; -} lldiv_t; - -#ifdef __cplusplus -extern "C" -{ -#endif - - /* Aborts the program. */ - __lc_noreturn void abort(void); - - /* Normally exits the program with the specified status code. */ - __lc_noreturn void exit(int status); - - /* Abnormally exits the program with the specified status code. */ - __lc_noreturn void _Exit(int status); - - /* Registers a handler function to be run at normal program termination. */ - int atexit(void (*handler)(void)); - - /* Returns a floating point number parsed from the string str. */ - float atof(const char* str); - - /* Returns an integer (of type int) parsed from the string str. */ - int atoi(const char* str); - - /* Returns an integer (of type long) parsed from the string str. */ - long atol(const char* str); - - /* Returns an integer (of type long long) parsed from the string str. */ - long long atoll(const char* str); - - /* Returns an integer (of type unsigned long) parsed from the string str. */ - unsigned long strtoul(const char* str, char** endptr, int base); - - double strtod(const char* str, char** endptr); // Not implemented. - - /* Returns an integer (of type long) parsed from the string str. */ - long strtol(const char* str, char** endptr, int base); - - /* Not implemented. */ - char* getenv(const char*); - - /* Allocates n bytes of memory and returns a pointer to it. This memory should be freed by calling free() when it is - * not in use anymore. */ - void* malloc(size_t n); - - /* Allocates enough bytes of memory for an array containing nmemb items of size n and returns a pointer to it. This - * memory should be freed by calling free() when it is not in use anymore. */ - void* calloc(size_t nmemb, size_t n); - - /* Resizes memory allocated by malloc() or calloc() to n bytes. Returns a pointer to the new resized region of - * memory, which should be used instead of the old one. This memory should be freed by calling free() when it is not - * in use anymore. */ - void* realloc(void* ptr, size_t n); - - /* Frees a pointer to memory allocated by malloc(), calloc() or realloc(). Accessing the contents of ptr afterwards - * is undefined behavior. */ - void free(void* ptr); - - /* Returns a random number. */ - int rand(void); - - /* Seeds the random number generator with the specified seed. */ - void srand(unsigned int seed); - - /* Returns the absolute value of an integer. */ - int abs(int val); - - /* Returns the absolute value of an integer. */ - long labs(long val); - - /* Returns the absolute value of an integer. */ - long long llabs(long long val); - - /* Returns the result of dividing a by b. */ - div_t div(int a, int b); - - /* Returns the result of dividing a by b. */ - ldiv_t ldiv(long a, long b); - - /* Returns the result of dividing a by b. */ - lldiv_t lldiv(long long a, long long b); - - /* Runs a shell command. */ - int system(const char* command); - - /* Sorts the array pointed to by base of nmemb items of the specified size using the comparison function compar. */ - void qsort(void* base, size_t nmemb, size_t size, int (*compar)(const void*, const void*)); - - /* Searches the sorted array base of nmemb items of the specified size for the given key using the comparison - * function compar. */ - void* bsearch(const void* key, const void* base, size_t nmemb, size_t size, - int (*compar)(const void*, const void*)); - - size_t mbstowcs(wchar_t* dest, const char* src, - size_t n); // Not implemented. - - /* Generate a unique filename from the template string str. The last 6 bytes of str must be 'XXXXXX', and they will - * be replaced with random characters. This function is deprecated due to race conditions; between the name being - * generated and creating a file with that name, that filename could have already been used. */ - __lc_is_deprecated char* mktemp(char* str); - -#ifdef __cplusplus -} -#endif - -#endif \ No newline at end of file diff --git a/libs/libc/include/string.h b/libs/libc/include/string.h deleted file mode 100644 index cdfb4dee..00000000 --- a/libs/libc/include/string.h +++ /dev/null @@ -1,105 +0,0 @@ -#ifndef _STRING_H -#define _STRING_H - -#include -#include - -#ifdef __cplusplus -extern "C" -{ -#endif - - /* Copies n bytes from src to dst. */ - void* memcpy(void* dest, const void* src, size_t n); - - /* Sets n bytes of buf to c, cast to a character. */ - void* memset(void* buf, int c, size_t n); - - /* Searches for the character c in n bytes of buf. */ - void* memchr(const void* buf, int c, size_t n); - - /* Compares n bytes of memory at a and b. */ - int memcmp(const void* a, const void* b, size_t n); - - /* Copies n bytes from src to dst. Can be used if src and dst overlap. */ - void* memmove(void* dest, const void* src, size_t n); - - /* Returns a heap-allocated copy of the string str. Should be freed when it is not used anymore. */ - char* strdup(const char* str); - - /* Returns a heap-allocated copy of the string str, copying at maximum max bytes. Should be freed when it is not - * used anymore. */ - char* strndup(const char* str, size_t max); - - /* Returns the length of the string str. */ - size_t strlen(const char* str); - - /* Returns the length of the string str, while examining at most max bytes of str. */ - size_t strnlen(const char* str, size_t max); - - /* Copies at most size-1 bytes from the string src into dest, null-terminating the result. */ - size_t strlcpy(char* dst, const char* src, size_t size); - - /* Copies at most max bytes from the string src into dest. */ - char* strncpy(char* dest, const char* src, size_t max); - - /* Returns a pointer to the first occurrence of the character c in str, or NULL if it is not found. */ - char* strchr(const char* str, int c); - - /* Returns a pointer to the last occurrence of the character c in str, or NULL if it is not found. */ - char* strrchr(const char* str, int c); - - /* Returns a pointer to the first occurrence of the character c in str, or a pointer to the terminating null byte of - * str if it is not found. */ - char* strchrnul(const char* str, int c); - - /* Concatenates at most max bytes of the string src into dest. */ - char* strncat(char* dest, const char* src, size_t max); - - /* Returns the length of the initial segment of str which consists entirely of bytes not in reject. */ - size_t strcspn(const char* str, const char* reject); - - /* Returns the length of the initial segment of str which consists entirely of bytes in accept. */ - size_t strspn(const char* str, const char* accept); - - /* Returns a pointer to the first occurrence of any character of b in a. */ - char* strpbrk(const char* a, const char* b); - - /* Compares strings a and b. You might prefer to use the safer strncmp function. */ - int strcmp(const char* a, const char* b); - - /* Compares at most max bytes of the strings a and b. */ - int strncmp(const char* a, const char* b, size_t max); - - /* Compares a and b based on the current locale. */ - int strcoll(const char* a, const char* b); - - /* Transforms src based on the current locale and stores n bytes of it in dest. */ - size_t strxfrm(char* dest, const char* src, size_t n); - - /* Searches for the needle string in the haystack string. */ - char* strstr(const char* haystack, const char* needle); - - /* Returns the error string associated with the error number err. */ - char* strerror(int err); - - /* Copies the string src into dest. This function is unsafe, use strlcpy instead. */ - __lc_deprecated("strcpy is unsafe and should not be used; use strlcpy instead") char* strcpy(char* dest, - const char* src); - - /* Concatenates the string src into dest. This function is unsafe, use strncat instead. */ - __lc_deprecated("strcat is unsafe and should not be used; use strncat instead") char* strcat(char* dest, - const char* src); - -#ifdef _GNU_SOURCE - /* Copies the string src into dest, returning a pointer to the end of dest. */ - __lc_is_deprecated char* stpcpy(char* dest, const char* src); -#endif - - char* strtok(char* str, const char* delim); // Not implemented. - -#ifdef __cplusplus -} -#endif - -#endif \ No newline at end of file diff --git a/libs/libc/include/strings.h b/libs/libc/include/strings.h deleted file mode 100644 index dd0952ad..00000000 --- a/libs/libc/include/strings.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef _STRINGS_H -#define _STRINGS_H - -#include - -#ifdef __cplusplus -extern "C" -{ -#endif - - /* Clears n bytes of buf. */ - void bzero(void* buf, size_t n); - - /* Copies n bytes of src into dest. */ - void bcopy(void* dest, const void* src, size_t n); - - /* Compares strings a and b while treating uppercase and lowercase characters as the same. */ - int strcasecmp(const char* a, const char* b); - - /* Compares at most max bytes of strings a and b while treating uppercase and lowercase characters as the same. */ - int strncasecmp(const char* a, const char* b, size_t max); - -#ifdef __cplusplus -} -#endif - -#endif \ No newline at end of file diff --git a/libs/libc/include/sys/ioctl.h b/libs/libc/include/sys/ioctl.h deleted file mode 100644 index 2de4dac5..00000000 --- a/libs/libc/include/sys/ioctl.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef _SYS_IOCTL_H -#define _SYS_IOCTL_H - -#include - -/* Get the width of a framebuffer device. */ -#define FB_GET_WIDTH 0 -/* Get the height of a framebuffer device. */ -#define FB_GET_HEIGHT 1 -/* Get the scanline of a framebuffer device. */ -#define FB_GET_SCANLINE 2 - -#ifdef __cplusplus -extern "C" -{ -#endif - - /* Perform an arbitrary operation on an open file descriptor. Many operations are device-specific. */ - int ioctl(int fd, int cmd, ...); - -#ifdef __cplusplus -} -#endif - -#endif \ No newline at end of file diff --git a/libs/libc/include/sys/mman.h b/libs/libc/include/sys/mman.h deleted file mode 100644 index e2b86308..00000000 --- a/libs/libc/include/sys/mman.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef _SYS_MMAN_H -#define _SYS_MMAN_H - -#include -#include // for off_t - -/* Address returned by mmap when it fails. */ -#define MAP_FAILED (void*)-1 - -#define PROT_NONE 0 -#define PROT_READ 1 -#define PROT_WRITE 2 -#define PROT_EXEC 4 - -#define PAGE_SIZE 4096 - -#define MAP_PRIVATE 0 -#define MAP_SHARED 1 -#define MAP_ANONYMOUS 2 - -#ifdef __cplusplus -extern "C" -{ -#endif - - /* Maps size bytes of memory (rounded up to the nearest page-aligned size) into the current process's address - * space at addr. If addr is null, the kernel will choose an address. */ - void* mmap(void* addr, size_t size, int prot, int flags, int fd, off_t offset); - - /* Unmaps size bytes of memory (rounded up to the nearest page-aligned size) at addr from the current process's - * address space. */ - int munmap(void* addr, size_t size); - - /* Changes the permissions of size bytes of memory at addr zaccording to the prot argument. */ - int mprotect(void* addr, size_t size, int prot); - -#ifdef __cplusplus -} -#endif - -#endif \ No newline at end of file diff --git a/libs/libc/include/sys/param.h b/libs/libc/include/sys/param.h deleted file mode 100644 index e69de29b..00000000 diff --git a/libs/libc/include/sys/stat.h b/libs/libc/include/sys/stat.h deleted file mode 100644 index 7c54a3e0..00000000 --- a/libs/libc/include/sys/stat.h +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef _SYS_STAT_H -#define _SYS_STAT_H - -#include -#include - -struct stat // FIXME: This struct is quite stubbed out. -{ - ino_t st_ino; - mode_t st_mode; - off_t st_size; - int st_dev; // Not implemented. - int st_nlink; // Not implemented. - uid_t st_uid; - gid_t st_gid; - time_t st_atime; - time_t st_mtime; - time_t st_ctime; -}; - -/* Type of file. */ -#define S_IFMT 070000 -/* Directory. */ -#define S_IFDIR __VFS_TO_IFMT(__VFS_DIRECTORY) -/* Regular file. */ -#define S_IFREG __VFS_TO_IFMT(__VFS_FILE) -/* Character device. */ -#define S_IFCHR __VFS_TO_IFMT(__VFS_DEVICE) - -#define __S_IFCMP(mode, value) (mode & S_IFMT) == value - -/* Is it a directory? */ -#define S_ISDIR(mode) (__S_IFCMP((mode), S_IFDIR)) -/* Is it a regular file? */ -#define S_ISREG(mode) (__S_IFCMP((mode), S_IFREG)) -/* Is it a character device? */ -#define S_ISCHR(mode) (__S_IFCMP((mode), S_IFCHR)) - -// Not implemented. -#define S_ISBLK(mode) ((mode)&0) -#define S_ISFIFO(mode) ((mode)&0) - -#define S_IRWXU 0700 -#define S_IRUSR 0400 -#define S_IWUSR 0200 -#define S_IXUSR 0100 -#define S_IRWXG 070 -#define S_IRGRP 040 -#define S_IWGRP 020 -#define S_IXGRP 010 -#define S_IRWXO 07 -#define S_IROTH 04 -#define S_IWOTH 02 -#define S_IXOTH 01 -#define S_ISUID 04000 -#define S_ISGID 02000 - -#ifdef __cplusplus -extern "C" -{ -#endif - - /* Creates a new directory at the path pathname with the specified mode. */ - int mkdir(const char* pathname, mode_t mode); - - /* Returns information about the file pointed to by fd in buf. */ - int fstat(int fd, struct stat* buf); - - /* Returns information about the file pointed at path in buf. */ - int stat(const char* pathname, struct stat* buf); - - /* Changes the current process' file creation mask. */ - mode_t umask(mode_t cmask); - - int chmod(const char* pathname, mode_t mode); // Not implemented. - int fchmod(int fd, mode_t mode); // Not implemented. - -#ifdef __cplusplus -} -#endif - -#endif \ No newline at end of file diff --git a/libs/libc/include/sys/syscall.h b/libs/libc/include/sys/syscall.h deleted file mode 100644 index 27842925..00000000 --- a/libs/libc/include/sys/syscall.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef _SYS_SYSCALL_H -#define _SYS_SYSCALL_H - -#define SYS_exit 0 -#define SYS_yield 1 -#define SYS_sleep 2 -#define SYS_write 3 -#define SYS_getprocid 4 -#define SYS_mmap 5 -#define SYS_munmap 6 -#define SYS_open 7 -#define SYS_read 8 -#define SYS_close 9 -#define SYS_seek 10 -#define SYS_execv 11 -#define SYS_fcntl 12 -#define SYS_mprotect 13 -#define SYS_clock_gettime 14 -#define SYS_mkdir 15 -#define SYS_fork 16 -#define SYS_waitpid 17 -#define SYS_access 18 -#define SYS_fstat 19 -#define SYS_pstat 20 -#define SYS_getdents 21 -#define SYS_stat 22 -#define SYS_dup2 23 -#define SYS_setuid 24 -#define SYS_setgid 25 -#define SYS_umask 26 -#define SYS_ioctl 27 -#define SYS_seteuid 28 -#define SYS_setegid 29 - -#endif \ No newline at end of file diff --git a/libs/libc/include/sys/time.h b/libs/libc/include/sys/time.h deleted file mode 100644 index 39f5707f..00000000 --- a/libs/libc/include/sys/time.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef _SYS_TIME_H -#define _SYS_TIME_H - -#include -#include - -// Captures elapsed time with microsecond precision. -struct timeval -{ - time_t tv_sec; - suseconds_t tv_usec; -}; - -#ifdef __cplusplus -extern "C" -{ -#endif - - /* Retrieves the current time and stores it in tp. */ - __lc_is_deprecated int gettimeofday(struct timeval* tp, void* tzp); - -#ifdef __cplusplus -} -#endif - -#endif \ No newline at end of file diff --git a/libs/libc/include/sys/types.h b/libs/libc/include/sys/types.h deleted file mode 100644 index 9e96a25f..00000000 --- a/libs/libc/include/sys/types.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef _SYS_TYPES_H -#define _SYS_TYPES_H - -/* The type of a process identifier. */ -typedef long int pid_t; - -/* The type returned by sizeof(). */ -typedef unsigned long int size_t; - -/* Signed version of size_t. */ -typedef long int ssize_t; - -/* The type of an offset into a file. */ -typedef long int off_t; - -/* The type of a file's mode. */ -typedef unsigned short mode_t; - -/* The type of a filesystem inode. */ -typedef unsigned long ino_t; - -/* Value representing a time unit since the start of the current program. */ -typedef long int clock_t; - -/* Value representing time in seconds. */ -typedef long int time_t; - -/* Type representing signed time in microseconds. */ -typedef long int suseconds_t; - -/* Type representing a user ID. */ -typedef int uid_t; - -/* Type representing a group ID. */ -typedef int gid_t; - -/* Type representing a system clock. */ -typedef int clockid_t; - -#endif \ No newline at end of file diff --git a/libs/libc/include/sys/wait.h b/libs/libc/include/sys/wait.h deleted file mode 100644 index 792ad645..00000000 --- a/libs/libc/include/sys/wait.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef _SYS_WAIT_H -#define _SYS_WAIT_H - -#include - -/* Has the child process exited by calling exit() or _exit()? */ -#define WIFEXITED(status) ((status) || 1) - -/* What was the child's exit status? */ -#define WEXITSTATUS(status) (char)((status)&0xff) - -/* Do not block the current process if no child has exited. */ -#define WNOHANG 1 - -#ifdef __cplusplus -extern "C" -{ -#endif - - /* Waits for the child process to finish running. */ - pid_t waitpid(pid_t pid, int* wstatus, int options); - - /* Waits for any child process to finish running. */ - pid_t wait(int* wstatus); - -#ifdef __cplusplus -} -#endif - -#endif \ No newline at end of file diff --git a/libs/libc/include/time.h b/libs/libc/include/time.h deleted file mode 100644 index 1e66f35a..00000000 --- a/libs/libc/include/time.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef _TIME_H -#define _TIME_H - -#include -#include -#include - -// Structure representing broken-down time. -struct tm -{ - int tm_sec; - int tm_min; - int tm_hour; - int tm_mday; - int tm_mon; - int tm_year; - int tm_wday; - int tm_yday; - int tm_isdst; -}; - -// Captures elapsed time with nanosecond precision. -struct timespec -{ - time_t tv_sec; - long tv_nsec; -}; - -#define CLOCKS_PER_SEC 10000000 // Number of clock_t per second. - -#define CLOCK_REALTIME 0 -#define CLOCK_MONOTONIC 1 -#define CLOCK_PROCTIME 2 - -#ifdef __cplusplus -extern "C" -{ -#endif - - /* Returns a number representing how much CPU time has been used by this process. Divide this by CLOCKS_PER_SEC to - * get the value in seconds. */ - clock_t clock(void); - - /* Returns the current UNIX time in seconds, which is also stored in tloc if it is nonnull. */ - time_t time(time_t* tloc); - - /* Retrieves precise time from a specific system clock. */ - int clock_gettime(clockid_t clock_id, struct timespec* tp); - - /* Converts the UNIX timestamp time to broken-down time in UTC. */ - struct tm* gmtime(const time_t* time); - - /* Converts the UNIX timestamp time to broken-down time in UTC. Thread-safe. */ - struct tm* gmtime_r(const time_t* time, struct tm* result); - - /* Converts the UNIX timestamp time to broken-down time in local time. */ - struct tm* localtime(const time_t* time); - - /* Converts the UNIX timestamp time to broken-down time in local time. Thread-safe. */ - struct tm* localtime_r(const time_t* time, struct tm* result); - - /* Returns a string representation of the broken-down time in the time structure. */ - char* asctime(const struct tm* time); - - /* Fills buf with the string representation of the broken-down time in the time structure. Thread-safe. */ - char* asctime_r(const struct tm* time, char buf[26]); - - /* Returns a string representation of time. */ - char* ctime(const time_t* time); - - /* Fills buf with a string representation of time. Thread-safe. */ - char* ctime_r(const time_t* time, char buf[26]); - - /* Returns the UNIX timestamp representation of the broken-down time in the time structure. */ - time_t mktime(struct tm* time); - - /* Fills str with a formatted string representation of time according to the format string. */ - size_t strftime(char* str, size_t max, const char* format, const struct tm* time); - - /* Returns the difference between two times. */ - double difftime(time_t time2, time_t time1); - -#ifdef __cplusplus -} -#endif - -#endif \ No newline at end of file diff --git a/libs/libc/include/unistd.h b/libs/libc/include/unistd.h deleted file mode 100644 index aaa87201..00000000 --- a/libs/libc/include/unistd.h +++ /dev/null @@ -1,121 +0,0 @@ -#ifndef _UNISTD_H -#define _UNISTD_H - -#include -#include -#include -#include - -// Standard IO streams. -#define STDIN_FILENO 0 // The standard input stream. -#define STDOUT_FILENO 1 // The standard output stream. -#define STDERR_FILENO 2 // The standard error stream. - -// Possible arguments to access() -#define F_OK 0 // Check for a file's existence. -#define R_OK 1 // Check whether a file is readable. -#define W_OK 2 // Check whether a file is writable. -#define X_OK 4 // Check whether a file is executable. - -// Name values for pathconf() -#define _PC_PATH_MAX 0 // Maximum length of a path relative to the provided name. - -#ifdef __cplusplus -extern "C" -{ -#endif - - /* Executes the program program, passing the arguments in the argument list argv. On success, does not return. */ - int execv(const char* program, char* const argv[]); - - /* Not implemented. */ - int execve(const char*, char* const[], char* const[]); - /* Not implemented. */ - int execvp(const char*, char* const[]); - - /* Creates an identical copy (child) of the current process (parent). Returns 0 to the child, and the child's PID to - * the parent. */ - pid_t fork(void); - - /* Returns the current process' process ID. */ - pid_t getpid(void); - - /* Returns the current process' parent's process ID. */ - pid_t getppid(void); - - /* Returns the current process' real user ID. */ - uid_t getuid(void); - - /* Returns the current process' effective user ID. */ - uid_t geteuid(void); - - /* Returns the current process' real group ID. */ - gid_t getgid(void); - - /* Returns the current process' effective group ID. */ - gid_t getegid(void); - - /* Sets the current process' real and effective user IDs. */ - int setuid(uid_t uid); - - /* Sets the current process' effective user ID. */ - int seteuid(uid_t euid); - - /* Sets the current process' real and effective group IDs. */ - int setgid(gid_t gid); - - /* Sets the current process' effective group ID. */ - int setegid(gid_t egid); - - /* Terminates the program with the status code status. */ - __lc_noreturn void _exit(int status); - - /* Calls the kernel for a specific service, determined by number. */ - long syscall(long number, ...); - - /* Suspends execution for a chosen amount of seconds. */ - unsigned int sleep(unsigned int seconds); - - /* Reads count bytes from the file descriptor fd into the memory at buf. */ - ssize_t read(int fd, void* buf, size_t count); - - /* Writes count bytes of the memory at buf to the file descriptor fd. */ - ssize_t write(int fd, const void* buf, size_t count); - - /* Closes the file descriptor fd. */ - int close(int fd); - - /* Moves the read/write file offset for fd to offset, depending on whence. */ - off_t lseek(int fd, off_t offset, int whence); - - /* Returns a copy of the file descriptor fd. */ - int dup(int fd); - - /* Causes the file descriptor fd2 to refer to the file descriptor fd. */ - int dup2(int fd, int fd2); - - /* Checks if the current program can access the file or directory at path. */ - int access(const char* path, int amode); - - /* Checks if the file descriptor fd refers to a terminal. */ - int isatty(int fd); - - /* Writes the current process's current working directory to buf. */ - char* getcwd(char* buf, size_t size); - - int unlink(const char* path); // Not implemented. - int rmdir(const char* path); // Not implemented. - int chdir(const char* path); // Not implemented. - int pipe(int fd[2]); // Not implemented. - - /* Returns a configuration value for the file at path. */ - long pathconf(const char* path, int name); - - /* Returns the maximum number of file descriptors a process can have open at the same time. */ - int getdtablesize(void); - -#ifdef __cplusplus -} -#endif - -#endif \ No newline at end of file diff --git a/libs/libc/include/utime.h b/libs/libc/include/utime.h deleted file mode 100644 index 6111ecdb..00000000 --- a/libs/libc/include/utime.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _UTIME_H -#define _UTIME_H - -#include - -struct utimbuf -{ - time_t actime; - time_t modtime; -}; - -#ifdef __cplusplus -extern "C" -{ -#endif - - int utime(const char*, const struct utimbuf*); // Not implemented. - -#ifdef __cplusplus -} -#endif - -#endif \ No newline at end of file diff --git a/libs/libc/include/wchar.h b/libs/libc/include/wchar.h deleted file mode 100644 index a206751e..00000000 --- a/libs/libc/include/wchar.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef _WCHAR_H -#define _WCHAR_H - -#include -#include - -typedef unsigned int wint_t; - -#ifdef __cplusplus -extern "C" -{ -#endif - - /* Return the length of a wide-character string. */ - size_t wcslen(const wchar_t* str); - - /* Concatenates the wide-character string src into dest. */ - __lc_is_deprecated wchar_t* wcscat(wchar_t* dest, const wchar_t* src); - -#ifdef __cplusplus -} -#endif - -#endif \ No newline at end of file diff --git a/libs/libc/src/assert.cpp b/libs/libc/src/assert.cpp deleted file mode 100644 index c0c64a1c..00000000 --- a/libs/libc/src/assert.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include -#include -#include - -extern "C" -{ - __lc_noreturn bool __assertion_failed(const char* file, int line, const char* function, const char* expr) - { - fprintf(stderr, "%s:%d: %s: Assertion '%s' failed.", file, line, function, expr); - abort(); - } -} \ No newline at end of file diff --git a/libs/libc/src/atexit.cpp b/libs/libc/src/atexit.cpp deleted file mode 100644 index a27b81f2..00000000 --- a/libs/libc/src/atexit.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include - -#define ATEXIT_MAX_FUNCS 32 - -typedef void (*atexit_func_t)(void); - -atexit_func_t atexit_functions[ATEXIT_MAX_FUNCS]; -int atexit_function_count = 0; - -extern "C" -{ - int atexit(atexit_func_t handler) - { - if (atexit_function_count >= ATEXIT_MAX_FUNCS) return -1; - atexit_functions[atexit_function_count++] = handler; - return 0; - } - - __lc_noreturn void exit(int status) - { - for (int i = 0; i < atexit_function_count; i++) { atexit_functions[i](); } - _exit(status); - } -} \ No newline at end of file diff --git a/libs/libc/src/bits/bindings.c b/libs/libc/src/bits/bindings.c deleted file mode 100644 index 40bdca95..00000000 --- a/libs/libc/src/bits/bindings.c +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include - -int liballoc_lock() -{ - return 0; -} - -int liballoc_unlock() -{ - return 0; -} - -void* liballoc_alloc(size_t size) -{ - void* result = mmap(NULL, size * PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS, 0, 0); - if (result == MAP_FAILED) return 0; - return (void*)result; -} - -int liballoc_free(void* address, size_t size) -{ - return munmap(address, size * PAGE_SIZE); -} \ No newline at end of file diff --git a/libs/libc/src/bits/liballoc.c b/libs/libc/src/bits/liballoc.c deleted file mode 100644 index e5bdabef..00000000 --- a/libs/libc/src/bits/liballoc.c +++ /dev/null @@ -1,748 +0,0 @@ -#include - -#pragma GCC push_options -#pragma GCC diagnostic ignored "-Wconversion" -#pragma GCC diagnostic ignored "-Wsign-conversion" // FIXME: Actually solve these warnings. - -#include -#include - -/** Durand's Amazing Super Duper Memory functions. */ - -#define VERSION "1.1" -#define ALIGNMENT \ - 16ul // 4ul ///< This is the byte alignment that memory must be allocated on. IMPORTANT for GTK and - // other stuff. - -#define ALIGN_TYPE char /// unsigned char[16] /// unsigned short -#define ALIGN_INFO \ - sizeof(ALIGN_TYPE) * 16 ///< Alignment information is stored right before the pointer. This is the number of bytes - ///< of information stored there. - -#define USE_CASE1 -#define USE_CASE2 -#define USE_CASE3 -#define USE_CASE4 -#define USE_CASE5 - -/** This macro will conveniently align our pointer upwards */ -#define ALIGN(ptr) \ - if (ALIGNMENT > 1) \ - { \ - uintptr_t align_diff; \ - ptr = (void*)((uintptr_t)ptr + ALIGN_INFO); \ - align_diff = (uintptr_t)ptr & (ALIGNMENT - 1); \ - if (align_diff != 0) \ - { \ - align_diff = ALIGNMENT - align_diff; \ - ptr = (void*)((uintptr_t)ptr + align_diff); \ - } \ - *((ALIGN_TYPE*)((uintptr_t)ptr - ALIGN_INFO)) = align_diff + ALIGN_INFO; \ - } - -#define UNALIGN(ptr) \ - if (ALIGNMENT > 1) \ - { \ - uintptr_t align_diff = *((ALIGN_TYPE*)((uintptr_t)ptr - ALIGN_INFO)); \ - if (align_diff < (ALIGNMENT + ALIGN_INFO)) { ptr = (void*)((uintptr_t)ptr - align_diff); } \ - } - -#define LIBALLOC_MAGIC 0xc001c0de -#define LIBALLOC_DEAD 0xdeaddead - -#if defined DEBUG || defined INFO -#include -#include - -#define FLUSH() fflush(stdout) - -#endif - -/** A structure found at the top of all system allocated - * memory blocks. It details the usage of the memory block. - */ -struct liballoc_major -{ - struct liballoc_major* prev; ///< Linked list information. - struct liballoc_major* next; ///< Linked list information. - unsigned int pages; ///< The number of pages in the block. - unsigned int size; ///< The number of pages in the block. - unsigned int usage; ///< The number of bytes used in the block. - struct liballoc_minor* first; ///< A pointer to the first allocated memory in the block. -}; - -/** This is a structure found at the beginning of all - * sections in a major block which were allocated by a - * malloc, calloc, realloc call. - */ -struct liballoc_minor -{ - struct liballoc_minor* prev; ///< Linked list information. - struct liballoc_minor* next; ///< Linked list information. - struct liballoc_major* block; ///< The owning block. A pointer to the major structure. - unsigned int magic; ///< A magic number to idenfity correctness. - unsigned int size; ///< The size of the memory allocated. Could be 1 byte or more. - unsigned int req_size; ///< The size of memory requested. -}; - -static struct liballoc_major* l_memRoot = NULL; ///< The root memory block acquired from the system. -static struct liballoc_major* l_bestBet = NULL; ///< The major with the most free memory. - -static unsigned int l_pageSize = 4096; ///< The size of an individual page. Set up in liballoc_init. -static unsigned int l_pageCount = 16; ///< The number of pages to request per chunk. Set up in liballoc_init. -static unsigned long long l_allocated = 0; ///< Running total of allocated memory. -static unsigned long long l_inuse = 0; ///< Running total of used memory. - -static long long l_warningCount = 0; ///< Number of warnings encountered -static long long l_errorCount = 0; ///< Number of actual errors -static long long l_possibleOverruns = 0; ///< Number of possible overruns - -// *********** HELPER FUNCTIONS ******************************* - -static void* liballoc_memset(void* s, int c, size_t n) -{ - unsigned int i; - for (i = 0; i < n; i++) ((char*)s)[i] = c; - - return s; -} -static void* liballoc_memcpy(void* s1, const void* s2, size_t n) -{ - char* cdest; - const char* csrc; - unsigned int* ldest = (unsigned int*)s1; - const unsigned int* lsrc = (const unsigned int*)s2; - - while (n >= sizeof(unsigned int)) - { - *ldest++ = *lsrc++; - n -= sizeof(unsigned int); - } - - cdest = (char*)ldest; - csrc = (const char*)lsrc; - - while (n > 0) - { - *cdest++ = *csrc++; - n -= 1; - } - - return s1; -} - -#if defined DEBUG || defined INFO -static void liballoc_dump() -{ -#ifdef DEBUG - struct liballoc_major* maj = l_memRoot; - struct liballoc_minor* min = NULL; -#endif - - printf("liballoc: ------ Memory data ---------------\n"); - printf("liballoc: System memory allocated: %i bytes\n", l_allocated); - printf("liballoc: Memory in used (malloc'ed): %i bytes\n", l_inuse); - printf("liballoc: Warning count: %i\n", l_warningCount); - printf("liballoc: Error count: %i\n", l_errorCount); - printf("liballoc: Possible overruns: %i\n", l_possibleOverruns); - -#ifdef DEBUG - while (maj != NULL) - { - printf("liballoc: %x: total = %i, used = %i\n", maj, maj->size, maj->usage); - - min = maj->first; - while (min != NULL) - { - printf("liballoc: %x: %i bytes\n", min, min->size); - min = min->next; - } - - maj = maj->next; - } -#endif - - FLUSH(); -} -#endif - -// *************************************************************** - -static struct liballoc_major* allocate_new_page(unsigned int size) -{ - unsigned int st; - struct liballoc_major* maj; - - // This is how much space is required. - st = size + sizeof(struct liballoc_major); - st += sizeof(struct liballoc_minor); - - // Perfect amount of space? - if ((st % l_pageSize) == 0) st = st / (l_pageSize); - else - st = st / (l_pageSize) + 1; - // No, add the buffer. - - // Make sure it's >= the minimum size. - if (st < l_pageCount) st = l_pageCount; - - maj = (struct liballoc_major*)liballoc_alloc(st); - - if (maj == NULL) - { - l_warningCount += 1; -#if defined DEBUG || defined INFO - printf("liballoc: WARNING: liballoc_alloc( %i ) return NULL\n", st); - FLUSH(); -#endif - return NULL; // uh oh, we ran out of memory. - } - - maj->prev = NULL; - maj->next = NULL; - maj->pages = st; - maj->size = st * l_pageSize; - maj->usage = sizeof(struct liballoc_major); - maj->first = NULL; - - l_allocated += maj->size; - -#ifdef DEBUG - printf("liballoc: Resource allocated %x of %i pages (%i bytes) for %i size.\n", maj, st, maj->size, size); - - printf("liballoc: Total memory usage = %i KB\n", (int)((l_allocated / (1024)))); - FLUSH(); -#endif - - return maj; -} - -void* PREFIX(malloc)(size_t req_size) -{ - int startedBet = 0; - unsigned long long bestSize = 0; - void* p = NULL; - uintptr_t diff; - struct liballoc_major* maj; - struct liballoc_minor* min; - struct liballoc_minor* new_min; - unsigned long size = req_size; - - // For alignment, we adjust size so there's enough space to align. - if (ALIGNMENT > 1) { size += ALIGNMENT + ALIGN_INFO; } - // So, ideally, we really want an alignment of 0 or 1 in order - // to save space. - - liballoc_lock(); - - if (size == 0) - { - l_warningCount += 1; -#if defined DEBUG || defined INFO - printf("liballoc: WARNING: alloc( 0 ) called from %x\n", __builtin_return_address(0)); - FLUSH(); -#endif - liballoc_unlock(); - return PREFIX(malloc)(1); - } - - if (l_memRoot == NULL) - { -#if defined DEBUG || defined INFO -#ifdef DEBUG - printf("liballoc: initialization of liballoc " VERSION "\n"); -#endif - atexit(liballoc_dump); - FLUSH(); -#endif - - // This is the first time we are being used. - l_memRoot = allocate_new_page(size); - if (l_memRoot == NULL) - { - liballoc_unlock(); -#ifdef DEBUG - printf("liballoc: initial l_memRoot initialization failed\n", p); - FLUSH(); -#endif - return NULL; - } - -#ifdef DEBUG - printf("liballoc: set up first memory major %x\n", l_memRoot); - FLUSH(); -#endif - } - -#ifdef DEBUG - printf("liballoc: %x PREFIX(malloc)( %i ): ", __builtin_return_address(0), size); - FLUSH(); -#endif - - // Now we need to bounce through every major and find enough space.... - - maj = l_memRoot; - startedBet = 0; - - // Start at the best bet.... - if (l_bestBet != NULL) - { - bestSize = l_bestBet->size - l_bestBet->usage; - - if (bestSize > (size + sizeof(struct liballoc_minor))) - { - maj = l_bestBet; - startedBet = 1; - } - } - - while (maj != NULL) - { - diff = maj->size - maj->usage; - // free memory in the block - - if (bestSize < diff) - { - // Hmm.. this one has more memory then our bestBet. Remember! - l_bestBet = maj; - bestSize = diff; - } - -#ifdef USE_CASE1 - - // CASE 1: There is not enough space in this major block. - if (diff < (size + sizeof(struct liballoc_minor))) - { -#ifdef DEBUG - printf("CASE 1: Insufficient space in block %x\n", maj); - FLUSH(); -#endif - - // Another major block next to this one? - if (maj->next != NULL) - { - maj = maj->next; // Hop to that one. - continue; - } - - if (startedBet == 1) // If we started at the best bet, - { // let's start all over again. - maj = l_memRoot; - startedBet = 0; - continue; - } - - // Create a new major block next to this one and... - maj->next = allocate_new_page(size); // next one will be okay. - if (maj->next == NULL) break; // no more memory. - maj->next->prev = maj; - maj = maj->next; - - // .. fall through to CASE 2 .. - } - -#endif - -#ifdef USE_CASE2 - - // CASE 2: It's a brand new block. - if (maj->first == NULL) - { - maj->first = (struct liballoc_minor*)((uintptr_t)maj + sizeof(struct liballoc_major)); - - maj->first->magic = LIBALLOC_MAGIC; - maj->first->prev = NULL; - maj->first->next = NULL; - maj->first->block = maj; - maj->first->size = size; - maj->first->req_size = req_size; - maj->usage += size + sizeof(struct liballoc_minor); - - l_inuse += size; - - p = (void*)((uintptr_t)(maj->first) + sizeof(struct liballoc_minor)); - - ALIGN(p); - -#ifdef DEBUG - printf("CASE 2: returning %x\n", p); - FLUSH(); -#endif - liballoc_unlock(); // release the lock - return p; - } - -#endif - -#ifdef USE_CASE3 - - // CASE 3: Block in use and enough space at the start of the block. - diff = (uintptr_t)(maj->first); - diff -= (uintptr_t)maj; - diff -= sizeof(struct liballoc_major); - - if (diff >= (size + sizeof(struct liballoc_minor))) - { - // Yes, space in front. Squeeze in. - maj->first->prev = (struct liballoc_minor*)((uintptr_t)maj + sizeof(struct liballoc_major)); - maj->first->prev->next = maj->first; - maj->first = maj->first->prev; - - maj->first->magic = LIBALLOC_MAGIC; - maj->first->prev = NULL; - maj->first->block = maj; - maj->first->size = size; - maj->first->req_size = req_size; - maj->usage += size + sizeof(struct liballoc_minor); - - l_inuse += size; - - p = (void*)((uintptr_t)(maj->first) + sizeof(struct liballoc_minor)); - ALIGN(p); - -#ifdef DEBUG - printf("CASE 3: returning %x\n", p); - FLUSH(); -#endif - liballoc_unlock(); // release the lock - return p; - } - -#endif - -#ifdef USE_CASE4 - - // CASE 4: There is enough space in this block. But is it contiguous? - min = maj->first; - - // Looping within the block now... - while (min != NULL) - { - // CASE 4.1: End of minors in a block. Space from last and end? - if (min->next == NULL) - { - // the rest of this block is free... is it big enough? - diff = (uintptr_t)(maj) + maj->size; - diff -= (uintptr_t)min; - diff -= sizeof(struct liballoc_minor); - diff -= min->size; - // minus already existing usage.. - - if (diff >= (size + sizeof(struct liballoc_minor))) - { - // yay.... - min->next = (struct liballoc_minor*)((uintptr_t)min + sizeof(struct liballoc_minor) + min->size); - min->next->prev = min; - min = min->next; - min->next = NULL; - min->magic = LIBALLOC_MAGIC; - min->block = maj; - min->size = size; - min->req_size = req_size; - maj->usage += size + sizeof(struct liballoc_minor); - - l_inuse += size; - - p = (void*)((uintptr_t)min + sizeof(struct liballoc_minor)); - ALIGN(p); - -#ifdef DEBUG - printf("CASE 4.1: returning %x\n", p); - FLUSH(); -#endif - liballoc_unlock(); // release the lock - return p; - } - } - - // CASE 4.2: Is there space between two minors? - if (min->next != NULL) - { - // is the difference between here and next big enough? - diff = (uintptr_t)(min->next); - diff -= (uintptr_t)min; - diff -= sizeof(struct liballoc_minor); - diff -= min->size; - // minus our existing usage. - - if (diff >= (size + sizeof(struct liballoc_minor))) - { - // yay...... - new_min = (struct liballoc_minor*)((uintptr_t)min + sizeof(struct liballoc_minor) + min->size); - - new_min->magic = LIBALLOC_MAGIC; - new_min->next = min->next; - new_min->prev = min; - new_min->size = size; - new_min->req_size = req_size; - new_min->block = maj; - min->next->prev = new_min; - min->next = new_min; - maj->usage += size + sizeof(struct liballoc_minor); - - l_inuse += size; - - p = (void*)((uintptr_t)new_min + sizeof(struct liballoc_minor)); - ALIGN(p); - -#ifdef DEBUG - printf("CASE 4.2: returning %x\n", p); - FLUSH(); -#endif - - liballoc_unlock(); // release the lock - return p; - } - } // min->next != NULL - - min = min->next; - } // while min != NULL ... - -#endif - -#ifdef USE_CASE5 - - // CASE 5: Block full! Ensure next block and loop. - if (maj->next == NULL) - { -#ifdef DEBUG - printf("CASE 5: block full\n"); - FLUSH(); -#endif - - if (startedBet == 1) - { - maj = l_memRoot; - startedBet = 0; - continue; - } - - // we've run out. we need more... - maj->next = allocate_new_page(size); // next one guaranteed to be okay - if (maj->next == NULL) break; // uh oh, no more memory..... - maj->next->prev = maj; - } - -#endif - - maj = maj->next; - } // while (maj != NULL) - - liballoc_unlock(); // release the lock - -#ifdef DEBUG - printf("All cases exhausted. No memory available.\n"); - FLUSH(); -#endif -#if defined DEBUG || defined INFO - printf("liballoc: WARNING: PREFIX(malloc)( %i ) returning NULL.\n", size); - liballoc_dump(); - FLUSH(); -#endif - return NULL; -} - -void PREFIX(free)(void* ptr) -{ - struct liballoc_minor* min; - struct liballoc_major* maj; - - if (ptr == NULL) - { - l_warningCount += 1; -#if defined DEBUG || defined INFO - printf("liballoc: WARNING: PREFIX(free)( NULL ) called from %x\n", __builtin_return_address(0)); - FLUSH(); -#endif - return; - } - - UNALIGN(ptr); - - liballoc_lock(); // lockit - - min = (struct liballoc_minor*)((uintptr_t)ptr - sizeof(struct liballoc_minor)); - - if (min->magic != LIBALLOC_MAGIC) - { - l_errorCount += 1; - - // Check for overrun errors. For all bytes of LIBALLOC_MAGIC - if (((min->magic & 0xFFFFFF) == (LIBALLOC_MAGIC & 0xFFFFFF)) || - ((min->magic & 0xFFFF) == (LIBALLOC_MAGIC & 0xFFFF)) || ((min->magic & 0xFF) == (LIBALLOC_MAGIC & 0xFF))) - { - l_possibleOverruns += 1; -#if defined DEBUG || defined INFO - printf("liballoc: ERROR: Possible 1-3 byte overrun for magic %x != %x\n", min->magic, LIBALLOC_MAGIC); - FLUSH(); -#endif - } - - if (min->magic == LIBALLOC_DEAD) - { -#if defined DEBUG || defined INFO - printf("liballoc: ERROR: multiple PREFIX(free)() attempt on %x from %x.\n", ptr, - __builtin_return_address(0)); - FLUSH(); -#endif - } - else - { -#if defined DEBUG || defined INFO - printf("liballoc: ERROR: Bad PREFIX(free)( %x ) called from %x\n", ptr, __builtin_return_address(0)); - FLUSH(); -#endif - } - - // being lied to... - liballoc_unlock(); // release the lock - return; - } - -#ifdef DEBUG - printf("liballoc: %x PREFIX(free)( %x ): ", __builtin_return_address(0), ptr); - FLUSH(); -#endif - - maj = min->block; - - l_inuse -= min->size; - - maj->usage -= (min->size + sizeof(struct liballoc_minor)); - min->magic = LIBALLOC_DEAD; // No mojo. - - if (min->next != NULL) min->next->prev = min->prev; - if (min->prev != NULL) min->prev->next = min->next; - - if (min->prev == NULL) maj->first = min->next; - // Might empty the block. This was the first - // minor. - - // We need to clean up after the majors now.... - - if (maj->first == NULL) // Block completely unused. - { - if (l_memRoot == maj) l_memRoot = maj->next; - if (l_bestBet == maj) l_bestBet = NULL; - if (maj->prev != NULL) maj->prev->next = maj->next; - if (maj->next != NULL) maj->next->prev = maj->prev; - l_allocated -= maj->size; - - liballoc_free(maj, maj->pages); - } - else - { - if (l_bestBet != NULL) - { - int bestSize = l_bestBet->size - l_bestBet->usage; - int majSize = maj->size - maj->usage; - - if (majSize > bestSize) l_bestBet = maj; - } - } - -#ifdef DEBUG - printf("OK\n"); - FLUSH(); -#endif - - liballoc_unlock(); // release the lock -} - -void* PREFIX(calloc)(size_t nobj, size_t size) -{ - int real_size; - void* p; - - real_size = nobj * size; - - p = PREFIX(malloc)(real_size); - - liballoc_memset(p, 0, real_size); - - return p; -} - -void* PREFIX(realloc)(void* p, size_t size) -{ - void* ptr; - struct liballoc_minor* min; - unsigned int real_size; - - // Honour the case of size == 0 => free old and return NULL - if (size == 0) - { - PREFIX(free)(p); - return NULL; - } - - // In the case of a NULL pointer, return a simple malloc. - if (p == NULL) return PREFIX(malloc)(size); - - // Unalign the pointer if required. - ptr = p; - UNALIGN(ptr); - - liballoc_lock(); // lockit - - min = (struct liballoc_minor*)((uintptr_t)ptr - sizeof(struct liballoc_minor)); - - // Ensure it is a valid structure. - if (min->magic != LIBALLOC_MAGIC) - { - l_errorCount += 1; - - // Check for overrun errors. For all bytes of LIBALLOC_MAGIC - if (((min->magic & 0xFFFFFF) == (LIBALLOC_MAGIC & 0xFFFFFF)) || - ((min->magic & 0xFFFF) == (LIBALLOC_MAGIC & 0xFFFF)) || ((min->magic & 0xFF) == (LIBALLOC_MAGIC & 0xFF))) - { - l_possibleOverruns += 1; -#if defined DEBUG || defined INFO - printf("liballoc: ERROR: Possible 1-3 byte overrun for magic %x != %x\n", min->magic, LIBALLOC_MAGIC); - FLUSH(); -#endif - } - - if (min->magic == LIBALLOC_DEAD) - { -#if defined DEBUG || defined INFO - printf("liballoc: ERROR: multiple PREFIX(free)() attempt on %x from %x.\n", ptr, - __builtin_return_address(0)); - FLUSH(); -#endif - } - else - { -#if defined DEBUG || defined INFO - printf("liballoc: ERROR: Bad PREFIX(free)( %x ) called from %x\n", ptr, __builtin_return_address(0)); - FLUSH(); -#endif - } - - // being lied to... - liballoc_unlock(); // release the lock - return NULL; - } - - // Definitely a memory block. - - real_size = min->req_size; - - if (real_size >= size) - { - min->req_size = size; - liballoc_unlock(); - return p; - } - - liballoc_unlock(); - - // If we got here then we're reallocating to a block bigger than us. - ptr = PREFIX(malloc)(size); // We need to allocate new memory - liballoc_memcpy(ptr, p, real_size); - PREFIX(free)(p); - - return ptr; -} - -#pragma GCC pop_options diff --git a/libs/libc/src/ctype.cpp b/libs/libc/src/ctype.cpp deleted file mode 100644 index 8610ce6b..00000000 --- a/libs/libc/src/ctype.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include - -extern "C" -{ - int isalnum(int c) - { - return isalpha(c) || isdigit(c); - } - - int isalpha(int c) - { - return islower(c) || isupper(c); - } - - int isascii(int c) - { - return !(c & ~0x7f); - } - - int isblank(int c) - { - return c == ' ' || c == '\t'; - } - - int iscntrl(int c) - { - return (unsigned int)c < 0x20 || c == 0x7f; - } - - int isdigit(int c) - { - return c >= '0' && c < ':'; - } - - int isgraph(int c) - { - return (unsigned int)c - 0x21 < 0x5e; - } - - int islower(int c) - { - return c >= 'a' && c < '{'; - } - - int isprint(int c) - { - return (unsigned int)c - 0x20 < 0x5f; - } - - int ispunct(int c) - { - return isgraph(c) && !isalnum(c); - } - - int isspace(int c) - { - return c == ' ' || (unsigned int)c - '\t' < 5; - } - - int isupper(int c) - { - return c >= 'A' && c < '['; - } - - int isxdigit(int c) - { - return isdigit(c) || ((unsigned int)c | 32) - 'a' < 6; - } - - int tolower(int c) - { - if (isupper(c)) return c | 32; - return c; - } - - int toupper(int c) - { - if (islower(c)) return c & 0x5f; - return c; - } - - int toascii(int c) - { - return c & 0x7f; - } -} \ No newline at end of file diff --git a/libs/libc/src/cxxabi.cpp b/libs/libc/src/cxxabi.cpp deleted file mode 100644 index 47734a45..00000000 --- a/libs/libc/src/cxxabi.cpp +++ /dev/null @@ -1,50 +0,0 @@ -typedef void* (*cxa_atexit_func_t)(void*); - -struct cxa_atexit_entry -{ - cxa_atexit_func_t function; - void* argument; - void* dso_handle; -}; - -#define CXA_ATEXIT_MAX 64 - -int cxa_atexit_entry_count = 0; - -cxa_atexit_entry cxa_atexit_entries[CXA_ATEXIT_MAX]; - -extern "C" -{ - int __cxa_atexit(cxa_atexit_func_t func, void* arg, void* dso) - { - if (cxa_atexit_entry_count >= CXA_ATEXIT_MAX) return -1; - cxa_atexit_entries[cxa_atexit_entry_count].function = func; - cxa_atexit_entries[cxa_atexit_entry_count].argument = arg; - cxa_atexit_entries[cxa_atexit_entry_count].dso_handle = dso; - cxa_atexit_entry_count++; - return 0; - } - - void __cxa_finalize(void* f) - { - int i = cxa_atexit_entry_count; - if (!f) - { - while (i--) - { - if (cxa_atexit_entries[i].function) { cxa_atexit_entries[i].function(cxa_atexit_entries[i].argument); } - } - } - else - { - while (i--) - { - if (cxa_atexit_entries[i].function == (cxa_atexit_func_t)f) - { - cxa_atexit_entries[i].function(cxa_atexit_entries[i].argument); - cxa_atexit_entries[i].function = 0; - } - } - } - } -} \ No newline at end of file diff --git a/libs/libc/src/dirent.cpp b/libs/libc/src/dirent.cpp deleted file mode 100644 index 48523a19..00000000 --- a/libs/libc/src/dirent.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -extern "C" -{ - DIR* opendir(const char* path) - { - int fd = open(path, O_RDONLY | O_DIRECTORY); - if (fd < 0) return NULL; - return fdopendir(fd); - } - - DIR* fdopendir(int fd) - { - if (fd < 0) return NULL; - DIR* result = (DIR*)malloc(sizeof(DIR)); - if (!result) return NULL; - result->d_dirfd = fd; - return result; - } - - int closedir(DIR* stream) - { - int status = close(stream->d_dirfd); - if (status < 0) - { - int savederr = errno; - free(stream); - errno = savederr; // free might reset errno. We don't want that. - } - else { free(stream); } - return status; - } - - struct dirent* readdir(DIR* stream) - { - static struct dirent result; - struct luna_dirent ent; - ssize_t nread = getdents(stream->d_dirfd, &ent, 1); // FIXME: Use a buffer to avoid too many system calls. - if (nread <= 0) return NULL; // Either EOF or error. - result.d_ino = ent.inode; - result.d_reclen = sizeof(result); - result.d_off = ent.offset; - result.d_type = DT_UNKNOWN; - strlcpy(result.d_name, ent.name, NAME_MAX); - return &result; - } - - int dirfd(DIR* stream) - { - return stream->d_dirfd; - } - - void rewinddir(DIR* stream) - { - lseek(stream->d_dirfd, 0, SEEK_SET); - } - - long telldir(DIR* stream) - { - return lseek(stream->d_dirfd, 0, SEEK_CUR); - } - - void seekdir(DIR* stream, long offset) - { - lseek(stream->d_dirfd, offset, SEEK_SET); - } -} \ No newline at end of file diff --git a/libs/libc/src/errno.cpp b/libs/libc/src/errno.cpp deleted file mode 100644 index ccd33dd5..00000000 --- a/libs/libc/src/errno.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include - -int errno; -char* program_invocation_name; \ No newline at end of file diff --git a/libs/libc/src/fcntl.cpp b/libs/libc/src/fcntl.cpp deleted file mode 100644 index c6a7d64d..00000000 --- a/libs/libc/src/fcntl.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include -#include -#include -#include -#include - -extern "C" -{ - int open(const char* pathname, int flags, ...) - { - va_list ap; - va_start(ap, flags); - long result = __lc_fast_syscall3(SYS_open, pathname, flags, va_arg(ap, unsigned int)); - va_end(ap); - return (int)result; - } - - int creat(const char* pathname, mode_t mode) - { - return (int)__lc_fast_syscall3(SYS_open, pathname, O_WRONLY | O_CREAT | O_TRUNC, - mode); // we don't need to pass this through to open(), we can avoid variadic - // stuff since we're sure mode exists. - } - - int fcntl(int fd, int cmd, ...) - { - va_list ap; - va_start(ap, cmd); - long result = __lc_fast_syscall3(SYS_fcntl, fd, cmd, va_arg(ap, uintptr_t)); - va_end(ap); - return (int)result; - } -} \ No newline at end of file diff --git a/libs/libc/src/file.cpp b/libs/libc/src/file.cpp deleted file mode 100644 index d686d8da..00000000 --- a/libs/libc/src/file.cpp +++ /dev/null @@ -1,305 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -FILE* stderr; -FILE* stdout; -FILE* stdin; - -static void file_read_buf(FILE* stream) -{ - if (!stream->f_buf) - { - stream->f_buf = (char*)malloc(BUFSIZ); // FIXME: Handle errors. - stream->f_bufrsize = BUFSIZ; - } - stream->f_bufoff = 0; - ssize_t nread = read(stream->f_fd, stream->f_buf, stream->f_bufrsize); - if (nread < 0) - { - stream->f_err = 1; - return; - } - if (nread == 0) - { - stream->f_eof = 1; - return; - } - stream->f_bufsize = nread; -} - -static int file_parse_mode(const char* mode) -{ - int flags = 0; - switch (mode[0]) - { - case 'r': flags |= O_RDONLY; break; - case 'w': - flags |= O_WRONLY; - flags |= O_CREAT; - flags |= O_TRUNC; - break; - case 'a': - flags |= O_WRONLY; - flags |= O_CREAT; - flags |= O_APPEND; - break; - default: errno = EINVAL; return -1; - } - - if (strchr(mode, '+')) flags |= O_RDWR; - return flags; -} - -extern "C" -{ - int fclose(FILE* stream) - { - if (stream->f_buf) free(stream->f_buf); - int status = close(stream->f_fd); - if (status < 0) - { - int savederr = errno; - free(stream); // We do not want to leak memory. man fclose(3) says that whether fclose() fails or not, any - // further operation on the stream results in undefined behavior. So we are free to free the - // stream. - errno = savederr; // free might reset errno. We don't want that. - } - else { free(stream); } - return status; - } - - int fflush(FILE*) - { - return 0; // FIXME: Implement buffered IO. - } - - FILE* fopen(const char* pathname, const char* mode) - { - int flags = file_parse_mode(mode); - if (flags < 0) return NULL; - int fd = open(pathname, flags, 0666); // If we create the file, create it as rw-rw-rw-. - if (fd < 0) { return 0; } - return fdopen(fd, mode); - } - - FILE* fdopen(int fd, const char*) - { - if (fd < 0) // FIXME: Also check if the mode string is compatible with how fd was opened. - { - errno = EBADF; - return 0; - } - FILE* stream = (FILE*)malloc(sizeof(FILE)); - if (!stream) { return 0; } - stream->f_fd = fd; - clearerr(stream); - stream->f_buf = 0; - stream->f_bufoff = 0; - stream->f_bufsize = 0; - return stream; - } - - FILE* freopen(const char* pathname, const char* mode, - FILE* stream) // FIXME: If pathname is NULL, open the original file with the new mode. - { - int flags = file_parse_mode(mode); - if (flags < 0) return NULL; - int fd = open(pathname, flags, 0666); // If we create the file, create it as rw-rw-rw-. - if (fd < 0) { return 0; } - - fflush(stream); // To make it future-proof. - fclose(stream); - - stream->f_fd = fd; - clearerr(stream); - return stream; - } - - int fileno(FILE* stream) - { - return stream->f_fd; - } - - size_t fread(void* buf, size_t size, size_t nmemb, FILE* stream) - { - size_t rsize = size * nmemb; - ssize_t status = read(stream->f_fd, buf, rsize); - if (status < 0) - { - stream->f_err = 1; - return 0; - } - if (status == 0 && rsize) stream->f_eof = 1; - if (status == 0) return (size_t)status; - return (size_t)status / size; - } - - char* fgets(char* buf, int size, FILE* stream) - { - char* s = buf; - int original_size = size; - while (size > 1) - { - if (stream->f_bufoff < stream->f_bufsize) - { - *buf = *(stream->f_buf + stream->f_bufoff); - stream->f_bufoff++; - if (*buf == '\n') - { - buf++; - break; - } - if (*buf == '\b') - { - if (size != original_size) - { - buf--; - size++; - } - } - else - { - buf++; - size--; - } - } - else - { - file_read_buf(stream); - if (ferror(stream)) return NULL; - if (feof(stream)) break; - } - } - if (size == original_size && feof(stream)) return NULL; // EOF while reading the first character - *buf = 0; - return s; - } - - int fgetc(FILE* stream) - { - char result; - read: - if (stream->f_bufoff < stream->f_bufsize) - { - result = *(stream->f_buf + stream->f_bufoff); - stream->f_bufoff++; - } - else - { - file_read_buf(stream); - if (ferror(stream)) return EOF; - if (feof(stream)) return EOF; - goto read; - } - return (int)result; - } - - int getc(FILE* stream) - { - return fgetc(stream); - } - - int getchar() - { - return fgetc(stdin); - } - - int ungetc(int c, FILE* stream) - { - if (stream->f_bufoff > 0) - { - stream->f_bufoff--; - stream->f_buf[stream->f_bufoff] = (char)c; - return c; - } - else - { - return EOF; // FIXME: Handle this case properly. - } - } - - int ferror(FILE* stream) - { - return stream->f_err; - } - - int feof(FILE* stream) - { - return stream->f_eof; - } - - void clearerr(FILE* stream) - { - stream->f_err = stream->f_eof = 0; - } - - int fseek(FILE* stream, long offset, int whence) - { - long result = lseek(stream->f_fd, offset, whence); - if (result < 0) { return -1; } - return 0; - } - - int fseeko(FILE* stream, off_t offset, int whence) - { - return fseek(stream, offset, whence); - } - - int fsetpos(FILE* stream, const fpos_t* pos) - { - return fseek(stream, *pos, SEEK_SET); - } - - long ftell(FILE* stream) - { - return lseek(stream->f_fd, 0, SEEK_CUR); - } - - off_t ftello(FILE* stream) - { - return ftell(stream); - } - - int fgetpos(FILE* stream, fpos_t* pos) - { - long result = ftell(stream); - if (result < 0) { return -1; } - *pos = result; - return 0; - } - - void rewind(FILE* stream) - { - lseek(stream->f_fd, 0, SEEK_SET); - clearerr(stream); - } - - size_t fwrite(const void* buf, size_t size, size_t nmemb, FILE* stream) - { - size_t rsize = size * nmemb; - ssize_t status = write(stream->f_fd, buf, rsize); - if (status < 0) - { - stream->f_err = 1; - return 0; - } - if (status == 0 && rsize) stream->f_eof = 1; - if (status == 0) return (size_t)status; - return (size_t)status / size; - } - - void setbuf(FILE*, char*) - { - NOT_IMPLEMENTED("setbuf"); - } - - int setvbuf(FILE*, char*, int, size_t) - { - NOT_IMPLEMENTED("setvbuf"); - } -} \ No newline at end of file diff --git a/libs/libc/src/init.cpp b/libs/libc/src/init.cpp deleted file mode 100644 index 00a777d4..00000000 --- a/libs/libc/src/init.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include -#include -#include -#include -#include - -char** environ = {nullptr}; - -static void terminate_libc() -{ - fclose(stdout); - fclose(stderr); - fclose(stdin); -} - -static void initialize_random() -{ - unsigned int seed = 3735928559U; - - int fd = open("/dev/random", O_RDONLY | O_CLOEXEC); // If we somehow fail to close this file, close it on exec. - FILE* fp = fdopen(fd, "r"); - if (!fp) - { - errno = 0; - goto failed_to_read_dev_random; - } - - fread(&seed, sizeof(seed), 1, fp); - if (ferror(fp)) - { - errno = 0; - fclose(fp); - goto failed_to_read_dev_random; - } - - fclose(fp); - -failed_to_read_dev_random: - srand(seed); // If we failed, this will be seeded with a known value. Else, it will be seeded with a random value - // from the kernel. - return; -} - -static void check_for_file(int fd, FILE** target_stream, const char* path, const char* mode) -{ - if (lseek(fd, 0, SEEK_CUR) < 0) - { - if (errno == EBADF) *target_stream = fopen(path, mode); - else - exit(-errno); - if (!*target_stream) exit(-errno); - errno = 0; - } - else { *target_stream = fdopen(fd, mode); } -} - -extern char* program_invocation_name; - -extern "C" void initialize_libc(int, char** argv) -{ - check_for_file(STDIN_FILENO, &stdin, "/dev/console", "r"); - check_for_file(STDOUT_FILENO, &stdout, "/dev/console", "a"); - check_for_file(STDERR_FILENO, &stderr, "/dev/console", "a"); - - if (argv) program_invocation_name = argv[0]; - - initialize_random(); - atexit(terminate_libc); -} \ No newline at end of file diff --git a/libs/libc/src/libgen.cpp b/libs/libc/src/libgen.cpp deleted file mode 100644 index c1bcbfc6..00000000 --- a/libs/libc/src/libgen.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include -#include - -static char dot[] = "."; - -extern "C" -{ - char* basename(char* path) - { - // If path is NULL, or the string's length is 0, return . - if (!path) return dot; - size_t len = strlen(path); - if (!len) return dot; - - // Strip trailing slashes. - char* it = path + len - 1; - while (*it == '/' && it != path) { it--; } - *(it + 1) = 0; - if (it == path) return path; - - // Return path from the first character if there are no more slashes, or from the first character after the last - // slash. - char* beg = strrchr(path, '/'); - if (!beg) return path; - return beg + 1; - } - - char* dirname(char* path) - { - // If path is NULL, or the string's length is 0, return . - if (!path) return dot; - size_t len = strlen(path); - if (!len) return dot; - - // Strip trailing slashes. - char* it = path + len - 1; - while (*it == '/' && it != path) { it--; } - *(char*)(it + 1) = 0; - if (it == path) return path; - - // Search for the last slash. If there is none, return . - // Otherwise, we end the string there and return. - char* end = strrchr(path, '/'); - if (!end) return dot; - if (end != path) *end = 0; - else - *(end + 1) = 0; - return path; - } -} \ No newline at end of file diff --git a/libs/libc/src/locale.cpp b/libs/libc/src/locale.cpp deleted file mode 100644 index 656cfa3b..00000000 --- a/libs/libc/src/locale.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include -#include - -static char default_locale[] = "C"; - -static char dot[] = "."; -static char empty[] = ""; - -static struct lconv default_lconv = {dot, empty, empty, empty, empty, empty, - empty, empty, empty, empty, CHAR_MAX, CHAR_MAX, - CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX}; - -extern "C" -{ - char* setlocale(int, const char*) - { - return default_locale; - } - - struct lconv* localeconv(void) - { - return &default_lconv; - } -} \ No newline at end of file diff --git a/libs/libc/src/luna.cpp b/libs/libc/src/luna.cpp deleted file mode 100644 index 48dc1285..00000000 --- a/libs/libc/src/luna.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include -#include -#include -#include -#include - -extern "C" -{ - long getprocid(int field) - { - return __lc_fast_syscall1(SYS_getprocid, field); - } - - unsigned int msleep(unsigned int ms) - { - return (unsigned int)__lc_fast_syscall1(SYS_sleep, ms); - } - - __lc_noreturn void __luna_abort(const char* message) - { - fputs(message, stderr); - abort(); - } -} \ No newline at end of file diff --git a/libs/libc/src/luna/dirent.cpp b/libs/libc/src/luna/dirent.cpp deleted file mode 100644 index 967e2e5b..00000000 --- a/libs/libc/src/luna/dirent.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include -#include -#include - -extern "C" -{ - ssize_t getdents(int fd, struct luna_dirent* buf, size_t count) - { - return __lc_fast_syscall3(SYS_getdents, fd, buf, count); - } -} \ No newline at end of file diff --git a/libs/libc/src/luna/pstat.cpp b/libs/libc/src/luna/pstat.cpp deleted file mode 100644 index 1221b6de..00000000 --- a/libs/libc/src/luna/pstat.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include -#include - -extern "C" -{ - pid_t pstat(pid_t pid, struct pstat* buf) - { - return __lc_fast_syscall2(SYS_pstat, pid, buf); - } - - const char* pstatname(struct pstat* buf) - { - switch (buf->pt_state) - { - case PT_IDLE: return "Idle"; - case PT_RUNNING: return "Running"; - case PT_SLEEPING: return "Sleeping"; - case PT_WAITING: return "Waiting"; - case PT_ZOMBIE: return "Zombie"; - default: return "Unknown"; - } - } -} \ No newline at end of file diff --git a/libs/libc/src/luna/syscall.asm b/libs/libc/src/luna/syscall.asm deleted file mode 100644 index b6c1797c..00000000 --- a/libs/libc/src/luna/syscall.asm +++ /dev/null @@ -1,50 +0,0 @@ -global __luna_syscall0 -__luna_syscall0: - mov rax, rdi - int 0x42 - ret - -global __luna_syscall1 -__luna_syscall1: - mov rax, rdi - mov rdi, rsi - int 0x42 - ret - -global __luna_syscall2 -__luna_syscall2: - mov rax, rdi - mov rdi, rsi - mov rsi, rdx - int 0x42 - ret - -global __luna_syscall3 -__luna_syscall3: - mov rax, rdi - mov rdi, rsi - mov rsi, rdx - mov rdx, rcx - int 0x42 - ret - -global __luna_syscall4 -__luna_syscall4: - mov rax, rdi - mov rdi, rsi - mov rsi, rdx - mov rdx, rcx - mov r10, r8 - int 0x42 - ret - -global __luna_syscall5 -__luna_syscall5: - mov rax, rdi - mov rdi, rsi - mov rsi, rdx - mov rdx, rcx - mov r10, r8 - mov r8, r9 - int 0x42 - ret \ No newline at end of file diff --git a/libs/libc/src/math.cpp b/libs/libc/src/math.cpp deleted file mode 100644 index 52367eb0..00000000 --- a/libs/libc/src/math.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include - -// FIXME: Provide our own definitions instead of relying on the compiler's builtins. - -#define WRAP_AROUND_BUILTIN(name) \ - double name(double val) \ - { \ - return __builtin_##name(val); \ - } \ - float name##f(float val) \ - { \ - return __builtin_##name##f(val); \ - } \ - long double name##l(long double val) \ - { \ - return __builtin_##name##l(val); \ - } - -#define WRAP_AROUND_BUILTIN2(name) \ - double name(double val1, double val2) \ - { \ - return __builtin_##name(val1, val2); \ - } \ - float name##f(float val1, float val2) \ - { \ - return __builtin_##name##f(val1, val2); \ - } \ - long double name##l(long double val1, long double val2) \ - { \ - return __builtin_##name##l(val1, val2); \ - } - -#define WRAP_AROUND_BUILTIN_WITH_PARAMETER_TYPE(name, type) \ - double name(double val1, type val2) \ - { \ - return __builtin_##name(val1, val2); \ - } \ - float name##f(float val1, type val2) \ - { \ - return __builtin_##name##f(val1, val2); \ - } \ - long double name##l(long double val1, type val2) \ - { \ - return __builtin_##name##l(val1, val2); \ - } - -#define WRAP_AROUND_BUILTIN_WITH_POINTER(name) \ - double name(double val1, double* val2) \ - { \ - return __builtin_##name(val1, val2); \ - } \ - float name##f(float val1, float* val2) \ - { \ - return __builtin_##name##f(val1, val2); \ - } \ - long double name##l(long double val1, long double* val2) \ - { \ - return __builtin_##name##l(val1, val2); \ - } - -extern "C" -{ - WRAP_AROUND_BUILTIN(cos); - - WRAP_AROUND_BUILTIN(sin); - - WRAP_AROUND_BUILTIN(tan); - - WRAP_AROUND_BUILTIN(acos); - - WRAP_AROUND_BUILTIN(asin); - - WRAP_AROUND_BUILTIN(atan); - - WRAP_AROUND_BUILTIN(cosh); - - WRAP_AROUND_BUILTIN(sinh); - - WRAP_AROUND_BUILTIN(tanh); - - WRAP_AROUND_BUILTIN(log); - - WRAP_AROUND_BUILTIN(exp); - - WRAP_AROUND_BUILTIN(sqrt); - - WRAP_AROUND_BUILTIN(fabs); - - WRAP_AROUND_BUILTIN(floor); - - WRAP_AROUND_BUILTIN(ceil); - - WRAP_AROUND_BUILTIN(log10); - - WRAP_AROUND_BUILTIN2(fmod); - - WRAP_AROUND_BUILTIN2(pow); - - WRAP_AROUND_BUILTIN2(atan2); - - WRAP_AROUND_BUILTIN_WITH_PARAMETER_TYPE(frexp, int*); - - WRAP_AROUND_BUILTIN_WITH_PARAMETER_TYPE(ldexp, int); - - WRAP_AROUND_BUILTIN_WITH_POINTER(modf); -} \ No newline at end of file diff --git a/libs/libc/src/printf.cpp b/libs/libc/src/printf.cpp deleted file mode 100644 index 3be32613..00000000 --- a/libs/libc/src/printf.cpp +++ /dev/null @@ -1,331 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -typedef long int ssize_t; - -static void printf_strrev(char* arr, int size) -{ - int left = 0; - int right = size - 1; - for (int i = left; i < right; i++) - { - char temp = arr[i]; - arr[i] = arr[right]; - arr[right] = temp; - right--; - } -} - -template static char* printf_unsigned_to_string(IntegerType number, char* arr, int base) -{ - int i = 0; - - if (number == 0) - { - arr[i] = '0'; - arr[i + 1] = '\0'; - return arr; - } - - while (number != 0) - { - IntegerType r = number % (IntegerType)base; - arr[i] = (char)((r > 9) ? (r - 10) + 'a' : r + '0'); - i++; - number /= base; - } - - printf_strrev(arr, i); - - arr[i] = '\0'; - - return arr; -} - -template static char* printf_signed_to_string(IntegerType number, char* arr, int base) -{ - int i = 0, negative = 0; - - if (number == 0) - { - arr[i] = '0'; - arr[i + 1] = '\0'; - return arr; - } - - if (number < 0 && base == 10) - { - number *= -1; - negative = 1; - } - - while (number != 0) - { - IntegerType r = number % base; - arr[i] = (char)((r > 9) ? (r - 10) + 'a' : r + '0'); - i++; - number /= base; - } - - if (negative) - { - arr[i] = '-'; - i++; - } - - printf_strrev(arr, i); - - arr[i] = '\0'; - - return arr; -} - -#pragma GCC push_options -#pragma GCC optimize("O0") - -template -static int internal_printf(const char* format, PutString put_string_callback, ssize_t max, va_list ap) -{ - char buffer[1025]; // 1024 with null terminator - size_t format_size = strlen(format); - size_t format_index = 0; - size_t buffer_insert_index = 0; - ssize_t max_remaining = max; - size_t written = 0; - - auto flush_buffer = [&]() { - size_t buffer_length = buffer_insert_index; - written += buffer_length; - buffer_insert_index = 0; - if (max_remaining < 0) - { - buffer[buffer_length] = 0; - put_string_callback(buffer); - return; - } - if (max_remaining == 0) { return; } - if (buffer_length <= (size_t)max_remaining) - { - max_remaining -= buffer_length; - buffer[buffer_length] = 0; - put_string_callback(buffer); - } - else - { - buffer[max_remaining] = 0; - max_remaining = 0; - put_string_callback(buffer); - } - }; - - auto append_string = [&](const char* str) { - while (strlen(str) > 1024) - { - flush_buffer(); - memcpy(buffer, str, 1024); - str += 1024; - buffer_insert_index = 1024; - } - if (buffer_insert_index + strlen(str) > 1024) flush_buffer(); - memcpy(buffer + buffer_insert_index, str, strlen(str)); - buffer_insert_index += strlen(str); - if (buffer_insert_index == 1024) flush_buffer(); - }; - - auto append_char = [&](char c) { - buffer[buffer_insert_index++] = c; - if (buffer_insert_index == 1024) flush_buffer(); - }; - - bool is_long = false; - bool is_unsigned_long = false; - - bool preserve_format = false; - - while (format_index < format_size) - { - char current_char = format[format_index]; - if (current_char == '%' || preserve_format) - { - if (!preserve_format && format_index + 1 == format_size) // end of format string - { - format_index++; - continue; - } - else - { - if (!preserve_format) format_index++; - preserve_format = false; - current_char = format[format_index]; - switch (current_char) - { - case 'c': { - append_char((char)va_arg(ap, int)); - break; - } - case '%': { - append_char('%'); - break; - } - case 'z': { - is_unsigned_long = true; - preserve_format = true; - break; - } - case 'l': { - is_long = true; - preserve_format = true; - break; - } - case 'i': - case 'd': { - char result[32]; - if (is_unsigned_long) - { - printf_unsigned_to_string(va_arg(ap, uint64_t), result, 10); - is_unsigned_long = is_long = false; - } - else if (is_long) - { - printf_signed_to_string(va_arg(ap, int64_t), result, 10); - is_unsigned_long = is_long = false; - } - else { printf_signed_to_string(va_arg(ap, int32_t), result, 10); } - append_string(result); - break; - } - case 'u': { - char result[32]; - if (is_unsigned_long || is_long) - { - printf_unsigned_to_string(va_arg(ap, uint64_t), result, 10); - is_unsigned_long = is_long = false; - } - else { printf_unsigned_to_string(va_arg(ap, uint32_t), result, 10); } - append_string(result); - break; - } - case 'x': { - char result[32]; - if (is_unsigned_long || is_long) - { - printf_unsigned_to_string(va_arg(ap, uint64_t), result, 16); - is_unsigned_long = is_long = false; - } - else { printf_unsigned_to_string(va_arg(ap, uint32_t), result, 16); } - append_string(result); - break; - } - case 'p': { - char result[32]; - printf_unsigned_to_string(va_arg(ap, uint64_t), result, 16); - append_string(result); - break; - } - case 'm': { - append_string(strerror(errno)); - break; - } - case 's': { - append_string(va_arg(ap, const char*)); - break; - } - default: { - fputs("printf: unknown format specifier ", stderr); - fputc('%', stderr); - fputc(current_char, stderr); - fputc('\n', stderr); - abort(); - } - } - } - } - else { append_char(current_char); } - format_index++; - } - - if (buffer_insert_index > 0) flush_buffer(); - return (int)written; -} - -#pragma GCC pop_options - -extern "C" -{ - int vprintf(const char* format, va_list ap) - { - return vfprintf(stdout, format, ap); - } - - int vsprintf(char* str, const char* format, va_list ap) - { - if (str) *str = 0; // so strncat starts from the beginning - return internal_printf( - format, - [&](const char* s) { - if (str) strncat(str, s, 1025); - }, - -1, ap); - } - - int vsnprintf(char* str, size_t max, const char* format, va_list ap) - { - if (max && str) *str = 0; // so strncat starts from the beginning - return internal_printf( - format, - [&](const char* s) { - if (str) strncat(str, s, 1025); - }, - max == 0 ? 0 : max - 1, ap); - } - - int snprintf(char* str, size_t max, const char* format, ...) - { - va_list ap; - va_start(ap, format); - int written = vsnprintf(str, max, format, ap); - va_end(ap); - return written; - } - - int sprintf(char* str, const char* format, ...) - { - va_list ap; - va_start(ap, format); - int written = vsprintf(str, format, ap); - va_end(ap); - return written; - } - - int printf(const char* format, ...) - { - va_list ap; - va_start(ap, format); - int written = vfprintf(stdout, format, ap); - va_end(ap); - return written; - } - - int fprintf(FILE* stream, const char* format, ...) - { - va_list ap; - va_start(ap, format); - int written = vfprintf(stream, format, ap); - va_end(ap); - return written; - } - - int vfprintf(FILE* stream, const char* format, va_list ap) - { - return internal_printf( - format, [&](const char* s) { fwrite(s, strlen(s), 1, stream); }, -1, ap); - } -} \ No newline at end of file diff --git a/libs/libc/src/pwd.cpp b/libs/libc/src/pwd.cpp deleted file mode 100644 index e33493fb..00000000 --- a/libs/libc/src/pwd.cpp +++ /dev/null @@ -1,196 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -static FILE* pwd_file = nullptr; -static FILE* pwnam_file = nullptr; -static FILE* pwuid_file = nullptr; - -static int initialize_pwd(FILE** stream) -{ - int pwfd = open("/etc/passwd", O_RDONLY | O_CLOEXEC); - if (pwfd < 0) return 0; - FILE* file = fdopen(pwfd, "r"); - if (!file) return 0; - *stream = file; - return 1; -} - -static int pwd_unbuffered_fgetc(FILE* stream) -{ - char c; - fread(&c, 1, 1, stream); - if (ferror(stream) || feof(stream)) return EOF; - return (int)c; -} - -static char* pwd_unbuffered_fgets(char* buf, size_t size, FILE* stream) -{ - char* s = buf; - memset(buf, 0, size); - while (size) - { - int c = pwd_unbuffered_fgetc(stream); - if (c == EOF) - { - if (ferror(stream)) return NULL; - if (feof(stream)) - { - if (s != buf) return s; - else - return NULL; - }; - } - size--; - *buf = (char)c; - buf++; - *buf = 0; - if ((char)c == '\n') return s; - } - return s; -} - -static char* pwd_strchrtok(char* s, char delim) -{ - static char* saved = nullptr; - if (s) saved = s; - else - s = saved; - if (!saved) return nullptr; - char* loc = strchr(saved, delim); - if (loc) - { - saved = loc + 1; - if (*saved == 0) saved = nullptr; - *loc = 0; - } - else { saved = nullptr; } - return s; -} - -static void pwd_strip_newline(char* buf) -{ - size_t len = strlen(buf); - if (buf[len - 1] == '\n') buf[len - 1] = 0; -} - -static struct passwd* internal_getpwent(FILE* stream) -{ -#define PWENT_INVALID \ - do { \ - errno = EINVAL; \ - return NULL; \ - } while (0) - - static struct passwd result; - static char buf[BUFSIZ]; - - if (!pwd_unbuffered_fgets(buf, BUFSIZ, stream)) return NULL; - pwd_strip_newline(buf); - result.pw_name = pwd_strchrtok(buf, ':'); - if (!result.pw_name) PWENT_INVALID; - result.pw_passwd = pwd_strchrtok(NULL, ':'); - if (!result.pw_passwd) PWENT_INVALID; - char* uid_string = pwd_strchrtok(NULL, ':'); - if (!uid_string) PWENT_INVALID; - result.pw_uid = atoi(uid_string); - char* gid_string = pwd_strchrtok(NULL, ':'); - if (!gid_string) PWENT_INVALID; - result.pw_gid = atoi(gid_string); - result.pw_gecos = pwd_strchrtok(NULL, ':'); - if (!result.pw_gecos) PWENT_INVALID; - result.pw_dir = pwd_strchrtok(NULL, ':'); - if (!result.pw_dir) PWENT_INVALID; - result.pw_shell = pwd_strchrtok(NULL, ':'); - if (!result.pw_shell) PWENT_INVALID; - return &result; -} - -extern "C" -{ - struct passwd* getpwent() - { - if (!pwd_file) - { - if (!initialize_pwd(&pwd_file)) return NULL; - } - if (feof(pwd_file)) - { - endpwent(); - return NULL; - } - return internal_getpwent(pwd_file); - } - - struct passwd* getpwnam(const char* name) - { - if (!pwnam_file) - { - if (!initialize_pwd(&pwnam_file)) return NULL; - } - else - rewind(pwnam_file); - struct passwd* pwd = internal_getpwent(pwnam_file); - while (pwd) - { - if (strcmp(pwd->pw_name, name) == 0) break; - if (feof(pwnam_file)) - { - pwd = nullptr; - break; - } - pwd = internal_getpwent(pwnam_file); - } - return pwd; // if we matched one, pwd contains a pointer to it. else it is NULL - } - - struct passwd* getpwuid(uid_t uid) - { - if (!pwuid_file) - { - if (!initialize_pwd(&pwuid_file)) return NULL; - } - else - rewind(pwuid_file); - struct passwd* pwd = internal_getpwent(pwuid_file); - while (pwd) - { - if (pwd->pw_uid == uid) break; - if (feof(pwuid_file)) - { - pwd = nullptr; - break; - } - pwd = internal_getpwent(pwuid_file); - } - return pwd; // if we matched one, pwd contains a pointer to it. else it is NULL - } - - void setpwent() - { - if (pwd_file) rewind(pwd_file); - } - - void endpwent() - { - if (pwd_file) - { - fclose(pwd_file); - pwd_file = nullptr; - } - if (pwuid_file) - { - fclose(pwuid_file); - pwuid_file = nullptr; - } - if (pwnam_file) - { - fclose(pwnam_file); - pwnam_file = nullptr; - } - } -} \ No newline at end of file diff --git a/libs/libc/src/rand.cpp b/libs/libc/src/rand.cpp deleted file mode 100644 index 8398928d..00000000 --- a/libs/libc/src/rand.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include -#include -#include -#include - -typedef uint32_t word_t; -#define STATE_SIZE 624 -#define MIDDLE 397 -#define INIT_SHIFT 30 -#define INIT_FACT 1812433253 -#define TWIST_MASK 0x9908b0df -#define SHIFT1 11 -#define MASK1 0xffffffff -#define SHIFT2 7 -#define MASK2 0x9d2c5680 -#define SHIFT3 15 -#define MASK3 0xefc60000 -#define SHIFT4 18 - -#define LOWER_MASK 0x7fffffff -#define UPPER_MASK (~(word_t)LOWER_MASK) - -static word_t state[STATE_SIZE]; -static size_t index = STATE_SIZE + 1; - -static void twist() -{ - for (size_t i = 0; i < STATE_SIZE; i++) - { - word_t x = (state[i] & UPPER_MASK) | (state[(i + 1) % STATE_SIZE] & LOWER_MASK); - x = (x >> 1) ^ (x & 1 ? TWIST_MASK : 0); - state[i] = state[(i + MIDDLE) % STATE_SIZE] ^ x; - } - index = 0; -} - -extern "C" -{ - int rand() - { - if (index >= STATE_SIZE) - { - assert(index == STATE_SIZE && "Mersenne generator was never seeded"); - twist(); - } - - word_t y = state[index]; - y ^= (y >> SHIFT1) & MASK1; - y ^= (y << SHIFT2) & MASK2; - y ^= (y << SHIFT3) & MASK3; - y ^= y >> SHIFT4; - - index++; - return y; - } - - void srand(unsigned int seed) - { - index = STATE_SIZE; - state[0] = seed; - for (size_t i = 1; i < STATE_SIZE; i++) - state[i] = (word_t)((INIT_FACT * (state[i - 1] ^ (state[i - 1] >> INIT_SHIFT))) + i); - } -} \ No newline at end of file diff --git a/libs/libc/src/sched.cpp b/libs/libc/src/sched.cpp deleted file mode 100644 index 917b17d6..00000000 --- a/libs/libc/src/sched.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include -#include -#include - -extern "C" -{ - int sched_yield() - { - return (int)__lc_fast_syscall0(SYS_yield); - } -} \ No newline at end of file diff --git a/libs/libc/src/setjmp.asm b/libs/libc/src/setjmp.asm deleted file mode 100644 index 21526397..00000000 --- a/libs/libc/src/setjmp.asm +++ /dev/null @@ -1,36 +0,0 @@ -global _setjmp -global setjmp -_setjmp: -setjmp: - mov rsi, 0 - mov [rdi], rbx - mov [rdi+8], r12 - mov [rdi+16], r13 - mov [rdi+24], r14 - mov [rdi+32], r15 - mov [rdi+40], rbp - mov [rdi+48], rsp - mov rax, [rsp] - mov [rdi+56], rax - xor rax, rax - ret - -global _longjmp -global longjmp -_longjmp: -longjmp: - mov rax, rsi - cmp rax, 0 - jne .nonzero - mov rax, 1 -.nonzero: - mov rbx, [rdi] - mov r12, [rdi+8] - mov r13, [rdi+16] - mov r14, [rdi+24] - mov r15, [rdi+32] - mov rbp, [rdi+40] - mov rsp, [rdi+48] - mov rcx, [rdi+56] - mov [rsp], rcx - ret \ No newline at end of file diff --git a/libs/libc/src/setjmp.cpp b/libs/libc/src/setjmp.cpp deleted file mode 100644 index d7d0e226..00000000 --- a/libs/libc/src/setjmp.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include -#include - -extern "C" -{ - int sigsetjmp(sigjmp_buf env, int) - { - return setjmp(env); - } - - __lc_noreturn void siglongjmp(sigjmp_buf env, int val) - { - longjmp(env, val); - } -} \ No newline at end of file diff --git a/libs/libc/src/signal.cpp b/libs/libc/src/signal.cpp deleted file mode 100644 index a82b3f9d..00000000 --- a/libs/libc/src/signal.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include -#include - -extern "C" -{ - void (*signal(int, void (*)(int)))(int) - { - NOT_IMPLEMENTED("signal"); - } - - int raise(int) - { - NOT_IMPLEMENTED("raise"); - } -} \ No newline at end of file diff --git a/libs/libc/src/stdio.cpp b/libs/libc/src/stdio.cpp deleted file mode 100644 index 1d6a0542..00000000 --- a/libs/libc/src/stdio.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -extern "C" -{ - int puts(const char* s) - { - int nwritten = fputs(s, stdout); - if (nwritten < 0) return -1; - if (putchar('\n') < 0) return -1; - return nwritten + 1; - } - - int fputs(const char* s, FILE* stream) - { - int result = (int)fwrite(s, strlen(s), 1, stream); - if (ferror(stream)) return -1; - return result; - } - - int fputc(int c, FILE* stream) - { - char chr = (char)c; - fwrite(&chr, 1, 1, stream); - if (ferror(stream)) { return -1; } - return c; - } - - int putc(int c, FILE* stream) - { - return fputc(c, stream); - } - - int putchar(int c) - { - return fputc(c, stdout); - } - - void perror(const char* s) - { - int savederr = - errno; // This was necessary before, but even more now since we clear errno on successful syscalls now. - if (s && *s) { fprintf(stderr, "%s: ", s); } - fprintf(stderr, "%s\n", strerror(savederr)); - } - - int remove(const char*) - { - NOT_IMPLEMENTED("remove"); - } - - int sscanf(const char*, const char*, ...) - { - NOT_IMPLEMENTED("sscanf"); - } - - int fscanf(FILE*, const char*, ...) - { - NOT_IMPLEMENTED("fscanf"); - } - - int scanf(const char*, ...) - { - NOT_IMPLEMENTED("scanf"); - } - - int rename(const char*, const char*) - { - NOT_IMPLEMENTED("rename"); - } - - FILE* tmpfile() - { - errno = ENOTSUP; - return NULL; - } -} \ No newline at end of file diff --git a/libs/libc/src/stdlib.cpp b/libs/libc/src/stdlib.cpp deleted file mode 100644 index 012f8c27..00000000 --- a/libs/libc/src/stdlib.cpp +++ /dev/null @@ -1,311 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -template static T string_to_integer_type(const char* str) -{ - bool neg = false; - T val = 0; - - switch (*str) - { - case '-': - neg = true; - str++; - break; - case '+': str++; break; - default: break; - } - - while (isdigit(*str)) { val = (10 * val) + (*str++ - '0'); } - - return (neg ? -val : val); -} - -template static T string_to_float_type(const char* str) -{ - bool neg = false; - T val = 0; - - T small = 0; - - switch (*str) - { - case '-': - neg = true; - str++; - break; - case '+': str++; break; - default: break; - } - - while (isdigit(*str)) { val = (10 * val) + (T)(*str++ - '0'); } - if (*str == '.') - { - str++; - T div = 10; - while (isdigit(*str)) - { - small = small + (T)(*str++ - '0') / div; - div *= 10; - } - - val += small; - } - - return (neg ? -val : val); -} - -template static inline Struct common_div(Arg a, Arg b) -{ - Struct result; - result.quot = a / b; - result.rem = a % b; - - if (a >= 0 && result.rem < 0) - { - result.quot++; - result.rem -= b; - } - - return result; -} - -static void qswap(void* ptr1, void* ptr2, size_t size) -{ - char* x = (char*)ptr1; - char* y = (char*)ptr2; - - while (size--) - { - char t = *x; - *x = *y; - *y = t; - x += 1; - y += 1; - } -} - -static size_t partition(void* base, size_t start, size_t end, size_t size, int (*compar)(const void*, const void*)) -{ - auto atindex = [&base, &size](size_t index) { return (void*)((char*)base + (index * size)); }; - - void* pivot = atindex(end); - size_t i = (start - 1); - - for (size_t j = start; j <= end - 1; j++) - { - if (compar(atindex(j), pivot) < 0) - { - i++; - qswap(atindex(i), atindex(j), size); - } - } - - qswap(atindex(i + 1), pivot, size); - return i + 1; -} - -static void quicksort(void* base, size_t start, size_t end, size_t size, int (*compar)(const void*, const void*)) -{ - if (start < end) - { - size_t pivot = partition(base, start, end, size, compar); - quicksort(base, start, pivot - 1, size, compar); - quicksort(base, pivot + 1, end, size, compar); - } -} - -void* binary_search(const void* key, const void* base, size_t start, size_t end, size_t size, - int (*compar)(const void*, const void*)) -{ - auto atindex = [&base, &size](size_t index) { return (const void*)((const char*)base + (index * size)); }; - - if (end >= start) - { - size_t middle = start + (end - start) / 2; - int rc = compar(atindex(middle), key); - - if (rc == 0) return const_cast(atindex(middle)); // we found it!! - - if (rc < 0) return binary_search(key, base, middle + 1, end, size, compar); - - return binary_search(key, base, start, middle - 1, size, compar); - } - - return NULL; -} - -extern "C" -{ - __lc_noreturn void abort() - { - _Exit(-1); - } - - float atof(const char* str) - { - return string_to_float_type(str); - } - - int atoi(const char* str) - { - return string_to_integer_type(str); - } - - long atol(const char* str) - { - return string_to_integer_type(str); - } - - long long atoll(const char* str) - { - return string_to_integer_type(str); - } - - unsigned long strtoul(const char* str, char** endptr, int base) - { - if (base != 0 && base != 10) NOT_IMPLEMENTED("strtoul with base not in (0,10)"); - if (endptr) NOT_IMPLEMENTED("strtoul with non-null endptr"); - return string_to_integer_type(str); - } - - long strtol(const char* str, char** endptr, int base) - { - if (base != 0 && base != 10) NOT_IMPLEMENTED("strtol with base not in (0,10)"); - if (endptr) NOT_IMPLEMENTED("strtol with non-null endptr"); - return string_to_integer_type(str); - } - - char* getenv(const char*) - { - return NULL; // FIXME: Not implemented :) - } - - __lc_noreturn void _Exit(int status) - { - __lc_fast_syscall1(SYS_exit, status); - __lc_unreachable(); - } - - int abs(int val) - { - return __builtin_abs(val); - } - - long labs(long val) - { - return __builtin_labs(val); - } - - long long llabs(long long val) - { - return __builtin_llabs(val); - } - - div_t div(int a, int b) - { - return common_div(a, b); - } - - ldiv_t ldiv(long a, long b) - { - return common_div(a, b); - } - - lldiv_t lldiv(long long a, long long b) - { - return common_div(a, b); - } - - int system(const char* command) - { - pid_t child = fork(); - if (child < 0) return -1; - if (child == 0) - { - char* argv[] = {const_cast("/bin/sh"), const_cast("-c"), const_cast(command), - nullptr}; // FIXME: This is very verbose. - execv(argv[0], argv); - exit(127); - } - int status; - waitpid(child, &status, 0); - return status; - } - - void qsort(void* base, size_t nmemb, size_t size, int (*compar)(const void*, const void*)) - { - quicksort(base, 0, nmemb - 1, size, compar); - } - - void* bsearch(const void* key, const void* base, size_t nmemb, size_t size, int (*compar)(const void*, const void*)) - { - return binary_search(key, base, 0, nmemb - 1, size, compar); - } - - size_t mbstowcs(wchar_t*, const char*, size_t) - { - NOT_IMPLEMENTED("mbstowcs"); - } - - static void gentemp(char* startptr) - { - for (int i = 0; i < 6; i++) - { - startptr[i] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"[rand() % 63]; - } - } - - char* mktemp(char* str) - { - size_t len = strlen(str); - if (len < 6) - { - errno = EINVAL; - return NULL; - } - char* startptr = str + (len - 6); - if (strncmp(startptr, "XXXXXX", 6)) - { - errno = EINVAL; - return NULL; - } - do { - gentemp(startptr); - } while (access(str, F_OK) == 0); - return str; - } - - char* mkdtemp(char* str) - { - size_t len = strlen(str); - if (len < 6) - { - errno = EINVAL; - return NULL; - } - char* startptr = str + (len - 6); - if (strncmp(startptr, "XXXXXX", 6)) - { - errno = EINVAL; - return NULL; - } - do { - gentemp(startptr); - } while (mkdir(str, 0700) < 0 && errno == EEXIST); - if (errno) return NULL; - return str; - } - - double strtod(const char*, char**) - { - NOT_IMPLEMENTED("strtod"); - } -} \ No newline at end of file diff --git a/libs/libc/src/strftime.cpp b/libs/libc/src/strftime.cpp deleted file mode 100644 index d185f5bf..00000000 --- a/libs/libc/src/strftime.cpp +++ /dev/null @@ -1,318 +0,0 @@ -#include -#include -#include -#include -#include - -static void printf_strrev(char* arr, int size) -{ - int left = 0; - int right = size - 1; - for (int i = left; i < right; i++) - { - char temp = arr[i]; - arr[i] = arr[right]; - arr[right] = temp; - right--; - } -} - -template static char* printf_unsigned_to_string(IntegerType number, char* arr, int base) -{ - int i = 0; - - if (number == 0) - { - arr[i] = '0'; - arr[i + 1] = '\0'; - return arr; - } - - while (number != 0) - { - IntegerType r = number % (IntegerType)base; - arr[i] = (char)((r > 9) ? (r - 10) + 'a' : r + '0'); - i++; - number /= base; - } - - printf_strrev(arr, i); - - arr[i] = '\0'; - - return arr; -} - -template static char* printf_signed_to_string(IntegerType number, char* arr, int base) -{ - int i = 0, negative = 0; - - if (number == 0) - { - arr[i] = '0'; - arr[i + 1] = '\0'; - return arr; - } - - if (number < 0 && base == 10) - { - number *= -1; - negative = 1; - } - - while (number != 0) - { - IntegerType r = number % base; - arr[i] = (char)((r > 9) ? (r - 10) + 'a' : r + '0'); - i++; - number /= base; - } - - if (negative) - { - arr[i] = '-'; - i++; - } - - printf_strrev(arr, i); - - arr[i] = '\0'; - - return arr; -} - -const char* short_week_days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; -const char* long_week_days[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; -const char* short_month_names[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; -const char* long_month_names[] = {"January", "February", "March", "April", "May", "June", - "July", "August", "September", "October", "November", "December"}; - -extern "C" size_t strftime(char* s, size_t max, const char* format, const struct tm* time) -{ - char buffer[1025]; // 1024 with null terminator - size_t format_size = strlen(format); - size_t format_index = 0; - size_t buffer_insert_index = 0; - ssize_t max_remaining = (ssize_t)max; - size_t written = 0; - - if (s && max) *s = 0; - - auto flush_buffer = [&]() { - size_t buffer_length = buffer_insert_index; - written += buffer_length; - buffer_insert_index = 0; - if (max_remaining < 0) - { - buffer[buffer_length] = 0; - if (s) strncat(s, buffer, sizeof(buffer)); - return; - } - if (max_remaining == 0) { return; } - if (buffer_length <= (size_t)max_remaining) - { - max_remaining -= buffer_length; - buffer[buffer_length] = 0; - if (s) strncat(s, buffer, sizeof(buffer)); - } - else - { - buffer[max_remaining] = 0; - max_remaining = 0; - if (s) strncat(s, buffer, sizeof(buffer)); - } - }; - - auto append_string = [&](const char* str) { - while (strlen(str) > 1024) - { - flush_buffer(); - memcpy(buffer, str, 1024); - str += 1024; - buffer_insert_index = 1024; - } - if (buffer_insert_index + strlen(str) > 1024) flush_buffer(); - memcpy(buffer + buffer_insert_index, str, strlen(str)); - buffer_insert_index += strlen(str); - if (buffer_insert_index == 1024) flush_buffer(); - }; - - auto append_char = [&](char c) { - buffer[buffer_insert_index++] = c; - if (buffer_insert_index == 1024) flush_buffer(); - }; - - while (format_index < format_size) - { - char current_char = format[format_index]; - if (current_char == '%') - { - if (format_index + 1 == format_size) // end of format string - { - format_index++; - continue; - } - else - { - format_index++; - current_char = format[format_index]; - switch (current_char) - { - case '%': { - append_char('%'); - break; - } - case 'a': { - append_string(short_week_days[time->tm_wday % 7]); - break; - } - case 'A': { - append_string(long_week_days[time->tm_wday % 7]); - break; - } - case 'b': { - append_string(short_month_names[(time->tm_mon - 1) % 12]); - break; - } - case 'B': { - append_string(long_month_names[(time->tm_mon - 1) % 12]); - break; - } - case 'c': { - char buf[32]; - append_string(short_week_days[time->tm_wday % 7]); - append_char(' '); - append_string(short_month_names[(time->tm_mon - 1) % 12]); - append_char(' '); - printf_signed_to_string(time->tm_mday, buf, 10); - append_string(buf); - append_char(' '); - printf_signed_to_string(time->tm_hour % 24, buf, 10); - append_string(buf); - append_char(':'); - printf_signed_to_string(time->tm_min % 60, buf, 10); - append_string(buf); - append_char(':'); - printf_signed_to_string(time->tm_sec % 60, buf, 10); - append_string(buf); - append_char(' '); - printf_signed_to_string(time->tm_year + 1900, buf, 10); - append_string(buf); - break; - } - case 'd': { - char buf[30]; - printf_signed_to_string(time->tm_mday % 32, buf, 10); - append_string(buf); - break; - } - case 'H': { - char buf[30]; - printf_signed_to_string(time->tm_hour % 24, buf, 10); - append_string(buf); - break; - } - case 'I': { - char buf[30]; - int hour = time->tm_hour % 12; - if (hour == 0) hour = 12; - printf_signed_to_string(hour, buf, 10); - append_string(buf); - break; - } - case 'j': { - char buf[30]; - printf_signed_to_string(time->tm_yday % 367, buf, 10); - append_string(buf); - break; - } - case 'm': { - char buf[30]; - printf_signed_to_string(time->tm_mon % 13, buf, 10); - append_string(buf); - break; - } - case 'M': { - char buf[30]; - printf_signed_to_string(time->tm_min % 60, buf, 10); - append_string(buf); - break; - } - case 'p': { - if (time->tm_hour < 12) append_string("AM"); - else - append_string("PM"); - break; - } - case 'P': { - if (time->tm_hour < 12) append_string("am"); - else - append_string("pm"); - break; - } - case 'S': { - char buf[30]; - printf_signed_to_string(time->tm_sec % 61, buf, 10); - append_string(buf); - break; - } - case 'w': { - char buf[30]; - printf_signed_to_string(time->tm_wday % 7, buf, 10); - append_string(buf); - break; - } - case 'x': { - char buf[30]; - printf_signed_to_string(time->tm_mon % 13, buf, 10); - append_string(buf); - append_char('/'); - printf_signed_to_string(time->tm_mday % 32, buf, 10); - append_string(buf); - append_char('/'); - printf_signed_to_string((time->tm_year + 1900) % 100, buf, 10); - append_string(buf); - break; - } - case 'X': { - char buf[30]; - printf_signed_to_string(time->tm_hour % 24, buf, 10); - append_string(buf); - append_char(':'); - printf_signed_to_string(time->tm_min % 60, buf, 10); - append_string(buf); - append_char(':'); - printf_signed_to_string(time->tm_sec % 60, buf, 10); - append_string(buf); - break; - } - case 'y': { - char buf[30]; - printf_signed_to_string((time->tm_year + 1900) % 100, buf, 10); - append_string(buf); - break; - } - case 'Y': { - char buf[30]; - printf_signed_to_string(time->tm_year + 1900, buf, 10); - append_string(buf); - break; - } - case 'Z': { - append_string("UTC"); // FIXME: Add timezone support. - break; - } - default: { - fprintf(stderr, "strftime: unknown format specifier %%%c\n", current_char); - abort(); - } - } - } - } - else { append_char(current_char); } - format_index++; - } - - if (buffer_insert_index > 0) flush_buffer(); - return written; -} \ No newline at end of file diff --git a/libs/libc/src/string.cpp b/libs/libc/src/string.cpp deleted file mode 100644 index 44184d4f..00000000 --- a/libs/libc/src/string.cpp +++ /dev/null @@ -1,311 +0,0 @@ -#include -#include -#include -#include - -extern "C" -{ - void* memcpy(void* dest, const void* src, size_t n) - { - for (size_t i = 0; i < n; ++i) { *((char*)dest + i) = *((const char*)src + i); } - return dest; - } - - void* memset(void* buf, int c, size_t n) - { - for (size_t i = 0; i < n; ++i) { *((char*)buf + i) = (char)c; } - return buf; - } - - void* memchr(const void* buf, int c, size_t n) - { - const char* s = (const char*)buf; - for (; n && *s != (char)c; s++, n--) - ; - if (n) return (void*)(const_cast(s)); - return NULL; - } - - int memcmp(const void* a, const void* b, size_t n) - { - if (!n) return 0; - const unsigned char* ap = (const unsigned char*)a; - const unsigned char* bp = (const unsigned char*)b; - while (--n && *ap == *bp) - { - ap++; - bp++; - } - return *ap - *bp; - } - - void* memmove(void* dest, const void* src, size_t n) - { - if (dest == src) return dest; - if (dest > src) - for (long i = n - 1; i >= 0; i++) { *((char*)dest + i) = *((const char*)src + i); } - else - for (long i = 0; i < (long)n; i++) { *((char*)dest + i) = *((const char*)src + i); } - return dest; - } - - char* strdup(const char* str) - { - size_t len = strlen(str); - char* dest = (char*)malloc(len + 1); - if (!dest) return dest; - return (char*)memcpy(dest, str, len + 1); - } - - char* strndup(const char* str, size_t max) - { - size_t len = strnlen(str, max); - char* dest = (char*)malloc(len + 1); - if (!dest) return dest; - memcpy(dest, str, len); - dest[len] = 0; - return dest; - } - - size_t strlen(const char* str) - { - const char* i = str; - for (; *i; ++i) - ; - return (i - str); - } - - size_t strnlen(const char* str, size_t max) - { - char* p = (char*)memchr(str, 0, max); - return p ? p - str : max; - } - - char* strcpy(char* dest, const char* src) - { - return (char*)memcpy(dest, src, strlen(src) + 1); - } - - char* strncpy(char* dest, const char* src, size_t max) - { - size_t i; - for (i = 0; i < max && src[i] != 0; i++) dest[i] = src[i]; - for (; i < max; i++) dest[i] = 0; - return dest; - } - - size_t strlcpy(char* dest, const char* src, size_t size) - { - size_t len = strlen(src); - if (size == 0) return len; - if (len < (size - 1)) - { - memcpy(dest, src, len); - dest[len] = 0; - } - else - { - memcpy(dest, src, size - 1); - dest[size - 1] = 0; - } - return len; - } - - char* stpcpy(char* dest, const char* src) - { - size_t len = strlen(src); - size_t rc = strlcpy(dest, src, len + 1); - return dest + rc; - } - - int strcmp(const char* a, const char* b) - { - while (*a && (*a == *b)) - { - a++; - b++; - } - return *(const unsigned char*)a - *(const unsigned char*)b; - } - - int strncmp(const char* a, const char* b, size_t max) - { - const char* base = a; - while (*a && (*a == *b) && (size_t)(a - base) < (max - 1)) - { - a++; - b++; - } - return *(const unsigned char*)a - *(const unsigned char*)b; - } - - int strcoll(const char* a, const char* b) - { - return strcmp(a, b); - } - - size_t strxfrm(char* dest, const char* src, size_t n) - { - strncpy(dest, src, n); - return n; - } - - size_t strcspn(const char* str, const char* reject) - { - const char* s = str; - while (*s) - { - const char* rp = reject; - while (*rp) - { - if (*s == *rp) return s - str; - rp++; - } - s++; - } - return s - str; - } - - size_t strspn(const char* str, const char* accept) - { - const char* s = str; - while (*s) - { - const char* ap = accept; - bool match = false; - while (*ap) - { - if (*s == *ap) - { - match = true; - break; - } - ap++; - } - if (!match) return s - str; - s++; - } - return s - str; - } - - char* strpbrk(const char* a, const char* b) - { - while (*a) - { - if (strchr(b, *a)) return const_cast(a); - a++; - } - return NULL; - } - - char* strcat(char* dest, const char* src) - { - size_t dest_len = strlen(dest); - size_t i; - - for (i = 0; *(src + i); i++) *(dest + dest_len + i) = *(src + i); - - *(dest + dest_len + i) = '\0'; - - return dest; - } - - char* strncat(char* dest, const char* src, size_t max) - { - size_t dest_len = strlen(dest); - size_t i; - - for (i = 0; i < max && *(src + i); i++) *(dest + dest_len + i) = *(src + i); - - *(dest + dest_len + i) = '\0'; - - return dest; - } - - char* strchr(const char* str, int c) - { - while (*str && *str != (char)c) str++; - if (*str) return const_cast(str); - return NULL; - } - - char* strchrnul(const char* str, int c) - { - while (*str && *str != (char)c) str++; - return const_cast(str); - } - - char* strrchr(const char* str, int c) - { - const char* s = str + strlen(str); - while (s != str && *s != (char)c) s--; - if (s != str) return const_cast(s); - if (*s == (char)c) return const_cast(s); - return NULL; - } - - char* strstr(const char* haystack, const char* needle) - { - size_t needle_size = strlen(needle); - size_t haystack_size = strlen(haystack); - while (*haystack) - { - if (*haystack == *needle) - { - if (needle_size <= haystack_size) - { - if (!strncmp(haystack, needle, needle_size)) return const_cast(haystack); - } - else { return NULL; } - } - haystack++; - haystack_size--; - } - return NULL; - } - -#pragma GCC push_options -#pragma GCC diagnostic ignored "-Wwrite-strings" - - char* strerror(int err) - { - switch (err) - { - case EPERM: return "Operation not permitted"; - case ENOENT: return "No such file or directory"; - case ESRCH: return "No such process"; - case EINTR: return "Interrupted system call"; - case EIO: return "Input/output error"; - case E2BIG: return "Argument list too long"; - case ENOEXEC: return "Exec format error"; - case EBADF: return "Bad file descriptor"; - case ECHILD: return "No child processes"; - case EAGAIN: return "Resource temporarily unavailable"; - case ENOMEM: return "Cannot allocate memory"; - case EACCES: return "Permission denied"; - case EFAULT: return "Bad address"; - case EEXIST: return "File exists"; - case ENOTDIR: return "Not a directory"; - case EISDIR: return "Is a directory"; - case EINVAL: return "Invalid argument"; - case EMFILE: return "Too many open files"; - case ENOTTY: return "Inappropriate ioctl for device"; - case EFBIG: return "File too large"; - case ENOSPC: return "No space left on device"; - case EPIPE: return "Broken pipe"; - case EDOM: return "Numerical argument out of domain"; - case ERANGE: return "Numerical result out of range"; - case ENOSYS: return "Function not implemented"; - case ENOTSUP: return "Operation not supported"; - case 0: return "Success"; - default: return "Unknown error"; - } - } - -#pragma GCC pop_options - - char* strtok(char*, const char*) - { - NOT_IMPLEMENTED("strtok"); - } -} \ No newline at end of file diff --git a/libs/libc/src/strings.cpp b/libs/libc/src/strings.cpp deleted file mode 100644 index b8f436e5..00000000 --- a/libs/libc/src/strings.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include -#include -#include - -static char lowercase(char c) -{ - if (isalpha(c)) return (char)tolower(c); - return c; -} - -extern "C" -{ - void bzero(void* buf, size_t n) - { - memset(buf, 0, n); - } - - void bcopy(void* dest, const void* src, size_t n) - { - memcpy(dest, src, n); - } - - int strcasecmp(const char* a, const char* b) - { - while (*a && (lowercase(*a) == lowercase(*b))) - { - a++; - b++; - } - return (unsigned char)lowercase(*a) - (unsigned char)lowercase(*b); - } - - int strncasecmp(const char* a, const char* b, size_t max) - { - const char* base = a; - while (*a && (lowercase(*a) == lowercase(*b)) && (size_t)(a - base) < (max - 1)) - { - a++; - b++; - } - return (unsigned char)lowercase(*a) - (unsigned char)lowercase(*b); - } -} \ No newline at end of file diff --git a/libs/libc/src/sys/ioctl.cpp b/libs/libc/src/sys/ioctl.cpp deleted file mode 100644 index 053fb7e6..00000000 --- a/libs/libc/src/sys/ioctl.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include -#include -#include -#include -#include - -extern "C" -{ - int ioctl(int fd, int cmd, ...) - { - va_list ap; - va_start(ap, cmd); - long result = __lc_fast_syscall3(SYS_ioctl, fd, cmd, va_arg(ap, uintptr_t)); - va_end(ap); - return (int)result; - } -} \ No newline at end of file diff --git a/libs/libc/src/sys/mman.cpp b/libs/libc/src/sys/mman.cpp deleted file mode 100644 index 3a5b6b1a..00000000 --- a/libs/libc/src/sys/mman.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include -#include - -extern "C" -{ - // FIXME: Implement a POSIX-compliant mmap. - void* mmap(void* addr, size_t len, int prot, int flags, int fd, off_t offset) - { - long result = __luna_syscall5(SYS_mmap, (sysarg_t)addr, (sysarg_t)len, (sysarg_t)prot, - flags & MAP_ANONYMOUS ? (sysarg_t)-1 : (sysarg_t)fd, (sysarg_t)offset); - _RETURN_WITH_MEMORY_ERRNO(result, void*); - } - - int munmap(void* addr, size_t len) - { - return (int)__lc_fast_syscall2(SYS_munmap, addr, len); - } - - int mprotect(void* addr, size_t size, int prot) - { - return (int)__lc_fast_syscall3(SYS_mprotect, addr, size, prot); - } -} \ No newline at end of file diff --git a/libs/libc/src/sys/stat.cpp b/libs/libc/src/sys/stat.cpp deleted file mode 100644 index f2820101..00000000 --- a/libs/libc/src/sys/stat.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include -#include -#include - -extern "C" -{ - int mkdir(const char* pathname, mode_t mode) - { - return (int)__lc_fast_syscall2(SYS_mkdir, pathname, mode); - } - - int fstat(int fd, struct stat* buf) - { - return (int)__lc_fast_syscall2(SYS_fstat, fd, buf); - } - - int stat(const char* path, struct stat* buf) - { - return (int)__lc_fast_syscall2(SYS_stat, path, buf); - } - - mode_t umask(mode_t cmask) - { - return (mode_t)__lc_fast_syscall1(SYS_umask, cmask); - } - - int chmod(const char*, mode_t) - { - NOT_IMPLEMENTED("chmod"); - } - - int fchmod(int, mode_t) - { - NOT_IMPLEMENTED("fchmod"); - } -} \ No newline at end of file diff --git a/libs/libc/src/sys/wait.cpp b/libs/libc/src/sys/wait.cpp deleted file mode 100644 index ca9e524e..00000000 --- a/libs/libc/src/sys/wait.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include -#include -#include - -extern "C" -{ - pid_t waitpid(pid_t pid, int* wstatus, int options) - { - return __lc_fast_syscall3(SYS_waitpid, pid, wstatus, options); - } - - pid_t wait(int* wstatus) - { - return waitpid(-1, wstatus, 0); - } -} \ No newline at end of file diff --git a/libs/libc/src/syscall.cpp b/libs/libc/src/syscall.cpp deleted file mode 100644 index bad85517..00000000 --- a/libs/libc/src/syscall.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include -#include -#include -#include -#include - -extern "C" long syscall(long number, ...) -{ - typedef unsigned long arg; - long result; - va_list ap; - va_start(ap, number); - switch (number) - { - case SYS_yield: - case SYS_fork: result = __luna_syscall0(number); break; - case SYS_exit: - case SYS_getprocid: - case SYS_close: - case SYS_umask: - case SYS_setuid: - case SYS_setgid: - case SYS_seteuid: - case SYS_setegid: - case SYS_sleep: result = __luna_syscall1(number, va_arg(ap, arg)); break; - case SYS_munmap: - case SYS_execv: - case SYS_access: - case SYS_fstat: - case SYS_stat: - case SYS_mkdir: - case SYS_dup2: - case SYS_clock_gettime: - case SYS_pstat: { - arg arg0 = va_arg(ap, arg); - arg arg1 = va_arg(ap, arg); - result = __luna_syscall2(number, arg0, arg1); - break; - } - case SYS_open: - case SYS_getdents: - case SYS_fcntl: - case SYS_seek: - case SYS_write: - case SYS_read: - case SYS_ioctl: - case SYS_mprotect: - case SYS_waitpid: { - arg arg0 = va_arg(ap, arg); - arg arg1 = va_arg(ap, arg); - arg arg2 = va_arg(ap, arg); - result = __luna_syscall3(number, arg0, arg1, arg2); - break; - } - case SYS_mmap: { - arg arg0 = va_arg(ap, arg); - arg arg1 = va_arg(ap, arg); - arg arg2 = va_arg(ap, arg); - arg arg3 = va_arg(ap, arg); - arg arg4 = va_arg(ap, arg); - result = __luna_syscall5(number, arg0, arg1, arg2, arg3, arg4); - break; - } - default: result = -ENOSYS; break; - } - va_end(ap); - if (number == SYS_mmap) { _RETURN_WITH_MEMORY_ERRNO(result, long int); } - else { _RETURN_WITH_ERRNO(result, long); } -} \ No newline at end of file diff --git a/libs/libc/src/time.cpp b/libs/libc/src/time.cpp deleted file mode 100644 index f6516871..00000000 --- a/libs/libc/src/time.cpp +++ /dev/null @@ -1,183 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#define SECONDS_PER_DAY 86400 - -static int isleap(int year) -{ - return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); -} - -static int make_yday(int year, int month) -{ - static const short int upto[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; - int yd; - - yd = upto[month - 1]; - if (month > 2 && isleap(year)) yd++; - return yd; -} - -static int day_of_week(int year, int mon, int day) -{ - static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4}; - year -= mon < 3; - return (year + year / 4 - year / 100 + year / 400 + t[mon - 1] + day) % 7; -} - -static time_t broken_down_to_unix(time_t year, time_t yday, time_t hour, time_t min, time_t sec) -{ - return sec + min * 60 + hour * 3600 + yday * 86400 + (year - 70) * 31536000 + ((year - 69) / 4) * 86400 - - ((year - 1) / 100) * 86400 + ((year + 299) / 400) * 86400; -} - -static void time_to_struct_tm(time_t time, struct tm* result) -{ - result->tm_isdst = 0; // No DST/timezone support for now. - - int year = 1970; - - while (time > 0) - { - time_t seconds_in_year = (isleap(year) ? 366 : 365) * SECONDS_PER_DAY; - if (seconds_in_year <= time) - { - year++; - time -= seconds_in_year; - continue; - } - break; - } - - int month_days[] = {31, isleap(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - - int month = 0; - - while (1) - { - time_t seconds_in_month = month_days[month] * SECONDS_PER_DAY; - if (seconds_in_month <= time) - { - month++; - time -= seconds_in_month; - continue; - } - break; - } - - int day = (int)(time / SECONDS_PER_DAY); - time %= SECONDS_PER_DAY; - - assert(day < month_days[month]); - - int hour = (int)(time / 3600); - time %= 3600; - - int min = (int)(time / 60); - time %= 60; - - result->tm_year = year - 1900; - result->tm_mon = month + 1; - result->tm_yday = make_yday(year, month + 1) + day; - result->tm_wday = day_of_week(year, month + 1, day + 1); - result->tm_mday = day + 1; - result->tm_hour = hour; - result->tm_min = min; - result->tm_sec = (int)time; -} - -const char* wday_names[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; -const char* month_names[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; - -extern "C" -{ - clock_t clock() - { - struct timespec tp; - clock_gettime(CLOCK_PROCTIME, &tp); - return (tp.tv_sec * CLOCKS_PER_SEC) + (tp.tv_nsec / 1000); - } - - time_t time(time_t* tloc) - { - struct timespec tp; - clock_gettime(CLOCK_REALTIME, &tp); - if (tloc) { *tloc = tp.tv_sec; } - return tp.tv_sec; - } - - int clock_gettime(clockid_t clock_id, struct timespec* tp) - { - return (int)__lc_fast_syscall2(SYS_clock_gettime, clock_id, tp); - } - - int gettimeofday(struct timeval* tp, __lc_unused void* tzp) - { - struct timespec tspec; - clock_gettime(CLOCK_REALTIME, &tspec); - tp->tv_sec = tspec.tv_sec; - tp->tv_usec = tspec.tv_nsec / 1000; - return 0; - } - - struct tm* localtime(const time_t* time) - { - static struct tm result; - return localtime_r(time, &result); - } - - struct tm* gmtime(const time_t* time) - { - static struct tm result; - return gmtime_r(time, &result); - } - - struct tm* localtime_r(const time_t* time, struct tm* result) - { - return gmtime_r(time, result); // FIXME: Implement timezones. - } - - struct tm* gmtime_r(const time_t* time, struct tm* result) - { - time_to_struct_tm(*time, result); - return result; - } - - char* asctime_r(const struct tm* time, char buf[26]) - { - strftime(buf, 26, "%a %b %d %H:%M:%S %Y\n", time); - return buf; - } - - char* asctime(const struct tm* time) - { - static char buf[26]; - return asctime_r(time, buf); - } - - char* ctime_r(const time_t* time, char buf[26]) - { - struct tm stm; - return asctime_r(localtime_r(time, &stm), buf); - } - - char* ctime(const time_t* time) - { - return asctime(localtime(time)); - } - - time_t mktime(struct tm* time) - { - return broken_down_to_unix(time->tm_year, time->tm_yday, time->tm_hour, time->tm_min, time->tm_sec); - } - - double difftime(time_t time2, time_t time1) - { - return (double)(time2 - time1); - } -} \ No newline at end of file diff --git a/libs/libc/src/unistd.cpp b/libs/libc/src/unistd.cpp deleted file mode 100644 index 29ec9fed..00000000 --- a/libs/libc/src/unistd.cpp +++ /dev/null @@ -1,180 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -extern "C" -{ - int execv(const char* program, char* const argv[]) - { - return (int)__lc_fast_syscall2(SYS_execv, program, argv); - } - - int execve(const char*, char* const[], char* const[]) - { - NOT_IMPLEMENTED("execve"); - } - int execvp(const char*, char* const[]) - { - NOT_IMPLEMENTED("execvp"); - } - - pid_t fork(void) - { - return __lc_fast_syscall0(SYS_fork); - } - - pid_t getpid(void) - { - return getprocid(ID_PID); - } - - pid_t getppid(void) - { - return getprocid(ID_PPID); - } - - uid_t getuid(void) - { - return (uid_t)getprocid(ID_UID); - } - - uid_t geteuid(void) - { - return (uid_t)getprocid(ID_EUID); - } - - gid_t getgid(void) - { - return (gid_t)getprocid(ID_GID); - } - - gid_t getegid(void) - { - return (gid_t)getprocid(ID_EGID); - } - - int setuid(uid_t uid) - { - return (int)__lc_fast_syscall1(SYS_setuid, uid); - } - - int seteuid(uid_t euid) - { - return (int)__lc_fast_syscall1(SYS_seteuid, euid); - } - - int setgid(gid_t gid) - { - return (int)__lc_fast_syscall1(SYS_setgid, gid); - } - - int setegid(gid_t egid) - { - return (int)__lc_fast_syscall1(SYS_setegid, egid); - } - - unsigned int sleep(unsigned int seconds) - { - return msleep(seconds * 1000); - } - - ssize_t read(int fd, void* buf, size_t count) - { - return __lc_fast_syscall3(SYS_read, fd, count, buf); // yes, our read() syscall is in the wrong order. - } - - ssize_t write(int fd, const void* buf, size_t count) - { - return __lc_fast_syscall3(SYS_write, fd, count, buf); // yes, our write() syscall is in the wrong order. - } - - int close(int fd) - { - return (int)__lc_fast_syscall1(SYS_close, fd); - } - - off_t lseek(int fd, off_t offset, int whence) - { - return __lc_fast_syscall3(SYS_seek, fd, offset, whence); - } - - __lc_noreturn void _exit(int status) - { - __lc_fast_syscall1(SYS_exit, status); - __lc_unreachable(); - } - - int dup(int fd) - { - return fcntl(fd, F_DUPFD, 0); - } - - int dup2(int fd, int fd2) - { - return (int)__lc_fast_syscall2(SYS_dup2, fd, fd2); - } - - int access(const char* path, int amode) - { - return (int)__lc_fast_syscall2(SYS_access, path, amode); - } - - int isatty(int fd) - { - int result = fcntl(fd, F_ISTTY); - if (result < 0) return 0; - return 1; - } - - char* getcwd(char* buf, size_t size) - { - const char* dummy_cwd = "/"; // FIXME: Actually retrieve the current working directory from the kernel. - if (size < 2) - { - errno = ERANGE; - return NULL; - } - if (!buf) { buf = (char*)malloc(size); } - strlcpy(buf, dummy_cwd, 2); - return buf; - } - - int unlink(const char*) - { - NOT_IMPLEMENTED("unlink"); - } - - int rmdir(const char*) - { - NOT_IMPLEMENTED("rmdir"); - } - - int chdir(const char*) - { - NOT_IMPLEMENTED("chdir"); - } - - int pipe(int[2]) - { - NOT_IMPLEMENTED("pipe"); - } - - long pathconf(const char* path, int name) - { - switch (name) - { - case _PC_PATH_MAX: return PATH_MAX - (strlen(path) + 1); - default: errno = EINVAL; return -1; - } - } - - int getdtablesize(void) - { - return OPEN_MAX; - } -} \ No newline at end of file diff --git a/libs/libc/src/utime.cpp b/libs/libc/src/utime.cpp deleted file mode 100644 index b3ffb991..00000000 --- a/libs/libc/src/utime.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include -#include - -extern "C" -{ - int utime(const char*, const struct utimbuf*) - { - NOT_IMPLEMENTED("utime"); - } -} \ No newline at end of file diff --git a/libs/libc/src/wchar.cpp b/libs/libc/src/wchar.cpp deleted file mode 100644 index 50d32df9..00000000 --- a/libs/libc/src/wchar.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include - -extern "C" -{ - size_t wcslen(const wchar_t* str) - { - const wchar_t* i = str; - for (; *i; ++i) - ; - return (i - str); - } - - wchar_t* wcscat(wchar_t* dest, const wchar_t* src) - { - size_t dest_len = wcslen(dest); - size_t i; - - for (i = 0; *(src + i); i++) *(dest + dest_len + i) = *(src + i); - - *(dest + dest_len + i) = L'\0'; - - return dest; - } -} \ No newline at end of file diff --git a/luna/CMakeLists.txt b/luna/CMakeLists.txt new file mode 100644 index 00000000..4fbc5114 --- /dev/null +++ b/luna/CMakeLists.txt @@ -0,0 +1,59 @@ +# The miscellaneous library shared between the Luna kernel and userspace, with stuff such as custom types, common routines and data structures. + +file(GLOB HEADERS include/luna/*.h) + +set(FREESTANDING_SOURCES + ${HEADERS} + src/Format.cpp + src/NumberParsing.cpp + src/CString.cpp + src/Units.cpp + src/SystemError.cpp + src/Bitmap.cpp + src/Stack.cpp + src/Alloc.cpp + src/OwnedStringView.cpp + src/Utf8.cpp + src/TarStream.cpp + src/DebugLog.cpp +) + +set(SOURCES + ${FREESTANDING_SOURCES} + src/Check.cpp +) + +add_library(luna-freestanding ${FREESTANDING_SOURCES}) +target_compile_definitions(luna-freestanding PRIVATE USE_FREESTANDING) +target_compile_options(luna-freestanding PRIVATE -Wall -Wextra -Werror -Wvla) +target_compile_options(luna-freestanding PRIVATE -Wdisabled-optimization -Wformat=2 -Winit-self -Wsign-conversion) +target_compile_options(luna-freestanding PRIVATE -Wmissing-include-dirs -Wswitch-default -Wcast-qual -Wundef) +target_compile_options(luna-freestanding PRIVATE -Wcast-align -Wwrite-strings -Wlogical-op -Wredundant-decls -Wshadow -Wconversion) +target_compile_options(luna-freestanding PRIVATE -fno-rtti -ffreestanding -fno-exceptions) +target_compile_options(luna-freestanding PRIVATE -fno-asynchronous-unwind-tables -fno-omit-frame-pointer) +target_compile_options(luna-freestanding PRIVATE -nostdlib -mcmodel=kernel) + +target_include_directories(luna-freestanding PUBLIC include/) +set_target_properties(luna-freestanding PROPERTIES CXX_STANDARD 20) + +add_library(luna ${SOURCES}) +target_compile_options(luna PRIVATE -Wall -Wextra -Werror -Wvla) +target_compile_options(luna PRIVATE -Wdisabled-optimization -Wformat=2 -Winit-self) +target_compile_options(luna PRIVATE -Wmissing-include-dirs -Wswitch-default -Wcast-qual -Wundef) +target_compile_options(luna PRIVATE -Wcast-align -Wwrite-strings -Wlogical-op -Wredundant-decls -Wshadow -Wconversion) +target_compile_options(luna PRIVATE -fno-asynchronous-unwind-tables -fno-omit-frame-pointer -std=c++20 -fno-rtti -fno-exceptions) +target_include_directories(luna PUBLIC include/) +target_include_directories(luna PUBLIC ${LUNA_BASE}/usr/include) + +if("${ARCH}" MATCHES "x86_64") +target_compile_options(luna-freestanding PRIVATE -mno-red-zone) +target_compile_options(luna-freestanding PRIVATE -mno-80387 -mno-mmx -mno-sse -mno-sse2) +target_compile_definitions(luna-freestanding PUBLIC ARCH_X86_64) +target_compile_definitions(luna PUBLIC ARCH_X86_64) +endif() + +if(LUNA_DEBUG_SYMBOLS) + message(STATUS "Building Luna with debug symbols") + target_compile_options(luna PRIVATE -ggdb) + target_compile_options(luna-freestanding PRIVATE -ggdb) +endif() diff --git a/luna/include/luna/Alignment.h b/luna/include/luna/Alignment.h new file mode 100644 index 00000000..af572950 --- /dev/null +++ b/luna/include/luna/Alignment.h @@ -0,0 +1,53 @@ +#pragma once +#include +#include + +// Must ALWAYS be called with a power of two as alignment. +template constexpr T is_aligned(T value) +{ + static_assert(IsPowerOfTwo); + return (value % alignment == 0); +} + +static_assert(is_aligned<512>(1024u)); +static_assert(!is_aligned<32>(235u)); +static_assert(is_aligned<4096>(40960u)); + +// Must ALWAYS be called with a power of two as alignment. +template constexpr T align_down(T value) +{ + static_assert(IsPowerOfTwo); + return value - value % alignment; +} + +static_assert(align_down<512>(598ul) == 512ul); +static_assert(align_down<64>(194ul) == 192ul); +static_assert(align_down<32>(64ul) == 64ul); + +// Must ALWAYS be called with a power of two as alignment. +template constexpr T align_up(T value) +{ + if (is_aligned(value)) return value; + return align_down(value) + alignment; +} + +static_assert(align_up<512>(598ul) == 1024ul); +static_assert(align_up<64>(194ul) == 256ul); +static_assert(align_up<32>(64ul) == 64ul); + +template constexpr T get_blocks_from_size(T value, T block_size) +{ + return (value + (block_size - 1)) / block_size; +} + +static_assert(get_blocks_from_size(40960, 4096) == 10); +static_assert(get_blocks_from_size(194, 64) == 4); +static_assert(get_blocks_from_size(2, 32) == 1); +static_assert(get_blocks_from_size(0, 256) == 0); + +// Offset a pointer by exactly bytes, no matter the type. Useful to avoid the quirks that come from C pointer +// arithmetic. +template constexpr T* offset_ptr(T* ptr, Offset offset) +{ + return (T*)((char*)ptr + offset); +} diff --git a/luna/include/luna/Alloc.h b/luna/include/luna/Alloc.h new file mode 100644 index 00000000..96ef2b94 --- /dev/null +++ b/luna/include/luna/Alloc.h @@ -0,0 +1,47 @@ +#pragma once +#include + +namespace std +{ + struct nothrow_t + { + explicit nothrow_t() = default; + }; + + extern const nothrow_t nothrow; + + enum class align_val_t : usize + { + }; +}; + +[[nodiscard]] void* raw_malloc(usize); +void raw_free(void*); + +void* operator new(usize size, const std::nothrow_t&) noexcept; +void* operator new[](usize size, const std::nothrow_t&) noexcept; +void operator delete(void* ptr, usize size, std::align_val_t alignment) noexcept; + +template [[nodiscard]] Result make(Args... args) +{ + T* const result = new (std::nothrow) T(args...); + if (!result) return err(ENOMEM); + return result; +} + +template [[nodiscard]] Result make_array(usize count) +{ + T* const result = new (std::nothrow) T[count]; + if (!result) return err(ENOMEM); + return result; +} + +template void destroy(T* item) +{ + delete item; +} + +template void destroy_array(T* item) +{ + delete[] item; +} diff --git a/luna/include/luna/Atomic.h b/luna/include/luna/Atomic.h new file mode 100644 index 00000000..f2c9cd79 --- /dev/null +++ b/luna/include/luna/Atomic.h @@ -0,0 +1,118 @@ +#pragma once + +enum class MemoryOrder +{ + Relaxed = __ATOMIC_RELAXED, + Consume = __ATOMIC_CONSUME, + Acquire = __ATOMIC_ACQUIRE, + Release = __ATOMIC_RELEASE, + AcqRel = __ATOMIC_ACQ_REL, + SeqCst = __ATOMIC_SEQ_CST, +}; + +template class Atomic +{ + public: + Atomic() : m_value() + { + } + + Atomic(T value) : m_value(value) + { + } + + T operator=(T other) + { + store(other); + return other; + } + + T load(MemoryOrder order = MemoryOrder::SeqCst) const + { + return __atomic_load_n(&m_value, (int)order); + } + + operator T() const + { + return load(); + } + + void store(T value, MemoryOrder order = MemoryOrder::SeqCst) + { + return __atomic_store_n(&m_value, value, (int)order); + } + + T exchange(T value, MemoryOrder order = MemoryOrder::SeqCst) + { + return __atomic_exchange_n(&m_value, value, (int)order); + } + + bool compare_exchange_strong(T& expected, T desired, MemoryOrder success, MemoryOrder failure) + { + return __atomic_compare_exchange_n(&m_value, &expected, desired, false, (int)success, (int)failure); + } + + bool compare_exchange_strong(T& expected, T desired, MemoryOrder order = MemoryOrder::SeqCst) + { + MemoryOrder failure = (order == MemoryOrder::AcqRel) ? MemoryOrder::Acquire + : (order == MemoryOrder::Release) ? MemoryOrder::Relaxed + : order; + return __atomic_compare_exchange_n(&m_value, &expected, desired, false, (int)order, (int)failure); + } + + bool compare_exchange_weak(T& expected, T desired, MemoryOrder success, MemoryOrder failure) + { + return __atomic_compare_exchange_n(&m_value, &expected, desired, true, (int)success, (int)failure); + } + + bool compare_exchange_weak(T& expected, T desired, MemoryOrder order = MemoryOrder::SeqCst) + { + MemoryOrder failure = (order == MemoryOrder::AcqRel) ? MemoryOrder::Acquire + : (order == MemoryOrder::Release) ? MemoryOrder::Relaxed + : order; + return __atomic_compare_exchange_n(&m_value, &expected, desired, true, (int)order, (int)failure); + } + + T fetch_add(T other, MemoryOrder order = MemoryOrder::SeqCst) + { + return __atomic_fetch_add(&m_value, other, (int)order); + } + + T fetch_sub(T other, MemoryOrder order = MemoryOrder::SeqCst) + { + return __atomic_fetch_sub(&m_value, other, (int)order); + } + + T operator++() + { + return fetch_add(1) + 1; + } + + T operator++(int) + { + return fetch_add(1); + } + + T operator--() + { + return fetch_sub(1) - 1; + } + + T operator--(int) + { + return fetch_sub(1); + } + + T operator+=(const T& other) + { + return fetch_add(other) + other; + } + + T operator-=(const T& other) + { + return fetch_sub(other) - other; + } + + private: + T m_value; +}; diff --git a/luna/include/luna/Attributes.h b/luna/include/luna/Attributes.h new file mode 100644 index 00000000..28d84975 --- /dev/null +++ b/luna/include/luna/Attributes.h @@ -0,0 +1,5 @@ +#pragma once + +#define _weak __attribute__((weak)) +#define _format(n, m) __attribute__((format(printf, n, m))) +#define _align(x) __attribute__((aligned(x))) diff --git a/luna/include/luna/Badge.h b/luna/include/luna/Badge.h new file mode 100644 index 00000000..50cb5cbc --- /dev/null +++ b/luna/include/luna/Badge.h @@ -0,0 +1,12 @@ +#pragma once + +template struct Badge +{ + private: + constexpr Badge() = default; + + Badge(const Badge&) = delete; + Badge(Badge&&) = delete; + + friend T; +}; diff --git a/luna/include/luna/Bitmap.h b/luna/include/luna/Bitmap.h new file mode 100644 index 00000000..5b062fd7 --- /dev/null +++ b/luna/include/luna/Bitmap.h @@ -0,0 +1,48 @@ +#pragma once +#include + +class Bitmap +{ + public: + Bitmap(); + Bitmap(void* location, usize size_in_bytes); + + void initialize(void* location, usize size_in_bytes); + void* move(void* new_location, usize new_location_size_in_bytes); + + void set(usize index, bool value); + bool get(usize index) const; + + // size() returns size in bits! If you want the size in bytes, call size_in_bytes(). + usize size() const + { + return m_size_in_bytes * 8; + } + + usize size_in_bytes() const + { + return m_size_in_bytes; + } + + void* location() const + { + return (void*)m_location; + } + + bool initialized() const + { + return m_location; + } + + void clear(bool value); + void clear_region(usize start, usize bits, bool value); + + private: + u8 value_byte(bool b) + { + return b ? 0xff : 0; + } + + u8* m_location = nullptr; + usize m_size_in_bytes = 0; +}; diff --git a/luna/include/luna/CString.h b/luna/include/luna/CString.h new file mode 100644 index 00000000..b4ac3029 --- /dev/null +++ b/luna/include/luna/CString.h @@ -0,0 +1,24 @@ +#pragma once +#include + +extern "C" +{ + void* memcpy(void* dest, const void* src, usize n); + void* memset(void* buf, int c, usize n); + int memcmp(const void* a, const void* b, usize n); + void* memmove(void* dest, const void* src, usize n); + usize strlen(const char* str); + int strcmp(const char* a, const char* b); + + usize wcslen(const wchar_t* str); + + char* strdup(const char* str); + + // Copies len bytes from src into dest and adds a null terminator. + void nullcpy(char* dest, const char* src, usize len); + + [[deprecated]] char* strcpy(char* dst, const char* src); + [[deprecated]] char* strcat(char* dst, const char* src); + + char* strchr(const char* str, int c); +} diff --git a/luna/include/luna/CType.h b/luna/include/luna/CType.h new file mode 100644 index 00000000..91994286 --- /dev/null +++ b/luna/include/luna/CType.h @@ -0,0 +1,96 @@ +#pragma once + +inline constexpr int _isascii(int c) +{ + return !(c & ~0x7f); +} + +inline constexpr int _isblank(int c) +{ + return c == ' ' || c == '\t'; +} + +inline constexpr int _iscntrl(int c) +{ + return (unsigned int)c < 0x20 || c == 0x7f; +} + +inline constexpr int _isdigit(int c) +{ + return c >= '0' && c < ':'; +} + +inline constexpr int _isgraph(int c) +{ + return (unsigned int)c - 0x21 < 0x5e; +} + +inline constexpr int _islower(int c) +{ + return c >= 'a' && c < '{'; +} + +inline constexpr int _isupper(int c) +{ + return c >= 'A' && c < '['; +} + +inline constexpr int _isprint(int c) +{ + return (unsigned int)c - 0x20 < 0x5f; +} + +inline constexpr int _isalpha(int c) +{ + return _islower(c) || _isupper(c); +} + +inline constexpr int _isalnum(int c) +{ + return _isalpha(c) || _isdigit(c); +} + +inline constexpr int _ispunct(int c) +{ + return _isgraph(c) && !_isalnum(c); +} + +inline constexpr int _isspace(int c) +{ + return c == ' ' || (unsigned int)c - '\t' < 5; +} + +inline constexpr int _isxdigit(int c) +{ + return _isdigit(c) || ((unsigned int)c | 32) - 'a' < 6; +} + +inline constexpr int _tolower(int c) +{ + if (_isupper(c)) return c | 32; + return c; +} + +inline constexpr int _toupper(int c) +{ + if (_islower(c)) return c & 0x5f; + return c; +} + +#if defined(_LUNA_OVERRIDE_STDC) || defined(IN_MOON) +#define isalnum _isalnum +#define isalpha _isalpha +#define isascii _isascii +#define iscntrl _iscntrl +#define isdigit _isdigit +#define isxdigit _isxdigit +#define isspace _isspace +#define ispunct _ispunct +#define isprint _isprint +#define isgraph _isgraph +#define islower _islower +#define isupper _isupper +#define isblank _isblank +#define tolower _tolower +#define toupper _toupper +#endif diff --git a/luna/include/luna/Check.h b/luna/include/luna/Check.h new file mode 100644 index 00000000..897c4486 --- /dev/null +++ b/luna/include/luna/Check.h @@ -0,0 +1,29 @@ +#pragma once + +[[noreturn]] extern bool __check_failed(const char* file, const char* line, const char* func, const char* expr); + +#ifndef STRINGIZE_VALUE_OF +#define STRINGIZE(x) #x +#define STRINGIZE_VALUE_OF(x) STRINGIZE(x) +#endif + +#define expect(expr, message) \ + do { \ + if (!(expr)) [[unlikely]] \ + { \ + __check_failed(__FILE__, STRINGIZE_VALUE_OF(__LINE__), __PRETTY_FUNCTION__, message); \ + } \ + } while (0) + +#define check(expr) \ + do { \ + if (!(expr)) [[unlikely]] \ + { \ + __check_failed(__FILE__, STRINGIZE_VALUE_OF(__LINE__), __PRETTY_FUNCTION__, #expr); \ + } \ + } while (0) + +#define unreachable() \ + __check_failed(__FILE__, STRINGIZE_VALUE_OF(__LINE__), __PRETTY_FUNCTION__, "Reached unreachable code") + +#define todo() __check_failed(__FILE__, STRINGIZE_VALUE_OF(__LINE__), __PRETTY_FUNCTION__, "Reached a TODO!") diff --git a/luna/include/luna/CircularQueue.h b/luna/include/luna/CircularQueue.h new file mode 100644 index 00000000..3960854e --- /dev/null +++ b/luna/include/luna/CircularQueue.h @@ -0,0 +1,57 @@ +#pragma once +#include +#include + +template class CircularQueue +{ + enum + { + Capacity = Size + 1 + }; + + public: + CircularQueue() + { + } + + bool try_push(const T& value) + { + usize current_tail = m_tail.load(MemoryOrder::Relaxed); + const usize new_tail = (current_tail + 1) % Capacity; + if (new_tail == m_head.load(MemoryOrder::Acquire)) + { + // Queue is full + return false; + } + m_data[current_tail] = value; + if (!m_tail.compare_exchange_strong(current_tail, new_tail, MemoryOrder::Release, MemoryOrder::Relaxed)) + { + // Someone else updated the tail + return false; + } + return true; + } + + bool try_pop(T& value) + { + usize current_head = m_head.load(MemoryOrder::Relaxed); + if (current_head == m_tail.load(MemoryOrder::Acquire)) + { + // Queue is empty + return false; + } + value = m_data[current_head]; + const usize new_head = (current_head + 1) % Capacity; + if (!m_head.compare_exchange_strong(current_head, new_head, MemoryOrder::Release, MemoryOrder::Relaxed)) + { + // Someone else updated the head + return false; + } + return true; + } + + private: + T m_data[Capacity]; + Atomic m_head = 0; + Atomic m_tail = 0; +}; diff --git a/luna/include/luna/DebugLog.h b/luna/include/luna/DebugLog.h new file mode 100644 index 00000000..0f78aa53 --- /dev/null +++ b/luna/include/luna/DebugLog.h @@ -0,0 +1,7 @@ +#pragma once +#include +#include + +extern void debug_log_impl(const char* format, va_list ap); + +void dbgln(const char* format, ...) _format(1, 2); diff --git a/luna/include/luna/Format.h b/luna/include/luna/Format.h new file mode 100644 index 00000000..7fe3bcdc --- /dev/null +++ b/luna/include/luna/Format.h @@ -0,0 +1,19 @@ +#pragma once +#include +#include +#include + +typedef Result (*callback_t)(char, void*); +typedef void (*pure_callback_t)(char, void*); + +// Used to format anything that can fail (writing to C FILEs, etc...) +Result cstyle_format(const char* format, callback_t callback, void* arg, va_list ap); + +// Used to format anything that cannot fail (formatting to a string, writing to the serial port (kernel-only)) +usize pure_cstyle_format(const char* format, pure_callback_t callback, void* arg, va_list ap); + +// Convenience function which outputs into a fixed-size buffer (not unlike vsnprintf) +usize vstring_format(char* buf, usize max, const char* format, va_list ap); + +// Convenience function which outputs into a fixed-size buffer (not unlike snprintf) +usize string_format(char* buf, usize max, const char* format, ...) _format(3, 4); diff --git a/luna/include/luna/LinkedList.h b/luna/include/luna/LinkedList.h new file mode 100644 index 00000000..f1e6df08 --- /dev/null +++ b/luna/include/luna/LinkedList.h @@ -0,0 +1,223 @@ +#pragma once +#include +#include + +template class LinkedList; + +template class LinkedListNode +{ + using SelfType = LinkedListNode; + + private: + SelfType* m_next_node; + SelfType* m_last_node; + + void set_next(SelfType* next) + { + m_next_node = next; + } + + void set_last(SelfType* last) + { + m_last_node = last; + } + + SelfType* get_next() + { + return m_next_node; + } + + SelfType* get_last() + { + return m_last_node; + } + + void detach_from_list() + { + if (m_next_node) m_next_node->m_last_node = m_last_node; + if (m_last_node) m_last_node->m_next_node = m_next_node; + } + + void append_to_list(SelfType* end_node) + { + end_node->m_next_node = this; + this->m_last_node = end_node; + this->m_next_node = nullptr; + } + + void prepend_to_list(SelfType* start_node) + { + start_node->m_last_node = this; + this->m_next_node = start_node; + this->m_last_node = nullptr; + } + + friend class LinkedList; +}; + +template class LinkedList +{ + using Node = LinkedListNode; + + static_assert(IsBaseOf, T>); + + public: + void append(T* ptr) + { + Node* const node = extract_node(ptr); + if (!m_start_node) m_start_node = node; + if (m_end_node) node->append_to_list(m_end_node); + else + { + node->set_next(nullptr); + node->set_last(nullptr); + } + m_end_node = node; + + m_count++; + } + + void prepend(T* ptr) + { + Node* const node = extract_node(ptr); + if (!m_end_node) m_end_node = node; + if (m_start_node) node->prepend_to_list(m_start_node); + else + { + node->set_next(nullptr); + node->set_last(nullptr); + } + m_start_node = node; + + m_count++; + } + + void add_after(T* base, T* ptr) + { + Node* const new_node = extract_node(ptr); + Node* const base_node = extract_node(base); + + if (m_end_node == base_node) m_end_node = new_node; + + if (base_node->get_next()) base_node->get_next()->set_last(new_node); + + new_node->set_next(base_node->get_next()); + base_node->set_next(new_node); + new_node->set_last(base_node); + + m_count++; + } + + T* remove(T* ptr) + { + Node* const node = extract_node(ptr); + + if (node == m_end_node) m_end_node = node->get_last(); + if (node == m_start_node) m_start_node = node->get_next(); + + node->detach_from_list(); + + m_count--; + + return ptr; + } + + Option first() + { + return nonnull_or_empty_option((T*)m_start_node); + } + + T* expect_first() + { + check(m_start_node); + return (T*)m_start_node; + } + + Option last() + { + return nonnull_or_empty_option((T*)m_end_node); + } + + T* expect_last() + { + check(m_end_node); + return (T*)m_end_node; + } + + Option next(T* item) + { + return nonnull_or_empty_option((T*)extract_node(item)->get_next()); + } + + Option previous(T* item) + { + return nonnull_or_empty_option((T*)extract_node(item)->get_last()); + } + + // Iterates over the elements of the LinkedList from start to end, calling callback for every element. + template void for_each(Callback callback) + { + for (Node* node = m_start_node; node; node = node->get_next()) { callback((T*)node); } + } + + // Iterates over the elements of the LinkedList from start to end, calling callback for every element. This + // for_each is implemented in such a way that elements can be removed while iterating over it. + template void delayed_for_each(Callback callback) + { + for (Node* node = m_start_node; node;) + { + T* current = (T*)node; + node = node->get_next(); + callback(current); + } + } + + // Iterates over the elements of the LinkedList from end to start, calling callback for every element. + template void for_each_reversed(Callback callback) + { + for (Node* node = m_end_node; node; node = node->get_last()) { callback((T*)node); } + } + + // Iterates over the elements of the LinkedList from the element after 'start' to end, calling callback for + // every element. + template void for_each_after(T* start, Callback callback) + { + for (Node* node = extract_node(start)->m_next_node; node; node = node->get_next()) { callback((T*)node); } + } + + // Iterates over the elements of the LinkedList from the element before 'end' to start, calling callback for + // every element. + template void for_each_before(T* end, Callback callback) + { + for (Node* node = extract_node(end)->m_last_node; node; node = node->get_last()) { callback((T*)node); } + } + + // Iterates over the elements of the LinkedList from start to end, removing each element before passing it to + // the callback. + template void consume(Callback callback) + { + for (Node* node = m_start_node; node;) + { + T* current = (T*)node; + node = node->get_next(); + remove(current); + callback(current); + } + } + + usize count() + { + return m_count; + } + + private: + Node* m_start_node = nullptr; + Node* m_end_node = nullptr; + + Node* extract_node(T* item) + { + return (Node*)item; + } + + usize m_count = 0; +}; diff --git a/kernel/include/utils/move.h b/luna/include/luna/Move.h similarity index 97% rename from kernel/include/utils/move.h rename to luna/include/luna/Move.h index 9006d68a..6a88f7b0 100644 --- a/kernel/include/utils/move.h +++ b/luna/include/luna/Move.h @@ -3,4 +3,4 @@ template inline T&& move(T& lvalue) { return (T &&) lvalue; -} \ No newline at end of file +} diff --git a/luna/include/luna/NumberParsing.h b/luna/include/luna/NumberParsing.h new file mode 100644 index 00000000..ca00841c --- /dev/null +++ b/luna/include/luna/NumberParsing.h @@ -0,0 +1,14 @@ +#pragma once +#include + +// Parse an unsigned integer and advance *str to point to the first non-digit character after the number. +usize scan_unsigned_integer(const char** str); + +// Parse a signed integer and advance *str to point to the first non-digit character after the number. +isize scan_signed_integer(const char** str); + +// Parse an unsigned integer, similar to strtoull(). +usize parse_unsigned_integer(const char* str, const char** endptr, int base); + +// Parse a signed integer, similar to strtoll(). +isize parse_signed_integer(const char* str, const char** endptr, int base); diff --git a/luna/include/luna/Option.h b/luna/include/luna/Option.h new file mode 100644 index 00000000..db68653b --- /dev/null +++ b/luna/include/luna/Option.h @@ -0,0 +1,179 @@ +#pragma once +#include +#include +#include +#include + +template class Result; + +template class Option +{ + public: + Option(const T& value) : m_has_value(true) + { + m_storage.store_reference(value); + } + + Option(T&& value) : m_has_value(true) + { + m_storage.store_moved_reference(move(value)); + } + + Option(const Option& other) : m_has_value(other.m_has_value) + { + if (m_has_value) { m_storage.store_reference(other.m_storage.fetch_reference()); } + } + + Option(Option&& other) : m_has_value(other.m_has_value) + { + other.m_has_value = false; + if (m_has_value) { m_storage.store_moved_reference(move(other.m_storage.fetch_reference())); } + } + + Option& operator=(const Option& other) + { + if (this == &other) return *this; + + if (m_has_value) m_storage.destroy(); + m_has_value = other.m_has_value; + + if (m_has_value) { m_storage.store_reference(other.m_storage.fetch_reference()); } + + return *this; + } + + Option& operator=(Option&& other) + { + if (this == &other) return *this; + + if (m_has_value) m_storage.destroy(); + m_has_value = other.m_has_value; + other.m_has_value = false; + + if (m_has_value) { m_storage.store_moved_reference(move(other.m_storage.fetch_reference())); } + + return *this; + } + + Option() : m_has_value(false) + { + } + + bool has_value() const + { + return m_has_value; + } + + T value() const + { + expect(has_value(), "Option::value called on an empty Option"); + return m_storage.fetch_reference(); + } + + T unchecked_value(Badge>) const + { + return m_storage.fetch_reference(); + } + + T release_value() + { + expect(has_value(), "Option::release_value called on an empty Option"); + m_has_value = false; + return move(m_storage.fetch_reference()); + } + + T unchecked_release_value(Badge>) + { + m_has_value = false; + return move(m_storage.fetch_reference()); + } + + T value_or(const T& other) const + { + if (has_value()) return m_storage.fetch_reference(); + return other; + } + + bool try_set_value(T& ref) const + { + if (!has_value()) return false; + ref = m_storage.fetch_reference(); + return true; + } + + ~Option() + { + if (has_value()) m_storage.destroy(); + } + + // For compatibility with TRY() + struct ErrorHandle + { + private: + explicit ErrorHandle() + { + } + + friend class Option; + }; + + Option(const ErrorHandle&) : m_has_value(false) + { + } + + ErrorHandle release_error() + { + expect(!has_value(), "Option::release_error called on a non-empty Option"); + return ErrorHandle {}; + } + + private: + struct Storage + { + u8 buffer[sizeof(T)]; + + T* fetch_ptr() + { + return (T*)buffer; + } + + T& fetch_reference() + { + return *fetch_ptr(); + } + + const T* fetch_ptr() const + { + return (const T*)buffer; + } + + const T& fetch_reference() const + { + return *fetch_ptr(); + } + + void store_reference(const T& ref) + { + new (buffer) T(ref); + } + + void store_moved_reference(T&& ref) + { + new (buffer) T(move(ref)); + } + + void destroy() + { + fetch_reference().~T(); + } + }; + Storage m_storage; + bool m_has_value { false }; +}; + +template inline Option nonnull_or_empty_option(T* ptr) +{ + if (ptr == nullptr) return {}; + else + return ptr; +} diff --git a/luna/include/luna/OwnedPtr.h b/luna/include/luna/OwnedPtr.h new file mode 100644 index 00000000..01911ea8 --- /dev/null +++ b/luna/include/luna/OwnedPtr.h @@ -0,0 +1,65 @@ +#pragma once +#include +#include + +template class SharedPtr; + +template class OwnedPtr +{ + public: + OwnedPtr(T* ptr) + { + m_ptr = ptr; + } + + ~OwnedPtr() + { + if (m_ptr) delete m_ptr; + } + + OwnedPtr(const OwnedPtr& other) = delete; + + OwnedPtr(OwnedPtr&& other) + { + m_ptr = other.m_ptr; + other.m_ptr = nullptr; + } + + T* ptr() const + { + return m_ptr; + } + + T* operator->() const + { + return m_ptr; + } + + T& operator*() const + { + return *m_ptr; + } + + template friend Result> adopt_shared_from_owned(OwnedPtr&&); + + private: + T* m_ptr; +}; + +template Result> make_owned(Args... args) +{ + T* raw = TRY(make(args...)); + return OwnedPtr { raw }; +} + +template OwnedPtr adopt_owned(T* ptr) +{ + return OwnedPtr { ptr }; +} + +template Result> adopt_owned_if_nonnull(T* ptr) +{ + if (ptr) return OwnedPtr { ptr }; + else + return err(ENOMEM); +} diff --git a/luna/include/luna/OwnedStringView.h b/luna/include/luna/OwnedStringView.h new file mode 100644 index 00000000..876e9c60 --- /dev/null +++ b/luna/include/luna/OwnedStringView.h @@ -0,0 +1,32 @@ +#pragma once +#include + +class OwnedStringView +{ + public: + OwnedStringView(char* c_str); + OwnedStringView(); + OwnedStringView(OwnedStringView&&); + OwnedStringView(const OwnedStringView&) = delete; + ~OwnedStringView(); + + Result clone() const; + + static Result from_string_literal(const char* str); + + const char* chars() const + { + return m_string; + } + + usize length() const + { + return m_length; + } + + const char& operator[](usize) const; + + private: + char* m_string { nullptr }; + usize m_length { 0 }; +}; diff --git a/luna/include/luna/PlacementNew.h b/luna/include/luna/PlacementNew.h new file mode 100644 index 00000000..554bde97 --- /dev/null +++ b/luna/include/luna/PlacementNew.h @@ -0,0 +1,13 @@ +#pragma once +#include + +inline void* operator new(usize, void* p) noexcept +{ + return p; +} +inline void* operator new[](usize, void* p) noexcept +{ + return p; +} +inline void operator delete(void*, void*) noexcept {}; +inline void operator delete[](void*, void*) noexcept {}; diff --git a/luna/include/luna/Result.h b/luna/include/luna/Result.h new file mode 100644 index 00000000..1bfb1cf4 --- /dev/null +++ b/luna/include/luna/Result.h @@ -0,0 +1,254 @@ +#pragma once +#define _LUNA_SYSTEM_ERROR_EXTENSIONS +#include +#include +#include +#include +#include +#include + +struct Error +{ + Error(int err) + { + error = err; + } + + int error; +}; + +template class Result +{ + public: + Result(const T& value) : m_value(value), m_has_value(true) + { + } + + Result(T&& value) : m_value(move(value)), m_has_value(true) + { + } + + Result(const Result& other) : m_value(other.m_value), m_has_value(other.m_has_value), m_error(other.m_error) + { + } + + Result(Result&& other) : m_value(move(other.m_value)), m_has_value(other.m_has_value), m_error(other.m_error) + { + other.m_has_value = false; + } + + Result(const Error& err) : m_value(), m_has_value(false), m_error(err.error) + { + } + + Result& operator=(const Result& other) + { + if (this == &other) return *this; + + m_has_value = other.m_has_value; + m_error = other.m_error; + m_value = other.m_value; + + return *this; + } + + Result& operator=(Result&& other) + { + if (this == &other) return *this; + + m_has_value = other.m_has_value; + other.m_has_value = false; + m_error = other.m_error; + m_value = move(other.m_value); + + return *this; + } + + bool has_error() const + { + return !m_has_value; + } + + bool has_value() const + { + return m_has_value; + } + + int error() const + { + expect(has_error(), "Result::error() called on a Result that holds a value"); + return m_error; + } + + Error release_error() const + { + expect(has_error(), "Result::release_error() called on a Result that holds a value"); + return { m_error }; + } + + const char* error_string() const + { + expect(has_error(), "Result::error_string() called on a Result that holds a value"); + return ::error_string(m_error); + } + + T value() const + { + expect(has_value(), "Result::value() called on a Result that holds an error"); + return m_value.unchecked_value({}); + } + + T expect_value(const char* reason) const + { + expect(has_value(), reason); + return m_value.unchecked_value({}); + } + + T value_or(const T& other) const + { + return m_value.value_or(other); + } + + bool try_set_value(T& ref) const + { + return m_value.try_set_value(ref); + } + + Result try_set_value_with_specific_error(T& ref, int error) + { + if (has_error() && m_error != error) return release_error(); + + return m_value.try_set_value(ref); + } + + T release_value() + { + expect(has_value(), "Result::release_value() called on a Result that holds an error"); + return m_value.unchecked_release_value({}); + } + + T expect_release_value(const char* reason) + { + expect(has_value(), reason); + return m_value.unchecked_release_value({}); + } + + private: + Option m_value; + bool m_has_value; + int m_error; +}; + +template <> class Result +{ + public: + Result() : m_has_error(false) + { + } + + Result(const Result& other) : m_has_error(other.m_has_error), m_error(other.m_error) + { + } + + Result(Result&& other) : m_has_error(other.m_has_error), m_error(other.m_error) + { + } + + Result(const Error& err) : m_has_error(true), m_error(err.error) + { + } + + Result& operator=(const Result& other) + { + if (this == &other) return *this; + + m_has_error = other.m_has_error; + m_error = other.m_error; + + return *this; + } + + Result& operator=(Result&& other) + { + if (this == &other) return *this; + + m_has_error = other.m_has_error; + m_error = other.m_error; + + return *this; + } + + bool has_error() const + { + return m_has_error; + } + + bool has_value() const + { + return !m_has_error; + } + + int error() const + { + expect(has_error(), "Result::error() called on a Result that holds a value"); + return m_error; + } + + Error release_error() const + { + expect(has_error(), "Result::release_error() called on a Result that holds a value"); + return { m_error }; + } + + const char* error_string() const + { + expect(has_error(), "Result::error_string() called on a Result that holds a value"); + return ::error_string(m_error); + } + + void value() const + { + expect(has_value(), "Result::value() called on a Result that holds an error"); + return; + } + + void expect_value(const char* reason) const + { + expect(has_value(), reason); + return; + } + + void release_value() const + { + expect(has_value(), "Result::release_value() called on a Result that holds an error"); + return; + } + + void expect_release_value(const char* reason) const + { + expect(has_value(), reason); + return; + } + + private: + bool m_has_error; + int m_error; +}; + +// clang-format off +#define err(x) Error{x} +// clang-format on + +#define TRY(expr) \ + ({ \ + auto _expr_rc = (expr); \ + if (!_expr_rc.has_value()) return _expr_rc.release_error(); \ + _expr_rc.release_value(); \ + }) + +template inline Result nonnull_or_error(T* ptr, int error) +{ + if (ptr == nullptr) return err(error); + else + return ptr; +} diff --git a/luna/include/luna/SafeArithmetic.h b/luna/include/luna/SafeArithmetic.h new file mode 100644 index 00000000..95f48ce4 --- /dev/null +++ b/luna/include/luna/SafeArithmetic.h @@ -0,0 +1,56 @@ +#pragma once +#include + +template Result safe_add(T a, T b) +{ + T result; + + if (__builtin_add_overflow(a, b, &result)) return err(EOVERFLOW); + + return result; +} + +template Result safe_sub(T a, T b) +{ + T result; + + if (__builtin_sub_overflow(a, b, &result)) return err(EOVERFLOW); + + return result; +} + +template Result safe_mul(T a, T b) +{ + T result; + + if (__builtin_mul_overflow(a, b, &result)) return err(EOVERFLOW); + + return result; +} + +template bool add_will_overflow(T a, T b) +{ +#ifdef __GNUC__ + return __builtin_add_overflow_p(a, b, (T)0); +#else + return safe_add(a, b).has_error(); +#endif +} + +template bool sub_will_overflow(T a, T b) +{ +#ifdef __GNUC__ + return __builtin_sub_overflow_p(a, b, (T)0); +#else + return safe_sub(a, b).has_error(); +#endif +} + +template bool mul_will_overflow(T a, T b) +{ +#ifdef __GNUC__ + return __builtin_mul_overflow_p(a, b, (T)0); +#else + return safe_mul(a, b).has_error(); +#endif +} diff --git a/luna/include/luna/ScopeGuard.h b/luna/include/luna/ScopeGuard.h new file mode 100644 index 00000000..faded0ba --- /dev/null +++ b/luna/include/luna/ScopeGuard.h @@ -0,0 +1,28 @@ +#pragma once + +template class ScopeGuard +{ + public: + ScopeGuard(const Callback& callback) : m_callback(callback) + { + } + + void deactivate() + { + m_activated = false; + } + + ~ScopeGuard() + { + if (m_activated) m_callback(); + } + + private: + bool m_activated { true }; + Callback m_callback; +}; + +template [[nodiscard]] ScopeGuard make_scope_guard(const Callback& callback) +{ + return { callback }; +} diff --git a/luna/include/luna/SharedPtr.h b/luna/include/luna/SharedPtr.h new file mode 100644 index 00000000..304b906e --- /dev/null +++ b/luna/include/luna/SharedPtr.h @@ -0,0 +1,136 @@ +#pragma once +#include +#include +#include +#include +#include + +namespace __detail +{ + struct RefCount + { + void ref() + { + m_ref_count++; + } + + bool unref() + { + m_ref_count--; + return m_ref_count == 0; + } + + private: + Atomic m_ref_count { 1 }; + }; +} + +template class SharedPtr +{ + using RefCount = __detail::RefCount; + + public: + SharedPtr(T* ptr, RefCount* ref_count) : m_ptr(ptr), m_ref_count(ref_count) + { + } + + SharedPtr(const SharedPtr& other) : m_ptr(other.m_ptr), m_ref_count(other.m_ref_count) + { + m_ref_count->ref(); + } + + SharedPtr(SharedPtr&& other) : m_ptr(other.m_ptr), m_ref_count(other.m_ref_count) + { + other.m_ptr = nullptr; + other.m_ref_count = nullptr; + } + + ~SharedPtr() + { + if (m_ref_count && m_ref_count->unref()) + { + delete m_ref_count; + delete m_ptr; + } + } + + SharedPtr& operator=(const SharedPtr& other) + { + if (&other == this) return *this; + + if (m_ref_count && m_ref_count->unref()) + { + delete m_ref_count; + delete m_ptr; + } + + m_ptr = other.m_ptr; + m_ref_count = other.m_ref_count; + + m_ref_count->ref(); + + return *this; + } + + T* ptr() const + { + return m_ptr; + } + + T* operator->() const + { + return m_ptr; + } + + T& operator*() const + { + return *m_ptr; + } + + private: + T* m_ptr; + RefCount* m_ref_count; +}; + +template Result> make_shared(Args... args) +{ + using RefCount = __detail::RefCount; + + RefCount* ref_count = TRY(make()); + auto guard = make_scope_guard([&] { delete ref_count; }); + + T* ptr = TRY(make(args...)); + guard.deactivate(); + + return SharedPtr { ptr, ref_count }; +} + +template Result> adopt_shared(T* ptr) +{ + using RefCount = __detail::RefCount; + + RefCount* ref_count = TRY(make()); + + return SharedPtr { ptr, ref_count }; +} + +template Result> adopt_shared_if_nonnull(T* ptr) +{ + if (ptr) return adopt_shared(ptr); + else + return err(ENOMEM); +} + +template Result> adopt_shared_from_owned(OwnedPtr&& other) +{ + T* ptr = other.m_ptr; + other.m_ptr = nullptr; + + auto guard = make_scope_guard([&] { delete ptr; }); + + SharedPtr shared_ptr = TRY(adopt_shared(ptr)); + + guard.deactivate(); + + return shared_ptr; +} diff --git a/luna/include/luna/Stack.h b/luna/include/luna/Stack.h new file mode 100644 index 00000000..fbd3f64c --- /dev/null +++ b/luna/include/luna/Stack.h @@ -0,0 +1,24 @@ +#pragma once +#include + +struct Stack +{ + Stack() = default; + Stack(u64 base, usize bytes); + + u64 bottom() + { + return m_base; + } + + u64 top(); + + usize bytes() + { + return m_bytes; + } + + private: + u64 m_base; + usize m_bytes; +}; diff --git a/luna/include/luna/Syscall.h b/luna/include/luna/Syscall.h new file mode 100644 index 00000000..2b36b2e9 --- /dev/null +++ b/luna/include/luna/Syscall.h @@ -0,0 +1,12 @@ +#pragma once + +#define enumerate_syscalls(_e) _e(exit) _e(console_write) _e(clock_gettime) + +enum Syscalls +{ +#undef __enumerate +#define __enumerate(name) SYS_##name, + enumerate_syscalls(__enumerate) +#undef __enumerate + __count +}; diff --git a/luna/include/luna/SystemError.h b/luna/include/luna/SystemError.h new file mode 100644 index 00000000..45f4f921 --- /dev/null +++ b/luna/include/luna/SystemError.h @@ -0,0 +1,63 @@ +#pragma once + +#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 // Input/output 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 descriptor +#define ECHILD 10 // No child processes +#define EAGAIN 11 // Resource temporarily unavailable +#define EWOULDBLOCK 11 // Resource temporarily unavailable +#define ENOMEM 12 // Cannot allocate 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 // Invalid 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 // Too many open files in system +#define EMFILE 24 // Too many open files +#define ENOTTY 25 // Inappropriate ioctl for device +#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 // Numerical argument out of domain +#define ERANGE 34 // Numerical result out of range +#define EDEADLK 35 // Resource deadlock avoided +#define ENAMETOOLONG 36 // File name too long +#define ENOLCK 37 // No locks available +#define ENOSYS 38 // Function not implemented +#define ENOTEMPTY 39 // Directory not empty +#define ELOOP 40 // Too many levels of symbolic links +#define ENOMSG 42 // No message of desired type +#define EOVERFLOW 75 // Value too large for defined data type +#define EILSEQ 84 // Invalid or incomplete multibyte or wide character +#define ENOTSOCK 88 // Socket operation on non-socket +#define ENOTSUP 95 // Operation not supported +#define EOPNOTSUPP 95 // Operation not supported +#define EADDRINUSE 98 // Address already in use +#define ENETRESET 102 // Network dropped connection on reset +#define ECONNRESET 104 // Connection reset by peer +#define EISCONN 106 // Transport endpoint is already connected +#define ETIMEDOUT 110 // Connection timed out +#define EALREADY 114 // Operation already in progress + +#if defined(IN_MOON) || defined(USE_FREESTANDING) || defined(_LUNA_SYSTEM_ERROR_EXTENSIONS) +// This one is Luna-specific. +#define EFIXME 342 // Functionality not yet implemented + +const char* error_string(int error); + +#endif diff --git a/luna/include/luna/TarStream.h b/luna/include/luna/TarStream.h new file mode 100644 index 00000000..e21a0aa3 --- /dev/null +++ b/luna/include/luna/TarStream.h @@ -0,0 +1,70 @@ +#pragma once +#include +#include +#include + +class TarStream +{ + public: + enum class EntryType + { + RegularFile, + Directory + }; + + struct Entry + { + char name[257]; + usize size; + EntryType type; + + private: + usize pos; + + friend class TarStream; + }; + + TarStream() = default; + TarStream(void* base, usize size); + + void initialize(void* base, usize size); + + Result read_next_entry(); + + void rewind(); + + usize read_contents(const Entry& entry, void* buf, usize offset, usize length) const; + + Result read_contents_as_string(const Entry& entry, usize offset, usize max) const; + + private: + struct [[gnu::packed]] TarHeader + { + char name[100]; + char mode[8]; + char uid[8]; + char gid[8]; + char size[12]; + char mtime[12]; + char chksum[8]; + char typeflag; + char linkname[100]; + char magic[6]; + char version[2]; + char uname[32]; + char gname[32]; + char devmajor[8]; + char devminor[8]; + char prefix[155]; + }; + + Result find_valid_header(TarHeader* out, bool& success); + + Result read_header(TarHeader* out); + Result parse_header(const TarHeader* hdr); + + void* m_base; + void* m_pos; + usize m_size; + usize m_offset = 0; +}; diff --git a/luna/include/luna/TypeTraits.h b/luna/include/luna/TypeTraits.h new file mode 100644 index 00000000..4894ac1a --- /dev/null +++ b/luna/include/luna/TypeTraits.h @@ -0,0 +1,49 @@ +#pragma once + +template inline constexpr bool IsBaseOf = __is_base_of(Base, Derived); +template inline constexpr bool IsPowerOfTwo = (value & (value - 1)) == 0; + +template struct __remove_const_impl +{ + using type = T; +}; + +template struct __remove_const_impl +{ + using type = T; +}; + +template using RemoveConst = __remove_const_impl::type; + +template struct __remove_volatile_impl +{ + using type = T; +}; + +template struct __remove_volatile_impl +{ + using type = T; +}; + +template using RemoveVolatile = __remove_volatile_impl::type; + +template using RemoveCV = RemoveVolatile>; + +template struct __remove_ref_impl +{ + using type = T; +}; + +template struct __remove_ref_impl +{ + using type = T; +}; + +template struct __remove_ref_impl +{ + using type = T; +}; + +template using RemoveReference = __remove_ref_impl::type; + +template using RemoveCVReference = RemoveCV>; diff --git a/luna/include/luna/Types.h b/luna/include/luna/Types.h new file mode 100644 index 00000000..e1924440 --- /dev/null +++ b/luna/include/luna/Types.h @@ -0,0 +1,25 @@ +#include +#include + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; +typedef int8_t i8; +typedef int16_t i16; +typedef int32_t i32; +typedef int64_t i64; +typedef size_t usize; +typedef intptr_t isize; + +static_assert(sizeof(u8) == 1UL); +static_assert(sizeof(u16) == 2UL); +static_assert(sizeof(u32) == 4UL); +static_assert(sizeof(u64) == 8UL); +static_assert(sizeof(i8) == 1UL); +static_assert(sizeof(i16) == 2UL); +static_assert(sizeof(i32) == 4UL); +static_assert(sizeof(i64) == 8UL); + +static_assert(sizeof(usize) == sizeof(void*)); +static_assert(sizeof(isize) == sizeof(void*)); diff --git a/luna/include/luna/Units.h b/luna/include/luna/Units.h new file mode 100644 index 00000000..edc22635 --- /dev/null +++ b/luna/include/luna/Units.h @@ -0,0 +1,6 @@ +#pragma once +#include +#include + +usize to_dynamic_unit_cstr(usize value, char* buffer, usize max); +Result to_dynamic_unit(usize value); diff --git a/luna/include/luna/Utf8.h b/luna/include/luna/Utf8.h new file mode 100644 index 00000000..2f5b1b45 --- /dev/null +++ b/luna/include/luna/Utf8.h @@ -0,0 +1,69 @@ +#pragma once +#include +#include +#include + +class Utf8StringDecoder +{ + public: + Utf8StringDecoder(const char* str); + + usize byte_length() const + { + return m_byte_length; + } + + Result code_points() const; + + // The caller must ensure that 'buf' is at least code_points() + a NULL wide. + Result decode(wchar_t* buf) const; + + Result decode(wchar_t* buf, size_t max) const; + + private: + const char* m_str; + usize m_byte_length; +}; + +class Utf8StringEncoder +{ + public: + Utf8StringEncoder(const wchar_t* str); + + usize code_points() const + { + return m_code_points; + } + + Result byte_length() const; + + // The caller must ensure that 'buf' is at least byte_length() + a NULL wide. + Result encode(char* buf) const; + + Result encode(char* buf, size_t max) const; + + private: + const wchar_t* m_str; + usize m_code_points; +}; + +class Utf8StateDecoder +{ + public: + Utf8StateDecoder(); + + Result> feed(char c); + void reset(); + + private: + char m_state[4]; + usize m_state_len = 0; + usize m_state_index = 0; +}; + +class Utf8Encoder +{ + public: + // Does not null-terminate. Returns the number of bytes written. + Result encode(wchar_t c, char buf[4]); +}; diff --git a/luna/src/Alloc.cpp b/luna/src/Alloc.cpp new file mode 100644 index 00000000..65d8c609 --- /dev/null +++ b/luna/src/Alloc.cpp @@ -0,0 +1,38 @@ +#include + +#ifndef USE_FREESTANDING +#include +#endif + +[[nodiscard]] void* raw_malloc(usize size) +{ +#ifdef USE_FREESTANDING + char* const rc = new (std::nothrow) char[size]; + return (void*)rc; +#else + // return malloc(size); + (void)size; + return NULL; +#endif +} + +void raw_free(void* ptr) +{ +#ifdef USE_FREESTANDING + char* const arr = (char*)ptr; + delete[] arr; +#else + // return free(ptr); + (void)ptr; +#endif +} + +void operator delete(void* ptr, usize size, std::align_val_t) noexcept +{ +#ifdef USE_FREESTANDING + operator delete(ptr, size); +#else + (void)ptr; + (void)size; +#endif +} diff --git a/luna/src/Bitmap.cpp b/luna/src/Bitmap.cpp new file mode 100644 index 00000000..5a3e5130 --- /dev/null +++ b/luna/src/Bitmap.cpp @@ -0,0 +1,88 @@ +#include +#include +#include + +Bitmap::Bitmap() +{ +} + +Bitmap::Bitmap(void* location, usize size_in_bytes) : m_location((u8*)location), m_size_in_bytes(size_in_bytes) +{ +} + +void Bitmap::initialize(void* location, usize size_in_bytes) +{ + m_location = (u8*)location; + m_size_in_bytes = size_in_bytes; +} + +void* Bitmap::move(void* new_location, usize new_location_size_in_bytes) +{ + expect(initialized(), "Bitmap was never initialized"); + + if (new_location_size_in_bytes > m_size_in_bytes) memcpy(new_location, m_location, m_size_in_bytes); + else + memcpy(new_location, m_location, new_location_size_in_bytes); + + void* old_location = (void*)m_location; + + m_location = (u8*)new_location; + m_size_in_bytes = new_location_size_in_bytes; + + return old_location; +} + +void Bitmap::set(usize index, bool value) +{ + expect(initialized(), "Bitmap was never initialized"); + expect(index < size(), "Bitmap access out of range"); + u64 byte_index = index / 8; + u8 bit_mask = (u8)(0b10000000 >> (index % 8)); + m_location[byte_index] &= (u8)(~bit_mask); + if (value) { m_location[byte_index] |= bit_mask; } +} + +bool Bitmap::get(usize index) const +{ + expect(initialized(), "Bitmap was never initialized"); + expect(index < size(), "Bitmap access out of range"); + usize byte_index = index / 8; + u8 bit_mask = (u8)(0b10000000 >> (index % 8)); + return (m_location[byte_index] & bit_mask) > 0; +} + +void Bitmap::clear(bool value) +{ + expect(initialized(), "Bitmap was never initialized"); + memset(m_location, value_byte(value), m_size_in_bytes); +} + +void Bitmap::clear_region(usize start, usize bits, bool value) +{ + expect(initialized(), "Bitmap was never initialized"); + expect((start + bits) <= size(), "Bitmap clear out of range"); + + if (!bits) return; + + // Set individual bits while not on a byte boundary. + while ((start % 8) && bits) + { + set(start, value); + start++; + bits--; + } + + // Clear out the rest in bytes. + usize bytes = bits / 8; + + memset(&m_location[start / 8], value_byte(value), bytes); + start += bytes * 8; + bits -= bytes * 8; + + // Set the remaining individual bits. + while (bits--) + { + set(start, value); + start++; + } +} diff --git a/luna/src/CString.cpp b/luna/src/CString.cpp new file mode 100644 index 00000000..06f129f6 --- /dev/null +++ b/luna/src/CString.cpp @@ -0,0 +1,108 @@ +#include +#include + +extern "C" +{ + void* memcpy(void* dest, const void* src, usize n) + { + for (usize i = 0; i < n; ++i) { *((u8*)dest + i) = *((const u8*)src + i); } + return dest; + } + + void* memset(void* buf, int c, usize n) + { + for (usize i = 0; i < n; ++i) { *((u8*)buf + i) = (u8)c; } + return buf; + } + + int memcmp(const void* a, const void* b, usize n) + { + if (!n) return 0; + const u8* ap = (const u8*)a; + const u8* bp = (const u8*)b; + while (--n && *ap == *bp) + { + ap++; + bp++; + } + return *ap - *bp; + } + + void* memmove(void* dest, const void* src, usize n) + { + if (dest == src) return dest; + if (dest > src) + for (long i = (long)n - 1; i >= 0; i++) { *((u8*)dest + i) = *((const u8*)src + i); } + else + for (long i = 0; i < (long)n; i++) { *((u8*)dest + i) = *((const u8*)src + i); } + return dest; + } + + usize strlen(const char* str) + { + const char* i = str; + for (; *i; ++i) + ; + return (usize)(i - str); + } + + int strcmp(const char* a, const char* b) + { + while (*a && (*a == *b)) + { + a++; + b++; + } + return *(const u8*)a - *(const u8*)b; + } + + usize wcslen(const wchar_t* str) + { + const wchar_t* i = str; + for (; *i; ++i) + ; + return (usize)(i - str); + } + + char* strdup(const char* str) + { + const usize len = strlen(str); + + char* dest = (char*)raw_malloc(len + 1); + if (!dest) return nullptr; + + memcpy(dest, str, len + 1); + + return dest; + } + + void nullcpy(char* dest, const char* src, usize len) + { + memcpy(dest, src, len); + dest[len] = 0; + } + + char* strcpy(char* dest, const char* src) + { + char* s = dest; + for (; *src; dest++, src++) *dest = *src; + *dest = 0; + return s; + } + + char* strcat(char* dest, const char* src) + { + char* s = dest; + while (*dest) dest++; + for (; *src; dest++, src++) *dest = *src; + *dest = 0; + return s; + } + + char* strchr(const char* str, int c) + { + while (*str && *str != c) str++; + if (*str) return const_cast(str); + return NULL; + } +} diff --git a/luna/src/Check.cpp b/luna/src/Check.cpp new file mode 100644 index 00000000..b57856e7 --- /dev/null +++ b/luna/src/Check.cpp @@ -0,0 +1,6 @@ +#include + +_weak [[noreturn]] bool __check_failed(const char*, const char*, const char*, const char*) +{ + __builtin_trap(); +} diff --git a/luna/src/DebugLog.cpp b/luna/src/DebugLog.cpp new file mode 100644 index 00000000..c926390c --- /dev/null +++ b/luna/src/DebugLog.cpp @@ -0,0 +1,9 @@ +#include + +void dbgln(const char* format, ...) +{ + va_list ap; + va_start(ap, format); + debug_log_impl(format, ap); + va_end(ap); +} diff --git a/luna/src/Format.cpp b/luna/src/Format.cpp new file mode 100644 index 00000000..c06a51a9 --- /dev/null +++ b/luna/src/Format.cpp @@ -0,0 +1,696 @@ +#include +#include +#include +#include +#include +#include + +extern "C" usize strlen(const char*); + +typedef int flags_t; +#define FLAG_ZERO_PAD 1 << 0 +#define FLAG_LEFT_ALIGN 1 << 1 +#define FLAG_BLANK_SIGNED 1 << 2 +#define FLAG_ALTERNATE 1 << 3 +#define FLAG_SIGN 1 << 4 +#define FLAG_USE_PRECISION 1 << 5 +#define FLAG_LONG 1 << 6 +#define FLAG_LONG_LONG 1 << 7 +#define FLAG_SHORT 1 << 8 +#define FLAG_CHAR 1 << 9 + +struct format_state +{ + usize count; + callback_t callback; + void* arg; +}; + +struct pure_format_state +{ + usize count; + pure_callback_t callback; + void* arg; +}; + +struct conv_state +{ + flags_t flags; + usize width; + usize precision; +}; + +static Result format_putchar(char c, format_state& state) +{ + state.count++; + return state.callback(c, state.arg); +} + +static void pure_format_putchar(char c, pure_format_state& state) +{ + state.count++; + return state.callback(c, state.arg); +} + +static Result format_puts(const char* s, format_state& state) +{ + while (*s) + { + TRY(format_putchar(*s, state)); + s++; + } + + return {}; +} + +static void pure_format_puts(const char* s, pure_format_state& state) +{ + while (*s) + { + pure_format_putchar(*s, state); + s++; + } +} + +static Result start_pad(const conv_state& vstate, format_state& state, usize start) +{ + if (!(vstate.flags & FLAG_LEFT_ALIGN)) + { + while (start++ < vstate.width) TRY(format_putchar(' ', state)); + } + + return {}; +} + +static void pure_start_pad(const conv_state& vstate, pure_format_state& state, usize start) +{ + if (!(vstate.flags & FLAG_LEFT_ALIGN)) + { + while (start++ < vstate.width) pure_format_putchar(' ', state); + } +} + +static Result end_pad(const conv_state& vstate, format_state& state, usize start) +{ + if (vstate.flags & FLAG_LEFT_ALIGN) + { + while (start++ < vstate.width) TRY(format_putchar(' ', state)); + } + + return {}; +} + +static void pure_end_pad(const conv_state& vstate, pure_format_state& state, usize start) +{ + if (vstate.flags & FLAG_LEFT_ALIGN) + { + while (start++ < vstate.width) pure_format_putchar(' ', state); + } +} + +static flags_t parse_flags(const char** format) +{ + flags_t result = 0; + + while (true) + { + switch (**format) + { + case '#': + result |= FLAG_ALTERNATE; + (*format)++; + break; + case '0': + result |= FLAG_ZERO_PAD; + (*format)++; + break; + case ' ': + result |= FLAG_BLANK_SIGNED; + (*format)++; + break; + case '-': + result |= FLAG_LEFT_ALIGN; + (*format)++; + break; + case '+': + result |= FLAG_SIGN; + (*format)++; + break; + default: return result; + } + } +} + +static usize parse_width(const char** format, flags_t& flags, va_list ap) +{ + usize result = 0; + + if (_isdigit(**format)) result = scan_unsigned_integer(format); + else if (**format == '*') + { + const int width = va_arg(ap, int); + if (width >= 0) result = (usize)width; + else + { + flags |= FLAG_LEFT_ALIGN; + result = (usize)-width; + } + } + + return result; +} + +static usize parse_precision(const char** format, flags_t& flags, va_list ap) +{ + usize result = 0; + + if (**format == '.') + { + (*format)++; + + flags |= FLAG_USE_PRECISION; + + if (_isdigit(**format)) result = scan_unsigned_integer(format); + else if (**format == '*') + { + const int precision = va_arg(ap, int); + if (precision >= 0) result = (usize)precision; + else + result = 0; + } + } + + return result; +} + +static void parse_length(const char** format, flags_t& flags) +{ + // FIXME: Support %j (intmax_t/uintmax_t) + switch (**format) + { + case 'h': + flags |= FLAG_SHORT; + (*format)++; + if (**format == 'h') + { + flags |= FLAG_CHAR; + (*format)++; + } + break; + case 'l': + flags |= FLAG_LONG; + (*format)++; + if (**format == 'l') + { + flags |= FLAG_LONG_LONG; + (*format)++; + } + break; + case 't': + flags |= (sizeof(ptrdiff_t) == sizeof(long)) ? FLAG_LONG : FLAG_LONG_LONG; + (*format)++; + break; + case 'z': + flags |= (sizeof(usize) == sizeof(long)) ? FLAG_LONG : FLAG_LONG_LONG; + (*format)++; + break; + default: break; + } +} + +static bool is_integer_format_specifier(char c) +{ + return (c == 'd') || (c == 'i') || (c == 'u') || (c == 'x') || (c == 'X') || (c == 'o') || (c == 'b'); +} + +static usize to_string(usize value, usize base, char* buf, usize max, bool uppercase) +{ + usize i = 0; + if (!max) return 0; + if (!value) + { + buf[i] = '0'; + return 1; + } + do { + const int digit = (int)(value % base); + const char c = (char)(digit < 10 ? '0' + digit : ((uppercase ? 'A' : 'a') + (digit - 10))); + buf[i++] = c; + value /= base; + } while (value && i < max); + return i; +} + +static Result output_integer_data(conv_state& vstate, format_state& state, char* buf, usize len) +{ + if (!(vstate.flags & FLAG_ZERO_PAD)) TRY(start_pad(vstate, state, len)); + + usize i = len; + + while (i--) TRY(format_putchar(buf[i], state)); + + TRY(end_pad(vstate, state, len)); + + return {}; +} + +static void output_pure_integer_data(conv_state& vstate, pure_format_state& state, char* buf, usize len) +{ + if (!(vstate.flags & FLAG_ZERO_PAD)) pure_start_pad(vstate, state, len); + + usize i = len; + + while (i--) pure_format_putchar(buf[i], state); + + pure_end_pad(vstate, state, len); +} + +template +static ReturnType output_integer_generic(char specifier, conv_state& vstate, FormatStateType& state, usize value, + bool negative, + ReturnType (*output_data)(conv_state&, FormatStateType&, char*, usize)) +{ + usize base = 10; + bool uppercase = false; + + switch (specifier) + { + case 'p': + case 'x': + case 'X': base = 16; break; + case 'o': base = 8; break; + case 'b': base = 2; break; + default: break; + } + if (specifier == 'X') uppercase = true; + + if (base == 10) vstate.flags &= ~FLAG_ALTERNATE; // decimal doesn't have an alternate form + + char buf[1024]; + usize buflen = to_string(value, base, buf, sizeof(buf), uppercase); + + if (!(vstate.flags & FLAG_LEFT_ALIGN) && + (vstate.flags & FLAG_ZERO_PAD)) // we're padding with zeroes from the beginning + { + const bool extra_char = + negative || ((vstate.flags & FLAG_SIGN) || + (vstate.flags & FLAG_BLANK_SIGNED)); // are we adding an extra character after the buffer? + if (vstate.width && extra_char) vstate.width--; + + if (vstate.width && (vstate.flags & FLAG_ALTERNATE)) // fit in the characters we're using for the alternate form + { + vstate.width--; + if (vstate.width && (base == 2 || base == 16)) vstate.width--; + } + + while (buflen < vstate.width && buflen < sizeof(buf)) buf[buflen++] = '0'; + } + + while (buflen < vstate.precision && buflen < sizeof(buf)) buf[buflen++] = '0'; + + if (vstate.flags & FLAG_ALTERNATE) + { + if (base == 16 && !uppercase && buflen < sizeof(buf)) buf[buflen++] = 'x'; + if (base == 16 && uppercase && buflen < sizeof(buf)) buf[buflen++] = 'X'; + if (base == 2 && buflen < sizeof(buf)) buf[buflen++] = 'b'; + if (buflen < sizeof(buf)) buf[buflen++] = '0'; + } + + if (buflen < sizeof(buf)) + { + if (negative) buf[buflen++] = '-'; + else if (vstate.flags & FLAG_SIGN) + buf[buflen++] = '+'; + else if (vstate.flags & FLAG_BLANK_SIGNED) + buf[buflen++] = ' '; + } + + return output_data(vstate, state, buf, buflen); +} + +static Result output_integer(char specifier, conv_state& vstate, format_state& state, usize value, bool negative) +{ + return output_integer_generic, format_state>(specifier, vstate, state, value, negative, + output_integer_data); +} + +static void pure_output_integer(char specifier, conv_state& vstate, pure_format_state& state, usize value, + bool negative) +{ + return output_integer_generic(specifier, vstate, state, value, negative, + output_pure_integer_data); +} + +template +static ReturnType va_generic_output_integer(char specifier, conv_state& vstate, FormatStateType& state, + ReturnType (*integer_output)(char, conv_state&, FormatStateType&, usize, + bool), + va_list ap) +{ + bool is_signed = false; + bool negative = false; + + if (specifier == 'd' || specifier == 'i') is_signed = true; + + if (!is_signed) vstate.flags &= ~(FLAG_SIGN | FLAG_BLANK_SIGNED); + + if (vstate.flags & FLAG_CHAR) + { + if (is_signed) + { + char v = (char)va_arg(ap, int); + if (v < 0) + { + v = -v; + negative = true; + } + return integer_output(specifier, vstate, state, (unsigned char)v, negative); + } + else + { + const unsigned char v = (unsigned char)va_arg(ap, unsigned int); + return integer_output(specifier, vstate, state, v, false); + } + } + else if (vstate.flags & FLAG_SHORT) + { + if (is_signed) + { + short v = (short)va_arg(ap, int); + if (v < 0) + { + v = -v; + negative = true; + } + return integer_output(specifier, vstate, state, (unsigned short)v, negative); + } + else + { + const unsigned short v = (unsigned short)va_arg(ap, unsigned int); + return integer_output(specifier, vstate, state, v, false); + } + } + else if (vstate.flags & FLAG_LONG_LONG) + { + if (is_signed) + { + long long v = va_arg(ap, long long); + if (v < 0) + { + v = -v; + negative = true; + } + return integer_output(specifier, vstate, state, (unsigned long long)v, negative); + } + else + { + const unsigned long long v = va_arg(ap, unsigned long long); + return integer_output(specifier, vstate, state, v, false); + } + } + else if (vstate.flags & FLAG_LONG) + { + if (is_signed) + { + long v = va_arg(ap, long); + if (v < 0) + { + v = -v; + negative = true; + } + return integer_output(specifier, vstate, state, (unsigned long)v, negative); + } + else + { + const unsigned long v = va_arg(ap, unsigned long); + return integer_output(specifier, vstate, state, v, false); + } + } + else + { + if (is_signed) + { + int v = va_arg(ap, int); + if (v < 0) + { + v = -v; + negative = true; + } + return integer_output(specifier, vstate, state, (unsigned int)v, negative); + } + else + { + const unsigned int v = va_arg(ap, unsigned int); + return integer_output(specifier, vstate, state, v, false); + } + } +} + +static Result va_output_integer(char specifier, conv_state& vstate, format_state& state, va_list ap) +{ + return va_generic_output_integer, format_state>(specifier, vstate, state, output_integer, ap); +} + +static void va_pure_output_integer(char specifier, conv_state& vstate, pure_format_state& state, va_list ap) +{ + return va_generic_output_integer(specifier, vstate, state, pure_output_integer, ap); +} + +Result cstyle_format(const char* format, callback_t callback, void* arg, va_list ap) +{ + format_state state; + state.callback = callback; + state.arg = arg; + state.count = 0; + + while (*format) + { + if (*format != '%') + { + TRY(format_putchar(*format, state)); + format++; + continue; + } + + format++; + + if (*format == '%') + { + TRY(format_putchar('%', state)); + continue; + } + + // %[flags][width][.precision][length]conversion + + flags_t flags = parse_flags(&format); + const usize width = parse_width(&format, flags, ap); + usize precision = parse_precision(&format, flags, ap); + parse_length(&format, flags); + + conv_state vstate = { flags, width, precision }; + + const char specifier = *format; + format++; + + if (is_integer_format_specifier(specifier)) + { + TRY(va_output_integer(specifier, vstate, state, ap)); + continue; + } + else if (specifier == 'p') + { + const void* ptr = va_arg(ap, void*); + if (ptr == nullptr) + { + TRY(start_pad(vstate, state, 5)); + TRY(format_puts("(nil)", state)); + TRY(end_pad(vstate, state, 5)); + continue; + } + vstate.width = (sizeof(void*) * 2) + 2; + vstate.flags |= (FLAG_ZERO_PAD | FLAG_ALTERNATE); + TRY(output_integer('p', vstate, state, (usize)ptr, false)); + continue; + } + else if (specifier == 'c') + { + const char c = (char)va_arg(ap, int); + + TRY(start_pad(vstate, state, 1)); + TRY(format_putchar(c, state)); + TRY(end_pad(vstate, state, 1)); + + continue; + } + else if (specifier == 's') + { + const char* str = va_arg(ap, const char*); + if (str == nullptr) + { + TRY(start_pad(vstate, state, 6)); + TRY(format_puts("(null)", state)); + TRY(end_pad(vstate, state, 6)); + continue; + } + else + { + usize len = strlen(str); + + bool use_precision = (flags & FLAG_USE_PRECISION); + if (use_precision && len > precision) len = precision; + + TRY(start_pad(vstate, state, len)); + while (*str && (!use_precision || precision)) + { + TRY(format_putchar(*str, state)); + precision--; + str++; + } + TRY(end_pad(vstate, state, len)); + continue; + } + } + else { continue; } + } + + return state.count; +} + +usize pure_cstyle_format(const char* format, pure_callback_t callback, void* arg, va_list ap) +{ + pure_format_state state; + state.callback = callback; + state.arg = arg; + state.count = 0; + + while (*format) + { + if (*format != '%') + { + pure_format_putchar(*format, state); + format++; + continue; + } + + format++; + + if (*format == '%') + { + pure_format_putchar('%', state); + continue; + } + + // %[flags][width][.precision][length]conversion + + flags_t flags = parse_flags(&format); + const usize width = parse_width(&format, flags, ap); + usize precision = parse_precision(&format, flags, ap); + parse_length(&format, flags); + + conv_state vstate = { flags, width, precision }; + + const char specifier = *format; + format++; + + if (is_integer_format_specifier(specifier)) + { + va_pure_output_integer(specifier, vstate, state, ap); + continue; + } + else if (specifier == 'p') + { + const void* ptr = va_arg(ap, void*); + if (ptr == nullptr) + { + pure_start_pad(vstate, state, 5); + pure_format_puts("(nil)", state); + pure_end_pad(vstate, state, 5); + continue; + } + vstate.width = (sizeof(void*) * 2) + 2; + vstate.flags |= (FLAG_ZERO_PAD | FLAG_ALTERNATE); + pure_output_integer('p', vstate, state, (usize)ptr, false); + continue; + } + else if (specifier == 'c') + { + const char c = (char)va_arg(ap, int); + + pure_start_pad(vstate, state, 1); + pure_format_putchar(c, state); + pure_end_pad(vstate, state, 1); + + continue; + } + else if (specifier == 's') + { + const char* str = va_arg(ap, const char*); + if (str == nullptr) + { + pure_start_pad(vstate, state, 6); + pure_format_puts("(null)", state); + pure_end_pad(vstate, state, 6); + continue; + } + else + { + usize len = strlen(str); + + bool use_precision = (flags & FLAG_USE_PRECISION); + if (use_precision && len > precision) len = precision; + + pure_start_pad(vstate, state, len); + while (*str && (!use_precision || precision)) + { + pure_format_putchar(*str, state); + precision--; + str++; + } + pure_end_pad(vstate, state, len); + continue; + } + } + else { continue; } + } + + return state.count; +} + +struct StringFormatInfo +{ + char* buffer; + usize remaining; +}; + +usize vstring_format(char* buf, usize max, const char* format, va_list ap) +{ + StringFormatInfo info = { .buffer = buf, .remaining = max - 1 }; + + usize result = pure_cstyle_format( + format, + [](char c, void* arg) { + StringFormatInfo* info_arg = (StringFormatInfo*)arg; + if (!info_arg->remaining) return; + *(info_arg->buffer) = c; + info_arg->buffer++; + info_arg->remaining--; + return; + }, + &info, ap); + + *(info.buffer) = 0; + + return result; +} + +usize string_format(char* buf, usize max, const char* format, ...) +{ + va_list ap; + va_start(ap, format); + + usize result = vstring_format(buf, max, format, ap); + + va_end(ap); + + return result; +} diff --git a/luna/src/NumberParsing.cpp b/luna/src/NumberParsing.cpp new file mode 100644 index 00000000..b9345452 --- /dev/null +++ b/luna/src/NumberParsing.cpp @@ -0,0 +1,100 @@ +#include +#include +#include + +// This function assumes you have called is_valid_digit_for_base() to validate the digit first. +static isize parse_digit_unchecked(char c) +{ + if (_isdigit(c)) return c - '0'; + if (_islower(c)) return (c - 'a') + 10; + return (c - 'A') + 10; +} + +static bool is_valid_digit_for_base(int base, char c) +{ + if (!_isalnum(c)) return false; + if (parse_digit_unchecked(c) >= (isize)base) return false; + return true; +} + +static usize do_unsigned_parse(const char* str, const char** endptr, int base) +{ + usize val = 0; + + // 1. If base is zero or 16, the string may then include a "0x" prefix, and the number will be read in base 16; + // otherwise, a zero base is taken as 10 (decimal) unless the next character is '0', in which case it is taken as + // 8 (octal). + if ((base == 0 || base == 16) && *str == '0') + { + str++; + if (_tolower(*str) == 'x') + { + base = 16; + str++; + } + else if (base == 0) + base = 8; + } + else if (base == 0) + base = 10; + + // 2. The remainder of the string is converted to an unsigned long value in + // the obvious manner, stopping at the first character which is not a + // valid digit in the given base. + while (is_valid_digit_for_base(base, *str)) + { + val = ((usize)base * val) + (usize)parse_digit_unchecked(*str); + str++; + } + + // 3. If endptr is not NULL, this function stores the address of the first invalid character in *endptr. + if (endptr) *endptr = str; + + return val; +} + +usize parse_unsigned_integer(const char* str, const char** endptr, int base) +{ + // The string may begin with an arbitrary amount of white space (as determined by isspace(3)), + while (_isspace(*str)) str++; + + // followed by a single optional '+' or '-' sign. + if (*str == '-' || *str == '+') str++; + + return do_unsigned_parse(str, endptr, base); +} + +#define SSIZE_MAX LONG_MAX +#define SSIZE_MIN (-SSIZE_MAX - (isize)1) + +isize parse_signed_integer(const char* str, const char** endptr, int base) +{ + bool negative = false; + + // The string may begin with an arbitrary amount of white space (as determined by isspace(3)), + while (_isspace(*str)) str++; + + // followed by a single optional '+' or '-' sign. + if (*str == '-' || *str == '+') + { + if (*str == '-') negative = true; + str++; + } + + usize rc = do_unsigned_parse(str, endptr, base); + + // If an underflow occurs, this function returns SSIZE_MIN. If an overflow occurs, this function returns SSIZE_MAX. + if (rc > SSIZE_MAX) { return negative ? SSIZE_MIN : SSIZE_MAX; } + + return negative ? -(isize)rc : (isize)rc; +} + +usize scan_unsigned_integer(const char** str) +{ + return parse_unsigned_integer(*str, str, 10); +} + +isize scan_signed_integer(const char** str) +{ + return parse_signed_integer(*str, str, 10); +} diff --git a/luna/src/OwnedStringView.cpp b/luna/src/OwnedStringView.cpp new file mode 100644 index 00000000..90e0f549 --- /dev/null +++ b/luna/src/OwnedStringView.cpp @@ -0,0 +1,49 @@ +#include +#include +#include + +OwnedStringView::OwnedStringView() +{ +} + +OwnedStringView::OwnedStringView(OwnedStringView&& other) +{ + m_string = other.m_string; + m_length = other.m_length; + + other.m_string = nullptr; +} + +OwnedStringView::OwnedStringView(char* c_str) +{ + m_string = c_str; + + if (m_string) { m_length = strlen(m_string); } +} + +OwnedStringView::~OwnedStringView() +{ + if (m_string) raw_free(m_string); +} + +Result OwnedStringView::clone() const +{ + char* const c_str = strdup(m_string); + + if (!c_str) return err(ENOMEM); + + return OwnedStringView { c_str }; +} + +const char& OwnedStringView::operator[](usize index) const +{ + expect(index < m_length, "index out of range"); + return m_string[index]; +} + +Result OwnedStringView::from_string_literal(const char* str) +{ + char* dup = strdup(str); + if (!dup) return err(ENOMEM); + return OwnedStringView { dup }; +} diff --git a/luna/src/Stack.cpp b/luna/src/Stack.cpp new file mode 100644 index 00000000..f323470b --- /dev/null +++ b/luna/src/Stack.cpp @@ -0,0 +1,10 @@ +#include + +Stack::Stack(u64 base, usize bytes) : m_base(base), m_bytes(bytes) +{ +} + +u64 Stack::top() +{ + return (m_base + m_bytes) - sizeof(void*); +} diff --git a/luna/src/SystemError.cpp b/luna/src/SystemError.cpp new file mode 100644 index 00000000..5237d5a7 --- /dev/null +++ b/luna/src/SystemError.cpp @@ -0,0 +1,63 @@ +#define _LUNA_SYSTEM_ERROR_EXTENSIONS +#include + +const char* error_string(int error) +{ + switch (error) + { + case 0: return "Success (not an error)"; + case EPERM: return "Operation not permitted"; + case ENOENT: return "No such file or directory"; + case ESRCH: return "No such process"; + case EINTR: return "Interrupted system call"; + case EIO: return "Input/output error"; + case ENXIO: return "No such device or address"; + case E2BIG: return "Argument list too long"; + case ENOEXEC: return "Exec format error"; + case EBADF: return "Bad file descriptor"; + case ECHILD: return "No child processes"; + case EAGAIN: return "Resource temporarily unavailable"; + case ENOMEM: return "Cannot allocate memory"; + case EACCES: return "Permission denied"; + case EFAULT: return "Bad address"; + case ENOTBLK: return "Block device required"; + case EBUSY: return "Device or resource busy"; + case EEXIST: return "File exists"; + case EXDEV: return "Invalid cross-device link"; + case ENODEV: return "No such device"; + case ENOTDIR: return "Not a directory"; + case EISDIR: return "Is a directory"; + case EINVAL: return "Invalid argument"; + case ENFILE: return "Too many open files in system"; + case EMFILE: return "Too many open files"; + case ENOTTY: return "Inappropriate ioctl for device"; + case ETXTBSY: return "Text file busy"; + case EFBIG: return "File too large"; + case ENOSPC: return "No space left on device"; + case ESPIPE: return "Illegal seek"; + case EROFS: return "Read-only file system"; + case EMLINK: return "Too many links"; + case EPIPE: return "Broken pipe"; + case EDOM: return "Numerical argument out of domain"; + case ERANGE: return "Numerical result out of range"; + case EDEADLK: return "Resource deadlock avoided"; + case ENAMETOOLONG: return "File name too long"; + case ENOLCK: return "No locks available"; + case ENOSYS: return "Function not implemented"; + case ENOTEMPTY: return "Directory not empty"; + case ELOOP: return "Too many levels of symbolic links"; + case ENOMSG: return "No message of desired type"; + case EOVERFLOW: return "Value too large for defined data type"; + case EILSEQ: return "Invalid or incomplete multibyte or wide character"; + case ENOTSOCK: return "Socket operation on non-socket"; + case ENOTSUP: return "Operation not supported"; + case EADDRINUSE: return "Address already in use"; + case ENETRESET: return "Network dropped connection on reset"; + case ECONNRESET: return "Connection reset by peer"; + case EISCONN: return "Transport endpoint is already connected"; + case ETIMEDOUT: return "Connection timed out"; + case EALREADY: return "Operation already in progress"; + case EFIXME: return "Functionality not yet implemented"; + default: return "Unknown error"; + } +} diff --git a/luna/src/TarStream.cpp b/luna/src/TarStream.cpp new file mode 100644 index 00000000..c4e4cced --- /dev/null +++ b/luna/src/TarStream.cpp @@ -0,0 +1,109 @@ +#define _LUNA_SYSTEM_ERROR_EXTENSIONS +#include +#include +#include +#include +#include + +TarStream::TarStream(void* base, usize size) : m_base(base), m_pos(base), m_size(size) +{ +} + +void TarStream::initialize(void* base, usize size) +{ + m_base = m_pos = base; + m_size = size; + m_offset = 0; +} + +void TarStream::rewind() +{ + m_pos = m_base; + m_offset = 0; +} + +Result TarStream::read_header(TarHeader* out) +{ + if ((m_offset + 512) > m_size) return err(0); + memcpy(out, m_pos, sizeof(TarHeader)); + m_pos = offset_ptr(m_pos, 512); + m_offset += 512; + return {}; +} + +Result TarStream::parse_header(const TarStream::TarHeader* hdr) +{ + Entry entry; + + char size[13]; + nullcpy(size, hdr->size, 12); + entry.size = parse_unsigned_integer(size, nullptr, 8); + + entry.pos = m_offset; + + switch (hdr->typeflag) + { + case '\0': + case '0': entry.type = EntryType::RegularFile; break; + case '5': entry.type = EntryType::Directory; break; + default: return err(EFIXME); + } + + if (!strlen(hdr->prefix)) { nullcpy(entry.name, hdr->name, 100); } + else { return err(EFIXME); } + + if (entry.size) + { + m_pos = offset_ptr(m_pos, align_up<512ul>(entry.size)); + m_offset += align_up<512ul>(entry.size); + } + + return entry; +} + +Result TarStream::find_valid_header(TarStream::TarHeader* out, bool& success) +{ + success = false; + while (true) + { + TRY(read_header(out)); + if (!memcmp(out->magic, "ustar", 5)) + { + success = true; + return {}; + } + } +} + +// FIXME: How do we know whether an error is an error or just EOF? Returning an error code of 0 as EOF seems a bit +// clunky to me... +Result TarStream::read_next_entry() +{ + bool success; + TarHeader header; + auto rc = find_valid_header(&header, success); + if (!success) return rc.release_error(); + + return parse_header(&header); +} + +usize TarStream::read_contents(const Entry& entry, void* buf, usize offset, usize length) const +{ + if (offset >= entry.size) return 0; + if ((length + offset) > entry.size) length = entry.size - offset; + + memcpy(buf, offset_ptr(m_base, entry.pos + offset), length); + + return length; +} + +Result TarStream::read_contents_as_string(const Entry& entry, usize offset, usize max) const +{ + char* buf = TRY(make_array(max + 1)); + + usize nread = read_contents(entry, buf, offset, max); + + buf[nread] = 0; + + return OwnedStringView { buf }; +} diff --git a/luna/src/Units.cpp b/luna/src/Units.cpp new file mode 100644 index 00000000..1476e637 --- /dev/null +++ b/luna/src/Units.cpp @@ -0,0 +1,28 @@ +#include +#include +#include +#include +#include + +usize to_dynamic_unit_cstr(usize value, char* buffer, usize max) +{ + if (value < 1024) { return string_format(buffer, max, "%zu bytes", value); } + + const char* unit_prefixes = "KMGTPE"; + while (value > (1024 * 1024)) + { + value /= 1024; + unit_prefixes++; + } + + return string_format(buffer, max, "%zu.%zu %ciB", value / 1024, (value % 1024) / 103, *unit_prefixes); +} + +Result to_dynamic_unit(usize value) +{ + char* buf = TRY(make_array(64)); + + to_dynamic_unit_cstr(value, buf, 64); + + return OwnedStringView { buf }; +} diff --git a/luna/src/Utf8.cpp b/luna/src/Utf8.cpp new file mode 100644 index 00000000..5ebb880d --- /dev/null +++ b/luna/src/Utf8.cpp @@ -0,0 +1,257 @@ +#include +#include +#include + +static_assert(WCHAR_MAX > 0x10ffff); + +static Result utf8_char_length(char c) +{ + if ((c & 0b11111000) == 0b11110000) return 4; + if ((c & 0b11110000) == 0b11100000) return 3; + if ((c & 0b11100000) == 0b11000000) return 2; + if ((c & 0b10000000) == 0b00000000) return 1; + return err(EILSEQ); +} + +static Result wide_char_length_as_utf8(wchar_t c) +{ + if (c <= 0x7f) return 1; + if (c <= 0x7ff) return 2; + if (c <= 0xffff) return 3; + if (c <= 0x10ffff) return 4; + return err(EILSEQ); +} + +static inline usize wide_char_length_as_utf8_unchecked(wchar_t c) +{ + if (c <= 0x7f) return 1; + if (c <= 0x7ff) return 2; + if (c <= 0xffff) return 3; + return 4; +} + +static Result encode_wide_char_as_utf8(wchar_t c, char* result, usize& len) +{ + usize utf8_len = TRY(wide_char_length_as_utf8(c)); + + if (utf8_len > len) { return err(EILSEQ); } + + u8* buf = (u8*)result; + + if (len == 1) + { + buf[0] = c & 0x7f; + return {}; + } + if (len == 2) + { + buf[0] = 0b11000000 | ((c & 0x7c0) >> 6); + buf[1] = 0b10000000 | (c & 0x3f); + return {}; + } + if (len == 3) + { + buf[0] = 0b11100000 | ((c & 0xf000) >> 12); + buf[1] = 0b10000000 | ((c & 0xfc0) >> 6); + buf[2] = 0b10000000 | (c & 0x3f); + return {}; + } + if (len == 4) + { + buf[0] = 0b11110000 | ((c & 0x1c0000) >> 18); + buf[1] = 0b10000000 | ((c & 0x3f000) >> 12); + buf[2] = 0b10000000 | ((c & 0xfc0) >> 6); + buf[3] = 0b10000000 | (c & 0x3f); + return {}; + } + + unreachable(); +} + +static Result encode_utf8_as_wide_char_impl(const char* beg, usize& len) +{ + usize utf8_len = TRY(utf8_char_length(*beg)); + if (utf8_len > len) return err(EILSEQ); // Unterminated sequence + len = utf8_len; // Enough space for the sequence, let's return the resulting length + + if (len == 1) { return beg[0] & 0x7f; } + if (len == 2) + { + if ((beg[1] & 0b11000000) != 0b10000000) return err(EILSEQ); + wchar_t c = beg[0] & 0x1f; + c <<= 6; + c |= beg[1] & 0x3f; + return c; + } + if (len == 3) + { + if ((beg[1] & 0b11000000) != 0b10000000) return err(EILSEQ); + if ((beg[2] & 0b11000000) != 0b10000000) return err(EILSEQ); + wchar_t c = beg[0] & 0x0f; + c <<= 6; + c |= beg[1] & 0x3f; + c <<= 6; + c |= beg[2] & 0x3f; + return c; + } + if (len == 4) + { + if ((beg[1] & 0b11000000) != 0b10000000) return err(EILSEQ); + if ((beg[2] & 0b11000000) != 0b10000000) return err(EILSEQ); + if ((beg[3] & 0b11000000) != 0b10000000) return err(EILSEQ); + wchar_t c = beg[0] & 0x07; + c <<= 6; + c |= beg[1] & 0x3f; + c <<= 6; + c |= beg[2] & 0x3f; + c <<= 6; + c |= beg[3] & 0x3f; + if (c > 0x10ffff) return err(EILSEQ); + return c; + } + + unreachable(); +} + +static Result encode_utf8_as_wide_char(const char* beg, usize& len) +{ + wchar_t result = TRY(encode_utf8_as_wide_char_impl(beg, len)); + // NOTE: We already know this is a valid code-point, since we constructed it ourselves and already checked the + // range. + if (len != wide_char_length_as_utf8_unchecked(result)) + { + // OVERLONG ENCODING!! This is nasty, error out. + return err(EILSEQ); + } + return result; +} + +Utf8StringDecoder::Utf8StringDecoder(const char* str) : m_str(str), m_byte_length(strlen(str)) +{ +} + +Result Utf8StringDecoder::code_points() const +{ + const char* it = m_str; + usize len = 0; + + while ((usize)(it - m_str) < m_byte_length) + { + usize utf8_len = TRY(utf8_char_length(*it)); + if ((usize)(it - m_str) + utf8_len > m_byte_length) return err(EILSEQ); + it += utf8_len; + len++; + } + + return len; +} + +Result Utf8StringDecoder::decode(wchar_t* buf, size_t max) const +{ + const char* it = m_str; + + while ((usize)(it - m_str) < m_byte_length && max--) + { + usize len = m_byte_length - (usize)(it - m_str); // Remaining space + *buf = TRY(encode_utf8_as_wide_char(it, len)); + it += len; + buf++; + } + + *buf = 0; + + return {}; +} + +Result Utf8StringDecoder::decode(wchar_t* buf) const +{ + return decode(buf, (size_t)-1); +} + +Utf8StringEncoder::Utf8StringEncoder(const wchar_t* str) : m_str(str), m_code_points(wcslen(str)) +{ +} + +Result Utf8StringEncoder::byte_length() const +{ + const wchar_t* it = m_str; + usize len = 0; + + while (*it) + { + len += TRY(wide_char_length_as_utf8(*it)); + it++; + } + + return len; +} + +Result Utf8StringEncoder::encode(char* buf, size_t max) const +{ + const wchar_t* it = m_str; + + while (*it && max > 1) + { + usize len = max - 1; + TRY(encode_wide_char_as_utf8(*it, buf, len)); + buf += len; + max -= len; + it++; + } + + *buf = 0; + + return {}; +} + +Result Utf8StringEncoder::encode(char* buf) const +{ + return encode(buf, (size_t)-1); +} + +Utf8StateDecoder::Utf8StateDecoder() : m_state_len(0), m_state_index(0) +{ +} + +Result> Utf8StateDecoder::feed(char c) +{ + if (m_state_len == 0) + { + m_state_len = TRY(utf8_char_length(c)); + if (m_state_len == 1) + { + m_state_len = 0; + return Option { c & 0x7f }; + } + m_state_index = 0; + m_state[m_state_index] = c; + return { {} }; + } + + m_state_index++; + m_state[m_state_index] = c; + + if (m_state_index == m_state_len - 1) + { + usize len = m_state_len; + wchar_t wc = TRY(encode_utf8_as_wide_char(m_state, len)); + m_state_len = 0; + return Option { wc }; + } + + return { {} }; +} + +void Utf8StateDecoder::reset() +{ + m_state_index = m_state_len = 0; +} + +Result Utf8Encoder::encode(wchar_t c, char buf[4]) +{ + usize len = 0; + + TRY(encode_wide_char_as_utf8(c, buf, len)); + + return len; +} diff --git a/ports/add-port.sh b/ports/add-port.sh deleted file mode 100755 index 222931ac..00000000 --- a/ports/add-port.sh +++ /dev/null @@ -1,140 +0,0 @@ -#!/usr/bin/env bash - -set -e - -cd $(dirname $0)/.. - -unset LUNA_BASE - -source tools/env.sh - -cd ports - -unset pkgname -unset pkgver -unset pkgurl -unset pkgmode -unset setupdir -unset builddir -unset installdir -unset srcdir -unset port_unpack -unset port_patch -unset port_configure -unset port_build -unset port_install -unset port_uninstall - -export DESTDIR=${DESTDIR:-"$LUNA_ROOT/initrd"} - -export listdir=$PWD - -if [ -z $1 ] -then - echo "Usage: add-port.sh " - exit 1 -fi - -if [ -d $1 ] -then - pkgscript=$1/package.sh -elif [ -f $1 ] -then - pkgscript=$1 -else - echo "Unrecognized argument: $1" - exit 1 -fi - -export portdir=$(realpath $(dirname $pkgscript)) -export workdir=$portdir/workdir -mkdir -p $workdir - -source $pkgscript - -if ! [ -z ${pkgdeps+x} ] -then - echo "Installing dependencies of $pkgname..." - for pkg in ${pkgdeps[@]} - do - set +e - grep $pkg ports.list >/dev/null - if [ "$?" = "0" ] - then - echo "Dependency $pkg is already installed." - else - echo "Installing dependency $pkg..." - ./add-port.sh $pkg - fi - set -e - done -fi - -echo "Building $pkgname version $pkgver..." - -cd $workdir - -if ! [ -d $srcdir ] -then - mkdir -p $setupdir - cd $setupdir - - echo "Downloading $pkgname version $pkgver..." - - case $pkgmode in - "web") wget $pkgurl;; - "git") git clone $pkgurl;; - *) echo "Don't know how to download package mode '$pkgmode'"; exit 1;; - esac - - set +e - command -v port_unpack >/dev/null - set -e - if [ "$?" = "0" ] - then - echo "Unpacking $pkgname version $pkgver..." - port_unpack | filter-lines $pkgname "unpack" - fi - - set +e - command -v port_patch >/dev/null - set -e - if [ "$?" = "0" ] - then - echo "Patching $pkgname version $pkgver..." - port_patch | filter-lines $pkgname "patch" - fi -fi - -cd $workdir - -mkdir -p $builddir -cd $builddir - -set +e -command -v port_configure >/dev/null -set -e -if [ "$?" = "0" ] -then - echo "Configuring $pkgname version $pkgver..." - port_configure | filter-lines $pkgname "configure" -fi - -echo "Making $pkgname version $pkgver..." -port_build | filter-lines $pkgname "build" # this one is required - -cd $workdir - -mkdir -p $installdir -cd $installdir - -echo "Installing $pkgname version $pkgver..." -port_install | filter-lines $pkgname "install" - -if ! [ "$SKIP_ADD_TO_PORTS_LIST" = "1" ] -then - echo "$pkgname" >> $listdir/ports.list - cat $listdir/ports.list | sort | uniq | tee $listdir/ports.list >/dev/null # avoid duplicates - - echo "Success! Registered port: $pkgname version $pkgver." -fi \ No newline at end of file diff --git a/ports/bc/bc.patch b/ports/bc/bc.patch deleted file mode 100644 index a4a4ffdc..00000000 --- a/ports/bc/bc.patch +++ /dev/null @@ -1,60 +0,0 @@ -diff --color -rN -u bc-vanilla/include/library.h bc-6.0.4/include/library.h ---- a/bc-6.0.4/include/library.h 2022-09-26 19:34:34.000000000 +0200 -+++ b/bc-6.0.4/include/library.h 2022-10-15 14:59:11.413415573 +0200 -@@ -36,7 +36,7 @@ - #ifndef LIBBC_PRIVATE_H - #define LIBBC_PRIVATE_H - --#ifndef _WIN32 -+#if !defined(_WIN32) && !defined(__luna__) - - #include - -@@ -236,13 +236,17 @@ - BcVm* - bcl_getspecific(void); - --#ifndef _WIN32 -+#if !defined(_WIN32) && !defined(__luna__) - - typedef pthread_key_t BclTls; - - #else // _WIN32 - -+#ifdef __luna__ -+typedef int BclTls; -+#else - typedef DWORD BclTls; -+#endif - - #endif // _WIN32 - -diff --color -rN -u bc-vanilla/src/vm.c bc-6.0.4/src/vm.c ---- a/bc-6.0.4/src/vm.c 2022-09-26 19:34:35.000000000 +0200 -+++ b/bc-6.0.4/src/vm.c 2022-10-21 17:29:13.511229371 +0200 -@@ -193,7 +193,7 @@ - static void - bc_vm_sigaction(void) - { --#ifndef _WIN32 -+#if !defined(_WIN32) && !defined(__luna__) - - struct sigaction sa; - -@@ -223,11 +223,15 @@ - if (BC_TTY) sigaction(SIGHUP, &sa, NULL); - #endif // BC_ENABLE_HISTORY - --#else // _WIN32 -+#else -+ -+#ifndef __luna__ - - signal(SIGTERM, bc_vm_sig); - signal(SIGINT, bc_vm_sig); - -+#endif -+ - #endif // _WIN32 - } - diff --git a/ports/bc/package.sh b/ports/bc/package.sh deleted file mode 100644 index a307fd32..00000000 --- a/ports/bc/package.sh +++ /dev/null @@ -1,40 +0,0 @@ -pkgname="bc" -pkgver="6.0.4" -pkgurl="https://github.com/gavinhoward/bc/releases/download/$pkgver/bc-$pkgver.tar.gz" - -pkgmode="web" - -setupdir="$workdir" -builddir="$workdir/build" -installdir="$workdir/build" -srcdir="$workdir/bc-$pkgver" - -port_unpack() -{ - tar xvf bc-$pkgver.tar.gz -} - -port_patch() -{ - patch -u -i $portdir/bc.patch -p 1 -d $workdir -} - -port_configure() -{ - HOSTCC=gcc PREFIX=${PREFIX:-""} $srcdir/configure --disable-nls --bc-only --disable-history --disable-man-pages -} - -port_build() -{ - make -j$(nproc) -} - -port_install() -{ - make install -} - -port_uninstall() -{ - make uninstall -} \ No newline at end of file diff --git a/ports/binutils/binutils.patch b/ports/binutils/binutils.patch deleted file mode 100644 index 6c8e94a6..00000000 --- a/ports/binutils/binutils.patch +++ /dev/null @@ -1,144 +0,0 @@ -diff --color -rN -u binutils-2.38/bfd/config.bfd binutils-2.38/bfd/config.bfd ---- a/binutils-2.38/bfd/config.bfd 2022-01-22 13:14:07.000000000 +0100 -+++ b/binutils-2.38/bfd/config.bfd 2022-11-09 16:09:46.143869977 +0100 -@@ -651,6 +651,11 @@ - targ_selvecs="iamcu_elf32_vec i386_pei_vec" - targ64_selvecs="x86_64_elf64_vec x86_64_elf32_vec x86_64_pe_vec x86_64_pei_vec l1om_elf64_vec k1om_elf64_vec" - ;; -+ i[3-7]86-*-luna*) -+ targ_defvec=i386_elf32_vec -+ targ_selvecs= -+ targ64_selvecs=x86_64_elf64_vec -+ ;; - i[3-7]86-*-redox*) - targ_defvec=i386_elf32_vec - targ_selvecs= -@@ -706,6 +711,11 @@ - targ_selvecs="i386_elf32_vec iamcu_elf32_vec x86_64_elf32_vec i386_pei_vec x86_64_pe_vec x86_64_pei_vec l1om_elf64_vec k1om_elf64_vec" - want64=true - ;; -+ x86_64-*-luna*) -+ targ_defvec=x86_64_elf64_vec -+ targ_selvecs=i386_elf32_vec -+ want64=true -+ ;; - x86_64-*-mingw* | x86_64-*-pe | x86_64-*-pep | x86_64-*-cygwin) - targ_defvec=x86_64_pe_vec - targ_selvecs="x86_64_pe_vec x86_64_pei_vec x86_64_pe_big_vec x86_64_elf64_vec l1om_elf64_vec k1om_elf64_vec i386_pe_vec i386_pei_vec i386_elf32_vec iamcu_elf32_vec" -diff --color -rN -u binutils-2.38/gas/configure.tgt binutils-2.38/gas/configure.tgt ---- a/binutils-2.38/gas/configure.tgt 2022-01-22 13:14:08.000000000 +0100 -+++ b/binutils-2.38/gas/configure.tgt 2022-11-09 16:09:46.144869977 +0100 -@@ -238,6 +238,7 @@ - x86_64*-linux-gnux32) arch=x86_64:32 ;; - esac ;; - i386-*-lynxos*) fmt=elf em=lynx ;; -+ i386-*-luna*) fmt=elf em=gnu ;; - i386-*-redox*) fmt=elf ;; - i386-*-solaris*) fmt=elf em=solaris ;; - i386-*-freebsd* \ -diff --color -rN -u binutils-2.38/gas/messages.c binutils-2.38/gas/messages.c ---- a/binutils-2.38/gas/messages.c 2022-01-22 13:14:08.000000000 +0100 -+++ b/binutils-2.38/gas/messages.c 2022-11-09 16:26:03.275802078 +0100 -@@ -324,7 +324,9 @@ - signal_crash (int signo) - { - /* Reset, to prevent unbounded recursion. */ -+#ifndef __luna__ - signal (signo, SIG_DFL); -+#endif - - as_abort (NULL, 0, strsignal (signo)); - } -diff --color -rN -u binutils-2.38/ld/configure.tgt binutils-2.38/ld/configure.tgt ---- a/binutils-2.38/ld/configure.tgt 2022-01-22 15:19:36.000000000 +0100 -+++ b/binutils-2.38/ld/configure.tgt 2022-11-09 16:09:46.145869977 +0100 -@@ -329,6 +329,11 @@ - targ64_extra_emuls="elf_x86_64 elf32_x86_64 elf_l1om elf_k1om" - targ64_extra_libpath="elf_x86_64 elf32_x86_64" - ;; -+i[3-7]86-*-luna*) -+ targ_emul=elf_i386_luna -+ targ_extra_emuls=elf_i386 -+ targ64_extra_emuls="elf_x86_64_luna elf_x86_64" -+ ;; - i[3-7]86-*-redox*) targ_emul=elf_i386 - targ_extra_emuls=elf_x86_64 - ;; -@@ -967,6 +972,10 @@ - targ_extra_libpath="elf_i386 elf32_x86_64 elf_l1om elf_k1om" - tdir_elf_i386=`echo ${targ_alias} | sed -e 's/x86_64/i386/'` - ;; -+x86_64-*-luna*) -+ targ_emul=elf_x86_64_luna -+ targ_extra_emuls="elf_i386_luna elf_x86_64 elf_i386" -+ ;; - x86_64-*-redox*) targ_emul=elf_x86_64 - targ_extra_emuls=elf_i386 - ;; -diff --color -rN -u binutils-2.38/ld/emulparams/elf_i386_luna.sh binutils-2.38/ld/emulparams/elf_i386_luna.sh ---- a/binutils-2.38/ld/emulparams/elf_i386_luna.sh 1970-01-01 01:00:00.000000000 +0100 -+++ b/binutils-2.38/ld/emulparams/elf_i386_luna.sh 2022-11-09 16:09:46.145869977 +0100 -@@ -0,0 +1,3 @@ -+source_sh ${srcdir}/emulparams/elf_i386.sh -+TEXT_START_ADDR=0x08000000 -+MAXPAGESIZE=0x1000 -\ No newline at end of file -diff --color -rN -u binutils-2.38/ld/emulparams/elf_x86_64_luna.sh binutils-2.38/ld/emulparams/elf_x86_64_luna.sh ---- a/binutils-2.38/ld/emulparams/elf_x86_64_luna.sh 1970-01-01 01:00:00.000000000 +0100 -+++ b/binutils-2.38/ld/emulparams/elf_x86_64_luna.sh 2022-11-09 16:09:46.145869977 +0100 -@@ -0,0 +1,2 @@ -+source_sh ${srcdir}/emulparams/elf_x86_64.sh -+MAXPAGESIZE=0x1000 -\ No newline at end of file -diff --color -rN -u binutils-2.38/ld/Makefile.am binutils-2.38/ld/Makefile.am ---- a/binutils-2.38/ld/Makefile.am 2022-01-22 13:14:09.000000000 +0100 -+++ b/binutils-2.38/ld/Makefile.am 2022-11-09 16:09:46.145869977 +0100 -@@ -278,6 +278,7 @@ - eelf32xtensa.c \ - eelf32z80.c \ - eelf_i386.c \ -+ eelf_i386_luna.c \ - eelf_i386_be.c \ - eelf_i386_fbsd.c \ - eelf_i386_haiku.c \ -@@ -464,6 +465,7 @@ - eelf_x86_64_fbsd.c \ - eelf_x86_64_haiku.c \ - eelf_x86_64_sol2.c \ -+ eelf_x86_64_luna.c \ - ehppa64linux.c \ - ei386pep.c \ - emmo.c -diff --color -rN -u binutils-2.38/ld/Makefile.in binutils-2.38/ld/Makefile.in ---- a/binutils-2.38/ld/Makefile.in 2022-02-09 12:49:03.000000000 +0100 -+++ b/binutils-2.38/ld/Makefile.in 2022-11-09 16:09:46.146869977 +0100 -@@ -769,6 +769,7 @@ - eelf32xtensa.c \ - eelf32z80.c \ - eelf_i386.c \ -+ eelf_i386_luna.c \ - eelf_i386_be.c \ - eelf_i386_fbsd.c \ - eelf_i386_haiku.c \ -@@ -954,6 +955,7 @@ - eelf_x86_64_fbsd.c \ - eelf_x86_64_haiku.c \ - eelf_x86_64_sol2.c \ -+ eelf_x86_64_luna.c \ - ehppa64linux.c \ - ei386pep.c \ - emmo.c -diff --color -rN -u binutils-2.38/libiberty/pex-unix.c binutils-2.38/libiberty/pex-unix.c ---- a/binutils-2.38/libiberty/pex-unix.c 2022-01-22 13:14:09.000000000 +0100 -+++ b/binutils-2.38/libiberty/pex-unix.c 2022-11-09 16:25:21.767804963 +0100 -@@ -773,8 +773,10 @@ - { - /* If we are cleaning up when the caller didn't retrieve process - status for some reason, encourage the process to go away. */ -+#ifndef __luna__ - if (done) - kill (pid, SIGTERM); -+#endif - - if (pex_wait (obj, pid, status, time) < 0) - { diff --git a/ports/binutils/package.sh b/ports/binutils/package.sh deleted file mode 100644 index e712b772..00000000 --- a/ports/binutils/package.sh +++ /dev/null @@ -1,48 +0,0 @@ -pkgname="binutils" -pkgver="2.38" -pkgurl="https://ftp.gnu.org/gnu/binutils/binutils-$pkgver.tar.xz" - -pkgmode="web" - -pkgdeps=('gmp' 'mpfr' 'mpc') - -setupdir="$workdir" -builddir="$workdir/build" -installdir="$workdir/build" -srcdir="$workdir/binutils-$pkgver" - -port_unpack() -{ - tar xvf binutils-$pkgver.tar.xz -} - -port_patch() -{ - patch -u -i $portdir/binutils.patch -p 1 -d $workdir -} - -port_configure() -{ - CFLAGS="-ffunction-sections -fdata-sections" LDFLAGS="-Wl,--gc-sections" $srcdir/configure --target=x86_64-luna --prefix="" --disable-werror --disable-nls --disable-dependency-tracking --with-build-sysroot=$LUNA_ROOT/base --host=x86_64-luna -} - -port_build() -{ - make -j$(nproc) -} - -port_install() -{ - make install-strip-binutils - rm -rf $DESTDIR/include/ - rm -rf $DESTDIR/lib/ - rm -rf $DESTDIR/share/ - rm -rf $DESTDIR/x86_64-luna/ - # keep only a few binaries since we only use an initial ramdisk for now, which doesn't like having many of these large binaries - rm -f $DESTDIR/bin/{ar,as,elfedit,gprof,ld,ld.bfd,objcopy,ranlib,strip} -} - -port_uninstall() -{ - rm -f $DESTDIR/bin/{addr2line,c++filt,nm,objdump,readelf,size,strings} -} \ No newline at end of file diff --git a/ports/gmp/gmp.patch b/ports/gmp/gmp.patch deleted file mode 100644 index ab6934dd..00000000 --- a/ports/gmp/gmp.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff --color -rN -u gmp-vanilla/invalid.c gmp-6.2.1/invalid.c ---- a/gmp-6.2.1/invalid.c 2020-11-14 19:45:09.000000000 +0100 -+++ b/gmp-6.2.1/invalid.c 2022-10-26 21:09:20.102237128 +0200 -@@ -77,6 +77,6 @@ - void - __gmp_invalid_operation (void) - { -- raise (SIGFPE); -+// raise (SIGFPE); - abort (); - } diff --git a/ports/gmp/package.sh b/ports/gmp/package.sh deleted file mode 100644 index d8fde85b..00000000 --- a/ports/gmp/package.sh +++ /dev/null @@ -1,44 +0,0 @@ -pkgname="gmp" -pkgver="6.2.1" -pkgurl="https://ftp.gnu.org/gnu/gmp/gmp-$pkgver.tar.xz" - -pkgmode="web" - -islib=1 - -setupdir="$workdir" -builddir="$workdir/build" -installdir="$workdir/build" -srcdir="$workdir/gmp-$pkgver" - -port_unpack() -{ - tar xvf gmp-$pkgver.tar.xz -} - -port_patch() -{ - patch -u -i $portdir/gmp.patch -p 1 -d $workdir -} - -port_configure() -{ - CC_FOR_BUILD=gcc $srcdir/configure --enable-shared=no --with-gnu-ld --host=x86_64-luna --prefix=/usr -} - -port_build() -{ - make -j$(nproc) -} - -port_install() -{ - make DESTDIR=$LUNA_BASE install - rm -f $LUNA_BASE/usr/lib/*.la -} - -port_uninstall() -{ - make DESTDIR=$LUNA_BASE uninstall - rm -f $LUNA_BASE/usr/lib/libgmp.a -} \ No newline at end of file diff --git a/ports/list-ports.sh b/ports/list-ports.sh deleted file mode 100755 index d812c1fe..00000000 --- a/ports/list-ports.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env bash - -set -e - -cd $(dirname $0)/.. - -source tools/env.sh - -cd ports - -unset_vars() -{ - unset pkgname - unset pkgver - unset pkgurl - unset pkgmode - unset setupdir - unset builddir - unset installdir - unset srcdir - unset port_unpack - unset port_patch - unset port_configure - unset port_build - unset port_install - unset port_uninstall -} - -if ! [ -f ./ports.list ] -then - echo "No ports installed." - exit 0 -fi - -export HAVE_PORTS=0 - -install_port() -{ - HAVE_PORTS=1 - unset_vars - cd $LUNA_ROOT/ports - export DESTDIR=${DESTDIR:-"$LUNA_ROOT/initrd"} - export portdir=$PWD/$1 - export workdir=$portdir/workdir - source $portdir/package.sh - echo "$pkgname $pkgver" -} - -while read package; do - install_port $package -done < ./ports.list - -if [ "$HAVE_PORTS" = "0" ] -then - echo "No ports installed." -fi \ No newline at end of file diff --git a/ports/make-package.sh b/ports/make-package.sh deleted file mode 100755 index 41424b89..00000000 --- a/ports/make-package.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env bash - -set -e - -source $(dirname $0)/../tools/env.sh - -export DESTDIR=$PWD/pkgroot -export SKIP_ADD_TO_PORTS_LIST=1 - -source $LUNA_ROOT/ports/$1/package.sh - -mkdir pkgroot - -$LUNA_ROOT/ports/add-port.sh $pkgname - -cd pkgroot - -tar cJf ../$pkgname-$pkgver.pkg.tar.xz * - -cd - - -rm -rf pkgroot - -echo "Built package $pkgname-$pkgver.pkg.tar.xz" \ No newline at end of file diff --git a/ports/mpc/package.sh b/ports/mpc/package.sh deleted file mode 100644 index d28aaa7d..00000000 --- a/ports/mpc/package.sh +++ /dev/null @@ -1,41 +0,0 @@ -pkgname="mpc" -pkgver="1.2.1" -pkgurl="https://ftp.gnu.org/gnu/mpc/mpc-$pkgver.tar.gz" - -pkgmode="web" - -pkgdeps=('gmp' 'mpfr') - -islib=1 - -setupdir="$workdir" -builddir="$workdir/build" -installdir="$workdir/build" -srcdir="$workdir/mpc-$pkgver" - -port_unpack() -{ - tar xvf mpc-$pkgver.tar.gz -} - -port_configure() -{ - $srcdir/configure --host=x86_64-luna --with-gnu-ld --enable-shared=no --prefix=/usr -} - -port_build() -{ - make -j$(nproc) -} - -port_install() -{ - make DESTDIR=$LUNA_BASE install - rm -f $LUNA_BASE/usr/lib/*.la -} - -port_uninstall() -{ - make DESTDIR=$LUNA_BASE uninstall - rm -f $LUNA_BASE/usr/lib/libmpc.a -} \ No newline at end of file diff --git a/ports/mpfr/package.sh b/ports/mpfr/package.sh deleted file mode 100644 index b9df3d56..00000000 --- a/ports/mpfr/package.sh +++ /dev/null @@ -1,41 +0,0 @@ -pkgname="mpfr" -pkgver="4.1.0" -pkgurl="https://ftp.gnu.org/gnu/mpfr/mpfr-$pkgver.tar.gz" - -pkgmode="web" - -pkgdeps=('gmp') - -islib=1 - -setupdir="$workdir" -builddir="$workdir/build" -installdir="$workdir/build" -srcdir="$workdir/mpfr-$pkgver" - -port_unpack() -{ - tar xvf mpfr-$pkgver.tar.gz -} - -port_configure() -{ - $srcdir/configure --with-gnu-ld --host=x86_64-luna --enable-shared=no --prefix=/usr -} - -port_build() -{ - make -j$(nproc) -} - -port_install() -{ - make DESTDIR=$LUNA_BASE install - rm -f $LUNA_BASE/usr/lib/*.la -} - -port_uninstall() -{ - make DESTDIR=$LUNA_BASE uninstall - rm -f $LUNA_BASE/usr/lib/libmpfr.a -} \ No newline at end of file diff --git a/ports/nasm/nasm.patch b/ports/nasm/nasm.patch deleted file mode 100644 index 49e2d0fc..00000000 --- a/ports/nasm/nasm.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --color -rN -u nasm-vanilla/Makefile.in nasm-2.15.05/Makefile.in ---- a/nasm-2.15.05/Makefile.in 2020-08-28 18:04:43.000000000 +0200 -+++ b/nasm-2.15.05/Makefile.in 2022-10-30 18:00:40.386258721 +0100 -@@ -389,9 +389,6 @@ - $(MKDIR_P) $(DESTDIR)$(bindir) - $(INSTALL_PROGRAM) nasm$(X) $(DESTDIR)$(bindir)/nasm$(X) - $(INSTALL_PROGRAM) ndisasm$(X) $(DESTDIR)$(bindir)/ndisasm$(X) -- $(MKDIR_P) $(DESTDIR)$(mandir)/man1 -- $(INSTALL_DATA) $(srcdir)/nasm.1 $(DESTDIR)$(mandir)/man1/nasm.1 -- $(INSTALL_DATA) $(srcdir)/ndisasm.1 $(DESTDIR)$(mandir)/man1/ndisasm.1 - - clean: - for d in . $(SUBDIRS) $(XSUBDIRS); do \ diff --git a/ports/nasm/package.sh b/ports/nasm/package.sh deleted file mode 100644 index baf8787d..00000000 --- a/ports/nasm/package.sh +++ /dev/null @@ -1,41 +0,0 @@ -pkgname="nasm" -pkgver="2.15.05" -pkgurl="https://www.nasm.us/pub/nasm/releasebuilds/$pkgver/nasm-$pkgver.tar.gz" - -pkgmode="web" - -setupdir="$workdir" -builddir="$workdir/build" -installdir="$workdir/build" -srcdir="$workdir/nasm-$pkgver" - -port_unpack() -{ - tar xvf nasm-$pkgver.tar.gz -} - -port_patch() -{ - patch -u -i $portdir/nasm.patch -p 1 -d $workdir -} - -port_configure() -{ - $srcdir/configure --host=x86_64-luna --prefix="" -} - -port_build() -{ - make -j$(nproc) -} - -port_install() -{ - make install - $STRIP $DESTDIR/bin/{nasm,ndisasm} -} - -port_uninstall() # nasm's Makefile does not provide an uninstall target. -{ - rm -f $DESTDIR/bin/{nasm,ndisasm} -} \ No newline at end of file diff --git a/ports/remove-port.sh b/ports/remove-port.sh deleted file mode 100755 index 22cc8240..00000000 --- a/ports/remove-port.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env bash - -set -e - -cd $(dirname $0)/.. - -source tools/env.sh - -cd ports - -export DESTDIR=${DESTDIR:-"$LUNA_ROOT/initrd"} -export listdir=$PWD - -if [ -z $1 ] -then - echo "Usage: remove-port.sh " - exit 1 -fi - -if [ -d $1 ] -then - pkgscript=$1/package.sh -elif [ -f $1 ] -then - pkgscript=$1 -else - echo "Unrecognized argument: $1" - exit 1 -fi - -export portdir=$(realpath $(dirname $pkgscript)) -export workdir=$portdir/workdir -mkdir -p $workdir - -source $pkgscript - -echo "Removing $pkgname version $pkgver..." - -cd $installdir -port_uninstall | filter-lines $pkgname "uninstall" - -rm -rf $workdir -cat $listdir/ports.list | grep -v $pkgname | tee $listdir/ports.list >/dev/null - -echo "Success! Removed port: $pkgname version $pkgver." \ No newline at end of file diff --git a/tests/Makefile b/tests/Makefile deleted file mode 100644 index 38f21741..00000000 --- a/tests/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -build: - make -C libc build - -install: - make -C libc install - -test: - make -C libc test - \ No newline at end of file diff --git a/tests/Test.h b/tests/Test.h deleted file mode 100644 index 4836e95f..00000000 --- a/tests/Test.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef __TEST_H_ -#define __TEST_H_ -#include - -int printf(const char*, ...); - -#define DEFINE_TEST(name) bool test_##name() -#define START_TEST(name) printf("testing whether %s works... ", #name) -#define START_TEST_CASE(name) printf("testing %s...\n", #name) - -#define TEST_SUCCESS() \ - do { \ - printf("yes!\n"); \ - return true; \ - } while (0) - -#define TEST_FAIL(expr) \ - do { \ - printf("no (%s)\n", #expr); \ - return false; \ - } while (0) - -#define TEST_NOT_SURE(expr) \ - do { \ - printf("not sure (%s)\n", #expr); \ - return true; \ - } while (0) - -#define EXPECT(expr) \ - do { \ - if (!(expr)) { TEST_FAIL(expr); } \ - } while (0) - -#define EXPECT_EQ(a, b) EXPECT((a) == (b)) - -#define EXPECT_NOT_EQ(a, b) EXPECT((a) != (b)) - -#define EXPECT_NOT_CRASHED() TEST_SUCCESS() - -#define RUN_TEST(name) \ - do { \ - if (!test_##name()) return 1; \ - } while (0) - -#endif \ No newline at end of file diff --git a/tests/libc/Makefile b/tests/libc/Makefile deleted file mode 100644 index 698044bc..00000000 --- a/tests/libc/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -TESTDIR := $(LUNA_ROOT)/tests/libc -DESTDIR := $(LUNA_ROOT)/initrd/bin - -build: - @mkdir -p $(TESTDIR)/bin - $(LUNA_ROOT)/tools/sync-libc.sh - $(CC) $(TESTDIR)/string.c $(TESTDIR)/stdlib.c $(TESTDIR)/wchar.c $(TESTDIR)/Test.c -I$(LUNA_ROOT)/tests -o $(TESTDIR)/bin/test-libc -Wall -Wextra -Wno-deprecated-declarations -Wno-stringop-overread -Werror - -install: - $(LUNA_ROOT)/tools/clean.sh - @mkdir -p $(DESTDIR) - cp $(TESTDIR)/bin/test-libc $(DESTDIR)/test-libc - -test: - CFLAGS="-DRUN_TEST_AS_INIT=/bin/test-libc" $(LUNA_ROOT)/tools/run.sh \ No newline at end of file diff --git a/tests/libc/Test.c b/tests/libc/Test.c deleted file mode 100644 index afc9b17d..00000000 --- a/tests/libc/Test.c +++ /dev/null @@ -1,70 +0,0 @@ -#include "Test.h" - -// string.h -DEFINE_TEST(memset); -DEFINE_TEST(memcpy); -DEFINE_TEST(memchr); -DEFINE_TEST(memcmp); -DEFINE_TEST(memmove); -DEFINE_TEST(strlen); -DEFINE_TEST(strnlen); -DEFINE_TEST(strcmp); -DEFINE_TEST(strncmp); -DEFINE_TEST(strcspn); -DEFINE_TEST(strspn); -DEFINE_TEST(strchr); -DEFINE_TEST(strchrnul); -DEFINE_TEST(strrchr); -DEFINE_TEST(strpbrk); -DEFINE_TEST(strdup); -DEFINE_TEST(strndup); - -// stdlib.h -DEFINE_TEST(atoi); -DEFINE_TEST(atol); -DEFINE_TEST(atoll); -DEFINE_TEST(srand); -DEFINE_TEST(malloc); -DEFINE_TEST(calloc); -DEFINE_TEST(mktemp); -DEFINE_TEST(qsort); -DEFINE_TEST(bsearch); - -// wchar.h -DEFINE_TEST(wcslen); - -int main() -{ - START_TEST_CASE(string.h); - RUN_TEST(memset); - RUN_TEST(memcpy); - RUN_TEST(memchr); - RUN_TEST(memcmp); - RUN_TEST(memmove); - RUN_TEST(strlen); - RUN_TEST(strnlen); - RUN_TEST(strcmp); - RUN_TEST(strncmp); - RUN_TEST(strcspn); - RUN_TEST(strspn); - RUN_TEST(strchr); - RUN_TEST(strchrnul); - RUN_TEST(strrchr); - RUN_TEST(strpbrk); - RUN_TEST(strdup); - RUN_TEST(strndup); - - START_TEST_CASE(stdlib.h); - RUN_TEST(atoi); - RUN_TEST(atol); - RUN_TEST(atoll); - RUN_TEST(srand); - RUN_TEST(malloc); - RUN_TEST(calloc); - RUN_TEST(mktemp); - RUN_TEST(qsort); - RUN_TEST(bsearch); - - START_TEST_CASE(wchar.h); - RUN_TEST(wcslen); -} \ No newline at end of file diff --git a/tests/libc/stdlib.c b/tests/libc/stdlib.c deleted file mode 100644 index d869808c..00000000 --- a/tests/libc/stdlib.c +++ /dev/null @@ -1,234 +0,0 @@ -#include "Test.h" -#include -#include -#include - -DEFINE_TEST(atoi) -{ - START_TEST(atoi); - - const char* str = "42"; - int num = atoi(str); - - EXPECT_EQ(num, 42); - - str = "-56"; - num = atoi(str); - - EXPECT_EQ(num, -56); - - str = "Not a number"; - num = atoi(str); - - EXPECT_EQ(num, 0); - - TEST_SUCCESS(); -} - -DEFINE_TEST(atol) -{ - START_TEST(atol); - - const char* str = "42"; - long num = atol(str); - - EXPECT_EQ(num, 42); - - str = "-56"; - num = atol(str); - - EXPECT_EQ(num, -56); - - str = "Not a number"; - num = atol(str); - - EXPECT_EQ(num, 0); - - str = "68719476735"; - num = atol(str); - - EXPECT_EQ(num, 68719476735); - - TEST_SUCCESS(); -} - -DEFINE_TEST(atoll) -{ - START_TEST(atoll); - - const char* str = "42"; - long long num = atoll(str); - - EXPECT_EQ(num, 42); - - str = "-56"; - num = atoll(str); - - EXPECT_EQ(num, -56); - - str = "Not a number"; - num = atoll(str); - - EXPECT_EQ(num, 0); - - str = "68719476735"; - num = atoll(str); - - EXPECT_EQ(num, 68719476735); - - TEST_SUCCESS(); -} - -DEFINE_TEST(srand) -{ - START_TEST(srand); - - srand(5849); - - int val = rand(); - - EXPECT_EQ(val, -1731894882); - - TEST_SUCCESS(); -} - -DEFINE_TEST(malloc) -{ - START_TEST(malloc); - - int* ptr = malloc(6 * sizeof(int)); - - if (!ptr) - { - TEST_NOT_SURE(ptr); - return true; - } - - *ptr = 6; - - EXPECT_EQ(*ptr, 6); - - ptr[5] = 4; - - EXPECT_EQ(ptr[5], 4); - - free(ptr); - - TEST_SUCCESS(); -} - -DEFINE_TEST(calloc) -{ - START_TEST(calloc); - - int* ptr = calloc(6, sizeof(int)); - - if (!ptr) { TEST_NOT_SURE(ptr); } - - EXPECT_EQ(*ptr, 0); - EXPECT_EQ(ptr[5], 0); - - *ptr = 6; - - EXPECT_EQ(*ptr, 6); - - ptr[5] = 4; - - EXPECT_EQ(ptr[5], 4); - - free(ptr); - - TEST_SUCCESS(); -} - -DEFINE_TEST(mktemp) -{ - START_TEST(mktemp); - - char template[] = "/tmp/file.XXXXXX"; - - const char* template2 = "/tmp/file.XXXXXX"; - - char* ptr = mktemp(template); - - EXPECT_NOT_EQ(ptr, NULL); // mktemp only fails if we give it an invalid template. - - int rc = access(ptr, F_OK); - - EXPECT_NOT_EQ(rc, 0); // FIXME: This could actually happen, since that's why mktemp is deprecated. - // Another process could create the file between generating the name and actually using it. - - rc = strcmp(ptr, template2); - - EXPECT_NOT_EQ(rc, 0); - - TEST_SUCCESS(); -} - -static int compare_char(const void* p1, const void* p2) -{ - const char* c1 = (const char*)p1; - const char* c2 = (const char*)p2; - if (*c1 < *c2) return -1; - if (*c1 > *c2) return 1; - return 0; -} - -static int compare_int(const void* p1, const void* p2) -{ - const int* c1 = (const int*)p1; - const int* c2 = (const int*)p2; - if (*c1 < *c2) return -1; - if (*c1 > *c2) return 1; - return 0; -} - -DEFINE_TEST(qsort) -{ - START_TEST(qsort); - - char unsorted[] = "elacbkdjf"; - const char sorted[] = "abcdefjkl"; - - qsort(unsorted, 9, sizeof(char), compare_char); - - int rc = memcmp(sorted, unsorted, 9); - - EXPECT_EQ(rc, 0); - - int unsorted2[] = {1500, 45, 3, 11, 41, 90, 6, 32, 5, 76}; - const int sorted2[] = {3, 5, 6, 11, 32, 41, 45, 76, 90, 1500}; - - qsort(unsorted2, 10, sizeof(int), compare_int); - - rc = memcmp(unsorted2, sorted2, 10); - - EXPECT_EQ(rc, 0); - - TEST_SUCCESS(); -} - -DEFINE_TEST(bsearch) -{ - START_TEST(bsearch); - - const char sorted[] = "abcdefjkl"; - char key = 'j'; - - char* ptr = bsearch(&key, sorted, 9, sizeof(char), compare_char); // try with sorted array first - - EXPECT_EQ(*ptr, 'j'); - EXPECT_EQ(ptr, &sorted[6]); - - int unsorted[] = {1500, 45, 3, 11, 41, 90, 6, 32, 5, 76}; - qsort(unsorted, 10, sizeof(int), compare_int); - - int key2 = 90; - - int* ptr2 = bsearch(&key2, unsorted, 10, sizeof(int), compare_int); - - EXPECT_EQ(*ptr2, 90); - EXPECT_EQ(ptr2, &unsorted[8]); - - TEST_SUCCESS(); -} \ No newline at end of file diff --git a/tests/libc/string.c b/tests/libc/string.c deleted file mode 100644 index 30a3554e..00000000 --- a/tests/libc/string.c +++ /dev/null @@ -1,385 +0,0 @@ -#include "Test.h" -#include -#include - -DEFINE_TEST(memset) -{ - START_TEST(memset); - - char test[10]; - char* ptr = memset(test, 0, 10); - - EXPECT_EQ(ptr, test); - - for (int i = 0; i < 10; i++) { EXPECT_EQ(test[i], 0); } - - ptr = memset(test, 42, 10); - - EXPECT_EQ(ptr, test); - - for (int i = 0; i < 10; i++) { EXPECT_EQ(test[i], 42); } - - TEST_SUCCESS(); -} - -DEFINE_TEST(memcpy) -{ - START_TEST(memcpy); - - char buf[20] = "Nothing is going on"; - const char* str = "Something is going!"; - - char* ptr = memcpy(buf, str, 20); - - EXPECT_EQ(ptr, buf); - - for (int i = 0; i < 20; i++) { EXPECT_EQ(buf[i], str[i]); } - - const char* new = "Well..."; - - ptr = memcpy(buf, new, 7); - - EXPECT_EQ(ptr, buf); - - for (int i = 0; i < 7; i++) { EXPECT_EQ(buf[i], new[i]); } - for (int i = 7; i < 20; i++) { EXPECT_EQ(buf[i], str[i]); } - - TEST_SUCCESS(); -} - -DEFINE_TEST(memchr) -{ - START_TEST(memchr); - - char buf[20] = "abcdefghijklmnopqrs"; - - char* ptr = memchr(buf, 'z', 20); - - EXPECT_EQ(ptr, NULL); - - ptr = memchr(buf, 'd', 20); - - EXPECT_EQ(ptr, buf + 3); - - ptr = memchr(buf, 's', 20); - - EXPECT_EQ(ptr, buf + 18); - - TEST_SUCCESS(); -} - -DEFINE_TEST(memcmp) -{ - START_TEST(memcmp); - - char buf[20] = "abcdefghijklmnopqrs"; - char buf2[20] = "abcdefghijklmnopqrp"; - - int val = memcmp(buf, buf, 20); - - EXPECT_EQ(val, 0); - - val = memcmp(buf, buf2, 20); - - EXPECT(val > 0); - - val = memcmp(buf2, buf, 20); - - EXPECT(val < 0); - - TEST_SUCCESS(); -} - -DEFINE_TEST(memmove) -{ - START_TEST(memmove); - - char buf[20] = "Nothing is going on"; - const char* str = "Something is going!"; - - char* ptr = memmove(buf, str, 20); - - EXPECT_EQ(ptr, buf); - - for (int i = 0; i < 20; i++) { EXPECT_EQ(buf[i], str[i]); } - - const char* new = "Well..."; - - ptr = memmove(buf, new, 7); - - EXPECT_EQ(ptr, buf); - - for (int i = 0; i < 7; i++) { EXPECT_EQ(buf[i], new[i]); } - for (int i = 7; i < 20; i++) { EXPECT_EQ(buf[i], str[i]); } - - char newbuf[16] = "part_a is part_b"; - char result[16] = "is part_b part_b"; - - ptr = memmove(newbuf, newbuf + 7, 9); - - EXPECT_EQ(ptr, newbuf); - - EXPECT(memcmp(newbuf, result, 16) == 0); // we have tested memcmp at this point - - TEST_SUCCESS(); -} - -DEFINE_TEST(strlen) -{ - START_TEST(strlen); - - const char* str = "Hello, World!"; - - size_t len = strlen(str); - - EXPECT_EQ(len, 13); - - char null[] = {'\0'}; - - len = strlen(null); - - EXPECT_EQ(len, 0); - - TEST_SUCCESS(); -} - -DEFINE_TEST(strnlen) -{ - START_TEST(strnlen); - - const char* str = "What is going on?"; - - size_t len = strnlen(str, 20); - - EXPECT_EQ(len, 17); - - len = strnlen(str, 15); - - EXPECT_EQ(len, 15); - - char buf[] = {'H', 'e', 'l', 'l', 'o'}; - - len = strnlen(buf, sizeof(buf)); - - EXPECT_EQ(len, sizeof(buf)); - - TEST_SUCCESS(); -} - -DEFINE_TEST(strcmp) -{ - START_TEST(strcmp); - - const char* str1 = "Hello, World!"; - const char* str2 = "Hello, Planet!"; - - int rc = strcmp(str1, str1); - - EXPECT_EQ(rc, 0); - - rc = strcmp(str1, str2); - - EXPECT(rc > 0); - - rc = strcmp(str2, str1); - - EXPECT(rc < 0); - - TEST_SUCCESS(); -} - -DEFINE_TEST(strncmp) -{ - START_TEST(strncmp); - - const char* str1 = "Hello, World!"; - const char* str2 = "Hello, Planet!"; - - int rc = strncmp(str1, str1, 14); - - EXPECT_EQ(rc, 0); - - rc = strncmp(str1, str2, 14); - - EXPECT(rc > 0); - - rc = strncmp(str2, str1, 14); - - EXPECT(rc < 0); - - rc = strncmp(str1, str2, 6); - - EXPECT_EQ(rc, 0); - - TEST_SUCCESS(); -} - -DEFINE_TEST(strcspn) -{ - START_TEST(strcspn); - - const char* str = "This string has vowels"; - const char* vowels = "aeiou"; - - size_t len = strcspn(str, vowels); - - EXPECT_EQ(len, 2); - - str = "WWWWW"; - len = strcspn(str, vowels); - - EXPECT_EQ(len, 5); - - TEST_SUCCESS(); -} - -DEFINE_TEST(strspn) -{ - START_TEST(strspn); - - const char* str = "This is a test string"; - const char* accept = "This "; - - size_t len = strspn(str, accept); - - EXPECT_EQ(len, 8); - - str = "WWWWW"; - len = strspn(str, accept); - - EXPECT_EQ(len, 0); - - str = "This is hi"; - len = strspn(str, accept); - - EXPECT_EQ(len, 10); - - TEST_SUCCESS(); -} - -DEFINE_TEST(strchr) -{ - START_TEST(strchr); - - const char* str = "Hello, world!"; - - char* ptr = strchr(str, 'l'); - - EXPECT_EQ(ptr, str + 2); - - ptr = strchr(str, 'u'); - - EXPECT_EQ(ptr, NULL); - - ptr = strchr(str, '!'); - - EXPECT_EQ(ptr, str + 12); - - TEST_SUCCESS(); -} - -DEFINE_TEST(strchrnul) -{ - START_TEST(strchrnul); - - const char* str = "Hello, world!"; - - char* ptr = strchrnul(str, 'l'); - - EXPECT_EQ(ptr, str + 2); - - ptr = strchrnul(str, 'u'); - - EXPECT_EQ(ptr, str + 13); - - ptr = strchrnul(str, '!'); - - EXPECT_EQ(ptr, str + 12); - - TEST_SUCCESS(); -} - -DEFINE_TEST(strrchr) -{ - START_TEST(strrchr); - - const char* str = "Hello, world!"; - - char* ptr = strrchr(str, 'l'); - - EXPECT_EQ(ptr, str + 10); - - ptr = strrchr(str, 'u'); - - EXPECT_EQ(ptr, NULL); - - ptr = strrchr(str, '!'); - - EXPECT_EQ(ptr, str + 12); - - TEST_SUCCESS(); -} - -DEFINE_TEST(strpbrk) -{ - START_TEST(strpbrk); - - const char* str = "Hello, world!"; - const char* vowels = "aeiou"; - - char* ptr = strpbrk(str, vowels); - - EXPECT_EQ(ptr, str + 1); - - str = "There are more vowels"; - ptr = strpbrk(str, vowels); - - EXPECT_EQ(ptr, str + 2); - - str = "zzzzzz"; - ptr = strpbrk(str, vowels); - - EXPECT_EQ(ptr, NULL); - - TEST_SUCCESS(); -} - -DEFINE_TEST(strdup) -{ - START_TEST(strdup); - - const char* orig = "Well hello there!"; - - char* copy = strdup(orig); - if (!copy) { TEST_NOT_SURE(copy); } - - EXPECT(memcmp(orig, copy, 17) == 0); - - free(copy); - - TEST_SUCCESS(); -} - -DEFINE_TEST(strndup) -{ - START_TEST(strndup); - - const char* orig = "Well hello there!"; - - char* copy = strndup(orig, 17); - if (!copy) { TEST_NOT_SURE(copy); } - - EXPECT(memcmp(orig, copy, 17) == 0); - - free(copy); - - copy = strndup(orig, 12); - if (!copy) { TEST_NOT_SURE(copy); } - - EXPECT_NOT_EQ(memcmp(orig, copy, 14), - 0); // FIXME: This is undefined behaviour and the memory could also be by chance identical. - - free(copy); - - TEST_SUCCESS(); -} \ No newline at end of file diff --git a/tests/libc/wchar.c b/tests/libc/wchar.c deleted file mode 100644 index bec6dc7e..00000000 --- a/tests/libc/wchar.c +++ /dev/null @@ -1,21 +0,0 @@ -#include "Test.h" -#include - -DEFINE_TEST(wcslen) -{ - START_TEST(wcslen); - - const wchar_t* str = L"Hello, World!"; - - size_t len = wcslen(str); - - EXPECT_EQ(len, 13); - - wchar_t null[] = {L'\0'}; - - len = wcslen(null); - - EXPECT_EQ(len, 0); - - TEST_SUCCESS(); -} \ No newline at end of file diff --git a/tools/binutils.patch b/tools/binutils.patch index d375e06f..d262e7f8 100644 --- a/tools/binutils.patch +++ b/tools/binutils.patch @@ -1,6 +1,6 @@ -diff --color -rN -u binutils-2.38/bfd/config.bfd build/binutils-2.38/bfd/config.bfd ---- a/binutils-2.38/bfd/config.bfd 2022-01-22 13:14:07.000000000 +0100 -+++ b/binutils-2.38/bfd/config.bfd 2022-10-01 22:12:16.914033792 +0200 +diff --color -rN -u binutils-2.39/bfd/config.bfd build/binutils-2.39/bfd/config.bfd +--- a/binutils-2.39/bfd/config.bfd 2022-01-22 13:14:07.000000000 +0100 ++++ b/binutils-2.39/bfd/config.bfd 2022-10-01 22:12:16.914033792 +0200 @@ -651,6 +651,11 @@ targ_selvecs="iamcu_elf32_vec i386_pei_vec" targ64_selvecs="x86_64_elf64_vec x86_64_elf32_vec x86_64_pe_vec x86_64_pei_vec l1om_elf64_vec k1om_elf64_vec" @@ -25,9 +25,9 @@ diff --color -rN -u binutils-2.38/bfd/config.bfd build/binutils-2.38/bfd/config. x86_64-*-mingw* | x86_64-*-pe | x86_64-*-pep | x86_64-*-cygwin) targ_defvec=x86_64_pe_vec targ_selvecs="x86_64_pe_vec x86_64_pei_vec x86_64_pe_big_vec x86_64_elf64_vec l1om_elf64_vec k1om_elf64_vec i386_pe_vec i386_pei_vec i386_elf32_vec iamcu_elf32_vec" -diff --color -rN -u binutils-2.38/gas/configure.tgt build/binutils-2.38/gas/configure.tgt ---- a/binutils-2.38/gas/configure.tgt 2022-01-22 13:14:08.000000000 +0100 -+++ b/binutils-2.38/gas/configure.tgt 2022-10-01 22:12:38.115093972 +0200 +diff --color -rN -u binutils-2.39/gas/configure.tgt build/binutils-2.39/gas/configure.tgt +--- a/binutils-2.39/gas/configure.tgt 2022-01-22 13:14:08.000000000 +0100 ++++ b/binutils-2.39/gas/configure.tgt 2022-10-01 22:12.39.115093972 +0200 @@ -238,6 +238,7 @@ x86_64*-linux-gnux32) arch=x86_64:32 ;; esac ;; @@ -36,9 +36,9 @@ diff --color -rN -u binutils-2.38/gas/configure.tgt build/binutils-2.38/gas/conf i386-*-redox*) fmt=elf ;; i386-*-solaris*) fmt=elf em=solaris ;; i386-*-freebsd* \ -diff --color -rN -u binutils-2.38/ld/configure.tgt build/binutils-2.38/ld/configure.tgt ---- a/binutils-2.38/ld/configure.tgt 2022-01-22 15:19:36.000000000 +0100 -+++ b/binutils-2.38/ld/configure.tgt 2022-10-01 22:15:04.853571062 +0200 +diff --color -rN -u binutils-2.39/ld/configure.tgt build/binutils-2.39/ld/configure.tgt +--- a/binutils-2.39/ld/configure.tgt 2022-01-22 15:19:36.000000000 +0100 ++++ b/binutils-2.39/ld/configure.tgt 2022-10-01 22:15:04.853571062 +0200 @@ -329,6 +329,11 @@ targ64_extra_emuls="elf_x86_64 elf32_x86_64 elf_l1om elf_k1om" targ64_extra_libpath="elf_x86_64 elf32_x86_64" @@ -62,24 +62,24 @@ diff --color -rN -u binutils-2.38/ld/configure.tgt build/binutils-2.38/ld/config x86_64-*-redox*) targ_emul=elf_x86_64 targ_extra_emuls=elf_i386 ;; -diff --color -rN -u binutils-2.38/ld/emulparams/elf_i386_luna.sh build/binutils-2.38/ld/emulparams/elf_i386_luna.sh +diff --color -rN -u binutils-2.39/ld/emulparams/elf_i386_luna.sh build/binutils-2.39/ld/emulparams/elf_i386_luna.sh --- a/dev/null 1970-01-01 01:00:00.000000000 +0100 -+++ b/binutils-2.38/ld/emulparams/elf_i386_luna.sh 2022-10-01 21:52:12.394068335 +0200 ++++ b/binutils-2.39/ld/emulparams/elf_i386_luna.sh 2022-10-01 21:52:12.394068335 +0200 @@ -0,0 +1,3 @@ +source_sh ${srcdir}/emulparams/elf_i386.sh +TEXT_START_ADDR=0x08000000 +MAXPAGESIZE=0x1000 \ No newline at end of file -diff --color -rN -u binutils-2.38/ld/emulparams/elf_x86_64_luna.sh build/binutils-2.38/ld/emulparams/elf_x86_64_luna.sh +diff --color -rN -u binutils-2.39/ld/emulparams/elf_x86_64_luna.sh build/binutils-2.39/ld/emulparams/elf_x86_64_luna.sh --- a/dev/null 1970-01-01 01:00:00.000000000 +0100 -+++ b/binutils-2.38/ld/emulparams/elf_x86_64_luna.sh 2022-10-01 21:53:00.411200592 +0200 ++++ b/binutils-2.39/ld/emulparams/elf_x86_64_luna.sh 2022-10-01 21:53:00.411200592 +0200 @@ -0,0 +1,2 @@ +source_sh ${srcdir}/emulparams/elf_x86_64.sh +MAXPAGESIZE=0x1000 \ No newline at end of file -diff --color -rN -u binutils-2.38/ld/Makefile.am build/binutils-2.38/ld/Makefile.am ---- a/binutils-2.38/ld/Makefile.am 2022-01-22 13:14:09.000000000 +0100 -+++ b/binutils-2.38/ld/Makefile.am 2022-10-01 22:18:02.660263017 +0200 +diff --color -rN -u binutils-2.39/ld/Makefile.am build/binutils-2.39/ld/Makefile.am +--- a/binutils-2.39/ld/Makefile.am 2022-01-22 13:14:09.000000000 +0100 ++++ b/binutils-2.39/ld/Makefile.am 2022-10-01 22:18:02.660263017 +0200 @@ -278,6 +278,7 @@ eelf32xtensa.c \ eelf32z80.c \ @@ -96,9 +96,9 @@ diff --color -rN -u binutils-2.38/ld/Makefile.am build/binutils-2.38/ld/Makefile ehppa64linux.c \ ei386pep.c \ emmo.c -diff --color -rN -u binutils-2.38/ld/Makefile.in build/binutils-2.38/ld/Makefile.in ---- a/binutils-2.38/ld/Makefile.in 2022-02-09 12:49:03.000000000 +0100 -+++ b/binutils-2.38/ld/Makefile.in 2022-10-01 22:17:46.740196925 +0200 +diff --color -rN -u binutils-2.39/ld/Makefile.in build/binutils-2.39/ld/Makefile.in +--- a/binutils-2.39/ld/Makefile.in 2022-02-09 12:49:03.000000000 +0100 ++++ b/binutils-2.39/ld/Makefile.in 2022-10-01 22:17:46.740196925 +0200 @@ -769,6 +769,7 @@ eelf32xtensa.c \ eelf32z80.c \ diff --git a/tools/build-debug.sh b/tools/build-debug.sh index 877def35..e571ff01 100755 --- a/tools/build-debug.sh +++ b/tools/build-debug.sh @@ -1,6 +1,18 @@ #!/usr/bin/env bash - set -e + source $(dirname $0)/env.sh -MOON_BUILD_DEBUG=1 tools/rebuild-iso.sh \ No newline at end of file +cd $LUNA_ROOT + +tools/setup.sh + +tools/full-clean.sh + +tools/install-headers.sh + +cmake -S . -B $BUILD_DIR -DMOON_DEBUG_SYMBOLS=ON -DLUNA_DEBUG_SYMBOLS=ON -G "$CMAKE_GEN" +cmake --build $BUILD_DIR +cmake --install $BUILD_DIR + +mkbootimg luna.json Luna.iso diff --git a/tools/build-iso.sh b/tools/build-iso.sh index c810c1e9..ee0177dc 100755 --- a/tools/build-iso.sh +++ b/tools/build-iso.sh @@ -9,7 +9,9 @@ tools/setup.sh tools/install-headers.sh -make -j$(nproc) -make install +mkdir -p $BUILD_DIR +cmake -S . -B $BUILD_DIR -G "$CMAKE_GEN" +cmake --build $BUILD_DIR +cmake --install $BUILD_DIR -mkbootimg luna.json Luna.iso \ No newline at end of file +mkbootimg luna.json Luna.iso diff --git a/tools/build-stable-iso.sh b/tools/build-stable-iso.sh deleted file mode 100755 index 270c97b1..00000000 --- a/tools/build-stable-iso.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash -set -e - -source $(dirname $0)/env.sh - -cd $LUNA_ROOT - -MOON_BUILD_STABLE=1 tools/rebuild-iso.sh \ No newline at end of file diff --git a/tools/build-stable-iso.sh b/tools/build-stable-iso.sh new file mode 120000 index 00000000..0b6e6f17 --- /dev/null +++ b/tools/build-stable-iso.sh @@ -0,0 +1 @@ +./rebuild-iso.sh \ No newline at end of file diff --git a/tools/build.sh b/tools/build.sh index 0d0e5d9e..f854d8e5 100755 --- a/tools/build.sh +++ b/tools/build.sh @@ -9,4 +9,6 @@ tools/setup.sh tools/install-headers.sh -make -j$(nproc) \ No newline at end of file +mkdir -p $BUILD_DIR +cmake -S . -B $BUILD_DIR -G "$CMAKE_GEN" +cmake --build $BUILD_DIR diff --git a/tools/buildstep.sh b/tools/buildstep.sh deleted file mode 100755 index fe06e0d3..00000000 --- a/tools/buildstep.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -set -e - -unset -f filter-lines -filter-lines() -{ - sed $'s|^|\x1b[33m('"$1/$2"$')\x1b[39m |' -} - -make -C $1 $2 | filter-lines $1 $2 \ No newline at end of file diff --git a/tools/check-formatting.sh b/tools/check-formatting.sh index fa7c7449..9be40812 100755 --- a/tools/check-formatting.sh +++ b/tools/check-formatting.sh @@ -4,16 +4,17 @@ source $(dirname $0)/env.sh cd $LUNA_ROOT -SOURCES=($(find kernel/src -type f | grep "\.c") $(find kernel/include -type f)) -SOURCES+=($(find libs/libc/src -type f | grep "\.c") $(find libs/libc/include -type f)) -SOURCES+=($(find apps/src -type f)) +SOURCES=($(find kernel/src -type f | grep -v "\.asm")) +SOURCES+=($(find luna/src -type f)) +SOURCES+=($(find luna/include/luna -type f)) ALL_OK=1 for f in ${SOURCES[@]} do - clang-format -n $f 2>&1 | grep ".*" >/dev/null - if [ "$?" = "0" ] + clang-format -n $f 2>&1 | grep -q ^ + RESULT=$? + if [ "$RESULT" -eq "0" ] then echo "File $f needs formatting" ALL_OK=0 diff --git a/tools/check-stdint.sh b/tools/check-stdint.sh new file mode 100755 index 00000000..8bd9cfb4 --- /dev/null +++ b/tools/check-stdint.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash + +set -e +source $(dirname $0)/env.sh + +cd $LUNA_ROOT + +SOURCES=($(find kernel/src -type f | grep -v "\.asm" | grep -v "bootboot.h")) +SOURCES+=($(find luna/src -type f)) +SOURCES+=($(find luna/include/luna -type f | grep -v "Types.h")) + +SUCCESS=1 + +lint-file() +{ + info="$(grep -Hnow $1 $3 | awk -v wrong="$1" -v right="$2" 'BEGIN { FS=":" }{ print $1 ":" $2 ": " wrong " -> " right }')" + if ! [ "$info" = "" ] + then + echo "$info" + SUCCESS=0 + fi +} + +for f in ${SOURCES[@]} +do + lint-file uint8_t u8 $f + lint-file uint16_t u16 $f + lint-file uint32_t u32 $f + lint-file uint64_t u64 $f + + lint-file int8_t i8 $f + lint-file int16_t i16 $f + lint-file int32_t i32 $f + lint-file int64_t i64 $f + + lint-file size_t usize $f + lint-file ssize_t isize $f +done + +if [ "$SUCCESS" = "0" ] +then +exit 1 +else +echo All files OK +fi \ No newline at end of file diff --git a/tools/clean.sh b/tools/clean.sh index e005b12c..6d9139c6 100755 --- a/tools/clean.sh +++ b/tools/clean.sh @@ -3,6 +3,6 @@ set -e source $(dirname $0)/env.sh -cd $LUNA_ROOT +cd $BUILD_DIR -make clean \ No newline at end of file +$BUILD clean \ No newline at end of file diff --git a/tools/debug.sh b/tools/debug.sh index ad05afad..9623df96 100755 --- a/tools/debug.sh +++ b/tools/debug.sh @@ -3,4 +3,4 @@ set -e source $(dirname $0)/env.sh -qemu-system-x86_64 -cdrom Luna.iso -smp 1 -m 256M -serial stdio -d int,cpu_reset -s $@ \ No newline at end of file +qemu-system-$ARCH -cdrom Luna.iso -smp 1 -m 256M -serial stdio -d int,cpu_reset -s $@ \ No newline at end of file diff --git a/tools/env.sh b/tools/env.sh index 4a9e8061..72d65835 100755 --- a/tools/env.sh +++ b/tools/env.sh @@ -1,16 +1,19 @@ #!/usr/bin/env bash export LUNA_ROOT=${LUNA_ROOT:-$(realpath $(dirname $0)/..)} export LUNA_BASE=${LUNA_BASE:-$LUNA_ROOT/base} -export PATH=$LUNA_ROOT/toolchain/x86-64-luna/bin:$LUNA_ROOT/toolchain/dist:$PATH +export PATH=$LUNA_ROOT/toolchain/x86_64-luna/bin:$LUNA_ROOT/toolchain/dist:$PATH -export CC=x86_64-luna-gcc -export CXX=x86_64-luna-g++ -export LD=x86_64-luna-ld -export AR=x86_64-luna-ar -export ASM=nasm -export STRIP=x86_64-luna-strip +[ -f "$LUNA_ROOT/env-local.sh" ] && source $LUNA_ROOT/env-local.sh -filter-lines() -{ - sed $'s|^|\x1b[32m('"$1/$2"$')\x1b[39m |' -} \ No newline at end of file +export ARCH=${ARCH:-x86_64} + +if [ "$USE_MAKE" = "1" ] +then +export BUILD=make +export CMAKE_GEN="Unix Makefiles" +else +export BUILD=ninja +export CMAKE_GEN="Ninja" +fi + +export BUILD_DIR=$LUNA_ROOT/build/$BUILD-$ARCH diff --git a/tools/fast-run.sh b/tools/fast-run.sh index 1d9f21c3..49f43dd9 100755 --- a/tools/fast-run.sh +++ b/tools/fast-run.sh @@ -5,4 +5,4 @@ source $(dirname $0)/env.sh cd $LUNA_ROOT -qemu-system-x86_64 -cdrom Luna.iso -smp 1 -m 256M -serial stdio -enable-kvm $@ \ No newline at end of file +qemu-system-$ARCH -cdrom Luna.iso -smp 1 -m 256M -serial stdio -enable-kvm $@ \ No newline at end of file diff --git a/tools/full-clean.sh b/tools/full-clean.sh new file mode 100755 index 00000000..e4e03188 --- /dev/null +++ b/tools/full-clean.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -e + +source $(dirname $0)/env.sh + +rm -rf $BUILD_DIR +mkdir -p $BUILD_DIR \ No newline at end of file diff --git a/tools/gcc.patch b/tools/gcc.patch index 04500e4d..3a984f97 100644 --- a/tools/gcc.patch +++ b/tools/gcc.patch @@ -34,7 +34,7 @@ diff --color -rN -u gcc-12.2.0/gcc/config/i386/x86_64-luna-kernel build/gcc-12.2 diff --color -rN -u gcc-12.2.0/gcc/config/luna.h build/gcc-12.2.0/gcc/config/luna.h --- a/dev/null 1970-01-01 01:00:00.000000000 +0100 +++ b/gcc-12.2.0/gcc/config/luna.h 2022-10-02 11:27:45.663055404 +0200 -@@ -0,0 +1,40 @@ +@@ -0,0 +1,36 @@ +#undef TARGET_LUNA +#define TARGET_LUNA 1 + @@ -52,9 +52,6 @@ diff --color -rN -u gcc-12.2.0/gcc/config/luna.h build/gcc-12.2.0/gcc/config/lun +#undef ENDFILE_SPEC +#define ENDFILE_SPEC "crtend.o%s crtn.o%s" + -+#undef PID_TYPE -+#define PID_TYPE "long int" -+ +#undef SIZE_TYPE +#define SIZE_TYPE (TARGET_64BIT ? "long unsigned int" : "unsigned int") + diff --git a/tools/gdb.sh b/tools/gdb.sh index f0363a98..bae0b3ab 100755 --- a/tools/gdb.sh +++ b/tools/gdb.sh @@ -3,4 +3,6 @@ set -e source $(dirname $0)/env.sh -gdb -x .gdbconf \ No newline at end of file +cd $BUILD_DIR + +gdb -x $LUNA_ROOT/.gdbconf \ No newline at end of file diff --git a/tools/install-built-ports.sh b/tools/install-built-ports.sh deleted file mode 100755 index 8e21fbc4..00000000 --- a/tools/install-built-ports.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env bash - -set -e - -source $(dirname $0)/env.sh - -cd $LUNA_ROOT/ports - -unset_vars() -{ - unset pkgname - unset pkgver - unset pkgurl - unset pkgmode - unset setupdir - unset builddir - unset installdir - unset srcdir - unset port_unpack - unset port_patch - unset port_configure - unset port_build - unset port_install - unset port_uninstall - unset islib -} - -if ! [ -f ./ports.list ] -then - echo "No ports built." - exit 0 -fi - -install_port() -{ - unset_vars - cd $LUNA_ROOT/ports - export DESTDIR=${DESTDIR:-"$LUNA_ROOT/initrd"} - export portdir=$PWD/$1 - export workdir=$portdir/workdir - source $portdir/package.sh - if ! [ "$islib" = "1" ] - then - echo "installing port: $pkgname version $pkgver" - mkdir -p $installdir - cd $installdir - port_install | filter-lines $pkgname "install" - fi -} - -while read package; do - install_port $package -done < ./ports.list diff --git a/tools/install-headers.sh b/tools/install-headers.sh index cbacbd09..c851192f 100755 --- a/tools/install-headers.sh +++ b/tools/install-headers.sh @@ -5,9 +5,9 @@ source $(dirname $0)/env.sh cd $LUNA_ROOT -mkdir -p base -mkdir -p base/usr/include -mkdir -p base/usr/include/moon +mkdir -p $LUNA_BASE +mkdir -p $LUNA_BASE/usr/include +mkdir -p $LUNA_BASE/usr/include/luna -cp -RT libs/libc/include base/usr/include -cp -RT kernel/include base/usr/include/moon \ No newline at end of file +cp -RT libc/include/ $LUNA_BASE/usr/include +cp -RT luna/include/luna/ $LUNA_BASE/usr/include/luna diff --git a/tools/install.sh b/tools/install.sh index 7b903dc2..73a507f6 100755 --- a/tools/install.sh +++ b/tools/install.sh @@ -5,4 +5,4 @@ source $(dirname $0)/env.sh cd $LUNA_ROOT -make install \ No newline at end of file +cmake --install $BUILD_DIR \ No newline at end of file diff --git a/tools/rebuild-iso.sh b/tools/rebuild-iso.sh index fb38d5b3..012df09c 100755 --- a/tools/rebuild-iso.sh +++ b/tools/rebuild-iso.sh @@ -7,11 +7,12 @@ cd $LUNA_ROOT tools/setup.sh -make clean +tools/full-clean.sh tools/install-headers.sh -make -j$(nproc) -make install +cmake -S . -B $BUILD_DIR -G "$CMAKE_GEN" +cmake --build $BUILD_DIR +cmake --install $BUILD_DIR -mkbootimg luna.json Luna.iso \ No newline at end of file +mkbootimg luna.json Luna.iso diff --git a/tools/rebuild.sh b/tools/rebuild.sh index ee3649b0..524b7ba1 100755 --- a/tools/rebuild.sh +++ b/tools/rebuild.sh @@ -7,8 +7,9 @@ cd $LUNA_ROOT tools/setup.sh +tools/full-clean.sh + tools/install-headers.sh -make clean - -make -j$(nproc) \ No newline at end of file +cmake -S . -B $BUILD_DIR -G "$CMAKE_GEN" +cmake --build $BUILD_DIR diff --git a/tools/replace-stdint.sh b/tools/replace-stdint.sh new file mode 100755 index 00000000..2b42c24a --- /dev/null +++ b/tools/replace-stdint.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +set -e +source $(dirname $0)/env.sh + +cd $LUNA_ROOT + +SOURCES=($(find kernel/src -type f | grep -v "\.asm" | grep -v "bootboot.h")) +SOURCES+=($(find luna/src -type f)) +SOURCES+=($(find luna/include/luna -type f | grep -v "Types.h")) + +for f in ${SOURCES[@]} +do + sed -i 's/uint8_t/u8/g' $f + sed -i 's/uint16_t/u16/g' $f + sed -i 's/uint32_t/u32/g' $f + sed -i 's/uint64_t/u64/g' $f + + sed -i 's/int8_t/i8/g' $f + sed -i 's/int16_t/i16/g' $f + sed -i 's/int32_t/i32/g' $f + sed -i 's/int64_t/i64/g' $f + + sed -i 's/size_t/usize/g' $f + sed -i 's/ssize_t/isize/g' $f +done \ No newline at end of file diff --git a/tools/run-clang-format.sh b/tools/run-clang-format.sh index 4e88d1ec..eed14fac 100755 --- a/tools/run-clang-format.sh +++ b/tools/run-clang-format.sh @@ -5,9 +5,9 @@ source $(dirname $0)/env.sh cd $LUNA_ROOT -SOURCES=($(find kernel/src -type f | grep "\.c") $(find kernel/include -type f)) -SOURCES+=($(find libs/libc/src -type f | grep "\.c") $(find libs/libc/include -type f)) -SOURCES+=($(find apps/src -type f)) +SOURCES=($(find kernel/src -type f | grep -v "\.asm")) +SOURCES+=($(find luna/src -type f)) +SOURCES+=($(find luna/include/luna -type f)) for f in ${SOURCES[@]} do diff --git a/tools/setup-binutils.sh b/tools/setup-binutils.sh index e7f59b03..8360520a 100755 --- a/tools/setup-binutils.sh +++ b/tools/setup-binutils.sh @@ -24,7 +24,7 @@ echo Patching Binutils... cd toolchain -patch -u -i $LUNA_ROOT/tools/binutils.patch -p 1 -d build | filter-lines "binutils" "patch" +patch -u -i $LUNA_ROOT/tools/binutils.patch -p 1 -d build cd - @@ -39,12 +39,12 @@ unset CXX unset LD unset AR -../binutils-$LUNA_BINUTILS_VERSION_REQUIRED/configure --prefix="$BUILD_PREFIX" --target=$BUILD_TARGET --disable-nls --with-sysroot=$BUILD_SYSROOT --disable-werror | filter-lines "binutils" "configure" +../binutils-$LUNA_BINUTILS_VERSION_REQUIRED/configure --prefix="$BUILD_PREFIX" --target=$BUILD_TARGET --disable-nls --with-sysroot=$BUILD_SYSROOT --disable-werror --enable-warn-rwx-segments=no echo Building Binutils... -make -j$(nproc) | filter-lines "binutils" "build" +make -j$(nproc) echo Installing Binutils... -make install | filter-lines "binutils" "install" \ No newline at end of file +make install diff --git a/tools/setup-env.sh b/tools/setup-env.sh index 1d3aa3d0..13885c62 100755 --- a/tools/setup-env.sh +++ b/tools/setup-env.sh @@ -2,8 +2,8 @@ source $(dirname $0)/env.sh export LUNA_GCC_VERSION_REQUIRED=12.2.0 -export LUNA_BINUTILS_VERSION_REQUIRED=2.38 +export LUNA_BINUTILS_VERSION_REQUIRED=2.39 -export BUILD_PREFIX=$LUNA_ROOT/toolchain/x86-64-luna +export BUILD_PREFIX=$LUNA_ROOT/toolchain/x86_64-luna export BUILD_TARGET=x86_64-luna -export BUILD_SYSROOT=$LUNA_ROOT/base \ No newline at end of file +export BUILD_SYSROOT=$LUNA_ROOT/base diff --git a/tools/setup-gcc.sh b/tools/setup-gcc.sh index 844509bf..94500386 100755 --- a/tools/setup-gcc.sh +++ b/tools/setup-gcc.sh @@ -32,7 +32,7 @@ echo Patching GCC... cd toolchain -patch -u -i $LUNA_ROOT/tools/gcc.patch -p 1 -d build | filter-lines "gcc" "patch" +patch -u -i $LUNA_ROOT/tools/gcc.patch -p 1 -d build cd - @@ -47,23 +47,14 @@ unset CXX unset LD unset AR -../gcc-$LUNA_GCC_VERSION_REQUIRED/configure --prefix="$BUILD_PREFIX" --target=$BUILD_TARGET --disable-nls --with-sysroot=$BUILD_SYSROOT --enable-languages=c,c++ --without-headers | filter-lines "gcc" "configure" +../gcc-$LUNA_GCC_VERSION_REQUIRED/configure --prefix="$BUILD_PREFIX" --target=$BUILD_TARGET --disable-nls --with-sysroot=$BUILD_SYSROOT --enable-languages=c,c++ --without-headers echo Building GCC... -make all-gcc -j$(nproc) | filter-lines "gcc" "build" -make all-target-libgcc -j$(nproc) CFLAGS_FOR_TARGET='-g -O2 -mcmodel=large -mno-red-zone' | filter-lines "libgcc" "build" +make all-gcc -j$(nproc) +make all-target-libgcc -j$(nproc) CFLAGS_FOR_TARGET='-g -O2 -mcmodel=large -mno-red-zone' echo Installing GCC... -make install-gcc | filter-lines "gcc" "install" -make install-target-libgcc | filter-lines "libgcc" "install" - -echo Building libstdc++... - -$LUNA_ROOT/tools/sync-libc.sh # libstdc++ needs libc to be built -make all-target-libstdc++-v3 CXXFLAGS_FOR_TARGET="-fno-exceptions" -j$(nproc) | filter-lines "libstdc++" "build" - -echo Installing libstdc++... - -make install-target-libstdc++-v3 | filter-lines "libstdc++" "install" \ No newline at end of file +make install-gcc +make install-target-libgcc diff --git a/tools/sync-libc.sh b/tools/sync-libc.sh deleted file mode 100755 index cf6df110..00000000 --- a/tools/sync-libc.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash - -set -e -source $(dirname $0)/env.sh - -cd $LUNA_ROOT - -tools/install-headers.sh - -cd libs/ - -$LUNA_ROOT/tools/buildstep.sh libc build -$LUNA_ROOT/tools/buildstep.sh libc install \ No newline at end of file diff --git a/tools/test.sh b/tools/test.sh deleted file mode 100755 index d73fd091..00000000 --- a/tools/test.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash - -set -e -source $(dirname $0)/env.sh - -cd $LUNA_ROOT - -make -C tests build -make -C tests install -make -C tests test \ No newline at end of file