Compare commits

...

78 Commits

Author SHA1 Message Date
e145690db8 apps: Remove demo programs (except for init)
We no longer need those, and they just make the initrd larger.
2022-10-11 21:37:27 +02:00
25ab31c7ce Remove unnecessary comments 2022-10-11 21:32:28 +02:00
d3ac590e24 Kernel: Remove the sys_getversion() syscall
User programs can now acquire this information by reading /dev/version.
2022-10-11 21:31:28 +02:00
112e375b5e Kernel: Add a FIXME 2022-10-11 21:21:27 +02:00
c30041b733 fix naming 2022-10-11 21:17:07 +02:00
88a01fcfc7 libc: make perror output to stderr 2022-10-11 21:13:38 +02:00
b67011c626 libc: Use the new write() syscall
The new one is write(fd, buf, count).
The old one was write(buf, count).

So the old one tries to pass buf as a file descriptor, and write() complains that 4000000 is too large of a file descriptor and throws EBADF.

We now use the new syscall, through the wrapper that fwrite() provides us.
2022-10-11 21:12:19 +02:00
0f47f59364 libc: make fprintf actually write to the chosen file
Also, printf now is kind of an alias for fprintf(stdout,...), as it should be.
2022-10-11 21:10:19 +02:00
2f46e46aa4 libc: Implement fwrite()
Now that we have the write() syscall and libc wrapper, fwrite can finally be implemented.
2022-10-11 21:09:30 +02:00
80ab982fe4 libc: make stdout and stderr functional
what were before one extern FILE* without reference now are opened by libc on program initialization, to point to /dev/console by default.
2022-10-11 21:08:46 +02:00
53a4b3b85e libc: Add new flags to open()
Since we now have write support, we can add O_WRONLY and O_RDWR to fcntl.h :)
2022-10-11 21:07:21 +02:00
12cf37d0a7 Kernel/syscalls: Modify sys_write to accept a file descriptor and write to it
Previously, sys_write only wrote to the tty. Now, it uses the VFS interface, as it should.
2022-10-11 21:06:12 +02:00
e764647133 Devices: add a new ConsoleDevice
This new device is the userspace interface to the text console/tty.
2022-10-11 21:04:50 +02:00
b1fcfd0d74 VersionDevice: Ignore offset instead of erroring out + set flags to 0 2022-10-11 21:04:14 +02:00
e67ef7778c VFS: Support writing to files 2022-10-11 21:03:30 +02:00
f6e783ea45 init: do not show 'read n bytes' when printing version
that was to debug why reading /dev/version returned 'versionmoon 0.10-' instead of 'moon 0.10-fffffff'

it works now, so...
2022-10-11 20:13:00 +02:00
8e57df518f apps: build with optimizations enabled 2022-10-11 19:57:24 +02:00
0c451e504e Kernel: Mounting /dev MUST succeed 2022-10-11 19:53:55 +02:00
04da26bff5 kernel: add a few comments 2022-10-11 19:51:24 +02:00
feb8c1c31b libc: Implement strchr() 2022-10-11 19:50:18 +02:00
0131193379 ELFLoader, Scheduler: Transition to use VFS
We should start to drop the old InitRD API, which only allows for files to be loaded from the initrd, and which forces pathnames to be relative (bin/init)
With VFS, we can load any kind of file from any kind of filesystem, and using paths that make sense (/bin/init)
2022-10-11 19:33:48 +02:00
86b50a6aa0 Remove random demos
Cool, but cumbersome in practice: have to continually restart until I get the demo I want.

So let's stick to init for now.
2022-10-11 19:25:19 +02:00
0a7d4a530d VFS, DeviceFS: Implement a device filesystem
For now, we just have a version device. (this will allow us to get rid of sys_getversion!!)
More should be implemented soon.
2022-10-11 19:21:16 +02:00
a198cf8d8d Add initrd_mkdir to registered directories in the initrd 2022-10-11 18:25:11 +02:00
4aa3da8c12 VFS: Add basic mount(), unmount() and mkdir() functions (not accessible to userspace yet) 2022-10-11 18:23:00 +02:00
1278cec065 VFS: Add a 'type' flag to Nodes, implement EISDIR 2022-10-11 17:48:11 +02:00
7a097f16ea apps: add a new example app which does all kinds of stdio misbehaving >.< 2022-10-11 17:31:06 +02:00
667d308fc3 kernel/main.cpp: remove obsolete reference to _userspace 2022-10-11 17:30:40 +02:00
6088031c49 stdio: log stuff more 2022-10-11 17:19:03 +02:00
81815a0bdd Refactor sys/stdio.cpp 2022-10-11 17:10:44 +02:00
2a755fcd93 sys_open(): actually return EMFILE if the process has used all of its file slots 2022-10-11 17:03:16 +02:00
6c51477197 libc: Implement ferror() and feof() 2022-10-11 16:57:08 +02:00
d25e8a43db build system: strip apps 2022-10-10 21:24:21 +02:00
4f2b3ce5d1 fclose: restore errno after call to free() if close() fails 2022-10-10 21:18:24 +02:00
93f6be9319 libc: Implement the start of a FILE* API (the standard, portable C way of doing file stuff) 2022-10-10 21:08:57 +02:00
9e0bd39964 libc: Implement wrappers for sys_{open,read,write}
read() and close() are in unistd.h, but open() in fnctl.h.
I thought only the definitions for O_SOMETHING were in fnctl.h, but it is as it is.
Don't know why, but let's not anger the Unix gods.

The FILE* C API is pending as well.
2022-10-10 20:45:26 +02:00
1b84c443fe Merge branch VFS into main
Reviewed-on: #10
2022-10-10 18:25:43 +00:00
da2ede3450 Kernel, libc, userspace: Implement file descriptors
Kernel: Implement a descriptor struct which stores the opened node and read offset, and give each task 8 of those.
Implement three syscalls: sys_read, sys_open and sys_close (sys_write still writes to the console instead of using a fd, for now)
Implement three new errors: ENOENT, EBADF and EMFILE.

libc: Implement the new errors, and the new syscalls in syscall().
Also fix _RETURN_WITH_ERRNO() to set errno correctly, which was making strerror() return null, thus crashing perror().

userspace: make init demonstrate the new file API.
2022-10-10 20:21:39 +02:00
63b2de4e3c Basic FDs 2022-10-10 19:00:24 +02:00
da84f1713c InitRD: Use get_blocks_from_size() 2022-10-10 18:45:49 +02:00
bbe7c6e658 VFS: Implement resolve_path and form the initial ramdisk's VFS properly
Finally, resolve_path: a function which takes a path (/etc/fstab for example), and walks the VFS:
In this case, it would start with the root FS node, and ask it: "do you have a directory/file named etc?"
The node could say 'yes', 'no', or 'i'm not a directory, I'm a file' (should not be the case for the VFS root, but for the other ones it could be)
If it says yes, we continue and ask the child if it has a file named fstab. Etc...
2022-10-10 18:44:43 +02:00
2be70d0bc1 VFS: Use 64-bit numbers in read()
There is no need for any kind of 32-bit compatibility.
2022-10-09 21:30:38 +02:00
8158ddc94f VFS: be more verbose 2022-10-09 21:19:22 +02:00
b38c52f8c7 more vfs stuff 2022-10-08 21:35:19 +02:00
f3d7e220ac The beginnings of a VFS implementation!! 2022-10-08 21:22:46 +02:00
49c7900407 Add %m to userspace printf
%m as a format specifier is a nonstandard glibc extension, but I like it so I'm implementing it.
What it does is print the value of strerror(errno), without consuming any arguments to printf().
2022-10-08 18:44:14 +02:00
4b74c14f1b Merge branch printf_pointers into main
Reviewed-on: #9
2022-10-08 16:27:37 +00:00
3686e03bb7 Cast %p usage to void*
Apparently, %p only accepts void*, and not any pointer type. Still better than casting a pointer to uint64_t.
2022-10-08 18:27:05 +02:00
3feb7782bc Kernel/mmap, munmap: Use %p in printf 2022-10-08 18:24:05 +02:00
d5f59b666a Kernel/Memory: Use %p in printf 2022-10-08 18:21:02 +02:00
8ce58e9e30 Kernel/InitRD: Use %p with printf() 2022-10-08 18:16:55 +02:00
5fc543c179 Kernel/ACPI: Use printf() with %p 2022-10-08 18:15:08 +02:00
40099feb80 Apps: Use the new %p in printf() 2022-10-08 18:11:41 +02:00
3ee1f34bc4 Forgot to add break :)
And that, is why you test before pushing and commiting >.<
2022-10-08 18:08:50 +02:00
c67079dd74 Kernel, libc: Implement %p in *printf()
So we can avoid writing (unsigned long)ptr or (uint64_t)ptr everywhere when wanting to print a pointer.
2022-10-08 18:07:33 +02:00
247645d301 Merge branch exit_status into main
Reviewed-on: #8
2022-10-08 15:58:51 +00:00
f83a6ace51 Kernel, libc: Add support for providing a status code to exit()
The exit() libc function already accepted an integer, but didn't pass it on to the kernel since we had no mechanism for it to do that.
Now, the kernel stores a task's exit status to display it later (and in the future, return it to userspace via wait()/waitpid())
2022-10-08 17:56:40 +02:00
1e0c8c5fe7 Kernel: Strip kernel symbols when installing
Since we already extract the symbols into a separate file which the kernel then uses for backtraces, this only brings us a smaller kernel, with no downsides :)
2022-10-08 15:57:07 +02:00
4a212b4c92 Modify shebangs to use /usr/bin/env bash instead of /bin/sh 2022-10-08 15:35:39 +02:00
aa5c1be945 Separate building a debug image and running it, and provide a script for GDB. 2022-10-08 15:32:48 +02:00
309058888c Bugfix: remove duplicate error check when loading a userspace ELF program
Also, remember to delete the allocated task, since we do not want memory leaks :)
2022-10-08 13:12:19 +00:00
159d025d9f ACPI::get_rsdt_or_xsdt(): Use a temporary variable to do mappings, then set cache to it. 2022-10-08 15:05:59 +02:00
a5daa24fbf Fix bug :) 2022-10-08 15:03:10 +02:00
533b7c9e71 Refactor ACPI::get_rsdt_or_xsdt()
Much better now.

Also, remove a FIXME in PMM.cpp, since we do map the page bitmap to virtual memory now.
2022-10-08 15:00:42 +02:00
abcf1b6118 Define PAGE_SIZE as 4096 and use it everywhere instead of using 4096 as a magic number 2022-10-08 14:52:28 +02:00
1235ce8b32 Avoid magic numbers 2022-10-08 14:44:48 +02:00
ce6ec3585c Kernel, libc: Add ENOSYS
This error is returned by the kernel/C Library when an attempt is made to use a system call that doesn't exist.
2022-10-08 14:18:25 +02:00
ac72d64490 Make (v)fprintf alias to (v)printf instead of throwing an error
We don't have files :) (yet)
But if someone wants to fprintf(stderr), then fine. Do it. Except it won't be any different from fprintf(stdout) or printf().
2022-10-08 13:45:57 +02:00
a086ec514b Remove the Superblock.h file which has never been used.
This file was included for a future Ext2 implementation. It should be included when said Ext2 implementation is actually started.
2022-10-08 13:28:30 +02:00
9b778254f1 Merge branch perror into main
Reviewed-on: #6
2022-10-08 10:46:02 +00:00
e76d903642 apps: make memeater use perror 2022-10-08 12:42:46 +02:00
ee7558a9b7 Add a perror() function 2022-10-08 12:42:25 +02:00
d6f45c284e Merge branch strerror into main
Reviewed-on: #5
2022-10-08 10:32:12 +00:00
21e8ea1486 apps: make memeater use strerror() 2022-10-08 12:29:19 +02:00
8f0b6d80b2 libc: Implement strerror() 2022-10-08 12:29:06 +02:00
71e15e94af Kernel, libc and userspace: Add basic errno support.
Kernel: Add an errno.h header with definitions for each header,
and return those, negated, from syscalls when there is an error.
mmap() returns an invalid address with errno encoded, instead of
returning a negated errno; this address is encoded as ffffffffffffffEE
where EE is errno in hex.

libc: make syscall() return -1 and set errno on error, instead of
returning the raw return value of the system call. Also, add mmap()
and munmap() wrappers in sys/mman.h :).

userspace: make the memeater program show the value of errno
when allocating memory fails.

Things to improve: add perror() and strerror() to make the errno
experience even better! >.<
2022-10-08 12:06:09 +02:00
ad115e9bab libc: Correct include guards 2022-10-08 11:32:01 +02:00
1f655fabe2 The beginnings of Moon 0.10
Right now the kernel is the only thing with a version number, the user apps just fetch it from the kernel using the sys_getversion() syscall
2022-10-07 20:33:00 +02:00
94 changed files with 1520 additions and 500 deletions

4
.gdbconf Normal file
View File

