Compare commits

..

No commits in common. "3c1146f2c5a7eef2fe1a45be21bb68ad89170dd8" and "97461c7c1f2f9b94bdc6ed2f54e9d9b139b31553" have entirely different histories.

104 changed files with 481 additions and 2220 deletions

1
.gitignore vendored
View File

@ -7,7 +7,6 @@ kernel/bin/moon.elf
initrd/sys/moon.sym
initrd/bin/**
apps/bin/**
tests/**/bin/**
base/usr/include/**
base/usr/lib/**
**/*.a

View File

@ -6,12 +6,11 @@ Not so much at the moment.
- x86_64-compatible [kernel](kernel/).
- Keeps track of which [memory](kernel/src/memory/) is used and which memory is free, and can allocate memory for itself and [user programs](kernel/src/sys/mem.cpp).
- Can load files from a [virtual file system](kernel/src/fs/) supporting an initial ramdisk, device pseudo-filesystems... but no hard disks yet.
- Can [load files](kernel/src/fs/) from an [initial ramdisk](initrd/), no disk support yet.
- Basic preemptive multitasking, round-robin [scheduler](kernel/src/thread/) that can switch between tasks.
- Can [load userspace ELF programs](kernel/src/sys/elf/) from the file system as user tasks.
- [System call](kernel/src/sys/) interface and simple [C Library](libs/libc/), aiming to be POSIX-compatible.
- Some very simple [example programs](apps/), written in C, that then can get loaded and executed by the kernel.
- UNIX-like [multitasking primitives](kernel/src/sys/exec.cpp), which allow user tasks to spawn other tasks.
- Can [load userspace ELF programs](kernel/src/sys/elf/) from the initial ramdisk as user tasks.
- [System call](kernel/src/sys/) interface and bare-bones [C Library](libs/libc/).
- Some very simple [example programs](apps/), written in C, that the kernel then loads from the initial ramdisk.
## Setup
To build and run Luna, you will need to build a [GCC Cross-Compiler](https://wiki.osdev.org/Why_do_I_need_a_Cross_Compiler%3F) and cross-binutils for `x86_64-luna`. (Yes, Luna is advanced enough that it can use its own [OS-Specific Toolchain](https://wiki.osdev.org/OS_Specific_Toolchain), instead of a bare metal target like `x86_64-elf`. It is the first of my OS projects to be able to do so. The patches for Binutils and GCC are [binutils.patch](tools/binutils.patch) and [gcc.patch](tools/gcc.patch)).

View File

@ -11,6 +11,7 @@ CFLAGS := -Wall -Wextra -Werror -Os
$(APPS_BIN)/%: $(APPS_SRC)/%.c
@mkdir -p $(@D)
$(CC) $(CFLAGS) -o $@ $^
$(STRIP) $@
build: $(REAL_APPS)

View File

@ -1,24 +1,26 @@
#include <errno.h>
#include <luna.h>
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <unistd.h>
typedef long ssize_t;
int print_version()
{
char version[4096];
FILE* fp = fopen("/dev/version", "r");
if (!fp)
FILE* verfile = fopen("/dev/version", "r");
if (!verfile)
{
perror("fopen");
return 1;
}
size_t nread = fread(version, 4096, 1, fp);
if (ferror(fp))
size_t nread = fread(version, 4096, 1, verfile);
if (ferror(verfile))
{
perror("fread");
return 1;
@ -26,7 +28,7 @@ int print_version()
version[nread] = 0;
if (fclose(fp) < 0)
if (fclose(verfile) < 0)
{
perror("fclose");
return 1;
@ -39,9 +41,9 @@ int print_version()
int main()
{
if (getpid() != 1)
if (gettid() == 0) // why are we the idle task?
{
fprintf(stderr, "init should be started as PID 1\n");
fprintf(stderr, "SHENANIGANS! init is tid 0 (which is reserved for the idle task)\n");
return 1;
}
@ -64,7 +66,7 @@ int main()
printf("Welcome to Luna!\n");
printf("Running as PID %ld\n\n", getpid());
printf("Running as tid %ld\n\n", gettid());
sleep(1);
@ -115,69 +117,9 @@ int main()
if (fclose(config) < 0) { perror("fclose"); }
printf("\n\nGot random number %d\n\n", rand());
sleep(2);
printf("Press any key to restart.\n\n");
printf("\n\nPress any key to restart.\n\n");
int stderr_fd = fileno(stderr);
int new_stderr_fd = dup(stderr_fd);
if (new_stderr_fd < 0)
{
perror("dup");
return 1;
}
FILE* new_stderr = fdopen(new_stderr_fd, "rw");
if (!new_stderr)
{
perror("fdopen");
return 1;
}
fprintf(new_stderr, "Bye!\n\n");
fclose(new_stderr);
const char* pathname = "/etc";
printf("Creating directory %s\n", pathname);
if (mkdir(pathname, 0) < 0)
{
perror("mkdir");
return 1;
}
printf("Success!!\n");
printf("Forking...\n");
pid_t child = fork();
if (child < 0)
{
perror("fork");
return 1;
}
if (child == 0)
{
msleep(500);
printf("I am the child, who is my parent?\n");
execv("/bin/sym", NULL);
perror("execv");
return 1;
}
else { printf("Success!! Got PID %ld\n", child); }
jmp_buf env;
int val = setjmp(env);
if (val == 0) { printf("Returning from setjmp!\n"); }
else
{
printf("Returning from longjmp! val=%d\n", val);
return 0;
}
longjmp(env, 3);
return 0;
}

View File

@ -4,7 +4,7 @@
int main()
{
sleep(2);
sleep(6);
FILE* syms = fopen("/sys/moon.sym", "r");
if (!syms)
@ -13,15 +13,15 @@ int main()
return 1;
}
char buf[1200];
char buf[1025];
if (fseek(syms, -1199, SEEK_END) < 0)
if (fseek(syms, 8000, SEEK_SET) < 0)
{
perror("fseek");
return 1;
}
size_t nread = fread(buf, 1199, 1, syms);
size_t nread = fread(buf, 1024, 1, syms);
if (ferror(syms))
{
perror("fread");

39
kernel/include/assert.h Normal file
View File

@ -0,0 +1,39 @@
#pragma once
#include "log/Log.h"
#include "misc/hang.h"
#include "thread/Scheduler.h"
#include "trace/StackTracer.h"
#define __call_assert_fail(...) \
kerrorln(__VA_ARGS__); \
StackTracer tracer; \
tracer.trace(); \
hang();
#define ASSERT(expr) \
do { \
if (!(expr)) \
{ \
Task* cur_task = Scheduler::current_task(); \
if (cur_task) \
{ \
__call_assert_fail("Assertion failed in task %ld at %s, line %d: %s", cur_task->id, __FILE__, \
__LINE__, #expr); \
} \
else { __call_assert_fail("Assertion failed at %s, line %d: %s", __FILE__, __LINE__, #expr); } \
} \
} while (0)
#define TODO(message) \
do { \
Task* cur_task = Scheduler::current_task(); \
if (cur_task) \
{ \
__call_assert_fail("TODO in task %ld at %s, line %d: %s", cur_task->id, __FILE__, __LINE__, message); \
} \
else { __call_assert_fail("TODO at %s, line %d: %s", __FILE__, __LINE__, message); } \
} while (0)
#ifdef ___weird_hack_to_put_something_at_end_of_file
#undef ___weird_hack_to_put_something_at_end_of_file
#endif

View File

@ -6,11 +6,7 @@
#define EBADF 9
#define ENOMEM 12
#define EFAULT 14
#define EEXIST 17
#define ENOTDIR 20
#define EISDIR 21
#define EINVAL 22
#define EMFILE 24
#define ENOSPC 28
#define ENOSYS 38
#define ENOTSUP 95
#define ENOSYS 38

View File

@ -43,8 +43,6 @@ struct Descriptor
Descriptor(const Descriptor& other);
Descriptor();
const Descriptor& operator=(const Descriptor& other);
private:
bool m_is_open;
bool m_can_read;

View File

@ -35,15 +35,12 @@ namespace VFS
ssize_t read(Node* node, size_t offset, size_t length, char* buffer);
ssize_t write(Node* node, size_t offset, size_t length, const char* buffer);
int mkdir(const char* path, const char* name);
int mkdir(const char* pathname);
int 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);
bool exists(const char* pathname);
void mount(Node* mountpoint, Node* mounted);
void mount(const char* pathname, Node* mounted);

View File

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

View File

@ -1,6 +0,0 @@
#pragma once
#include "panic/Panic.h"
#define ASSERT(expr) (bool)(expr) || panic("Assertion failed: " #expr)
#define TODO(message) panic("TODO: " message)

View File

@ -22,7 +22,6 @@ namespace KernelLog
void logln(const char* function, LogLevel level, const char* message, ...) PRINTF_LIKE(3, 4);
void toggle_log_level(LogLevel level);
void toggle_log_backend(Backend backend);
void enable_log_backend(Backend backend);
}
#ifndef MODULE

View File

@ -7,7 +7,7 @@ struct AddressSpace
void destroy();
void clear();
void detach();
AddressSpace clone();
@ -16,6 +16,12 @@ struct AddressSpace
return m_pml4;
}
bool is_cloned()
{
return m_cloned;
}
private:
PageTable* m_pml4;
bool m_cloned;
};

View File

@ -1,27 +0,0 @@
#pragma once
#include <stdint.h>
struct UserHeap
{
bool init();
uint64_t request_virtual_page();
uint64_t request_virtual_pages(uint64_t count);
void free_virtual_page(uint64_t address);
void free_virtual_pages(uint64_t address, uint64_t count);
void free();
bool inherit(UserHeap& other);
private:
uint8_t* bitmap = nullptr;
uint64_t bitmap_size = 0;
uint64_t start_index = 0;
bool bitmap_read(uint64_t index);
void bitmap_set(uint64_t index, bool value);
bool try_expand();
bool try_expand_size(uint64_t size);
};

View File

@ -5,11 +5,13 @@
extern "C"
{
#endif
[[noreturn]] bool __do_int_panic(Context* context, const char* file, int line, const char* message);
[[noreturn]] bool __do_panic(const char* file, int line, const char* message);
[[noreturn]] void __do_int_panic(Context* context, const char* file, int line, const char* message);
[[noreturn]] void __do_panic(Context* context, const char* message);
[[noreturn]] void __panic(const char* message);
#ifdef __cplusplus
}
#endif
#define panic(message) __do_panic(__FILE__, __LINE__, message)
#define panic(message) asm volatile("cli\npush $16\npushq %%rsp\npushfq\npush $8\ncall __panic" : : "D"(message))
#define int_panic(context, message) __do_int_panic(context, __FILE__, __LINE__, message)

View File

@ -1,4 +0,0 @@
#pragma once
char* basename(char* path);
char* dirname(char* path);

View File

@ -8,7 +8,6 @@ __attribute__((deprecated)) int strcmp(const char* a, const char* b);
__attribute__((deprecated)) char* strcat(char* dest, const char* src);
char* strncpy(char* dest, const char* src, size_t n);
size_t strlcpy(char* dest, const char* src, size_t size);
int strncmp(const char* a, const char* b, size_t n);
char* strncat(char* dest, const char* src, size_t n);
@ -19,5 +18,4 @@ void* memset(void* dest, int c, size_t n);
int memcmp(const void* a, const void* b, size_t n);
void* memmove(void* dest, void* src, size_t n);
char* strdup(const char* src);
char* strrchr(const char* str, int c);
char* strdup(const char* src);

View File

@ -7,19 +7,15 @@
#define SYS_sleep 2
#define SYS_write 3
#define SYS_paint 4
#define SYS_getpid 5
#define SYS_mmap 6
#define SYS_munmap 7
#define SYS_open 8
#define SYS_read 9
#define SYS_close 10
#define SYS_seek 11
#define SYS_exec 12
#define SYS_fcntl 13
#define SYS_mprotect 14
#define SYS_clock 15
#define SYS_mkdir 16
#define SYS_fork 17
#define SYS_rand 5
#define SYS_gettid 6
#define SYS_mmap 7
#define SYS_munmap 8
#define SYS_open 9
#define SYS_read 10
#define SYS_close 11
#define SYS_seek 12
#define SYS_exec 13
namespace Syscall
{
@ -33,16 +29,12 @@ void sys_yield(Context* context);
void sys_sleep(Context* context, uint64_t ms);
void sys_write(Context* context, int fd, size_t size, const char* addr);
void sys_paint(Context* context, uint64_t x, uint64_t y, uint64_t w, uint64_t h, uint64_t col);
void sys_getpid(Context* context);
void sys_mmap(Context* context, void* address, size_t size, int prot);
void sys_rand(Context* context);
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);
void sys_seek(Context* context, int fd, long offset, int whence);
void sys_exec(Context* context, const char* pathname);
void sys_fcntl(Context* context, int fd, int command, uintptr_t arg);
void sys_mprotect(Context* context, void* address, size_t size, int prot);
void sys_clock(Context* context);
void sys_mkdir(Context* context, const char* filename);
void sys_fork(Context* context);
void sys_exec(Context* context, const char* pathname);

View File

@ -9,11 +9,11 @@ namespace Scheduler
void yield();
void exit(int status);
void sleep(unsigned long ms);
void add_kernel_task(const char* taskname, void (*task)(void));
void add_kernel_task(void (*task)(void));
Task* create_user_task();
long load_user_task(const char* filename);
void load_user_task(const char* filename);
void task_exit(Context* context, int64_t status);
void task_misbehave(Context* context, int64_t status);
@ -27,8 +27,4 @@ namespace Scheduler
void reap_tasks();
void reset_task(Task* task, ELFImage* new_image);
void append_task(Task* task);
Task* find_by_pid(uint64_t pid);
}

View File

@ -2,10 +2,9 @@
#include "fs/FileDescriptor.h"
#include "interrupts/Context.h"
#include "memory/AddressSpace.h"
#include "memory/UserHeap.h"
#include "sys/elf/Image.h"
#define TASK_MAX_FDS 32
#define TASK_MAX_FDS 8
struct Task
{
@ -47,22 +46,10 @@ struct Task
Descriptor files[TASK_MAX_FDS];
AddressSpace address_space;
};
UserHeap allocator;
void set_context_from_task(Task& task, Context* ctx);
void get_context_to_task(Task& task, Context* ctx);
int alloc_fd();
int alloc_fd_greater_than_or_equal(int base_fd);
void save_context(Context* context);
void restore_context(Context* context);
void save_floating();
void restore_floating();
void switch_to_address_space();
bool has_died();
char name[128];
};
void task_save_floating(Task& task);
void task_restore_floating(Task& task);

View File

@ -1,5 +1,4 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
void get_symbol_name(uintptr_t address, char* buffer, size_t size);
void get_symbol_name(uintptr_t address, char* buffer);

View File

@ -40,14 +40,4 @@ int Descriptor::seek(long offset)
return -EINVAL; // FIXME: Support seeking beyond the current file's length.
m_offset = (uint64_t)offset;
return 0;
}
const Descriptor& Descriptor::operator=(const Descriptor& other)
{
m_is_open = other.m_is_open;
m_can_read = other.m_can_read;
m_can_write = other.m_can_write;
m_offset = other.m_offset;
m_node = other.m_node;
return other;
}

View File

@ -3,7 +3,6 @@
#include "fs/VFS.h"
#include "errno.h"
#include "log/Log.h"
#include "std/libgen.h"
#include "std/stdlib.h"
#include "std/string.h"
@ -132,54 +131,16 @@ int VFS::mkdir(const char* path, const char* name)
if (!node)
{
kwarnln("Attempting to mkdir in %s, which does not exist", path);
return -ENOENT;
}
if (node->type != VFS_DIRECTORY)
{
kwarnln("Attempting to mkdir in %s, which is not a directory!!", path);
return -ENOTDIR;
return -1;
}
if (!node->mkdir_func)
{
kwarnln("Chosen node does not support mkdir()");
return -ENOTSUP;
}
if (!node->find_func)
{
kwarnln("Chosen node does not support finddir()");
return -ENOTSUP;
}
if (node->find_func(node, name) != nullptr)
{
kwarnln("Already exists");
return -EEXIST;
return -1;
}
return node->mkdir_func(node, name);
}
int VFS::mkdir(const char* pathname)
{
char* bstr = strdup(pathname);
char* dstr = strdup(pathname);
char* base = basename(bstr);
char* dir = dirname(dstr);
kdbgln("mkdir(): creating %s in directory %s", base, dir);
int result = mkdir(dir, base);
kfree(bstr);
kfree(dstr);
return result;
}
bool VFS::exists(const char* pathname)
{
return resolve_path(pathname) != nullptr;
}
void VFS::mount(Node* mountpoint, Node* mounted)
{
if (!mountpoint || !mounted) return;

View File

@ -1,6 +1,5 @@
#include "fs/devices/DeviceFS.h"
#include "fs/devices/Console.h"
#include "fs/devices/Random.h"
#include "fs/devices/Serial.h"
#include "fs/devices/Version.h"
#include "std/stdlib.h"
@ -26,7 +25,6 @@ VFS::Node* DeviceFS::get()
devfs_files[devfs_file_count++] = VersionDevice::create_new("version");
devfs_files[devfs_file_count++] = ConsoleDevice::create_new("console");
devfs_files[devfs_file_count++] = SerialDevice::create_new("serial");
devfs_files[devfs_file_count++] = RandomDevice::create_new("random");
return devfs_root;
}

