Compare commits

..

No commits in common. "da41784183fe38f7ac07cf1d09ddf1a1da5c5194" and "185757e2a7dcce05f14d65efab4da41e7e8b3199" have entirely different histories.

180 changed files with 896 additions and 5869 deletions

7
.gitignore vendored
View File

@ -2,13 +2,14 @@ Luna.iso
toolchain/
.vscode/
**/*.o
initrd/boot/moon
kernel/bin/moon
initrd/boot/moon.elf
kernel/bin/moon.elf
initrd/sys/moon.sym
initrd/bin/**
apps/bin/**
tests/**/bin/**
base/usr/**
base/usr/include/**
base/usr/lib/**
**/*.a
ports/**/workdir/**
ports/ports.list

View File

@ -5,22 +5,22 @@ AR := x86_64-luna-ar
LD := x86_64-luna-ld
build:
+@tools/sync-libc.sh
+@tools/buildstep.sh kernel build
+@tools/buildstep.sh libs build
+@tools/buildstep.sh apps build
tools/sync-libc.sh
@$(MAKE) -C kernel build
@$(MAKE) -C libs build
@$(MAKE) -C apps build
clean: initrd-clean
+@tools/buildstep.sh kernel clean
+@tools/buildstep.sh libs clean
+@tools/buildstep.sh apps clean
@$(MAKE) -C kernel clean
@$(MAKE) -C libs clean
@$(MAKE) -C apps clean
initrd-clean:
rm -f $(LUNA_ROOT)/initrd/boot/moon $(LUNA_ROOT)/Luna.iso
rm -f $(LUNA_ROOT)/initrd/boot/moon.elf $(LUNA_ROOT)/Luna.iso
rm -rf $(LUNA_ROOT)/initrd/bin
install:
+@tools/buildstep.sh kernel install
+@tools/buildstep.sh libs install
+@tools/buildstep.sh apps install
+@tools/install-built-ports.sh
@$(MAKE) -C kernel install
@$(MAKE) -C libs install
@$(MAKE) -C apps install
@tools/install-built-ports.sh

View File

@ -1,20 +1,16 @@
# Luna
A simple kernel and userspace for the x86_64 platform, written mostly in C++ and C.
A simple kernel and userspace for the x86_64 platform, written mostly in C++.
## Features
- x86_64-compatible [kernel](kernel/).
- Keeps track of which [memory](kernel/src/memory/) is used and which memory is free, and can allocate memory for itself and [user programs](kernel/src/sys/mem.cpp).
- Can read, write and execute files from a [virtual file system](kernel/src/fs/) supporting an initial ramdisk, device pseudo-filesystems... but no hard disks yet.
- Preemptive multitasking, with a round-robin [scheduler](kernel/src/thread/) that can switch between tasks.
- Can [load ELF programs](kernel/src/sys/elf/) from the file system as userspace tasks.
- [System call](kernel/src/sys/) interface and [C Library](libs/libc/), aiming to be mostly POSIX-compatible.
- Can load files from a [virtual file system](kernel/src/fs/) supporting an initial ramdisk, device pseudo-filesystems... but no hard disks yet.
- Basic preemptive multitasking, round-robin [scheduler](kernel/src/thread/) that can switch between tasks.
- Can [load userspace ELF programs](kernel/src/sys/elf/) from the file system as user tasks.
- [System call](kernel/src/sys/) interface and simple [C Library](libs/libc/), aiming to be POSIX-compatible.
- Some very simple [example programs](apps/), written in C, that then can get loaded and executed by the kernel at userspace demand.
- UNIX-like [multitasking primitives](kernel/src/sys/exec.cpp), which allow user tasks to spawn other tasks.
- Some simple [userspace programs](apps/src/), written in C.
- Simple [command-line shell](apps/src/sh.c), allowing for interactive use of the system.
- Basic multi-user system with [a password file](initrd/etc/passwd) and utilities for [logging in](apps/src/session.c) and [switching users](apps/src/su.c).
## Notes
- The default user is named 'selene' and you can log into it with the password 'moon'.
- Very simple [command-line shell](apps/src/sh.c), allowing interactive use of the system.
## Setup
To build and run Luna, you will need to build a [GCC Cross-Compiler](https://wiki.osdev.org/Why_do_I_need_a_Cross_Compiler%3F) and cross-binutils for `x86_64-luna`. (Yes, Luna is advanced enough that it can use its own [OS-Specific Toolchain](https://wiki.osdev.org/OS_Specific_Toolchain), instead of a bare metal target like `x86_64-elf`. It is the first of my OS projects to be able to do so. The patches for Binutils and GCC are [binutils.patch](tools/binutils.patch) and [gcc.patch](tools/gcc.patch)).
@ -62,7 +58,7 @@ You can choose between 3 run scripts:
`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 with optimizations disabled may cause the kernel to behave differently, which is why I don't use it that often.
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.
Essentially, since `run.sh` builds the toolchain if it hasn't been built, builds Luna if it hasn't been built, and runs it, you could just checkout this repo, run `run.sh`, and you're done. No need for the other scripts. Those are included for more fine-grained control/building step-by-step.
@ -70,20 +66,18 @@ You can pass any arguments you want to the run scripts, and those will be forwar
## Prebuilt images
Prebuilt ISO images (numbered) for every version can be found at [pub.cloudapio.eu](https://pub.cloudapio.eu/luna/releases).
Prebuilt ISO images for every version can be found at [pub.cloudapio.eu](https://pub.cloudapio.eu/luna).
These images are built manually whenever I decide to make a new version, and thus don't reflect the latest changes on the `main` branch.
Every hour, my server pulls the latest commits on `main` and builds an hourly ISO image. The ten most recent ones can be found in the [hourly](https://pub.cloudapio.eu/luna/hourly) directory, and [Luna-latest.iso](https://pub.cloudapio.eu/luna/Luna-latest.iso) should always be symlinked to the newest one.
These images do reflect the latest changes on the `main` branch, but are obviously less stable. Additionally, an hourly image will be skipped if building the latest commit of the project fails.
## Is there third-party software I can use on Luna?
Yes, actually! Check out the [ports](ports/) directory.
Right now, there are very few ports, because our C Library is a bit primitive and doesn't support complex projects.
Right now, only [bc](https://github.com/gavinhoward/bc) is ported, because right now our C Library is quite primitive and doesn't support projects more complex than that.
You should also keep in mind that it is not possible to compile software written in any language other than C/C++ (and C++ was added recently, its standard library doesn't work very well) for Luna right now.
And bc itself doesn't run very well... most notably, user input doesn't echo. But that's on our side. At least it runs!
You should also keep in mind that it is not possible to compile software written in any language other than C for Luna right now.
But feel free to try to port some program yourself and add it to the ports directory!

View File

@ -1,33 +1,22 @@
C_APPS := init sh uname uptime hello ps ls args cat stat su session date mkdir screen
CXX_APPS := hello-cpp
APPS := init sym sh crash uname uptime hello ps ls
APPS_DIR := $(LUNA_ROOT)/apps
APPS_SRC := $(APPS_DIR)/src
APPS_BIN := $(APPS_DIR)/bin
C_APPS_PATH := $(patsubst %, $(APPS_BIN)/%, $(C_APPS))
CXX_APPS_PATH := $(patsubst %, $(APPS_BIN)/%, $(CXX_APPS))
REAL_APPS := $(patsubst %, $(APPS_BIN)/%, $(APPS))
CFLAGS := -Wall -Wextra -Werror -Os -fno-asynchronous-unwind-tables -ffunction-sections -fdata-sections -Wl,--gc-sections
CXXFLAGS := -fno-exceptions
CFLAGS := -Wall -Wextra -Werror -Os -fno-asynchronous-unwind-tables
$(APPS_BIN)/%: $(APPS_SRC)/%.c
@mkdir -p $(@D)
@$(CC) $(CFLAGS) -o $@ $^
@echo " CC $^"
$(CC) $(CFLAGS) -o $@ $^
$(APPS_BIN)/%: $(APPS_SRC)/%.cpp
@mkdir -p $(@D)
@$(CXX) $(CFLAGS) $(CXXFLAGS) -o $@ $^
@echo " CXX $^"
build: $(REAL_APPS)
build: $(C_APPS_PATH) $(CXX_APPS_PATH)
install: $(C_APPS_PATH) $(CXX_APPS_PATH)
install: $(REAL_APPS)
@mkdir -p $(LUNA_ROOT)/initrd/bin
@cp $(C_APPS_PATH) $(CXX_APPS_PATH) $(LUNA_ROOT)/initrd/bin
@echo " INSTALL $(C_APPS_PATH) $(CXX_APPS_PATH)"
@chmod a+s $(LUNA_ROOT)/initrd/bin/su
cp $(REAL_APPS) $(LUNA_ROOT)/initrd/bin
clean:
rm -f $(APPS_BIN)/*

View File

@ -1,7 +0,0 @@
#include <stdio.h>
#include <unistd.h>
int main(int argc, char** argv)
{
for (int i = 0; i < argc; i++) puts(argv[i]);
}

View File

@ -1,45 +0,0 @@
#define _GNU_SOURCE // for program_invocation_name
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void cat(FILE* stream)
{
char buf[BUFSIZ];
do {
fgets(buf, BUFSIZ, stream);
if (ferror(stream))
{
perror(program_invocation_name);
exit(EXIT_FAILURE);
}
fputs(buf, stdout);
} while (!feof(stream));
}
int main(int argc, char** argv)
{
if (argc == 1) cat(stdin);
else
{
for (int i = 1; i < argc; i++)
{
if (strcmp(argv[i], "-") == 0) cat(stdin);
else if (strcmp(argv[i], "-n") == 0 || strcmp(argv[i], "--newline") == 0)
putchar('\n');
else
{
FILE* stream = fopen(argv[i], "r");
if (!stream)
{
perror(program_invocation_name);
return EXIT_FAILURE;
}
cat(stream);
fclose(stream);
}
}
}
}

5
apps/src/crash.c Normal file
View File

@ -0,0 +1,5 @@
int main()
{
int* ptr = (int*)0xdeadbeef;
*ptr = 6;
}

View File

@ -1,9 +0,0 @@
#include <stdio.h>
#include <time.h>
int main()
{
time_t date = time(NULL);
fputs(ctime(&date), stdout);
}

View File

@ -1,6 +0,0 @@
#include <cstdio>
int main()
{
printf("Well hello world!\n");
}

View File

@ -1,5 +1,4 @@
#include <errno.h>
#include <fcntl.h>
#include <luna.h>
#include <stdio.h>
#include <sys/wait.h>
@ -7,21 +6,15 @@
void show_motd()
{
int fd = open("/etc/motd", O_RDONLY | O_CLOEXEC);
if (fd < 0)
{
if (errno != ENOENT) { perror("open"); }
return;
}
FILE* fp = fdopen(fd, "r");
FILE* fp = fopen("/etc/motd", "r");
if (!fp)
{
perror("fopen");
if (errno != ENOENT) { perror("fopen"); }
return;
}
char buf[4096];
size_t nread = fread(buf, 1, sizeof(buf) - 1, fp);
size_t nread = fread(buf, sizeof(buf) - 1, 1, fp);
if (ferror(fp))
{
perror("fread");
@ -41,18 +34,14 @@ int main()
{
if (getpid() != 1)
{
fprintf(stderr, "init must be started as PID 1\n");
return 1;
}
if (getuid() != 0)
{
fprintf(stderr, "init must be started as root\n");
fprintf(stderr, "init should be started as PID 1\n");
return 1;
}
show_motd();
msleep(200);
pid_t child = fork();
if (child < 0)
{
@ -61,8 +50,7 @@ int main()
}
if (child == 0)
{
char* argv[] = {"/bin/session", NULL};
execv(argv[0], argv);
execv("/bin/sh", NULL);
perror("execv");
return 1;
}
@ -71,7 +59,10 @@ int main()
for (;;)
{
result = wait(NULL);
if (result == child) return 0;
while ((result = wait(NULL)) == 0) // No child has exited yet
{
msleep(100);
}
if (result == child) { return 0; }
}
}

View File

@ -1,31 +1,22 @@
#include <dirent.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc, char** argv)
int main()
{
const char* pathname;
if (argc == 1) pathname = "/";
else
pathname = argv[1];
DIR* dp = opendir(pathname);
DIR* dp = opendir("/bin");
if (!dp)
{
perror("opendir");
return 1;
}
bool first_ent = true;
do {
struct dirent* ent = readdir(dp);
if (!ent) break;
printf(first_ent ? "%s" : " %s", ent->d_name);
first_ent = false;
printf("%s\n", ent->d_name);
} while (1);
printf("\n");
closedir(dp);
return 0;
}

View File

@ -1,17 +0,0 @@
#include <stdio.h>
#include <sys/stat.h>
int main(int argc, char** argv)
{
if (argc == 1)
{
fprintf(stderr, "Usage: %s [directory]", argv[0]);
return 1;
}
if (mkdir(argv[1], 0755) < 0)
{
perror("mkdir");
return 1;
}
}

View File

@ -1,6 +1,5 @@
#include <errno.h>
#include <luna/pstat.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@ -18,10 +17,8 @@ pid_t get_current_max_threads()
void display_process(struct pstat* pstatbuf)
{
struct passwd* pwd = getpwuid(pstatbuf->pt_uid);
if (!pwd && errno) perror("getpwuid");
printf("%s %ld %ld %s %s (%ld ms)\n", pwd ? pwd->pw_name : "???", pstatbuf->pt_pid, pstatbuf->pt_ppid,
pstatbuf->pt_name, pstatname(pstatbuf), pstatbuf->pt_time);
printf("%ld %ld %s %s (%ld ms)\n", pstatbuf->pt_pid, pstatbuf->pt_ppid, pstatbuf->pt_name, pstatname(pstatbuf),
pstatbuf->pt_time);
}
int try_pstat(pid_t pid, struct pstat* pstatbuf)
@ -44,5 +41,4 @@ int main()
{
if (try_pstat(pid, &pst)) { display_process(&pst); }
}
endpwent();
}

View File

@ -1,32 +0,0 @@
#include <fcntl.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <unistd.h>
int main()
{
int fd = open("/dev/fb0", O_WRONLY | O_CLOEXEC);
if (fd < 0)
{
perror("open");
return 1;
}
int fb_width = ioctl(fd, FB_GET_WIDTH);
if (fb_width < 0)
{
perror("ioctl(FB_GET_WIDTH)");
return 1;
}
int fb_height = ioctl(fd, FB_GET_HEIGHT);
if (fb_height < 0)
{
perror("ioctl(FB_GET_HEIGHT)");
return 1;
}
printf("Your screen is %dx%d\n", fb_width, fb_height);
close(fd);
}

View File

@ -1,145 +0,0 @@
#include <errno.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
static char* echoing_fgets(char* buf, size_t size, FILE* stream)
{
char* s = buf;
memset(buf, 0, size);
size_t oldsize = size;
while (size)
{
int c = fgetc(stream);
if (c == EOF)
{
if (ferror(stream)) return NULL;
if (feof(stream))
{
if (s != buf) return s;
else
return NULL;
};
}
if ((char)c == '\b')
{
if (size != oldsize)
{
buf--;
size++;
putchar('\b');
}
}
else
{
size--;
*buf = (char)c;
buf++;
putchar((char)c);
if ((char)c == '\n') return s;
}
*buf = 0;
}
return s;
}
static void strip_newline(char* str)
{
size_t len = strlen(str);
if (str[len - 1] == '\n') str[len - 1] = 0;
}
static char* collect_password()
{
static char buf[BUFSIZ];
printf("Password: ");
fgets(buf, BUFSIZ, stdin);
strip_newline(buf);
putchar('\n');
char* copy = strdup(
buf); // The password only stays in a caller-controlled heap-allocated buffer, where it can be freed at will.
memset(buf, 0, BUFSIZ);
return copy;
}
static void login_as(struct passwd* user)
{
pid_t child = fork();
if (child < 0)
{
perror("fork");
return;
}
if (child == 0)
{
setgid(user->pw_gid);
setuid(user->pw_uid);
char* argv[] = {user->pw_shell, NULL};
execv(argv[0], argv);
perror("execv");
exit(EXIT_FAILURE);
}
wait(NULL);
}
static int login()
{
printf("Username: ");
char username[BUFSIZ];
echoing_fgets(username, BUFSIZ, stdin);
strip_newline(username);
if (strcmp("exit", username) == 0) return 1;
struct passwd* user = getpwnam(username);
if (!user)
{
if (errno) perror("getpwnam");
else
printf("Unknown user %s\n", username);
return 0;
}
char* password = collect_password();
putchar('\n');
if (strcmp(user->pw_passwd, password) == 0)
{
free(password);
login_as(user);
puts("logout\n");
}
else
{
free(password);
puts("Invalid password.\n");
}
return 0;
}
int main(int argc, char** argv)
{
(void)argc;
if (getuid() != 0)
{
fprintf(stderr,
"%s must be run as root.\nYou are probably looking for the 'su' command, which lets you switch users "
"once logged in.\n",
argv[0]);
return EXIT_FAILURE;
}
for (;;)
{
if (login()) break;
}
endpwent();
return EXIT_SUCCESS;
}

View File

@ -1,7 +1,6 @@
#include <assert.h>
#include <errno.h>
#include <luna.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -9,89 +8,29 @@
#include <unistd.h>
static int status = 0;
static char* username = NULL;
typedef struct
{
char* buffer;
size_t size;
size_t capacity;
int interactive;
} command_t;
char** split_command_into_argv(const char* cmd)
{
size_t argc = 1;
char* ptr = strdup(cmd);
char* endptr;
char** arr = calloc(sizeof(char*), argc);
for (;;)
{
endptr = strchr(ptr, ' ');
arr[argc - 1] = ptr;
if (endptr == NULL) break;
*endptr = 0;
ptr = endptr + 1;
if (*ptr)
{
argc++;
arr = realloc(arr, sizeof(char*) * argc);
}
else
break;
}
argc++;
arr = realloc(arr, sizeof(char*) * argc);
arr[argc - 1] = NULL;
return arr;
}
char* shell_concat_path(const char* dirname, const char* basename)
{
char* buf = malloc(strlen(basename) + strlen(dirname) + 6);
strlcpy(buf, dirname, strlen(dirname) + 1);
strncat(buf, basename, strlen(basename));
return buf;
}
void shell_execvp(char* pathname, char* const argv[])
{
char* new_path;
if (access(pathname, F_OK) == 0)
{
execv(pathname, argv);
return;
}
if (pathname[0] == '/') return; // We do not want to lookup absolute paths
new_path = shell_concat_path("/bin/", pathname);
if (access(new_path, F_OK) == 0)
{
execv(new_path, argv);
return;
}
free(new_path);
new_path = shell_concat_path("/usr/bin/", pathname);
execv(new_path, argv);
int saved = errno;
free(new_path);
errno = saved;
}
} command;
void show_prompt()
{
if (WEXITSTATUS(status)) { printf("%d [%s]> ", WEXITSTATUS(status), username); }
if (WEXITSTATUS(status)) { printf("%d [%ld]> ", WEXITSTATUS(status), getpid()); }
else
printf("[%s]> ", username);
printf("[%ld]> ", getpid());
}
int command_matches(command_t* cmd, const char* string)
int command_matches(command* cmd, const char* string)
{
if (cmd->size <= strlen(string)) // cmd->size includes null terminator
return 0;
return strncmp(cmd->buffer, string, strlen(string)) == 0;
}
int command_matches_exactly(command_t* cmd, const char* string)
int command_matches_exactly(command* cmd, const char* string)
{
if (cmd->size <= strlen(string)) // cmd->size includes null terminator
return 0;
@ -99,24 +38,19 @@ int command_matches_exactly(command_t* cmd, const char* string)
return strncmp(cmd->buffer, string, strlen(string)) == 0;
}
int command_match_builtins(command_t* cmd)
int command_match_builtins(command* cmd)
{
if (command_matches(cmd, "exit ")) { exit(atoi(cmd->buffer + 5)); }
if (command_matches_exactly(cmd, "exit")) { exit(0); }
if (command_matches_exactly(cmd, "id"))
if (command_matches_exactly(cmd, "pid"))
{
printf("pid %ld, ppid %ld, uid %d (%s), gid %d\n", getpid(), getppid(), getuid(), username, getgid());
return 1;
}
if (command_matches_exactly(cmd, "clear"))
{
fputs("\033@", stdout); // clear screen. for now, escape sequences in luna are non-standard.
printf("pid %ld, ppid %ld\n", getpid(), getppid());
return 1;
}
return 0;
}
void command_expand(command_t* cmd, long new_capacity)
void command_expand(command* cmd, long new_capacity)
{
char* buffer = realloc(cmd->buffer, new_capacity);
if (!buffer)
@ -128,101 +62,105 @@ void command_expand(command_t* cmd, long new_capacity)
cmd->capacity = new_capacity;
}
void command_push(command_t* cmd, char c)
void command_push(command* cmd, char c)
{
if (cmd->size == cmd->capacity) command_expand(cmd, cmd->capacity + 8);
cmd->buffer[cmd->size] = c;
cmd->size++;
}
void command_pop(command_t* cmd)
void command_pop(command* cmd)
{
cmd->size--;
}
void command_init(command_t* cmd)
void command_init(command* cmd)
{
cmd->buffer = malloc(5);
cmd->capacity = 5;
cmd->size = 0;
}
void command_clear(command_t* cmd)
void command_clear(command* cmd)
{
free(cmd->buffer);
return command_init(cmd);
}
void process_execute_command(const char* command)
{
char** argv = split_command_into_argv(command);
shell_execvp(argv[0], argv);
perror(argv[0]);
exit(127);
}
void command_execute(command_t* cmd)
void command_execute(command* cmd)
{
command_push(cmd, '\0');
if (command_match_builtins(cmd))
{
command_clear(cmd);
if (cmd->interactive) show_prompt();
show_prompt();
return;
}
pid_t child = fork();
if (child < 0)
{
perror("fork");
perror(cmd->buffer);
command_clear(cmd);
if (cmd->interactive) show_prompt();
show_prompt();
return;
}
if (child == 0) process_execute_command(cmd->buffer);
pid_t result = waitpid(child, &status, 0);
if (child == 0)
{
if (cmd->buffer[0] != '/' && access(cmd->buffer, F_OK) < 0) // FIXME: Race condition.
{
if (errno == ENOENT)
{ // Try in /bin
char* buf = malloc(cmd->size + 6);
strlcpy(buf, "/bin/", 6);
strncat(buf, cmd->buffer, cmd->size);
execv(buf, NULL);
}
}
else
execv(cmd->buffer, NULL);
perror(cmd->buffer);
exit(127);
}
pid_t result;
while ((result = waitpid(child, &status, 0)) == 0) { msleep(20); }
if (result < 0)
{
perror("waitpid");
command_clear(cmd);
if (cmd->interactive) show_prompt();
show_prompt();
return;
}
int exit_status = WEXITSTATUS(status);
if (exit_status == -2 || exit_status == -3) printf("(PID %ld) Segmentation fault\n", result);
if (exit_status == -1) printf("(PID %ld) Aborted\n", result);
command_clear(cmd);
if (cmd->interactive) show_prompt();
show_prompt();
}
void command_concat_char(command_t* cmd, char c)
void command_concat_char(command* cmd, char c)
{
if (c == '\b')
{
if (cmd->size != 0)
{
if (cmd->interactive) putchar(c);
putchar(c);
command_pop(cmd);
}
}
else if (c == '\n')
{
if (cmd->interactive) putchar(c);
if (cmd->size == 0)
{
status = 0;
if (cmd->interactive) show_prompt();
}
putchar(c);
if (cmd->size == 0) show_prompt();
else
command_execute(cmd);
}
else
{
if (cmd->interactive) putchar(c);
putchar(c);
command_push(cmd, c);
}
}
void command_concat(command_t* cmd, const char* str)
void command_concat(command* cmd, const char* str)
{
while (*str)
{
@ -231,15 +169,13 @@ void command_concat(command_t* cmd, const char* str)
}
}
void shell_interactive()
int main()
{
show_prompt();
command_t shell_command;
command shell_command;
command_init(&shell_command);
shell_command.interactive = 1;
while (1)
{
int c = getchar();
@ -248,112 +184,11 @@ void shell_interactive()
if (ferror(stdin))
{
perror("getchar");
exit(EXIT_FAILURE);
return 1;
}
if (feof(stdin)) exit(EXIT_SUCCESS);
if (feof(stdin)) { return 0; }
assert(false); // we should never get here
}
command_concat_char(&shell_command, (char)c);
}
}
void shell_read_from_file(const char* pathname)
{
FILE* fp = fopen(pathname, "r");
if (!fp)
{
perror("sh");
exit(EXIT_FAILURE);
}
command_t file_command;
command_init(&file_command);
file_command.interactive = 0;
char buffer[BUFSIZ];
while (fgets(buffer, BUFSIZ, fp))
{
command_concat(&file_command, buffer);
if (feof(fp)) break;
}
if (file_command.size > 0) // last line of file, does not end with newline
{
command_execute(&file_command);
}
fclose(fp);
}
void shell_execute_command(const char* command)
{
command_t cmd;
cmd.buffer = strdup(command);
cmd.size = strlen(command) + 1;
if (command_match_builtins(&cmd)) return;
command_clear(&cmd);
process_execute_command(command);
}
void fetch_username()
{
struct passwd* user = getpwuid(getuid());
if (!user)
{
perror("getpwuid");
exit(EXIT_FAILURE);
}
username = user->pw_name;
endpwent();
}
int main(int argc, char** argv)
{
fetch_username();
if (argc == 1) shell_interactive();
else if (argc == 2)
{
if (!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version"))
{
puts("Luna sh version 0.1"); // FIXME: Store the version somewhere, or use the kernel's version.
return 0;
}
if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
{
printf("To use interactively: %s\n", argv[0]);
printf("To run a script: %s [script-name]\n", argv[0]);
printf("To get help: %s --help\n", argv[0]);
printf("To show the version: %s --version\n", argv[0]);
printf("To run a command: %s -c [command]\n", argv[0]);
return 0;
}
if (!strcmp(argv[1], "-c") || !strcmp(argv[1], "--command"))
{
fprintf(stderr, "Usage: %s %s [command]\n", argv[0], argv[1]);
fprintf(stderr, "Use the --help flag for more help.\n");
return 1;
}
shell_read_from_file(argv[1]);
}
else if (argc == 3)
{
if (!strcmp(argv[1], "-c") || !strcmp(argv[1], "--command")) shell_execute_command(argv[2]);
else
{
fprintf(stderr, "%s: too many arguments\n", argv[0]);
fprintf(stderr, "Use the --help flag for more help.\n");
return 1;
}
}
else
{
fprintf(stderr, "%s: too many arguments\n", argv[0]);
fprintf(stderr, "Use the --help flag for more help.\n");
return 1;
}
}

View File

@ -1,66 +0,0 @@
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <time.h>
const char* mode_to_string(mode_t mode)
{
static char mode_string[12];
char mode_set[12] = {'s', 'g', 'r', 'w', 'x', 'r', 'w', 'x', 'r', 'w', 'x', 0};
mode_t mode_val[12] = {S_ISUID, S_ISGID, S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP,
S_IWGRP, S_IXGRP, S_IROTH, S_IWOTH, S_IXOTH, S_IFMT};
for (int i = 0; i < 12; i++)
{
if (mode & mode_val[i]) mode_string[i] = mode_set[i];
else
mode_string[i] = '-';
}
return mode_string;
}
int main(int argc, char** argv)
{
if (argc == 1)
{
fprintf(stderr, "Usage: stat [file]\n");
return EXIT_FAILURE;
}
struct stat st;
if (stat(argv[1], &st) < 0)
{
perror("stat");
return EXIT_FAILURE;
}
printf("Type: ");
switch (st.st_mode & S_IFMT)
{
case S_IFREG: puts("Regular file"); break;
case S_IFDIR: puts("Directory"); break;
case S_IFCHR: puts("Character device"); break;
default: puts("Unknown"); break;
}
struct passwd* own = getpwuid(st.st_uid);
printf("Length: %ld\n", st.st_size);
printf("Inode: %ld\n", st.st_ino);
if (!own) printf("Owned by: UID %d\n", st.st_uid);
else
printf("Owned by: %s\n", own->pw_name);
printf("Mode: %s\n", mode_to_string(st.st_mode));
printf("Accessed on: %s", ctime(&st.st_atime));
printf("Modified on: %s", ctime(&st.st_mtime));
printf("Changed on: %s", ctime(&st.st_ctime));
endpwent();
return EXIT_SUCCESS;
}

View File

@ -1,88 +0,0 @@
#include <errno.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
void run_program(char** argv)
{
execv(argv[0], argv);
perror("execv");
exit(EXIT_FAILURE);
}
void strip_newline(char* str)
{
size_t len = strlen(str);
if (str[len - 1] == '\n') str[len - 1] = 0;
}
static const char* collect_password()
{
static char buf[BUFSIZ];
printf("Password: ");
fgets(buf, BUFSIZ, stdin);
strip_newline(buf);
putchar('\n');
return buf;
}
int main(int argc, char** argv)
{
const char* username;
if (argc == 1) username = "root";
else
username = argv[1];
if (geteuid() != 0)
{
fprintf(stderr, "%s must be setuid root", argv[0]);
return EXIT_FAILURE;
}
struct passwd* user = getpwnam(username);
endpwent();
if (!user)
{
if (errno) perror("getpwnam");
else
fprintf(stderr, "Unknown user %s\n", username);
return EXIT_FAILURE;
}
if (getuid() != geteuid()) // we were started from a non-root user
{
const char* pw = collect_password();
if (strcmp(pw, user->pw_passwd) != 0)
{
fprintf(stderr, "Invalid password\n");
return EXIT_FAILURE;
}
}
if (setgid(user->pw_gid) < 0)
{
perror("setgid");
return EXIT_FAILURE;
}
if (setuid(user->pw_uid) < 0)
{
perror("setuid");
return EXIT_FAILURE;
}
char* default_argv[] = {user->pw_shell, NULL};
if (argc < 3) run_program(default_argv);
else
run_program(argv + 2);
}

36
apps/src/sym.c Normal file
View File

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

View File

@ -1,38 +1,27 @@
#include <stdio.h>
#include <time.h>
#define VALUE_SINGULAR_AT_ONE(v) v, v == 1 ? "" : "s"
#include <stdlib.h>
int main()
{
struct timespec tp;
clock_gettime(CLOCK_MONOTONIC, &tp); // On Luna, CLOCK_MONOTONIC starts at boot.
FILE* fp = fopen("/dev/uptime", "r");
if (!fp)
{
perror("fopen");
return 1;
}
struct tm* time = gmtime(
&tp.tv_sec); // just splitting the value into seconds, minutes, hours, days... not the best way to do it but ok.
time->tm_year -= 70;
char buf[BUFSIZ];
fgets(buf, sizeof(buf), fp);
if (time->tm_year)
if (ferror(fp))
{
printf("up for %d year%s, %d day%s, %d hour%s, %d minute%s, %d second%s\n",
VALUE_SINGULAR_AT_ONE(time->tm_year), VALUE_SINGULAR_AT_ONE(time->tm_yday),
VALUE_SINGULAR_AT_ONE(time->tm_hour), VALUE_SINGULAR_AT_ONE(time->tm_min),
VALUE_SINGULAR_AT_ONE(time->tm_sec));
perror("fgets");
return 1;
}
else if (time->tm_yday)
{
printf("up for %d day%s, %d hour%s, %d minute%s, %d second%s\n", VALUE_SINGULAR_AT_ONE(time->tm_yday),
VALUE_SINGULAR_AT_ONE(time->tm_hour), VALUE_SINGULAR_AT_ONE(time->tm_min),
VALUE_SINGULAR_AT_ONE(time->tm_sec));
}
else if (time->tm_hour)
{
printf("up for %d hour%s, %d minute%s, %d second%s\n", VALUE_SINGULAR_AT_ONE(time->tm_hour),
VALUE_SINGULAR_AT_ONE(time->tm_min), VALUE_SINGULAR_AT_ONE(time->tm_sec));
}
else if (time->tm_min)
printf("up for %d minute%s, %d second%s\n", VALUE_SINGULAR_AT_ONE(time->tm_min),
VALUE_SINGULAR_AT_ONE(time->tm_sec));
else
printf("up for %d second%s\n", VALUE_SINGULAR_AT_ONE(time->tm_sec));
long ms_uptime = atol(buf);
printf("up for %ld seconds\n", ms_uptime / 1000);
fclose(fp);
}

View File

@ -1,3 +1,3 @@
Welcome to Luna!
Tip of the day: Log in as user 'selene' and password 'moon' :)
Tip of the day: Type 'help' to get started!

View File

@ -1,2 +0,0 @@
root:secure:0:0:Administrator:/:/bin/sh
selene:moon:1:1:Default User:/:/bin/sh

View File

@ -1,3 +1,3 @@
screen=1024x768
kernel=boot/moon
kernel=boot/moon.elf
verbose=1

View File

@ -4,7 +4,7 @@ MOON_OBJ := $(MOON_DIR)/lib
MOON_BIN := $(MOON_DIR)/bin
CFLAGS ?= -Os
CFLAGS := ${CFLAGS} -pedantic -Wall -Wextra -Werror -Wvla -Wfloat-equal -Wdisabled-optimization -Wformat=2 -Winit-self -Wmissing-include-dirs -Wswitch-default -Wcast-qual -Wundef -Wcast-align -Wwrite-strings -Wlogical-op -Wredundant-decls -Wshadow -Wconversion -ffreestanding -fstack-protector-strong -fno-omit-frame-pointer -mno-red-zone -mno-mmx -mno-sse -mno-sse2 -fshort-wchar -mcmodel=kernel -I$(MOON_DIR)/include -isystem $(MOON_DIR)/include/std
CFLAGS := ${CFLAGS} -pedantic -Wall -Wextra -Werror -Wfloat-equal -Wdisabled-optimization -Wformat=2 -Winit-self -Wmissing-include-dirs -Wswitch-default -Wcast-qual -Wundef -Wcast-align -Wwrite-strings -Wlogical-op -Wredundant-decls -Wshadow -Wconversion -ffreestanding -fstack-protector-strong -fno-omit-frame-pointer -mno-red-zone -mno-mmx -mno-sse -mno-sse2 -fshort-wchar -mcmodel=kernel -I$(MOON_DIR)/include -isystem $(MOON_DIR)/include/std
CXXFLAGS := -fno-rtti -fno-exceptions -Wsign-promo -Wstrict-null-sentinel -Wctor-dtor-privacy
ASMFLAGS := -felf64
LDFLAGS := -T$(MOON_DIR)/moon.ld -nostdlib -lgcc -Wl,--build-id=none -z max-page-size=0x1000 -mno-red-zone -mcmodel=kernel
@ -14,7 +14,7 @@ CFLAGS := ${CFLAGS} -D_MOON_SUFFIX=-$(shell git rev-parse --short HEAD)
endif
ifeq ($(MOON_BUILD_DEBUG), 1)
CFLAGS := -ggdb -fsanitize=undefined ${CFLAGS}
CFLAGS := -ggdb ${CFLAGS}
endif
rwildcard=$(foreach d,$(wildcard $(1:=/*)),$(call rwildcard,$d,$2) $(filter $(subst *,%,$2),$d))
@ -27,59 +27,45 @@ OBJS = $(patsubst $(MOON_SRC)/%.cpp, $(MOON_OBJ)/%.cpp.o, $(CXX_SRC))
OBJS += $(patsubst $(MOON_SRC)/%.c, $(MOON_OBJ)/%.c.o, $(C_SRC))
OBJS += $(patsubst $(MOON_SRC)/%.asm, $(MOON_OBJ)/%.asm.o, $(NASM_SRC))
default: $(MOON_BIN)/moon
default: $(MOON_BIN)/moon.elf
$(MOON_OBJ)/main.cpp.o: $(MOON_SRC)/main.cpp
@mkdir -p $(@D)
@$(CXX) $(CFLAGS) -fno-stack-protector $(CXXFLAGS) -o $@ -c $^
@echo " CXX $^"
$(CXX) $(CFLAGS) -fno-stack-protector $(CXXFLAGS) -o $@ -c $^
$(MOON_OBJ)/misc/config.cpp.o: $(MOON_SRC)/misc/config.cpp FORCE
@mkdir -p $(@D)
@$(CXX) $(CFLAGS) $(CXXFLAGS) -o $@ -c $(MOON_SRC)/misc/config.cpp
@echo " CXX $^"
$(CXX) $(CFLAGS) $(CXXFLAGS) -o $@ -c $(MOON_SRC)/misc/config.cpp
$(MOON_OBJ)/init/Init.cpp.o: $(MOON_SRC)/init/Init.cpp
@mkdir -p $(@D)
@$(CXX) $(CFLAGS) -fno-stack-protector $(CXXFLAGS) -o $@ -c $^
@echo " CXX $^"
$(CXX) $(CFLAGS) -fno-stack-protector $(CXXFLAGS) -o $@ -c $^
$(MOON_OBJ)/%.cpp.o: $(MOON_SRC)/%.cpp
@mkdir -p $(@D)
@$(CXX) $(CFLAGS) $(CXXFLAGS) -o $@ -c $^
@echo " CXX $^"
$(MOON_OBJ)/memory/liballoc/liballoc.c.o: $(MOON_SRC)/memory/liballoc/liballoc.c
@mkdir -p $(@D)
@$(CC) $(CFLAGS) -fno-sanitize=undefined -o $@ -c $^
@echo " CC $^"
$(CXX) $(CFLAGS) $(CXXFLAGS) -o $@ -c $^
$(MOON_OBJ)/%.c.o: $(MOON_SRC)/%.c
@mkdir -p $(@D)
@$(CC) $(CFLAGS) -o $@ -c $^
@echo " CC $^"
$(CC) $(CFLAGS) -o $@ -c $^
$(MOON_OBJ)/%.asm.o: $(MOON_SRC)/%.asm
@mkdir -p $(@D)
@$(ASM) $(ASMFLAGS) -o $@ $^
@echo " ASM $^"
$(ASM) $(ASMFLAGS) -o $@ $^
build: $(OBJS)
@mkdir -p $(MOON_BIN)
@$(CC) $(OBJS) $(LDFLAGS) -o $(MOON_BIN)/moon
@echo " CCLD $(MOON_BIN)/moon"
@mkdir -p $(@D)
$(CC) $(OBJS) $(LDFLAGS) -o $(MOON_BIN)/moon.elf
clean:
rm -rf $(MOON_OBJ)/*
rm -rf $(MOON_BIN)/*
install: $(MOON_BIN)/moon
@mkdir -p $(LUNA_ROOT)/initrd/boot
@cp $^ $(LUNA_ROOT)/initrd/boot/moon
@echo " INSTALL $^"
@$(LUNA_ROOT)/tools/generate-symbols.sh
@$(STRIP) $(LUNA_ROOT)/initrd/boot/moon
@echo " STRIP $(LUNA_ROOT)/initrd/boot/moon"
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:

View File

@ -10,5 +10,4 @@ namespace CPU
uint64_t get_feature_bitmask();
uint64_t get_initial_apic_id();
bool has_feature(CPU::Features);
bool has_nx();
}

View File

@ -32,13 +32,6 @@ struct Descriptor
ssize_t read(size_t size, char* buffer);
ssize_t write(size_t size, const char* buffer);
ssize_t user_read(size_t size, char* buffer);
ssize_t user_write(size_t size, const char* buffer);
uintptr_t mmap(uintptr_t addr, size_t size, int prot, off_t offset);
long ioctl(int cmd, uintptr_t arg);
void open(VFS::Node* node, bool can_read, bool can_write, bool able_to_block, bool close_on_exec);
int seek(long offset);
@ -62,11 +55,6 @@ struct Descriptor
return m_close_on_exec;
}
void set_close_on_exec(bool value)
{
m_close_on_exec = value;
}
Descriptor(const Descriptor& other);
Descriptor();

View File

@ -1,7 +1,6 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
#include <sys/types.h>
typedef long ssize_t;
@ -20,35 +19,24 @@ namespace VFS
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*, mode_t);
typedef int (*node_mkdir)(Node*, const char*);
typedef int (*node_block)(Node*);
typedef Node* (*node_readdir)(Node*, long);
typedef uintptr_t (*node_mmap)(Node*, uintptr_t, size_t, int, off_t);
typedef long (*node_ioctl)(Node*, int, uintptr_t);
struct Node
{
char name[NAME_MAX];
int type;
int flags;
int tty = 0;
int uid;
int gid;
mode_t mode;
uint64_t impl;
uint64_t atime;
uint64_t ctime;
uint64_t mtime;
uint64_t inode;
uint64_t length;
int type;
int flags;
node_read read_func;
node_finddir find_func;
node_readdir readdir_func;
node_mkdir mkdir_func;
node_write write_func;
node_block block_func;
node_mmap mmap_func;
node_ioctl ioctl_func;
int tty = 0;
Node* link;
};
@ -57,9 +45,6 @@ namespace VFS
int mkdir(const char* path, const char* name);
int mkdir(const char* pathname);
int do_mkdir(const char* path, const char* name, int uid, int gid, mode_t mode);
int do_mkdir(const char* pathname, int uid, int gid, mode_t mode);
int would_block(Node* node);
void mount_root(Node* root);
@ -76,11 +61,4 @@ namespace VFS
Node* root();
Node* readdir(Node* dir, long offset);
bool can_execute(Node* node, int uid, int gid);
bool can_read(Node* node, int uid, int gid);
bool can_write(Node* node, int uid, int gid);
bool is_setuid(Node* node);
bool is_setgid(Node* node);
}

View File

@ -6,10 +6,4 @@ namespace ConsoleDevice
VFS::Node* create_new(const char* devname);
ssize_t write(VFS::Node* node, size_t offset, size_t size, const char* buffer);
ssize_t read(VFS::Node* node, size_t offset, size_t size, char* buffer);
int would_block(VFS::Node* node);
void append(char c);
}

View File

@ -1,13 +0,0 @@
#pragma once
#include "fs/VFS.h"
namespace FramebufferDevice
{
VFS::Node* create_new(const char* devname);
ssize_t write(VFS::Node* node, size_t offset, size_t size, const char* buffer);
uintptr_t mmap(VFS::Node* node, uintptr_t addr, size_t size, int prot, off_t offset);
long ioctl(VFS::Node* node, int cmd, uintptr_t arg);
}

View File

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

View File

@ -1,6 +1,5 @@
#pragma once
#include <stdint.h>
#include <sys/types.h>
#define TAR_MAGIC "ustar"
#define TAR_BLOCKSIZE 512
@ -34,7 +33,6 @@ namespace InitRD
uint64_t size;
uint64_t size_in_blocks;
void* addr;
mode_t mode;
};
uint64_t get_total_blocks();

View File

@ -8,14 +8,11 @@
#define MAP_READ_WRITE 1 << 0
#define MAP_USER 1 << 1
#define MAP_EXEC 1 << 2
#define MAP_AS_OWNED_BY_TASK 1 << 3
namespace MemoryManager
{
void init();
void protect_kernel_sections();
void* get_mapping(void* physicalAddress, int flags = MAP_READ_WRITE);
void release_mapping(void* mapping);
@ -34,7 +31,4 @@ namespace MemoryManager
void release_pages(void* pages, uint64_t count);
void protect(void* page, uint64_t count, int flags);
void map_several_pages(uint64_t physicalAddress, uint64_t virtualAddress, uint64_t count,
int flags = MAP_READ_WRITE);
}

View File

@ -17,18 +17,13 @@ struct PageDirectoryEntry
bool larger_pages : 1;
bool ignore1 : 1;
uint8_t available : 3;
uint64_t address : 48;
bool owned_by_task : 1; // Part of the available for OS use bits.
uint8_t available2 : 2;
bool no_execute : 1;
uint64_t address : 52;
void set_address(uint64_t addr);
uint64_t get_address();
} __attribute__((packed));
};
struct PageTable
{
PageDirectoryEntry entries[512];
} __attribute__((aligned(PAGE_SIZE)));
static_assert(sizeof(PageDirectoryEntry) == 8UL);

View File

@ -6,8 +6,7 @@ enum Flags
{
ReadWrite = 1 << 0,
User = 1 << 1,
Execute = 1 << 2,
OwnedByTask = 1 << 3,
Execute = 1 << 2
};
namespace VMM
{
@ -34,11 +33,9 @@ namespace VMM
PageDirectoryEntry* create_pde_if_not_exists(PageTable* root, uint64_t vaddr);
void propagate_read_write(PageTable* root, uint64_t vaddr);
void propagate_no_execute(PageTable* root, uint64_t vaddr);
void propagate_user(PageTable* root, uint64_t vaddr);
void flush_tlb(uint64_t addr);
void flush_tlb_full();
void decompose_vaddr(uint64_t vaddr, uint64_t& page_index, uint64_t& pt_index, uint64_t& pd_index,
uint64_t& pdp_index);

View File

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

View File

@ -1,9 +0,0 @@
#pragma once
#include "panic/Panic.h"
#define STRINGIZE(x) #x
#define STRINGIZE_VALUE_OF(x) STRINGIZE(x)
// clang-format off
#define ensure(expr) (bool)(expr) || panic("Check failed at " __FILE__ ", line " STRINGIZE_VALUE_OF(__LINE__) ": " #expr)
// clang-format on

View File

@ -4,13 +4,10 @@
#define ENOENT 2
#define ESRCH 3
#define EINTR 4
#define E2BIG 7
#define ENOEXEC 8
#define EBADF 9
#define ECHILD 10
#define EAGAIN 11
#define ENOMEM 12
#define EACCES 13
#define EFAULT 14
#define EEXIST 17
#define ENOTDIR 20
@ -19,6 +16,5 @@
#define EMFILE 24
#define ENOTTY 25
#define ENOSPC 28
#define ERANGE 36
#define ENOSYS 38
#define ENOTSUP 95

View File

@ -1,43 +1,34 @@
#pragma once
#include "interrupts/Context.h"
#include <stddef.h>
#include <sys/types.h>
#define SYS_exit 0
#define SYS_yield 1
#define SYS_sleep 2
#define SYS_write 3
#define SYS_getprocid 4
#define SYS_mmap 5
#define SYS_munmap 6
#define SYS_open 7
#define SYS_read 8
#define SYS_close 9
#define SYS_seek 10
#define SYS_execv 11
#define SYS_fcntl 12
#define SYS_mprotect 13
#define SYS_clock_gettime 14
#define SYS_mkdir 15
#define SYS_fork 16
#define SYS_waitpid 17
#define SYS_access 18
#define SYS_fstat 19
#define SYS_pstat 20
#define SYS_getdents 21
#define SYS_stat 22
#define SYS_dup2 23
#define SYS_setuid 24
#define SYS_setgid 25
#define SYS_umask 26
#define SYS_ioctl 27
#define SYS_seteuid 28
#define SYS_setegid 29
#define SYS_paint 4
#define SYS_getprocid 5
#define SYS_mmap 6
#define SYS_munmap 7
#define SYS_open 8
#define SYS_read 9
#define SYS_close 10
#define SYS_seek 11
#define SYS_exec 12
#define SYS_fcntl 13
#define SYS_mprotect 14
#define SYS_clock 15
#define SYS_mkdir 16
#define SYS_fork 17
#define SYS_waitpid 18
#define SYS_access 19
#define SYS_fstat 20
#define SYS_pstat 21
#define SYS_getdents 22
struct stat;
struct pstat;
struct luna_dirent;
struct timespec;
namespace Syscall
{
@ -48,29 +39,22 @@ 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, 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_getprocid(Context* context, int field);
void sys_mmap(Context* context, void* address, size_t size, int prot, int fd, off_t offset);
void sys_mmap(Context* context, void* address, size_t size, int prot);
void sys_munmap(Context* context, void* address, size_t size);
void sys_open(Context* context, const char* filename, int flags, mode_t mode);
void sys_open(Context* context, const char* filename, int flags);
void sys_read(Context* context, int fd, size_t size, char* buffer);
void sys_close(Context* context, int fd);
void sys_seek(Context* context, int fd, long offset, int whence);
void sys_execv(Context* context, const char* pathname, char** argv);
void sys_exec(Context* context, const char* pathname);
void sys_fcntl(Context* context, int fd, int command, uintptr_t arg);
void sys_mprotect(Context* context, void* address, size_t size, int prot);
void sys_clock_gettime(Context* context, int clock_id, struct timespec* tp);
void sys_mkdir(Context* context, const char* filename, mode_t mode);
void sys_clock(Context* context);
void sys_mkdir(Context* context, const char* filename);
void sys_fork(Context* context);
void sys_waitpid(Context* context, long pid, int* wstatus, int options);
void sys_access(Context* context, const char* path, int amode);
void sys_fstat(Context* context, int fd, struct stat* buf);
void sys_pstat(Context* context, long pid, struct pstat* buf);
void sys_getdents(Context* context, int fd, struct luna_dirent* buf, size_t count);
void sys_stat(Context* context, const char* path, struct stat* buf);
void sys_dup2(Context* context, int fd, int fd2);
void sys_setuid(Context* context, uid_t uid);
void sys_setgid(Context* context, gid_t gid);
void sys_umask(Context* context, mode_t cmask);
void sys_ioctl(Context* context, int fd, int request, uintptr_t arg);
void sys_seteuid(Context* context, uid_t euid);
void sys_setegid(Context* context, gid_t egid);

View File

@ -8,16 +8,8 @@
#include "memory/MemoryManager.h"
#include "memory/VMM.h"
#include "misc/utils.h"
#include <stddef.h>
char* strdup_from_user(const char* user_string);
bool validate_user_readable_page(uintptr_t address);
bool validate_user_writable_page(uintptr_t address);
bool validate_user_read(uintptr_t address, size_t size);
bool validate_user_write(uintptr_t address, size_t size);
bool copy_from_user(const void* user_ptr, void* ptr, size_t size);
bool copy_to_user(void* user_ptr, const void* ptr, size_t size);
// FIXME: Map the physical addresses into kernel address space. Right now, something overwrites KernelHeap and crashes
// it, so that's not really possible. But it should be done in the future.

View File

@ -4,20 +4,9 @@
#include "memory/AddressSpace.h"
#include "memory/UserHeap.h"
#include "sys/elf/Image.h"
#include <sys/types.h>
#define TASK_MAX_FDS 32
enum class BlockReason
{
None,
Reading,
Waiting,
};
// FIXME: To make this struct more C++-styled, maybe we could make a lot of these variables private and add
// getters/setters?
struct Task
{
enum TaskState
@ -40,11 +29,6 @@ struct Task
int64_t task_time = 0;
uid_t uid;
uid_t euid;
gid_t gid;
gid_t egid;
Task* next_task = nullptr;
Task* prev_task = nullptr;
@ -61,8 +45,7 @@ struct Task
bool is_user_task();
ELFImage* image = nullptr; // FIXME: we probably don't need to keep track of this anymore since the ELF sections are
// freed automatically when calling destroy() or clear() on the address space.
ELFImage* image = nullptr;
Descriptor files[TASK_MAX_FDS];
@ -86,38 +69,14 @@ struct Task
char name[128];
mode_t umask;
struct
{
size_t size;
int fd;
char* buf;
} blocking_read_info;
BlockReason block_reason;
union {
struct
{
size_t size;
int fd;
char* buf;
} blocking_read_info;
struct
{
int64_t pid;
int* wstatus;
} blocking_wait_info;
};
void resume();
void resume_read();
bool is_still_blocking();
// FIXME: These two functions are a bit clunky.
Descriptor* open_descriptor_from_fd(int fd, int& error);
Descriptor* descriptor_from_fd(int fd, int& error);
bool is_superuser();
private:
void resume_read();
void resume_wait();
bool is_read_still_blocking();
bool is_wait_still_blocking();
};

View File

@ -1,4 +0,0 @@
#pragma once
#include <stdint.h>
void determine_user_page_fault_reason(uintptr_t faulting_address);

View File

@ -1,4 +0,0 @@
#pragma once
long parse_decimal(const char* str);
long parse_octal(const char* str);

View File

@ -1,8 +0,0 @@
#pragma once
#include <stdint.h>
int make_yday(int year, int month);
uint64_t broken_down_to_unix(uint64_t year, uint64_t yday, uint64_t hour, uint64_t min, uint64_t sec);
uint64_t unix_boottime(uint8_t boottime[8]);

View File

@ -16,19 +16,14 @@ SECTIONS
kernel_start = .;
.text : {
KEEP(*(.text.boot)) *(.text .text.*) /* code */
. = ALIGN(0x1000);
start_of_kernel_rodata = .;
*(.rodata .rodata.*) /* data */
end_of_kernel_rodata = .;
. = ALIGN(0x1000);
start_of_kernel_data = .;
*(.data .data.*)
} :boot
.bss (NOLOAD) : { /* bss */
. = ALIGN(16);
*(.bss .bss.*)
*(COMMON)
} :boot
end_of_kernel_data = .;
kernel_end = .;
/DISCARD/ : { *(.eh_frame) *(.comment) }