@ -0,0 +1,4 @@
file initrd/boot/moon.elf
break _start
target remote :1234
continue

View File

@ -38,6 +38,8 @@ There are a variety of scripts for building Luna.
`tools/build-iso.sh` will build, install, and make an ISO disk image named Luna.iso.
`tools/build-debug.sh` will rebuild the kernel with debug symbols and optimizations disabled, install, and make an ISO image. This script should only be used when you are going to be running the system with a debugger (such as GDB).
`tools/build-stable-iso.sh` does the same thing as build-iso.sh, but configures the kernel so that the version does not show the commit hash (used for stable versions).
`tools/rebuild-iso.sh` will do a clean rebuild, install, and make an ISO disk image.
@ -54,7 +56,7 @@ You can choose between 3 run scripts:
`tools/rebuild-and-run.sh` will rebuild, install, make an ISO, and run Luna in QEMU.
`tools/debug.sh` will rebuild the kernel with debug symbols and optimizations disabled, install, make an ISO image, and run Luna in QEMU with a port open for GDB to connect to. (run `gdb initrd/boot/moon.elf`, `break _start`, `target remote :1234`, and then `debug.sh` for an optimal debugging experience)
`tools/debug.sh` will run Luna in QEMU with a port open for GDB to connect to. (run `tools/build-debug.sh`, `tools/gdb.sh`, and then `tools/debug.sh` in a separate terminal for an optimal debugging experience)
Beware that running without hardware virtualization/with optimizations disabled may cause the kernel to behave differently, which is why I don't use it that often.

View File

@ -1,4 +1,4 @@
APPS := init fib leap art memeater
APPS := init
APPS_DIR := $(LUNA_ROOT)/apps
APPS_SRC := $(APPS_DIR)/src
@ -6,11 +6,12 @@ APPS_BIN := $(APPS_DIR)/bin
REAL_APPS := $(patsubst %, $(APPS_BIN)/%, $(APPS))
CFLAGS := -Wall -Wextra -Werror
CFLAGS := -Wall -Wextra -Werror -Os
$(APPS_BIN)/%: $(APPS_SRC)/%.c
@mkdir -p $(@D)
$(CC) $(CFLAGS) -o $@ $^
$(STRIP) $@
build: $(REAL_APPS)

View File

@ -1,18 +0,0 @@
#include <stdio.h>
#include <sys/syscall.h>
#include <unistd.h>
int main()
{
sleep(1);
syscall(SYS_paint, 0, 0, 400, 300, 0x000000FF);
sleep(1);
printf("Hello, colorful world!\n");
sleep(1);
printf("Press any key to restart.");
}

View File

@ -1,34 +0,0 @@
#include <luna.h>
#include <stdio.h>
#include <unistd.h>
void fib_next(unsigned long int* a, unsigned long int* b)
{
unsigned long int _a = *a;
unsigned long int _b = *b;
*a = *b;
*b = _a + _b;
}
int main()
{
unsigned long int fib_a = 1;
unsigned long int fib_b = 1;
printf("Calculating the 50 first Fibonacci numbers...\n");
sleep(2);
printf("%lu\n", fib_a);
msleep(500);
for (int i = 0; i < 49; i++)
{
printf("%lu\n", fib_b);
fib_next(&fib_a, &fib_b);
msleep(500);
}
printf("\nDone, press any key to restart.\n");
}

View File

@ -1,3 +1,4 @@
#include <errno.h>
#include <luna.h>
#include <stdio.h>
#include <stdlib.h>
@ -5,6 +6,39 @@
#include <sys/syscall.h>
#include <unistd.h>
typedef long ssize_t;
int print_version()
{
char version[4096];
FILE* verfile = fopen("/dev/version", "r");
if (!verfile)
{
perror("fopen");
return 1;
}
size_t nread = fread(version, 4096, 1, verfile);
if (ferror(verfile))
{
perror("fread");
return 1;
}
version[nread] = 0;
if (fclose(verfile) < 0)
{
perror("fclose");
return 1;
}
printf("Your kernel version is %s\n\n", version);
return 0;
}
int main()
{
if (gettid() == 0) // why are we the idle task?
@ -18,21 +52,37 @@ int main()
sleep(1);
char version[40];
syscall(SYS_getversion, version, sizeof(version));
printf("Your kernel version is %s\n\n", version);
if (print_version()) return 1;
sleep(2);
const char* filename = "/sys/config";
printf("Opening %s for reading...\n", filename);
FILE* config = fopen(filename, "r");
if (!config)
{
char* variable = malloc(200);
*variable = 3;
printf("Allocated variable at address %lx\n", (unsigned long int)variable);
free(variable);
perror("fopen");
return 1;
}
printf("Press any key to restart.\n");
char buf[4096];
size_t nread = fread(buf, sizeof(buf), 1, config);
if (ferror(config)) { perror("fread"); }
else
{
buf[nread] = 0;
printf("Read %zd bytes\n\n", nread);
printf("%s", buf);
}
if (fclose(config) < 0) { perror("fclose"); }
printf("\n\nPress any key to restart.\n");
return 0;
}

View File

@ -1,38 +0,0 @@
#include <luna.h>
#include <stdio.h>
#include <sys/syscall.h>
#include <unistd.h>
unsigned long random_year() // Return a year from 1000 to 2500.
{
unsigned long result = syscall(SYS_rand);
return (result % 1500) + 1000;
}
int is_leap(unsigned long year)
{
return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
}
int main()
{
printf("Welcome to the Luna Leap Year Program!\n\n");
sleep(1);
printf("Choosing a random year between 1000 and 2500... ");
msleep(500);
unsigned long year = random_year();
printf("%lu!\n\n", year);
sleep(1);
printf("%lu is %s\n", year, is_leap(year) ? "a leap year!" : "not a leap year :(");
msleep(500);
printf("Press any key to restart.\n");
}

View File

@ -1,17 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define CHUNK 4194304 // 4 MB
int main()
{
printf("Welcome to memeater! This little program is designed to eat up all the memory on your system.\n");
sleep(1);
void* allocated = malloc(CHUNK);
do {
printf("Allocating 4 MB of memory... %lx\n", (unsigned long)allocated);
sleep(1);
} while ((allocated = malloc(CHUNK)));
printf("Out of memory.\n");
}

View File

