Compare commits
No commits in common. "da41784183fe38f7ac07cf1d09ddf1a1da5c5194" and "185757e2a7dcce05f14d65efab4da41e7e8b3199" have entirely different histories.
da41784183
...
185757e2a7
.gitignoreMakefileREADME.md
apps
Makefile
src
initrd
kernel
Makefilemoon.ld
include
cpu
fs
init
memory
std
sys
thread
utils
src
cpu
fs
gdt
init
interrupts
main.cppmemory
misc
panic
rand
render
std
sys
thread
trace
utils
libs/libc
7
.gitignore
vendored
7
.gitignore
vendored
@ -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
|
||||
|
24
Makefile
24
Makefile
@ -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
|
32
README.md
32
README.md
@ -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!
|
||||
|
||||
|
@ -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)/*
|
@ -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]);
|
||||
}
|
@ -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
5
apps/src/crash.c
Normal file
@ -0,0 +1,5 @@
|
||||
int main()
|
||||
{
|
||||
int* ptr = (int*)0xdeadbeef;
|
||||
*ptr = 6;
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
time_t date = time(NULL);
|
||||
|
||||
fputs(ctime(&date), stdout);
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
#include <cstdio>
|
||||
|
||||
int main()
|
||||
{
|
||||
printf("Well hello world!\n");
|
||||
}
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
261
apps/src/sh.c
261
apps/src/sh.c
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -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
36
apps/src/sym.c
Normal 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;
|
||||
}
|
@ -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);
|
||||
}
|
@ -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!
|
@ -1,2 +0,0 @@
|
||||
root:secure:0:0:Administrator:/:/bin/sh
|
||||
selene:moon:1:1:Default User:/:/bin/sh
|
@ -1,3 +1,3 @@
|
||||
screen=1024x768
|
||||
kernel=boot/moon
|
||||
kernel=boot/moon.elf
|
||||
verbose=1
|
@ -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:
|
@ -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();
|
||||
}
|
@ -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();
|
||||
|
||||
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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();
|
@ -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);
|
||||
}
|
@ -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);
|
@ -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);
|
||||
|
6
kernel/include/std/assert.h
Normal file
6
kernel/include/std/assert.h
Normal 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)
|
@ -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
|
@ -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
|
@ -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);
|
@ -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.
|
||||
|
@ -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();
|
||||
};
|
@ -1,4 +0,0 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
void determine_user_page_fault_reason(uintptr_t faulting_address);
|
@ -1,4 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
long parse_decimal(const char* str);
|
||||
long parse_octal(const char* str);
|
@ -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]);
|
@ -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) }
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
24
kernel/src/fs/devices/Uptime.cpp
Normal file
24
kernel/src/fs/devices/Uptime.cpp
Normal 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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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));
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
@ -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)
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -8,7 +8,7 @@
|
||||
#endif
|
||||
|
||||
#ifndef MOON_MINOR
|
||||
#define MOON_MINOR 14
|
||||
#define MOON_MINOR 13
|
||||
#endif
|
||||
|
||||
#ifndef _MOON_SUFFIX
|
||||
|
@ -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
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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
27
kernel/src/sys/paint.cpp
Normal 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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
@ -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());
|
||||
}
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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'; });
|
||||
}
|
@ -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);
|
||||
}
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -1,6 +0,0 @@
|
||||
#ifndef _ALLOCA_H
|
||||
#define _ALLOCA_H
|
||||
|
||||
#define alloca __builtin_alloca
|
||||
|
||||
#endif
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
@ -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
Loading…
x
Reference in New Issue
Block a user