Compare commits

..

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

75 changed files with 571 additions and 1653 deletions

View File

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

View File

@ -6,7 +6,7 @@ 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](kernel/src/fs/) from an [initial ramdisk](initrd/), no disk support yet.
- Can [load files](kernel/src/init/InitRD.cpp) 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 initial ramdisk as user tasks.
- [System call](kernel/src/sys/) interface and bare-bones [C Library](libs/libc/).

View File

@ -1,4 +1,4 @@
APPS := init sym
APPS := init
APPS_DIR := $(LUNA_ROOT)/apps
APPS_SRC := $(APPS_DIR)/src

View File

@ -43,25 +43,7 @@ int main()
{
if (gettid() == 0) // why are we the idle task?
{
fprintf(stderr, "SHENANIGANS! init is tid 0 (which is reserved for the idle task)\n");
return 1;
}
FILE* serial = fopen("/dev/serial", "r");
if (!serial)
{
perror("fopen");
return 1;
}
if (fputs("Hello from init!\n", serial) < 0)
{
perror("fputs");
return 1;
}
if (fclose(serial) < 0)
{
perror("fclose");
return 1;
__luna_abort("SHENANIGANS! init is tid 0 (which is reserved for the idle task)\n");
}
printf("Welcome to Luna!\n");
@ -85,23 +67,6 @@ int main()
return 1;
}
if (fseek(config, 0, SEEK_END) < 0)
{
perror("fseek");
return 1;
}
long offset = ftell(config);
if (offset < 0)
{
perror("ftell");
return 1;
}
printf("%s is %ld bytes long\n", filename, offset);
rewind(config);
char buf[4096];
size_t nread = fread(buf, sizeof(buf), 1, config);
@ -117,9 +82,7 @@ int main()
if (fclose(config) < 0) { perror("fclose"); }
sleep(2);
printf("\n\nPress any key to restart.\n\n");
printf("\n\nPress any key to restart.\n");
return 0;
}

View File

@ -1,38 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main()
{
sleep(6);
FILE* syms = fopen("/sys/moon.sym", "r");
if (!syms)
{
perror("fopen");
return 1;
}
char buf[1025];
if (fseek(syms, 8000, SEEK_SET) < 0)
{
perror("fseek");
return 1;
}
size_t nread = fread(buf, 1024, 1, syms);
if (ferror(syms))
{
perror("fread");
return 1;
}
buf[nread] = 0;
printf("%s\n", strchr(buf, '\n') + 1);
fclose(syms);
return 0;
}

View File

@ -3,8 +3,7 @@ MOON_SRC := $(MOON_DIR)/src
MOON_OBJ := $(MOON_DIR)/lib
MOON_BIN := $(MOON_DIR)/bin
CFLAGS ?= -Os
CFLAGS := ${CFLAGS} -pedantic -Wall -Wextra -Werror -Wfloat-equal -Wdisabled-optimization -Wformat=2 -Winit-self -Wmissing-include-dirs -Wswitch-default -Wcast-qual -Wundef -Wcast-align -Wwrite-strings -Wlogical-op -Wredundant-decls -Wshadow -Wconversion -ffreestanding -fstack-protector-strong -fno-omit-frame-pointer -mno-red-zone -mno-mmx -mno-sse -mno-sse2 -fshort-wchar -mcmodel=kernel -I$(MOON_DIR)/include -isystem $(MOON_DIR)/include/std
CFLAGS := -pedantic -Wall -Wextra -Werror -Wfloat-equal -Wdisabled-optimization -Wformat=2 -Winit-self -Wmissing-include-dirs -Wswitch-default -Wcast-qual -Wundef -Wcast-align -Wwrite-strings -Wlogical-op -Wredundant-decls -Wshadow -Wconversion -Os -ffreestanding -fstack-protector-all -fno-omit-frame-pointer -mno-red-zone -mno-mmx -mno-sse -mno-sse2 -fshort-wchar -mcmodel=kernel -I$(MOON_DIR)/include -isystem $(MOON_DIR)/include/std
CXXFLAGS := -fno-rtti -fno-exceptions -Wsign-promo -Wstrict-null-sentinel -Wctor-dtor-privacy
ASMFLAGS := -felf64
LDFLAGS := -T$(MOON_DIR)/moon.ld -nostdlib -lgcc -Wl,--build-id=none -z max-page-size=0x1000 -mno-red-zone -mcmodel=kernel

View File

@ -2,10 +2,8 @@
#define EPERM 1
#define ENOENT 2
#define ENOEXEC 8
#define EBADF 9
#define ENOMEM 12
#define EFAULT 14
#define EISDIR 21
#define EINVAL 22
#define EMFILE 24

View File

@ -29,17 +29,6 @@ struct Descriptor
void open(VFS::Node* node, bool can_read, bool can_write);
int seek(long offset);
long offset()
{
return (long)m_offset;
}
unsigned long length()
{
return m_node->length;
}
Descriptor(const Descriptor& other);
Descriptor();

View File

@ -6,7 +6,6 @@ typedef long ssize_t;
#define VFS_FILE 0x0
#define VFS_DIRECTORY 0x1
#define VFS_DEVICE 0x2
#define VFS_MOUNTPOINT 0x1

View File

@ -3,7 +3,7 @@
namespace ConsoleDevice
{
VFS::Node* create_new(const char* devname);
VFS::Node* create_new();
ssize_t write(VFS::Node* node, size_t offset, size_t size, const char* buffer);
}

View File

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

View File

@ -3,7 +3,7 @@
namespace VersionDevice
{
VFS::Node* create_new(const char* devname);
VFS::Node* create_new();
ssize_t read(VFS::Node* node, size_t offset, size_t size, char* buffer);
}

View File

@ -8,10 +8,4 @@ namespace Interrupts
bool is_in_handler();
void return_from_handler(Context* context);
bool are_enabled();
bool were_enabled();
void push_and_disable();
void push_and_enable();
void pop();
}

View File

@ -1,27 +0,0 @@
#pragma once
#include "memory/Paging.h"
struct AddressSpace
{
static AddressSpace create();
void destroy();
void detach();
AddressSpace clone();
PageTable* get_pml4()
{
return m_pml4;
}
bool is_cloned()
{
return m_cloned;
}
private:
PageTable* m_pml4;
bool m_cloned;
};

View File

@ -29,6 +29,4 @@ namespace MemoryManager
void release_page(void* page);
void release_pages(void* pages, uint64_t count);
void protect(void* page, uint64_t count, int flags);
}

View File

@ -5,25 +5,27 @@
#define PAGE_SIZE 4096
#endif
struct PageDirectoryEntry
namespace Paging
{
bool present : 1;
bool read_write : 1;
bool user : 1;
bool write_through : 1;
bool cache_disabled : 1;
bool accessed : 1;
bool ignore0 : 1;
bool larger_pages : 1;
bool ignore1 : 1;
uint8_t available : 3;
uint64_t address : 52;
struct PageDirectoryEntry
{
bool Present : 1;
bool ReadWrite : 1;
bool UserSuper : 1;
bool WriteThrough : 1;
bool CacheDisabled : 1;
bool Accessed : 1;
bool ignore0 : 1;
bool LargerPages : 1;
bool ignore1 : 1;
uint8_t Available : 3;
uint64_t Address : 52;
void set_address(uint64_t addr);
uint64_t get_address();
};
void set_address(uint64_t addr);
};
struct PageTable
{
PageDirectoryEntry entries[512];
} __attribute__((aligned(PAGE_SIZE)));
struct PageTable
{
PageDirectoryEntry entries[512];
} __attribute__((aligned(0x1000)));
}

View File

@ -1,45 +1,29 @@
#pragma once
#include "memory/AddressSpace.h"
#include "memory/Paging.h"
enum Flags
namespace Paging
{
ReadWrite = 1 << 0,
User = 1 << 1,
Execute = 1 << 2
};
namespace VMM
{
void init(); // Fetch page table from cr3
enum Flags
{
ReadWrite = 1 << 0,
User = 1 << 1,
Execute = 1 << 2
};
class VirtualMemoryManager
{
public:
void init(); // fetch page table from cr3
void init(PageTable* cr3);
void switch_to_user_address_space(AddressSpace& space);
void switch_to_previous_user_address_space();
void switch_back_to_kernel_address_space();
void map(uint64_t virtualAddress, uint64_t physicalAddress, int flags);
void remap(uint64_t virtualAddress, int flags);
void unmap(uint64_t virtualAddress);
uint64_t getPhysical(uint64_t virtualAddress);
uint64_t getFlags(uint64_t virtualAddress);
void enter_syscall_context();
void exit_syscall_context();
private:
PageTable* PML4;
};
}
void apply_address_space();
bool is_using_kernel_address_space();
void map(uint64_t vaddr, uint64_t paddr, int flags);
void remap(uint64_t vaddr, int flags);
void unmap(uint64_t vaddr);
uint64_t get_physical(uint64_t vaddr);
uint64_t get_flags(uint64_t vaddr);
PageDirectoryEntry* find_pde(PageTable* root, uint64_t vaddr);
PageDirectoryEntry* create_pde_if_not_exists(PageTable* root, uint64_t vaddr);
void propagate_read_write(PageTable* root, uint64_t vaddr);
void propagate_user(PageTable* root, uint64_t vaddr);
void flush_tlb(uint64_t addr);
void decompose_vaddr(uint64_t vaddr, uint64_t& page_index, uint64_t& pt_index, uint64_t& pd_index,
uint64_t& pdp_index);
uint64_t recompose_vaddr(uint64_t page_index, uint64_t pt_index, uint64_t pd_index, uint64_t pdp_index);
void install_kernel_page_directory_into_address_space(AddressSpace& space);
};
extern Paging::VirtualMemoryManager kernelVMM;

View File

@ -3,8 +3,6 @@
namespace Utilities
{
inline uint64_t get_blocks_from_size(uint64_t blocksize, uint64_t size)
{
return (size + (blocksize - 1)) / blocksize;
}
uint64_t get_blocks_from_size(uint64_t blocksize,
uint64_t size); // Returns how many blocks of size blocksize does size occupy.
}

View File

@ -16,6 +16,4 @@ char* strstr(char* haystack, const char* needle);
void* memcpy(void* dest, const void* src, size_t n);
void* memset(void* dest, int c, size_t n);
int memcmp(const void* a, const void* b, size_t n);
void* memmove(void* dest, void* src, size_t n);
char* strdup(const char* src);
void* memmove(void* dest, void* src, size_t n);

View File

@ -14,14 +14,10 @@
#define SYS_open 9
#define SYS_read 10
#define SYS_close 11
#define SYS_seek 12
#define SYS_exec 13
namespace Syscall
{
void entry(Context* context);
char* strdup_from_user(const char* user_string);
}
void sys_exit(Context* context, int status);
@ -35,6 +31,4 @@ 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_close(Context* context, int fd);

View File

@ -1,13 +1,9 @@
#pragma once
#include "fs/VFS.h"
#include "sys/elf/Image.h"
#include <stdint.h>
namespace ELFLoader
{
ELFImage* load_elf_from_vfs(VFS::Node* node); // This function assumes check_elf_image has been called first.
ELFImage* load_elf_from_address(uintptr_t addr);
ELFImage* load_elf_from_filesystem(const char* filename);
void release_elf_image(ELFImage* image);
long check_elf_image(VFS::Node* node);
long check_elf_image_from_filesystem(const char* filename);
}

View File

@ -1,8 +1,6 @@
#pragma once
#include "thread/Task.h"
#define TASK_PAGES_IN_STACK 4
namespace Scheduler
{
void init();
@ -10,8 +8,7 @@ namespace Scheduler
void exit(int status);
void sleep(unsigned long ms);
void add_kernel_task(void (*task)(void));
Task* create_user_task();
void add_user_task(void* task);
void load_user_task(const char* filename);
@ -25,6 +22,4 @@ namespace Scheduler
void reap_task(Task* task);
void reap_tasks();
void reset_task(Task* task, ELFImage* new_image);
}

View File

@ -1,7 +1,6 @@
#pragma once
#include "fs/FileDescriptor.h"
#include "interrupts/Context.h"
#include "memory/AddressSpace.h"
#include "sys/elf/Image.h"
#define TASK_MAX_FDS 8
@ -37,15 +36,11 @@ struct Task
char floating_region[512] __attribute__((aligned(16)));
bool floating_saved = false;
bool user_task = true;
bool is_user_task();
ELFImage* image = nullptr;
Descriptor files[TASK_MAX_FDS];
AddressSpace address_space;
};
void set_context_from_task(Task& task, Context* ctx);