@ -6,7 +6,7 @@ MOON_BIN := $(MOON_DIR)/bin
CFLAGS := -pedantic -Wall -Wextra -Werror -Wfloat-equal -Wdisabled-optimization -Wformat=2 -Winit-self -Wmissing-include-dirs -Wswitch-default -Wcast-qual -Wundef -Wcast-align -Wwrite-strings -Wlogical-op -Wredundant-decls -Wshadow -Wconversion -Os -ffreestanding -fstack-protector-all -fno-omit-frame-pointer -mno-red-zone -mno-mmx -mno-sse -mno-sse2 -fshort-wchar -mcmodel=kernel -I$(MOON_DIR)/include -isystem $(MOON_DIR)/include/std
CXXFLAGS := -fno-rtti -fno-exceptions -Wsign-promo -Wstrict-null-sentinel -Wctor-dtor-privacy
ASMFLAGS := -felf64
LDFLAGS := -T$(MOON_DIR)/moon.ld -nostdlib -lgcc -Wl,--build-id=none -z max-page-size=0x1000
LDFLAGS := -T$(MOON_DIR)/moon.ld -nostdlib -lgcc -Wl,--build-id=none -z max-page-size=0x1000 -mno-red-zone -mcmodel=kernel
ifneq ($(MOON_BUILD_STABLE), 1)
CFLAGS := ${CFLAGS} -D_MOON_SUFFIX=-$(shell git rev-parse --short HEAD)
@ -54,7 +54,7 @@ $(MOON_OBJ)/%.asm.o: $(MOON_SRC)/%.asm
build: $(OBJS)
@mkdir -p $(@D)
$(CC) $(OBJS) $(CFLAGS) $(LDFLAGS) -o $(MOON_BIN)/moon.elf
$(CC) $(OBJS) $(LDFLAGS) -o $(MOON_BIN)/moon.elf
clean:
rm -rf $(MOON_OBJ)/*
@ -64,6 +64,7 @@ install: $(MOON_BIN)/moon.elf
@mkdir -p $(@D)
cp $^ $(LUNA_ROOT)/initrd/boot/moon.elf
$(LUNA_ROOT)/tools/generate-symbols.sh
$(STRIP) $(LUNA_ROOT)/initrd/boot/moon.elf
.PHONY: build clean install FORCE
FORCE:

10
kernel/include/errno.h Normal file
View File

@ -0,0 +1,10 @@
#pragma once
#define EPERM 1
#define ENOENT 2
#define EBADF 9
#define ENOMEM 12
#define EISDIR 21
#define EINVAL 22
#define EMFILE 24
#define ENOSYS 38

View File

@ -0,0 +1,41 @@
#pragma once
#include "fs/VFS.h"
#include <stdint.h>
struct Descriptor
{
bool is_open()
{
return m_is_open;
}
bool can_read()
{
return m_can_read && m_is_open;
}
bool can_write()
{
return m_can_write && m_is_open;
}
void close()
{
m_is_open = false;
}
ssize_t read(size_t size, char* buffer);
ssize_t write(size_t size, const char* buffer);
void open(VFS::Node* node, bool can_read, bool can_write);
Descriptor(const Descriptor& other);
Descriptor();
private:
bool m_is_open;
bool m_can_read;
bool m_can_write;
VFS::Node* m_node;
uint64_t m_offset;
};

49
kernel/include/fs/VFS.h Normal file
View File

@ -0,0 +1,49 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
typedef long ssize_t;
#define VFS_FILE 0x0
#define VFS_DIRECTORY 0x1
#define VFS_MOUNTPOINT 0x1
namespace VFS
{
struct Node;
typedef ssize_t (*node_read)(Node*, size_t, size_t, char*);
typedef ssize_t (*node_write)(Node*, size_t, size_t, const char*);
typedef Node* (*node_finddir)(Node*, const char*);
typedef int (*node_mkdir)(Node*, const char*);
struct Node
{
char name[64];
uint64_t inode;
uint64_t length;
int type;
int flags;
node_read read_func;
node_finddir find_func;
node_mkdir mkdir_func;
node_write write_func;
Node* link;
};
ssize_t read(Node* node, size_t offset, size_t length, char* buffer);
ssize_t write(Node* node, size_t offset, size_t length, const char* buffer);
int mkdir(const char* path, const char* name); // FIXME: Support deducing this via a single path.
void mount_root(Node* root);
Node* resolve_path(const char* filename, Node* root = nullptr);
void mount(Node* mountpoint, Node* mounted);
void mount(const char* pathname, Node* mounted);
void unmount(Node* mountpoint);
Node* root();
}

View File

@ -0,0 +1,9 @@
#pragma once
#include "fs/VFS.h"
namespace ConsoleDevice
{
VFS::Node* create_new();
ssize_t write(VFS::Node* node, size_t offset, size_t size, const char* buffer);
}

View File

@ -0,0 +1,9 @@
#pragma once
#include "fs/VFS.h"
namespace DeviceFS
{
VFS::Node* get();
VFS::Node* finddir(VFS::Node* node, const char* filename);
}

View File

@ -0,0 +1,9 @@
#pragma once
#include "fs/VFS.h"
namespace VersionDevice
{
VFS::Node* create_new();
ssize_t read(VFS::Node* node, size_t offset, size_t size, char* buffer);
}

View File

@ -1,34 +0,0 @@
#pragma once
#include <stdint.h>
namespace Ext2
{
struct Superblock
{
uint32_t fs_inodes; // Total number of inodes in file system
uint32_t fs_blocks; // Total number of blocks in file system
uint32_t su_blocks; // Number of blocks reserved for superuser
uint32_t free_blocks; // Total number of unallocated blocks
uint32_t free_inodes; // Total number of unallocated inodes
uint32_t superblock_number; // Block number of the block containing the superblock
uint32_t block_size; // log2(block size) - 10
uint32_t frag_size; // log2(fragment size) - 10
uint32_t num_blocks; // Number of blocks in each block group
uint32_t num_frag; // Number of fragments in each block group
uint32_t num_inodes; // Number of inodes in each block group
uint32_t mount_time; // Last mount time (in POSIX time)
uint32_t write_time; // Last written time (in POSIX time)
uint16_t fsck_mounts; // Number of times the volume has been mounted since its last consistency check
uint16_t fsck_mounts_allowed; // Number of mounts allowed before a consistency check must be done
uint16_t signature; // Ext2 signature (0xef53)
uint16_t fs_state; // File system state
uint16_t error_action; // What to do when an error is detected
uint16_t version_minor; // Minor portion of version
uint32_t fsck_time; // POSIX time of last consistency check
uint32_t fsck_interval; // Interval (in POSIX time) between forced consistency checks
uint32_t os_id; // Operating system ID from which the filesystem on this volume was created
uint32_t version_major; // Major portion of version
uint16_t su_uid; // User ID that can use reserved blocks (superuser)
uint16_t su_gid; // Group ID that can use reserved blocks
};
}

View File

@ -1,6 +1,10 @@
#pragma once
#include <stdint.h>
#ifndef PAGE_SIZE
#define PAGE_SIZE 4096
#endif
#define MAP_READ_WRITE 1 << 0
#define MAP_USER 1 << 1
#define MAP_EXEC 1 << 2

View File

@ -1,6 +1,10 @@
#pragma once
#include <stdint.h>
#ifndef PAGE_SIZE
#define PAGE_SIZE 4096
#endif
namespace Paging
{
struct PageDirectoryEntry

View File

@ -8,23 +8,27 @@
#define SYS_write 3
#define SYS_paint 4
#define SYS_rand 5
#define SYS_getversion 6
#define SYS_gettid 7
#define SYS_mmap 8
#define SYS_munmap 9
#define SYS_gettid 6
#define SYS_mmap 7
#define SYS_munmap 8
#define SYS_open 9
#define SYS_read 10
#define SYS_close 11
namespace Syscall
{
void entry(Context* context);
}
void sys_exit(Context* context);
void sys_exit(Context* context, int status);
void sys_yield(Context* context);
void sys_sleep(Context* context, uint64_t ms);
void sys_write(Context* context, const char* addr, size_t size);
void sys_write(Context* context, int fd, size_t size, const char* addr);
void sys_paint(Context* context, uint64_t x, uint64_t y, uint64_t w, uint64_t h, uint64_t col);
void sys_rand(Context* context);
void sys_getversion(Context* context, char* buffer, size_t max);
void sys_gettid(Context* context);
void sys_mmap(Context* context, void* address, size_t size, int flags);
void sys_munmap(Context* context, void* address, size_t size);
void sys_open(Context* context, const char* filename, int flags);
void sys_read(Context* context, int fd, size_t size, char* buffer);
void sys_close(Context* context, int fd);

View File

@ -5,5 +5,5 @@
namespace ELFLoader
{
ELFImage* load_elf_from_address(uintptr_t addr);
ELFImage* load_elf_from_initrd(const char* filename);
ELFImage* load_elf_from_filesystem(const char* filename);
}

View File

@ -5,15 +5,15 @@ namespace Scheduler
{
void init();
void yield();
void exit();
void exit(int status);
void sleep(unsigned long ms);
void add_kernel_task(void (*task)(void));
void add_user_task(void* task);
void load_user_task(const char* filename);
void task_exit(Context* context);
void task_misbehave(Context* context);
void task_exit(Context* context, int64_t status);
void task_misbehave(Context* context, int64_t status);
Task* current_task();

View File

@ -1,7 +1,10 @@
#pragma once
#include "fs/FileDescriptor.h"
#include "interrupts/Context.h"
#include "sys/elf/Image.h"
#define TASK_MAX_FDS 8
struct Task
{
enum TaskState
@ -16,6 +19,9 @@ struct Task
Context regs;
int64_t task_sleep = 0;
int64_t exit_status;
int64_t task_time = 0;
Task* next_task = nullptr;
@ -33,6 +39,8 @@ struct Task
bool is_user_task();
ELFImage* image = nullptr;
Descriptor files[TASK_MAX_FDS];
};
void set_context_from_task(Task& task, Context* ctx);

View File

@ -4,6 +4,7 @@
#include "bootboot.h"
#include "log/Log.h"
#include "memory/MemoryManager.h"
#include "misc/utils.h"
#include "std/stdio.h"
#include "std/string.h"
@ -11,24 +12,27 @@ extern BOOTBOOT bootboot;
ACPI::SDTHeader* ACPI::get_rsdt_or_xsdt()
{
static void* cache = nullptr;
if (cache) return (SDTHeader*)cache;
static SDTHeader* cache = nullptr;
if (cache) return cache;
kdbgln("First time accessing the RSDT/XSDT, mapping it into memory");
void* physical = (void*)bootboot.arch.x86_64.acpi_ptr;
uint64_t offset = (uint64_t)physical % 4096;
kdbgln("RSDT/XSDT physical address: %lx", (uint64_t)physical);
cache = MemoryManager::get_unaligned_mapping(physical);
uint64_t numPages = 1;
while ((offset + ((SDTHeader*)cache)->Length) > (numPages * 4096))
kdbgln("RSDT/XSDT physical address: %p", physical);
SDTHeader* rsdt = (SDTHeader*)MemoryManager::get_unaligned_mapping(physical);
uint64_t offset = (uint64_t)physical % PAGE_SIZE;
uint64_t rsdt_pages = Utilities::get_blocks_from_size(PAGE_SIZE, (offset + rsdt->Length));
if (rsdt_pages > 1)
{
kwarnln("RSDT/XSDT extends beyond the mapped page, mapping one more page");
MemoryManager::release_unaligned_mappings(cache, numPages);
numPages++;
cache = MemoryManager::get_unaligned_mappings(cache, numPages);
MemoryManager::release_unaligned_mapping(rsdt);
rsdt = (SDTHeader*)MemoryManager::get_unaligned_mappings(cache, rsdt_pages);
}
kdbgln("Mapped RSDT/XSDT to virtual address %lx, uses %ld pages", (uint64_t)cache, numPages);
SDTHeader* result = (SDTHeader*)cache;
return result;
kdbgln("Mapped RSDT/XSDT to virtual address %p, uses %ld pages", (void*)rsdt, rsdt_pages);
cache = rsdt;
return rsdt;
}
bool ACPI::validate_rsdt_or_xsdt(ACPI::SDTHeader* root_sdt)
@ -54,8 +58,8 @@ void* ACPI::find_table(ACPI::SDTHeader* root_sdt, const char* signature)
{
bool isXSDT = is_xsdt();
uint64_t entries = (root_sdt->Length - sizeof(SDTHeader)) / (isXSDT ? 8 : 4);
kdbgln("Searching for table %s in the %s at %lx (table contains %ld entries)", signature, isXSDT ? "XSDT" : "RSDT",
(uint64_t)root_sdt, entries);
kdbgln("Searching for table %s in the %s at %p (table contains %ld entries)", signature, isXSDT ? "XSDT" : "RSDT",
(void*)root_sdt, entries);
for (uint64_t i = 0; i < entries; i++)
{
@ -77,9 +81,9 @@ void* ACPI::find_table(ACPI::SDTHeader* root_sdt, const char* signature)
kwarnln("Entry %ld in the %s points to null", i, isXSDT ? "XSDT" : "RSDT");
continue;
}
kdbgln("Physical address of entry: %lx", (uint64_t)h);
kdbgln("Physical address of entry: %p", (void*)h);
SDTHeader* realHeader = (SDTHeader*)MemoryManager::get_unaligned_mapping(h);
kdbgln("Mapped entry to virtual address %lx", (uint64_t)realHeader);
kdbgln("Mapped entry to virtual address %p", (void*)realHeader);
if (!validate_sdt_header(realHeader))
{
kwarnln("Header of entry %ld is not valid, skipping this entry", i);

View File

@ -0,0 +1,34 @@
#include "fs/FileDescriptor.h"
Descriptor::Descriptor() : m_is_open(false)
{
}
Descriptor::Descriptor(const Descriptor& other)
: m_is_open(other.m_is_open), m_can_read(other.m_can_read), m_can_write(other.m_can_write), m_node(other.m_node),
m_offset(other.m_offset)
{
}
void Descriptor::open(VFS::Node* node, bool can_read, bool can_write)
{
m_can_read = can_read;
m_can_write = can_write;
m_node = node;
m_offset = 0;
m_is_open = true;
}
ssize_t Descriptor::read(size_t size, char* buffer)
{
ssize_t result = VFS::read(m_node, m_offset, size, buffer);
m_offset += result;
return result;
}
ssize_t Descriptor::write(size_t size, const char* buffer)
{
ssize_t result = VFS::write(m_node, m_offset, size, buffer);
m_offset += result;
return result;
}

162
kernel/src/fs/VFS.cpp Normal file
View File

@ -0,0 +1,162 @@
#define MODULE "vfs"
#include "fs/VFS.h"
#include "errno.h"
#include "log/Log.h"
#include "std/stdlib.h"
#include "std/string.h"
static VFS::Node* vfs_root;
ssize_t VFS::read(Node* node, size_t offset, size_t length, char* buffer)
{
if (!node)
{
kwarnln("read() failed: trying to read from nullptr");
return -1;
}
if (node->type == VFS_DIRECTORY)
{
kwarnln("read() failed: is a directory");
return -EISDIR;
}
if (!node->read_func)
{
kwarnln("read() failed: the chosen node doesn't support reading");
return -1;
}
return node->read_func(node, offset, length, buffer);
}
ssize_t VFS::write(Node* node, size_t offset, size_t length, const char* buffer)
{
if (!node)
{
kwarnln("write() failed: trying to write to nullptr");
return -1;
}
if (node->type == VFS_DIRECTORY)
{
kwarnln("write() failed: is a directory");
return -EISDIR;
}
if (!node->write_func)
{
kwarnln("write() failed: the chosen node doesn't support writing");
return -1;
}
return node->write_func(node, offset, length, buffer);
}
void VFS::mount_root(Node* root)
{
if (!root)
{
kwarnln("mount_root() failed: attempted to mount nullptr");
return;
}
if (vfs_root)
{
kwarnln("mount_root() failed: root filesystem already mounted");
return;
}
kinfoln("mounting node '%s' as vfs root", root->name);
vfs_root = root;
}
VFS::Node* VFS::root()
{
return vfs_root;
}
VFS::Node* VFS::resolve_path(const char* filename, Node* root)
{
if (!root) root = vfs_root;
if (strlen(filename) == 0) return 0;
if (*filename == '/') // Absolute path.
{
filename++;
root = vfs_root;
}
Node* current_node = root;
while (true)
{
while (*filename == '/') { filename++; }
if (*filename == 0) { return current_node; }
size_t path_section_size = 0;
while (filename[path_section_size] && filename[path_section_size] != '/') { path_section_size++; }
if (strncmp(filename, ".", path_section_size) != 0) // The current path section is not '.'
{
char* buffer = (char*)kmalloc(path_section_size + 1);
memcpy(buffer, filename, path_section_size);
buffer[path_section_size] = 0;
if (!current_node->find_func)
{
kwarnln("Current node has no way to find child nodes");
return 0;
}
Node* child = current_node->find_func(current_node, buffer);
if (!child)
{
kwarnln("Current node did not find our target node");
return 0;
}
if (child->flags & VFS_MOUNTPOINT)
{
if (!child->link)
{
kwarnln("Current node's link is null");
return 0;
}
child = child->link;
}
current_node = child;
kfree(buffer);
}
filename += path_section_size;
}
}
int VFS::mkdir(const char* path, const char* name)
{
Node* node = resolve_path(path, vfs_root);
if (!node)
{
kwarnln("Attempting to mkdir in %s, which does not exist", path);
return -1;
}
if (!node->mkdir_func)
{
kwarnln("Chosen node does not support mkdir()");
return -1;
}
return node->mkdir_func(node, name);
}
void VFS::mount(Node* mountpoint, Node* mounted)
{
if (!mountpoint || !mounted) return;
if (mountpoint->flags & VFS_MOUNTPOINT || mounted->flags & VFS_MOUNTPOINT) return;
mountpoint->link = mounted;
mountpoint->flags |= VFS_MOUNTPOINT;
}
void VFS::mount(const char* pathname, Node* mounted)
{
return mount(resolve_path(pathname), mounted);
}
void VFS::unmount(Node* mountpoint)
{
if (!mountpoint) return;
if (!(mountpoint->flags & VFS_MOUNTPOINT)) return;
mountpoint->flags &= ~VFS_MOUNTPOINT;
}

View File

@ -0,0 +1,25 @@
#include "fs/devices/Console.h"
#include "config.h"
#include "render/TextRenderer.h"
#include "std/stdio.h"
#include "std/stdlib.h"
#include "std/string.h"
VFS::Node* ConsoleDevice::create_new()
{
VFS::Node* dev = new VFS::Node;
dev->write_func = ConsoleDevice::write;
dev->inode = 0;
dev->length = 0;
dev->type = VFS_FILE;
dev->flags = 0;
strncpy(dev->name, "console", sizeof(dev->name));
return dev;
}
ssize_t ConsoleDevice::write(VFS::Node* node, size_t, size_t size, const char* buffer)
{
if (!node) return -1;
TextRenderer::write(buffer, size);
return (ssize_t)size;
}

View File

@ -0,0 +1,37 @@
#include "fs/devices/DeviceFS.h"
#include "fs/devices/Console.h"
#include "fs/devices/Version.h"
#include "std/stdlib.h"
#include "std/string.h"
#define DEVFS_MAX_FILES 32
VFS::Node* devfs_root = nullptr;
VFS::Node* devfs_files[DEVFS_MAX_FILES];
int devfs_file_count = 0;
VFS::Node* DeviceFS::get()
{
if (devfs_root) return devfs_root;
devfs_root = new VFS::Node;
devfs_root->length = 0;
devfs_root->inode = 0;
devfs_root->type = VFS_DIRECTORY;
devfs_root->find_func = DeviceFS::finddir;
strncpy(devfs_root->name, "dev", sizeof(devfs_root->name));
devfs_files[devfs_file_count++] = VersionDevice::create_new();
devfs_files[devfs_file_count++] = ConsoleDevice::create_new();
return devfs_root;
}
VFS::Node* DeviceFS::finddir(VFS::Node* node, const char* filename)
{
if (!node) return 0;
for (int i = 0; i < devfs_file_count; i++)
{
if (strncmp(devfs_files[i]->name, filename, sizeof(VFS::Node::name)) == 0) { return devfs_files[i]; }
}
return 0;
}

View File

@ -0,0 +1,26 @@
#include "fs/devices/Version.h"
#include "config.h"
#include "std/stdio.h"
#include "std/stdlib.h"
#include "std/string.h"
VFS::Node* VersionDevice::create_new()
{
VFS::Node* dev = new VFS::Node;
dev->read_func = VersionDevice::read;
dev->inode = 0;
dev->length = strlen(moon_version()) + 5;
dev->type = VFS_FILE;
dev->flags = 0;
strncpy(dev->name, "version", sizeof(dev->name));
return dev;
}
ssize_t VersionDevice::read(VFS::Node* node, size_t offset, size_t size, char* buffer)
{
if (!node) return -1;
if (offset > node->length) return -1;
if (offset + size > node->length) { size = node->length - offset; }
snprintf(buffer, size + 1, "moon %s", moon_version()); // FIXME: Support offseting this read
return (ssize_t)size;
}

View File

@ -84,7 +84,8 @@ void GDT::load()
gdtr.offset = (uint64_t)&internal_gdt;
gdtr.size = sizeof(InternalGDT);
memset(&main_tss, 0, sizeof(TSS));
main_tss.rsp[0] = (uint64_t)MemoryManager::get_pages(4) + (4096 * 4) - 8; // allocate 16KB for the syscall stack
main_tss.rsp[0] =
(uint64_t)MemoryManager::get_pages(4) + (PAGE_SIZE * 4) - 8; // allocate 16KB for the syscall stack
main_tss.iomap_base = sizeof(TSS);
set_base(&internal_gdt.tss, (uint64_t)&main_tss & 0xffffffff);
internal_gdt.tss2.base_high = (uint32_t)(((uint64_t)&main_tss >> 32) & 0xffffffff);

View File

@ -2,18 +2,21 @@
#include "init/InitRD.h"
#include "bootboot.h"
#include "fs/VFS.h"
#include "io/Serial.h"
#include "log/Log.h"
#include "memory/MemoryManager.h"
#include "misc/utils.h"
#include "std/stdlib.h"
#include <string.h>
#include "std/string.h"
extern BOOTBOOT bootboot;
static void* initrd_base;
static bool initrd_initialized = false;
static VFS::Node initrd_root;
bool InitRD::is_initialized()
{
return initrd_initialized;
@ -112,10 +115,267 @@ void InitRD::for_each(void (*callback)(File& f))
}
}
#define INITRD_MAX_FILES_IN_DIR 8
#define INITRD_MAX_FILES 32
namespace InitRD
{
struct Directory
{
char name[64];
int entries = 0;
VFS::Node* files[INITRD_MAX_FILES_IN_DIR];
};
}
void initrd_for_each_dir(void (*callback)(InitRD::Directory& f))
{
uint64_t block = 0;
uint64_t total_blocks = InitRD::get_total_blocks();
while (block < total_blocks)
{
InitRD::TarHeader* hdr = (InitRD::TarHeader*)InitRD::get_block(block);
if (!InitRD::is_valid_header(hdr))
{
block++;
continue;
}
if (hdr->typeflag == 53)
{
InitRD::Directory dir;
strncpy(dir.name, hdr->name, sizeof(dir.name));
callback(dir);
block++;
continue;
}
auto f = get_file(hdr);
block += get_file_size_in_blocks(f) + 1;
}
}
static InitRD::File files[32];
static uint32_t total_files = 0;
static InitRD::Directory dirs[32];
static uint32_t total_dirs = 0;
static VFS::Node nodes[63]; // One of the dirs is the initrd_root
static uint32_t total_nodes = 0;
ssize_t initrd_read(VFS::Node* node, size_t offset, size_t length, char* buffer)
{
if (!node) return -1;
if (node->inode >= total_files) return -1;
InitRD::File& file = files[node->inode];
if (offset > file.size) return -1;
if (offset + length > file.size) { length = file.size - offset; }
memcpy(buffer, (void*)((uintptr_t)file.addr + offset), length);
return length;
}
VFS::Node* initrd_scan_dir(VFS::Node* node, const char* filename)
{
if (!node) return 0;
if (node->inode >= total_dirs) return 0;
InitRD::Directory dir = dirs[node->inode];
for (int i = 0; i < dir.entries; i++)
{
if (strncmp(dir.files[i]->name, filename, sizeof(VFS::Node::name)) == 0) { return dir.files[i]; }
}
return 0;
}
int initrd_mkdir(VFS::Node* node, const char* name) // FIXME: Return proper error numbers.
{
if (total_dirs >= 32)
{
kwarnln("mkdir() failed: too many directories");
return -1;
}
if (node->inode > total_dirs)
{
kwarnln("mkdir() failed: invalid node");
return -1;
}
if (!(node->type & VFS_DIRECTORY))
{
kwarnln("mkdir() failed: not a directory");
return -1;
}
InitRD::Directory& parent = dirs[node->inode];
if (parent.entries == INITRD_MAX_FILES_IN_DIR)
{
kwarnln("mkdir() failed: parent is null");
return -1;
}
uint64_t inode = total_dirs;
VFS::Node& new_node = nodes[total_nodes++];
new_node.inode = inode;
new_node.find_func = initrd_scan_dir;
new_node.mkdir_func = initrd_mkdir;
new_node.length = 0;
new_node.type = VFS_DIRECTORY;
strncpy(new_node.name, name, sizeof(new_node.name));
InitRD::Directory dir;
strncpy(dir.name, name, sizeof(dir.name));
dir.entries = 0;
dirs[total_dirs++] = dir; // FIXME: Right now this isn't of worry, but there is a possibility for a TOCTOU bug here.
// Should use a spinlock or something.
parent.files[parent.entries++] = &new_node;
return 0;
}
static bool initrd_register_dir(InitRD::Directory& dir, uint64_t inode)
{
const char* filename = dir.name;
VFS::Node* current_node = &initrd_root;
while (true)
{
while (*filename == '/') { filename++; }
if (*filename == 0) { return false; }
size_t path_section_size = 0;
while (filename[path_section_size] && filename[path_section_size] != '/') { path_section_size++; }
if (filename[path_section_size]) // We are in a '/'
{
char* buffer = (char*)kmalloc(path_section_size + 1);
memcpy(buffer, filename, path_section_size);
buffer[path_section_size] = 0;
if (!current_node->find_func) { return false; }
VFS::Node* child = current_node->find_func(current_node, buffer);
if (!child) { return false; }
current_node = child;
kfree(buffer);
}
else
{
if (strncmp(filename, ".", path_section_size) != 0) // The current path section is not '.'
{
if (strncmp(filename, "..", path_section_size) == 0) { return false; }
if (!current_node->find_func) { return false; }
InitRD::Directory& parent = dirs[current_node->inode];
if (parent.entries == INITRD_MAX_FILES_IN_DIR) { return false; }
char* buffer = (char*)kmalloc(path_section_size + 1);
memcpy(buffer, filename, path_section_size);
buffer[path_section_size] = 0;
VFS::Node& node = nodes[total_nodes++];
node.inode = inode;
node.find_func = initrd_scan_dir;
node.length = 0;
node.type = VFS_DIRECTORY;
node.mkdir_func = initrd_mkdir;
strncpy(node.name, buffer, sizeof(node.name));
strncpy(dir.name, buffer, sizeof(dir.name));
parent.files[parent.entries++] = &node;
kfree(buffer);
return true;
}
else { return false; }
}
filename += path_section_size;
}
}
static bool initrd_register_file(InitRD::File& f, uint64_t inode)
{
const char* filename = f.name;
VFS::Node* current_node = &initrd_root;
while (true)
{
while (*filename == '/') { filename++; }
if (*filename == 0) { return false; }
size_t path_section_size = 0;
while (filename[path_section_size] && filename[path_section_size] != '/') { path_section_size++; }
if (filename[path_section_size]) // We are in a '/'
{
char* buffer = (char*)kmalloc(path_section_size + 1);
memcpy(buffer, filename, path_section_size);
buffer[path_section_size] = 0;
if (!current_node->find_func) { return false; }
VFS::Node* child = current_node->find_func(current_node, buffer);
if (!child) { return false; }
current_node = child;
kfree(buffer);
}
else
{
if (strncmp(filename, ".", path_section_size) != 0) // The current path section is not '.'
{
if (strncmp(filename, "..", path_section_size) == 0) { return false; }
if (!current_node->find_func) { return false; }
InitRD::Directory& parent = dirs[current_node->inode];
if (parent.entries == INITRD_MAX_FILES_IN_DIR) { return false; }
char* buffer = (char*)kmalloc(path_section_size + 1);
memcpy(buffer, filename, path_section_size);
buffer[path_section_size] = 0;
VFS::Node& node = nodes[total_nodes++];
node.inode = inode;
node.read_func = initrd_read;
node.length = f.size;
node.type = VFS_FILE;
strncpy(node.name, buffer, sizeof(node.name));
strncpy(f.name, buffer, sizeof(f.name));
parent.files[parent.entries++] = &node;
kfree(buffer);
return true;
}
else { return false; }
}
filename += path_section_size;
}
}
static void initrd_scan()
{
initrd_for_each_dir([](InitRD::Directory& dir) {
if (total_dirs >= 32) return;
uint64_t inode = total_dirs;
if (initrd_register_dir(dir, inode)) dirs[total_dirs++] = dir;
});
InitRD::for_each([](InitRD::File& f) {
if (total_files >= 32) return;
uint64_t inode = total_files;
if (initrd_register_file(f, inode)) files[total_files++] = f;
});
}
static void initrd_initialize_root()
{
initrd_root.length = 0;
initrd_root.inode = 0;
initrd_root.type |= VFS_DIRECTORY;
InitRD::Directory& root = dirs[0];
total_dirs++;
strncpy(initrd_root.name, "initrd", sizeof(initrd_root.name));
strncpy(root.name, "initrd", sizeof(root.name));
initrd_root.find_func = initrd_scan_dir;
initrd_root.mkdir_func = initrd_mkdir;
}
void InitRD::init()
{
initrd_base = MemoryManager::get_unaligned_mappings((void*)bootboot.initrd_ptr, bootboot.initrd_size / 4096 + 1);
kdbgln("physical base at %lx, size %lx, mapped to %lx", bootboot.initrd_ptr, bootboot.initrd_size,
(uint64_t)initrd_base);
initrd_base = MemoryManager::get_unaligned_mappings(
(void*)bootboot.initrd_ptr, Utilities::get_blocks_from_size(PAGE_SIZE, bootboot.initrd_size));
kdbgln("physical base at %lx, size %lx, mapped to %p", bootboot.initrd_ptr, bootboot.initrd_size, initrd_base);
kdbgln("total blocks: %ld", get_total_blocks());
initrd_initialize_root();
initrd_scan();
VFS::mount_root(&initrd_root);
initrd_initialized = true;
}

View File

@ -34,7 +34,7 @@ extern "C" void common_handler(Context* context)
StackTracer tracer(context->rbp);
tracer.trace_with_ip(context->rip);
Scheduler::task_misbehave(context);
Scheduler::task_misbehave(context, -2);
}
}
if (context->number == 14)
@ -51,7 +51,7 @@ extern "C" void common_handler(Context* context)
StackTracer tracer(context->rbp);
tracer.trace_with_ip(context->rip);
Scheduler::task_misbehave(context);
Scheduler::task_misbehave(context, -3);
}
}
if (context->number == 8) { int_panic(context, "Double fault, halting"); }

View File

@ -4,6 +4,8 @@
#include "assert.h"
#include "config.h"
#include "cpu/CPU.h"
#include "fs/VFS.h"
#include "fs/devices/DeviceFS.h"
#include "gdt/GDT.h"
#include "init/Init.h"
#include "init/InitRD.h"
@ -32,8 +34,6 @@
#include "thread/PIT.h"
#include "thread/Scheduler.h"
extern "C" void _userspace();
extern "C" void _start()
{
Init::check_magic();
@ -70,52 +70,6 @@ extern "C" void _start()
kinfoln("Prepared scheduler");
/*Scheduler::add_kernel_task([]() {
int64_t x = 0;
int64_t y = 0;
int64_t xvel = 10;
int64_t yvel = 10;
while (1)
{
sleep(2);
uint32_t color = (uint32_t)Mersenne::get();
x += xvel;
y += yvel;
if ((x + 10) >= framebuffer0.width())
{
xvel = -xvel;
x = (framebuffer0.width() - 10);
}
if ((y + 10) >= framebuffer0.height())
{
yvel = -yvel;
y = (framebuffer0.height() - 10);
}
if (xvel < 0 && (x - 10) < 0)
{
xvel = -xvel;
x = 0;
}
if (yvel < 0 && (y - 10) < 0)
{
yvel = -yvel;
y = 0;
}
framebuffer0.paint_rect(x, y, 10, 10, Color::from_integer(color));
}
});*/
/*Scheduler::add_kernel_task([]() {
while (1)
{
sleep(100);
uint32_t color = (uint32_t)Mersenne::get();
framebuffer0.paint_rect(Mersenne::get() % (framebuffer0.width() - 256),
Mersenne::get() % (framebuffer0.height() - 256), Mersenne::get() % 255,
Mersenne::get() % 255, Color::from_integer(color));
}
});*/
Scheduler::add_kernel_task([]() {
while (1)
{
@ -124,38 +78,16 @@ extern "C" void _start()
}
});
uint64_t demo = Mersenne::get() % 5;
switch (demo)
{
case 0:
kinfoln("Loading demo: example init program");
Scheduler::load_user_task("bin/init");
break;
case 1:
kinfoln("Loading demo: first 50 fibonacci numbers");
Scheduler::load_user_task("bin/fib");
break;
case 2:
kinfoln("Loading demo: leap year calculator");
Scheduler::load_user_task("bin/leap");
break;
case 3:
kinfoln("Loading demo: painting program");
Scheduler::load_user_task("bin/art");
break;
case 4:
kinfoln("Loading demo: memory eating program");
Scheduler::load_user_task("bin/memeater");
break;
default: break;
}
Scheduler::load_user_task("/bin/init");
kinfoln("Prepared scheduler tasks");
ASSERT(VFS::mkdir("/", "dev") == 0);
VFS::mount("/dev", DeviceFS::get());
Init::finish_kernel_boot();
Interrupts::enable();
Interrupts::enable(); // Task switching commences here
kinfoln("Interrupts enabled");
@ -163,5 +95,5 @@ extern "C" void _start()
kinfoln("Found PCI device %x:%x, %s", dev.id().vendor, dev.id().device, pci_type_name(dev.type()));
});
Scheduler::exit();
Scheduler::exit(0);
}

