summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore15
-rw-r--r--applications/init/main.cpp50
-rw-r--r--applications/init/makefile12
-rw-r--r--applications/init/source/main.cpp28
-rw-r--r--applications/link.ld38
-rw-r--r--documentation/compositor.txt26
-rw-r--r--documentation/euler/heap.txt32
-rw-r--r--documentation/panics.txt8
-rw-r--r--documentation/sockets.txt28
-rw-r--r--documentation/syscalls.txt160
-rw-r--r--euler/include/cstdio15
-rw-r--r--euler/include/cstring8
-rw-r--r--euler/include/euler/heap.hpp8
-rw-r--r--euler/include/euler/stream.hpp48
-rw-r--r--euler/include/euler/syscall.hpp61
-rw-r--r--euler/makefile29
-rw-r--r--euler/source/empty.asm0
-rw-r--r--euler/source/euler/entry.cpp11
-rw-r--r--euler/source/euler/gcc.asm53
-rw-r--r--euler/source/euler/heap.cpp66
-rw-r--r--euler/source/euler/stream.cpp151
-rw-r--r--euler/source/euler/syscall.asm102
-rw-r--r--euler/source/io/fclose.cpp10
-rw-r--r--euler/source/io/fopen.cpp54
-rw-r--r--euler/source/io/fread.cpp9
-rw-r--r--euler/source/memory/delete.cpp17
-rw-r--r--euler/source/memory/new.cpp13
-rw-r--r--euler/source/strings/memcpy.cpp14
-rw-r--r--euler/source/strings/strlen.cpp12
-rw-r--r--kernel/application.cpp280
-rw-r--r--kernel/framebuffer.cpp65
-rw-r--r--kernel/include/hilbert/kernel/application.hpp193
-rw-r--r--kernel/include/hilbert/kernel/framebuffer.hpp10
-rw-r--r--kernel/include/hilbert/kernel/input.hpp2
-rw-r--r--kernel/include/hilbert/kernel/panic.hpp3
-rw-r--r--kernel/include/hilbert/kernel/terminal.hpp32
-rw-r--r--kernel/input.cpp13
-rw-r--r--kernel/makefile19
-rw-r--r--kernel/panic.cpp10
-rw-r--r--kernel/source/allocator.cpp (renamed from kernel/allocator.cpp)0
-rw-r--r--kernel/source/application.asm171
-rw-r--r--kernel/source/application.cpp550
-rw-r--r--kernel/source/entry.cpp (renamed from kernel/entry.cpp)76
-rw-r--r--kernel/source/framebuffer.cpp40
-rw-r--r--kernel/source/input.cpp22
-rw-r--r--kernel/source/interrupts.asm (renamed from kernel/interrupts.asm)22
-rw-r--r--kernel/source/interrupts.cpp (renamed from kernel/interrupts.cpp)90
-rw-r--r--kernel/source/paging.asm (renamed from kernel/paging.asm)0
-rw-r--r--kernel/source/paging.cpp (renamed from kernel/paging.cpp)0
-rw-r--r--kernel/source/panic.cpp11
-rw-r--r--kernel/source/storage.cpp (renamed from kernel/storage.cpp)0
-rw-r--r--kernel/source/storage/bd/memory.cpp (renamed from kernel/storage/bd/memory.cpp)0
-rw-r--r--kernel/source/storage/fs/tarfs.cpp (renamed from kernel/storage/fs/tarfs.cpp)0
-rw-r--r--kernel/source/syscall.cpp538
-rw-r--r--kernel/source/utility.cpp (renamed from kernel/utility.cpp)0
-rw-r--r--kernel/source/vfile.cpp (renamed from kernel/vfile.cpp)0
-rw-r--r--kernel/syscall.asm88
-rw-r--r--kernel/syscall.cpp262
-rw-r--r--kernel/terminal.cpp121
-rw-r--r--libraries/daguerre/include/daguerre.hpp131
-rw-r--r--libraries/daguerre/include/daguerre/image.hpp155
-rw-r--r--libraries/daguerre/makefile12
-rw-r--r--libraries/daguerre/ppm.cpp52
-rw-r--r--libraries/daguerre/source/daguerre.cpp58
-rw-r--r--libraries/euler/allocator.cpp147
-rw-r--r--libraries/euler/cassert.cpp16
-rw-r--r--libraries/euler/cctype.cpp11
-rw-r--r--libraries/euler/cstdio.cpp102
-rw-r--r--libraries/euler/entry.cpp19
-rw-r--r--libraries/euler/include/cassert13
-rw-r--r--libraries/euler/include/cctype7
l---------libraries/euler/include/cstddef1
l---------libraries/euler/include/cstdint1
-rw-r--r--libraries/euler/include/cstdio19
-rw-r--r--libraries/euler/include/cstring14
-rw-r--r--libraries/euler/include/euler/syscall.hpp51
-rw-r--r--libraries/euler/syscall.asm88
-rw-r--r--limine.cfg5
-rw-r--r--makefile205
-rw-r--r--patches/binutils.txt17
-rw-r--r--qemu.gdb8
-rw-r--r--readme.txt104
-rw-r--r--skeleton/assets/burden.ppm (renamed from skeleton/init/burdon.ppm)0
-rw-r--r--skeleton/assets/readme.txt4
l---------skeleton/cfg/default.key1
-rw-r--r--skeleton/cfg/init.sh1
-rw-r--r--skeleton/init/readme.txt3
-rw-r--r--terminus/license.txt94
-rw-r--r--terminus/readme.txt5
-rw-r--r--terminus/ter-u16b.psfbin5140 -> 0 bytes
90 files changed, 2935 insertions, 2105 deletions
diff --git a/.gitignore b/.gitignore
index b601867..4f5133e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,10 @@
-.vscode/
-limine
-mintsuki-freestanding-headers
-obj
-out
+.vscode/*
+
+build/*
+dependencies/*
+toolchain/*
+
+euler/build/*
+kernel/build/*
+applications/*/build/*
+libraries/*/build/*
diff --git a/applications/init/main.cpp b/applications/init/main.cpp
deleted file mode 100644
index 57ebd02..0000000
--- a/applications/init/main.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-#include <daguerre/image.hpp>
-
-int main(int, char **) {
-
- auto fb = daguerre::get_hilbert_framebuffer();
-
- auto white = daguerre::to_hilbert_color({.r = 255, .g = 255, .b = 255});
- auto gray = daguerre::to_hilbert_color({.r = 127, .g = 127, .b = 127});
-
- for (unsigned y = 0; y < fb.get_height(); ++y)
- for (unsigned x = 0; x < fb.get_width(); ++x) {
- uint8_t v = (y / 16) % 2 == (x / 16) % 2;
- fb.get(x, y) = v ? white : gray;
- }
-
- daguerre::image<daguerre::color24> img;
-
- std::FILE *file = std::fopen("/init/burdon.ppm", "r");
- assert(file != 0);
- assert(daguerre::try_load_ppm(file, img));
- std::fclose(file);
-
- unsigned width =
- img.get_width() < fb.get_width() ? img.get_width() : fb.get_width();
- unsigned height =
- img.get_height() < fb.get_height() ? img.get_height() : fb.get_height();
-
- unsigned x_off = (fb.get_width() - width) / 2;
- unsigned y_off = (fb.get_height() - height) / 2;
-
- daguerre::copy_image(img, fb, 0, 0, x_off, y_off, width, height);
-
- while (true) {
-
- uint32_t kp = _syscall_read_key_packet();
- if ((kp & 0x0400ff) == 0x04005a) {
- for (unsigned y = 0; y < img.get_height(); ++y)
- for (unsigned x = 0; x < img.get_width(); ++x) {
- img.get(x, y).r = ~img.get(x, y).r;
- img.get(x, y).g = ~img.get(x, y).g;
- img.get(x, y).b = ~img.get(x, y).b;
- }
- daguerre::copy_image(img, fb, 0, 0, x_off, y_off, width, height);
- }
-
- }
-
- return 0;
-
-}
diff --git a/applications/init/makefile b/applications/init/makefile
new file mode 100644
index 0000000..6799406
--- /dev/null
+++ b/applications/init/makefile
@@ -0,0 +1,12 @@
+SOURCES = \
+ main.cpp
+
+build/%.cpp.o: source/%.cpp
+ @mkdir -p $(@D)
+ $(HILBERT_CC) -c $^ -o $@
+
+build/init.elf: $(SOURCES:%=build/%.o)
+ $(HILBERT_CC) $^ -ldaguerre -o $@
+
+clean:
+ rm -rf build
diff --git a/applications/init/source/main.cpp b/applications/init/source/main.cpp
new file mode 100644
index 0000000..ed0ef8e
--- /dev/null
+++ b/applications/init/source/main.cpp
@@ -0,0 +1,28 @@
+#include <daguerre.hpp>
+
+int main(int, char **) {
+
+ auto hfb = daguerre::get_hilbert_framebuffer();
+ daguerre::image<daguerre::rgb24> bim;
+
+ std::FILE *burdon = std::fopen("/assets/burden.ppm", "r");
+ daguerre::try_load_ppm(burdon, bim);
+ std::fclose(burdon);
+
+ unsigned width = bim.width < hfb.width ? bim.width : hfb.width;
+ unsigned height = bim.height < hfb.height ? bim.height : hfb.height;
+ unsigned x = (hfb.width - width) / 2;
+ unsigned y = (hfb.height - height) / 2;
+
+ while (1) {
+ daguerre::copy_region<>(hfb, bim, 0, 0, x, y, width, height);
+ while ((__euler_read_key_packet() & 0x0400ff) != 0x00005a)
+ ;
+ for (unsigned i = 0; i < bim.width * bim.height; ++i) {
+ bim.buffer[i].r = 255 - bim.buffer[i].r;
+ bim.buffer[i].g = 255 - bim.buffer[i].g;
+ bim.buffer[i].b = 255 - bim.buffer[i].b;
+ }
+ }
+
+}
diff --git a/applications/link.ld b/applications/link.ld
deleted file mode 100644
index f8c09a2..0000000
--- a/applications/link.ld
+++ /dev/null
@@ -1,38 +0,0 @@
-OUTPUT_FORMAT(elf64-x86-64)
-OUTPUT_ARCH(i386:x86-64)
-
-ENTRY(_entry)
-
-PHDRS {
- rx PT_LOAD FLAGS(5);
- ro PT_LOAD FLAGS(4);
- rw PT_LOAD FLAGS(6);
-}
-
-SECTIONS {
-
- /* see also ../documentation/memory.txt */
- . = 0x200000;
-
- .text : {
- *(.text .text.*)
- } : rx
-
- . = ALIGN(4096);
-
- .rodata : {
- *(.rodata .rodata.*)
- } : ro
-
- . = ALIGN(4096);
-
- .data : {
- *(.data .data.*)
- } : rw
-
- .bss : {
- *(.bss .bss.*)
- *(COMMON)
- } : rw
-
-}
diff --git a/documentation/compositor.txt b/documentation/compositor.txt
new file mode 100644
index 0000000..8946eff
--- /dev/null
+++ b/documentation/compositor.txt
@@ -0,0 +1,26 @@
+compositors listen on the socket id "hilbert.compositor".
+
+data types:
+
+ color24:
+ byte: red
+ byte: green
+ byte: blue
+
+ color24 rectangle:
+ multiple color24's, top to bottom by row, left to right within row
+
+messages from applications to compositor:
+
+ open window:
+ byte: 0x00
+ dword: window width
+ dword: window height
+
+ update window region:
+ byte: 0x01
+ dword: start x
+ dword: start y
+ dword: width
+ dword: height
+ color24 rectangle: the data
diff --git a/documentation/euler/heap.txt b/documentation/euler/heap.txt
new file mode 100644
index 0000000..de1deec
--- /dev/null
+++ b/documentation/euler/heap.txt
@@ -0,0 +1,32 @@
+this file documents dynamic memory allocation and deallocation in userspace.
+the unused areas of a process's usable mapped memory are divided into "chunks"
+with a start and a length, satisfying the following properties:
+ a) the length of a chunk is a positive power of 2
+ b) the start of a chunk is a multiple of its length
+ c) let s be a power of 2 and k be an integer. there are never two chunks with
+ length s and starts s * (2 * k) and s * (2 * k + 1). if ever an operation
+ would result in two such chunks, they are combined into one chunk with
+ length 2 * s and start 2 * s * k.
+
+a "chunk info page" is divided into 512 64-bit integers describing up to 255
+chunks and a pointer to another chunk info page. for each n from 0 to 254:
+ if the (2 * n)'th integer (where the first integer is the 0th one) is 0:
+ the (2 * n + 1)'th integer is unused.
+ if the (2 * n)'th integer is not 0:
+ the (2 * n)'th integer describes the length of a chunk
+ the (2 * n + 1)'th integer describes the start of the same chunk
+the 510th integer is a pointer to the next chunk info page, and the 511th
+integer is never used.
+
+when a program calls new or malloc with needed size s, we find a free chunk of
+length at least s + 8. we then remove that chunk from the list of free chunks,
+and add back in whatever is left after the first s + 8 bytes, if anything.
+in the first 8 bytes of the original chunk, we store the value s + 8. the
+remainder of the orginal chunk is returned to the program.
+
+during that process, if there isn't a chunk with the needed size, one or more
+new pages are requested from the kernel to create such a chunk.
+
+when a program calls delete or free with pointer ptr, we read the integer in
+the 8 bytes starting at ptr - 8 into a variable s. we then add the region
+starting at ptr - 8 with length s to the free memory.
diff --git a/documentation/panics.txt b/documentation/panics.txt
new file mode 100644
index 0000000..e1b6ec1
--- /dev/null
+++ b/documentation/panics.txt
@@ -0,0 +1,8 @@
+when the kernel panics, it fills the screen with a color indicating the type of
+panic. the following are the defined colors so far:
+ #48a6ed - failed to get root node of initfs
+ #5f8860 - no initfs module was given
+ #7e874d - failed to look up /bin/init
+ #9af5e6 - an unimplemented path in the kernel
+ #ba40bb - cpu exception occurred
+ #c39db3 - failed to parse /bin/init
diff --git a/documentation/sockets.txt b/documentation/sockets.txt
new file mode 100644
index 0000000..73dade6
--- /dev/null
+++ b/documentation/sockets.txt
@@ -0,0 +1,28 @@
+in hilbert os, a "socket" is a two-way byte-wise communication construct. each
+socket has two ends, which can be either open or closed. each process has a
+number of handles to sockets. sockets can be created in one of two ways: either
+creating a private socket or connecting to a socket listener.
+
+private sockets:
+ a private socket is created with the "create private socket" system call. the
+ process creating the socket gets both ends of the socket.
+
+socket listeners:
+ a socket listener is created with the "create socket listener" system call.
+ an id string is passed to that system call and remains associated with the
+ listener throughout its lifetime. only one socket listener may have a given
+ id at once. while a socket listener exists, the owner of the listener can
+ call the "accept socket connection" system call, and any process can call the
+ "connect to socket" system call with that id passed. each of these system
+ calls blocks until the other occurs, at which point a socket is created with
+ the two process as its endpoints, and then both system calls return. the
+ listener remains alive after the socket is created, and can be used to create
+ more sockets until stopped with the "stop socket listener" system call.
+
+when a process is created, an end of a socket can be "gifted" to that process.
+when that happens, the end remains open, and is now accessible by the giftee
+and not by the gifter.
+
+when either end of a socket is closed, the other end of the socket remains
+valid, and can be read from until empty. when both ends of a socket are closed,
+the socket disappears.
diff --git a/documentation/syscalls.txt b/documentation/syscalls.txt
index 15aabfa..52e909d 100644
--- a/documentation/syscalls.txt
+++ b/documentation/syscalls.txt
@@ -3,19 +3,32 @@ on application entry:
executable with guard pages on either side, and rsp is
set to the top of that. all other registers are set to 0.
+the ARGC environment variable holds the number of arguments to main.
+the ARGV0, ARGV1, ARGV2, etc environment variables hold those arguments.
+
for all system calls:
rax, rdi, rsi, rdx are in/out paramters.
rbx, rbp, rsp, r12-r15 are preserved.
rcx, rflags, r8-r11 are clobbered.
-file result:
- 0 = success
- 1 = bad file handle
- 2 = device error
- 3 = file system corrupt
- 4 = tried to read out of bounds
- 5 = file does not exist
- 6 = tried to open directory
+interrupts (including the timer!) are disabled during system calls.
+
+stream result:
+ 0 = success
+ 1 = bad handle
+ 2 = io error
+ 3 = out of bounds
+ 4 = does not exist
+ 5 = not a regular file
+ 6 = not an executable
+ 7 = not writable
+ 8 = not seekable
+ 9 = socket id already used
+ 10 = socket id not in use
+ 11 = socket listener closed
+ 12 = other end closed
+ 13 = already exists
+ 14 = not sized
encode color:
rax in: 0
@@ -34,39 +47,122 @@ open file:
rax in: 2
rdi in: pointer to file path
rsi in: file path length
- rax out: file result
- rdi out: file handle (if rax = success)
+ rdx in:
+ bit 0: allow creation
+ bit 1: only allow creation
+ rax out: stream result
+ rdi out: stream handle (if rax = success)
-get file length:
+end this thread:
rax in: 3
- rdi in: file handle
- rax out: file result
- rdi out: file length (if rax = success)
+ edi in: exit code (signed, only used if this was last thread)
-read from file:
+get new pages:
rax in: 4
- rdi in: pointer to request struct
- rax out: file result
- request struct:
- qword: file handle
- qword: start offset in bytes
- qword: length in bytes
- qword: pointer to buffer
+ rdi in: number of pages to allocate
+ rax out: start of first page
+ the allocated pages are next to each other, writable, and not executable.
-end this process:
+read key packet:
rax in: 5
- edi in: exit code (signed)
+ eax out: key packet
-get new pages:
+create private socket:
rax in: 6
- rdi in: number of pages to allocate
- rax out: start of first page
- the allocated pages are next to each other, writable, and not executable.
+ rax out: end 1 stream handle
+ rdi out: end 2 stream handle
-close file:
+create socket listener:
rax in: 7
- rdi in: file handle
+ rdi in: pointer to id string
+ rsi in: id string length
+ rax out: stream result
+ rdi out: listener handle (if rax = 0)
-read key packet:
+stop socket listener:
rax in: 8
- eax out: key packet
+ rdi in: listener handle
+
+accept socket connection:
+ rax in: 9
+ rdi in: listener handle
+ rax out: stream result
+ rdi out: stream handle
+
+connect to socket:
+ rax in: 10
+ rdi in: pointer to id string
+ rsi in: id string length
+ rax out: stream result
+ rdi out: stream handle (if rax = 0)
+ if the listener is closed while this syscall is blocked, rax is
+ set to "socket id not in use" and not "socket listener closed"
+
+close stream:
+ rax in: 11
+ rdi in: stream handle
+
+seek stream:
+ returns "not seekable" for sockets
+ rax in: 12
+ rdi in: stream handle
+ sil in:
+ 0 = relative to beginning
+ 1 = relative to end
+ 2 = relative to current position
+ rdx in: offset (signed)
+ rax out: stream result
+
+read from stream:
+ rax in: 13
+ rdi in: stream handle
+ rsi in: count
+ rdx in: pointer to buffer
+ rax out: stream result
+
+write to stream:
+ rax in: 14
+ rdi in: stream handle
+ rsi in: count
+ rdx in: pointer to buffer
+ rax out: stream result
+
+get stream length:
+ returns "not sized" for sockets
+ rax in: 15
+ rdi in: stream handle
+ rax out: stream result
+ rdi out: stream length (if rax = success)
+
+start process:
+ rax in: 16
+ rdi in: pointer to process start info struct
+ rax out: stream result
+ rdi out: process handle (if rax = success)
+ process start info struct:
+ qword: file path length
+ qword: pointer to file path
+ qword: count of environment variables
+ qword: pointer to array of environment variable structs
+ qword: count of gifted stream ends
+ qword: pointer to array of gifted stream structs
+ environment variable struct:
+ qword: name length
+ qword: pointer to name
+ qword: value length
+ qword: pointer to value
+ gifted stream struct:
+ qword: stream handle here
+ qword: new stream handle in child
+ new handle must be < 65536
+
+end this process:
+ rax in: 17
+ edi in: exit code (signed)
+
+set stream length:
+ returns "not sized" for sockets
+ rax in: 18
+ rdi in: stream handle
+ rsi in: new length
+ rax out: stream result
diff --git a/euler/include/cstdio b/euler/include/cstdio
new file mode 100644
index 0000000..27073db
--- /dev/null
+++ b/euler/include/cstdio
@@ -0,0 +1,15 @@
+#pragma once
+
+#include <euler/stream.hpp>
+#include <stddef.h>
+
+namespace std {
+
+ typedef euler::stream FILE;
+
+ FILE *fopen(const char *filename, const char *mode);
+ int fclose(FILE *stream);
+
+ size_t fread(void *buffer, size_t size, size_t count, FILE *stream);
+
+}
diff --git a/euler/include/cstring b/euler/include/cstring
new file mode 100644
index 0000000..45bc94e
--- /dev/null
+++ b/euler/include/cstring
@@ -0,0 +1,8 @@
+#pragma once
+
+#include <stddef.h>
+
+namespace std {
+ size_t strlen(const char *str);
+ void *memcpy(void *dest, const void *src, size_t count);
+}
diff --git a/euler/include/euler/heap.hpp b/euler/include/euler/heap.hpp
new file mode 100644
index 0000000..e2a4852
--- /dev/null
+++ b/euler/include/euler/heap.hpp
@@ -0,0 +1,8 @@
+#pragma once
+
+#include <stdint.h>
+
+namespace euler {
+ void *alloc(uint64_t bytes);
+ void dealloc(void *start, uint64_t bytes);
+}
diff --git a/euler/include/euler/stream.hpp b/euler/include/euler/stream.hpp
new file mode 100644
index 0000000..a364ec4
--- /dev/null
+++ b/euler/include/euler/stream.hpp
@@ -0,0 +1,48 @@
+#pragma once
+
+#include <euler/syscall.hpp>
+
+namespace euler {
+
+ class stream {
+
+ public:
+ virtual ~stream();
+ virtual bool try_read(void *into, uint64_t bytes) = 0;
+ virtual bool try_seek(__euler_seek_from from, int64_t offset) = 0;
+
+ };
+
+ class file_stream : public stream {
+
+ private:
+
+ __euler_stream_handle handle;
+ bool is_readable;
+ bool is_writable;
+ uint64_t length;
+ uint64_t offset;
+
+ uint8_t *buffer;
+ uint64_t buffer_offset;
+ uint64_t buffer_size;
+ bool buffer_dirty;
+
+ void write_buffer();
+
+ public:
+
+ bool good;
+
+ file_stream(
+ __euler_stream_handle handle, bool is_readable, bool is_writable,
+ bool clear, bool seek_to_end);
+
+ ~file_stream();
+
+ bool try_read(void *into, uint64_t bytes) override;
+ bool try_seek(__euler_seek_from from, int64_t offset) override;
+
+ };
+
+}
diff --git a/euler/include/euler/syscall.hpp b/euler/include/euler/syscall.hpp
new file mode 100644
index 0000000..9255642
--- /dev/null
+++ b/euler/include/euler/syscall.hpp
@@ -0,0 +1,61 @@
+#pragma once
+
+#include <stdint.h>
+
+enum __euler_stream_result : uint64_t {
+ __EULER_SR_SUCCESS = 0,
+ __EULER_SR_BAD_HANDLE,
+ __EULER_SR_IO_ERROR,
+ __EULER_SR_OUT_OF_BOUNDS,
+ __EULER_SR_DOES_NOT_EXIST,
+ __EULER_SR_NOT_A_REGULAR_FILE,
+ __EULER_SR_NOT_AN_EXECUTABLE,
+ __EULER_SR_NOT_WRITABLE,
+ __EULER_SR_NOT_SEEKABLE,
+ __EULER_SR_SOCKET_ID_ALREADY_IN_USE,
+ __EULER_SR_SOCKET_ID_NOT_IN_USE,
+ __EULER_SR_SOCKET_LISTENER_CLOSED,
+ __EULER_SR_OTHER_END_CLOSED,
+ __EULER_SR_ALREADY_EXISTS,
+ __EULER_SR_NOT_SIZED
+};
+
+enum __euler_seek_from : uint8_t {
+ __EULER_SF_BEGINNING = 0,
+ __EULER_SF_END,
+ __EULER_SF_CURRENT_POSITION
+};
+
+typedef uint64_t __euler_stream_handle;
+
+extern "C" __euler_stream_result __euler_open_file(
+ const char *path, uint64_t path_len, __euler_stream_handle &handle_out,
+ bool allow_creation, bool only_allow_creation);
+
+extern "C" [[noreturn]] void __euler_end_this_thread(int32_t exit_code);
+
+extern "C" __euler_stream_result __euler_seek_stream(
+ __euler_stream_handle handle, __euler_seek_from from, int64_t offset);
+
+extern "C" __euler_stream_result __euler_set_stream_length(
+ __euler_stream_handle handle, uint64_t new_length);
+
+extern "C" void __euler_close_stream(__euler_stream_handle handle);
+
+extern "C" __euler_stream_result __euler_get_stream_length(
+ __euler_stream_handle handle, uint64_t &length_out);
+
+extern "C" void *__euler_get_new_pages(uint64_t count);
+
+extern "C" __euler_stream_result __euler_write_to_stream(
+ __euler_stream_handle handle, uint64_t count, const void *buffer);
+
+extern "C" __euler_stream_result __euler_read_from_stream(
+ __euler_stream_handle handle, uint64_t count, void *buffer);
+
+extern "C" uint32_t *__euler_get_framebuffer(
+ uint32_t &width_out, uint32_t &height_out, uint32_t &pitch_out);
+
+extern "C" uint32_t __euler_encode_color(uint8_t r, uint8_t g, uint8_t b);
+
+extern "C" uint32_t __euler_read_key_packet();
diff --git a/euler/makefile b/euler/makefile
new file mode 100644
index 0000000..3b8022d
--- /dev/null
+++ b/euler/makefile
@@ -0,0 +1,29 @@
+LIBSTDCPP_SOURCES = euler/stream.cpp strings/strlen.cpp euler/syscall.asm \
+ euler/entry.cpp io/fopen.cpp euler/gcc.asm memory/delete.cpp euler/heap.cpp \
+ memory/new.cpp io/fclose.cpp io/fread.cpp strings/memcpy.cpp
+
+clean:
+ rm -rf build
+
+build/%.asm.o: source/%.asm
+ @mkdir -p $(@D)
+ $(HILBERT_NASM) $^ -o $@
+
+build/%.cpp.o: source/%.cpp
+ @mkdir -p $(@D)
+ $(HILBERT_CC) -c $^ -o $@
+
+build/crt0.o: build/empty.asm.o
+ cp $^ $@
+
+build/libc.a: build/empty.asm.o
+ $(HILBERT_AR) rcs $@ $^
+
+build/libg.a: build/empty.asm.o
+ $(HILBERT_AR) rcs $@ $^
+
+build/libm.a: build/empty.asm.o
+ $(HILBERT_AR) rcs $@ $^
+
+build/libstdc++.a: ${LIBSTDCPP_SOURCES:%=build/%.o}
+ $(HILBERT_AR) rcs $@ $^
diff --git a/euler/source/empty.asm b/euler/source/empty.asm
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/euler/source/empty.asm
diff --git a/euler/source/euler/entry.cpp b/euler/source/euler/entry.cpp
new file mode 100644
index 0000000..69611b7
--- /dev/null
+++ b/euler/source/euler/entry.cpp
@@ -0,0 +1,11 @@
+#include <euler/syscall.hpp>
+
+int main(int argc, char **argv);
+
+extern "C" [[noreturn]] void _start() {
+ //TODO: call global constructors
+ //TODO: get argc, argv from environment
+ int exit_code = main(0, 0);
+ //TODO: call global destructors
+ __euler_end_this_thread(exit_code);
+}
diff --git a/euler/source/euler/gcc.asm b/euler/source/euler/gcc.asm
new file mode 100644
index 0000000..6fc6fd5
--- /dev/null
+++ b/euler/source/euler/gcc.asm
@@ -0,0 +1,53 @@
+bits 64
+
+global strlen
+
+section .text
+
+strlen:
+ xor rax, rax
+.loop:
+ mov rdx, qword [rdi]
+ test edx, 0xff
+ jz .plus0
+ test edx, 0xff00
+ jz .plus1
+ test edx, 0xff0000
+ jz .plus2
+ test edx, 0xff000000
+ jz .plus3
+ shr rdx, 32
+ test edx, 0xff
+ jz .plus4
+ test edx, 0xff00
+ jz .plus5
+ test edx, 0xff0000
+ jz .plus6
+ test edx, 0xff000000
+ jz .plus7
+ add rax, 8
+ add rdi, 8
+ jmp .loop
+.plus0:
+ ret
+.plus1:
+ add rax, 1
+ ret
+.plus2:
+ add rax, 2
+ ret
+.plus3:
+ add rax, 3
+ ret
+.plus4:
+ add rax, 4
+ ret
+.plus5:
+ add rax, 5
+ ret
+.plus6:
+ add rax, 6
+ ret
+.plus7:
+ add rax, 7
+ ret
diff --git a/euler/source/euler/heap.cpp b/euler/source/euler/heap.cpp
new file mode 100644
index 0000000..f7d407f
--- /dev/null
+++ b/euler/source/euler/heap.cpp
@@ -0,0 +1,66 @@
+#include <euler/syscall.hpp>
+#include <euler/heap.hpp>
+
+namespace euler {
+
+ static uint64_t *last_chunk_info_page = 0;
+
+ void add_record(uint64_t start, uint64_t length) {
+ uint64_t dual_start = start ^ length;
+ for (uint64_t *cip = last_chunk_info_page; cip; cip = (uint64_t *)cip[510])
+ for (int i = 0; i < 255; ++i)
+ if (cip[i * 2] == length && cip[i * 2 + 1] == dual_start) {
+ cip[i * 2] = length * 2;
+ cip[i * 2 + 1] &= start;
+ return;
+ }
+ for (uint64_t *cip = last_chunk_info_page; cip; cip = (uint64_t *)cip[510])
+ for (int i = 0; i < 255; ++i)
+ if (cip[i * 2] == 0) {
+ cip[i * 2] = length;
+ cip[i * 2 + 1] = start;
+ return;
+ }
+ uint64_t *new_cip = (uint64_t *)__euler_get_new_pages(1);
+ new_cip[0] = length;
+ new_cip[1] = start;
+ for (int i = 1; i < 255; ++i)
+ new_cip[i * 2] = 0;
+ new_cip[510] = (uint64_t)last_chunk_info_page;
+ last_chunk_info_page = new_cip;
+ }
+
+ void *alloc(uint64_t bytes) {
+ for (uint64_t *cip = last_chunk_info_page; cip; cip = (uint64_t *)cip[510])
+ for (int i = 0; i < 255; ++i)
+ if (cip[i * 2] >= bytes) {
+ uint64_t start = cip[i * 2 + 1];
+ uint64_t extra_length = cip[i * 2] - bytes;
+ cip[i * 2] = 0;
+ if (extra_length > 0)
+ dealloc((void *)(start + bytes), extra_length);
+ return (void *)start;
+ }
+ uint64_t pages_needed = (bytes - 1) / 4096 + 1;
+ uint64_t start = (uint64_t)__euler_get_new_pages(pages_needed);
+ if (bytes != pages_needed * 4096)
+ dealloc((void *)(start + bytes), pages_needed * 4096 - bytes);
+ return (void *)start;
+ }
+
+ //this implementation is a little lazy
+ void dealloc(void *start, uint64_t bytes) {
+ uint64_t s = (uint64_t)start;
+ while (bytes > 0) {
+ uint64_t l = 1;
+ do
+ l *= 2;
+ while (l <= bytes && s % l == 0);
+ l /= 2;
+ add_record(s, l);
+ s += l;
+ bytes -= l;
+ }
+ }
+
+}
diff --git a/euler/source/euler/stream.cpp b/euler/source/euler/stream.cpp
new file mode 100644
index 0000000..950f3c5
--- /dev/null
+++ b/euler/source/euler/stream.cpp
@@ -0,0 +1,151 @@
+#include <euler/stream.hpp>
+#include <cstring>
+
+namespace euler {
+
+ stream::~stream() {}
+
+ void file_stream::write_buffer() {
+ if (__euler_write_to_stream(handle, buffer_size, buffer)
+ != __EULER_SR_SUCCESS)
+ good = false;//TODO: more precise error reporting
+ else
+ buffer_dirty = false;
+ }
+
+ file_stream::file_stream(
+ __euler_stream_handle handle, bool is_readable, bool is_writable,
+ bool clear, bool seek_to_end)
+
+ : handle(handle), is_readable(is_readable), is_writable(is_writable),
+ buffer(0), good(true) {
+
+ if (clear) {
+ if (__euler_set_stream_length(handle, 0) != __EULER_SR_SUCCESS) {
+ good = false;
+ return;
+ }
+ length = 0;
+ }
+
+ else if (__euler_get_stream_length(handle, length) != __EULER_SR_SUCCESS) {
+ good = false;
+ return;
+ }
+
+ if (seek_to_end) {
+ if (__euler_seek_stream(handle, __EULER_SF_END, 0)
+ != __EULER_SR_SUCCESS) {
+ good = false;
+ return;
+ }
+ offset = length;
+ }
+
+ else
+ offset = 0;
+
+ }
+
+ file_stream::~file_stream() {
+ if (buffer) {
+ if (buffer_dirty)
+ write_buffer();
+ delete[] buffer;
+ }
+ __euler_close_stream(handle);
+ }
+
+ bool file_stream::try_read(void *into, uint64_t bytes) {
+
+ if (bytes == 0)
+ return true;
+
+ if (offset + bytes > length)
+ return false;
+
+ if (buffer) {
+ uint64_t start = offset > buffer_offset ? offset : buffer_offset;
+ uint64_t end = offset + bytes < buffer_offset + buffer_size
+ ? offset + bytes : buffer_offset + buffer_size;
+ if (end > start) {
+
+ uint64_t real_end = offset + bytes;
+
+ std::memcpy(
+ (uint8_t *)into + start - offset, buffer + start - buffer_offset,
+ end - start);
+ if (start != offset)
+ if (!try_read(into, start - offset))
+ return false;
+
+ if (end != real_end) {
+ if (!try_seek(__EULER_SF_BEGINNING, end))
+ return false;
+ if (!try_read((uint8_t *)into + end, real_end - end))
+ return false;
+ }
+
+ else if (offset != real_end)
+ if (!try_seek(__EULER_SF_BEGINNING, real_end))
+ return false;
+
+ return true;
+
+ }
+ }
+
+ if (buffer_dirty) {
+ write_buffer();
+ if (!good)
+ return false;
+ }
+
+ //1024 is arbitrary
+ buffer_size = length - offset < 1024 ? length - offset : 1024;
+
+ if (buffer != 0)
+ delete[] buffer;
+
+ buffer = new uint8_t[buffer_size];
+ buffer_dirty = false;
+ buffer_offset = offset;
+
+ if (__euler_read_from_stream(handle, buffer_size, buffer)
+ != __EULER_SR_SUCCESS) {
+ delete[] buffer;
+ buffer = 0;
+ return false;
+ }
+
+ uint64_t read_this_buffer = buffer_size < bytes ? buffer_size : bytes;
+ std::memcpy(into, buffer, read_this_buffer);
+ offset += read_this_buffer;
+
+ if (read_this_buffer == bytes)
+ return true;
+
+ return try_read(
+ (uint8_t *)into + read_this_buffer, bytes - read_this_buffer);
+
+ }
+
+ bool file_stream::try_seek(__euler_seek_from from, int64_t offset) {
+ if (__euler_seek_stream(handle, from, offset) != __EULER_SR_SUCCESS)
+ return false;
+ switch (from) {
+ case __EULER_SF_BEGINNING:
+ this->offset = offset;
+ return true;
+ case __EULER_SF_END:
+ this->offset = length + offset;
+ return true;
+ case __EULER_SF_CURRENT_POSITION:
+ this->offset += offset;
+ return true;
+ default:
+ return false;
+ }
+ }
+
+}
diff --git a/euler/source/euler/syscall.asm b/euler/source/euler/syscall.asm
new file mode 100644
index 0000000..34f2735
--- /dev/null
+++ b/euler/source/euler/syscall.asm
@@ -0,0 +1,102 @@
+bits 64
+
+global __euler_open_file
+global __euler_close_stream
+global __euler_get_new_pages
+global __euler_write_to_stream
+global __euler_seek_stream
+global __euler_get_stream_length
+global __euler_set_stream_length
+global __euler_end_this_thread
+global __euler_read_from_stream
+global __euler_get_framebuffer
+global __euler_encode_color
+global __euler_read_key_packet
+
+section .text
+
+__euler_open_file:
+ mov rax, 2
+ push rdx
+ xor rdx, rdx
+ or rdx, r8
+ shl r9, 1
+ or rdx, r9
+ syscall
+ pop rdx
+ mov qword [rdx], rdi
+ ret
+
+__euler_close_stream:
+ mov rax, 11
+ syscall
+ ret
+
+__euler_get_new_pages:
+ mov rax, 4
+ syscall
+ ret
+
+__euler_write_to_stream:
+ mov rax, 14
+ syscall
+ ret
+
+__euler_seek_stream:
+ mov rax, 12
+ syscall
+ ret
+
+__euler_get_stream_length:
+ push rsi
+ mov rax, 15
+ syscall
+ pop rsi
+ mov qword [rsi], rdi
+ ret
+
+__euler_set_stream_length:
+ mov rax, 18
+ syscall
+ ret
+
+__euler_end_this_thread:
+ mov rax, 3
+ syscall
+
+__euler_read_from_stream:
+ mov rax, 13
+ syscall
+ ret
+
+__euler_get_framebuffer:
+ push rdi
+ push rsi
+ push rdx
+ mov rax, 1
+ syscall
+ pop rdx
+ mov dword [rdx], esi
+ pop rdx
+ pop rsi
+ mov dword [rsi], edi
+ shr rdi, 32
+ mov dword [rdx], edi
+ ret
+
+__euler_encode_color:
+ xor ah, ah
+ mov al, dl
+ shl ax, 8
+ mov al, sil
+ shl eax, 8
+ mov al, dil
+ mov edi, eax
+ xor rax, rax
+ syscall
+ ret
+
+__euler_read_key_packet:
+ mov rax, 5
+ syscall
+ ret
diff --git a/euler/source/io/fclose.cpp b/euler/source/io/fclose.cpp
new file mode 100644
index 0000000..6f43f85
--- /dev/null
+++ b/euler/source/io/fclose.cpp
@@ -0,0 +1,10 @@
+#include <cstdio>
+
+namespace std {
+
+ int fclose(FILE *stream) {
+ delete stream;
+ return 0;
+ }
+
+}
diff --git a/euler/source/io/fopen.cpp b/euler/source/io/fopen.cpp
new file mode 100644
index 0000000..8d47bf0
--- /dev/null
+++ b/euler/source/io/fopen.cpp
@@ -0,0 +1,54 @@
+#include <stdint.h>
+#include <cstring>
+#include <cstdio>
+
+namespace std {
+
+ FILE *fopen(const char *filename, const char *mode) {
+
+ bool read = false;
+ bool write = false;
+ bool append = false;
+ bool extended = false;
+ bool create = false;
+
+ for (const char *p = mode; *p; ++p)
+ switch (*p) {
+ case 'r':
+ read = true;
+ continue;
+ case 'w':
+ write = true;
+ continue;
+ case 'a':
+ append = true;
+ continue;
+ case '+':
+ extended = true;
+ continue;
+ case 'x':
+ create = true;
+ continue;
+ default:
+ continue;
+ }
+
+ __euler_stream_handle handle;
+ __euler_stream_result res = __euler_open_file(
+ filename, strlen(filename), handle, write || append, create);
+
+ if (res != __EULER_SR_SUCCESS)
+ return 0;
+
+ euler::file_stream *f = new euler::file_stream(handle, read || extended,
+ write || extended, write && !append, append);
+
+ if (f->good)
+ return f;
+
+ delete f;
+ return 0;
+
+ }
+
+}
diff --git a/euler/source/io/fread.cpp b/euler/source/io/fread.cpp
new file mode 100644
index 0000000..e2d05b6
--- /dev/null
+++ b/euler/source/io/fread.cpp
@@ -0,0 +1,9 @@
+#include <cstdio>
+
+namespace std {
+
+ size_t fread(void *buffer, size_t size, size_t count, FILE *stream) {
+ return stream->try_read(buffer, size * count) ? count : 0;
+ }
+
+}
diff --git a/euler/source/memory/delete.cpp b/euler/source/memory/delete.cpp
new file mode 100644
index 0000000..e4cc288
--- /dev/null
+++ b/euler/source/memory/delete.cpp
@@ -0,0 +1,17 @@
+#include <euler/heap.hpp>
+
+void operator delete(void *ptr) {
+ euler::dealloc((uint8_t *)ptr - 8, *(uint64_t *)((uint8_t *)ptr - 8));
+}
+
+void operator delete(void *ptr, uint64_t) {
+ euler::dealloc((uint8_t *)ptr - 8, *(uint64_t *)((uint8_t *)ptr - 8));
+}
+
+void operator delete[](void *ptr) {
+ euler::dealloc((uint8_t *)ptr - 8, *(uint64_t *)((uint8_t *)ptr - 8));
+}
+
+void operator delete[](void *ptr, uint64_t) {
+ euler::dealloc((uint8_t *)ptr - 8, *(uint64_t *)((uint8_t *)ptr - 8));
+}
diff --git a/euler/source/memory/new.cpp b/euler/source/memory/new.cpp
new file mode 100644
index 0000000..931328f
--- /dev/null
+++ b/euler/source/memory/new.cpp
@@ -0,0 +1,13 @@
+#include <euler/heap.hpp>
+
+void *operator new(uint64_t size) {
+ void *ptr = euler::alloc(size + 8);
+ *(uint64_t *)ptr = size + 8;
+ return (uint8_t *)ptr + 8;
+}
+
+void *operator new[](uint64_t size) {
+ void *ptr = euler::alloc(size + 8);
+ *(uint64_t *)ptr = size + 8;
+ return (uint8_t *)ptr + 8;
+}
diff --git a/euler/source/strings/memcpy.cpp b/euler/source/strings/memcpy.cpp
new file mode 100644
index 0000000..d5a1d6c
--- /dev/null
+++ b/euler/source/strings/memcpy.cpp
@@ -0,0 +1,14 @@
+#include <stdint.h>
+#include <cstring>
+
+namespace std {
+
+ void *memcpy(void *dest, const void *src, size_t count) {
+ uint8_t *d8 = (uint8_t *)dest;
+ const uint8_t *s8 = (const uint8_t *)src;
+ for (size_t i = 0; i < count; ++i)
+ d8[i] = s8[i];
+ return dest;
+ }
+
+}
diff --git a/euler/source/strings/strlen.cpp b/euler/source/strings/strlen.cpp
new file mode 100644
index 0000000..7a6fe2a
--- /dev/null
+++ b/euler/source/strings/strlen.cpp
@@ -0,0 +1,12 @@
+#include <cstring>
+
+namespace std {
+
+ size_t strlen(const char *str) {
+ size_t len = 0;
+ while (str[len])
+ ++len;
+ return len;
+ }
+
+}
diff --git a/kernel/application.cpp b/kernel/application.cpp
deleted file mode 100644
index af31a09..0000000
--- a/kernel/application.cpp
+++ /dev/null
@@ -1,280 +0,0 @@
-#include <hilbert/kernel/application.hpp>
-#include <hilbert/kernel/paging.hpp>
-
-//TODO - scheduling.
-
-namespace hilbert::kernel::application {
-
- app_instance::app_instance()
- : state(app_state::paused), framebuffer_vaddr(0) {
-
- uint64_t p4_vaddr;
- paging::map_new_kernel_page(p4_vaddr, p4_paddr);
- p4 = (uint64_t *)p4_vaddr;
-
- uint64_t p3_paddr;
- uint64_t p3_vaddr;
- paging::map_new_kernel_page(p3_vaddr, p3_paddr);
- p3 = (uint64_t *)p3_vaddr;
-
- for (int i = 1; i < 511; ++i)
- p4[i] = 0;
- p4[0] = paging::encode_pte(p3_paddr, true, true, true);
- p4[511] = paging::kernel_p4e;
-
- for (int i = 0; i < 512; ++i) {
- p3[i] = 0;
- p2s[i] = 0;
- p1s[i] = 0;
- p1es_to_free_on_exit[i] = 0;
- }
-
- }
-
- void app_instance::map_page(uint64_t vaddr, uint64_t paddr,
- bool write, bool execute, bool free_pram_on_exit
- ) {
-
- uint64_t i = ((vaddr / 4096) / 512) / 512;
- uint64_t j = ((vaddr / 4096) / 512) % 512;
- uint64_t k = (vaddr / 4096) % 512;
-
- if (p2s[i] == 0) {
- uint64_t p2_paddr;
- uint64_t p2_vaddr;
- paging::map_new_kernel_page(p2_vaddr, p2_paddr);
- p3[i] = paging::encode_pte(p2_paddr, true, true, true);
- p2s[i] = (uint64_t *)p2_vaddr;
- p1s[i] = new uint64_t *[512];
- p1es_to_free_on_exit[i] = new bool *[512];
- for (int u = 0; u < 512; ++u) {
- p2s[i][u] = 0;
- p1s[i][u] = 0;
- p1es_to_free_on_exit[i][u] = 0;
- }
- }
-
- if (p2s[i][j] == 0) {
- uint64_t p1_paddr;
- uint64_t p1_vaddr;
- paging::map_new_kernel_page(p1_vaddr, p1_paddr);
- p2s[i][j] = paging::encode_pte(p1_paddr, true, true, true);
- p1s[i][j] = (uint64_t *)p1_vaddr;
- p1es_to_free_on_exit[i][j] = new bool[512];
- for (int u = 0; u < 512; ++u) {
- p1s[i][j][u] = 0;
- p1es_to_free_on_exit[i][j][u] = false;
- }
- }
-
- p1s[i][j][k] = paging::encode_pte(paddr, true, write, execute);
- p1es_to_free_on_exit[i][j][k] = free_pram_on_exit;
-
- }
-
- bool app_instance::is_page_owned(uint64_t vaddr) {
- uint64_t i = ((vaddr / 4096) / 512) / 512;
- uint64_t j = ((vaddr / 4096) / 512) % 512;
- uint64_t k = (vaddr / 4096) % 512;
- return
- i < 512 && p1s[i] != 0 && p1s[i][j] != 0 &&
- p1s[i][j][k] != 0 && p1es_to_free_on_exit[i][j][k];
- }
-
- uint64_t app_instance::get_free_vaddr_pages(uint64_t count) {
- uint64_t start = 0x200000 / 4096;
- uint64_t length = 0;
- while (start + length <= 0x8000000000 / 4096) {
- if (length == count)
- return start * 4096;
- int i = ((start + length) / 512) / 512;
- int j = ((start + length) / 512) % 512;
- int k = (start + length) % 512;
- if (p1s[i] == 0 || p1s[i][j] == 0 || p1s[i][j][k] == 0)
- ++length;
- else {
- start += length + 1;
- length = 0;
- }
- }
- //TODO: handle out of memory
- return 0;
- }
-
- uint64_t app_instance::count_mapped_vram_pages() {
- uint64_t count = 0;
- for (int i = 0; i < 512; ++i)
- if (p1s[i] != 0)
- for (int j = 0; j < 512; ++j)
- if (p1s[i][j] != 0)
- for (int k = 0; k < 512; ++k)
- if (p1s[i][j][k] != 0)
- ++count;
- return count;
- }
-
- app_instance *running_app;
-
- static uint8_t correct_magic[16] = {
- 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00,
- 0x02, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00
- };
-
-#define READ(a, b, c) \
- { \
- storage::fs_result _result = file.read_file(a, b, c); \
- if (_result == storage::fs_result::device_error) \
- return create_app_result::device_error; \
- if (_result == storage::fs_result::fs_corrupt) \
- return create_app_result::fs_corrupt; \
- }
-
- struct load_info {
- uint64_t foffset;
- uint64_t fsize;
- uint64_t vaddr;
- uint64_t vpages;
- bool writable;
- bool executable;
- };
-
- create_app_result create_app(
- const vfile::vfile &file, app_instance *&out,
- const vfile::vfile &working_dir
- ) {
-
- uint8_t magic[16];
- if (file.dir_entry.length < 64)
- return create_app_result::app_corrupt;
- READ(0, 8, magic)
- READ(16, 8, magic + 8)
- for (int i = 0; i < 16; ++i)
- if (magic[i] != correct_magic[i])
- return create_app_result::app_corrupt;
-
- uint64_t entry_point;
- uint64_t phead_start;
- uint16_t phead_entry_size;
- uint16_t phead_entry_count;
-
- READ(24, 8, &entry_point)
- READ(32, 8, &phead_start)
- READ(54, 2, &phead_entry_size)
- READ(56, 2, &phead_entry_count)
-
- if (file.dir_entry.length <
- phead_start + phead_entry_size * phead_entry_count)
- return create_app_result::app_corrupt;
-
- utility::vector<load_info> load_infos;
-
- for (uint16_t i = 0; i < phead_entry_count; ++i) {
-
- uint64_t entry_start = phead_start + phead_entry_size * i;
-
- uint32_t seg_type;
- READ(entry_start, 4, &seg_type)
- if (seg_type != 1)
- continue;
-
- uint64_t foffset;
- uint64_t vaddr;
- uint64_t fsize;
- uint64_t vsize;
- uint32_t flags;
-
- READ(entry_start + 8, 8, &foffset)
- READ(entry_start + 16, 8, &vaddr)
- READ(entry_start + 32, 8, &fsize)
- READ(entry_start + 40, 8, &vsize)
- READ(entry_start + 4, 4, &flags)
-
- if (vaddr & 4095)
- return create_app_result::app_corrupt;
- if (file.dir_entry.length < foffset + fsize)
- return create_app_result::app_corrupt;
- if (fsize > vsize)
- return create_app_result::app_corrupt;
-
- if (vaddr < 0x200000)
- return create_app_result::app_corrupt;
-
- uint64_t vpages = (vsize - 1) / 4096 + 1;
-
- if (vaddr + vpages * 4096 > 0x8000000000)
- return create_app_result::app_corrupt;
-
- load_info info = {
- .foffset = foffset,
- .fsize = fsize,
- .vaddr = vaddr,
- .vpages = vpages,
- .writable = (flags & 2) == 2,
- .executable = (flags & 1) == 1
- };
- load_infos.add_end(info);
-
- }
-
- out = new app_instance();
-
- for (unsigned i = 0; i < load_infos.count; ++i) {
- const auto &info = load_infos.buffer[i];
- for (uint64_t j = 0; j < info.vpages; ++j) {
- uint64_t paddr = paging::take_pram_page();
- out->map_page(info.vaddr + j * 4096, paddr,
- info.writable, info.executable, true);
- uint64_t kvaddr = paging::find_unmapped_vram_region(1);
- paging::map_kernel_page(paddr, kvaddr, true, false);
- storage::fs_result result = storage::fs_result::success;
- if (info.fsize > j * 4096) {
- if (info.fsize >= j * 4096 + 4096)
- result = file.read_file(
- info.foffset + j * 4096, 4096, (void *)kvaddr);
- else {
- int to_read = info.fsize - j * 4096;
- result = file.read_file(
- info.foffset + j * 4096, to_read, (void *)kvaddr);
- uint8_t *blank = (uint8_t *)(kvaddr + to_read);
- for (int i = 0; i < 4096 - to_read; ++i)
- blank[i] = 0;
- }
- }
- else {
- uint8_t *blank = (uint8_t *)kvaddr;
- for (int i = 0; i < 4096; ++i)
- blank[i] = 0;
- }
- paging::unmap_kernel_page(kvaddr);
- if (result == storage::fs_result::device_error) {
- delete out;
- return create_app_result::device_error;
- }
- if (result == storage::fs_result::fs_corrupt) {
- delete out;
- return create_app_result::fs_corrupt;
- }
- }
- }
-
- for (uint64_t vaddr = 0x1000; vaddr < 0x1ff000; vaddr += 4096) {
- uint64_t paddr = paging::take_pram_page();
- uint64_t kvaddr = paging::find_unmapped_vram_region(1);
- paging::map_kernel_page(paddr, kvaddr, true, false);
- uint8_t *p = (uint8_t *)kvaddr;
- for (int i = 0; i < 4096; ++i)
- p[i] = 0;
- paging::unmap_kernel_page(kvaddr);
- out->map_page(vaddr, paddr, true, false, true);
- }
-
- out->saved_regs.rsp = 0x1ff000;
- out->saved_regs.rip = entry_point;
-
- out->working_dir = working_dir;
-
- return create_app_result::success;
-
- }
-
-}
diff --git a/kernel/framebuffer.cpp b/kernel/framebuffer.cpp
deleted file mode 100644
index 08d0e16..0000000
--- a/kernel/framebuffer.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-#include <hilbert/kernel/application.hpp>
-#include <hilbert/kernel/framebuffer.hpp>
-
-namespace hilbert::kernel::framebuffer {
-
- uint64_t paddr;
- static uint32_t *vaddr;
- int width;
- int height;
- int dword_pitch;
-
- void init_framebuffer(uint64_t paddr, uint64_t vaddr,
- uint64_t width, uint64_t height, uint64_t pitch
- ) {
-
- //TODO: assumes 32-bpp rgb
-
- framebuffer::paddr = paddr;
- framebuffer::vaddr = (uint32_t *)vaddr;
- framebuffer::width = width;
- framebuffer::height = height;
- dword_pitch = pitch / 4;
-
- }
-
- color encode_color(uint8_t r, uint8_t g, uint8_t b) {
- return ((uint32_t)r << 16) | ((uint32_t)g << 8) | (uint32_t)b;
- }
-
- void set_pixel(int x, int y, color c) {
- vaddr[y * dword_pitch + x] = c;
- }
-
- void move_region(
- int from_start_x, int from_start_y, int from_end_x,
- int from_end_y, int to_start_x, int to_start_y
- ) {
-
- int region_width = from_end_x - from_start_x;
- int region_height = from_end_y - from_start_y;
-
- int from_start_offset = from_start_y * dword_pitch + from_start_x;
- int to_start_offset = to_start_y * dword_pitch + to_start_x;
-
- if (from_start_offset > to_start_offset)
- for (int y = 0; y < region_height; ++y)
- for (int x = 0; x < region_width; ++x)
- vaddr[to_start_offset + y * dword_pitch + x] =
- vaddr[from_start_offset + y * dword_pitch + x];
-
- else if (from_start_offset < to_start_offset)
- for (int y = region_height - 1; y >= 0; --y)
- for (int x = region_width - 1; x >= 0; --x)
- vaddr[to_start_offset + y * dword_pitch + x] =
- vaddr[from_start_offset + y * dword_pitch + x];
-
- }
-
- void fill_region(int start_x, int start_y, int end_x, int end_y, color c) {
- for (int y = start_y; y < end_y; ++y)
- for (int x = start_x; x < end_x; ++x)
- vaddr[y * dword_pitch + x] = c;
- }
-
-}
diff --git a/kernel/include/hilbert/kernel/application.hpp b/kernel/include/hilbert/kernel/application.hpp
index 51f304d..7d48d8d 100644
--- a/kernel/include/hilbert/kernel/application.hpp
+++ b/kernel/include/hilbert/kernel/application.hpp
@@ -7,21 +7,165 @@
namespace hilbert::kernel::application {
- void init_syscalls();
+ class process;
+ class thread;
- enum class app_state {
+ enum class thread_state {
running,
paused,
- zombie
+ waiting
};
- struct app_instance {
+ enum class stream_result {
+ success,
+ bad_handle,
+ io_error,
+ out_of_bounds,
+ does_not_exist,
+ not_a_regular_file,
+ not_an_executable,
+ not_writable,
+ not_seekable,
+ socket_id_already_used,
+ socket_id_not_in_use,
+ socket_listener_closed,
+ other_end_closed,
+ already_exists,
+ not_sized
+ };
+
+ enum class seek_origin {
+ beginning,
+ end,
+ current_position
+ };
+
+ class stream {
+ public:
+ virtual ~stream() {}
+ virtual stream_result seek(seek_origin origin, int64_t offset) = 0;
+ virtual stream_result read(uint64_t count, void *into) = 0;
+ virtual stream_result write(uint64_t count, const void *from) = 0;
+ virtual stream_result get_length(uint64_t &out) = 0;
+ virtual stream_result set_length(uint64_t to) = 0;
+ };
+
+ class vfile_stream : public stream {
- utility::id_allocator<vfile::vfile> open_files;
+ private:
+ vfile::vfile file;
+ uint64_t offset;
- vfile::vfile working_dir;
+ public:
+ vfile_stream(vfile::vfile &&file);
+ virtual stream_result seek(seek_origin origin, int64_t offset) override;
+ virtual stream_result read(uint64_t count, void *into) override;
+ virtual stream_result write(uint64_t count, const void *from) override;
+ virtual stream_result get_length(uint64_t &out) override;
+ virtual stream_result set_length(uint64_t to) override;
- app_state state;
+ };
+
+ struct socket {
+ utility::queue<thread *> process_a_threads_waiting_to_read;
+ utility::queue<thread *> process_b_threads_waiting_to_read;
+ utility::queue<uint8_t> a_to_b;
+ utility::queue<uint8_t> b_to_a;
+ bool a_closed;
+ bool b_closed;
+ };
+
+ class socket_stream : public stream {
+
+ private:
+ socket *sock;
+ bool are_we_b;
+
+ utility::queue<thread *> &our_threads_waiting_to_read;
+ utility::queue<thread *> &their_threads_waiting_to_read;
+ utility::queue<uint8_t> &them_to_us;
+ utility::queue<uint8_t> &us_to_them;
+ bool &them_closed;
+ bool &us_closed;
+
+ public:
+ socket_stream(socket *sock, bool are_we_b);
+ ~socket_stream();
+ virtual stream_result seek(seek_origin origin, int64_t offset) override;
+ virtual stream_result read(uint64_t count, void *into) override;
+ virtual stream_result write(uint64_t count, const void *from) override;
+ virtual stream_result get_length(uint64_t &out) override;
+ virtual stream_result set_length(uint64_t to) override;
+
+ };
+
+ struct string_pair {
+ utility::string a;
+ utility::string b;
+ };
+
+ struct socket_listener {
+ utility::string id;
+ utility::queue<thread *> waiting_to_accept_connection;
+ utility::queue<thread *> waiting_to_connect;
+ bool is_listening;
+ };
+
+ struct [[gnu::packed]] cpu_state {
+
+ uint64_t rax;
+ uint64_t rbx;
+ uint64_t rcx;
+ uint64_t rdx;
+ uint64_t rdi;
+ uint64_t rsi;
+ uint64_t rbp;
+ uint64_t rsp;
+ uint64_t r8;
+ uint64_t r9;
+ uint64_t r10;
+ uint64_t r11;
+ uint64_t r12;
+ uint64_t r13;
+ uint64_t r14;
+ uint64_t r15;
+
+ uint64_t rflags;
+ uint64_t rip;
+ uint64_t cr3;
+
+ //only used if in_syscall is true. starts at rsp. no red zone
+ //needs to be saved since save_thread_state doesn't use it.
+ void *kernel_stack_copy;
+ bool in_syscall;
+
+ };
+
+ struct thread {
+
+ //propogated to process on destruction if this is the last thread.
+ int exit_code;
+ ~thread();
+
+ process *the_process;
+ thread_state state;
+ //only valid if paused or waiting
+ cpu_state cpu;
+
+ stream *just_connected_to;
+ stream *just_accepted;
+
+ };
+
+ struct process {
+
+ void end_process(unsigned exit_code);
+ void cleanup();
+
+ utility::list<thread *> threads;
+ utility::vector<string_pair> environment;
+ utility::id_allocator<stream *> open_streams;
+ utility::id_allocator<socket_listener *> socket_listeners;
uint64_t *p4;
uint64_t *p3;
@@ -35,17 +179,10 @@ namespace hilbert::kernel::application {
//set to 0 if none
uint64_t framebuffer_vaddr;
- //only valid if state is zombie
+ //only valid if there are no threads
int32_t exit_code;
- //only valid if state is paused
- struct {
- uint64_t rip;
- uint64_t rsp;
- //TODO: etc.
- } saved_regs;
-
- app_instance();
+ process();
//vaddr and paddr must be aligned, and vaddr must be < 0x0080.0000.0000
void map_page(uint64_t vaddr, uint64_t paddr,
@@ -62,16 +199,22 @@ namespace hilbert::kernel::application {
};
- extern app_instance *running_app;
+ extern utility::id_allocator<process *> *processes;
+ extern utility::queue<thread *> *paused_threads;
+ extern utility::queue<thread *> *threads_waiting_for_input;
+ extern thread *running_thread;
+ extern utility::list<socket_listener *> *all_socket_listeners;
- enum class create_app_result {
- success,
- device_error,
- app_corrupt,
- fs_corrupt
- };
+ stream_result create_application(
+ const vfile::vfile &file, process *&process_out, thread *&thread_out);
+
+ void init_applications();
+
+ //returns true when resumed, false right now.
+ //must be called from non-interruptable syscall context.
+ extern "C" bool save_thread_state(cpu_state &into);
- create_app_result create_app(const vfile::vfile &file,
- app_instance *&out, const vfile::vfile &working_dir);
+ //must be called from non-interruptable context
+ [[noreturn]] void resume_next();
}
diff --git a/kernel/include/hilbert/kernel/framebuffer.hpp b/kernel/include/hilbert/kernel/framebuffer.hpp
index fb28462..d4d6b1c 100644
--- a/kernel/include/hilbert/kernel/framebuffer.hpp
+++ b/kernel/include/hilbert/kernel/framebuffer.hpp
@@ -18,14 +18,6 @@ namespace hilbert::kernel::framebuffer {
void set_pixel(int x, int y, color c);
- //[from_start_x, from_end_x) x [from_start_y, from_end_y)
- // -> [to_start_x, ...) x [to_start_y, ...).
- //we assume from_start_x < from_end_x and from_start_y < from_end_y.
- void move_region(
- int from_start_x, int from_start_y, int from_end_x,
- int from_end_y, int to_start_x, int to_start_y);
-
- //[start_x, end_x) x [start_y, end_y)
- void fill_region(int start_x, int start_y, int end_x, int end_y, color c);
+ void fill_color(color c);
}
diff --git a/kernel/include/hilbert/kernel/input.hpp b/kernel/include/hilbert/kernel/input.hpp
index cccb71f..2209ddc 100644
--- a/kernel/include/hilbert/kernel/input.hpp
+++ b/kernel/include/hilbert/kernel/input.hpp
@@ -19,6 +19,8 @@ namespace hilbert::kernel::input {
};
extern utility::queue<uint32_t> *key_queue;
+ //notify a process waiting for input
+ void got_input();
//must be post switch to kernel page tables and mounting of file systems
void init_input();
diff --git a/kernel/include/hilbert/kernel/panic.hpp b/kernel/include/hilbert/kernel/panic.hpp
index 545d703..0478142 100644
--- a/kernel/include/hilbert/kernel/panic.hpp
+++ b/kernel/include/hilbert/kernel/panic.hpp
@@ -1,6 +1,5 @@
#pragma once
namespace hilbert::kernel {
- //prints to terminal and then halts.
- [[noreturn]] void panic(const char *string_sz);
+ [[noreturn]] void panic(uint32_t code);
}
diff --git a/kernel/include/hilbert/kernel/terminal.hpp b/kernel/include/hilbert/kernel/terminal.hpp
deleted file mode 100644
index 350d79b..0000000
--- a/kernel/include/hilbert/kernel/terminal.hpp
+++ /dev/null
@@ -1,32 +0,0 @@
-#pragma once
-
-#include <hilbert/kernel/framebuffer.hpp>
-#include <hilbert/kernel/utility.hpp>
-#include <stddef.h>
-#include <stdint.h>
-
-namespace hilbert::kernel::terminal {
-
- extern uint8_t *termfont;
- extern uint64_t termfont_len;
-
- void init_terminal();
-
- extern int width;
- extern int height;
-
- extern int cursor_x;
- extern int cursor_y;
-
- extern framebuffer::color bg_color;
- extern framebuffer::color fg_color;
-
- void put_char(char ch);
- void put_string(const utility::string &str);
- void put_string_sz(const char *str);
-
- void put_int_decimal(uint64_t n, bool with_commas = true);
-
- void put_int_hex(uint64_t n, int digits, bool with_dots = true);
-
-}
diff --git a/kernel/input.cpp b/kernel/input.cpp
deleted file mode 100644
index 6bed7f5..0000000
--- a/kernel/input.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-#include <hilbert/kernel/input.hpp>
-#include <hilbert/kernel/panic.hpp>
-#include <hilbert/kernel/vfile.hpp>
-
-namespace hilbert::kernel::input {
-
- utility::queue<uint32_t> *key_queue;
-
- void init_input() {
- key_queue = new utility::queue<uint32_t>();
- }
-
-}
diff --git a/kernel/makefile b/kernel/makefile
new file mode 100644
index 0000000..1cb2d52
--- /dev/null
+++ b/kernel/makefile
@@ -0,0 +1,19 @@
+SOURCES = \
+ storage/bd/memory.cpp storage/fs/tarfs.cpp application.asm application.cpp \
+ framebuffer.cpp interrupts.asm interrupts.cpp allocator.cpp storage.cpp \
+ syscall.cpp utility.cpp paging.asm paging.cpp entry.cpp input.cpp panic.cpp \
+ vfile.cpp
+
+build/%.asm.o: source/%.asm
+ @mkdir -p $(@D)
+ $(HILBERT_NASM) $^ -o $@
+
+build/%.cpp.o: source/%.cpp
+ @mkdir -p $(@D)
+ $(HILBERT_CC) -c -ffreestanding -mcmodel=kernel -I ${LIMINE_DIR} $^ -o $@
+
+build/kernel.elf: $(SOURCES:%=build/%.o)
+ $(HILBERT_LD) -T link.ld $^ -o $@
+
+clean:
+ rm -rf build
diff --git a/kernel/panic.cpp b/kernel/panic.cpp
deleted file mode 100644
index 233fcf4..0000000
--- a/kernel/panic.cpp
+++ /dev/null
@@ -1,10 +0,0 @@
-#include <hilbert/kernel/terminal.hpp>
-#include <hilbert/kernel/panic.hpp>
-
-namespace hilbert::kernel {
- [[noreturn]] void panic(const char *string_sz) {
- terminal::put_string_sz(string_sz);
- while (1)
- asm ("hlt");
- }
-}
diff --git a/kernel/allocator.cpp b/kernel/source/allocator.cpp
index 324f992..324f992 100644
--- a/kernel/allocator.cpp
+++ b/kernel/source/allocator.cpp
diff --git a/kernel/source/application.asm b/kernel/source/application.asm
new file mode 100644
index 0000000..ed8b190
--- /dev/null
+++ b/kernel/source/application.asm
@@ -0,0 +1,171 @@
+bits 64
+
+extern do_syscall
+
+section .text
+
+syscall_entry:
+ mov r11, rsp
+ mov rsp, 0xfffffffffffff000
+ push r11
+ push rcx
+
+ push rdx
+ push rsi
+ push rdi
+ push rax
+
+ mov rdi, rsp
+ lea rsi, [rsp + 8]
+ lea rdx, [rsp + 16]
+ lea rcx, [rsp + 24]
+
+ call do_syscall
+
+ pop rax
+ pop rdi
+ pop rsi
+ pop rdx
+
+ xor r8, r8
+ xor r9, r9
+ xor r10, r10
+ xor r11, r11
+ or r11, 0x200
+ pop rcx
+ pop rsp
+
+ o64 sysret
+
+global init_applications_asm
+init_applications_asm:
+
+ ;efer <- efer | 0x1
+ mov rcx, 0xc0000080
+ rdmsr
+ or al, 1
+ wrmsr
+
+ ;lstar <- syscall_entry
+ mov rdx, syscall_entry
+ mov eax, edx
+ shr rdx, 32
+ mov ecx, 0xc0000082
+ wrmsr
+
+ ;star <- 0x0030.0028.0000.0000
+ mov edx, 0x00300028
+ xor eax, eax
+ mov ecx, 0xc0000081
+ wrmsr
+
+ ;sfmask <- 0x0000.0000.0000.0200 (if)
+ xor edx, edx
+ mov eax, 0x200
+ mov ecx, 0xc0000084
+ wrmsr
+
+ ret
+
+section .bss
+
+resume_stack:
+ resb 4096
+
+section .text
+
+extern restore_syscall_stack
+;rdi = pointer to copy
+;rsi = intended rsp
+
+global resume_thread
+resume_thread:
+;rdi = ptr to cpu_state
+;rdi is not inside stack
+;interrupts are disabled
+
+ mov al, byte [rdi + 160] ;in_syscall
+ test al, al
+ jnz .in_syscall
+
+ mov rax, 0x3b
+ mov rbx, 0x43
+
+.common:
+ push rax
+ mov rax, qword [rdi + 56] ;rsp
+ push rax
+ mov rax, qword [rdi + 128] ;rflags
+ push rax
+ push rbx
+ mov rax, qword [rdi + 136] ;rip
+ push rax
+
+ mov rax, qword [rdi + 144] ;cr3
+ mov cr3, rax
+
+ mov rax, qword [rdi]
+ mov rbx, qword [rdi + 8]
+ mov rcx, qword [rdi + 16]
+ mov rdx, qword [rdi + 24]
+ mov rsi, qword [rdi + 40]
+ mov rbp, qword [rdi + 48]
+ mov r8, qword [rdi + 64]
+ mov r9, qword [rdi + 72]
+ mov r10, qword [rdi + 80]
+ mov r11, qword [rdi + 88]
+ mov r12, qword [rdi + 96]
+ mov r13, qword [rdi + 104]
+ mov r14, qword [rdi + 112]
+ mov r15, qword [rdi + 120]
+ mov rdi, qword [rdi + 32]
+
+ iretq
+
+.in_syscall:
+ mov rsp, resume_stack + 4096
+
+ push rdi
+ mov rsi, qword [rdi + 56] ;rsp
+ mov rdi, qword [rdi + 152] ;kernel_stack_copy
+ call restore_syscall_stack
+ pop rdi
+
+ mov rax, 0x30
+ mov rbx, 0x28
+ jmp .common
+
+extern copy_syscall_stack
+;rdi = bottom
+
+global save_thread_state
+save_thread_state:
+;rdi = pointer to cpu state structure
+
+ ;only saving registers that need to be preserved by this function
+ mov qword [rdi + 8], rbx
+ mov qword [rdi + 48], rbp
+ mov qword [rdi + 56], rsp
+ mov qword [rdi + 96], r12
+ mov qword [rdi + 104], r13
+ mov qword [rdi + 112], r14
+ mov qword [rdi + 120], r15
+
+ mov qword [rdi + 136], .resume_to ;rip
+ mov rax, cr3
+ mov qword [rdi + 144], rax ;cr3
+
+ push rdi
+ lea rdi, [rsp + 8]
+ call copy_syscall_stack
+ pop rdi
+
+ mov qword [rdi + 152], rax ;kernel_stack_copy
+ mov byte [rdi + 160], 0x01 ;in_syscall
+
+ xor al, al
+ ret
+
+.resume_to:
+ mov al, 0x01
+ ret
diff --git a/kernel/source/application.cpp b/kernel/source/application.cpp
new file mode 100644
index 0000000..c3ce2f1
--- /dev/null
+++ b/kernel/source/application.cpp
@@ -0,0 +1,550 @@
+#include <hilbert/kernel/application.hpp>
+#include <hilbert/kernel/paging.hpp>
+#include <hilbert/kernel/panic.hpp>
+
+//TODO - scheduling.
+
+namespace hilbert::kernel::application {
+
+ process::process() : framebuffer_vaddr(0) {
+
+ uint64_t p4_vaddr;
+ paging::map_new_kernel_page(p4_vaddr, p4_paddr);
+ p4 = (uint64_t *)p4_vaddr;
+
+ uint64_t p3_paddr;
+ uint64_t p3_vaddr;
+ paging::map_new_kernel_page(p3_vaddr, p3_paddr);
+ p3 = (uint64_t *)p3_vaddr;
+
+ for (int i = 1; i < 511; ++i)
+ p4[i] = 0;
+ p4[0] = paging::encode_pte(p3_paddr, true, true, true);
+ p4[511] = paging::kernel_p4e;
+
+ for (int i = 0; i < 512; ++i) {
+ p3[i] = 0;
+ p2s[i] = 0;
+ p1s[i] = 0;
+ p1es_to_free_on_exit[i] = 0;
+ }
+
+ }
+
+ void process::map_page(uint64_t vaddr, uint64_t paddr,
+ bool write, bool execute, bool free_pram_on_exit
+ ) {
+
+ uint64_t i = ((vaddr / 4096) / 512) / 512;
+ uint64_t j = ((vaddr / 4096) / 512) % 512;
+ uint64_t k = (vaddr / 4096) % 512;
+
+ if (p2s[i] == 0) {
+ uint64_t p2_paddr;
+ uint64_t p2_vaddr;
+ paging::map_new_kernel_page(p2_vaddr, p2_paddr);
+ p3[i] = paging::encode_pte(p2_paddr, true, true, true);
+ p2s[i] = (uint64_t *)p2_vaddr;
+ p1s[i] = new uint64_t *[512];
+ p1es_to_free_on_exit[i] = new bool *[512];
+ for (int u = 0; u < 512; ++u) {
+ p2s[i][u] = 0;
+ p1s[i][u] = 0;
+ p1es_to_free_on_exit[i][u] = 0;
+ }
+ }
+
+ if (p2s[i][j] == 0) {
+ uint64_t p1_paddr;
+ uint64_t p1_vaddr;
+ paging::map_new_kernel_page(p1_vaddr, p1_paddr);
+ p2s[i][j] = paging::encode_pte(p1_paddr, true, true, true);
+ p1s[i][j] = (uint64_t *)p1_vaddr;
+ p1es_to_free_on_exit[i][j] = new bool[512];
+ for (int u = 0; u < 512; ++u) {
+ p1s[i][j][u] = 0;
+ p1es_to_free_on_exit[i][j][u] = false;
+ }
+ }
+
+ p1s[i][j][k] = paging::encode_pte(paddr, true, write, execute);
+ p1es_to_free_on_exit[i][j][k] = free_pram_on_exit;
+
+ }
+
+ bool process::is_page_owned(uint64_t vaddr) {
+ uint64_t i = ((vaddr / 4096) / 512) / 512;
+ uint64_t j = ((vaddr / 4096) / 512) % 512;
+ uint64_t k = (vaddr / 4096) % 512;
+ return
+ i < 512 && p1s[i] != 0 && p1s[i][j] != 0 &&
+ p1s[i][j][k] != 0 && p1es_to_free_on_exit[i][j][k];
+ }
+
+ uint64_t process::get_free_vaddr_pages(uint64_t count) {
+ uint64_t start = 0x200000 / 4096;
+ uint64_t length = 0;
+ while (start + length <= 0x8000000000 / 4096) {
+ if (length == count)
+ return start * 4096;
+ int i = ((start + length) / 512) / 512;
+ int j = ((start + length) / 512) % 512;
+ int k = (start + length) % 512;
+ if (p1s[i] == 0 || p1s[i][j] == 0 || p1s[i][j][k] == 0)
+ ++length;
+ else {
+ start += length + 1;
+ length = 0;
+ }
+ }
+ //TODO: handle out of memory
+ return 0;
+ }
+
+ uint64_t process::count_mapped_vram_pages() {
+ uint64_t count = 0;
+ for (int i = 0; i < 512; ++i)
+ if (p1s[i] != 0)
+ for (int j = 0; j < 512; ++j)
+ if (p1s[i][j] != 0)
+ for (int k = 0; k < 512; ++k)
+ if (p1s[i][j][k] != 0)
+ ++count;
+ return count;
+ }
+
+ utility::id_allocator<process *> *processes;
+ utility::queue<thread *> *paused_threads;
+ utility::queue<thread *> *threads_waiting_for_input;
+ thread *running_thread;
+ utility::list<socket_listener *> *all_socket_listeners;
+
+ static uint8_t correct_magic[16] = {
+ 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00,
+ 0x02, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00
+ };
+
+#define READ(a, b, c) \
+ { \
+ storage::fs_result _result = file.read_file(a, b, c); \
+ if (_result != storage::fs_result::success) \
+ return stream_result::io_error; \
+ }
+
+#define TRY_MAR(expr) \
+ { \
+ storage::fs_result _result = expr; \
+ if (_result != storage::fs_result::success) { \
+ delete process_out; \
+ return stream_result::io_error; \
+ } \
+ }
+
+ struct load_info {
+ uint64_t foffset;
+ uint64_t fsize;
+ uint64_t vaddr;
+ uint64_t voffset;
+ uint64_t vpages;
+ bool writable;
+ bool executable;
+ };
+
+ storage::fs_result map_and_read(
+ const vfile::vfile &file, process *process, uint64_t vaddr, uint64_t faddr,
+ uint64_t len, bool writable, bool executable
+ ) {
+
+ uint64_t page_vaddr = vaddr & ~4095;
+ int at_start = vaddr & 4095;
+ int at_end = 4096 - len - at_start;
+
+ uint64_t page_paddr = paging::take_pram_page();
+ process->map_page(page_vaddr, page_paddr, writable, executable, true);
+ uint64_t page_kvaddr = paging::find_unmapped_vram_region(1);
+ paging::map_kernel_page(page_paddr, page_kvaddr, true, false);
+
+ storage::fs_result result = storage::fs_result::success;
+
+ if (at_start) {
+ uint8_t *blank = (uint8_t *)page_kvaddr;
+ for (int i = 0; i < at_start; ++i)
+ blank[i] = 0;
+ }
+
+ if (len != 0)
+ result = file.read_file(faddr, len, (void *)(page_kvaddr + at_start));
+
+ if (at_end) {
+ uint8_t *blank = (uint8_t *)(page_kvaddr + at_start + len);
+ for (int i = 0; i < at_end; ++i)
+ blank[i] = 0;
+ }
+
+ paging::unmap_kernel_page(page_kvaddr);
+ return result;
+
+ }
+
+ stream_result create_application(
+ const vfile::vfile &file, process *&process_out, thread *&thread_out
+ ) {
+
+ uint8_t magic[16];
+ if (file.dir_entry.type != storage::file_type::regular_file)
+ return stream_result::not_a_regular_file;
+ if (file.dir_entry.length < 64)
+ return stream_result::not_an_executable;
+ READ(0, 8, magic)
+ READ(16, 8, magic + 8)
+ for (int i = 0; i < 16; ++i)
+ if (magic[i] != correct_magic[i])
+ return stream_result::not_an_executable;
+
+ uint64_t entry_point;
+ uint64_t phead_start;
+ uint16_t phead_entry_size;
+ uint16_t phead_entry_count;
+
+ READ(24, 8, &entry_point)
+ READ(32, 8, &phead_start)
+ READ(54, 2, &phead_entry_size)
+ READ(56, 2, &phead_entry_count)
+
+ if (file.dir_entry.length <
+ phead_start + phead_entry_size * phead_entry_count)
+ return stream_result::not_an_executable;
+
+ utility::vector<load_info> load_infos;
+
+ for (uint16_t i = 0; i < phead_entry_count; ++i) {
+
+ uint64_t entry_start = phead_start + phead_entry_size * i;
+
+ uint32_t seg_type;
+ READ(entry_start, 4, &seg_type)
+ if (seg_type != 1)
+ continue;
+
+ uint64_t foffset;
+ uint64_t vaddr;
+ uint64_t voffset;
+ uint64_t fsize;
+ uint64_t vsize;
+ uint32_t flags;
+
+ READ(entry_start + 8, 8, &foffset)
+ READ(entry_start + 16, 8, &vaddr)
+ READ(entry_start + 32, 8, &fsize)
+ READ(entry_start + 40, 8, &vsize)
+ READ(entry_start + 4, 4, &flags)
+
+ voffset = vaddr % 4096;
+ vaddr -= voffset;
+
+ if (vsize == 0)
+ continue;
+
+ if (file.dir_entry.length < foffset + fsize)
+ return stream_result::not_an_executable;
+ if (fsize > vsize)
+ return stream_result::not_an_executable;
+
+ if (vaddr < 0x200000)
+ return stream_result::not_an_executable;
+
+ uint64_t vpages = (voffset + vsize - 1) / 4096 + 1;
+
+ if (vaddr + vpages * 4096 > 0x8000000000)
+ return stream_result::not_an_executable;
+
+ load_info info = {
+ .foffset = foffset,
+ .fsize = fsize,
+ .vaddr = vaddr,
+ .voffset = voffset,
+ .vpages = vpages,
+ .writable = (flags & 2) == 2,
+ .executable = (flags & 1) == 1
+ };
+ load_infos.add_end(info);
+
+ }
+
+ process_out = new process();
+
+ for (unsigned i = 0; i < load_infos.count; ++i) {
+ const auto &info = load_infos.buffer[i];
+
+ uint64_t vaddr = info.vaddr + info.voffset;
+ uint64_t faddr = info.foffset;
+ uint64_t v_remaining = info.vpages * 4096 - info.voffset;
+ uint64_t f_remaining = info.fsize;
+
+ if (info.voffset != 0) {
+ int to_read = info.fsize < 4096 - info.voffset
+ ? info.fsize : 4096 - info.voffset;
+ if (to_read > 0) {
+ TRY_MAR(map_and_read(file, process_out, vaddr, faddr, to_read,
+ info.writable, info.executable))
+ vaddr += to_read;
+ faddr += to_read;
+ v_remaining -= to_read;
+ f_remaining -= to_read;
+ }
+ }
+
+ while (f_remaining > 0) {
+ int to_read = f_remaining < 4096 ? f_remaining : 4096;
+ TRY_MAR(map_and_read(file, process_out, vaddr, faddr, to_read,
+ info.writable, info.executable))
+ vaddr += to_read;
+ faddr += to_read;
+ v_remaining -= to_read;
+ f_remaining -= to_read;
+ }
+
+ if (vaddr & 4095) {
+ v_remaining -= 4096 - (vaddr & 4095);
+ vaddr += 4096 - (vaddr & 4095);
+ }
+
+ while (v_remaining > 0) {
+ map_and_read(
+ file, process_out, vaddr, 0, 0, info.writable, info.executable);
+ vaddr += 4096;
+ v_remaining -= 4096;
+ }
+
+ }
+
+ for (uint64_t vaddr = 0x1000; vaddr < 0x1ff000; vaddr += 4096) {
+ uint64_t paddr = paging::take_pram_page();
+ uint64_t kvaddr = paging::find_unmapped_vram_region(1);
+ paging::map_kernel_page(paddr, kvaddr, true, false);
+ uint8_t *p = (uint8_t *)kvaddr;
+ for (int i = 0; i < 4096; ++i)
+ p[i] = 0;
+ paging::unmap_kernel_page(kvaddr);
+ process_out->map_page(vaddr, paddr, true, false, true);
+ }
+
+ thread_out = new thread();
+ process_out->threads.insert_end(thread_out);
+ thread_out->the_process = process_out;
+
+ thread_out->state = thread_state::paused;
+
+ thread_out->cpu.rax = 0;
+ thread_out->cpu.rbx = 0;
+ thread_out->cpu.rcx = 0;
+ thread_out->cpu.rdx = 0;
+ thread_out->cpu.rdi = 0;
+ thread_out->cpu.rsi = 0;
+ thread_out->cpu.rbp = 0;
+ thread_out->cpu.rsp = 0x1ff000;
+ thread_out->cpu.r8 = 0;
+ thread_out->cpu.r9 = 0;
+ thread_out->cpu.r10 = 0;
+ thread_out->cpu.r11 = 0;
+ thread_out->cpu.r12 = 0;
+ thread_out->cpu.r13 = 0;
+ thread_out->cpu.r14 = 0;
+ thread_out->cpu.r15 = 0;
+
+ thread_out->cpu.rflags = 0x200;
+ thread_out->cpu.rip = entry_point;
+ thread_out->cpu.cr3 = process_out->p4_paddr;
+ thread_out->cpu.in_syscall = false;
+
+ return stream_result::success;
+
+ }
+
+ extern "C" void init_applications_asm();
+
+ void init_applications() {
+ processes = new utility::id_allocator<process *>();
+ paused_threads = new utility::queue<thread *>();
+ threads_waiting_for_input = new utility::queue<thread *>();
+ all_socket_listeners = new utility::list<socket_listener *>();
+ init_applications_asm();
+ }
+
+ //only called from non-interruptable contexts.
+ //cpu argument not on stack.
+ extern "C" [[noreturn]] void resume_thread(const cpu_state &cpu);
+
+ extern "C" void *copy_syscall_stack(uint8_t *rsp) {
+ uint64_t size = 0xfffffffffffff000 - (uint64_t)rsp;
+ uint8_t *buffer = new uint8_t[size];
+ for (uint64_t i = 0; i < size; ++i)
+ buffer[i] = rsp[i];
+ return buffer;
+ }
+
+ extern "C" void restore_syscall_stack(const uint8_t *from, uint8_t *rsp) {
+ uint64_t size = 0xfffffffffffff000 - (uint64_t)rsp;
+ for (uint64_t i = 0; i < size; ++i)
+ rsp[i] = from[i];
+ delete[] from;
+ }
+
+ thread::~thread() {
+ for (auto *p = the_process->threads.first; p; p = p->next)
+ if (p->value == this) {
+ the_process->threads.remove(p);
+ break;
+ }
+ if (the_process->threads.first == 0) {
+ the_process->exit_code = exit_code;
+ the_process->cleanup();
+ }
+ if (state != thread_state::running)
+ panic(0x9af5e6);
+ }
+
+ [[noreturn]] void resume_next() {
+ while (paused_threads->count == 0)
+ asm volatile ("sti\nhlt\ncli");
+ auto *t = paused_threads->take();
+ running_thread = t;
+ t->state = thread_state::running;
+ resume_thread(t->cpu);
+ }
+
+ void process::end_process(unsigned exit_code) {
+ while (threads.first != 0)
+ delete threads.first->value;
+ this->exit_code = exit_code;
+ cleanup();
+ }
+
+ void process::cleanup() {
+ //TODO
+ panic(0x9af5e6);
+ }
+
+ socket_stream::socket_stream(socket *sock, bool are_we_b)
+ : sock(sock), are_we_b(are_we_b),
+ our_threads_waiting_to_read(are_we_b
+ ? sock->process_b_threads_waiting_to_read
+ : sock->process_a_threads_waiting_to_read),
+ their_threads_waiting_to_read(are_we_b
+ ? sock->process_a_threads_waiting_to_read
+ : sock->process_b_threads_waiting_to_read),
+ them_to_us(are_we_b ? sock->a_to_b : sock->b_to_a),
+ us_to_them(are_we_b ? sock->b_to_a : sock->a_to_b),
+ them_closed(are_we_b ? sock->a_closed : sock->b_closed),
+ us_closed(are_we_b ? sock->b_closed : sock->a_closed) {}
+
+ stream_result socket_stream::seek(seek_origin, int64_t) {
+ return stream_result::not_seekable;
+ }
+
+ stream_result socket_stream::read(uint64_t count, void *into) {
+ uint8_t *buffer = (uint8_t *)into;
+ for (uint64_t i = 0; i < count; ++i) {
+ while (them_to_us.count == 0) {
+ if (them_closed)
+ return stream_result::other_end_closed;
+ if (!save_thread_state(running_thread->cpu)) {
+ running_thread->state = thread_state::waiting;
+ our_threads_waiting_to_read.insert(running_thread);
+ resume_next();
+ }
+ }
+ buffer[i] = them_to_us.take();
+ }
+ return stream_result::success;
+ }
+
+ stream_result socket_stream::write(uint64_t count, const void *from) {
+ if (them_closed)
+ return stream_result::other_end_closed;
+ const uint8_t *buffer = (const uint8_t *)from;
+ for (uint64_t i = 0; i < count; ++i) {
+ if (their_threads_waiting_to_read.count > 0) {
+ auto *ot = their_threads_waiting_to_read.take();
+ ot->state = thread_state::paused;
+ paused_threads->insert(ot);
+ }
+ us_to_them.insert(buffer[i]);
+ }
+ return stream_result::success;
+ }
+
+ stream_result socket_stream::get_length(uint64_t &) {
+ return stream_result::not_sized;
+ }
+
+ stream_result socket_stream::set_length(uint64_t) {
+ return stream_result::not_sized;
+ }
+
+ socket_stream::~socket_stream() {
+ if (our_threads_waiting_to_read.count > 0)
+ panic(0x9af5e6);
+ if (them_closed)
+ delete sock;
+ else {
+ us_closed = true;
+ while (their_threads_waiting_to_read.count > 0) {
+ auto *t = their_threads_waiting_to_read.take();
+ t->state = thread_state::paused;
+ paused_threads->insert(t);
+ }
+ }
+ }
+
+ vfile_stream::vfile_stream(vfile::vfile &&file)
+ : file(utility::move(file)), offset(0) {}
+
+ stream_result vfile_stream::seek(seek_origin origin, int64_t offset) {
+ uint64_t start_at = {};
+ switch (origin) {
+ case seek_origin::beginning:
+ start_at = 0;
+ break;
+ case seek_origin::end:
+ start_at = file.dir_entry.length;
+ break;
+ case seek_origin::current_position:
+ start_at = this->offset;
+ break;
+ }
+ if (offset < 0 && (uint64_t)-offset > start_at)
+ return stream_result::out_of_bounds;
+ if (offset + start_at > file.dir_entry.length)
+ return stream_result::out_of_bounds;
+ this->offset = start_at + offset;
+ return stream_result::success;
+ }
+
+ stream_result vfile_stream::read(uint64_t count, void *into) {
+ if (offset + count > file.dir_entry.length)
+ return stream_result::out_of_bounds;
+ if (file.read_file(offset, count, into) != storage::fs_result::success)
+ return stream_result::io_error;
+ offset += count;
+ return stream_result::success;
+ }
+
+ stream_result vfile_stream::write(uint64_t count, const void *from) {
+ if (offset + count > file.dir_entry.length)
+ return stream_result::out_of_bounds;
+ (void)from;
+ panic(0x9af5e6);
+ }
+
+ stream_result vfile_stream::get_length(uint64_t &out) {
+ out = file.dir_entry.length;
+ return stream_result::success;
+ }
+
+ stream_result vfile_stream::set_length(uint64_t to) {
+ (void)to;
+ panic(0x9af5e6);
+ }
+
+}
diff --git a/kernel/entry.cpp b/kernel/source/entry.cpp
index cc74e69..820b107 100644
--- a/kernel/entry.cpp
+++ b/kernel/source/entry.cpp
@@ -2,12 +2,11 @@
#include <hilbert/kernel/storage/fs/tarfs.hpp>
#include <hilbert/kernel/application.hpp>
#include <hilbert/kernel/framebuffer.hpp>
-#include <hilbert/kernel/terminal.hpp>
#include <hilbert/kernel/paging.hpp>
#include <hilbert/kernel/input.hpp>
#include <hilbert/kernel/panic.hpp>
#include <hilbert/kernel/vfile.hpp>
-#include "../limine/limine.h"
+#include <limine.h>
using namespace hilbert::kernel;
@@ -37,34 +36,20 @@ static volatile limine_hhdm_request hhdm_request {
.response = 0
};
-static limine_internal_module initfs_module = {
- .path = "initfs.tgz",
- .cmdline = "initfs",
- .flags = LIMINE_INTERNAL_MODULE_REQUIRED | LIMINE_INTERNAL_MODULE_COMPRESSED
-};
-
-static limine_internal_module termfont_module = {
- .path = "termfont.psf",
- .cmdline = "termfont",
- .flags = LIMINE_INTERNAL_MODULE_REQUIRED
-};
-
-static limine_internal_module *internal_modules[] = {
- &initfs_module, &termfont_module
-};
-
static volatile limine_module_request module_request = {
.id = LIMINE_MODULE_REQUEST,
.revision = 2,
.response = 0,
- .internal_module_count = 2,
- .internal_modules = internal_modules
+ .internal_module_count = 0,
+ .internal_modules = 0
};
bool try_map_module_by_cmdline(
const char *cmdline, void *&vaddr_out, uint64_t &len_out
) {
auto response = module_request.response;
+ if (!response)
+ return false;
for (uint64_t i = 0; i < response->module_count; ++i) {
limine_file *file = response->modules[i];
for (uint64_t j = 0; cmdline[j] == file->cmdline[j]; ++j)
@@ -108,6 +93,8 @@ uint64_t initfs_len;
extern "C" void load_gdt_and_idt();
+static bool have_initfs;
+
extern "C" [[noreturn]] void entry() {
//TODO?: maybe we should check if the limine requests were
@@ -166,11 +153,8 @@ extern "C" [[noreturn]] void entry() {
for (uint64_t i = 0; i < fb_end - fb_start; i += 4096)
paging::map_kernel_page(fb_start + i, fb_vaddr + i, true, false);
- //initfs and termfont - these are required modules
- //so there is no worry about them not being present.
- try_map_module_by_cmdline("initfs", (void *&)initfs, initfs_len);
- try_map_module_by_cmdline(
- "termfont", (void *&)terminal::termfont, terminal::termfont_len);
+ have_initfs =
+ try_map_module_by_cmdline("initfs", (void *&)initfs, initfs_len);
//set up framebuffer and terminal:
//TODO: assumes framebuffer is 32-bpp rgb
@@ -186,12 +170,13 @@ extern "C" [[noreturn]] void entry() {
}
-extern "C" [[noreturn]] void start_user_mode(
- uint64_t rip, uint64_t rsp, uint64_t p4_paddr);
-
[[noreturn]] static void with_kernel_p4() {
- terminal::init_terminal();
+ if (!have_initfs)
+ panic(0x5f8860);
+
+ input::init_input();
+ application::init_applications();
auto *initfs_bd = new storage::bd::memory(initfs, initfs_len);
auto *initfs_fs = new storage::fs::tarfs_instance(initfs_bd);
@@ -204,27 +189,34 @@ extern "C" [[noreturn]] void start_user_mode(
if (initfs_fs->get_root_node(initfs_root.dir_entry.node) !=
storage::fs_result::success)
- panic("failed to get root node of initfs.");
+ panic(0x48a6ed);
vfile::set_root(initfs_root);
- input::init_input();
-
- utility::string init_path_string("/bin/init.elf", 13);
+ utility::string init_path_string("/bin/init", 9);
vfile::canon_path init_path;
vfile::canonize_path(init_path_string, init_path);
vfile::vfile init_file;
if (vfile::lookup_path(init_path, init_file, true) !=
storage::fs_result::success)
- panic("failed to look up /bin/init.elf.");
-
- application::app_instance *init;
- if (application::create_app(init_file, init, initfs_root) !=
- application::create_app_result::success)
- panic("failed to parse /bin/init.elf.");
-
- application::running_app = init;
- start_user_mode(init->saved_regs.rip, init->saved_regs.rsp, init->p4_paddr);
+ panic(0x7e874d);
+
+ application::process *init_process;
+ application::thread *init_thread;
+ if (application::create_application(init_file, init_process, init_thread) !=
+ application::stream_result::success)
+ panic(0xc39db3);
+
+ init_process->environment.add_end({
+ .a = utility::string("ARGC", 4),
+ .b = utility::string("1", 1)});
+ init_process->environment.add_end({
+ .a = utility::string("ARGV0", 5),
+ .b = utility::string("/bin/init", 9)});
+
+ init_thread->state = application::thread_state::paused;
+ application::paused_threads->insert(init_thread);
+ application::resume_next();
}
diff --git a/kernel/source/framebuffer.cpp b/kernel/source/framebuffer.cpp
new file mode 100644
index 0000000..ab1b3d7
--- /dev/null
+++ b/kernel/source/framebuffer.cpp
@@ -0,0 +1,40 @@
+#include <hilbert/kernel/application.hpp>
+#include <hilbert/kernel/framebuffer.hpp>
+
+namespace hilbert::kernel::framebuffer {
+
+ uint64_t paddr;
+ static uint32_t *vaddr;
+ int width;
+ int height;
+ int dword_pitch;
+
+ void init_framebuffer(uint64_t paddr, uint64_t vaddr,
+ uint64_t width, uint64_t height, uint64_t pitch
+ ) {
+
+ //TODO: assumes 32-bpp rgb
+
+ framebuffer::paddr = paddr;
+ framebuffer::vaddr = (uint32_t *)vaddr;
+ framebuffer::width = width;
+ framebuffer::height = height;
+ dword_pitch = pitch / 4;
+
+ }
+
+ color encode_color(uint8_t r, uint8_t g, uint8_t b) {
+ return ((uint32_t)r << 16) | ((uint32_t)g << 8) | (uint32_t)b;
+ }
+
+ void set_pixel(int x, int y, color c) {
+ vaddr[y * dword_pitch + x] = c;
+ }
+
+ void fill_color(color c) {
+ for (int y = 0; y < height; ++y)
+ for (int x = 0; x < width; ++x)
+ vaddr[y * dword_pitch + x] = c;
+ }
+
+}
diff --git a/kernel/source/input.cpp b/kernel/source/input.cpp
new file mode 100644
index 0000000..696cb13
--- /dev/null
+++ b/kernel/source/input.cpp
@@ -0,0 +1,22 @@
+#include <hilbert/kernel/application.hpp>
+#include <hilbert/kernel/input.hpp>
+#include <hilbert/kernel/panic.hpp>
+#include <hilbert/kernel/vfile.hpp>
+
+namespace hilbert::kernel::input {
+
+ utility::queue<uint32_t> *key_queue;
+
+ void init_input() {
+ key_queue = new utility::queue<uint32_t>();
+ }
+
+ void got_input() {
+ if (application::threads_waiting_for_input->count > 0) {
+ auto *t = application::threads_waiting_for_input->take();
+ t->state = application::thread_state::paused;
+ application::paused_threads->insert(t);
+ }
+ }
+
+}
diff --git a/kernel/interrupts.asm b/kernel/source/interrupts.asm
index c096ddb..babc020 100644
--- a/kernel/interrupts.asm
+++ b/kernel/source/interrupts.asm
@@ -192,20 +192,18 @@ exception_common:
set_isr:
;rdi - index
-;sil - 1 if this is a trap, 0 if it is an interrupt
-;rdx - isr pointer
+;rsi - isr pointer
shl rdi, 4
add rdi, idt
- mov word [rdi], dx
- shr rdx, 16
- mov word [rdi + 6], dx
- shr rdx, 16
- mov dword [rdi + 8], edx
+ mov word [rdi], si
+ shr rsi, 16
+ mov word [rdi + 6], si
+ shr rsi, 16
+ mov dword [rdi + 8], esi
- or sil, 0x8e
- mov byte [rdi + 5], sil
+ mov byte [rdi + 5], 0x8e
mov word [rdi + 2], 0x28
mov byte [rdi + 4], 1
@@ -281,8 +279,7 @@ load_gdt_and_idt:
mov rdi, rcx
dec rdi
- mov sil, 1
- mov rdx, qword [exception_isrs + rdi * 8]
+ mov rsi, qword [exception_isrs + rdi * 8]
call set_isr
loop .loop
@@ -312,8 +309,7 @@ load_gdt_and_idt:
out 0xa1, al
mov rdi, 0x21
- xor sil, sil
- mov rdx, keyboard_isr
+ mov rsi, keyboard_isr
call set_isr
;set keyboard config
diff --git a/kernel/interrupts.cpp b/kernel/source/interrupts.cpp
index cd57c4f..6e22121 100644
--- a/kernel/interrupts.cpp
+++ b/kernel/source/interrupts.cpp
@@ -1,4 +1,3 @@
-#include <hilbert/kernel/terminal.hpp>
#include <hilbert/kernel/input.hpp>
#include <hilbert/kernel/panic.hpp>
@@ -36,93 +35,15 @@ struct [[gnu::packed]] exception_info_t {
extern exception_info_t exception_info;
-static const char *exception_types[] = {
- "division error",
- "",
- "non-maskable interrupt",
- "",
- "",
- "",
- "invalid opcode",
- "",
- "double fault (uh oh)",
- "",
- "",
- "",
- "stack fault",
- "general protection fault",
- "page fault",
- ""
-};
-
-static const char *flag_names[] = {
- " cf",
- "",
- " pf",
- "",
- " af",
- "",
- " zf",
- " sf",
- " tf",
- " if",
- " df",
- " of",
- "",
- "",
- " nt",
- " md"
-};
-
-static void print_line(const char *r1, const char *r2, uint64_t r1v, uint64_t r2v) {
- terminal::put_string_sz("\n ");
- terminal::put_string_sz(r1);
- terminal::put_string_sz(": 0x");
- terminal::put_int_hex(r1v, 16);
- terminal::put_string_sz(" ");
- terminal::put_string_sz(r2);
- terminal::put_string_sz(": 0x");
- terminal::put_int_hex(r2v, 16);
-}
-
extern "C" [[noreturn]] void print_exception() {
- terminal::put_string_sz("exception handler:\n type: ");
- terminal::put_string_sz(exception_types[exception_info.exception_number]);
- terminal::put_string_sz(" (0x");
- terminal::put_int_hex(exception_info.exception_number, 2);
- terminal::put_char(')');
-
- if (exception_info.has_error == 1) {
- terminal::put_string_sz("\n error code: 0x");
- terminal::put_int_hex(exception_info.error, 16);
- }
-
- terminal::put_string_sz("\n flags:");
- if (exception_info.rflags == 0)
- terminal::put_string_sz(" [none]");
- else
- for (int i = 0; i < 16; ++i)
- if (((exception_info.rflags >> i) & 1) == 1)
- terminal::put_string_sz(flag_names[i]);
-
- if (exception_info.exception_number == 0x0e) {
- terminal::put_string_sz("\n cr2: 0x");
- terminal::put_int_hex(exception_info.cr2, 16);
- }
+ //so exception_info's type is known by gdb
+ exception_info_t the_exception_info = exception_info;
+ (void)the_exception_info;
- print_line("cr3", "rip", exception_info.cr3, exception_info.rip);
- print_line("rax", "rbx", exception_info.rax, exception_info.rbx);
- print_line("rcx", "rdx", exception_info.rcx, exception_info.rdx);
- print_line("rdi", "rsi", exception_info.rdi, exception_info.rsi);
- print_line("rbp", "rsp", exception_info.rbp, exception_info.rsp);
- print_line("r8 ", "r9 ", exception_info.r8 , exception_info.r9 );
- print_line("r10", "r11", exception_info.r10, exception_info.r11);
- print_line("r12", "r13", exception_info.r12, exception_info.r13);
- print_line("r14", "r15", exception_info.r14, exception_info.r15);
+ //TODO: log exception, and recover if possible.
- while (1)
- asm ("hlt");
+ panic(0xba40bb);
}
@@ -134,6 +55,7 @@ static uint32_t current_flags = 0;
static void got_key(uint32_t key) {
input::key_queue->insert(current_flags | key);
+ input::got_input();
if (key == (input::BREAK | 0x77))
current_flags ^= input::NUM_LOCK;
diff --git a/kernel/paging.asm b/kernel/source/paging.asm
index f1047a9..f1047a9 100644
--- a/kernel/paging.asm
+++ b/kernel/source/paging.asm
diff --git a/kernel/paging.cpp b/kernel/source/paging.cpp
index d8869fc..d8869fc 100644
--- a/kernel/paging.cpp
+++ b/kernel/source/paging.cpp
diff --git a/kernel/source/panic.cpp b/kernel/source/panic.cpp
new file mode 100644
index 0000000..d99be91
--- /dev/null
+++ b/kernel/source/panic.cpp
@@ -0,0 +1,11 @@
+#include <hilbert/kernel/framebuffer.hpp>
+#include <hilbert/kernel/panic.hpp>
+
+namespace hilbert::kernel {
+ [[noreturn]] void panic(uint32_t code) {
+ framebuffer::fill_color(framebuffer::encode_color(
+ code >> 16, (code >> 8) & 0xff, code & 0xff));
+ while (1)
+ asm ("hlt");
+ }
+}
diff --git a/kernel/storage.cpp b/kernel/source/storage.cpp
index b6b1a04..b6b1a04 100644
--- a/kernel/storage.cpp
+++ b/kernel/source/storage.cpp
diff --git a/kernel/storage/bd/memory.cpp b/kernel/source/storage/bd/memory.cpp
index d6a6719..d6a6719 100644
--- a/kernel/storage/bd/memory.cpp
+++ b/kernel/source/storage/bd/memory.cpp
diff --git a/kernel/storage/fs/tarfs.cpp b/kernel/source/storage/fs/tarfs.cpp
index 5986f62..5986f62 100644
--- a/kernel/storage/fs/tarfs.cpp
+++ b/kernel/source/storage/fs/tarfs.cpp
diff --git a/kernel/source/syscall.cpp b/kernel/source/syscall.cpp
new file mode 100644
index 0000000..768ff0d
--- /dev/null
+++ b/kernel/source/syscall.cpp
@@ -0,0 +1,538 @@
+#include <hilbert/kernel/application.hpp>
+#include <hilbert/kernel/framebuffer.hpp>
+#include <hilbert/kernel/paging.hpp>
+#include <hilbert/kernel/input.hpp>
+#include <hilbert/kernel/panic.hpp>
+#include <hilbert/kernel/vfile.hpp>
+
+namespace hilbert::kernel::syscall {
+
+ enum file_result : uint64_t {
+ file_result_success,
+ file_result_bad_file_handle,
+ file_result_device_error,
+ file_result_file_system_corrupt,
+ file_result_out_of_bounds,
+ file_result_does_not_exist,
+ file_result_directory
+ };
+
+ bool is_range_owned_by_application(uint64_t start, uint64_t end) {
+ auto *process = application::running_thread->the_process;
+ uint64_t pstart = (start / 4096) * 4096;
+ uint64_t pend = ((end - 1) / 4096 + 1) * 4096;
+ for (uint64_t p = pstart; p < pend; p += 4096)
+ if (!process->is_page_owned(p))
+ return false;
+ return true;
+ }
+
+ void set_zero(uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) {
+ rax = 0;
+ rdi = 0;
+ rsi = 0;
+ rdx = 0;
+ }
+
+ void encode_color_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+ ) {
+ rax = (uint64_t)framebuffer::encode_color(
+ rdi & 0xff, (rdi >> 8) & 0xff, (rdi >> 16) & 0xff);
+ rdi = 0;
+ rsi = 0;
+ rdx = 0;
+ }
+
+ void get_framebuffer_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+ ) {
+
+ auto *process = application::running_thread->the_process;
+ if (process->framebuffer_vaddr == 0) {
+ uint64_t pages_needed =
+ (framebuffer::dword_pitch * framebuffer::height * 4 - 1) / 4096 + 1;
+ uint64_t vaddr = process->get_free_vaddr_pages(pages_needed);
+ for (uint64_t i = 0; i < pages_needed; ++i)
+ process->map_page(
+ vaddr + i * 4096, framebuffer::paddr + i * 4096, true, false, false);
+ process->framebuffer_vaddr = vaddr;
+ }
+
+ rax = process->framebuffer_vaddr;
+ rdi =
+ (uint64_t)(uint32_t)framebuffer::width |
+ ((uint64_t)(uint32_t)framebuffer::height << 32);
+ rsi = (uint32_t)framebuffer::dword_pitch;
+ rdx = 0;
+
+ }
+
+ void open_file_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+ ) {
+
+ if (!is_range_owned_by_application(rdi, rdi + rsi)) {
+ set_zero(rax, rdi, rsi, rdx);
+ return;
+ }
+
+ utility::string path_string((const char *)rdi, rsi);
+
+ set_zero(rax, rdi, rsi, rdx);
+
+ vfile::canon_path cp;
+ vfile::vfile file;
+ vfile::canonize_path(path_string, cp);
+
+ switch (vfile::lookup_path(cp, file, true)) {
+
+ case storage::fs_result::device_error:
+ case storage::fs_result::fs_corrupt:
+
+ rax = (uint64_t)application::stream_result::io_error;
+ return;
+
+ case storage::fs_result::does_not_exist:
+
+ if (!(rdx & 1)) {
+ rax = (uint64_t)application::stream_result::does_not_exist;
+ return;
+ }
+
+ //TODO: create the file
+ panic(0x9af5e6);
+
+ case storage::fs_result::success:
+
+ if (rdx & 2) {
+ rax = (uint64_t)application::stream_result::already_exists;
+ return;
+ }
+
+ if (file.dir_entry.type != storage::file_type::regular_file) {
+ rax = (uint64_t)application::stream_result::not_a_regular_file;
+ return;
+ }
+
+ rax = (uint64_t)application::stream_result::success;
+ rdi = application::running_thread->the_process->open_streams.add_new(
+ new application::vfile_stream(utility::move(file)));
+
+ return;
+
+ }
+
+ }
+
+ void end_this_thread_syscall(
+ uint64_t &, uint64_t &rdi, uint64_t &, uint64_t &
+ ) {
+ application::running_thread->exit_code = (int)(uint32_t)rdi;
+ delete application::running_thread;
+ application::resume_next();
+ }
+
+ void get_new_pages_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+ ) {
+
+ uint64_t count = rdi;
+ set_zero(rax, rdi, rsi, rdx);
+
+ auto *p = application::running_thread->the_process;
+ uint64_t vaddr = p->get_free_vaddr_pages(count);
+
+ for (uint64_t i = 0; i < count; ++i) {
+ uint64_t kvaddr;
+ uint64_t paddr;
+ paging::map_new_kernel_page(kvaddr, paddr);
+ for (int i = 0; i < 4096; ++i)
+ ((uint8_t *)kvaddr)[i] = 0;
+ paging::unmap_kernel_page((uint64_t)kvaddr);
+ p->map_page(vaddr + i * 4096, paddr, true, false, true);
+ }
+
+ rax = vaddr;
+
+ }
+
+ void read_key_packet_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+ ) {
+
+ set_zero(rax, rdi, rsi, rdx);
+ auto *t = application::running_thread;
+
+ do
+ if (input::key_queue->count > 0) {
+ rax = (uint64_t)input::key_queue->take();
+ return;
+ }
+ while (application::save_thread_state(t->cpu));
+
+ t->state = application::thread_state::waiting;
+ application::threads_waiting_for_input->insert(t);
+ application::resume_next();
+
+ }
+
+ void create_private_socket_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+ ) {
+ auto *s = new application::socket;
+ auto *ss1 = new application::socket_stream(s, false);
+ auto *ss2 = new application::socket_stream(s, true);
+ set_zero(rax, rdi, rsi, rdx);
+ auto *p = application::running_thread->the_process;
+ rax = (uint64_t)p->open_streams.add_new(ss1);
+ rdi = (uint64_t)p->open_streams.add_new(ss2);
+ }
+
+ void create_socket_listener_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+ ) {
+
+ if (!is_range_owned_by_application(rdi, rdi + rsi)) {
+ set_zero(rax, rdi, rsi, rdx);
+ return;
+ }
+
+ utility::string id_string((const char *)rdi, rsi);
+ set_zero(rax, rdi, rsi, rdx);
+
+ for (auto *p = application::all_socket_listeners->first; p; p = p->next)
+ if (p->value->id == id_string) {
+ rax = (uint64_t)application::stream_result::socket_id_already_used;
+ return;
+ }
+
+ auto *sl = new application::socket_listener();
+ sl->id = utility::move(id_string);
+ sl->is_listening = true;
+ rax = (uint64_t)application::stream_result::success;
+ rdi = (uint64_t)application::running_thread->the_process
+ ->socket_listeners.add_new(utility::move(sl));
+
+ }
+
+ void stop_socket_listener_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+ ) {
+
+ unsigned handle = (unsigned)rdi;
+ set_zero(rax, rdi, rsi, rdx);
+ auto *p = application::running_thread->the_process;
+
+ if (p->socket_listeners.has_id(handle)) {
+ auto *sl = p->socket_listeners.get(handle);
+ p->socket_listeners.remove_id(handle);
+ if (sl->waiting_to_accept_connection.count > 0 ||
+ sl->waiting_to_connect.count > 0) {
+ sl->is_listening = false;
+ while (sl->waiting_to_accept_connection.count > 0) {
+ auto *t = sl->waiting_to_accept_connection.take();
+ t->state = application::thread_state::paused;
+ application::paused_threads->insert(t);
+ }
+ while (sl->waiting_to_connect.count > 0) {
+ auto *t = sl->waiting_to_connect.take();
+ t->state = application::thread_state::paused;
+ application::paused_threads->insert(t);
+ }
+ }
+ else
+ delete sl;
+ }
+
+ }
+
+ void accept_socket_connection_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+ ) {
+
+ unsigned handle = (unsigned)rdi;
+ set_zero(rax, rdi, rsi, rdx);
+ auto *t = application::running_thread;
+ auto *p = t->the_process;
+
+ if (!p->socket_listeners.has_id(handle)) {
+ rax = (uint64_t)application::stream_result::socket_id_not_in_use;
+ return;
+ }
+
+ auto *sl = p->socket_listeners.get(handle);
+
+ if (sl->waiting_to_connect.count > 0) {
+ auto *ot = sl->waiting_to_connect.take();
+ auto *sock = new application::socket();
+ application::stream *s1 = new application::socket_stream(sock, false);
+ application::stream *s2 = new application::socket_stream(sock, true);
+ unsigned handle = p->open_streams.add_new(utility::move(s1));
+ ot->just_connected_to = s2;
+ ot->state = application::thread_state::paused;
+ application::paused_threads->insert(ot);
+ rax = (uint64_t)application::stream_result::success;
+ rdi = handle;
+ return;
+ }
+
+ if (application::save_thread_state(t->cpu)) {
+ if (sl->is_listening) {
+ rax = (uint64_t)application::stream_result::success;
+ rdi = p->open_streams.add_new(utility::move(t->just_accepted));
+ }
+ else {
+ if (sl->waiting_to_accept_connection.count == 0 &&
+ sl->waiting_to_connect.count == 0)
+ delete sl;
+ rax = (uint64_t)application::stream_result::socket_listener_closed;
+ }
+ return;
+ }
+
+ t->state = application::thread_state::waiting;
+ sl->waiting_to_accept_connection.insert(t);
+ application::resume_next();
+
+ }
+
+ void connect_to_socket_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+ ) {
+
+ if (!is_range_owned_by_application(rdi, rdi + rsi)) {
+ set_zero(rax, rdi, rsi, rdx);
+ return;
+ }
+
+ utility::string id_string((const char *)rdi, rsi);
+ set_zero(rax, rdi, rsi, rdx);
+
+ for (auto *i = application::all_socket_listeners->first; i; i = i->next)
+ if (i->value->id == id_string) {
+ auto *sl = i->value;
+ auto *t = application::running_thread;
+ auto *p = t->the_process;
+
+ if (sl->waiting_to_accept_connection.count > 0) {
+ auto *ot = sl->waiting_to_accept_connection.take();
+ auto *sock = new application::socket();
+ auto *s1 = new application::socket_stream(sock, false);
+ auto *s2 = new application::socket_stream(sock, true);
+ unsigned handle = p->open_streams.add_new(utility::move(s1));
+ ot->just_accepted = s2;
+ ot->state = application::thread_state::paused;
+ application::paused_threads->insert(ot);
+ rax = (uint64_t)application::stream_result::success;
+ rdi = handle;
+ return;
+ }
+
+ if (application::save_thread_state(t->cpu)) {
+ if (sl->is_listening) {
+ rax = (uint64_t)application::stream_result::success;
+ rdi = p->open_streams.add_new(utility::move(t->just_connected_to));
+ }
+ else {
+ if (sl->waiting_to_accept_connection.count == 0 &&
+ sl->waiting_to_connect.count == 0)
+ delete sl;
+ rax = (uint64_t)application::stream_result::socket_id_not_in_use;
+ }
+ return;
+ }
+
+ t->state = application::thread_state::waiting;
+ sl->waiting_to_connect.insert(t);
+ application::resume_next();
+
+ }
+
+ rax = (uint64_t)application::stream_result::socket_id_not_in_use;
+
+ }
+
+ void close_stream_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+ ) {
+
+ unsigned handle = (unsigned)rdi;
+ set_zero(rax, rdi, rsi, rdx);
+ auto *p = application::running_thread->the_process;
+
+ if (p->open_streams.has_id(handle)) {
+ application::stream *s = p->open_streams.get(handle);
+ p->open_streams.remove_id(handle);
+ delete s;
+ }
+
+ }
+
+ void seek_stream_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+ ) {
+
+ unsigned handle = (unsigned)rdi;
+ uint8_t origin = (uint8_t)rsi;
+ int64_t offset = (int64_t)rdx;
+ set_zero(rax, rdi, rsi, rdx);
+
+ if (origin >= 3)
+ return;
+
+ auto *p = application::running_thread->the_process;
+
+ if (!p->open_streams.has_id(handle)) {
+ rax = (uint64_t)application::stream_result::bad_handle;
+ return;
+ }
+
+ rax = (uint64_t)p->open_streams.get(handle)
+ ->seek((application::seek_origin)origin, offset);
+
+ }
+
+ void read_from_stream_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+ ) {
+
+ unsigned handle = (unsigned)rdi;
+ uint64_t count = (uint64_t)rsi;
+ uint64_t buffer = (uint64_t)rdx;
+ set_zero(rax, rdi, rsi, rdx);
+
+ if (!is_range_owned_by_application(buffer, buffer + count))
+ return;
+
+ auto *p = application::running_thread->the_process;
+
+ if (!p->open_streams.has_id(handle)) {
+ rax = (uint64_t)application::stream_result::bad_handle;
+ return;
+ }
+
+ rax = (uint64_t)p->open_streams.get(handle)->read(count, (void *)buffer);
+
+ }
+
+ void write_to_stream_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+ ) {
+
+ unsigned handle = (unsigned)rdi;
+ uint64_t count = (uint64_t)rsi;
+ uint64_t buffer = (uint64_t)rdx;
+ set_zero(rax, rdi, rsi, rdx);
+
+ if (!is_range_owned_by_application(buffer, buffer + count))
+ return;
+
+ auto *p = application::running_thread->the_process;
+
+ if (!p->open_streams.has_id(handle)) {
+ rax = (uint64_t)application::stream_result::bad_handle;
+ return;
+ }
+
+ rax = (uint64_t)p->open_streams.get(handle)
+ ->write(count, (const void *)buffer);
+
+ }
+
+ void get_stream_length_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+ ) {
+
+ unsigned handle = (unsigned)rdi;
+ set_zero(rax, rdi, rsi, rdx);
+
+ auto *p = application::running_thread->the_process;
+
+ if (!p->open_streams.has_id(handle)) {
+ rax = (uint64_t)application::stream_result::bad_handle;
+ return;
+ }
+
+ rax = (uint64_t)p->open_streams.get(handle)->get_length(rdi);
+
+ }
+
+ void start_process_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+ ) {
+ //TODO
+ (void)rax;
+ (void)rdi;
+ (void)rsi;
+ (void)rdx;
+ panic(0x9af5e6);
+ }
+
+ void end_this_process_syscall(
+ uint64_t &, uint64_t &rdi, uint64_t &, uint64_t &
+ ) {
+ application::running_thread->the_process->end_process((unsigned)rdi);
+ application::resume_next();
+ }
+
+ void set_stream_length_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+ ) {
+
+ unsigned handle = (unsigned)rdi;
+ uint64_t new_length = rsi;
+ set_zero(rax, rdi, rsi, rdx);
+
+ auto *p = application::running_thread->the_process;
+
+ if (!p->open_streams.has_id(handle)) {
+ rax = (uint64_t)application::stream_result::bad_handle;
+ return;
+ }
+
+ rax = (uint64_t)p->open_streams.get(handle)->set_length(new_length);
+
+ }
+
+ typedef void (*syscall_handler)(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx);
+
+ syscall_handler handlers[] = {
+ &encode_color_syscall,
+ &get_framebuffer_syscall,
+ &open_file_syscall,
+ &end_this_thread_syscall,
+ &get_new_pages_syscall,
+ &read_key_packet_syscall,
+ &create_private_socket_syscall,
+ &create_socket_listener_syscall,
+ &stop_socket_listener_syscall,
+ &accept_socket_connection_syscall,
+ &connect_to_socket_syscall,
+ &close_stream_syscall,
+ &seek_stream_syscall,
+ &read_from_stream_syscall,
+ &write_to_stream_syscall,
+ &get_stream_length_syscall,
+ &start_process_syscall,
+ &end_this_process_syscall,
+ &set_stream_length_syscall
+ };
+
+ static constexpr int max_syscall_number = 18;
+
+}
+
+using namespace hilbert::kernel::syscall;
+
+extern "C" void do_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+) {
+
+ if (rax <= max_syscall_number && handlers[rax] != 0)
+ handlers[rax](rax, rdi, rsi, rdx);
+ else
+ set_zero(rax, rdi, rsi, rdx);
+
+}
diff --git a/kernel/utility.cpp b/kernel/source/utility.cpp
index 12e88fd..12e88fd 100644
--- a/kernel/utility.cpp
+++ b/kernel/source/utility.cpp
diff --git a/kernel/vfile.cpp b/kernel/source/vfile.cpp
index 89c95e6..89c95e6 100644
--- a/kernel/vfile.cpp
+++ b/kernel/source/vfile.cpp
diff --git a/kernel/syscall.asm b/kernel/syscall.asm
deleted file mode 100644
index c293402..0000000
--- a/kernel/syscall.asm
+++ /dev/null
@@ -1,88 +0,0 @@
-bits 64
-
-global start_user_mode
-
-section .text
-
-extern do_syscall
-
-syscall_entry:
- mov r11, rsp
- mov rsp, 0xfffffffffffff000
- push r11
- push rcx
-
- push rdx
- push rsi
- push rdi
- push rax
-
- mov rdi, rsp
- lea rsi, [rsp + 8]
- lea rdx, [rsp + 16]
- lea rcx, [rsp + 24]
-
- call do_syscall
-
- pop rax
- pop rdi
- pop rsi
- pop rdx
-
- xor r8, r8
- xor r9, r9
- xor r10, r10
- xor r11, r11
- or r11, 0x200
- pop rcx
- pop rsp
-
- o64 sysret
-
-start_user_mode:
-;intended rip in rdi
-;intended rsp in rsi
-;intended p4_paddr in rdx
-
- mov rax, rdx
- mov cr3, rax
-
- ;efer <- efer | 0x1
- mov rcx, 0xc0000080
- rdmsr
- or al, 1
- wrmsr
-
- ;lstar <- syscall_entry
- mov rdx, syscall_entry
- mov eax, edx
- shr rdx, 32
- mov ecx, 0xc0000082
- wrmsr
-
- ;star <- 0x0030.0028.0000.0000
- mov edx, 0x00300028
- xor eax, eax
- mov ecx, 0xc0000081
- wrmsr
-
- mov rcx, rdi
- mov rsp, rsi
- xor r11, r11
- or r11, 0x200
-
- xor rax, rax
- xor rbx, rbx
- xor rdx, rdx
- xor rdi, rdi
- 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
diff --git a/kernel/syscall.cpp b/kernel/syscall.cpp
deleted file mode 100644
index e194eb1..0000000
--- a/kernel/syscall.cpp
+++ /dev/null
@@ -1,262 +0,0 @@
-#include <hilbert/kernel/application.hpp>
-#include <hilbert/kernel/framebuffer.hpp>
-#include <hilbert/kernel/paging.hpp>
-#include <hilbert/kernel/input.hpp>
-#include <hilbert/kernel/vfile.hpp>
-
-namespace hilbert::kernel::syscall {
-
- enum file_result : uint64_t {
- file_result_success,
- file_result_bad_file_handle,
- file_result_device_error,
- file_result_file_system_corrupt,
- file_result_out_of_bounds,
- file_result_does_not_exist,
- file_result_directory
- };
-
- bool is_range_owned_by_application(uint64_t start, uint64_t end) {
- auto *app = application::running_app;
- uint64_t pstart = (start / 4096) * 4096;
- uint64_t pend = ((end - 1) / 4096 + 1) * 4096;
- for (uint64_t p = pstart; p < pend; p += 4096)
- if (!app->is_page_owned(p))
- return false;
- return true;
- }
-
- void set_zero(uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) {
- rax = 0;
- rdi = 0;
- rsi = 0;
- rdx = 0;
- }
-
- void encode_color_syscall(
- uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
- ) {
- rax = (uint64_t)framebuffer::encode_color(
- rdi & 0xff, (rdi >> 8) & 0xff, (rdi >> 16) & 0xff);
- rdi = 0;
- rsi = 0;
- rdx = 0;
- }
-
- void get_framebuffer_syscall(
- uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
- ) {
-
- auto *app = application::running_app;
- if (app->framebuffer_vaddr == 0) {
- uint64_t pages_needed =
- (framebuffer::dword_pitch * framebuffer::height * 4 - 1) / 4096 + 1;
- uint64_t vaddr = app->get_free_vaddr_pages(pages_needed);
- for (uint64_t i = 0; i < pages_needed; ++i)
- app->map_page(
- vaddr + i * 4096, framebuffer::paddr + i * 4096, true, false, false);
- app->framebuffer_vaddr = vaddr;
- }
-
- rax = app->framebuffer_vaddr;
- rdi =
- (uint64_t)(uint32_t)framebuffer::width |
- ((uint64_t)(uint32_t)framebuffer::height << 32);
- rsi = (uint32_t)framebuffer::dword_pitch;
- rdx = 0;
-
- }
-
- void open_file_syscall(
- uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
- ) {
-
- if (!is_range_owned_by_application(rdi, rdi + rsi)) {
- set_zero(rax, rdi, rsi, rdx);
- return;
- }
-
- utility::string path((const char *)rdi, rsi);
- vfile::canon_path cp;
- vfile::canonize_path(path, cp);
-
- set_zero(rax, rdi, rsi, rdx);
-
- vfile::vfile file;
- switch (vfile::lookup_path(cp, file, true)) {
- case storage::fs_result::success:
- break;
- case storage::fs_result::device_error:
- rax = file_result_device_error;
- return;
- case storage::fs_result::fs_corrupt:
- rax = file_result_file_system_corrupt;
- return;
- case storage::fs_result::does_not_exist:
- rax = file_result_does_not_exist;
- return;
- }
-
- if (file.dir_entry.type != storage::file_type::regular_file) {
- rax = file_result_directory;
- return;
- }
-
- unsigned handler =
- application::running_app->open_files.add_new(utility::move(file));
- rax = file_result_success;
- rdi = (uint64_t)handler;
-
- }
-
- void get_file_length_syscall(
- uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
- ) {
-
- auto &open_files = application::running_app->open_files;
- unsigned handle = (unsigned)rdi;
-
- set_zero(rax, rdi, rsi, rdx);
-
- if (!open_files.has_id(handle)) {
- rax = file_result_bad_file_handle;
- return;
- }
-
- rax = file_result_success;
- rdi = open_files.get(handle).dir_entry.length;
-
- }
-
- void read_from_file_syscall(
- uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
- ) {
-
- if (!is_range_owned_by_application(rdi, rdi + 32)) {
- set_zero(rax, rdi, rsi, rdx);
- return;
- }
-
- const uint64_t *request = (const uint64_t *)rdi;
- unsigned handle = (unsigned)request[0];
- uint64_t start = request[1];
- uint64_t length = request[2];
- uint64_t buffer_vaddr = request[3];
-
- set_zero(rax, rdi, rsi, rdx);
-
- if (!is_range_owned_by_application(buffer_vaddr, buffer_vaddr + length))
- return;
-
- auto &open_files = application::running_app->open_files;
-
- if (!open_files.has_id(handle))
- rax = file_result_bad_file_handle;
-
- vfile::vfile &file = open_files.get(handle);
-
- if (start + length > file.dir_entry.length)
- rax = file_result_out_of_bounds;
-
- switch (file.read_file(start, length, (void *)buffer_vaddr)) {
- case storage::fs_result::success:
- rax = file_result_success;
- return;
- case storage::fs_result::device_error:
- rax = file_result_device_error;
- return;
- case storage::fs_result::fs_corrupt:
- case storage::fs_result::does_not_exist:
- rax = file_result_file_system_corrupt;
- return;
- }
-
- }
-
- [[noreturn]] void end_this_process_syscall(
- uint64_t &, uint64_t &, uint64_t &, uint64_t &
- ) {
-
- //TODO
- while (1)
- ;
-
- }
-
- void get_new_pages_syscall(
- uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
- ) {
-
- uint64_t count = rdi;
- set_zero(rax, rdi, rsi, rdx);
-
- auto *app = application::running_app;
- uint64_t vaddr = app->get_free_vaddr_pages(count);
-
- for (uint64_t i = 0; i < count; ++i) {
- uint64_t paddr = paging::take_pram_page();
- app->map_page(vaddr + i * 4096, paddr, true, false, true);
- }
-
- rax = vaddr;
-
- }
-
- void close_file_syscall(
- uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
- ) {
-
- unsigned handle = rdi;
- set_zero(rax, rdi, rsi, rdx);
- application::running_app->open_files.remove_id(handle);
-
- }
-
- void read_key_packet_syscall(
- uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
- ) {
-
- set_zero(rax, rdi, rsi, rdx);
-
- asm ("cli");
-
- while (input::key_queue->count == 0)
- asm ("sti\nhlt\ncli");
-
- rax = (uint64_t)input::key_queue->take();
-
- asm ("sti");
-
- }
-
- typedef void (*syscall_handler)(
- uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx);
-
- syscall_handler handlers[] = {
- &encode_color_syscall,
- &get_framebuffer_syscall,
- &open_file_syscall,
- &get_file_length_syscall,
- &read_from_file_syscall,
- &end_this_process_syscall,
- &get_new_pages_syscall,
- &close_file_syscall,
- &read_key_packet_syscall
- };
-
- static constexpr int max_syscall_number = 8;
-
-}
-
-using namespace hilbert::kernel::syscall;
-
-extern "C" void do_syscall(
- uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
-) {
-
- if (rax <= max_syscall_number && handlers[rax] != 0)
- handlers[rax](rax, rdi, rsi, rdx);
- else
- set_zero(rax, rdi, rsi, rdx);
-
-}
diff --git a/kernel/terminal.cpp b/kernel/terminal.cpp
deleted file mode 100644
index 167e6cf..0000000
--- a/kernel/terminal.cpp
+++ /dev/null
@@ -1,121 +0,0 @@
-#include <hilbert/kernel/framebuffer.hpp>
-#include <hilbert/kernel/terminal.hpp>
-
-namespace hilbert::kernel::terminal {
-
- uint8_t *termfont;
- uint64_t termfont_len;
-
- int width;
- int height;
-
- int cursor_x;
- int cursor_y;
-
- framebuffer::color bg_color;
- framebuffer::color fg_color;
-
- static uint8_t glyph_height;
-
- void init_terminal() {
- //TODO - verify that termfont fits inside termfont_len (i.e. that no other
- // functions in this file will try to access memory outside termfont)
- //TODO - check magic header to verify that this is actually a font and to
- // see whether this is a psf1 font or a psf2 font.
- //TODO - support psf2 fonts. currently psf1 is assumed.
- //TODO - read unicode table if there is one. currently it is assumed that
- // all 256 codepoints have glyphs, and that they appear in order.
-
- glyph_height = termfont[3];
- width = framebuffer::width / 8;
- height = framebuffer::height / glyph_height;
- cursor_x = 0;
- cursor_y = 0;
- bg_color = framebuffer::encode_color(0, 0, 0);
- fg_color = framebuffer::encode_color(255, 255, 255);
-
- }
-
- static void cursor_down() {
- if (++cursor_y == height) {
- --cursor_y;
- framebuffer::move_region(
- 0, glyph_height, width * 8, height * glyph_height, 0, 0);
- framebuffer::fill_region(0, (height - 1) * glyph_height,
- width * 8, height * glyph_height, bg_color);
- }
- }
-
- static void cursor_right() {
- if (++cursor_x == width) {
- cursor_x = 0;
- cursor_down();
- }
- }
-
- void draw_char(char ch, int x, int y) {
- const uint8_t *glyph = termfont + 4 + glyph_height * (unsigned)ch;
- for (int i = 0; i < glyph_height; ++i)
- for (int j = 0; j < 8; ++j)
- framebuffer::set_pixel(x * 8 + j, y * glyph_height + i,
- ((glyph[i] << j) & 0x80) ? fg_color : bg_color);
- }
-
- void put_char(char ch) {
- switch (ch) {
- case '\n':
- cursor_x = 0;
- cursor_down();
- break;
- default:
- draw_char(ch, cursor_x, cursor_y);
- cursor_right();
- break;
- }
- }
-
- void put_string(const utility::string &str) {
- for (size_t i = 0; i < str.count; ++i)
- put_char(str.buffer[i]);
- }
-
- void put_string_sz(const char *str) {
- for (size_t i = 0; str[i]; ++i)
- put_char(str[i]);
- }
-
- void put_int_decimal(uint64_t n, bool with_commas) {
-
- if (n == 0) {
- put_char('0');
- return;
- }
-
- uint64_t d = 1;
- int i = 0;
- while (d <= n / 10) {
- d *= 10;
- ++i;
- }
-
- while (d) {
- put_char('0' + ((n / d) % 10));
- d /= 10;
- if (with_commas && (i % 3 == 0) && (i != 0))
- put_char(',');
- --i;
- }
-
- }
-
- static char hex_digits[] = "0123456789abcdef";
-
- void put_int_hex(uint64_t n, int digits, bool with_dots) {
- for (int digit = digits - 1; digit >= 0; --digit) {
- put_char(hex_digits[(n >> (digit * 4)) & 0xf]);
- if (with_dots && digit % 4 == 0 && digit != 0)
- put_char('.');
- }
- }
-
-}
diff --git a/libraries/daguerre/include/daguerre.hpp b/libraries/daguerre/include/daguerre.hpp
new file mode 100644
index 0000000..274e257
--- /dev/null
+++ b/libraries/daguerre/include/daguerre.hpp
@@ -0,0 +1,131 @@
+#pragma once
+
+#include <stdint.h>
+#include <cstdio>
+
+namespace daguerre {
+
+ typedef uint32_t hilbert_color;
+
+ struct rgb24 {
+ uint8_t r;
+ uint8_t g;
+ uint8_t b;
+ };
+
+ template <class to_type, class from_type>
+ to_type convert_color(const from_type &from);
+
+ template <>
+ inline hilbert_color convert_color<hilbert_color, rgb24>(const rgb24 &from) {
+ return __euler_encode_color(from.r, from.g, from.b);
+ }
+
+ template <class color_t>
+ class image {
+
+ public:
+ bool delete_buffer_on_destruct;
+ color_t *buffer;
+ unsigned width;
+ unsigned height;
+ unsigned pitch;//in sizeof(color_t)
+
+ image()
+ : delete_buffer_on_destruct(false), buffer(0), width(0), height(0),
+ pitch(0) {}
+
+ image(unsigned width, unsigned height)
+ : delete_buffer_on_destruct(true), buffer(new color_t[width * height]),
+ width(width), height(height), pitch(width) {}
+
+ image(
+ color_t *buffer, unsigned width, unsigned height, unsigned pitch,
+ bool delete_buffer_on_destruct)
+ : delete_buffer_on_destruct(delete_buffer_on_destruct), buffer(buffer),
+ width(width), height(height), pitch(pitch) {}
+
+ ~image() {
+ if (delete_buffer_on_destruct && buffer)
+ delete[] buffer;
+ }
+
+ image(const image<color_t> &other) = delete;
+
+ image(image<color_t> &&other)
+ : delete_buffer_on_destruct(other.delete_buffer_on_destruct),
+ buffer(other.buffer), width(other.width), height(other.height),
+ pitch(other.pitch) {
+ other.buffer = 0;
+ }
+
+ image<color_t> &operator =(const image<color_t> &other) = delete;
+
+ image<color_t> &operator =(image<color_t> &&other) {
+ if (delete_buffer_on_destruct && buffer)
+ delete[] buffer;
+ delete_buffer_on_destruct = other.delete_buffer_on_destruct;
+ buffer = other.buffer;
+ width = other.width;
+ height = other.height;
+ pitch = other.pitch;
+ other.buffer = 0;
+ return *this;
+ }
+
+ color_t get(unsigned x, unsigned y) const {
+ return buffer[y * pitch + x];
+ }
+
+ void set(unsigned x, unsigned y, const color_t &c) {
+ buffer[y * pitch + x] = c;
+ }
+
+ };
+
+ //it is assumed that the regions do not overlap in memory.
+ //copies into [to_x, to_x + width) x [to_y, to_y + height)
+ //from [from_x, from_x + width) x [from_y, from_y + height).
+ template <class color_t>
+ void copy_region(
+ image<color_t> &to, const image<color_t> &from, unsigned from_x,
+ unsigned from_y, unsigned to_x, unsigned to_y, unsigned width,
+ unsigned height) {
+
+ color_t *to_start = to.buffer + to.pitch * to_y + to_x;
+ const color_t *from_start = from.buffer + from.pitch * from_y + from_x;
+
+ for (unsigned y = 0; y < height; ++y)
+ memcpy(
+ to_start + to.pitch * y, from_start + from.pitch * y,
+ width * sizeof(color_t));
+
+ }
+
+ //it is assumed that the regions do not overlap in memory.
+ //copies into [to_x, to_x + width) x [to_y, to_y + height)
+ //from [from_x, from_x + width) x [from_y, from_y + height).
+ template <
+ class to_color_t, class from_color_t,
+ to_color_t converter(const from_color_t &) =
+ convert_color<to_color_t, from_color_t>>
+ void copy_region(
+ image<to_color_t> &to, const image<from_color_t> &from, unsigned from_x,
+ unsigned from_y, unsigned to_x, unsigned to_y, unsigned width,
+ unsigned height) {
+
+ to_color_t *to_start = to.buffer + to.pitch * to_y + to_x;
+ const from_color_t *from_start =
+ from.buffer + from.pitch * from_y + from_x;
+
+ for (unsigned y = 0; y < height; ++y)
+ for (unsigned x = 0; x < width; ++x)
+ to_start[to.pitch * y + x] = converter(from_start[from.pitch * y + x]);
+
+ }
+
+ image<hilbert_color> get_hilbert_framebuffer();
+
+ bool try_load_ppm(std::FILE *input, image<rgb24> &into);
+
+}
diff --git a/libraries/daguerre/include/daguerre/image.hpp b/libraries/daguerre/include/daguerre/image.hpp
deleted file mode 100644
index 6129306..0000000
--- a/libraries/daguerre/include/daguerre/image.hpp
+++ /dev/null
@@ -1,155 +0,0 @@
-#pragma once
-
-#include <euler/syscall.hpp>
-#include <cassert>
-#include <cstdint>
-#include <cstdio>
-
-namespace daguerre {
-
- struct color24 {
- uint8_t r;
- uint8_t g;
- uint8_t b;
- };
-
- using hilbert_color = euler::syscall::encoded_color;
-
- static inline hilbert_color to_hilbert_color(const color24 &c) {
- return _syscall_encode_color(c.r, c.g, c.b);
- }
-
- template <class pixel_type = color24>
- class image {
-
- pixel_type *buffer;
- unsigned width;
- unsigned height;
- unsigned pitch; //in pixels
-
- bool buffer_owned;
-
- public:
- image() : buffer(0) {}
-
- image(pixel_type *buffer, unsigned width,
- unsigned height, unsigned pitch, bool buffer_owned
- ) : buffer(buffer), width(width), height(height),
- pitch(pitch), buffer_owned(buffer_owned) {}
-
- image(unsigned width, unsigned height)
- : buffer(new pixel_type[width * height]), width(width),
- height(height), pitch(width), buffer_owned(true) {}
-
- image(const image<pixel_type> &other) = delete;
-
- image(image<pixel_type> &&other)
- : buffer(other.buffer), width(other.width), height(other.height),
- pitch(other.pitch), buffer_owned(other.buffer_owned) {
- other.buffer = 0;
- }
-
- ~image() {
- if (buffer && buffer_owned)
- delete[] buffer;
- }
-
- image &operator =(const image<pixel_type> &other) = delete;
-
- image &operator =(image<pixel_type> &&other) {
- if (buffer && buffer_owned)
- delete[] buffer;
- buffer = other.buffer;
- width = other.width;
- height = other.height;
- pitch = other.pitch;
- buffer_owned = other.buffer_owned;
- other.buffer = 0;
- return *this;
- }
-
- pixel_type &get(unsigned x, unsigned y) {
- return buffer[y * pitch + x];
- }
-
- const pixel_type &get(unsigned x, unsigned y) const {
- return buffer[y * pitch + x];
- }
-
- pixel_type *get_buffer() {
- return buffer;
- }
-
- const pixel_type *get_buffer() const {
- return buffer;
- }
-
- unsigned get_width() const {
- return width;
- }
-
- unsigned get_height() const {
- return height;
- }
-
- unsigned get_pitch() const {
- return pitch;
- }
-
- };
-
- template <class pixel_type>
- void default_converter(const pixel_type &i, pixel_type &o) {
- o = i;
- }
-
- static inline void default_converter(const color24 &i, hilbert_color &o) {
- o = to_hilbert_color(i);
- }
-
- //copies a rectangle of size width x height from source to destination. the
- //rectangle starts in source at (source_x, source_y), and in destination at
- //(destination_x, destination_y). every pixel is passed through the converter
- //template argument.
- template <
- class source_pixel_type, class destination_pixel_type,
- void (*converter)(const source_pixel_type &, destination_pixel_type &) =
- &default_converter>
- void copy_image(const image<source_pixel_type> &source,
- image<destination_pixel_type> &destination, unsigned source_x,
- unsigned source_y, unsigned destination_x, unsigned destination_y,
- unsigned width, unsigned height
- ) {
-
- assert(source_x + width <= source.get_width());
- assert(source_y + height <= source.get_height());
- assert(destination_x + width <= destination.get_width());
- assert(destination_y + height <= destination.get_height());
-
- unsigned source_pitch = source.get_pitch();
- unsigned destination_pitch = destination.get_pitch();
-
- const source_pixel_type *source_buffer =
- &source.get_buffer()[source_y * source_pitch + source_x];
- destination_pixel_type *destination_buffer = &destination.get_buffer()[
- destination_y * destination_pitch + destination_x];
-
- for (unsigned y = 0; y < height; ++y)
- for (unsigned x = 0; x < width; ++x)
- converter(source_buffer[y * source_pitch + x],
- destination_buffer[y * destination_pitch + x]);
-
- }
-
- static inline image<hilbert_color> get_hilbert_framebuffer() {
- hilbert_color *ptr;
- uint32_t width;
- uint32_t height;
- uint32_t pitch;
- _syscall_get_framebuffer(ptr, width, height, pitch);
- return image<hilbert_color>(ptr, width, height, pitch, false);
- }
-
- bool try_load_ppm(std::FILE *from, image<color24> &into);
-
-}
diff --git a/libraries/daguerre/makefile b/libraries/daguerre/makefile
new file mode 100644
index 0000000..3505d35
--- /dev/null
+++ b/libraries/daguerre/makefile
@@ -0,0 +1,12 @@
+SOURCES = \
+ daguerre.cpp
+
+build/%.cpp.o: source/%.cpp
+ @mkdir -p $(@D)
+ $(HILBERT_CC) -c $^ -o $@
+
+build/libdaguerre.a: $(SOURCES:%=build/%.o)
+ $(HILBERT_AR) rcs $@ $^
+
+clean:
+ rm -rf build
diff --git a/libraries/daguerre/ppm.cpp b/libraries/daguerre/ppm.cpp
deleted file mode 100644
index e909503..0000000
--- a/libraries/daguerre/ppm.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-#include <daguerre/image.hpp>
-#include <cctype>
-
-namespace daguerre {
-
- static unsigned read_int(std::FILE *from) {
- unsigned out = 0;
- int ch;
- do
- ch = std::fgetc(from);
- while (std::isspace(ch));
- while (true) {
- if (ch == EOF)
- return out;
- if (ch < '0' || ch > '9') {
- std::ungetc(ch, from);
- return out;
- }
- out = out * 10 + (ch - '0');
- ch = std::fgetc(from);
- }
- }
-
- bool try_load_ppm(std::FILE *from, image<color24> &into) {
-
- if (std::fgetc(from) != 'P' || std::fgetc(from) != '6' ||
- std::fgetc(from) != '\n')
- return false;
-
- unsigned width = read_int(from);
- unsigned height = read_int(from);
- unsigned max = read_int(from);
- std::fgetc(from);//newline
-
- if (max != 255)
- return false;
-
- into = image<color24>(width, height);
- color24 *buffer = into.get_buffer();
-
- for (unsigned y = 0; y < height; ++y)
- for (unsigned x = 0; x < width; ++x) {
- buffer[y * width + x].r = std::fgetc(from);
- buffer[y * width + x].g = std::fgetc(from);
- buffer[y * width + x].b = std::fgetc(from);
- }
-
- return true;
-
- }
-
-}
diff --git a/libraries/daguerre/source/daguerre.cpp b/libraries/daguerre/source/daguerre.cpp
new file mode 100644
index 0000000..fb3ddc7
--- /dev/null
+++ b/libraries/daguerre/source/daguerre.cpp
@@ -0,0 +1,58 @@
+#include <daguerre.hpp>
+
+namespace daguerre {
+
+ image<hilbert_color> get_hilbert_framebuffer() {
+ uint32_t width, height, pitch;
+ hilbert_color *ptr = __euler_get_framebuffer(width, height, pitch);
+ return image<hilbert_color>(ptr, width, height, pitch, false);
+ }
+
+ unsigned read_text_int(std::FILE *input) {
+ unsigned n = 0;
+ char ch;
+ while (true) {
+ std::fread(&ch, 1, 1, input);
+ if (ch < '0' || ch > '9')
+ return n;
+ n = n * 10 + ch - '0';
+ }
+ }
+
+ bool try_load_ppm(std::FILE *input, image<rgb24> &into) {
+
+ char header[3];
+ if (std::fread(header, 1, 3, input) != 3)
+ return false;
+
+ if (header[0] != 'P' || header[1] != '6' || header[2] != '\n')
+ return false;
+
+ unsigned width = read_text_int(input);
+ unsigned height = read_text_int(input);
+ unsigned max = read_text_int(input);
+
+ into = image<rgb24>(width, height);
+
+ for (unsigned y = 0; y < height; ++y)
+ for (unsigned x = 0; x < width; ++x) {
+ if (std::fread(&into.buffer[y * width + x].r, 1, 1, input) != 1)
+ return false;
+ if (std::fread(&into.buffer[y * width + x].g, 1, 1, input) != 1)
+ return false;
+ if (std::fread(&into.buffer[y * width + x].b, 1, 1, input) != 1)
+ return false;
+ }
+
+ if (max != 255)
+ for (unsigned v = 0; v < width * height; ++v) {
+ into.buffer[v].r = ((uint16_t)into.buffer[v].r * 255) / max;
+ into.buffer[v].g = ((uint16_t)into.buffer[v].g * 255) / max;
+ into.buffer[v].b = ((uint16_t)into.buffer[v].b * 255) / max;
+ }
+
+ return true;
+
+ }
+
+}
diff --git a/libraries/euler/allocator.cpp b/libraries/euler/allocator.cpp
deleted file mode 100644
index 5242df1..0000000
--- a/libraries/euler/allocator.cpp
+++ /dev/null
@@ -1,147 +0,0 @@
-#include <euler/syscall.hpp>
-
-//i guess we could figure out which parts of the pages the kernel allocated to
-//load the application were not actually needed and add those to the memory
-//that is available to be allocated, but whatever.
-
-namespace euler::allocator {
-
- struct block_info {
- //vaddr, divisible by size
- uint64_t start;
- //power of 2, 0 for unused
- uint64_t size;
- };
-
- struct block_info_page {
- block_info infos[255];
- block_info_page *next;
- };
-
- static_assert(sizeof(block_info_page) == 4088);
-
- static block_info_page *first_bi_page = 0;
-
- static block_info *try_find_block(uint64_t start, uint64_t size) {
- for (block_info_page *bip = first_bi_page; bip; bip = bip->next)
- for (int i = 0; i < 255; ++i)
- if (bip->infos[i].start == start && bip->infos[i].size == size)
- return bip->infos + i;
- return 0;
- }
-
- static block_info *add_block(uint64_t start, uint64_t size) {
- for (block_info_page *bip = first_bi_page; bip; bip = bip->next)
- for (int i = 0; i < 255; ++i)
- if (bip->infos[i].size == 0) {
- bip->infos[i].start = start;
- bip->infos[i].size = size;
- return bip->infos + i;
- }
- block_info_page *new_bip = (block_info_page *)_syscall_get_new_pages(1);
- new_bip->infos[0].start = start;
- new_bip->infos[0].size = size;
- for (int i = 1; i < 255; ++i)
- new_bip->infos[i].size = 0;
- new_bip->next = first_bi_page;
- first_bi_page = new_bip;
- return new_bip->infos;
- }
-
- static block_info *find_minimal_block(uint64_t minimum_length) {
- block_info *minimal_so_far = 0;
- uint64_t length_so_far = UINT64_MAX;
- for (block_info_page *bip = first_bi_page; bip; bip = bip->next)
- for (int i = 0; i < 255; ++i)
- if (bip->infos[i].size == minimum_length)
- return bip->infos + i;
- else if (
- bip->infos[i].size > minimum_length &&
- bip->infos[i].size < length_so_far
- ) {
- minimal_so_far = bip->infos + i;
- length_so_far = bip->infos[i].size;
- }
- if (minimal_so_far != 0)
- return minimal_so_far;
- uint64_t pages_needed = (minimum_length - 1) / 4096 + 1;
- void *block_start = _syscall_get_new_pages(pages_needed);
- return add_block((uint64_t)block_start, pages_needed * 4096);
- }
-
- static void deallocate_aligned(uint64_t start, uint64_t length) {
- block_info *buddy = try_find_block(start ^ length, length);
- if (buddy) {
- buddy->size = 0;
- deallocate_aligned(start & ~length, length * 2);
- return;
- }
- add_block(start, length);
- }
-
- static void deallocate(void *start, uint64_t length) {
- uint64_t at = (uint64_t)start;
- uint64_t left = length;
- uint64_t i;
- for (i = 1; i <= left; i *= 2)
- if (at & i) {
- deallocate_aligned(at, i);
- at += i;
- left -= i;
- }
- for (i /= 2; left > 0; i /= 2)
- if (i <= left) {
- deallocate_aligned(at, i);
- at += i;
- left -= i;
- }
- }
-
- [[nodiscard]] static void *allocate(uint64_t length) {
- block_info *bi = find_minimal_block(length);
- void *to_return = (void *)bi->start;
- void *new_start = (void *)(bi->start + length);
- uint64_t new_length = bi->size - length;
- bi->size = 0;
- deallocate(new_start, new_length);
- return to_return;
- }
-
- static void deallocate_with_length(void *start) {
- uint64_t real_start = (uint64_t)start - 8;
- deallocate((void *)real_start, *(uint64_t *)real_start);
- }
-
- [[nodiscard]] static void *allocate_with_length(uint64_t length) {
- uint64_t *real_start = (uint64_t *)allocate(length + 8);
- *real_start = length + 8;
- return real_start + 1;
- }
-
-}
-
-using namespace euler::allocator;
-
-void operator delete[](void *start) {
- deallocate_with_length(start);
-}
-
-void operator delete(void *start) {
- deallocate_with_length(start);
-}
-
-void operator delete[](void *start, uint64_t) {
- deallocate_with_length(start);
-}
-
-void operator delete(void *start, uint64_t) {
- deallocate_with_length(start);
-}
-
-void *operator new[](uint64_t size) {
- return allocate_with_length(size);
-}
-
-void *operator new(uint64_t size) {
- return allocate_with_length(size);
-}
diff --git a/libraries/euler/cassert.cpp b/libraries/euler/cassert.cpp
deleted file mode 100644
index e811b38..0000000
--- a/libraries/euler/cassert.cpp
+++ /dev/null
@@ -1,16 +0,0 @@
-#include <cassert>
-
-namespace euler {
-
- [[noreturn]] void assert_failed(
- const char *, const char *, int, const char *
- ) {
- //TODO: print error and abort
- //we could just exit right now but i want to keep us in
- //the application so we can get a stack trace in gdb.
- while (1)
- ;
- }
-
-
-}
diff --git a/libraries/euler/cctype.cpp b/libraries/euler/cctype.cpp
deleted file mode 100644
index 98234bb..0000000
--- a/libraries/euler/cctype.cpp
+++ /dev/null
@@ -1,11 +0,0 @@
-#include <cctype>
-
-namespace std {
-
- int isspace(int ch) {
- return
- ch == ' ' || ch == '\n' || ch == '\t' ||
- ch == '\r' || ch == '\v' || ch == '\f';
- }
-
-}
diff --git a/libraries/euler/cstdio.cpp b/libraries/euler/cstdio.cpp
deleted file mode 100644
index 367e7e0..0000000
--- a/libraries/euler/cstdio.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-#include <euler/syscall.hpp>
-#include <cassert>
-#include <cstring>
-#include <cstdio>
-
-namespace euler {
-
- //read-only with no error bits for now
- struct file_t {
-
- syscall::file_handle handle;
-
- //TODO: variable size buffer? maybe a multiple of block size for device?
- char buffer[1024];
- //in bytes, aligned to buffer size; 1 for no buffer loaded
- uint64_t buffer_start;
-
- bool is_offset_in_buffer() {
- return
- buffer_start != 1 && offset >= buffer_start &&
- offset < buffer_start + 1024;
- }
-
- syscall::file_result ensure_offset_in_buffer() {
- if (is_offset_in_buffer())
- return syscall::file_result::success;
- uint64_t new_buffer_start = (offset / 1024) * 1024;
- uint64_t new_buffer_end = new_buffer_start + 1024;
- if (length < new_buffer_end)
- new_buffer_end = length;
- syscall::file_result result = _syscall_read_from_file(
- handle, new_buffer_start, new_buffer_end - new_buffer_start, buffer);
- if (result == syscall::file_result::success)
- buffer_start = new_buffer_start;
- return result;
- }
-
- uint64_t offset;
- uint64_t length;
-
- };
-
-}
-
-namespace std {
-
- FILE *fopen(const char *path, const char *mode) {
-
- assert(mode[0] == 'r' && mode[1] == '\0');
-
- euler::syscall::file_handle handle;
- euler::syscall::file_result result =
- _syscall_open_file(path, strlen(path), handle);
- if (result != euler::syscall::file_result::success)
- return 0;
-
- uint64_t length;
- result = _syscall_get_file_length(handle, length);
- if (result != euler::syscall::file_result::success) {
- _syscall_close_file(handle);
- return 0;
- }
-
- return new FILE {
- .handle = handle,
- .buffer = {},
- .buffer_start = 1,
- .offset = 0,
- .length = length
- };
-
- }
-
- int fclose(FILE *file) {
- _syscall_close_file(file->handle);
- delete file;
- return 0;
- }
-
- int fgetc(FILE *from) {
- if (from->offset >= from->length)
- return EOF;
- assert(
- from->ensure_offset_in_buffer() == euler::syscall::file_result::success);
- char ch = from->buffer[from->offset - from->buffer_start];
- ++from->offset;
- return ch;
- }
-
- int ungetc(int ch, FILE *from) {
- if (ch == EOF || from->offset == 0)
- return EOF;
- --from->offset;
- if (!from->is_offset_in_buffer()) {
- ++from->offset;
- return EOF;
- }
- from->buffer[from->offset - from->buffer_start] = ch;
- return ch;
- }
-
-}
diff --git a/libraries/euler/entry.cpp b/libraries/euler/entry.cpp
deleted file mode 100644
index 0bbffda..0000000
--- a/libraries/euler/entry.cpp
+++ /dev/null
@@ -1,19 +0,0 @@
-#include <euler/syscall.hpp>
-
-int main(int argc, char **argv);
-
-extern "C" [[noreturn]] void _entry() {
-
- //TODO: static constructors
-
- //TODO: get command line via system call and populate argc and argv.
- int argc = 0;
- char **argv = 0;
-
- int result = main(argc, argv);
-
- //TODO: static destructors
-
- _syscall_end_this_process(result);
-
-}
diff --git a/libraries/euler/include/cassert b/libraries/euler/include/cassert
deleted file mode 100644
index bc716a0..0000000
--- a/libraries/euler/include/cassert
+++ /dev/null
@@ -1,13 +0,0 @@
-#pragma once
-
-namespace euler {
- [[noreturn]] void assert_failed(
- const char *file, const char *function, int line, const char *condition);
-}
-
-#ifdef NDEBUG
-#define assert(condition) ((void)0)
-#else
-#define assert(condition) ((condition) ? ((void)0) : \
- euler::assert_failed(__FILE__, __func__, __LINE__, #condition))
-#endif
diff --git a/libraries/euler/include/cctype b/libraries/euler/include/cctype
deleted file mode 100644
index 087b191..0000000
--- a/libraries/euler/include/cctype
+++ /dev/null
@@ -1,7 +0,0 @@
-#pragma once
-
-namespace std {
-
- int isspace(int ch);
-
-}
diff --git a/libraries/euler/include/cstddef b/libraries/euler/include/cstddef
deleted file mode 120000
index 9eac9b6..0000000
--- a/libraries/euler/include/cstddef
+++ /dev/null
@@ -1 +0,0 @@
-../../../mintsuki-freestanding-headers/stddef.h \ No newline at end of file
diff --git a/libraries/euler/include/cstdint b/libraries/euler/include/cstdint
deleted file mode 120000
index b087235..0000000
--- a/libraries/euler/include/cstdint
+++ /dev/null
@@ -1 +0,0 @@
-../../../mintsuki-freestanding-headers/stdint.h \ No newline at end of file
diff --git a/libraries/euler/include/cstdio b/libraries/euler/include/cstdio
deleted file mode 100644
index 3bb293b..0000000
--- a/libraries/euler/include/cstdio
+++ /dev/null
@@ -1,19 +0,0 @@
-#pragma once
-
-#define EOF (-1)
-
-namespace euler {
- struct file_t;
-}
-
-namespace std {
-
- typedef euler::file_t FILE;
-
- FILE *fopen(const char *path, const char *mode);
- int fclose(FILE *file);
-
- int fgetc(FILE *from);
- int ungetc(int ch, FILE *from);
-
-}
diff --git a/libraries/euler/include/cstring b/libraries/euler/include/cstring
deleted file mode 100644
index 65d00dc..0000000
--- a/libraries/euler/include/cstring
+++ /dev/null
@@ -1,14 +0,0 @@
-#pragma once
-
-#include <cstddef>
-
-namespace std {
-
- static inline size_t strlen(const char *str) {
- size_t i = 0;
- while (str[i])
- ++i;
- return i;
- }
-
-}
diff --git a/libraries/euler/include/euler/syscall.hpp b/libraries/euler/include/euler/syscall.hpp
deleted file mode 100644
index 2dc88b8..0000000
--- a/libraries/euler/include/euler/syscall.hpp
+++ /dev/null
@@ -1,51 +0,0 @@
-#pragma once
-
-#include <cstdint>
-
-namespace euler::syscall {
-
- typedef uint32_t encoded_color;
- typedef int32_t exit_code;
- typedef uint64_t file_handle;
- typedef uint32_t key_packet;
-
- enum [[nodiscard]] file_result : uint64_t {
- success,
- bad_file_handle,
- device_error,
- file_system_corrupt,
- out_of_bounds,
- does_not_exist,
- directory
- };
-
-}
-
-extern "C" {
-
- euler::syscall::encoded_color _syscall_encode_color(
- uint8_t red, uint8_t green, uint8_t blue);
-
- void _syscall_get_framebuffer(
- euler::syscall::encoded_color *&ptr_out, uint32_t &width_out,
- uint32_t &height_out, uint32_t &pitch_out);
-
- euler::syscall::file_result _syscall_open_file(
- const char *path, uint64_t path_length, euler::syscall::file_handle &out);
-
- euler::syscall::file_result _syscall_get_file_length(
- euler::syscall::file_handle file, uint64_t &out);
-
- euler::syscall::file_result _syscall_read_from_file(
- euler::syscall::file_handle file,
- uint64_t start_offset, uint64_t length, void *into);
-
- [[noreturn]] void _syscall_end_this_process(euler::syscall::exit_code code);
-
- [[nodiscard]] void *_syscall_get_new_pages(uint64_t count);
-
- void _syscall_close_file(euler::syscall::file_handle file);
-
- euler::syscall::key_packet _syscall_read_key_packet();
-
-}
diff --git a/libraries/euler/syscall.asm b/libraries/euler/syscall.asm
deleted file mode 100644
index c76a641..0000000
--- a/libraries/euler/syscall.asm
+++ /dev/null
@@ -1,88 +0,0 @@
-bits 64
-
-section .text
-
-global _syscall_encode_color
-_syscall_encode_color:
- xor rax, rax
- and edi, 0xff
- and dx, 0xff
- shl si, 8
- shl edx, 16
- or di, si
- or edi, edx
- syscall
- ret
-
-global _syscall_get_framebuffer
-_syscall_get_framebuffer:
- push rcx
- push rdx
- push rsi
- push rdi
- mov rax, 1
- syscall
- pop rcx
- mov qword [rcx], rax
- pop rcx
- mov dword [rcx], edi
- pop rcx
- shr rdi, 32
- mov dword [rcx], edi
- pop rcx
- mov dword [rcx], esi
- ret
-
-global _syscall_open_file
-_syscall_open_file:
- mov rax, 2
- push rdx
- syscall
- pop rdx
- mov qword [rdx], rdi
- ret
-
-global _syscall_get_file_length
-_syscall_get_file_length:
- mov rax, 3
- push rsi
- syscall
- pop rsi
- mov qword [rsi], rdi
- ret
-
-global _syscall_read_from_file
-_syscall_read_from_file:
- mov rax, 4
- push rcx
- push rdx
- push rsi
- push rdi
- mov rdi, rsp
- syscall
- add rsp, 32
- ret
-
-global _syscall_end_this_process
-_syscall_end_this_process:
- mov rax, 5
- syscall
- ;does not return
-
-global _syscall_get_new_pages
-_syscall_get_new_pages:
- mov rax, 6
- syscall
- ret
-
-global _syscall_close_file
-_syscall_close_file:
- mov rax, 7
- syscall
- ret
-
-global _syscall_read_key_packet
-_syscall_read_key_packet:
- mov rax, 8
- syscall
- ret
diff --git a/limine.cfg b/limine.cfg
deleted file mode 100644
index 4a411a1..0000000
--- a/limine.cfg
+++ /dev/null
@@ -1,5 +0,0 @@
-TIMEOUT=0
-
-:Hilbert
-PROTOCOL=limine
-KERNEL_PATH=boot:///kernel.elf
diff --git a/makefile b/makefile
index cf8405e..060ec5b 100644
--- a/makefile
+++ b/makefile
@@ -1,93 +1,124 @@
-GPP_ARGS = -std=c++17 -Wall -Wextra -O3 -ggdb -nostdinc \
- -fno-exceptions -ffreestanding -fno-rtti -mno-sse
-KGPP_ARGS = ${GPP_ARGS} -I kernel/include -I mintsuki-freestanding-headers
-AGPP_ARGS = ${GPP_ARGS} -I libraries/euler/include \
- -I libraries/daguerre/include
+LIMINE_DIR = $(abspath dependencies/limine)
+TOOLCHAIN_DIR = $(abspath toolchain)
-LD_ARGS = -z noexecstack
-KLD_ARGS = -T kernel/link.ld ${LD_ARGS}
-ALD_ARGS = -T applications/link.ld ${LD_ARGS}
-LLD_ARGS = ${LD_ARGS}
+HILBERT_NASM = nasm -f elf64
+HILBERT_CC = ${TOOLCHAIN_DIR}/usr/bin/x86_64-elf-c++ -std=c++17 -Wall \
+ -Wextra -O3 -ggdb -static -fno-exceptions -fno-rtti -mno-sse -I include \
+ -I $(abspath dependencies/mintsuki-headers) -I $(abspath euler/include) \
+ -I $(abspath libraries/daguerre/include)
+HILBERT_AR = ${TOOLCHAIN_DIR}/usr/bin/x86_64-elf-ar
+HILBERT_LD = ${TOOLCHAIN_DIR}/usr/bin/x86_64-elf-ld -z noexecstack
-all: out/disk.iso
+.EXPORT_ALL_VARIABLES:
-run: out/disk.iso
+LIB_DIR = toolchain/usr/x86_64-elf/lib/
+
+LIMINE_DEP = dependencies/.limine-done
+MINTSUKI_HEADERS_DEP = dependencies/.mintsuki-headers-done
+BINUTILS_DEP = toolchain/.binutils-done
+GCC_DEP = toolchain/.gcc-done
+LIBGCC_DEP = toolchain/.libgcc-done
+
+EULER_DEP = toolchain/.euler-done
+DAGUERRE_DEP = toolchain/.daguerre-done
+
+APP_DEPS = ${GCC_DEP} ${LIBGCC_DEP} ${EULER_DEP} ${MINTSUKI_HEADERS_DEP}
+LIBRARY_DEPS = ${GCC_DEP} ${MINTSUKI_HEADERS_DEP}
+
+.PHONY: default run clean clean-dependencies
+
+default: build/disk.iso
+
+run: build/disk.iso
gdb -x qemu.gdb
clean:
- rm -rf obj out
-
-dist-clean:
- rm -rf limine mintsuki-freestanding-headers
-
-limine:
- git clone --depth=1 -b v6.x-branch \
- https://github.com/limine-bootloader/limine.git limine
- cd limine && ./bootstrap && ./configure -q --enable-bios --enable-bios-cd
- +make -C limine
-
-mintsuki-freestanding-headers:
- git clone --depth=1 \
- https://github.com/mintsuki/freestanding-headers.git \
- mintsuki-freestanding-headers
-
-obj/kernel/entry.cpp.o: kernel/entry.cpp limine mintsuki-freestanding-headers
- @mkdir -p $(@D)
- g++ -c ${KGPP_ARGS} $< -o $@
-
-obj/kernel/%.cpp.o: kernel/%.cpp mintsuki-freestanding-headers
- @mkdir -p $(@D)
- g++ -c ${KGPP_ARGS} $< -o $@
-
-obj/kernel/%.asm.o: kernel/%.asm
- @mkdir -p $(@D)
- nasm -f elf64 $< -o $@
-
-KERNEL_OBJECTS = allocator.cpp application.cpp entry.cpp framebuffer.cpp \
- paging.asm paging.cpp storage.cpp storage/bd/memory.cpp terminal.cpp \
- storage/fs/tarfs.cpp utility.cpp vfile.cpp syscall.asm syscall.cpp \
- interrupts.asm interrupts.cpp input.cpp panic.cpp
-obj/kernel.elf: ${KERNEL_OBJECTS:%=obj/kernel/%.o}
- ld ${KLD_ARGS} $^ -o $@
-
-obj/%.cpp.o: %.cpp mintsuki-freestanding-headers
- @mkdir -p $(@D)
- g++ -c ${AGPP_ARGS} $< -o $@
-
-obj/%.asm.o: %.asm
- @mkdir -p $(@D)
- nasm -f elf64 $< -o $@
-
-EULER_OBJECTS = entry.cpp syscall.asm cassert.cpp allocator.cpp cstdio.cpp \
- cctype.cpp
-obj/euler.o: ${EULER_OBJECTS:%=obj/libraries/euler/%.o}
- ld -r ${LLD_ARGS} $^ -o $@
-
-DAGUERRE_OBJECTS = ppm.cpp
-obj/daguerre.o: ${DAGUERRE_OBJECTS:%=obj/libraries/daguerre/%.o}
- ld -r ${LLD_ARGS} $^ -o $@
-
-INIT_OBJECTS = main.cpp
-obj/initfs/bin/init.elf: ${INIT_OBJECTS:%=obj/applications/init/%.o} \
- obj/euler.o obj/daguerre.o
- @mkdir -p $(@D)
- ld ${ALD_ARGS} $^ -o $@
-
-obj/initfs/.skeleton:
- @mkdir -p obj/initfs
- cp -r skeleton/* obj/initfs/
- @touch obj/initfs/.skeleton
-
-APPLICATIONS = init
-obj/initfs.tgz: ${APPLICATIONS:%=obj/initfs/bin/%.elf} obj/initfs/.skeleton
- tar czf obj/initfs.tgz -C obj/initfs .
-
-out/disk.iso: obj/kernel.elf obj/initfs.tgz limine
- mkdir -p obj/iso out
- cp obj/kernel.elf obj/initfs.tgz limine/bin/limine-bios.sys \
- limine/bin/limine-bios-cd.bin limine.cfg obj/iso/
- cp terminus/ter-u16b.psf obj/iso/termfont.psf
- xorriso -as mkisofs -quiet -no-emul-boot -boot-info-table \
- -boot-load-size 4 -b limine-bios-cd.bin obj/iso -o $@
- limine/bin/limine bios-install $@
- rm -rf obj/iso
+ rm -rf build ${EULER_DEP} ${DAGUERRE_DEP}
+ make -C euler clean
+ make -C kernel clean
+ make -C applications/init clean
+ make -C libraries/daguerre clean
+
+clean-dependencies: clean
+ rm -rf toolchain dependencies
+
+${LIMINE_DEP}:
+ mkdir -p dependencies
+ test -e dependencies/limine || git clone --depth 1 -b v7.5.1 https://github.com/limine-bootloader/limine dependencies/limine
+ cd ${LIMINE_DIR} && ./bootstrap
+ cd ${LIMINE_DIR} && ./configure --enable-bios --enable-bios-cd
+ +make -C ${LIMINE_DIR}
+ touch $@
+
+${MINTSUKI_HEADERS_DEP}:
+ mkdir -p dependencies
+ test -e dependencies/mintsuki-headers || git clone --depth 1 https://github.com/mintsuki/freestanding-headers dependencies/mintsuki-headers
+ touch $@
+
+${BINUTILS_DEP}:
+ mkdir -p dependencies toolchain/usr
+ test -e dependencies/binutils || (git clone --depth 1 -b binutils-2_42 https://sourceware.org/git/binutils-gdb dependencies/binutils && cd dependencies/binutils && git apply ../../patches/binutils.txt)
+ mkdir -p dependencies/binutils/build
+ cd dependencies/binutils/build && ../configure --disable-gdb \
+ --target=x86_64-elf --prefix=${TOOLCHAIN_DIR}/usr
+ +make -C dependencies/binutils/build
+ +make -C dependencies/binutils/build install
+ touch $@
+
+${GCC_DEP}: ${BINUTILS_DEP}
+ mkdir -p toolchain/usr/include
+ test -e dependencies/gcc || git clone --depth 1 -b releases/gcc-14.1.0 https://gcc.gnu.org/git/gcc dependencies/gcc
+ mkdir -p dependencies/gcc/build
+ cd dependencies/gcc/build && ../configure --disable-fixed-point \
+ --disable-gcov --disable-multilib --disable-shared --enable-languages=c++ \
+ --target=x86_64-elf --prefix=${TOOLCHAIN_DIR}/usr --without-headers
+ +make -C dependencies/gcc/build all-gcc
+ +make -C dependencies/gcc/build install-gcc
+ touch $@
+
+${LIBGCC_DEP}: ${GCC_DEP}
+ +make -C dependencies/gcc/build all-target-libgcc
+ +make -C dependencies/gcc/build install-target-libgcc
+ touch $@
+
+${EULER_DEP}: ${GCC_DEP} ${MINTSUKI_HEADERS_DEP}
+ +make -C euler build/crt0.o build/libc.a build/libg.a build/libm.a \
+ build/libstdc++.a
+ mkdir -p toolchain/usr/x86_64-elf/lib
+ cp euler/build/crt0.o euler/build/libc.a euler/build/libg.a \
+ euler/build/libm.a euler/build/libstdc++.a ${LIB_DIR}
+ touch $@
+
+${DAGUERRE_DEP}: ${LIBRARY_DEPS}
+ +make -C libraries/daguerre build/libdaguerre.a
+ cp libraries/daguerre/build/libdaguerre.a ${LIB_DIR}
+ touch $@
+
+kernel/build/kernel.elf: ${GCC_DEP} ${MINTSUKI_HEADERS_DEP} ${LIMINE_DEP}
+ +make -C kernel build/kernel.elf
+
+applications/init/build/init.elf: ${APP_DEPS} ${DAGUERRE_DEP}
+ +make -C applications/init build/init.elf
+
+build/initfs.tgz: applications/init/build/init.elf
+ @mkdir -p build
+ rm -rf build/initfs
+ cp -r skeleton build/initfs
+ mkdir build/initfs/bin
+ cp applications/init/build/init.elf build/initfs/bin/init
+ cd build/initfs && tar czf ../initfs.tgz .
+
+build/disk.iso: kernel/build/kernel.elf build/initfs.tgz ${LIMINE_DEP}
+ @mkdir -p build
+ rm -rf build/iso
+ mkdir build/iso
+ cp kernel/build/kernel.elf ${LIMINE_DIR}/bin/limine-bios.sys \
+ ${LIMINE_DIR}/bin/limine-bios-cd.bin build/initfs.tgz build/iso/
+ echo 'TIMEOUT=0' > build/iso/limine.cfg
+ echo ':Hilbert OS' >> build/iso/limine.cfg
+ echo 'PROTOCOL=limine' >> build/iso/limine.cfg
+ echo 'KERNEL_PATH=boot:///kernel.elf' >> build/iso/limine.cfg
+ echo 'MODULE_PATH=$$boot:///initfs.tgz' >> build/iso/limine.cfg
+ echo 'MODULE_CMDLINE=initfs' >> build/iso/limine.cfg
+ xorriso -as mkisofs -b limine-bios-cd.bin -no-emul-boot -boot-load-size 4 \
+ -boot-info-table --protective-msdos-label build/iso -o $@
diff --git a/patches/binutils.txt b/patches/binutils.txt
new file mode 100644
index 0000000..b2dcff7
--- /dev/null
+++ b/patches/binutils.txt
@@ -0,0 +1,17 @@
+diff --git a/ld/emulparams/elf_x86_64.sh b/ld/emulparams/elf_x86_64.sh
+index 466da2c4..806cd413 100644
+--- a/ld/emulparams/elf_x86_64.sh
++++ b/ld/emulparams/elf_x86_64.sh
+@@ -14,9 +14,9 @@ SCRIPT_NAME=elf
+ ELFSIZE=64
+ OUTPUT_FORMAT="elf64-x86-64"
+ NO_REL_RELOCS=yes
+-TEXT_START_ADDR=0x400000
+-MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
+-COMMONPAGESIZE="CONSTANT (COMMONPAGESIZE)"
++TEXT_START_ADDR=0x200000
++MAXPAGESIZE="0x1000"
++COMMONPAGESIZE="0x1000"
+ ARCH="i386:x86-64"
+ MACHINE=
+ TEMPLATE_NAME=elf
diff --git a/qemu.gdb b/qemu.gdb
index d27659b..f11f85c 100644
--- a/qemu.gdb
+++ b/qemu.gdb
@@ -1,8 +1,6 @@
-target remote | qemu-system-x86_64 -gdb stdio -cdrom out/disk.iso -boot d
-symbol-file obj/kernel.elf
-add-symbol-file obj/initfs/bin/init.elf
+target remote | qemu-system-x86_64 -gdb stdio -cdrom build/disk.iso -boot d
+symbol-file kernel/build/kernel.elf
+add-symbol-file build/initfs/bin/init
set disassembly-flavor intel
set print asm-demangle on
-break entry
-break main
layout src
diff --git a/readme.txt b/readme.txt
index bdd8e45..d48c43c 100644
--- a/readme.txt
+++ b/readme.txt
@@ -1,48 +1,74 @@
-hilbert os is a 64-bit hobby operating system, which is not
-very mature yet. to build and test it, you will need some
-dependencies. these can be installed on debian with:
- apt install g++ gcc gdb git make nasm qemu-system-x86 xorriso
+hilbert os is a 64-bit hobby operating system, which is not very mature yet. to
+build and test it, you will need some software installed. on debian, i believe
+running command [1] below as root (e.g. with sudo) is sufficient. the default
+makefile target builds a disk image at build/disk.iso that can be booted on a
+64-bit bios system. you can use command [2] to build that. finally, use command
+[3] to run the disk in qemu with gdb attached.
-then, just run "make -jx", replacing x with the number of threads to use
-while building. this will create a bios-bootable disk image in out/disk.iso.
-you can then test it in qemu with gdb attached by running "make run".
+ [1] apt install g++ gdb git make nasm qemu-system-x86 xorriso
+ [2] make -j$(nproc)
+ [3] make run
-acknowledgements (* = downloaded during make):
+acknowledgements (any under "dependencies" are downloaded during build):
- - limine bootloader*
- homepage: https://limine-bootloader.org/
- license: limine/COPYING (bsd two-clause)
+ - dependencies/binutils (gnu binutils v2.42)
+ copyright 2024 free software foundation, inc.
+ license: dependencies/binutils/COPYING (gnu gpl v2)
+ homepage: https://www.gnu.org/software/binutils/
+ note: the patch in patches/binutils.txt is applied before building
- - terminus font
- homepage: https://terminus-font.sourceforge.net/
- license: terminus/license.txt (sil open font license v1.1)
+ - dependencies/gcc (gnu compiler collection v14.1.0)
+ copyright 2024 free software foundation, inc.
+ license:
+ dependencies/gcc/COPYING3 (gnu gpl v3)
+ dependencies/gcc/COPYING.RUNTIME (gcc runtime library exception v3.1)
+ homepage: https://gcc.gnu.org/
- - photo at skeleton/assets/burdon.ppm
- photographer: aaron burdon
- source: https://unsplash.com/photos/selective-focus-photography-snowflakes-9yhy1FXlKwI
- license: https://unsplash.com/license
+ - dependencies/limine (limine bootloader v7.5.1)
+ copyright 2019 - 2024 mintsuki and contributors
+ license: dependencies/limine/COPYING (bsd two-clause)
+ homepage: https://limine-bootloader.org/
- - mintsuki's freestanding c headers*
- homepage: https://github.com/mintsuki/freestanding-headers
- license: mintsuki-freestanding-headers/LICENSE (bsd zero-clause)
+ - dependencies/minstuki-headers
+ copyright 2022 - 2024 mintsuki and contributors
+ license: dependencies/mintsuki-headers/LICENSE (bsd zero-clause)
+ homepage: https://github.com/mintsuki/freestanding-headers/
+
+ - skeleton/assets/burden.ppm
+ ("selective focus photography snowflakes" by aaron burden)
+ license: https://unsplash.com/license
+ source: https://unsplash.com/photos/selective-focus-photography-snowflakes-9yhy1FXlKwI
+
+everything in the following directories is copyright 2024 benji dial, under the
+license in license.txt (the isc license):
+
+ - applications
+ - euler
+ - kernel
+ - libraries
project structure:
- - applications/init: the first application started by the kernel
- - applications/link.ld: a common linker script used by every application
- - documentation: documentation on the kernel (not very organized)
- - kernel: the kernel of hilbert os
- - libraries/daguerre: an image loading / rendering library
- - libraries/euler: the c++ standard library and runtime for applications
- - limine: the limine bootloader (see acknowledgements)
- - mintsuki-freestanding-headers:
- mintsuki's freestanding headers (see acknowledgements)
- - obj: built object files
- - out: completed builds
- - skeleton: files that are directly copied to the initfs
- - terminus: the terminus font (see acknowledgements)
- - license.txt: the license that hilbert os is under
- - limine.cfg: the limine configuration used by the built disk
- - makefile: the makefile that is used to build the entire os
- - qmeu.gdb: a file for gdb to include when doing make run
- - readme.txt: this file
+ - applications/init:
+ the initial program loaded by the kernel. currently it displays the image
+ by aaron burden, and inverts the colors when the enter key is pressed.
+
+ - documentation:
+ documentation. currently this directory is a bit disorganized, and has
+ some descriptions of things that have not been created yet.
+
+ - euler:
+ (a minimal start to) a c/c++ standard library and runtime. the plan is to
+ follow the c++17 standard, and only add things as i need them.
+
+ - kernel:
+ the kernel.
+
+ - libraries/daguerre:
+ an image loading / rendering library.
+
+ - patches/binutils.txt:
+ a patch that is applied to gnu binutils before it is built.
+
+ - skeleton:
+ files that are copied directly to the initfs.
diff --git a/skeleton/init/burdon.ppm b/skeleton/assets/burden.ppm
index fe4a66a..fe4a66a 100644
--- a/skeleton/init/burdon.ppm
+++ b/skeleton/assets/burden.ppm
diff --git a/skeleton/assets/readme.txt b/skeleton/assets/readme.txt
new file mode 100644
index 0000000..56b1a9b
--- /dev/null
+++ b/skeleton/assets/readme.txt
@@ -0,0 +1,4 @@
+the photo in burden.ppm is "selective focus photography snowflakes" by aaron
+burden. it can be found online at
+https://unsplash.com/photos/selective-focus-photography-snowflakes-9yhy1FXlKwI.
+its license can be found online at https://unsplash.com/license.
diff --git a/skeleton/cfg/default.key b/skeleton/cfg/default.key
new file mode 120000
index 0000000..9ad07aa
--- /dev/null
+++ b/skeleton/cfg/default.key
@@ -0,0 +1 @@
+qwerty.key \ No newline at end of file
diff --git a/skeleton/cfg/init.sh b/skeleton/cfg/init.sh
new file mode 100644
index 0000000..312dba0
--- /dev/null
+++ b/skeleton/cfg/init.sh
@@ -0,0 +1 @@
+/bin/wm &
diff --git a/skeleton/init/readme.txt b/skeleton/init/readme.txt
deleted file mode 100644
index 294909f..0000000
--- a/skeleton/init/readme.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-the photo in burdon.ppm is by aaron burdon, and can be found online at
-https://unsplash.com/photos/selective-focus-photography-snowflakes-9yhy1FXlKwI.
-its license can be found at https://unsplash.com/license.
diff --git a/terminus/license.txt b/terminus/license.txt
deleted file mode 100644
index 5168372..0000000
--- a/terminus/license.txt
+++ /dev/null
@@ -1,94 +0,0 @@
-Copyright (C) 2020 Dimitar Toshkov Zhekov,
-with Reserved Font Name "Terminus Font".
-
-This Font Software is licensed under the SIL Open Font License, Version 1.1.
-This license is copied below, and is also available with a FAQ at:
-http://scripts.sil.org/OFL
-
-
------------------------------------------------------------
-SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
------------------------------------------------------------
-
-PREAMBLE
-The goals of the Open Font License (OFL) are to stimulate worldwide
-development of collaborative font projects, to support the font creation
-efforts of academic and linguistic communities, and to provide a free and
-open framework in which fonts may be shared and improved in partnership
-with others.
-
-The OFL allows the licensed fonts to be used, studied, modified and
-redistributed freely as long as they are not sold by themselves. The
-fonts, including any derivative works, can be bundled, embedded,
-redistributed and/or sold with any software provided that any reserved
-names are not used by derivative works. The fonts and derivatives,
-however, cannot be released under any other type of license. The
-requirement for fonts to remain under this license does not apply
-to any document created using the fonts or their derivatives.
-
-DEFINITIONS
-"Font Software" refers to the set of files released by the Copyright
-Holder(s) under this license and clearly marked as such. This may
-include source files, build scripts and documentation.
-
-"Reserved Font Name" refers to any names specified as such after the
-copyright statement(s).
-
-"Original Version" refers to the collection of Font Software components as
-distributed by the Copyright Holder(s).
-
-"Modified Version" refers to any derivative made by adding to, deleting,
-or substituting -- in part or in whole -- any of the components of the
-Original Version, by changing formats or by porting the Font Software to a
-new environment.
-
-"Author" refers to any designer, engineer, programmer, technical
-writer or other person who contributed to the Font Software.
-
-PERMISSION & CONDITIONS
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of the Font Software, to use, study, copy, merge, embed, modify,
-redistribute, and sell modified and unmodified copies of the Font
-Software, subject to the following conditions:
-
-1) Neither the Font Software nor any of its individual components,
-in Original or Modified Versions, may be sold by itself.
-
-2) Original or Modified Versions of the Font Software may be bundled,
-redistributed and/or sold with any software, provided that each copy
-contains the above copyright notice and this license. These can be
-included either as stand-alone text files, human-readable headers or
-in the appropriate machine-readable metadata fields within text or
-binary files as long as those fields can be easily viewed by the user.
-
-3) No Modified Version of the Font Software may use the Reserved Font
-Name(s) unless explicit written permission is granted by the corresponding
-Copyright Holder. This restriction only applies to the primary font name as
-presented to the users.
-
-4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
-Software shall not be used to promote, endorse or advertise any
-Modified Version, except to acknowledge the contribution(s) of the
-Copyright Holder(s) and the Author(s) or with their explicit written
-permission.
-
-5) The Font Software, modified or unmodified, in part or in whole,
-must be distributed entirely under this license, and must not be
-distributed under any other license. The requirement for fonts to
-remain under this license does not apply to any document created
-using the Font Software.
-
-TERMINATION
-This license becomes null and void if any of the above conditions are
-not met.
-
-DISCLAIMER
-THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
-OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
-COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
-DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
-OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/terminus/readme.txt b/terminus/readme.txt
deleted file mode 100644
index dcf0163..0000000
--- a/terminus/readme.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-the file ter-u16b.psf contains the terminus font, version 4.49.1, at 8x16
-bold with the td1 patch applied. terminus is licensed under the sil open
-font license, version 1.1, which is in the file license.txt.
-
-terminus home page: https://terminus-font.sourceforge.net/
diff --git a/terminus/ter-u16b.psf b/terminus/ter-u16b.psf
deleted file mode 100644
index 3215b16..0000000
--- a/terminus/ter-u16b.psf
+++ /dev/null
Binary files differ