View File

@ -66,17 +66,9 @@ uint64_t CPU::get_feature_bitmask()
return bitmask;
}
bool CPU::has_nx()
{
unsigned int unused;
unsigned int edx;
__get_cpuid(0x80000001, &unused, &unused, &unused, &edx);
return edx & (1 << 20);
}
static bool _has_feature(int feature)
{
return (CPU::get_feature_bitmask() & (uint64_t)(1UL << feature)) > 0;
return (CPU::get_feature_bitmask() & (uint64_t)(1 << feature)) > 0;
}
bool CPU::has_feature(CPU::Features feature)

View File

@ -1,7 +1,5 @@
#include "fs/FileDescriptor.h"
#include "std/errno.h"
#include "std/stdlib.h"
#include "sys/UserMemory.h"
Descriptor::Descriptor() : m_is_open(false)
{
@ -39,42 +37,6 @@ ssize_t Descriptor::write(size_t size, const char* buffer)
return result;
}
ssize_t Descriptor::user_read(size_t size, char* buffer)
{
char* buf = (char*)kmalloc(size);
if (!buf) return -ENOMEM;
ssize_t result = read(size, buf);
if (!copy_to_user(buffer, buf, size)) result = -EFAULT;
kfree(buf);
return result;
}
ssize_t Descriptor::user_write(size_t size, const char* buffer)
{
char* buf = (char*)kmalloc(size);
if (!buf) return -ENOMEM;
ssize_t result;
if (!copy_from_user(buffer, buf, size)) result = -EFAULT;
else
result = write(size, buf);
kfree(buf);
return result;
}
#define MAP_FAIL(errno) 0xffffffffffffff00 | (unsigned char)(errno)
uintptr_t Descriptor::mmap(uintptr_t addr, size_t size, int prot, off_t offset)
{
if (!m_node->mmap_func) return MAP_FAIL(ENOTSUP);
return m_node->mmap_func(m_node, addr, size, prot, offset);
}
long Descriptor::ioctl(int cmd, uintptr_t arg)
{
if (!m_node->ioctl_func) return MAP_FAIL(ENOTSUP);
return m_node->ioctl_func(m_node, cmd, arg);
}
int Descriptor::seek(long offset)
{
if (m_node->type == VFS_FILE && (uint64_t)offset > m_node->length)

View File

@ -152,58 +152,12 @@ int VFS::mkdir(const char* path, const char* name)
kwarnln("Chosen node does not support finddir()");
return -ENOTSUP;
}
if (!strncmp(name, ".", strlen(name)) || !strncmp(name, "..", strlen(name)))
{
kwarnln("Attempted to mkdir . or .., which already exist");
return -EEXIST;
}
if (node->find_func(node, name) != nullptr)
{
kwarnln("Already exists");
return -EEXIST;
}
return node->mkdir_func(node, name, 0755);
}
int VFS::do_mkdir(const char* path, const char* name, int uid, int gid, mode_t mode)
{
Node* node = resolve_path(path, vfs_root);
if (!node)
{
kwarnln("Attempting to mkdir in %s, which does not exist", path);
return -ENOENT;
}
if (node->type != VFS_DIRECTORY)
{
kwarnln("Attempting to mkdir in %s, which is not a directory!!", path);
return -ENOTDIR;
}
if (!node->mkdir_func)
{
kwarnln("Chosen node does not support mkdir()");
return -ENOTSUP;
}
if (!node->find_func)
{
kwarnln("Chosen node does not support finddir()");
return -ENOTSUP;
}
if (!strncmp(name, ".", strlen(name)) || !strncmp(name, "..", strlen(name)))
{
kwarnln("Attempted to mkdir . or .., which already exist");
return -EEXIST;
}
if (node->find_func(node, name) != nullptr)
{
kwarnln("Already exists");
return -EEXIST;
}
if (!can_write(node, uid, gid))
{
kwarnln("Not enough permissions");
return -EACCES;
}
return node->mkdir_func(node, name, mode);
return node->mkdir_func(node, name);
}
int VFS::mkdir(const char* pathname)
@ -224,24 +178,6 @@ int VFS::mkdir(const char* pathname)
return result;
}
int VFS::do_mkdir(const char* pathname, int uid, int gid, mode_t mode)
{
char* bstr = strdup(pathname);
char* dstr = strdup(pathname);
char* base = basename(bstr);
char* dir = dirname(dstr);
kdbgln("mkdir(): creating %s in directory %s", base, dir);
int result = do_mkdir(dir, base, uid, gid, mode);
kfree(bstr);
kfree(dstr);
return result;
}
bool VFS::exists(const char* pathname)
{
return resolve_path(pathname) != nullptr;
@ -273,34 +209,3 @@ VFS::Node* VFS::readdir(VFS::Node* dir, long offset)
if (!dir->readdir_func) return 0;
return dir->readdir_func(dir, offset);
}
bool VFS::can_execute(VFS::Node* node, int uid, int gid)
{
if (uid == node->uid) return node->mode & 0100;
if (gid == node->gid) return node->mode & 0010;
return node->mode & 0001;
}
bool VFS::can_write(VFS::Node* node, int uid, int gid)
{
if (uid == node->uid) return node->mode & 0200;
if (gid == node->gid) return node->mode & 0020;
return node->mode & 0002;
}
bool VFS::can_read(VFS::Node* node, int uid, int gid)
{
if (uid == node->uid) return node->mode & 0400;
if (gid == node->gid) return node->mode & 0040;
return node->mode & 0004;
}
bool VFS::is_setuid(VFS::Node* node)
{
return node->mode & 04000;
}
bool VFS::is_setgid(VFS::Node* node)
{
return node->mode & 02000;
}