View File

@ -1,6 +1,10 @@
#include "memory/KernelHeap.h"
#include "assert.h"
#ifndef PAGE_SIZE
#define PAGE_SIZE 4096
#endif
static uint8_t page_bitmap[2048];
#define ALLOC_BASE 0xfffffffff8000000
@ -28,7 +32,7 @@ uint64_t KernelHeap::request_virtual_page()
if (bitmap_read(index)) continue;
bitmap_set(index, true);
start_index = index + 1;
return ALLOC_BASE + (index * 4096);
return ALLOC_BASE + (index * PAGE_SIZE);
}
return 0;
@ -55,7 +59,7 @@ uint64_t KernelHeap::request_virtual_pages(uint64_t count)
if (contiguous == count)
{
for (uint64_t i = 0; i < count; i++) bitmap_set(contiguous_start + i, true);
return ALLOC_BASE + (contiguous_start * 4096);
return ALLOC_BASE + (contiguous_start * PAGE_SIZE);
}
}
@ -65,7 +69,7 @@ uint64_t KernelHeap::request_virtual_pages(uint64_t count)
void KernelHeap::free_virtual_page(uint64_t address)
{
ASSERT(address >= ALLOC_BASE && address < ALLOC_END);
uint64_t index = (address - ALLOC_BASE) / 4096;
uint64_t index = (address - ALLOC_BASE) / PAGE_SIZE;
bitmap_set(index, false);
if (start_index > index) start_index = index;
}
@ -73,7 +77,7 @@ void KernelHeap::free_virtual_page(uint64_t address)
void KernelHeap::free_virtual_pages(uint64_t address, uint64_t count)
{
ASSERT(address >= ALLOC_BASE && address < ALLOC_END);
uint64_t index = (address - ALLOC_BASE) / 4096;
uint64_t index = (address - ALLOC_BASE) / PAGE_SIZE;
for (uint64_t i = 0; i < count; i++) { bitmap_set(index + i, false); }
if (start_index > index) start_index = index;
}