View File

@ -1,24 +0,0 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
#ifndef PAGE_SIZE
#define PAGE_SIZE 4096
#endif
inline uintptr_t get_top_of_stack(uintptr_t bottom, size_t stack_pages)
{
return bottom + (stack_pages * PAGE_SIZE) - sizeof(uintptr_t);
}
inline uintptr_t round_down_to_nearest_page(uintptr_t addr)
{
return addr - (addr % PAGE_SIZE);
}
inline uintptr_t round_up_to_nearest_page(uintptr_t addr)
{
if (addr % PAGE_SIZE) return addr + (PAGE_SIZE - (addr % PAGE_SIZE));
return addr;
}

View File

@ -1,52 +0,0 @@
#pragma once
#include <stdint.h>
extern "C" uintptr_t asm_get_rflags();
extern "C" void asm_set_rflags(uintptr_t);
inline uintptr_t read_rflags()
{
return asm_get_rflags();
}
inline void write_rflags(uintptr_t value)
{
asm_set_rflags(value);
}
inline uintptr_t read_cr0()
{
uintptr_t value;
asm volatile("mov %%cr0, %0" : "=r"(value));
return value;
}
inline uintptr_t read_cr3()
{
uintptr_t value;
asm volatile("mov %%cr3, %0" : "=r"(value));
return value;
}
inline uintptr_t read_cr4()
{
uintptr_t value;
asm volatile("mov %%cr4, %0" : "=r"(value));
return value;
}
template <typename T> inline void write_cr0(T value)
{
asm volatile("mov %0, %%cr0" : : "r"(value));
}
template <typename T> inline void write_cr3(T value)
{
asm volatile("mov %0, %%cr3" : : "r"(value));
}
template <typename T> inline void write_cr4(T value)
{
asm volatile("mov %0, %%cr4" : : "r"(value));
}

View File

@ -1,6 +0,0 @@
#pragma once
template <typename T> inline T&& move(T& lvalue)
{
return (T &&) lvalue;
}

View File

@ -1,5 +1,4 @@
#include "fs/FileDescriptor.h"
#include "errno.h"
Descriptor::Descriptor() : m_is_open(false)
{
@ -32,12 +31,4 @@ ssize_t Descriptor::write(size_t size, const char* buffer)
ssize_t result = VFS::write(m_node, m_offset, size, buffer);
m_offset += result;
return result;
}
int Descriptor::seek(long offset)
{
if (m_node->type != VFS_DEVICE && (uint64_t)offset > m_node->length)
return -EINVAL; // FIXME: Support seeking beyond the current file's length.
m_offset = (uint64_t)offset;
return 0;
}

View File

@ -5,15 +5,15 @@
#include "std/stdlib.h"
#include "std/string.h"
VFS::Node* ConsoleDevice::create_new(const char* devname)
VFS::Node* ConsoleDevice::create_new()
{
VFS::Node* dev = new VFS::Node;
dev->write_func = ConsoleDevice::write;
dev->inode = 0;
dev->length = 0;
dev->type = VFS_DEVICE;
dev->type = VFS_FILE;
dev->flags = 0;
strncpy(dev->name, devname, sizeof(dev->name));
strncpy(dev->name, "console", sizeof(dev->name));
return dev;
}

View File

@ -1,6 +1,5 @@
#include "fs/devices/DeviceFS.h"
#include "fs/devices/Console.h"
#include "fs/devices/Serial.h"
#include "fs/devices/Version.h"
#include "std/stdlib.h"
#include "std/string.h"
@ -22,9 +21,8 @@ VFS::Node* DeviceFS::get()
devfs_root->find_func = DeviceFS::finddir;
strncpy(devfs_root->name, "dev", sizeof(devfs_root->name));
devfs_files[devfs_file_count++] = VersionDevice::create_new("version");
devfs_files[devfs_file_count++] = ConsoleDevice::create_new("console");
devfs_files[devfs_file_count++] = SerialDevice::create_new("serial");
devfs_files[devfs_file_count++] = VersionDevice::create_new();
devfs_files[devfs_file_count++] = ConsoleDevice::create_new();
return devfs_root;
}

View File

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

View File

@ -4,15 +4,15 @@
#include "std/stdlib.h"
#include "std/string.h"
VFS::Node* VersionDevice::create_new(const char* devname)
VFS::Node* VersionDevice::create_new()
{
VFS::Node* dev = new VFS::Node;
dev->read_func = VersionDevice::read;
dev->inode = 0;
dev->length = strlen(moon_version()) + 5;
dev->type = VFS_DEVICE;
dev->type = VFS_FILE;
dev->flags = 0;
strncpy(dev->name, devname, sizeof(dev->name));
strncpy(dev->name, "version", sizeof(dev->name));
return dev;
}

View File

@ -49,15 +49,15 @@ struct InternalGDT
GDTEntry user_data;
GDTEntry tss;
HighGDTEntry tss2;
} __attribute__((packed)) __attribute((aligned(PAGE_SIZE)));
} __attribute__((packed)) __attribute((aligned(0x1000)));
__attribute__((aligned(PAGE_SIZE))) static InternalGDT internal_gdt = {{0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00},
{0xffff, 0x0000, 0x00, 0x9a, 0xaf, 0x00},
{0xffff, 0x0000, 0x00, 0x92, 0xcf, 0x00},
{0xffff, 0x0000, 0x00, 0xfa, 0xaf, 0x00},
{0xffff, 0x0000, 0x00, 0xf2, 0xcf, 0x00},
{0x0000, 0x0000, 0x00, 0xe9, 0x0f, 0x00},
{0x00000000, 0x00000000}};
__attribute__((aligned(0x1000))) static InternalGDT internal_gdt = {{0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00},
{0xffff, 0x0000, 0x00, 0x9a, 0xaf, 0x00},
{0xffff, 0x0000, 0x00, 0x92, 0xcf, 0x00},
{0xffff, 0x0000, 0x00, 0xfa, 0xaf, 0x00},
{0xffff, 0x0000, 0x00, 0xf2, 0xcf, 0x00},
{0x0000, 0x0000, 0x00, 0xe9, 0x0f, 0x00},
{0x00000000, 0x00000000}};
static TSS main_tss;
@ -78,35 +78,20 @@ static void set_limit(GDTEntry* entry, uint32_t limit)
entry->limit1_flags = (entry->limit1_flags & 0xF0) | ((limit >> 16) & 0xF);
}
static void set_tss_base(GDTEntry* tss1, HighGDTEntry* tss2, uint64_t addr)
{
set_base(tss1, addr & 0xffffffff);
tss2->base_high = (uint32_t)(addr >> 32);
}
static void setup_tss()
{
memset(&main_tss, 0, sizeof(TSS));
main_tss.rsp[0] =
(uint64_t)MemoryManager::get_pages(4) + (PAGE_SIZE * 4) - 8; // allocate 16KB for the syscall stack
main_tss.iomap_base = sizeof(TSS);
set_tss_base(&internal_gdt.tss, &internal_gdt.tss2, (uint64_t)&main_tss);
set_limit(&internal_gdt.tss, sizeof(TSS) - 1);
}
static void load_tss()
{
kdbgln("Loading TR (GDT entry 0x2b)");
load_tr(0x2b);
}
void GDT::load()
{
static GDTR gdtr;
gdtr.offset = (uint64_t)&internal_gdt;
gdtr.size = sizeof(InternalGDT);
setup_tss();
memset(&main_tss, 0, sizeof(TSS));
main_tss.rsp[0] =
(uint64_t)MemoryManager::get_pages(4) + (PAGE_SIZE * 4) - 8; // allocate 16KB for the syscall stack
main_tss.iomap_base = sizeof(TSS);
set_base(&internal_gdt.tss, (uint64_t)&main_tss & 0xffffffff);
internal_gdt.tss2.base_high = (uint32_t)(((uint64_t)&main_tss >> 32) & 0xffffffff);
set_limit(&internal_gdt.tss, sizeof(TSS) - 1);
kdbgln("Loading GDT at offset %lx, size %d", gdtr.offset, gdtr.size);
load_gdt(&gdtr);
load_tss();
kdbgln("Loading TR (GDT entry 0x2b)");
load_tr(0x2b);
}

View File

@ -51,8 +51,6 @@ extern "C" void common_handler(Context* context)
StackTracer tracer(context->rbp);
tracer.trace_with_ip(context->rip);
hang(); // FIXME: Remove this when multiple address spaces are working.
Scheduler::task_misbehave(context, -3);
}
}

View File

@ -1,6 +1,5 @@
#include "interrupts/Interrupts.h"
#include "trace/StackTracer.h"
#include "utils/Registers.h"
void Interrupts::disable()
{
@ -25,35 +24,4 @@ void Interrupts::return_from_handler(Context* context)
"jmp _asm_interrupt_exit"
:
: "r"(context));
}
bool Interrupts::are_enabled()
{
return (read_rflags() & 0x200) > 0;
}
static bool saved_interrupt_state;
void Interrupts::push_and_disable()
{
saved_interrupt_state = are_enabled();
disable();
}
void Interrupts::push_and_enable()
{
saved_interrupt_state = are_enabled();
enable();
}
void Interrupts::pop()
{
if (saved_interrupt_state && !are_enabled()) enable();
else if (!saved_interrupt_state && are_enabled())
disable();
}
bool Interrupts::were_enabled()
{
return saved_interrupt_state;
}

View File

@ -25,16 +25,4 @@ asm_enable_sse:
mov rax, cr4
or ax, 3 << 9
mov cr4, rax
ret
global asm_get_rflags
asm_get_rflags:
pushfq
pop rax
ret
global asm_set_rflags
asm_set_rflags:
push rdi
popfq
ret

View File

@ -16,7 +16,6 @@
#include "io/PIC.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"
@ -57,6 +56,12 @@ extern "C" void _start()
kinfoln("Loaded IDT");
PIC::remap();
PIC::enable_master(0b11111100); // enable keyboard and PIT
PIC::enable_slave(0b11111111);
kinfoln("Prepared PIC");
PIT::initialize(1000); // 1000 times per second
kinfoln("Prepared PIT");
@ -82,9 +87,7 @@ extern "C" void _start()
Init::finish_kernel_boot();
PIC::remap();
PIC::enable_master(0b11111100); // enable keyboard and PIT
PIC::enable_slave(0b11111111);
Interrupts::enable(); // Task switching commences here
kinfoln("Interrupts enabled");

View File