View File

@ -5,30 +5,15 @@
#include "std/stdlib.h"
#include "std/string.h"
char* conin_buffer = nullptr;
uint64_t conin_bufsize = 0;
int ConsoleDevice::would_block(VFS::Node*)
{
return conin_bufsize == 0;
}
extern uint64_t clock_now();
VFS::Node* ConsoleDevice::create_new(const char* devname)
{
VFS::Node* dev = new VFS::Node;
dev->write_func = ConsoleDevice::write;
dev->read_func = ConsoleDevice::read;
dev->block_func = ConsoleDevice::would_block;
dev->inode = 0;
dev->length = 0;
dev->type = VFS_DEVICE;
dev->flags = 0;
dev->tty = 1;
dev->uid = dev->gid = 0;
dev->mode = 0666;
dev->atime = dev->ctime = dev->mtime = clock_now();
strncpy(dev->name, devname, sizeof(dev->name));
return dev;
}
@ -39,23 +24,3 @@ ssize_t ConsoleDevice::write(VFS::Node* node, size_t, size_t size, const char* b
TextRenderer::write(buffer, size);
return (ssize_t)size;
}
ssize_t ConsoleDevice::read(VFS::Node* node, size_t, size_t size, char* buffer)
{
if (!node) return -1;
if (!conin_buffer) return 0;
if (size > conin_bufsize) size = conin_bufsize;
memcpy(buffer, conin_buffer, size);
memmove(conin_buffer, conin_buffer + size, conin_bufsize - size);
conin_bufsize -= size;
conin_buffer = (char*)krealloc(conin_buffer, conin_bufsize);
return (ssize_t)size;
}
void ConsoleDevice::append(char c)
{
conin_bufsize++;
conin_buffer = (char*)krealloc(
conin_buffer, conin_bufsize); // FIXME: We should probably not be calling realloc every time a key is pressed.
conin_buffer[conin_bufsize - 1] = c;
}

View File

@ -1,10 +1,9 @@
#include "fs/devices/DeviceFS.h"
#include "fs/devices/Console.h"
#include "fs/devices/Framebuffer.h"
#include "fs/devices/Keyboard.h"
#include "fs/devices/NullDevice.h"
#include "fs/devices/Random.h"
#include "fs/devices/Serial.h"
#include "fs/devices/Uptime.h"
#include "fs/devices/Version.h"
#include "std/stdlib.h"
#include "std/string.h"
@ -16,8 +15,6 @@ VFS::Node* devfs_root = nullptr;
VFS::Node* devfs_files[DEVFS_MAX_FILES];
int devfs_file_count = 0;
extern uint64_t clock_boot();
VFS::Node* DeviceFS::get()
{
if (devfs_root) return devfs_root;
@ -27,9 +24,6 @@ VFS::Node* DeviceFS::get()
devfs_root->type = VFS_DIRECTORY;
devfs_root->find_func = DeviceFS::finddir;
devfs_root->readdir_func = DeviceFS::readdir;
devfs_root->mode = 0755;
devfs_root->uid = devfs_root->gid = 0;
devfs_root->atime = devfs_root->ctime = devfs_root->mtime = clock_boot();
strncpy(devfs_root->name, "dev", sizeof(devfs_root->name));
devfs_files[devfs_file_count++] = VersionDevice::create_new("version");
@ -37,8 +31,7 @@ VFS::Node* DeviceFS::get()
devfs_files[devfs_file_count++] = SerialDevice::create_new("serial");
devfs_files[devfs_file_count++] = RandomDevice::create_new("random");
devfs_files[devfs_file_count++] = KeyboardDevice::create_new("kbd");
devfs_files[devfs_file_count++] = NullDevice::create_new("null");
devfs_files[devfs_file_count++] = FramebufferDevice::create_new("fb0");
devfs_files[devfs_file_count++] = UptimeDevice::create_new("uptime");
devfs_root->length = devfs_file_count;
return devfs_root;
}

View File

@ -1,71 +0,0 @@
#include "fs/devices/Framebuffer.h"
#include "bootboot.h"
#include "memory/MemoryManager.h"
#include "misc/utils.h"
#include "std/errno.h"
#include "std/stdio.h"
#include "std/stdlib.h"
#include "std/string.h"
#include "utils/Addresses.h"
extern BOOTBOOT bootboot;
extern char fb[1];
#define MAP_FAIL(errno) 0xffffffffffffff00 | (unsigned char)(errno)
extern uint64_t clock_now();
VFS::Node* FramebufferDevice::create_new(const char* devname)
{
VFS::Node* dev = new VFS::Node;
dev->write_func = FramebufferDevice::write;
dev->mmap_func = FramebufferDevice::mmap;
dev->ioctl_func = FramebufferDevice::ioctl;
dev->inode = 0;
dev->length = 0;
dev->type = VFS_DEVICE;
dev->flags = 0;
dev->uid = dev->gid = 0;
dev->mode = 0222;
dev->atime = dev->ctime = dev->mtime = clock_now();
strncpy(dev->name, devname, sizeof(dev->name));
return dev;
}
uintptr_t FramebufferDevice::mmap(VFS::Node* node, uintptr_t addr, size_t size, int prot, off_t offset)
{
if (!node) return -1;
int real_prot = prot & ~(MAP_AS_OWNED_BY_TASK);
if (round_down_to_nearest_page(offset) != (uintptr_t)offset) { return MAP_FAIL(EINVAL); }
if ((size + offset) > bootboot.fb_size)
{
return MAP_FAIL(ERANGE); // FIXME: Should probably be EOVERFLOW.
}
MemoryManager::map_several_pages(bootboot.fb_ptr + offset, addr, Utilities::get_blocks_from_size(PAGE_SIZE, size),
real_prot);
return addr;
}
ssize_t FramebufferDevice::write(VFS::Node* node, size_t offset, size_t size, const char* buffer)
{
if (!node) return -1;
if ((size + offset) > (uint64_t)bootboot.fb_size) { size = (uint64_t)bootboot.fb_size - offset; }
memcpy(fb + offset, buffer, size);
return (ssize_t)size;
}
#define FB_GET_WIDTH 0
#define FB_GET_HEIGHT 1
#define FB_GET_SCANLINE 2
long FramebufferDevice::ioctl(VFS::Node* node, int cmd, uintptr_t)
{
if (!node) return -1;
switch (cmd)
{
case FB_GET_WIDTH: return (long)bootboot.fb_width;
case FB_GET_HEIGHT: return (long)bootboot.fb_height;
case FB_GET_SCANLINE: return (long)bootboot.fb_scanline;
default: return -EINVAL;
}
}

View File

@ -16,8 +16,6 @@ int KeyboardDevice::would_block(VFS::Node*)
return kbd_bufsize == 0;
}
extern uint64_t clock_boot();
VFS::Node* KeyboardDevice::create_new(const char* devname)
{
VFS::Node* dev = new VFS::Node;
@ -28,9 +26,6 @@ VFS::Node* KeyboardDevice::create_new(const char* devname)
dev->type = VFS_DEVICE;
dev->flags = 0;
dev->tty = 1;
dev->uid = dev->gid = 0;
dev->mode = 0444;
dev->atime = dev->ctime = dev->mtime = clock_boot();
strncpy(dev->name, devname, sizeof(dev->name));
return dev;
}

View File

@ -1,34 +0,0 @@
#include "fs/devices/NullDevice.h"
#include "std/stdio.h"
#include "std/stdlib.h"
#include "std/string.h"
extern uint64_t clock_boot();
VFS::Node* NullDevice::create_new(const char* devname)
{
VFS::Node* dev = new VFS::Node;
dev->write_func = NullDevice::write;
dev->read_func = NullDevice::read;
dev->inode = 0;
dev->length = 0;
dev->type = VFS_DEVICE;
dev->flags = 0;
dev->uid = dev->gid = 0;
dev->mode = 0666;
dev->atime = dev->ctime = dev->mtime = clock_boot();
strncpy(dev->name, devname, sizeof(dev->name));
return dev;
}
ssize_t NullDevice::write(VFS::Node* node, size_t, size_t size, const char*)
{
if (!node) return -1;
return (ssize_t)size;
}
ssize_t NullDevice::read(VFS::Node* node, size_t, size_t, char*)
{
if (!node) return -1;
return 0;
}

View File

@ -6,8 +6,6 @@
#include "std/stdlib.h"
#include "std/string.h"
extern uint64_t clock_boot();
VFS::Node* RandomDevice::create_new(const char* devname)
{
VFS::Node* dev = new VFS::Node;
@ -16,9 +14,6 @@ VFS::Node* RandomDevice::create_new(const char* devname)
dev->length = 0;
dev->type = VFS_DEVICE;
dev->flags = 0;
dev->uid = dev->gid = 0;
dev->mode = 0444;
dev->atime = dev->ctime = dev->mtime = clock_boot();
strncpy(dev->name, devname, sizeof(dev->name));
return dev;
}

View File

@ -5,8 +5,6 @@
#include "std/stdlib.h"
#include "std/string.h"
extern uint64_t clock_boot();
VFS::Node* SerialDevice::create_new(const char* devname)
{
VFS::Node* dev = new VFS::Node;
@ -15,9 +13,6 @@ VFS::Node* SerialDevice::create_new(const char* devname)
dev->length = 0;
dev->type = VFS_DEVICE;
dev->flags = 0;
dev->uid = dev->gid = 0;
dev->mode = 0222;
dev->atime = dev->ctime = dev->mtime = clock_boot();
strncpy(dev->name, devname, sizeof(dev->name));
return dev;
}

View File

@ -0,0 +1,24 @@
#include "fs/devices/Uptime.h"
#include "std/stdio.h"
#include "std/stdlib.h"
#include "std/string.h"
#include "thread/PIT.h"
VFS::Node* UptimeDevice::create_new(const char* devname)
{
VFS::Node* dev = new VFS::Node;
dev->read_func = UptimeDevice::read;
dev->inode = 0;
dev->length = 0;
dev->type = VFS_DEVICE;
dev->flags = 0;
strncpy(dev->name, devname, sizeof(dev->name));
return dev;
}
ssize_t UptimeDevice::read(VFS::Node* node, size_t, size_t size, char* buffer)
{
if (!node) return -1;
snprintf(buffer, size + 1, "%ld", PIT::ms_since_boot); // FIXME: Support offseting this read
return (ssize_t)size;
}

View File

@ -4,8 +4,6 @@
#include "std/stdlib.h"
#include "std/string.h"
extern uint64_t clock_boot();
VFS::Node* VersionDevice::create_new(const char* devname)
{
VFS::Node* dev = new VFS::Node;
@ -14,9 +12,6 @@ VFS::Node* VersionDevice::create_new(const char* devname)
dev->length = strlen(moon_version()) + 5;
dev->type = VFS_DEVICE;
dev->flags = 0;
dev->uid = dev->gid = 0;
dev->mode = 0444;
dev->atime = dev->ctime = dev->mtime = clock_boot();
strncpy(dev->name, devname, sizeof(dev->name));
return dev;
}
@ -24,7 +19,8 @@ VFS::Node* VersionDevice::create_new(const char* devname)
ssize_t VersionDevice::read(VFS::Node* node, size_t offset, size_t size, char* buffer)
{
if (!node) return -1;
if (offset > 0) return 0; // EOF after first read (FIXME: Should be only if everything was read)
if (offset > node->length) return -1;
if (offset + size > node->length) { size = node->length - offset; }
snprintf(buffer, size + 1, "moon %s", moon_version()); // FIXME: Support offseting this read
return (ssize_t)size;
}

View File

@ -3,7 +3,7 @@
#include "gdt/GDT.h"
#include "log/Log.h"
#include "memory/MemoryManager.h"
#include "std/ensure.h"
#include "std/assert.h"
#include "std/string.h"
#include <stdint.h>
@ -73,7 +73,7 @@ static void set_base(GDTEntry* entry, uint32_t base)
static void set_limit(GDTEntry* entry, uint32_t limit)
{
ensure(limit <= 0xFFFFF);
ASSERT(limit <= 0xFFFFF);
entry->limit0 = limit & 0xFFFF;
entry->limit1_flags = (entry->limit1_flags & 0xF0) | ((limit >> 16) & 0xF);
}