View File

@ -1,38 +0,0 @@
#include "fs/devices/Random.h"
#include "config.h"
#include "rand/Mersenne.h"
#include "render/TextRenderer.h"
#include "std/stdio.h"
#include "std/stdlib.h"
#include "std/string.h"
VFS::Node* RandomDevice::create_new(const char* devname)
{
VFS::Node* dev = new VFS::Node;
dev->read_func = RandomDevice::read;
dev->inode = 0;
dev->length = 0;
dev->type = VFS_DEVICE;
dev->flags = 0;
strncpy(dev->name, devname, sizeof(dev->name));
return dev;
}
ssize_t RandomDevice::read(VFS::Node* node, size_t, size_t size, char* buffer)
{
if (!node) return -1;
size_t nread = size;
while (size >= sizeof(uint64_t))
{
*(uint64_t*)buffer = Mersenne::get();
size -= sizeof(uint64_t);
buffer += sizeof(uint64_t);
}
while (size)
{
*buffer = (char)(Mersenne::get() & 0xFF);
size--;
buffer++;
}
return (ssize_t)nread;
}

View File

@ -1,7 +1,7 @@
#define MODULE "gdt"
#include "gdt/GDT.h"
#include "kassert.h"
#include "assert.h"
#include "log/Log.h"
#include "memory/MemoryManager.h"
#include "std/string.h"

View File

@ -1,12 +1,12 @@
#define MODULE "init"
#include "init/Init.h"
#include "assert.h"
#include "bootboot.h"
#include "cpu/CPU.h"
#include "init/InitRD.h"
#include "interrupts/Interrupts.h"
#include "io/Serial.h"
#include "kassert.h"
#include "log/Log.h"
#include "memory/MemoryManager.h"
#include "memory/PMM.h"

View File

@ -2,7 +2,6 @@
#include "init/InitRD.h"
#include "bootboot.h"
#include "errno.h"
#include "fs/VFS.h"
#include "io/Serial.h"
#include "log/Log.h"
@ -191,23 +190,23 @@ int initrd_mkdir(VFS::Node* node, const char* name) // FIXME: Return proper erro
if (total_dirs >= 32)
{
kwarnln("mkdir() failed: too many directories");
return -ENOSPC;
return -1;
}
if (node->inode > total_dirs)
{
kwarnln("mkdir() failed: invalid node");
return -EINVAL;
return -1;
}
if (!(node->type & VFS_DIRECTORY))
{
kwarnln("mkdir() failed: not a directory");
return -ENOTDIR;
return -1;
}
InitRD::Directory& parent = dirs[node->inode];
if (parent.entries == INITRD_MAX_FILES_IN_DIR)
{
kwarnln("mkdir() failed: parent is full");
return -ENOSPC;
kwarnln("mkdir() failed: parent is null");
return -1;
}
uint64_t inode = total_dirs;
VFS::Node& new_node = nodes[total_nodes++];

View File

@ -1,10 +1,10 @@
#define MODULE "isr"
#include "assert.h"
#include "interrupts/Context.h"
#include "interrupts/IRQ.h"
#include "interrupts/Interrupts.h"
#include "io/Serial.h"
#include "kassert.h"
#include "log/Log.h"
#include "misc/hang.h"
#include "panic/Panic.h"

View File

@ -1,7 +1,7 @@
#define MODULE "idt"
#include "interrupts/IDT.h"
#include "kassert.h"
#include "assert.h"
#include "log/Log.h"
struct IDTEntry

View File

@ -80,9 +80,4 @@ void KernelLog::toggle_log_level(LogLevel level)
void KernelLog::toggle_log_backend(Backend backend)
{
backend_mask ^= (1 << (int)backend);
}
void KernelLog::enable_log_backend(Backend backend)
{
backend_mask |= (1 << (int)backend);
}

View File