View File

@ -32,7 +32,7 @@ void* MemoryManager::get_mapping(void* physicalAddress, int flags)
void* MemoryManager::get_unaligned_mapping(void* physicalAddress, int flags)
{
uint64_t offset = (uint64_t)physicalAddress % 4096;
uint64_t offset = (uint64_t)physicalAddress % PAGE_SIZE;
uint64_t virtualAddress = KernelHeap::request_virtual_page();
if (!virtualAddress)
{
@ -49,7 +49,7 @@ void* MemoryManager::get_unaligned_mappings(void* physicalAddress, uint64_t coun
{
if (!count) return 0;
if (count == 1) return get_unaligned_mapping(physicalAddress, flags);
uint64_t offset = (uint64_t)physicalAddress % 4096;
uint64_t offset = (uint64_t)physicalAddress % PAGE_SIZE;
uint64_t virtualAddress = KernelHeap::request_virtual_pages(count);
if (!virtualAddress)
{
@ -62,14 +62,14 @@ void* MemoryManager::get_unaligned_mappings(void* physicalAddress, uint64_t coun
}
for (uint64_t i = 0; i < count; i++)
{
kernelVMM.map(virtualAddress + (i * 4096), ((uint64_t)physicalAddress - offset) + (i * 4096), flags);
kernelVMM.map(virtualAddress + (i * PAGE_SIZE), ((uint64_t)physicalAddress - offset) + (i * PAGE_SIZE), flags);
}
return (void*)(virtualAddress + offset);
}
void MemoryManager::release_unaligned_mapping(void* mapping)
{
uint64_t offset = (uint64_t)mapping % 4096;
uint64_t offset = (uint64_t)mapping % PAGE_SIZE;
kernelVMM.unmap((uint64_t)mapping - offset);
KernelHeap::free_virtual_page((uint64_t)mapping - offset);
}
@ -78,9 +78,9 @@ void MemoryManager::release_unaligned_mappings(void* mapping, uint64_t count)
{
if (!count) return;
if (count == 1) return release_unaligned_mapping(mapping);
uint64_t offset = (uint64_t)mapping % 4096;
uint64_t offset = (uint64_t)mapping % PAGE_SIZE;
KernelHeap::free_virtual_pages((uint64_t)mapping - offset, count);
for (uint64_t i = 0; i < count; i++) { kernelVMM.unmap(((uint64_t)mapping - offset) + (i * 4096)); }
for (uint64_t i = 0; i < count; i++) { kernelVMM.unmap(((uint64_t)mapping - offset) + (i * PAGE_SIZE)); }
}
void MemoryManager::release_mapping(void* mapping)
@ -148,7 +148,7 @@ void* MemoryManager::get_pages_at(uint64_t addr, uint64_t count, int flags)
if (!count) return 0;
if (count == 1) return get_page_at(addr, flags);
#ifdef MM_DEBUG
kdbgln("allocating several pages (%ld), at address %ld", count, addr);
kdbgln("allocating several pages (%ld), at address %lx", count, addr);
#endif
for (uint64_t i = 0; i < count; i++)
{
@ -162,9 +162,9 @@ void* MemoryManager::get_pages_at(uint64_t addr, uint64_t count, int flags)
#endif
return 0;
}
kernelVMM.map(addr + (i * 4096), (uint64_t)physicalAddress, flags);
kernelVMM.map(addr + (i * PAGE_SIZE), (uint64_t)physicalAddress, flags);
#ifdef MM_DEBUG
kdbgln("allocating virtual %lx, physical %lx", virtualAddress + (i * 4096), (uint64_t)physicalAddress);
kdbgln("allocating virtual %lx, physical %p", virtualAddress + (i * PAGE_SIZE), physicalAddress);
#endif
}
return (void*)addr;
@ -179,12 +179,12 @@ void MemoryManager::release_pages(void* pages, uint64_t count)
#endif
for (uint64_t i = 0; i < count; i++)
{
void* page = (void*)((uint64_t)pages + (i * 4096));
void* page = (void*)((uint64_t)pages + (i * PAGE_SIZE));
uint64_t physicalAddress = kernelVMM.getPhysical((uint64_t)page);
ASSERT(physicalAddress != UINT64_MAX);
kernelVMM.unmap((uint64_t)page);
#ifdef MM_DEBUG
kdbgln("releasing virtual %lx, physical %lx", (uint64_t)page, physicalAddress);
kdbgln("releasing virtual %p, physical %lx", page, physicalAddress);
#endif
PMM::free_page((void*)physicalAddress);
}

View File

@ -48,26 +48,25 @@ void PMM::init()
}
bitmap_addr = (char*)biggest_chunk;
virtual_bitmap_addr =
bitmap_addr; // FIXME: map this to a virtual address (ideally in the kernel heap between -128M and -64M)
ASSERT((total_mem / 4096 / 8) < biggest_chunk_size);
bitmap_size = total_mem / 4096 / 8 + 1;
virtual_bitmap_addr = bitmap_addr;
ASSERT((total_mem / PAGE_SIZE / 8) < biggest_chunk_size);
bitmap_size = total_mem / PAGE_SIZE / 8 + 1;
memset(bitmap_addr, 0xFF, bitmap_size);
ptr = &bootboot.mmap;
for (uint64_t i = 0; i < mmap_entries; i++)
{
uint64_t index = MMapEnt_Ptr(ptr) / 4096;
uint64_t index = MMapEnt_Ptr(ptr) / PAGE_SIZE;
if (!MMapEnt_IsFree(ptr)) { reserved_mem += MMapEnt_Size(ptr); }
else
{
free_mem += MMapEnt_Size(ptr);
for (uint64_t j = 0; j < (MMapEnt_Size(ptr) / 4096); j++) { bitmap_set(index + j, false); }
for (uint64_t j = 0; j < (MMapEnt_Size(ptr) / PAGE_SIZE); j++) { bitmap_set(index + j, false); }
}
ptr++;
}
lock_pages(bitmap_addr, bitmap_size / 4096 + 1);
lock_pages(bitmap_addr, bitmap_size / PAGE_SIZE + 1);
}
static bool bitmap_read(uint64_t index)
@ -90,9 +89,9 @@ void* PMM::request_page()
if (bitmap_read(index)) continue;
bitmap_set(index, true);
start_index = index + 1;
free_mem -= 4096;
used_mem += 4096;
return (void*)(index * 4096);
free_mem -= PAGE_SIZE;
used_mem += PAGE_SIZE;
return (void*)(index * PAGE_SIZE);
}
return PMM_FAILED;
@ -119,9 +118,9 @@ void* PMM::request_pages(uint64_t count)
if (contiguous == count)
{
for (uint64_t i = 0; i < count; i++) bitmap_set(contiguous_start + i, true);
free_mem -= (count * 4096);
used_mem += (count * 4096);
return (void*)(contiguous_start * 4096);
free_mem -= (count * PAGE_SIZE);
used_mem += (count * PAGE_SIZE);
return (void*)(contiguous_start * PAGE_SIZE);
}
}
@ -130,11 +129,11 @@ void* PMM::request_pages(uint64_t count)
void PMM::free_page(void* address)
{
uint64_t index = (uint64_t)address / 4096;
uint64_t index = (uint64_t)address / PAGE_SIZE;
if (!bitmap_read(index)) return;
bitmap_set(index, false);
used_mem -= 4096;
free_mem += 4096;
used_mem -= PAGE_SIZE;
free_mem += PAGE_SIZE;
if (start_index > index) start_index = index;
}
@ -145,11 +144,11 @@ void PMM::free_pages(void* address, uint64_t count)
void PMM::lock_page(void* address)
{
uint64_t index = ((uint64_t)address) / 4096;
uint64_t index = ((uint64_t)address) / PAGE_SIZE;
if (bitmap_read(index)) return;
bitmap_set(index, true);
used_mem += 4096;
free_mem -= 4096;
used_mem += PAGE_SIZE;
free_mem -= PAGE_SIZE;
}
void PMM::lock_pages(void* address, uint64_t count)
@ -179,6 +178,6 @@ uint64_t PMM::get_bitmap_size()
void PMM::map_bitmap_to_virtual()
{
virtual_bitmap_addr =
(char*)MemoryManager::get_unaligned_mappings(bitmap_addr, Utilities::get_blocks_from_size(4096, bitmap_size));
virtual_bitmap_addr = (char*)MemoryManager::get_unaligned_mappings(
bitmap_addr, Utilities::get_blocks_from_size(PAGE_SIZE, bitmap_size));
}

View File

@ -8,7 +8,7 @@
#endif
#ifndef MOON_MINOR
#define MOON_MINOR 9
#define MOON_MINOR 10
#endif
#ifndef _MOON_SUFFIX