@ -1,95 +0,0 @@
#define MODULE "vmm"
#include "memory/AddressSpace.h"
#include "log/Log.h"
#include "memory/PMM.h"
#include "memory/VMM.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++)
{
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);
}
pages_freed++;
PMM::free_page(m_pml4);
kdbgln("Reclaimed %ld pages from address space!", pages_freed);
}
void AddressSpace::detach()
{
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()
{
AddressSpace result;
result.m_pml4 = m_pml4;
result.m_cloned = true;
return result;
}

View File

@ -1,5 +1,3 @@
#define MODULE "kheap"
#include "memory/KernelHeap.h"
#include "assert.h"
@ -70,7 +68,7 @@ uint64_t KernelHeap::request_virtual_pages(uint64_t count)
void KernelHeap::free_virtual_page(uint64_t address)
{
if (address < ALLOC_BASE || address >= ALLOC_END) return;
ASSERT(address >= ALLOC_BASE && address < ALLOC_END);
uint64_t index = (address - ALLOC_BASE) / PAGE_SIZE;
bitmap_set(index, false);
if (start_index > index) start_index = index;
@ -78,7 +76,7 @@ void KernelHeap::free_virtual_page(uint64_t address)
void KernelHeap::free_virtual_pages(uint64_t address, uint64_t count)
{
if (address < ALLOC_BASE || address >= ALLOC_END) return;
ASSERT(address >= ALLOC_BASE && address < ALLOC_END);
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

@ -45,7 +45,7 @@ uint64_t Memory::get_usable()
bool Memory::is_kernel_address(uintptr_t address)
{
return address >= 0xfffffffff8000000;
return address > 0xfffffffff8000000;
}
bool Memory::is_user_address(uintptr_t address)

View File

@ -12,7 +12,7 @@
void MemoryManager::init()
{
PMM::init();
VMM::init();
kernelVMM.init();
PMM::map_bitmap_to_virtual();
}
@ -26,7 +26,7 @@ void* MemoryManager::get_mapping(void* physicalAddress, int flags)
#endif
return 0;
}
VMM::map(virtualAddress, (uint64_t)physicalAddress, flags);
kernelVMM.map(virtualAddress, (uint64_t)physicalAddress, flags);
return (void*)virtualAddress;
}
@ -41,7 +41,7 @@ void* MemoryManager::get_unaligned_mapping(void* physicalAddress, int flags)
#endif
return 0;
}
VMM::map(virtualAddress, (uint64_t)physicalAddress - offset, flags);
kernelVMM.map(virtualAddress, (uint64_t)physicalAddress - offset, flags);
return (void*)(virtualAddress + offset);
}
@ -62,7 +62,7 @@ void* MemoryManager::get_unaligned_mappings(void* physicalAddress, uint64_t coun
}
for (uint64_t i = 0; i < count; i++)
{
VMM::map(virtualAddress + (i * PAGE_SIZE), ((uint64_t)physicalAddress - offset) + (i * PAGE_SIZE), flags);
kernelVMM.map(virtualAddress + (i * PAGE_SIZE), ((uint64_t)physicalAddress - offset) + (i * PAGE_SIZE), flags);
}
return (void*)(virtualAddress + offset);
}
@ -70,7 +70,7 @@ void* MemoryManager::get_unaligned_mappings(void* physicalAddress, uint64_t coun
void MemoryManager::release_unaligned_mapping(void* mapping)
{
uint64_t offset = (uint64_t)mapping % PAGE_SIZE;
VMM::unmap((uint64_t)mapping - offset);
kernelVMM.unmap((uint64_t)mapping - offset);
KernelHeap::free_virtual_page((uint64_t)mapping - offset);
}
@ -80,12 +80,12 @@ void MemoryManager::release_unaligned_mappings(void* mapping, uint64_t count)
if (count == 1) return release_unaligned_mapping(mapping);
uint64_t offset = (uint64_t)mapping % PAGE_SIZE;
KernelHeap::free_virtual_pages((uint64_t)mapping - offset, count);
for (uint64_t i = 0; i < count; i++) { VMM::unmap(((uint64_t)mapping - offset) + (i * PAGE_SIZE)); }
for (uint64_t i = 0; i < count; i++) { kernelVMM.unmap(((uint64_t)mapping - offset) + (i * PAGE_SIZE)); }
}
void MemoryManager::release_mapping(void* mapping)
{
VMM::unmap((uint64_t)mapping);
kernelVMM.unmap((uint64_t)mapping);
KernelHeap::free_virtual_page((uint64_t)mapping);
}
@ -112,15 +112,15 @@ void* MemoryManager::get_page_at(uint64_t addr, int flags)
#endif
return 0;
}
VMM::map(addr, (uint64_t)physicalAddress, flags);
kernelVMM.map(addr, (uint64_t)physicalAddress, flags);
return (void*)addr;
}
void MemoryManager::release_page(void* page)
{
uint64_t physicalAddress = VMM::get_physical((uint64_t)page);
uint64_t physicalAddress = kernelVMM.getPhysical((uint64_t)page);
ASSERT(physicalAddress != UINT64_MAX); // this address is not mapped in the virtual address space...
VMM::unmap((uint64_t)page);
kernelVMM.unmap((uint64_t)page);
PMM::free_page((void*)physicalAddress);
}
@ -158,13 +158,13 @@ void* MemoryManager::get_pages_at(uint64_t addr, uint64_t count, int flags)
// smaller range, so this might not be fatal.
{
#ifdef MM_DEBUG
kwarnln("OOM while allocating page %ld of memory. this might be recoverable...", i);
kwarnln("OOM while allocating page %ld of memory. this might be recoverable...");
#endif
return 0;
}
VMM::map(addr + (i * PAGE_SIZE), (uint64_t)physicalAddress, flags);
kernelVMM.map(addr + (i * PAGE_SIZE), (uint64_t)physicalAddress, flags);
#ifdef MM_DEBUG
kdbgln("allocating virtual %lx, physical %p", addr + (i * PAGE_SIZE), physicalAddress);
kdbgln("allocating virtual %lx, physical %p", virtualAddress + (i * PAGE_SIZE), physicalAddress);
#endif
}
return (void*)addr;
@ -180,18 +180,13 @@ void MemoryManager::release_pages(void* pages, uint64_t count)
for (uint64_t i = 0; i < count; i++)
{
void* page = (void*)((uint64_t)pages + (i * PAGE_SIZE));
uint64_t physicalAddress = VMM::get_physical((uint64_t)page);
uint64_t physicalAddress = kernelVMM.getPhysical((uint64_t)page);
ASSERT(physicalAddress != UINT64_MAX);
VMM::unmap((uint64_t)page);
kernelVMM.unmap((uint64_t)page);
#ifdef MM_DEBUG
kdbgln("releasing virtual %p, physical %lx", page, physicalAddress);
#endif
PMM::free_page((void*)physicalAddress);
}
KernelHeap::free_virtual_pages((uint64_t)pages, count);
}
void MemoryManager::protect(void* page, uint64_t count, int flags)
{
for (uint64_t i = 0; i < count; i++) { VMM::remap((uint64_t)page + (i * PAGE_SIZE), flags); }
}

View File

@ -3,14 +3,9 @@
#pragma GCC push_options
#pragma GCC diagnostic ignored "-Wconversion"
void PageDirectoryEntry::set_address(uint64_t addr)
void Paging::PageDirectoryEntry::set_address(uint64_t addr)
{
this->address = (addr >> 12);
}
uint64_t PageDirectoryEntry::get_address()
{
return (uint64_t)this->address << 12;
this->Address = (addr >> 12);
}
#pragma GCC pop_options

View File