@ -1,26 +1,40 @@
#define MODULE "main"
#include "acpi/RSDT.h"
#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"
#include "interrupts/IDT.h"
#include "interrupts/Install.h"
#include "interrupts/Interrupts.h"
#include "io/PCI.h"
#include "io/PIC.h"
#include "kassert.h"
#include "io/Serial.h"
#include "log/Log.h"
#include "memory/AddressSpace.h"
#include "memory/Memory.h"
#include "memory/MemoryManager.h"
#include "memory/MemoryMap.h"
#include "misc/hang.h"
#include "memory/PMM.h"
#include "memory/VMM.h"
#include "misc/PCITypes.h"
#include "misc/reboot.h"
#include "panic/Panic.h"
#include "rand/Mersenne.h"
#include "render/Framebuffer.h"
#include "render/TextRenderer.h"
#include "std/stdio.h"
#include "std/stdlib.h"
#include "std/string.h"
#include "sys/elf/ELFLoader.h"
#include "thread/PIT.h"
#include "thread/Scheduler.h"
#define STRINGIZE(x) #x
#define STRINGIZE_VALUE_OF(x) STRINGIZE(x)
extern "C" void _start()
{
Init::check_magic();
@ -51,13 +65,7 @@ extern "C" void _start()
kinfoln("Prepared scheduler");
#ifdef RUN_TEST_AS_INIT
ASSERT(Scheduler::load_user_task(STRINGIZE_VALUE_OF(RUN_TEST_AS_INIT)) > 0);
#else
ASSERT(Scheduler::load_user_task("/bin/init") > 0);
#endif
Scheduler::add_kernel_task("[moon-reaper]", []() {
Scheduler::add_kernel_task([]() {
while (1)
{
sleep(400);
@ -65,18 +73,24 @@ extern "C" void _start()
}
});
Scheduler::load_user_task("/bin/init");
kinfoln("Prepared scheduler tasks");
ASSERT(VFS::mkdir("/dev") == 0);
ASSERT(VFS::mkdir("/", "dev") == 0);
VFS::mount("/dev", DeviceFS::get());
Init::finish_kernel_boot();
PIC::remap();
PIC::enable_master(0b11111100);
PIC::enable_master(0b11111100); // enable keyboard and PIT
PIC::enable_slave(0b11111111);
Interrupts::enable();
kinfoln("Interrupts enabled");
while (1) halt();
PCI::scan([](PCI::Device& dev) {
kinfoln("Found PCI device %x:%x, %s", dev.id().vendor, dev.id().device, pci_type_name(dev.type()));
});
Scheduler::exit(0);
}

View File

@ -4,20 +4,24 @@
#include "log/Log.h"
#include "memory/PMM.h"
#include "memory/VMM.h"
#include "std/stdlib.h"
#include "std/string.h"
#include "utils/move.h"
AddressSpace AddressSpace::create()
{
AddressSpace result;
result.m_pml4 = (PageTable*)PMM::request_page();
result.m_cloned = false;
VMM::install_kernel_page_directory_into_address_space(result);
return move(result);
}
void AddressSpace::destroy()
{
if (m_cloned)
{
kdbgln("Will not destroy a cloned address space, I don't own it");
return;
}
uint64_t pages_freed = 0;
for (int i = 0; i < 512; i++)
{
@ -74,128 +78,18 @@ void AddressSpace::destroy()
kdbgln("Reclaimed %ld pages from address space!", pages_freed);
}
void AddressSpace::clear()
void AddressSpace::detach()
{
uint64_t pages_freed = 0;
for (int i = 0; i < 512; i++)
{
PageDirectoryEntry& pdp_pde = m_pml4->entries[i];
if (!pdp_pde.present) continue;
if (pdp_pde.larger_pages)
{
pages_freed++;
PMM::free_page((void*)pdp_pde.get_address());
continue;
}
PageTable* pdp = (PageTable*)pdp_pde.get_address();
for (int j = 0; j < 511; j++) // skip the last page directory, it's the kernel one
{
PageDirectoryEntry& pd_pde = pdp->entries[j];
if (!pd_pde.present) continue;
if (pd_pde.larger_pages)
{
pages_freed++;
PMM::free_page((void*)pd_pde.get_address());
continue;
}
PageTable* pd = (PageTable*)pd_pde.get_address();
for (int k = 0; k < 512; k++)
{
PageDirectoryEntry& pt_pde = pd->entries[k];
if (!pt_pde.present) continue;
if (pt_pde.larger_pages)
{
pages_freed++;
PMM::free_page((void*)pt_pde.get_address());
continue;
}
PageTable* pt = (PageTable*)pt_pde.get_address();
for (int l = 0; l < 512; l++)
{
PageDirectoryEntry& pde = pt->entries[l];
if (!pde.present) continue;
pages_freed++;
PMM::free_page((void*)pde.get_address());
}
pages_freed++;
PMM::free_page(pt);
}
pages_freed++;
PMM::free_page(pd);
}
pages_freed++;
PMM::free_page(pdp);
}
kdbgln("Reclaimed %ld pages from address space!", pages_freed);
if (!m_cloned) return;
m_pml4 = (PageTable*)PMM::request_page();
VMM::install_kernel_page_directory_into_address_space(*this);
m_cloned = false;
}
AddressSpace AddressSpace::clone() // FIXME: Add out-of-memory checks to this function.
AddressSpace AddressSpace::clone()
{
AddressSpace result;
result.m_pml4 = (PageTable*)PMM::request_page();
if (!result.m_pml4) return result;
memcpy(result.m_pml4, m_pml4, PAGE_SIZE);
for (int i = 0; i < 512; i++)
{
PageDirectoryEntry& pdp_pde = m_pml4->entries[i];
PageDirectoryEntry& cloned_pdp_pde = result.m_pml4->entries[i];
if (!pdp_pde.present) continue;
if (pdp_pde.larger_pages)
{
void* cloned = PMM::request_page();
memcpy(cloned, (void*)pdp_pde.get_address(), PAGE_SIZE);
cloned_pdp_pde.set_address((uint64_t)cloned);
continue;
}
PageTable* pdp = (PageTable*)pdp_pde.get_address();
PageTable* cloned_pdp = (PageTable*)PMM::request_page();
memcpy(cloned_pdp, pdp, PAGE_SIZE);
cloned_pdp_pde.set_address((uint64_t)cloned_pdp);
for (int j = 0; j < 511; j++) // skip the last page directory, it's the kernel one
{
PageDirectoryEntry& pd_pde = pdp->entries[j];
PageDirectoryEntry& cloned_pd_pde = cloned_pdp->entries[j];
if (!pd_pde.present) continue;
if (pd_pde.larger_pages)
{
void* cloned = PMM::request_page();
memcpy(cloned, (void*)pd_pde.get_address(), PAGE_SIZE);
cloned_pd_pde.set_address((uint64_t)cloned);
continue;
}
PageTable* pd = (PageTable*)pd_pde.get_address();
PageTable* cloned_pd = (PageTable*)PMM::request_page();
memcpy(cloned_pd, pd, PAGE_SIZE);
cloned_pd_pde.set_address((uint64_t)cloned_pd);
for (int k = 0; k < 512; k++)
{
PageDirectoryEntry& pt_pde = pd->entries[k];
PageDirectoryEntry& cloned_pt_pde = cloned_pd->entries[k];
if (!pt_pde.present) continue;
if (pt_pde.larger_pages)
{
void* cloned = PMM::request_page();
memcpy(cloned, (void*)pt_pde.get_address(), PAGE_SIZE);
cloned_pt_pde.set_address((uint64_t)cloned);
continue;
}
PageTable* pt = (PageTable*)pt_pde.get_address();
PageTable* cloned_pt = (PageTable*)PMM::request_page();
memcpy(cloned_pt, pt, PAGE_SIZE);
cloned_pt_pde.set_address((uint64_t)cloned_pt);
for (int l = 0; l < 512; l++)
{
PageDirectoryEntry& pde = pt->entries[l];
PageDirectoryEntry& cloned_pde = cloned_pt->entries[l];
if (!pde.present) continue;
void* cloned = PMM::request_page();
memcpy(cloned, (void*)pde.get_address(), PAGE_SIZE);
cloned_pde.set_address((uint64_t)cloned);
continue;
}
}
}
}
result.m_pml4 = m_pml4;
result.m_cloned = true;
return result;
}

View File

@ -3,7 +3,7 @@
#include "log/Log.h"
#endif
#include "kassert.h"
#include "assert.h"
#include "memory/KernelHeap.h"
#include "memory/MemoryManager.h"
#include "memory/PMM.h"

View File

@ -1,8 +1,8 @@
#define MODULE "mem"
#include "memory/PMM.h"
#include "assert.h"
#include "bootboot.h"
#include "kassert.h"
#include "memory/Memory.h"
#include "memory/MemoryManager.h"
#include "misc/utils.h"

View File

@ -1,164 +0,0 @@
#define MODULE "mem"
#include "memory/UserHeap.h"
#include "log/Log.h"
#include "misc/utils.h"
#include "std/stdlib.h"
#include "std/string.h"
#ifndef USER_HEAP_DEBUG
#undef kdbgln
#define kdbgln(...)
#endif
#ifndef PAGE_SIZE
#define PAGE_SIZE 4096
#endif
#define ALLOC_BASE 0xa00000
#define INITIAL_SIZE 0x2000
#define EXPAND_SIZE 0x1000
bool UserHeap::init()
{
bitmap = (uint8_t*)kmalloc(INITIAL_SIZE);
if (!bitmap) return false;
bitmap_size = INITIAL_SIZE;
memset(bitmap, 0, bitmap_size);
kdbgln("new user heap, bitmap at %p, size %ld", (void*)bitmap, bitmap_size);
return true;
}
bool UserHeap::inherit(UserHeap& other)
{
bitmap = (uint8_t*)kmalloc(other.bitmap_size);
if (!bitmap) return false;
bitmap_size = other.bitmap_size;
memcpy(bitmap, other.bitmap, bitmap_size);
kdbgln("child user heap, bitmap at %p, size %ld", (void*)bitmap, bitmap_size);
return true;
}
void UserHeap::free()
{
kdbgln("freeing user heap, bitmap at %p, size %ld", (void*)bitmap, bitmap_size);
kfree(bitmap);
}
bool UserHeap::try_expand()
{
kdbgln("attempting to expand user heap");
void* new_bitmap = krealloc(bitmap, bitmap_size + EXPAND_SIZE);
if (!new_bitmap)
{
kdbgln("expansion failed");
return false;
}
bitmap = (uint8_t*)new_bitmap;
memset(bitmap + bitmap_size, 0, EXPAND_SIZE);
bitmap_size += EXPAND_SIZE;
kdbgln("expanded user heap, bitmap at %p, size %ld", (void*)bitmap, bitmap_size);
return true;
}
bool UserHeap::try_expand_size(uint64_t size)
{
void* new_bitmap = krealloc(bitmap, bitmap_size + size);
if (!new_bitmap)
{
kdbgln("expansion failed");
return false;
}
bitmap = (uint8_t*)new_bitmap;
memset(bitmap + bitmap_size, 0, size);
bitmap_size += size;
kdbgln("expanded user heap, bitmap at %p, size %ld", (void*)bitmap, bitmap_size);
return true;
}
bool UserHeap::bitmap_read(uint64_t index)
{
return (bitmap[index / 8] & (0b10000000 >> (index % 8))) > 0;
}
void UserHeap::bitmap_set(uint64_t index, bool value)
{
uint64_t byteIndex = index / 8;
uint8_t bitIndexer = 0b10000000 >> (index % 8);
bitmap[byteIndex] &= ~bitIndexer;
if (value) { bitmap[byteIndex] |= bitIndexer; }
}
uint64_t UserHeap::request_virtual_page()
{
uint64_t attempts = 0;
allocate:
for (uint64_t index = start_index; index < bitmap_size * 8; index++)
{
if (bitmap_read(index)) continue;
bitmap_set(index, true);
start_index = index + 1;
return ALLOC_BASE + (index * PAGE_SIZE);
}
if (attempts == 0 && try_expand()) // We are allocating ONE PAGE, only one attempt should be necessary.
{
attempts++;
goto allocate;
}
return 0;
}
uint64_t UserHeap::request_virtual_pages(uint64_t count)
{
uint64_t attempts = 0;
allocate:
uint64_t contiguous = 0;
uint64_t contiguous_start = 0;
for (uint64_t index = start_index; index < bitmap_size * 8; index++)
{
if (bitmap_read(index))
{
contiguous = 0;
continue;
}
if (contiguous == 0)
{
contiguous_start = index;
contiguous++;
}
else
contiguous++;
if (contiguous == count)
{
for (uint64_t i = 0; i < count; i++) bitmap_set(contiguous_start + i, true);
return ALLOC_BASE + (contiguous_start * PAGE_SIZE);
}
}
if (attempts == 0 && try_expand_size(Utilities::get_blocks_from_size(8, count) + 256))
{
attempts++;
goto allocate;
}
return 0;
}
void UserHeap::free_virtual_page(uint64_t address)
{
if (address < ALLOC_BASE || address >= (ALLOC_BASE + bitmap_size * 8 * PAGE_SIZE)) return;
uint64_t index = (address - ALLOC_BASE) / PAGE_SIZE;
bitmap_set(index, false);
if (start_index > index) start_index = index;
}
void UserHeap::free_virtual_pages(uint64_t address, uint64_t count)
{
if (address < ALLOC_BASE || address >= (ALLOC_BASE + bitmap_size * 8 * PAGE_SIZE)) return;
uint64_t index = (address - ALLOC_BASE) / PAGE_SIZE;
for (uint64_t i = 0; i < count; i++) { bitmap_set(index + i, false); }
if (start_index > index) start_index = index;
}

View File

@ -1,7 +1,7 @@
#define MODULE "vmm"
#include "memory/VMM.h"
#include "kassert.h"
#include "assert.h"
#include "log/Log.h"
#include "memory/PMM.h"
#include "misc/utils.h"
@ -275,19 +275,13 @@ void VMM::install_kernel_page_directory_into_address_space(AddressSpace& space)
PageTable* kernel_last_pdp = (PageTable*)kernel_pml4->entries[511].get_address();
PageTable* kernel_last_pd = (PageTable*)kernel_last_pdp->entries[511].get_address();
PageTable* space_last_pdp = (PageTable*)PMM::request_page();
PageDirectoryEntry& space_last_pdp_pde = space_pml4->entries[511];
PageTable* space_last_pdp;
if (!space_last_pdp_pde.present)
{
space_last_pdp = (PageTable*)PMM::request_page();
space_last_pdp_pde.present = true;
space_last_pdp_pde.read_write = true;
space_last_pdp_pde.set_address((uint64_t)space_last_pdp);
}
else { space_last_pdp = (PageTable*)space_last_pdp_pde.get_address(); }
space_last_pdp_pde.present = true;
space_last_pdp_pde.read_write = true;
space_last_pdp_pde.set_address((uint64_t)space_last_pdp);
PageDirectoryEntry& space_last_pd_pde = space_last_pdp->entries[511];

View File

@ -8,7 +8,7 @@
#endif
#ifndef MOON_MINOR
#define MOON_MINOR 12
#define MOON_MINOR 11
#endif
#ifndef _MOON_SUFFIX

View File

@ -1,14 +1,9 @@
#define MODULE "stack"
#include "log/Log.h"
#include "misc/hang.h"
#include "render/TextRenderer.h"
#include "panic/Panic.h"
#include <stdint.h>
extern "C" void __stack_chk_fail()
{
KernelLog::enable_log_backend(Backend::Console);
TextRenderer::reset();
kerrorln("stack smashing detected");
hang();
panic("Stack smashing detected");
}

View File

@ -0,0 +1,34 @@
extern __do_panic
global __panic
__panic:
push BYTE 0 ; interrupt number
push BYTE 0 ; error code
push rax
push rbx
push rcx
push rdx
push rbp
push rdi
push rsi
push r8
push r9
push r10
push r11
push r12
push r13
push r14
push r15
mov r8, cr2
push r8
mov rsi, rdi
mov rdi, rsp
call __do_panic
cli
loop:
hlt
jmp loop

View File

@ -6,45 +6,33 @@
#include "io/PIC.h"
#include "log/Log.h"
#include "misc/MSR.h"
#include "render/TextRenderer.h"
#include "std/stdio.h"
#include "thread/Scheduler.h"
#include "trace/StackTracer.h"
void dump_registers(Context* context)
static void dump_registers(Context* context)
{
kinfoln("-- Registers:");
kinfoln("rax: %lx, rbx: %lx, rcx: %lx, rdx: %lx", context->rax, context->rbx, context->rcx, context->rdx);
kinfoln("rsi: %lx, rdi: %lx, rsp: %lx, rbp: %lx", context->rsi, context->rdi, context->rsp, context->rbp);
kinfoln("r8: %lx, r9: %lx, r10: %lx, r11: %lx", context->r8, context->r9, context->r10, context->r11);
kinfoln("r12: %lx, r13: %lx, r14: %lx, r15: %lx", context->r12, context->r13, context->r14, context->r15);
kinfoln("rip: %lx, cs: %lx, ss: %lx", context->rip, context->cs, context->ss);
kinfoln("rflags: %lx, cr2: %lx", context->rflags, context->cr2);
kinfoln("ia32_efer: %lx", MSR::read_from(IA32_EFER_MSR));
printf("-- Registers: \n");
printf("rax: %lx, rbx: %lx, rcx: %lx, rdx: %lx\n", context->rax, context->rbx, context->rcx, context->rdx);
printf("rsi: %lx, rdi: %lx, rsp: %lx, rbp: %lx\n", context->rsi, context->rdi, context->rsp, context->rbp);
printf("r8: %lx, r9: %lx, r10: %lx, r11: %lx\n", context->r8, context->r9, context->r10, context->r11);
printf("r12: %lx, r13: %lx, r14: %lx, r15: %lx\n", context->r12, context->r13, context->r14, context->r15);
printf("rip: %lx, cs: %lx, ss: %lx\n", context->rip, context->cs, context->ss);
printf("rflags: %lx, cr2: %lx\n", context->rflags, context->cr2);
printf("ia32_efer: %lx\n", MSR::read_from(IA32_EFER_MSR));
}
[[noreturn]] void __panic_stub(Context* context)
[[noreturn]] static void __panic_stub(Context* context)
{
if (context) dump_registers(context);
dump_registers(context);
if (InitRD::is_initialized())
{
kinfoln("-- Stack trace:");
if (context)
{
StackTracer tracer(context->rbp);
tracer.trace_with_ip(context->rip);
}
else
{
uintptr_t rbp;
asm volatile("mov %%rbp, %0" : "=r"(rbp));
StackTracer tracer(rbp);
tracer.trace();
}
printf("-- Stack trace:\n");
StackTracer tracer(context->rbp);
tracer.trace_with_ip(context->rip);
}
else { kinfoln("-- No stack trace available"); }
else { printf("-- No stack trace available\n"); }
PIC::enable_master(0b11111101); // enable keyboard only
PIC::enable_slave(0b11111111);
@ -65,14 +53,10 @@ void dump_registers(Context* context)
while (1) asm volatile("hlt");
}
extern "C" [[noreturn]] bool __do_int_panic(Context* context, const char* file, int line, const char* message)
extern "C" [[noreturn]] void __do_int_panic(Context* context, const char* file, int line, const char* message)
{
asm volatile("cli");
KernelLog::enable_log_backend(Backend::Console);
TextRenderer::reset();
if (context->number >= 0x20 && context->number < 0x30) { PIC::send_eoi((uint8_t)(context->irq_number & 0xFF)); }
Task* task;
@ -85,20 +69,11 @@ extern "C" [[noreturn]] bool __do_int_panic(Context* context, const char* file,
__panic_stub(context);
}
extern "C" [[noreturn]] bool __do_panic(const char* file, int line, const char* message)
extern "C" [[noreturn]] void __do_panic(Context* context, const char* message)
{
asm volatile("cli");
KernelLog::enable_log_backend(Backend::Console);
TextRenderer::reset();
Task* task;
if ((task = Scheduler::current_task()))
{
kerrorln("Kernel panic in task %ld, at %s, line %d: %s", task->id, file, line, message);
}
else { kerrorln("Kernel panic at %s, line %d: %s", file, line, message); }
if ((task = Scheduler::current_task())) { kerrorln("Kernel panic in task %ld: %s", task->id, message); }
else { kerrorln("Kernel panic: %s", message); }
__panic_stub(nullptr);
__panic_stub(context);
}

View File

@ -1,7 +1,7 @@
#define MODULE "rand"
#include "rand/Mersenne.h"
#include "kassert.h"
#include "assert.h"
#include <stddef.h>
typedef uint64_t word_t;

View File

@ -1,47 +0,0 @@
#include "std/libgen.h"
#include "std/string.h"
static char dot[] = ".";
char* basename(char* path)
{
// If path is NULL, or the string's length is 0, return .
if (!path) return dot;
size_t len = strlen(path);
if (!len) return dot;
// Strip trailing slashes.
char* it = path + len - 1;
while (*it == '/' && it != path) { it--; }
*(it + 1) = 0;
if (it == path) return path;
// Return path from the first character if there are no more slashes, or from the first character after the last
// slash.
char* beg = strrchr(path, '/');
if (!beg) return path;
return beg + 1;
}
char* dirname(char* path)
{
// If path is NULL, or the string's length is 0, return .
if (!path) return dot;
size_t len = strlen(path);
if (!len) return dot;
// Strip trailing slashes.
char* it = path + len - 1;
while (*it == '/' && it != path) { it--; }
*(char*)(it + 1) = 0;
if (it == path) return path;
// Search for the last slash. If there is none, return .
// Otherwise, we end the string there and return.
char* end = strrchr(path, '/');
if (!end) return dot;
if (end != path) *end = 0;
else
*(end + 1) = 0;
return path;
}

View File

@ -17,29 +17,11 @@ char* strcpy(char* dest, const char* src)
char* strncpy(char* dest, const char* src, size_t n)
{
size_t i;
for (i = 0; i < n && src[i] != 0; i++) dest[i] = src[i];
for (; i < n; i++) dest[i] = 0;
size_t src_len = strlen(src) + 1; // NULL byte
memcpy(dest, src, src_len > n ? n : src_len);
return dest;
}
size_t strlcpy(char* dest, const char* src, size_t size)
{
size_t len = strlen(src);
if (size == 0) return len;
if (len < (size - 1))
{
memcpy(dest, src, len);
dest[len] = 0;
}
else
{
memcpy(dest, src, size - 1);
dest[size - 1] = 0;
}
return len;
}
int strcmp(const char* a, const char* b)
{
while (*a && (*a == *b))
@ -148,12 +130,4 @@ char* strdup(const char* src)
char* duplicated = (char*)kmalloc(length + 1);
memcpy(duplicated, src, length + 1);
return duplicated;
}
char* strrchr(const char* str, int c)
{
const char* s = str + strlen(str);
while (s != str && *s != (char)c) s--;
if (*s == (char)c) return const_cast<char*>(s);
return NULL;
}

View File

@ -16,7 +16,8 @@ void Syscall::entry(Context* context)
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_getpid: sys_getpid(context); break;
case SYS_rand: sys_rand(context); 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;
case SYS_open: sys_open(context, (const char*)context->rdi, (int)context->rsi); break;
@ -24,17 +25,12 @@ void Syscall::entry(Context* context)
case SYS_close: sys_close(context, (int)context->rdi); break;
case SYS_seek: sys_seek(context, (int)context->rdi, (long)context->rsi, (int)context->rdx); break;
case SYS_exec: sys_exec(context, (const char*)context->rdi); break;
case SYS_fcntl: sys_fcntl(context, (int)context->rdi, (int)context->rsi, context->rdx); break;
case SYS_mprotect: sys_mprotect(context, (void*)context->rdi, context->rsi, (int)context->rdx); break;
case SYS_clock: sys_clock(context); break;
case SYS_mkdir: sys_mkdir(context, (const char*)context->rdi); break;
case SYS_fork: sys_fork(context); break;
default: context->rax = -ENOSYS; break;
}
VMM::exit_syscall_context();
}
char* Syscall::strdup_from_user(const char* user_string) // FIXME: This function is a little hacky.
char* Syscall::strdup_from_user(const char* user_string)
{
uint64_t phys = VMM::get_physical((uint64_t)user_string);
if (phys == (uint64_t)-1) { return nullptr; }

View File

@ -1,9 +0,0 @@
#include "interrupts/Context.h"
#include "thread/Scheduler.h"
void sys_clock(Context* context)
{
Task* current_task = Scheduler::current_task();
context->rax = (long)current_task->cpu_time;
return;
}

View File

@ -1,10 +1,10 @@
#define MODULE "elf"
#include "sys/elf/ELFLoader.h"
#include "assert.h"
#include "errno.h"
#include "fs/VFS.h"
#include "init/InitRD.h"
#include "kassert.h"
#include "log/Log.h"
#include "memory/Memory.h"
#include "memory/MemoryManager.h"
@ -123,40 +123,40 @@ ELFImage* ELFLoader::load_elf_from_vfs(VFS::Node* node)
long ELFLoader::check_elf_image(VFS::Node* node)
{
Elf64_Ehdr elf_ehdr;
if (VFS::read(node, 0, sizeof(elf_ehdr), (char*)&elf_ehdr) < (long)sizeof(elf_ehdr))
if (VFS::read(node, 0, sizeof(elf_ehdr), (char*)&elf_ehdr) < 0)
{
kwarnln("Unable to read ELF header");
return -ENOEXEC;
return -1;
}
if (strncmp((const char*)elf_ehdr.e_ident, ELFMAG, SELFMAG) != 0)
{
kwarnln("ELF file has invalid magic, skipping");
return -ENOEXEC;
return -1;
}
if (elf_ehdr.e_ident[EI_CLASS] != ELFCLASS64)
{
kwarnln("ELF file is not ELF64, skipping");
return -ENOEXEC;
return -1;
}
if (elf_ehdr.e_ident[EI_DATA] != ELFDATA2LSB)
{
kwarnln("ELF file is not little-endian, skipping");
return -ENOEXEC;
return -1;
}
if (elf_ehdr.e_type != ET_EXEC)
{
kwarnln("not supported: ELF file is not an executable");
return -ENOEXEC;
return -1;
}
if (elf_ehdr.e_machine != EM_MACH)
{
kwarnln("Unsupported target machine");
return -ENOEXEC;
return -1;
}
if (elf_ehdr.e_phnum == 0)
{
kwarnln("ELF file has no PHDRS");
return -ENOEXEC;
return -1;
}
int i;
int loadable_sections = 0;
@ -170,12 +170,12 @@ long ELFLoader::check_elf_image(VFS::Node* node)
if (!phdr.p_vaddr)
{
kerrorln("segment address is NULL, this is invalid :(");
return -ENOEXEC;
return -1;
}
if (Memory::is_kernel_address(phdr.p_vaddr) || Memory::is_kernel_address(phdr.p_vaddr + phdr.p_memsz))
{
kerrorln("trying to load ELF into kernel memory");
return -ENOEXEC;
return -1;
}
loadable_sections++;
memusage += Utilities::get_blocks_from_size(PAGE_SIZE, phdr.p_memsz) * PAGE_SIZE;
@ -184,7 +184,7 @@ long ELFLoader::check_elf_image(VFS::Node* node)
if (!loadable_sections)
{
kwarnln("No loadable sections");
return -ENOEXEC;
return -1;
}
return memusage;
}

View File

@ -1,9 +1,8 @@
#define MODULE "exec"
#include "assert.h"
#include "errno.h"
#include "interrupts/Interrupts.h"
#include "kassert.h"
#include "log/Log.h"
#include "memory/MemoryManager.h"
#include "memory/PMM.h"
#include "memory/VMM.h"
@ -13,48 +12,11 @@
#include "sys/elf/ELFLoader.h"
#include "thread/Scheduler.h"
void sys_fork(Context* context)
{
kinfoln("fork(): attempting fork");
Task* parent = Scheduler::current_task();
Task* child = Scheduler::create_user_task();
if (!child)
{
context->rax = -ENOMEM;
return;
}
if (!child->allocator.inherit(parent->allocator))
{
child->state = child->Exited;
child->exit_status = -127; // so the reaper reaps it on next reaping
context->rax = -ENOMEM;
return;
}
child->save_context(context);
child->save_floating();
for (int i = 0; i < TASK_MAX_FDS; i++) { child->files[i] = parent->files[i]; }
child->address_space = parent->address_space.clone();
child->regs.rax = 0;
context->rax = child->id;
strlcpy(child->name, parent->name, sizeof(child->name));
child->state = child->Running;
kinfoln("fork(): forked parent %ld into child %ld", parent->id, child->id);
return;
}
void sys_exec(Context* context, const char* pathname)
{
/*context->rax = -ENOSYS; // FIXME: Make exec() work under separate address spaces.
return;*/
char* kpathname = Syscall::strdup_from_user(pathname);
if (!kpathname)
{
@ -87,9 +49,20 @@ void sys_exec(Context* context, const char* pathname)
return;
}
uint64_t allocated_stack = (uint64_t)MemoryManager::get_pages(TASK_PAGES_IN_STACK, MAP_READ_WRITE | MAP_USER);
if (!allocated_stack)
{
kfree(kpathname);
context->rax = -ENOMEM;
return;
}
uint64_t allocated_stack_phys = VMM::get_physical(allocated_stack);
if ((uint64_t)memusage > PMM::get_free())
{
kfree(kpathname);
MemoryManager::release_pages((void*)allocated_stack, TASK_PAGES_IN_STACK);
context->rax = -ENOMEM;
return;
}
@ -102,25 +75,20 @@ void sys_exec(Context* context, const char* pathname)
// At this point, pretty much nothing can fail.
task->allocator.free();
task->allocator
.init(); // If we had enough space for the old bitmap, we should have enough space for the new bitmap.
task->address_space.clear();
task->allocated_stack = (uint64_t)MemoryManager::get_pages_at(
0x100000, TASK_PAGES_IN_STACK,
MAP_USER | MAP_READ_WRITE); // If we had enough space for the old stack, there should be enough space for the
// new stack.
ELFImage* image = ELFLoader::load_elf_from_vfs(program);
ASSERT(image); // If check_elf_image succeeded, load_elf_from_vfs MUST succeed, unless something has gone terribly
// wrong.
strlcpy(task->name, kpathname, sizeof(task->name));
task->allocated_stack = allocated_stack;
for (uint64_t i = 0; i < TASK_PAGES_IN_STACK; i++)
{
VMM::map(allocated_stack + (i * PAGE_SIZE), allocated_stack_phys + (i * PAGE_SIZE), MAP_READ_WRITE | MAP_USER);
}
Scheduler::reset_task(task, image);
task->restore_context(context);
set_context_from_task(*task, context);
kfree(kpathname);

View File

@ -3,37 +3,14 @@
#include "errno.h"
#include "interrupts/Context.h"
#include "log/Log.h"
#include "memory/Memory.h"
#include "memory/MemoryManager.h"
#include "memory/VMM.h"
#include "misc/utils.h"
#include "thread/Scheduler.h"
#include <stddef.h>
#define MAP_READ 1
#define MAP_WRITE 2
#define MAP_NONE 0
#define MAP_FAIL(errno) 0xffffffffffffff00 | (unsigned char)(errno)
static const char* format_prot(int prot)
{
static char prot_string[3];
prot_string[2] = 0;
prot_string[0] = ((prot & MAP_READ) > 0) ? 'r' : '-';
prot_string[1] = ((prot & MAP_WRITE) > 0) ? 'w' : '-';
return prot_string;
}
static int mman_flags_from_prot(int prot)
{
prot &= 0b11;
if (prot == MAP_NONE) return 0;
if ((prot & MAP_WRITE) > 0) return MAP_USER | MAP_READ_WRITE;
return MAP_USER;
}
void sys_mmap(Context* context, void* address, size_t size, int prot)
void sys_mmap(Context* context, void* address, size_t size, int flags)
{
if (size < PAGE_SIZE)
{
@ -47,16 +24,12 @@ void sys_mmap(Context* context, void* address, size_t size, int prot)
context->rax = MAP_FAIL(EINVAL);
return;
}
int real_flags = mman_flags_from_prot(prot);
int real_flags = MAP_USER;
if (flags & MAP_READ_WRITE) real_flags |= MAP_READ_WRITE;
if (address)
{
kdbgln("mmap(): %ld pages at address %p, %s", size / PAGE_SIZE, address, format_prot(prot));
if (Memory::is_kernel_address((uintptr_t)address))
{
kwarnln("munmap() failed: attempted to unmap a kernel page");
context->rax = MAP_FAIL(ENOMEM);
return;
}
kdbgln("mmap(): %ld pages at address %p, %s", size / PAGE_SIZE, address,
real_flags & MAP_READ_WRITE ? "rw" : "ro");
if (VMM::get_physical((uint64_t)address) != (uint64_t)-1) // Address is already used.
{
kwarnln("attempt to map an already mapped address");
@ -74,21 +47,14 @@ void sys_mmap(Context* context, void* address, size_t size, int prot)
}
else
{
kwarnln("mmap() failed: failed to allocate physical memory");
kwarnln("mmap() failed");
context->rax = MAP_FAIL(ENOMEM);
return;
}
}
kdbgln("mmap(): %ld pages at any address, %s", Utilities::get_blocks_from_size(PAGE_SIZE, size), format_prot(prot));
uint64_t ptr =
Scheduler::current_task()->allocator.request_virtual_pages(Utilities::get_blocks_from_size(PAGE_SIZE, size));
if (!ptr)
{
kwarnln("mmap() failed: failed to allocate virtual address");
context->rax = MAP_FAIL(ENOMEM);
return;
}
void* result = MemoryManager::get_pages_at(ptr, Utilities::get_blocks_from_size(PAGE_SIZE, size), real_flags);
kdbgln("mmap(): %ld pages at any address, %s", Utilities::get_blocks_from_size(PAGE_SIZE, size),
real_flags & MAP_READ_WRITE ? "rw" : "ro");
void* result = MemoryManager::get_pages(Utilities::get_blocks_from_size(PAGE_SIZE, size), real_flags);
if (result)
{
kdbgln("mmap() succeeded: %p", result);
@ -97,7 +63,7 @@ void sys_mmap(Context* context, void* address, size_t size, int prot)
}
else
{
kwarnln("mmap() failed: failed to allocate physical memory");
kwarnln("mmap() failed");
context->rax = MAP_FAIL(ENOMEM);
return;
}
@ -124,68 +90,16 @@ void sys_munmap(Context* context, void* address, size_t size)
context->rax = -EINVAL;
return;
}
if (Memory::is_kernel_address((uintptr_t)address))
uint64_t flags = VMM::get_flags((uint64_t)address);
if (!(flags & MAP_USER))
{
kwarnln("munmap() failed: attempted to unmap a kernel page");
context->rax = -EINVAL;
return;
}
uint64_t phys = VMM::get_physical((uint64_t)address);
if (phys == (uint64_t)-1)
{
kwarnln("munmap() failed: attempted to unmap a non-existent page");
kwarnln("munmap() failed: attempted to unmap a non-existent or kernel page");
context->rax = -EINVAL;
return;
}
uint64_t offset = (uint64_t)address % PAGE_SIZE;
Scheduler::current_task()->allocator.free_virtual_pages(((uint64_t)address - offset),
Utilities::get_blocks_from_size(PAGE_SIZE, size));
MemoryManager::release_pages((void*)((uint64_t)address - offset), Utilities::get_blocks_from_size(PAGE_SIZE, size));
kdbgln("munmap() succeeded");
context->rax = 0;
return;
}
void sys_mprotect(Context* context, void* address, size_t size, int prot)
{
kdbgln("mprotect(): attempting to protect %p with %s", address, format_prot(prot));
if (size < PAGE_SIZE)
{
kwarnln("mprotect() failed: size is too small");
context->rax = -EINVAL;
return;
}
if (size % PAGE_SIZE)
{
kwarnln("mprotect() failed: size is not a multiple of PAGE_SIZE");
context->rax = -EINVAL;
return;
}
if (!address)
{
kwarnln("mprotect() failed: attempted to protect page 0");
context->rax = -EINVAL;
return;
}
if (Memory::is_kernel_address((uintptr_t)address))
{
kwarnln("mprotect() failed: attempted to protect a kernel page");
context->rax = -EINVAL;
return;
}
uint64_t phys = VMM::get_physical((uint64_t)address);
if (phys == (uint64_t)-1)
{
kwarnln("mprotect() failed: attempted to protect a non-existent page");
context->rax = -EINVAL;
return;
}
uint64_t offset = (uint64_t)address % PAGE_SIZE;
MemoryManager::protect((void*)((uint64_t)address - offset), Utilities::get_blocks_from_size(PAGE_SIZE, size),
mman_flags_from_prot(prot));
kdbgln("mprotect() succeeded");
context->rax = 0;
return;
}

7
kernel/src/sys/rand.cpp Normal file
View File

@ -0,0 +1,7 @@
#include "interrupts/Context.h"
#include "rand/Mersenne.h"
void sys_rand(Context* context)
{
context->rax = Mersenne::get();
}

View File

@ -20,7 +20,7 @@ void sys_sleep(Context* context, uint64_t ms)
Scheduler::task_yield(context);
}
void sys_getpid(Context* context)
void sys_gettid(Context* context)
{
context->rax = Scheduler::current_task()->id;
}

View File

@ -18,47 +18,6 @@
#define SEEK_CUR 1
#define SEEK_END 2
#define FNCTL_DUPFD 0
void sys_fcntl(Context* context, int fd, int command, uintptr_t arg)
{
if (fd >= TASK_MAX_FDS || fd < 0)
{
context->rax = -EBADF;
return;
}
Task* current_task = Scheduler::current_task();
if (!current_task->files[fd].is_open())
{
context->rax = -EBADF;
return;
}
Descriptor& file = current_task->files[fd];
if (command == FNCTL_DUPFD)
{
if ((int)arg < 0 || (int)arg >= TASK_MAX_FDS)
{
context->rax = -EINVAL;
return;
}
int dupfd = current_task->alloc_fd_greater_than_or_equal((int)arg);
if (dupfd < 0)
{
context->rax = -EMFILE;
return;
}
current_task->files[dupfd] = file;
context->rax = dupfd;
kdbgln("fcntl(F_DUPFD): duplicated fd %d, result is %d", fd, dupfd);
return;
}
else
{
context->rax = -EINVAL;
return;
}
}
void sys_seek(Context* context, int fd, long offset, int whence)
{
if (whence < SEEK_SET || whence > SEEK_END)
@ -77,13 +36,12 @@ void sys_seek(Context* context, int fd, long offset, int whence)
context->rax = -EBADF;
return;
}
Descriptor& file = current_task->files[fd];
long new_offset;
if (whence == SEEK_SET) new_offset = offset;
else if (whence == SEEK_CUR)
new_offset = offset + file.offset();
new_offset = offset + current_task->files[fd].offset();
else if (whence == SEEK_END)
new_offset = file.length() + offset;
new_offset = current_task->files[fd].length() + offset;
else
__builtin_unreachable();
if (new_offset < 0)
@ -91,12 +49,7 @@ void sys_seek(Context* context, int fd, long offset, int whence)
context->rax = -EINVAL; // FIXME: Is this the right error?
return;
}
if (new_offset == file.offset())
{
context->rax = new_offset;
return;
}
int result = file.seek(new_offset);
int result = current_task->files[fd].seek(new_offset);
if (result < 0)
{
context->rax = result;
@ -124,13 +77,12 @@ void sys_write(Context* context, int fd, size_t size, const char* addr)
context->rax = -EBADF;
return;
}
Descriptor& file = current_task->files[fd];
if (!file.can_write())
if (!current_task->files[fd].can_write())
{
context->rax = -EBADF;
return;
}
ssize_t result = file.write(size, (const char*)VMM::get_physical((uint64_t)addr));
ssize_t result = current_task->files[fd].write(size, (const char*)VMM::get_physical((uint64_t)addr));
context->rax = (size_t)result;
return;
}
@ -138,8 +90,13 @@ void sys_write(Context* context, int fd, size_t size, const char* addr)
void sys_open(Context* context, const char* filename, int flags)
{
Task* current_task = Scheduler::current_task();
int fd = current_task->alloc_fd();
if (fd < 0)
int fd;
for (fd = 0; fd < TASK_MAX_FDS; fd++)
{
if (!current_task->files[fd].is_open()) break;
}
if (fd == TASK_MAX_FDS)
{
context->rax = -EMFILE;
return;
@ -221,20 +178,4 @@ void sys_close(Context* context, int fd)
current_task->files[fd].close();
context->rax = 0;
return;
}
void sys_mkdir(Context* context, const char* filename)
{
char* kfilename = Syscall::strdup_from_user(filename);
if (!kfilename)
{
context->rax = -EFAULT;
return;
}
int rc = VFS::mkdir(kfilename);
kfree(kfilename);
context->rax = rc;
}

View File

@ -1,12 +1,10 @@
#define MODULE "sched"
#include "thread/Scheduler.h"
#include "errno.h"
#include "assert.h"
#include "interrupts/Interrupts.h"
#include "kassert.h"
#include "log/Log.h"
#include "memory/MemoryManager.h"
#include "memory/PMM.h"
#include "memory/VMM.h"
#include "misc/hang.h"
#include "misc/utils.h"
@ -33,51 +31,6 @@ extern "C" void idle_task_function();
static uint64_t frequency;
template <typename Callback> void sched_for_each_task(Callback callback)
{
Task* task = base_task;
if (!task) return;
do {
bool will_continue = callback(task);
if (!will_continue) break;
task = task->next_task;
} while (task != base_task);
}
Task* Scheduler::find_by_pid(uint64_t pid)
{
Task* result = nullptr;
sched_for_each_task([&](Task* task) {
if (task->id == pid)
{
result = task;
return false;
}
return true;
});
return result;
}
void Scheduler::append_task(Task* task)
{
if (!base_task)
{
ASSERT(!end_task);
base_task = task;
end_task = base_task;
task->next_task = task;
task->prev_task = task;
}
else
{
end_task->next_task = task;
task->prev_task = end_task;
base_task->prev_task = task;
task->next_task = base_task;
end_task = task;
}
}
void Scheduler::init()
{
memset(&idle_task, 0, sizeof(Task));
@ -91,12 +44,22 @@ void Scheduler::init()
idle_task.user_task = false;
idle_task.state = idle_task.Idle;
sched_current_task = &idle_task;
base_task = new Task;
end_task = base_task;
sched_current_task = base_task;
sched_current_task->id = free_tid++;
sched_current_task->task_time = 20; // gets 20 ms of cpu time before next switch
sched_current_task->next_task = sched_current_task;
sched_current_task->prev_task = sched_current_task;
sched_current_task->state = sched_current_task->Running;
sched_current_task->user_task = false;
task_num++;
// the other registers will be saved next task switch
frequency = 1000 / PIT::frequency();
}
void Scheduler::add_kernel_task(const char* taskname, void (*task)(void))
void Scheduler::add_kernel_task(void (*task)(void))
{
Task* new_task = new Task;
ASSERT(new_task);
@ -113,51 +76,53 @@ void Scheduler::add_kernel_task(const char* taskname, void (*task)(void))
new_task->task_sleep = 0;
new_task->task_time = 0;
new_task->cpu_time = 0;
strlcpy(new_task->name, taskname, sizeof(new_task->name));
append_task(new_task);
end_task->next_task = new_task;
new_task->prev_task = end_task;
base_task->prev_task = new_task;
new_task->next_task = base_task;
end_task = new_task;
new_task->state = new_task->Running;
task_num++;
kinfoln("Adding kernel task: %s, starts at %lx, PID %ld, stack at %lx, total tasks: %ld", new_task->name,
new_task->regs.rip, new_task->id, new_task->regs.rsp, task_num);
kinfoln("Adding kernel task: starts at %lx, tid %ld, stack at %lx, total tasks: %ld", new_task->regs.rip,
new_task->id, new_task->regs.rsp, task_num);
}
Task* Scheduler::create_user_task()
{
Task* new_task = new Task;
if (!new_task) return nullptr;
ASSERT(new_task);
memset(&new_task->regs, 0, sizeof(Context));
new_task->user_task = true;
new_task->id = free_tid++;
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 = get_top_of_stack(new_task->allocated_stack, TASK_PAGES_IN_STACK);
new_task->task_sleep = 0;
new_task->task_time = 0;
new_task->cpu_time = 0;
append_task(new_task);
end_task->next_task = new_task;
new_task->prev_task = end_task;
base_task->prev_task = new_task;
new_task->next_task = base_task;
end_task = new_task;
task_num++;
return new_task;
}
long Scheduler::load_user_task(const char* filename)
void Scheduler::load_user_task(const char* filename)
{
kinfoln("Loading user task: %s", filename);
Interrupts::push_and_disable();
long result;
if ((result = ELFLoader::check_elf_image_from_filesystem(filename)) < 0)
if (ELFLoader::check_elf_image_from_filesystem(filename) < 0)
{
kerrorln("Failed to load %s from initrd", filename);
Interrupts::pop();
return result;
return;
}
if ((uint64_t)result > PMM::get_free()) { return -ENOMEM; }
Task* new_task = new Task;
ASSERT(new_task);
memset(&new_task->regs, 0, sizeof(Context));
new_task->id = free_tid++;
if (!new_task->allocator.init())
{
delete new_task;
Interrupts::pop();
return -ENOMEM;
}
new_task->address_space = AddressSpace::create();
VMM::switch_to_user_address_space(new_task->address_space);
ELFImage* image = ELFLoader::load_elf_from_filesystem(
@ -167,17 +132,8 @@ long Scheduler::load_user_task(const char* filename)
new_task->user_task = true;
new_task->regs.rip = image->entry;
new_task->image = image;
new_task->allocated_stack = (uint64_t)MemoryManager::get_pages_at(
0x100000, TASK_PAGES_IN_STACK, MAP_READ_WRITE | MAP_USER); // 16 KB is enough for everyone, right?
if (!new_task->allocated_stack)
{
new_task->address_space.destroy();
delete new_task;
ELFLoader::release_elf_image(image);
VMM::switch_back_to_kernel_address_space();
Interrupts::pop();
return -ENOMEM;
}
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 = get_top_of_stack(new_task->allocated_stack, TASK_PAGES_IN_STACK);
new_task->regs.cs = 0x18 | 0x03;
new_task->regs.ss = 0x20 | 0x03;
@ -186,15 +142,17 @@ long Scheduler::load_user_task(const char* filename)
new_task->task_sleep = 0;
new_task->task_time = 0;
new_task->cpu_time = 0;
strlcpy(new_task->name, filename, sizeof(new_task->name));
append_task(new_task);
end_task->next_task = new_task;
new_task->prev_task = end_task;
base_task->prev_task = new_task;
new_task->next_task = base_task;
end_task = new_task;
new_task->state = new_task->Running;
task_num++;
kinfoln("Adding user task: %s, loaded at %lx, PID %ld, stack at %lx, total tasks: %ld", new_task->name,
new_task->regs.rip, new_task->id, new_task->regs.rsp, task_num);
kinfoln("Adding user task: loaded at %lx, tid %ld, stack at %lx, total tasks: %ld", new_task->regs.rip,
new_task->id, new_task->regs.rsp, task_num);
VMM::switch_back_to_kernel_address_space();
Interrupts::pop();
return (long)new_task->id;
}
void Scheduler::reset_task(Task* task, ELFImage* new_image)
@ -210,8 +168,8 @@ void Scheduler::reset_task(Task* task, ELFImage* new_image)
task->regs.rflags = (1 << 21) | (1 << 9); // enable interrupts
task->task_sleep = 0;
task->cpu_time = 0;
kinfoln("Resetting task: %s, loaded at %lx, PID %ld, stack at %lx, total tasks: %ld", task->name, task->regs.rip,
task->id, task->regs.rsp, task_num);
kinfoln("Resetting task: loaded at %lx, tid %ld, stack at %lx, total tasks: %ld", task->regs.rip, task->id,
task->regs.rsp, task_num);
}
void Scheduler::reap_task(Task* task)
@ -226,9 +184,8 @@ void Scheduler::reap_task(Task* task)
VMM::apply_address_space();
VMM::switch_to_user_address_space(exiting_task->address_space);
}
kinfoln("reaping task %s, PID %ld, exited with code %ld", exiting_task->name, exiting_task->id,
exiting_task->exit_status);
if (exiting_task->allocated_stack && !exiting_task->is_user_task())
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) // FIXME: Also free pages the task has mmap-ed but not munmap-ed.
{
@ -237,7 +194,6 @@ void Scheduler::reap_task(Task* task)
}
if (exiting_task->is_user_task())
{
exiting_task->allocator.free();
VMM::switch_back_to_kernel_address_space();
VMM::apply_address_space();
Interrupts::push_and_enable();
@ -320,15 +276,17 @@ void Scheduler::reap_tasks()
static void sched_decrement_sleep_times()
{
sched_for_each_task([](Task* task) {
Task* task = base_task;
if (!task) return;
do {
if (task->task_sleep > 0)
{
task->task_sleep -= frequency;
if (task->task_sleep < 0) task->task_sleep = 0;
}
if (task->task_sleep == 0 && task->state == task->Sleeping) task->state = task->Running;
return true;
});
task = task->next_task;
} while (task != base_task);
}
void Scheduler::task_tick(Context* context)
@ -351,7 +309,7 @@ void Scheduler::task_yield(Context* context)
{
ASSERT(Interrupts::is_in_handler());
Interrupts::disable();
sched_current_task->save_context(context);
get_context_to_task(*sched_current_task, context);
bool was_idle = false;
if (sched_current_task->state == sched_current_task->Idle)
{
@ -365,14 +323,15 @@ void Scheduler::task_yield(Context* context)
{
if (sched_current_task->id != original_task->id || was_idle)
{
if (!was_idle && original_task->is_user_task() && !original_task->has_died())
if (!was_idle && original_task->is_user_task() && original_task->state != original_task->Exited)
{
original_task->save_floating();
task_save_floating(*original_task);
}
if (sched_current_task->is_user_task())
{
sched_current_task->switch_to_address_space();
sched_current_task->restore_floating();
VMM::switch_to_user_address_space(sched_current_task->address_space);
VMM::apply_address_space();
task_restore_floating(*sched_current_task);
}
else if (!was_idle && original_task->is_user_task() && !sched_current_task->is_user_task())
{
@ -381,17 +340,17 @@ void Scheduler::task_yield(Context* context)
}
}
sched_current_task->task_time = 20;
sched_current_task->restore_context(context);
set_context_from_task(*sched_current_task, context);
return;
}
} while (sched_current_task != original_task);
if (!was_idle && original_task->is_user_task() && original_task->state != original_task->Exited)
{
original_task->save_floating();
task_save_floating(*original_task);
}
sched_current_task = &idle_task;
sched_current_task->task_time = frequency;
if (!was_idle) { sched_current_task->restore_context(context); }
if (!was_idle) { set_context_from_task(*sched_current_task, context); }
return;
}

View File

@ -1,68 +1,29 @@
#include "thread/Task.h"
#include "memory/VMM.h"
#include "std/string.h"
void Task::restore_context(Context* context)
void set_context_from_task(Task& task, Context* ctx)
{
memcpy(context, &regs, sizeof(Context));
memcpy(ctx, &task.regs, sizeof(Context));
}
void Task::save_context(Context* context)
void get_context_to_task(Task& task, Context* ctx)
{
memcpy(&regs, context, sizeof(Context));
memcpy(&task.regs, ctx, sizeof(Context));
}
void Task::save_floating()
void task_save_floating(Task& task)
{
floating_saved = true;
asm volatile("fxsave (%0)" : : "r"((char*)floating_region));
task.floating_saved = true;
asm volatile("fxsave (%0)" : : "r"(&task.floating_region));
}
void Task::restore_floating()
void task_restore_floating(Task& task)
{
if (!floating_saved) return;
asm volatile("fxrstor (%0)" : : "r"((char*)floating_region));
if (!task.floating_saved) return;
asm volatile("fxrstor (%0)" : : "r"(&task.floating_region));
}
bool Task::is_user_task()
{
return user_task;
}
int Task::alloc_fd()
{
int fd;
for (fd = 0; fd < TASK_MAX_FDS; fd++)
{
if (!files[fd].is_open()) break;
}
if (fd == TASK_MAX_FDS) { return -1; }
return fd;
}
int Task::alloc_fd_greater_than_or_equal(int base_fd)
{
int fd;
if (base_fd >= TASK_MAX_FDS) return -1;
for (fd = base_fd; fd < TASK_MAX_FDS; fd++)
{
if (!files[fd].is_open()) break;
}
if (fd == TASK_MAX_FDS) { return -1; }
return fd;
}
void Task::switch_to_address_space()
{
VMM::switch_to_user_address_space(address_space);
VMM::apply_address_space();
}
bool Task::has_died()
{
return state == Exited;
}

View File

@ -17,10 +17,10 @@ static size_t symbol_strlen(const char* symbol)
return (i - symbol);
}
void get_symbol_name(uintptr_t address, char* buffer, size_t max)
void get_symbol_name(uintptr_t address, char* buffer)
{
if (symbol_map.addr == (void*)-1) { symbol_map = InitRD::open("sys/moon.sym"); }
if (!symbol_map.addr) { strlcpy(buffer, "(no symbols loaded)", max); }
if (!symbol_map.addr) { strncpy(buffer, "(no symbols loaded)", 20); }
while (address >= (uintptr_t)&kernel_start && address <= (uintptr_t)&kernel_end)
{
char addr_as_str[60];
@ -30,12 +30,11 @@ void get_symbol_name(uintptr_t address, char* buffer, size_t max)
{
symbol += 19;
size_t symlen = symbol_strlen(symbol);
size_t copylen = (max - 1) < symlen ? (max - 1) : symlen;
memcpy(buffer, symbol, copylen);
buffer[copylen] = 0;
memcpy(buffer, symbol, symlen);
buffer[symlen] = 0;
return;
}
address--;
}
strlcpy(buffer, "(no symbol)", max);
strncpy(buffer, "(no symbol)", 12);
}