View File

@ -29,8 +29,9 @@ void TextRenderer::reset()
#pragma GCC push_options
#pragma GCC optimize("O0")
static void putchar_at_offset(char c, [[maybe_unused]] uint32_t cx, [[maybe_unused]] uint32_t cy,
[[maybe_unused]] Color& fg, [[maybe_unused]] Color& bg)
static void putchar_at_offset(
char c, [[maybe_unused]] uint32_t cx, [[maybe_unused]] uint32_t cy, [[maybe_unused]] Color& fg,
[[maybe_unused]] Color& bg) // FIXME: Rewrite this function to actually work with foreground and background colors.
{
uint8_t* glyph = &font[c * 16];
for (uint32_t y = 0; y < FONT_HEIGHT; y++)

View File

@ -159,6 +159,15 @@ static int internal_printf(const char* format, PutString put_string_callback, ss
}
break;
}
case 'p': {
char result[25];
ultoa(va_arg(ap, uint64_t), result, 16);
if (buffer_insert_index + strlen(result) > 1024) flush_buffer();
memcpy(buffer + buffer_insert_index, result, strlen(result));
buffer_insert_index += strlen(result);
if (buffer_insert_index == 1024) flush_buffer();
break;
}
case 's': {
const char* str = va_arg(ap, const char*);
while (strlen(str) > 1024)

View File

@ -1,4 +1,5 @@
#include "sys/Syscall.h"
#include "errno.h"
#include "io/Serial.h"
#include "thread/Scheduler.h"
@ -7,24 +8,18 @@ void Syscall::entry(Context* context)
asm volatile("cli");
switch (context->rax)
{
case SYS_exit: // sys_exit
sys_exit(context);
break;
case SYS_yield: // sys_yield
sys_yield(context);
break;
case SYS_sleep: // sys_sleep
sys_sleep(context, context->rdi);
break;
case SYS_write: // sys_write
sys_write(context, (const char*)context->rdi, context->rsi);
break;
case SYS_exit: sys_exit(context, (int)context->rdi); break;
case SYS_yield: sys_yield(context); break;
case SYS_sleep: sys_sleep(context, context->rdi); break;
case SYS_write: sys_write(context, (int)context->rdi, context->rsi, (const char*)context->rdx); break;
case SYS_paint: sys_paint(context, context->rdi, context->rsi, context->rdx, context->r10, context->r8); break;
case SYS_rand: sys_rand(context); break;
case SYS_getversion: sys_getversion(context, (char*)context->rdi, context->rsi); break;
case SYS_gettid: sys_gettid(context); break;
case SYS_mmap: sys_mmap(context, (void*)context->rdi, context->rsi, (int)context->rdx); break;
case SYS_munmap: sys_munmap(context, (void*)context->rdi, context->rsi); break;
default: context->rax = -1; break;
case SYS_open: sys_open(context, (const char*)context->rdi, (int)context->rsi); break;
case SYS_read: sys_read(context, (int)context->rdi, context->rsi, (char*)context->rdx); break;
case SYS_close: sys_close(context, (int)context->rdi); break;
default: context->rax = -ENOSYS; break;
}
}

View File

@ -1,6 +1,7 @@
#define MODULE "elf"
#include "sys/elf/ELFLoader.h"
#include "fs/VFS.h"
#include "init/InitRD.h"
#include "log/Log.h"
#include "memory/MemoryManager.h"
@ -19,16 +20,37 @@ static const char* format_permissions(uint32_t flags)
return perms;
}
ELFImage* ELFLoader::load_elf_from_initrd(const char* filename)
ELFImage* ELFLoader::load_elf_from_filesystem(const char* filename)
{
InitRD::File elf_file = InitRD::open(filename);
if (!elf_file.addr)
VFS::Node* node = VFS::resolve_path(filename);
if (!node)
{
kwarnln("Failed to open file %s for loading", filename);
return 0;
}
return load_elf_from_address((uintptr_t)elf_file.addr);
if (node->type == VFS_DIRECTORY)
{
kwarnln("Failed to load %s: is a directory", filename);
return 0;
}
void* file = kmalloc(node->length);
if (VFS::read(node, 0, node->length, (char*)file) < 0)
{
kwarnln("Failed to read ELF image from file");
kfree(file);
return 0;
}
ELFImage* result =
load_elf_from_address((uintptr_t)file); // FIXME: Read headers and sections as we go along the file, to avoid
// loading the entire file at once into memory.
kfree(file);
return result;
}
ELFImage* ELFLoader::load_elf_from_address(uintptr_t addr)

View File