@ -1,291 +1,228 @@
#define MODULE "vmm"
#include "memory/VMM.h"
#include "assert.h"
#include "log/Log.h"
#include "memory/PMM.h"
#include "misc/utils.h"
#include "std/string.h"
#include "utils/Addresses.h"
#include "utils/Registers.h"
static PageTable* kernel_pml4;
static PageTable* current_pml4;
static AddressSpace* user_address_space;
Paging::VirtualMemoryManager kernelVMM;
void VMM::switch_back_to_kernel_address_space()
namespace Paging
{
if (current_pml4 != kernel_pml4) { current_pml4 = kernel_pml4; }
}
void VMM::switch_to_user_address_space(AddressSpace& space)
{
user_address_space = &space;
current_pml4 = user_address_space->get_pml4();
}
void VMM::switch_to_previous_user_address_space()
{
current_pml4 = user_address_space->get_pml4();
}
void VMM::enter_syscall_context()
{
if (current_pml4 != kernel_pml4)
void VirtualMemoryManager::init()
{
current_pml4 = kernel_pml4;
apply_address_space();
switch_to_previous_user_address_space();
}
}
void VMM::exit_syscall_context()
{
if (current_pml4 != user_address_space->get_pml4()) { switch_to_previous_user_address_space(); }
apply_address_space();
}
void VMM::apply_address_space()
{
write_cr3(current_pml4);
}
bool VMM::is_using_kernel_address_space()
{
return current_pml4 == kernel_pml4;
}
void VMM::init()
{
kernel_pml4 = (PageTable*)read_cr3();
current_pml4 = kernel_pml4;
}
void VMM::unmap(uint64_t vaddr)
{
vaddr = round_down_to_nearest_page(vaddr);
PageDirectoryEntry* pde = find_pde(current_pml4, vaddr);
if (!pde) return; // Already unmapped
memset(pde, 0, sizeof(PageDirectoryEntry));
flush_tlb(vaddr);
}
void VMM::remap(uint64_t vaddr, int flags)
{
vaddr = round_down_to_nearest_page(vaddr);
PageDirectoryEntry* pde = find_pde(current_pml4, vaddr);
if (!pde) return; // Not mapped
if (flags & User) propagate_user(current_pml4, vaddr);
else
pde->user = false;
if (flags & ReadWrite) propagate_read_write(current_pml4, vaddr);
else
pde->read_write = false;
flush_tlb(vaddr);
}
uint64_t VMM::get_physical(uint64_t vaddr)
{
PageDirectoryEntry* pde = find_pde(current_pml4, round_down_to_nearest_page(vaddr));
if (!pde) return UINT64_MAX; // Not mapped
return pde->get_address() | (vaddr % PAGE_SIZE);
}
uint64_t VMM::get_flags(uint64_t vaddr)
{
PageDirectoryEntry* pde = find_pde(current_pml4, round_down_to_nearest_page(vaddr));
if (!pde) return 0; // Not mapped
uint64_t flags = 0;
if (pde->user) flags |= User;
if (pde->read_write) flags |= ReadWrite;
return flags;
}
void VMM::map(uint64_t vaddr, uint64_t paddr, int flags)
{
vaddr = round_down_to_nearest_page(vaddr);
PageDirectoryEntry* pde = find_pde(current_pml4, vaddr);
bool will_flush_tlb = true;
if (!pde)
{
pde = create_pde_if_not_exists(current_pml4, vaddr);
will_flush_tlb = false;
}
else if (pde->larger_pages)
{
unmap(vaddr);
pde = create_pde_if_not_exists(current_pml4, vaddr);
asm volatile("mov %%cr3, %0" : "=r"(PML4));
}
pde->set_address(round_down_to_nearest_page(paddr));
if (flags & User) propagate_user(current_pml4, vaddr);
else
pde->user = false;
if (flags & ReadWrite) propagate_read_write(current_pml4, vaddr);
else
pde->read_write = false;
if (will_flush_tlb) flush_tlb(vaddr);
}
PageDirectoryEntry* VMM::find_pde(PageTable* root, uint64_t vaddr)
{
uint64_t page_index;
PageDirectoryEntry* pde;
PageTable* pt = root;
uint64_t indexes[3];
decompose_vaddr(vaddr, page_index, indexes[2], indexes[1], indexes[0]);
for (int i = 0; i < 3;
i++) // Walk through the page map level 4, page directory pointer, and page directory to find the page table.
void VirtualMemoryManager::init(PageTable* cr3)
{
pde = &pt->entries[indexes[i]];
if (!pde->present) return nullptr;
else if (pde->larger_pages)
return pde;
else { pt = (PageTable*)pde->get_address(); }
PML4 = cr3;
}
pde = &pt->entries[page_index]; // PT
if (!pde->present) return nullptr;
return pde;
}
PageDirectoryEntry* VMM::create_pde_if_not_exists(PageTable* root, uint64_t vaddr)
{
uint64_t page_index;
PageDirectoryEntry* pde;
PageTable* pt = root;
uint64_t indexes[3];
decompose_vaddr(vaddr, page_index, indexes[2], indexes[1], indexes[0]);
auto pde_create_if_not_present = [&]() {
pt = (PageTable*)PMM::request_page();
ASSERT(!(PMM_DID_FAIL(pt)));
memset(pt, 0, PAGE_SIZE);
pde->set_address((uint64_t)pt);
pde->present = true;
};
for (int i = 0; i < 3; i++)
void VirtualMemoryManager::unmap(uint64_t virtualAddress)
{
pde = &pt->entries[indexes[i]];
if (!pde->present) { pde_create_if_not_present(); }
else if (pde->larger_pages)
return pde;
else { pt = (PageTable*)pde->get_address(); }
}
virtualAddress >>= 12;
uint64_t P_i = virtualAddress & 0x1ff;
virtualAddress >>= 9;
uint64_t PT_i = virtualAddress & 0x1ff;
virtualAddress >>= 9;
uint64_t PD_i = virtualAddress & 0x1ff;
virtualAddress >>= 9;
uint64_t PDP_i = virtualAddress & 0x1ff;
pde = &pt->entries[page_index];
if (!pde->present) { pde->present = true; }
return pde;
}
PageDirectoryEntry PDE;
void VMM::propagate_read_write(PageTable* root, uint64_t vaddr)
{
uint64_t page_index;
PageDirectoryEntry* pde;
PageTable* pt = root;
uint64_t indexes[3];
decompose_vaddr(vaddr, page_index, indexes[2], indexes[1], indexes[0]);
for (int i = 0; i < 3; i++)
{
pde = &pt->entries[indexes[i]];
if (!pde->present) return;
else
PDE = PML4->entries[PDP_i];
PageTable* PDP;
if (!PDE.Present)
{
pde->read_write = true;
if (pde->larger_pages) return;
pt = (PageTable*)pde->get_address();
return; // Already unmapped
}
}
else { PDP = (PageTable*)((uint64_t)PDE.Address << 12); }
pde = &pt->entries[page_index];
if (!pde->present) return;
else
pde->read_write = true;
}
void VMM::propagate_user(PageTable* root, uint64_t vaddr)
{
uint64_t page_index;
PageDirectoryEntry* pde;
PageTable* pt = root;
uint64_t indexes[3];
decompose_vaddr(vaddr, page_index, indexes[2], indexes[1], indexes[0]);
for (int i = 0; i < 3; i++)
{
pde = &pt->entries[indexes[i]];
if (!pde->present) return;
else
PDE = PDP->entries[PD_i];
PageTable* PD;
if (!PDE.Present)
{
pde->user = true;
if (pde->larger_pages) return;
pt = (PageTable*)pde->get_address();
return; // Already unmapped
}
else { PD = (PageTable*)((uint64_t)PDE.Address << 12); }
PDE = PD->entries[PT_i];
PageTable* PT;
if (!PDE.Present)
{
return; // Already unmapped
}
else { PT = (PageTable*)((uint64_t)PDE.Address << 12); }
PDE = PT->entries[P_i];
PDE.Present = false;
PT->entries[P_i] = PDE;
}
pde = &pt->entries[page_index];
if (!pde->present) return;
else
pde->user = true;
}
uint64_t VirtualMemoryManager::getPhysical(uint64_t virtualAddress)
{
virtualAddress >>= 12;
uint64_t P_i = virtualAddress & 0x1ff;
virtualAddress >>= 9;
uint64_t PT_i = virtualAddress & 0x1ff;
virtualAddress >>= 9;
uint64_t PD_i = virtualAddress & 0x1ff;
virtualAddress >>= 9;
uint64_t PDP_i = virtualAddress & 0x1ff;
void VMM::flush_tlb(uint64_t addr)
{
asm volatile("invlpg (%0)" : : "r"(addr) : "memory");
}
PageDirectoryEntry PDE;
void VMM::decompose_vaddr(uint64_t vaddr, uint64_t& page_index, uint64_t& pt_index, uint64_t& pd_index,
uint64_t& pdp_index)
{
vaddr >>= 12;
page_index = vaddr & 0x1ff;
vaddr >>= 9;
pt_index = vaddr & 0x1ff;
vaddr >>= 9;
pd_index = vaddr & 0x1ff;
vaddr >>= 9;
pdp_index = vaddr & 0x1ff;
}
PDE = PML4->entries[PDP_i];
PageTable* PDP;
if (!PDE.Present)
{
return UINT64_MAX; // Not mapped
}
else { PDP = (PageTable*)((uint64_t)PDE.Address << 12); }
uint64_t VMM::recompose_vaddr(uint64_t page_index, uint64_t pt_index, uint64_t pd_index, uint64_t pdp_index)
{
return pdp_index << 39 | pd_index << 30 | pt_index << 21 | page_index << 12;
}
PDE = PDP->entries[PD_i];
PageTable* PD;
if (!PDE.Present)
{
return UINT64_MAX; // Not mapped
}
else { PD = (PageTable*)((uint64_t)PDE.Address << 12); }
void VMM::install_kernel_page_directory_into_address_space(AddressSpace& space)
{
PageTable* space_pml4 = space.get_pml4();
PageTable* kernel_last_pdp = (PageTable*)kernel_pml4->entries[511].get_address();
PageTable* kernel_last_pd = (PageTable*)kernel_last_pdp->entries[511].get_address();
PDE = PD->entries[PT_i];
PageTable* PT;
if (!PDE.Present)
{
return UINT64_MAX; // Not mapped
}
else { PT = (PageTable*)((uint64_t)PDE.Address << 12); }
PageTable* space_last_pdp = (PageTable*)PMM::request_page();
PDE = PT->entries[P_i];
return PDE.Address << 12;
}
PageDirectoryEntry& space_last_pdp_pde = space_pml4->entries[511];
uint64_t VirtualMemoryManager::getFlags(uint64_t virtualAddress)
{
virtualAddress >>= 12;
uint64_t P_i = virtualAddress & 0x1ff;
virtualAddress >>= 9;
uint64_t PT_i = virtualAddress & 0x1ff;
virtualAddress >>= 9;
uint64_t PD_i = virtualAddress & 0x1ff;
virtualAddress >>= 9;
uint64_t PDP_i = virtualAddress & 0x1ff;
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 PDE;
PageDirectoryEntry& space_last_pd_pde = space_last_pdp->entries[511];
PDE = PML4->entries[PDP_i];
PageTable* PDP;
if (!PDE.Present)
{
return 0; // Not mapped
}
else { PDP = (PageTable*)((uint64_t)PDE.Address << 12); }
space_last_pd_pde.present = true;
space_last_pd_pde.read_write = true;
space_last_pd_pde.set_address((uint64_t)kernel_last_pd);
PDE = PDP->entries[PD_i];
PageTable* PD;
if (!PDE.Present)
{
return 0; // Not mapped
}
else { PD = (PageTable*)((uint64_t)PDE.Address << 12); }
PDE = PD->entries[PT_i];
PageTable* PT;
if (!PDE.Present)
{
return 0; // Not mapped
}
else { PT = (PageTable*)((uint64_t)PDE.Address << 12); }
uint64_t flags = 0;
PDE = PT->entries[P_i];
if (PDE.UserSuper) flags |= User;
if (PDE.ReadWrite) flags |= ReadWrite;
return flags;
}
void VirtualMemoryManager::map(uint64_t virtualAddress, uint64_t physicalAddress, int flags)
{
virtualAddress >>= 12;
uint64_t P_i = virtualAddress & 0x1ff;
virtualAddress >>= 9;
uint64_t PT_i = virtualAddress & 0x1ff;
virtualAddress >>= 9;
uint64_t PD_i = virtualAddress & 0x1ff;
virtualAddress >>= 9;
uint64_t PDP_i = virtualAddress & 0x1ff;
PageDirectoryEntry PDE;
PDE = PML4->entries[PDP_i];
PageTable* PDP;
if (!PDE.Present)
{
PDP = (PageTable*)PMM::request_page();
ASSERT(!(PMM_DID_FAIL(PDP)));
memset(PDP, 0, 0x1000);
PDE.set_address((uint64_t)PDP);
PDE.Present = true;
PDE.ReadWrite = true;
if (flags & User) PDE.UserSuper = true;
PML4->entries[PDP_i] = PDE;
}
else { PDP = (PageTable*)((uint64_t)PDE.Address << 12); }
if ((flags & User) && !PDE.UserSuper)
{
PDE.UserSuper = true;
PML4->entries[PDP_i] = PDE;
}
PDE = PDP->entries[PD_i];
PageTable* PD;
if (!PDE.Present)
{
PD = (PageTable*)PMM::request_page();
ASSERT(!(PMM_DID_FAIL(PD)));
memset(PD, 0, 0x1000);
PDE.set_address((uint64_t)PD);
PDE.Present = true;
PDE.ReadWrite = true;
if (flags & User) PDE.UserSuper = true;
PDP->entries[PD_i] = PDE;
}
else { PD = (PageTable*)((uint64_t)PDE.Address << 12); }
if ((flags & User) && !PDE.UserSuper)
{
PDE.UserSuper = true;
PDP->entries[PD_i] = PDE;
}
PDE = PD->entries[PT_i];
PageTable* PT;
if (!PDE.Present)
{
PT = (PageTable*)PMM::request_page();
ASSERT(!(PMM_DID_FAIL(PT)));
memset(PT, 0, 0x1000);
PDE.set_address((uint64_t)PT);
PDE.Present = true;
PDE.ReadWrite = true;
if (flags & User) PDE.UserSuper = true;
PD->entries[PT_i] = PDE;
}
else { PT = (PageTable*)((uint64_t)PDE.Address << 12); }
if ((flags & User) && !PDE.UserSuper)
{
PDE.UserSuper = true;
PD->entries[PT_i] = PDE;
}
PDE = PT->entries[P_i];
PDE.Present = true;
PDE.ReadWrite = flags & ReadWrite;
PDE.UserSuper = flags & User;
PDE.set_address(physicalAddress);
PT->entries[P_i] = PDE;
}
}

View File

@ -8,7 +8,7 @@
#endif
#ifndef MOON_MINOR
#define MOON_MINOR 11
#define MOON_MINOR 10
#endif
#ifndef _MOON_SUFFIX
@ -35,4 +35,4 @@ const char* __moon_version_suffix()
const char* moon_version()
{
return STRINGIZE_VALUE_OF(MOON_MAJOR) "." STRINGIZE_VALUE_OF(MOON_MINOR) MOON_SUFFIX;
}
}

View File

@ -8,7 +8,6 @@
#include "interrupts/Interrupts.h"
#include "io/IO.h"
#include "log/Log.h"
#include "memory/VMM.h"
#include "misc/hang.h"
#include "std/string.h"
@ -86,11 +85,6 @@ static void try_idt_triple_fault()
[[noreturn]] void reboot()
{
Interrupts::disable();
if (!VMM::is_using_kernel_address_space())
{
VMM::switch_back_to_kernel_address_space();
VMM::apply_address_space();
}
kinfoln("Attempting reboot using ACPI");
try_acpi_reboot();
kinfoln("Attempting reboot using keyboard RESET pulsing");

View File

@ -0,0 +1,6 @@
#include "misc/utils.h"
uint64_t Utilities::get_blocks_from_size(uint64_t blocksize, uint64_t size)
{
return (size + (blocksize - 1)) / blocksize;
}

View File

@ -1,5 +1,4 @@
#include "std/string.h"
#include "std/stdlib.h"
#include <string.h>
size_t strlen(const char* __s)
{
@ -122,12 +121,4 @@ void* memmove(void* dest, void* src, size_t n)
for (long i = 0; i < (long)n; i++) { *((char*)dest + i) = *((char*)src + i); }
}
return dest;
}
char* strdup(const char* src)
{
size_t length = strlen(src);
char* duplicated = (char*)kmalloc(length + 1);
memcpy(duplicated, src, length + 1);
return duplicated;
}

View File

@ -1,14 +1,11 @@
#include "sys/Syscall.h"
#include "errno.h"
#include "io/Serial.h"
#include "memory/VMM.h"
#include "std/string.h"
#include "thread/Scheduler.h"
void Syscall::entry(Context* context)
{
asm volatile("cli");
VMM::enter_syscall_context();
switch (context->rax)
{
case SYS_exit: sys_exit(context, (int)context->rdi); break;
@ -23,16 +20,6 @@ void Syscall::entry(Context* context)
case SYS_open: sys_open(context, (const char*)context->rdi, (int)context->rsi); break;
case SYS_read: sys_read(context, (int)context->rdi, context->rsi, (char*)context->rdx); break;
case SYS_close: sys_close(context, (int)context->rdi); break;
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;
default: context->rax = -ENOSYS; break;
}
VMM::exit_syscall_context();
}
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; }
return strdup((const char*)phys);
}

View File