View File

@ -1,7 +1,4 @@
#define MODULE "trace"
#include "trace/StackTracer.h"
#include "log/Log.h"
#include "memory/Memory.h"
#include "std/stdio.h"
#include "trace/Resolve.h"
@ -24,11 +21,11 @@ typedef struct stackframe
void StackTracer::trace()
{
stackframe* frame = (stackframe*)m_base_pointer;
while (frame && frame->instruction)
while (frame)
{
char symbol_name[512];
get_symbol_name(frame->instruction - sizeof(uintptr_t), symbol_name, sizeof(symbol_name));
kinfoln("%lx: %s", frame->instruction - sizeof(uintptr_t), symbol_name);
get_symbol_name(frame->instruction, symbol_name);
printf("%lx: %s\n", frame->instruction, symbol_name);
frame = frame->next;
}
}
@ -36,8 +33,8 @@ void StackTracer::trace()
void StackTracer::trace_with_ip(uintptr_t ip)
{
char symbol_name[512];
get_symbol_name(ip, symbol_name, sizeof(symbol_name));
kinfoln("%lx: %s", ip, symbol_name);
get_symbol_name(ip, symbol_name);
printf("%lx: %s\n", ip, symbol_name);
trace();
}

View File

@ -1,24 +0,0 @@
#ifndef _ASSERT_H
#define _ASSERT_H
#include <bits/macros.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C"
{
#endif
__lc_noreturn bool __assertion_failed(const char* file, int line, const char* function, const char* expr);
#ifdef __cplusplus
}
#endif
#ifdef NDEBUG
#define assert(expr) (void)0
#else
#define assert(expr) (bool)(expr) || __assertion_failed(__FILE__, __LINE__, __FUNCTION__, #expr)
#endif
#endif