@ -1,80 +1,89 @@
#define MODULE "mem"
#include "errno.h"
#include "interrupts/Context.h"
#include "log/Log.h"
#include "memory/MemoryManager.h"
#include "memory/VMM.h"
#include <stddef.h>
#define MAP_FAIL(errno) 0xffffffffffffff00 | (unsigned char)(errno)
void sys_mmap(Context* context, void* address, size_t size, int flags)
{
if (size < 4096)
if (size < PAGE_SIZE)
{
kdbgln("sys_mmap: size too small");
context->rax = 0;
context->rax = MAP_FAIL(EINVAL);
return;
}
int real_flags = MAP_USER;
if (flags & MAP_READ_WRITE) real_flags |= MAP_READ_WRITE;
if (address)
{
kdbgln("sys_mmap: %ld pages at address %lx, %s", size / 4096, (uint64_t)address,
kdbgln("sys_mmap: %ld pages at address %p, %s", size / PAGE_SIZE, address,
real_flags & MAP_READ_WRITE ? "rw" : "ro");
if (kernelVMM.getPhysical((uint64_t)address) != (uint64_t)-1) // Address is already used.
{
kdbgln("attempt to mmap an already mapped address");
context->rax = 0;
context->rax = MAP_FAIL(ENOMEM);
return;
}
uint64_t offset = (uint64_t)address % 4096;
void* result = MemoryManager::get_pages_at((uint64_t)address - offset, size / 4096, real_flags);
uint64_t offset = (uint64_t)address % PAGE_SIZE;
void* result = MemoryManager::get_pages_at((uint64_t)address - offset, size / PAGE_SIZE, real_flags);
if (result)
{
kdbgln("mmap succeeded: %lx", (uint64_t)result);
kdbgln("mmap succeeded: %p", result);
context->rax = (uint64_t)result;
return;
}
else
{
kdbgln("mmap failed");
context->rax = 0;
context->rax = MAP_FAIL(ENOMEM);
return;
}
}
kdbgln("sys_mmap: %ld pages at any address, %s", size / 4096, real_flags & MAP_READ_WRITE ? "rw" : "ro");
void* result = MemoryManager::get_pages(size / 4096, real_flags);
kdbgln("sys_mmap: %ld pages at any address, %s", size / PAGE_SIZE, real_flags & MAP_READ_WRITE ? "rw" : "ro");
void* result = MemoryManager::get_pages(size / PAGE_SIZE, real_flags);
if (result)
{
kdbgln("mmap succeeded: %lx", (uint64_t)result);
kdbgln("mmap succeeded: %p", result);
context->rax = (uint64_t)result;
return;
}
else
{
kdbgln("mmap failed");
context->rax = 0;
context->rax = MAP_FAIL(ENOMEM);
return;
}
}
void sys_munmap(Context* context, void* address, size_t size)
{
kdbgln("sys_munmap: attempting to unmap %lx", (uint64_t)address);
kdbgln("sys_munmap: attempting to unmap %p", address);
if (size < PAGE_SIZE)
{
kdbgln("munmap failed: size is too small");
context->rax = -EINVAL;
return;
}
if (!address)
{
kdbgln("munmap failed: attempted to unmap page 0");
context->rax = -1;
context->rax = -EINVAL;
return;
}
uint64_t flags = kernelVMM.getFlags((uint64_t)address);
if (!(flags & MAP_USER))
{
kdbgln("munmap failed: attempted to unmap a kernel page");
context->rax = -1;
context->rax = -EINVAL;
return;
}
uint64_t offset = (uint64_t)address % 4096;
MemoryManager::release_pages((void*)((uint64_t)address - offset), size / 4096);
uint64_t offset = (uint64_t)address % PAGE_SIZE;
MemoryManager::release_pages((void*)((uint64_t)address - offset), size / PAGE_SIZE);
kdbgln("munmap succeeded");
context->rax = 0;
return;

View File

@ -1,4 +1,5 @@
#include "bootboot.h"
#include "errno.h"
#include "interrupts/Context.h"
#include "render/Framebuffer.h"
#include <stdint.h>
@ -9,12 +10,12 @@ void sys_paint(Context* context, uint64_t x, uint64_t y, uint64_t w, uint64_t h,
{
if ((x + w) > bootboot.fb_width)
{
context->rax = -1;
context->rax = -EINVAL;
return;
}
if ((y + h) > bootboot.fb_height)
{
context->rax = -1;
context->rax = -EINVAL;
return;
}

View File

@ -1,8 +1,8 @@
#include "thread/Scheduler.h"
void sys_exit(Context* context)
void sys_exit(Context* context, int status)
{
Scheduler::task_exit(context);
Scheduler::task_exit(context, status);
}
void sys_yield(Context* context)

View File

@ -1,9 +1,140 @@
#define MODULE "stdio"
#include "errno.h"
#include "interrupts/Context.h"
#include "io/Serial.h"
#include "log/Log.h"
#include "render/TextRenderer.h"
#include "thread/Scheduler.h"
#include "thread/Task.h"
void sys_write(Context* context, const char* addr, size_t size)
#define OPEN_READ 1
#define OPEN_WRITE 2
#define STDIO_FAIL(function, error) kwarnln("%s failed with %s", #function, #error)
void sys_write(Context* context, int fd, size_t size, const char* addr)
{
context->rax = size;
TextRenderer::write(addr, size);
if (!addr)
{
STDIO_FAIL(write, EINVAL);
context->rax = -EINVAL; // FIXME: This should probably return EFAULT.
return;
}
if (fd >= TASK_MAX_FDS || fd < 0)
{
kwarnln("file descriptor %d is outside the valid range", fd);
STDIO_FAIL(write, EBADF);
context->rax = -EBADF;
return;
}
Task* current_task = Scheduler::current_task();
if (!current_task->files[fd].is_open())
{
kwarnln("file descriptor %d is not open", fd);
STDIO_FAIL(write, EBADF);
context->rax = -EBADF;
return;
}
if (!current_task->files[fd].can_write())
{
kwarnln("file descriptor %d is not open for writing", fd);
STDIO_FAIL(write, EBADF);
context->rax = -EBADF;
return;
}
ssize_t result = current_task->files[fd].write(size, addr);
context->rax = (size_t)result;
return;
}
void sys_open(Context* context, const char* filename, int flags)
{
Task* current_task = Scheduler::current_task();
int fd;
for (fd = 0; fd < TASK_MAX_FDS; fd++)
{
if (!current_task->files[fd].is_open()) break;
}
if (fd == TASK_MAX_FDS)
{
STDIO_FAIL(open, EMFILE);
context->rax = -EMFILE;
return;
}
VFS::Node* node = VFS::resolve_path(filename);
if (!node)
{
STDIO_FAIL(open, ENOENT);
context->rax = -ENOENT;
return;
}
bool can_read = (flags & OPEN_READ) > 0;
bool can_write = (flags & OPEN_WRITE) > 0;
if (!can_read && !can_write)
{
STDIO_FAIL(open, EINVAL);
context->rax = -EINVAL;
return;
}
kdbgln("open(): opening %s %s, allocated file descriptor %d", filename,
(can_read && can_write) ? "rw"
: can_read ? "r-"
: "-w",
fd);
current_task->files[fd].open(node, can_read, can_write);
context->rax = fd;
return;
}
void sys_read(Context* context, int fd, size_t size, char* buffer)
{
if (!buffer)
{
STDIO_FAIL(read, EINVAL);
context->rax = -EINVAL; // FIXME: This should probably return EFAULT.
return;
}
if (fd >= TASK_MAX_FDS || fd < 0)
{
STDIO_FAIL(read, EBADF);
context->rax = -EBADF;
return;
}
Task* current_task = Scheduler::current_task();
if (!current_task->files[fd].is_open() || !current_task->files[fd].can_read())
{
STDIO_FAIL(read, EBADF);
context->rax = -EBADF;
return;
}
ssize_t result = current_task->files[fd].read(size, buffer);
context->rax = (size_t)result;
return;
}
void sys_close(Context* context, int fd)
{
if (fd >= TASK_MAX_FDS || fd < 0)
{
STDIO_FAIL(close, EBADF);
context->rax = -EBADF;
return;
}
Task* current_task = Scheduler::current_task();
if (!current_task->files[fd].is_open())
{
STDIO_FAIL(close, EBADF);
context->rax = -EBADF;
return;
}
kdbgln("close(): releasing file descriptor %d", fd);
current_task->files[fd].close();
context->rax = 0;
return;
}

View File

@ -1,8 +0,0 @@
#include "config.h"
#include "interrupts/Context.h"
#include "std/stdio.h"
void sys_getversion(Context* context, char* buffer, size_t max)
{
context->rax = snprintf(buffer, max, "moon %s", moon_version());
}

View File

@ -64,7 +64,7 @@ void Scheduler::add_kernel_task(void (*task)(void))
new_task->regs.rip = (uint64_t)task;
new_task->allocated_stack =
(uint64_t)MemoryManager::get_pages(TASK_PAGES_IN_STACK); // 16 KB is enough for everyone, right?
new_task->regs.rsp = new_task->allocated_stack + (4096 * TASK_PAGES_IN_STACK) - sizeof(uintptr_t);
new_task->regs.rsp = new_task->allocated_stack + (PAGE_SIZE * TASK_PAGES_IN_STACK) - sizeof(uintptr_t);
new_task->regs.cs = 0x08;
new_task->regs.ss = 0x10;
new_task->regs.ds = 0x10;
@ -92,7 +92,7 @@ void Scheduler::add_user_task(void* task)
new_task->regs.rip = (uint64_t)task;
new_task->allocated_stack = (uint64_t)MemoryManager::get_pages(
TASK_PAGES_IN_STACK, MAP_READ_WRITE | MAP_USER); // 16 KB is enough for everyone, right?
new_task->regs.rsp = new_task->allocated_stack + (4096 * TASK_PAGES_IN_STACK) - sizeof(uintptr_t);
new_task->regs.rsp = new_task->allocated_stack + (PAGE_SIZE * TASK_PAGES_IN_STACK) - sizeof(uintptr_t);
new_task->regs.cs = 0x18 | 0x03;
new_task->regs.ss = 0x20 | 0x03;
new_task->regs.ds = 0x20 | 0x03;
@ -117,23 +117,18 @@ void Scheduler::load_user_task(const char* filename)
Task* new_task = new Task;
ASSERT(new_task);
new_task->id = free_tid++;
ELFImage* image = ELFLoader::load_elf_from_initrd(filename);
ELFImage* image = ELFLoader::load_elf_from_filesystem(filename);
if (!image)
{
kerrorln("Failed to load %s from initrd", filename);
delete new_task;
return;
}
new_task->regs.rip = image->entry;
new_task->image = image;
if (!new_task->regs.rip)
{
kwarnln("Failed to load user task %s", filename);
delete new_task;
return;
}
new_task->allocated_stack = (uint64_t)MemoryManager::get_pages(
TASK_PAGES_IN_STACK, MAP_READ_WRITE | MAP_USER); // 16 KB is enough for everyone, right?
new_task->regs.rsp = new_task->allocated_stack + (4096 * TASK_PAGES_IN_STACK) - sizeof(uintptr_t);
new_task->regs.rsp = new_task->allocated_stack + (PAGE_SIZE * TASK_PAGES_IN_STACK) - sizeof(uintptr_t);
new_task->regs.cs = 0x18 | 0x03;
new_task->regs.ss = 0x20 | 0x03;
new_task->regs.ds = 0x20 | 0x03;
@ -158,7 +153,7 @@ void Scheduler::reap_task(Task* task)
task_num--;
Task* exiting_task = task;
ASSERT(task->id != 0); // WHY IN THE WORLD WOULD WE BE REAPING THE IDLE TASK?
kinfoln("reaping task %ld", exiting_task->id);
kinfoln("reaping task %ld, exited with code %ld", exiting_task->id, exiting_task->exit_status);
if (exiting_task->allocated_stack)
MemoryManager::release_pages((void*)exiting_task->allocated_stack, TASK_PAGES_IN_STACK);
if (exiting_task->image)
@ -173,20 +168,22 @@ void Scheduler::reap_task(Task* task)
delete exiting_task;
}
void Scheduler::task_exit(Context* context)
void Scheduler::task_exit(Context* context, int64_t status)
{
ASSERT(Interrupts::is_in_handler());
kdbgln("exit: task %ld finished running, used %ld ms of cpu time", sched_current_task->id,
sched_current_task->cpu_time);
sched_current_task->state = sched_current_task->Exited;
sched_current_task->exit_status = status;
task_yield(context);
}
void Scheduler::task_misbehave(Context* context)
void Scheduler::task_misbehave(Context* context, int64_t status)
{
ASSERT(Interrupts::is_in_handler());
kdbgln("exit: task %ld misbehaved, used %ld ms of cpu time", sched_current_task->id, sched_current_task->cpu_time);
sched_current_task->state = sched_current_task->Exited;
sched_current_task->exit_status = status;
task_yield(context);
}
@ -316,9 +313,9 @@ void Scheduler::yield()
asm volatile("int $0x42" : : "a"(1));
}
void Scheduler::exit()
void Scheduler::exit(int status)
{
asm volatile("int $0x42" : : "a"(0));
asm volatile("int $0x42" : : "a"(0), "D"(status));
}
void Scheduler::sleep(unsigned long ms)

View File

@ -21,7 +21,7 @@ typedef struct stackframe
void StackTracer::trace()
{
stackframe* frame = (stackframe*)m_base_pointer;
while (Memory::is_kernel_address((uintptr_t)frame))
while (frame)
{
char symbol_name[512];
get_symbol_name(frame->instruction, symbol_name);
@ -32,11 +32,6 @@ void StackTracer::trace()
void StackTracer::trace_with_ip(uintptr_t ip)
{
if (!Memory::is_kernel_address(ip))
{
printf("(user stack)");
return;
}
char symbol_name[512];
get_symbol_name(ip, symbol_name);
printf("%lx: %s\n", ip, symbol_name);

View File

@ -3,6 +3,7 @@ section .text
extern _init
extern main
extern _fini
extern initialize_libc
extern exit
global _start
@ -13,6 +14,8 @@ _start:
push rbp ; rbp=0
mov rbp, rsp
call initialize_libc
call _init
mov rdi, 0 ; argc = 0

View File

@ -0,0 +1,28 @@
#ifndef _BITS_ERROR_H
#define _BITS_ERROR_H
#include <errno.h>
#define _RETURN_WITH_ERRNO(rc, type) \
do { \
if (rc < 0) \
{ \
errno = (int)(-rc); \
return -1; \
} \
errno = 0; \
return (type)rc; \
} while (0)
#define _RETURN_WITH_MEMORY_ERRNO(rc, type) \
do { \
if ((unsigned long int)rc > 0xffffffffffffff00) \
{ \
errno = (int)((rc)&0xff); \
return (type)-1; \
} \
errno = 0; \
return (type)rc; \
} while (0)
#endif

View File

@ -1,5 +1,5 @@
#ifndef _LIBALLOC_H
#define _LIBALLOC_H
#ifndef _BITS_LIBALLOC_H
#define _BITS_LIBALLOC_H
#include <stddef.h>

View File

@ -1,5 +1,5 @@
#ifndef __MACROS_H
#define __MACROS_H
#ifndef _BITS_MACROS_H
#define _BITS_MACROS_H
#define noreturn __attribute__((noreturn))
#define align(n) __attribute__((aligned(n)))

View File

@ -0,0 +1,15 @@
#ifndef _ERRNO_H
#define _ERRNO_H
extern int errno;
#define EPERM 1
#define ENOENT 2
#define EBADF 9
#define ENOMEM 12
#define EISDIR 21
#define EINVAL 22
#define EMFILE 24
#define ENOSYS 38
#endif

19
libs/libc/include/fcntl.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef _FCNTL_H
#define _FCNTL_H
#define O_RDONLY 1
#define O_WRONLY 2
#define O_RDWR 3
#ifdef __cplusplus
extern "C"
{
#endif
int open(const char*, int);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -7,10 +7,12 @@
#define SYS_write 3
#define SYS_paint 4
#define SYS_rand 5
#define SYS_getversion 6
#define SYS_gettid 7
#define SYS_mmap 8
#define SYS_munmap 9
#define SYS_gettid 6
#define SYS_mmap 7
#define SYS_munmap 8
#define SYS_open 9
#define SYS_read 10
#define SYS_close 11
#ifndef __want_syscalls
#ifdef __cplusplus

View File

@ -8,16 +8,20 @@
typedef struct
{
int unused;
int f_fd;
int f_eof;
int f_err;
} FILE;
extern FILE* __stderr;
extern FILE* __stdout;
#define stderr __stderr
#define stdout __stdout
#ifdef __cplusplus
extern "C"
{
#endif
extern FILE* stderr;
#define stderr stderr
int fclose(FILE*);
int fflush(FILE*);
FILE* fopen(const char*, const char*);
@ -26,6 +30,9 @@ extern "C"
int fseek(FILE*, long, int);
long ftell(FILE*);
size_t fwrite(const void*, size_t, size_t, FILE*);
int ferror(FILE*);
int feof(FILE*);
void clearerr(FILE*);
void setbuf(FILE*, char*);
int vfprintf(FILE*, const char*, va_list);
int printf(const char*, ...);
@ -35,6 +42,7 @@ extern "C"
int vsprintf(char*, const char*, va_list);
int vsnprintf(char*, size_t, const char*, va_list);
int puts(const char*);
void perror(const char*);
#ifdef __cplusplus
}

View File

@ -23,6 +23,8 @@ extern "C"
deprecated("strcat is unsafe and should not be used; use strncat instead") char* strcat(char*, const char*);
char* strncat(char*, const char*, size_t);
char* strerror(int);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,26 @@
#ifndef _SYS_MMAN_H
#define _SYS_MMAN_H
#include <stddef.h>
typedef unsigned long off_t;
#define MAP_FAILED (void*)-1
#define PROT_READ_WRITE 1
#define PAGE_SIZE 4096
#ifdef __cplusplus
extern "C"
{
#endif
void* mmap(void*, size_t, int, int, int, off_t);
int munmap(void* addr, size_t len);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,4 +1,8 @@
#ifndef _SYS_TYPES_H
#define _SYS_TYPES_H
typedef long int pid_t;
typedef unsigned long int size_t;
typedef long int ssize_t;
#endif

View File

@ -1,10 +1,13 @@
#ifndef _UNISTD_H
#define _UNISTD_H
#include <sys/types.h>
#ifdef __cplusplus
extern "C"
{
#endif
int execv(const char*, char* const[]);
int execve(const char*, char* const[], char* const[]);
int execvp(const char*, char* const[]);
@ -12,7 +15,12 @@ extern "C"
long syscall(long, ...);
unsigned int sleep(unsigned int);
ssize_t read(int, void*, size_t);
ssize_t write(int, const void*, size_t);
int close(int);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,6 +1,5 @@
#include <stddef.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <sys/mman.h>
int liballoc_lock()
{
@ -14,14 +13,12 @@ int liballoc_unlock()
void* liballoc_alloc(size_t size)
{
unsigned long int result = (unsigned long int)syscall(SYS_mmap, NULL, size * 4096, 1);
void* result = mmap(NULL, size * PAGE_SIZE, PROT_READ_WRITE, 0, 0, 0);
if (result == MAP_FAILED) return 0;
return (void*)result;
}
int liballoc_free(void* address, size_t size)
{
int result = (int)syscall(SYS_munmap, address, size * 4096);
if (result < 0) return 1;
else
return 0;
return munmap(address, size * PAGE_SIZE);
}

3
libs/libc/src/errno.cpp Normal file
View File

@ -0,0 +1,3 @@
#include <errno.h>
int errno;

11
libs/libc/src/fcntl.cpp Normal file
View File

@ -0,0 +1,11 @@
#include <fcntl.h>
#include <sys/syscall.h>
#include <unistd.h>
extern "C"
{
int open(const char* pathname, int flags)
{
return (int)syscall(SYS_open, pathname, flags);
}
}

96
libs/libc/src/file.cpp Normal file
View File

@ -0,0 +1,96 @@
#include <errno.h>
#include <fcntl.h>
#include <luna.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
FILE* __stderr;
FILE* __stdout;
extern "C"
{
int fclose(FILE* stream)
{
int status = close(stream->f_fd);
if (status < 0)
{
int savederr = errno;
free(stream); // We do not want to leak memory. man fclose(3) says that whether fclose() fails or not, any
// further operation on the stream results in undefined behavior. So we are free to free the
// stream.
errno = savederr; // free might reset errno. We don't want that.
}
else { free(stream); }
return status;
}
int fflush(FILE*)
{
return 0; // FIXME: Implement buffered IO.
}
FILE* fopen(const char* pathname, const char*)
{
int fd = open(pathname, O_RDWR); // FIXME: Use the mode string.
if (fd < 0) { return 0; }
FILE* stream = (FILE*)malloc(sizeof(FILE));
stream->f_fd = fd;
clearerr(stream);
return stream;
}
size_t fread(void* buf, size_t size, size_t nmemb, FILE* stream)
{
ssize_t status = read(stream->f_fd, buf, size * nmemb);
if (status < 0)
{
stream->f_err = 1;
return 0;
}
if (status == 0) stream->f_eof = 1;
return (size_t)status;
}
int ferror(FILE* stream)
{
return stream->f_err;
}
int feof(FILE* stream)
{
return stream->f_eof;
}
void clearerr(FILE* stream)
{
stream->f_err = stream->f_eof = 0;
}
int fseek(FILE*, long, int)
{
NOT_IMPLEMENTED("fseek");
}
long ftell(FILE*)
{
NOT_IMPLEMENTED("ftell");
}
size_t fwrite(const void* buf, size_t size, size_t nmemb, FILE* stream)
{
ssize_t status = write(stream->f_fd, buf, size * nmemb);
if (status < 0)
{
stream->f_err = 1;
return 0;
}
if (status == 0) stream->f_eof = 1;
return (size_t)status;
}
void setbuf(FILE*, char*)
{
NOT_IMPLEMENTED("setbuf");
}
}

14
libs/libc/src/init.cpp Normal file
View File

@ -0,0 +1,14 @@
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
extern "C" void initialize_libc()
{
__stderr = fopen("/dev/console", "rw");
if (!stderr) exit(errno);
__stdout = fopen("/dev/console", "rw");
if (!stdout) exit(errno);
clearerr(__stderr);
clearerr(__stdout);
}

View File

@ -1,4 +1,6 @@
#include <luna.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/syscall.h>
#include <unistd.h>
@ -19,8 +21,7 @@ extern "C"
noreturn void __luna_abort(const char* message)
{
syscall(SYS_write, message, strlen(message));
syscall(SYS_exit);
__builtin_unreachable();
fwrite(message, strlen(message), 1, stdout);
abort();
}
}

View File

@ -1,3 +1,4 @@
#include <errno.h>
#include <luna.h>
#include <stdarg.h>
#include <stddef.h>
@ -242,6 +243,30 @@ static int internal_printf(const char* format, PutString put_string_callback, ss
}
break;
}
case 'p': {
char result[25];
__unsignedtoa<unsigned long>(va_arg(ap, uint64_t), result, 16);
if (buffer_insert_index + strlen(result) > 1024) flush_buffer();
memcpy(buffer + buffer_insert_index, result, strlen(result));
buffer_insert_index += strlen(result);
if (buffer_insert_index == 1024) flush_buffer();
break;
}
case 'm': {
const char* str = strerror(errno);
while (strlen(str) > 1024)
{
flush_buffer();
memcpy(buffer, str, 1024);
str += 1024;
buffer_insert_index = 1024;
}
if (buffer_insert_index + strlen(str) > 1024) flush_buffer();
memcpy(buffer + buffer_insert_index, str, strlen(str));
buffer_insert_index += strlen(str);
if (buffer_insert_index == 1024) flush_buffer();
break;
}
case 's': {
const char* str = va_arg(ap, const char*);
while (strlen(str) > 1024)
@ -281,8 +306,7 @@ extern "C"
{
int vprintf(const char* format, va_list ap)
{
return internal_printf(
format, [](const char* s) { syscall(SYS_write, s, strlen(s)); }, -1, ap);
return vfprintf(stdout, format, ap);
}
int vsprintf(char* str, const char* format, va_list ap)
@ -304,4 +328,46 @@ extern "C"
},
max == 0 ? 0 : max - 1, ap);
}
int snprintf(char* str, size_t max, const char* format, ...)
{
va_list ap;
va_start(ap, format);
int written = vsnprintf(str, max, format, ap);
va_end(ap);
return written;
}
int sprintf(char* str, const char* format, ...)
{
va_list ap;
va_start(ap, format);
int written = vsprintf(str, format, ap);
va_end(ap);
return written;
}
int printf(const char* format, ...)
{
va_list ap;
va_start(ap, format);
int written = vfprintf(stdout, format, ap);
va_end(ap);
return written;
}
int fprintf(FILE* stream, const char* format, ...)
{
va_list ap;
va_start(ap, format);
int written = vfprintf(stream, format, ap);
va_end(ap);
return written;
}
int vfprintf(FILE* stream, const char* format, va_list ap)
{
return internal_printf(
format, [&](const char* s) { fwrite(s, strlen(s), 1, stream); }, -1, ap);
}
}

View File

@ -1,3 +1,4 @@
#include <errno.h>
#include <luna.h>
#include <stdio.h>
#include <stdlib.h>
@ -7,74 +8,18 @@
extern "C"
{
int fclose(FILE*)
{
NOT_IMPLEMENTED("fclose");
}
int fflush(FILE*)
{
NOT_IMPLEMENTED("fflush");
}
FILE* fopen(const char*, const char*)
{
NOT_IMPLEMENTED("fopen");
}
int fprintf(FILE*, const char*, ...)
{
NOT_IMPLEMENTED("fprintf");
}
size_t fread(void*, size_t, size_t, FILE*)
{
NOT_IMPLEMENTED("fread");
}
int fseek(FILE*, long, int)
{
NOT_IMPLEMENTED("fseek");
}
long ftell(FILE*)
{
NOT_IMPLEMENTED("ftell");
}
size_t fwrite(const void*, size_t, size_t, FILE*)
{
NOT_IMPLEMENTED("fwrite");
}
void setbuf(FILE*, char*)
{
NOT_IMPLEMENTED("setbuf");
}
int vfprintf(FILE*, const char*, va_list)
{
NOT_IMPLEMENTED("vfprintf");
}
int puts(const char* s)
{
long nwritten = syscall(SYS_write, s, strlen(s));
nwritten += syscall(SYS_write, "\n", 1);
long nwritten = fwrite(s, strlen(s), 1, stdout);
if (nwritten < 0) return -1;
nwritten += fwrite("\n", 1, 1, stdout);
return (int)nwritten;
}
int snprintf(char* str, size_t max, const char* format, ...)
void perror(const char* s)
{
va_list ap;
va_start(ap, format);
int written = vsnprintf(str, max, format, ap);
va_end(ap);
return written;
}
int sprintf(char* str, const char* format, ...)
{
va_list ap;
va_start(ap, format);
int written = vsprintf(str, format, ap);
va_end(ap);
return written;
}
int printf(const char* format, ...)
{
va_list ap;
va_start(ap, format);
int written = vprintf(format, ap);
va_end(ap);
return written;
int savederr =
errno; // This was necessary before, but even more now since we clear errno on successful syscalls now.
if (s && *s) { fprintf(stderr, "%s: ", s); }
fprintf(stderr, "%s\n", strerror(savederr));
}
}

View File

@ -15,9 +15,9 @@ extern "C"
exit(-1);
}
noreturn void exit(int)
noreturn void exit(int status)
{
syscall(SYS_exit);
syscall(SYS_exit, status);
__builtin_unreachable();
}

View File

@ -1,3 +1,4 @@
#include <errno.h>
#include <luna.h>
#include <string.h>
@ -60,9 +61,11 @@ extern "C"
return dest;
}
char* strchr(const char*, int)
char* strchr(const char* str, int chr)
{
NOT_IMPLEMENTED("strchr");
while (*str && *str != (char)chr) str++;
if (*str) return const_cast<char*>(str);
return NULL;
}
void* memclr(void* start, size_t count)
@ -108,4 +111,26 @@ extern "C"
// we return "m_start" + the amount of bytes that were transfered
return (void*)(((size_t)start) + i);
}
#pragma GCC push_options
#pragma GCC diagnostic ignored "-Wwrite-strings"
char* strerror(int errnum)
{
switch (errnum)
{
case EPERM: return "Operation not permitted";
case EINVAL: return "Invalid argument";
case ENOMEM: return "Out of memory";
case ENOSYS: return "Function not implemented";
case ENOENT: return "No such file or directory";
case EBADF: return "Bad file descriptor";
case EMFILE: return "Too many open files";
case EISDIR: return "Is a directory";
case 0: return "Success";
default: return (char*)(unsigned long int)errnum;
}
}
#pragma GCC pop_options
}

View File

@ -0,0 +1,17 @@
#include <sys/mman.h>
#include <sys/syscall.h>
#include <unistd.h>
extern "C"
{
// FIXME: Implement a POSIX-compliant mmap.
void* mmap(void* addr, size_t len, int prot, int, int, off_t)
{
return (void*)syscall(SYS_mmap, addr, len, prot);
}
int munmap(void* addr, size_t len)
{
return (int)syscall(SYS_munmap, addr, len);
}
}

View File

@ -1,3 +1,4 @@
#include <bits/error.h>
#include <luna.h>
#include <luna/syscall.h>
#include <stdarg.h>
@ -30,19 +31,21 @@ extern "C"
va_start(ap, number);
switch (number)
{
case SYS_exit:
case SYS_yield:
case SYS_gettid:
case SYS_rand: result = __luna_syscall0(number); break;
case SYS_exit:
case SYS_close:
case SYS_sleep: result = __luna_syscall1(number, va_arg(ap, arg)); break;
case SYS_write:
case SYS_munmap:
case SYS_getversion: {
case SYS_open: {
arg arg0 = va_arg(ap, arg);
arg arg1 = va_arg(ap, arg);
result = __luna_syscall2(number, arg0, arg1);
break;
}
case SYS_write:
case SYS_read:
case SYS_mmap: {
arg arg0 = va_arg(ap, arg);
arg arg1 = va_arg(ap, arg);
@ -59,14 +62,30 @@ extern "C"
result = __luna_syscall5(number, arg0, arg1, arg2, arg3, arg4);
break;
}
default: result = -1; break;
default: result = -ENOSYS; break;
}
va_end(ap);
return result;
if (number == SYS_mmap) { _RETURN_WITH_MEMORY_ERRNO(result, long int); }
else { _RETURN_WITH_ERRNO(result, long); }
}
unsigned int sleep(unsigned int seconds)
{
return msleep(seconds * 1000);
}
ssize_t read(int fd, void* buf, size_t count)
{
return syscall(SYS_read, fd, count, buf); // yes, our read() syscall is in the wrong order.
}
ssize_t write(int fd, const void* buf, size_t count)
{
return syscall(SYS_write, fd, count, buf); // yes, our write() syscall is in the wrong order.
}
int close(int fd)
{
return (int)syscall(SYS_close, fd);
}
}