@ -1,19 +1,14 @@
#define MODULE "elf"
#include "sys/elf/ELFLoader.h"
#include "assert.h"
#include "errno.h"
#include "fs/VFS.h"
#include "init/InitRD.h"
#include "log/Log.h"
#include "memory/Memory.h"
#include "memory/MemoryManager.h"
#include "memory/VMM.h"
#include "misc/utils.h"
#include "std/stdlib.h"
#include "std/string.h"
#include "sys/elf/ELF.h"
#include "utils/Addresses.h"
static const char* format_permissions(uint32_t flags)
{
@ -41,72 +36,78 @@ ELFImage* ELFLoader::load_elf_from_filesystem(const char* filename)
return 0;
}
ELFImage* result = load_elf_from_vfs(node);
void* file = kmalloc(node->length);
if (VFS::read(node, 0, node->length, (char*)file) < 0)
{
kwarnln("Failed to read ELF image from file");
kfree(file);
return 0;
}
ELFImage* result =
load_elf_from_address((uintptr_t)file); // FIXME: Read headers and sections as we go along the file, to avoid
// loading the entire file at once into memory.
kfree(file);
return result;
}
long ELFLoader::check_elf_image_from_filesystem(const char* filename)
ELFImage* ELFLoader::load_elf_from_address(uintptr_t addr)
{
VFS::Node* node = VFS::resolve_path(filename);
if (!node)
Elf64_Ehdr* elf_ehdr = (Elf64_Ehdr*)addr;
if (strncmp((const char*)elf_ehdr->e_ident, ELFMAG, SELFMAG) != 0)
{
kwarnln("Failed to open file %s for checking", filename);
return -ENOENT;
kwarnln("ELF file has invalid magic, skipping");
return 0;
}
if (node->type == VFS_DIRECTORY)
if (elf_ehdr->e_ident[EI_CLASS] != ELFCLASS64)
{
kwarnln("Failed to check %s: is a directory", filename);
return -EISDIR;
kwarnln("ELF file is not ELF64, skipping");
return 0;
}
if (elf_ehdr->e_ident[EI_DATA] != ELFDATA2LSB)
{
kwarnln("ELF file is not little-endian, skipping");
return 0;
}
if (elf_ehdr->e_type != ET_EXEC)
{
kwarnln("not supported: ELF file is not an executable");
return 0;
}
if (elf_ehdr->e_machine != EM_MACH)
{
kwarnln("Unsupported target machine");
return 0;
}
if (elf_ehdr->e_phnum == 0)
{
kwarnln("ELF file has no PHDRS");
return 0;
}
return check_elf_image(node);
}
ELFImage* ELFLoader::load_elf_from_vfs(VFS::Node* node)
{
Elf64_Ehdr elf_ehdr;
ASSERT(VFS::read(node, 0, sizeof(elf_ehdr), (char*)&elf_ehdr) >= 0);
ASSERT(strncmp((const char*)elf_ehdr.e_ident, ELFMAG, SELFMAG) ==
0); // If you haven't checked the ELF executable with check_elf_image() first, then an assertion fail is your
// fault =D
ASSERT(elf_ehdr.e_ident[EI_CLASS] == ELFCLASS64);
ASSERT(elf_ehdr.e_ident[EI_DATA] == ELFDATA2LSB);
ASSERT(elf_ehdr.e_type == ET_EXEC);
ASSERT(elf_ehdr.e_machine == EM_MACH);
ASSERT(elf_ehdr.e_phnum != 0);
ELFImage* image = (ELFImage*)kmalloc(sizeof(ELFImage) - sizeof(ELFSection));
memset(image, 0, sizeof(ELFImage) - sizeof(ELFSection));
image->entry = elf_ehdr.e_entry;
image->entry = elf_ehdr->e_entry;
int i;
Elf64_Phdr phdr;
for (VFS::read(node, elf_ehdr.e_phoff, sizeof(Elf64_Phdr), (char*)&phdr), i = 0; i < elf_ehdr.e_phnum;
i++, VFS::read(node, elf_ehdr.e_phoff + (i * elf_ehdr.e_phentsize), sizeof(Elf64_Phdr), (char*)&phdr))
Elf64_Phdr* phdr;
for (phdr = (Elf64_Phdr*)((uint64_t)addr + elf_ehdr->e_phoff), i = 0; i < elf_ehdr->e_phnum;
i++, phdr = (Elf64_Phdr*)((uint8_t*)phdr + elf_ehdr->e_phentsize))
{
if (phdr.p_type == PT_LOAD)
if (phdr->p_type == PT_LOAD)
{
kdbgln("Loading loadable segment at address %lx, file size %ld, mem size %ld, permissions %s", phdr.p_vaddr,
phdr.p_filesz, phdr.p_memsz, format_permissions(phdr.p_flags));
ASSERT(phdr.p_vaddr);
uint64_t pages = Utilities::get_blocks_from_size(PAGE_SIZE, (phdr.p_vaddr % PAGE_SIZE) + phdr.p_memsz);
void* buffer = (void*)((uint64_t)MemoryManager::get_pages_at(round_down_to_nearest_page(phdr.p_vaddr),
pages, MAP_READ_WRITE) +
(phdr.p_vaddr % PAGE_SIZE));
if (VMM::is_using_kernel_address_space()) { VMM::switch_to_previous_user_address_space(); }
VMM::apply_address_space();
VFS::read(node, phdr.p_offset, phdr.p_filesz, (char*)buffer);
memset((void*)((uint64_t)buffer + phdr.p_filesz), 0, phdr.p_memsz - phdr.p_filesz);
VMM::switch_back_to_kernel_address_space();
VMM::apply_address_space();
VMM::switch_to_previous_user_address_space();
MemoryManager::protect(buffer, pages, phdr.p_flags & 2 ? MAP_READ_WRITE | MAP_USER : MAP_USER);
kdbgln("Loading loadable segment at address %lx, file size %ld, mem size %ld, permissions %s",
phdr->p_vaddr, phdr->p_filesz, phdr->p_memsz, format_permissions(phdr->p_flags));
if (!phdr->p_vaddr)
{
kerrorln("Address is NULL, this is invalid :(");
return 0;
}
uint64_t pages = Utilities::get_blocks_from_size(0x1000, phdr->p_memsz);
void* buffer = MemoryManager::get_pages_at(phdr->p_vaddr, pages,
phdr->p_flags & 2 ? MAP_READ_WRITE | MAP_USER : MAP_USER);
memcpy(buffer, (void*)(addr + phdr->p_offset), phdr->p_filesz);
memset((void*)((uint64_t)buffer + phdr->p_filesz), 0, phdr->p_memsz - phdr->p_filesz);
image = (ELFImage*)krealloc(image, (sizeof(ELFImage) - sizeof(ELFSection)) +
(image->section_count + 1) * sizeof(ELFSection));
ELFSection& section = image->sections[image->section_count];
@ -116,86 +117,10 @@ ELFImage* ELFLoader::load_elf_from_vfs(VFS::Node* node)
}
else { kdbgln("skipping non-loadable segment"); }
}
ASSERT(image->section_count);
if (!image->section_count)
{
kfree(image);
return 0;
}
return image;
}
long ELFLoader::check_elf_image(VFS::Node* node)
{
Elf64_Ehdr elf_ehdr;
if (VFS::read(node, 0, sizeof(elf_ehdr), (char*)&elf_ehdr) < 0)
{
kwarnln("Unable to read ELF header");
return -1;
}
if (strncmp((const char*)elf_ehdr.e_ident, ELFMAG, SELFMAG) != 0)
{
kwarnln("ELF file has invalid magic, skipping");
return -1;
}
if (elf_ehdr.e_ident[EI_CLASS] != ELFCLASS64)
{
kwarnln("ELF file is not ELF64, skipping");
return -1;
}
if (elf_ehdr.e_ident[EI_DATA] != ELFDATA2LSB)
{
kwarnln("ELF file is not little-endian, skipping");
return -1;
}
if (elf_ehdr.e_type != ET_EXEC)
{
kwarnln("not supported: ELF file is not an executable");
return -1;
}
if (elf_ehdr.e_machine != EM_MACH)
{
kwarnln("Unsupported target machine");
return -1;
}
if (elf_ehdr.e_phnum == 0)
{
kwarnln("ELF file has no PHDRS");
return -1;
}
int i;
int loadable_sections = 0;
long memusage = 0;
Elf64_Phdr phdr;
for (VFS::read(node, elf_ehdr.e_phoff, sizeof(Elf64_Phdr), (char*)&phdr), i = 0; i < elf_ehdr.e_phnum;
i++, VFS::read(node, elf_ehdr.e_phoff + (i * elf_ehdr.e_phentsize), sizeof(Elf64_Phdr), (char*)&phdr))
{
if (phdr.p_type == PT_LOAD)
{
if (!phdr.p_vaddr)
{
kerrorln("segment address is NULL, this is invalid :(");
return -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 -1;
}
loadable_sections++;
memusage += Utilities::get_blocks_from_size(PAGE_SIZE, phdr.p_memsz) * PAGE_SIZE;
}
}
if (!loadable_sections)
{
kwarnln("No loadable sections");
return -1;
}
return memusage;
}
void ELFLoader::release_elf_image(ELFImage* image)
{
for (uint64_t i = 0; i < image->section_count; i++)
{
ELFSection& section = image->sections[i];
kdbgln("Freeing up section %lx, was using %ld pages", section.base, section.pages);
MemoryManager::release_pages((void*)round_down_to_nearest_page(section.base), section.pages);
}
kfree(image);
}

View File

@ -1,96 +0,0 @@
#define MODULE "exec"
#include "assert.h"
#include "errno.h"
#include "interrupts/Interrupts.h"
#include "memory/MemoryManager.h"
#include "memory/PMM.h"
#include "memory/VMM.h"
#include "std/stdlib.h"
#include "std/string.h"
#include "sys/Syscall.h"
#include "sys/elf/ELFLoader.h"
#include "thread/Scheduler.h"
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)
{
context->rax = -EFAULT;
return;
}
kinfoln("exec(): executing %s", kpathname);
VFS::Node* program = VFS::resolve_path(kpathname);
if (!program)
{
kfree(kpathname);
context->rax = -ENOENT;
return;
}
if (program->type == VFS_DIRECTORY)
{
kfree(kpathname);
context->rax = -EISDIR;
return;
}
long memusage;
if ((memusage = ELFLoader::check_elf_image(program)) < 0)
{
kfree(kpathname);
context->rax = -ENOEXEC;
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;
}
Interrupts::disable();
ASSERT(!Interrupts::are_enabled()); // This part is pretty sensitive.
Task* task = Scheduler::current_task();
ASSERT(task);
// At this point, pretty much nothing can fail.
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.
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);
set_context_from_task(*task, context);
kfree(kpathname);
return;
}

View File

