From 52a0628827888204c28e05e7d6842c1339650c37 Mon Sep 17 00:00:00 2001 From: Benji Dial Date: Thu, 23 Jul 2026 19:30:57 -0400 Subject: [PATCH] reboot part i --- clean-build.sh | 3 + clean-dependencies.sh | 3 + compile_flags.txt | 9 +- disk/calcite/init.rc | 1 - disk/calcite/qwerty.bin | Bin 2048 -> 0 bytes disk/limine/limine.conf | 5 +- get-dependencies.sh | 21 +- include/calcite/assert.hxx | 30 + include/calcite/dispatch.h | 24 - include/calcite/file-streams.h | 30 - include/calcite/format.h | 26 - include/calcite/memory.h | 29 - include/calcite/result.hxx | 86 ++ include/calcite/syscalls.h | 88 -- include/calcite/terminal.h | 46 - include/kernel-public/files.h | 40 - include/kernel-public/framebuffer.h | 27 - include/kernel-public/input.h | 153 ---- include/kernel-public/ipc.h | 38 - include/kernel-public/process.h | 32 - include/kernel-public/sync.h | 23 - include/kernel-public/syscall-numbers.h | 50 -- include/silver/image.h | 36 - include/silver/pam.h | 23 - make-build.sh | 243 ++--- qemu.gdb | 2 +- readme.txt | 119 ++- src/core/core.asm | 28 + src/core/core.cxx | 456 ++++++++++ src/core/limine.hxx | 1 + src/{kernel => core}/link.ld | 24 +- src/kernel/debug.c | 113 --- src/kernel/debug.h | 44 - src/kernel/drives.c | 55 -- src/kernel/drives.h | 46 - src/kernel/entry.c | 328 ------- src/kernel/framebuffer.c | 24 - src/kernel/framebuffer.h | 26 - src/kernel/fs.c | 105 --- src/kernel/fs.h | 58 -- src/kernel/heap.c | 104 --- src/kernel/heap.h | 23 - src/kernel/input.c | 140 --- src/kernel/input.h | 28 - src/kernel/interrupts.asm | 171 ---- src/kernel/interrupts.c | 320 ------- src/kernel/interrupts.h | 26 - src/kernel/ipc-dgram.c | 269 ------ src/kernel/ipc-dgram.h | 68 -- src/kernel/iso9660.c | 382 -------- src/kernel/iso9660.h | 22 - src/kernel/paging.asm | 49 - src/kernel/paging.c | 232 ----- src/kernel/paging.h | 63 -- src/kernel/pata.c | 250 ------ src/kernel/pata.h | 23 - src/kernel/pci.asm | 40 - src/kernel/pci.c | 61 -- src/kernel/pci.h | 32 - src/kernel/process.asm | 55 -- src/kernel/process.c | 1098 ----------------------- src/kernel/process.h | 205 ----- src/kernel/ps2.asm | 71 -- src/kernel/ps2.c | 118 --- src/kernel/ps2.h | 23 - src/kernel/scheduler.asm | 82 -- src/kernel/scheduler.c | 100 --- src/kernel/scheduler.h | 64 -- src/kernel/serial.asm | 73 -- src/kernel/serial.c | 54 -- src/kernel/serial.h | 26 - src/kernel/syscalls.asm | 87 -- src/kernel/syscalls.c | 46 - src/kernel/syscalls.h | 27 - src/kernel/timer.asm | 37 - src/kernel/timer.c | 111 --- src/kernel/timer.h | 28 - src/kernel/utility.asm | 62 -- src/kernel/utility.c | 117 --- src/kernel/utility.h | 57 -- src/service/hello/hello.cxx | 22 + src/{user-apps => service}/link.ld | 13 +- src/user-apps/init/init.c | 75 -- src/user-apps/init/libraries.txt | 1 - src/user-apps/shell/assembler.c | 218 ----- src/user-apps/shell/assembler.h | 38 - src/user-apps/shell/builtin-words.c | 226 ----- src/user-apps/shell/builtin-words.h | 20 - src/user-apps/shell/libraries.txt | 1 - src/user-apps/shell/main.c | 36 - src/user-apps/shell/runtime.asm | 40 - src/user-apps/shell/runtime.c | 218 ----- src/user-apps/shell/runtime.h | 63 -- src/user-apps/terminal/libraries.txt | 2 - src/user-apps/terminal/terminal.c | 196 ---- src/user-libs/calcite/dispatch.c | 87 -- src/user-libs/calcite/entry.c | 25 - src/user-libs/calcite/file-streams.c | 150 ---- src/user-libs/calcite/format.c | 42 - src/user-libs/calcite/memory.c | 197 ---- src/user-libs/calcite/syscalls.asm | 28 - src/user-libs/calcite/syscalls.c | 155 ---- src/user-libs/calcite/terminal.c | 271 ------ src/user-libs/silver/image.c | 31 - src/user-libs/silver/pam.c | 128 --- 105 files changed, 858 insertions(+), 8764 deletions(-) create mode 100755 clean-build.sh create mode 100755 clean-dependencies.sh delete mode 100644 disk/calcite/init.rc delete mode 100644 disk/calcite/qwerty.bin mode change 100644 => 100755 get-dependencies.sh create mode 100644 include/calcite/assert.hxx delete mode 100644 include/calcite/dispatch.h delete mode 100644 include/calcite/file-streams.h delete mode 100644 include/calcite/format.h delete mode 100644 include/calcite/memory.h create mode 100644 include/calcite/result.hxx delete mode 100644 include/calcite/syscalls.h delete mode 100644 include/calcite/terminal.h delete mode 100644 include/kernel-public/files.h delete mode 100644 include/kernel-public/framebuffer.h delete mode 100644 include/kernel-public/input.h delete mode 100644 include/kernel-public/ipc.h delete mode 100644 include/kernel-public/process.h delete mode 100644 include/kernel-public/sync.h delete mode 100644 include/kernel-public/syscall-numbers.h delete mode 100644 include/silver/image.h delete mode 100644 include/silver/pam.h mode change 100644 => 100755 make-build.sh create mode 100644 src/core/core.asm create mode 100644 src/core/core.cxx create mode 120000 src/core/limine.hxx rename src/{kernel => core}/link.ld (65%) delete mode 100644 src/kernel/debug.c delete mode 100644 src/kernel/debug.h delete mode 100644 src/kernel/drives.c delete mode 100644 src/kernel/drives.h delete mode 100644 src/kernel/entry.c delete mode 100644 src/kernel/framebuffer.c delete mode 100644 src/kernel/framebuffer.h delete mode 100644 src/kernel/fs.c delete mode 100644 src/kernel/fs.h delete mode 100644 src/kernel/heap.c delete mode 100644 src/kernel/heap.h delete mode 100644 src/kernel/input.c delete mode 100644 src/kernel/input.h delete mode 100644 src/kernel/interrupts.asm delete mode 100644 src/kernel/interrupts.c delete mode 100644 src/kernel/interrupts.h delete mode 100644 src/kernel/ipc-dgram.c delete mode 100644 src/kernel/ipc-dgram.h delete mode 100644 src/kernel/iso9660.c delete mode 100644 src/kernel/iso9660.h delete mode 100644 src/kernel/paging.asm delete mode 100644 src/kernel/paging.c delete mode 100644 src/kernel/paging.h delete mode 100644 src/kernel/pata.c delete mode 100644 src/kernel/pata.h delete mode 100644 src/kernel/pci.asm delete mode 100644 src/kernel/pci.c delete mode 100644 src/kernel/pci.h delete mode 100644 src/kernel/process.asm delete mode 100644 src/kernel/process.c delete mode 100644 src/kernel/process.h delete mode 100644 src/kernel/ps2.asm delete mode 100644 src/kernel/ps2.c delete mode 100644 src/kernel/ps2.h delete mode 100644 src/kernel/scheduler.asm delete mode 100644 src/kernel/scheduler.c delete mode 100644 src/kernel/scheduler.h delete mode 100644 src/kernel/serial.asm delete mode 100644 src/kernel/serial.c delete mode 100644 src/kernel/serial.h delete mode 100644 src/kernel/syscalls.asm delete mode 100644 src/kernel/syscalls.c delete mode 100644 src/kernel/syscalls.h delete mode 100644 src/kernel/timer.asm delete mode 100644 src/kernel/timer.c delete mode 100644 src/kernel/timer.h delete mode 100644 src/kernel/utility.asm delete mode 100644 src/kernel/utility.c delete mode 100644 src/kernel/utility.h create mode 100644 src/service/hello/hello.cxx rename src/{user-apps => service}/link.ld (80%) delete mode 100644 src/user-apps/init/init.c delete mode 100644 src/user-apps/init/libraries.txt delete mode 100644 src/user-apps/shell/assembler.c delete mode 100644 src/user-apps/shell/assembler.h delete mode 100644 src/user-apps/shell/builtin-words.c delete mode 100644 src/user-apps/shell/builtin-words.h delete mode 100644 src/user-apps/shell/libraries.txt delete mode 100644 src/user-apps/shell/main.c delete mode 100644 src/user-apps/shell/runtime.asm delete mode 100644 src/user-apps/shell/runtime.c delete mode 100644 src/user-apps/shell/runtime.h delete mode 100644 src/user-apps/terminal/libraries.txt delete mode 100644 src/user-apps/terminal/terminal.c delete mode 100644 src/user-libs/calcite/dispatch.c delete mode 100644 src/user-libs/calcite/entry.c delete mode 100644 src/user-libs/calcite/file-streams.c delete mode 100644 src/user-libs/calcite/format.c delete mode 100644 src/user-libs/calcite/memory.c delete mode 100644 src/user-libs/calcite/syscalls.asm delete mode 100644 src/user-libs/calcite/syscalls.c delete mode 100644 src/user-libs/calcite/terminal.c delete mode 100644 src/user-libs/silver/image.c delete mode 100644 src/user-libs/silver/pam.c diff --git a/clean-build.sh b/clean-build.sh new file mode 100755 index 0000000..e548695 --- /dev/null +++ b/clean-build.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +rm -rf build build.ninja diff --git a/clean-dependencies.sh b/clean-dependencies.sh new file mode 100755 index 0000000..f16a2aa --- /dev/null +++ b/clean-dependencies.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +rm -rf dependencies diff --git a/compile_flags.txt b/compile_flags.txt index bfe9d86..5fb5551 100644 --- a/compile_flags.txt +++ b/compile_flags.txt @@ -1,10 +1,3 @@ --std=c23 --ffreestanding --I -dependencies/limine --I -dependencies/flanterm/src +-std=c++17 -I include --D -CALCITE_DEBUG diff --git a/disk/calcite/init.rc b/disk/calcite/init.rc deleted file mode 100644 index cfef8bd..0000000 --- a/disk/calcite/init.rc +++ /dev/null @@ -1 +0,0 @@ -root://calcite/apps/terminal/terminal.elf diff --git a/disk/calcite/qwerty.bin b/disk/calcite/qwerty.bin deleted file mode 100644 index a5141fe4132e49989e843efabd3725eed703b9ae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2048 zcmds%S5v}J5QWbx`4x60F%UX}1$#pUdpGum3ikfnJ$tVY4l|i?95WNxm(A`bnVfuQ zFYqHmt}bdZ=GVLZr#Nul04mD=e>R*(hPkmFlm3eb%c&z}8u8)m(v{V1;#PVV% zFh4Rixv|Un+{{XsiE#hy^g_4?7#u3*N_*_L;mu-#@qu^A9uY|WuKw7v@E85$FZvaK z(NF$LzwoDi#h>~$|6;z>B>Zc_U;JOt{#X3P|KzXyFZ}6$#h?Dy{42R?lkoRr|6@pI q_}83BJeAJ!!b;dCkB$F}fbV}p=yx>^KlZ;N^naiKe(Zlh^?w0*`i6x7 diff --git a/disk/limine/limine.conf b/disk/limine/limine.conf index 9dd1bae..7e148c3 100644 --- a/disk/limine/limine.conf +++ b/disk/limine/limine.conf @@ -1,7 +1,6 @@ timeout: 0 -quiet: yes +quiet: yes /Calcite protocol: limine -path: boot():/calcite/kernel.elf -cmdline: root-drive=pata0,root-fs=iso9660 +path: boot():/calcite/core.elf diff --git a/get-dependencies.sh b/get-dependencies.sh old mode 100644 new mode 100755 index da748d5..8376843 --- a/get-dependencies.sh +++ b/get-dependencies.sh @@ -1,22 +1,25 @@ #!/bin/sh -LIMINE_VERSION="9.3.4" -FLANTERM_VERSION="2.1.0" +LIMINE_VERSION="12.5.2" +LIMINE_PROTOCOL_COMMIT="630686a3dd3ce40f9e510a7dd9fea6b4c60d952e" if [ -e dependencies ]; then - echo dependencies directory already exists. + echo The dependencies directory already exists. + echo Use clean-dependencies.sh to remove it. exit fi set -e mkdir dependencies - cd dependencies -curl -L https://codeberg.org/Limine/Limine/archive/v${LIMINE_VERSION}-binary.tar.gz | tar xz -make -C limine -cd .. -cd dependencies -curl -L https://codeberg.org/Mintsuki/Flanterm/archive/v${FLANTERM_VERSION}.tar.gz | tar xz +curl -L https://github.com/Limine-Bootloader/Limine/releases/download/v12.5.2/limine-binary.tar.gz | tar xz +make -C limine-binary + +curl -L https://github.com/Limine-Bootloader/limine-protocol/archive/${LIMINE_PROTOCOL_COMMIT}.zip -o limine-protocol.zip +unzip limine-protocol.zip +rm limine-protocol.zip +mv limine-protocol-${LIMINE_PROTOCOL_COMMIT} limine-protocol + cd .. diff --git a/include/calcite/assert.hxx b/include/calcite/assert.hxx new file mode 100644 index 0000000..a32ad28 --- /dev/null +++ b/include/calcite/assert.hxx @@ -0,0 +1,30 @@ +/* include/calcite/assert.hxx + * Runtime assertions and panics. + * + * Copyright 2026 Benji Dial + * This file is part of the Calcite Operating System. + * + * Calcite is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, version 3 only. + * + * Calcite is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * Calcite. If not, see . + */ + +#pragma once + +#define assert(cond) { \ + if (cond) {} \ + else ::calcite::assert_fail(); \ +} + +namespace calcite { + + [[noreturn]] void assert_fail(); + +} diff --git a/include/calcite/dispatch.h b/include/calcite/dispatch.h deleted file mode 100644 index a159a0d..0000000 --- a/include/calcite/dispatch.h +++ /dev/null @@ -1,24 +0,0 @@ -/* Calcite, include/calcite/dispatch.h - * Copyright 2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -struct dispatch_queue; - -struct dispatch_queue *create_dispatch_queue(); -void dispatch(struct dispatch_queue *queue, void (*callback)(void *x), void *x); -[[noreturn]] void dispatch_loop(struct dispatch_queue *queue); diff --git a/include/calcite/file-streams.h b/include/calcite/file-streams.h deleted file mode 100644 index 597c070..0000000 --- a/include/calcite/file-streams.h +++ /dev/null @@ -1,30 +0,0 @@ -/* Calcite, include/calcite/file-streams.h - * Copyright 2025 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -#include - -struct file_stream; - -enum fs_access_result open_file_stream(const char *path, struct file_stream **file_stream_out); -void close_file_stream(struct file_stream *file_stream); - -enum fs_access_result read_file_stream(struct file_stream *file_stream, void *buffer, uint64_t bytes); - -//returns next byte casted to int. on error or eof, returns -1. -int read_file_stream_byte(struct file_stream *file_stream); diff --git a/include/calcite/format.h b/include/calcite/format.h deleted file mode 100644 index fb11257..0000000 --- a/include/calcite/format.h +++ /dev/null @@ -1,26 +0,0 @@ -/* Calcite, include/calcite/format.h - * Copyright 2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -#include - -//does not write null terminator. buffer must be at least digit_count bytes long. -void to_hex(uint64_t value, int digit_count, char *buffer); - -//buffer must be at least digit_count bytes long. -uint64_t from_hex(int digit_count, char *buffer); diff --git a/include/calcite/memory.h b/include/calcite/memory.h deleted file mode 100644 index 7a74414..0000000 --- a/include/calcite/memory.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Calcite, include/calcite/memory.h - * Copyright 2025-2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -#include - -void *heap_alloc(uint64_t bytes); - -//start should be something returned from heap_alloc, -//unless this is called (carefully) from inside memory.c -void heap_dealloc(void *start, uint64_t bytes); - -void memcpy(void *to, const void *from, uint64_t bytes); -void memset(void *start, uint8_t value, uint64_t length); diff --git a/include/calcite/result.hxx b/include/calcite/result.hxx new file mode 100644 index 0000000..7c89d5b --- /dev/null +++ b/include/calcite/result.hxx @@ -0,0 +1,86 @@ +/* include/calcite/result.hxx + * Result type returned from functions across Calcite. + * + * Copyright 2026 Benji Dial + * This file is part of the Calcite Operating System. + * + * Calcite is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, version 3 only. + * + * Calcite is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * Calcite. If not, see . + */ + +#pragma once + +#include +#include +#include +#include + +namespace calcite { + + enum class result_code { + good, + out_of_memory, + not_found + }; + + class empty {}; + + template + class [[nodiscard]] result { + private: + + result_code code; + uint8_t buffer[sizeof(type)]; + + public: + + result(result_code code) : code(code) { + assert(code != result_code::good); + } + + template + result(param_types &&...params) : code(result_code::good) { + new ((type *)buffer) type(std::forward(params)...); + } + + ~result() { + if (code != result_code::good) + ((type *)buffer)->~type(); + } + + result(result &&other) = delete; + result(const result &other) = delete; + + result &operator =(result &&other) = delete; + result &operator =(const result &other) = delete; + + type &unwrap() { + assert(code == result_code::good); + return *(type *)buffer; + } + + const type &unwrap() const { + assert(code == result_code::good); + return *(const type *)buffer; + } + + bool is_error() const { + return code != result_code::good; + } + + result_code get_error() const { + assert(code != result_code::good); + return code; + } + + }; + +} diff --git a/include/calcite/syscalls.h b/include/calcite/syscalls.h deleted file mode 100644 index fd881b8..0000000 --- a/include/calcite/syscalls.h +++ /dev/null @@ -1,88 +0,0 @@ -/* Calcite, include/calcite/syscalls.h - * Copyright 2025-2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -#include -#include -#include -#include -#include -#include - -[[noreturn]] void end_thread(); - -void map_framebuffer(struct framebuffer_info *info_out); - -enum fs_access_result open_file(const char *path, file_handle_t *handle_out); -void close_file(file_handle_t handle); - -enum fs_access_result get_file_size(file_handle_t handle, uint64_t *bytes_out); - -enum fs_access_result read_file(struct read_file_parameter *parameter); -enum fs_access_result read_file_splat(file_handle_t handle, void *buffer, uint64_t start, uint64_t bytes); - -void wait_for_mouse_packet(struct mouse_packet *packet_out); -int wait_for_keyboard_packet(); - -void *map_pages(uint64_t count); - -void sleep_ms(uint64_t ms_to_sleep); - -//1 on success, 0 on failure. -int start_elf(const char *path, const struct process_start_info *info); - -enum ipc_dgram_result ipc_create_dgram_receiver(const char *address, ipc_dgram_receiver_handle_t *handle_out); -enum ipc_dgram_result ipc_create_dgram_sender(const char *address, ipc_dgram_sender_handle_t *handle_out); - -//on entry, bytes is maximum accepted packet length. -//on exit, if result was IPR_SUCCESS or IPR_TOO_BIG, bytes is actual packet length. -//actual packet length will always be positive. -enum ipc_dgram_result ipc_receive_dgram(ipc_dgram_receiver_handle_t handle, void *buffer, int *bytes); - -//bytes must be positive. -enum ipc_dgram_result ipc_send_dgram(ipc_dgram_sender_handle_t handle, const void *data, int bytes); - -//returned id is global across processes. only one receiver and one sender can be created per pipe. -uint64_t ipc_create_private_dgram_pipe(); -enum ipc_dgram_result ipc_create_private_dgram_receiver(uint64_t id, ipc_dgram_receiver_handle_t *handle_out); -enum ipc_dgram_result ipc_create_private_dgram_sender(uint64_t id, ipc_dgram_sender_handle_t *handle_out); - -//f should not return -void create_thread(void (*f)(uint64_t x), uint64_t x); - -//value_space must be positive at entry. -//looks up the environment variable with this key. if there is no such -//variable, sets value_space to 0. otherwise, sets value_space to the -//length of the value including null terminator (which will be positive), -//and if that is at most what value_space was set to at entry, also -//copies the value including null terminator to value_out. -void get_envvar(const char *key, char *value_out, int *value_space); - -mutex_handle_t create_mutex(); -void acquire_mutex(mutex_handle_t handle); -void release_mutex(mutex_handle_t handle); - -event_handle_t create_event(); -void signal_event(event_handle_t handle); -void wait_event(event_handle_t handle); - -uint64_t get_ms_since_boot(); -void sleep_until_ms_since_boot(uint64_t ms); - -//vma should be page-aligned. writable and executable should be 1 or 0. -void change_page_permissions(void *vma, int writable, int executable); diff --git a/include/calcite/terminal.h b/include/calcite/terminal.h deleted file mode 100644 index f910161..0000000 --- a/include/calcite/terminal.h +++ /dev/null @@ -1,46 +0,0 @@ -/* Calcite, include/calcite/terminal.h - * Copyright 2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -#include - -void init_terminal(); - -void terminal_write(const void *data, int bytes); -void terminal_flush(); - -enum terminal_key_flags { - TKF_LEFT_SHIFT = 0x20000, - TKF_RIGHT_SHIFT = 0x40000, - TKF_LEFT_CTRL = 0x80000, - TKF_RIGHT_CTRL = 0x100000, - TKF_LEFT_ALT = 0x200000, - TKF_RIGHT_ALT = 0x400000, - TKF_CAPS_LOCK = 0x800000, - TKF_NUM_LOCK = 0x1000000 -}; - -//0x000000ff is printable character, if any, otherwise 0. -// this includes space, newline, and tab, but not delete or backspace. -// control, alt, and make are ignored, but shift, caps lock, and num lock are considered. -//0x0001ff00 is result of syscall_wait_for_keyboard_packet, shifted left. -//0x01fe0000 is flags as above. -int terminal_readkey(); - -//has null terminator, no newline. returned pointer is invalidated by next call. -const char *terminal_readline(); diff --git a/include/kernel-public/files.h b/include/kernel-public/files.h deleted file mode 100644 index 32205af..0000000 --- a/include/kernel-public/files.h +++ /dev/null @@ -1,40 +0,0 @@ -/* Calcite, include/kernel-public/files.h - * Copyright 2025 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -#include - -enum fs_access_result { - FAR_SUCCESS, - FAR_HARDWARE_ERROR, - FAR_FORMAT_ERROR, - FAR_UNKNOWN_FS_TYPE, - FAR_NOT_FOUND, - FAR_OUT_OF_BOUNDS, - FAR_BAD_HANDLE -}; - -typedef uint64_t file_handle_t; - -struct read_file_parameter { - file_handle_t handle; - void *buffer; - //in bytes - uint64_t start; - uint64_t bytes; -}; diff --git a/include/kernel-public/framebuffer.h b/include/kernel-public/framebuffer.h deleted file mode 100644 index 6ee1267..0000000 --- a/include/kernel-public/framebuffer.h +++ /dev/null @@ -1,27 +0,0 @@ -/* Calcite, include/kernel-public/framebuffer.h - * Copyright 2025 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -#include - -struct framebuffer_info { - uint8_t *fb_base; - int fb_width; - int fb_height; - int fb_pitch; -}; diff --git a/include/kernel-public/input.h b/include/kernel-public/input.h deleted file mode 100644 index 8736a31..0000000 --- a/include/kernel-public/input.h +++ /dev/null @@ -1,153 +0,0 @@ -/* Calcite, include/kernel-public/input.h - * Copyright 2025-2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -struct mouse_packet { - int x_change; - int y_change; -}; - -//named after qwerty value of key -enum key_value { - KEY_F9 = 0x01, - KEY_F5 = 0x03, - KEY_F3 = 0x04, - KEY_F1 = 0x05, - KEY_F2 = 0x06, - KEY_F12 = 0x07, - KEY_F10 = 0x09, - KEY_F8 = 0x0a, - KEY_F6 = 0x0b, - KEY_F4 = 0x0c, - KEY_TAB = 0x0d, - KEY_GRAVE = 0x0e, - KEY_LEFT_ALT = 0x11, - KEY_LEFT_SHIFT = 0x12, - KEY_LEFT_CTRL = 0x14, - KEY_Q = 0x15, - KEY_1 = 0x16, - KEY_Z = 0x1a, - KEY_S = 0x1b, - KEY_A = 0x1c, - KEY_W = 0x1d, - KEY_2 = 0x1e, - KEY_C = 0x21, - KEY_X = 0x22, - KEY_D = 0x23, - KEY_E = 0x24, - KEY_4 = 0x25, - KEY_3 = 0x26, - KEY_SPACE = 0x29, - KEY_V = 0x2a, - KEY_F = 0x2b, - KEY_T = 0x2c, - KEY_R = 0x2d, - KEY_5 = 0x2e, - KEY_N = 0x31, - KEY_B = 0x32, - KEY_H = 0x33, - KEY_G = 0x34, - KEY_Y = 0x35, - KEY_6 = 0x36, - KEY_M = 0x3a, - KEY_J = 0x3b, - KEY_U = 0x3c, - KEY_7 = 0x3d, - KEY_8 = 0x3e, - KEY_COMMA = 0x41, - KEY_K = 0x42, - KEY_I = 0x43, - KEY_O = 0x44, - KEY_0 = 0x45, - KEY_9 = 0x46, - KEY_PERIOD = 0x49, - KEY_SLASH = 0x4a, - KEY_L = 0x4b, - KEY_SEMICOLON = 0x4c, - KEY_P = 0x4d, - KEY_MINUS = 0x4e, - KEY_APOSTRAPHE = 0x52, - KEY_OPEN_BRACKET = 0x54, - KEY_EQUALS = 0x55, - KEY_CAPS_LOCK = 0x58, - KEY_RIGHT_SHIFT = 0x59, - KEY_ENTER = 0x5a, - KEY_CLOSE_BRACKET = 0x5b, - KEY_BACKSLASH = 0x5d, - KEY_BACKSPACE = 0x66, - KEY_NUM_1 = 0x69, - KEY_NUM_4 = 0x6b, - KEY_NUM_7 = 0x6c, - KEY_NUM_0 = 0x70, - KEY_NUM_PERIOD = 0x71, - KEY_NUM_2 = 0x72, - KEY_NUM_5 = 0x73, - KEY_NUM_6 = 0x74, - KEY_NUM_8 = 0x75, - KEY_ESCAPE = 0x76, - KEY_NUM_LOCK = 0x77, - KEY_F11 = 0x78, - KEY_NUM_PLUS = 0x79, - KEY_NUM_3 = 0x7a, - KEY_NUM_MINUS = 0x7b, - KEY_NUM_TIMES = 0x7c, - KEY_NUM_9 = 0x7d, - KEY_SCROLL_LOCK = 0x7e, - KEY_F7 = 0x83, - KEY_WEB_SEARCH = 0x90, - KEY_RIGHT_ALT = 0x91, - KEY_RIGHT_CTRL = 0x94, - KEY_MEDIA_PREVIOUS = 0x95, - KEY_WEB_FAVORITES = 0x98, - KEY_LEFT_GUI = 0x9f, - KEY_WEB_REFRESH = 0xa0, - KEY_MEDIA_VOLUME_DOWN = 0xa1, - KEY_MEDIA_MUTE = 0xa3, - KEY_RIGHT_GUI = 0xa7, - KEY_WEB_STOP = 0xa8, - KEY_CALCULATOR = 0xab, - KEY_MENU = 0xaf, - KEY_WEB_FORWARD = 0xb0, - KEY_MEDIA_VOLUME_UP = 0xb2, - KEY_MEDIA_PAUSE = 0xb4, - KEY_ACPI_POWER = 0xb7, - KEY_WEB_BACK = 0xb8, - KEY_WEB_HOME = 0xba, - KEY_MEDIA_STOP = 0xbb, - KEY_ACPI_SLEEP = 0xbf, - KEY_COMPUTER = 0xc0, - KEY_EMAIL = 0xc8, - KEY_NUM_DIVIDE = 0xca, - KEY_MEDIA_NEXT = 0xcd, - KEY_MEDIA_SELECT = 0xd0, - KEY_NUM_ENTER = 0xda, - KEY_ACPI_WAKE = 0xde, - KEY_END = 0xe9, - KEY_LEFT = 0xeb, - KEY_HOME = 0xec, - KEY_INSERT = 0xf0, - KEY_DELETE = 0xf1, - KEY_DOWN = 0xf2, - KEY_RIGHT = 0xf4, - KEY_UP = 0xf5, - KEY_PAGE_DOWN = 0xfa, - KEY_PAGE_UP = 0xfd, - KEY_PRINT_SCREEN = 0xfe, - KEY_PAUSE_BREAK = 0xff, - KEY_FLAG_MAKE = 0x100 -}; diff --git a/include/kernel-public/ipc.h b/include/kernel-public/ipc.h deleted file mode 100644 index 56f9f2c..0000000 --- a/include/kernel-public/ipc.h +++ /dev/null @@ -1,38 +0,0 @@ -/* Calcite, include/kernel-public/ipc.h - * Copyright 2025 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -#include - -enum ipc_dgram_result { - - IPR_SUCCESS, - - //on write, packet is bigger than kernel data structure. - //on read, packet is bigger than max requested size. - IPR_TOO_BIG, - - IPR_BAD_HANDLE, - - //on create receiver, someone is already receiving at that address. - IPR_IN_USE - -}; - -typedef uint64_t ipc_dgram_receiver_handle_t; -typedef uint64_t ipc_dgram_sender_handle_t; diff --git a/include/kernel-public/process.h b/include/kernel-public/process.h deleted file mode 100644 index 320acea..0000000 --- a/include/kernel-public/process.h +++ /dev/null @@ -1,32 +0,0 @@ -/* Calcite, include/kernel-public/process.h - * Copyright 2025 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -struct process_start_info { - - //keys of envvars to copy to new process. - const char **forwared_envvars; - int forwared_envvar_count; - - //keys and values to set in new process. - //entry i has key set_envvars[i * 2] and value set_envvars[i * 2 + 1]. - //set_envvar_count is number of envvars, not twice that. - const char **set_envvars; - int set_envvar_count; - -}; diff --git a/include/kernel-public/sync.h b/include/kernel-public/sync.h deleted file mode 100644 index 893b6ca..0000000 --- a/include/kernel-public/sync.h +++ /dev/null @@ -1,23 +0,0 @@ -/* Calcite, include/kernel-public/sync.h - * Copyright 2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -#include - -typedef uint64_t mutex_handle_t; -typedef uint64_t event_handle_t; diff --git a/include/kernel-public/syscall-numbers.h b/include/kernel-public/syscall-numbers.h deleted file mode 100644 index 6e80c4e..0000000 --- a/include/kernel-public/syscall-numbers.h +++ /dev/null @@ -1,50 +0,0 @@ -/* Calcite, include/kernel-public/syscall-numbers.h - * Copyright 2025-2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -enum { - SYSCALL_END_THREAD, - SYSCALL_MAP_FRAMEBUFFER, - SYSCALL_OPEN_FILE, - SYSCALL_CLOSE_FILE, - SYSCALL_GET_FILE_SIZE, - SYSCALL_READ_FILE, - SYSCALL_WAIT_FOR_MOUSE_PACKET, - SYSCALL_MAP_PAGES, - SYSCALL_SLEEP_MS, - SYSCALL_START_ELF, - SYSCALL_IPC_CREATE_DGRAM_RECEIVER, - SYSCALL_IPC_CREATE_DGRAM_SENDER, - SYSCALL_IPC_RECEIVE_DGRAM, - SYSCALL_IPC_SEND_DGRAM, - SYSCALL_CREATE_THREAD, - SYSCALL_GET_ENVVAR, - SYSCALL_CREATE_MUTEX, - SYSCALL_ACQUIRE_MUTEX, - SYSCALL_RELEASE_MUTEX, - SYSCALL_CREATE_EVENT, - SYSCALL_SIGNAL_EVENT, - SYSCALL_WAIT_EVENT, - SYSCALL_IPC_CREATE_PRIVATE_DGRAM_PIPE, - SYSCALL_IPC_CREATE_PRIVATE_DGRAM_RECEIVER, - SYSCALL_IPC_CREATE_PRIVATE_DGRAM_SENDER, - SYSCALL_GET_MS_SINCE_BOOT, - SYSCALL_SLEEP_UNTIL_MS_SINCE_BOOT, - SYSCALL_CHANGE_PAGE_PERMISSIONS, - SYSCALL_WAIT_FOR_KEYBOARD_PACKET -}; diff --git a/include/silver/image.h b/include/silver/image.h deleted file mode 100644 index 73061d9..0000000 --- a/include/silver/image.h +++ /dev/null @@ -1,36 +0,0 @@ -/* Calcite, include/silver/image.h - * Copyright 2025 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -#include - -struct pixel { - uint8_t r; - uint8_t g; - uint8_t b; - uint8_t a; -}; - -struct image { - int width; - int height; - struct pixel *pixels; -}; - -void create_image(int width, int height, struct image **image_out); -void destroy_image(struct image *image); diff --git a/include/silver/pam.h b/include/silver/pam.h deleted file mode 100644 index 8566c2d..0000000 --- a/include/silver/pam.h +++ /dev/null @@ -1,23 +0,0 @@ -/* Calcite, include/silver/pam.h - * Copyright 2025 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -#include - -//returns 0 on failure, 1 on success. -int load_pam(const char *path, struct image **image_out); diff --git a/make-build.sh b/make-build.sh old mode 100644 new mode 100755 index 5747e4d..03690bb --- a/make-build.sh +++ b/make-build.sh @@ -1,145 +1,148 @@ #!/bin/sh -COMMON_CC_EXTRA_FLAGS="-Wall -Wextra" -COMMON_LD_EXTRA_FLAGS="" - -COMMON_CC_FLAGS="-std=c23 -ffreestanding -I include ${COMMON_CC_EXTRA_FLAGS}" -COMMON_LD_FLAGS="${COMMON_LD_EXTRA_FLAGS}" - -if [ "$1" = debug ]; then - COMMON_CC_FLAGS="-O0 -ggdb -D CALCITE_DEBUG ${COMMON_CC_FLAGS}" -elif [ "$1" = release ]; then - COMMON_CC_FLAGS="-O3 -D CALCITE_RELEASE ${COMMON_CC_FLAGS}" - COMMON_LD_FLAGS="-s ${COMMON_LD_FLAGS}" -else - echo pass either "debug" or "release" as an argument. +if [ -e build.ninja ]; then + echo The build.ninja file already exists. + echo Remove it with clean-build.sh. exit fi -KERNEL_CC_FLAGS="-mno-sse -I dependencies/limine ${COMMON_CC_FLAGS}" -#in the future user code will be allowed to use sse -USER_CC_FLAGS="-mno-sse -I dependencies/flanterm/src ${COMMON_CC_FLAGS}" - -FLANTERM_CC_FLAGS="-D FLANTERM_FB_DISABLE_BUMP_ALLOC ${USER_CC_FLAGS}" - -if [ -e build.ninja ]; then - echo build.ninja already exists. +if [ "$#" -eq 0 ]; then + echo This script must be run with at least one flag. The recognized flags are: + echo + echo " -- Do nothing, but silence this message." + echo + echo " --cxx-flags FLAGS Add FLAGS to the flags sent to the C++ compiler. The flags" + echo " should be quoted, so that they are all read by this script" + echo " as one argument." + echo + echo " --debug Enable debugging symbols." + echo + echo " --ld-flags FLAGS Add FLAGS to the flags sent to ld. The flags should be" + echo " quoted, so that they are all read by this script as one" + echo " argument." + echo + echo " --no-optimize Disable compiler optimizations. This might help with using" + echo " the debugger. A bug could only appear when optimizations" + echo " are enabled, so it might be necessary to run the debugger" + echo " without this flag." + echo + echo These options can be combined. exit fi set -e -echo "rule nasm" >> build.ninja -echo " command = nasm -f elf64 \$in -o \$out" >> build.ninja +CXX_FLAGS="-std=c++17 -ffreestanding -fno-exceptions -fno-rtti -mno-sse -I include -Wall -Wextra" +LD_FLAGS="-L build/libraries" -echo "rule kernel_cc" >> build.ninja -echo " depfile = \$out.d" >> build.ninja -echo " command = cc -c -MD -MF \$out.d ${KERNEL_CC_FLAGS} \$in -o \$out" >> build.ninja +OPTIMIZE_CXX_FLAGS="-O2" +DEBUG_CXX_FLAGS="" +NO_DEBUG_LD_FLAGS="-s" +EXTRA_CXX_FLAGS="" +EXTRA_LD_FLAGS="" -echo "rule user_cc" >> build.ninja -echo " depfile = \$out.d" >> build.ninja -echo " command = cc -c -MD -MF \$out.d ${USER_CC_FLAGS} \$in -o \$out" >> build.ninja +while [ "$#" -gt 0 ]; do + case "$1" in + --cxx-flags) + shift + EXTRA_CXX_FLAGS="$EXTRA_CXX_FLAGS $1" + ;; + --debug) + DEBUG_CXX_FLAGS="-ggdb" + NO_DEBUG_LD_FLAGS="" + ;; + --ld-flags) + shift + EXTRA_LD_FLAGS="$EXTRA_LD_FLAGS $1" + ;; + --no-optimize) + OPTIMIZE_CXX_FLAGS="" + ;; + --) + ;; + *) + echo Unknown argument. + exit + esac + shift +done -echo "rule flanterm_cc" >> build.ninja -echo " depfile = \$out.d" >> build.ninja -echo " command = cc -c -MD -MF \$out.d ${FLANTERM_CC_FLAGS} \$in -o \$out" >> build.ninja - -echo "rule kernel_ld" >> build.ninja -echo " command = ld ${COMMON_LD_FLAGS} -T src/kernel/link.ld \$in -o \$out" >> build.ninja - -echo "rule user_lib_ld" >> build.ninja -echo " command = ld -r \$in -o \$out" >> build.ninja - -#eventually maybe a libc will be linked in -echo "rule user_app_ld" >> build.ninja -echo " command = ld ${COMMON_LD_FLAGS} -T src/user-apps/link.ld \$in -o \$out" >> build.ninja - -#builds everything in a directory -# $1 - source directory -# $2 - cc rule -# $3 - ld rule -# $4 - linked object name -# $5 - extra objects to link in -build_all() { - - sources="$1/*.asm $1/*.c" - objects="$5" - - for src in $sources; do - if echo $src | grep -q -v '*'; then - build=$(echo $src | sed -e 's/^src/build/').o - if echo $src | grep -q '.c$'; then - echo "build $build: $2 $src" >> build.ninja - else - echo "build $build: nasm $src" >> build.ninja - fi - objects="$objects $build" - fi - done - - build_dir=$(echo $1 | sed -e 's/^src/build/') - echo "build $build_dir/$4: $3 $objects" >> build.ninja +CXX_FLAGS="$CXX_FLAGS $OPTIMIZE_CXX_FLAGS $DEBUG_CXX_FLAGS $EXTRA_CXX_FLAGS" +LD_FLAGS="$LD_FLAGS $NO_DEBUG_LD_FLAGS $EXTRA_LD_FLAGS" +rules() { + echo "rule asm" + echo " command = nasm -f elf64 \$in -o \$out" + echo "rule cxx" + echo " depfile = \$out.d" + echo " command = c++ -c -MD -MF \$out.d $CXX_FLAGS \$in -o \$out" + echo "rule core_ld" + echo " depfile = \$out.d" + echo " command = ld $LD_FLAGS -T src/core/link.ld \$in -o \$out" + echo "rule service_ld" + echo " depfile = \$out.d" + echo " command = ld $LD_FLAGS -T src/service/link.ld \$in -o \$out" + echo "rule disk" + echo " command =" \ + "rm -rf build/disk &&" \ + "cp -r disk build/disk &&" \ + "mkdir -p build/disk/EFI/BOOT &&" \ + "mkdir -p build/disk/limine &&" \ + "mkdir -p build/disk/calcite/service &&" \ + "cp dependencies/limine-binary/BOOTX64.EFI build/disk/EFI/BOOT/ &&" \ + "cp dependencies/limine-binary/limine-uefi-cd.bin build/disk/limine/ &&" \ + "cp dependencies/limine-binary/limine-bios-cd.bin build/disk/limine/ &&" \ + "cp dependencies/limine-binary/limine-bios.sys build/disk/limine/ &&" \ + "cp build/core.elf build/disk/calcite/ &&" \ + "cp build/service/*.elf build/disk/calcite/service/ &&" \ + "xorriso -as mkisofs -R -r -J -b limine/limine-bios-cd.bin -no-emul-boot -boot-load-size 4" \ + "-boot-info-table -hfsplus -apm-block-size 2048 --efi-boot limine/limine-uefi-cd.bin" \ + "-efi-boot-part --efi-boot-image --protective-msdos-label build/disk -o build/disk.iso &&" \ + "dependencies/limine-binary/limine bios-install build/disk.iso" } -build_all src/kernel kernel_cc kernel_ld kernel.elf +build_core() { + echo "build build/core/core.cxx.o: cxx src/core/core.cxx" + echo "build build/core/core.asm.o: asm src/core/core.asm" + echo "build build/core.elf: core_ld build/core/core.cxx.o build/core/core.asm.o" +} -objects="" -for file in flanterm.c flanterm_backends/fb.c; do - src="dependencies/flanterm/src/$file" - build="build/user-libs/flanterm/$file.o" - echo "build $build: flanterm_cc $src" >> build.ninja - objects="$objects $build" -done -echo "build build/user-libs/flanterm/libflanterm.o: user_lib_ld $objects" >> build.ninja +build_service() { + SERVICE="$1" + OBJECTS="" + for SOURCE in $(find "src/service/$SERVICE" -regex '.*\.cxx'); do + OBJECT="$(echo $SOURCE | sed 's/src/build/').o" + echo "build $OBJECT: cxx $SOURCE" + OBJECTS="$OBJECTS $OBJECT" + done + for SOURCE in $(find "src/service/$SERVICE" -regex '.*\.asm'); do + OBJECT="$(echo $SOURCE | sed 's/src/build/').o" + echo "build $OBJECT: asm $SOURCE" + OBJECTS="$OBJECTS $OBJECT" + done + echo "build build/service/$SERVICE.elf: service_ld$OBJECTS" +} -for dir in src/user-libs/*; do - lib_name=$(echo $dir | sed -e 's/^src\/user-libs\///') - build_all $dir user_cc user_lib_ld lib$lib_name.o -done +build_disk() { + echo "build build/disk.iso: disk | $@" +} -cp_apps="" -app_deps="" +default() { + echo "default build/disk.iso" +} -for dir in src/user-apps/*; do - if [ -d $dir ]; then +rules >> build.ninja - if [ -e $dir/libraries.txt ]; then - lib_paths=$(cat $dir/libraries.txt | sed -e 's/^.*$/build\/user-libs\/\0\/lib\0.o/' | tr '\n' ' ') - else - lib_paths="" - fi - - app_name=$(echo $dir | sed -e 's/^src\/user-apps\///') - build_all $dir user_cc user_app_ld $app_name.elf "$lib_paths" - - build_elf=$(echo $dir | sed -e 's/^src/build/')/$app_name.elf - disk_dir=build/disk/calcite/apps/$app_name - disk_elf=$disk_dir/$app_name.elf - - cp_apps=$(echo "$cp_apps" \ - "mkdir -p $disk_dir &&" \ - "cp $build_elf $disk_elf &&") - app_deps="$app_deps $build_elf" +DISK_DEPS="build/core.elf" +build_core >> build.ninja +for DIRECTORY in src/service/*; do + if [ -d "$DIRECTORY" ]; then + SERVICE="$(basename $DIRECTORY)" + DISK_DEPS="$DISK_DEPS build/service/$SERVICE.elf" + build_service $SERVICE >> build.ninja fi done -echo "rule disk" >> build.ninja -echo " command =" \ - "rm -rf build/disk &&" \ - "cp -r disk build/disk &&" \ - "cp dependencies/limine/limine-uefi-cd.bin build/disk/limine/ &&" \ - "cp dependencies/limine/limine-bios-cd.bin build/disk/limine/ &&" \ - "cp dependencies/limine/limine-bios.sys build/disk/limine/ &&"\ - "mkdir -p build/disk/EFI/BOOT &&" \ - "cp dependencies/limine/BOOTX64.EFI build/disk/EFI/BOOT/ &&" \ - "mkdir -p build/disk/calcite &&" \ - "cp build/kernel/kernel.elf build/disk/calcite/ &&" \ - $cp_apps \ - "xorriso -as mkisofs -R -r -J -b limine/limine-bios-cd.bin -no-emul-boot -boot-load-size 4 -boot-info-table -hfsplus -apm-block-size 2048 --efi-boot limine/limine-uefi-cd.bin -efi-boot-part --efi-boot-image --protective-msdos-label -quiet build/disk -o build/disk.iso &&" \ - "dependencies/limine/limine bios-install --quiet build/disk.iso" >> build.ninja - -echo "build build/disk.iso: disk | build/kernel/kernel.elf $app_deps" >> build.ninja - -echo "default build/disk.iso" >> build.ninja +build_disk $DISK_DEPS >> build.ninja +default >> build.ninja diff --git a/qemu.gdb b/qemu.gdb index 8ec043a..f422028 100644 --- a/qemu.gdb +++ b/qemu.gdb @@ -1,5 +1,5 @@ target remote | qemu-system-x86_64 -gdb stdio -cdrom build/disk.iso -boot d -symbol-file build/kernel/kernel.elf +symbol-file build/core.elf set disassembly-flavor intel set print asm-demangle on layout src diff --git a/readme.txt b/readme.txt index 5c3f22f..21b7516 100644 --- a/readme.txt +++ b/readme.txt @@ -1,72 +1,95 @@ - ____ _ _ _ - / ___|__ _| | ___(_) |_ ___ -| | / _` | |/ __| | __/ _ \ -| |__| (_| | | (__| | || __/ - \____\__,_|_|\___|_|\__\___| + ___ _ _ _ + / __|__ _| |__(_) |_ ___ + | (__/ _` | / _| | _/ -_) + \___\__,_|_\__|_|\__\___| Calcite is a hobby operating system. I am maintaining a weblog with occasional status updates at . Calcite is very much alpha software. Do not expect it to do anything useful. -=== Building + === Building === Calcite requires some software to be installed before it can be built: - * curl - * GCC (Any C compiler supporting both C99 and C23 should work.) - * GNU Binutils (Specifically, "ld" is used to link the kernel.) - * GNU xorriso - * NASM - * Ninja build system +* a C compiler supporting C99 (e.g. GCC) +* a C++ compiler supporting C++17 (e.g. GCC) +* curl +* GNU ld +* GNU tar +* GNU xorriso +* NASM +* Ninja build system On Debian, it is sufficient to run this command: - apt install binutils curl gcc nasm ninja-build xorriso + apt install binutils curl g++ gcc nasm ninja-build tar xorriso -To build Calcite, run these commands: - sh get-dependencies.sh - sh make-build.sh release - ninja +The Calcite disk includes some software that is not in this repository. +To download that software into the repository tree, use the get-dependencies.sh +script. To remove those files, use the clean-dependencies.sh script. -This will build a disk image at "build/disk.iso" that can be booted with -either BIOS or UEFI. +Next, use the make-build.sh script to make the ninja.build file. Running this +script with no arguments will display information about the arguments that this +script accepts. -=== Debugging +Finally, just run ninja to build the disk. A disk image will be placed at +build/disk.iso. This disk must be booted with UEFI. All build files, including +ninja.build, but not including the files downloaded by get-dependencies.sh, +can be removed with the clean-build.sh script. -Once Calcite has been built, some more software is required to debug it: - * GNU's GDB - * QEMU, including the x86_64 system + === Debugging === + +More software must be installed to debug Calcite: +* GNU's GDB +* QEMU, including the x86_64 system On Debian, it is sufficient to run this command: apt install gdb qemu-system-x86 -Then, just run "gdb -x qemu.gdb". Calcite will be booted in QEMU, and GDB will -be attached to it. Use "c" or "continue" in GDB to start execution. +Run "gdb -x qemu.gdb" to boot Calcite in QEMU and attach GDB to it. +The debugging experience will be nicer if debugging symbols were +enabled during the make-build.sh step. -While debugging, it is useful to disable optimizations and enable debugging -information. If you already built Calcite in "release" mode, run: - rm -r build build.ninja - sh make-build.sh debug - ninja + === License === -If you did not already build Calcite, then you do not need the first command. +Calcite is Copyright 2026 Benji Dial. -=== License +Calcite is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation (version 3 only). -Calcite is Copyright 2025-2026 Benji Dial, and licensed under the GNU GPL v3. -See "license.txt" for the text of the license. +Calcite is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. -The disk image includes the Limine bootloader, version 9.3.4. Limine is -Copyright 2019-2025 Mintsuki and contributors, and is released under the -BSD 2-Clause license. You can find Limine online at - . -After running "sh get-dependencies.sh", you can find the license of Limine -at "dependencies/limine/LICENSE". Limine also has its own dependencies. -In the source repository of Limine, you can find a list of these with -their licenses at "3RDPARTY.md". +You should have received a copy of the GNU General Public License along with +Calcite (in license.txt). If not, see . -The terminal, included in the disk image, is linked with the Flanterm library, -version 2.1.0. Flanterm is Copyright 2022-2025 minstuki and contributors, and -is released under the BSD 2-Clause license. You can find Flanterm online at - . -After running "sh get-dependencies.sh", you can find the license of Flanterm -at "dependencies/flanterm/LICENSE". +The Calcite disk image includes the Limine bootloader, version 12.5.0. Limine is +Copyright 2019-2026 Mintsuki and contributors, and is used under the terms of +the BSD 2-Clause License, reproduced below: + + Copyright (C) 2019-2026 Mintsuki and contributors. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must n the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Limine has some transitive dependencies. Information about these can be found at +. diff --git a/src/core/core.asm b/src/core/core.asm new file mode 100644 index 0000000..bab145e --- /dev/null +++ b/src/core/core.asm @@ -0,0 +1,28 @@ + ; src/core/core.asm + ; The core of the Calcite Operating System. + ; + ; Copyright 2026 Benji Dial + ; This file is part of the Calcite Operating System. + ; + ; Calcite is free software: you can redistribute it and/or modify it under the + ; terms of the GNU General Public License as published by the Free Software + ; Foundation, version 3 only. + ; + ; Calcite is distributed in the hope that it will be useful, but WITHOUT ANY + ; WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + ; A PARTICULAR PURPOSE. See the GNU General Public License for more details. + ; + ; You should have received a copy of the GNU General Public License along with + ; Calcite. If not, see . + +bits 64 + +section .text + +global asm_set_cr3 +asm_set_cr3: + mov cr3, rdi + mov rsp, rsi + push qword 0 + xor rbp, rbp + jmp rdx diff --git a/src/core/core.cxx b/src/core/core.cxx new file mode 100644 index 0000000..16692ac --- /dev/null +++ b/src/core/core.cxx @@ -0,0 +1,456 @@ +/* src/core/core.cxx + * The core of the Calcite Operating System. + * + * Copyright 2026 Benji Dial + * This file is part of the Calcite Operating System. + * + * Calcite is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, version 3 only. + * + * Calcite is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * Calcite. If not, see . + */ + +#include +#include +#include "limine.hxx" + +using namespace calcite; + +//the following abbreviations are used in here: +// p1 = page table +// p2 = page directory +// p3 = page directory pointer table +// p4 = page map level 4 +// pma = physical memory address +// vma = virtual memory address + +//the core has one p3 that is mapped in all services at: +// 0xffff.ff80.0000.0000 - 0xffff.ffff.ffff.ffff + +//the core's p1's are mapped into: +// 0xffff.ffff.c000.0000 - 0xffff.ffff.ffff.ffff + +//each service has its own p3 that is mapped in only that service at: +// 0xffff.ff00.0000.0000 - 0xffff.ff7f.ffff.ffff + +//in a p1, a stack guard is 0x1000 + +static uint64_t max_physical; +static uint64_t *physical_free_bitmap; +static uint64_t physical_free_count_bytes; + +static uint64_t next_try_physical_free; + +alignas(4096) static uint64_t core_p4[512]; +alignas(4096) static uint64_t core_p3[512]; +alignas(4096) static uint64_t core_p2s[512 * 512]; +alignas(4096) static uint64_t core_top_p1s[512 * 512]; + +constexpr uint64_t temp_stack_length = 65536; +alignas(4096) static uint64_t temp_stack_and_guards[temp_stack_length + 8192]; + +static uint64_t hhdm; + +extern uint8_t __image_rx_start; +extern uint8_t __image_rx_end; +extern uint8_t __image_ro_start; +extern uint8_t __image_ro_end; +extern uint8_t __image_rw_start; +extern uint8_t __image_rw_end; + +//remove 4 once limine updates +uint64_t limine_base_revision[4] = LIMINE_BASE_REVISION(6); + +limine_hhdm_request hhdm_request = { + .id = LIMINE_HHDM_REQUEST_ID, + .revision = 0, + .response = 0 +}; + +limine_executable_address_request executable_address_request = { + .id = LIMINE_EXECUTABLE_ADDRESS_REQUEST_ID, + .revision = 0, + .response = 0 +}; + +limine_memmap_request memmap_request = { + .id = LIMINE_MEMMAP_REQUEST_ID, + .revision = 0, + .response = 0 +}; + +[[noreturn]] static void die() { + while (true) + __asm__ ("hlt"); +} + +[[noreturn]] void calcite::assert_fail() { + die(); +} + +static void mark_physical_free(uint64_t start, uint64_t end) { + + assert(start % 4096 == 0); + assert(end % 4096 == 0); + assert(start <= end); + assert(end <= max_physical); + + physical_free_count_bytes += end - start; + + start /= 4096; + end /= 4096; + + if (start / 64 == end / 64) { + uint64_t mask = (1ULL << (end % 64)) - (1ULL << (start % 64)); + assert((physical_free_bitmap[start / 64] & mask) == 0); + physical_free_bitmap[start / 64] |= mask; + return; + } + + if (start % 64 != 0) { + uint64_t mask = -(1ULL << (start % 64)); + assert((physical_free_bitmap[start / 64] & mask) == 0); + physical_free_bitmap[start / 64] |= mask; + start += 64 - start % 64; + } + + if (end % 64 != 0) { + uint64_t mask = (1ULL << (end % 64)) - 1; + assert((physical_free_bitmap[end / 64] & mask) == 0); + physical_free_bitmap[end / 64] |= mask; + end -= end % 64; + } + + for (uint64_t i = start / 64; i < end / 64; ++i) { + assert(physical_free_bitmap[i] == 0); + physical_free_bitmap[i] = -1ULL; + } + +} + +static result take_free_physical_page() { + + uint64_t i = next_try_physical_free; + + while (true) { + + if (physical_free_bitmap[i] != 0) { + next_try_physical_free = i; + for (int j = 0;; ++j) + if (physical_free_bitmap[i] & (1ULL << j)) { + physical_free_bitmap[i] &= ~(1ULL << j); + physical_free_count_bytes -= 4096; + return (i * 64 + j) * 4096; + } + } + + i = (i + 1) % (max_physical / 4096 / 64); + + if (i == next_try_physical_free) + return result_code::out_of_memory; + + } + +} + +//maps p1 if needed. returns old p1e value. +template +static result set_core_p1e(void *vma, uint64_t p1e) { + + uint64_t vma64 = (uint64_t)vma; + + assert(vma64 % 4096 == 0); + assert(vma64 >= 0xffffff8000000000); + assert(vma64 < 0xffffffffc0000000); + + int p1i = (vma64 / 4096) % 512; + int p2i = (vma64 / 4096 / 512) % 512; + int p3i = (vma64 / 4096 / 512 / 512) % 512; + + bool p1_is_new = false; + + if (core_top_p1s[p3i * 512 + p2i] == 0) { + auto result = take_free_physical_page(); + if (result.is_error()) + return result.get_error(); + uint64_t p1_pma = result.unwrap(); + core_top_p1s[p3i * 512 + p2i] = p1_pma | 0x8000000000000003; + core_p2s[p3i * 512 + p2i] = p1_pma | 0x3; + p1_is_new = true; + } + + uint64_t *p1_vma; + if constexpr (hhdm_p1s) { + uint64_t p1_pma = core_top_p1s[p3i * 512 + p2i] & 0x7ffffffffffff000; + p1_vma = (uint64_t *)(hhdm + p1_pma); + } + else + p1_vma = (uint64_t *)(0xffffffffc0000000 + (p3i * 512 + p2i) * 4096); + + if (p1_is_new) + for (int i = 0; i < 512; ++i) + p1_vma[i] = 0; + + uint64_t old_p1e = p1_vma[p1i]; + p1_vma[p1i] = p1e; + return old_p1e; + +} + +template +static result create_core_stack_guard(void *vma) { + + auto result = set_core_p1e(vma, 0x1000); + if (result.is_error()) + return result.get_error(); + + assert(result.unwrap() == 0); + return {}; + +} + +template +static result map_core_page( + void *vma, uint64_t pma, bool executable, bool writable) { + + auto result = set_core_p1e(vma, + pma | 0x1 | (executable ? 0 : 0x8000000000000000) | (writable ? 0x2 : 0)); + if (result.is_error()) + return result.get_error(); + + assert(result.unwrap() == 0); + return {}; + +} + +//might return error with some mapped +template +static result map_core_page_range( + void *vma, uint64_t pma, uint64_t page_count, + bool executable, bool writable) { + + for (uint64_t i = 0; i < page_count; ++i) { + auto result = map_core_page( + (uint8_t *)vma + 4096 * i, pma + 4096 * i, executable, writable); + if (result.is_error()) + return result.get_error(); + } + + return {}; + +} + +template +static result find_free_core_virtual_pages(uint64_t page_count) { + + uint64_t start_i = 0; + uint64_t on_i = 0; + uint64_t count = 0; + + while (true) { + + if (count >= page_count) + return (void *)(0xffffff8000000000 + start_i * 4096); + + if (on_i >= 512 * 512 * 511) + return result_code::out_of_memory; + + int p2si = on_i / 512; + int p1i = on_i % 512; + + if (p1i == 0 && core_p2s[p2si] == 0) { + count += 512; + on_i += 512; + continue; + } + + uint64_t *p1; + if constexpr (hhdm_p1s) { + uint64_t p1_pma = core_p2s[p2si] & 0x7ffffffffffff000; + p1 = (uint64_t *)(hhdm + p1_pma); + } + else + p1 = (uint64_t *)(0xffffffffc0000000 + p2si * 4096); + + if (p1[p1i] == 0) { + ++count; + ++on_i; + continue; + } + + count = 0; + ++on_i; + start_i = on_i; + + } + +} + +template +static result unmap_and_free_core_page(void *vma) { + + auto result = set_core_p1e(vma, 0); + if (result.is_error()) + return result.get_error(); + uint64_t old_p1e = result.unwrap(); + + assert(old_p1e & 0x1); + + uint64_t pma = old_p1e & 0x7ffffffffffff000; + mark_physical_free(pma, pma + 4096); + + return {}; + +} + +extern "C" [[noreturn]] void asm_set_cr3( + uint64_t cr3, void *stack_top, void (*jump_to)()); + +[[noreturn]] static void with_cr3(); + +extern "C" [[noreturn]] void __limine_entry() { + + if (!LIMINE_BASE_REVISION_SUPPORTED(limine_base_revision)) + die(); + + auto hhdm_response = hhdm_request.response; + if (hhdm_response == 0) + die(); + + hhdm = hhdm_response->offset; + + auto executable_address_response = executable_address_request.response; + if (executable_address_response == 0) + die(); + + auto exe_offset = + executable_address_response->virtual_base - + executable_address_response->physical_base; + + auto memmap_response = memmap_request.response; + if (memmap_response == 0) + die(); + + for (uint64_t i = 0; i < memmap_response->entry_count; ++i) { + auto entry = memmap_response->entries[i]; + if (entry->type == LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE || + entry->type == LIMINE_MEMMAP_USABLE) { + if (entry->base % 4096 != 0 || entry->length % 4096 != 0) + die(); + if (entry->base + entry->length > max_physical) + max_physical = entry->base + entry->length; + } + } + + uint64_t physical_map_pages_needed = (max_physical - 1) / 32768 + 1; + uint64_t physical_map_physical; + bool found_physical_map_physical = false; + + for (uint64_t i = 0; i < memmap_response->entry_count; ++i) { + auto entry = memmap_response->entries[i]; + if (entry->type == LIMINE_MEMMAP_USABLE && + entry->length >= physical_map_pages_needed * 4096) { + physical_map_physical = entry->base; + entry->base += physical_map_pages_needed * 4096; + entry->length -= physical_map_pages_needed * 4096; + found_physical_map_physical = true; + break; + } + } + + if (!found_physical_map_physical) + die(); + + physical_free_bitmap = (uint64_t *)(hhdm + physical_map_physical); + for (uint64_t i = 0; i < physical_map_pages_needed * 4096 / 8; ++i) + physical_free_bitmap[i] = 0; + + for (uint64_t i = 0; i < memmap_response->entry_count; ++i) { + auto entry = memmap_response->entries[i]; + if (entry->type == LIMINE_MEMMAP_USABLE) + mark_physical_free(entry->base, entry->base + entry->length); + } + + for (int i = 0; i < 511; ++i) + core_p4[i] = 0; + core_p4[511] = ((uint64_t)core_p3 - exe_offset) | 0x3; + + for (int i = 0; i < 512; ++i) + core_p3[i] = ((uint64_t)&core_p2s[i * 512] - exe_offset) | 0x3; + + for (int i = 0; i < 512 * 511; ++i) + core_p2s[i] = 0; + for (int i = 0; i < 512; ++i) + core_p2s[512 * 511 + i] = + ((uint64_t)&core_top_p1s[i * 512] - exe_offset) | 0x3; + + for (int i = 0; i < 512 * 512; ++i) + core_top_p1s[i] = 0; + + auto result = map_core_page_range( + &__image_rx_start, (uint64_t)&__image_rx_start - exe_offset, + (&__image_rx_end - &__image_rx_start) / 4096, true, false); + if (result.is_error()) + die(); + + auto result_2 = map_core_page_range( + &__image_ro_start, (uint64_t)&__image_ro_start - exe_offset, + (&__image_ro_end - &__image_ro_start) / 4096, false, false); + if (result_2.is_error()) + die(); + + auto result_3 = map_core_page_range( + &__image_rw_start, (uint64_t)&__image_rw_start - exe_offset, + (&__image_rw_end - &__image_rw_start) / 4096, false, true); + if (result_3.is_error()) + die(); + + auto new_physical_free_bitmap_result = + find_free_core_virtual_pages(physical_map_physical); + if (new_physical_free_bitmap_result.is_error()) + die(); + void *new_physical_free_bitmap = new_physical_free_bitmap_result.unwrap(); + + auto result_4 = map_core_page_range( + new_physical_free_bitmap, physical_map_physical, + physical_map_pages_needed, false, true); + if (result_4.is_error()) + die(); + + auto result_5 = unmap_and_free_core_page(temp_stack_and_guards); + if (result_5.is_error()) + die(); + auto result_6 = create_core_stack_guard(temp_stack_and_guards); + if (result_6.is_error()) + die(); + + auto result_7 = unmap_and_free_core_page( + &temp_stack_and_guards[4096 + temp_stack_length]); + if (result_7.is_error()) + die(); + auto result_8 = create_core_stack_guard( + &temp_stack_and_guards[4096 + temp_stack_length]); + if (result_8.is_error()) + die(); + + physical_free_bitmap = (uint64_t *)new_physical_free_bitmap; + + asm_set_cr3( + (uint64_t)core_p4 - exe_offset, + &temp_stack_and_guards[4096 + temp_stack_length], + &with_cr3); + +} + +[[noreturn]] static void with_cr3() { + + while (true) + ; + +} diff --git a/src/core/limine.hxx b/src/core/limine.hxx new file mode 120000 index 0000000..5f027f0 --- /dev/null +++ b/src/core/limine.hxx @@ -0,0 +1 @@ +../../dependencies/limine-protocol/include/limine.h \ No newline at end of file diff --git a/src/kernel/link.ld b/src/core/link.ld similarity index 65% rename from src/kernel/link.ld rename to src/core/link.ld index f3f4a2f..de3298c 100644 --- a/src/kernel/link.ld +++ b/src/core/link.ld @@ -1,7 +1,7 @@ OUTPUT_FORMAT(elf64-x86-64) OUTPUT_ARCH(i386:x86-64) -ENTRY(kernel_entry) +ENTRY(__limine_entry) PHDRS { rx PT_LOAD FLAGS(5); @@ -11,36 +11,36 @@ PHDRS { SECTIONS { - . = 0xffffffffc0000000; - __kernel_rx_start = .; + . = 0xffffffff80000000; + __image_rx_start = .; .text : { *(.text .text.*) } : rx - . = ALIGN(4096); - __kernel_rx_end = .; - __kernel_ro_start = .; + __image_rx_end = .; + __image_ro_start = .; .rodata : { *(.rodata .rodata.*) } : ro - . = ALIGN(4096); - __kernel_ro_end = .; - __kernel_rw_start = .; + __image_ro_end = .; + __image_rw_start = .; .data : { *(.data .data.*) } : rw - . = ALIGN(4096); .bss : { *(.bss .bss.*) *(COMMON) } : rw - . = ALIGN(4096); - __kernel_rw_end = .; + __image_rw_end = .; + + /DISCARD/ : { + *(.eh_frame) + } } diff --git a/src/kernel/debug.c b/src/kernel/debug.c deleted file mode 100644 index 2c794ab..0000000 --- a/src/kernel/debug.c +++ /dev/null @@ -1,113 +0,0 @@ -/* Calcite, src/kernel/debug.c - * Copyright 2025-2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "serial.h" -#include "debug.h" - -#include - -void log_core(const char *file, const char *function, const char *format, ...) { - - int file_length = 0; - while (file[file_length] != 0) - ++file_length; - - int function_length = 0; - while (function[function_length] != 0) - ++function_length; - - write_serial_string_n(file, file_length); - write_serial_string_n(" ", 1); - write_serial_string_n(function, function_length); - - write_serial_string_n(" -", 2); - for (int i = file_length + function_length + 3; i < 49; ++i) - write_serial_string_n("-", 1); - while (format[0] == ' ') { - write_serial_string_n("-", 1); - ++format; - } - write_serial_string_n(" ", 1); - - va_list args; - va_start(args, format); - - while (1) { - - int next_percent = 0; - while (format[next_percent] != '%') { - if (format[next_percent] == 0) { - write_serial_string_n(format, next_percent); - va_end(args); - write_serial_string_n("\r\n", 2); - return; - } - ++next_percent; - } - - write_serial_string_n(format, next_percent); - - switch (format[next_percent + 1]) { - case 's': { - const char *arg = va_arg(args, const char *); - write_serial_string(arg); - break; - } - case 'd': { - int arg = va_arg(args, int); - write_serial_integer(arg); - break; - } - case 'h': { - uint64_t arg1 = va_arg(args, uint64_t); - int arg2 = va_arg(args, int); - write_serial_hex(arg1, arg2); - break; - } - case 'B': { - uint64_t arg = va_arg(args, uint64_t); - if (arg < 10000) { - write_serial_integer(arg); - write_serial_string_n(" B", 2); - } - else if ((arg + 512) / 1024 < 10000) { - write_serial_integer((arg + 512) / 1024); - write_serial_string_n(" kiB", 4); - } - else if ((arg + 512 * 1024) / (1024 * 1024) < 10000) { - write_serial_integer((arg + 512 * 1024) / (1024 * 1024)); - write_serial_string_n(" MiB", 4); - } - else if ((arg + 512 * 1024 * 1024) / (1024 * 1024 * 1024) < 10000) { - write_serial_integer((arg + 512 * 1024 * 1024) / (1024 * 1024 * 1024)); - write_serial_string_n(" GiB", 4); - } - else { - write_serial_integer((arg + 512 * 1024 * 1024 * 1024ULL) / (1024 * 1024 * 1024 * 1024ULL)); - write_serial_string_n(" TiB", 4); - } - break; - } - default: - panic("bad format string") - } - - format = &format[next_percent + 2]; - - } - -} diff --git a/src/kernel/debug.h b/src/kernel/debug.h deleted file mode 100644 index 3c531d1..0000000 --- a/src/kernel/debug.h +++ /dev/null @@ -1,44 +0,0 @@ -/* Calcite, src/kernel/debug.h - * Copyright 2025-2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -void log_core(const char *file, const char *function, const char *format, ...); - -#define log(...) { \ - log_core(__FILE__, __func__, __VA_ARGS__); \ -} - -#ifdef CALCITE_DEBUG -#define debug_log(...) log(__VA_ARGS__) -#elif CALCITE_RELEASE -#define debug_log(...) {} -#else -#error neither CALCITE_DEBUG nor CALCITE_RELEASE defined -#endif - -#define panic(message) { \ - log_core(__FILE__, __func__, "kernel panic: %s", message); \ - while (1) \ - __asm__ ("hlt"); \ -} - -#define assert(condition) \ - { \ - if (!(condition)) \ - panic("assertion failed: " #condition) \ - } diff --git a/src/kernel/drives.c b/src/kernel/drives.c deleted file mode 100644 index 422cf8b..0000000 --- a/src/kernel/drives.c +++ /dev/null @@ -1,55 +0,0 @@ -/* Calcite, src/kernel/drives.c - * Copyright 2025 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "utility.h" -#include "drives.h" -#include "heap.h" - -struct drive_info *drive_list; -int drive_list_buffer_length = 0; -int drive_list_count = 0; - -#define DRIVE_LIST_INITIAL_LENGTH 16 - -struct drive_info *add_drive() { - - if (drive_list_buffer_length == 0) { - drive_list = heap_alloc(DRIVE_LIST_INITIAL_LENGTH * sizeof(struct drive_info)); - drive_list_buffer_length = DRIVE_LIST_INITIAL_LENGTH; - } - - else if (drive_list_count == drive_list_buffer_length) { - struct drive_info *new_drive_list = - heap_alloc(2 * drive_list_buffer_length * sizeof(struct drive_info)); - memcpy(new_drive_list, drive_list, drive_list_count * sizeof(struct drive_info)); - heap_dealloc(drive_list, drive_list_count * sizeof(struct drive_info)); - drive_list = new_drive_list; - drive_list_buffer_length *= 2; - } - - struct drive_info *to_return = &drive_list[drive_list_count]; - ++drive_list_count; - return to_return; - -} - -const struct drive_info *look_up_drive(const char *name) { - for (int i = 0; i < drive_list_count; ++i) - if (strequ(drive_list[i].name, name)) - return &drive_list[i]; - return 0; -} diff --git a/src/kernel/drives.h b/src/kernel/drives.h deleted file mode 100644 index 6baef36..0000000 --- a/src/kernel/drives.h +++ /dev/null @@ -1,46 +0,0 @@ -/* Calcite, src/kernel/drives.h - * Copyright 2025 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -#include - -enum drive_access_result { - DAR_SUCCESS, - DAR_HARDWARE_ERROR -}; - -struct drive_info { - - const char *name; - uint64_t block_size; - uint64_t block_count; - const void *driver_info; - - //start and count are both in blocks. bounds-checking is caller responsibility. - enum drive_access_result (*read_blocks)( - const struct drive_info *info, void *buffer, uint64_t start, uint64_t count); - -}; - -//add a drive by calling this and writing to the returned pointer. -//the returned pointer might be invalidated by future calls. -struct drive_info *add_drive(); - -//returned pointer might be invalidated by future calls to add_drive. -//returns 0 if there is no drive with that name. -const struct drive_info *look_up_drive(const char *name); diff --git a/src/kernel/entry.c b/src/kernel/entry.c deleted file mode 100644 index 44e6486..0000000 --- a/src/kernel/entry.c +++ /dev/null @@ -1,328 +0,0 @@ -/* Calcite, src/kernel/entry.c - * Copyright 2025-2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "framebuffer.h" -#include "interrupts.h" -#include "ipc-dgram.h" -#include "scheduler.h" -#include "syscalls.h" -#include "process.h" -#include "utility.h" -#include "drives.h" -#include "paging.h" -#include "serial.h" -#include "debug.h" -#include "input.h" -#include "timer.h" -#include "heap.h" -#include "pci.h" -#include "ps2.h" -#include "fs.h" - -#include -#include - -LIMINE_BASE_REVISION(3) - -static volatile struct limine_framebuffer_request fb_request = { - .id = LIMINE_FRAMEBUFFER_REQUEST, - .revision = 0, - .response = 0 -}; - -static volatile struct limine_hhdm_request hhdm_request = { - .id = LIMINE_HHDM_REQUEST, - .revision = 0, - .response = 0 -}; - -static volatile struct limine_kernel_address_request ka_request = { - .id = LIMINE_KERNEL_ADDRESS_REQUEST, - .revision = 0, - .response = 0 -}; - -static volatile struct limine_memmap_request memmap_request = { - .id = LIMINE_MEMMAP_REQUEST, - .revision = 0, - .response = 0 -}; - -static volatile struct limine_executable_cmdline_request cmdline_request = { - .id = LIMINE_EXECUTABLE_CMDLINE_REQUEST, - .revision = 0, - .response = 0 -}; - -[[noreturn]] static void die() { - while (1) - __asm__ ("hlt"); -} - -//these are defined in the linker script. they are page-aligned. -extern uint8_t __kernel_rx_start; -extern uint8_t __kernel_rx_end; -extern uint8_t __kernel_ro_start; -extern uint8_t __kernel_ro_end; -extern uint8_t __kernel_rw_start; -extern uint8_t __kernel_rw_end; - -static void map_kernel_region( - uint64_t physical_start, void *virtual_start, - uint64_t length, int writable, int executable) { - for (uint64_t i = 0; i < length; i += 4096) - map_in_kernel_page_table( - physical_start + i, (uint8_t *)virtual_start + i, writable, executable); -} - -#define MAX_CMDLINE_LENGTH 1000 -static char cmdline_copy[MAX_CMDLINE_LENGTH + 1]; - -[[noreturn]] static void with_kernel_page_tables(); - -[[noreturn]] void kernel_entry() { - - //die if the bootloader hasn't given us something that we need. - - if (fb_request.response == 0 || hhdm_request.response == 0 || - ka_request.response == 0 || memmap_request.response == 0 || - fb_request.response->framebuffer_count == 0) - die(); - - struct limine_framebuffer *fb = fb_request.response->framebuffers[0]; - if (fb->memory_model != LIMINE_FRAMEBUFFER_RGB || fb->bpp != 32 || - fb->red_mask_shift != 16 || fb->red_mask_size != 8 || - fb->green_mask_shift != 8 || fb->green_mask_size != 8 || - fb->blue_mask_shift != 0 || fb->blue_mask_size != 8) - die(); - - //set up page tables. we will mark the regions with bootloader structures as - //usable, so we need to be careful not to allocate any physical pages until - //after we are done using bootloader structures. we map the kernel into our - //page tables, and we remap the framebuffer to somewhere in kernel memory. - //we do not map the bootloader structures, so we also need to not switch - //to the new tables until we are done using them. - - uint64_t kernel_physical_base = ka_request.response->physical_base; - uint8_t *kernel_virtual_base = (uint8_t *)ka_request.response->virtual_base; - init_paging(kernel_physical_base, kernel_virtual_base); - - struct limine_memmap_response *mm_response = memmap_request.response; - for (uint64_t i = 0; i < mm_response->entry_count; ++i) { - struct limine_memmap_entry *entry = mm_response->entries[i]; - if (entry->type == LIMINE_MEMMAP_USABLE || - entry->type == LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE) - //limine guarantees these two types are page-aligned already. - mark_physical_memory_free(entry->base, entry->length); - } - - map_kernel_region( - &__kernel_rx_start - kernel_virtual_base + kernel_physical_base, - &__kernel_rx_start, &__kernel_rx_end - &__kernel_rx_start, 0, 1); - map_kernel_region( - &__kernel_ro_start - kernel_virtual_base + kernel_physical_base, - &__kernel_ro_start, &__kernel_ro_end - &__kernel_ro_start, 0, 0); - map_kernel_region( - &__kernel_rw_start - kernel_virtual_base + kernel_physical_base, - &__kernel_rw_start, &__kernel_rw_end - &__kernel_rw_start, 1, 0); - - //we round up to a multiple of a page. - uint64_t fb_length = ((fb->height * fb->pitch - 1) / 4096 + 1) * 4096; - fb_physical_base = (uint64_t)fb->address - hhdm_request.response->offset; - fb_base = find_free_kernel_region(fb_length); - map_kernel_region( - fb_physical_base, fb_base, fb_length, 1, 0); - - //store rest of framebuffer information - - fb_width = fb->width; - fb_height = fb->height; - fb_pitch = fb->pitch; - - //make a copy of the kernel cmdline - - const char *original_cmdline = cmdline_request.response->cmdline; - int cmdline_length = 0; - while (original_cmdline[cmdline_length] != 0) - ++cmdline_length; - - if (cmdline_length > MAX_CMDLINE_LENGTH) - die(); - - memcpy(cmdline_copy, original_cmdline, cmdline_length + 1); - - //switch to kernel page tables! - - switch_to_kernel_page_tables(&with_kernel_page_tables); - -} - -struct cmdline_pair { - const char *key; - const char *value; -}; - -static const struct cmdline_pair *cmdline_pairs; -static int cmdline_pair_count; - -//returns the corresponding value if the key exists, otherwise returns 0. -static const char *cmdline_look_up(const char *key) { - for (int i = 0; i < cmdline_pair_count; ++i) - if (strequ(cmdline_pairs[i].key, key)) - return cmdline_pairs[i].value; - return 0; -} - -[[noreturn]] static void with_kernel_page_tables() { - - init_serial(); - - //store cmdline as key-value pairs - - if (cmdline_copy[0] == 0) - cmdline_pair_count = 0; - - else { - - int comma_count = 0; - for (int i = 0; cmdline_copy[i] != 0; ++i) - if (cmdline_copy[i] == ',') - ++comma_count; - - cmdline_pair_count = comma_count + 1; - struct cmdline_pair *pairs = heap_alloc(cmdline_pair_count * sizeof(struct cmdline_pair)); - - int key_start = 0; - for (int i = 0; i < cmdline_pair_count; ++i) { - - int key_end = key_start; - while (1) { - if (cmdline_copy[key_end] == '=') - break; - if (cmdline_copy[key_end] == ',' || cmdline_copy[key_end] == 0) - die(); - ++key_end; - } - - int value_start = key_end + 1; - int value_end = value_start; - while (1) { - if (cmdline_copy[value_end] == ',' || cmdline_copy[value_end] == 0) - break; - if (cmdline_copy[value_end] == '=') - die(); - ++value_end; - } - - char *key = heap_alloc(key_end - key_start + 1); - memcpy(key, &cmdline_copy[key_start], key_end - key_start); - key[key_end - key_start] = 0; - pairs[i].key = key; - - char *value = heap_alloc(value_end - value_start + 1); - memcpy(value, &cmdline_copy[value_start], value_end - value_start); - value[value_end - value_start] = 0; - pairs[i].value = value; - - key_start = value_end + 1; - - } - - cmdline_pairs = pairs; - - } - - debug_log("command line") - for (int i = 0; i < cmdline_pair_count; ++i) - debug_log(" %s %s", cmdline_pairs[i].key, cmdline_pairs[i].value) - - //set up interrupts - - init_timer(); - init_ps2(); - - set_irq_handler(0x00, &on_pit_irq); - set_irq_handler(0x01, &on_keyboard_irq); - set_irq_handler(0x0c, &on_mouse_irq); - - init_interrupts(); - - //set up syscalls - - init_syscalls(); - register_syscall(SYSCALL_END_THREAD, (void *)&syscall_end_thread); - register_syscall(SYSCALL_MAP_FRAMEBUFFER, (void *)&syscall_map_framebuffer); - register_syscall(SYSCALL_OPEN_FILE, (void *)&syscall_open_file); - register_syscall(SYSCALL_CLOSE_FILE, (void *)&syscall_close_file); - register_syscall(SYSCALL_GET_FILE_SIZE, (void *)&syscall_get_file_size); - register_syscall(SYSCALL_READ_FILE, (void *)&syscall_read_file); - register_syscall(SYSCALL_WAIT_FOR_MOUSE_PACKET, (void *)&syscall_wait_for_mouse_packet); - register_syscall(SYSCALL_MAP_PAGES, (void *)&syscall_map_pages); - register_syscall(SYSCALL_SLEEP_MS, (void *)&syscall_sleep_ms); - register_syscall(SYSCALL_START_ELF, (void *)&syscall_start_elf); - register_syscall(SYSCALL_IPC_CREATE_DGRAM_RECEIVER, (void *)&syscall_ipc_create_dgram_receiver); - register_syscall(SYSCALL_IPC_CREATE_DGRAM_SENDER, (void *)&syscall_ipc_create_dgram_sender); - register_syscall(SYSCALL_IPC_RECEIVE_DGRAM, (void *)&syscall_ipc_receive_dgram); - register_syscall(SYSCALL_IPC_SEND_DGRAM, (void *)&syscall_ipc_send_dgram); - register_syscall(SYSCALL_CREATE_THREAD, (void *)&syscall_create_thread); - register_syscall(SYSCALL_GET_ENVVAR, (void *)&syscall_get_envvar); - register_syscall(SYSCALL_CREATE_MUTEX, (void *)&syscall_create_mutex); - register_syscall(SYSCALL_ACQUIRE_MUTEX, (void *)&syscall_acquire_mutex); - register_syscall(SYSCALL_RELEASE_MUTEX, (void *)&syscall_release_mutex); - register_syscall(SYSCALL_CREATE_EVENT, (void *)&syscall_create_event); - register_syscall(SYSCALL_SIGNAL_EVENT, (void *)&syscall_signal_event); - register_syscall(SYSCALL_WAIT_EVENT, (void *)&syscall_wait_event); - register_syscall(SYSCALL_IPC_CREATE_PRIVATE_DGRAM_PIPE, (void *)&syscall_ipc_create_private_dgram_pipe); - register_syscall(SYSCALL_IPC_CREATE_PRIVATE_DGRAM_RECEIVER, (void *)&syscall_ipc_create_private_dgram_receiver); - register_syscall(SYSCALL_IPC_CREATE_PRIVATE_DGRAM_SENDER, (void *)&syscall_ipc_create_private_dgram_sender); - register_syscall(SYSCALL_GET_MS_SINCE_BOOT, (void *)&syscall_get_ms_since_boot); - register_syscall(SYSCALL_SLEEP_UNTIL_MS_SINCE_BOOT, (void *)&syscall_sleep_until_ms_since_boot); - register_syscall(SYSCALL_CHANGE_PAGE_PERMISSIONS, (void *)&syscall_change_page_permissions); - register_syscall(SYSCALL_WAIT_FOR_KEYBOARD_PACKET, (void *)&syscall_wait_for_keyboard_packet); - - //probe pci devices - - probe_pci(); - - //load root file system - - const char *root_drive_name = cmdline_look_up("root-drive"); - if (!root_drive_name) - panic("root drive mising from cmdline") - const struct drive_info *root_drive = look_up_drive(root_drive_name); - if (!root_drive) - panic("could not find root drive") - - const char *root_fs_type = cmdline_look_up("root-fs"); - if (!root_fs_type) - panic("root fs missing from cmdline") - struct fs_info *root_fs = heap_alloc(sizeof(struct fs_info)); - if (create_fs_info(root_drive, root_fs, root_fs_type) != FAR_SUCCESS) - panic("could not create root file system info") - - set_fs("root", root_fs); - - //load init and start it - - init_scheduler(); - - if (start_elf("root://calcite/apps/init/init.elf") == 0) - panic("could not start init.elf") - - resume_next_continuation(); - -} diff --git a/src/kernel/framebuffer.c b/src/kernel/framebuffer.c deleted file mode 100644 index a9e545d..0000000 --- a/src/kernel/framebuffer.c +++ /dev/null @@ -1,24 +0,0 @@ -/* Calcite, src/kernel/framebuffer.c - * Copyright 2025 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "framebuffer.h" - -uint64_t fb_physical_base; -uint8_t *fb_base; -int fb_width; -int fb_height; -int fb_pitch; diff --git a/src/kernel/framebuffer.h b/src/kernel/framebuffer.h deleted file mode 100644 index 71bdb57..0000000 --- a/src/kernel/framebuffer.h +++ /dev/null @@ -1,26 +0,0 @@ -/* Calcite, src/kernel/framebuffer.h - * Copyright 2025 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -#include - -extern uint64_t fb_physical_base; -extern uint8_t *fb_base; -extern int fb_width; -extern int fb_height; -extern int fb_pitch; diff --git a/src/kernel/fs.c b/src/kernel/fs.c deleted file mode 100644 index 0270dc6..0000000 --- a/src/kernel/fs.c +++ /dev/null @@ -1,105 +0,0 @@ -/* Calcite, src/kernel/fs.c - * Copyright 2025 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "iso9660.h" -#include "utility.h" -#include "debug.h" -#include "heap.h" -#include "fs.h" - -#include - -enum fs_access_result create_fs_info( - const struct drive_info *drive, struct fs_info *fs_out, const char *fs_type) { - - if (strequ(fs_type, "iso9660")) - return create_iso9660_info(drive, fs_out); - - return FAR_UNKNOWN_FS_TYPE; - -} - -struct set_fs { - const char *name; - const struct fs_info *fs; -}; - -struct set_fs *set_fses; -int set_fses_buffer_length = 0; -int set_fses_count = 0; - -#define SET_FSES_INITIAL_LENGTH 16 - -void set_fs(const char *name, const struct fs_info *fs) { - - assert(get_fs(name) == 0) - - if (set_fses_buffer_length == 0) { - set_fses = heap_alloc(SET_FSES_INITIAL_LENGTH * sizeof(struct set_fs)); - set_fses_buffer_length = SET_FSES_INITIAL_LENGTH; - } - - else if (set_fses_count == set_fses_buffer_length) { - struct set_fs *new_set_fses = heap_alloc(2 * set_fses_buffer_length * sizeof(struct set_fs)); - memcpy(new_set_fses, set_fses, set_fses_count * sizeof(struct set_fs)); - heap_dealloc(set_fses, set_fses_count * sizeof(struct set_fs)); - set_fses = new_set_fses; - set_fses_buffer_length *= 2; - } - - set_fses[set_fses_count].name = name; - set_fses[set_fses_count].fs = fs; - ++set_fses_count; - -} - -const struct fs_info *get_fs(const char *name) { - for (int i = 0; i < set_fses_count; ++i) - if (strequ(set_fses[i].name, name)) - return set_fses[i].fs; - return 0; -} - -enum fs_access_result look_up_file( - const char *uri, const struct fs_info **fs_out, void **node_out) { - - int colon = 0; - while (1) { - if (uri[colon] == ':') - break; - if (uri[colon] == 0) - panic("bad uri") - ++colon; - } - - if (uri[colon + 1] != '/' || uri[colon + 2] != '/') - panic("bad uri") - - char *uri_copy = heap_alloc(colon + 1); - memcpy(uri_copy, uri, colon); - uri_copy[colon] = 0; - - *fs_out = get_fs(uri_copy); - - heap_dealloc(uri_copy, colon + 1); - - if (!*fs_out) - return FAR_NOT_FOUND; - - return (*(*fs_out)->look_up_file)(*fs_out, node_out, &uri[colon + 3]); - -} diff --git a/src/kernel/fs.h b/src/kernel/fs.h deleted file mode 100644 index a60d679..0000000 --- a/src/kernel/fs.h +++ /dev/null @@ -1,58 +0,0 @@ -/* Calcite, src/kernel/fs.h - * Copyright 2025 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -#include "drives.h" - -#include -#include - -struct fs_stat { - uint64_t bytes; -}; - -struct fs_info { - - const struct drive_info *drive; - const void *driver_info; - - enum fs_access_result (*free_node)( - const struct fs_info *info, void *node); - - enum fs_access_result (*look_up_file)( - const struct fs_info *info, void **node_out, const char *path); - - enum fs_access_result (*stat_file)( - const struct fs_info *info, void *node, struct fs_stat *stat_out); - - //start is in bytes. bounds-checking is caller responsibility. - enum fs_access_result (*read_file)( - const struct fs_info *info, void *node, - void *buffer, uint64_t start, uint64_t bytes); - -}; - -enum fs_access_result create_fs_info( - const struct drive_info *drive, struct fs_info *fs_out, const char *fs_type); - -void set_fs(const char *name, const struct fs_info *fs); - -//returns 0 if no fs is set with that name. -const struct fs_info *get_fs(const char *name); - -enum fs_access_result look_up_file(const char *uri, const struct fs_info **fs_out, void **node_out); diff --git a/src/kernel/heap.c b/src/kernel/heap.c deleted file mode 100644 index 4a9c1f9..0000000 --- a/src/kernel/heap.c +++ /dev/null @@ -1,104 +0,0 @@ -/* Calcite, src/kernel/heap.c - * Copyright 2025 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "paging.h" -#include "heap.h" - -struct dealloc_record { - //0 for unused - uint64_t length; - void *start; -}; - -struct dealloc_record_page { - struct dealloc_record records[255]; - struct dealloc_record_page *prev_page; -}; - -static struct dealloc_record_page *last_page; - -static void *map_pages(uint64_t page_count) { - - void *vma = find_free_kernel_region(page_count * 4096); - - for (uint64_t i = 0; i < page_count; ++i) { - uint64_t pma = take_free_physical_page(); - map_in_kernel_page_table(pma, vma + i * 4096, 1, 0); - } - - return vma; - -} - -static struct dealloc_record *get_unused_record() { - - for (struct dealloc_record_page *page = last_page; - page != 0; page = page->prev_page) - for (int i = 0; i < 255; ++i) - if (page->records[i].length == 0) - return &page->records[i]; - - struct dealloc_record_page *page = map_pages(1); - page->prev_page = last_page; - last_page = page; - - page->records[0].start = (void *)page + 4096 - 8; - page->records[0].length = 8; - - for (int i = 2; i < 255; ++i) - page->records[i].length = 0; - - return &page->records[1]; - -} - -void *heap_alloc(uint64_t length) { - - for (struct dealloc_record_page *page = last_page; - page != 0; page = page->prev_page) - for (int i = 0; i < 255; ++i) - if (page->records[i].length == length) { - page->records[i].length = 0; - return page->records[i].start; - } - - for (struct dealloc_record_page *page = last_page; - page != 0; page = page->prev_page) - for (int i = 0; i < 255; ++i) - if (page->records[i].length > length) { - page->records[i].length -= length; - return page->records[i].start + page->records[i].length; - } - - uint64_t pages = (length - 1) / 4096 + 1; - void *vma = map_pages(pages); - - if (pages * 4096 != length) { - struct dealloc_record *record = get_unused_record(); - record->start = vma + length; - record->length = pages * 4096 - length; - } - - return vma; - -} - -void heap_dealloc(void *start, uint64_t length) { - struct dealloc_record *record = get_unused_record(); - record->start = start; - record->length = length; -} diff --git a/src/kernel/heap.h b/src/kernel/heap.h deleted file mode 100644 index a999f49..0000000 --- a/src/kernel/heap.h +++ /dev/null @@ -1,23 +0,0 @@ -/* Calcite, src/kernel/heap.h - * Copyright 2025 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -#include - -void *heap_alloc(uint64_t length); -void heap_dealloc(void *start, uint64_t length); diff --git a/src/kernel/input.c b/src/kernel/input.c deleted file mode 100644 index ca7f831..0000000 --- a/src/kernel/input.c +++ /dev/null @@ -1,140 +0,0 @@ -/* Calcite, src/kernel/input.c - * Copyright 2025-2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "scheduler.h" -#include "process.h" -#include "debug.h" -#include "input.h" -#include "heap.h" - -static int is_somebody_waiting_for_mouse_packet = 0; -static struct continuation_info waiting_continuation_mouse; -static struct mouse_packet *resume_by_reporting_to_mouse; - -static int total_unreported_x_movement = 0; -static int total_unreported_y_movement = 0; - -void add_mouse_movement(int x, int y) { - - total_unreported_x_movement += x; - total_unreported_y_movement += y; - - if (is_somebody_waiting_for_mouse_packet) { - resume_by_reporting_to_mouse->x_change = total_unreported_x_movement; - resume_by_reporting_to_mouse->y_change = total_unreported_y_movement; - add_to_queue(&ready_continuations, &waiting_continuation_mouse); - total_unreported_x_movement = 0; - total_unreported_y_movement = 0; - is_somebody_waiting_for_mouse_packet = 0; - } - -} - -void syscall_wait_for_mouse_packet(struct mouse_packet *packet_out) { - - assert(running_thread != 0); - - //TODO: handle these - if (is_somebody_waiting_for_mouse_packet || - !is_mapped_writable( - running_thread->process, packet_out, sizeof(struct mouse_packet))) - panic("TODO") - - if (total_unreported_x_movement != 0 || total_unreported_y_movement != 0) { - packet_out->x_change = total_unreported_x_movement; - packet_out->y_change = total_unreported_y_movement; - total_unreported_x_movement = 0; - total_unreported_y_movement = 0; - return; - } - - is_somebody_waiting_for_mouse_packet = 1; - resume_by_reporting_to_mouse = packet_out; - yield(&waiting_continuation_mouse); - -} - -static int is_somebody_waiting_for_keyboard_packet = 0; -static struct continuation_info waiting_continuation_keyboard; -static int *resume_by_reporting_to_keyboard; - -//in packets -#define INITIAL_KEYBOARD_BUFFER_LENGTH 1024 - -static int *keyboard_buffer = 0; -static int keyboard_buffer_length = 0; -static int keyboard_buffer_used = 0; -static int keyboard_buffer_read_pointer = 0; - -void add_keyboard_packet(int packet) { - - if (is_somebody_waiting_for_keyboard_packet) { - *resume_by_reporting_to_keyboard = packet; - add_to_queue(&ready_continuations, &waiting_continuation_keyboard); - is_somebody_waiting_for_keyboard_packet = 0; - } - - else if (keyboard_buffer_used < keyboard_buffer_length) { - int write_pointer = (keyboard_buffer_read_pointer + keyboard_buffer_used) % keyboard_buffer_length; - keyboard_buffer[write_pointer] = packet; - ++keyboard_buffer_used; - } - - else if (keyboard_buffer == 0) { - keyboard_buffer = heap_alloc(INITIAL_KEYBOARD_BUFFER_LENGTH * sizeof(int)); - keyboard_buffer_length = INITIAL_KEYBOARD_BUFFER_LENGTH; - keyboard_buffer[0] = packet; - keyboard_buffer_used = 1; - } - - else { - int *new_buffer = heap_alloc(2 * keyboard_buffer_length * sizeof(int)); - memcpy( - new_buffer, &keyboard_buffer[keyboard_buffer_read_pointer], - keyboard_buffer_length - keyboard_buffer_read_pointer); - memcpy( - &new_buffer[keyboard_buffer_length - keyboard_buffer_read_pointer], - keyboard_buffer, keyboard_buffer_read_pointer); - heap_dealloc(keyboard_buffer, keyboard_buffer_length * sizeof(int)); - keyboard_buffer = new_buffer; - keyboard_buffer_length *= 2; - keyboard_buffer_read_pointer = 0; - keyboard_buffer[keyboard_buffer_length / 2] = packet; - ++keyboard_buffer_used; - } - -} - -int syscall_wait_for_keyboard_packet() { - - if (keyboard_buffer_used > 0) { - int value = keyboard_buffer[keyboard_buffer_read_pointer]; - keyboard_buffer_read_pointer = (keyboard_buffer_read_pointer + 1) % keyboard_buffer_length; - --keyboard_buffer_used; - return value; - } - - if (is_somebody_waiting_for_keyboard_packet) - panic("TODO") - - is_somebody_waiting_for_keyboard_packet = 1; - int result; - resume_by_reporting_to_keyboard = &result; - yield(&waiting_continuation_keyboard); - return result; - -} diff --git a/src/kernel/input.h b/src/kernel/input.h deleted file mode 100644 index ef215ea..0000000 --- a/src/kernel/input.h +++ /dev/null @@ -1,28 +0,0 @@ -/* Calcite, src/kernel/input.h - * Copyright 2025-2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -#include - -void add_mouse_movement(int x, int y); - -void syscall_wait_for_mouse_packet(struct mouse_packet *packet_out); - -void add_keyboard_packet(int packet); - -int syscall_wait_for_keyboard_packet(); diff --git a/src/kernel/interrupts.asm b/src/kernel/interrupts.asm deleted file mode 100644 index 769c2ab..0000000 --- a/src/kernel/interrupts.asm +++ /dev/null @@ -1,171 +0,0 @@ - ; Calcite, src/kernel/interrupts.asm - ; Copyright 2025-2026 Benji Dial - ; - ; This program is free software: you can redistribute it and/or modify - ; it under the terms of the GNU General Public License as published by - ; the Free Software Foundation, either version 3 of the License, or - ; (at your option) any later version. - ; - ; This program is distributed in the hope that it will be useful, but - ; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - ; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - ; for more details. - ; - ; You should have received a copy of the GNU General Public License along - ; with this program. If not, see . - - -bits 64 -default rel - -;both defined in interrupts.c -extern isr_exception_c -extern isr_irq_c - -section .rodata - -;referenced in interrupts.c -global isrs -isrs: -%assign n 0 -%rep 48 - dq isr_ %+ n -%assign n n + 1 -%endrep - -section .text - -%assign n 0 - -%rep 32 -isr_ %+ n: -%if n <= 0x07 || n = 0x09 || (n >= 0x0f && n <= 0x1c && n <> 0x11 && n <> 0x15) || n = 0x1f - push qword 0 -%endif - push qword n - jmp isr_exception_common -%assign n n + 1 -%endrep - -%rep 16 -isr_ %+ n: - push rdi - mov rdi, n - 32 - jmp isr_irq_common -%assign n n + 1 -%endrep - -isr_exception_common: - push rax - push rbx - push rcx - push rdx - push rdi - push rsi - push rbp - push r8 - push r9 - push r10 - push r11 - push r12 - push r13 - push r14 - push r15 - mov rax, cr2 - push rax - mov rax, cr3 - push rax - mov rdi, rsp - - call isr_exception_c - - add rsp, 48 - pop r11 - pop r10 - pop r9 - pop r8 - add rsp, 8 - pop rsi - pop rdi - pop rdx - pop rcx - add rsp, 8 - pop rax - add rsp, 16 - iretq - -isr_irq_common: - push rax - push rcx - push rdx - push rsi - push r8 - push r9 - push r10 - push r11 - - test dil, 0x08 - jnz .high - - call isr_irq_c - mov al, 0x20 - out 0x20, al - jmp .common_end - -.high: - call isr_irq_c - mov al, 0x20 - out 0xa0, al - out 0x20, al - -.common_end: - pop r11 - pop r10 - pop r9 - pop r8 - pop rsi - pop rdx - pop rcx - pop rax - pop rdi - - iretq - -;referenced in interrupts.c -;rdi is pointer to gdt descriptor -;rsi is pointer to idt descriptor -;dx is offset of tss into gdt -global init_interrupts_asm -init_interrupts_asm: - - ;load tables - - lgdt [rdi] - ltr dx - lidt [rsi] - - ;initialize interrupt controllers - - mov al, 0x11 - out 0x20, al - mov al, 0x20 - out 0x21, al - mov al, 0x04 - out 0x21, al - mov al, 0x01 - out 0x21, al - mov al, 0x00 - out 0x21, al - - mov al, 0x11 - out 0xa0, al - mov al, 0x28 - out 0xa1, al - mov al, 0x02 - out 0xa1, al - mov al, 0x01 - out 0xa1, al - mov al, 0x00 - out 0xa1, al - - ret diff --git a/src/kernel/interrupts.c b/src/kernel/interrupts.c deleted file mode 100644 index 6a9f4da..0000000 --- a/src/kernel/interrupts.c +++ /dev/null @@ -1,320 +0,0 @@ -/* Calcite, src/kernel/interrupts.c - * Copyright 2025-2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -//relevant sources: -// amd64 architecture programmer's manual, volume 2: system programming -// https://osdev.wiki/wiki/Global_Descriptor_Table -// https://osdev.wiki/wiki/Interrupt_Descriptor_Table -// https://osdev.wiki/wiki/Task_State_Segment - -#include "interrupts.h" -#include "process.h" -#include "paging.h" -#include "debug.h" - -//interrupts.asm depends on layout -struct [[gnu::packed]] exception_parameter { - uint64_t cr3; - uint64_t cr2; - uint64_t r15; - uint64_t r14; - uint64_t r13; - uint64_t r12; - uint64_t r11; - uint64_t r10; - uint64_t r9; - uint64_t r8; - uint64_t rbp; - uint64_t rsi; - uint64_t rdi; - uint64_t rdx; - uint64_t rcx; - uint64_t rbx; - uint64_t rax; - uint64_t exception_number; - //0 if exception pushes no error code - uint64_t error_code; - uint64_t rip; - uint64_t cs; - uint64_t rflags; - uint64_t rsp; - uint64_t ss; -}; - -//names are from amd64 manual mentioned above -const char *exception_names[32] = { - "divide-by-zero-error", "debug", "non-maskable-interrupt", "breakpoint", "overflow", - "bound-range", "invalid-opcode", "device-not-available", "double-fault", 0, - "invalid-tss", "segment-not-present", "stack", "general-protection", "page-fault", - 0, "x87 floating-point exception-pending", "alignment-check", "machine-check", - "simd floating-point", 0, 0, 0, 0, 0, 0, 0, 0, - "hypervisor injection exception", "vmm communication exception", "security exception", 0 -}; - -[[noreturn]] static void unhandled_exception(const struct exception_parameter *parameter) { - - assert(parameter->exception_number < 32 && exception_names[parameter->exception_number] != 0) - - log("unhandled exception") - log(" exception name = %s", exception_names[parameter->exception_number]) - log(" error code = 0x%h", parameter->error_code, 16) - log(" cr2 = 0x%h", parameter->cr2, 16) - log(" cr3 = 0x%h", parameter->cr3, 16) - log(" cs = 0x%h", parameter->cs, 16) - log(" rip = 0x%h", parameter->rip, 16) - log(" ss = 0x%h", parameter->ss, 16) - log(" rsp = 0x%h", parameter->rsp, 16) - log(" rflags = 0x%h", parameter->rflags, 16) - log(" rax = 0x%h", parameter->rax, 16) - log(" rbx = 0x%h", parameter->rbx, 16) - log(" rcx = 0x%h", parameter->rcx, 16) - log(" rdx = 0x%h", parameter->rdx, 16) - log(" rdi = 0x%h", parameter->rdi, 16) - log(" rsi = 0x%h", parameter->rsi, 16) - log(" rbp = 0x%h", parameter->rbp, 16) - log(" r8 = 0x%h", parameter->r8, 16) - log(" r9 = 0x%h", parameter->r9, 16) - log(" r10 = 0x%h", parameter->r10, 16) - log(" r11 = 0x%h", parameter->r11, 16) - log(" r12 = 0x%h", parameter->r12, 16) - log(" r13 = 0x%h", parameter->r13, 16) - log(" r14 = 0x%h", parameter->r14, 16) - log(" r15 = 0x%h", parameter->r15, 16) - log("halting") - - while (1) - __asm__ ("hlt"); - -} - -//referenced in interrupts.asm -void isr_exception_c(const struct exception_parameter *parameter) { - - if (running_thread != 0 && - parameter->exception_number == 0x0e && - (parameter->error_code & 0x1) == 0x0 && - parameter->cr2 >= (uint64_t)running_thread->stack_bottom + 4096 && - parameter->cr2 < (uint64_t)running_thread->stack_top) { - - void *vma = (void *)(parameter->cr2 & 0xfffffffffffff000); - unmap_page_for_process(running_thread->process, vma); - uint64_t pma = take_free_physical_page(); - map_page_for_process( - running_thread->process, pma, - vma, 1, 0, 1); - - } - - else - unhandled_exception(parameter); - -} - -void (*irq_handlers[16])() = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 -}; - -//referenced in interrupts.asm -void isr_irq_c(uint64_t irq_number) { - if (irq_handlers[irq_number]) - (*irq_handlers[irq_number])(); -} - -void set_irq_handler(uint8_t irq_line, void (*handler)(void)) { - assert(irq_line < 16); - irq_handlers[irq_line] = handler; -} - -enum { - - GDT_AB_CODE_DATA_ACCESSED = 0x01, - GDT_AB_DATA_WRITABLE = 0x02, - - GDT_AB_TYPE_TSS = 0x09, - GDT_AB_TYPE_DATA = 0x10, - GDT_AB_TYPE_CODE = 0x18, - - GDT_AB_DPL_ZERO = 0x00, - GDT_AB_DPL_THREE = 0x60, - - GDT_AB_PRESENT = 0x80, - - GDT_FLAG_LONG = 0x20 - -}; - -struct [[gnu::packed]] gdt_entry { - uint32_t zero; - uint8_t zero_; - uint8_t access_byte; - uint8_t flags; - uint8_t zero__; -}; - -struct [[gnu::packed]] gdt_entry_system { - uint16_t limit_0; - uint16_t base_0; - uint8_t base_16; - uint8_t access_byte; - uint8_t flags; - uint8_t base_24; - uint32_t base_32; - uint32_t zero; -}; - -static struct gdt_entry the_gdt[7]; - -struct [[gnu::packed]] gdt_descriptor { - uint16_t limit; - void *base; -}; - -static struct gdt_descriptor the_gdt_descriptor = { - .limit = 7 * sizeof(struct gdt_entry) - 1, - .base = the_gdt -}; - -struct [[gnu::packed]] tss { - uint32_t zero; - uint64_t rsp0; - uint64_t rsp1; - uint64_t rsp2; - uint64_t zero_; - uint64_t ist1; - uint64_t ist2; - uint64_t ist3; - uint64_t ist4; - uint64_t ist5; - uint64_t ist6; - uint64_t ist7; - uint64_t zero__; - uint16_t zero___; - uint16_t io_permission_map_offset; -}; - -static struct tss the_tss; - -//maybe these should be allocated dynamically with guard pages? -#define INTERRUPT_STACK_SIZE (16 << 20) -static uint8_t interrupt_stack_one[INTERRUPT_STACK_SIZE]; -static uint8_t interrupt_stack_two[INTERRUPT_STACK_SIZE]; - -enum { - - //"interrupt" here just means disable interrupts on entry. - //in our case, we use this for both irq's and exceptions. - IDT_TYPE_INTERRUPT = 0x0e, - - IDT_TYPE_DPL_ZERO = 0x00, - IDT_TYPE_DPL_THREE = 0x60, - - IDT_TYPE_PRESENT = 0x80 - -}; - -struct [[gnu::packed]] idt_entry { - uint16_t offset_0; - uint16_t segment_selector; - uint8_t interrupt_stack_index; - uint8_t type; - uint16_t offset_16; - uint32_t offset_32; - uint32_t zero; -}; - -static struct idt_entry the_idt[256]; - -struct [[gnu::packed]] idt_descriptor { - uint16_t limit; - void *base; -}; - -static struct idt_descriptor the_idt_descriptor = { - .limit = 256 * sizeof(struct idt_entry) - 1, - .base = the_idt -}; - -//defined in interrupts.asm -extern void *isrs[48]; - -//defined in interrupts.asm -void init_interrupts_asm( - struct gdt_descriptor *gdtr, - struct idt_descriptor *idtr, - uint16_t tssr); - -void init_interrupts() { - - the_tss.ist1 = (uint64_t)interrupt_stack_one + INTERRUPT_STACK_SIZE; - the_tss.ist2 = (uint64_t)interrupt_stack_two + INTERRUPT_STACK_SIZE; - - //having the table past the end of the tss will lead to a gpf when the - //cpu tries to access it, which is the same effect as a disabled port. - the_tss.io_permission_map_offset = 256; - - uint64_t tss_base = (uint64_t)&the_tss; - uint16_t tss_limit = sizeof(struct tss) - 1; - - struct gdt_entry_system *tss_entry = (struct gdt_entry_system *)&the_gdt[1]; - tss_entry->limit_0 = tss_limit; - tss_entry->base_0 = tss_base & 0xffff; - tss_entry->base_16 = (tss_base >> 16) & 0xff; - tss_entry->access_byte = - GDT_AB_TYPE_TSS | GDT_AB_DPL_ZERO | GDT_AB_PRESENT; - tss_entry->flags = GDT_FLAG_LONG; - tss_entry->base_24 = (tss_base >> 24) & 0xff; - tss_entry->base_32 = tss_base >> 32; - - struct gdt_entry *user_data_entry = &the_gdt[3]; - user_data_entry->access_byte = - GDT_AB_CODE_DATA_ACCESSED | GDT_AB_DATA_WRITABLE | - GDT_AB_TYPE_DATA | GDT_AB_DPL_THREE | GDT_AB_PRESENT; - user_data_entry->flags = GDT_FLAG_LONG; - - struct gdt_entry *user_code_entry = &the_gdt[4]; - user_code_entry->access_byte = - GDT_AB_CODE_DATA_ACCESSED | GDT_AB_TYPE_CODE | - GDT_AB_DPL_THREE | GDT_AB_PRESENT; - user_code_entry->flags = GDT_FLAG_LONG; - - struct gdt_entry *kernel_code_entry = &the_gdt[5]; - kernel_code_entry->access_byte = - GDT_AB_CODE_DATA_ACCESSED | GDT_AB_TYPE_CODE | - GDT_AB_DPL_ZERO | GDT_AB_PRESENT; - kernel_code_entry->flags = GDT_FLAG_LONG; - - struct gdt_entry *kernel_data_entry = &the_gdt[6]; - kernel_data_entry->access_byte = - GDT_AB_CODE_DATA_ACCESSED | GDT_AB_DATA_WRITABLE | - GDT_AB_TYPE_DATA | GDT_AB_DPL_ZERO | GDT_AB_PRESENT; - kernel_data_entry->flags = GDT_FLAG_LONG; - - for (int i = 0; i < 48; ++i) { - uint64_t offset = (uint64_t)isrs[i]; - the_idt[i].offset_0 = offset & 0xffff; - the_idt[i].segment_selector = 0x0028; - the_idt[i].interrupt_stack_index = i < 32 ? 0x02 : 0x01; - the_idt[i].type = - IDT_TYPE_INTERRUPT | IDT_TYPE_DPL_ZERO | IDT_TYPE_PRESENT; - the_idt[i].offset_16 = (offset >> 16) & 0xffff; - the_idt[i].offset_32 = offset >> 32; - } - - init_interrupts_asm(&the_gdt_descriptor, &the_idt_descriptor, 0x08); - -} diff --git a/src/kernel/interrupts.h b/src/kernel/interrupts.h deleted file mode 100644 index 3a1d227..0000000 --- a/src/kernel/interrupts.h +++ /dev/null @@ -1,26 +0,0 @@ -/* Calcite, src/kernel/interrupts.h - * Copyright 2025-2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -#include - -//switches to kernel gdt and idt, maps and unmasks irqs -void init_interrupts(); - -//the handler should have normal C linkage -void set_irq_handler(uint8_t irq_line, void (*handler)()); diff --git a/src/kernel/ipc-dgram.c b/src/kernel/ipc-dgram.c deleted file mode 100644 index 74c64fe..0000000 --- a/src/kernel/ipc-dgram.c +++ /dev/null @@ -1,269 +0,0 @@ -/* Calcite, src/kernel/ipc-dgram.c - * Copyright 2025-2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "ipc-dgram.h" -#include "process.h" -#include "scheduler.h" -#include "utility.h" -#include "debug.h" -#include "heap.h" - -#include - -struct ipc_dgram_address_book { - const char *address; - struct ipc_dgram_box box; - struct ipc_dgram_address_book *prev; -}; - -static struct ipc_dgram_address_book *last = 0; - -#define INITIAL_SEND_BACKLOG 4 - -struct ipc_dgram_box *get_ipc_dgram_box(const char *address) { - - for (struct ipc_dgram_address_book *book = last; book != 0; book = book->prev) - if (strequ(book->address, address)) - return &book->box; - - struct ipc_dgram_address_book *new = heap_alloc(sizeof(struct ipc_dgram_address_book)); - - int address_length = 0; - while (address[address_length] != 0) - ++address_length; - - char *new_address = heap_alloc(address_length + 1); - memcpy(new_address, address, address_length); - new_address[address_length] = 0; - new->address = new_address; - - new->box.is_receiver_held = 0; - new->box.is_private = 0; - new->box.is_someone_waiting_to_receive = 0; - create_queue(&new->box.waiting_to_send, INITIAL_SEND_BACKLOG); - new->box.buffer_read_pointer = 0; - new->box.buffer_read_available = 0; - - new->prev = last; - last = new; - return &new->box; - -} - -int get_ipc_dgram_size(struct ipc_dgram_box *box) { - - if (box->is_someone_waiting_to_receive) - return -1; - - while (box->buffer_read_available == 0) { - box->is_someone_waiting_to_receive = 1; - yield(&box->waiting_to_receive); - } - - assert(box->buffer_read_available >= 4) - return *(int *)&box->buffer[box->buffer_read_pointer]; - -} - -void receive_ipc_dgram(struct ipc_dgram_box *box, void *buffer) { - - assert(box->is_someone_waiting_to_receive == 0) - assert(box->buffer_read_available >= 4) - - int size = *(int *)&box->buffer[box->buffer_read_pointer]; - - box->buffer_read_available -= 4; - box->buffer_read_pointer = (box->buffer_read_pointer + 4) % IPC_DGRAM_BOX_BUFFER_LENGTH; - - int size_rounded_up = ((size - 1) / 4 + 1) * 4; - - assert(box->buffer_read_available >= size_rounded_up) - - int first_block = IPC_DGRAM_BOX_BUFFER_LENGTH - box->buffer_read_pointer; - if (size < first_block) - first_block = size; - - memcpy(buffer, &box->buffer[box->buffer_read_pointer], first_block); - if (first_block != size) - memcpy(buffer + first_block, box->buffer, size - first_block); - - box->buffer_read_available -= size_rounded_up; - box->buffer_read_pointer = (box->buffer_read_pointer + size_rounded_up) % IPC_DGRAM_BOX_BUFFER_LENGTH; - - struct continuation_info ci; - while (take_from_queue(&box->waiting_to_send, &ci)) - add_to_queue(&ready_continuations, &ci); - -} - -enum ipc_dgram_result send_ipc_dgram(struct ipc_dgram_box *box, const void *data, int bytes) { - - assert(bytes > 0) - - int bytes_round_up = ((bytes - 1) / 4 + 1) * 4; - - if (4 + bytes_round_up > IPC_DGRAM_BOX_BUFFER_LENGTH) - return IPR_TOO_BIG; - - while (IPC_DGRAM_BOX_BUFFER_LENGTH - box->buffer_read_available < 4 + bytes_round_up) - yield_to_queue(&box->waiting_to_send); - - int write_pointer = (box->buffer_read_pointer + box->buffer_read_available) % IPC_DGRAM_BOX_BUFFER_LENGTH; - assert(write_pointer + 4 <= IPC_DGRAM_BOX_BUFFER_LENGTH) - - *(int *)&box->buffer[write_pointer] = bytes; - - write_pointer = (write_pointer + 4) % IPC_DGRAM_BOX_BUFFER_LENGTH; - - int first_block = IPC_DGRAM_BOX_BUFFER_LENGTH - write_pointer; - if (bytes < first_block) - first_block = bytes; - - memcpy(&box->buffer[write_pointer], data, first_block); - if (first_block != bytes) - memcpy(box->buffer, data + first_block, bytes - first_block); - - box->buffer_read_available += 4 + bytes_round_up; - - if (box->is_someone_waiting_to_receive) { - box->is_someone_waiting_to_receive = 0; - add_to_queue(&ready_continuations, &box->waiting_to_receive); - } - - return IPR_SUCCESS; - -} - -static uint64_t next_private_id = 0; - -struct ipc_dgram_private_book { - uint64_t id; - struct ipc_dgram_box *box; - struct ipc_dgram_private_book *prev; -}; - -static struct ipc_dgram_private_book *last_without_receiver = 0; -static struct ipc_dgram_private_book *last_without_sender = 0; - -//0 for none with that id -static struct ipc_dgram_box *take_from_private_book(struct ipc_dgram_private_book **book, uint64_t id) { - - while (*book != 0) { - - if ((*book)->id == id) { - struct ipc_dgram_box *box = (*book)->box; - struct ipc_dgram_private_book *prev = (*book)->prev; - heap_dealloc(*book, sizeof(struct ipc_dgram_private_book)); - *book = prev; - return box; - } - - book = &(*book)->prev; - - } - - return 0; - -} - -uint64_t syscall_ipc_create_private_dgram_pipe() { - - uint64_t id = next_private_id++; - - struct ipc_dgram_box *box = heap_alloc(sizeof(struct ipc_dgram_box)); - box->is_receiver_held = 0; - box->is_private = 1; - box->is_someone_waiting_to_receive = 0; - create_queue(&box->waiting_to_send, INITIAL_SEND_BACKLOG); - box->buffer_read_pointer = 0; - box->buffer_read_available = 0; - - struct ipc_dgram_private_book *without_receiver = heap_alloc(sizeof(struct ipc_dgram_private_book)); - without_receiver->id = id; - without_receiver->box = box; - without_receiver->prev = last_without_receiver; - last_without_receiver = without_receiver; - - struct ipc_dgram_private_book *without_sender = heap_alloc(sizeof(struct ipc_dgram_private_book)); - without_sender->id = id; - without_sender->box = box; - without_sender->prev = last_without_sender; - last_without_sender = without_sender; - - return id; - -} - -enum ipc_dgram_result syscall_ipc_create_private_dgram_receiver( - uint64_t id, ipc_dgram_receiver_handle_t *handle_out) { - - assert(running_thread != 0) - - if (!is_mapped_writable( - running_thread->process, handle_out, sizeof(ipc_dgram_receiver_handle_t))) - syscall_illegal_args(); - - struct ipc_dgram_box *box = take_from_private_book(&last_without_receiver, id); - if (box == 0) - return IPR_BAD_HANDLE; - - assert(box->is_receiver_held == 0) - assert(box->private_sides < 2) - - box->is_receiver_held = 1; - ++box->private_sides; - - struct process_ipc_dgram_handle_info *handle_info = - add_handle(&running_thread->process->ipc_dgram_handles, handle_out); - - handle_info->box = box; - handle_info->is_receiver = 1; - return IPR_SUCCESS; - -} - -enum ipc_dgram_result syscall_ipc_create_private_dgram_sender( - uint64_t id, ipc_dgram_sender_handle_t *handle_out) { - - assert(running_thread != 0) - - if (!is_mapped_writable( - running_thread->process, handle_out, sizeof(ipc_dgram_sender_handle_t))) - syscall_illegal_args(); - - struct ipc_dgram_box *box = take_from_private_book(&last_without_sender, id); - if (box == 0) - return IPR_BAD_HANDLE; - - assert(box->private_sides < 2) - - ++box->private_sides; - - struct process_ipc_dgram_handle_info *handle_info = - add_handle(&running_thread->process->ipc_dgram_handles, handle_out); - - handle_info->box = box; - handle_info->is_receiver = 0; - return IPR_SUCCESS; - -} - -void destroy_ipc_dgram_box(struct ipc_dgram_box *box) { - assert(box->is_someone_waiting_to_receive == 0) - assert(box->waiting_to_send.count == 0) - destroy_queue(&box->waiting_to_send); -} diff --git a/src/kernel/ipc-dgram.h b/src/kernel/ipc-dgram.h deleted file mode 100644 index fd399f8..0000000 --- a/src/kernel/ipc-dgram.h +++ /dev/null @@ -1,68 +0,0 @@ -/* Calcite, src/kernel/ipc-dgram.h - * Copyright 2025-2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -#include "scheduler.h" - -#include - -//must be a multiple of 4 -#define IPC_DGRAM_BOX_BUFFER_LENGTH 1024 - -struct ipc_dgram_box { - - int is_receiver_held; - int is_private; - int private_sides; - - int is_someone_waiting_to_receive; - struct continuation_info waiting_to_receive; - - struct continuation_queue waiting_to_send; - - int buffer_read_pointer; - int buffer_read_available; - - //packets are of the form: - // int size; - // uint8_t packet[size]; - // uint8_t padding[size % 4 == 0 ? 0 : 4 - size % 4]; - uint8_t buffer[IPC_DGRAM_BOX_BUFFER_LENGTH]; - -}; - -struct ipc_dgram_box *get_ipc_dgram_box(const char *address); - -//waits until a packet is available, then returns the size of that packet. -//returns -1 if someone is already waiting. -int get_ipc_dgram_size(struct ipc_dgram_box *box); - -//should only be called just after get_ipc_dgram_size -//(i.e. with no intervening continuation resumptions) -void receive_ipc_dgram(struct ipc_dgram_box *box, void *buffer); - -//only returns IPR_SUCCESS or IPR_TOO_BIG -enum ipc_dgram_result send_ipc_dgram(struct ipc_dgram_box *box, const void *data, int bytes); - -uint64_t syscall_ipc_create_private_dgram_pipe(); -enum ipc_dgram_result syscall_ipc_create_private_dgram_receiver( - uint64_t id, ipc_dgram_receiver_handle_t *handle_out); -enum ipc_dgram_result syscall_ipc_create_private_dgram_sender( - uint64_t id, ipc_dgram_sender_handle_t *handle_out); - -void destroy_ipc_dgram_box(struct ipc_dgram_box *box); diff --git a/src/kernel/iso9660.c b/src/kernel/iso9660.c deleted file mode 100644 index b89c070..0000000 --- a/src/kernel/iso9660.c +++ /dev/null @@ -1,382 +0,0 @@ -/* Calcite, src/kernel/iso9660.c - * Copyright 2025 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "iso9660.h" -#include "kernel-public/files.h" -#include "utility.h" -#include "drives.h" -#include "debug.h" -#include "heap.h" -#include "fs.h" - -//relevant sources: -// https://www.ecma-international.org/wp-content/uploads/ECMA-119_2nd_edition_december_1987.pdf - -//case-insensitive equality -static bool ciequ(char c1, char c2) { - if (c1 >= 'a' && c1 <= 'z') - c1 &= 0xdf; - if (c2 >= 'a' && c2 <= 'z') - c2 &= 0xdf; - return c1 == c2; -} - -struct iso9660_driver_info { - const void *path_table; - //in bytes - int path_table_length; -}; - -static const struct iso9660_driver_info *get_driver_info(const struct fs_info *info) { - return (const struct iso9660_driver_info *)info->driver_info; -} - -struct iso9660_node { - uint32_t first_block; - //in bytes - uint32_t length; -}; - -static enum fs_access_result free_node_iso9660(const struct fs_info *info, void *node) { - (void)info; - heap_dealloc(node, sizeof(struct iso9660_node)); - return FAR_SUCCESS; -} - -static uint8_t directory_buffer[2048]; - -static enum fs_access_result look_up_in_directory( - const struct fs_info *info, void **node_out, - const char *path, int path_length, - uint32_t first_directory_block) { - - if (first_directory_block >= info->drive->block_count) - return FAR_FORMAT_ERROR; - - switch ((*info->drive->read_blocks)(info->drive, directory_buffer, first_directory_block, 1)) { - case DAR_SUCCESS: - break; - case DAR_HARDWARE_ERROR: - return FAR_HARDWARE_ERROR; - default: - assert(0); - } - - int length = *(uint32_t *)&directory_buffer[10]; - if (length % 2048 != 0) - return FAR_FORMAT_ERROR; - - uint32_t loaded_block = first_directory_block; - int offset_in_block = 0; - int total_offset = 0; - - while (1) { - - if (total_offset == length) - return FAR_NOT_FOUND; - - if (offset_in_block == 2048 || directory_buffer[offset_in_block] == 0) { - ++loaded_block; - if (loaded_block >= info->drive->block_count) - return FAR_FORMAT_ERROR; - switch ((*info->drive->read_blocks)(info->drive, directory_buffer, loaded_block, 1)) { - case DAR_SUCCESS: - break; - case DAR_HARDWARE_ERROR: - return FAR_HARDWARE_ERROR; - default: - assert(0); - } - total_offset = total_offset - offset_in_block + 2048; - offset_in_block = 0; - if (total_offset == length) - return FAR_NOT_FOUND; - } - - int dr_length = directory_buffer[offset_in_block]; - if (offset_in_block + dr_length > 2048) - return FAR_FORMAT_ERROR; - - int id_length = directory_buffer[offset_in_block + 32]; - if (33 + id_length > dr_length) - return FAR_FORMAT_ERROR; - - for (int i = 0; i < id_length; ++i) - if (directory_buffer[offset_in_block + 33 + i] == ';') { - id_length = i; - break; - } - - if (id_length != path_length) - goto next_entry; - - for (int i = 0; i < id_length; ++i) - if (!ciequ(directory_buffer[offset_in_block + 33 + i], path[i])) - goto next_entry; - - struct iso9660_node *node = heap_alloc(sizeof(struct iso9660_node)); - node->first_block = *(uint32_t *)&directory_buffer[offset_in_block + 2]; - node->length = *(uint32_t *)&directory_buffer[offset_in_block + 10]; - - *node_out = node; - return FAR_SUCCESS; - - next_entry: - offset_in_block += dr_length; - total_offset += dr_length; - - } - -} - -static enum fs_access_result look_up_recursive( - const struct fs_info *info, void **node_out, - const char *path, int parent_path_table_offset, - int parent_directory_number) { - - //FIXME: this function is pretty unoptimized - -recurse: - - int slash_location = 0; - int path_length; - while (1) { - if (path[slash_location] == '/') - break; - if (path[slash_location] == 0) { - path_length = slash_location; - slash_location = -1; - break; - } - ++slash_location; - } - - const struct iso9660_driver_info *driver_info = get_driver_info(info); - - int on_offset = parent_path_table_offset; - int on_number = parent_directory_number; - - if (slash_location == -1) { - if (on_offset + 6 > driver_info->path_table_length) - return FAR_NOT_FOUND; - uint32_t first_directory_block = *(uint32_t *)(driver_info->path_table + on_offset + 2); - return look_up_in_directory(info, node_out, path, path_length, first_directory_block); - } - - while (1) { - - if (on_offset >= driver_info->path_table_length) - return FAR_NOT_FOUND; - - int old_id_length = *(uint8_t *)(driver_info->path_table + on_offset); - on_offset += 8 + old_id_length + (old_id_length & 0x01); - ++on_number; - - if (on_offset + 8 > driver_info->path_table_length) - return FAR_NOT_FOUND; - - int this_entry_parent = *(uint16_t *)(driver_info->path_table + on_offset + 6); - if (this_entry_parent != parent_directory_number) - continue; - - int this_entry_id_length = *(uint8_t *)(driver_info->path_table + on_offset); - if (this_entry_id_length != slash_location) - continue; - - if (on_offset + 8 + this_entry_id_length > driver_info->path_table_length) - return FAR_NOT_FOUND; - - char *this_entry_id = (char *)(driver_info->path_table + on_offset + 8); - for (int i = 0; i < slash_location; ++i) - if (!ciequ(this_entry_id[i], path[i])) - goto next_entry; - - path = path + slash_location + 1; - parent_path_table_offset = on_offset; - parent_directory_number = on_number; - goto recurse; - - next_entry: - ; - - } - -} - -static enum fs_access_result look_up_file_iso9660( - const struct fs_info *info, void **node_out, const char *path) { - - return look_up_recursive(info, node_out, path, 0, 1); - -} - -static enum fs_access_result stat_file_iso9660( - const struct fs_info *info, void *node, struct fs_stat *stat_out) { - - (void)info; - struct iso9660_node *iso9660_node = (struct iso9660_node *)node; - stat_out->bytes = iso9660_node->length; - return FAR_SUCCESS; - -} - -static uint8_t read_buffer[2048]; - -static enum fs_access_result read_file_iso9660( - const struct fs_info *info, void *node, void *buffer, uint64_t start, uint64_t bytes) { - - struct iso9660_node *iso9660_node = (struct iso9660_node *)node; - if (iso9660_node->first_block + (start + bytes - 1) / 2048 + 1 > info->drive->block_count) - return FAR_FORMAT_ERROR; - - if (start % 2048 != 0) { - - switch ((*info->drive->read_blocks)( - info->drive, read_buffer, iso9660_node->first_block + start / 2048, 1)) { - case DAR_SUCCESS: - break; - case DAR_HARDWARE_ERROR: - return FAR_HARDWARE_ERROR; - default: - assert(0); - } - - if (start + bytes <= ((start - 1) / 2048 + 1) * 2048) { - memcpy(buffer, read_buffer + (start % 2048), bytes); - return FAR_SUCCESS; - } - - int to_copy = 2048 - (start % 2048); - memcpy(buffer, read_buffer + (start % 2048), to_copy); - buffer += to_copy; - start += to_copy; - bytes -= to_copy; - - } - - switch ((*info->drive->read_blocks)( - info->drive, buffer, - iso9660_node->first_block + start / 2048, - bytes / 2048)) { - case DAR_SUCCESS: - break; - case DAR_HARDWARE_ERROR: - return FAR_HARDWARE_ERROR; - default: - assert(0); - } - - buffer += (bytes / 2048) * 2048; - start += (bytes / 2048) * 2048; - bytes %= 2048; - - if (bytes > 0) { - - switch ((*info->drive->read_blocks)( - info->drive, read_buffer, iso9660_node->first_block + start / 2048, 1)) { - case DAR_SUCCESS: - break; - case DAR_HARDWARE_ERROR: - return FAR_HARDWARE_ERROR; - default: - assert(0); - } - - memcpy(buffer, read_buffer + (start % 2048), bytes); - - } - - return FAR_SUCCESS; - -} - -static uint8_t vd_buffer[2048]; - -enum fs_access_result create_iso9660_info(const struct drive_info *drive, struct fs_info *fs_out) { - - if (drive->block_size != 2048) - panic("TODO") - - int descriptor_number = 0; - while (1) { - - if ((uint64_t)(16 + descriptor_number) >= drive->block_count) - return FAR_FORMAT_ERROR; - - switch ((*drive->read_blocks)(drive, vd_buffer, 16 + descriptor_number, 1)) { - case DAR_SUCCESS: - break; - case DAR_HARDWARE_ERROR: - return FAR_HARDWARE_ERROR; - default: - assert(0) - } - - if (vd_buffer[0] == 0xff) - return FAR_FORMAT_ERROR; - - if (vd_buffer[0] == 0x01) - break; - - ++descriptor_number; - - } - - uint32_t path_table_length = *(uint32_t *)&vd_buffer[132]; - uint32_t path_table_start = *(uint32_t *)&vd_buffer[140]; - - uint64_t path_table_length_rounded_up = ((path_table_length - 1) / 2048 + 1) * 2048; - void *path_table = heap_alloc(path_table_length_rounded_up); - - if (path_table_start >= drive->block_count) - return FAR_FORMAT_ERROR; - - switch ((*drive->read_blocks)( - drive, path_table, path_table_start, - path_table_length_rounded_up / 2048)) { - case DAR_SUCCESS: - break; - case DAR_HARDWARE_ERROR: - heap_dealloc(path_table, path_table_length_rounded_up); - return FAR_HARDWARE_ERROR; - default: - assert(0); - } - - heap_dealloc( - path_table + path_table_length, - path_table_length_rounded_up - path_table_length); - - struct iso9660_driver_info *driver_info = heap_alloc(sizeof(struct iso9660_driver_info)); - driver_info->path_table = path_table; - driver_info->path_table_length = path_table_length; - - fs_out->drive = drive; - fs_out->driver_info = driver_info; - fs_out->free_node = &free_node_iso9660; - fs_out->look_up_file = &look_up_file_iso9660; - fs_out->stat_file = &stat_file_iso9660; - fs_out->read_file = &read_file_iso9660; - - debug_log("created iso9660 file system") - debug_log(" drive name %s", drive->name) - debug_log(" path table start block %d", path_table_start) - debug_log(" path table block count %d", path_table_length_rounded_up / 2048) - - return FAR_SUCCESS; - -} diff --git a/src/kernel/iso9660.h b/src/kernel/iso9660.h deleted file mode 100644 index be3f5c7..0000000 --- a/src/kernel/iso9660.h +++ /dev/null @@ -1,22 +0,0 @@ -/* Calcite, src/kernel/iso9660.h - * Copyright 2025 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -#include "fs.h" - -enum fs_access_result create_iso9660_info(const struct drive_info *drive, struct fs_info *fs_out); diff --git a/src/kernel/paging.asm b/src/kernel/paging.asm deleted file mode 100644 index 2d5dd6e..0000000 --- a/src/kernel/paging.asm +++ /dev/null @@ -1,49 +0,0 @@ - ; Calcite, src/kernel/paging.asm - ; Copyright 2025 Benji Dial - ; - ; This program is free software: you can redistribute it and/or modify - ; it under the terms of the GNU General Public License as published by - ; the Free Software Foundation, either version 3 of the License, or - ; (at your option) any later version. - ; - ; This program is distributed in the hope that it will be useful, but - ; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - ; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - ; for more details. - ; - ; You should have received a copy of the GNU General Public License along - ; with this program. If not, see . - - -bits 64 -default rel - -;both defined in paging.c -extern kernel_p4_physical_address -extern init_stack - -init_stack_length equ 16384 - -section .text - -;referenced in paging.c -extern invlpg -invlpg: - invlpg [rdi] - ret - -extern switch_to_kernel_page_tables -switch_to_kernel_page_tables: - - ;switch the page table - mov rax, qword [kernel_p4_physical_address] - mov cr3, rax - - ;set the stack - mov rsp, init_stack + init_stack_length - - ;push 0 before jumping to continuation so that if the continuation - ;does return (which it shouldn't), it returns to null instead of - ;popping garbage and returning there - push qword 0 - jmp rdi diff --git a/src/kernel/paging.c b/src/kernel/paging.c deleted file mode 100644 index e16deeb..0000000 --- a/src/kernel/paging.c +++ /dev/null @@ -1,232 +0,0 @@ -/* Calcite, src/kernel/paging.c - * Copyright 2025-2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "paging.h" -#include "debug.h" - -#define MAX_PHYSICAL_GB 64ULL - -//this is a simple bitmap. physical_map[i / 8] & (1 << (i % 8)) is nonzero if -//and only if the physical page with base i * 4096 is free. -static uint8_t physical_map[MAX_PHYSICAL_GB << 15]; - -//kernel virtual memory is the top gigabyte, i.e. one "page directory" worth -//of pages. in the future i might make it more reactive, and allow new page -//directories to be allocated as needed, but for now there is just the one -//page directory, and all of the page tables in that directory are statically -//allocated. i do not like the intel/amd names for the paging structures, so -//i will use these names throughout the rest of this file: -// p4 = "page map level 4" -// p3 = "page directory pointer table" -// p2 = "page directory" -// p1 = "page table" - -//referenced from paging.asm -uint64_t kernel_p4_physical_address; - -uint64_t kernel_p3_physical_address; - -alignas(4096) static uint64_t kernel_p4[512]; -alignas(4096) static uint64_t kernel_p3[512]; -alignas(4096) static uint64_t kernel_p2[512]; -alignas(4096) static uint64_t kernel_p1s[512 * 512]; - -//referenced from paging.asm. at the end of init, this will either be marked -//free or reused as an interrupt / syscall stack. if the length of this is -//changed, it also needs to be changed in paging.asm. there is no guard page, -//but i don't expect init to need much stack. -alignas(4096) uint64_t init_stack[16384]; - -void init_paging(uint64_t kernel_physical_base, void *kernel_virtual_base) { - - uint64_t kernel_load_offset = - (uint64_t)kernel_virtual_base - kernel_physical_base; - - kernel_p4_physical_address = (uint64_t)kernel_p4 - kernel_load_offset; - kernel_p3_physical_address = (uint64_t)kernel_p3 - kernel_load_offset; - - kernel_p4[511] = ((uint64_t)kernel_p3 - kernel_load_offset) | 0x3; - for (int i = 0; i < 511; ++i) - kernel_p4[i] = 0; - - kernel_p3[511] = ((uint64_t)kernel_p2 - kernel_load_offset) | 0x3; - for (int i = 0; i < 511; ++i) - kernel_p3[i] = 0; - - for (int i = 0; i < 512; ++i) - kernel_p2[i] = - ((uint64_t)kernel_p1s - kernel_load_offset + i * 4096) | 0x03; - - for (int i = 0; i < 512 * 512; ++i) - kernel_p1s[i] = 0; - -} - -void mark_physical_memory_free(uint64_t base, uint64_t length) { - - if (base + length > MAX_PHYSICAL_GB << 30) - length = (MAX_PHYSICAL_GB << 30) - base; - - while (length && (base & (0x7 << 12))) { - physical_map[base >> 15] |= 1 << ((base >> 12) % 8); - base += 4096; - length -= 4096; - } - - while (length >= 4096 * 8) { - physical_map[base >> 15] = 0xff; - base += 4096 * 8; - length -= 4096 * 8; - } - - while (length) { - physical_map[base >> 15] |= 1 << ((base >> 12) % 8); - base += 4096; - length -= 4096; - } - -} - -//defined in paging.asm -void invlpg(void *address); - -void map_in_kernel_page_table(uint64_t physical_base, void *virtual_base, int writable, int executable) { - - uint64_t virtual_base_u64 = (uint64_t)virtual_base; - assert(virtual_base_u64 >= 0xffffffffc0000000); - - uint64_t p1s_index = (virtual_base_u64 - 0xffffffffc0000000) >> 12; - assert(kernel_p1s[p1s_index] == 0); - - kernel_p1s[p1s_index] = - physical_base | (writable ? 0x3 : 0x1) | - (executable ? 0 : 0x8000000000000000); - - invlpg(virtual_base); - -} - -void create_kernel_guard_page(void *virtual_base) { - - uint64_t virtual_base_u64 = (uint64_t)virtual_base; - assert(virtual_base_u64 >= 0xffffffffc0000000); - - uint64_t p1s_index = (virtual_base_u64 - 0xffffffffc0000000) >> 12; - assert(kernel_p1s[p1s_index] == 0); - - kernel_p1s[p1s_index] = 0x2; - -} - -void unmap_kernel_page(void *virtual_base) { - - uint64_t virtual_base_u64 = (uint64_t)virtual_base; - assert(virtual_base_u64 >= 0xffffffffc0000000); - - uint64_t p1s_index = (virtual_base_u64 - 0xffffffffc0000000) >> 12; - assert(kernel_p1s[p1s_index] != 0); - - kernel_p1s[p1s_index] = 0; - - invlpg(virtual_base); - -} - -void unmap_and_free_kernel_page(void *virtual_base) { - - uint64_t virtual_base_u64 = (uint64_t)virtual_base; - assert(virtual_base_u64 >= 0xffffffffc0000000); - - uint64_t p1s_index = (virtual_base_u64 - 0xffffffffc0000000) >> 12; - assert(kernel_p1s[p1s_index] != 0); - - uint64_t pma = kernel_p1s[p1s_index] & 0x7ffffffffffff000; - mark_physical_memory_free(pma, 4096); - - kernel_p1s[p1s_index] = 0; - - invlpg(virtual_base); - -} - -void *find_free_kernel_region(uint64_t length) { - - length /= 4096; - - uint64_t next = 0; - - uint64_t run_start = 0; - uint64_t run_length = 0; - - while (1) { - if (run_length == length) - return (void *)(run_start * 4096 + 0xffffffffc0000000); - if (next == 512 * 512) - panic("out of kernel virtual memory"); - if (kernel_p1s[next] == 0) - ++run_length; - else { - run_length = 0; - run_start = next + 1; - } - ++next; - } - -} - -uint64_t take_free_physical_page() { - for (uint64_t i = 0; i < (MAX_PHYSICAL_GB << 15); ++i) - for (int j = 0; j < 8; ++j) - if (physical_map[i] & (1 << j)) { - physical_map[i] &= ~(1 << j); - return (i << 15) + (j << 12); - } - panic("out of physical memory"); -} - -#define SYSCALL_STACK_BYTES (1 << 15) - -void *create_syscall_stack() { - void *vma = find_free_kernel_region(SYSCALL_STACK_BYTES); - for (uint64_t i = 0; i < SYSCALL_STACK_BYTES; i += 4096) { - uint64_t pma = take_free_physical_page(); - map_in_kernel_page_table(pma, vma + i * 4096, 1, 0); - } - return vma + SYSCALL_STACK_BYTES; -} - -void destroy_syscall_stack(void *stack_top) { - for (uint64_t i = 0; i < SYSCALL_STACK_BYTES; i += 4096) - unmap_and_free_kernel_page(stack_top - SYSCALL_STACK_BYTES + i * 4096); -} - -uint64_t count_free_pram() { - uint64_t total = 0; - for (uint64_t i = 0; i < (MAX_PHYSICAL_GB << 15); ++i) - for (int j = 0; j < 8; ++j) - if (physical_map[i] & (1 << j)) - total += 4096; - return total; -} - -uint64_t count_free_kernel_vram() { - uint64_t total = 0; - for (uint64_t i = 0; i < 512 * 512; ++i) - if (kernel_p1s[i] == 0) - total += 4096; - return total; -} diff --git a/src/kernel/paging.h b/src/kernel/paging.h deleted file mode 100644 index 60f0ca9..0000000 --- a/src/kernel/paging.h +++ /dev/null @@ -1,63 +0,0 @@ -/* Calcite, src/kernel/paging.h - * Copyright 2025-2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -#include - -extern uint64_t kernel_p3_physical_address; - -//kernel physical and virtual bases are passed so that we can compute the -//physical addresses of the kernel's statically allocated paging structures. -void init_paging(uint64_t kernel_physical_base, void *kernel_virtual_base); - -//base and length should be page-aligned -void mark_physical_memory_free(uint64_t base, uint64_t length); - -//maps one page. physical and virtual bases should be page-aligned. -//virtual address should be within kernel range. -void map_in_kernel_page_table( - uint64_t physical_base, void *virtual_base, int writable, int executable); - -//virtual base should be page-aligned and within kernel range. -void create_kernel_guard_page(void *virtual_base); - -//unmaps one page. base should be page-aligned and within kernel range. -void unmap_kernel_page(void *virtual_base); - -//unmaps one page, and frees the corresponding physical page. -//base should be page-aligned and within kernel range. -void unmap_and_free_kernel_page(void *virtual_base); - -//returns a region of contiguous pages in kernel virtual memory where nothing -//is mapped. length should be page-aligned. -void *find_free_kernel_region(uint64_t length); - -uint64_t take_free_physical_page(); - -//implemented in paging.asm. the continuation should be noreturn. -[[noreturn]] void switch_to_kernel_page_tables(void (*continuation)()); - -//returns the top -void *create_syscall_stack(); -void destroy_syscall_stack(void *stack_top); - -//return value in bytes -uint64_t count_free_pram(); - -//return value in bytes -uint64_t count_free_kernel_vram(); diff --git a/src/kernel/pata.c b/src/kernel/pata.c deleted file mode 100644 index 0f34efa..0000000 --- a/src/kernel/pata.c +++ /dev/null @@ -1,250 +0,0 @@ -/* Calcite, src/kernel/pata.c - * Copyright 2025-2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "utility.h" -#include "drives.h" -#include "debug.h" -#include "heap.h" -#include "pata.h" -#include "pci.h" - -//some relevant sources: -// https://www.isdaman.com/alsos/hardware/hdc/pciide.pdf -// ANSI: AT Attachment 8 - ATA/ATAPI Command Set -// Seagate: SCSI Commands Reference Manual -// OSDev Wiki: ATAPI, PCI IDE Controller - -enum pata_result { - PR_SUCCESS, - PR_NO_CONTROLLER, - PR_ABORTED -}; - -enum pata_result wait_pio(uint16_t command_block_base) { - while (1) { - uint8_t status = inb(command_block_base + 7); - //0x00 happens in qemu, 0x7f happens in virtualbox - if (status == 0x00 || status == 0x7f) - return PR_NO_CONTROLLER; - if (status & 0x01) { - uint8_t error = inb(command_block_base + 1); - if (error == 0x04) - return PR_ABORTED; - panic("TODO") - } - if ((status & 0x80) || !(status & 0x08)) - continue; - return PR_SUCCESS; - } -} - -//buffer should have room for 256 words. -static enum pata_result - pata_identify_packet_device(uint16_t command_block_base, uint8_t device_byte, uint16_t *buffer) { - - outb(command_block_base + 6, device_byte); - outb(command_block_base + 7, 0xa1); - - enum pata_result result = wait_pio(command_block_base); - if (result != PR_SUCCESS) - return result; - - insw(command_block_base, buffer, 256); - return PR_SUCCESS; - -} - -static enum pata_result patapi_read_capacity( - uint16_t command_block_base, uint8_t device_byte, uint32_t *max_block_out, uint32_t *block_size_out) { - - outb(command_block_base + 6, device_byte); - outb(command_block_base + 1, 0); - outb(command_block_base + 3, 0); - outb(command_block_base + 4, 8); - outb(command_block_base + 5, 0); - outb(command_block_base + 7, 0xa0); - - enum pata_result result = wait_pio(command_block_base); - if (result != PR_SUCCESS) - return result; - - uint8_t cmd[12] = { - 0x25, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0 }; - outsw(command_block_base, cmd, 6); - - result = wait_pio(command_block_base); - if (result != PR_SUCCESS) - return result; - - uint32_t actual_response_size = - inb(command_block_base + 4) | (inb(command_block_base + 5) << 8); - if (actual_response_size != 8) - panic("TODO") - - uint32_t response[2]; - insw(command_block_base, response, 4); - - *max_block_out = end_swap_u32(response[0]); - *block_size_out = end_swap_u32(response[1]); - return PR_SUCCESS; - -} - -static enum pata_result patapi_read( - uint16_t command_block_base, uint8_t device_byte, uint16_t block_size, - uint32_t start_block, uint32_t block_count, void *buffer) { - - outb(command_block_base + 6, device_byte); - outb(command_block_base + 1, 0); - outb(command_block_base + 3, 0); - outb(command_block_base + 4, block_size & 0xff); - outb(command_block_base + 5, block_size >> 8); - outb(command_block_base + 7, 0xa0); - - enum pata_result result = wait_pio(command_block_base); - if (result != PR_SUCCESS) - return result; - - uint8_t cmd[12] = { - 0xa8, 0, - start_block >> 24, - (start_block >> 16) & 0xff, - (start_block >> 8) & 0xff, - start_block & 0xff, - block_count >> 24, - (block_count >> 16) & 0xff, - (block_count >> 8) & 0xff, - block_count & 0xff, - 0, 0 }; - outsw(command_block_base, cmd, 6); - - for (uint32_t i = 0; i < block_count; ++i) { - - result = wait_pio(command_block_base); - if (result != PR_SUCCESS) - return result; - - uint32_t actual_response_size = - inb(command_block_base + 4) | (inb(command_block_base + 5) << 8); - - if (actual_response_size != block_size) - panic("TODO") - - insw(command_block_base, buffer + i * block_size, block_size / 2); - - } - - return PR_SUCCESS; - -} - -static uint16_t ipd_buffer[256]; - -struct pata_driver_info { - uint16_t command_block_base; - uint8_t device_byte; -}; - -static enum drive_access_result read_blocks_patapi( - const struct drive_info *drive_info, - void *buffer, uint64_t start, uint64_t count) { - - if (count >= (1ULL << 32) || start >= (1ULL << 32)) - panic("TODO") - - const struct pata_driver_info *driver_info = drive_info->driver_info; - - return - patapi_read( - driver_info->command_block_base, driver_info->device_byte, - drive_info->block_size, start, count, buffer) == PR_SUCCESS - ? DAR_SUCCESS : DAR_HARDWARE_ERROR; - -} - -int next_pata_drive_number = 0; - -static void probe_pata_drive(uint16_t command_block_base, uint8_t device_byte) { - - if (pata_identify_packet_device(command_block_base, device_byte, ipd_buffer) != PR_SUCCESS) - return; - - uint32_t max_block, block_size; - if (patapi_read_capacity( - command_block_base, device_byte, &max_block, &block_size) != PR_SUCCESS) - return; - - if (next_pata_drive_number > 9) - panic("TODO") - - struct drive_info *di = add_drive(); - - char *name = heap_alloc(6); - memcpy(name, "pata", 4); - name[4] = '0' + next_pata_drive_number++; - name[5] = 0; - di->name = name; - - di->block_size = block_size; - di->block_count = max_block + 1; - - struct pata_driver_info *driver_info = - heap_alloc(sizeof(struct pata_driver_info)); - driver_info->command_block_base = command_block_base; - driver_info->device_byte = device_byte; - di->driver_info = driver_info; - - di->read_blocks = &read_blocks_patapi; - - debug_log("added pata drive") - debug_log(" drive name %s", di->name) - debug_log(" command block base 0x%h", command_block_base, 4) - debug_log(" device byte 0x%h", device_byte, 2) - debug_log(" block size %d", di->block_size) - debug_log(" block count %d", di->block_count) - debug_log(" total size %B", di->block_count * di->block_size) - -} - -void probe_pata_drives(uint32_t pci_address_base, uint32_t pci_class_etc) { - - if (pci_class_etc & 0x00000100) { - uint32_t bar = read_pci_config(pci_address_base + 0x10); - if ((bar & 0xffff0003) != 0x00000001) - panic("TODO") - probe_pata_drive(bar & 0xfffc, 0x00); - probe_pata_drive(bar & 0xfffc, 0x10); - } - else { - probe_pata_drive(0x01f0, 0x00); - probe_pata_drive(0x01f0, 0x10); - } - - if (pci_class_etc & 0x00000400) { - uint32_t bar = read_pci_config(pci_address_base + 0x18); - if ((bar & 0xffff0003) != 0x00000001) - panic("TODO") - probe_pata_drive(bar & 0xfffc, 0x00); - probe_pata_drive(bar & 0xfffc, 0x10); - } - else { - probe_pata_drive(0x0170, 0x00); - probe_pata_drive(0x0170, 0x10); - } - -} diff --git a/src/kernel/pata.h b/src/kernel/pata.h deleted file mode 100644 index 908e3ae..0000000 --- a/src/kernel/pata.h +++ /dev/null @@ -1,23 +0,0 @@ -/* Calcite, src/kernel/pata.h - * Copyright 2025 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -#include - -//probes for pata drives on this "card" and adds any that exist to drives.h -void probe_pata_drives(uint32_t pci_address_base, uint32_t pci_class_etc); diff --git a/src/kernel/pci.asm b/src/kernel/pci.asm deleted file mode 100644 index 5f3c739..0000000 --- a/src/kernel/pci.asm +++ /dev/null @@ -1,40 +0,0 @@ - ; Calcite, src/kernel/pci.asm - ; Copyright 2025 Benji Dial - ; - ; This program is free software: you can redistribute it and/or modify - ; it under the terms of the GNU General Public License as published by - ; the Free Software Foundation, either version 3 of the License, or - ; (at your option) any later version. - ; - ; This program is distributed in the hope that it will be useful, but - ; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - ; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - ; for more details. - ; - ; You should have received a copy of the GNU General Public License along - ; with this program. If not, see . - - -bits 64 -default rel - -section .text - -global read_pci_config -read_pci_config: - mov dx, 0x0cf8 - mov eax, edi - out dx, eax - mov dx, 0x0cfc - in eax, dx - ret - -global write_pci_config -write_pci_config: - mov dx, 0x0cf8 - mov eax, edi - out dx, eax - mov dx, 0x0cfc - mov eax, esi - out dx, eax - ret diff --git a/src/kernel/pci.c b/src/kernel/pci.c deleted file mode 100644 index ac705f5..0000000 --- a/src/kernel/pci.c +++ /dev/null @@ -1,61 +0,0 @@ -/* Calcite, src/kernel/pci.c - * Copyright 2025 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "debug.h" -#include "pata.h" -#include "pci.h" - -#include - -static void probe_bus(uint32_t bus_address_base) { - - for (uint32_t device_address_base = bus_address_base; - device_address_base < bus_address_base + 0x00010000; - device_address_base += 0x00000800) - for (uint32_t function_address_base = device_address_base; - function_address_base < device_address_base + 0x00000800; - function_address_base += 0x00000100) { - - uint8_t header_type = (read_pci_config(function_address_base | 0x0c) >> 16) & 0xff; - if (header_type == 0xff) - break; - - if ((header_type & 0x7f) == 0x01) - //this is a pci-to-pci bridge - probe_bus((read_pci_config(function_address_base | 0x18) >> 8) & 0xff); - - else if ((header_type & 0x7f) == 0x00) { - //this is a normal function - uint32_t class_etc = read_pci_config(function_address_base | 0x08); - debug_log("pci device with class %h:%h", class_etc >> 24, 2, class_etc >> 16, 2); - switch (class_etc & 0xffff0000) { - case 0x01010000: - probe_pata_drives(function_address_base, class_etc); - break; - } - } - - if (!(header_type & 0x80)) - break; - - } - -} - -void probe_pci() { - probe_bus(0x80000000); -} diff --git a/src/kernel/pci.h b/src/kernel/pci.h deleted file mode 100644 index dc1ddc1..0000000 --- a/src/kernel/pci.h +++ /dev/null @@ -1,32 +0,0 @@ -/* Calcite, src/kernel/pci.h - * Copyright 2025 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -#include - -//reads one dword from config space. -//address is 0x8000000 | (bus << 16) | (device << 11) | (function << 8) | (bytes into that function's space). -//bytes into that function's space must be dword-aligned. -uint32_t read_pci_config(uint32_t address); - -//writes one dword to config space. -//address is 0x8000000 | (bus << 16) | (device << 11) | (function << 8) | (bytes into that function's space). -//bytes into that function's space must be dword-aligned. -void write_pci_config(uint32_t address, uint32_t value); - -void probe_pci(); diff --git a/src/kernel/process.asm b/src/kernel/process.asm deleted file mode 100644 index d3c6bcf..0000000 --- a/src/kernel/process.asm +++ /dev/null @@ -1,55 +0,0 @@ - ; Calcite, src/kernel/process.asm - ; Copyright 2025 Benji Dial - ; - ; This program is free software: you can redistribute it and/or modify - ; it under the terms of the GNU General Public License as published by - ; the Free Software Foundation, either version 3 of the License, or - ; (at your option) any later version. - ; - ; This program is distributed in the hope that it will be useful, but - ; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - ; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - ; for more details. - ; - ; You should have received a copy of the GNU General Public License along - ; with this program. If not, see . - - -bits 64 -default rel - -section .bss - - resb 16384 -temporary_stack: - -section .text - -;referenced in process.c -global thread_start -thread_start: - mov cr3, rbp - mov rcx, r12 - mov r11, 0x200 - mov rdi, r13 - - xor rax, rax - xor rbx, rbx - xor rdx, rdx - xor rsi, rsi - xor rbp, rbp - xor r8, r8 - xor r9, r9 - xor r10, r10 - xor r12, r12 - xor r13, r13 - xor r14, r14 - xor r15, r15 - - o64 sysret - -;referenced in process.c -global with_temporary_stack -with_temporary_stack: - mov rsp, temporary_stack - jmp rdi diff --git a/src/kernel/process.c b/src/kernel/process.c deleted file mode 100644 index 10df5a1..0000000 --- a/src/kernel/process.c +++ /dev/null @@ -1,1098 +0,0 @@ -/* Calcite, src/kernel/process.c - * Copyright 2025-2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "framebuffer.h" -#include "ipc-dgram.h" -#include "scheduler.h" -#include "process.h" -#include "utility.h" -#include "paging.h" -#include "debug.h" -#include "heap.h" -#include "fs.h" - -#include -#include -#include -#include - -void create_process(struct process *process_out) { - - process_out->p4_physical_base = take_free_physical_page(); - process_out->p4_virtual_base = find_free_kernel_region(4096); - map_in_kernel_page_table( - process_out->p4_physical_base, - process_out->p4_virtual_base, - 1, 0); - - process_out->p3_physical_base = take_free_physical_page(); - process_out->p3_virtual_base = find_free_kernel_region(4096); - map_in_kernel_page_table( - process_out->p3_physical_base, - process_out->p3_virtual_base, - 1, 0); - - process_out->p4_virtual_base[0] = process_out->p3_physical_base | 0x7; - process_out->p4_virtual_base[511] = kernel_p3_physical_address | 0x3; - for (int i = 1; i < 511; ++i) - process_out->p4_virtual_base[i] = 0; - - for (int i = 0; i < 512; ++i) { - process_out->p3_virtual_base[i] = 0; - process_out->p2_virtual_bases[i] = 0; - process_out->p1_virtual_bases[i] = 0; - process_out->owned_pages_bitmaps[i] = 0; - } - - process_out->n_threads = 0; - process_out->env_pairs = 0; - - create_handle_list(&process_out->file_handles, sizeof(struct process_file_info)); - create_handle_list( - &process_out->ipc_dgram_handles, sizeof(struct process_ipc_dgram_handle_info)); - create_handle_list(&process_out->mutex_handles, sizeof(struct process_mutex_info)); - create_handle_list(&process_out->event_handles, sizeof(struct process_event_info)); - -} - -static void get_page_table_entry( - struct process *process, void *virtual_base, int *p1i_out, int *p2i_out, int *p3i_out) { - - uint64_t vma = (uint64_t)virtual_base; - assert(vma % 4096 == 0) - assert(vma != 0) - assert(vma < 0x0000008000000000) - - int p1i = (vma >> 12) & 0x1ff; - int p2i = (vma >> 21) & 0x1ff; - int p3i = (vma >> 30) & 0x1ff; - - if (process->p3_virtual_base[p3i] == 0) { - uint64_t p2_pma = take_free_physical_page(); - uint64_t *p2_vma = find_free_kernel_region(4096); - map_in_kernel_page_table(p2_pma, p2_vma, 1, 0); - process->p3_virtual_base[p3i] = p2_pma | 0x7; - process->p2_virtual_bases[p3i] = p2_vma; - process->p1_virtual_bases[p3i] = heap_alloc(4096); - process->owned_pages_bitmaps[p3i] = heap_alloc(4096); - for (int i = 0; i < 512; ++i) { - p2_vma[i] = 0; - process->p1_virtual_bases[p3i][i] = 0; - process->owned_pages_bitmaps[p3i][i] = 0; - } - } - - if (process->p2_virtual_bases[p3i][p2i] == 0) { - uint64_t p1_pma = take_free_physical_page(); - uint64_t *p1_vma = find_free_kernel_region(4096); - map_in_kernel_page_table(p1_pma, p1_vma, 1, 0); - process->p2_virtual_bases[p3i][p2i] = p1_pma | 0x7; - process->p1_virtual_bases[p3i][p2i] = p1_vma; - process->owned_pages_bitmaps[p3i][p2i] = heap_alloc(64); - for (int i = 0; i < 512; ++i) - p1_vma[i] = 0; - for (int i = 0; i < 64; ++i) - process->owned_pages_bitmaps[p3i][p2i][i] = 0; - } - - *p1i_out = p1i; - *p2i_out = p2i; - *p3i_out = p3i; - -} - -void map_page_for_process( - struct process *process, uint64_t physical_base, - void *virtual_base, int writable, int executable, int owned) { - - assert(physical_base % 4096 == 0) - - int p1i, p2i, p3i; - get_page_table_entry(process, virtual_base, &p1i, &p2i, &p3i); - - assert(process->p1_virtual_bases[p3i][p2i][p1i] == 0) - - process->p1_virtual_bases[p3i][p2i][p1i] = - physical_base | 0x5 | (writable ? 0x2 : 0x0) | - (executable ? 0 : 0x8000000000000000); - - if (owned) - process->owned_pages_bitmaps[p3i][p2i][p1i / 8] |= 1 << (p1i % 8); - -} - -void syscall_change_page_permissions(void *vma, int writable, int executable) { - - assert(running_thread != 0) - - if (((uint64_t)vma & 0xfff) != 0 || (uint64_t)vma >= 0x0000008000000000 || vma == 0 || - writable < 0 || writable > 1 || executable < 0 || executable > 1) - syscall_illegal_args(); - - int p1i, p2i, p3i; - get_page_table_entry( - running_thread->process, vma, &p1i, &p2i, &p3i); - - uint64_t *entry = &running_thread->process->p1_virtual_bases[p3i][p2i][p1i]; - - if (!(*entry & 0x1)) - syscall_illegal_args(); - - *entry = - (*entry & 0x7ffffffffffffffd) | - (executable ? 0 : 0x8000000000000000) | - (writable ? 0x2 : 0x0); - -} - -void create_guard_page_for_process(struct process *process, void *virtual_base) { - - int p1i, p2i, p3i; - get_page_table_entry(process, virtual_base, &p1i, &p2i, &p3i); - - assert(process->p1_virtual_bases[p3i][p2i][p1i] == 0) - - process->p1_virtual_bases[p3i][p2i][p1i] = 0x6; - -} - -void unmap_page_for_process( - struct process *process, void *virtual_base) { - - uint64_t vma = (uint64_t)virtual_base; - assert(vma % 4096 == 0) - assert(vma != 0) - assert(vma < 0x0000008000000000) - - int p1i = (vma >> 12) & 0x1ff; - int p2i = (vma >> 21) & 0x1ff; - int p3i = (vma >> 30) & 0x1ff; - - assert( - process->p1_virtual_bases[p3i] && - process->p1_virtual_bases[p3i][p2i] && - process->p1_virtual_bases[p3i][p2i][p1i]) - - if (process->owned_pages_bitmaps[p3i][p2i][p1i / 8] & (1 << (p1i % 8))) { - process->owned_pages_bitmaps[p3i][p2i][p1i / 8] &= ~(1 << (p1i % 8)); - uint64_t pma = process->p1_virtual_bases[p3i][p2i][p1i] & 0x7ffffffffffff000; - mark_physical_memory_free(pma, 4096); - } - - process->p1_virtual_bases[p3i][p2i][p1i] = 0; - -} - -static int is_mapped_with_flags(struct process *process, const void *start, uint64_t length, uint64_t flags) { - - uint64_t vma_start = (uint64_t)start; - uint64_t vma_end = vma_start + length; - vma_start = (vma_start / 4096) * 4096; - vma_end = ((vma_end - 1) / 4096 + 1) * 4096; - - for (uint64_t vma = vma_start; vma < vma_end; vma += 4096) { - - if (vma == 0 || vma >= 0x0000008000000000) - return 0; - - int p1i = (vma >> 12) & 0x1ff; - int p2i = (vma >> 21) & 0x1ff; - int p3i = (vma >> 30) & 0x1ff; - - if (!process->p1_virtual_bases[p3i] || - !process->p1_virtual_bases[p3i][p2i] || - !process->p1_virtual_bases[p3i][p2i][p1i] || - (process->p1_virtual_bases[p3i][p2i][p1i] & flags) != flags) - return 0; - - } - - return 1; - -} - -int is_mapped_writable(struct process *process, const void *start, uint64_t length) { - return is_mapped_with_flags(process, start, length, 0x7); -} - -int is_mapped_readable(struct process *process, const void *start, uint64_t length) { - return is_mapped_with_flags(process, start, length, 0x5); -} - -int is_mapped_readable_string(struct process *process, const char *start) { - - if (!is_mapped_readable(process, start, 1)) - return 0; - - while (1) { - if ((uint64_t)start % 4096 == 0) - if (!is_mapped_readable(process, start, 1)) - return 0; - if (*start == 0) - return 1; - ++start; - } - -} - -void *find_free_process_region( - struct process *process, uint64_t page_count) { - - uint64_t start = 512 * 512 * 4096; - uint64_t length = 0; - - while (1) { - - if (length >= page_count * 4096) - break; - - uint64_t vma = start + length; - if (vma >= 0x0000008000000000) - goto no_mem; - - int p1i = (vma >> 12) & 0x1ff; - int p2i = (vma >> 21) & 0x1ff; - int p3i = (vma >> 30) & 0x1ff; - - if (p2i == 0 && p1i == 0 && process->p2_virtual_bases[p3i] == 0) { - length += 512 * 512 * 4096; - continue; - } - - if (p1i == 0 && process->p1_virtual_bases[p3i][p2i] == 0) { - length += 512 * 4096; - continue; - } - - if (process->p1_virtual_bases[p3i][p2i][p1i] == 0) { - length += 4096; - continue; - } - - start = start + length + 4096; - length = 0; - - } - - return (void *)start; - -no_mem: - panic("process out of virtual memory") - -} - -int load_elf( - struct process *process, uint64_t *entry_out, - const struct fs_info *fs_info, void *fs_node) { - - struct fs_stat stat; - if ((*fs_info->stat_file)(fs_info, fs_node, &stat) != FAR_SUCCESS) - return 0; - - if (stat.bytes < 58) - return 0; - - uint8_t head_part[34]; - if ((*fs_info->read_file)(fs_info, fs_node, head_part, 24, 34) != FAR_SUCCESS) - return 0; - - *entry_out = *(uint64_t *)head_part; - - uint64_t phead_start = *(uint64_t *)(head_part + 8); - uint16_t phead_entry_size = *(uint16_t *)(head_part + 30); - uint16_t phead_entry_count = *(uint16_t *)(head_part + 32); - - if (stat.bytes < phead_start + phead_entry_count * phead_entry_size) - panic("malformed elf") - - for (uint16_t i = 0; i < phead_entry_count; ++i) { - - uint64_t entry[6]; - if ((*fs_info->read_file)( - fs_info, fs_node, entry, - phead_start + i * phead_entry_size, - 6 * sizeof(uint64_t)) != FAR_SUCCESS) - return 0; - - if ((entry[0] & 0xffffffff) != 1) - continue; - - int executable = (entry[0] >> 32) & 0x1; - int writable = (entry[0] >> 33) & 0x1; - - uint64_t file_start = entry[1]; - void *virtual_start = (void *)entry[2]; - uint64_t file_length = entry[4]; - uint64_t virtual_length = ((entry[5] - 1) / 4096 + 1) * 4096; - - if (stat.bytes < file_start + file_length) - return 0; - if (file_length > virtual_length) - return 0; - - if ((uint64_t)virtual_start % 4096 != 0 || virtual_length % 4096 != 0) - return 0; - - for (uint64_t i = 0; i < virtual_length; i += 4096) { - - uint64_t pma = take_free_physical_page(); - map_page_for_process( - process, pma, virtual_start + i, writable, executable, 1); - - void *kvma = find_free_kernel_region(4096); - map_in_kernel_page_table(pma, kvma, 1, 0); - - if (i + 4096 <= file_length) { - if ((*fs_info->read_file)( - fs_info, fs_node, kvma, - file_start + i, 4096) != FAR_SUCCESS) - return 0; - } - else if (i >= file_length) - memzero(kvma, 4096); - else { - if ((*fs_info->read_file)( - fs_info, fs_node, kvma, - file_start + i, - file_length & 0xfff) != FAR_SUCCESS) - return 0; - memzero(kvma + (file_length & 0xfff), 4096 - (file_length & 0xfff)); - } - - unmap_kernel_page(kvma); - - } - - } - - return 1; - -} - -//defined in process.asm. enters user mode with: -// cr3 = value of rbp when we jump here -// rsp = value of rsp when we jump here -// rip = rcx = value of r12 when we jump here -// rflags = r11 = 0x200 (IF) -// rdi = value of r13 when we jump here -// all other registers zeroed -extern uint8_t thread_start; - -//returns 0 on failure -struct process *start_elf(const char *uri) { - - struct process *process = heap_alloc(sizeof(struct process)); - create_process(process); - debug_log("new process") - debug_log(" path %s", uri) - debug_log(" process struct 0x%h", process, 16) - - const struct fs_info *fs_info; - void *fs_node; - uint64_t entry; - - if (look_up_file(uri, &fs_info, &fs_node) != FAR_SUCCESS || - !load_elf(process, &entry, fs_info, fs_node)) { - destroy_process(process); - return 0; - } - - if ((*fs_info->free_node)(fs_info, fs_node) != FAR_SUCCESS) - panic("TODO") - - struct thread *thread = heap_alloc(sizeof(struct thread)); - create_thread(process, thread); - - struct continuation_info ci; - ci.rip = (uint64_t)&thread_start; - ci.rbp = thread->process->p4_physical_base; - ci.rsp = (uint64_t)thread->stack_top; - ci.r12 = entry; - ci.r13 = 0; - ci.running_thread = thread; - - add_to_queue(&ready_continuations, &ci); - - return process; - -} - -void syscall_create_thread(void (*f)(uint64_t), uint64_t x) { - - assert(running_thread != 0) - - struct thread *thread = heap_alloc(sizeof(struct thread)); - create_thread(running_thread->process, thread); - - struct continuation_info ci; - ci.rip = (uint64_t)&thread_start; - ci.rbp = thread->process->p4_physical_base; - ci.rsp = (uint64_t)thread->stack_top; - ci.r12 = (uint64_t)f; - ci.r13 = x; - ci.running_thread = thread; - - add_to_queue(&ready_continuations, &ci); - -} - -int syscall_start_elf(const char *path, const struct process_start_info *info) { - - assert(running_thread != 0) - - if (!is_mapped_readable_string(running_thread->process, path) || - !is_mapped_readable( - running_thread->process, info, sizeof(struct process_start_info)) || - !is_mapped_readable( - running_thread->process, - info->forwared_envvars, - info->forwared_envvar_count * sizeof(const char *)) || - !is_mapped_readable( - running_thread->process, - info->set_envvars, - 2 * info->set_envvar_count * sizeof(const char *))) - syscall_illegal_args(); - - for (int i = 0; i < info->forwared_envvar_count; ++i) - if (!is_mapped_readable_string(running_thread->process, info->forwared_envvars[i])) - syscall_illegal_args(); - - for (int i = 0; i < 2 * info->set_envvar_count; ++i) - if (!is_mapped_readable_string(running_thread->process, info->set_envvars[i])) - syscall_illegal_args(); - - struct process *process = start_elf(path); - if (process == 0) - return 0; - - for (int i = 0; i < info->forwared_envvar_count; ++i) { - struct process_env_pair *pair = get_envvar(running_thread->process, info->forwared_envvars[i]); - if (pair != 0) - set_envvar(process, info->forwared_envvars[i], pair->value); - } - - for (int i = 0; i < info->set_envvar_count; ++i) - set_envvar(process, info->set_envvars[2 * i], info->set_envvars[2 * i + 1]); - - return 1; - -} - -static void destroy_process_file_info(struct process_file_info *info) { - (*info->fs->free_node)(info->fs, info->node); -} - -static void destroy_process_ipc_dgram_handle_info(struct process_ipc_dgram_handle_info *info) { - if (info->is_receiver == 1) - info->box->is_receiver_held = 0; - if (info->box->is_private) { - if (info->box->private_sides == 1) { - destroy_ipc_dgram_box(info->box); - heap_dealloc(info->box, sizeof(struct ipc_dgram_box)); - } - else - --info->box->private_sides; - } -} - -static void destroy_process_mutex_info(struct process_mutex_info *info) { - destroy_queue(&info->waiting_to_acquire); -} - -static void destroy_process_event_info(struct process_event_info *info) { - destroy_queue(&info->waiting_for_signal); -} - -void destroy_process(struct process *process) { - - assert(process->n_threads == 0) - - for_each_handle(&process->file_handles, (void *)&destroy_process_file_info); - for_each_handle(&process->ipc_dgram_handles, (void *)&destroy_process_ipc_dgram_handle_info); - for_each_handle(&process->mutex_handles, (void *)&destroy_process_mutex_info); - for_each_handle(&process->event_handles, (void *)&destroy_process_event_info); - - destroy_handle_list(&process->file_handles); - destroy_handle_list(&process->ipc_dgram_handles); - destroy_handle_list(&process->mutex_handles); - destroy_handle_list(&process->event_handles); - - if (process->env_pairs) { - for (int i = 0; i < process->env_pairs_buffer_size; ++i) - if (process->env_pairs[i].key_length != 0) { - heap_dealloc(process->env_pairs[i].key, process->env_pairs[i].key_length + 1); - heap_dealloc(process->env_pairs[i].value, process->env_pairs[i].value_length + 1); - } - heap_dealloc( - process->env_pairs, process->env_pairs_buffer_size * sizeof(struct process_env_pair)); - } - - for (int p3i = 0; p3i < 512; ++p3i) - if (process->p3_virtual_base[p3i]) { - for (int p2i = 0; p2i < 512; ++p2i) - if (process->p2_virtual_bases[p3i][p2i]) { - for (int p1i = 0; p1i < 512; ++p1i) { - uint64_t pma = - process->p1_virtual_bases[p3i][p2i][p1i] & 0x7ffffffffffff000; - if (process->owned_pages_bitmaps[p3i][p2i][p1i / 8] & (1 << (p1i % 8))) - mark_physical_memory_free(pma, 4096); - } - unmap_and_free_kernel_page(process->p1_virtual_bases[p3i][p2i]); - heap_dealloc(process->owned_pages_bitmaps[p3i][p2i], 64); - } - unmap_and_free_kernel_page(process->p2_virtual_bases[p3i]); - heap_dealloc(process->p1_virtual_bases[p3i], 4096); - heap_dealloc(process->owned_pages_bitmaps[p3i], 4096); - } - unmap_and_free_kernel_page(process->p3_virtual_base); - unmap_and_free_kernel_page(process->p4_virtual_base); - heap_dealloc(process, sizeof(struct process)); - - debug_log("process destroyed") - debug_log(" process struct 0x%h", process, 16) - debug_log(" free physical memory %B", count_free_pram()) - debug_log(" free kernel virtual memory %B", count_free_kernel_vram()) - -} - -void destroy_thread(struct thread *thread) { - - assert(thread->process->n_threads >= 1) - - --thread->process->n_threads; - - unmap_kernel_page(thread->syscall_stack_bottom); - for (void *p = thread->syscall_stack_bottom + 4096; p < thread->syscall_stack_top; p += 4096) - unmap_and_free_kernel_page(p); - - if (thread->process->n_threads == 0) - destroy_process(thread->process); - else - for (void *p = thread->stack_bottom; p < thread->stack_top; p += 4096) - unmap_page_for_process(thread->process, p); - - heap_dealloc(thread, sizeof(struct thread)); - - debug_log("thread destroyed") - debug_log(" thread struct 0x%h", thread, 16) - debug_log(" free physical memory %B", count_free_pram()) - debug_log(" free kernel virtual memory %B", count_free_kernel_vram()) - -} - -#define MAX_STACK_SIZE ((16 << 20) - 4096) -#define INITIAL_STACK_SIZE 16384 - -#define SYSCALL_STACK_SIZE 12288 - -void create_thread(struct process *process, struct thread *thread_out) { - - void *stack_bottom_vma = - find_free_process_region(process, MAX_STACK_SIZE + 4096); - - for (int i = 0; i < MAX_STACK_SIZE - INITIAL_STACK_SIZE + 4096; i += 4096) - create_guard_page_for_process(process, stack_bottom_vma + i); - - for (int i = MAX_STACK_SIZE - INITIAL_STACK_SIZE + 4096; i < MAX_STACK_SIZE + 4096; i += 4096) { - - uint64_t pma = take_free_physical_page(); - map_page_for_process( - process, pma, - stack_bottom_vma + i, - 1, 0, 1); - - void *kvma = find_free_kernel_region(4096); - map_in_kernel_page_table(pma, kvma, 1, 0); - memzero(kvma, 4096); - unmap_kernel_page(kvma); - - } - - void *syscall_stack_bottom = find_free_kernel_region(SYSCALL_STACK_SIZE + 4096); - - create_kernel_guard_page(syscall_stack_bottom); - - for (int i = 4096; i < 4096 + SYSCALL_STACK_SIZE; i += 4096) { - uint64_t pma = take_free_physical_page(); - map_in_kernel_page_table( - pma, syscall_stack_bottom + i, 1, 0); - } - - thread_out->process = process; - thread_out->stack_bottom = stack_bottom_vma; - thread_out->stack_top = stack_bottom_vma + 4096 + MAX_STACK_SIZE; - thread_out->syscall_stack_bottom = syscall_stack_bottom; - thread_out->syscall_stack_top = syscall_stack_bottom + 4096 + SYSCALL_STACK_SIZE; - - ++process->n_threads; - - debug_log("new thread") - debug_log(" process struct 0x%h", process, 16) - debug_log(" thread struct 0x%h", thread_out, 16) - debug_log(" free physical memory %B", count_free_pram()) - debug_log(" free kernel virtual memory %B", count_free_kernel_vram()) - -} - -[[noreturn]] void syscall_illegal_args() { - panic("bad syscall") -} - -struct thread *running_thread = 0; - -//defined in process.asm. -//function should not return. -[[noreturn]] void with_temporary_stack(void (*function)()); - -[[noreturn]] static void syscall_end_thread_with_temporary_stack() { - - assert(running_thread != 0) - - struct thread *the_thread = running_thread; - running_thread = 0; - - destroy_thread(the_thread); - resume_next_continuation(); - -} - -[[noreturn]] void syscall_end_thread() { - with_temporary_stack(&syscall_end_thread_with_temporary_stack); -} - -void syscall_map_framebuffer(struct framebuffer_info *info_out) { - - assert(running_thread != 0) - - if (!is_mapped_writable( - running_thread->process, - info_out, sizeof(struct framebuffer_info))) - syscall_illegal_args(); - - uint64_t pages_needed = (fb_pitch * fb_height - 1) / 4096 + 1; - - void *base = find_free_process_region(running_thread->process, pages_needed); - - for (uint64_t i = 0; i < pages_needed; ++i) - map_page_for_process( - running_thread->process, - fb_physical_base + i * 4096, - base + i * 4096, 1, 0, 0); - - info_out->fb_base = base; - info_out->fb_pitch = fb_pitch; - info_out->fb_height = fb_height; - info_out->fb_width = fb_width; - -} - -enum fs_access_result syscall_open_file(const char *path, file_handle_t *handle_out) { - - assert(running_thread != 0) - - if (!is_mapped_readable_string(running_thread->process, path) || - !is_mapped_writable(running_thread->process, handle_out, sizeof(file_handle_t))) - syscall_illegal_args(); - - const struct fs_info *fs; - void *node; - enum fs_access_result result = look_up_file(path, &fs, &node); - if (result != FAR_SUCCESS) - return result; - - struct fs_stat stat; - result = (*fs->stat_file)(fs, node, &stat); - if (result != FAR_SUCCESS) { - (*fs->free_node)(fs, node); - return result; - } - - struct process_file_info *info = add_handle(&running_thread->process->file_handles, handle_out); - info->fs = fs; - info->node = node; - memcpy(&info->stat, &stat, sizeof(struct fs_stat)); - return FAR_SUCCESS; - -} - -void syscall_close_file(file_handle_t handle) { - - assert(running_thread != 0) - - struct process_file_info *file = look_up_handle(&running_thread->process->file_handles, handle); - if (file != 0) { - (*file->fs->free_node)(file->fs, file->node); - file->fs = 0; - } - -} - -enum fs_access_result syscall_get_file_size(file_handle_t handle, uint64_t *bytes_out) { - - assert(running_thread != 0) - - struct process_file_info *file = look_up_handle(&running_thread->process->file_handles, handle); - if (file == 0) - return FAR_BAD_HANDLE; - - *bytes_out = file->stat.bytes; - return FAR_SUCCESS; - -} - -enum fs_access_result syscall_read_file(struct read_file_parameter *parameter) { - - assert(running_thread != 0) - - if (!is_mapped_readable( - running_thread->process, parameter, sizeof(struct read_file_parameter)) || - !is_mapped_writable( - running_thread->process, parameter->buffer, parameter->bytes)) - syscall_illegal_args(); - - struct process_file_info *file = - look_up_handle(&running_thread->process->file_handles, parameter->handle); - - if (file == 0) - return FAR_BAD_HANDLE; - - if (parameter->start + parameter->bytes > file->stat.bytes) - return FAR_OUT_OF_BOUNDS; - - return (*file->fs->read_file)(file->fs, file->node, parameter->buffer, parameter->start, parameter->bytes); - -} - -void *syscall_map_pages(uint64_t count) { - - assert(running_thread != 0) - - void *vma = find_free_process_region(running_thread->process, count); - for (uint64_t i = 0; i < count; ++i) { - uint64_t pma = take_free_physical_page(); - map_page_for_process( - running_thread->process, - pma, vma + i * 4096, - 1, 0, 1); - } - - return vma; - -} - -enum ipc_dgram_result syscall_ipc_create_dgram_receiver( - const char *address, ipc_dgram_receiver_handle_t *handle_out) { - - assert(running_thread != 0) - - if (!is_mapped_readable_string(running_thread->process, address) || - !is_mapped_writable( - running_thread->process, handle_out, sizeof(ipc_dgram_receiver_handle_t))) - syscall_illegal_args(); - - struct ipc_dgram_box *box = get_ipc_dgram_box(address); - if (box->is_receiver_held) - return IPR_IN_USE; - - box->is_receiver_held = 1; - - struct process_ipc_dgram_handle_info *info = - add_handle(&running_thread->process->ipc_dgram_handles, handle_out); - info->box = box; - info->is_receiver = 1; - return IPR_SUCCESS; - -} - -enum ipc_dgram_result syscall_ipc_create_dgram_sender( - const char *address, ipc_dgram_sender_handle_t *handle_out) { - - assert(running_thread != 0) - - if (!is_mapped_readable_string(running_thread->process, address) || - !is_mapped_writable( - running_thread->process, handle_out, sizeof(ipc_dgram_receiver_handle_t))) - syscall_illegal_args(); - - struct ipc_dgram_box *box = get_ipc_dgram_box(address); - - struct process_ipc_dgram_handle_info *info = - add_handle(&running_thread->process->ipc_dgram_handles, handle_out); - info->box = box; - info->is_receiver = 0; - return IPR_SUCCESS; - -} - -enum ipc_dgram_result syscall_ipc_receive_dgram( - ipc_dgram_receiver_handle_t handle, void *buffer, int *bytes) { - - assert(running_thread != 0) - - if (!is_mapped_writable(running_thread->process, bytes, sizeof(int)) || - !is_mapped_writable(running_thread->process, buffer, *bytes)) - syscall_illegal_args(); - - struct process_ipc_dgram_handle_info *info = - look_up_handle(&running_thread->process->ipc_dgram_handles, handle); - - if (info == 0 || info->is_receiver != 1) - return IPR_BAD_HANDLE; - - int actual_bytes = get_ipc_dgram_size(info->box); - assert(actual_bytes > 0); - - if (actual_bytes > *bytes) { - *bytes = actual_bytes; - return IPR_TOO_BIG; - } - - receive_ipc_dgram(info->box, buffer); - *bytes = actual_bytes; - return IPR_SUCCESS; - -} - -enum ipc_dgram_result syscall_ipc_send_dgram( - ipc_dgram_sender_handle_t handle, const void *data, int bytes) { - - assert(running_thread != 0) - - if (bytes <= 0 || !is_mapped_readable(running_thread->process, data, bytes)) - syscall_illegal_args(); - - struct process_ipc_dgram_handle_info *info = - look_up_handle(&running_thread->process->ipc_dgram_handles, handle); - - if (info == 0 || info->is_receiver != 0) - return IPR_BAD_HANDLE; - - return send_ipc_dgram(info->box, data, bytes); - -} - -#define INITIAL_ENVVAR_BUFFER_SIZE 32 - -void set_envvar(struct process *process, const char *key, const char *value) { - - if (!process->env_pairs) { - process->env_pairs = heap_alloc(INITIAL_ENVVAR_BUFFER_SIZE * sizeof(struct process_env_pair)); - process->env_pairs_buffer_size = INITIAL_ENVVAR_BUFFER_SIZE; - for (int i = 0; i < INITIAL_ENVVAR_BUFFER_SIZE; ++i) - process->env_pairs[i].key_length = 0; - } - - int key_length = 0; - while (key[key_length] != 0) - ++key_length; - - int value_length = 0; - while (value[value_length] != 0) - ++value_length; - - assert(key_length != 0) - assert(value_length != 0) - - for (int i = 0; i < process->env_pairs_buffer_size; ++i) { - if (process->env_pairs[i].key_length != key_length) - continue; - for (int j = 0; j < key_length; ++j) - if (process->env_pairs[i].key[j] != key[j]) - continue; - heap_dealloc(process->env_pairs[i].value, process->env_pairs[i].value_length + 1); - char *value_copy = heap_alloc(value_length + 1); - memcpy(value_copy, value, value_length + 1); - process->env_pairs[i].value = value_copy; - process->env_pairs[i].value_length = value_length; - return; - } - - struct process_env_pair *pair; - for (int i = 0; i < process->env_pairs_buffer_size; ++i) - if (process->env_pairs[i].key_length == 0) { - pair = &process->env_pairs[i]; - goto got_pair; - } - - double_buffer_zero( - (void **)&process->env_pairs, - &process->env_pairs_buffer_size, - sizeof(struct process_env_pair)); - - pair = &process->env_pairs[process->env_pairs_buffer_size / 2]; - -got_pair: - char *key_copy = heap_alloc(key_length + 1); - memcpy(key_copy, key, key_length + 1); - pair->key = key_copy; - pair->key_length = key_length; - char *value_copy = heap_alloc(value_length + 1); - memcpy(value_copy, value, value_length + 1); - pair->value = value_copy; - pair->value_length = value_length; - -} - -struct process_env_pair *get_envvar(struct process *process, const char *key) { - - int key_length = 0; - while (key[key_length] != 0) - ++key_length; - - assert(key_length > 0) - - for (int i = 0; i < process->env_pairs_buffer_size; ++i) { - if (process->env_pairs[i].key_length != key_length) - continue; - for (int j = 0; j < key_length; ++j) - if (process->env_pairs[i].key[j] != key[j]) - continue; - return &process->env_pairs[i]; - } - - return 0; - -} - -void syscall_get_envvar(const char *key, char *value_out, int *value_space) { - - assert(running_thread != 0) - - if (!is_mapped_readable_string(running_thread->process, key) || - !is_mapped_writable(running_thread->process, value_space, sizeof(int)) || - *value_space <= 0 || - !is_mapped_writable(running_thread->process, value_out, *value_space)) - syscall_illegal_args(); - - struct process_env_pair *pair = get_envvar(running_thread->process, key); - - if (pair == 0) { - *value_space = 0; - return; - } - - if (*value_space < pair->value_length + 1) { - *value_space = pair->value_length + 1; - return; - } - - *value_space = pair->value_length + 1; - memcpy(value_out, pair->value, pair->value_length + 1); - -} - -mutex_handle_t syscall_create_mutex() { - - assert(running_thread != 0) - - mutex_handle_t handle; - struct process_mutex_info *info = - add_handle(&running_thread->process->mutex_handles, &handle); - - info->is_acquired = 0; - create_queue(&info->waiting_to_acquire, 4); - - return handle; - -} - -void syscall_acquire_mutex(mutex_handle_t handle) { - - assert(running_thread != 0) - - struct process_mutex_info *info = look_up_handle(&running_thread->process->mutex_handles, handle); - if (info == 0) - syscall_illegal_args(); - - while (info->is_acquired == 1) - yield_to_queue(&info->waiting_to_acquire); - - info->is_acquired = 1; - -} - -void syscall_release_mutex(mutex_handle_t handle) { - - assert(running_thread != 0) - - struct process_mutex_info *info = look_up_handle(&running_thread->process->mutex_handles, handle); - if (info == 0 || info->is_acquired == 0) - syscall_illegal_args(); - - info->is_acquired = 0; - - struct continuation_info ci; - if (take_from_queue(&info->waiting_to_acquire, &ci)) - add_to_queue(&ready_continuations, &ci); - -} - -event_handle_t syscall_create_event() { - - assert(running_thread != 0) - - event_handle_t handle; - struct process_event_info *info = - add_handle(&running_thread->process->event_handles, &handle); - - info->is_signaled = 0; - create_queue(&info->waiting_for_signal, 4); - - return handle; - -} - -void syscall_signal_event(event_handle_t handle) { - - assert(running_thread != 0) - - struct process_event_info *info = look_up_handle(&running_thread->process->event_handles, handle); - if (info == 0) - syscall_illegal_args(); - - if (info->is_signaled == 1) - return; - - int resumed_any = 0; - - struct continuation_info ci; - while (take_from_queue(&info->waiting_for_signal, &ci)) { - add_to_queue(&ready_continuations, &ci); - resumed_any = 1; - } - - if (resumed_any == 0) - info->is_signaled = 1; - -} - -void syscall_wait_event(event_handle_t handle) { - - assert(running_thread != 0) - - struct process_event_info *info = look_up_handle(&running_thread->process->event_handles, handle); - if (info == 0) - syscall_illegal_args(); - - if (info->is_signaled == 1) { - info->is_signaled = 0; - return; - } - - yield_to_queue(&info->waiting_for_signal); - -} diff --git a/src/kernel/process.h b/src/kernel/process.h deleted file mode 100644 index 20aa9bc..0000000 --- a/src/kernel/process.h +++ /dev/null @@ -1,205 +0,0 @@ -/* Calcite, src/kernel/process.h - * Copyright 2025-2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -#include "scheduler.h" -#include "utility.h" -#include "fs.h" - -#include -#include -#include -#include -#include - -struct ipc_dgram_box; - -struct process_file_info { - const struct fs_info *fs; - void *node; - struct fs_stat stat; -}; - -struct process_ipc_dgram_handle_info { - struct ipc_dgram_box *box; - //1 if this is a receiver handle, 0 if this is a sender handle. - int is_receiver; -}; - -struct process_mutex_info { - int is_acquired; - struct continuation_queue waiting_to_acquire; -}; - -struct process_event_info { - int is_signaled; - struct continuation_queue waiting_for_signal; -}; - -//lengths don't include null terminators, buffers do. -//key and value should not be empty. -struct process_env_pair { - //0 for unused - int key_length; - int value_length; - char *key; - char *value; -}; - -//layout used in scheduler.asm -struct process { - - uint64_t p4_physical_base; - uint64_t *p4_virtual_base; - uint64_t p3_physical_base; - uint64_t *p3_virtual_base; - - int n_threads; - - struct handle_list file_handles; - struct handle_list ipc_dgram_handles; - struct handle_list mutex_handles; - struct handle_list event_handles; - - struct process_env_pair *env_pairs; - int env_pairs_buffer_size; - - //0 for missing levels. just bottom p3 of address space. - uint64_t *p2_virtual_bases[512]; - uint64_t **p1_virtual_bases[512]; - - //also just bottom p3. bit set indicates we should free - //the physical page when we clean up this process. - uint8_t **owned_pages_bitmaps[512]; - -}; - -//layout used in syscalls.asm and scheduler.asm -struct thread { - - struct process *process; - - //both page-aligned - void *stack_bottom; - void *stack_top; - - //both page-aligned - void *syscall_stack_bottom; - void *syscall_stack_top; - -}; - -extern struct thread *running_thread; - -void create_process(struct process *process_out); -void create_thread(struct process *process, struct thread *thread_out); - -//physical and virtual bases must be page-aligned. -//virtual base must be in bottom p3 and not zero. -void map_page_for_process( - struct process *process, uint64_t physical_base, - void *virtual_base, int writable, int executable, int owned); - -//physical and virtual bases must be page-aligned. -void create_guard_page_for_process(struct process *process, void *virtual_base); - -//virtual base must be page-aligned, in bottom p3, and not zero. -//also frees physical page if owned by process. -void unmap_page_for_process( - struct process *process, void *virtual_base); - -//finds a free memory region in the bottom p3 -//of the address space, and not the bottom p2. -void *find_free_process_region( - struct process *process, uint64_t page_count); - -//returns 0 on failure, 1 on success. -int load_elf( - struct process *process, uint64_t *entry_out, - const struct fs_info *fs_info, void *fs_node); - -//returns 0 on failure. -//creates a process and a thread in that process, loads the elf into the process, -//and schedules a ready task that sets the running thread to the new thread and -//starts user mode at the elf's entry point. -struct process *start_elf(const char *uri); - -int syscall_start_elf(const char *path, const struct process_start_info *info); - -void destroy_process(struct process *process); -//must not be called with syscall stack of the thread being destroyed -void destroy_thread(struct thread *thread); - -[[noreturn]] void syscall_illegal_args(); - -//returs 1 if [start, start + length) is writable by process, otherwise 0. -int is_mapped_writable(struct process *process, const void *start, uint64_t length); - -//returs 1 if [start, start + length) is readable by process, otherwise 0. -int is_mapped_readable(struct process *process, const void *start, uint64_t length); - -//return 1 if the entire null-terminated string starting at start is readable by process, otherwise 0. -int is_mapped_readable_string(struct process *process, const char *start); - -[[noreturn]] void syscall_end_thread(); - -void syscall_map_framebuffer(struct framebuffer_info *info_out); - -enum fs_access_result syscall_open_file(const char *path, file_handle_t *handle_out); -void syscall_close_file(file_handle_t handle); -enum fs_access_result syscall_get_file_size(file_handle_t handle, uint64_t *bytes_out); -enum fs_access_result syscall_read_file(struct read_file_parameter *parameter); - -void *syscall_map_pages(uint64_t count); - -void syscall_change_page_permissions(void *vma, int writable, int executable); - -enum ipc_dgram_result syscall_ipc_create_dgram_receiver( - const char *address, ipc_dgram_receiver_handle_t *handle_out); - -enum ipc_dgram_result syscall_ipc_create_dgram_sender( - const char *address, ipc_dgram_sender_handle_t *handle_out); - -//on entry, bytes is maximum accepted packet length. -//on exit, if result was IPR_SUCCESS or IPR_TOO_BIG, bytes is actual packet length. -//actual packet length will always be positive. -enum ipc_dgram_result syscall_ipc_receive_dgram( - ipc_dgram_receiver_handle_t handle, void *buffer, int *bytes); - -//bytes must be positive. -enum ipc_dgram_result syscall_ipc_send_dgram( - ipc_dgram_sender_handle_t handle, const void *data, int bytes); - -//f should not return. -void syscall_create_thread(void (*f)(uint64_t x), uint64_t x); - -void set_envvar(struct process *process, const char *key, const char *value); - -//0 if unset -struct process_env_pair *get_envvar(struct process *process, const char *key); - -//see comment in include/calcite/syscalls.h -void syscall_get_envvar(const char *key, char *value_out, int *value_space); - -mutex_handle_t syscall_create_mutex(); -void syscall_acquire_mutex(mutex_handle_t handle); -void syscall_release_mutex(mutex_handle_t handle); - -event_handle_t syscall_create_event(); -void syscall_signal_event(event_handle_t handle); -void syscall_wait_event(event_handle_t handle); diff --git a/src/kernel/ps2.asm b/src/kernel/ps2.asm deleted file mode 100644 index 48b2078..0000000 --- a/src/kernel/ps2.asm +++ /dev/null @@ -1,71 +0,0 @@ - ; Calcite, src/kernel/ps2.asm - ; Copyright 2025 Benji Dial - ; - ; This program is free software: you can redistribute it and/or modify - ; it under the terms of the GNU General Public License as published by - ; the Free Software Foundation, either version 3 of the License, or - ; (at your option) any later version. - ; - ; This program is distributed in the hope that it will be useful, but - ; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - ; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - ; for more details. - ; - ; You should have received a copy of the GNU General Public License along - ; with this program. If not, see . - - -bits 64 -default rel - -section .text - -global init_ps2 -init_ps2: - mov al, 0x60 - out 0x64, al - -.wait_ready: - in al, 0x64 - test al, 0x02 - jnz .wait_ready - - mov al, 0x07 - out 0x60, al - - mov al, 0xd4 - out 0x64, al - -.wait_ready_2: - in al, 0x64 - test al, 0x02 - jnz .wait_ready_2 - - mov al, 0xf4 - out 0x60, al - -.wait_ready_3: - in al, 0x64 - test al, 0x01 - jz .wait_ready_3 - - in al, 0x60 - ret - -;referenced in ps2.c -;return type is int -;returns -1 if no byte available -global read_ps2_byte -read_ps2_byte: - - in al, 0x64 - test al, 0x01 - jz .no_data - - xor eax, eax - in al, 0x60 - ret - -.no_data: - mov eax, -1 - ret diff --git a/src/kernel/ps2.c b/src/kernel/ps2.c deleted file mode 100644 index 5abe7c8..0000000 --- a/src/kernel/ps2.c +++ /dev/null @@ -1,118 +0,0 @@ -/* Calcite, src/kernel/ps2.c - * Copyright 2025-2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "input.h" -#include "ps2.h" - -#include -#include - -//defined in ps2.asm -//returns -1 if no byte available -int read_ps2_byte(); - -static uint8_t keyboard_packet[7]; -static int keyboard_packet_length = 0; - -void on_keyboard_irq() { - - int byte = read_ps2_byte(); - if (byte == -1) - return; - - if (keyboard_packet_length == 0 && byte != 0xe0 && byte != 0xe1 && byte != 0xf0) { - add_keyboard_packet(KEY_FLAG_MAKE | byte); - return; - } - - if (keyboard_packet_length == 1 && keyboard_packet[0] == 0xe0 && byte != 0xf0 && byte != 0x12) { - add_keyboard_packet(KEY_FLAG_MAKE | 0x80 | byte); - keyboard_packet_length = 0; - return; - } - - if (keyboard_packet_length == 1 && keyboard_packet[0] == 0xf0) { - add_keyboard_packet(byte); - keyboard_packet_length = 0; - return; - } - - if (keyboard_packet_length == 2 && keyboard_packet[0] == 0xe0 && keyboard_packet[1] == 0xf0 && byte != 0x7c) { - add_keyboard_packet(0x80 | byte); - keyboard_packet_length = 0; - return; - } - - if (keyboard_packet_length == 3 && keyboard_packet[0] == 0xe0 && keyboard_packet[1] == 0x12 && - keyboard_packet[2] == 0xe0 && byte == 0x7c) { - add_keyboard_packet(KEY_FLAG_MAKE | KEY_PRINT_SCREEN); - keyboard_packet_length = 0; - return; - } - - if (keyboard_packet_length == 5 && keyboard_packet[0] == 0xe0 && keyboard_packet[1] == 0xf0 && - keyboard_packet[2] == 0x7c && keyboard_packet[3] == 0xe0 && keyboard_packet[4] == 0xf0 && byte == 0x12) { - add_keyboard_packet(KEY_PRINT_SCREEN); - keyboard_packet_length = 0; - return; - } - - if (keyboard_packet_length == 7 && keyboard_packet[0] == 0xe1 && keyboard_packet[1] == 0x14 && - keyboard_packet[2] == 0x77 && keyboard_packet[3] == 0xe1 && keyboard_packet[4] == 0xf0 && - keyboard_packet[5] == 0x14 && keyboard_packet[6] == 0xf0 && byte == 0x77) { - add_keyboard_packet(KEY_FLAG_MAKE | KEY_PAUSE_BREAK); - add_keyboard_packet(KEY_PAUSE_BREAK); - keyboard_packet_length = 0; - return; - } - - if (keyboard_packet_length == 7) { - keyboard_packet_length = 0; - return; - } - - keyboard_packet[keyboard_packet_length++] = byte; - -} - -static uint8_t mouse_packet[3]; -static int mouse_packet_length = 0; - -void on_mouse_irq() { - - int byte = read_ps2_byte(); - if (byte == -1) - return; - - mouse_packet[mouse_packet_length] = byte; - if (mouse_packet_length < 2) { - ++mouse_packet_length; - return; - } - mouse_packet_length = 0; - - int x_change = mouse_packet[1]; - if (mouse_packet[0] & 0x10) - x_change -= 256; - - int y_change = mouse_packet[2]; - if (mouse_packet[0] & 0x20) - y_change -= 256; - - add_mouse_movement(x_change, y_change); - -} diff --git a/src/kernel/ps2.h b/src/kernel/ps2.h deleted file mode 100644 index 235caf2..0000000 --- a/src/kernel/ps2.h +++ /dev/null @@ -1,23 +0,0 @@ -/* Calcite, src/kernel/ps2.h - * Copyright 2025 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -void init_ps2(); - -void on_keyboard_irq(); -void on_mouse_irq(); diff --git a/src/kernel/scheduler.asm b/src/kernel/scheduler.asm deleted file mode 100644 index 61bd1d1..0000000 --- a/src/kernel/scheduler.asm +++ /dev/null @@ -1,82 +0,0 @@ - ; Calcite, src/kernel/scheduler.asm - ; Copyright 2025-2026 Benji Dial - ; - ; This program is free software: you can redistribute it and/or modify - ; it under the terms of the GNU General Public License as published by - ; the Free Software Foundation, either version 3 of the License, or - ; (at your option) any later version. - ; - ; This program is distributed in the hope that it will be useful, but - ; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - ; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - ; for more details. - ; - ; You should have received a copy of the GNU General Public License along - ; with this program. If not, see . - - -bits 64 -default rel - -extern resume_next_continuation -extern running_thread -extern add_to_queue - -;referenced in scheduler.c -global resume_continuation -resume_continuation: - - mov rax, qword [rdi] - mov rbx, qword [rdi + 8] - mov rbp, qword [rdi + 16] - mov rsp, qword [rdi + 24] - mov r12, qword [rdi + 32] - mov r13, qword [rdi + 40] - mov r14, qword [rdi + 48] - mov r15, qword [rdi + 56] - mov rdi, qword [rdi + 64] - mov qword [running_thread], rdi - mov rdi, qword [rdi] - mov rdi, qword [rdi] - mov cr3, rdi - - jmp rax - -global yield -yield: - mov qword [rdi], .ret - mov qword [rdi + 8], rbx - mov qword [rdi + 16], rbp - mov qword [rdi + 24], rsp - mov qword [rdi + 32], r12 - mov qword [rdi + 40], r13 - mov qword [rdi + 48], r14 - mov qword [rdi + 56], r15 - mov qword rsi, qword [running_thread] - mov qword [rdi + 64], rsi - - jmp resume_next_continuation - -.ret: - ret - -global yield_to_queue -yield_to_queue: - mov qword [rsp - 72], .ret - mov qword [rsp - 64], rbx - mov qword [rsp - 56], rbp - mov qword [rsp - 48], rsp - mov qword [rsp - 40], r12 - mov qword [rsp - 32], r13 - mov qword [rsp - 24], r14 - mov qword [rsp - 16], r15 - mov rdx, qword [running_thread] - mov qword [rsp - 8], rdx - - sub rsp, 72 - mov rsi, rsp - call add_to_queue - jmp resume_next_continuation - -.ret: - ret diff --git a/src/kernel/scheduler.c b/src/kernel/scheduler.c deleted file mode 100644 index 1994539..0000000 --- a/src/kernel/scheduler.c +++ /dev/null @@ -1,100 +0,0 @@ -/* Calcite, src/kernel/scheduler.c - * Copyright 2025-2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "scheduler.h" -#include "process.h" -#include "utility.h" -#include "debug.h" -#include "heap.h" - -struct continuation_queue ready_continuations; - -void init_scheduler() { - create_queue(&ready_continuations, 128); -} - -//defined in scheduler.asm -[[noreturn]] void resume_continuation(const struct continuation_info *info); - -[[noreturn]] void resume_next_continuation() { - - running_thread = 0; - - struct continuation_info ci; - while (!take_from_queue(&ready_continuations, &ci)) { - __asm__ ("sti"); - __asm__ ("hlt"); - __asm__ ("cli"); - } - - assert(running_thread == 0) - assert(ci.running_thread != 0) - resume_continuation(&ci); - -} - -void create_queue(struct continuation_queue *queue, int buffer_size) { - queue->cis = heap_alloc(buffer_size * sizeof(struct continuation_info)); - queue->next_read_index = 0; - queue->buffer_size = buffer_size; - queue->count = 0; -} - -void destroy_queue(struct continuation_queue *queue) { - assert(queue->count == 0) - heap_dealloc(queue->cis, queue->buffer_size * sizeof(struct continuation_info)); -} - -void add_to_queue(struct continuation_queue *queue, struct continuation_info *ci) { - - if (queue->count == queue->buffer_size) { - - struct continuation_info *new_buffer = - heap_alloc(2 * queue->buffer_size * sizeof(struct continuation_info)); - - memcpy( - new_buffer, &queue->cis[queue->next_read_index], - (queue->buffer_size - queue->next_read_index) * sizeof(struct continuation_info)); - memcpy( - &new_buffer[queue->buffer_size - queue->next_read_index], - queue->cis, queue->next_read_index * sizeof(struct continuation_info)); - - heap_dealloc(queue->cis, queue->buffer_size * sizeof(struct continuation_info)); - queue->cis = new_buffer; - queue->buffer_size *= 2; - queue->next_read_index = 0; - - } - - memcpy( - &queue->cis[(queue->next_read_index + queue->count) % queue->buffer_size], - ci, sizeof(struct continuation_info)); - ++queue->count; - -} - -int take_from_queue(struct continuation_queue *queue, struct continuation_info *ci) { - - if (queue->count == 0) - return 0; - - memcpy(ci, &queue->cis[queue->next_read_index], sizeof(struct continuation_info)); - queue->next_read_index = (queue->next_read_index + 1) % queue->buffer_size; - --queue->count; - return 1; - -} diff --git a/src/kernel/scheduler.h b/src/kernel/scheduler.h deleted file mode 100644 index 59c3cb6..0000000 --- a/src/kernel/scheduler.h +++ /dev/null @@ -1,64 +0,0 @@ -/* Calcite, src/kernel/scheduler.h - * Copyright 2025-2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -#include - -struct thread; - -//scheduler.asm depends on layout -struct continuation_info { - uint64_t rip; - uint64_t rbx; - uint64_t rbp; - uint64_t rsp; - uint64_t r12; - uint64_t r13; - uint64_t r14; - uint64_t r15; - struct thread *running_thread; -}; - -void init_scheduler(); - -[[noreturn]] void resume_next_continuation(); - -struct continuation_queue { - struct continuation_info *cis; - int next_read_index; - int buffer_size; - int count; -}; - -extern struct continuation_queue ready_continuations; - -void create_queue(struct continuation_queue *queue, int buffer_size); -void destroy_queue(struct continuation_queue *queue); - -//ci is copied. -void add_to_queue(struct continuation_queue *queue, struct continuation_info *ci); - -//if queue is empty, returns 0. otherwise, copies next read to ci, advances read, and returns 1. -int take_from_queue(struct continuation_queue *queue, struct continuation_info *ci); - -//saves a continuation that returns from this function to save_current_continuation_to, then resumes -//the next ready continuation (thus doesn't return until save_current_continuation_to is resumed). -void yield(struct continuation_info *save_current_continuation_to); - -//same as yield, but instead of saving continuation to a pointer, saves it to the end of the queue. -void yield_to_queue(struct continuation_queue *queue); diff --git a/src/kernel/serial.asm b/src/kernel/serial.asm deleted file mode 100644 index a4731dc..0000000 --- a/src/kernel/serial.asm +++ /dev/null @@ -1,73 +0,0 @@ - ; Calcite, src/kernel/serial.asm - ; Copyright 2025 Benji Dial - ; - ; This program is free software: you can redistribute it and/or modify - ; it under the terms of the GNU General Public License as published by - ; the Free Software Foundation, either version 3 of the License, or - ; (at your option) any later version. - ; - ; This program is distributed in the hope that it will be useful, but - ; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - ; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - ; for more details. - ; - ; You should have received a copy of the GNU General Public License along - ; with this program. If not, see . - - -bits 64 -default rel - -section .text - -global init_serial -init_serial: - mov dx, 0x03f9 - mov al, 0x00 - out dx, al - - mov dl, 0xfb - mov al, 0x80 - out dx, al - - mov dl, 0xf8 - mov al, 0x03 - out dx, al - - mov dl, 0xf9 - mov al, 0x00 - out dx, al - - mov dl, 0xfb - mov al, 0x03 - out dx, al - - mov dl, 0xfa - mov al, 0xc7 - out dx, al - - ret - -global write_serial_string_n -write_serial_string_n: - test esi, esi - jz .ret - mov ecx, esi - -.wait_ready: - mov dx, 0x03fd - in al, dx - test al, 0x20 - jnz .ready - pause - jmp .wait_ready - -.ready: - mov dl, 0xf8 - mov al, byte [rdi] - out dx, al - - inc rdi - loop .wait_ready -.ret: - ret diff --git a/src/kernel/serial.c b/src/kernel/serial.c deleted file mode 100644 index 0c9f4de..0000000 --- a/src/kernel/serial.c +++ /dev/null @@ -1,54 +0,0 @@ -/* Calcite, src/kernel/serial.c - * Copyright 2025 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "serial.h" -#include "debug.h" - -void write_serial_string(const char *string) { - int n = 0; - while (string[n] != 0) - ++n; - write_serial_string_n(string, n); -} - -void write_serial_integer(int integer) { - - if (integer == 0) { - write_serial_string_n("0", 1); - return; - } - - char buffer[10]; - char *ptr = &buffer[9]; - - while (integer != 0) { - *ptr = '0' + integer % 10; - integer /= 10; - --ptr; - } - - write_serial_string_n(ptr + 1, (buffer + 10) - (ptr + 1)); - -} - -void write_serial_hex(uint64_t value, int places) { - assert(places <= 16) - char buffer[16]; - for (int i = 0; i < places; ++i) - buffer[i] = "0123456789abcdef"[(value >> (4 * (places - i - 1))) & 0xf]; - write_serial_string_n(buffer, places); -} diff --git a/src/kernel/serial.h b/src/kernel/serial.h deleted file mode 100644 index a70cfdf..0000000 --- a/src/kernel/serial.h +++ /dev/null @@ -1,26 +0,0 @@ -/* Calcite, src/kernel/serial.h - * Copyright 2025 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -#include - -void init_serial(); -void write_serial_string(const char *string); -void write_serial_string_n(const char *string, int n); -void write_serial_integer(int integer); -void write_serial_hex(uint64_t value, int places); diff --git a/src/kernel/syscalls.asm b/src/kernel/syscalls.asm deleted file mode 100644 index a064002..0000000 --- a/src/kernel/syscalls.asm +++ /dev/null @@ -1,87 +0,0 @@ - ; Calcite, src/kernel/syscalls.asm - ; Copyright 2025-2026 Benji Dial - ; - ; This program is free software: you can redistribute it and/or modify - ; it under the terms of the GNU General Public License as published by - ; the Free Software Foundation, either version 3 of the License, or - ; (at your option) any later version. - ; - ; This program is distributed in the hope that it will be useful, but - ; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - ; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - ; for more details. - ; - ; You should have received a copy of the GNU General Public License along - ; with this program. If not, see . - - -bits 64 -default rel - -;defined in syscalls.c -extern syscall_entry_c - -extern running_thread - -section .text - -;system call number is in rax. -;system call arguments are in rdi, rsi, rdx. -;system call returns a value in rax. -;depends on layout of struct thread from process.h -syscall_entry: - mov r8, qword [running_thread] - test r8, r8 - jz .assert_fail - - mov r8, qword [r8 + 32] - mov qword [r8 - 8], rsp - mov rsp, r8 - sub rsp, 8 - push rcx - push r11 - - mov rcx, rax - cli - call syscall_entry_c - sti - - xor rdi, rdi - xor rsi, rsi - xor rdx, rdx - xor r8, r8 - xor r9, r9 - xor r10, r10 - - pop r11 - pop rcx - pop rsp - o64 sysret - -.assert_fail: - ud2 - -global init_syscalls -init_syscalls: - mov ecx, 0xc0000080 - rdmsr - or al, 0x01 - wrmsr - - mov edx, 0x00130028 - xor eax, eax - mov ecx, 0xc0000081 - wrmsr - - mov rdx, syscall_entry - mov eax, edx - shr rdx, 32 - mov ecx, 0xc0000082 - wrmsr - - xor edx, edx - xor eax, eax - mov ecx, 0xc0000084 - wrmsr - - ret diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c deleted file mode 100644 index 8132dfd..0000000 --- a/src/kernel/syscalls.c +++ /dev/null @@ -1,46 +0,0 @@ -/* Calcite, src/kernel/syscalls.c - * Copyright 2025 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "syscalls.h" -#include "debug.h" - -#define MAX_SYSCALL_NUMBER 99 - -static uint64_t (*syscall_handlers[MAX_SYSCALL_NUMBER])( - uint64_t, uint64_t, uint64_t); - -void register_syscall( - int number, - uint64_t (*handler)(uint64_t, uint64_t, uint64_t)) { - - assert(number >= 0 && number <= MAX_SYSCALL_NUMBER) - assert(syscall_handlers[number] == 0) - - syscall_handlers[number] = handler; - -} - -//referenced in syscalls.asm -uint64_t syscall_entry_c( - uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t number) { - - if (number > MAX_SYSCALL_NUMBER || syscall_handlers[number] == 0) - panic("TODO: bad syscall"); - - return (*syscall_handlers[number])(arg1, arg2, arg3); - -} diff --git a/src/kernel/syscalls.h b/src/kernel/syscalls.h deleted file mode 100644 index 3171a7a..0000000 --- a/src/kernel/syscalls.h +++ /dev/null @@ -1,27 +0,0 @@ -/* Calcite, src/kernel/syscalls.h - * Copyright 2025 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -#include -#include - -void init_syscalls(); - -void register_syscall( - int number, - uint64_t (*handler)(uint64_t arg1, uint64_t arg2, uint64_t arg3)); diff --git a/src/kernel/timer.asm b/src/kernel/timer.asm deleted file mode 100644 index 45e1c27..0000000 --- a/src/kernel/timer.asm +++ /dev/null @@ -1,37 +0,0 @@ - ; Calcite, src/kernel/timer.asm - ; Copyright 2025 Benji Dial - ; - ; This program is free software: you can redistribute it and/or modify - ; it under the terms of the GNU General Public License as published by - ; the Free Software Foundation, either version 3 of the License, or - ; (at your option) any later version. - ; - ; This program is distributed in the hope that it will be useful, but - ; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - ; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - ; for more details. - ; - ; You should have received a copy of the GNU General Public License along - ; with this program. If not, see . - - -bits 64 -default rel - -section .text - -global init_timer -init_timer: - - ;generate an irq every 1193 cycles (~ every millisecond) - - mov al, 0x34 - out 0x43, al - - mov al, 0xa9 - out 0x40, al - - mov al, 0x04 - out 0x40, al - - ret diff --git a/src/kernel/timer.c b/src/kernel/timer.c deleted file mode 100644 index 80e7278..0000000 --- a/src/kernel/timer.c +++ /dev/null @@ -1,111 +0,0 @@ -/* Calcite, src/kernel/timer.c - * Copyright 2025-2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "scheduler.h" -#include "timer.h" -#include "heap.h" - -struct sleeping_list_entry { - struct sleeping_list_entry *next; - uint64_t sleeping_until;//pit irqs since boot - struct continuation_info continuation; -}; - -//entries are always sorted increasing by sleeping_until -static struct sleeping_list_entry *first_entry = 0; -static struct sleeping_list_entry *last_entry = 0; - -//pit irq happens ~ once per millisecond -static uint64_t pit_irqs_since_boot = 0; - -static struct sleeping_list_entry *local_sleeping_list_entry_pool = 0; - -void on_pit_irq() { - - ++pit_irqs_since_boot; - - while (first_entry != 0 && pit_irqs_since_boot >= first_entry->sleeping_until) { - - add_to_queue(&ready_continuations, &first_entry->continuation); - - struct sleeping_list_entry *old_first = first_entry; - first_entry = old_first->next; - *(struct sleeping_list_entry **)old_first = local_sleeping_list_entry_pool; - local_sleeping_list_entry_pool = old_first; - - if (first_entry == 0) - last_entry = 0; - - } - -} - -//until in pit irqs since boot. -//must be called with interrupts disabled. -//on return, interrupts are enabled. -static void sleep_until(uint64_t until) { - - struct sleeping_list_entry *entry; - if (local_sleeping_list_entry_pool != 0) { - entry = local_sleeping_list_entry_pool; - local_sleeping_list_entry_pool = *(struct sleeping_list_entry **)entry; - } - else - entry = heap_alloc(sizeof(struct sleeping_list_entry)); - - entry->sleeping_until = until; - - if (first_entry == 0) { - entry->next = 0; - first_entry = entry; - last_entry = entry; - } - - else if (first_entry->sleeping_until >= until) { - entry->next = first_entry; - first_entry = entry; - } - - else if (last_entry->sleeping_until <= until) { - entry->next = 0; - last_entry->next = entry; - last_entry = entry; - } - - else { - struct sleeping_list_entry *just_before = first_entry; - while (just_before->next->sleeping_until <= until) - just_before = just_before->next; - entry->next = just_before->next; - just_before->next = entry; - } - - yield(&entry->continuation); - -} - -void syscall_sleep_ms(uint64_t ms_to_sleep) { - sleep_until(pit_irqs_since_boot + ms_to_sleep); -} - -uint64_t syscall_get_ms_since_boot() { - return pit_irqs_since_boot; -} - -void syscall_sleep_until_ms_since_boot(uint64_t ms) { - sleep_until(ms); -} diff --git a/src/kernel/timer.h b/src/kernel/timer.h deleted file mode 100644 index c4466e2..0000000 --- a/src/kernel/timer.h +++ /dev/null @@ -1,28 +0,0 @@ -/* Calcite, src/kernel/timer.h - * Copyright 2025-2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -#include - -void init_timer(); - -void on_pit_irq(); - -void syscall_sleep_ms(uint64_t ms_to_sleep); -uint64_t syscall_get_ms_since_boot(); -void syscall_sleep_until_ms_since_boot(uint64_t ms); diff --git a/src/kernel/utility.asm b/src/kernel/utility.asm deleted file mode 100644 index a29b82d..0000000 --- a/src/kernel/utility.asm +++ /dev/null @@ -1,62 +0,0 @@ - ; Calcite, src/kernel/utility.asm - ; Copyright 2025 Benji Dial - ; - ; This program is free software: you can redistribute it and/or modify - ; it under the terms of the GNU General Public License as published by - ; the Free Software Foundation, either version 3 of the License, or - ; (at your option) any later version. - ; - ; This program is distributed in the hope that it will be useful, but - ; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - ; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - ; for more details. - ; - ; You should have received a copy of the GNU General Public License along - ; with this program. If not, see . - - -bits 64 -default rel - -section .text - -global memcpy -memcpy: - mov rcx, rdx - rep movsb - ret - -global memzero -memzero: - xor al, al - mov rcx, rsi - rep stosb - ret - -global outb -outb: - mov dx, di - mov al, sil - out dx, al - ret - -global inb -inb: - mov dx, di - in al, dx - ret - -global outsw -outsw: - mov rcx, rdx - mov dx, di - rep outsw - ret - -global insw -insw: - mov rcx, rdx - mov dx, di - mov rdi, rsi - rep insw - ret diff --git a/src/kernel/utility.c b/src/kernel/utility.c deleted file mode 100644 index ed5245e..0000000 --- a/src/kernel/utility.c +++ /dev/null @@ -1,117 +0,0 @@ -/* Calcite, src/kernel/utility.c - * Copyright 2025-2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "utility.h" -#include "heap.h" - -int strequ(const char *str1, const char *str2) { - while (1) { - if (!*str1 && !*str2) - return 1; - if (*str1 != *str2) - return 0; - ++str1; - ++str2; - } -} - -uint32_t end_swap_u32(uint32_t value) { - return - (value >> 24) | - (((value >> 16) & 0xff) << 8) | - (((value >> 8) & 0xff) << 16) | - ((value & 0xff) << 24); -} - -void double_buffer_zero(void **buffer, int *length, uint64_t bytes_per_entry) { - void *new_buffer = heap_alloc(2 * *length * bytes_per_entry); - memcpy(new_buffer, *buffer, *length * bytes_per_entry); - heap_dealloc(*buffer, *length * bytes_per_entry); - memzero(new_buffer + *length * bytes_per_entry, *length * bytes_per_entry); - *buffer = new_buffer; - *length *= 2; -} - -void create_handle_list(struct handle_list *list, uint64_t entry_size) { - list->entry_size = entry_size; - list->buffer = 0; - list->buffer_used_bitmap = 0; - list->buffer_size = 0; -} - -//must be multiple of 8 -#define HANDLE_LIST_INITIAL_SIZE 16 - -void *add_handle(struct handle_list *list, uint64_t *handle_out) { - - if (list->buffer == 0) { - list->buffer = heap_alloc(HANDLE_LIST_INITIAL_SIZE * list->entry_size); - list->buffer_used_bitmap = heap_alloc(HANDLE_LIST_INITIAL_SIZE / 8); - list->buffer_size = HANDLE_LIST_INITIAL_SIZE; - list->buffer_used_bitmap[0] = 1; - memzero(list->buffer_used_bitmap + 1, HANDLE_LIST_INITIAL_SIZE / 8 - 1); - *handle_out = 0; - return list->buffer; - } - - for (uint64_t i = 0; i < list->buffer_size; ++i) - if ((list->buffer_used_bitmap[i / 8] & (1 << (i % 8))) == 0) { - list->buffer_used_bitmap[i / 8] |= (1 << (i % 8)); - *handle_out = i; - return list->buffer + i * list->entry_size; - } - - void *new_buffer = heap_alloc(2 * list->buffer_size * list->entry_size); - uint8_t *new_used_bitmap = heap_alloc(list->buffer_size / 4); - - memcpy(new_buffer, list->buffer, list->buffer_size * list->entry_size); - memcpy(new_used_bitmap, list->buffer_used_bitmap, list->buffer_size / 8); - - heap_dealloc(list->buffer, list->buffer_size * list->entry_size); - heap_dealloc(list->buffer_used_bitmap, list->buffer_size / 8); - - new_used_bitmap[list->buffer_size / 8] = 1; - memzero(new_used_bitmap + list->buffer_size / 8 + 1, list->buffer_size / 8 - 1); - - list->buffer = new_buffer; - list->buffer_used_bitmap = new_used_bitmap; - list->buffer_size *= 2; - - *handle_out = list->buffer_size / 2; - return list->buffer + (list->buffer_size / 2) * list->entry_size; - -} - -void *look_up_handle(struct handle_list *list, uint64_t handle) { - if (list->buffer == 0 || handle >= list->buffer_size || - (list->buffer_used_bitmap[handle / 8] & (1 << (handle % 8))) == 0) - return 0; - return list->buffer + handle * list->entry_size; -} - -void for_each_handle(struct handle_list *list, void (*callback)(void *object)) { - for (uint64_t i = 0; i < list->buffer_size; ++i) - if ((list->buffer_used_bitmap[i / 8] & (1 << (i % 8))) != 0) - (*callback)(list->buffer + i * list->entry_size); -} - -void destroy_handle_list(struct handle_list *list) { - if (list->buffer != 0) { - heap_dealloc(list->buffer, list->buffer_size * list->entry_size); - heap_dealloc(list->buffer_used_bitmap, list->buffer_size / 8); - } -} diff --git a/src/kernel/utility.h b/src/kernel/utility.h deleted file mode 100644 index e9f35b8..0000000 --- a/src/kernel/utility.h +++ /dev/null @@ -1,57 +0,0 @@ -/* Calcite, src/kernel/utility.h - * Copyright 2025-2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -#include - -//returns 1 if equal, 0 if not. -int strequ(const char *str1, const char *str2); - -void memcpy(void *to, const void *from, uint64_t bytes); -void memzero(void *start, uint64_t bytes); - -//swaps the endianness of the value -uint32_t end_swap_u32(uint32_t value); - -//1. allocates a new buffer with 2 * length * bytes_per_entry bytes -//2. copies length * bytes_per_entry bytes from old buffer to new buffer -//3. deallocates old buffer -//4. zeroes rest of new buffer -//5. sets buffer and length to new buffer and twice length -void double_buffer_zero(void **buffer, int *length, uint64_t bytes_per_entry); - -void outb(uint16_t port, uint8_t byte); -uint8_t inb(uint16_t port); -void outsw(uint16_t port, const void *buffer, uint64_t words); -void insw(uint16_t port, void *buffer, uint64_t words); - -struct handle_list { - uint64_t entry_size; - void *buffer; - uint8_t *buffer_used_bitmap; - //in entries, always a multiple of 8 - uint64_t buffer_size; -}; - -void create_handle_list(struct handle_list *list, uint64_t entry_size); -//add to list by calling this and writing into returned object -void *add_handle(struct handle_list *list, uint64_t *handle_out); -//zero if not in list -void *look_up_handle(struct handle_list *list, uint64_t handle); -void for_each_handle(struct handle_list *list, void (*callback)(void *object)); -void destroy_handle_list(struct handle_list *list); diff --git a/src/service/hello/hello.cxx b/src/service/hello/hello.cxx new file mode 100644 index 0000000..330d4d7 --- /dev/null +++ b/src/service/hello/hello.cxx @@ -0,0 +1,22 @@ +/* src/service/hello/hello.cxx + * A temporary dummy service. + * + * Copyright 2026 Benji Dial + * This file is part of the Calcite Operating System. + * + * Calcite is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, version 3 only. + * + * Calcite is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * Calcite. If not, see . + */ + +extern "C" [[noreturn]] void __entry() { + while (true) + ; +} diff --git a/src/user-apps/link.ld b/src/service/link.ld similarity index 80% rename from src/user-apps/link.ld rename to src/service/link.ld index 84c8d32..c8fea08 100644 --- a/src/user-apps/link.ld +++ b/src/service/link.ld @@ -1,7 +1,7 @@ OUTPUT_FORMAT(elf64-x86-64) OUTPUT_ARCH(i386:x86-64) -ENTRY(_start) +ENTRY(__entry) PHDRS { rx PT_LOAD FLAGS(5); @@ -11,29 +11,30 @@ PHDRS { SECTIONS { - . = 0x400000; + . = 0xffffff0000000000; .text : { *(.text .text.*) } : rx - . = ALIGN(4096); .rodata : { *(.rodata .rodata.*) } : ro - . = ALIGN(4096); .data : { *(.data .data.*) } : rw - . = ALIGN(4096); - .bss : { *(.bss .bss.*) *(COMMON) } : rw + . = ALIGN(4096); + + /DISCARD/ : { + *(.eh_frame) + } } diff --git a/src/user-apps/init/init.c b/src/user-apps/init/init.c deleted file mode 100644 index 8f6f280..0000000 --- a/src/user-apps/init/init.c +++ /dev/null @@ -1,75 +0,0 @@ -/* Calcite, src/user-apps/init/init.c - * Copyright 2025-2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include -#include -#include -#include -#include - -#define MAX_LINE_LENGTH 1023 - -void main() { - - struct file_stream *rc; - if (open_file_stream("root://calcite/init.rc", &rc) != FAR_SUCCESS) - return; - - int at_file_end = 0; - - while (!at_file_end) { - - char line[MAX_LINE_LENGTH + 1]; - int line_length = 0; - - while (1) { - - char ch = read_file_stream_byte(rc); - - if (ch == -1) { - at_file_end = 1; - break; - } - if (ch == '\n') - break; - if (line_length == MAX_LINE_LENGTH) { - while (1) { - ch = read_file_stream_byte(rc); - if (ch == -1 || ch == '\n') - break; - } - break; - } - - line[line_length++] = ch; - - } - - if (line_length == 0 || line[0] == '#') - continue; - - line[line_length] = 0; - - struct process_start_info psi; - psi.forwared_envvar_count = 0; - psi.set_envvar_count = 0; - - start_elf(line, &psi); - - } - -} diff --git a/src/user-apps/init/libraries.txt b/src/user-apps/init/libraries.txt deleted file mode 100644 index 8503661..0000000 --- a/src/user-apps/init/libraries.txt +++ /dev/null @@ -1 +0,0 @@ -calcite diff --git a/src/user-apps/shell/assembler.c b/src/user-apps/shell/assembler.c deleted file mode 100644 index b07a602..0000000 --- a/src/user-apps/shell/assembler.c +++ /dev/null @@ -1,218 +0,0 @@ -/* Calcite, src/user-apps/shell/assembler.c - * Copyright 2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "assembler.h" - -#include -#include -#include - -static uint8_t *function_buffer = 0; -static int function_buffer_length; -static int function_buffer_used; - -struct relocation_info { - int offset_into_function; - int from_offset_into_function; - void *to; - struct relocation_info *previous; -}; - -static struct relocation_info *relocations = 0; -static char *function_name = 0; -static int function_name_length; - -struct function_alloc { - void *start; - int bytes; - struct function_alloc *previous; -}; - -static struct function_alloc *allocs = 0; - -#define FUNCTION_BUFFER_INITIAL_SIZE 4096 - -void start_function(const char *name, int name_length) { - - if (function_buffer == 0) { - function_buffer_length = FUNCTION_BUFFER_INITIAL_SIZE; - function_buffer = heap_alloc(function_buffer_length); - } - - function_buffer_used = 0; - function_name_length = name_length; - - char *name_copy = heap_alloc(name_length); - memcpy(name_copy, name, name_length); - function_name = name_copy; - -} - -static void destroy_relocations() { - struct relocation_info *r = relocations; - while (r != 0) { - struct relocation_info *p = r->previous; - heap_dealloc(r, sizeof(struct relocation_info)); - r = p; - } - relocations = 0; -} - -static void destroy_function_allocs(int and_free) { - struct function_alloc *a = allocs; - while (a != 0) { - struct function_alloc *p = a->previous; - if (and_free) - heap_dealloc(a->start, a->bytes); - heap_dealloc(a, sizeof(struct function_alloc)); - a = p; - } - allocs = 0; -} - -const char *get_function_name() { - return function_name; -} - -int get_function_name_length() { - return function_name_length; -} - -//must be multiple of 4096. -#define MIN_RX_SPACE (1 << 20) - -static void *rx_pointer; -static int rx_space = 0; - -void (*end_function())() { - - void *function_start = 0; - - if (function_buffer_used <= rx_space) { - function_start = rx_pointer; - rx_pointer += function_buffer_used; - rx_space -= function_buffer_used; - } - - else { - int to_allocate = ((function_buffer_length - 1) / 4096 + 1) * 4096; - if (to_allocate < MIN_RX_SPACE) - to_allocate = MIN_RX_SPACE; - void *pages = map_pages(to_allocate / 4096); - for (int i = 0; i < to_allocate; i += 4096) - change_page_permissions(pages + i, 1, 1); - function_start = pages; - rx_pointer = pages + function_buffer_used; - rx_space = to_allocate - function_buffer_used; - } - - memcpy(function_start, function_buffer, function_buffer_used); - - for (struct relocation_info *r = relocations; r != 0; r = r->previous) { - int32_t *at = function_start + r->offset_into_function; - void *from = function_start + r->from_offset_into_function; - *at = r->to - from; - } - - destroy_relocations(); - destroy_function_allocs(0); - function_name = 0; - - return function_start; - -} - -void abort_function() { - destroy_relocations(); - destroy_function_allocs(1); - if (function_name != 0) { - heap_dealloc(function_name, function_name_length); - function_name = 0; - } -} - -void *function_data_alloc(int bytes) { - void *start = heap_alloc(bytes); - struct function_alloc *a = heap_alloc(sizeof(struct function_alloc)); - a->start = start; - a->bytes = bytes; - a->previous = allocs; - allocs = a; - return start; -} - -static void emit_bytes(const uint8_t *bytes, int count) { - - if (function_buffer_used + count > function_buffer_length) { - int new_length = function_name_length * 2; - while (function_buffer_used + count > function_buffer_length) - new_length *= 2; - void *new_buffer = heap_alloc(new_length); - memcpy(new_buffer, function_buffer, function_buffer_used); - heap_dealloc(function_buffer, function_buffer_length); - function_buffer = new_buffer; - function_buffer_length = new_length; - } - - memcpy(function_buffer + function_buffer_used, bytes, count); - function_buffer_used += count; - -} - -static struct relocation_info *new_relocation() { - struct relocation_info *r = heap_alloc(sizeof(struct relocation_info)); - r->previous = relocations; - relocations = r; - return r; -} - -void emit_ret() { - uint8_t byte = 0xc3; - emit_bytes(&byte, 1); -} - -void emit_call(void (*to)()) { - struct relocation_info *r = new_relocation(); - r->offset_into_function = function_buffer_used + 1; - r->from_offset_into_function = function_buffer_used + 5; - r->to = to; - uint8_t bytes[5]; - bytes[0] = 0xe8; - emit_bytes(bytes, 5); -} - -void emit_mov_edi(int value) { - uint8_t bytes[5]; - bytes[0] = 0xbf; - *(int32_t *)&bytes[1] = value; - emit_bytes(bytes, 5); -} - -void emit_mov_esi(int value) { - uint8_t bytes[5]; - bytes[0] = 0xbe; - *(int32_t *)&bytes[1] = value; - emit_bytes(bytes, 5); -} - -void emit_mov_rdi(uint64_t value) { - uint8_t bytes[10]; - bytes[0] = 0x48; - bytes[1] = 0xbf; - *(uint64_t *)&bytes[2] = value; - emit_bytes(bytes, 10); -} diff --git a/src/user-apps/shell/assembler.h b/src/user-apps/shell/assembler.h deleted file mode 100644 index f5f25f7..0000000 --- a/src/user-apps/shell/assembler.h +++ /dev/null @@ -1,38 +0,0 @@ -/* Calcite, src/user-apps/shell/assembler.h - * Copyright 2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -#include - -//name is copied -void start_function(const char *name, int name_length); - -const char *get_function_name(); -int get_function_name_length(); - -//returns interpret -void (*end_function())(); -void abort_function(); - -void *function_data_alloc(int bytes); - -void emit_ret(); -void emit_call(void (*to)()); -void emit_mov_edi(int value); -void emit_mov_esi(int value); -void emit_mov_rdi(uint64_t value); diff --git a/src/user-apps/shell/builtin-words.c b/src/user-apps/shell/builtin-words.c deleted file mode 100644 index f177c44..0000000 --- a/src/user-apps/shell/builtin-words.c +++ /dev/null @@ -1,226 +0,0 @@ -/* Calcite, src/user-apps/shell/builtin-words.c - * Copyright 2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include -#include - -#include "builtin-words.h" -#include "assembler.h" -#include "runtime.h" - -static void words_interpret() { - print_all_words(); -} - -static void dup_interpret() { - int x = pop(); - push(x); - push(x); -} - -static void drop_interpret() { - pop(); -} - -static void swap_interpret() { - int y = pop(); - int x = pop(); - push(y); - push(x); -} - -static void rot_interpret() { - int z = pop(); - int y = pop(); - int x = pop(); - push(y); - push(z); - push(x); -} - -static void plus_interpret() { - int y = pop(); - int x = pop(); - push(x + y); -} - -static void minus_interpret() { - int y = pop(); - int x = pop(); - push(x - y); -} - -static void times_interpret() { - int y = pop(); - int x = pop(); - push(x * y); -} - -static void divide_interpret() { - int y = pop(); - int x = pop(); - if (y == 0) - error("division by zero"); - push(x / y); -} - -static void mod_interpret() { - int y = pop(); - int x = pop(); - if (y == 0) - error("division by zero"); - push(x % y); -} - -static void print_integer(int x) { - - if (x == 0) { - terminal_write("0 ", 2); - return; - } - - int is_negative; - if (x < 0) { - x = -x; - is_negative = 1; - } - else - is_negative = 0; - - char text[12]; - text[11] = ' '; - int text_ptr = 11; - while (x > 0) { - --text_ptr; - text[text_ptr] = '0' + x % 10; - x /= 10; - } - - if (is_negative) { - --text_ptr; - text[text_ptr] = '-'; - } - - terminal_write(&text[text_ptr], 12 - text_ptr); - -} - -static void dot_s_interpret() { - int *stack_pointer = get_data_stack_pointer(); - int *stack_top = get_data_stack_top(); - for (int *i = stack_top - 1; i >= stack_pointer; --i) - print_integer(*i); -} - -static void dot_interpret() { - print_integer(pop()); -} - -static void dot_quote_interpret() { - const char *start; - int length; - read_until('"', &start, &length); - terminal_write(start, length); -} - -static void dot_quote_compile() { - const char *start; - int length; - read_until('"', &start, &length); - void *address = function_data_alloc(length); - memcpy(address, start, length); - emit_mov_rdi((uint64_t)address); - emit_mov_esi(length); - emit_call((void *)&terminal_write); -} - -static void cr_interpret() { - terminal_write("\n", 1); -} - -static void colon_interpret() { - - const char *name_start; - int name_length; - read_input_word(&name_start, &name_length); - if (name_length == 0) - error("colon at end of input"); - - start_function(name_start, name_length); - compiling = 1; - -} - -static void semicolon_compile() { - - emit_ret(); - - const char *function_name = get_function_name(); - int function_name_length = get_function_name_length(); - void (*interpret)() = end_function(); - - struct word *word = new_word(); - word->name_length = function_name_length; - word->name = function_name; - word->interpret = interpret; - word->compile = COMPILE_EMIT_CALL; - - compiling = 0; - -} - -static void add(const char *name, void (*interpret)(), void (*compile)()) { - int name_length = 0; - while (name[name_length] != 0) - ++name_length; - struct word *w = new_word(); - w->name_length = name_length; - w->name = name; - w->interpret = interpret; - w->compile = compile; -} - -static void add_compile_only(const char *name, void (*compile)()) { - add(name, INTERPRET_ERROR, compile); -} - -static void add_interpret_only(const char *name, void (*interpret)()) { - add(name, interpret, COMPILE_ERROR); -} - -static void add_emit_call(const char *name, void (*interpret)()) { - add(name, interpret, COMPILE_EMIT_CALL); -} - -void add_builtin_words() { - add_emit_call( "words", &words_interpret); - add_emit_call( "dup", &dup_interpret); - add_emit_call( "drop", &drop_interpret); - add_emit_call( "swap", &swap_interpret); - add_emit_call( "rot", &rot_interpret); - add_emit_call( "+", &plus_interpret); - add_emit_call( "-", &minus_interpret); - add_emit_call( "*", ×_interpret); - add_emit_call( "/", ÷_interpret); - add_emit_call( "mod", &mod_interpret); - add_emit_call( ".s", &dot_s_interpret); - add_emit_call( ".", &dot_interpret); - add( ".\"", &dot_quote_interpret, &dot_quote_compile); - add_emit_call( "cr", &cr_interpret); - add_interpret_only(":", &colon_interpret); - add_compile_only( ";", &semicolon_compile); -} diff --git a/src/user-apps/shell/builtin-words.h b/src/user-apps/shell/builtin-words.h deleted file mode 100644 index 335fb4d..0000000 --- a/src/user-apps/shell/builtin-words.h +++ /dev/null @@ -1,20 +0,0 @@ -/* Calcite, src/user-apps/shell/builtin-words.h - * Copyright 2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -void add_builtin_words(); diff --git a/src/user-apps/shell/libraries.txt b/src/user-apps/shell/libraries.txt deleted file mode 100644 index 8503661..0000000 --- a/src/user-apps/shell/libraries.txt +++ /dev/null @@ -1 +0,0 @@ -calcite diff --git a/src/user-apps/shell/main.c b/src/user-apps/shell/main.c deleted file mode 100644 index bf7435e..0000000 --- a/src/user-apps/shell/main.c +++ /dev/null @@ -1,36 +0,0 @@ -/* Calcite, src/user-apps/shell/main.c - * Copyright 2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "builtin-words.h" -#include "runtime.h" - -#include - -void main() { - - init_terminal(); - save_return_stack(); - create_data_stack(); - add_builtin_words(); - - terminal_write("words: ", 7); - print_all_words(); - terminal_write("\n", 1); - - main_loop(); - -} diff --git a/src/user-apps/shell/runtime.asm b/src/user-apps/shell/runtime.asm deleted file mode 100644 index 6f3fceb..0000000 --- a/src/user-apps/shell/runtime.asm +++ /dev/null @@ -1,40 +0,0 @@ - ; Calcite, src/user-apps/shell/runtime.asm - ; Copyright 2026 Benji Dial - ; - ; This program is free software: you can redistribute it and/or modify - ; it under the terms of the GNU General Public License as published by - ; the Free Software Foundation, either version 3 of the License, or - ; (at your option) any later version. - ; - ; This program is distributed in the hope that it will be useful, but - ; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - ; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - ; for more details. - ; - ; You should have received a copy of the GNU General Public License along - ; with this program. If not, see . - - -bits 64 -default rel - -section .bss - -saved_return_stack: - resq 1 - -section .text - -global save_return_stack -save_return_stack: - mov rax, rsp - and ax, 0xf000 - add rax, 0x1000 - mov qword [saved_return_stack], rax - ret - -global restore_return_stack -restore_return_stack: - mov rsp, qword [saved_return_stack] - push qword 0 - jmp rdi diff --git a/src/user-apps/shell/runtime.c b/src/user-apps/shell/runtime.c deleted file mode 100644 index b983390..0000000 --- a/src/user-apps/shell/runtime.c +++ /dev/null @@ -1,218 +0,0 @@ -/* Calcite, src/user-apps/shell/runtime.c - * Copyright 2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "assembler.h" -#include "runtime.h" - -#include -#include - -static int *data_stack_bottom; -static int *data_stack_top; -static int *data_stack_pointer; - -#define INITIAL_DATA_STACK_INTS 1024 - -void create_data_stack() { - data_stack_bottom = heap_alloc(INITIAL_DATA_STACK_INTS * sizeof(int)); - data_stack_top = data_stack_bottom + INITIAL_DATA_STACK_INTS; - data_stack_pointer = data_stack_top; -} - -void push(int value) { - - if (data_stack_pointer == data_stack_bottom) { - int old_size = data_stack_top - data_stack_bottom; - int new_size = old_size * 2; - int *new_stack = heap_alloc(new_size * sizeof(int)); - memcpy(new_stack + old_size, data_stack_bottom, old_size * sizeof(int)); - heap_dealloc(data_stack_bottom, old_size * sizeof(int)); - data_stack_bottom = new_stack; - data_stack_top = new_stack + new_size; - data_stack_pointer = new_stack + old_size; - } - - *--data_stack_pointer = value; - -} - -int pop() { - - if (data_stack_pointer == data_stack_top) - error("stack underflow"); - - return *(data_stack_pointer++); - -} - -int *get_data_stack_pointer() { - return data_stack_pointer; -} - -int *get_data_stack_top() { - return data_stack_top; -} - -//null-terminated -static const char *input_buffer; -static const char *input_pointer; - -void set_input(const char *buffer) { - input_buffer = buffer; - input_pointer = buffer; -} - -static int is_ws(char ch) { - return ch == ' '; -} - -void read_input_word(const char **start_out, int *length_out) { - const char *start = input_pointer; - while (start[0] != 0 && is_ws(start[0])) - ++start; - int length = 0; - while (start[length] != 0 && !is_ws(start[length])) - ++length; - *start_out = start; - *length_out = length; - if (start[length] == 0) - input_pointer = &start[length]; - else - input_pointer = &start[length + 1]; -} - -void read_until(char end, const char **start_out, int *length_out) { - const char *start = input_pointer; - int length = 0; - while (start[length] != 0 && start[length] != end) - ++length; - if (start[length] == 0) - error("unexpected eof"); - *start_out = start; - *length_out = length; - input_pointer = &start[length + 1]; -} - -static const struct word *dictionary = 0; - -const struct word *look_up_word(int name_length, const char *name) { - for (const struct word *word = dictionary; word != 0; word = word->previous) { - if (word->name_length == name_length) { - for (int i = 0; i < name_length; ++i) - if (word->name[i] != name[i]) - goto next_word; - return word; - } - next_word: - ; - } - return 0; -} - -struct word *new_word() { - struct word *word = heap_alloc(sizeof(struct word)); - word->previous = dictionary; - dictionary = word; - return word; -} - -void print_all_words() { - for (const struct word *w = dictionary; w != 0; w = w->previous) { - terminal_write(w->name, w->name_length); - terminal_write(" ", 1); - } -} - -[[noreturn]] void error(const char *message) { - terminal_write("*** error: ", 11); - int length = 0; - while (message[length] != 0) - ++length; - terminal_write(message, length); - terminal_write("\n", 1); - abort_function(); - restore_return_stack(&main_loop); -} - -static void interpret_all() { - - while (1) { - - const char *start; - int length; - read_input_word(&start, &length); - if (length == 0) - return; - - const struct word *word = look_up_word(length, start); - if (word != 0) { - if (compiling) { - if (word->compile == COMPILE_ERROR) - error("interpret-only word in compile context"); - else if (word->compile == COMPILE_EMIT_CALL) - emit_call(word->interpret); - else - (*word->compile)(); - } - else { - if (word->interpret == INTERPRET_ERROR) - error("compile-only word in interpret context"); - else - (*word->interpret)(); - } - continue; - } - - int is_negative; - if (start[0] == '-') { - is_negative = 1; - ++start; - --length; - } - else - is_negative = 0; - - int abs = 0; - for (int i = 0; i < length; ++i) { - if (start[i] < '0' || start[i] > '9') - error("unknown word"); - abs = abs * 10 + start[i] - '0'; - } - - int x = is_negative ? -abs : abs; - - if (compiling) { - emit_mov_edi(x); - emit_call((void *)&push); - } - else - push(x); - - } - -} - -[[noreturn]] void main_loop() { - compiling = 0; - while (1) { - terminal_write("> ", 2); - set_input(terminal_readline()); - interpret_all(); - } -} - -int compiling; diff --git a/src/user-apps/shell/runtime.h b/src/user-apps/shell/runtime.h deleted file mode 100644 index 58dffe4..0000000 --- a/src/user-apps/shell/runtime.h +++ /dev/null @@ -1,63 +0,0 @@ -/* Calcite, src/user-apps/shell/runtime.h - * Copyright 2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#pragma once - -void save_return_stack(); -//and_call should not return. -[[noreturn]] void restore_return_stack(void (*and_call)()); - -void create_data_stack(); -void push(int value); -int pop(); - -int *get_data_stack_pointer(); -int *get_data_stack_top(); - -//null-terminated. not copied. -void set_input(const char *buffer); - -//length_out is set to 0 on eof. skips all whitespace before and up to one character after. -void read_input_word(const char **start_out, int *length_out); - -//errors on eof before end. skips end. end not included in length. -void read_until(char end, const char **start_out, int *length_out); - -struct word { - int name_length; - const char *name; - void (*interpret)(); - void (*compile)(); - const struct word *previous; -}; - -#define INTERPRET_ERROR ((void (*)())-1) - -#define COMPILE_ERROR ((void (*)())-1) -#define COMPILE_EMIT_CALL ((void (*)())-2) - -//returns 0 if not found. name does not need to be null-terminated. -const struct word *look_up_word(int name_length, const char *name); -struct word *new_word(); - -void print_all_words(); - -[[noreturn]] void error(const char *message); - -extern int compiling; - -[[noreturn]] void main_loop(); diff --git a/src/user-apps/terminal/libraries.txt b/src/user-apps/terminal/libraries.txt deleted file mode 100644 index 12c28c2..0000000 --- a/src/user-apps/terminal/libraries.txt +++ /dev/null @@ -1,2 +0,0 @@ -calcite -flanterm diff --git a/src/user-apps/terminal/terminal.c b/src/user-apps/terminal/terminal.c deleted file mode 100644 index 606ce51..0000000 --- a/src/user-apps/terminal/terminal.c +++ /dev/null @@ -1,196 +0,0 @@ -/* Calcite, src/user-apps/terminal/terminal.c - * Copyright 2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct flanterm_context *flanterm_context; - -static ipc_dgram_receiver_handle_t input_handle; -static ipc_dgram_receiver_handle_t output_handle; - -static char keytable[2048]; - -static struct dispatch_queue *queue; - -struct got_output_param { - int dgram_bytes; - void *dgram; -}; - -static void got_output(void *x) { - struct got_output_param *param = x; - flanterm_write(flanterm_context, param->dgram, param->dgram_bytes); - heap_dealloc(param->dgram, param->dgram_bytes); - heap_dealloc(param, sizeof(struct got_output_param)); -} - -[[noreturn]] static void output_thread(uint64_t) { - - while (1) { - - int dgram_bytes = 0; - ipc_receive_dgram(output_handle, 0, &dgram_bytes); - - void *dgram = heap_alloc(dgram_bytes); - ipc_receive_dgram(output_handle, dgram, &dgram_bytes); - - struct got_output_param *param = heap_alloc(sizeof(struct got_output_param)); - param->dgram_bytes = dgram_bytes; - param->dgram = dgram; - - dispatch(queue, &got_output, param); - - } - -} - -static int flags = 0; -static int entering_caps_lock = 0; -static int entering_num_lock = 0; - -[[noreturn]] static void input_thread(uint64_t) { - while (1) { - - int key = wait_for_keyboard_packet(); - int shift = flags & (TKF_LEFT_SHIFT | TKF_RIGHT_SHIFT); - int caps = flags & TKF_CAPS_LOCK; - int num = flags & TKF_NUM_LOCK; - char printable = keytable[(key & 0xff) | (shift ? 0x100 : 0x0) | (caps ? 0x200 : 0x0) | (num ? 0x400 : 0x0)]; - - if (key == KEY_LEFT_SHIFT) - flags &= ~TKF_LEFT_SHIFT; - else if (key == KEY_RIGHT_SHIFT) - flags &= ~TKF_RIGHT_SHIFT; - else if (key == KEY_LEFT_CTRL) - flags &= ~TKF_LEFT_CTRL; - else if (key == KEY_RIGHT_CTRL) - flags &= ~TKF_RIGHT_CTRL; - else if (key == KEY_LEFT_ALT) - flags &= ~TKF_LEFT_ALT; - else if (key == KEY_RIGHT_ALT) - flags &= ~TKF_RIGHT_ALT; - else if (key == KEY_CAPS_LOCK) { - if (!entering_caps_lock) - flags &= ~TKF_CAPS_LOCK; - else - entering_caps_lock = 0; - } - else if (key == KEY_NUM_LOCK) { - if (!entering_num_lock) - flags &= ~TKF_NUM_LOCK; - else - entering_num_lock = 0; - } - else if (key == (KEY_FLAG_MAKE | KEY_LEFT_SHIFT)) - flags |= TKF_LEFT_SHIFT; - else if (key == (KEY_FLAG_MAKE | KEY_RIGHT_SHIFT)) - flags |= TKF_RIGHT_SHIFT; - else if (key == (KEY_FLAG_MAKE | KEY_LEFT_CTRL)) - flags |= TKF_LEFT_CTRL; - else if (key == (KEY_FLAG_MAKE | KEY_RIGHT_CTRL)) - flags |= TKF_RIGHT_CTRL; - else if (key == (KEY_FLAG_MAKE | KEY_LEFT_ALT)) - flags |= TKF_LEFT_ALT; - else if (key == (KEY_FLAG_MAKE | KEY_RIGHT_ALT)) - flags |= TKF_RIGHT_ALT; - else if (key == (KEY_FLAG_MAKE | KEY_CAPS_LOCK)) { - if (!(flags & TKF_CAPS_LOCK)) { - flags |= TKF_CAPS_LOCK; - entering_caps_lock = 1; - } - } - else if (key == (KEY_FLAG_MAKE | KEY_NUM_LOCK)) { - if (!(flags & TKF_NUM_LOCK)) { - flags |= TKF_NUM_LOCK; - entering_num_lock = 1; - } - } - - int packet = flags | (key << 8) | printable; - ipc_send_dgram(input_handle, &packet, sizeof(int)); - - } -} - -void main() { - - file_handle_t keytable_handle; - if (open_file("root://calcite/qwerty.bin", &keytable_handle) == FAR_SUCCESS) { - struct read_file_parameter param; - param.handle = keytable_handle; - param.buffer = keytable; - param.start = 0; - param.bytes = 2048; - read_file(¶m); - close_file(keytable_handle); - } - - uint64_t output_pipe = ipc_create_private_dgram_pipe(); - uint64_t input_pipe = ipc_create_private_dgram_pipe(); - - ipc_create_private_dgram_receiver(output_pipe, &output_handle); - ipc_create_private_dgram_sender(input_pipe, &input_handle); - - struct framebuffer_info fb; - map_framebuffer(&fb); - - flanterm_context = - flanterm_fb_init( - &heap_alloc, &heap_dealloc, (void *)fb.fb_base, fb.fb_width, - fb.fb_height, fb.fb_pitch, 8, 16, 8, - 8, 8, 0, 0, 0, - 0, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, 0); - - queue = create_dispatch_queue(); - - create_thread(&output_thread, 0); - create_thread(&input_thread, 0); - - char input_pipe_hex[17]; - to_hex(input_pipe, 16, input_pipe_hex); - input_pipe_hex[16] = 0; - - char output_pipe_hex[17]; - to_hex(output_pipe, 16, output_pipe_hex); - output_pipe_hex[16] = 0; - - const char *envvars[4] = { - "TERMINAL_INPUT_PIPE_ID", input_pipe_hex, - "TERMINAL_OUTPUT_PIPE_ID", output_pipe_hex }; - - struct process_start_info psi; - psi.forwared_envvar_count = 0; - psi.set_envvar_count = 2; - psi.set_envvars = envvars; - - start_elf("root://calcite/apps/shell/shell.elf", &psi); - - dispatch_loop(queue); - -} diff --git a/src/user-libs/calcite/dispatch.c b/src/user-libs/calcite/dispatch.c deleted file mode 100644 index 516f1a1..0000000 --- a/src/user-libs/calcite/dispatch.c +++ /dev/null @@ -1,87 +0,0 @@ -/* Calcite, src/user-libs/calcite/dispatch.c - * Copyright 2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include -#include -#include - -struct dispatch_callback { - void (*callback)(void *x); - void *x; - struct dispatch_callback *next; -}; - -struct dispatch_queue { - struct dispatch_callback *start; - struct dispatch_callback *end; - mutex_handle_t mutex; - event_handle_t event; -}; - -struct dispatch_queue *create_dispatch_queue() { - struct dispatch_queue *queue = heap_alloc(sizeof(struct dispatch_queue)); - queue->start = 0; - queue->end = 0; - queue->mutex = create_mutex(); - queue->event = create_event(); - return queue; -} - -void dispatch(struct dispatch_queue *queue, void (*callback)(void *x), void *x) { - - struct dispatch_callback *new = heap_alloc(sizeof(struct dispatch_callback)); - new->callback = callback; - new->x = x; - new->next = 0; - - acquire_mutex(queue->mutex); - - if (queue->start == 0) - queue->start = new; - else - queue->end->next = new; - - queue->end = new; - - release_mutex(queue->mutex); - signal_event(queue->event); - -} - -[[noreturn]] void dispatch_loop(struct dispatch_queue *queue) { - - while (1) { - - wait_event(queue->event); - acquire_mutex(queue->mutex); - - struct dispatch_callback *start = queue->start; - queue->start = 0; - queue->end = 0; - - release_mutex(queue->mutex); - - while (start != 0) { - (*start->callback)(start->x); - struct dispatch_callback *next = start->next; - heap_dealloc(start, sizeof(struct dispatch_callback)); - start = next; - } - - } - -} diff --git a/src/user-libs/calcite/entry.c b/src/user-libs/calcite/entry.c deleted file mode 100644 index 71dd204..0000000 --- a/src/user-libs/calcite/entry.c +++ /dev/null @@ -1,25 +0,0 @@ -/* Calcite, src/user-libs/calcite/entry.c - * Copyright 2025 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include - -void main(); - -[[noreturn]] void _start() { - main(); - end_thread(); -} diff --git a/src/user-libs/calcite/file-streams.c b/src/user-libs/calcite/file-streams.c deleted file mode 100644 index 3f3bdd5..0000000 --- a/src/user-libs/calcite/file-streams.c +++ /dev/null @@ -1,150 +0,0 @@ -/* Calcite, src/user-libs/calcite/file-streams.c - * Copyright 2025 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include -#include -#include -#include - -static uint64_t min(uint64_t a, uint64_t b) { - return a < b ? a : b; -} - -//in bytes -#define FS_BUFFER_SIZE 8192 - -struct file_stream { - - file_handle_t handle; - - //both in bytes - uint64_t length; - uint64_t pointer; - - int is_there_buffer; - //in bytes - uint64_t buffer_start; - uint8_t buffer[FS_BUFFER_SIZE]; - -}; - -enum fs_access_result open_file_stream(const char *path, struct file_stream **file_stream_out) { - - file_handle_t handle; - enum fs_access_result result = open_file(path, &handle); - if (result != FAR_SUCCESS) - return result; - - uint64_t length; - result = get_file_size(handle, &length); - if (result != FAR_SUCCESS) { - close_file(handle); - return result; - } - - *file_stream_out = heap_alloc(sizeof(struct file_stream)); - (*file_stream_out)->handle = handle; - (*file_stream_out)->length = length; - (*file_stream_out)->pointer = 0; - (*file_stream_out)->is_there_buffer = 0; - return FAR_SUCCESS; - -} - -void close_file_stream(struct file_stream *file_stream) { - close_file(file_stream->handle); - heap_dealloc(file_stream, sizeof(struct file_stream)); -} - -enum fs_access_result get_in_buffer(struct file_stream *file_stream, uint64_t pointer) { - - uint64_t bstart = (pointer / FS_BUFFER_SIZE) * FS_BUFFER_SIZE; - uint64_t bbytes = min(FS_BUFFER_SIZE, file_stream->length - bstart); - - if (file_stream->is_there_buffer && file_stream->buffer_start == bstart) - return FAR_SUCCESS; - - enum fs_access_result result = - read_file_splat(file_stream->handle, file_stream->buffer, bstart, bbytes); - - if (result == FAR_SUCCESS) { - file_stream->is_there_buffer = 1; - file_stream->buffer_start = bstart; - return FAR_SUCCESS; - } - - file_stream->is_there_buffer = 0; - return result; - -} - -enum fs_access_result read_file_stream(struct file_stream *file_stream, void *buffer, uint64_t bytes) { - - if (bytes == 0) - return FAR_SUCCESS; - - if (file_stream->pointer + bytes > file_stream->length) - return FAR_OUT_OF_BOUNDS; - - enum fs_access_result result = get_in_buffer(file_stream, file_stream->pointer); - if (result != FAR_SUCCESS) - return result; - - uint64_t in_buffer = min(bytes, FS_BUFFER_SIZE - (file_stream->pointer - file_stream->buffer_start)); - memcpy( - buffer, - file_stream->buffer + file_stream->pointer - file_stream->buffer_start, - in_buffer); - - uint64_t pointer = file_stream->pointer + in_buffer; - uint64_t left = bytes - in_buffer; - void *buffer_pointer = buffer + in_buffer; - - while (left >= FS_BUFFER_SIZE) { - enum fs_access_result result = - read_file_splat(file_stream->handle, buffer_pointer, pointer, FS_BUFFER_SIZE); - if (result != FAR_SUCCESS) - return result; - pointer += FS_BUFFER_SIZE; - left -= FS_BUFFER_SIZE; - buffer_pointer += FS_BUFFER_SIZE; - } - - if (left > 0) { - enum fs_access_result result = get_in_buffer(file_stream, pointer); - if (result != FAR_SUCCESS) - return result; - memcpy(buffer_pointer, file_stream->buffer, left); - } - - file_stream->pointer += bytes; - return FAR_SUCCESS; - -} - -int read_file_stream_byte(struct file_stream *file_stream) { - - if (file_stream->pointer == file_stream->length) - return -1; - - enum fs_access_result result = get_in_buffer(file_stream, file_stream->pointer); - if (result != FAR_SUCCESS) - return -1; - - return file_stream->buffer[file_stream->pointer++ - file_stream->buffer_start]; - -} diff --git a/src/user-libs/calcite/format.c b/src/user-libs/calcite/format.c deleted file mode 100644 index 650e9e9..0000000 --- a/src/user-libs/calcite/format.c +++ /dev/null @@ -1,42 +0,0 @@ -/* Calcite, src/user-libs/calcite/format.c - * Copyright 2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include - -void to_hex(uint64_t value, int digit_count, char *buffer) { - for (int i = 0; i < digit_count; ++i) { - char *digit = &buffer[digit_count - 1 - i]; - uint8_t place_value = (value >> (i * 4)) & 0xf; - if (place_value < 10) - *digit = '0' + place_value; - else - *digit = 'a' - 10 + place_value; - } -} - -uint64_t from_hex(int digit_count, char *buffer) { - uint64_t value = 0; - for (int i = 0; i < digit_count; ++i) { - uint64_t place_value = 0; - if (buffer[i] >= '0' && buffer[i] <= '9') - place_value = buffer[i] - '0'; - else if (buffer[i] >= 'a' && buffer[i] <= 'f') - place_value = buffer[i] - 'a' + 10; - value |= place_value << ((digit_count - 1 - i) * 4); - } - return value; -} diff --git a/src/user-libs/calcite/memory.c b/src/user-libs/calcite/memory.c deleted file mode 100644 index 766bbf5..0000000 --- a/src/user-libs/calcite/memory.c +++ /dev/null @@ -1,197 +0,0 @@ -/* Calcite, src/user-libs/calcite/memory.c - * Copyright 2025-2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include -#include - -struct block_list_entry { - struct block_list_entry *prev; - struct block_list_entry *next; -}; - -struct block_list { - struct block_list_entry *first_entry; - struct block_list_entry *last_entry; -}; - -#define BASE_BLOCK_SIZE 16ULL -#define BLOCK_LEVELS 32 -//BASE_BLOCK_SIZE << MIN_MAP_BLOCK_LEVEL must be at least 4096 -#define MIN_MAP_BLOCK_LEVEL 16 - -//block_lists[n] is a list of free blocks of size BASE_BLOCK_SIZE * 2^n bytes -static struct block_list block_lists[BLOCK_LEVELS]; - -void *heap_alloc(uint64_t bytes) { - - bytes = ((bytes - 1) / BASE_BLOCK_SIZE + 1) * BASE_BLOCK_SIZE; - - //TODO: handle this case? - if (bytes > (BASE_BLOCK_SIZE << (BLOCK_LEVELS - 1))) - return 0; - - int block_n_minimum = 0; - uint64_t block_size_minimum = BASE_BLOCK_SIZE; - while (block_size_minimum < bytes) { - ++block_n_minimum; - block_size_minimum *= 2; - } - - int block_n = block_n_minimum; - uint64_t block_size = block_size_minimum; - while (1) { - if (block_n == BLOCK_LEVELS) { - block_n = -1; - break; - } - if (block_lists[block_n].first_entry != 0) - break; - ++block_n; - block_size *= 2; - } - - if (block_n == -1) { - block_n = block_n_minimum > MIN_MAP_BLOCK_LEVEL ? block_n_minimum : MIN_MAP_BLOCK_LEVEL; - block_size = BASE_BLOCK_SIZE << block_n; - void *start = map_pages(block_size / 4096); - if (block_size != bytes) - heap_dealloc(start + bytes, block_size - bytes); - return start; - } - - struct block_list_entry *e = block_lists[block_n].first_entry; - if (e->next) - e->next->prev = 0; - else - block_lists[block_n].last_entry = 0; - block_lists[block_n].first_entry = e->next; - - void *start = e; - if (block_size != bytes) - heap_dealloc(start + bytes, block_size - bytes); - - return start; - -} - -static void heap_dealloc_aligned(void *start, uint64_t block_n, uint64_t block_size) { -recurse: - - if (block_size != BLOCK_LEVELS - 1) { - - void *buddy = (void *)((uint64_t)start ^ block_size); - - for (struct block_list_entry *e = block_lists[block_n].first_entry; e != 0; e = e->next) - if (e == buddy) { - if (e->next) - e->next->prev = e->prev; - else - block_lists[block_n].last_entry = e->prev; - if (e->prev) - e->prev->next = e->next; - else - block_lists[block_n].first_entry = e->next; - start = (void *)((uint64_t)start & ~block_size); - ++block_n; - block_size *= 2; - goto recurse; - } - - } - - if (block_lists[block_n].first_entry == 0) { - struct block_list_entry *e = start; - e->next = 0; - e->prev = 0; - block_lists[block_n].first_entry = e; - block_lists[block_n].last_entry = e; - return; - } - - if (start < (void *)block_lists[block_n].first_entry) { - struct block_list_entry *e = start; - e->next = block_lists[block_n].first_entry; - e->prev = 0; - block_lists[block_n].first_entry->prev = e; - block_lists[block_n].first_entry = e; - return; - } - - if (start > (void *)block_lists[block_n].last_entry) { - struct block_list_entry *e = start; - e->next = 0; - e->prev = block_lists[block_n].last_entry; - block_lists[block_n].last_entry->next = e; - block_lists[block_n].last_entry = e; - return; - } - - struct block_list_entry *after = block_lists[block_n].first_entry; - while ((void *)after < start) - after = after->next; - struct block_list_entry *before = after->prev; - struct block_list_entry *e = start; - - e->next = after; - e->prev = before; - after->prev = e; - before->next = e; - -} - -void heap_dealloc(void *start, uint64_t bytes) { - - bytes = ((bytes - 1) / BASE_BLOCK_SIZE + 1) * BASE_BLOCK_SIZE; - //bytes is guaranteed to be at most BASE_BLOCK_SIZE << (BLOCK_LEVELS - 1) - - int block_n = 0; - uint64_t block_size = BASE_BLOCK_SIZE; - - while (block_size <= bytes) { - if ((uint64_t)start & block_size) { - heap_dealloc_aligned(start, block_n, block_size); - start += block_size; - bytes -= block_size; - } - ++block_n; - block_size *= 2; - } - - while (block_n >= 0) { - if (block_size <= bytes) { - heap_dealloc_aligned(start, block_n, block_size); - start += block_size; - bytes -= block_size; - } - --block_n; - block_size /= 2; - } - -} - -void memcpy(void *to, const void *from, uint64_t bytes) { - uint8_t *to8 = to; - const uint8_t *from8 = from; - for (uint64_t i = 0; i < bytes; ++i) - to8[i] = from8[i]; -} - -void memset(void *start, uint8_t value, uint64_t length) { - uint8_t *start8 = start; - for (uint64_t i = 0; i < length; ++i) - start8[i] = value; -} diff --git a/src/user-libs/calcite/syscalls.asm b/src/user-libs/calcite/syscalls.asm deleted file mode 100644 index 0c00a5d..0000000 --- a/src/user-libs/calcite/syscalls.asm +++ /dev/null @@ -1,28 +0,0 @@ - ; Calcite, src/user-libs/calcite/syscalls.asm - ; Copyright 2025 Benji Dial - ; - ; This program is free software: you can redistribute it and/or modify - ; it under the terms of the GNU General Public License as published by - ; the Free Software Foundation, either version 3 of the License, or - ; (at your option) any later version. - ; - ; This program is distributed in the hope that it will be useful, but - ; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - ; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - ; for more details. - ; - ; You should have received a copy of the GNU General Public License along - ; with this program. If not, see . - - -bits 64 -default rel - -section .text - -;referenced in syscalls.c -global do_syscall -do_syscall: - mov rax, rcx - syscall - ret diff --git a/src/user-libs/calcite/syscalls.c b/src/user-libs/calcite/syscalls.c deleted file mode 100644 index ad6bba0..0000000 --- a/src/user-libs/calcite/syscalls.c +++ /dev/null @@ -1,155 +0,0 @@ -/* Calcite, src/user-libs/calcite/syscalls.c - * Copyright 2025-2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include - -//defined in syscalls.asm -uint64_t do_syscall - (uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t number); - -[[noreturn]] void end_thread() { - do_syscall(0, 0, 0, SYSCALL_END_THREAD); - __builtin_unreachable(); -} - -void map_framebuffer(struct framebuffer_info *info_out) { - do_syscall((uint64_t)info_out, 0, 0, SYSCALL_MAP_FRAMEBUFFER); -} - -enum fs_access_result open_file(const char *path, file_handle_t *handle_out) { - return do_syscall((uint64_t)path, (uint64_t)handle_out, 1, SYSCALL_OPEN_FILE); -} - -void close_file(file_handle_t handle) { - do_syscall(handle, 0, 0, SYSCALL_CLOSE_FILE); -} - -enum fs_access_result get_file_size(file_handle_t handle, uint64_t *bytes_out) { - return do_syscall(handle, (uint64_t)bytes_out, 0, SYSCALL_GET_FILE_SIZE); -} - -enum fs_access_result read_file(struct read_file_parameter *parameter) { - return do_syscall((uint64_t)parameter, 0, 0, SYSCALL_READ_FILE); -} - -enum fs_access_result read_file_splat(file_handle_t handle, void *buffer, uint64_t start, uint64_t bytes) { - struct read_file_parameter parameter = { .handle = handle, .buffer = buffer, .start = start, .bytes = bytes }; - return do_syscall((uint64_t)¶meter, 0, 0, SYSCALL_READ_FILE); -} - -void wait_for_mouse_packet(struct mouse_packet *packet_out) { - do_syscall((uint64_t)packet_out, 0, 0, SYSCALL_WAIT_FOR_MOUSE_PACKET); -} - -void *map_pages(uint64_t count) { - return (void *)do_syscall(count, 0, 0, SYSCALL_MAP_PAGES); -} - -void sleep_ms(uint64_t ms_to_sleep) { - do_syscall(ms_to_sleep, 0, 0, SYSCALL_SLEEP_MS); -} - -int start_elf(const char *path, const struct process_start_info *info) { - return do_syscall((uint64_t)path, (uint64_t)info, 0, SYSCALL_START_ELF); -} - -enum ipc_dgram_result ipc_create_dgram_receiver(const char *address, ipc_dgram_receiver_handle_t *handle_out) { - return do_syscall( - (uint64_t)address, (uint64_t)handle_out, 0, SYSCALL_IPC_CREATE_DGRAM_RECEIVER); -} - -enum ipc_dgram_result ipc_create_dgram_sender(const char *address, ipc_dgram_sender_handle_t *handle_out) { - return do_syscall( - (uint64_t)address, (uint64_t)handle_out, 0, SYSCALL_IPC_CREATE_DGRAM_SENDER); -} - -enum ipc_dgram_result ipc_receive_dgram(ipc_dgram_receiver_handle_t handle, void *buffer, int *bytes) { - return do_syscall( - handle, (uint64_t)buffer, (uint64_t)bytes, SYSCALL_IPC_RECEIVE_DGRAM); -} - -enum ipc_dgram_result ipc_send_dgram(ipc_dgram_sender_handle_t handle, const void *data, int bytes) { - return do_syscall(handle, (uint64_t)data, bytes, SYSCALL_IPC_SEND_DGRAM); -} - -void create_thread(void (*f)(uint64_t x), uint64_t x) { - do_syscall((uint64_t)f, x, 0, SYSCALL_CREATE_THREAD); -} - -void get_envvar(const char *key, char *value_out, int *value_space) { - do_syscall( - (uint64_t)key, (uint64_t)value_out, (uint64_t)value_space, SYSCALL_GET_ENVVAR); -} - -mutex_handle_t create_mutex() { - return do_syscall(0, 0, 0, SYSCALL_CREATE_MUTEX); -} - -void acquire_mutex(mutex_handle_t handle) { - do_syscall(handle, 0, 0, SYSCALL_ACQUIRE_MUTEX); -} - -void release_mutex(mutex_handle_t handle) { - do_syscall(handle, 0, 0, SYSCALL_RELEASE_MUTEX); -} - -event_handle_t create_event() { - return do_syscall(0, 0, 0, SYSCALL_CREATE_EVENT); -} - -void signal_event(event_handle_t handle) { - do_syscall(handle, 0, 0, SYSCALL_SIGNAL_EVENT); -} - -void wait_event(event_handle_t handle) { - do_syscall(handle, 0, 0, SYSCALL_WAIT_EVENT); -} - -uint64_t ipc_create_private_dgram_pipe() { - return do_syscall(0, 0, 0, SYSCALL_IPC_CREATE_PRIVATE_DGRAM_PIPE); -} - -enum ipc_dgram_result ipc_create_private_dgram_receiver(uint64_t id, ipc_dgram_receiver_handle_t *handle_out) { - return do_syscall( - id, (uint64_t)handle_out, 0, SYSCALL_IPC_CREATE_PRIVATE_DGRAM_RECEIVER); -} - -enum ipc_dgram_result ipc_create_private_dgram_sender(uint64_t id, ipc_dgram_sender_handle_t *handle_out) { - return do_syscall( - id, (uint64_t)handle_out, 0, SYSCALL_IPC_CREATE_PRIVATE_DGRAM_SENDER); -} - -uint64_t get_ms_since_boot() { - return do_syscall(0, 0, 0, SYSCALL_GET_MS_SINCE_BOOT); -} - -void sleep_until_ms_since_boot(uint64_t ms) { - do_syscall(ms, 0, 0, SYSCALL_SLEEP_UNTIL_MS_SINCE_BOOT); -} - -void change_page_permissions(void *vma, int writable, int executable) { - do_syscall((uint64_t)vma, writable, executable, SYSCALL_CHANGE_PAGE_PERMISSIONS); -} - -int wait_for_keyboard_packet() { - return do_syscall(0, 0, 0, SYSCALL_WAIT_FOR_KEYBOARD_PACKET); -} diff --git a/src/user-libs/calcite/terminal.c b/src/user-libs/calcite/terminal.c deleted file mode 100644 index 935be1b..0000000 --- a/src/user-libs/calcite/terminal.c +++ /dev/null @@ -1,271 +0,0 @@ -/* Calcite, src/user-libs/calcite/terminal.c - * Copyright 2026 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include - -static ipc_dgram_receiver_handle_t input_handle; -static ipc_dgram_sender_handle_t output_handle; - -static int set_up_terminal_input = 0; -static int set_up_terminal_output = 0; - -static uint8_t *output_buffer; -static int output_buffer_size; -static int output_buffer_used; - -static void output_buffer_size_at_least(int bytes) { - - if (output_buffer_size >= bytes) - return; - - int new_size = output_buffer_size * 2; - while (new_size < bytes) - new_size *= 2; - - uint8_t *new_buffer = heap_alloc(new_size); - memcpy(new_buffer, output_buffer, output_buffer_used); - heap_dealloc(output_buffer, output_buffer_size); - output_buffer = new_buffer; - output_buffer_size = new_size; - -} - -#define MAX_PACKET_LENGTH 500 - -static void send_output(const void *buffer, int bytes) { - - if (set_up_terminal_output == 0) - return; - - while (bytes >= MAX_PACKET_LENGTH) { - ipc_send_dgram(output_handle, buffer, MAX_PACKET_LENGTH); - buffer += MAX_PACKET_LENGTH; - bytes -= MAX_PACKET_LENGTH; - } - - if (bytes > 0) - ipc_send_dgram(output_handle, buffer, bytes); - -} - -void init_terminal() { - - output_buffer_size = 512; - output_buffer_used = 0; - output_buffer = heap_alloc(output_buffer_size); - - char hex[17]; - int bytes = 17; - get_envvar("TERMINAL_INPUT_PIPE_ID", hex, &bytes); - - if (bytes == 17 && - ipc_create_private_dgram_receiver( - from_hex(16, hex), - &input_handle) == IPR_SUCCESS) - set_up_terminal_input = 1; - - bytes = 17; - get_envvar("TERMINAL_OUTPUT_PIPE_ID", hex, &bytes); - - if (bytes == 17 && - ipc_create_private_dgram_sender( - from_hex(16, hex), - &output_handle) == IPR_SUCCESS) - set_up_terminal_output = 1; - -} - -void terminal_write(const void *data, int bytes) { - - if (bytes == 0) - return; - - const uint8_t *data8 = (const uint8_t *)data; - - int last_newline = bytes - 1; - while (last_newline >= 0 && data8[last_newline] != '\n') - --last_newline; - - if (last_newline == -1) { - output_buffer_size_at_least(output_buffer_used + bytes); - memcpy(&output_buffer[output_buffer_used], data, bytes); - output_buffer_used += bytes; - } - - else { - if (output_buffer_used != 0) { - send_output(output_buffer, output_buffer_used); - output_buffer_used = 0; - } - send_output(data, last_newline + 1); - if (last_newline != bytes - 1) { - output_buffer_size_at_least(bytes - last_newline - 1); - memcpy(output_buffer, data + last_newline + 1, bytes - last_newline - 1); - output_buffer_used = bytes - last_newline - 1; - } - } - -} - -void terminal_flush() { - if (output_buffer_used != 0) { - send_output(output_buffer, output_buffer_used); - output_buffer_used = 0; - } -} - -int terminal_readkey() { - - if (!set_up_terminal_input) - return -1; - - terminal_flush(); - int result; - int bytes = sizeof(int); - ipc_receive_dgram(input_handle, &result, &bytes); - //TODO: handle case where terminal misbehaves and sends more than sizeof(int) - - return result; - -} - -static char *readline_buffer = 0; -static int readline_buffer_length = 0; -static int readline_buffer_used = 0; -static int readline_cursor = 0; - -static void room_for_one_more() { - - if (readline_buffer == 0) { - readline_buffer_length = 1024; - readline_buffer = heap_alloc(readline_buffer_length); - } - - else if (readline_buffer_used == readline_buffer_length) { - char *new_buffer = heap_alloc(readline_buffer_length * 2); - memcpy(new_buffer, readline_buffer, readline_buffer_length); - heap_dealloc(readline_buffer, readline_buffer_length); - readline_buffer = new_buffer; - readline_buffer_length *= 2; - } - -} - -const char *terminal_readline() { - - readline_buffer_used = 0; - readline_cursor = 0; - - while (1) { - - int key_packet = terminal_readkey(); - if (!(key_packet & (KEY_FLAG_MAKE << 8)) || - (key_packet & (TKF_LEFT_CTRL | TKF_RIGHT_CTRL | TKF_LEFT_ALT | TKF_RIGHT_ALT))) - continue; - int key = (key_packet >> 8) & 0xff; - int num_lock = key_packet & TKF_NUM_LOCK; - - if (key == KEY_LEFT || (!num_lock && key == KEY_NUM_4)) { - if (readline_cursor != 0) { - --readline_cursor; - terminal_write("\x1b[D", 3); - } - } - - else if (key == KEY_RIGHT || (!num_lock && key == KEY_NUM_6)) { - if (readline_cursor != readline_buffer_used) { - ++readline_cursor; - terminal_write("\x1b[C", 3); - } - } - - else if (key == KEY_BACKSPACE) { - if (readline_cursor != 0) { - for (int i = readline_cursor; i < readline_buffer_used; ++i) - readline_buffer[i - 1] = readline_buffer[i]; - --readline_cursor; - --readline_buffer_used; - terminal_write("\x1b[D", 3); - terminal_write(&readline_buffer[readline_cursor], readline_buffer_used - readline_cursor); - terminal_write(" ", 1); - for (int i = readline_cursor; i < readline_buffer_used + 1; ++i) - terminal_write("\x1b[D", 3); - } - } - - else if (key == KEY_DELETE || (!num_lock && key == KEY_NUM_PERIOD)) { - if (readline_cursor != readline_buffer_used) { - ++readline_cursor; - for (int i = readline_cursor; i < readline_buffer_used; ++i) - readline_buffer[i - 1] = readline_buffer[i]; - --readline_cursor; - --readline_buffer_used; - terminal_write(&readline_buffer[readline_cursor], readline_buffer_used - readline_cursor); - terminal_write(" ", 1); - for (int i = readline_cursor; i < readline_buffer_used + 1; ++i) - terminal_write("\x1b[D", 3); - } - } - - else if (key == KEY_ENTER || key == KEY_NUM_ENTER) { - room_for_one_more(); - readline_buffer[readline_buffer_used] = 0; - for (int i = readline_cursor; i < readline_buffer_used; ++i) - terminal_write("\x1b[C", 3); - terminal_write("\n", 1); - return readline_buffer; - } - - else if (key == KEY_TAB) - continue; - - else if (key == KEY_HOME || (!num_lock && key == KEY_NUM_7)) { - for (int i = 0; i < readline_cursor; ++i) - terminal_write("\x1b[D", 3); - readline_cursor = 0; - } - - else if (key == KEY_END || (!num_lock && key == KEY_NUM_1)) { - for (int i = readline_cursor; i < readline_buffer_used; ++i) - terminal_write("\x1b[C", 3); - readline_cursor = readline_buffer_used; - } - - else { - char value = key_packet & 0xff; - if (value != 0) { - room_for_one_more(); - for (int i = readline_buffer_used; i > readline_cursor; --i) - readline_buffer[i] = readline_buffer[i - 1]; - readline_buffer[readline_cursor] = value; - ++readline_buffer_used; - terminal_write(&readline_buffer[readline_cursor], readline_buffer_used - readline_cursor); - ++readline_cursor; - for (int i = readline_buffer_used; i > readline_cursor; --i) - terminal_write("\x1b[D", 3); - } - } - - } - -} diff --git a/src/user-libs/silver/image.c b/src/user-libs/silver/image.c deleted file mode 100644 index c78eb18..0000000 --- a/src/user-libs/silver/image.c +++ /dev/null @@ -1,31 +0,0 @@ -/* Calcite, src/user-libs/silver/image.c - * Copyright 2025 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include -#include - -void create_image(int width, int height, struct image **image_out) { - *image_out = heap_alloc(sizeof(struct image)); - (*image_out)->width = width; - (*image_out)->height = height; - (*image_out)->pixels = heap_alloc(width * height * sizeof(struct pixel)); -} - -void destroy_image(struct image *image) { - heap_dealloc(image->pixels, image->width * image->height * sizeof(struct pixel)); - heap_dealloc(image, sizeof(struct image)); -} diff --git a/src/user-libs/silver/pam.c b/src/user-libs/silver/pam.c deleted file mode 100644 index 2d5625c..0000000 --- a/src/user-libs/silver/pam.c +++ /dev/null @@ -1,128 +0,0 @@ -/* Calcite, src/user-libs/silver/pam.c - * Copyright 2025 Benji Dial - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include -#include - -static int starts_with(const char *big_string, const char *little_string) { - while (*little_string) { - if (*big_string != *little_string) - return 0; - ++big_string; - ++little_string; - } - return 1; -} - -static int strequ(const char *str1, const char *str2) { - while (1) { - if (!*str1 && !*str2) - return 1; - if (*str1 != *str2) - return 0; - ++str1; - ++str2; - } -} - -static int parse_uint(const char *str) { - int i = 0; - while (*str) - i = i * 10 + *(str++) - '0'; - return i; -} - -enum pam_tupltype { - PTT_RGB_ALPHA -}; - -#define MAX_LINE_LENGTH 1023 - -int load_pam(const char *path, struct image **image_out) { - - struct file_stream *stream; - if (open_file_stream(path, &stream) != FAR_SUCCESS) - return 0; - - if (read_file_stream_byte(stream) != 'P' || - read_file_stream_byte(stream) != '7' || - read_file_stream_byte(stream) != '\n') { - close_file_stream(stream); - return 0; - } - - int width = -1, height = -1, depth = -1, maxval = -1, tupltype = -1; - - while (1) { - - char line[MAX_LINE_LENGTH + 1]; - int line_length = 0; - while (1) { - int c = read_file_stream_byte(stream); - if (c == -1) { - close_file_stream(stream); - return 0; - } - if (c == '\n') { - line[line_length] = 0; - break; - } - if (line_length == MAX_LINE_LENGTH) { - close_file_stream(stream); - return 0; - } - line[line_length++] = c; - } - - if (line[0] == '#') - continue; - - if (starts_with(line, "WIDTH ")) - width = parse_uint(&line[6]); - else if (starts_with(line, "HEIGHT ")) - height = parse_uint(&line[7]); - else if (starts_with(line, "DEPTH ")) - depth = parse_uint(&line[6]); - else if (starts_with(line, "MAXVAL ")) - maxval = parse_uint(&line[7]); - else if (strequ(line, "TUPLTYPE RGB_ALPHA")) - tupltype = PTT_RGB_ALPHA; - else if (strequ(line, "ENDHDR")) - break; - - } - - if (width == -1 || height == -1 || depth != 4 || maxval != 255 || tupltype != PTT_RGB_ALPHA) { - close_file_stream(stream); - return 0; - } - - create_image(width, height, image_out); - - if (read_file_stream( - stream, - (*image_out)->pixels, - width * height * 4) != FAR_SUCCESS) { - close_file_stream(stream); - destroy_image(*image_out); - return 0; - } - - close_file_stream(stream); - return 1; - -}