6
tools/build-debug.sh Normal file
View File

@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -e
source $(dirname $0)/env.sh
MOON_BUILD_DEBUG=1 tools/rebuild-iso.sh

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/usr/bin/env bash
set -e
source $(dirname $0)/env.sh

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/usr/bin/env bash
set -e
source $(dirname $0)/env.sh

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/usr/bin/env bash
set -e
source $(dirname $0)/env.sh

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/usr/bin/env bash
set -e
source $(dirname $0)/env.sh

View File

@ -1,8 +1,6 @@
#!/bin/sh
#!/usr/bin/env bash
set -e
source $(dirname $0)/env.sh
MOON_BUILD_DEBUG=1 tools/rebuild-iso.sh
qemu-system-x86_64 -cdrom Luna.iso -smp 1 -m 256M -serial stdio -d int,cpu_reset -s -no-reboot $@
qemu-system-x86_64 -cdrom Luna.iso -smp 1 -m 256M -serial stdio -d int,cpu_reset -s $@

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/usr/bin/env bash
export LUNA_ROOT=$(realpath $(dirname $0)/..)
export LUNA_BASE=$LUNA_ROOT/base
export PATH=$LUNA_ROOT/toolchain/x86-64-luna/bin:$LUNA_ROOT/toolchain/dist:$PATH
@ -8,3 +8,4 @@ export CXX=x86_64-luna-g++
export LD=x86_64-luna-ld
export AR=x86_64-luna-ar
export ASM=nasm
export STRIP=x86_64-luna-strip

6
tools/gdb.sh Normal file
View File

@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -e
source $(dirname $0)/env.sh
gdb -x .gdbconf

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/usr/bin/env bash
set -e

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/usr/bin/env bash
set -e
source $(dirname $0)/env.sh

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/usr/bin/env bash
set -e
source $(dirname $0)/env.sh

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/usr/bin/env bash
set -e
source $(dirname $0)/env.sh

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/usr/bin/env bash
set -e
source $(dirname $0)/env.sh

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/usr/bin/env bash
set -e
source $(dirname $0)/env.sh

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/usr/bin/env bash
set -e
source $(dirname $0)/env.sh

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/usr/bin/env bash
set -e
source $(dirname $0)/setup-env.sh

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/usr/bin/env bash
source $(dirname $0)/env.sh
export LUNA_GCC_VERSION_REQUIRED=12.2.0

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/usr/bin/env bash
set -e
source $(dirname $0)/setup-env.sh

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/usr/bin/env bash
set -e
source $(dirname $0)/env.sh

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/usr/bin/env bash
set -e
if ! $(dirname $0)/test-binutils.sh

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/usr/bin/env bash
set -e
source $(dirname $0)/env.sh

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/usr/bin/env bash
set -e
source $(dirname $0)/setup-env.sh

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/usr/bin/env bash
set -e
source $(dirname $0)/setup-env.sh