@ -5,7 +5,6 @@
#include "log/Log.h"
#include "memory/MemoryManager.h"
#include "memory/VMM.h"
#include "misc/utils.h"
#include <stddef.h>
#define MAP_FAIL(errno) 0xffffffffffffff00 | (unsigned char)(errno)
@ -14,13 +13,7 @@ void sys_mmap(Context* context, void* address, size_t size, int flags)
{
if (size < PAGE_SIZE)
{
kwarnln("mmap(): size too small");
context->rax = MAP_FAIL(EINVAL);
return;
}
if (size % PAGE_SIZE)
{
kwarnln("mmap(): size not a multiple of PAGE_SIZE");
kdbgln("sys_mmap: size too small");
context->rax = MAP_FAIL(EINVAL);
return;
}
@ -28,42 +21,40 @@ void sys_mmap(Context* context, void* address, size_t size, int flags)
if (flags & MAP_READ_WRITE) real_flags |= MAP_READ_WRITE;
if (address)
{
kdbgln("mmap(): %ld pages at address %p, %s", size / PAGE_SIZE, address,
kdbgln("sys_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.
if (kernelVMM.getPhysical((uint64_t)address) != (uint64_t)-1) // Address is already used.
{
kwarnln("attempt to map an already mapped address");
kdbgln("attempt to mmap an already mapped address");
context->rax = MAP_FAIL(ENOMEM);
return;
}
uint64_t offset = (uint64_t)address % PAGE_SIZE;
void* result = MemoryManager::get_pages_at((uint64_t)address - offset,
Utilities::get_blocks_from_size(PAGE_SIZE, size), real_flags);
void* result = MemoryManager::get_pages_at((uint64_t)address - offset, size / PAGE_SIZE, real_flags);
if (result)
{
kdbgln("mmap() succeeded: %p", result);
kdbgln("mmap succeeded: %p", result);
context->rax = (uint64_t)result;
return;
}
else
{
kwarnln("mmap() failed");
kdbgln("mmap failed");
context->rax = MAP_FAIL(ENOMEM);
return;
}
}
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);
kdbgln("sys_mmap: %ld pages at any address, %s", size / PAGE_SIZE, real_flags & MAP_READ_WRITE ? "rw" : "ro");
void* result = MemoryManager::get_pages(size / PAGE_SIZE, real_flags);
if (result)
{
kdbgln("mmap() succeeded: %p", result);
kdbgln("mmap succeeded: %p", result);
context->rax = (uint64_t)result;
return;
}
else
{
kwarnln("mmap() failed");
kdbgln("mmap failed");
context->rax = MAP_FAIL(ENOMEM);
return;
}
@ -71,35 +62,29 @@ void sys_mmap(Context* context, void* address, size_t size, int flags)
void sys_munmap(Context* context, void* address, size_t size)
{
kdbgln("munmap(): attempting to unmap %p", address);
kdbgln("sys_munmap: attempting to unmap %p", address);
if (size < PAGE_SIZE)
{
kwarnln("munmap() failed: size is too small");
context->rax = -EINVAL;
return;
}
if (size % PAGE_SIZE)
{
kwarnln("munmap() failed: size is not a multiple of PAGE_SIZE");
kdbgln("munmap failed: size is too small");
context->rax = -EINVAL;
return;
}
if (!address)
{
kwarnln("munmap() failed: attempted to unmap page 0");
kdbgln("munmap failed: attempted to unmap page 0");
context->rax = -EINVAL;
return;
}
uint64_t flags = VMM::get_flags((uint64_t)address);
uint64_t flags = kernelVMM.getFlags((uint64_t)address);
if (!(flags & MAP_USER))
{
kwarnln("munmap() failed: attempted to unmap a non-existent or kernel page");
kdbgln("munmap failed: attempted to unmap a kernel page");
context->rax = -EINVAL;
return;
}
uint64_t offset = (uint64_t)address % PAGE_SIZE;
MemoryManager::release_pages((void*)((uint64_t)address - offset), Utilities::get_blocks_from_size(PAGE_SIZE, size));
kdbgln("munmap() succeeded");
MemoryManager::release_pages((void*)((uint64_t)address - offset), size / PAGE_SIZE);
kdbgln("munmap succeeded");
context->rax = 0;
return;
}

View File

@ -4,85 +4,46 @@
#include "interrupts/Context.h"
#include "io/Serial.h"
#include "log/Log.h"
#include "memory/VMM.h"
#include "render/TextRenderer.h"
#include "std/stdlib.h"
#include "sys/Syscall.h"
#include "thread/Scheduler.h"
#include "thread/Task.h"
#define OPEN_READ 1
#define OPEN_WRITE 2
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
void sys_seek(Context* context, int fd, long offset, int whence)
{
if (whence < SEEK_SET || whence > SEEK_END)
{
context->rax = -EINVAL;
return;
}
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;
}
long new_offset;
if (whence == SEEK_SET) new_offset = offset;
else if (whence == SEEK_CUR)
new_offset = offset + current_task->files[fd].offset();
else if (whence == SEEK_END)
new_offset = current_task->files[fd].length() + offset;
else
__builtin_unreachable();
if (new_offset < 0)
{
context->rax = -EINVAL; // FIXME: Is this the right error?
return;
}
int result = current_task->files[fd].seek(new_offset);
if (result < 0)
{
context->rax = result;
return;
}
context->rax = new_offset;
return;
}
#define STDIO_FAIL(function, error) kwarnln("%s failed with %s", #function, #error)
void sys_write(Context* context, int fd, size_t size, const char* addr)
{
if (!addr)
{
context->rax = -EFAULT;
STDIO_FAIL(write, EINVAL);
context->rax = -EINVAL; // FIXME: This should probably return EFAULT.
return;
}
if (fd >= TASK_MAX_FDS || fd < 0)
{
kwarnln("file descriptor %d is outside the valid range", fd);
STDIO_FAIL(write, EBADF);
context->rax = -EBADF;
return;
}
Task* current_task = Scheduler::current_task();
if (!current_task->files[fd].is_open())
{
kwarnln("file descriptor %d is not open", fd);
STDIO_FAIL(write, EBADF);
context->rax = -EBADF;
return;
}
if (!current_task->files[fd].can_write())
{
kwarnln("file descriptor %d is not open for writing", fd);
STDIO_FAIL(write, EBADF);
context->rax = -EBADF;
return;
}
ssize_t result = current_task->files[fd].write(size, (const char*)VMM::get_physical((uint64_t)addr));
ssize_t result = current_task->files[fd].write(size, addr);
context->rax = (size_t)result;
return;
}
@ -98,21 +59,15 @@ void sys_open(Context* context, const char* filename, int flags)
if (fd == TASK_MAX_FDS)
{
STDIO_FAIL(open, EMFILE);
context->rax = -EMFILE;
return;
}
char* kernel_filename = Syscall::strdup_from_user(filename);
if (!kernel_filename)
{
context->rax = -EFAULT;
return;
}
VFS::Node* node = VFS::resolve_path(kernel_filename);
VFS::Node* node = VFS::resolve_path(filename);
if (!node)
{
kfree(kernel_filename);
STDIO_FAIL(open, ENOENT);
context->rax = -ENOENT;
return;
}
@ -121,18 +76,17 @@ void sys_open(Context* context, const char* filename, int flags)
bool can_write = (flags & OPEN_WRITE) > 0;
if (!can_read && !can_write)
{
kfree(kernel_filename);
STDIO_FAIL(open, EINVAL);
context->rax = -EINVAL;
return;
}
kdbgln("open(): opening %s %s, allocated file descriptor %d", kernel_filename,
kdbgln("open(): opening %s %s, allocated file descriptor %d", filename,
(can_read && can_write) ? "rw"
: can_read ? "r-"
: "-w",
fd);
kfree(kernel_filename);
current_task->files[fd].open(node, can_read, can_write);
context->rax = fd;
return;
@ -142,21 +96,24 @@ void sys_read(Context* context, int fd, size_t size, char* buffer)
{
if (!buffer)
{
context->rax = -EFAULT;
STDIO_FAIL(read, EINVAL);
context->rax = -EINVAL; // FIXME: This should probably return EFAULT.
return;
}
if (fd >= TASK_MAX_FDS || fd < 0)
{
STDIO_FAIL(read, EBADF);
context->rax = -EBADF;
return;
}
Task* current_task = Scheduler::current_task();
if (!current_task->files[fd].is_open() || !current_task->files[fd].can_read())
{
STDIO_FAIL(read, EBADF);
context->rax = -EBADF;
return;
}
ssize_t result = current_task->files[fd].read(size, (char*)VMM::get_physical((uint64_t)buffer));
ssize_t result = current_task->files[fd].read(size, buffer);
context->rax = (size_t)result;
return;
}
@ -165,12 +122,14 @@ void sys_close(Context* context, int fd)
{
if (fd >= TASK_MAX_FDS || fd < 0)
{
STDIO_FAIL(close, EBADF);
context->rax = -EBADF;
return;
}
Task* current_task = Scheduler::current_task();
if (!current_task->files[fd].is_open())
{
STDIO_FAIL(close, EBADF);
context->rax = -EBADF;
return;
}

View File

@ -7,15 +7,14 @@
#include "memory/MemoryManager.h"
#include "memory/VMM.h"
#include "misc/hang.h"
#include "misc/utils.h"
#include "panic/Panic.h"
#include "std/stdlib.h"
#include "std/string.h"
#include "sys/elf/ELFLoader.h"
#include "thread/PIT.h"
#include "thread/Task.h"
#include "utils/Addresses.h"
#include "utils/Registers.h"
#define TASK_PAGES_IN_STACK 4
static uint64_t task_num = 0;
@ -36,12 +35,11 @@ void Scheduler::init()
memset(&idle_task, 0, sizeof(Task));
idle_task.id = free_tid++;
idle_task.regs.rip = (uint64_t)idle_task_function;
idle_task.regs.rsp = get_top_of_stack((uint64_t)MemoryManager::get_page(), 1);
idle_task.regs.rsp = (uint64_t)MemoryManager::get_page();
idle_task.regs.cs = 0x08;
idle_task.regs.ss = 0x10;
idle_task.regs.rflags = (1 << 21) | (1 << 9);
idle_task.task_sleep = 1000;
idle_task.user_task = false;
idle_task.state = idle_task.Idle;
base_task = new Task;
@ -52,7 +50,6 @@ void Scheduler::init()
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
@ -63,16 +60,16 @@ void Scheduler::add_kernel_task(void (*task)(void))
{
Task* new_task = new Task;
ASSERT(new_task);
new_task->user_task = false;
new_task->id = free_tid++;
new_task->regs.rip = (uint64_t)task;
new_task->allocated_stack =
(uint64_t)MemoryManager::get_pages(TASK_PAGES_IN_STACK); // 16 KB is enough for everyone, right?
new_task->regs.rsp = get_top_of_stack(new_task->allocated_stack, TASK_PAGES_IN_STACK);
new_task->regs.rsp = new_task->allocated_stack + (PAGE_SIZE * TASK_PAGES_IN_STACK) - sizeof(uintptr_t);
new_task->regs.cs = 0x08;
new_task->regs.ss = 0x10;
new_task->regs.ds = 0x10;
new_task->regs.rflags = read_rflags() | 0x200; // enable interrupts
asm volatile("pushfq; movq (%%rsp), %%rax; movq %%rax, %0; popfq;" : "=m"(new_task->regs.rflags)::"%rax");
new_task->regs.rflags |= 0x200; // enable interrupts
new_task->task_sleep = 0;
new_task->task_time = 0;
new_task->cpu_time = 0;
@ -87,16 +84,19 @@ void Scheduler::add_kernel_task(void (*task)(void))
new_task->id, new_task->regs.rsp, task_num);
}
Task* Scheduler::create_user_task()
void Scheduler::add_user_task(void* task)
{
Task* new_task = new Task;
ASSERT(new_task);
memset(&new_task->regs, 0, sizeof(Context));
new_task->user_task = true;
new_task->id = free_tid++;
new_task->regs.rip = (uint64_t)task;
new_task->allocated_stack = (uint64_t)MemoryManager::get_pages(
TASK_PAGES_IN_STACK, MAP_READ_WRITE | MAP_USER); // 16 KB is enough for everyone, right?
new_task->regs.rsp = get_top_of_stack(new_task->allocated_stack, TASK_PAGES_IN_STACK);
new_task->regs.rsp = new_task->allocated_stack + (PAGE_SIZE * TASK_PAGES_IN_STACK) - sizeof(uintptr_t);
new_task->regs.cs = 0x18 | 0x03;
new_task->regs.ss = 0x20 | 0x03;
new_task->regs.ds = 0x20 | 0x03;
new_task->regs.rflags = (1 << 21) | (1 << 9); // enable interrupts
new_task->task_sleep = 0;
new_task->task_time = 0;
new_task->cpu_time = 0;
@ -105,36 +105,30 @@ Task* Scheduler::create_user_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++;
return new_task;
kinfoln("Adding user 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);
}
void Scheduler::load_user_task(const char* filename)
{
kinfoln("Loading user task: %s", filename);
Interrupts::push_and_disable();
if (ELFLoader::check_elf_image_from_filesystem(filename) < 0)
{
kerrorln("Failed to load %s from initrd", filename);
Interrupts::pop();
return;
}
Task* new_task = new Task;
ASSERT(new_task);
memset(&new_task->regs, 0, sizeof(Context));
new_task->id = free_tid++;
new_task->address_space = AddressSpace::create();
VMM::switch_to_user_address_space(new_task->address_space);
ELFImage* image = ELFLoader::load_elf_from_filesystem(
filename); // FIXME: TOCTOU? Right now, impossible, since interrupts are disabled and SMP is not a thing. But in
// the future, it might be possible.
ASSERT(image);
new_task->user_task = true;
ELFImage* image = ELFLoader::load_elf_from_filesystem(filename);
if (!image)
{
kerrorln("Failed to load %s from initrd", filename);
delete new_task;
return;
}
new_task->regs.rip = image->entry;
new_task->image = image;
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.rsp = new_task->allocated_stack + (PAGE_SIZE * TASK_PAGES_IN_STACK) - sizeof(uintptr_t);
new_task->regs.cs = 0x18 | 0x03;
new_task->regs.ss = 0x20 | 0x03;
new_task->regs.ds = 0x20 | 0x03;
@ -151,25 +145,6 @@ void Scheduler::load_user_task(const char* filename)
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();
}
void Scheduler::reset_task(Task* task, ELFImage* new_image)
{
memset(&task->regs, 0, sizeof(Context));
task->state = task->Running;
task->regs.rip = new_image->entry;
task->image = new_image;
task->regs.rsp = get_top_of_stack(task->allocated_stack, TASK_PAGES_IN_STACK);
task->regs.cs = 0x18 | 0x03;
task->regs.ss = 0x20 | 0x03;
task->regs.ds = 0x20 | 0x03;
task->regs.rflags = (1 << 21) | (1 << 9); // enable interrupts
task->task_sleep = 0;
task->cpu_time = 0;
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)
@ -178,29 +153,18 @@ void Scheduler::reap_task(Task* task)
task_num--;
Task* exiting_task = task;
ASSERT(task->id != 0); // WHY IN THE WORLD WOULD WE BE REAPING THE IDLE TASK?
if (exiting_task->is_user_task())
{
VMM::switch_back_to_kernel_address_space();
VMM::apply_address_space();
VMM::switch_to_user_address_space(exiting_task->address_space);
}
kinfoln("reaping task %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.
if (exiting_task->image)
{
// ELFLoader::release_elf_image(exiting_task->image);
for (uint64_t i = 0; i < exiting_task->image->section_count; i++)
{
ELFSection& section = exiting_task->image->sections[i];
kdbgln("Task was using region %lx, which used %ld pages", section.base, section.pages);
}
kfree(exiting_task->image);
}
if (exiting_task->is_user_task())
{
VMM::switch_back_to_kernel_address_space();
VMM::apply_address_space();
Interrupts::push_and_enable();
exiting_task->address_space.destroy();
Interrupts::pop();
}
for (int i = 0; i < TASK_MAX_FDS; i++) { exiting_task->files[i].close(); }
delete exiting_task;
}
@ -327,17 +291,7 @@ void Scheduler::task_yield(Context* context)
{
task_save_floating(*original_task);
}
if (sched_current_task->is_user_task())
{
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())
{
VMM::switch_back_to_kernel_address_space();
VMM::apply_address_space();
}
if (sched_current_task->is_user_task()) { task_restore_floating(*sched_current_task); }
}
sched_current_task->task_time = 20;
set_context_from_task(*sched_current_task, context);

View File

@ -25,5 +25,5 @@ void task_restore_floating(Task& task)
bool Task::is_user_task()
{
return user_task;
return (regs.cs & 3) > 0;
}

View File

@ -1,8 +0,0 @@
#ifndef _BITS_SEEK_H
#define _BITS_SEEK_H
#define SEEK_SET 0 // Seek from beginning of file.
#define SEEK_CUR 1 // Seek from current position.
#define SEEK_END 2 // Seek from end of file.
#endif

View File

@ -1,18 +1,15 @@
#ifndef _ERRNO_H
#define _ERRNO_H
/* The last error encountered during a call to a library or system function. */
extern int errno;
#define EPERM 1 // Operation not permitted
#define ENOENT 2 // No such file or directory
#define 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
#define EPERM 1
#define ENOENT 2
#define EBADF 9
#define ENOMEM 12
#define EISDIR 21
#define EINVAL 22
#define EMFILE 24
#define ENOSYS 38
#endif

View File

@ -1,11 +1,8 @@
#ifndef _FCNTL_H
#define _FCNTL_H
/* Open for reading only. */
#define O_RDONLY 1
/* Open for writing only. */
#define O_WRONLY 2
/* Open for reading and writing. */
#define O_RDWR 3
#ifdef __cplusplus
@ -13,8 +10,7 @@ extern "C"
{
#endif
/* Opens the file specified by pathname. Returns a file descriptor on success, or -1 on error. */
int open(const char* pathname, int flags);
int open(const char*, int);
#ifdef __cplusplus
}

View File

@ -9,13 +9,8 @@ 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. */
unsigned int msleep(unsigned int);
noreturn void __luna_abort(const char* message);
#ifdef __cplusplus

View File

@ -13,8 +13,6 @@
#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

@ -4,7 +4,7 @@
#include <stdarg.h>
#include <stddef.h>
#include <bits/seek.h>
#define SEEK_SET 0
typedef struct
{
@ -13,109 +13,36 @@ typedef struct
int f_err;
} FILE;
extern FILE* stderr;
extern FILE* stdout;
#define stdout stdout
#define stderr stderr
typedef struct
{
long f_offset;
} fpos_t;
extern FILE* __stderr;
extern FILE* __stdout;
#define stderr __stderr
#define stdout __stdout
#ifdef __cplusplus
extern "C"
{
#endif
/* Closes the file handle stream. */
int fclose(FILE* stream);
/* Does not do anything for now, since buffered IO is not implemented yet. */
int fflush(FILE* stream);
/* Opens the file specified by pathname. Returns the file handle on success, or NULL on error. */
FILE* fopen(const char* pathname, const char* mode);
/* Returns a new file associated with the file descriptor fd. */
FILE* fdopen(int fd, const char* mode);
/* Writes formatted output according to the string format to the file stream. */
int fprintf(FILE* stream, const char* format, ...);
/* Reads nmemb items of size size from the file stream into buf. */
size_t fread(void* buf, size_t size, size_t nmemb, FILE* stream);
/* Moves stream's read/write offset by offset, depending on whence. */
int fseek(FILE* stream, long offset, int whence);
/* Moves stream's read/write offset to the offset stored in the pos structure. */
int fsetpos(FILE* stream, const fpos_t* pos);
/* Returns the current offset for stream. */
long ftell(FILE* stream);
/* Stores the current offset for stream in the pos structure. */
int fgetpos(FILE* stream, fpos_t* pos);
/* Rewinds stream's offset to start of file. */
void rewind(FILE* stream);
/* Writes nmemb items of size size from buf into the file stream. */
size_t fwrite(const void* buf, size_t size, size_t nmemb, FILE* stream);
/* Returns nonzero if the error flag in stream was set. */
int ferror(FILE* stream);
/* Returns nonzero if the end-of-file flag in stream was set. */
int feof(FILE* stream);
/* Clears the error and end-of-file flags from stream. */
void clearerr(FILE* stream);
void setbuf(FILE*, char*); // Not implemented.
/* Writes formatted output according to the string format to the file stream. */
int vfprintf(FILE* stream, const char* format, va_list ap);
/* Writes formatted output according to the string format to standard output. */
int printf(const char* format, ...);
/* Writes formatted output according to the string format to standard output. */
int vprintf(const char* format, va_list ap);
/* Writes formatted output according to the string format to the string str. This function is unsafe, use snprintf
* instead. */
int sprintf(char* str, const char* format, ...);
/* Writes at most max bytes of formatted output according to the string format to the string str.*/
int snprintf(char* str, size_t max, const char* format, ...);
/* Writes formatted output according to the string format to the string str. This function is unsafe, use vsnprintf
* instead. */
int vsprintf(char* str, const char* format, va_list ap);
/* Writes at most max bytes of formatted output according to the string format to the string str. */
int vsnprintf(char* str, size_t max, const char* format, va_list ap);
/* Writes the string str followed by a trailing newline to stdout. */
int puts(const char* str);
/* Writes the string str to the file stream. */
int fputs(const char* str, FILE* stream);
/* Writes the character c to the file stream. */
int fputc(int c, FILE* stream);
/* Writes the character c to the file stream. */
int putc(int c, FILE* stream);
/* Writes the character c to standard output. */
int putchar(int c);
/* Prints a message to standard error consisting of the string str followed by a colon and the string representation
* of the last error encountered during a call to a system or library function. */
void perror(const char* str);
int fclose(FILE*);
int fflush(FILE*);
FILE* fopen(const char*, const char*);
int fprintf(FILE*, const char*, ...);
size_t fread(void*, size_t, size_t, FILE*);
int fseek(FILE*, long, int);
long ftell(FILE*);
size_t fwrite(const void*, size_t, size_t, FILE*);
int ferror(FILE*);
int feof(FILE*);
void clearerr(FILE*);
void setbuf(FILE*, char*);
int vfprintf(FILE*, const char*, va_list);
int printf(const char*, ...);
int vprintf(const char*, va_list);
int sprintf(char*, const char*, ...);
int snprintf(char*, size_t, const char*, ...);
int vsprintf(char*, const char*, va_list);
int vsnprintf(char*, size_t, const char*, va_list);
int puts(const char*);
void perror(const char*);
#ifdef __cplusplus
}

View File

@ -9,37 +9,13 @@ extern "C"
{
#endif
/* Aborts the program. */
noreturn void abort();
/* Normally exits the program with the specified status code. */
noreturn void exit(int status);
/* Registers a handler function to be run at normal program termination. */
int atexit(void (*handler)(void));
/* Not implemented.*/
noreturn void exit(int);
int atexit(void (*)(void));
int atoi(const char*);
/* Not implemented. */
void free(void*);
char* getenv(const char*);
/* Allocates n bytes of memory and returns a pointer to it. This memory should be freed by calling free() when it is
* not in use anymore. */
void* malloc(size_t n);
/* Allocates enough bytes of memory for an array containing nmemb items of size n and returns a pointer to it. This
* memory should be freed by calling free() when it is not in use anymore. */
void* calloc(size_t nmemb, size_t n);
/* Resizes memory allocated by malloc() or calloc() to n bytes. Returns a pointer to the new resized region of
* memory, which should be used instead of the old one. This memory should be freed by calling free() when it is not
* in use anymore. */
void* realloc(void* ptr, size_t n);
/* Frees a pointer to memory allocated by malloc(), calloc() or realloc(). Accessing the contents of ptr afterwards
* is undefined behavior. */
void free(void* ptr);
void* malloc(size_t);
#ifdef __cplusplus
}

View File

@ -9,37 +9,21 @@ extern "C"
{
#endif
/* Copies n bytes from src to dst. */
void* memcpy(void* dest, const void* src, size_t n);
void* memcpy(void*, const void*, size_t);
void* memset(void*, int, size_t);
void* memclr(void*, size_t);
/* Sets n bytes of buf to c, cast to a character. */
void* memset(void* buf, int c, size_t n);
size_t strlen(const char*);
/* Clears n bytes of buf. */
void* memclr(void* buf, size_t n);
deprecated("strcpy is unsafe and should not be used; use strncpy instead") char* strcpy(char*, const char*);
char* strncpy(char*, const char*, size_t);
/* Returns the length of the string str. */
size_t strlen(const char* str);
char* strchr(const char*, int);
/* 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);
deprecated("strcat is unsafe and should not be used; use strncat instead") char* strcat(char*, const char*);
char* strncat(char*, const char*, size_t);
/* Copies at most max bytes from the string src into dest. */
char* strncpy(char* dest, const char* src, size_t max);
/* Returns a pointer to the first occurrence of the character c in str, or NULL if it is not found. */
char* strchr(const char* str, int c);
/* 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);
/* Returns the error string associated with the error number err. */
char* strerror(int err);
char* strerror(int);
#ifdef __cplusplus
}

View File

@ -2,9 +2,9 @@
#define _SYS_MMAN_H
#include <stddef.h>
#include <sys/types.h> // for off_t
/* Address returned by mmap when it fails. */
typedef unsigned long off_t;
#define MAP_FAILED (void*)-1
#define PROT_READ_WRITE 1
@ -16,13 +16,8 @@ extern "C"
{
#endif
/* Maps size bytes of memory (rounded up to the nearest page-aligned size) into the current process's address
* space at addr. If addr is null, the kernel will choose an address. */
void* mmap(void* addr, size_t size, int prot, int flags, int fd, off_t offset);
/* Unmaps size bytes of memory (rounded up to the nearest page-aligned size) at addr from the current process's
* address space. */
int munmap(void* addr, size_t size);
void* mmap(void*, size_t, int, int, int, off_t);
int munmap(void* addr, size_t len);
#ifdef __cplusplus
}

View File

@ -1,16 +1,8 @@
#ifndef _SYS_TYPES_H
#define _SYS_TYPES_H
/* The type of a process identifier. */
typedef long int pid_t;
/* The type returned by sizeof(). */
typedef unsigned long int size_t;
/* Signed version of size_t. */
typedef long int ssize_t;
/* The type of an offset into a file. */
typedef long int off_t;
#endif

View File

@ -1,8 +1,6 @@
#ifndef _UNISTD_H
#define _UNISTD_H
#include <bits/macros.h>
#include <bits/seek.h>
#include <sys/types.h>
#ifdef __cplusplus
@ -10,37 +8,16 @@ extern "C"
{
#endif
/* Executes the program program. On success, does not return. The second parameter (arguments) is not implemented
* for now. You can pass NULL to it. */
int execv(const char* program, char* const[]);
/* Not implemented. */
int execv(const char*, char* const[]);
int execve(const char*, char* const[], char* const[]);
/* Not implemented. */
int execvp(const char*, char* const[]);
/* Not implemented. */
pid_t fork(void);
long syscall(long, ...);
unsigned int sleep(unsigned int);
/* Terminates the program with the status code status. */
noreturn void _exit(int status);
/* Calls the kernel for a specific service, determined by number. */
long syscall(long number, ...);
/* Suspends execution for a chosen amount of seconds. */
unsigned int sleep(unsigned int seconds);
/* Reads count bytes from the file descriptor fd into the memory at buf. */
ssize_t read(int fd, void* buf, size_t count);
/* Writes count bytes of the memory at buf to the file descriptor fd. */
ssize_t write(int fd, const void* buf, size_t count);
/* Closes the file descriptor fd. */
int close(int fd);
/* Moves the read/write file offset for fd to offset, depending on whence. */
off_t lseek(int fd, off_t offset, int whence);
ssize_t read(int, void*, size_t);
ssize_t write(int, const void*, size_t);
int close(int);
#ifdef __cplusplus
}

View File

@ -1,25 +0,0 @@
#include <stdlib.h>
#include <unistd.h>
#define ATEXIT_MAX_FUNCS 32
typedef void (*atexit_func_t)(void);
atexit_func_t atexit_functions[ATEXIT_MAX_FUNCS];
int atexit_function_count = 0;
extern "C"
{
int atexit(atexit_func_t handler)
{
if (atexit_function_count >= ATEXIT_MAX_FUNCS) return -1;
atexit_functions[atexit_function_count++] = handler;
return 0;
}
noreturn void exit(int status)
{
for (int i = 0; i < atexit_function_count; i++) { atexit_functions[i](); }
_exit(status);
}
}

View File

@ -5,8 +5,8 @@
#include <stdlib.h>
#include <unistd.h>
FILE* stderr;
FILE* stdout;
FILE* __stderr;
FILE* __stdout;
extern "C"
{
@ -40,19 +40,6 @@ extern "C"
return stream;
}
FILE* fdopen(int fd, const char*)
{
if (fd < 0) // FIXME: Also check if the mode string is compatible with how fd was opened.
{
errno = EBADF;
return 0;
}
FILE* stream = (FILE*)malloc(sizeof(FILE));
stream->f_fd = fd;
clearerr(stream);
return stream;
}
size_t fread(void* buf, size_t size, size_t nmemb, FILE* stream)
{
ssize_t status = read(stream->f_fd, buf, size * nmemb);
@ -80,37 +67,14 @@ extern "C"
stream->f_err = stream->f_eof = 0;
}
int fseek(FILE* stream, long offset, int whence)
int fseek(FILE*, long, int)
{
long result = lseek(stream->f_fd, offset, whence);
if (result < 0) { return -1; }
return 0;
NOT_IMPLEMENTED("fseek");
}
int fsetpos(FILE* stream, const fpos_t* pos)
long ftell(FILE*)
{
return fseek(stream, pos->f_offset, SEEK_SET);
}
long ftell(FILE* stream)
{
return lseek(stream->f_fd, 0,
SEEK_CUR); // FIXME: Store the last seeked position in the file struct to avoid redundant syscalls
// maybe? We'd have to update this value in fread() and fwrite() as well...
}
int fgetpos(FILE* stream, fpos_t* pos)
{
long result = ftell(stream);
if (result < 0) { return -1; }
pos->f_offset = result;
return 0;
}
void rewind(FILE* stream)
{
lseek(stream->f_fd, 0, SEEK_SET);
clearerr(stream);
NOT_IMPLEMENTED("ftell");
}
size_t fwrite(const void* buf, size_t size, size_t nmemb, FILE* stream)

View File

@ -2,30 +2,13 @@
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static void terminate_libc()
{
fclose(stdout);
fclose(stderr);
}
static void check_for_file(int fd, FILE** target_stream, const char* path, const char* mode)
{
if (lseek(fd, 0, SEEK_CUR) < 0)
{
if (errno == EBADF) *target_stream = fopen(path, mode);
else
exit(errno);
if (!*target_stream) exit(errno);
errno = 0;
}
else { *target_stream = fdopen(fd, mode); }
}
extern "C" void initialize_libc()
{
check_for_file(0, &stdout, "/dev/console", "rw");
check_for_file(1, &stderr, "/dev/console", "rw");
atexit(terminate_libc);
__stderr = fopen("/dev/console", "rw");
if (!stderr) exit(errno);
__stdout = fopen("/dev/console", "rw");
if (!stdout) exit(errno);
clearerr(__stderr);
clearerr(__stdout);
}

View File

@ -5,6 +5,8 @@
#include <sys/syscall.h>
#include <unistd.h>
#define noreturn __attribute__((noreturn))
extern "C"
{
pid_t gettid()
@ -19,7 +21,7 @@ extern "C"
noreturn void __luna_abort(const char* message)
{
fputs(message, stderr);
fwrite(message, strlen(message), 1, stdout);
abort();
}
}

View File

@ -42,7 +42,7 @@ long int __luna_syscall5(long int sys_num, unsigned long int arg0, unsigned long
{
long int result;
register unsigned long int value0 asm("r10") = arg3;
register unsigned long int value1 asm("r8") = arg4;
register unsigned long int value1 asm("r10") = arg4;
asm volatile("int $0x42" : "=a"(result) : "a"(sys_num), "D"(arg0), "S"(arg1), "d"(arg2), "r"(value0), "r"(value1));
return result;
}

View File

@ -10,31 +10,10 @@ extern "C"
{
int puts(const char* s)
{
int nwritten = fputs(s, stdout);
long nwritten = fwrite(s, strlen(s), 1, stdout);
if (nwritten < 0) return -1;
if (putchar('\n') < 0) return -1;
return nwritten + 1;
}
int fputs(const char* s, FILE* stream)
{
int result = (int)fwrite(s, strlen(s), 1, stream);
if (ferror(stream)) return -1;
return result;
}
int fputc(int c, FILE* stream)
{
char chr = (char)c;
fwrite(&chr, 1, 1, stream);
if (ferror(stream)) { return -1; }
return c;
}
int putc(int c, FILE* stream)
{
return fputc(c, stream);
}
int putchar(int c)
{
return fputc(c, stdout);
nwritten += fwrite("\n", 1, 1, stdout);
return (int)nwritten;
}
void perror(const char* s)
{

View File

@ -3,18 +3,32 @@
#include <sys/syscall.h>
#include <unistd.h>
#define noreturn __attribute__((noreturn))
#define maybe_unused __attribute__((maybe_unused))
#define unused __attribute__((unused))
extern "C"
{
noreturn void abort()
{
_exit(-1);
exit(-1);
}
noreturn void exit(int status)
{
syscall(SYS_exit, status);
__builtin_unreachable();
}
int atexit(void (*)(void))
{
NOT_IMPLEMENTED("atexit");
}
int atoi(const char*)
{
NOT_IMPLEMENTED("atoi");
}
char* getenv(const char*)
{
NOT_IMPLEMENTED("getenv");

View File

@ -10,18 +10,18 @@ extern "C"
return dest;
}
void* memset(void* buf, int c, size_t n)
void* memset(void* dest, int c, size_t n)
{
for (size_t i = 0; i < n; ++i) { *((char*)buf + i) = (char)c; }
return buf;
for (size_t i = 0; i < n; ++i) { *((char*)dest + i) = (char)c; }
return dest;
}
size_t strlen(const char* str)
size_t strlen(const char* s)
{
const char* i = str;
const char* i = s;
for (; *i; ++i)
;
return (i - str);
return (i - s);
}
char* strcpy(char* dest, const char* src)
@ -30,10 +30,10 @@ extern "C"
return dest;
}
char* strncpy(char* dest, const char* src, size_t max) // FIXME: Implement strncpy according to the specification.
char* strncpy(char* dest, const char* src, size_t n)
{
size_t src_len = strlen(src) + 1; // NULL byte
memcpy(dest, src, src_len > max ? max : src_len);
memcpy(dest, src, src_len > n ? n : src_len);
return dest;
}
@ -49,40 +49,40 @@ extern "C"
return dest;
}
char* strncat(char* dest, const char* src, size_t max)
char* strncat(char* dest, const char* src, size_t n)
{
size_t dest_len = strlen(dest);
size_t i;
for (i = 0; i < max && *(src + i); i++) *(char*)(dest + dest_len + i) = *(const char*)(src + i);
for (i = 0; i < n && *(src + i); i++) *(char*)(dest + dest_len + i) = *(const char*)(src + i);
*(char*)(dest + dest_len + i) = '\0';
return dest;
}
char* strchr(const char* str, int c)
char* strchr(const char* str, int chr)
{
while (*str && *str != (char)c) str++;
while (*str && *str != (char)chr) str++;
if (*str) return const_cast<char*>(str);
return NULL;
}
void* memclr(void* buf, size_t n)
void* memclr(void* start, size_t count)
{
// "i" is our counter of how many bytes we've cleared
size_t i;
// find out if "m_start" is aligned on a SSE_XMM_SIZE boundary
if ((size_t)buf & (15))
if ((size_t)start & (15))
{
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)
while (((size_t)start + i) & (15) && i < count)
{
asm("stosb;" ::"D"((size_t)buf + i), "a"(0));
asm("stosb;" ::"D"((size_t)start + i), "a"(0));
i++;
}
}
@ -93,44 +93,42 @@ extern "C"
}
// clear 64-byte chunks of memory (4 16-byte operations)
for (; i + 64 <= n; i += 64)
for (; i + 64 <= count; 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));
" movdqa %%xmm0, 48(%0); " ::"r"((size_t)start + i));
}
// copy the remaining bytes (if any)
asm(" rep stosb; " ::"a"((size_t)(0)), "D"(((size_t)buf) + i), "c"(n - i));
asm(" rep stosb; " ::"a"((size_t)(0)), "D"(((size_t)start) + i), "c"(count - i));
// "i" will contain the total amount of bytes that were actually transfered
i += n - i;
i += count - i;
// we return "m_start" + the amount of bytes that were transfered
return (void*)(((size_t)buf) + i);
return (void*)(((size_t)start) + i);
}
#pragma GCC push_options
#pragma GCC diagnostic ignored "-Wwrite-strings"
char* strerror(int err)
char* strerror(int errnum)
{
switch (err)
switch (errnum)
{
case EPERM: return "Operation not permitted";
case EINVAL: return "Invalid argument";
case ENOMEM: return "Cannot allocate memory";
case ENOMEM: return "Out of memory";
case ENOSYS: return "Function not implemented";
case ENOENT: return "No such file or directory";
case EBADF: return "Bad file descriptor";
case EMFILE: return "Too many open files";
case EISDIR: return "Is a directory";
case ENOEXEC: return "Exec format error";
case EFAULT: return "Bad address";
case 0: return "Success";
default: return (char*)(unsigned long int)err;
default: return (char*)(unsigned long int)errnum;
}
}

View File

@ -6,9 +6,9 @@
extern "C"
{
int execv(const char* program, char* const[])
int execv(const char*, char* const[])
{
return (int)syscall(SYS_exec, program);
NOT_IMPLEMENTED("execv");
}
int execve(const char*, char* const[], char* const[])
{
@ -36,7 +36,6 @@ extern "C"
case SYS_rand: result = __luna_syscall0(number); break;
case SYS_exit:
case SYS_close:
case SYS_exec:
case SYS_sleep: result = __luna_syscall1(number, va_arg(ap, arg)); break;
case SYS_munmap:
case SYS_open: {
@ -45,7 +44,6 @@ extern "C"
result = __luna_syscall2(number, arg0, arg1);
break;
}
case SYS_seek:
case SYS_write:
case SYS_read:
case SYS_mmap: {
@ -90,15 +88,4 @@ extern "C"
{
return (int)syscall(SYS_close, fd);
}
off_t lseek(int fd, off_t offset, int whence)
{
return syscall(SYS_seek, fd, offset, whence);
}
noreturn void _exit(int status)
{
syscall(SYS_exit, status);
__builtin_unreachable();
}
}

0
tools/build-debug.sh Executable file → Normal file
View File

0
tools/gdb.sh Executable file → Normal file
View File