View File

@ -1,9 +1,8 @@
#ifndef _BITS_MACROS_H
#define _BITS_MACROS_H
#define __lc_noreturn __attribute__((noreturn))
#define __lc_align(n) __attribute__((aligned(n)))
#define __lc_deprecated(msg) __attribute__((deprecated(msg)))
#define __lc_unreachable __builtin_unreachable
#define noreturn __attribute__((noreturn))
#define align(n) __attribute__((aligned(n)))
#define deprecated(msg) __attribute__((deprecated(msg)))
#endif

View File

@ -1,58 +0,0 @@
#ifndef _CTYPE_H
#define _CTYPE_H
#ifdef __cplusplus
extern "C"
{
#endif
/* Is this character alphanumeric? */
int isalnum(int c);
/* Is this character a letter? */
int isalpha(int c);
/* Is this character part of ASCII? */
int isascii(int c);
/* Is this character a blank character (space or tab)? */
int isblank(int c);
/* Is this character a control character? */
int iscntrl(int c);
/* Is this character a digit? */
int isdigit(int c);
/* Is this character any printable character except space? */
int isgraph(int c);
/* Is this character a lowercase letter? */
int islower(int c);
/* Is this character any printable character (including space)? */
int isprint(int c);
/* Is this character any printable character which is not a space or an alphanumeric character? */
int ispunct(int c);
/* Is this character any space character (space, form feed, newline, carriage return, tab, vertical tab)? */
int isspace(int c);
/* Is this character an uppercase letter? */
int isupper(int c);
/* Is this character a hexadecimal digit (0-9, a-f, A-F)? */
int isxdigit(int c);
/* Returns the lowercase form of the specified character. */
int tolower(int c);
/* Returns the uppercase form of the specified character. */
int toupper(int c);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -4,20 +4,15 @@
/* The last error encountered during a call to a library or system function. */
extern int errno;
#define EPERM 1 // Operation not permitted
#define ENOENT 2 // No such file or directory
#define ENOEXEC 8 // Exec format error
#define EBADF 9 // Bad file descriptor
#define ENOMEM 12 // Cannot allocate memory
#define EFAULT 14 // Bad address
#define EEXIST 17 // File exists
#define ENOTDIR 20 // Not a directory
#define EISDIR 21 // Is a directory
#define EINVAL 22 // Invalid argument
#define EMFILE 24 // Too many open files
#define ENOSPC 28 // No space left on device
#define EPIPE 32 // Broken pipe. Not implemented.
#define ENOSYS 38 // Function not implemented
#define ENOTSUP 95 // Operation not supported.
#define EPERM 1 // Operation not permitted
#define ENOENT 2 // No such file or directory
#define ENOEXEC 8 // Exec format error
#define EBADF 9 // Bad file descriptor
#define ENOMEM 12 // Cannot allocate memory
#define EFAULT 14 // Bad address
#define EISDIR 21 // Is a directory
#define EINVAL 22 // Invalid argument
#define EMFILE 24 // Too many open files
#define ENOSYS 38 // Function not implemented
#endif

View File

@ -8,9 +8,6 @@
/* Open for reading and writing. */
#define O_RDWR 3
/* Duplicate a file descriptor. */
#define F_DUPFD 0
#ifdef __cplusplus
extern "C"
{
@ -19,9 +16,6 @@ extern "C"
/* Opens the file specified by pathname. Returns a file descriptor on success, or -1 on error. */
int open(const char* pathname, int flags);
/* Performs an operation on the file descriptor fd determined by cmd. */
int fcntl(int fd, int cmd, ...);
#ifdef __cplusplus
}
#endif

View File

@ -1,63 +0,0 @@
#ifndef _INTTYPES_H
#define _INTTYPES_H
#include <stdint.h>
#define PRId8 "%d"
#define PRId16 "%d"
#define PRId32 "%d"
#define PRId64 "%ld"
#define PRIdLEAST8 "%d"
#define PRIdLEAST16 "%d"
#define PRIdLEAST32 "%d"
#define PRIdLEAST64 "%ld"
#define PRIdFAST8 "%d"
#define PRIdFAST16 "%d"
#define PRIdFAST32 "%d"
#define PRIdFAST64 "%ld"
#define PRIdMAX "%ld"
#define PRIdPTR "%ld"
#define PRIi8 "%d"
#define PRIi16 "%d"
#define PRIi32 "%d"
#define PRIi64 "%ld"
#define PRIiLEAST8 "%d"
#define PRIiLEAST16 "%d"
#define PRIiLEAST32 "%d"
#define PRIiLEAST64 "%ld"
#define PRIiFAST8 "%d"
#define PRIiFAST16 "%d"
#define PRIiFAST32 "%d"
#define PRIiFAST64 "%ld"
#define PRIiMAX "%ld"
#define PRIiPTR "%ld"
#define PRIu8 "%u"
#define PRIu16 "%u"
#define PRIu32 "%u"
#define PRIu64 "%lu"
#define PRIuLEAST8 "%u"
#define PRIuLEAST16 "%u"
#define PRIuLEAST32 "%u"
#define PRIuLEAST64 "%lu"
#define PRIuFAST8 "%u"
#define PRIuFAST16 "%u"
#define PRIuFAST32 "%u"
#define PRIuFAST64 "%lu"
#define PRIuMAX "%lu"
#define PRIuPTR "%lu"
#define PRIx8 "%x"
#define PRIx16 "%x"
#define PRIx32 "%x"
#define PRIx64 "%lx"
#define PRIxLEAST8 "%x"
#define PRIxLEAST16 "%x"
#define PRIxLEAST32 "%x"
#define PRIxLEAST64 "%lx"
#define PRIxFAST8 "%x"
#define PRIxFAST16 "%x"
#define PRIxFAST32 "%x"
#define PRIxFAST64 "%lx"
#define PRIxMAX "%lx"
#define PRIxPTR "%lx"
#endif

View File

@ -1,21 +0,0 @@
#ifndef _LIBGEN_H
#define _LIBGEN_H
#ifdef __cplusplus
extern "C"
{
#endif
/* Returns the last component of a path. This function is allowed to modify the string passed to it, so it should
* probably be a copy of another string. */
char* basename(char* path);
/* Returns the parent directory of a path. This function is allowed to modify the string passed to it, so it should
* probably be a copy of another string. */
char* dirname(char* path);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -9,11 +9,14 @@ extern "C"
{
#endif
/* Returns the current program's thread identifier. */
pid_t gettid();
/* Sleeps for ms milliseconds. */
unsigned int msleep(unsigned int ms);
/* Prints a message to standard error and aborts the program. */
__lc_noreturn void __luna_abort(const char* message);
noreturn void __luna_abort(const char* message);
#ifdef __cplusplus
}

View File

@ -1,10 +0,0 @@
#ifndef _LUNA_OS_LIMITS_H
#define _LUNA_OS_LIMITS_H
#define OPEN_MAX 32
#define ATEXIT_MAX 32
#define PAGESIZE 4096
#define PAGE_SIZE 4096
#endif

View File

@ -6,19 +6,15 @@
#define SYS_sleep 2
#define SYS_write 3
#define SYS_paint 4
#define SYS_getpid 5
#define SYS_mmap 6
#define SYS_munmap 7
#define SYS_open 8
#define SYS_read 9
#define SYS_close 10
#define SYS_seek 11
#define SYS_exec 12
#define SYS_fcntl 13
#define SYS_mprotect 14
#define SYS_clock 15
#define SYS_mkdir 16
#define SYS_fork 17
#define SYS_rand 5
#define SYS_gettid 6
#define SYS_mmap 7
#define SYS_munmap 8
#define SYS_open 9
#define SYS_read 10
#define SYS_close 11
#define SYS_seek 12
#define SYS_exec 13
#ifndef __want_syscalls
#ifdef __cplusplus

View File

@ -1,16 +0,0 @@
#ifndef _SCHED_H
#define _SCHED_H
#ifdef __cplusplus
extern "C"
{
#endif
/* Yield the processor. */
int sched_yield(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,32 +0,0 @@
#ifndef _SETJMP_H
#define _SETJMP_H
#include <bits/macros.h>
#include <stdint.h>
typedef uintptr_t jmp_buf[8];
typedef uintptr_t sigjmp_buf[8];
#ifdef __cplusplus
extern "C"
{
#endif
/* Saves the current execution state in env. Returns 0 when called from the first time, or nonzero when returning
* from longjmp. */
int setjmp(jmp_buf env);
/* Right now, does the exact same as setjmp() (savesigs is ignored), since signals are not implemented. */
int sigsetjmp(sigjmp_buf env, int savesigs);
/* Restores the execution state saved in env by a setjmp() call. */
__lc_noreturn void longjmp(jmp_buf env, int val);
/* Right now, does the exact same as longjmp(), since signals are not implemented. */
__lc_noreturn void siglongjmp(sigjmp_buf env, int val);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,7 +0,0 @@
#ifndef _SIGNAL_H
#define _SIGNAL_H
typedef int sig_atomic_t; // FIXME: Implement signals (I'm trying to build bc, this header is only to satisfy it) and
// use a proper atomic integer type.
#endif

View File

@ -6,8 +6,6 @@
#include <bits/seek.h>
#define FOPEN_MAX 32
typedef struct
{
int f_fd;
@ -42,9 +40,6 @@ extern "C"
/* Returns a new file associated with the file descriptor fd. */
FILE* fdopen(int fd, const char* mode);
/* Returns the file descriptor associated with the file stream. */
int fileno(FILE* stream);
/* Writes formatted output according to the string format to the file stream. */
int fprintf(FILE* stream, const char* format, ...);

View File

@ -10,25 +10,16 @@ extern "C"
#endif
/* Aborts the program. */
__lc_noreturn void abort(void);
noreturn void abort();
/* Normally exits the program with the specified status code. */
__lc_noreturn void exit(int status);
/* Abnormally exits the program with the specified status code. */
__lc_noreturn void _Exit(int status);
noreturn void exit(int status);
/* Registers a handler function to be run at normal program termination. */
int atexit(void (*handler)(void));
/* Returns an integer (of type int) parsed from the string str. */
int atoi(const char* str);
/* Returns an integer (of type long) parsed from the string str. */
long atol(const char* str);
/* Returns an integer (of type long long) parsed from the string str. */
long long atoll(const char* str);
/* Not implemented.*/
int atoi(const char*);
/* Not implemented. */
char* getenv(const char*);
@ -50,12 +41,6 @@ extern "C"
* is undefined behavior. */
void free(void* ptr);
/* Returns a random number. */
int rand(void);
/* Seeds the random number generator with the specified seed. */
void srand(unsigned int seed);
#ifdef __cplusplus
}
#endif

View File

@ -15,26 +15,15 @@ extern "C"
/* Sets n bytes of buf to c, cast to a character. */
void* memset(void* buf, int c, size_t n);
/* Searches for the character c in n bytes of buf. */
void* memchr(const void* buf, int c, size_t n);
/* Compares n bytes of memory at a and b. */
int memcmp(const void* a, const void* b, size_t n);
/* Copies n bytes from src to dst. Can be used if src and dst overlap. */
void* memmove(void* dest, const void* src, size_t n);
/* Returns a heap-allocated copy of the string str. Should be freed when it is not used anymore. */
char* strdup(const char* str);
/* Clears n bytes of buf. */
void* memclr(void* buf, size_t n);
/* Returns the length of the string str. */
size_t strlen(const char* str);
/* Returns the length of the string str, while examining at most max bytes of str. */
size_t strnlen(const char* str, size_t max);
/* Copies at most size-1 bytes from the string src into dest, null-terminating the result. */
size_t strlcpy(char* dst, const char* src, size_t size);
/* Copies the string src into dest. This function is unsafe, use strncpy instead. */
deprecated("strcpy is unsafe and should not be used; use strncpy instead") char* strcpy(char* dest,
const char* src);
/* Copies at most max bytes from the string src into dest. */
char* strncpy(char* dest, const char* src, size_t max);
@ -42,35 +31,16 @@ extern "C"
/* Returns a pointer to the first occurrence of the character c in str, or NULL if it is not found. */
char* strchr(const char* str, int c);
/* Returns a pointer to the last occurrence of the character c in str, or NULL if it is not found. */
char* strrchr(const char* str, int c);
/* Concatenates the string src into dest. This function is unsafe, use strncat instead. */
deprecated("strcat is unsafe and should not be used; use strncat instead") char* strcat(char* dest,
const char* src);
/* Concatenates at most max bytes of the string src into dest. */
char* strncat(char* dest, const char* src, size_t max);
/* Compares strings a and b. You might prefer to use the safer strncmp function. */
int strcmp(const char* a, const char* b);
/* Compares at most max bytes of the strings a and b. */
int strncmp(const char* a, const char* b, size_t max);
/* Searches for the needle string in the haystack string. */
char* strstr(const char* haystack, const char* needle);
/* Returns the error string associated with the error number err. */
char* strerror(int err);
/* Clears n bytes of buf. */
void* bzero(void* buf, size_t n);
/* Copies the string src into dest. This function is unsafe, use strlcpy instead. */
__lc_deprecated("strcpy is unsafe and should not be used; use strlcpy instead") char* strcpy(char* dest,
const char* src);
/* Concatenates the string src into dest. This function is unsafe, use strncat instead. */
__lc_deprecated("strcat is unsafe and should not be used; use strncat instead") char* strcat(char* dest,
const char* src);
#ifdef __cplusplus
}
#endif

View File

@ -7,9 +7,7 @@
/* Address returned by mmap when it fails. */
#define MAP_FAILED (void*)-1
#define PROT_NONE 0
#define PROT_READ 1
#define PROT_WRITE 2
#define PROT_READ_WRITE 1
#define PAGE_SIZE 4096
@ -26,9 +24,6 @@ extern "C"
* address space. */
int munmap(void* addr, size_t size);
/* Protects size bytes of memory according to the prot argument. */
int mprotect(void* addr, size_t size, int prot);
#ifdef __cplusplus
}
#endif

View File

@ -1,18 +0,0 @@
#ifndef _SYS_STAT_H
#define _SYS_STAT_H
#include <sys/types.h>
#ifdef __cplusplus
extern "C"
{
#endif
/* Creates a new directory at the path pathname. FIXME: For now, mode is ignored. */
int mkdir(const char* pathname, mode_t mode);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -13,7 +13,4 @@ typedef long int ssize_t;
/* The type of an offset into a file. */
typedef long int off_t;
/* The type of a file's mode. */
typedef unsigned short mode_t;
#endif

View File

@ -1,22 +0,0 @@
#ifndef _TIME_H
#define _TIME_H
typedef long int clock_t;
typedef long int time_t;
#define CLOCKS_PER_SEC 1000
#ifdef __cplusplus
extern "C"
{
#endif
/* Returns a number representing how much CPU time has been used by this process. Divide this by CLOCKS_PER_SEC to
* get the value in seconds. */
clock_t clock(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -3,12 +3,8 @@
#include <bits/macros.h>
#include <bits/seek.h>
#include <luna/os-limits.h>
#include <sys/types.h>
#define STDOUT_FILENO 0
#define STDERR_FILENO 1
#ifdef __cplusplus
extern "C"
{
@ -22,16 +18,11 @@ extern "C"
int execve(const char*, char* const[], char* const[]);
/* Not implemented. */
int execvp(const char*, char* const[]);
/* Creates an identical copy (child) of the current process (parent). Returns 0 to the child, and the child's PID to
* the parent. */
/* Not implemented. */
pid_t fork(void);
/* Returns the current process's process ID. */
pid_t getpid(void);
/* Terminates the program with the status code status. */
__lc_noreturn void _exit(int status);
noreturn void _exit(int status);
/* Calls the kernel for a specific service, determined by number. */
long syscall(long number, ...);
@ -51,9 +42,6 @@ extern "C"
/* Moves the read/write file offset for fd to offset, depending on whence. */
off_t lseek(int fd, off_t offset, int whence);
/* Returns a copy of the file descriptor fd. */
int dup(int fd);
#ifdef __cplusplus
}
#endif

View File

@ -1,12 +0,0 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
extern "C"
{
__lc_noreturn bool __assertion_failed(const char* file, int line, const char* function, const char* expr)
{
fprintf(stderr, "%s:%d: %s: Assertion '%s' failed.", file, line, function, expr);
abort();
}
}

View File

@ -17,7 +17,7 @@ extern "C"
return 0;
}
__lc_noreturn void exit(int status)
noreturn void exit(int status)
{
for (int i = 0; i < atexit_function_count; i++) { atexit_functions[i](); }
_exit(status);

View File

@ -13,7 +13,7 @@ int liballoc_unlock()
void* liballoc_alloc(size_t size)
{
void* result = mmap(NULL, size * PAGE_SIZE, PROT_READ | PROT_WRITE, 0, 0, 0);
void* result = mmap(NULL, size * PAGE_SIZE, PROT_READ_WRITE, 0, 0, 0);
if (result == MAP_FAILED) return 0;
return (void*)result;
}

View File

@ -1,81 +0,0 @@
#include <ctype.h>
extern "C"
{
int isalnum(int c)
{
return isalpha(c) || isdigit(c);
}
int isalpha(int c)
{
return islower(c) || isupper(c);
}
int isascii(int c)
{
return !(c & ~0x7f);
}
int isblank(int c)
{
return c == ' ' || c == '\t';
}
int iscntrl(int c)
{
return (unsigned int)c < 0x20 || c == 0x7f;
}
int isdigit(int c)
{
return c >= '0' && c < ':';
}
int isgraph(int c)
{
return (unsigned int)c - 0x21 < 0x5e;
}
int islower(int c)
{
return c >= 'a' && c < '{';
}
int isprint(int c)
{
return (unsigned int)c - 0x20 < 0x5f;
}
int ispunct(int c)
{
return isgraph(c) && !isalnum(c);
}
int isspace(int c)
{
return c == ' ' || (unsigned int)c - '\t' < 5;
}
int isupper(int c)
{
return c >= 'A' && c < '[';
}
int isxdigit(int c)
{
return isdigit(c) || ((unsigned int)c | 32) - 'a' < 6;
}
int tolower(int c)
{
if (isupper(c)) return c | 32;
return c;
}
int toupper(int c)
{
if (islower(c)) return c & 0x5f;
return c;
}
}

View File

@ -1,6 +1,4 @@
#include <fcntl.h>
#include <stdarg.h>
#include <stdint.h>
#include <sys/syscall.h>
#include <unistd.h>
@ -10,13 +8,4 @@ extern "C"
{
return (int)syscall(SYS_open, pathname, flags);
}
int fcntl(int fd, int cmd, ...)
{
va_list ap;
va_start(ap, cmd);
long result = syscall(SYS_fcntl, fd, cmd, va_arg(ap, uintptr_t));
va_end(ap);
return (int)result;
}
}

View File

@ -30,11 +30,14 @@ extern "C"
return 0; // FIXME: Implement buffered IO.
}
FILE* fopen(const char* pathname, const char* mode)
FILE* fopen(const char* pathname, const char*)
{
int fd = open(pathname, O_RDWR); // FIXME: Use the mode string.
if (fd < 0) { return 0; }
return fdopen(fd, mode);
FILE* stream = (FILE*)malloc(sizeof(FILE));
stream->f_fd = fd;
clearerr(stream);
return stream;
}
FILE* fdopen(int fd, const char*)
@ -45,17 +48,11 @@ extern "C"
return 0;
}
FILE* stream = (FILE*)malloc(sizeof(FILE));
if (!stream) { return 0; }
stream->f_fd = fd;
clearerr(stream);
return stream;
}
int fileno(FILE* stream)
{
return stream->f_fd;
}
size_t fread(void* buf, size_t size, size_t nmemb, FILE* stream)
{
ssize_t status = read(stream->f_fd, buf, size * nmemb);

View File

@ -10,41 +10,14 @@ static void terminate_libc()
fclose(stderr);
}
static void initialize_random()
{
unsigned int seed = 3735928559U;
FILE* fp = fopen("/dev/random", "rw");
if (!fp)
{
errno = 0;
goto failed_to_read_dev_random;
}
fread(&seed, sizeof(seed), 1, fp);
if (ferror(fp))
{
errno = 0;
fclose(fp);
goto failed_to_read_dev_random;
}
fclose(fp);
failed_to_read_dev_random:
srand(seed); // If we failed, this will be seeded with a known value. Else, it will be seeded with a random value
// from the kernel.
return;
}
static void check_for_file(int fd, FILE** target_stream, const char* path, const char* mode)
{
if (lseek(fd, 0, SEEK_CUR) < 0)
{
if (errno == EBADF) *target_stream = fopen(path, mode);
else
exit(-127);
if (!*target_stream) exit(-127);
exit(errno);
if (!*target_stream) exit(errno);
errno = 0;
}
else { *target_stream = fdopen(fd, mode); }
@ -52,9 +25,7 @@ static void check_for_file(int fd, FILE** target_stream, const char* path, const
extern "C" void initialize_libc()
{
check_for_file(STDOUT_FILENO, &stdout, "/dev/console", "rw");
check_for_file(STDERR_FILENO, &stderr, "/dev/console", "rw");
initialize_random();
check_for_file(0, &stdout, "/dev/console", "rw");
check_for_file(1, &stderr, "/dev/console", "rw");
atexit(terminate_libc);
}

View File

@ -1,50 +0,0 @@
#include <libgen.h>
#include <string.h>
static char dot[] = ".";
extern "C"
{
char* basename(char* path)
{
// If path is NULL, or the string's length is 0, return .
if (!path) return dot;
size_t len = strlen(path);
if (!len) return dot;
// Strip trailing slashes.
char* it = path + len - 1;
while (*it == '/' && it != path) { it--; }
*(it + 1) = 0;
if (it == path) return path;
// Return path from the first character if there are no more slashes, or from the first character after the last
// slash.
char* beg = strrchr(path, '/');
if (!beg) return path;
return beg + 1;
}
char* dirname(char* path)
{
// If path is NULL, or the string's length is 0, return .
if (!path) return dot;
size_t len = strlen(path);
if (!len) return dot;
// Strip trailing slashes.
char* it = path + len - 1;
while (*it == '/' && it != path) { it--; }
*(char*)(it + 1) = 0;
if (it == path) return path;
// Search for the last slash. If there is none, return .
// Otherwise, we end the string there and return.
char* end = strrchr(path, '/');
if (!end) return dot;
if (end != path) *end = 0;
else
*(end + 1) = 0;
return path;
}
}

View File

@ -7,12 +7,17 @@
extern "C"
{
pid_t gettid()
{
return syscall(SYS_gettid);
}
unsigned int msleep(unsigned int ms)
{
return (unsigned int)syscall(SYS_sleep, ms);
}
__lc_noreturn void __luna_abort(const char* message)
noreturn void __luna_abort(const char* message)
{
fputs(message, stderr);
abort();

View File

@ -1,64 +0,0 @@
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
typedef uint32_t word_t;
#define STATE_SIZE 624
#define MIDDLE 397
#define INIT_SHIFT 30
#define INIT_FACT 1812433253
#define TWIST_MASK 0x9908b0df
#define SHIFT1 11
#define MASK1 0xffffffff
#define SHIFT2 7
#define MASK2 0x9d2c5680
#define SHIFT3 15
#define MASK3 0xefc60000
#define SHIFT4 18
#define LOWER_MASK 0x7fffffff
#define UPPER_MASK (~(word_t)LOWER_MASK)
static word_t state[STATE_SIZE];
static size_t index = STATE_SIZE + 1;
static void twist()
{
for (size_t i = 0; i < STATE_SIZE; i++)
{
word_t x = (state[i] & UPPER_MASK) | (state[(i + 1) % STATE_SIZE] & LOWER_MASK);
x = (x >> 1) ^ (x & 1 ? TWIST_MASK : 0);
state[i] = state[(i + MIDDLE) % STATE_SIZE] ^ x;
}
index = 0;
}
extern "C"
{
int rand()
{
if (index >= STATE_SIZE)
{
assert(index == STATE_SIZE && "Mersenne generator was never seeded");
twist();
}
word_t y = state[index];
y ^= (y >> SHIFT1) & MASK1;
y ^= (y << SHIFT2) & MASK2;
y ^= (y << SHIFT3) & MASK3;
y ^= y >> SHIFT4;
index++;
return y;
}
void srand(unsigned int seed)
{
index = STATE_SIZE;
state[0] = seed;
for (size_t i = 1; i < STATE_SIZE; i++)
state[i] = (word_t)((INIT_FACT * (state[i - 1] ^ (state[i - 1] >> INIT_SHIFT))) + i);
}
}

View File

@ -1,11 +0,0 @@
#include <sched.h>
#include <sys/syscall.h>
#include <unistd.h>
extern "C"
{
int sched_yield()
{
return (int)syscall(SYS_yield);
}
}

View File

@ -1,36 +0,0 @@
global _setjmp
global setjmp
_setjmp:
setjmp:
mov rsi, 0
mov [rdi], rbx
mov [rdi+8], r12
mov [rdi+16], r13
mov [rdi+24], r14
mov [rdi+32], r15
mov [rdi+40], rbp
mov [rdi+48], rsp
mov rax, [rsp]
mov [rdi+56], rax
xor rax, rax
ret
global _longjmp
global longjmp
_longjmp:
longjmp:
mov rax, rsi
cmp rax, 0
jne .nonzero
mov rax, 1
.nonzero:
mov rbx, [rdi]
mov r12, [rdi+8]
mov r13, [rdi+16]
mov r14, [rdi+24]
mov r15, [rdi+32]
mov rbp, [rdi+40]
mov rsp, [rdi+48]
mov rcx, [rdi+56]
mov [rsp], rcx
ret

View File

@ -1,15 +0,0 @@
#include <luna.h>
#include <setjmp.h>
extern "C"
{
int sigsetjmp(sigjmp_buf env, int)
{
return setjmp(env);
}
__lc_noreturn void siglongjmp(sigjmp_buf env, int val)
{
longjmp(env, val);
}
}

View File

@ -1,59 +1,22 @@
#include <ctype.h>
#include <luna.h>
#include <stdlib.h>
#include <sys/syscall.h>
#include <unistd.h>
template <typename T> T string_to_integer_type(const char* str)
{
bool neg = false;
T val = 0;
switch (*str)
{
case '-':
neg = true;
str++;
break;
case '+': str++; break;
default: break;
}
while (isdigit(*str)) { val = (10 * val) + (*str++ - '0'); }
return (neg ? -val : val);
}
extern "C"
{
__lc_noreturn void abort()
noreturn void abort()
{
_Exit(-1);
_exit(-1);
}
int atoi(const char* str)
int atoi(const char*)
{
return string_to_integer_type<int>(str);
}
long atol(const char* str)
{
return string_to_integer_type<long>(str);
}
long long atoll(const char* str)
{
return string_to_integer_type<long long>(str);
NOT_IMPLEMENTED("atoi");
}
char* getenv(const char*)
{
NOT_IMPLEMENTED("getenv");
}
__lc_noreturn void _Exit(int status)
{
syscall(SYS_exit, status);
__lc_unreachable();
}
}

View File

@ -1,5 +1,5 @@
#include <errno.h>
#include <stdlib.h>
#include <luna.h>
#include <string.h>
extern "C"
@ -16,44 +16,6 @@ extern "C"
return buf;
}
void* memchr(const void* buf, int c, size_t n)
{
const char* s = (const char*)buf;
for (; n && *s != (char)c; s++, n--)
;
if (n) return (void*)(const_cast<char*>(s));
return NULL;
}
int memcmp(const void* a, const void* b, size_t n)
{
const char* _a = (const char*)a;
const char* _b = (const char*)b;
for (; n && _a == _b; n--, _a++, _b++)
;
if (!n) return 0;
if (*_a > *_b) return 1;
return -1;
}
void* memmove(void* dest, const void* src, size_t n)
{
if (dest == src) return dest;
if (dest > src)
for (long i = n - 1; i >= 0; i++) { *((char*)dest + i) = *((const char*)src + i); }
else
for (long i = 0; i < (long)n; i++) { *((char*)dest + i) = *((const char*)src + i); }
return dest;
}
char* strdup(const char* str)
{
size_t len = strlen(str);
char* dest = (char*)malloc(len + 1);
if (!dest) return dest;
return (char*)memcpy(dest, str, len + 1);
}
size_t strlen(const char* str)
{
const char* i = str;
@ -62,61 +24,17 @@ extern "C"
return (i - str);
}
size_t strnlen(const char* str, size_t max)
{
char* p = (char*)memchr(str, 0, max);
return p ? p - str : max;
}
char* strcpy(char* dest, const char* src)
{
return (char*)memcpy(dest, src, strlen(src) + 1);
}
char* strncpy(char* dest, const char* src, size_t max)
{
size_t i;
for (i = 0; i < max && src[i] != 0; i++) dest[i] = src[i];
for (; i < max; i++) dest[i] = 0;
memcpy(dest, src, strlen(src) + 1);
return dest;
}
size_t strlcpy(char* dest, const char* src, size_t size)
char* strncpy(char* dest, const char* src, size_t max) // FIXME: Implement strncpy according to the specification.
{
size_t len = strlen(src);
if (size == 0) return len;
if (len < (size - 1))
{
memcpy(dest, src, len);
dest[len] = 0;
}
else
{
memcpy(dest, src, size - 1);
dest[size - 1] = 0;
}
return len;
}
int strcmp(const char* a, const char* b)
{
while (*a && (*a == *b))
{
a++;
b++;
}
return *(const unsigned char*)a - *(const unsigned char*)b;
}
int strncmp(const char* a, const char* b, size_t max)
{
const char* base = a;
while (*a && (*a == *b) && (size_t)(a - base) < (max - 1))
{
a++;
b++;
}
return *(const unsigned char*)a - *(const unsigned char*)b;
size_t src_len = strlen(src) + 1; // NULL byte
memcpy(dest, src, src_len > max ? max : src_len);
return dest;
}
char* strcat(char* dest, const char* src)
@ -150,38 +68,48 @@ extern "C"
return NULL;
}
char* strrchr(const char* str, int c)
void* memclr(void* buf, size_t n)
{
const char* s = str + strlen(str);
while (s != str && *s != (char)c) s--;
if (s != str) return const_cast<char*>(s);
if (*s == (char)c) return const_cast<char*>(s);
return NULL;
}
// "i" is our counter of how many bytes we've cleared
size_t i;
void* bzero(void* buf, size_t n)
{
return memset(buf, 0, n);
}
char* strstr(const char* haystack, const char* needle)
{
size_t needle_size = strlen(needle);
size_t haystack_size = strlen(haystack);
while (*haystack)
// find out if "m_start" is aligned on a SSE_XMM_SIZE boundary
if ((size_t)buf & (15))
{
if (*haystack == *needle)
i = 0;
// we need to clear byte-by-byte until "m_start" is aligned on an SSE_XMM_SIZE boundary
// ... and lets make sure we don't copy 'too' many bytes (i < m_count)
while (((size_t)buf + i) & (15) && i < n)
{
if (needle_size <= haystack_size)
{
if (!strncmp(haystack, needle, needle_size)) return const_cast<char*>(haystack);
}
else { return NULL; }
asm("stosb;" ::"D"((size_t)buf + i), "a"(0));
i++;
}
haystack++;
haystack_size--;
}
return NULL;
else
{
// if "m_start" was aligned, set our count to 0
i = 0;
}
// clear 64-byte chunks of memory (4 16-byte operations)
for (; i + 64 <= n; i += 64)
{
asm volatile(" pxor %%xmm0, %%xmm0; " // set XMM0 to 0
" movdqa %%xmm0, 0(%0); " // move 16 bytes from XMM0 to %0 + 0
" movdqa %%xmm0, 16(%0); "
" movdqa %%xmm0, 32(%0); "
" movdqa %%xmm0, 48(%0); " ::"r"((size_t)buf + i));
}
// copy the remaining bytes (if any)
asm(" rep stosb; " ::"a"((size_t)(0)), "D"(((size_t)buf) + i), "c"(n - i));
// "i" will contain the total amount of bytes that were actually transfered
i += n - i;
// we return "m_start" + the amount of bytes that were transfered
return (void*)(((size_t)buf) + i);
}
#pragma GCC push_options
@ -201,13 +129,8 @@ extern "C"
case EISDIR: return "Is a directory";
case ENOEXEC: return "Exec format error";
case EFAULT: return "Bad address";
case EEXIST: return "File exists";
case ENOTDIR: return "Not a directory";
case ENOSPC: return "No space left on device";
case ENOTSUP: return "Operation not supported";
case EPIPE: return "Broken pipe";
case 0: return "Success";
default: return "Unknown error";
default: return (char*)(unsigned long int)err;
}
}

View File

@ -14,9 +14,4 @@ extern "C"
{
return (int)syscall(SYS_munmap, addr, len);
}
int mprotect(void* addr, size_t size, int prot)
{
return (int)syscall(SYS_mprotect, addr, size, prot);
}
}

View File

@ -1,11 +0,0 @@
#include <sys/stat.h>
#include <sys/syscall.h>
#include <unistd.h>
extern "C"
{
int mkdir(const char* pathname, mode_t)
{
return (int)syscall(SYS_mkdir, pathname);
}
}

View File

@ -1,11 +0,0 @@
#include <sys/syscall.h>
#include <time.h>
#include <unistd.h>
extern "C"
{
clock_t clock()
{
return syscall(SYS_clock);
}
}

View File

@ -1,5 +1,4 @@
#include <bits/error.h>
#include <fcntl.h>
#include <luna.h>
#include <luna/syscall.h>
#include <stdarg.h>
@ -19,15 +18,9 @@ extern "C"
{
NOT_IMPLEMENTED("execvp");
}
pid_t fork(void)
{
return syscall(SYS_fork);
}
pid_t getpid(void)
{
return syscall(SYS_getpid);
NOT_IMPLEMENTED("fork");
}
long syscall(long number, ...)
@ -38,14 +31,12 @@ extern "C"
va_start(ap, number);
switch (number)
{
case SYS_clock:
case SYS_yield:
case SYS_fork:
case SYS_getpid: result = __luna_syscall0(number); break;
case SYS_gettid:
case SYS_rand: result = __luna_syscall0(number); break;
case SYS_exit:
case SYS_close:
case SYS_exec:
case SYS_mkdir:
case SYS_sleep: result = __luna_syscall1(number, va_arg(ap, arg)); break;
case SYS_munmap:
case SYS_open: {
@ -54,11 +45,9 @@ extern "C"
result = __luna_syscall2(number, arg0, arg1);
break;
}
case SYS_fcntl:
case SYS_seek:
case SYS_write:
case SYS_read:
case SYS_mprotect:
case SYS_mmap: {
arg arg0 = va_arg(ap, arg);
arg arg1 = va_arg(ap, arg);
@ -107,14 +96,9 @@ extern "C"
return syscall(SYS_seek, fd, offset, whence);
}
__lc_noreturn void _exit(int status)
noreturn void _exit(int status)
{
syscall(SYS_exit, status);
__lc_unreachable();
}
int dup(int fd)
{
return fcntl(fd, F_DUPFD, 0);
__builtin_unreachable();
}
}

View File

@ -1,9 +0,0 @@
build:
make -C libc build
install:
make -C libc install
test:
make -C libc test

View File

@ -1,39 +0,0 @@
#ifndef __TEST_H_
#define __TEST_H_
#include <stdbool.h>
int printf(const char*, ...);
#define DEFINE_TEST(name) bool test_##name()
#define START_TEST(name) printf("testing whether %s works... ", #name)
#define START_TEST_CASE(name) printf("testing %s...\n", #name)
#define TEST_SUCCESS() \
do { \
printf("yes!\n"); \
return true; \
} while (0)
#define TEST_FAIL(expr) \
do { \
printf("no (%s)\n", #expr); \
return false; \
} while (0)
#define EXPECT(expr) \
do { \
if (!(expr)) { TEST_FAIL(expr); } \
} while (0)
#define EXPECT_EQ(a, b) EXPECT((a) == (b))
#define EXPECT_NOT_EQ(a, b) EXPECT((a) != (b))
#define EXPECT_NOT_CRASHED() TEST_SUCCESS()
#define RUN_TEST(name) \
do { \
if (!test_##name()) return 1; \
} while (0)
#endif

View File

@ -1,15 +0,0 @@
TESTDIR := $(LUNA_ROOT)/tests/libc
DESTDIR := $(LUNA_ROOT)/initrd/bin
build:
@mkdir -p $(TESTDIR)/bin
$(LUNA_ROOT)/tools/sync-libc.sh
$(CC) $(TESTDIR)/string.c $(TESTDIR)/Test.c -I$(LUNA_ROOT)/tests -o $(TESTDIR)/bin/test-libc -Wall -Wextra -Wno-stringop-overread -Werror
install:
$(LUNA_ROOT)/tools/clean.sh
@mkdir -p $(DESTDIR)
cp $(TESTDIR)/bin/test-libc $(DESTDIR)/test-libc
test:
CFLAGS="-DRUN_TEST_AS_INIT=/bin/test-libc" $(LUNA_ROOT)/tools/run.sh

View File

@ -1,11 +0,0 @@
#include "Test.h"
DEFINE_TEST(strlen);
DEFINE_TEST(strnlen);
int main()
{
START_TEST_CASE(string.h);
RUN_TEST(strlen);
RUN_TEST(strnlen);
}

Some files were not shown because too many files have changed in this diff Show More