View File

@ -3,32 +3,29 @@
#include "init/Init.h"
#include "bootboot.h"
#include "cpu/CPU.h"
#include "fs/InitRD.h"
#include "init/InitRD.h"
#include "interrupts/Interrupts.h"
#include "io/Serial.h"
#include "log/Log.h"
#include "memory/MemoryManager.h"
#include "memory/PMM.h"
#include "memory/VMM.h"
#include "misc/MSR.h"
#include "misc/hang.h"
#include "rand/Init.h"
#include "rand/Mersenne.h"
#include "render/Framebuffer.h"
#include "render/TextRenderer.h"
#include "std/ensure.h"
#include "std/assert.h"
#include "std/string.h"
#include "utils/Time.h"
extern BOOTBOOT bootboot;
extern "C" char environment[4096];
extern uintptr_t fb;
uintptr_t __stack_chk_guard = 0xfeff34;
void Init::check_magic()
{
if (strncmp((char*)bootboot.magic, BOOTBOOT_MAGIC, 4) != 0) hang();
ASSERT(strncmp((char*)bootboot.magic, BOOTBOOT_MAGIC, 4) == 0);
}
void Init::disable_smp()
@ -38,42 +35,6 @@ void Init::disable_smp()
}
extern "C" void asm_enable_sse();
extern void clock_init();
extern void panic_prepare_keyboard_triple_fault();
#define NO_EXECUTE_ENABLED (1 << 11)
static void check_and_enable_nx()
{
if (!CPU::has_nx())
{
kerrorln("This machine does not support the NX feature, which is required to continue booting.");
kerrorln("On most cases, this means your machine is too old and not supported.");
kinfoln("Press any key to restart and select an OS that is suitable for your CPU.");
panic_prepare_keyboard_triple_fault();
while (1) halt();
}
kdbgln("nx supported");
MSR efer(IA32_EFER_MSR);
uint64_t value = efer.read();
if (value & NO_EXECUTE_ENABLED)
{
kdbgln("nx already enabled");
return;
}
kdbgln("nx not enabled, enabling it");
efer.write(value | NO_EXECUTE_ENABLED);
}
void Init::early_init()
{
@ -82,14 +43,11 @@ void Init::early_init()
asm_enable_sse();
framebuffer0.init((void*)&fb, bootboot.fb_type, bootboot.fb_scanline, bootboot.fb_width, bootboot.fb_height);
check_and_enable_nx();
framebuffer0.init((void*)bootboot.fb_ptr, bootboot.fb_type, bootboot.fb_scanline, bootboot.fb_width,
bootboot.fb_height);
MemoryManager::init();
MemoryManager::protect_kernel_sections();
if (strstr(environment, "quiet=1"))
{
KernelLog::toggle_log_level(LogLevel::DEBUG);
@ -97,8 +55,6 @@ void Init::early_init()
}
else if (!strstr(environment, "verbose=1")) { KernelLog::toggle_log_level(LogLevel::DEBUG); }
clock_init();
InitRD::init();
Mersenne::init();

View File

@ -1,6 +1,6 @@
#define MODULE "initrd"
#include "fs/InitRD.h"
#include "init/InitRD.h"
#include "bootboot.h"
#include "fs/VFS.h"
#include "io/Serial.h"
@ -10,9 +10,6 @@
#include "std/errno.h"
#include "std/stdlib.h"
#include "std/string.h"
#include "utils/StringParsing.h"
// FIXME: A lot of this code was written before the VFS was created and thus is quite messy and assumes other stuff.
extern BOOTBOOT bootboot;
@ -21,9 +18,6 @@ static bool initrd_initialized = false;
static VFS::Node initrd_root;
extern uint64_t clock_boot(); // defined in sys/clock.cpp
extern uint64_t clock_now();
bool InitRD::is_initialized()
{
return initrd_initialized;
@ -57,14 +51,17 @@ uint64_t InitRD::get_file_physical_address(InitRD::File& file)
InitRD::File InitRD::get_file(TarHeader* header)
{
File result;
char null_terminated_size[13];
memcpy(null_terminated_size, header->size, 12);
null_terminated_size[12] = 0;
result.size = parse_octal(null_terminated_size);
result.size = 0;
memcpy(result.name, header->name, 100);
int multiplier =
1; // why they decided to store the size as an octal-encoded string instead of an integer is beyond me
for (int i = 10; i >= 0; i--)
{
result.size += (multiplier * (header->size[i] - 48));
multiplier *= 8;
}
result.addr = (void*)((uint64_t)header + TAR_BLOCKSIZE);
result.size_in_blocks = Utilities::get_blocks_from_size(TAR_BLOCKSIZE, result.size);
result.mode = (mode_t)parse_octal(header->mode);
return result;
}
@ -119,7 +116,7 @@ void InitRD::for_each(void (*callback)(File& f))
}
}
#define INITRD_MAX_FILES_IN_DIR 32
#define INITRD_MAX_FILES_IN_DIR 16
#define INITRD_MAX_FILES 64
namespace InitRD
@ -198,7 +195,7 @@ VFS::Node* initrd_read_dir(VFS::Node* node, long offset)
return dir.files[offset];
}
int initrd_mkdir(VFS::Node* node, const char* name, mode_t mode) // FIXME: Return proper error numbers.
int initrd_mkdir(VFS::Node* node, const char* name) // FIXME: Return proper error numbers.
{
if (total_dirs >= 32)
{
@ -228,9 +225,6 @@ int initrd_mkdir(VFS::Node* node, const char* name, mode_t mode) // FIXME: Retur
new_node.mkdir_func = initrd_mkdir;
new_node.length = 0;
new_node.type = VFS_DIRECTORY;
new_node.mode = mode;
new_node.uid = new_node.gid = 0;
new_node.atime = new_node.ctime = new_node.mtime = clock_now();
strncpy(new_node.name, name, sizeof(new_node.name));
InitRD::Directory dir;
strncpy(dir.name, name, sizeof(dir.name));
@ -288,9 +282,6 @@ static bool initrd_register_dir(InitRD::Directory& dir, uint64_t inode)
node.mkdir_func = initrd_mkdir;
node.readdir_func = initrd_read_dir;
node.length = 0;
node.mode = 0755;
node.uid = node.gid = 0;
node.atime = node.ctime = node.mtime = clock_boot();
strncpy(node.name, buffer, sizeof(node.name));
strncpy(dir.name, buffer, sizeof(dir.name));
@ -350,9 +341,6 @@ static bool initrd_register_file(InitRD::File& f, uint64_t inode)
node.read_func = initrd_read;
node.length = f.size;
node.type = VFS_FILE;
node.mode = f.mode & 07555; // don't allow writing
node.uid = node.gid = 0;
node.atime = node.ctime = node.mtime = clock_boot();
strncpy(node.name, buffer, sizeof(node.name));
strncpy(f.name, buffer, sizeof(f.name));
@ -371,7 +359,7 @@ static bool initrd_register_file(InitRD::File& f, uint64_t inode)
static void initrd_scan()
{
initrd_for_each_dir([](InitRD::Directory& dir) {
if (total_dirs >= INITRD_MAX_FILES)
if (total_dirs >= 32)
{
kwarnln("Failed to register directory %s: Too many directories in initrd", dir.name);
return;
@ -380,7 +368,7 @@ static void initrd_scan()
if (initrd_register_dir(dir, inode)) dirs[total_dirs++] = dir;
});
InitRD::for_each([](InitRD::File& f) {
if (total_files >= INITRD_MAX_FILES)
if (total_files >= 32)
{
kwarnln("Failed to register file %s: Too many files in initrd", f.name);
return;
@ -395,9 +383,6 @@ static void initrd_initialize_root()
initrd_root.length = 0;
initrd_root.inode = 0;
initrd_root.type |= VFS_DIRECTORY;
initrd_root.mode = 0755;
initrd_root.uid = initrd_root.gid = 0;
initrd_root.atime = initrd_root.ctime = initrd_root.mtime = clock_boot();
InitRD::Directory& root = dirs[0];
total_dirs++;
strncpy(initrd_root.name, "initrd", sizeof(initrd_root.name));

View File

@ -5,19 +5,17 @@
#include "interrupts/Interrupts.h"
#include "io/Serial.h"
#include "log/Log.h"
#include "memory/VMM.h"
#include "misc/hang.h"
#include "panic/Panic.h"
#include "std/ensure.h"
#include "std/assert.h"
#include "std/stdio.h"
#include "sys/Syscall.h"
#include "thread/Scheduler.h"
#include "trace/StackTracer.h"
#include "utils/PageFaultReason.h"
extern "C" void common_handler(Context* context)
{
ensure(Interrupts::is_in_handler());
ASSERT(Interrupts::is_in_handler());
if (context->number >= 0x20 && context->number < 0x30)
{
IRQ::interrupt_handler(context);
@ -30,8 +28,6 @@ extern "C" void common_handler(Context* context)
if (context->cs == 0x8) { int_panic(context, "GPF in kernel task"); }
else
{
VMM::enter_syscall_context();
kerrorln("General protection fault at RIP %lx, cs %ld, ss %ld, RSP %lx, error code %ld", context->rip,
context->cs, context->ss, context->rsp, context->error_code);
kinfoln("Stack trace:");
@ -48,8 +44,6 @@ extern "C" void common_handler(Context* context)
if (context->cs == 0x8) { int_panic(context, "Page fault in kernel task"); }
else
{
VMM::enter_syscall_context();
kerrorln("Page fault in ring 3 (RIP %lx), while trying to access %lx, error code %ld", context->rip,
context->cr2, context->error_code);
kinfoln("Stack trace:");
@ -57,8 +51,6 @@ extern "C" void common_handler(Context* context)
StackTracer tracer(context->rbp);
tracer.trace_with_ip(context->rip);
determine_user_page_fault_reason(context->cr2);
Scheduler::task_misbehave(context, -3);
}
}

View File

@ -2,7 +2,7 @@
#include "interrupts/IDT.h"
#include "log/Log.h"
#include "std/ensure.h"
#include "std/assert.h"
struct IDTEntry
{
@ -37,8 +37,8 @@ uint64_t IDTEntry::get_offset()
void IDT::add_handler(short interrupt_number, void* handler, uint8_t type_attr)
{
ensure(handler != nullptr);
ensure(interrupt_number < 256);
ASSERT(handler != nullptr);
ASSERT(interrupt_number < 256);
IDTEntry* entry_for_handler = &entries[interrupt_number];
entry_for_handler->selector = 0x08;
entry_for_handler->type_attr = type_attr;

View File

@ -1,7 +1,6 @@
#define MODULE "irq"
#include "interrupts/IRQ.h"
#include "fs/devices/Console.h"
#include "fs/devices/Keyboard.h"
#include "io/IO.h"
#include "io/PIC.h"
@ -22,11 +21,10 @@ void IRQ::interrupt_handler(Context* context)
break;
case 1: {
unsigned char scancode = IO::inb(0x60);
KeyboardDevice::append((char)scancode);
bool ignore = false;
char key = translate_scancode(scancode, &ignore);
if (ignore) break;
ConsoleDevice::append(key);
KeyboardDevice::append(key);
break;
}
default: kwarnln("Unhandled IRQ: %ld", context->irq_number); break;

View File

@ -13,7 +13,7 @@
#include "memory/Memory.h"
#include "memory/MemoryMap.h"
#include "misc/hang.h"
#include "std/ensure.h"
#include "std/assert.h"
#include "std/stdlib.h"
#include "thread/PIT.h"
#include "thread/Scheduler.h"
@ -23,8 +23,8 @@
extern "C" void _start()
{
Init::disable_smp(); // Put all other cores except the bootstrap one in an infinite loop
Init::check_magic();
Init::disable_smp(); // Put all other cores except the bootstrap one in an infinite loop
Init::early_init();
kinfoln("Starting Moon %s", moon_version());
@ -52,9 +52,9 @@ extern "C" void _start()
kinfoln("Prepared scheduler");
#ifdef RUN_TEST_AS_INIT
ensure(Scheduler::load_user_task(STRINGIZE_VALUE_OF(RUN_TEST_AS_INIT)) > 0);
ASSERT(Scheduler::load_user_task(STRINGIZE_VALUE_OF(RUN_TEST_AS_INIT)) > 0);
#else
ensure(Scheduler::load_user_task("/bin/init") > 0);
ASSERT(Scheduler::load_user_task("/bin/init") > 0);
#endif
Scheduler::add_kernel_task("[reaper]", []() {
@ -67,7 +67,7 @@ extern "C" void _start()
kinfoln("Prepared scheduler tasks");
ensure(VFS::mkdir("/dev") == 0);
ASSERT(VFS::mkdir("/dev") == 0);
VFS::mount("/dev", DeviceFS::get());
Init::finish_kernel_boot();
@ -78,10 +78,5 @@ extern "C" void _start()
Interrupts::enable();
while (1)
halt(); // As soon as the first timer interrupt arrives, this idle loop is gone, since the main function is not
// registered as a task and thus the scheduler will never schedule this again. We still have to do
// something while waiting for a timer interrupt to arrive, though. In fact, in most cases, calling
// halt() once would be enough, since that function halts the CPU until the next interrupt (most likely
// the timer one) arrives. But we have to guarantee this function never returns.
while (1) halt();
}

View File

@ -26,11 +26,8 @@ void AddressSpace::destroy()
if (!pdp_pde.present) continue;
if (pdp_pde.larger_pages)
{
if (pdp_pde.owned_by_task)
{
pages_freed++;
PMM::free_page((void*)pdp_pde.get_address());
}
pages_freed++;
PMM::free_page((void*)pdp_pde.get_address());
continue;
}
PageTable* pdp = (PageTable*)pdp_pde.get_address();
@ -40,11 +37,8 @@ void AddressSpace::destroy()
if (!pd_pde.present) continue;
if (pd_pde.larger_pages)
{
if (pd_pde.owned_by_task)
{
pages_freed++;
PMM::free_page((void*)pd_pde.get_address());
}
pages_freed++;
PMM::free_page((void*)pd_pde.get_address());
continue;
}
PageTable* pd = (PageTable*)pd_pde.get_address();
@ -54,11 +48,8 @@ void AddressSpace::destroy()
if (!pt_pde.present) continue;
if (pt_pde.larger_pages)
{
if (pt_pde.owned_by_task)
{
pages_freed++;
PMM::free_page((void*)pt_pde.get_address());
}
pages_freed++;
PMM::free_page((void*)pt_pde.get_address());
continue;
}
PageTable* pt = (PageTable*)pt_pde.get_address();
@ -66,7 +57,6 @@ void AddressSpace::destroy()
{
PageDirectoryEntry& pde = pt->entries[l];
if (!pde.present) continue;
if (!pde.owned_by_task) continue;
pages_freed++;
PMM::free_page((void*)pde.get_address());
}
@ -94,11 +84,8 @@ void AddressSpace::clear()
if (!pdp_pde.present) continue;
if (pdp_pde.larger_pages)
{
if (pdp_pde.owned_by_task)
{
pages_freed++;
PMM::free_page((void*)pdp_pde.get_address());
}
pages_freed++;
PMM::free_page((void*)pdp_pde.get_address());
continue;
}
PageTable* pdp = (PageTable*)pdp_pde.get_address();
@ -108,11 +95,8 @@ void AddressSpace::clear()
if (!pd_pde.present) continue;
if (pd_pde.larger_pages)
{
if (pd_pde.owned_by_task)
{
pages_freed++;
PMM::free_page((void*)pd_pde.get_address());
}
pages_freed++;
PMM::free_page((void*)pd_pde.get_address());
continue;
}
PageTable* pd = (PageTable*)pd_pde.get_address();
@ -122,11 +106,8 @@ void AddressSpace::clear()
if (!pt_pde.present) continue;
if (pt_pde.larger_pages)
{
if (pt_pde.owned_by_task)
{
pages_freed++;
PMM::free_page((void*)pt_pde.get_address());
}
pages_freed++;
PMM::free_page((void*)pt_pde.get_address());
continue;
}
PageTable* pt = (PageTable*)pt_pde.get_address();
@ -134,7 +115,6 @@ void AddressSpace::clear()
{
PageDirectoryEntry& pde = pt->entries[l];
if (!pde.present) continue;
if (!pde.owned_by_task) continue;
pages_freed++;
PMM::free_page((void*)pde.get_address());
}
@ -174,11 +154,6 @@ AddressSpace AddressSpace::clone() // FIXME: Add out-of-memory checks to this fu
if (!pdp_pde.present) continue;
if (pdp_pde.larger_pages)
{
if (!pdp_pde.owned_by_task)
{
memcpy(&cloned_pdp_pde, &pdp_pde, sizeof(PageDirectoryEntry));
continue;
}
void* cloned = try_clone_page_table((PageTable*)pdp_pde.get_address());
if (!cloned)
{
@ -203,11 +178,6 @@ AddressSpace AddressSpace::clone() // FIXME: Add out-of-memory checks to this fu
if (!pd_pde.present) continue;
if (pd_pde.larger_pages)
{
if (!pd_pde.owned_by_task)
{
memcpy(&cloned_pd_pde, &pd_pde, sizeof(PageDirectoryEntry));
continue;
}
void* cloned = try_clone_page_table((PageTable*)pd_pde.get_address());
if (!cloned)
{
@ -232,11 +202,6 @@ AddressSpace AddressSpace::clone() // FIXME: Add out-of-memory checks to this fu
if (!pt_pde.present) continue;
if (pt_pde.larger_pages)
{
if (!pt_pde.owned_by_task)
{
memcpy(&cloned_pt_pde, &pt_pde, sizeof(PageDirectoryEntry));
continue;
}
void* cloned = try_clone_page_table((PageTable*)pt_pde.get_address());
if (!cloned)
{
@ -258,11 +223,6 @@ AddressSpace AddressSpace::clone() // FIXME: Add out-of-memory checks to this fu
{
PageDirectoryEntry& pde = pt->entries[l];
PageDirectoryEntry& cloned_pde = cloned_pt->entries[l];
if (!pde.owned_by_task)
{
memcpy(&cloned_pde, &pde, sizeof(PageDirectoryEntry));
continue;
}
if (!pde.present) continue;
void* cloned = try_clone_page_table((PageTable*)pde.get_address());
if (!cloned)

View File

@ -35,6 +35,7 @@ static void bitmap_set(uint64_t index, bool value)
void KernelHeap::clear()
{
memset(page_bitmap, 0, sizeof(page_bitmap));
kinfoln("page bitmap located at %p", (void*)page_bitmap);
}
uint64_t KernelHeap::request_virtual_page()

View File

@ -7,8 +7,7 @@
#include "memory/MemoryManager.h"
#include "memory/PMM.h"
#include "memory/VMM.h"
#include "misc/utils.h"
#include "std/ensure.h"
#include "std/assert.h"
void MemoryManager::init()
{
@ -18,19 +17,6 @@ void MemoryManager::init()
PMM::map_bitmap_to_virtual();
}
extern char start_of_kernel_rodata[1];
extern char end_of_kernel_rodata[1];
extern char start_of_kernel_data[1];
extern char end_of_kernel_data[1];
void MemoryManager::protect_kernel_sections()
{
protect(start_of_kernel_rodata,
Utilities::get_blocks_from_size(PAGE_SIZE, end_of_kernel_rodata - start_of_kernel_rodata), 0);
protect(start_of_kernel_data, Utilities::get_blocks_from_size(PAGE_SIZE, end_of_kernel_data - start_of_kernel_data),
MAP_READ_WRITE);
}
void* MemoryManager::get_mapping(void* physicalAddress, int flags)
{
uint64_t virtualAddress = KernelHeap::request_virtual_page();
@ -138,7 +124,7 @@ void* MemoryManager::get_page_at(uint64_t addr, int flags)
void MemoryManager::release_page(void* page)
{
uint64_t physicalAddress = VMM::get_physical((uint64_t)page);
ensure(physicalAddress != UINT64_MAX); // this address is not mapped in the virtual address space...
ASSERT(physicalAddress != UINT64_MAX); // this address is not mapped in the virtual address space...
VMM::unmap((uint64_t)page);
PMM::free_page((void*)physicalAddress);
}
@ -198,7 +184,7 @@ void MemoryManager::release_pages(void* pages, uint64_t count)
{
void* page = (void*)((uint64_t)pages + (i * PAGE_SIZE));
uint64_t physicalAddress = VMM::get_physical((uint64_t)page);
ensure(physicalAddress != UINT64_MAX);
ASSERT(physicalAddress != UINT64_MAX);
VMM::unmap((uint64_t)page);
PMM::free_page((void*)physicalAddress);
}
@ -209,11 +195,3 @@ void MemoryManager::protect(void* page, uint64_t count, int flags)
{
for (uint64_t i = 0; i < count; i++) { VMM::remap((uint64_t)page + (i * PAGE_SIZE), flags); }
}
void MemoryManager::map_several_pages(uint64_t physicalAddress, uint64_t virtualAddress, uint64_t count, int flags)
{
for (uint64_t i = 0; i < count; i++)
{
VMM::map(virtualAddress + (i * PAGE_SIZE), physicalAddress + (i * PAGE_SIZE), flags);
}
}

View File

@ -6,7 +6,7 @@
#include "memory/Memory.h"
#include "memory/MemoryManager.h"
#include "misc/utils.h"
#include "std/ensure.h"
#include "std/assert.h"
#include "std/string.h"
extern BOOTBOOT bootboot;
@ -50,7 +50,7 @@ void PMM::init()
bitmap_addr = (char*)biggest_chunk;
virtual_bitmap_addr = bitmap_addr;
ensure((total_mem / PAGE_SIZE / 8) < biggest_chunk_size);
ASSERT((total_mem / PAGE_SIZE / 8) < biggest_chunk_size);
bitmap_size = total_mem / PAGE_SIZE / 8 + 1;
memset(bitmap_addr, 0xFF, bitmap_size);

View File

@ -4,7 +4,7 @@
#include "log/Log.h"
#include "memory/PMM.h"
#include "misc/utils.h"
#include "std/ensure.h"
#include "std/assert.h"
#include "std/string.h"
#include "utils/Addresses.h"
#include "utils/Registers.h"
@ -13,8 +13,6 @@ static PageTable* kernel_pml4;
static PageTable* current_pml4;
static AddressSpace* user_address_space;
// FIXME: Switch to recursive paging instead of naively assuming the physical address space is identity mapped.
void VMM::switch_back_to_kernel_address_space()
{
if (current_pml4 != kernel_pml4) { current_pml4 = kernel_pml4; }
@ -61,16 +59,6 @@ void VMM::init()
{
kernel_pml4 = (PageTable*)read_cr3();
current_pml4 = kernel_pml4;
// Set up recursive paging
PageDirectoryEntry& recursive_pde = kernel_pml4->entries[510];
memset(&recursive_pde, 0, sizeof(PageDirectoryEntry));
recursive_pde.present = true;
recursive_pde.read_write = true;
recursive_pde.larger_pages = false;
recursive_pde.no_execute = true;
recursive_pde.set_address((uint64_t)kernel_pml4);
flush_tlb_full();
}
void VMM::unmap(uint64_t vaddr)
@ -97,12 +85,6 @@ void VMM::remap(uint64_t vaddr, int flags)
if (flags & ReadWrite) propagate_read_write(current_pml4, vaddr);
else
pde->read_write = false;
if (flags & Execute) pde->no_execute = false;
else
pde->no_execute = true;
if (flags & OwnedByTask) pde->owned_by_task = true;
else
pde->owned_by_task = false;
flush_tlb(vaddr);
}
@ -117,13 +99,11 @@ uint64_t VMM::get_physical(uint64_t vaddr)
uint64_t VMM::get_flags(uint64_t vaddr)
{
PageDirectoryEntry* pde = find_pde(current_pml4, round_down_to_nearest_page(vaddr));
if (!pde) return (uint64_t)-1; // Not mapped
if (!pde) return 0; // Not mapped
uint64_t flags = 0;
if (pde->user) flags |= User;
if (pde->read_write) flags |= ReadWrite;
if (!pde->no_execute) flags |= Execute;
if (pde->owned_by_task) flags |= OwnedByTask;
return flags;
}
@ -141,7 +121,6 @@ void VMM::map(uint64_t vaddr, uint64_t paddr, int flags)
{
unmap(vaddr);
pde = create_pde_if_not_exists(current_pml4, vaddr);
will_flush_tlb = false; // unmap() already flushes the TLB for us
}
pde->set_address(round_down_to_nearest_page(paddr));
@ -151,12 +130,6 @@ void VMM::map(uint64_t vaddr, uint64_t paddr, int flags)
if (flags & ReadWrite) propagate_read_write(current_pml4, vaddr);
else
pde->read_write = false;
if (flags & Execute) pde->no_execute = false;
else
pde->no_execute = true;
if (flags & OwnedByTask) pde->owned_by_task = true;
else
pde->owned_by_task = false;
if (will_flush_tlb) flush_tlb(vaddr);
}
@ -197,7 +170,7 @@ PageDirectoryEntry* VMM::create_pde_if_not_exists(PageTable* root, uint64_t vadd
auto pde_create_if_not_present = [&]() {
pt = (PageTable*)PMM::request_page();
ensure(!(PMM_DID_FAIL(pt)));
ASSERT(!(PMM_DID_FAIL(pt)));
memset(pt, 0, PAGE_SIZE);
pde->set_address((uint64_t)pt);
pde->present = true;
@ -273,44 +246,11 @@ void VMM::propagate_user(PageTable* root, uint64_t vaddr)
pde->user = true;
}
void VMM::propagate_no_execute(PageTable* root, uint64_t vaddr)
{
uint64_t page_index;
PageDirectoryEntry* pde;
PageTable* pt = root;
uint64_t indexes[3];
decompose_vaddr(vaddr, page_index, indexes[2], indexes[1], indexes[0]);
for (int i = 0; i < 3; i++)
{
pde = &pt->entries[indexes[i]];
if (!pde->present) return;
else
{
pde->no_execute = true;
if (pde->larger_pages) return;
pt = (PageTable*)pde->get_address();
}
}
pde = &pt->entries[page_index];
if (!pde->present) return;
else
pde->no_execute = true;
}
void VMM::flush_tlb(uint64_t addr)
{
asm volatile("invlpg (%0)" : : "r"(addr) : "memory");
}
void VMM::flush_tlb_full()
{
write_cr3(current_pml4);
}
void VMM::decompose_vaddr(uint64_t vaddr, uint64_t& page_index, uint64_t& pt_index, uint64_t& pd_index,
uint64_t& pdp_index)
{

View File

@ -8,7 +8,7 @@
#endif
#ifndef MOON_MINOR
#define MOON_MINOR 14
#define MOON_MINOR 13
#endif
#ifndef _MOON_SUFFIX

View File

@ -1,205 +0,0 @@
#define MODULE "ubsan"
#include <log/Log.h>
#include <panic/Panic.h>
#include <stdint.h>
#pragma GCC push_options
#pragma GCC diagnostic ignored "-Wpedantic"
struct source_location
{
const char* file;
uint32_t line;
uint32_t column;
};
struct type_descriptor
{
uint16_t kind;
uint16_t info;
char name[];
};
struct type_mismatch_info
{
struct source_location location;
struct type_descriptor* type;
uintptr_t alignment;
uint8_t type_check_kind;
};
struct type_mismatch_info_v1
{
struct source_location location;
struct type_descriptor* type;
unsigned char log_alignment;
unsigned char type_check_kind;
};
struct overflow_info
{
struct source_location location;
struct type_descriptor* type;
};
struct unreachable_info
{
struct source_location location;
};
struct out_of_bounds_info
{
struct source_location location;
struct type_descriptor* array_type;
struct type_descriptor* index_type;
};
struct invalid_value_info
{
struct source_location location;
struct type_descriptor* type;
};
struct shift_out_of_bounds_info
{
struct source_location location;
struct type_descriptor* lhs_type;
struct type_descriptor* rhs_type;
};
struct pointer_overflow_info
{
struct source_location location;
};
#define is_aligned(value, alignment) !(value & (alignment - 1))
const char* Type_Check_Kinds[] = {
"load of",
"store to",
"reference binding to",
"member access within",
"member call on",
"constructor call on",
"downcast of",
"downcast of",
"upcast of",
"cast to virtual base of",
};
static void log_location(source_location* location)
{
kinfoln("at %s:%d:%d", location->file, location->line, location->column);
}
extern "C" void __ubsan_handle_type_mismatch(type_mismatch_info* type_mismatch, uintptr_t pointer)
{
source_location* location = &type_mismatch->location;
if (pointer == 0) { kinfoln("Null pointer access"); }
else if (type_mismatch->alignment != 0 && is_aligned(pointer, type_mismatch->alignment))
{
// Most useful on architectures with stricter memory alignment requirements, like ARM.
kinfoln("Unaligned memory access");
}
else
{
kinfoln("Insufficient size");
kinfoln("%s address %p with insufficient space for object of type %s\n",
Type_Check_Kinds[type_mismatch->type_check_kind], (void*)pointer, type_mismatch->type->name);
}
log_location(location);
panic("Undefined behaviour detected");
}
extern "C" void __ubsan_handle_type_mismatch_v1(type_mismatch_info_v1* type_mismatch, unsigned long pointer)
{
type_mismatch_info info = {type_mismatch->location, type_mismatch->type, 1UL << type_mismatch->log_alignment,
type_mismatch->type_check_kind};
__ubsan_handle_type_mismatch(&info, pointer);
}
extern "C" void __ubsan_handle_add_overflow(overflow_info* overflow_data, uintptr_t, uintptr_t)
{
source_location* location = &overflow_data->location;
kinfoln("Addition overflow for two values of type %s", overflow_data->type->name);
log_location(location);
panic("Undefined behaviour detected");
}
extern "C" void __ubsan_handle_sub_overflow(overflow_info* overflow_data, uintptr_t, uintptr_t)
{
source_location* location = &overflow_data->location;
kinfoln("Substraction overflow for two values of type %s", overflow_data->type->name);
log_location(location);
panic("Undefined behaviour detected");
}
extern "C" void __ubsan_handle_mul_overflow(overflow_info* overflow_data, uintptr_t, uintptr_t)
{
source_location* location = &overflow_data->location;
kinfoln("Multiplication overflow for two values of type %s", overflow_data->type->name);
log_location(location);
panic("Undefined behaviour detected");
}
extern "C" void __ubsan_handle_negate_overflow(overflow_info* overflow_data, uintptr_t)
{
source_location* location = &overflow_data->location;
kinfoln("Negation overflow for two values of type %s", overflow_data->type->name);
log_location(location);
panic("Undefined behaviour detected");
}
extern "C" void __ubsan_handle_divrem_overflow(overflow_info* overflow_data, uintptr_t, uintptr_t)
{
source_location* location = &overflow_data->location;
kinfoln("Division overflow for two values of type %s", overflow_data->type->name);
log_location(location);
panic("Undefined behaviour detected");
}
extern "C" void __ubsan_handle_builtin_unreachable(unreachable_info* unreachable_data)
{
source_location* location = &unreachable_data->location;
kinfoln("Reached the unreachable");
log_location(location);
panic("Undefined behaviour detected");
}
extern "C" void __ubsan_handle_out_of_bounds(out_of_bounds_info* out_of_bounds_data, uintptr_t index)
{
source_location* location = &out_of_bounds_data->location;
kinfoln("Out of bounds access at index %ld of array type %s and index type %s", index,
out_of_bounds_data->array_type->name, out_of_bounds_data->index_type->name);
log_location(location);
panic("Undefined behaviour detected");
}
extern "C" void __ubsan_handle_load_invalid_value(invalid_value_info* invalid_value_data, uintptr_t)
{
source_location* location = &invalid_value_data->location;
kinfoln("Invalid value load of type %s", invalid_value_data->type->name);
log_location(location);
panic("Undefined behaviour detected");
}
extern "C" void __ubsan_handle_shift_out_of_bounds(shift_out_of_bounds_info* shift_out_of_bounds_data, uintptr_t,
uintptr_t)
{
source_location* location = &shift_out_of_bounds_data->location;
kinfoln("Shift out of bounds for type %s", shift_out_of_bounds_data->lhs_type->name);
log_location(location);
panic("Undefined behaviour detected");
}
extern "C" void __ubsan_handle_pointer_overflow(pointer_overflow_info* pointer_overflow_data, uintptr_t, uintptr_t)
{
source_location* location = &pointer_overflow_data->location;
kinfoln("Pointer overflow");
log_location(location);
panic("Undefined behaviour detected");
}
#pragma GCC pop_options

View File

@ -1,7 +1,7 @@
#define MODULE "panic"
#include "panic/Panic.h"
#include "fs/InitRD.h"
#include "init/InitRD.h"
#include "interrupts/IDT.h"
#include "io/PIC.h"
#include "log/Log.h"
@ -16,7 +16,7 @@
static bool g_is_in_panic = false;
static bool g_is_in_double_panic = false;
void panic_prepare_keyboard_triple_fault()
static void panic_prepare_keyboard_triple_fault()
{
PIC::enable_master(0b11111101); // enable keyboard only
PIC::enable_slave(0b11111111);

View File

@ -1,7 +1,7 @@
#define MODULE "rand"
#include "rand/Mersenne.h"
#include "std/ensure.h"
#include "std/assert.h"
#include <stddef.h>
typedef uint64_t word_t;
@ -47,7 +47,7 @@ uint64_t Mersenne::get()
{
if (index >= STATE_SIZE)
{
ensure(index == STATE_SIZE && "Mersenne generator was never seeded");
ASSERT(index == STATE_SIZE && "Mersenne generator was never seeded");
twist();
}

View File

@ -3,7 +3,7 @@
#include "render/TextRenderer.h"
#include "bootboot.h"
#include "font.h"
#include "fs/InitRD.h"
#include "init/InitRD.h"
#include "io/Serial.h"
#include "log/Log.h"
#include "render/Framebuffer.h"
@ -30,7 +30,7 @@ void TextRenderer::reset()
#pragma GCC optimize("O0")
static void putchar_at_offset(
char c, uint32_t cx, uint32_t cy, [[maybe_unused]] Color& fg,
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];
@ -46,67 +46,49 @@ static void putchar_at_offset(
}
}
static bool g_escape_sequence = false;
#pragma GCC pop_options
void TextRenderer::putchar(char chr)
{
if (g_escape_sequence)
switch (chr)
{
g_escape_sequence = false;
switch (chr)
case '\n': {
ypos += FONT_HEIGHT;
if ((ypos + FONT_HEIGHT) >= bootboot.fb_height)
{
case '@':
reset();
framebuffer0.clear(Color::Black);
break;
default: break;
memcpy((void*)bootboot.fb_ptr, (char*)bootboot.fb_ptr + (bootboot.fb_scanline * FONT_HEIGHT),
bootboot.fb_size - (bootboot.fb_scanline * FONT_HEIGHT));
ypos -= FONT_HEIGHT;
framebuffer0.paint_rect(0, ypos, bootboot.fb_width, FONT_HEIGHT, Color::Black);
}
xpos = 0;
break;
}
else
{
switch (chr)
case '\r': xpos = 0; break;
case '\b':
if (xpos != 0)
{
case '\n': {
xpos -= FONT_WIDTH;
framebuffer0.paint_rect(xpos, ypos, FONT_WIDTH, FONT_HEIGHT, Color::Black);
}
break;
default: {
putchar_at_offset(chr, xpos, ypos, fgColor, bgColor);
xpos += FONT_WIDTH;
if ((xpos + FONT_WIDTH) > bootboot.fb_width)
{
xpos = 0;
ypos += FONT_HEIGHT;
if ((ypos + FONT_HEIGHT) >= bootboot.fb_height)
if (ypos > bootboot.fb_height)
{
memcpy((void*)bootboot.fb_ptr, (char*)bootboot.fb_ptr + (bootboot.fb_scanline * FONT_HEIGHT),
bootboot.fb_size - (bootboot.fb_scanline * FONT_HEIGHT));
ypos -= FONT_HEIGHT;
framebuffer0.paint_rect(0, ypos, bootboot.fb_width, FONT_HEIGHT, Color::Black);
}
xpos = 0;
break;
}
case '\r': xpos = 0; break;
case '\b':
if (xpos != 0)
{
xpos -= FONT_WIDTH;
framebuffer0.paint_rect(xpos, ypos, FONT_WIDTH, FONT_HEIGHT, Color::Black);
}
break;
case '\033': g_escape_sequence = true; break;
default: {
putchar_at_offset(chr, xpos, ypos, fgColor, bgColor);
xpos += FONT_WIDTH;
if ((xpos + FONT_WIDTH) > bootboot.fb_width)
{
xpos = 0;
ypos += FONT_HEIGHT;
if ((ypos + FONT_HEIGHT) >= bootboot.fb_height)
{
memcpy((void*)bootboot.fb_ptr, (char*)bootboot.fb_ptr + (bootboot.fb_scanline * FONT_HEIGHT),
bootboot.fb_size - (bootboot.fb_scanline * FONT_HEIGHT));
ypos -= FONT_HEIGHT;
framebuffer0.paint_rect(0, ypos, bootboot.fb_width, FONT_HEIGHT, Color::Black);
}
}
break;
}
}
break;
}
}
}

View File

@ -228,7 +228,6 @@ int sprintf(char* __s, const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
if (__s) *__s = 0;
int written = internal_printf(
fmt,
[&](const char* s) {
@ -243,7 +242,6 @@ int snprintf(char* __s, size_t max, const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
if (__s && max) *__s = 0;
int written = internal_printf(
fmt,
[&](const char* s) {
@ -268,7 +266,6 @@ int vkprintf(const char* fmt, va_list ap)
int vsprintf(char* __s, const char* fmt, va_list ap)
{
*__s = 0;
return internal_printf(
fmt,
[&](const char* s) {
@ -279,7 +276,6 @@ int vsprintf(char* __s, const char* fmt, va_list ap)
int vsnprintf(char* __s, size_t max, const char* fmt, va_list ap)
{
if (max) *__s = 0;
return internal_printf(
fmt,
[&](const char* s) {

View File

@ -15,36 +15,27 @@ void Syscall::entry(Context* context)
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_getprocid: sys_getprocid(context, (int)context->rdi); break;
case SYS_mmap:
sys_mmap(context, (void*)context->rdi, context->rsi, (int)context->rdx, (int)context->r10, (off_t)context->r8);
break;
case SYS_mmap: sys_mmap(context, (void*)context->rdi, context->rsi, (int)context->rdx); break;
case SYS_munmap: sys_munmap(context, (void*)context->rdi, context->rsi); break;
case SYS_open: sys_open(context, (const char*)context->rdi, (int)context->rsi, (mode_t)context->rdx); 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;
case SYS_seek: sys_seek(context, (int)context->rdi, (long)context->rsi, (int)context->rdx); break;
case SYS_execv: sys_execv(context, (const char*)context->rdi, (char**)context->rsi); break;
case SYS_exec: sys_exec(context, (const char*)context->rdi); break;
case SYS_fcntl: sys_fcntl(context, (int)context->rdi, (int)context->rsi, context->rdx); break;
case SYS_mprotect: sys_mprotect(context, (void*)context->rdi, context->rsi, (int)context->rdx); break;
case SYS_clock_gettime: sys_clock_gettime(context, (int)context->rdi, (struct timespec*)context->rsi); break;
case SYS_mkdir: sys_mkdir(context, (const char*)context->rdi, (mode_t)context->rsi); break;
case SYS_clock: sys_clock(context); break;
case SYS_mkdir: sys_mkdir(context, (const char*)context->rdi); break;
case SYS_fork: sys_fork(context); break;
case SYS_waitpid: sys_waitpid(context, (long)context->rdi, (int*)context->rsi, (int)context->rdx); break;
case SYS_access: sys_access(context, (const char*)context->rdi, (int)context->rsi); break;
case SYS_fstat: sys_fstat(context, (int)context->rdi, (struct stat*)context->rsi); break;
case SYS_stat: sys_stat(context, (const char*)context->rdi, (struct stat*)context->rsi); break;
case SYS_pstat: sys_pstat(context, (long)context->rdi, (struct pstat*)context->rsi); break;
case SYS_getdents:
sys_getdents(context, (int)context->rdi, (struct luna_dirent*)context->rsi, (size_t)context->rdx);
break;
case SYS_dup2: sys_dup2(context, (int)context->rdi, (int)context->rsi); break;
case SYS_setuid: sys_setuid(context, (uid_t)context->rdi); break;
case SYS_setgid: sys_setgid(context, (gid_t)context->rdi); break;
case SYS_umask: sys_umask(context, (mode_t)context->rdi); break;
case SYS_ioctl: sys_ioctl(context, (int)context->rdi, (int)context->rsi, (uintptr_t)context->rdx); break;
case SYS_seteuid: sys_seteuid(context, (uid_t)context->rdi); break;
case SYS_setegid: sys_setegid(context, (gid_t)context->rdi); break;
default: context->rax = -ENOSYS; break;
}
VMM::exit_syscall_context();

View File

@ -1,212 +1,10 @@
#include "sys/UserMemory.h"
#include "memory/Memory.h"
#include "memory/MemoryManager.h"
#include "std/stdlib.h"
#include "std/string.h"
#include "utils/Addresses.h"
struct dynamic_string
char* strdup_from_user(
const char* user_string) // FIXME: This function is a little hacky. Use the obtain_user_ref and similar functions.
{
char* buf;
long capacity;
long size;
};
bool dynamic_expand(dynamic_string* str, long new_capacity)
{
char* buffer = (char*)krealloc(str->buf, new_capacity);
if (!buffer) { return false; }
str->buf = buffer;
str->capacity = new_capacity;
return true;
}
bool dynamic_push(dynamic_string* str, char c)
{
if (str->size == str->capacity)
{
if (!dynamic_expand(str, str->capacity + 16)) return false;
}
str->buf[str->size] = c;
str->size++;
return true;
}
bool dynamic_init(dynamic_string* str)
{
str->buf = (char*)kmalloc(10);
if (!str->buf) return false;
str->capacity = 10;
str->size = 0;
return true;
}
bool validate_user_readable_page(uintptr_t address)
{
if (Memory::is_kernel_address(address)) return false;
auto rc = VMM::get_flags(address);
if (rc == (uint64_t)-1) return false;
if (rc & MAP_USER) return true;
return false;
}
bool validate_user_writable_page(uintptr_t address)
{
if (Memory::is_kernel_address(address)) return false;
auto rc = VMM::get_flags(address);
if (rc == (uint64_t)-1) return false;
if (rc & (MAP_USER | MAP_READ_WRITE)) return true;
return false;
}
char* strdup_from_user(const char* user_string)
{
uintptr_t user_ptr = (uintptr_t)user_string;
auto aligned = round_down_to_nearest_page(user_ptr);
char* ptr = nullptr;
uintptr_t index = 0;
if (aligned != user_ptr) // Otherwise, we already do this check below.
{
if (!validate_user_readable_page(aligned)) return nullptr;
ptr = (char*)MemoryManager::get_mapping((void*)VMM::get_physical(aligned), 0);
index = user_ptr - aligned;
}
dynamic_string str;
if (!dynamic_init(&str))
{
if (ptr) MemoryManager::release_mapping(ptr);
return nullptr;
}
while (true) // FIXME: set a limit for this and fail with ENAMETOOLONG otherwise.
{
if (user_ptr % PAGE_SIZE == 0)
{
index = 0;
if (ptr) MemoryManager::release_mapping(ptr);
if (!validate_user_readable_page(user_ptr))
{
kfree(str.buf);
return nullptr;
}
ptr = (char*)MemoryManager::get_mapping((void*)VMM::get_physical(user_ptr), 0);
}
char c = ptr[index];
if (!dynamic_push(&str, c))
{
MemoryManager::release_mapping(ptr);
kfree(str.buf);
return nullptr;
}
if (!c) // We reached the null terminator!!
{
MemoryManager::release_mapping(ptr);
return str.buf;
}
user_ptr++;
index++;
}
}
bool validate_user_read(uintptr_t address, size_t size)
{
auto aligned = round_down_to_nearest_page(address);
if (aligned != address) // Otherwise, we already do this check below.
{
if (!validate_user_readable_page(aligned)) return false;
}
while (size--)
{
if (address % PAGE_SIZE == 0)
{
if (!validate_user_readable_page(address)) return false;
}
address++;
}
return true;
}
bool validate_user_write(uintptr_t address, size_t size)
{
auto aligned = round_down_to_nearest_page(address);
if (aligned != address) // Otherwise, we already do this check below.
{
if (!validate_user_writable_page(aligned)) return false;
}
while (size--)
{
if (address % PAGE_SIZE == 0)
{
if (!validate_user_writable_page(address)) return false;
}
address++;
}
return true;
}
bool do_copy_from_user(const char* uptr, char* ptr, size_t size)
{
uintptr_t user_ptr = (uintptr_t)uptr;
auto aligned = round_down_to_nearest_page(user_ptr);
char* mapping = nullptr;
uintptr_t index = 0;
if (aligned != user_ptr) // Otherwise, we already do this check below.
{
if (!validate_user_readable_page(aligned)) return false;
mapping = (char*)MemoryManager::get_mapping((void*)VMM::get_physical(aligned), 0);
index = user_ptr - aligned;
}
while (size--)
{
if (user_ptr % PAGE_SIZE == 0)
{
if (mapping) MemoryManager::release_mapping(mapping);
index = 0;
if (!validate_user_readable_page(user_ptr)) return false;
mapping = (char*)MemoryManager::get_mapping((void*)VMM::get_physical(user_ptr), 0);
}
*ptr = mapping[index];
user_ptr++;
ptr++;
index++;
}
return true;
}
bool do_copy_to_user(char* uptr, const char* ptr, size_t size)
{
uintptr_t user_ptr = (uintptr_t)uptr;
auto aligned = round_down_to_nearest_page(user_ptr);
char* mapping = nullptr;
uintptr_t index = 0;
if (aligned != user_ptr) // Otherwise, we already do this check below.
{
if (!validate_user_writable_page(aligned)) return false;
mapping = (char*)MemoryManager::get_mapping((void*)VMM::get_physical(aligned));
index = user_ptr - aligned;
}
while (size--)
{
if (user_ptr % PAGE_SIZE == 0)
{
if (mapping) MemoryManager::release_mapping(mapping);
index = 0;
if (!validate_user_writable_page(user_ptr)) return false;
mapping = (char*)MemoryManager::get_mapping((void*)VMM::get_physical(user_ptr));
}
mapping[index] = *ptr;
user_ptr++;
ptr++;
index++;
}
return true;
}
bool copy_from_user(const void* user_ptr, void* ptr, size_t size)
{
return do_copy_from_user((const char*)user_ptr, (char*)ptr, size);
}
bool copy_to_user(void* user_ptr, const void* ptr, size_t size)
{
return do_copy_to_user((char*)user_ptr, (const char*)ptr, size);
uint64_t phys = VMM::get_physical((uint64_t)user_string);
if (phys == (uint64_t)-1) { return nullptr; }
return strdup((const char*)phys);
}

View File

@ -1,83 +1,9 @@
#include "bootboot.h"
#include "interrupts/Context.h"
#include "std/errno.h"
#include "sys/UserMemory.h"
#include "thread/PIT.h"
#include "thread/Scheduler.h"
#include "utils/Time.h"
#include <sys/types.h>
static uint64_t unix_boot_time;
#define CLOCK_REALTIME 0
#define CLOCK_MONOTONIC 1
#define CLOCK_PROCTIME 2
struct timeval
void sys_clock(Context* context)
{
time_t tv_sec;
suseconds_t tv_usec;
};
struct timespec
{
time_t tv_sec;
long tv_nsec;
};
static void ms_to_timespec(long ms, struct timespec* tv)
{
tv->tv_sec = ms / 1000;
tv->tv_nsec = (ms % 1000) * 1000000;
}
void sys_clock_gettime(Context* context, int clock, struct timespec* tp)
{
struct timespec* ktp = obtain_user_ref(tp);
if (!ktp)
{
context->rax = -EFAULT; // FIXME: Not sure if clock_gettime can return EFAULT.
return;
}
Task* current_task = Scheduler::current_task();
switch (clock)
{
case CLOCK_REALTIME: {
ms_to_timespec(PIT::ms_since_boot, ktp);
ktp->tv_sec += unix_boot_time;
break;
}
case CLOCK_MONOTONIC: {
ms_to_timespec(PIT::ms_since_boot, ktp);
break;
}
case CLOCK_PROCTIME: {
ms_to_timespec(current_task->cpu_time, ktp);
break;
}
default:
release_user_ref(ktp);
context->rax = -EINVAL;
return;
}
release_user_ref(ktp);
context->rax = 0;
context->rax = (long)current_task->cpu_time;
return;
}
extern BOOTBOOT bootboot;
void clock_init()
{
unix_boot_time = unix_boottime(bootboot.datetime);
}
uint64_t clock_now()
{
return unix_boot_time + (PIT::ms_since_boot / 1000);
}
uint64_t clock_boot()
{
return unix_boot_time;
}

View File

@ -1,14 +1,14 @@
#define MODULE "elf"
#include "sys/elf/ELFLoader.h"
#include "fs/InitRD.h"
#include "fs/VFS.h"
#include "init/InitRD.h"
#include "log/Log.h"
#include "memory/Memory.h"
#include "memory/MemoryManager.h"
#include "memory/VMM.h"
#include "misc/utils.h"
#include "std/ensure.h"
#include "std/assert.h"
#include "std/errno.h"
#include "std/stdlib.h"
#include "std/string.h"
@ -25,16 +25,6 @@ static const char* format_permissions(uint32_t flags)
return perms;
}
static bool can_execute_segment(int flags)
{
return flags & 1;
}
static bool can_write_segment(int flags)
{
return flags & 2;
}
ELFImage* ELFLoader::load_elf_from_filesystem(const char* filename)
{
VFS::Node* node = VFS::resolve_path(filename);
@ -77,15 +67,15 @@ long ELFLoader::check_elf_image_from_filesystem(const char* filename)
ELFImage* ELFLoader::load_elf_from_vfs(VFS::Node* node)
{
Elf64_Ehdr elf_ehdr;
ensure(VFS::read(node, 0, sizeof(elf_ehdr), (char*)&elf_ehdr) >= 0);
ensure(strncmp((const char*)elf_ehdr.e_ident, ELFMAG, SELFMAG) ==
ASSERT(VFS::read(node, 0, sizeof(elf_ehdr), (char*)&elf_ehdr) >= 0);
ASSERT(strncmp((const char*)elf_ehdr.e_ident, ELFMAG, SELFMAG) ==
0); // If you haven't checked the ELF executable with check_elf_image() first, then an assertion fail is your
// fault =D
ensure(elf_ehdr.e_ident[EI_CLASS] == ELFCLASS64);
ensure(elf_ehdr.e_ident[EI_DATA] == ELFDATA2LSB);
ensure(elf_ehdr.e_type == ET_EXEC);
ensure(elf_ehdr.e_machine == EM_MACH);
ensure(elf_ehdr.e_phnum != 0);
ASSERT(elf_ehdr.e_ident[EI_CLASS] == ELFCLASS64);
ASSERT(elf_ehdr.e_ident[EI_DATA] == ELFDATA2LSB);
ASSERT(elf_ehdr.e_type == ET_EXEC);
ASSERT(elf_ehdr.e_machine == EM_MACH);
ASSERT(elf_ehdr.e_phnum != 0);
ELFImage* image = (ELFImage*)kmalloc(sizeof(ELFImage) - sizeof(ELFSection));
memset(image, 0, sizeof(ELFImage) - sizeof(ELFSection));
image->entry = elf_ehdr.e_entry;
@ -98,9 +88,7 @@ ELFImage* ELFLoader::load_elf_from_vfs(VFS::Node* node)
{
kdbgln("Loading loadable segment at address %lx, file size %ld, mem size %ld, permissions %s", phdr.p_vaddr,
phdr.p_filesz, phdr.p_memsz, format_permissions(phdr.p_flags));
ensure(phdr.p_vaddr);
ensure(!(can_write_segment(phdr.p_flags) && can_execute_segment(phdr.p_flags)));
ASSERT(phdr.p_vaddr);
uint64_t pages = Utilities::get_blocks_from_size(PAGE_SIZE, (phdr.p_vaddr % PAGE_SIZE) + phdr.p_memsz);
void* buffer = (void*)((uint64_t)MemoryManager::get_pages_at(round_down_to_nearest_page(phdr.p_vaddr),
@ -117,12 +105,7 @@ ELFImage* ELFLoader::load_elf_from_vfs(VFS::Node* node)
VMM::apply_address_space();
VMM::switch_to_previous_user_address_space();
int new_flags = MAP_USER | MAP_AS_OWNED_BY_TASK;
if (can_write_segment(phdr.p_flags)) new_flags |= MAP_READ_WRITE;
else if (can_execute_segment(phdr.p_flags))
new_flags |= MAP_EXEC;
MemoryManager::protect(buffer, pages, new_flags);
MemoryManager::protect(buffer, pages, phdr.p_flags & 2 ? MAP_READ_WRITE | MAP_USER : MAP_USER);
image = (ELFImage*)krealloc(image, (sizeof(ELFImage) - sizeof(ELFSection)) +
(image->section_count + 1) * sizeof(ELFSection));
@ -133,7 +116,7 @@ ELFImage* ELFLoader::load_elf_from_vfs(VFS::Node* node)
}
else { kdbgln("skipping non-loadable segment"); }
}
ensure(image->section_count);
ASSERT(image->section_count);
return image;
}
@ -194,11 +177,6 @@ long ELFLoader::check_elf_image(VFS::Node* node)
kerrorln("trying to load ELF into kernel memory");
return -ENOEXEC;
}
if (can_write_segment(phdr.p_flags) && can_execute_segment(phdr.p_flags))
{
kwarnln("executable violates W^X");
return -ENOEXEC;
}
loadable_sections++;
memusage += Utilities::get_blocks_from_size(PAGE_SIZE, phdr.p_memsz) * PAGE_SIZE;
}

View File

@ -2,11 +2,10 @@
#include "interrupts/Interrupts.h"
#include "log/Log.h"
#include "memory/Memory.h"
#include "memory/MemoryManager.h"
#include "memory/PMM.h"
#include "memory/VMM.h"
#include "std/ensure.h"
#include "std/assert.h"
#include "std/errno.h"
#include "std/stdlib.h"
#include "std/string.h"
@ -45,11 +44,6 @@ void sys_fork(Context* context)
child->ppid = parent->id;
child->uid = parent->uid;
child->euid = parent->euid;
child->gid = parent->gid;
child->egid = parent->egid;
child->regs.rax = 0;
context->rax = child->id;
@ -62,16 +56,7 @@ void sys_fork(Context* context)
return;
}
void push_on_user_stack(uint64_t* rsp, char* value,
size_t size) // FIXME: Handle segments of stack that extend beyond one page.
{
(*rsp) -= size;
char* kvalue = (char*)VMM::get_physical(*rsp);
ensure(kvalue != (char*)UINT64_MAX);
memcpy(kvalue, value, size);
}
void sys_execv(Context* context, const char* pathname, char** argv)
void sys_exec(Context* context, const char* pathname)
{
char* kpathname = strdup_from_user(pathname);
if (!kpathname)
@ -97,13 +82,6 @@ void sys_execv(Context* context, const char* pathname, char** argv)
return;
}
if (!VFS::can_execute(program, Scheduler::current_task()->euid, Scheduler::current_task()->egid))
{
kfree(kpathname);
context->rax = -EACCES;
return;
}
long memusage;
if ((memusage = ELFLoader::check_elf_image(program)) < 0)
{
@ -119,88 +97,11 @@ void sys_execv(Context* context, const char* pathname, char** argv)
return;
}
uint64_t kargc = 0;
char** kargv = nullptr;
char* arg;
auto free_kernel_argv_copy = [&]() {
for (uint64_t i = 0; i < kargc; i++)
{
if (kargv[i]) kfree(kargv[i]);
}
if (kargv) kfree(kargv);
};
// FIXME: This code is a bit messy. Should probably be refactored and moved into a separate function.
do {
if (!copy_from_user(argv, &arg, sizeof(char*)))
{
free_kernel_argv_copy();
context->rax = -EFAULT;
return;
}
kargv = (char**)krealloc(kargv, (kargc + 1) * sizeof(char*)); // we need a vector class for the kernel.
if (!kargv)
{
free_kernel_argv_copy();
context->rax = -ENOMEM;
return;
}
if (arg)
{
char* kcopy = strdup_from_user(arg);
if (!kcopy) // FIXME: This could also be EFAULT.
{
free_kernel_argv_copy();
context->rax = -ENOMEM;
return;
}
kargv[kargc] = kcopy;
}
else
{
kargv[kargc] = nullptr;
break;
}
kargc++;
argv++;
} while (arg != nullptr);
kinfoln("Copied %lu arguments from user process", kargc);
size_t stack_size = 0;
for (uint64_t i = 0; i <= kargc; i++)
{
stack_size += sizeof(char*);
if (kargv[i])
{
stack_size += strlen(kargv[i]) + 1; // count the null byte
}
}
if (stack_size >
((TASK_PAGES_IN_STACK / 2) *
PAGE_SIZE)) // FIXME: Maybe we should allocate a larger stack in this case, but still set a larger upper limit.
{
free_kernel_argv_copy();
context->rax = -E2BIG;
return;
}
char** user_argv = (char**)kcalloc(kargc + 1, sizeof(char*));
if (!user_argv)
{
free_kernel_argv_copy();
context->rax = -ENOMEM;
return;
}
Interrupts::disable();
ensure(!Interrupts::are_enabled()); // This part is pretty sensitive.
ASSERT(!Interrupts::are_enabled()); // This part is pretty sensitive.
Task* task = Scheduler::current_task();
ensure(task);
ASSERT(task);
// At this point, pretty much nothing can fail.
@ -211,16 +112,13 @@ void sys_execv(Context* context, const char* pathname, char** argv)
task->address_space.clear();
task->allocated_stack = (uint64_t)MemoryManager::get_pages_at(
0x100000, TASK_PAGES_IN_STACK,
MAP_USER | MAP_READ_WRITE | MAP_AS_OWNED_BY_TASK); // If we had enough space for the old stack, there should be
// enough space for the new stack.
MAP_USER | MAP_READ_WRITE); // If we had enough space for the old stack, there should be enough space for the
// new stack.
ELFImage* image = ELFLoader::load_elf_from_vfs(program);
ensure(image); // If check_elf_image succeeded, load_elf_from_vfs MUST succeed, unless something has gone terribly
ASSERT(image); // If check_elf_image succeeded, load_elf_from_vfs MUST succeed, unless something has gone terribly
// wrong.
if (VFS::is_setuid(program)) task->euid = program->uid;
if (VFS::is_setgid(program)) task->egid = program->gid;
strlcpy(task->name, kpathname, sizeof(task->name));
Scheduler::reset_task(task, image);
@ -231,29 +129,9 @@ void sys_execv(Context* context, const char* pathname, char** argv)
if (file.close_on_exec()) { file.close(); }
}
for (uint64_t i = 0; i <= kargc; i++)
{
if (kargv[i])
{
push_on_user_stack(&task->regs.rsp, kargv[i], strlen(kargv[i]) + 1);
user_argv[i] = (char*)task->regs.rsp;
}
else
user_argv[i] = nullptr;
}
push_on_user_stack(&task->regs.rsp, (char*)user_argv, (kargc + 1) * sizeof(char*));
task->regs.rdi = kargc; // argc
task->regs.rsi = task->regs.rsp; // argv
task->regs.rsp &= (UINT64_MAX ^ 15); // align it
free_kernel_argv_copy();
kfree(user_argv);
task->restore_context(context);
kfree(kpathname);
task->restore_context(context);
return;
}

View File

@ -1,13 +1,8 @@
#include "std/errno.h"
#include "thread/Scheduler.h"
#include <sys/types.h>
#define ID_PID 0
#define ID_PPID 1
#define ID_UID 2
#define ID_EUID 3
#define ID_GID 4
#define ID_EGID 5
void sys_getprocid(Context* context, int field)
{
@ -21,103 +16,9 @@ void sys_getprocid(Context* context, int field)
context->rax = Scheduler::current_task()->ppid;
return;
}
else if (field == ID_UID)
{
context->rax = Scheduler::current_task()->uid;
return;
}
else if (field == ID_EUID)
{
context->rax = Scheduler::current_task()->euid;
return;
}
else if (field == ID_GID)
{
context->rax = Scheduler::current_task()->gid;
return;
}
else if (field == ID_EGID)
{
context->rax = Scheduler::current_task()->egid;
return;
}
else
{
context->rax = -EINVAL;
return;
}
}
void sys_setuid(Context* context, uid_t uid)
{
Task* current_task = Scheduler::current_task();
if (!current_task->is_superuser())
{
if (uid != current_task->uid && uid != current_task->euid)
{
context->rax = -EPERM;
return;
}
}
current_task->uid = uid;
current_task->euid = uid;
context->rax = 0;
}
void sys_seteuid(Context* context, uid_t euid)
{
Task* current_task = Scheduler::current_task();
if (!current_task->is_superuser())
{
if (euid != current_task->uid)
{
context->rax = -EPERM;
return;
}
}
current_task->euid = euid;
context->rax = 0;
}
void sys_setgid(Context* context, gid_t gid)
{
Task* current_task = Scheduler::current_task();
if (!current_task->is_superuser())
{
if (gid != current_task->gid && gid != current_task->egid)
{
context->rax = -EPERM;
return;
}
}
current_task->gid = gid;
current_task->egid = gid;
context->rax = 0;
}
void sys_setegid(Context* context, gid_t egid)
{
Task* current_task = Scheduler::current_task();
if (!current_task->is_superuser())
{
if (egid != current_task->gid)
{
context->rax = -EPERM;
return;
}
}
current_task->egid = egid;
context->rax = 0;
}

View File

@ -10,34 +10,30 @@
#include "thread/Scheduler.h"
#include <stddef.h>
#define PROT_READ 1
#define PROT_WRITE 2
#define PROT_NONE 0
#define PROT_EXEC 4
#define MAP_READ 1
#define MAP_WRITE 2
#define MAP_NONE 0
#define MAP_FAIL(errno) 0xffffffffffffff00 | (unsigned char)(errno)
static const char* format_prot(int prot)
{
static char prot_string[4];
prot_string[3] = 0;
prot_string[0] = ((prot & PROT_READ) > 0) ? 'r' : '-';
prot_string[1] = ((prot & PROT_WRITE) > 0) ? 'w' : '-';
prot_string[2] = ((prot & PROT_EXEC) > 0) ? 'x' : '-';
static char prot_string[3];
prot_string[2] = 0;
prot_string[0] = ((prot & MAP_READ) > 0) ? 'r' : '-';
prot_string[1] = ((prot & MAP_WRITE) > 0) ? 'w' : '-';
return prot_string;
}
static int mman_flags_from_prot(int prot)
{
prot &= 0b111;
int flags = MAP_USER | MAP_AS_OWNED_BY_TASK;
if (prot == PROT_NONE) return MAP_AS_OWNED_BY_TASK;
if ((prot & PROT_WRITE) > 0) { flags |= MAP_READ_WRITE; }
if ((prot & PROT_EXEC) > 0) { flags |= MAP_EXEC; }
return flags;
prot &= 0b11;
if (prot == MAP_NONE) return 0;
if ((prot & MAP_WRITE) > 0) return MAP_USER | MAP_READ_WRITE;
return MAP_USER;
}
void sys_mmap(Context* context, void* address, size_t size, int prot, int fd, off_t offset)
void sys_mmap(Context* context, void* address, size_t size, int prot)
{
if (size < PAGE_SIZE)
{
@ -54,7 +50,7 @@ void sys_mmap(Context* context, void* address, size_t size, int prot, int fd, of
int real_flags = mman_flags_from_prot(prot);
if (address)
{
kdbgln("mmap(): %ld pages at address %p, %s, fd %d", size / PAGE_SIZE, address, format_prot(prot), fd);
kdbgln("mmap(): %ld pages at address %p, %s", size / PAGE_SIZE, address, format_prot(prot));
if (Memory::is_kernel_address((uintptr_t)address))
{
kwarnln("munmap() failed: attempted to unmap a kernel page");
@ -67,20 +63,8 @@ void sys_mmap(Context* context, void* address, size_t size, int prot, int fd, of
context->rax = MAP_FAIL(ENOMEM);
return;
}
uint64_t addr_offset = (uint64_t)address % PAGE_SIZE;
if (fd >= 0)
{
int err;
Descriptor* file = Scheduler::current_task()->open_descriptor_from_fd(fd, err);
if (!file)
{
context->rax = MAP_FAIL(err);
return;
}
context->rax = file->mmap((uint64_t)address - addr_offset, size, real_flags, offset);
return;
}
void* result = MemoryManager::get_pages_at((uint64_t)address - addr_offset,
uint64_t offset = (uint64_t)address % PAGE_SIZE;
void* result = MemoryManager::get_pages_at((uint64_t)address - offset,
Utilities::get_blocks_from_size(PAGE_SIZE, size), real_flags);
if (result)
{
@ -95,8 +79,7 @@ void sys_mmap(Context* context, void* address, size_t size, int prot, int fd, of
return;
}
}
kdbgln("mmap(): %ld pages at any address, %s, fd %d", Utilities::get_blocks_from_size(PAGE_SIZE, size),
format_prot(prot), fd);
kdbgln("mmap(): %ld pages at any address, %s", Utilities::get_blocks_from_size(PAGE_SIZE, size), format_prot(prot));
uint64_t ptr =
Scheduler::current_task()->allocator.request_virtual_pages(Utilities::get_blocks_from_size(PAGE_SIZE, size));
if (!ptr)
@ -105,18 +88,6 @@ void sys_mmap(Context* context, void* address, size_t size, int prot, int fd, of
context->rax = MAP_FAIL(ENOMEM);
return;
}
if (fd >= 0)
{
int err;
Descriptor* file = Scheduler::current_task()->open_descriptor_from_fd(fd, err);
if (!file)
{
context->rax = MAP_FAIL(err);
return;
}
context->rax = file->mmap(ptr, size, real_flags, offset);
return;
}
void* result = MemoryManager::get_pages_at(ptr, Utilities::get_blocks_from_size(PAGE_SIZE, size), real_flags);
if (result)
{
@ -159,8 +130,8 @@ void sys_munmap(Context* context, void* address, size_t size)
context->rax = -EINVAL;
return;
}
uint64_t flags = VMM::get_flags((uint64_t)address);
if (flags == (uint64_t)-1)
uint64_t phys = VMM::get_physical((uint64_t)address);
if (phys == (uint64_t)-1)
{
kwarnln("munmap() failed: attempted to unmap a non-existent page");
context->rax = -EINVAL;
@ -169,12 +140,7 @@ void sys_munmap(Context* context, void* address, size_t size)
uint64_t offset = (uint64_t)address % PAGE_SIZE;
Scheduler::current_task()->allocator.free_virtual_pages(((uint64_t)address - offset),
Utilities::get_blocks_from_size(PAGE_SIZE, size));
if (flags & MAP_AS_OWNED_BY_TASK)
MemoryManager::release_pages((void*)((uint64_t)address - offset),
Utilities::get_blocks_from_size(PAGE_SIZE, size));
else
MemoryManager::release_unaligned_mappings((void*)((uint64_t)address - offset),
Utilities::get_blocks_from_size(PAGE_SIZE, size));
MemoryManager::release_pages((void*)((uint64_t)address - offset), Utilities::get_blocks_from_size(PAGE_SIZE, size));
kdbgln("munmap() succeeded");
context->rax = 0;
return;
@ -208,8 +174,8 @@ void sys_mprotect(Context* context, void* address, size_t size, int prot)
context->rax = -EINVAL;
return;
}
uint64_t flags = VMM::get_flags((uint64_t)address);
if (flags == (uint64_t)-1)
uint64_t phys = VMM::get_physical((uint64_t)address);
if (phys == (uint64_t)-1)
{
kwarnln("mprotect() failed: attempted to protect a non-existent page");
context->rax = -EINVAL;
@ -218,8 +184,7 @@ void sys_mprotect(Context* context, void* address, size_t size, int prot)
uint64_t offset = (uint64_t)address % PAGE_SIZE;
MemoryManager::protect((void*)((uint64_t)address - offset), Utilities::get_blocks_from_size(PAGE_SIZE, size),
flags & MAP_AS_OWNED_BY_TASK ? mman_flags_from_prot(prot)
: mman_flags_from_prot(prot) & ~(MAP_AS_OWNED_BY_TASK));
mman_flags_from_prot(prot));
kdbgln("mprotect() succeeded");
context->rax = 0;
return;

27
kernel/src/sys/paint.cpp Normal file
View File

@ -0,0 +1,27 @@
#include "bootboot.h"
#include "interrupts/Context.h"
#include "render/Framebuffer.h"
#include "std/errno.h"
#include <stdint.h>
extern BOOTBOOT bootboot;
void sys_paint(Context* context, uint64_t x, uint64_t y, uint64_t w, uint64_t h, uint64_t c)
{
if ((x + w) > bootboot.fb_width)
{
context->rax = -EINVAL;
return;
}
if ((y + h) > bootboot.fb_height)
{
context->rax = -EINVAL;
return;
}
uint32_t color = (uint32_t)c;
framebuffer0.paint_rect((uint32_t)x, (uint32_t)y, (uint32_t)w, (uint32_t)h, Color::from_integer(color));
context->rax = 0;
}

View File

@ -1,10 +1,10 @@
#include "fs/VFS.h"
#include "interrupts/Context.h"
#include "std/errno.h"
#include "std/stdlib.h"
#include "sys/UserMemory.h"
#include "thread/Scheduler.h"
typedef unsigned long off_t;
typedef unsigned short mode_t;
typedef unsigned long ino_t;
@ -13,37 +13,8 @@ struct stat // FIXME: This struct is quite stubbed out.
ino_t st_ino;
mode_t st_mode;
off_t st_size;
int st_dev; // FIXME: Implement this.
int st_nlink; // FIXME: Implement this.
uid_t st_uid;
gid_t st_gid;
time_t st_atime;
time_t st_mtime;
time_t st_ctime;
};
void do_stat(Context* context, VFS::Node* node, struct stat* buf)
{
struct stat* kstat = obtain_user_ref(buf);
if (!kstat)
{
context->rax = -EFAULT; // FIXME: The manual doesn't say fstat can return EFAULT, but it seems logical here...
return;
}
kstat->st_ino = node->inode;
kstat->st_mode = node->mode | ((1 << (node->type)) * 010000);
kstat->st_size = node->length;
kstat->st_uid = node->uid;
kstat->st_gid = node->gid;
kstat->st_atime = node->atime;
kstat->st_ctime = node->ctime;
kstat->st_mtime = node->mtime;
kstat->st_dev = 0;
kstat->st_nlink = 0;
release_user_ref(kstat);
context->rax = 0;
}
void sys_fstat(Context* context, int fd, struct stat* buf)
{
Task* current_task = Scheduler::current_task();
@ -58,24 +29,16 @@ void sys_fstat(Context* context, int fd, struct stat* buf)
context->rax = -EBADF;
return;
}
struct stat* kstat = obtain_user_ref(buf);
if (!kstat)
{
context->rax = -EFAULT; // FIXME: The manual doesn't say fstat can return EFAULT, but it seems logical here...
return;
}
VFS::Node* node = file.node();
return do_stat(context, node, buf);
}
void sys_stat(Context* context, const char* path, struct stat* buf)
{
char* kpath = strdup_from_user(path);
if (!kpath)
{
context->rax = -EFAULT;
return;
}
VFS::Node* node = VFS::resolve_path(kpath);
kfree(kpath);
if (!node)
{
context->rax = -ENOENT;
return;
}
return do_stat(context, node, buf);
kstat->st_ino = node->inode;
kstat->st_mode = (mode_t)node->type;
kstat->st_size = node->length;
release_user_ref(kstat);
context->rax = 0;
}

View File

@ -11,17 +11,12 @@
#include "sys/UserMemory.h"
#include "thread/Scheduler.h"
#include "thread/Task.h"
#include <sys/types.h>
#define OPEN_READ 1
#define OPEN_WRITE 2
#define OPEN_NONBLOCK 4
#define OPEN_CLOEXEC 8
#define OPEN_DIRECTORY 16
#define OPEN_TRUNCATED 32
#define OPEN_CREATE 64
#define OPEN_APPEND 128
#define OPEN_EXCL 256
#define SEEK_SET 0
#define SEEK_CUR 1
@ -29,64 +24,47 @@
#define FCNTL_DUPFD 0
#define FCNTL_ISTTY 1
#define FCNTL_GETFD 2
#define FCNTL_SETFD 3
#define FD_CLOEXEC 1
void sys_fcntl(Context* context, int fd, int command, uintptr_t arg)
{
Task* current_task = Scheduler::current_task();
int err;
Descriptor* file = current_task->open_descriptor_from_fd(fd, err);
if (!file)
if (fd >= TASK_MAX_FDS || fd < 0)
{
context->rax = -err;
context->rax = -EBADF;
return;
}
Task* current_task = Scheduler::current_task();
if (!current_task->files[fd].is_open())
{
context->rax = -EBADF;
return;
}
Descriptor& file = current_task->files[fd];
if (command == FCNTL_DUPFD)
{
int minfd = (int)arg;
if (minfd < 0 || minfd >= TASK_MAX_FDS)
if ((int)arg < 0 || (int)arg >= TASK_MAX_FDS)
{
context->rax = -EINVAL;
return;
}
int dupfd = current_task->alloc_fd_greater_than_or_equal(minfd);
int dupfd = current_task->alloc_fd_greater_than_or_equal((int)arg);
if (dupfd < 0)
{
context->rax = -EMFILE;
return;
}
current_task->files[dupfd] = *file;
current_task->files[dupfd] = file;
context->rax = dupfd;
kdbgln("fcntl(F_DUPFD): duplicated fd %d, result is %d", fd, dupfd);
return;
}
else if (command == FCNTL_ISTTY)
{
VFS::Node* node = file->node();
VFS::Node* node = file.node();
if (node->tty) { context->rax = 1; }
else
context->rax = -ENOTTY;
return;
}
else if (command == FCNTL_GETFD)
{
int flags = 0;
if (file->close_on_exec()) context->rax |= FD_CLOEXEC;
context->rax = flags;
return;
}
else if (command == FCNTL_SETFD)
{
int flags = (int)arg;
if (flags & FD_CLOEXEC) file->set_close_on_exec(true);
else
file->set_close_on_exec(false);
context->rax = 0;
return;
}
else
{
context->rax = -EINVAL;
@ -101,19 +79,24 @@ void sys_seek(Context* context, int fd, long offset, int whence)
context->rax = -EINVAL;
return;
}
int err;
Descriptor* file = Scheduler::current_task()->open_descriptor_from_fd(fd, err);
if (!file)
if (fd >= TASK_MAX_FDS || fd < 0)
{
context->rax = -err;
context->rax = -EBADF;
return;
}
Task* current_task = Scheduler::current_task();
if (!current_task->files[fd].is_open())
{
context->rax = -EBADF;
return;
}
Descriptor& file = current_task->files[fd];
long new_offset;
if (whence == SEEK_SET) new_offset = offset;
else if (whence == SEEK_CUR)
new_offset = offset + file->offset();
new_offset = offset + file.offset();
else if (whence == SEEK_END)
new_offset = file->length() + offset;
new_offset = file.length() + offset;
else
__builtin_unreachable();
if (new_offset < 0)
@ -121,12 +104,12 @@ void sys_seek(Context* context, int fd, long offset, int whence)
context->rax = -EINVAL; // FIXME: Is this the right error?
return;
}
if (new_offset == file->offset())
if (new_offset == file.offset())
{
context->rax = new_offset;
return;
}
int result = file->seek(new_offset);
int result = file.seek(new_offset);
if (result < 0)
{
context->rax = result;
@ -138,29 +121,34 @@ void sys_seek(Context* context, int fd, long offset, int whence)
void sys_write(Context* context, int fd, size_t size, const char* addr)
{
if (!validate_user_read((uintptr_t)addr, size))
if (!addr)
{
context->rax = -EFAULT;
return;
}
int err;
Descriptor* file = Scheduler::current_task()->open_descriptor_from_fd(fd, err);
if (!file)
{
context->rax = -err;
return;
}
if (!file->can_write())
if (fd >= TASK_MAX_FDS || fd < 0)
{
context->rax = -EBADF;
return;
}
ssize_t result = file->user_write(size, addr);
Task* current_task = Scheduler::current_task();
if (!current_task->files[fd].is_open())
{
context->rax = -EBADF;
return;
}
Descriptor& file = current_task->files[fd];
if (!file.can_write())
{
context->rax = -EBADF;
return;
}
ssize_t result = file.write(size, (const char*)VMM::get_physical((uint64_t)addr));
context->rax = (size_t)result;
return;
}
void sys_open(Context* context, const char* filename, int flags, mode_t) // FIXME: mode is not used.
void sys_open(Context* context, const char* filename, int flags)
{
Task* current_task = Scheduler::current_task();
int fd = current_task->alloc_fd();
@ -180,23 +168,10 @@ void sys_open(Context* context, const char* filename, int flags, mode_t) // FIXM
VFS::Node* node = VFS::resolve_path(kfilename);
if (!node)
{
bool create = (flags & OPEN_CREATE) > 0;
if (create) kwarnln("FIXME: open(O_CREAT) is not implemented");
kfree(kfilename);
context->rax = -ENOENT;
return;
}
else
{
bool excl = (flags & OPEN_EXCL) > 0;
if (excl)
{
kfree(kfilename);
context->rax = -EEXIST;
return;
}
}
bool can_read = (flags & OPEN_READ) > 0;
bool can_write = (flags & OPEN_WRITE) > 0;
@ -207,40 +182,11 @@ void sys_open(Context* context, const char* filename, int flags, mode_t) // FIXM
return;
}
if (can_read && !VFS::can_read(node, current_task->euid, current_task->egid))
{
kwarnln("open failed because process with uid %d and gid %d couldn't open file %s with mode %d for reading",
current_task->euid, current_task->egid, kfilename, node->mode);
kfree(kfilename);
context->rax = -EACCES;
return;
}
if (can_write && !VFS::can_write(node, current_task->euid, current_task->egid))
{
kwarnln("open failed because process with uid %d and gid %d couldn't open file %s with mode %d for writing",
current_task->euid, current_task->egid, kfilename, node->mode);
kfree(kfilename);
context->rax = -EACCES;
return;
}
bool able_to_block = (flags & OPEN_NONBLOCK) == 0;
bool close_on_exec = (flags & OPEN_CLOEXEC) > 0;
bool only_directory = (flags & OPEN_DIRECTORY) > 0;
bool truncate = (flags & OPEN_TRUNCATED) > 0;
if (truncate)
{
kfree(kfilename);
kerrorln("FIXME: open(O_TRUNC) is not implemented");
context->rax = -ENOTSUP;
return;
}
bool append = (flags & OPEN_APPEND) > 0;
if (only_directory && node->type != VFS_DIRECTORY)
{
kfree(kfilename);
@ -256,71 +202,68 @@ void sys_open(Context* context, const char* filename, int flags, mode_t) // FIXM
kfree(kfilename);
current_task->files[fd].open(node, can_read, can_write, able_to_block, close_on_exec);
if (append && current_task->files[fd].node()->type != VFS_DEVICE)
{
current_task->files[fd].seek((long)current_task->files[fd].length());
}
context->rax = fd;
return;
}
void sys_read(Context* context, int fd, size_t size, char* buffer)
{
if (!validate_user_write((uintptr_t)buffer, size))
if (!buffer)
{
context->rax = -EFAULT;
return;
}
int err;
Descriptor* file = Scheduler::current_task()->open_descriptor_from_fd(fd, err);
if (!file)
{
context->rax = -err;
return;
}
if (!file->can_read())
if (fd >= TASK_MAX_FDS || fd < 0)
{
context->rax = -EBADF;
return;
}
if (VFS::would_block(file->node()))
Task* current_task = Scheduler::current_task();
if (!current_task->files[fd].is_open() || !current_task->files[fd].can_read())
{
if (!file->able_to_block())
context->rax = -EBADF;
return;
}
if (VFS::would_block(current_task->files[fd].node()))
{
if (!current_task->files[fd].able_to_block())
{
context->rax = -EAGAIN;
return;
}
Task* current_task = Scheduler::current_task();
current_task->state = current_task->Blocking;
current_task->block_reason = BlockReason::Reading;
current_task->blocking_read_info.fd = fd;
current_task->blocking_read_info.buf = buffer;
current_task->blocking_read_info.buf = (char*)VMM::get_physical((uint64_t)buffer); // FIXME: Handle errors.
current_task->blocking_read_info.size = size;
return Scheduler::task_yield(context);
}
ssize_t result = file->user_read(size, buffer);
ssize_t result = current_task->files[fd].read(
size, (char*)VMM::get_physical((uint64_t)buffer)); // FIXME: Handle errors, and big buffers which may not be
// across continuous physical pages.
context->rax = (size_t)result;
return;
}
void sys_close(Context* context, int fd)
{
int err;
Descriptor* file = Scheduler::current_task()->open_descriptor_from_fd(fd, err);
if (!file)
if (fd >= TASK_MAX_FDS || fd < 0)
{
context->rax = -err;
context->rax = -EBADF;
return;
}
Task* current_task = Scheduler::current_task();
if (!current_task->files[fd].is_open())
{
context->rax = -EBADF;
return;
}
kdbgln("close(): releasing file descriptor %d", fd);
file->close();
current_task->files[fd].close();
context->rax = 0;
return;
}
void sys_mkdir(Context* context, const char* filename, mode_t mode)
void sys_mkdir(Context* context, const char* filename)
{
char* kfilename = strdup_from_user(filename);
if (!kfilename)
@ -329,9 +272,7 @@ void sys_mkdir(Context* context, const char* filename, mode_t mode)
return;
}
Task* current_task = Scheduler::current_task();
int rc = VFS::do_mkdir(kfilename, current_task->euid, current_task->egid, mode & (~current_task->umask));
int rc = VFS::mkdir(kfilename);
kfree(kfilename);
@ -346,44 +287,3 @@ void sys_access(Context* context, const char* path, int) // FIXME: Use the amode
context->rax = 0;
kfree(kpath);
}
void sys_dup2(Context* context, int fd, int fd2)
{
int err;
Descriptor* file1 = Scheduler::current_task()->open_descriptor_from_fd(fd, err);
if (!file1)
{
context->rax = -err;
return;
}
Descriptor* file2 = Scheduler::current_task()->descriptor_from_fd(fd2, err);
if (!file2)
{
context->rax = -err;
return;
}
if (file2->is_open()) file2->close();
*file2 = *file1;
kinfoln("dup2(): overwrote fd %d with fd %d", fd2, fd);
context->rax = fd2;
}
void sys_umask(Context* context, mode_t cmask)
{
Task* current_task = Scheduler::current_task();
context->rax = current_task->umask;
current_task->umask = cmask;
}
void sys_ioctl(Context* context, int fd, int cmd, uintptr_t arg)
{
int err;
Descriptor* file = Scheduler::current_task()->open_descriptor_from_fd(fd, err);
if (!file)
{
context->rax = -err;
return;
}
kinfoln("ioctl(): fd %d, cmd %d, arg %lu", fd, cmd, arg);
context->rax = file->ioctl(cmd, arg);
}

View File

@ -10,7 +10,7 @@
#include "misc/reboot.h"
#include "misc/utils.h"
#include "panic/Panic.h"
#include "std/ensure.h"
#include "std/assert.h"
#include "std/errno.h"
#include "std/stdlib.h"
#include "std/string.h"
@ -25,7 +25,7 @@ static uint64_t task_num = 0;
static Task idle_task;
static uint64_t free_pid = 0;
static uint64_t free_tid = 0;
static Task* sched_current_task;
static Task* base_task;
@ -72,7 +72,7 @@ void Scheduler::append_task(Task* task)
{
if (!base_task)
{
ensure(!end_task);
ASSERT(!end_task);
base_task = task;
end_task = base_task;
task->next_task = task;
@ -91,7 +91,7 @@ void Scheduler::append_task(Task* task)
void Scheduler::init()
{
memset(&idle_task, 0, sizeof(Task));
idle_task.id = free_pid++;
idle_task.id = free_tid++;
idle_task.regs.rip = (uint64_t)idle_task_function;
idle_task.regs.rsp = get_top_of_stack((uint64_t)MemoryManager::get_page(), 1);
idle_task.regs.cs = 0x08;
@ -99,7 +99,6 @@ void Scheduler::init()
idle_task.regs.rflags = (1 << 21) | (1 << 9);
idle_task.task_sleep = 1000;
idle_task.user_task = false;
idle_task.block_reason = BlockReason::None;
idle_task.state = idle_task.Idle;
strlcpy(idle_task.name, "[cpu-idle]", sizeof(idle_task.name));
@ -112,11 +111,10 @@ void Scheduler::init()
void Scheduler::add_kernel_task(const char* taskname, void (*task)(void))
{
Task* new_task = new Task;
ensure(new_task);
ASSERT(new_task);
new_task->user_task = false;
new_task->id = free_pid++;
new_task->id = free_tid++;
new_task->ppid = 0;
new_task->uid = new_task->euid = new_task->gid = new_task->egid = 0;
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?
@ -130,7 +128,6 @@ void Scheduler::add_kernel_task(const char* taskname, void (*task)(void))
new_task->cpu_time = 0;
strlcpy(new_task->name, taskname, sizeof(new_task->name));
append_task(new_task);
new_task->block_reason = BlockReason::None;
new_task->state = new_task->Running;
task_num++;
kinfoln("Adding kernel task: %s, starts at %lx, PID %ld, stack at %lx, total tasks: %ld", new_task->name,
@ -143,12 +140,11 @@ Task* Scheduler::create_user_task()
if (!new_task) return nullptr;
memset(&new_task->regs, 0, sizeof(Context));
new_task->user_task = true;
new_task->id = free_pid++;
new_task->id = free_tid++;
new_task->ppid = 0;
new_task->task_sleep = 0;
new_task->task_time = 0;
new_task->cpu_time = 0;
new_task->block_reason = BlockReason::None;
append_task(new_task);
task_num++;
return new_task;
@ -158,51 +154,42 @@ long Scheduler::load_user_task(const char* filename)
{
kinfoln("Loading user task: %s", filename);
Interrupts::push_and_disable();
long result;
if ((result = ELFLoader::check_elf_image_from_filesystem(filename)) < 0)
{
kerrorln("Failed to load %s from initrd", filename);
Interrupts::pop();
return result;
}
if ((uint64_t)result > PMM::get_free()) { return -ENOMEM; }
Task* new_task = new Task;
ensure(new_task);
ASSERT(new_task);
memset(&new_task->regs, 0, sizeof(Context));
new_task->id = free_pid++;
new_task->id = free_tid++;
new_task->ppid = 0;
new_task->uid = new_task->euid = new_task->gid = new_task->egid = 0;
if (!new_task->allocator.init())
{
delete new_task;
free_pid--;
free_tid--;
Interrupts::pop();
return -ENOMEM;
}
new_task->address_space = AddressSpace::create();
VMM::switch_to_user_address_space(new_task->address_space);
long result;
if ((result = ELFLoader::check_elf_image_from_filesystem(filename)) < 0)
{
delete new_task;
free_pid--;
kerrorln("Failed to load %s from initrd", filename);
Interrupts::pop();
return result;
}
if ((uint64_t)result > PMM::get_free())
{
delete new_task;
free_pid--;
kerrorln("Not enough memory for task %s", filename);
Interrupts::pop();
return -ENOMEM;
}
ELFImage* image = ELFLoader::load_elf_from_filesystem(filename);
ensure(image);
ELFImage* image = ELFLoader::load_elf_from_filesystem(
filename); // FIXME: TOCTOU? Right now, impossible, since interrupts are disabled and SMP is not a thing. But in
// the future, it might be possible.
ASSERT(image);
new_task->user_task = true;
new_task->regs.rip = image->entry;
new_task->image = image;
new_task->allocated_stack = (uint64_t)MemoryManager::get_pages_at(
0x100000, TASK_PAGES_IN_STACK,
MAP_READ_WRITE | MAP_USER | MAP_AS_OWNED_BY_TASK); // 16 KB is enough for everyone, right?
0x100000, TASK_PAGES_IN_STACK, MAP_READ_WRITE | MAP_USER); // 16 KB is enough for everyone, right?
if (!new_task->allocated_stack)
{
new_task->address_space.destroy();
delete new_task;
free_pid--;
free_tid--;
ELFLoader::release_elf_image(image);
VMM::switch_back_to_kernel_address_space();
Interrupts::pop();
@ -218,7 +205,6 @@ long Scheduler::load_user_task(const char* filename)
new_task->cpu_time = 0;
strlcpy(new_task->name, filename, sizeof(new_task->name));
append_task(new_task);
new_task->block_reason = BlockReason::None;
new_task->state = new_task->Running;
task_num++;
kinfoln("Adding user task: %s, loaded at %lx, PID %ld, stack at %lx, total tasks: %ld", new_task->name,
@ -241,17 +227,16 @@ void Scheduler::reset_task(Task* task, ELFImage* new_image)
task->regs.rflags = (1 << 21) | (1 << 9); // enable interrupts
task->task_sleep = 0;
task->cpu_time = 0;
task->block_reason = BlockReason::None;
kinfoln("Resetting task: %s, loaded at %lx, PID %ld, stack at %lx, total tasks: %ld", task->name, task->regs.rip,
task->id, task->regs.rsp, task_num);
}
void Scheduler::reap_task(Task* task)
{
ensure(!Interrupts::is_in_handler());
ASSERT(!Interrupts::is_in_handler());
task_num--;
Task* exiting_task = task;
ensure(task->id != 0); // WHY IN THE WORLD WOULD WE BE REAPING THE IDLE TASK?
ASSERT(task->id != 0); // WHY IN THE WORLD WOULD WE BE REAPING THE IDLE TASK?
if (exiting_task->is_user_task())
{
VMM::switch_back_to_kernel_address_space();
@ -260,10 +245,13 @@ void Scheduler::reap_task(Task* task)
}
kinfoln("reaping task %s, PID %ld, exited with code %ld", exiting_task->name, exiting_task->id,
exiting_task->exit_status);
if (exiting_task->id == (free_pid - 1)) free_pid--; // If we are the last spawned thread, free our PID.
if (exiting_task->allocated_stack && !exiting_task->is_user_task())
MemoryManager::release_pages((void*)exiting_task->allocated_stack, TASK_PAGES_IN_STACK);
if (exiting_task->image) kfree(exiting_task->image);
if (exiting_task->image) // FIXME: Also free pages the task has mmap-ed but not munmap-ed.
{
// ELFLoader::release_elf_image(exiting_task->image);
kfree(exiting_task->image);
}
if (exiting_task->is_user_task())
{
exiting_task->allocator.free();
@ -274,6 +262,7 @@ void Scheduler::reap_task(Task* task)
Interrupts::pop();
}
for (int i = 0; i < TASK_MAX_FDS; i++) { exiting_task->files[i].close(); }
if (exiting_task->id == (free_tid - 1)) free_tid--; // If we are the last spawned thread, free our PID.
delete exiting_task;
}
@ -292,7 +281,6 @@ void sched_common_exit(Context* context, int64_t status)
}
else
{
kinfoln("PID 1 exited with code %ld", status);
#ifndef RUN_TEST_AS_INIT
reboot();
#else
@ -304,7 +292,7 @@ void sched_common_exit(Context* context, int64_t status)
void Scheduler::task_exit(Context* context, int64_t status)
{
ensure(Interrupts::is_in_handler());
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_common_exit(context, status);
@ -312,7 +300,7 @@ void Scheduler::task_exit(Context* context, int64_t status)
void Scheduler::task_misbehave(Context* context, int64_t status)
{
ensure(Interrupts::is_in_handler());
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_common_exit(context, status);
}
@ -320,7 +308,7 @@ void Scheduler::task_misbehave(Context* context, int64_t status)
void Scheduler::reap_tasks()
{
Interrupts::disable();
ensure(!Interrupts::is_in_handler());
ASSERT(!Interrupts::is_in_handler());
Task* reap_base = nullptr;
Task* reap_end = nullptr;
Task* task = base_task;
@ -383,7 +371,7 @@ static void sched_decrement_sleep_times()
void Scheduler::task_tick(Context* context)
{
ensure(Interrupts::is_in_handler());
ASSERT(Interrupts::is_in_handler());
Interrupts::disable();
sched_decrement_sleep_times();
sched_current_task->task_time -= frequency;
@ -399,7 +387,7 @@ void Scheduler::task_tick(Context* context)
void Scheduler::task_yield(Context* context)
{
ensure(Interrupts::is_in_handler());
ASSERT(Interrupts::is_in_handler());
Interrupts::disable();
sched_current_task->save_context(context);
bool was_idle = false;
@ -413,7 +401,11 @@ void Scheduler::task_yield(Context* context)
sched_current_task = sched_current_task->next_task;
if (sched_current_task->state == sched_current_task->Blocking)
{
if (!sched_current_task->is_still_blocking()) sched_current_task->resume();
if (!sched_current_task->is_still_blocking())
{
sched_current_task->resume_read();
sched_current_task->state = sched_current_task->Running;
}
}
if (sched_current_task->state == sched_current_task->Running)
{
@ -469,10 +461,8 @@ Task* Scheduler::current_task()
return sched_current_task;
}
#define WNOHANG 1
void sys_waitpid(Context* context, long pid, int* wstatus,
int options) // FIXME: only allow waiting for child processes when specifying a PID.
int) // FIXME: Use the value in options and block if WNOHANG has not been specified.
{
Task* child = nullptr;
if (pid == -1)
@ -487,17 +477,8 @@ void sys_waitpid(Context* context, long pid, int* wstatus,
});
if (!child)
{
if (options & WNOHANG)
{
context->rax = 0; // No child has exited, let's return 0.
return;
}
kdbgln("blocking wait on any child");
sched_current_task->state = sched_current_task->Blocking;
sched_current_task->block_reason = BlockReason::Waiting;
sched_current_task->blocking_wait_info.pid = -1;
sched_current_task->blocking_wait_info.wstatus = wstatus;
return Scheduler::task_yield(context);
context->rax = 0; // No child has exited, let's return 0.
return;
}
}
else
@ -505,84 +486,33 @@ void sys_waitpid(Context* context, long pid, int* wstatus,
child = Scheduler::find_by_pid(pid);
if (!child)
{
context->rax = -ECHILD;
context->rax = -ESRCH;
return;
}
}
if (child->ppid != sched_current_task->id)
if (child->state != child->Dying) // FIXME: This should block if WNOHANG has not been specified.
{
// We are trying to call waitpid() on a task that isn't a child of ours. This is not allowed.
context->rax = -ECHILD;
context->rax = 0;
return;
}
if (child->state != child->Dying)
if (wstatus)
{
if (options & WNOHANG)
int* kwstatus = obtain_user_ref(wstatus);
if (kwstatus)
{
context->rax = 0; // No child has exited, let's return 0.
*kwstatus = (int)(child->exit_status & 0xff);
release_user_ref(kwstatus);
}
else
{
kinfoln("wstatus ptr is invalid: %p", (void*)wstatus);
child->state = child->Exited;
context->rax = -EFAULT;
return;
}
sched_current_task->state = sched_current_task->Blocking;
sched_current_task->block_reason = BlockReason::Waiting;
sched_current_task->blocking_wait_info.pid = pid;
sched_current_task->blocking_wait_info.wstatus = wstatus;
return Scheduler::task_yield(context);
}
child->state = child->Exited;
context->rax = (long)child->id;
if (wstatus)
{
int status = (int)(child->exit_status & 0xff);
if (!copy_to_user(wstatus, &status, sizeof(int))) context->rax = -EFAULT;
}
}
bool Task::is_wait_still_blocking()
{
Task* child = nullptr;
if (blocking_wait_info.pid == -1)
{
sched_for_each_child(sched_current_task, [&](Task* task) {
if (task->state == task->Dying)
{
child = task;
return false;
}
return true;
});
if (!child) return true;
else
{
blocking_wait_info.pid = child->id; // We're committed to this child now.
return false;
}
}
else
{
child = Scheduler::find_by_pid(blocking_wait_info.pid);
ensure(child); // since sys_waitpid should have validated this child, and the only way for it to disappear from
// the process list is for someone to wait for it, this should be pretty safe.
if (child->state != child->Dying) return true;
else
return false;
}
}
void Task::resume_wait()
{
ensure(blocking_wait_info.pid != -1); // is_wait_still_blocking should have chosen a child for us if the user
// process told us to wait for any child.
Task* child = Scheduler::find_by_pid(blocking_wait_info.pid);
ensure(child); // This should also already have been validated.
child->state = child->Exited;
regs.rax = (long)child->id;
if (blocking_wait_info.wstatus)
{
int wstatus = (int)(child->exit_status & 0xff);
if (!copy_to_user(blocking_wait_info.wstatus, &wstatus, sizeof(int))) regs.rax = -EFAULT;
}
}
struct pstat
@ -592,14 +522,12 @@ struct pstat
char pt_name[128];
int pt_state;
long pt_time;
uid_t pt_uid;
gid_t pt_gid;
};
void sys_pstat(Context* context, long pid, struct pstat* buf)
{
Task* task;
if (pid == -1) task = Scheduler::find_by_pid(free_pid - 1);
if (pid == -1) task = Scheduler::find_by_pid(free_tid - 1);
else if (pid == 0)
task = &idle_task;
else
@ -614,17 +542,21 @@ void sys_pstat(Context* context, long pid, struct pstat* buf)
context->rax = -ESRCH;
return;
}
context->rax = task->id;
if (buf)
{
struct pstat stat;
stat.pt_pid = task->id;
stat.pt_ppid = task->ppid;
stat.pt_state = (int)task->state;
stat.pt_time = (long)task->cpu_time;
stat.pt_uid = task->uid;
stat.pt_gid = task->gid;
strlcpy(stat.pt_name, task->name, sizeof(stat.pt_name));
if (!copy_to_user(buf, &stat, sizeof(struct pstat))) context->rax = -EFAULT;
struct pstat* kpstat = obtain_user_ref(buf);
if (!kpstat)
{
context->rax = -EFAULT;
return;
}
kpstat->pt_pid = task->id;
kpstat->pt_ppid = task->ppid;
kpstat->pt_state = (int)task->state;
kpstat->pt_time = (long)task->cpu_time;
strlcpy(kpstat->pt_name, task->name, sizeof(kpstat->pt_name));
release_user_ref(kpstat);
}
context->rax = task->id;
return;
}

View File

@ -3,8 +3,6 @@
#include "thread/Task.h"
#include "log/Log.h"
#include "memory/VMM.h"
#include "std/ensure.h"
#include "std/errno.h"
#include "std/string.h"
void Task::restore_context(Context* context)
@ -73,68 +71,15 @@ bool Task::has_died()
}
void Task::resume_read()
{
regs.rax = files[blocking_read_info.fd].user_read(blocking_read_info.size, blocking_read_info.buf);
}
bool Task::is_read_still_blocking()
{
return VFS::would_block(files[blocking_read_info.fd].node());
}
void Task::resume()
{
VMM::switch_back_to_kernel_address_space();
VMM::apply_address_space();
VMM::switch_to_user_address_space(address_space);
switch (block_reason)
{
case BlockReason::None: return;
case BlockReason::Reading: resume_read(); break;
case BlockReason::Waiting: resume_wait(); break;
default: ensure(false);
}
VMM::switch_to_previous_user_address_space();
regs.rax = files[blocking_read_info.fd].read(blocking_read_info.size, blocking_read_info.buf);
VMM::apply_address_space();
block_reason = BlockReason::None;
state = Running;
}
bool Task::is_still_blocking()
{
switch (block_reason)
{
case BlockReason::None: return true;
case BlockReason::Reading: return is_read_still_blocking();
case BlockReason::Waiting: return is_wait_still_blocking();
default: return true;
}
}
Descriptor* Task::open_descriptor_from_fd(int fd, int& error)
{
Descriptor* file = descriptor_from_fd(fd, error);
if (!file) return nullptr;
if (!file->is_open())
{
error = EBADF;
return nullptr;
}
return file;
}
Descriptor* Task::descriptor_from_fd(int fd, int& error)
{
if (fd < 0 || fd >= TASK_MAX_FDS)
{
error = EBADF;
return nullptr;
}
return &files[fd];
}
bool Task::is_superuser()
{
return euid == 0;
return VFS::would_block(files[blocking_read_info.fd].node());
}

View File

@ -1,5 +1,5 @@
#include "trace/Resolve.h"
#include "fs/InitRD.h"
#include "init/InitRD.h"
#include "std/stdlib.h"
#include "std/string.h"
#include <stddef.h>
@ -7,7 +7,7 @@
extern int kernel_start;
extern int kernel_end;
static InitRD::File symbol_map = {"", 0, 0, (void*)-1, 0};
static InitRD::File symbol_map = {"", 0, 0, (void*)-1};
static size_t symbol_strlen(const char* symbol)
{

View File

@ -1,20 +0,0 @@
#define MODULE "mem"
#include "utils/PageFaultReason.h"
#include "log/Log.h"
#define PROGRAM_STACK_BOTTOM 0x100000
void determine_user_page_fault_reason(uintptr_t faulting_address)
{
if (faulting_address < 0x1000)
{
kinfoln("Address 0x%lx looks like a nullptr dereference", faulting_address);
return;
}
if (faulting_address < PROGRAM_STACK_BOTTOM && (PROGRAM_STACK_BOTTOM - faulting_address) < 0x1000)
{
kinfoln("Address 0x%lx looks like a stack overflow", faulting_address);
return;
}
}

View File

@ -1,49 +0,0 @@
#include "utils/StringParsing.h"
int isdigit(int c)
{
return c >= '0' && c < ':';
}
int isodigit(int c)
{
return c >= '0' && c < '8';
}
int isxdigit(int c)
{
return isdigit(c) || ((unsigned int)c | 32) - 'a' < 6;
}
template <typename T, typename ValidDigitChecker, typename Converter>
static T string_to_integer_type(const char* str, int base, ValidDigitChecker checker, Converter converter)
{
bool neg = false;
T val = 0;
switch (*str)
{
case '-':
neg = true;
str++;
break;
case '+': str++; break;
default: break;
}
while (checker(*str)) { val = (base * val) + converter(*str++); }
return (neg ? -val : val);
}
long parse_decimal(const char* str)
{
return string_to_integer_type<long>(
str, 10, [](char c) { return isdigit(c); }, [](char c) { return c - '0'; });
}
long parse_octal(const char* str)
{
return string_to_integer_type<long>(
str, 8, [](char c) { return isodigit(c); }, [](char c) { return c - '0'; });
}

View File

@ -1,42 +0,0 @@
#define MODULE "time"
#include "utils/Time.h"
#include "log/Log.h"
int isleap(int year)
{
return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
}
int make_yday(int year, int month)
{
static const short int upto[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
int yd;
yd = upto[month - 1];
if (month > 2 && isleap(year)) yd++;
return yd;
}
uint64_t broken_down_to_unix(uint64_t year, uint64_t yday, uint64_t hour, uint64_t min, uint64_t sec)
{
return sec + min * 60 + hour * 3600 + yday * 86400 + (year - 70) * 31536000 + ((year - 69) / 4) * 86400 -
((year - 1) / 100) * 86400 + ((year + 299) / 400) * 86400;
}
static int bcd_number_to_decimal(int num)
{
return ((num >> 4) * 10) + (num & 0xf);
}
uint64_t unix_boottime(uint8_t boottime[8])
{
int year = bcd_number_to_decimal(boottime[0]) * 100 + bcd_number_to_decimal(boottime[1]);
int month = bcd_number_to_decimal(boottime[2]);
int day = bcd_number_to_decimal(boottime[3]);
int hour = bcd_number_to_decimal(boottime[4]);
int minute = bcd_number_to_decimal(boottime[5]);
int second = bcd_number_to_decimal(boottime[6]);
kinfoln("UTC boot time: %d-%d-%d %d:%d:%d", year, month, day, hour, minute, second);
return broken_down_to_unix(year - 1900, make_yday(year, month) + (day - 1), hour, minute, second);
}

View File

@ -5,7 +5,7 @@ LIBC_BIN := $(LIBC_DIR)/bin
DESTDIR ?= $(LUNA_BASE)/usr/lib
CFLAGS := -Os -nostdlib -ffunction-sections -fdata-sections -fno-asynchronous-unwind-tables -fno-omit-frame-pointer -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
CFLAGS := -Os -nostdlib -fno-asynchronous-unwind-tables -fno-omit-frame-pointer -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
CXXFLAGS := -fno-rtti -fno-exceptions -Wsign-promo -Wstrict-null-sentinel -Wctor-dtor-privacy
ASMFLAGS := -felf64
@ -21,62 +21,49 @@ OBJS += $(patsubst $(LIBC_SRC)/%.asm, $(LIBC_OBJ)/%.asm.o, $(ASM_SRC))
$(LIBC_OBJ)/%.cpp.o: $(LIBC_SRC)/%.cpp
@mkdir -p $(@D)
@$(CXX) $(CFLAGS) $(CXXFLAGS) -o $@ -c $^
@echo " CXX $^"
$(CXX) $(CFLAGS) $(CXXFLAGS) -o $@ -c $^
$(LIBC_OBJ)/%.c.o: $(LIBC_SRC)/%.c
@mkdir -p $(@D)
@$(CC) $(CFLAGS) -o $@ -c $^
@echo " CC $^"
$(CC) $(CFLAGS) -o $@ -c $^
$(LIBC_OBJ)/%.asm.o: $(LIBC_SRC)/%.asm
@mkdir -p $(@D)
@$(ASM) $(ASMFLAGS) -o $@ $^
@echo " ASM $^"
$(ASM) $(ASMFLAGS) -o $@ $^
$(LIBC_BIN)/libc.a: $(OBJS)
@mkdir -p $(@D)
@$(AR) rcs $@ $(OBJS)
@echo " AR $@"
$(AR) rcs $@ $(OBJS)
$(LIBC_BIN)/crt0.o: $(LIBC_DIR)/crt0.asm
@mkdir -p $(@D)
@$(ASM) $(ASMFLAGS) -o $@ $^
@echo " ASM $^"
$(ASM) $(ASMFLAGS) -o $@ $^
$(LIBC_BIN)/crti.o: $(LIBC_DIR)/crti.asm
@mkdir -p $(@D)
@$(ASM) $(ASMFLAGS) -o $@ $^
@echo " ASM $^"
$(ASM) $(ASMFLAGS) -o $@ $^
$(LIBC_BIN)/crtn.o: $(LIBC_DIR)/crtn.asm
@mkdir -p $(@D)
@$(ASM) $(ASMFLAGS) -o $@ $^
@echo " ASM $^"
$(ASM) $(ASMFLAGS) -o $@ $^
build: $(LIBC_BIN)/crt0.o $(LIBC_BIN)/crti.o $(LIBC_BIN)/crtn.o $(LIBC_BIN)/libc.a
$(DESTDIR)/libc.a: $(LIBC_BIN)/libc.a
@mkdir -p $(@D)
@cp $^ $@
@rm -f $(DESTDIR)/libm.a
@ln -s $@ $(DESTDIR)/libm.a
@echo " INSTALL $^"
cp $^ $@
$(DESTDIR)/crt0.o: $(LIBC_BIN)/crt0.o
@mkdir -p $(@D)
@cp $^ $@
@echo " INSTALL $^"
cp $^ $@
$(DESTDIR)/crti.o: $(LIBC_BIN)/crti.o
@mkdir -p $(@D)
@cp $^ $@
@echo " INSTALL $^"
cp $^ $@
$(DESTDIR)/crtn.o: $(LIBC_BIN)/crtn.o
@mkdir -p $(@D)
@cp $^ $@
@echo " INSTALL $^"
cp $^ $@
install: $(DESTDIR)/libc.a $(DESTDIR)/crt0.o $(DESTDIR)/crti.o $(DESTDIR)/crtn.o

View File

@ -6,6 +6,8 @@ extern _fini
extern initialize_libc
extern exit
extern __argv
global _start
_start:
; Set up end of the stack frame linked list.
@ -14,15 +16,12 @@ _start:
push rbp ; rbp=0
mov rbp, rsp
push rdi
push rsi
call initialize_libc
call _init
pop rsi ; argv
pop rdi ; argc
mov rdi, 0 ; argc = 0
mov rsi, __argv ; Dummy argv which is equal to {NULL}
call main

View File

@ -1,6 +0,0 @@
#ifndef _ALLOCA_H
#define _ALLOCA_H
#define alloca __builtin_alloca
#endif

View File

@ -18,7 +18,7 @@ extern "C"
#ifdef NDEBUG
#define assert(expr) (void)0
#else
#define assert(expr) (bool)(expr) || __assertion_failed(__FILE__, __LINE__, __FUNCTION__, #expr) // Verify a condition.
#define assert(expr) (bool)(expr) || __assertion_failed(__FILE__, __LINE__, __FUNCTION__, #expr)
#endif
#endif

View File

@ -3,9 +3,5 @@
#define ID_PID 0
#define ID_PPID 1
#define ID_UID 2
#define ID_EUID 3
#define ID_GID 4
#define ID_EGID 5
#endif

View File

@ -4,9 +4,7 @@
#define __lc_noreturn __attribute__((noreturn))
#define __lc_align(n) __attribute__((aligned(n)))
#define __lc_deprecated(msg) __attribute__((deprecated(msg)))
#define __lc_is_deprecated __attribute__((deprecated))
#define __lc_unreachable __builtin_unreachable
#define __lc_used __attribute__((used))
#define __lc_unused __attribute__((unused))
#endif

View File

@ -1,8 +1,6 @@
#ifndef _CTYPE_H
#define _CTYPE_H
#include <bits/macros.h>
#ifdef __cplusplus
extern "C"
{
@ -53,10 +51,6 @@ extern "C"
/* Returns the uppercase form of the specified character. */
int toupper(int c);
/* Returns the character c, truncated to fit in the ASCII character set. This function should not be used, as it
* will convert accented letters into random characters. */
__lc_is_deprecated int toascii(int c);
#ifdef __cplusplus
}
#endif

View File

@ -4,7 +4,6 @@
#include <luna/os-limits.h>
#include <sys/types.h>
/* An entry in a directory. */
struct dirent
{
ino_t d_ino;
@ -14,16 +13,6 @@ struct dirent
char d_name[NAME_MAX];
};
#define DT_BLK 1 // This is a block device.
#define DT_CHR 2 // This is a character device.
#define DT_DIR 3 // This is a directory.
#define DT_FIFO 4 // This is a named pipe (FIFO).
#define DT_LNK 5 // This is a symbolic link.
#define DT_REG 6 // This is a regular file.
#define DT_SOCK 7 // This is a UNIX domain socket.
#define DT_UNKNOWN 0 // The file type could not be determined.
/* A stream representing a directory. */
typedef struct
{
int d_dirfd;

View File

@ -4,81 +4,24 @@
/* The last error encountered during a call to a library or system function. */
extern int errno;
#define EPERM 1 // Operation not permitted
#define ENOENT 2 // No such file or directory
#define ESRCH 3 // No such process
#define EINTR 4 // Interrupted system call. Not implemented.
#define EIO 5 // Input/output error. Not implemented.
#define ENXIO 6 // No such device or address. Not implemented.
#define E2BIG 7 // Argument list too long
#define ENOEXEC 8 // Exec format error
#define EBADF 9 // Bad file descriptor
#define ECHILD 10 // No child processes
#define EAGAIN 11 // Resource temporarily unavailable
#define EWOULDBLOCK 11 // Resource temporarily unavailable
#define ENOMEM 12 // Cannot allocate memory
#define EACCES 13 // Permission denied
#define EFAULT 14 // Bad address
#define EBUSY 16 // Device or resource busy. Not implemented.
#define EEXIST 17 // File exists
#define EXDEV 18 // Invalid cross-device link. Not implemented.
#define ENODEV 19 // No such device. Not implemented.
#define ENOTDIR 20 // Not a directory
#define EISDIR 21 // Is a directory
#define EINVAL 22 // Invalid argument
#define ENFILE 23 // Too many open files in system. Not implemented.
#define EMFILE 24 // Too many open files
#define ENOTTY 25 // Inappropriate ioctl for device
#define EFBIG 27 // File too large. Not implemented.
#define ENOSPC 28 // No space left on device
#define ESPIPE 29 // Illegal seek. Not implemented.
#define EROFS 30 // Read-only file system. Not implemented.
#define EMLINK 31 // Too many links. Not implemented.
#define EPIPE 32 // Broken pipe. Not implemented.
#define EDOM 33 // Numerical argument out of domain. Not implemented.
#define ERANGE 34 // Numerical result out of range
#define EDEADLK 35 // Resource deadlock avoided. Not implemented.
#define ENAMETOOLONG 36 // File name too long. Not implemented.
#define ENOLCK 37 // No locks available. Not implemented.
#define ENOSYS 38 // Function not implemented
#define ENOTEMPTY 39 // Directory not empty. Not implemented.
#define ELOOP 40 // Too many levels of symbolic links. Not implemented.
#define ENOMSG 42 // No message of desired type. Not implemented.
#define EOVERFLOW 75 // Value too large for defined data type. Not implemented.
#define EILSEQ 84 // Invalid or incomplete multibyte or wide character. Not implemented.
#define ENOTSOCK 88 // Socket operation on non-socket. Not implemented.
#define ENOTSUP 95 // Operation not supported
#define EOPNOTSUPP 95 // Operation not supported
#define EADDRINUSE 98 // Address already in use. Not implemented.
#define ENETRESET 102 // Network dropped connection on reset. Not implemented.
#define ECONNRESET 104 // Connection reset by peer. Not implemented.
#define EISCONN 106 // Transport endpoint is already connected. Not implemented.
#define ETIMEDOUT 110 // Connection timed out. Not implemented.
#define EALREADY 114 // Operation already in progress. Not implemented.
// FIXME: Right now I don't want to have to order and label these, since we have no net support anyways.
#define EADDRNOTAVAIL -1
#define EAFNOSUPPORT -2
#define ECONNABORTED -3
#define ECONNREFUSED -4
#define EDESTADDRREQ -5
#define EHOSTUNREACH -6
#define EINPROGRESS -7
#define EMSGSIZE -8
#define ENETDOWN -9
#define ENETRESET -10
#define ENETUNREACH -11
#define ENOBUFS -12
#define ENOMSG -13
#define ENOPROTOOPT -14
#define ENOTCONN -15
#define ENOTSOCK -16
#define EPROTONOSUPPORT -17
#define EPROTOTYPE -18
#ifdef _GNU_SOURCE // Give it only to programs that ask for it.
/* Name used to invoke calling program. Same value as argv[0] in main(), but can be used globally. */
extern char* program_invocation_name;
#endif
#define EPERM 1 // Operation not permitted
#define ENOENT 2 // No such file or directory
#define ESRCH 3 // No such process
#define EINTR 4 // Interrupted system call. Not implemented.
#define ENOEXEC 8 // Exec format error
#define EBADF 9 // Bad file descriptor
#define EAGAIN 11 // Resource temporarily unavailable
#define ENOMEM 12 // Cannot allocate memory
#define EFAULT 14 // Bad address
#define EEXIST 17 // File exists
#define ENOTDIR 20 // Not a directory
#define EISDIR 21 // Is a directory
#define EINVAL 22 // Invalid argument
#define EMFILE 24 // Too many open files
#define ENOTTY 25 // Inappropriate ioctl for device
#define ENOSPC 28 // No space left on device
#define EPIPE 32 // Broken pipe. Not implemented.
#define ENOSYS 38 // Function not implemented
#define ENOTSUP 95 // Operation not supported
#endif

View File

@ -13,26 +13,11 @@
#define O_CLOEXEC 8
/* Refuse to open the file if it is not a directory. */
#define O_DIRECTORY 16
/* Truncate the file on open. */
#define O_TRUNC 32
/* Create the file if it doesn't exist. */
#define O_CREAT 64
/* Open the file for appending. */
#define O_APPEND 128
/* Fail to open the file if it already exists. */
#define O_EXCL 256
/* Duplicate a file descriptor. */
#define F_DUPFD 0
/* Is a file descriptor a TTY? */
#define F_ISTTY 1
/* Get the file descriptor flags. */
#define F_GETFD 2
/* Set the file descriptor flags. */
#define F_SETFD 3
/* Close the file descriptor on a call to execve(). */
#define FD_CLOEXEC 1
#ifdef __cplusplus
extern "C"
@ -40,7 +25,7 @@ extern "C"
#endif
/* Opens the file specified by pathname. Returns a file descriptor on success, or -1 on error. */
int open(const char* pathname, int flags, ...);
int open(const char* pathname, int flags);
/* Performs an operation on the file descriptor fd determined by cmd. */
int fcntl(int fd, int cmd, ...);

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