Compare commits
78 Commits
8bf1aac961
...
e145690db8
Author | SHA1 | Date | |
---|---|---|---|
e145690db8 | |||
25ab31c7ce | |||
d3ac590e24 | |||
112e375b5e | |||
c30041b733 | |||
88a01fcfc7 | |||
b67011c626 | |||
0f47f59364 | |||
2f46e46aa4 | |||
80ab982fe4 | |||
53a4b3b85e | |||
12cf37d0a7 | |||
e764647133 | |||
b1fcfd0d74 | |||
e67ef7778c | |||
f6e783ea45 | |||
8e57df518f | |||
0c451e504e | |||
04da26bff5 | |||
feb8c1c31b | |||
0131193379 | |||
86b50a6aa0 | |||
0a7d4a530d | |||
a198cf8d8d | |||
4aa3da8c12 | |||
1278cec065 | |||
7a097f16ea | |||
667d308fc3 | |||
6088031c49 | |||
81815a0bdd | |||
2a755fcd93 | |||
6c51477197 | |||
d25e8a43db | |||
4f2b3ce5d1 | |||
93f6be9319 | |||
9e0bd39964 | |||
1b84c443fe | |||
da2ede3450 | |||
63b2de4e3c | |||
da84f1713c | |||
bbe7c6e658 | |||
2be70d0bc1 | |||
8158ddc94f | |||
b38c52f8c7 | |||
f3d7e220ac | |||
49c7900407 | |||
4b74c14f1b | |||
3686e03bb7 | |||
3feb7782bc | |||
d5f59b666a | |||
8ce58e9e30 | |||
5fc543c179 | |||
40099feb80 | |||
3ee1f34bc4 | |||
c67079dd74 | |||
247645d301 | |||
f83a6ace51 | |||
1e0c8c5fe7 | |||
4a212b4c92 | |||
aa5c1be945 | |||
309058888c | |||
159d025d9f | |||
a5daa24fbf | |||
533b7c9e71 | |||
abcf1b6118 | |||
1235ce8b32 | |||
ce6ec3585c | |||
ac72d64490 | |||
a086ec514b | |||
9b778254f1 | |||
e76d903642 | |||
ee7558a9b7 | |||
d6f45c284e | |||
21e8ea1486 | |||
8f0b6d80b2 | |||
71e15e94af | |||
ad115e9bab | |||
1f655fabe2 |
4
.gdbconf
Normal file
4
.gdbconf
Normal file
@ -0,0 +1,4 @@
|
||||
file initrd/boot/moon.elf
|
||||
break _start
|
||||
target remote :1234
|
||||
continue
|
@ -38,6 +38,8 @@ There are a variety of scripts for building Luna.
|
||||
|
||||
`tools/build-iso.sh` will build, install, and make an ISO disk image named Luna.iso.
|
||||
|
||||
`tools/build-debug.sh` will rebuild the kernel with debug symbols and optimizations disabled, install, and make an ISO image. This script should only be used when you are going to be running the system with a debugger (such as GDB).
|
||||
|
||||
`tools/build-stable-iso.sh` does the same thing as build-iso.sh, but configures the kernel so that the version does not show the commit hash (used for stable versions).
|
||||
|
||||
`tools/rebuild-iso.sh` will do a clean rebuild, install, and make an ISO disk image.
|
||||
@ -54,7 +56,7 @@ You can choose between 3 run scripts:
|
||||
|
||||
`tools/rebuild-and-run.sh` will rebuild, install, make an ISO, and run Luna in QEMU.
|
||||
|
||||
`tools/debug.sh` will rebuild the kernel with debug symbols and optimizations disabled, install, make an ISO image, and run Luna in QEMU with a port open for GDB to connect to. (run `gdb initrd/boot/moon.elf`, `break _start`, `target remote :1234`, and then `debug.sh` for an optimal debugging experience)
|
||||
`tools/debug.sh` will run Luna in QEMU with a port open for GDB to connect to. (run `tools/build-debug.sh`, `tools/gdb.sh`, and then `tools/debug.sh` in a separate terminal for an optimal debugging experience)
|
||||
|
||||
Beware that running without hardware virtualization/with optimizations disabled may cause the kernel to behave differently, which is why I don't use it that often.
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
APPS := init fib leap art memeater
|
||||
APPS := init
|
||||
|
||||
APPS_DIR := $(LUNA_ROOT)/apps
|
||||
APPS_SRC := $(APPS_DIR)/src
|
||||
@ -6,11 +6,12 @@ APPS_BIN := $(APPS_DIR)/bin
|
||||
|
||||
REAL_APPS := $(patsubst %, $(APPS_BIN)/%, $(APPS))
|
||||
|
||||
CFLAGS := -Wall -Wextra -Werror
|
||||
CFLAGS := -Wall -Wextra -Werror -Os
|
||||
|
||||
$(APPS_BIN)/%: $(APPS_SRC)/%.c
|
||||
@mkdir -p $(@D)
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
$(STRIP) $@
|
||||
|
||||
build: $(REAL_APPS)
|
||||
|
||||
|
@ -1,18 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
sleep(1);
|
||||
|
||||
syscall(SYS_paint, 0, 0, 400, 300, 0x000000FF);
|
||||
|
||||
sleep(1);
|
||||
|
||||
printf("Hello, colorful world!\n");
|
||||
|
||||
sleep(1);
|
||||
|
||||
printf("Press any key to restart.");
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
#include <luna.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void fib_next(unsigned long int* a, unsigned long int* b)
|
||||
{
|
||||
unsigned long int _a = *a;
|
||||
unsigned long int _b = *b;
|
||||
*a = *b;
|
||||
*b = _a + _b;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
unsigned long int fib_a = 1;
|
||||
unsigned long int fib_b = 1;
|
||||
|
||||
printf("Calculating the 50 first Fibonacci numbers...\n");
|
||||
|
||||
sleep(2);
|
||||
|
||||
printf("%lu\n", fib_a);
|
||||
|
||||
msleep(500);
|
||||
|
||||
for (int i = 0; i < 49; i++)
|
||||
{
|
||||
printf("%lu\n", fib_b);
|
||||
fib_next(&fib_a, &fib_b);
|
||||
msleep(500);
|
||||
}
|
||||
|
||||
printf("\nDone, press any key to restart.\n");
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
#include <errno.h>
|
||||
#include <luna.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -5,6 +6,39 @@
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
typedef long ssize_t;
|
||||
|
||||
int print_version()
|
||||
{
|
||||
char version[4096];
|
||||
|
||||
FILE* verfile = fopen("/dev/version", "r");
|
||||
if (!verfile)
|
||||
{
|
||||
perror("fopen");
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t nread = fread(version, 4096, 1, verfile);
|
||||
if (ferror(verfile))
|
||||
{
|
||||
perror("fread");
|
||||
return 1;
|
||||
}
|
||||
|
||||
version[nread] = 0;
|
||||
|
||||
if (fclose(verfile) < 0)
|
||||
{
|
||||
perror("fclose");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Your kernel version is %s\n\n", version);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
if (gettid() == 0) // why are we the idle task?
|
||||
@ -18,21 +52,37 @@ int main()
|
||||
|
||||
sleep(1);
|
||||
|
||||
char version[40];
|
||||
syscall(SYS_getversion, version, sizeof(version));
|
||||
|
||||
printf("Your kernel version is %s\n\n", version);
|
||||
if (print_version()) return 1;
|
||||
|
||||
sleep(2);
|
||||
|
||||
const char* filename = "/sys/config";
|
||||
|
||||
printf("Opening %s for reading...\n", filename);
|
||||
|
||||
FILE* config = fopen(filename, "r");
|
||||
if (!config)
|
||||
{
|
||||
char* variable = malloc(200);
|
||||
*variable = 3;
|
||||
printf("Allocated variable at address %lx\n", (unsigned long int)variable);
|
||||
free(variable);
|
||||
perror("fopen");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Press any key to restart.\n");
|
||||
char buf[4096];
|
||||
|
||||
size_t nread = fread(buf, sizeof(buf), 1, config);
|
||||
if (ferror(config)) { perror("fread"); }
|
||||
else
|
||||
{
|
||||
buf[nread] = 0;
|
||||
|
||||
printf("Read %zd bytes\n\n", nread);
|
||||
|
||||
printf("%s", buf);
|
||||
}
|
||||
|
||||
if (fclose(config) < 0) { perror("fclose"); }
|
||||
|
||||
printf("\n\nPress any key to restart.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,38 +0,0 @@
|
||||
#include <luna.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
unsigned long random_year() // Return a year from 1000 to 2500.
|
||||
{
|
||||
unsigned long result = syscall(SYS_rand);
|
||||
return (result % 1500) + 1000;
|
||||
}
|
||||
|
||||
int is_leap(unsigned long year)
|
||||
{
|
||||
return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
printf("Welcome to the Luna Leap Year Program!\n\n");
|
||||
|
||||
sleep(1);
|
||||
|
||||
printf("Choosing a random year between 1000 and 2500... ");
|
||||
|
||||
msleep(500);
|
||||
|
||||
unsigned long year = random_year();
|
||||
|
||||
printf("%lu!\n\n", year);
|
||||
|
||||
sleep(1);
|
||||
|
||||
printf("%lu is %s\n", year, is_leap(year) ? "a leap year!" : "not a leap year :(");
|
||||
|
||||
msleep(500);
|
||||
|
||||
printf("Press any key to restart.\n");
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define CHUNK 4194304 // 4 MB
|
||||
|
||||
int main()
|
||||
{
|
||||
printf("Welcome to memeater! This little program is designed to eat up all the memory on your system.\n");
|
||||
sleep(1);
|
||||
void* allocated = malloc(CHUNK);
|
||||
do {
|
||||
printf("Allocating 4 MB of memory... %lx\n", (unsigned long)allocated);
|
||||
sleep(1);
|
||||
} while ((allocated = malloc(CHUNK)));
|
||||
printf("Out of memory.\n");
|
||||
}
|
@ -6,7 +6,7 @@ MOON_BIN := $(MOON_DIR)/bin
|
||||
CFLAGS := -pedantic -Wall -Wextra -Werror -Wfloat-equal -Wdisabled-optimization -Wformat=2 -Winit-self -Wmissing-include-dirs -Wswitch-default -Wcast-qual -Wundef -Wcast-align -Wwrite-strings -Wlogical-op -Wredundant-decls -Wshadow -Wconversion -Os -ffreestanding -fstack-protector-all -fno-omit-frame-pointer -mno-red-zone -mno-mmx -mno-sse -mno-sse2 -fshort-wchar -mcmodel=kernel -I$(MOON_DIR)/include -isystem $(MOON_DIR)/include/std
|
||||
CXXFLAGS := -fno-rtti -fno-exceptions -Wsign-promo -Wstrict-null-sentinel -Wctor-dtor-privacy
|
||||
ASMFLAGS := -felf64
|
||||
LDFLAGS := -T$(MOON_DIR)/moon.ld -nostdlib -lgcc -Wl,--build-id=none -z max-page-size=0x1000
|
||||
LDFLAGS := -T$(MOON_DIR)/moon.ld -nostdlib -lgcc -Wl,--build-id=none -z max-page-size=0x1000 -mno-red-zone -mcmodel=kernel
|
||||
|
||||
ifneq ($(MOON_BUILD_STABLE), 1)
|
||||
CFLAGS := ${CFLAGS} -D_MOON_SUFFIX=-$(shell git rev-parse --short HEAD)
|
||||
@ -54,7 +54,7 @@ $(MOON_OBJ)/%.asm.o: $(MOON_SRC)/%.asm
|
||||
|
||||
build: $(OBJS)
|
||||
@mkdir -p $(@D)
|
||||
$(CC) $(OBJS) $(CFLAGS) $(LDFLAGS) -o $(MOON_BIN)/moon.elf
|
||||
$(CC) $(OBJS) $(LDFLAGS) -o $(MOON_BIN)/moon.elf
|
||||
|
||||
clean:
|
||||
rm -rf $(MOON_OBJ)/*
|
||||
@ -64,6 +64,7 @@ install: $(MOON_BIN)/moon.elf
|
||||
@mkdir -p $(@D)
|
||||
cp $^ $(LUNA_ROOT)/initrd/boot/moon.elf
|
||||
$(LUNA_ROOT)/tools/generate-symbols.sh
|
||||
$(STRIP) $(LUNA_ROOT)/initrd/boot/moon.elf
|
||||
|
||||
.PHONY: build clean install FORCE
|
||||
FORCE:
|
10
kernel/include/errno.h
Normal file
10
kernel/include/errno.h
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#define EPERM 1
|
||||
#define ENOENT 2
|
||||
#define EBADF 9
|
||||
#define ENOMEM 12
|
||||
#define EISDIR 21
|
||||
#define EINVAL 22
|
||||
#define EMFILE 24
|
||||
#define ENOSYS 38
|
41
kernel/include/fs/FileDescriptor.h
Normal file
41
kernel/include/fs/FileDescriptor.h
Normal file
@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
#include "fs/VFS.h"
|
||||
#include <stdint.h>
|
||||
|
||||
struct Descriptor
|
||||
{
|
||||
bool is_open()
|
||||
{
|
||||
return m_is_open;
|
||||
}
|
||||
|
||||
bool can_read()
|
||||
{
|
||||
return m_can_read && m_is_open;
|
||||
}
|
||||
|
||||
bool can_write()
|
||||
{
|
||||
return m_can_write && m_is_open;
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
m_is_open = false;
|
||||
}
|
||||
|
||||
ssize_t read(size_t size, char* buffer);
|
||||
ssize_t write(size_t size, const char* buffer);
|
||||
|
||||
void open(VFS::Node* node, bool can_read, bool can_write);
|
||||
|
||||
Descriptor(const Descriptor& other);
|
||||
Descriptor();
|
||||
|
||||
private:
|
||||
bool m_is_open;
|
||||
bool m_can_read;
|
||||
bool m_can_write;
|
||||
VFS::Node* m_node;
|
||||
uint64_t m_offset;
|
||||
};
|
49
kernel/include/fs/VFS.h
Normal file
49
kernel/include/fs/VFS.h
Normal file
@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef long ssize_t;
|
||||
|
||||
#define VFS_FILE 0x0
|
||||
#define VFS_DIRECTORY 0x1
|
||||
|
||||
#define VFS_MOUNTPOINT 0x1
|
||||
|
||||
namespace VFS
|
||||
{
|
||||
struct Node;
|
||||
|
||||
typedef ssize_t (*node_read)(Node*, size_t, size_t, char*);
|
||||
typedef ssize_t (*node_write)(Node*, size_t, size_t, const char*);
|
||||
typedef Node* (*node_finddir)(Node*, const char*);
|
||||
typedef int (*node_mkdir)(Node*, const char*);
|
||||
|
||||
struct Node
|
||||
{
|
||||
char name[64];
|
||||
uint64_t inode;
|
||||
uint64_t length;
|
||||
int type;
|
||||
int flags;
|
||||
node_read read_func;
|
||||
node_finddir find_func;
|
||||
node_mkdir mkdir_func;
|
||||
node_write write_func;
|
||||
Node* link;
|
||||
};
|
||||
|
||||
ssize_t read(Node* node, size_t offset, size_t length, char* buffer);
|
||||
ssize_t write(Node* node, size_t offset, size_t length, const char* buffer);
|
||||
int mkdir(const char* path, const char* name); // FIXME: Support deducing this via a single path.
|
||||
|
||||
void mount_root(Node* root);
|
||||
|
||||
Node* resolve_path(const char* filename, Node* root = nullptr);
|
||||
|
||||
void mount(Node* mountpoint, Node* mounted);
|
||||
void mount(const char* pathname, Node* mounted);
|
||||
|
||||
void unmount(Node* mountpoint);
|
||||
|
||||
Node* root();
|
||||
}
|
9
kernel/include/fs/devices/Console.h
Normal file
9
kernel/include/fs/devices/Console.h
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include "fs/VFS.h"
|
||||
|
||||
namespace ConsoleDevice
|
||||
{
|
||||
VFS::Node* create_new();
|
||||
|
||||
ssize_t write(VFS::Node* node, size_t offset, size_t size, const char* buffer);
|
||||
}
|
9
kernel/include/fs/devices/DeviceFS.h
Normal file
9
kernel/include/fs/devices/DeviceFS.h
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include "fs/VFS.h"
|
||||
|
||||
namespace DeviceFS
|
||||
{
|
||||
VFS::Node* get();
|
||||
|
||||
VFS::Node* finddir(VFS::Node* node, const char* filename);
|
||||
}
|
9
kernel/include/fs/devices/Version.h
Normal file
9
kernel/include/fs/devices/Version.h
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include "fs/VFS.h"
|
||||
|
||||
namespace VersionDevice
|
||||
{
|
||||
VFS::Node* create_new();
|
||||
|
||||
ssize_t read(VFS::Node* node, size_t offset, size_t size, char* buffer);
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
namespace Ext2
|
||||
{
|
||||
struct Superblock
|
||||
{
|
||||
uint32_t fs_inodes; // Total number of inodes in file system
|
||||
uint32_t fs_blocks; // Total number of blocks in file system
|
||||
uint32_t su_blocks; // Number of blocks reserved for superuser
|
||||
uint32_t free_blocks; // Total number of unallocated blocks
|
||||
uint32_t free_inodes; // Total number of unallocated inodes
|
||||
uint32_t superblock_number; // Block number of the block containing the superblock
|
||||
uint32_t block_size; // log2(block size) - 10
|
||||
uint32_t frag_size; // log2(fragment size) - 10
|
||||
uint32_t num_blocks; // Number of blocks in each block group
|
||||
uint32_t num_frag; // Number of fragments in each block group
|
||||
uint32_t num_inodes; // Number of inodes in each block group
|
||||
uint32_t mount_time; // Last mount time (in POSIX time)
|
||||
uint32_t write_time; // Last written time (in POSIX time)
|
||||
uint16_t fsck_mounts; // Number of times the volume has been mounted since its last consistency check
|
||||
uint16_t fsck_mounts_allowed; // Number of mounts allowed before a consistency check must be done
|
||||
uint16_t signature; // Ext2 signature (0xef53)
|
||||
uint16_t fs_state; // File system state
|
||||
uint16_t error_action; // What to do when an error is detected
|
||||
uint16_t version_minor; // Minor portion of version
|
||||
uint32_t fsck_time; // POSIX time of last consistency check
|
||||
uint32_t fsck_interval; // Interval (in POSIX time) between forced consistency checks
|
||||
uint32_t os_id; // Operating system ID from which the filesystem on this volume was created
|
||||
uint32_t version_major; // Major portion of version
|
||||
uint16_t su_uid; // User ID that can use reserved blocks (superuser)
|
||||
uint16_t su_gid; // Group ID that can use reserved blocks
|
||||
};
|
||||
}
|
@ -1,6 +1,10 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef PAGE_SIZE
|
||||
#define PAGE_SIZE 4096
|
||||
#endif
|
||||
|
||||
#define MAP_READ_WRITE 1 << 0
|
||||
#define MAP_USER 1 << 1
|
||||
#define MAP_EXEC 1 << 2
|
||||
|
@ -1,6 +1,10 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef PAGE_SIZE
|
||||
#define PAGE_SIZE 4096
|
||||
#endif
|
||||
|
||||
namespace Paging
|
||||
{
|
||||
struct PageDirectoryEntry
|
||||
|
@ -8,23 +8,27 @@
|
||||
#define SYS_write 3
|
||||
#define SYS_paint 4
|
||||
#define SYS_rand 5
|
||||
#define SYS_getversion 6
|
||||
#define SYS_gettid 7
|
||||
#define SYS_mmap 8
|
||||
#define SYS_munmap 9
|
||||
#define SYS_gettid 6
|
||||
#define SYS_mmap 7
|
||||
#define SYS_munmap 8
|
||||
#define SYS_open 9
|
||||
#define SYS_read 10
|
||||
#define SYS_close 11
|
||||
|
||||
namespace Syscall
|
||||
{
|
||||
void entry(Context* context);
|
||||
}
|
||||
|
||||
void sys_exit(Context* context);
|
||||
void sys_exit(Context* context, int status);
|
||||
void sys_yield(Context* context);
|
||||
void sys_sleep(Context* context, uint64_t ms);
|
||||
void sys_write(Context* context, const char* addr, size_t size);
|
||||
void sys_write(Context* context, int fd, size_t size, const char* addr);
|
||||
void sys_paint(Context* context, uint64_t x, uint64_t y, uint64_t w, uint64_t h, uint64_t col);
|
||||
void sys_rand(Context* context);
|
||||
void sys_getversion(Context* context, char* buffer, size_t max);
|
||||
void sys_gettid(Context* context);
|
||||
void sys_mmap(Context* context, void* address, size_t size, int flags);
|
||||
void sys_munmap(Context* context, void* address, size_t size);
|
||||
void sys_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);
|
@ -5,5 +5,5 @@
|
||||
namespace ELFLoader
|
||||
{
|
||||
ELFImage* load_elf_from_address(uintptr_t addr);
|
||||
ELFImage* load_elf_from_initrd(const char* filename);
|
||||
ELFImage* load_elf_from_filesystem(const char* filename);
|
||||
}
|
@ -5,15 +5,15 @@ namespace Scheduler
|
||||
{
|
||||
void init();
|
||||
void yield();
|
||||
void exit();
|
||||
void exit(int status);
|
||||
void sleep(unsigned long ms);
|
||||
void add_kernel_task(void (*task)(void));
|
||||
void add_user_task(void* task);
|
||||
|
||||
void load_user_task(const char* filename);
|
||||
|
||||
void task_exit(Context* context);
|
||||
void task_misbehave(Context* context);
|
||||
void task_exit(Context* context, int64_t status);
|
||||
void task_misbehave(Context* context, int64_t status);
|
||||
|
||||
Task* current_task();
|
||||
|
||||
|
@ -1,7 +1,10 @@
|
||||
#pragma once
|
||||
#include "fs/FileDescriptor.h"
|
||||
#include "interrupts/Context.h"
|
||||
#include "sys/elf/Image.h"
|
||||
|
||||
#define TASK_MAX_FDS 8
|
||||
|
||||
struct Task
|
||||
{
|
||||
enum TaskState
|
||||
@ -16,6 +19,9 @@ struct Task
|
||||
Context regs;
|
||||
|
||||
int64_t task_sleep = 0;
|
||||
|
||||
int64_t exit_status;
|
||||
|
||||
int64_t task_time = 0;
|
||||
|
||||
Task* next_task = nullptr;
|
||||
@ -33,6 +39,8 @@ struct Task
|
||||
bool is_user_task();
|
||||
|
||||
ELFImage* image = nullptr;
|
||||
|
||||
Descriptor files[TASK_MAX_FDS];
|
||||
};
|
||||
|
||||
void set_context_from_task(Task& task, Context* ctx);
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "bootboot.h"
|
||||
#include "log/Log.h"
|
||||
#include "memory/MemoryManager.h"
|
||||
#include "misc/utils.h"
|
||||
#include "std/stdio.h"
|
||||
#include "std/string.h"
|
||||
|
||||
@ -11,24 +12,27 @@ extern BOOTBOOT bootboot;
|
||||
|
||||
ACPI::SDTHeader* ACPI::get_rsdt_or_xsdt()
|
||||
{
|
||||
static void* cache = nullptr;
|
||||
if (cache) return (SDTHeader*)cache;
|
||||
static SDTHeader* cache = nullptr;
|
||||
if (cache) return cache;
|
||||
|
||||
kdbgln("First time accessing the RSDT/XSDT, mapping it into memory");
|
||||
void* physical = (void*)bootboot.arch.x86_64.acpi_ptr;
|
||||
uint64_t offset = (uint64_t)physical % 4096;
|
||||
kdbgln("RSDT/XSDT physical address: %lx", (uint64_t)physical);
|
||||
cache = MemoryManager::get_unaligned_mapping(physical);
|
||||
uint64_t numPages = 1;
|
||||
while ((offset + ((SDTHeader*)cache)->Length) > (numPages * 4096))
|
||||
kdbgln("RSDT/XSDT physical address: %p", physical);
|
||||
|
||||
SDTHeader* rsdt = (SDTHeader*)MemoryManager::get_unaligned_mapping(physical);
|
||||
|
||||
uint64_t offset = (uint64_t)physical % PAGE_SIZE;
|
||||
uint64_t rsdt_pages = Utilities::get_blocks_from_size(PAGE_SIZE, (offset + rsdt->Length));
|
||||
|
||||
if (rsdt_pages > 1)
|
||||
{
|
||||
kwarnln("RSDT/XSDT extends beyond the mapped page, mapping one more page");
|
||||
MemoryManager::release_unaligned_mappings(cache, numPages);
|
||||
numPages++;
|
||||
cache = MemoryManager::get_unaligned_mappings(cache, numPages);
|
||||
MemoryManager::release_unaligned_mapping(rsdt);
|
||||
rsdt = (SDTHeader*)MemoryManager::get_unaligned_mappings(cache, rsdt_pages);
|
||||
}
|
||||
kdbgln("Mapped RSDT/XSDT to virtual address %lx, uses %ld pages", (uint64_t)cache, numPages);
|
||||
SDTHeader* result = (SDTHeader*)cache;
|
||||
return result;
|
||||
|
||||
kdbgln("Mapped RSDT/XSDT to virtual address %p, uses %ld pages", (void*)rsdt, rsdt_pages);
|
||||
cache = rsdt;
|
||||
return rsdt;
|
||||
}
|
||||
|
||||
bool ACPI::validate_rsdt_or_xsdt(ACPI::SDTHeader* root_sdt)
|
||||
@ -54,8 +58,8 @@ void* ACPI::find_table(ACPI::SDTHeader* root_sdt, const char* signature)
|
||||
{
|
||||
bool isXSDT = is_xsdt();
|
||||
uint64_t entries = (root_sdt->Length - sizeof(SDTHeader)) / (isXSDT ? 8 : 4);
|
||||
kdbgln("Searching for table %s in the %s at %lx (table contains %ld entries)", signature, isXSDT ? "XSDT" : "RSDT",
|
||||
(uint64_t)root_sdt, entries);
|
||||
kdbgln("Searching for table %s in the %s at %p (table contains %ld entries)", signature, isXSDT ? "XSDT" : "RSDT",
|
||||
(void*)root_sdt, entries);
|
||||
|
||||
for (uint64_t i = 0; i < entries; i++)
|
||||
{
|
||||
@ -77,9 +81,9 @@ void* ACPI::find_table(ACPI::SDTHeader* root_sdt, const char* signature)
|
||||
kwarnln("Entry %ld in the %s points to null", i, isXSDT ? "XSDT" : "RSDT");
|
||||
continue;
|
||||
}
|
||||
kdbgln("Physical address of entry: %lx", (uint64_t)h);
|
||||
kdbgln("Physical address of entry: %p", (void*)h);
|
||||
SDTHeader* realHeader = (SDTHeader*)MemoryManager::get_unaligned_mapping(h);
|
||||
kdbgln("Mapped entry to virtual address %lx", (uint64_t)realHeader);
|
||||
kdbgln("Mapped entry to virtual address %p", (void*)realHeader);
|
||||
if (!validate_sdt_header(realHeader))
|
||||
{
|
||||
kwarnln("Header of entry %ld is not valid, skipping this entry", i);
|
||||
|
34
kernel/src/fs/FileDescriptor.cpp
Normal file
34
kernel/src/fs/FileDescriptor.cpp
Normal file
@ -0,0 +1,34 @@
|
||||
#include "fs/FileDescriptor.h"
|
||||
|
||||
Descriptor::Descriptor() : m_is_open(false)
|
||||
{
|
||||
}
|
||||
|
||||
Descriptor::Descriptor(const Descriptor& other)
|
||||
: m_is_open(other.m_is_open), m_can_read(other.m_can_read), m_can_write(other.m_can_write), m_node(other.m_node),
|
||||
m_offset(other.m_offset)
|
||||
{
|
||||
}
|
||||
|
||||
void Descriptor::open(VFS::Node* node, bool can_read, bool can_write)
|
||||
{
|
||||
m_can_read = can_read;
|
||||
m_can_write = can_write;
|
||||
m_node = node;
|
||||
m_offset = 0;
|
||||
m_is_open = true;
|
||||
}
|
||||
|
||||
ssize_t Descriptor::read(size_t size, char* buffer)
|
||||
{
|
||||
ssize_t result = VFS::read(m_node, m_offset, size, buffer);
|
||||
m_offset += result;
|
||||
return result;
|
||||
}
|
||||
|
||||
ssize_t Descriptor::write(size_t size, const char* buffer)
|
||||
{
|
||||
ssize_t result = VFS::write(m_node, m_offset, size, buffer);
|
||||
m_offset += result;
|
||||
return result;
|
||||
}
|
162
kernel/src/fs/VFS.cpp
Normal file
162
kernel/src/fs/VFS.cpp
Normal file
@ -0,0 +1,162 @@
|
||||
#define MODULE "vfs"
|
||||
|
||||
#include "fs/VFS.h"
|
||||
#include "errno.h"
|
||||
#include "log/Log.h"
|
||||
#include "std/stdlib.h"
|
||||
#include "std/string.h"
|
||||
|
||||
static VFS::Node* vfs_root;
|
||||
|
||||
ssize_t VFS::read(Node* node, size_t offset, size_t length, char* buffer)
|
||||
{
|
||||
if (!node)
|
||||
{
|
||||
kwarnln("read() failed: trying to read from nullptr");
|
||||
return -1;
|
||||
}
|
||||
if (node->type == VFS_DIRECTORY)
|
||||
{
|
||||
kwarnln("read() failed: is a directory");
|
||||
return -EISDIR;
|
||||
}
|
||||
if (!node->read_func)
|
||||
{
|
||||
kwarnln("read() failed: the chosen node doesn't support reading");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return node->read_func(node, offset, length, buffer);
|
||||
}
|
||||
|
||||
ssize_t VFS::write(Node* node, size_t offset, size_t length, const char* buffer)
|
||||
{
|
||||
if (!node)
|
||||
{
|
||||
kwarnln("write() failed: trying to write to nullptr");
|
||||
return -1;
|
||||
}
|
||||
if (node->type == VFS_DIRECTORY)
|
||||
{
|
||||
kwarnln("write() failed: is a directory");
|
||||
return -EISDIR;
|
||||
}
|
||||
if (!node->write_func)
|
||||
{
|
||||
kwarnln("write() failed: the chosen node doesn't support writing");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return node->write_func(node, offset, length, buffer);
|
||||
}
|
||||
|
||||
void VFS::mount_root(Node* root)
|
||||
{
|
||||
if (!root)
|
||||
{
|
||||
kwarnln("mount_root() failed: attempted to mount nullptr");
|
||||
return;
|
||||
}
|
||||
if (vfs_root)
|
||||
{
|
||||
kwarnln("mount_root() failed: root filesystem already mounted");
|
||||
return;
|
||||
}
|
||||
kinfoln("mounting node '%s' as vfs root", root->name);
|
||||
vfs_root = root;
|
||||
}
|
||||
|
||||
VFS::Node* VFS::root()
|
||||
{
|
||||
return vfs_root;
|
||||
}
|
||||
|
||||
VFS::Node* VFS::resolve_path(const char* filename, Node* root)
|
||||
{
|
||||
if (!root) root = vfs_root;
|
||||
|
||||
if (strlen(filename) == 0) return 0;
|
||||
if (*filename == '/') // Absolute path.
|
||||
{
|
||||
filename++;
|
||||
root = vfs_root;
|
||||
}
|
||||
|
||||
Node* current_node = root;
|
||||
|
||||
while (true)
|
||||
{
|
||||
while (*filename == '/') { filename++; }
|
||||
if (*filename == 0) { return current_node; }
|
||||
|
||||
size_t path_section_size = 0;
|
||||
while (filename[path_section_size] && filename[path_section_size] != '/') { path_section_size++; }
|
||||
|
||||
if (strncmp(filename, ".", path_section_size) != 0) // The current path section is not '.'
|
||||
{
|
||||
char* buffer = (char*)kmalloc(path_section_size + 1);
|
||||
memcpy(buffer, filename, path_section_size);
|
||||
buffer[path_section_size] = 0;
|
||||
if (!current_node->find_func)
|
||||
{
|
||||
kwarnln("Current node has no way to find child nodes");
|
||||
return 0;
|
||||
}
|
||||
Node* child = current_node->find_func(current_node, buffer);
|
||||
if (!child)
|
||||
{
|
||||
kwarnln("Current node did not find our target node");
|
||||
return 0;
|
||||
}
|
||||
if (child->flags & VFS_MOUNTPOINT)
|
||||
{
|
||||
if (!child->link)
|
||||
{
|
||||
kwarnln("Current node's link is null");
|
||||
return 0;
|
||||
}
|
||||
child = child->link;
|
||||
}
|
||||
current_node = child;
|
||||
kfree(buffer);
|
||||
}
|
||||
|
||||
filename += path_section_size;
|
||||
}
|
||||
}
|
||||
|
||||
int VFS::mkdir(const char* path, const char* name)
|
||||
{
|
||||
Node* node = resolve_path(path, vfs_root);
|
||||
if (!node)
|
||||
{
|
||||
kwarnln("Attempting to mkdir in %s, which does not exist", path);
|
||||
return -1;
|
||||
}
|
||||
if (!node->mkdir_func)
|
||||
{
|
||||
kwarnln("Chosen node does not support mkdir()");
|
||||
return -1;
|
||||
}
|
||||
return node->mkdir_func(node, name);
|
||||
}
|
||||
|
||||
void VFS::mount(Node* mountpoint, Node* mounted)
|
||||
{
|
||||
if (!mountpoint || !mounted) return;
|
||||
if (mountpoint->flags & VFS_MOUNTPOINT || mounted->flags & VFS_MOUNTPOINT) return;
|
||||
mountpoint->link = mounted;
|
||||
mountpoint->flags |= VFS_MOUNTPOINT;
|
||||
}
|
||||
|
||||
void VFS::mount(const char* pathname, Node* mounted)
|
||||
{
|
||||
return mount(resolve_path(pathname), mounted);
|
||||
}
|
||||
|
||||
void VFS::unmount(Node* mountpoint)
|
||||
{
|
||||
if (!mountpoint) return;
|
||||
if (!(mountpoint->flags & VFS_MOUNTPOINT)) return;
|
||||
mountpoint->flags &= ~VFS_MOUNTPOINT;
|
||||
}
|
25
kernel/src/fs/devices/Console.cpp
Normal file
25
kernel/src/fs/devices/Console.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
#include "fs/devices/Console.h"
|
||||
#include "config.h"
|
||||
#include "render/TextRenderer.h"
|
||||
#include "std/stdio.h"
|
||||
#include "std/stdlib.h"
|
||||
#include "std/string.h"
|
||||
|
||||
VFS::Node* ConsoleDevice::create_new()
|
||||
{
|
||||
VFS::Node* dev = new VFS::Node;
|
||||
dev->write_func = ConsoleDevice::write;
|
||||
dev->inode = 0;
|
||||
dev->length = 0;
|
||||
dev->type = VFS_FILE;
|
||||
dev->flags = 0;
|
||||
strncpy(dev->name, "console", sizeof(dev->name));
|
||||
return dev;
|
||||
}
|
||||
|
||||
ssize_t ConsoleDevice::write(VFS::Node* node, size_t, size_t size, const char* buffer)
|
||||
{
|
||||
if (!node) return -1;
|
||||
TextRenderer::write(buffer, size);
|
||||
return (ssize_t)size;
|
||||
}
|
37
kernel/src/fs/devices/DeviceFS.cpp
Normal file
37
kernel/src/fs/devices/DeviceFS.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
#include "fs/devices/DeviceFS.h"
|
||||
#include "fs/devices/Console.h"
|
||||
#include "fs/devices/Version.h"
|
||||
#include "std/stdlib.h"
|
||||
#include "std/string.h"
|
||||
|
||||
#define DEVFS_MAX_FILES 32
|
||||
|
||||
VFS::Node* devfs_root = nullptr;
|
||||
|
||||
VFS::Node* devfs_files[DEVFS_MAX_FILES];
|
||||
int devfs_file_count = 0;
|
||||
|
||||
VFS::Node* DeviceFS::get()
|
||||
{
|
||||
if (devfs_root) return devfs_root;
|
||||
devfs_root = new VFS::Node;
|
||||
devfs_root->length = 0;
|
||||
devfs_root->inode = 0;
|
||||
devfs_root->type = VFS_DIRECTORY;
|
||||
devfs_root->find_func = DeviceFS::finddir;
|
||||
strncpy(devfs_root->name, "dev", sizeof(devfs_root->name));
|
||||
|
||||
devfs_files[devfs_file_count++] = VersionDevice::create_new();
|
||||
devfs_files[devfs_file_count++] = ConsoleDevice::create_new();
|
||||
return devfs_root;
|
||||
}
|
||||
|
||||
VFS::Node* DeviceFS::finddir(VFS::Node* node, const char* filename)
|
||||
{
|
||||
if (!node) return 0;
|
||||
for (int i = 0; i < devfs_file_count; i++)
|
||||
{
|
||||
if (strncmp(devfs_files[i]->name, filename, sizeof(VFS::Node::name)) == 0) { return devfs_files[i]; }
|
||||
}
|
||||
return 0;
|
||||
}
|
26
kernel/src/fs/devices/Version.cpp
Normal file
26
kernel/src/fs/devices/Version.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
#include "fs/devices/Version.h"
|
||||
#include "config.h"
|
||||
#include "std/stdio.h"
|
||||
#include "std/stdlib.h"
|
||||
#include "std/string.h"
|
||||
|
||||
VFS::Node* VersionDevice::create_new()
|
||||
{
|
||||
VFS::Node* dev = new VFS::Node;
|
||||
dev->read_func = VersionDevice::read;
|
||||
dev->inode = 0;
|
||||
dev->length = strlen(moon_version()) + 5;
|
||||
dev->type = VFS_FILE;
|
||||
dev->flags = 0;
|
||||
strncpy(dev->name, "version", sizeof(dev->name));
|
||||
return dev;
|
||||
}
|
||||
|
||||
ssize_t VersionDevice::read(VFS::Node* node, size_t offset, size_t size, char* buffer)
|
||||
{
|
||||
if (!node) return -1;
|
||||
if (offset > node->length) return -1;
|
||||
if (offset + size > node->length) { size = node->length - offset; }
|
||||
snprintf(buffer, size + 1, "moon %s", moon_version()); // FIXME: Support offseting this read
|
||||
return (ssize_t)size;
|
||||
}
|
@ -84,7 +84,8 @@ void GDT::load()
|
||||
gdtr.offset = (uint64_t)&internal_gdt;
|
||||
gdtr.size = sizeof(InternalGDT);
|
||||
memset(&main_tss, 0, sizeof(TSS));
|
||||
main_tss.rsp[0] = (uint64_t)MemoryManager::get_pages(4) + (4096 * 4) - 8; // allocate 16KB for the syscall stack
|
||||
main_tss.rsp[0] =
|
||||
(uint64_t)MemoryManager::get_pages(4) + (PAGE_SIZE * 4) - 8; // allocate 16KB for the syscall stack
|
||||
main_tss.iomap_base = sizeof(TSS);
|
||||
set_base(&internal_gdt.tss, (uint64_t)&main_tss & 0xffffffff);
|
||||
internal_gdt.tss2.base_high = (uint32_t)(((uint64_t)&main_tss >> 32) & 0xffffffff);
|
||||
|
@ -2,18 +2,21 @@
|
||||
|
||||
#include "init/InitRD.h"
|
||||
#include "bootboot.h"
|
||||
#include "fs/VFS.h"
|
||||
#include "io/Serial.h"
|
||||
#include "log/Log.h"
|
||||
#include "memory/MemoryManager.h"
|
||||
#include "misc/utils.h"
|
||||
#include "std/stdlib.h"
|
||||
#include <string.h>
|
||||
#include "std/string.h"
|
||||
|
||||
extern BOOTBOOT bootboot;
|
||||
|
||||
static void* initrd_base;
|
||||
static bool initrd_initialized = false;
|
||||
|
||||
static VFS::Node initrd_root;
|
||||
|
||||
bool InitRD::is_initialized()
|
||||
{
|
||||
return initrd_initialized;
|
||||
@ -112,10 +115,267 @@ void InitRD::for_each(void (*callback)(File& f))
|
||||
}
|
||||
}
|
||||
|
||||
#define INITRD_MAX_FILES_IN_DIR 8
|
||||
#define INITRD_MAX_FILES 32
|
||||
|
||||
namespace InitRD
|
||||
{
|
||||
struct Directory
|
||||
{
|
||||
char name[64];
|
||||
int entries = 0;
|
||||
VFS::Node* files[INITRD_MAX_FILES_IN_DIR];
|
||||
};
|
||||
}
|
||||
|
||||
void initrd_for_each_dir(void (*callback)(InitRD::Directory& f))
|
||||
{
|
||||
uint64_t block = 0;
|
||||
uint64_t total_blocks = InitRD::get_total_blocks();
|
||||
while (block < total_blocks)
|
||||
{
|
||||
InitRD::TarHeader* hdr = (InitRD::TarHeader*)InitRD::get_block(block);
|
||||
if (!InitRD::is_valid_header(hdr))
|
||||
{
|
||||
block++;
|
||||
continue;
|
||||
}
|
||||
if (hdr->typeflag == 53)
|
||||
{
|
||||
InitRD::Directory dir;
|
||||
strncpy(dir.name, hdr->name, sizeof(dir.name));
|
||||
callback(dir);
|
||||
block++;
|
||||
continue;
|
||||
}
|
||||
auto f = get_file(hdr);
|
||||
block += get_file_size_in_blocks(f) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static InitRD::File files[32];
|
||||
static uint32_t total_files = 0;
|
||||
|
||||
static InitRD::Directory dirs[32];
|
||||
static uint32_t total_dirs = 0;
|
||||
|
||||
static VFS::Node nodes[63]; // One of the dirs is the initrd_root
|
||||
static uint32_t total_nodes = 0;
|
||||
|
||||
ssize_t initrd_read(VFS::Node* node, size_t offset, size_t length, char* buffer)
|
||||
{
|
||||
if (!node) return -1;
|
||||
if (node->inode >= total_files) return -1;
|
||||
InitRD::File& file = files[node->inode];
|
||||
if (offset > file.size) return -1;
|
||||
if (offset + length > file.size) { length = file.size - offset; }
|
||||
memcpy(buffer, (void*)((uintptr_t)file.addr + offset), length);
|
||||
return length;
|
||||
}
|
||||
|
||||
VFS::Node* initrd_scan_dir(VFS::Node* node, const char* filename)
|
||||
{
|
||||
if (!node) return 0;
|
||||
if (node->inode >= total_dirs) return 0;
|
||||
InitRD::Directory dir = dirs[node->inode];
|
||||
for (int i = 0; i < dir.entries; i++)
|
||||
{
|
||||
if (strncmp(dir.files[i]->name, filename, sizeof(VFS::Node::name)) == 0) { return dir.files[i]; }
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int initrd_mkdir(VFS::Node* node, const char* name) // FIXME: Return proper error numbers.
|
||||
{
|
||||
if (total_dirs >= 32)
|
||||
{
|
||||
kwarnln("mkdir() failed: too many directories");
|
||||
return -1;
|
||||
}
|
||||
if (node->inode > total_dirs)
|
||||
{
|
||||
kwarnln("mkdir() failed: invalid node");
|
||||
return -1;
|
||||
}
|
||||
if (!(node->type & VFS_DIRECTORY))
|
||||
{
|
||||
kwarnln("mkdir() failed: not a directory");
|
||||
return -1;
|
||||
}
|
||||
InitRD::Directory& parent = dirs[node->inode];
|
||||
if (parent.entries == INITRD_MAX_FILES_IN_DIR)
|
||||
{
|
||||
kwarnln("mkdir() failed: parent is null");
|
||||
return -1;
|
||||
}
|
||||
uint64_t inode = total_dirs;
|
||||
VFS::Node& new_node = nodes[total_nodes++];
|
||||
new_node.inode = inode;
|
||||
new_node.find_func = initrd_scan_dir;
|
||||
new_node.mkdir_func = initrd_mkdir;
|
||||
new_node.length = 0;
|
||||
new_node.type = VFS_DIRECTORY;
|
||||
strncpy(new_node.name, name, sizeof(new_node.name));
|
||||
InitRD::Directory dir;
|
||||
strncpy(dir.name, name, sizeof(dir.name));
|
||||
dir.entries = 0;
|
||||
dirs[total_dirs++] = dir; // FIXME: Right now this isn't of worry, but there is a possibility for a TOCTOU bug here.
|
||||
// Should use a spinlock or something.
|
||||
parent.files[parent.entries++] = &new_node;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool initrd_register_dir(InitRD::Directory& dir, uint64_t inode)
|
||||
{
|
||||
const char* filename = dir.name;
|
||||
VFS::Node* current_node = &initrd_root;
|
||||
while (true)
|
||||
{
|
||||
while (*filename == '/') { filename++; }
|
||||
if (*filename == 0) { return false; }
|
||||
|
||||
size_t path_section_size = 0;
|
||||
while (filename[path_section_size] && filename[path_section_size] != '/') { path_section_size++; }
|
||||
|
||||
if (filename[path_section_size]) // We are in a '/'
|
||||
{
|
||||
char* buffer = (char*)kmalloc(path_section_size + 1);
|
||||
memcpy(buffer, filename, path_section_size);
|
||||
buffer[path_section_size] = 0;
|
||||
if (!current_node->find_func) { return false; }
|
||||
VFS::Node* child = current_node->find_func(current_node, buffer);
|
||||
if (!child) { return false; }
|
||||
current_node = child;
|
||||
kfree(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strncmp(filename, ".", path_section_size) != 0) // The current path section is not '.'
|
||||
{
|
||||
if (strncmp(filename, "..", path_section_size) == 0) { return false; }
|
||||
|
||||
if (!current_node->find_func) { return false; }
|
||||
|
||||
InitRD::Directory& parent = dirs[current_node->inode];
|
||||
if (parent.entries == INITRD_MAX_FILES_IN_DIR) { return false; }
|
||||
|
||||
char* buffer = (char*)kmalloc(path_section_size + 1);
|
||||
memcpy(buffer, filename, path_section_size);
|
||||
buffer[path_section_size] = 0;
|
||||
|
||||
VFS::Node& node = nodes[total_nodes++];
|
||||
node.inode = inode;
|
||||
node.find_func = initrd_scan_dir;
|
||||
node.length = 0;
|
||||
node.type = VFS_DIRECTORY;
|
||||
node.mkdir_func = initrd_mkdir;
|
||||
strncpy(node.name, buffer, sizeof(node.name));
|
||||
strncpy(dir.name, buffer, sizeof(dir.name));
|
||||
|
||||
parent.files[parent.entries++] = &node;
|
||||
|
||||
kfree(buffer);
|
||||
return true;
|
||||
}
|
||||
else { return false; }
|
||||
}
|
||||
|
||||
filename += path_section_size;
|
||||
}
|
||||
}
|
||||
|
||||
static bool initrd_register_file(InitRD::File& f, uint64_t inode)
|
||||
{
|
||||
const char* filename = f.name;
|
||||
VFS::Node* current_node = &initrd_root;
|
||||
while (true)
|
||||
{
|
||||
while (*filename == '/') { filename++; }
|
||||
if (*filename == 0) { return false; }
|
||||
|
||||
size_t path_section_size = 0;
|
||||
while (filename[path_section_size] && filename[path_section_size] != '/') { path_section_size++; }
|
||||
|
||||
if (filename[path_section_size]) // We are in a '/'
|
||||
{
|
||||
char* buffer = (char*)kmalloc(path_section_size + 1);
|
||||
memcpy(buffer, filename, path_section_size);
|
||||
buffer[path_section_size] = 0;
|
||||
if (!current_node->find_func) { return false; }
|
||||
VFS::Node* child = current_node->find_func(current_node, buffer);
|
||||
if (!child) { return false; }
|
||||
current_node = child;
|
||||
kfree(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strncmp(filename, ".", path_section_size) != 0) // The current path section is not '.'
|
||||
{
|
||||
if (strncmp(filename, "..", path_section_size) == 0) { return false; }
|
||||
|
||||
if (!current_node->find_func) { return false; }
|
||||
|
||||
InitRD::Directory& parent = dirs[current_node->inode];
|
||||
if (parent.entries == INITRD_MAX_FILES_IN_DIR) { return false; }
|
||||
|
||||
char* buffer = (char*)kmalloc(path_section_size + 1);
|
||||
memcpy(buffer, filename, path_section_size);
|
||||
buffer[path_section_size] = 0;
|
||||
|
||||
VFS::Node& node = nodes[total_nodes++];
|
||||
node.inode = inode;
|
||||
node.read_func = initrd_read;
|
||||
node.length = f.size;
|
||||
node.type = VFS_FILE;
|
||||
strncpy(node.name, buffer, sizeof(node.name));
|
||||
strncpy(f.name, buffer, sizeof(f.name));
|
||||
|
||||
parent.files[parent.entries++] = &node;
|
||||
kfree(buffer);
|
||||
return true;
|
||||
}
|
||||
else { return false; }
|
||||
}
|
||||
|
||||
filename += path_section_size;
|
||||
}
|
||||
}
|
||||
|
||||
static void initrd_scan()
|
||||
{
|
||||
initrd_for_each_dir([](InitRD::Directory& dir) {
|
||||
if (total_dirs >= 32) return;
|
||||
uint64_t inode = total_dirs;
|
||||
if (initrd_register_dir(dir, inode)) dirs[total_dirs++] = dir;
|
||||
});
|
||||
InitRD::for_each([](InitRD::File& f) {
|
||||
if (total_files >= 32) return;
|
||||
uint64_t inode = total_files;
|
||||
if (initrd_register_file(f, inode)) files[total_files++] = f;
|
||||
});
|
||||
}
|
||||
|
||||
static void initrd_initialize_root()
|
||||
{
|
||||
initrd_root.length = 0;
|
||||
initrd_root.inode = 0;
|
||||
initrd_root.type |= VFS_DIRECTORY;
|
||||
InitRD::Directory& root = dirs[0];
|
||||
total_dirs++;
|
||||
strncpy(initrd_root.name, "initrd", sizeof(initrd_root.name));
|
||||
strncpy(root.name, "initrd", sizeof(root.name));
|
||||
initrd_root.find_func = initrd_scan_dir;
|
||||
initrd_root.mkdir_func = initrd_mkdir;
|
||||
}
|
||||
|
||||
void InitRD::init()
|
||||
{
|
||||
initrd_base = MemoryManager::get_unaligned_mappings((void*)bootboot.initrd_ptr, bootboot.initrd_size / 4096 + 1);
|
||||
kdbgln("physical base at %lx, size %lx, mapped to %lx", bootboot.initrd_ptr, bootboot.initrd_size,
|
||||
(uint64_t)initrd_base);
|
||||
initrd_base = MemoryManager::get_unaligned_mappings(
|
||||
(void*)bootboot.initrd_ptr, Utilities::get_blocks_from_size(PAGE_SIZE, bootboot.initrd_size));
|
||||
kdbgln("physical base at %lx, size %lx, mapped to %p", bootboot.initrd_ptr, bootboot.initrd_size, initrd_base);
|
||||
kdbgln("total blocks: %ld", get_total_blocks());
|
||||
initrd_initialize_root();
|
||||
initrd_scan();
|
||||
VFS::mount_root(&initrd_root);
|
||||
initrd_initialized = true;
|
||||
}
|
@ -34,7 +34,7 @@ extern "C" void common_handler(Context* context)
|
||||
|
||||
StackTracer tracer(context->rbp);
|
||||
tracer.trace_with_ip(context->rip);
|
||||
Scheduler::task_misbehave(context);
|
||||
Scheduler::task_misbehave(context, -2);
|
||||
}
|
||||
}
|
||||
if (context->number == 14)
|
||||
@ -51,7 +51,7 @@ extern "C" void common_handler(Context* context)
|
||||
StackTracer tracer(context->rbp);
|
||||
tracer.trace_with_ip(context->rip);
|
||||
|
||||
Scheduler::task_misbehave(context);
|
||||
Scheduler::task_misbehave(context, -3);
|
||||
}
|
||||
}
|
||||
if (context->number == 8) { int_panic(context, "Double fault, halting"); }
|
||||
|
@ -4,6 +4,8 @@
|
||||
#include "assert.h"
|
||||
#include "config.h"
|
||||
#include "cpu/CPU.h"
|
||||
#include "fs/VFS.h"
|
||||
#include "fs/devices/DeviceFS.h"
|
||||
#include "gdt/GDT.h"
|
||||
#include "init/Init.h"
|
||||
#include "init/InitRD.h"
|
||||
@ -32,8 +34,6 @@
|
||||
#include "thread/PIT.h"
|
||||
#include "thread/Scheduler.h"
|
||||
|
||||
extern "C" void _userspace();
|
||||
|
||||
extern "C" void _start()
|
||||
{
|
||||
Init::check_magic();
|
||||
@ -70,52 +70,6 @@ extern "C" void _start()
|
||||
|
||||
kinfoln("Prepared scheduler");
|
||||
|
||||
/*Scheduler::add_kernel_task([]() {
|
||||
int64_t x = 0;
|
||||
int64_t y = 0;
|
||||
int64_t xvel = 10;
|
||||
int64_t yvel = 10;
|
||||
while (1)
|
||||
{
|
||||
sleep(2);
|
||||
uint32_t color = (uint32_t)Mersenne::get();
|
||||
x += xvel;
|
||||
y += yvel;
|
||||
if ((x + 10) >= framebuffer0.width())
|
||||
{
|
||||
xvel = -xvel;
|
||||
x = (framebuffer0.width() - 10);
|
||||
}
|
||||
if ((y + 10) >= framebuffer0.height())
|
||||
{
|
||||
yvel = -yvel;
|
||||
y = (framebuffer0.height() - 10);
|
||||
}
|
||||
if (xvel < 0 && (x - 10) < 0)
|
||||
{
|
||||
xvel = -xvel;
|
||||
x = 0;
|
||||
}
|
||||
if (yvel < 0 && (y - 10) < 0)
|
||||
{
|
||||
yvel = -yvel;
|
||||
y = 0;
|
||||
}
|
||||
framebuffer0.paint_rect(x, y, 10, 10, Color::from_integer(color));
|
||||
}
|
||||
});*/
|
||||
|
||||
/*Scheduler::add_kernel_task([]() {
|
||||
while (1)
|
||||
{
|
||||
sleep(100);
|
||||
uint32_t color = (uint32_t)Mersenne::get();
|
||||
framebuffer0.paint_rect(Mersenne::get() % (framebuffer0.width() - 256),
|
||||
Mersenne::get() % (framebuffer0.height() - 256), Mersenne::get() % 255,
|
||||
Mersenne::get() % 255, Color::from_integer(color));
|
||||
}
|
||||
});*/
|
||||
|
||||
Scheduler::add_kernel_task([]() {
|
||||
while (1)
|
||||
{
|
||||
@ -124,38 +78,16 @@ extern "C" void _start()
|
||||
}
|
||||
});
|
||||
|
||||
uint64_t demo = Mersenne::get() % 5;
|
||||
|
||||
switch (demo)
|
||||
{
|
||||
case 0:
|
||||
kinfoln("Loading demo: example init program");
|
||||
Scheduler::load_user_task("bin/init");
|
||||
break;
|
||||
case 1:
|
||||
kinfoln("Loading demo: first 50 fibonacci numbers");
|
||||
Scheduler::load_user_task("bin/fib");
|
||||
break;
|
||||
case 2:
|
||||
kinfoln("Loading demo: leap year calculator");
|
||||
Scheduler::load_user_task("bin/leap");
|
||||
break;
|
||||
case 3:
|
||||
kinfoln("Loading demo: painting program");
|
||||
Scheduler::load_user_task("bin/art");
|
||||
break;
|
||||
case 4:
|
||||
kinfoln("Loading demo: memory eating program");
|
||||
Scheduler::load_user_task("bin/memeater");
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
Scheduler::load_user_task("/bin/init");
|
||||
|
||||
kinfoln("Prepared scheduler tasks");
|
||||
|
||||
ASSERT(VFS::mkdir("/", "dev") == 0);
|
||||
VFS::mount("/dev", DeviceFS::get());
|
||||
|
||||
Init::finish_kernel_boot();
|
||||
|
||||
Interrupts::enable();
|
||||
Interrupts::enable(); // Task switching commences here
|
||||
|
||||
kinfoln("Interrupts enabled");
|
||||
|
||||
@ -163,5 +95,5 @@ extern "C" void _start()
|
||||
kinfoln("Found PCI device %x:%x, %s", dev.id().vendor, dev.id().device, pci_type_name(dev.type()));
|
||||
});
|
||||
|
||||
Scheduler::exit();
|
||||
Scheduler::exit(0);
|
||||
}
|
@ -1,6 +1,10 @@
|
||||
#include "memory/KernelHeap.h"
|
||||
#include "assert.h"
|
||||
|
||||
#ifndef PAGE_SIZE
|
||||
#define PAGE_SIZE 4096
|
||||
#endif
|
||||
|
||||
static uint8_t page_bitmap[2048];
|
||||
|
||||
#define ALLOC_BASE 0xfffffffff8000000
|
||||
@ -28,7 +32,7 @@ uint64_t KernelHeap::request_virtual_page()
|
||||
if (bitmap_read(index)) continue;
|
||||
bitmap_set(index, true);
|
||||
start_index = index + 1;
|
||||
return ALLOC_BASE + (index * 4096);
|
||||
return ALLOC_BASE + (index * PAGE_SIZE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -55,7 +59,7 @@ uint64_t KernelHeap::request_virtual_pages(uint64_t count)
|
||||
if (contiguous == count)
|
||||
{
|
||||
for (uint64_t i = 0; i < count; i++) bitmap_set(contiguous_start + i, true);
|
||||
return ALLOC_BASE + (contiguous_start * 4096);
|
||||
return ALLOC_BASE + (contiguous_start * PAGE_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,7 +69,7 @@ uint64_t KernelHeap::request_virtual_pages(uint64_t count)
|
||||
void KernelHeap::free_virtual_page(uint64_t address)
|
||||
{
|
||||
ASSERT(address >= ALLOC_BASE && address < ALLOC_END);
|
||||
uint64_t index = (address - ALLOC_BASE) / 4096;
|
||||
uint64_t index = (address - ALLOC_BASE) / PAGE_SIZE;
|
||||
bitmap_set(index, false);
|
||||
if (start_index > index) start_index = index;
|
||||
}
|
||||
@ -73,7 +77,7 @@ void KernelHeap::free_virtual_page(uint64_t address)
|
||||
void KernelHeap::free_virtual_pages(uint64_t address, uint64_t count)
|
||||
{
|
||||
ASSERT(address >= ALLOC_BASE && address < ALLOC_END);
|
||||
uint64_t index = (address - ALLOC_BASE) / 4096;
|
||||
uint64_t index = (address - ALLOC_BASE) / PAGE_SIZE;
|
||||
for (uint64_t i = 0; i < count; i++) { bitmap_set(index + i, false); }
|
||||
if (start_index > index) start_index = index;
|
||||
}
|
@ -32,7 +32,7 @@ void* MemoryManager::get_mapping(void* physicalAddress, int flags)
|
||||
|
||||
void* MemoryManager::get_unaligned_mapping(void* physicalAddress, int flags)
|
||||
{
|
||||
uint64_t offset = (uint64_t)physicalAddress % 4096;
|
||||
uint64_t offset = (uint64_t)physicalAddress % PAGE_SIZE;
|
||||
uint64_t virtualAddress = KernelHeap::request_virtual_page();
|
||||
if (!virtualAddress)
|
||||
{
|
||||
@ -49,7 +49,7 @@ void* MemoryManager::get_unaligned_mappings(void* physicalAddress, uint64_t coun
|
||||
{
|
||||
if (!count) return 0;
|
||||
if (count == 1) return get_unaligned_mapping(physicalAddress, flags);
|
||||
uint64_t offset = (uint64_t)physicalAddress % 4096;
|
||||
uint64_t offset = (uint64_t)physicalAddress % PAGE_SIZE;
|
||||
uint64_t virtualAddress = KernelHeap::request_virtual_pages(count);
|
||||
if (!virtualAddress)
|
||||
{
|
||||
@ -62,14 +62,14 @@ void* MemoryManager::get_unaligned_mappings(void* physicalAddress, uint64_t coun
|
||||
}
|
||||
for (uint64_t i = 0; i < count; i++)
|
||||
{
|
||||
kernelVMM.map(virtualAddress + (i * 4096), ((uint64_t)physicalAddress - offset) + (i * 4096), flags);
|
||||
kernelVMM.map(virtualAddress + (i * PAGE_SIZE), ((uint64_t)physicalAddress - offset) + (i * PAGE_SIZE), flags);
|
||||
}
|
||||
return (void*)(virtualAddress + offset);
|
||||
}
|
||||
|
||||
void MemoryManager::release_unaligned_mapping(void* mapping)
|
||||
{
|
||||
uint64_t offset = (uint64_t)mapping % 4096;
|
||||
uint64_t offset = (uint64_t)mapping % PAGE_SIZE;
|
||||
kernelVMM.unmap((uint64_t)mapping - offset);
|
||||
KernelHeap::free_virtual_page((uint64_t)mapping - offset);
|
||||
}
|
||||
@ -78,9 +78,9 @@ void MemoryManager::release_unaligned_mappings(void* mapping, uint64_t count)
|
||||
{
|
||||
if (!count) return;
|
||||
if (count == 1) return release_unaligned_mapping(mapping);
|
||||
uint64_t offset = (uint64_t)mapping % 4096;
|
||||
uint64_t offset = (uint64_t)mapping % PAGE_SIZE;
|
||||
KernelHeap::free_virtual_pages((uint64_t)mapping - offset, count);
|
||||
for (uint64_t i = 0; i < count; i++) { kernelVMM.unmap(((uint64_t)mapping - offset) + (i * 4096)); }
|
||||
for (uint64_t i = 0; i < count; i++) { kernelVMM.unmap(((uint64_t)mapping - offset) + (i * PAGE_SIZE)); }
|
||||
}
|
||||
|
||||
void MemoryManager::release_mapping(void* mapping)
|
||||
@ -148,7 +148,7 @@ void* MemoryManager::get_pages_at(uint64_t addr, uint64_t count, int flags)
|
||||
if (!count) return 0;
|
||||
if (count == 1) return get_page_at(addr, flags);
|
||||
#ifdef MM_DEBUG
|
||||
kdbgln("allocating several pages (%ld), at address %ld", count, addr);
|
||||
kdbgln("allocating several pages (%ld), at address %lx", count, addr);
|
||||
#endif
|
||||
for (uint64_t i = 0; i < count; i++)
|
||||
{
|
||||
@ -162,9 +162,9 @@ void* MemoryManager::get_pages_at(uint64_t addr, uint64_t count, int flags)
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
kernelVMM.map(addr + (i * 4096), (uint64_t)physicalAddress, flags);
|
||||
kernelVMM.map(addr + (i * PAGE_SIZE), (uint64_t)physicalAddress, flags);
|
||||
#ifdef MM_DEBUG
|
||||
kdbgln("allocating virtual %lx, physical %lx", virtualAddress + (i * 4096), (uint64_t)physicalAddress);
|
||||
kdbgln("allocating virtual %lx, physical %p", virtualAddress + (i * PAGE_SIZE), physicalAddress);
|
||||
#endif
|
||||
}
|
||||
return (void*)addr;
|
||||
@ -179,12 +179,12 @@ void MemoryManager::release_pages(void* pages, uint64_t count)
|
||||
#endif
|
||||
for (uint64_t i = 0; i < count; i++)
|
||||
{
|
||||
void* page = (void*)((uint64_t)pages + (i * 4096));
|
||||
void* page = (void*)((uint64_t)pages + (i * PAGE_SIZE));
|
||||
uint64_t physicalAddress = kernelVMM.getPhysical((uint64_t)page);
|
||||
ASSERT(physicalAddress != UINT64_MAX);
|
||||
kernelVMM.unmap((uint64_t)page);
|
||||
#ifdef MM_DEBUG
|
||||
kdbgln("releasing virtual %lx, physical %lx", (uint64_t)page, physicalAddress);
|
||||
kdbgln("releasing virtual %p, physical %lx", page, physicalAddress);
|
||||
#endif
|
||||
PMM::free_page((void*)physicalAddress);
|
||||
}
|
||||
|
@ -48,26 +48,25 @@ void PMM::init()
|
||||
}
|
||||
|
||||
bitmap_addr = (char*)biggest_chunk;
|
||||
virtual_bitmap_addr =
|
||||
bitmap_addr; // FIXME: map this to a virtual address (ideally in the kernel heap between -128M and -64M)
|
||||
ASSERT((total_mem / 4096 / 8) < biggest_chunk_size);
|
||||
bitmap_size = total_mem / 4096 / 8 + 1;
|
||||
virtual_bitmap_addr = bitmap_addr;
|
||||
ASSERT((total_mem / PAGE_SIZE / 8) < biggest_chunk_size);
|
||||
bitmap_size = total_mem / PAGE_SIZE / 8 + 1;
|
||||
memset(bitmap_addr, 0xFF, bitmap_size);
|
||||
|
||||
ptr = &bootboot.mmap;
|
||||
for (uint64_t i = 0; i < mmap_entries; i++)
|
||||
{
|
||||
uint64_t index = MMapEnt_Ptr(ptr) / 4096;
|
||||
uint64_t index = MMapEnt_Ptr(ptr) / PAGE_SIZE;
|
||||
if (!MMapEnt_IsFree(ptr)) { reserved_mem += MMapEnt_Size(ptr); }
|
||||
else
|
||||
{
|
||||
free_mem += MMapEnt_Size(ptr);
|
||||
for (uint64_t j = 0; j < (MMapEnt_Size(ptr) / 4096); j++) { bitmap_set(index + j, false); }
|
||||
for (uint64_t j = 0; j < (MMapEnt_Size(ptr) / PAGE_SIZE); j++) { bitmap_set(index + j, false); }
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
|
||||
lock_pages(bitmap_addr, bitmap_size / 4096 + 1);
|
||||
lock_pages(bitmap_addr, bitmap_size / PAGE_SIZE + 1);
|
||||
}
|
||||
|
||||
static bool bitmap_read(uint64_t index)
|
||||
@ -90,9 +89,9 @@ void* PMM::request_page()
|
||||
if (bitmap_read(index)) continue;
|
||||
bitmap_set(index, true);
|
||||
start_index = index + 1;
|
||||
free_mem -= 4096;
|
||||
used_mem += 4096;
|
||||
return (void*)(index * 4096);
|
||||
free_mem -= PAGE_SIZE;
|
||||
used_mem += PAGE_SIZE;
|
||||
return (void*)(index * PAGE_SIZE);
|
||||
}
|
||||
|
||||
return PMM_FAILED;
|
||||
@ -119,9 +118,9 @@ void* PMM::request_pages(uint64_t count)
|
||||
if (contiguous == count)
|
||||
{
|
||||
for (uint64_t i = 0; i < count; i++) bitmap_set(contiguous_start + i, true);
|
||||
free_mem -= (count * 4096);
|
||||
used_mem += (count * 4096);
|
||||
return (void*)(contiguous_start * 4096);
|
||||
free_mem -= (count * PAGE_SIZE);
|
||||
used_mem += (count * PAGE_SIZE);
|
||||
return (void*)(contiguous_start * PAGE_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -130,11 +129,11 @@ void* PMM::request_pages(uint64_t count)
|
||||
|
||||
void PMM::free_page(void* address)
|
||||
{
|
||||
uint64_t index = (uint64_t)address / 4096;
|
||||
uint64_t index = (uint64_t)address / PAGE_SIZE;
|
||||
if (!bitmap_read(index)) return;
|
||||
bitmap_set(index, false);
|
||||
used_mem -= 4096;
|
||||
free_mem += 4096;
|
||||
used_mem -= PAGE_SIZE;
|
||||
free_mem += PAGE_SIZE;
|
||||
if (start_index > index) start_index = index;
|
||||
}
|
||||
|
||||
@ -145,11 +144,11 @@ void PMM::free_pages(void* address, uint64_t count)
|
||||
|
||||
void PMM::lock_page(void* address)
|
||||
{
|
||||
uint64_t index = ((uint64_t)address) / 4096;
|
||||
uint64_t index = ((uint64_t)address) / PAGE_SIZE;
|
||||
if (bitmap_read(index)) return;
|
||||
bitmap_set(index, true);
|
||||
used_mem += 4096;
|
||||
free_mem -= 4096;
|
||||
used_mem += PAGE_SIZE;
|
||||
free_mem -= PAGE_SIZE;
|
||||
}
|
||||
|
||||
void PMM::lock_pages(void* address, uint64_t count)
|
||||
@ -179,6 +178,6 @@ uint64_t PMM::get_bitmap_size()
|
||||
|
||||
void PMM::map_bitmap_to_virtual()
|
||||
{
|
||||
virtual_bitmap_addr =
|
||||
(char*)MemoryManager::get_unaligned_mappings(bitmap_addr, Utilities::get_blocks_from_size(4096, bitmap_size));
|
||||
virtual_bitmap_addr = (char*)MemoryManager::get_unaligned_mappings(
|
||||
bitmap_addr, Utilities::get_blocks_from_size(PAGE_SIZE, bitmap_size));
|
||||
}
|
@ -8,7 +8,7 @@
|
||||
#endif
|
||||
|
||||
#ifndef MOON_MINOR
|
||||
#define MOON_MINOR 9
|
||||
#define MOON_MINOR 10
|
||||
#endif
|
||||
|
||||
#ifndef _MOON_SUFFIX
|
||||
|
@ -29,8 +29,9 @@ void TextRenderer::reset()
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize("O0")
|
||||
|
||||
static void putchar_at_offset(char c, [[maybe_unused]] uint32_t cx, [[maybe_unused]] uint32_t cy,
|
||||
[[maybe_unused]] Color& fg, [[maybe_unused]] Color& bg)
|
||||
static void putchar_at_offset(
|
||||
char c, [[maybe_unused]] uint32_t cx, [[maybe_unused]] uint32_t cy, [[maybe_unused]] Color& fg,
|
||||
[[maybe_unused]] Color& bg) // FIXME: Rewrite this function to actually work with foreground and background colors.
|
||||
{
|
||||
uint8_t* glyph = &font[c * 16];
|
||||
for (uint32_t y = 0; y < FONT_HEIGHT; y++)
|
||||
|
@ -159,6 +159,15 @@ static int internal_printf(const char* format, PutString put_string_callback, ss
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'p': {
|
||||
char result[25];
|
||||
ultoa(va_arg(ap, uint64_t), result, 16);
|
||||
if (buffer_insert_index + strlen(result) > 1024) flush_buffer();
|
||||
memcpy(buffer + buffer_insert_index, result, strlen(result));
|
||||
buffer_insert_index += strlen(result);
|
||||
if (buffer_insert_index == 1024) flush_buffer();
|
||||
break;
|
||||
}
|
||||
case 's': {
|
||||
const char* str = va_arg(ap, const char*);
|
||||
while (strlen(str) > 1024)
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "sys/Syscall.h"
|
||||
#include "errno.h"
|
||||
#include "io/Serial.h"
|
||||
#include "thread/Scheduler.h"
|
||||
|
||||
@ -7,24 +8,18 @@ void Syscall::entry(Context* context)
|
||||
asm volatile("cli");
|
||||
switch (context->rax)
|
||||
{
|
||||
case SYS_exit: // sys_exit
|
||||
sys_exit(context);
|
||||
break;
|
||||
case SYS_yield: // sys_yield
|
||||
sys_yield(context);
|
||||
break;
|
||||
case SYS_sleep: // sys_sleep
|
||||
sys_sleep(context, context->rdi);
|
||||
break;
|
||||
case SYS_write: // sys_write
|
||||
sys_write(context, (const char*)context->rdi, context->rsi);
|
||||
break;
|
||||
case SYS_exit: sys_exit(context, (int)context->rdi); break;
|
||||
case SYS_yield: sys_yield(context); break;
|
||||
case SYS_sleep: sys_sleep(context, context->rdi); break;
|
||||
case SYS_write: sys_write(context, (int)context->rdi, context->rsi, (const char*)context->rdx); break;
|
||||
case SYS_paint: sys_paint(context, context->rdi, context->rsi, context->rdx, context->r10, context->r8); break;
|
||||
case SYS_rand: sys_rand(context); break;
|
||||
case SYS_getversion: sys_getversion(context, (char*)context->rdi, context->rsi); break;
|
||||
case SYS_gettid: sys_gettid(context); break;
|
||||
case SYS_mmap: sys_mmap(context, (void*)context->rdi, context->rsi, (int)context->rdx); break;
|
||||
case SYS_munmap: sys_munmap(context, (void*)context->rdi, context->rsi); break;
|
||||
default: context->rax = -1; break;
|
||||
case SYS_open: sys_open(context, (const char*)context->rdi, (int)context->rsi); break;
|
||||
case SYS_read: sys_read(context, (int)context->rdi, context->rsi, (char*)context->rdx); break;
|
||||
case SYS_close: sys_close(context, (int)context->rdi); break;
|
||||
default: context->rax = -ENOSYS; break;
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
#define MODULE "elf"
|
||||
|
||||
#include "sys/elf/ELFLoader.h"
|
||||
#include "fs/VFS.h"
|
||||
#include "init/InitRD.h"
|
||||
#include "log/Log.h"
|
||||
#include "memory/MemoryManager.h"
|
||||
@ -19,16 +20,37 @@ static const char* format_permissions(uint32_t flags)
|
||||
return perms;
|
||||
}
|
||||
|
||||
ELFImage* ELFLoader::load_elf_from_initrd(const char* filename)
|
||||
ELFImage* ELFLoader::load_elf_from_filesystem(const char* filename)
|
||||
{
|
||||
InitRD::File elf_file = InitRD::open(filename);
|
||||
if (!elf_file.addr)
|
||||
VFS::Node* node = VFS::resolve_path(filename);
|
||||
|
||||
if (!node)
|
||||
{
|
||||
kwarnln("Failed to open file %s for loading", filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return load_elf_from_address((uintptr_t)elf_file.addr);
|
||||
if (node->type == VFS_DIRECTORY)
|
||||
{
|
||||
kwarnln("Failed to load %s: is a directory", filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* file = kmalloc(node->length);
|
||||
if (VFS::read(node, 0, node->length, (char*)file) < 0)
|
||||
{
|
||||
kwarnln("Failed to read ELF image from file");
|
||||
kfree(file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ELFImage* result =
|
||||
load_elf_from_address((uintptr_t)file); // FIXME: Read headers and sections as we go along the file, to avoid
|
||||
// loading the entire file at once into memory.
|
||||
|
||||
kfree(file);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ELFImage* ELFLoader::load_elf_from_address(uintptr_t addr)
|
||||
|
@ -1,80 +1,89 @@
|
||||
#define MODULE "mem"
|
||||
|
||||
#include "errno.h"
|
||||
#include "interrupts/Context.h"
|
||||
#include "log/Log.h"
|
||||
#include "memory/MemoryManager.h"
|
||||
#include "memory/VMM.h"
|
||||
#include <stddef.h>
|
||||
|
||||
#define MAP_FAIL(errno) 0xffffffffffffff00 | (unsigned char)(errno)
|
||||
|
||||
void sys_mmap(Context* context, void* address, size_t size, int flags)
|
||||
{
|
||||
if (size < 4096)
|
||||
if (size < PAGE_SIZE)
|
||||
{
|
||||
kdbgln("sys_mmap: size too small");
|
||||
context->rax = 0;
|
||||
context->rax = MAP_FAIL(EINVAL);
|
||||
return;
|
||||
}
|
||||
int real_flags = MAP_USER;
|
||||
if (flags & MAP_READ_WRITE) real_flags |= MAP_READ_WRITE;
|
||||
if (address)
|
||||
{
|
||||
kdbgln("sys_mmap: %ld pages at address %lx, %s", size / 4096, (uint64_t)address,
|
||||
kdbgln("sys_mmap: %ld pages at address %p, %s", size / PAGE_SIZE, address,
|
||||
real_flags & MAP_READ_WRITE ? "rw" : "ro");
|
||||
if (kernelVMM.getPhysical((uint64_t)address) != (uint64_t)-1) // Address is already used.
|
||||
{
|
||||
kdbgln("attempt to mmap an already mapped address");
|
||||
context->rax = 0;
|
||||
context->rax = MAP_FAIL(ENOMEM);
|
||||
return;
|
||||
}
|
||||
uint64_t offset = (uint64_t)address % 4096;
|
||||
void* result = MemoryManager::get_pages_at((uint64_t)address - offset, size / 4096, real_flags);
|
||||
uint64_t offset = (uint64_t)address % PAGE_SIZE;
|
||||
void* result = MemoryManager::get_pages_at((uint64_t)address - offset, size / PAGE_SIZE, real_flags);
|
||||
if (result)
|
||||
{
|
||||
kdbgln("mmap succeeded: %lx", (uint64_t)result);
|
||||
kdbgln("mmap succeeded: %p", result);
|
||||
context->rax = (uint64_t)result;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
kdbgln("mmap failed");
|
||||
context->rax = 0;
|
||||
context->rax = MAP_FAIL(ENOMEM);
|
||||
return;
|
||||
}
|
||||
}
|
||||
kdbgln("sys_mmap: %ld pages at any address, %s", size / 4096, real_flags & MAP_READ_WRITE ? "rw" : "ro");
|
||||
void* result = MemoryManager::get_pages(size / 4096, real_flags);
|
||||
kdbgln("sys_mmap: %ld pages at any address, %s", size / PAGE_SIZE, real_flags & MAP_READ_WRITE ? "rw" : "ro");
|
||||
void* result = MemoryManager::get_pages(size / PAGE_SIZE, real_flags);
|
||||
if (result)
|
||||
{
|
||||
kdbgln("mmap succeeded: %lx", (uint64_t)result);
|
||||
kdbgln("mmap succeeded: %p", result);
|
||||
context->rax = (uint64_t)result;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
kdbgln("mmap failed");
|
||||
context->rax = 0;
|
||||
context->rax = MAP_FAIL(ENOMEM);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void sys_munmap(Context* context, void* address, size_t size)
|
||||
{
|
||||
kdbgln("sys_munmap: attempting to unmap %lx", (uint64_t)address);
|
||||
kdbgln("sys_munmap: attempting to unmap %p", address);
|
||||
if (size < PAGE_SIZE)
|
||||
{
|
||||
kdbgln("munmap failed: size is too small");
|
||||
context->rax = -EINVAL;
|
||||
return;
|
||||
}
|
||||
if (!address)
|
||||
{
|
||||
kdbgln("munmap failed: attempted to unmap page 0");
|
||||
context->rax = -1;
|
||||
context->rax = -EINVAL;
|
||||
return;
|
||||
}
|
||||
uint64_t flags = kernelVMM.getFlags((uint64_t)address);
|
||||
if (!(flags & MAP_USER))
|
||||
{
|
||||
kdbgln("munmap failed: attempted to unmap a kernel page");
|
||||
context->rax = -1;
|
||||
context->rax = -EINVAL;
|
||||
return;
|
||||
}
|
||||
uint64_t offset = (uint64_t)address % 4096;
|
||||
MemoryManager::release_pages((void*)((uint64_t)address - offset), size / 4096);
|
||||
uint64_t offset = (uint64_t)address % PAGE_SIZE;
|
||||
MemoryManager::release_pages((void*)((uint64_t)address - offset), size / PAGE_SIZE);
|
||||
kdbgln("munmap succeeded");
|
||||
context->rax = 0;
|
||||
return;
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "bootboot.h"
|
||||
#include "errno.h"
|
||||
#include "interrupts/Context.h"
|
||||
#include "render/Framebuffer.h"
|
||||
#include <stdint.h>
|
||||
@ -9,12 +10,12 @@ void sys_paint(Context* context, uint64_t x, uint64_t y, uint64_t w, uint64_t h,
|
||||
{
|
||||
if ((x + w) > bootboot.fb_width)
|
||||
{
|
||||
context->rax = -1;
|
||||
context->rax = -EINVAL;
|
||||
return;
|
||||
}
|
||||
if ((y + h) > bootboot.fb_height)
|
||||
{
|
||||
context->rax = -1;
|
||||
context->rax = -EINVAL;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
#include "thread/Scheduler.h"
|
||||
|
||||
void sys_exit(Context* context)
|
||||
void sys_exit(Context* context, int status)
|
||||
{
|
||||
Scheduler::task_exit(context);
|
||||
Scheduler::task_exit(context, status);
|
||||
}
|
||||
|
||||
void sys_yield(Context* context)
|
||||
|
@ -1,9 +1,140 @@
|
||||
#define MODULE "stdio"
|
||||
|
||||
#include "errno.h"
|
||||
#include "interrupts/Context.h"
|
||||
#include "io/Serial.h"
|
||||
#include "log/Log.h"
|
||||
#include "render/TextRenderer.h"
|
||||
#include "thread/Scheduler.h"
|
||||
#include "thread/Task.h"
|
||||
|
||||
void sys_write(Context* context, const char* addr, size_t size)
|
||||
#define OPEN_READ 1
|
||||
#define OPEN_WRITE 2
|
||||
|
||||
#define STDIO_FAIL(function, error) kwarnln("%s failed with %s", #function, #error)
|
||||
|
||||
void sys_write(Context* context, int fd, size_t size, const char* addr)
|
||||
{
|
||||
context->rax = size;
|
||||
TextRenderer::write(addr, size);
|
||||
if (!addr)
|
||||
{
|
||||
STDIO_FAIL(write, EINVAL);
|
||||
context->rax = -EINVAL; // FIXME: This should probably return EFAULT.
|
||||
return;
|
||||
}
|
||||
if (fd >= TASK_MAX_FDS || fd < 0)
|
||||
{
|
||||
kwarnln("file descriptor %d is outside the valid range", fd);
|
||||
STDIO_FAIL(write, EBADF);
|
||||
context->rax = -EBADF;
|
||||
return;
|
||||
}
|
||||
Task* current_task = Scheduler::current_task();
|
||||
if (!current_task->files[fd].is_open())
|
||||
{
|
||||
kwarnln("file descriptor %d is not open", fd);
|
||||
STDIO_FAIL(write, EBADF);
|
||||
context->rax = -EBADF;
|
||||
return;
|
||||
}
|
||||
if (!current_task->files[fd].can_write())
|
||||
{
|
||||
kwarnln("file descriptor %d is not open for writing", fd);
|
||||
STDIO_FAIL(write, EBADF);
|
||||
context->rax = -EBADF;
|
||||
return;
|
||||
}
|
||||
ssize_t result = current_task->files[fd].write(size, addr);
|
||||
context->rax = (size_t)result;
|
||||
return;
|
||||
}
|
||||
|
||||
void sys_open(Context* context, const char* filename, int flags)
|
||||
{
|
||||
Task* current_task = Scheduler::current_task();
|
||||
int fd;
|
||||
for (fd = 0; fd < TASK_MAX_FDS; fd++)
|
||||
{
|
||||
if (!current_task->files[fd].is_open()) break;
|
||||
}
|
||||
|
||||
if (fd == TASK_MAX_FDS)
|
||||
{
|
||||
STDIO_FAIL(open, EMFILE);
|
||||
context->rax = -EMFILE;
|
||||
return;
|
||||
}
|
||||
|
||||
VFS::Node* node = VFS::resolve_path(filename);
|
||||
if (!node)
|
||||
{
|
||||
STDIO_FAIL(open, ENOENT);
|
||||
context->rax = -ENOENT;
|
||||
return;
|
||||
}
|
||||
|
||||
bool can_read = (flags & OPEN_READ) > 0;
|
||||
bool can_write = (flags & OPEN_WRITE) > 0;
|
||||
if (!can_read && !can_write)
|
||||
{
|
||||
STDIO_FAIL(open, EINVAL);
|
||||
context->rax = -EINVAL;
|
||||
return;
|
||||
}
|
||||
|
||||
kdbgln("open(): opening %s %s, allocated file descriptor %d", filename,
|
||||
(can_read && can_write) ? "rw"
|
||||
: can_read ? "r-"
|
||||
: "-w",
|
||||
fd);
|
||||
|
||||
current_task->files[fd].open(node, can_read, can_write);
|
||||
context->rax = fd;
|
||||
return;
|
||||
}
|
||||
|
||||
void sys_read(Context* context, int fd, size_t size, char* buffer)
|
||||
{
|
||||
if (!buffer)
|
||||
{
|
||||
STDIO_FAIL(read, EINVAL);
|
||||
context->rax = -EINVAL; // FIXME: This should probably return EFAULT.
|
||||
return;
|
||||
}
|
||||
if (fd >= TASK_MAX_FDS || fd < 0)
|
||||
{
|
||||
STDIO_FAIL(read, EBADF);
|
||||
context->rax = -EBADF;
|
||||
return;
|
||||
}
|
||||
Task* current_task = Scheduler::current_task();
|
||||
if (!current_task->files[fd].is_open() || !current_task->files[fd].can_read())
|
||||
{
|
||||
STDIO_FAIL(read, EBADF);
|
||||
context->rax = -EBADF;
|
||||
return;
|
||||
}
|
||||
ssize_t result = current_task->files[fd].read(size, buffer);
|
||||
context->rax = (size_t)result;
|
||||
return;
|
||||
}
|
||||
|
||||
void sys_close(Context* context, int fd)
|
||||
{
|
||||
if (fd >= TASK_MAX_FDS || fd < 0)
|
||||
{
|
||||
STDIO_FAIL(close, EBADF);
|
||||
context->rax = -EBADF;
|
||||
return;
|
||||
}
|
||||
Task* current_task = Scheduler::current_task();
|
||||
if (!current_task->files[fd].is_open())
|
||||
{
|
||||
STDIO_FAIL(close, EBADF);
|
||||
context->rax = -EBADF;
|
||||
return;
|
||||
}
|
||||
kdbgln("close(): releasing file descriptor %d", fd);
|
||||
current_task->files[fd].close();
|
||||
context->rax = 0;
|
||||
return;
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
#include "config.h"
|
||||
#include "interrupts/Context.h"
|
||||
#include "std/stdio.h"
|
||||
|
||||
void sys_getversion(Context* context, char* buffer, size_t max)
|
||||
{
|
||||
context->rax = snprintf(buffer, max, "moon %s", moon_version());
|
||||
}
|
@ -64,7 +64,7 @@ void Scheduler::add_kernel_task(void (*task)(void))
|
||||
new_task->regs.rip = (uint64_t)task;
|
||||
new_task->allocated_stack =
|
||||
(uint64_t)MemoryManager::get_pages(TASK_PAGES_IN_STACK); // 16 KB is enough for everyone, right?
|
||||
new_task->regs.rsp = new_task->allocated_stack + (4096 * TASK_PAGES_IN_STACK) - sizeof(uintptr_t);
|
||||
new_task->regs.rsp = new_task->allocated_stack + (PAGE_SIZE * TASK_PAGES_IN_STACK) - sizeof(uintptr_t);
|
||||
new_task->regs.cs = 0x08;
|
||||
new_task->regs.ss = 0x10;
|
||||
new_task->regs.ds = 0x10;
|
||||
@ -92,7 +92,7 @@ void Scheduler::add_user_task(void* task)
|
||||
new_task->regs.rip = (uint64_t)task;
|
||||
new_task->allocated_stack = (uint64_t)MemoryManager::get_pages(
|
||||
TASK_PAGES_IN_STACK, MAP_READ_WRITE | MAP_USER); // 16 KB is enough for everyone, right?
|
||||
new_task->regs.rsp = new_task->allocated_stack + (4096 * TASK_PAGES_IN_STACK) - sizeof(uintptr_t);
|
||||
new_task->regs.rsp = new_task->allocated_stack + (PAGE_SIZE * TASK_PAGES_IN_STACK) - sizeof(uintptr_t);
|
||||
new_task->regs.cs = 0x18 | 0x03;
|
||||
new_task->regs.ss = 0x20 | 0x03;
|
||||
new_task->regs.ds = 0x20 | 0x03;
|
||||
@ -117,23 +117,18 @@ void Scheduler::load_user_task(const char* filename)
|
||||
Task* new_task = new Task;
|
||||
ASSERT(new_task);
|
||||
new_task->id = free_tid++;
|
||||
ELFImage* image = ELFLoader::load_elf_from_initrd(filename);
|
||||
ELFImage* image = ELFLoader::load_elf_from_filesystem(filename);
|
||||
if (!image)
|
||||
{
|
||||
kerrorln("Failed to load %s from initrd", filename);
|
||||
delete new_task;
|
||||
return;
|
||||
}
|
||||
new_task->regs.rip = image->entry;
|
||||
new_task->image = image;
|
||||
if (!new_task->regs.rip)
|
||||
{
|
||||
kwarnln("Failed to load user task %s", filename);
|
||||
delete new_task;
|
||||
return;
|
||||
}
|
||||
new_task->allocated_stack = (uint64_t)MemoryManager::get_pages(
|
||||
TASK_PAGES_IN_STACK, MAP_READ_WRITE | MAP_USER); // 16 KB is enough for everyone, right?
|
||||
new_task->regs.rsp = new_task->allocated_stack + (4096 * TASK_PAGES_IN_STACK) - sizeof(uintptr_t);
|
||||
new_task->regs.rsp = new_task->allocated_stack + (PAGE_SIZE * TASK_PAGES_IN_STACK) - sizeof(uintptr_t);
|
||||
new_task->regs.cs = 0x18 | 0x03;
|
||||
new_task->regs.ss = 0x20 | 0x03;
|
||||
new_task->regs.ds = 0x20 | 0x03;
|
||||
@ -158,7 +153,7 @@ void Scheduler::reap_task(Task* task)
|
||||
task_num--;
|
||||
Task* exiting_task = task;
|
||||
ASSERT(task->id != 0); // WHY IN THE WORLD WOULD WE BE REAPING THE IDLE TASK?
|
||||
kinfoln("reaping task %ld", exiting_task->id);
|
||||
kinfoln("reaping task %ld, exited with code %ld", exiting_task->id, exiting_task->exit_status);
|
||||
if (exiting_task->allocated_stack)
|
||||
MemoryManager::release_pages((void*)exiting_task->allocated_stack, TASK_PAGES_IN_STACK);
|
||||
if (exiting_task->image)
|
||||
@ -173,20 +168,22 @@ void Scheduler::reap_task(Task* task)
|
||||
delete exiting_task;
|
||||
}
|
||||
|
||||
void Scheduler::task_exit(Context* context)
|
||||
void Scheduler::task_exit(Context* context, int64_t status)
|
||||
{
|
||||
ASSERT(Interrupts::is_in_handler());
|
||||
kdbgln("exit: task %ld finished running, used %ld ms of cpu time", sched_current_task->id,
|
||||
sched_current_task->cpu_time);
|
||||
sched_current_task->state = sched_current_task->Exited;
|
||||
sched_current_task->exit_status = status;
|
||||
task_yield(context);
|
||||
}
|
||||
|
||||
void Scheduler::task_misbehave(Context* context)
|
||||
void Scheduler::task_misbehave(Context* context, int64_t status)
|
||||
{
|
||||
ASSERT(Interrupts::is_in_handler());
|
||||
kdbgln("exit: task %ld misbehaved, used %ld ms of cpu time", sched_current_task->id, sched_current_task->cpu_time);
|
||||
sched_current_task->state = sched_current_task->Exited;
|
||||
sched_current_task->exit_status = status;
|
||||
task_yield(context);
|
||||
}
|
||||
|
||||
@ -316,9 +313,9 @@ void Scheduler::yield()
|
||||
asm volatile("int $0x42" : : "a"(1));
|
||||
}
|
||||
|
||||
void Scheduler::exit()
|
||||
void Scheduler::exit(int status)
|
||||
{
|
||||
asm volatile("int $0x42" : : "a"(0));
|
||||
asm volatile("int $0x42" : : "a"(0), "D"(status));
|
||||
}
|
||||
|
||||
void Scheduler::sleep(unsigned long ms)
|
||||
|
@ -21,7 +21,7 @@ typedef struct stackframe
|
||||
void StackTracer::trace()
|
||||
{
|
||||
stackframe* frame = (stackframe*)m_base_pointer;
|
||||
while (Memory::is_kernel_address((uintptr_t)frame))
|
||||
while (frame)
|
||||
{
|
||||
char symbol_name[512];
|
||||
get_symbol_name(frame->instruction, symbol_name);
|
||||
@ -32,11 +32,6 @@ void StackTracer::trace()
|
||||
|
||||
void StackTracer::trace_with_ip(uintptr_t ip)
|
||||
{
|
||||
if (!Memory::is_kernel_address(ip))
|
||||
{
|
||||
printf("(user stack)");
|
||||
return;
|
||||
}
|
||||
char symbol_name[512];
|
||||
get_symbol_name(ip, symbol_name);
|
||||
printf("%lx: %s\n", ip, symbol_name);
|
||||
|
@ -3,6 +3,7 @@ section .text
|
||||
extern _init
|
||||
extern main
|
||||
extern _fini
|
||||
extern initialize_libc
|
||||
extern exit
|
||||
|
||||
global _start
|
||||
@ -13,6 +14,8 @@ _start:
|
||||
push rbp ; rbp=0
|
||||
mov rbp, rsp
|
||||
|
||||
call initialize_libc
|
||||
|
||||
call _init
|
||||
|
||||
mov rdi, 0 ; argc = 0
|
||||
|
28
libs/libc/include/bits/error.h
Normal file
28
libs/libc/include/bits/error.h
Normal file
@ -0,0 +1,28 @@
|
||||
#ifndef _BITS_ERROR_H
|
||||
#define _BITS_ERROR_H
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#define _RETURN_WITH_ERRNO(rc, type) \
|
||||
do { \
|
||||
if (rc < 0) \
|
||||
{ \
|
||||
errno = (int)(-rc); \
|
||||
return -1; \
|
||||
} \
|
||||
errno = 0; \
|
||||
return (type)rc; \
|
||||
} while (0)
|
||||
|
||||
#define _RETURN_WITH_MEMORY_ERRNO(rc, type) \
|
||||
do { \
|
||||
if ((unsigned long int)rc > 0xffffffffffffff00) \
|
||||
{ \
|
||||
errno = (int)((rc)&0xff); \
|
||||
return (type)-1; \
|
||||
} \
|
||||
errno = 0; \
|
||||
return (type)rc; \
|
||||
} while (0)
|
||||
|
||||
#endif
|
@ -1,5 +1,5 @@
|
||||
#ifndef _LIBALLOC_H
|
||||
#define _LIBALLOC_H
|
||||
#ifndef _BITS_LIBALLOC_H
|
||||
#define _BITS_LIBALLOC_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#ifndef __MACROS_H
|
||||
#define __MACROS_H
|
||||
#ifndef _BITS_MACROS_H
|
||||
#define _BITS_MACROS_H
|
||||
|
||||
#define noreturn __attribute__((noreturn))
|
||||
#define align(n) __attribute__((aligned(n)))
|
||||
|
@ -0,0 +1,15 @@
|
||||
#ifndef _ERRNO_H
|
||||
#define _ERRNO_H
|
||||
|
||||
extern int errno;
|
||||
|
||||
#define EPERM 1
|
||||
#define ENOENT 2
|
||||
#define EBADF 9
|
||||
#define ENOMEM 12
|
||||
#define EISDIR 21
|
||||
#define EINVAL 22
|
||||
#define EMFILE 24
|
||||
#define ENOSYS 38
|
||||
|
||||
#endif
|
19
libs/libc/include/fcntl.h
Normal file
19
libs/libc/include/fcntl.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef _FCNTL_H
|
||||
#define _FCNTL_H
|
||||
|
||||
#define O_RDONLY 1
|
||||
#define O_WRONLY 2
|
||||
#define O_RDWR 3
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
int open(const char*, int);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -7,10 +7,12 @@
|
||||
#define SYS_write 3
|
||||
#define SYS_paint 4
|
||||
#define SYS_rand 5
|
||||
#define SYS_getversion 6
|
||||
#define SYS_gettid 7
|
||||
#define SYS_mmap 8
|
||||
#define SYS_munmap 9
|
||||
#define SYS_gettid 6
|
||||
#define SYS_mmap 7
|
||||
#define SYS_munmap 8
|
||||
#define SYS_open 9
|
||||
#define SYS_read 10
|
||||
#define SYS_close 11
|
||||
|
||||
#ifndef __want_syscalls
|
||||
#ifdef __cplusplus
|
||||
|
@ -8,16 +8,20 @@
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int unused;
|
||||
int f_fd;
|
||||
int f_eof;
|
||||
int f_err;
|
||||
} FILE;
|
||||
|
||||
extern FILE* __stderr;
|
||||
extern FILE* __stdout;
|
||||
#define stderr __stderr
|
||||
#define stdout __stdout
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
extern FILE* stderr;
|
||||
#define stderr stderr
|
||||
int fclose(FILE*);
|
||||
int fflush(FILE*);
|
||||
FILE* fopen(const char*, const char*);
|
||||
@ -26,6 +30,9 @@ extern "C"
|
||||
int fseek(FILE*, long, int);
|
||||
long ftell(FILE*);
|
||||
size_t fwrite(const void*, size_t, size_t, FILE*);
|
||||
int ferror(FILE*);
|
||||
int feof(FILE*);
|
||||
void clearerr(FILE*);
|
||||
void setbuf(FILE*, char*);
|
||||
int vfprintf(FILE*, const char*, va_list);
|
||||
int printf(const char*, ...);
|
||||
@ -35,6 +42,7 @@ extern "C"
|
||||
int vsprintf(char*, const char*, va_list);
|
||||
int vsnprintf(char*, size_t, const char*, va_list);
|
||||
int puts(const char*);
|
||||
void perror(const char*);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -23,6 +23,8 @@ extern "C"
|
||||
deprecated("strcat is unsafe and should not be used; use strncat instead") char* strcat(char*, const char*);
|
||||
char* strncat(char*, const char*, size_t);
|
||||
|
||||
char* strerror(int);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
26
libs/libc/include/sys/mman.h
Normal file
26
libs/libc/include/sys/mman.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef _SYS_MMAN_H
|
||||
#define _SYS_MMAN_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef unsigned long off_t;
|
||||
|
||||
#define MAP_FAILED (void*)-1
|
||||
|
||||
#define PROT_READ_WRITE 1
|
||||
|
||||
#define PAGE_SIZE 4096
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void* mmap(void*, size_t, int, int, int, off_t);
|
||||
int munmap(void* addr, size_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,4 +1,8 @@
|
||||
#ifndef _SYS_TYPES_H
|
||||
#define _SYS_TYPES_H
|
||||
|
||||
typedef long int pid_t;
|
||||
typedef unsigned long int size_t;
|
||||
typedef long int ssize_t;
|
||||
|
||||
#endif
|
@ -1,10 +1,13 @@
|
||||
#ifndef _UNISTD_H
|
||||
#define _UNISTD_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
int execv(const char*, char* const[]);
|
||||
int execve(const char*, char* const[], char* const[]);
|
||||
int execvp(const char*, char* const[]);
|
||||
@ -12,7 +15,12 @@ extern "C"
|
||||
long syscall(long, ...);
|
||||
unsigned int sleep(unsigned int);
|
||||
|
||||
ssize_t read(int, void*, size_t);
|
||||
ssize_t write(int, const void*, size_t);
|
||||
int close(int);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,6 +1,5 @@
|
||||
#include <stddef.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
int liballoc_lock()
|
||||
{
|
||||
@ -14,14 +13,12 @@ int liballoc_unlock()
|
||||
|
||||
void* liballoc_alloc(size_t size)
|
||||
{
|
||||
unsigned long int result = (unsigned long int)syscall(SYS_mmap, NULL, size * 4096, 1);
|
||||
void* result = mmap(NULL, size * PAGE_SIZE, PROT_READ_WRITE, 0, 0, 0);
|
||||
if (result == MAP_FAILED) return 0;
|
||||
return (void*)result;
|
||||
}
|
||||
|
||||
int liballoc_free(void* address, size_t size)
|
||||
{
|
||||
int result = (int)syscall(SYS_munmap, address, size * 4096);
|
||||
if (result < 0) return 1;
|
||||
else
|
||||
return 0;
|
||||
return munmap(address, size * PAGE_SIZE);
|
||||
}
|
3
libs/libc/src/errno.cpp
Normal file
3
libs/libc/src/errno.cpp
Normal file
@ -0,0 +1,3 @@
|
||||
#include <errno.h>
|
||||
|
||||
int errno;
|
11
libs/libc/src/fcntl.cpp
Normal file
11
libs/libc/src/fcntl.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
#include <fcntl.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
int open(const char* pathname, int flags)
|
||||
{
|
||||
return (int)syscall(SYS_open, pathname, flags);
|
||||
}
|
||||
}
|
96
libs/libc/src/file.cpp
Normal file
96
libs/libc/src/file.cpp
Normal file
@ -0,0 +1,96 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <luna.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
FILE* __stderr;
|
||||
FILE* __stdout;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
int fclose(FILE* stream)
|
||||
{
|
||||
int status = close(stream->f_fd);
|
||||
if (status < 0)
|
||||
{
|
||||
int savederr = errno;
|
||||
free(stream); // We do not want to leak memory. man fclose(3) says that whether fclose() fails or not, any
|
||||
// further operation on the stream results in undefined behavior. So we are free to free the
|
||||
// stream.
|
||||
errno = savederr; // free might reset errno. We don't want that.
|
||||
}
|
||||
else { free(stream); }
|
||||
return status;
|
||||
}
|
||||
|
||||
int fflush(FILE*)
|
||||
{
|
||||
return 0; // FIXME: Implement buffered IO.
|
||||
}
|
||||
|
||||
FILE* fopen(const char* pathname, const char*)
|
||||
{
|
||||
int fd = open(pathname, O_RDWR); // FIXME: Use the mode string.
|
||||
if (fd < 0) { return 0; }
|
||||
FILE* stream = (FILE*)malloc(sizeof(FILE));
|
||||
stream->f_fd = fd;
|
||||
clearerr(stream);
|
||||
return stream;
|
||||
}
|
||||
|
||||
size_t fread(void* buf, size_t size, size_t nmemb, FILE* stream)
|
||||
{
|
||||
ssize_t status = read(stream->f_fd, buf, size * nmemb);
|
||||
if (status < 0)
|
||||
{
|
||||
stream->f_err = 1;
|
||||
return 0;
|
||||
}
|
||||
if (status == 0) stream->f_eof = 1;
|
||||
return (size_t)status;
|
||||
}
|
||||
|
||||
int ferror(FILE* stream)
|
||||
{
|
||||
return stream->f_err;
|
||||
}
|
||||
|
||||
int feof(FILE* stream)
|
||||
{
|
||||
return stream->f_eof;
|
||||
}
|
||||
|
||||
void clearerr(FILE* stream)
|
||||
{
|
||||
stream->f_err = stream->f_eof = 0;
|
||||
}
|
||||
|
||||
int fseek(FILE*, long, int)
|
||||
{
|
||||
NOT_IMPLEMENTED("fseek");
|
||||
}
|
||||
|
||||
long ftell(FILE*)
|
||||
{
|
||||
NOT_IMPLEMENTED("ftell");
|
||||
}
|
||||
|
||||
size_t fwrite(const void* buf, size_t size, size_t nmemb, FILE* stream)
|
||||
{
|
||||
ssize_t status = write(stream->f_fd, buf, size * nmemb);
|
||||
if (status < 0)
|
||||
{
|
||||
stream->f_err = 1;
|
||||
return 0;
|
||||
}
|
||||
if (status == 0) stream->f_eof = 1;
|
||||
return (size_t)status;
|
||||
}
|
||||
|
||||
void setbuf(FILE*, char*)
|
||||
{
|
||||
NOT_IMPLEMENTED("setbuf");
|
||||
}
|
||||
}
|
14
libs/libc/src/init.cpp
Normal file
14
libs/libc/src/init.cpp
Normal file
@ -0,0 +1,14 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
extern "C" void initialize_libc()
|
||||
{
|
||||
__stderr = fopen("/dev/console", "rw");
|
||||
if (!stderr) exit(errno);
|
||||
__stdout = fopen("/dev/console", "rw");
|
||||
if (!stdout) exit(errno);
|
||||
clearerr(__stderr);
|
||||
clearerr(__stdout);
|
||||
}
|
@ -1,4 +1,6 @@
|
||||
#include <luna.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
@ -19,8 +21,7 @@ extern "C"
|
||||
|
||||
noreturn void __luna_abort(const char* message)
|
||||
{
|
||||
syscall(SYS_write, message, strlen(message));
|
||||
syscall(SYS_exit);
|
||||
__builtin_unreachable();
|
||||
fwrite(message, strlen(message), 1, stdout);
|
||||
abort();
|
||||
}
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
#include <errno.h>
|
||||
#include <luna.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
@ -242,6 +243,30 @@ static int internal_printf(const char* format, PutString put_string_callback, ss
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'p': {
|
||||
char result[25];
|
||||
__unsignedtoa<unsigned long>(va_arg(ap, uint64_t), result, 16);
|
||||
if (buffer_insert_index + strlen(result) > 1024) flush_buffer();
|
||||
memcpy(buffer + buffer_insert_index, result, strlen(result));
|
||||
buffer_insert_index += strlen(result);
|
||||
if (buffer_insert_index == 1024) flush_buffer();
|
||||
break;
|
||||
}
|
||||
case 'm': {
|
||||
const char* str = strerror(errno);
|
||||
while (strlen(str) > 1024)
|
||||
{
|
||||
flush_buffer();
|
||||
memcpy(buffer, str, 1024);
|
||||
str += 1024;
|
||||
buffer_insert_index = 1024;
|
||||
}
|
||||
if (buffer_insert_index + strlen(str) > 1024) flush_buffer();
|
||||
memcpy(buffer + buffer_insert_index, str, strlen(str));
|
||||
buffer_insert_index += strlen(str);
|
||||
if (buffer_insert_index == 1024) flush_buffer();
|
||||
break;
|
||||
}
|
||||
case 's': {
|
||||
const char* str = va_arg(ap, const char*);
|
||||
while (strlen(str) > 1024)
|
||||
@ -281,8 +306,7 @@ extern "C"
|
||||
{
|
||||
int vprintf(const char* format, va_list ap)
|
||||
{
|
||||
return internal_printf(
|
||||
format, [](const char* s) { syscall(SYS_write, s, strlen(s)); }, -1, ap);
|
||||
return vfprintf(stdout, format, ap);
|
||||
}
|
||||
|
||||
int vsprintf(char* str, const char* format, va_list ap)
|
||||
@ -304,4 +328,46 @@ extern "C"
|
||||
},
|
||||
max == 0 ? 0 : max - 1, ap);
|
||||
}
|
||||
|
||||
int snprintf(char* str, size_t max, const char* format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
int written = vsnprintf(str, max, format, ap);
|
||||
va_end(ap);
|
||||
return written;
|
||||
}
|
||||
|
||||
int sprintf(char* str, const char* format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
int written = vsprintf(str, format, ap);
|
||||
va_end(ap);
|
||||
return written;
|
||||
}
|
||||
|
||||
int printf(const char* format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
int written = vfprintf(stdout, format, ap);
|
||||
va_end(ap);
|
||||
return written;
|
||||
}
|
||||
|
||||
int fprintf(FILE* stream, const char* format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
int written = vfprintf(stream, format, ap);
|
||||
va_end(ap);
|
||||
return written;
|
||||
}
|
||||
|
||||
int vfprintf(FILE* stream, const char* format, va_list ap)
|
||||
{
|
||||
return internal_printf(
|
||||
format, [&](const char* s) { fwrite(s, strlen(s), 1, stream); }, -1, ap);
|
||||
}
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
#include <errno.h>
|
||||
#include <luna.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -7,74 +8,18 @@
|
||||
|
||||
extern "C"
|
||||
{
|
||||
int fclose(FILE*)
|
||||
{
|
||||
NOT_IMPLEMENTED("fclose");
|
||||
}
|
||||
int fflush(FILE*)
|
||||
{
|
||||
NOT_IMPLEMENTED("fflush");
|
||||
}
|
||||
FILE* fopen(const char*, const char*)
|
||||
{
|
||||
NOT_IMPLEMENTED("fopen");
|
||||
}
|
||||
int fprintf(FILE*, const char*, ...)
|
||||
{
|
||||
NOT_IMPLEMENTED("fprintf");
|
||||
}
|
||||
size_t fread(void*, size_t, size_t, FILE*)
|
||||
{
|
||||
NOT_IMPLEMENTED("fread");
|
||||
}
|
||||
int fseek(FILE*, long, int)
|
||||
{
|
||||
NOT_IMPLEMENTED("fseek");
|
||||
}
|
||||
long ftell(FILE*)
|
||||
{
|
||||
NOT_IMPLEMENTED("ftell");
|
||||
}
|
||||
size_t fwrite(const void*, size_t, size_t, FILE*)
|
||||
{
|
||||
NOT_IMPLEMENTED("fwrite");
|
||||
}
|
||||
void setbuf(FILE*, char*)
|
||||
{
|
||||
NOT_IMPLEMENTED("setbuf");
|
||||
}
|
||||
int vfprintf(FILE*, const char*, va_list)
|
||||
{
|
||||
NOT_IMPLEMENTED("vfprintf");
|
||||
}
|
||||
int puts(const char* s)
|
||||
{
|
||||
long nwritten = syscall(SYS_write, s, strlen(s));
|
||||
nwritten += syscall(SYS_write, "\n", 1);
|
||||
long nwritten = fwrite(s, strlen(s), 1, stdout);
|
||||
if (nwritten < 0) return -1;
|
||||
nwritten += fwrite("\n", 1, 1, stdout);
|
||||
return (int)nwritten;
|
||||
}
|
||||
int snprintf(char* str, size_t max, const char* format, ...)
|
||||
void perror(const char* s)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
int written = vsnprintf(str, max, format, ap);
|
||||
va_end(ap);
|
||||
return written;
|
||||
}
|
||||
int sprintf(char* str, const char* format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
int written = vsprintf(str, format, ap);
|
||||
va_end(ap);
|
||||
return written;
|
||||
}
|
||||
int printf(const char* format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
int written = vprintf(format, ap);
|
||||
va_end(ap);
|
||||
return written;
|
||||
int savederr =
|
||||
errno; // This was necessary before, but even more now since we clear errno on successful syscalls now.
|
||||
if (s && *s) { fprintf(stderr, "%s: ", s); }
|
||||
fprintf(stderr, "%s\n", strerror(savederr));
|
||||
}
|
||||
}
|
@ -15,9 +15,9 @@ extern "C"
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
noreturn void exit(int)
|
||||
noreturn void exit(int status)
|
||||
{
|
||||
syscall(SYS_exit);
|
||||
syscall(SYS_exit, status);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include <errno.h>
|
||||
#include <luna.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -60,9 +61,11 @@ extern "C"
|
||||
return dest;
|
||||
}
|
||||
|
||||
char* strchr(const char*, int)
|
||||
char* strchr(const char* str, int chr)
|
||||
{
|
||||
NOT_IMPLEMENTED("strchr");
|
||||
while (*str && *str != (char)chr) str++;
|
||||
if (*str) return const_cast<char*>(str);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* memclr(void* start, size_t count)
|
||||
@ -108,4 +111,26 @@ extern "C"
|
||||
// we return "m_start" + the amount of bytes that were transfered
|
||||
return (void*)(((size_t)start) + i);
|
||||
}
|
||||
|
||||
#pragma GCC push_options
|
||||
#pragma GCC diagnostic ignored "-Wwrite-strings"
|
||||
|
||||
char* strerror(int errnum)
|
||||
{
|
||||
switch (errnum)
|
||||
{
|
||||
case EPERM: return "Operation not permitted";
|
||||
case EINVAL: return "Invalid argument";
|
||||
case ENOMEM: return "Out of memory";
|
||||
case ENOSYS: return "Function not implemented";
|
||||
case ENOENT: return "No such file or directory";
|
||||
case EBADF: return "Bad file descriptor";
|
||||
case EMFILE: return "Too many open files";
|
||||
case EISDIR: return "Is a directory";
|
||||
case 0: return "Success";
|
||||
default: return (char*)(unsigned long int)errnum;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma GCC pop_options
|
||||
}
|
17
libs/libc/src/sys/mman.cpp
Normal file
17
libs/libc/src/sys/mman.cpp
Normal file
@ -0,0 +1,17 @@
|
||||
#include <sys/mman.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
// FIXME: Implement a POSIX-compliant mmap.
|
||||
void* mmap(void* addr, size_t len, int prot, int, int, off_t)
|
||||
{
|
||||
return (void*)syscall(SYS_mmap, addr, len, prot);
|
||||
}
|
||||
|
||||
int munmap(void* addr, size_t len)
|
||||
{
|
||||
return (int)syscall(SYS_munmap, addr, len);
|
||||
}
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
#include <bits/error.h>
|
||||
#include <luna.h>
|
||||
#include <luna/syscall.h>
|
||||
#include <stdarg.h>
|
||||
@ -30,19 +31,21 @@ extern "C"
|
||||
va_start(ap, number);
|
||||
switch (number)
|
||||
{
|
||||
case SYS_exit:
|
||||
case SYS_yield:
|
||||
case SYS_gettid:
|
||||
case SYS_rand: result = __luna_syscall0(number); break;
|
||||
case SYS_exit:
|
||||
case SYS_close:
|
||||
case SYS_sleep: result = __luna_syscall1(number, va_arg(ap, arg)); break;
|
||||
case SYS_write:
|
||||
case SYS_munmap:
|
||||
case SYS_getversion: {
|
||||
case SYS_open: {
|
||||
arg arg0 = va_arg(ap, arg);
|
||||
arg arg1 = va_arg(ap, arg);
|
||||
result = __luna_syscall2(number, arg0, arg1);
|
||||
break;
|
||||
}
|
||||
case SYS_write:
|
||||
case SYS_read:
|
||||
case SYS_mmap: {
|
||||
arg arg0 = va_arg(ap, arg);
|
||||
arg arg1 = va_arg(ap, arg);
|
||||
@ -59,14 +62,30 @@ extern "C"
|
||||
result = __luna_syscall5(number, arg0, arg1, arg2, arg3, arg4);
|
||||
break;
|
||||
}
|
||||
default: result = -1; break;
|
||||
default: result = -ENOSYS; break;
|
||||
}
|
||||
va_end(ap);
|
||||
return result;
|
||||
if (number == SYS_mmap) { _RETURN_WITH_MEMORY_ERRNO(result, long int); }
|
||||
else { _RETURN_WITH_ERRNO(result, long); }
|
||||
}
|
||||
|
||||
unsigned int sleep(unsigned int seconds)
|
||||
{
|
||||
return msleep(seconds * 1000);
|
||||
}
|
||||
|
||||
ssize_t read(int fd, void* buf, size_t count)
|
||||
{
|
||||
return syscall(SYS_read, fd, count, buf); // yes, our read() syscall is in the wrong order.
|
||||
}
|
||||
|
||||
ssize_t write(int fd, const void* buf, size_t count)
|
||||
{
|
||||
return syscall(SYS_write, fd, count, buf); // yes, our write() syscall is in the wrong order.
|
||||
}
|
||||
|
||||
int close(int fd)
|
||||
{
|
||||
return (int)syscall(SYS_close, fd);
|
||||
}
|
||||
}
|
6
tools/build-debug.sh
Normal file
6
tools/build-debug.sh
Normal file
@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
source $(dirname $0)/env.sh
|
||||
|
||||
MOON_BUILD_DEBUG=1 tools/rebuild-iso.sh
|
@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
source $(dirname $0)/env.sh
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
source $(dirname $0)/env.sh
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
source $(dirname $0)/env.sh
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
source $(dirname $0)/env.sh
|
||||
|
@ -1,8 +1,6 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
source $(dirname $0)/env.sh
|
||||
|
||||
MOON_BUILD_DEBUG=1 tools/rebuild-iso.sh
|
||||
|
||||
qemu-system-x86_64 -cdrom Luna.iso -smp 1 -m 256M -serial stdio -d int,cpu_reset -s -no-reboot $@
|
||||
qemu-system-x86_64 -cdrom Luna.iso -smp 1 -m 256M -serial stdio -d int,cpu_reset -s $@
|
@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
export LUNA_ROOT=$(realpath $(dirname $0)/..)
|
||||
export LUNA_BASE=$LUNA_ROOT/base
|
||||
export PATH=$LUNA_ROOT/toolchain/x86-64-luna/bin:$LUNA_ROOT/toolchain/dist:$PATH
|
||||
@ -7,4 +7,5 @@ export CC=x86_64-luna-gcc
|
||||
export CXX=x86_64-luna-g++
|
||||
export LD=x86_64-luna-ld
|
||||
export AR=x86_64-luna-ar
|
||||
export ASM=nasm
|
||||
export ASM=nasm
|
||||
export STRIP=x86_64-luna-strip
|
6
tools/gdb.sh
Normal file
6
tools/gdb.sh
Normal file
@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
source $(dirname $0)/env.sh
|
||||
|
||||
gdb -x .gdbconf
|
@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
source $(dirname $0)/env.sh
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
source $(dirname $0)/env.sh
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
source $(dirname $0)/env.sh
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
source $(dirname $0)/env.sh
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
source $(dirname $0)/env.sh
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
source $(dirname $0)/env.sh
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
source $(dirname $0)/setup-env.sh
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
source $(dirname $0)/env.sh
|
||||
|
||||
export LUNA_GCC_VERSION_REQUIRED=12.2.0
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
source $(dirname $0)/setup-env.sh
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
source $(dirname $0)/env.sh
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
if ! $(dirname $0)/test-binutils.sh
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
source $(dirname $0)/env.sh
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
source $(dirname $0)/setup-env.sh
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
source $(dirname $0)/setup-env.sh
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user