Compare commits
No commits in common. "da41784183fe38f7ac07cf1d09ddf1a1da5c5194" and "185757e2a7dcce05f14d65efab4da41e7e8b3199" have entirely different histories.
da41784183
...
185757e2a7
7
.gitignore
vendored
7
.gitignore
vendored
@ -2,13 +2,14 @@ Luna.iso
|
|||||||
toolchain/
|
toolchain/
|
||||||
.vscode/
|
.vscode/
|
||||||
**/*.o
|
**/*.o
|
||||||
initrd/boot/moon
|
initrd/boot/moon.elf
|
||||||
kernel/bin/moon
|
kernel/bin/moon.elf
|
||||||
initrd/sys/moon.sym
|
initrd/sys/moon.sym
|
||||||
initrd/bin/**
|
initrd/bin/**
|
||||||
apps/bin/**
|
apps/bin/**
|
||||||
tests/**/bin/**
|
tests/**/bin/**
|
||||||
base/usr/**
|
base/usr/include/**
|
||||||
|
base/usr/lib/**
|
||||||
**/*.a
|
**/*.a
|
||||||
ports/**/workdir/**
|
ports/**/workdir/**
|
||||||
ports/ports.list
|
ports/ports.list
|
||||||
|
24
Makefile
24
Makefile
@ -5,22 +5,22 @@ AR := x86_64-luna-ar
|
|||||||
LD := x86_64-luna-ld
|
LD := x86_64-luna-ld
|
||||||
|
|
||||||
build:
|
build:
|
||||||
+@tools/sync-libc.sh
|
tools/sync-libc.sh
|
||||||
+@tools/buildstep.sh kernel build
|
@$(MAKE) -C kernel build
|
||||||
+@tools/buildstep.sh libs build
|
@$(MAKE) -C libs build
|
||||||
+@tools/buildstep.sh apps build
|
@$(MAKE) -C apps build
|
||||||
|
|
||||||
clean: initrd-clean
|
clean: initrd-clean
|
||||||
+@tools/buildstep.sh kernel clean
|
@$(MAKE) -C kernel clean
|
||||||
+@tools/buildstep.sh libs clean
|
@$(MAKE) -C libs clean
|
||||||
+@tools/buildstep.sh apps clean
|
@$(MAKE) -C apps clean
|
||||||
|
|
||||||
initrd-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
|
rm -rf $(LUNA_ROOT)/initrd/bin
|
||||||
|
|
||||||
install:
|
install:
|
||||||
+@tools/buildstep.sh kernel install
|
@$(MAKE) -C kernel install
|
||||||
+@tools/buildstep.sh libs install
|
@$(MAKE) -C libs install
|
||||||
+@tools/buildstep.sh apps install
|
@$(MAKE) -C apps install
|
||||||
+@tools/install-built-ports.sh
|
@tools/install-built-ports.sh
|
32
README.md
32
README.md
@ -1,20 +1,16 @@
|
|||||||
# Luna
|
# 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
|
## Features
|
||||||
- x86_64-compatible [kernel](kernel/).
|
- 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).
|
- 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.
|
- Can load 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.
|
- Basic preemptive multitasking, 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.
|
- Can [load userspace ELF programs](kernel/src/sys/elf/) from the file system as user tasks.
|
||||||
- [System call](kernel/src/sys/) interface and [C Library](libs/libc/), aiming to be mostly POSIX-compatible.
|
- [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.
|
- 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.
|
- Very simple [command-line shell](apps/src/sh.c), allowing interactive use of the system.
|
||||||
- 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'.
|
|
||||||
|
|
||||||
## Setup
|
## 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)).
|
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)
|
`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.
|
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 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.
|
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?
|
## Is there third-party software I can use on Luna?
|
||||||
|
|
||||||
Yes, actually! Check out the [ports](ports/) directory.
|
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!
|
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
|
APPS := init sym sh crash uname uptime hello ps ls
|
||||||
CXX_APPS := hello-cpp
|
|
||||||
|
|
||||||
APPS_DIR := $(LUNA_ROOT)/apps
|
APPS_DIR := $(LUNA_ROOT)/apps
|
||||||
APPS_SRC := $(APPS_DIR)/src
|
APPS_SRC := $(APPS_DIR)/src
|
||||||
APPS_BIN := $(APPS_DIR)/bin
|
APPS_BIN := $(APPS_DIR)/bin
|
||||||
|
|
||||||
C_APPS_PATH := $(patsubst %, $(APPS_BIN)/%, $(C_APPS))
|
REAL_APPS := $(patsubst %, $(APPS_BIN)/%, $(APPS))
|
||||||
CXX_APPS_PATH := $(patsubst %, $(APPS_BIN)/%, $(CXX_APPS))
|
|
||||||
|
|
||||||
CFLAGS := -Wall -Wextra -Werror -Os -fno-asynchronous-unwind-tables -ffunction-sections -fdata-sections -Wl,--gc-sections
|
CFLAGS := -Wall -Wextra -Werror -Os -fno-asynchronous-unwind-tables
|
||||||
CXXFLAGS := -fno-exceptions
|
|
||||||
|
|
||||||
$(APPS_BIN)/%: $(APPS_SRC)/%.c
|
$(APPS_BIN)/%: $(APPS_SRC)/%.c
|
||||||
@mkdir -p $(@D)
|
@mkdir -p $(@D)
|
||||||
@$(CC) $(CFLAGS) -o $@ $^
|
$(CC) $(CFLAGS) -o $@ $^
|
||||||
@echo " CC $^"
|
|
||||||
|
|
||||||
$(APPS_BIN)/%: $(APPS_SRC)/%.cpp
|
build: $(REAL_APPS)
|
||||||
@mkdir -p $(@D)
|
|
||||||
@$(CXX) $(CFLAGS) $(CXXFLAGS) -o $@ $^
|
|
||||||
@echo " CXX $^"
|
|
||||||
|
|
||||||
build: $(C_APPS_PATH) $(CXX_APPS_PATH)
|
install: $(REAL_APPS)
|
||||||
|
|
||||||
install: $(C_APPS_PATH) $(CXX_APPS_PATH)
|
|
||||||
@mkdir -p $(LUNA_ROOT)/initrd/bin
|
@mkdir -p $(LUNA_ROOT)/initrd/bin
|
||||||
@cp $(C_APPS_PATH) $(CXX_APPS_PATH) $(LUNA_ROOT)/initrd/bin
|
cp $(REAL_APPS) $(LUNA_ROOT)/initrd/bin
|
||||||
@echo " INSTALL $(C_APPS_PATH) $(CXX_APPS_PATH)"
|
|
||||||
@chmod a+s $(LUNA_ROOT)/initrd/bin/su
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(APPS_BIN)/*
|
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 <errno.h>
|
||||||
#include <fcntl.h>
|
|
||||||
#include <luna.h>
|
#include <luna.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
@ -7,21 +6,15 @@
|
|||||||
|
|
||||||
void show_motd()
|
void show_motd()
|
||||||
{
|
{
|
||||||
int fd = open("/etc/motd", O_RDONLY | O_CLOEXEC);
|
FILE* fp = fopen("/etc/motd", "r");
|
||||||
if (fd < 0)
|
|
||||||
{
|
|
||||||
if (errno != ENOENT) { perror("open"); }
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
FILE* fp = fdopen(fd, "r");
|
|
||||||
if (!fp)
|
if (!fp)
|
||||||
{
|
{
|
||||||
perror("fopen");
|
if (errno != ENOENT) { perror("fopen"); }
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
char buf[4096];
|
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))
|
if (ferror(fp))
|
||||||
{
|
{
|
||||||
perror("fread");
|
perror("fread");
|
||||||
@ -41,18 +34,14 @@ int main()
|
|||||||
{
|
{
|
||||||
if (getpid() != 1)
|
if (getpid() != 1)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "init must be started as PID 1\n");
|
fprintf(stderr, "init should be started as PID 1\n");
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getuid() != 0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "init must be started as root\n");
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
show_motd();
|
show_motd();
|
||||||
|
|
||||||
|
msleep(200);
|
||||||
|
|
||||||
pid_t child = fork();
|
pid_t child = fork();
|
||||||
if (child < 0)
|
if (child < 0)
|
||||||
{
|
{
|
||||||
@ -61,8 +50,7 @@ int main()
|
|||||||
}
|
}
|
||||||
if (child == 0)
|
if (child == 0)
|
||||||
{
|
{
|
||||||
char* argv[] = {"/bin/session", NULL};
|
execv("/bin/sh", NULL);
|
||||||
execv(argv[0], argv);
|
|
||||||
perror("execv");
|
perror("execv");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -71,7 +59,10 @@ int main()
|
|||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
result = wait(NULL);
|
while ((result = wait(NULL)) == 0) // No child has exited yet
|
||||||
if (result == child) return 0;
|
{
|
||||||
|
msleep(100);
|
||||||
|
}
|
||||||
|
if (result == child) { return 0; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,31 +1,22 @@
|
|||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main()
|
||||||
{
|
{
|
||||||
const char* pathname;
|
DIR* dp = opendir("/bin");
|
||||||
if (argc == 1) pathname = "/";
|
|
||||||
else
|
|
||||||
pathname = argv[1];
|
|
||||||
DIR* dp = opendir(pathname);
|
|
||||||
if (!dp)
|
if (!dp)
|
||||||
{
|
{
|
||||||
perror("opendir");
|
perror("opendir");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
bool first_ent = true;
|
|
||||||
do {
|
do {
|
||||||
struct dirent* ent = readdir(dp);
|
struct dirent* ent = readdir(dp);
|
||||||
if (!ent) break;
|
if (!ent) break;
|
||||||
printf(first_ent ? "%s" : " %s", ent->d_name);
|
printf("%s\n", ent->d_name);
|
||||||
first_ent = false;
|
|
||||||
} while (1);
|
} while (1);
|
||||||
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
closedir(dp);
|
closedir(dp);
|
||||||
return 0;
|
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 <errno.h>
|
||||||
#include <luna/pstat.h>
|
#include <luna/pstat.h>
|
||||||
#include <pwd.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -18,10 +17,8 @@ pid_t get_current_max_threads()
|
|||||||
|
|
||||||
void display_process(struct pstat* pstatbuf)
|
void display_process(struct pstat* pstatbuf)
|
||||||
{
|
{
|
||||||
struct passwd* pwd = getpwuid(pstatbuf->pt_uid);
|
printf("%ld %ld %s %s (%ld ms)\n", pstatbuf->pt_pid, pstatbuf->pt_ppid, pstatbuf->pt_name, pstatname(pstatbuf),
|
||||||
if (!pwd && errno) perror("getpwuid");
|
pstatbuf->pt_time);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int try_pstat(pid_t pid, struct pstat* pstatbuf)
|
int try_pstat(pid_t pid, struct pstat* pstatbuf)
|
||||||
@ -44,5 +41,4 @@ int main()
|
|||||||
{
|
{
|
||||||
if (try_pstat(pid, &pst)) { display_process(&pst); }
|
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 <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <luna.h>
|
#include <luna.h>
|
||||||
#include <pwd.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -9,89 +8,29 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
static int status = 0;
|
static int status = 0;
|
||||||
static char* username = NULL;
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
char* buffer;
|
char* buffer;
|
||||||
size_t size;
|
size_t size;
|
||||||
size_t capacity;
|
size_t capacity;
|
||||||
int interactive;
|
} command;
|
||||||
} 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
void show_prompt()
|
void show_prompt()
|
||||||
{
|
{
|
||||||
if (WEXITSTATUS(status)) { printf("%d [%s]> ", WEXITSTATUS(status), username); }
|
if (WEXITSTATUS(status)) { printf("%d [%ld]> ", WEXITSTATUS(status), getpid()); }
|
||||||
else
|
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
|
if (cmd->size <= strlen(string)) // cmd->size includes null terminator
|
||||||
return 0;
|
return 0;
|
||||||
return strncmp(cmd->buffer, string, strlen(string)) == 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
|
if (cmd->size <= strlen(string)) // cmd->size includes null terminator
|
||||||
return 0;
|
return 0;
|
||||||
@ -99,24 +38,19 @@ int command_matches_exactly(command_t* cmd, const char* string)
|
|||||||
return strncmp(cmd->buffer, string, strlen(string)) == 0;
|
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(cmd, "exit ")) { exit(atoi(cmd->buffer + 5)); }
|
||||||
if (command_matches_exactly(cmd, "exit")) { exit(0); }
|
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());
|
printf("pid %ld, ppid %ld\n", getpid(), getppid());
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (command_matches_exactly(cmd, "clear"))
|
|
||||||
{
|
|
||||||
fputs("\033@", stdout); // clear screen. for now, escape sequences in luna are non-standard.
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
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);
|
char* buffer = realloc(cmd->buffer, new_capacity);
|
||||||
if (!buffer)
|
if (!buffer)
|
||||||
@ -128,101 +62,105 @@ void command_expand(command_t* cmd, long new_capacity)
|
|||||||
cmd->capacity = 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);
|
if (cmd->size == cmd->capacity) command_expand(cmd, cmd->capacity + 8);
|
||||||
cmd->buffer[cmd->size] = c;
|
cmd->buffer[cmd->size] = c;
|
||||||
cmd->size++;
|
cmd->size++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void command_pop(command_t* cmd)
|
void command_pop(command* cmd)
|
||||||
{
|
{
|
||||||
cmd->size--;
|
cmd->size--;
|
||||||
}
|
}
|
||||||
|
|
||||||
void command_init(command_t* cmd)
|
void command_init(command* cmd)
|
||||||
{
|
{
|
||||||
cmd->buffer = malloc(5);
|
cmd->buffer = malloc(5);
|
||||||
cmd->capacity = 5;
|
cmd->capacity = 5;
|
||||||
cmd->size = 0;
|
cmd->size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void command_clear(command_t* cmd)
|
void command_clear(command* cmd)
|
||||||
{
|
{
|
||||||
free(cmd->buffer);
|
free(cmd->buffer);
|
||||||
return command_init(cmd);
|
return command_init(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void process_execute_command(const char* command)
|
void command_execute(command* cmd)
|
||||||
{
|
|
||||||
char** argv = split_command_into_argv(command);
|
|
||||||
shell_execvp(argv[0], argv);
|
|
||||||
perror(argv[0]);
|
|
||||||
exit(127);
|
|
||||||
}
|
|
||||||
|
|
||||||
void command_execute(command_t* cmd)
|
|
||||||
{
|
{
|
||||||
command_push(cmd, '\0');
|
command_push(cmd, '\0');
|
||||||
if (command_match_builtins(cmd))
|
if (command_match_builtins(cmd))
|
||||||
{
|
{
|
||||||
command_clear(cmd);
|
command_clear(cmd);
|
||||||
if (cmd->interactive) show_prompt();
|
show_prompt();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pid_t child = fork();
|
pid_t child = fork();
|
||||||
if (child < 0)
|
if (child < 0)
|
||||||
{
|
{
|
||||||
perror("fork");
|
perror(cmd->buffer);
|
||||||
command_clear(cmd);
|
command_clear(cmd);
|
||||||
if (cmd->interactive) show_prompt();
|
show_prompt();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (child == 0) process_execute_command(cmd->buffer);
|
if (child == 0)
|
||||||
pid_t result = waitpid(child, &status, 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)
|
if (result < 0)
|
||||||
{
|
{
|
||||||
perror("waitpid");
|
perror("waitpid");
|
||||||
command_clear(cmd);
|
command_clear(cmd);
|
||||||
if (cmd->interactive) show_prompt();
|
show_prompt();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int exit_status = WEXITSTATUS(status);
|
int exit_status = WEXITSTATUS(status);
|
||||||
if (exit_status == -2 || exit_status == -3) printf("(PID %ld) Segmentation fault\n", result);
|
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);
|
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 (c == '\b')
|
||||||
{
|
{
|
||||||
if (cmd->size != 0)
|
if (cmd->size != 0)
|
||||||
{
|
{
|
||||||
if (cmd->interactive) putchar(c);
|
putchar(c);
|
||||||
command_pop(cmd);
|
command_pop(cmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (c == '\n')
|
else if (c == '\n')
|
||||||
{
|
{
|
||||||
if (cmd->interactive) putchar(c);
|
putchar(c);
|
||||||
if (cmd->size == 0)
|
if (cmd->size == 0) show_prompt();
|
||||||
{
|
|
||||||
status = 0;
|
|
||||||
if (cmd->interactive) show_prompt();
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
command_execute(cmd);
|
command_execute(cmd);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (cmd->interactive) putchar(c);
|
putchar(c);
|
||||||
command_push(cmd, c);
|
command_push(cmd, c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void command_concat(command_t* cmd, const char* str)
|
void command_concat(command* cmd, const char* str)
|
||||||
{
|
{
|
||||||
while (*str)
|
while (*str)
|
||||||
{
|
{
|
||||||
@ -231,15 +169,13 @@ void command_concat(command_t* cmd, const char* str)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void shell_interactive()
|
int main()
|
||||||
{
|
{
|
||||||
show_prompt();
|
show_prompt();
|
||||||
|
|
||||||
command_t shell_command;
|
command shell_command;
|
||||||
command_init(&shell_command);
|
command_init(&shell_command);
|
||||||
|
|
||||||
shell_command.interactive = 1;
|
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
int c = getchar();
|
int c = getchar();
|
||||||
@ -248,112 +184,11 @@ void shell_interactive()
|
|||||||
if (ferror(stdin))
|
if (ferror(stdin))
|
||||||
{
|
{
|
||||||
perror("getchar");
|
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
|
assert(false); // we should never get here
|
||||||
}
|
}
|
||||||
command_concat_char(&shell_command, (char)c);
|
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 <stdio.h>
|
||||||
#include <time.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#define VALUE_SINGULAR_AT_ONE(v) v, v == 1 ? "" : "s"
|
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
struct timespec tp;
|
FILE* fp = fopen("/dev/uptime", "r");
|
||||||
clock_gettime(CLOCK_MONOTONIC, &tp); // On Luna, CLOCK_MONOTONIC starts at boot.
|
if (!fp)
|
||||||
|
{
|
||||||
|
perror("fopen");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
struct tm* time = gmtime(
|
char buf[BUFSIZ];
|
||||||
&tp.tv_sec); // just splitting the value into seconds, minutes, hours, days... not the best way to do it but ok.
|
fgets(buf, sizeof(buf), fp);
|
||||||
time->tm_year -= 70;
|
|
||||||
|
|
||||||
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",
|
perror("fgets");
|
||||||
VALUE_SINGULAR_AT_ONE(time->tm_year), VALUE_SINGULAR_AT_ONE(time->tm_yday),
|
return 1;
|
||||||
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_yday)
|
|
||||||
{
|
long ms_uptime = atol(buf);
|
||||||
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),
|
printf("up for %ld seconds\n", ms_uptime / 1000);
|
||||||
VALUE_SINGULAR_AT_ONE(time->tm_sec));
|
|
||||||
}
|
fclose(fp);
|
||||||
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));
|
|
||||||
}
|
}
|
@ -1,3 +1,3 @@
|
|||||||
Welcome to Luna!
|
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
|
screen=1024x768
|
||||||
kernel=boot/moon
|
kernel=boot/moon.elf
|
||||||
verbose=1
|
verbose=1
|
@ -4,7 +4,7 @@ MOON_OBJ := $(MOON_DIR)/lib
|
|||||||
MOON_BIN := $(MOON_DIR)/bin
|
MOON_BIN := $(MOON_DIR)/bin
|
||||||
|
|
||||||
CFLAGS ?= -Os
|
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
|
CXXFLAGS := -fno-rtti -fno-exceptions -Wsign-promo -Wstrict-null-sentinel -Wctor-dtor-privacy
|
||||||
ASMFLAGS := -felf64
|
ASMFLAGS := -felf64
|
||||||
LDFLAGS := -T$(MOON_DIR)/moon.ld -nostdlib -lgcc -Wl,--build-id=none -z max-page-size=0x1000 -mno-red-zone -mcmodel=kernel
|
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
|
endif
|
||||||
|
|
||||||
ifeq ($(MOON_BUILD_DEBUG), 1)
|
ifeq ($(MOON_BUILD_DEBUG), 1)
|
||||||
CFLAGS := -ggdb -fsanitize=undefined ${CFLAGS}
|
CFLAGS := -ggdb ${CFLAGS}
|
||||||
endif
|
endif
|
||||||
|
|
||||||
rwildcard=$(foreach d,$(wildcard $(1:=/*)),$(call rwildcard,$d,$2) $(filter $(subst *,%,$2),$d))
|
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)/%.c, $(MOON_OBJ)/%.c.o, $(C_SRC))
|
||||||
OBJS += $(patsubst $(MOON_SRC)/%.asm, $(MOON_OBJ)/%.asm.o, $(NASM_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
|
$(MOON_OBJ)/main.cpp.o: $(MOON_SRC)/main.cpp
|
||||||
@mkdir -p $(@D)
|
@mkdir -p $(@D)
|
||||||
@$(CXX) $(CFLAGS) -fno-stack-protector $(CXXFLAGS) -o $@ -c $^
|
$(CXX) $(CFLAGS) -fno-stack-protector $(CXXFLAGS) -o $@ -c $^
|
||||||
@echo " CXX $^"
|
|
||||||
|
|
||||||
$(MOON_OBJ)/misc/config.cpp.o: $(MOON_SRC)/misc/config.cpp FORCE
|
$(MOON_OBJ)/misc/config.cpp.o: $(MOON_SRC)/misc/config.cpp FORCE
|
||||||
@mkdir -p $(@D)
|
@mkdir -p $(@D)
|
||||||
@$(CXX) $(CFLAGS) $(CXXFLAGS) -o $@ -c $(MOON_SRC)/misc/config.cpp
|
$(CXX) $(CFLAGS) $(CXXFLAGS) -o $@ -c $(MOON_SRC)/misc/config.cpp
|
||||||
@echo " CXX $^"
|
|
||||||
|
|
||||||
$(MOON_OBJ)/init/Init.cpp.o: $(MOON_SRC)/init/Init.cpp
|
$(MOON_OBJ)/init/Init.cpp.o: $(MOON_SRC)/init/Init.cpp
|
||||||
@mkdir -p $(@D)
|
@mkdir -p $(@D)
|
||||||
@$(CXX) $(CFLAGS) -fno-stack-protector $(CXXFLAGS) -o $@ -c $^
|
$(CXX) $(CFLAGS) -fno-stack-protector $(CXXFLAGS) -o $@ -c $^
|
||||||
@echo " CXX $^"
|
|
||||||
|
|
||||||
$(MOON_OBJ)/%.cpp.o: $(MOON_SRC)/%.cpp
|
$(MOON_OBJ)/%.cpp.o: $(MOON_SRC)/%.cpp
|
||||||
@mkdir -p $(@D)
|
@mkdir -p $(@D)
|
||||||
@$(CXX) $(CFLAGS) $(CXXFLAGS) -o $@ -c $^
|
$(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 $^"
|
|
||||||
|
|
||||||
$(MOON_OBJ)/%.c.o: $(MOON_SRC)/%.c
|
$(MOON_OBJ)/%.c.o: $(MOON_SRC)/%.c
|
||||||
@mkdir -p $(@D)
|
@mkdir -p $(@D)
|
||||||
@$(CC) $(CFLAGS) -o $@ -c $^
|
$(CC) $(CFLAGS) -o $@ -c $^
|
||||||
@echo " CC $^"
|
|
||||||
|
|
||||||
$(MOON_OBJ)/%.asm.o: $(MOON_SRC)/%.asm
|
$(MOON_OBJ)/%.asm.o: $(MOON_SRC)/%.asm
|
||||||
@mkdir -p $(@D)
|
@mkdir -p $(@D)
|
||||||
@$(ASM) $(ASMFLAGS) -o $@ $^
|
$(ASM) $(ASMFLAGS) -o $@ $^
|
||||||
@echo " ASM $^"
|
|
||||||
|
|
||||||
build: $(OBJS)
|
build: $(OBJS)
|
||||||
@mkdir -p $(MOON_BIN)
|
@mkdir -p $(@D)
|
||||||
@$(CC) $(OBJS) $(LDFLAGS) -o $(MOON_BIN)/moon
|
$(CC) $(OBJS) $(LDFLAGS) -o $(MOON_BIN)/moon.elf
|
||||||
@echo " CCLD $(MOON_BIN)/moon"
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf $(MOON_OBJ)/*
|
rm -rf $(MOON_OBJ)/*
|
||||||
rm -rf $(MOON_BIN)/*
|
rm -rf $(MOON_BIN)/*
|
||||||
|
|
||||||
install: $(MOON_BIN)/moon
|
install: $(MOON_BIN)/moon.elf
|
||||||
@mkdir -p $(LUNA_ROOT)/initrd/boot
|
@mkdir -p $(@D)
|
||||||
@cp $^ $(LUNA_ROOT)/initrd/boot/moon
|
cp $^ $(LUNA_ROOT)/initrd/boot/moon.elf
|
||||||
@echo " INSTALL $^"
|
$(LUNA_ROOT)/tools/generate-symbols.sh
|
||||||
@$(LUNA_ROOT)/tools/generate-symbols.sh
|
$(STRIP) $(LUNA_ROOT)/initrd/boot/moon.elf
|
||||||
@$(STRIP) $(LUNA_ROOT)/initrd/boot/moon
|
|
||||||
@echo " STRIP $(LUNA_ROOT)/initrd/boot/moon"
|
|
||||||
|
|
||||||
.PHONY: build clean install FORCE
|
.PHONY: build clean install FORCE
|
||||||
FORCE:
|
FORCE:
|
@ -10,5 +10,4 @@ namespace CPU
|
|||||||
uint64_t get_feature_bitmask();
|
uint64_t get_feature_bitmask();
|
||||||
uint64_t get_initial_apic_id();
|
uint64_t get_initial_apic_id();
|
||||||
bool has_feature(CPU::Features);
|
bool has_feature(CPU::Features);
|
||||||
bool has_nx();
|
|
||||||
}
|
}
|
@ -32,13 +32,6 @@ struct Descriptor
|
|||||||
ssize_t read(size_t size, char* buffer);
|
ssize_t read(size_t size, char* buffer);
|
||||||
ssize_t write(size_t size, const 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);
|
void open(VFS::Node* node, bool can_read, bool can_write, bool able_to_block, bool close_on_exec);
|
||||||
|
|
||||||
int seek(long offset);
|
int seek(long offset);
|
||||||
@ -62,11 +55,6 @@ struct Descriptor
|
|||||||
return m_close_on_exec;
|
return m_close_on_exec;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_close_on_exec(bool value)
|
|
||||||
{
|
|
||||||
m_close_on_exec = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
Descriptor(const Descriptor& other);
|
Descriptor(const Descriptor& other);
|
||||||
Descriptor();
|
Descriptor();
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
typedef long ssize_t;
|
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_read)(Node*, size_t, size_t, char*);
|
||||||
typedef ssize_t (*node_write)(Node*, size_t, size_t, const char*);
|
typedef ssize_t (*node_write)(Node*, size_t, size_t, const char*);
|
||||||
typedef Node* (*node_finddir)(Node*, 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 int (*node_block)(Node*);
|
||||||
typedef Node* (*node_readdir)(Node*, long);
|
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
|
struct Node
|
||||||
{
|
{
|
||||||
char name[NAME_MAX];
|
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 inode;
|
||||||
uint64_t length;
|
uint64_t length;
|
||||||
|
int type;
|
||||||
|
int flags;
|
||||||
node_read read_func;
|
node_read read_func;
|
||||||
node_finddir find_func;
|
node_finddir find_func;
|
||||||
node_readdir readdir_func;
|
node_readdir readdir_func;
|
||||||
node_mkdir mkdir_func;
|
node_mkdir mkdir_func;
|
||||||
node_write write_func;
|
node_write write_func;
|
||||||
node_block block_func;
|
node_block block_func;
|
||||||
node_mmap mmap_func;
|
int tty = 0;
|
||||||
node_ioctl ioctl_func;
|
|
||||||
Node* link;
|
Node* link;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -57,9 +45,6 @@ namespace VFS
|
|||||||
int mkdir(const char* path, const char* name);
|
int mkdir(const char* path, const char* name);
|
||||||
int mkdir(const char* pathname);
|
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);
|
int would_block(Node* node);
|
||||||
|
|
||||||
void mount_root(Node* root);
|
void mount_root(Node* root);
|
||||||
@ -76,11 +61,4 @@ namespace VFS
|
|||||||
Node* root();
|
Node* root();
|
||||||
|
|
||||||
Node* readdir(Node* dir, long offset);
|
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);
|
VFS::Node* create_new(const char* devname);
|
||||||
|
|
||||||
ssize_t write(VFS::Node* node, size_t offset, size_t size, const char* buffer);
|
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
|
#pragma once
|
||||||
#include "fs/VFS.h"
|
#include "fs/VFS.h"
|
||||||
|
|
||||||
namespace NullDevice
|
namespace UptimeDevice
|
||||||
{
|
{
|
||||||
VFS::Node* create_new(const char* devname);
|
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);
|
ssize_t read(VFS::Node* node, size_t offset, size_t size, char* buffer);
|
||||||
}
|
}
|
@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
#define TAR_MAGIC "ustar"
|
#define TAR_MAGIC "ustar"
|
||||||
#define TAR_BLOCKSIZE 512
|
#define TAR_BLOCKSIZE 512
|
||||||
@ -34,7 +33,6 @@ namespace InitRD
|
|||||||
uint64_t size;
|
uint64_t size;
|
||||||
uint64_t size_in_blocks;
|
uint64_t size_in_blocks;
|
||||||
void* addr;
|
void* addr;
|
||||||
mode_t mode;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
uint64_t get_total_blocks();
|
uint64_t get_total_blocks();
|
@ -8,14 +8,11 @@
|
|||||||
#define MAP_READ_WRITE 1 << 0
|
#define MAP_READ_WRITE 1 << 0
|
||||||
#define MAP_USER 1 << 1
|
#define MAP_USER 1 << 1
|
||||||
#define MAP_EXEC 1 << 2
|
#define MAP_EXEC 1 << 2
|
||||||
#define MAP_AS_OWNED_BY_TASK 1 << 3
|
|
||||||
|
|
||||||
namespace MemoryManager
|
namespace MemoryManager
|
||||||
{
|
{
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
void protect_kernel_sections();
|
|
||||||
|
|
||||||
void* get_mapping(void* physicalAddress, int flags = MAP_READ_WRITE);
|
void* get_mapping(void* physicalAddress, int flags = MAP_READ_WRITE);
|
||||||
void release_mapping(void* mapping);
|
void release_mapping(void* mapping);
|
||||||
|
|
||||||
@ -34,7 +31,4 @@ namespace MemoryManager
|
|||||||
void release_pages(void* pages, uint64_t count);
|
void release_pages(void* pages, uint64_t count);
|
||||||
|
|
||||||
void protect(void* page, uint64_t count, int flags);
|
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 larger_pages : 1;
|
||||||
bool ignore1 : 1;
|
bool ignore1 : 1;
|
||||||
uint8_t available : 3;
|
uint8_t available : 3;
|
||||||
uint64_t address : 48;
|
uint64_t address : 52;
|
||||||
bool owned_by_task : 1; // Part of the available for OS use bits.
|
|
||||||
uint8_t available2 : 2;
|
|
||||||
bool no_execute : 1;
|
|
||||||
|
|
||||||
void set_address(uint64_t addr);
|
void set_address(uint64_t addr);
|
||||||
uint64_t get_address();
|
uint64_t get_address();
|
||||||
} __attribute__((packed));
|
};
|
||||||
|
|
||||||
struct PageTable
|
struct PageTable
|
||||||
{
|
{
|
||||||
PageDirectoryEntry entries[512];
|
PageDirectoryEntry entries[512];
|
||||||
} __attribute__((aligned(PAGE_SIZE)));
|
} __attribute__((aligned(PAGE_SIZE)));
|
||||||
|
|
||||||
static_assert(sizeof(PageDirectoryEntry) == 8UL);
|
|
@ -6,8 +6,7 @@ enum Flags
|
|||||||
{
|
{
|
||||||
ReadWrite = 1 << 0,
|
ReadWrite = 1 << 0,
|
||||||
User = 1 << 1,
|
User = 1 << 1,
|
||||||
Execute = 1 << 2,
|
Execute = 1 << 2
|
||||||
OwnedByTask = 1 << 3,
|
|
||||||
};
|
};
|
||||||
namespace VMM
|
namespace VMM
|
||||||
{
|
{
|
||||||
@ -34,11 +33,9 @@ namespace VMM
|
|||||||
PageDirectoryEntry* create_pde_if_not_exists(PageTable* root, uint64_t vaddr);
|
PageDirectoryEntry* create_pde_if_not_exists(PageTable* root, uint64_t vaddr);
|
||||||
|
|
||||||
void propagate_read_write(PageTable* root, uint64_t vaddr);
|
void propagate_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 propagate_user(PageTable* root, uint64_t vaddr);
|
||||||
|
|
||||||
void flush_tlb(uint64_t addr);
|
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,
|
void decompose_vaddr(uint64_t vaddr, uint64_t& page_index, uint64_t& pt_index, uint64_t& pd_index,
|
||||||
uint64_t& pdp_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 ENOENT 2
|
||||||
#define ESRCH 3
|
#define ESRCH 3
|
||||||
#define EINTR 4
|
#define EINTR 4
|
||||||
#define E2BIG 7
|
|
||||||
#define ENOEXEC 8
|
#define ENOEXEC 8
|
||||||
#define EBADF 9
|
#define EBADF 9
|
||||||
#define ECHILD 10
|
|
||||||
#define EAGAIN 11
|
#define EAGAIN 11
|
||||||
#define ENOMEM 12
|
#define ENOMEM 12
|
||||||
#define EACCES 13
|
|
||||||
#define EFAULT 14
|
#define EFAULT 14
|
||||||
#define EEXIST 17
|
#define EEXIST 17
|
||||||
#define ENOTDIR 20
|
#define ENOTDIR 20
|
||||||
@ -19,6 +16,5 @@
|
|||||||
#define EMFILE 24
|
#define EMFILE 24
|
||||||
#define ENOTTY 25
|
#define ENOTTY 25
|
||||||
#define ENOSPC 28
|
#define ENOSPC 28
|
||||||
#define ERANGE 36
|
|
||||||
#define ENOSYS 38
|
#define ENOSYS 38
|
||||||
#define ENOTSUP 95
|
#define ENOTSUP 95
|
@ -1,43 +1,34 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "interrupts/Context.h"
|
#include "interrupts/Context.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
#define SYS_exit 0
|
#define SYS_exit 0
|
||||||
#define SYS_yield 1
|
#define SYS_yield 1
|
||||||
#define SYS_sleep 2
|
#define SYS_sleep 2
|
||||||
#define SYS_write 3
|
#define SYS_write 3
|
||||||
#define SYS_getprocid 4
|
#define SYS_paint 4
|
||||||
#define SYS_mmap 5
|
#define SYS_getprocid 5
|
||||||
#define SYS_munmap 6
|
#define SYS_mmap 6
|
||||||
#define SYS_open 7
|
#define SYS_munmap 7
|
||||||
#define SYS_read 8
|
#define SYS_open 8
|
||||||
#define SYS_close 9
|
#define SYS_read 9
|
||||||
#define SYS_seek 10
|
#define SYS_close 10
|
||||||
#define SYS_execv 11
|
#define SYS_seek 11
|
||||||
#define SYS_fcntl 12
|
#define SYS_exec 12
|
||||||
#define SYS_mprotect 13
|
#define SYS_fcntl 13
|
||||||
#define SYS_clock_gettime 14
|
#define SYS_mprotect 14
|
||||||
#define SYS_mkdir 15
|
#define SYS_clock 15
|
||||||
#define SYS_fork 16
|
#define SYS_mkdir 16
|
||||||
#define SYS_waitpid 17
|
#define SYS_fork 17
|
||||||
#define SYS_access 18
|
#define SYS_waitpid 18
|
||||||
#define SYS_fstat 19
|
#define SYS_access 19
|
||||||
#define SYS_pstat 20
|
#define SYS_fstat 20
|
||||||
#define SYS_getdents 21
|
#define SYS_pstat 21
|
||||||
#define SYS_stat 22
|
#define SYS_getdents 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
|
|
||||||
|
|
||||||
struct stat;
|
struct stat;
|
||||||
struct pstat;
|
struct pstat;
|
||||||
struct luna_dirent;
|
struct luna_dirent;
|
||||||
struct timespec;
|
|
||||||
|
|
||||||
namespace Syscall
|
namespace Syscall
|
||||||
{
|
{
|
||||||
@ -48,29 +39,22 @@ void sys_exit(Context* context, int status);
|
|||||||
void sys_yield(Context* context);
|
void sys_yield(Context* context);
|
||||||
void sys_sleep(Context* context, uint64_t ms);
|
void sys_sleep(Context* context, uint64_t ms);
|
||||||
void sys_write(Context* context, int fd, size_t size, const char* addr);
|
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_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_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_read(Context* context, int fd, size_t size, char* buffer);
|
||||||
void sys_close(Context* context, int fd);
|
void sys_close(Context* context, int fd);
|
||||||
void sys_seek(Context* context, int fd, long offset, int whence);
|
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_fcntl(Context* context, int fd, int command, uintptr_t arg);
|
||||||
void sys_mprotect(Context* context, void* address, size_t size, int prot);
|
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_clock(Context* context);
|
||||||
void sys_mkdir(Context* context, const char* filename, mode_t mode);
|
void sys_mkdir(Context* context, const char* filename);
|
||||||
void sys_fork(Context* context);
|
void sys_fork(Context* context);
|
||||||
void sys_waitpid(Context* context, long pid, int* wstatus, int options);
|
void sys_waitpid(Context* context, long pid, int* wstatus, int options);
|
||||||
void sys_access(Context* context, const char* path, int amode);
|
void sys_access(Context* context, const char* path, int amode);
|
||||||
void sys_fstat(Context* context, int fd, struct stat* buf);
|
void sys_fstat(Context* context, int fd, struct stat* buf);
|
||||||
void sys_pstat(Context* context, long pid, struct pstat* 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_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/MemoryManager.h"
|
||||||
#include "memory/VMM.h"
|
#include "memory/VMM.h"
|
||||||
#include "misc/utils.h"
|
#include "misc/utils.h"
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
char* strdup_from_user(const char* user_string);
|
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
|
// 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.
|
// 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/AddressSpace.h"
|
||||||
#include "memory/UserHeap.h"
|
#include "memory/UserHeap.h"
|
||||||
#include "sys/elf/Image.h"
|
#include "sys/elf/Image.h"
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
#define TASK_MAX_FDS 32
|
#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
|
struct Task
|
||||||
{
|
{
|
||||||
enum TaskState
|
enum TaskState
|
||||||
@ -40,11 +29,6 @@ struct Task
|
|||||||
|
|
||||||
int64_t task_time = 0;
|
int64_t task_time = 0;
|
||||||
|
|
||||||
uid_t uid;
|
|
||||||
uid_t euid;
|
|
||||||
gid_t gid;
|
|
||||||
gid_t egid;
|
|
||||||
|
|
||||||
Task* next_task = nullptr;
|
Task* next_task = nullptr;
|
||||||
Task* prev_task = nullptr;
|
Task* prev_task = nullptr;
|
||||||
|
|
||||||
@ -61,8 +45,7 @@ struct Task
|
|||||||
|
|
||||||
bool is_user_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
|
ELFImage* image = nullptr;
|
||||||
// freed automatically when calling destroy() or clear() on the address space.
|
|
||||||
|
|
||||||
Descriptor files[TASK_MAX_FDS];
|
Descriptor files[TASK_MAX_FDS];
|
||||||
|
|
||||||
@ -86,38 +69,14 @@ struct Task
|
|||||||
|
|
||||||
char name[128];
|
char name[128];
|
||||||
|
|
||||||
mode_t umask;
|
|
||||||
|
|
||||||
BlockReason block_reason;
|
|
||||||
|
|
||||||
union {
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
size_t size;
|
size_t size;
|
||||||
int fd;
|
int fd;
|
||||||
char* buf;
|
char* buf;
|
||||||
} blocking_read_info;
|
} blocking_read_info;
|
||||||
struct
|
|
||||||
{
|
|
||||||
int64_t pid;
|
|
||||||
int* wstatus;
|
|
||||||
} blocking_wait_info;
|
|
||||||
};
|
|
||||||
|
|
||||||
void resume();
|
void resume_read();
|
||||||
|
|
||||||
bool is_still_blocking();
|
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 = .;
|
kernel_start = .;
|
||||||
.text : {
|
.text : {
|
||||||
KEEP(*(.text.boot)) *(.text .text.*) /* code */
|
KEEP(*(.text.boot)) *(.text .text.*) /* code */
|
||||||
. = ALIGN(0x1000);
|
|
||||||
start_of_kernel_rodata = .;
|
|
||||||
*(.rodata .rodata.*) /* data */
|
*(.rodata .rodata.*) /* data */
|
||||||
end_of_kernel_rodata = .;
|
|
||||||
. = ALIGN(0x1000);
|
|
||||||
start_of_kernel_data = .;
|
|
||||||
*(.data .data.*)
|
*(.data .data.*)
|
||||||
} :boot
|
} :boot
|
||||||
.bss (NOLOAD) : { /* bss */
|
.bss (NOLOAD) : { /* bss */
|
||||||
|
. = ALIGN(16);
|
||||||
*(.bss .bss.*)
|
*(.bss .bss.*)
|
||||||
*(COMMON)
|
*(COMMON)
|
||||||
} :boot
|
} :boot
|
||||||
end_of_kernel_data = .;
|
|
||||||
kernel_end = .;
|
kernel_end = .;
|
||||||
|
|
||||||
/DISCARD/ : { *(.eh_frame) *(.comment) }
|
/DISCARD/ : { *(.eh_frame) *(.comment) }
|
||||||
|
@ -66,17 +66,9 @@ uint64_t CPU::get_feature_bitmask()
|
|||||||
return 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)
|
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)
|
bool CPU::has_feature(CPU::Features feature)
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
#include "fs/FileDescriptor.h"
|
#include "fs/FileDescriptor.h"
|
||||||
#include "std/errno.h"
|
#include "std/errno.h"
|
||||||
#include "std/stdlib.h"
|
|
||||||
#include "sys/UserMemory.h"
|
|
||||||
|
|
||||||
Descriptor::Descriptor() : m_is_open(false)
|
Descriptor::Descriptor() : m_is_open(false)
|
||||||
{
|
{
|
||||||
@ -39,42 +37,6 @@ ssize_t Descriptor::write(size_t size, const char* buffer)
|
|||||||
return result;
|
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)
|
int Descriptor::seek(long offset)
|
||||||
{
|
{
|
||||||
if (m_node->type == VFS_FILE && (uint64_t)offset > m_node->length)
|
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()");
|
kwarnln("Chosen node does not support finddir()");
|
||||||
return -ENOTSUP;
|
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)
|
if (node->find_func(node, name) != nullptr)
|
||||||
{
|
{
|
||||||
kwarnln("Already exists");
|
kwarnln("Already exists");
|
||||||
return -EEXIST;
|
return -EEXIST;
|
||||||
}
|
}
|
||||||
return node->mkdir_func(node, name, 0755);
|
return node->mkdir_func(node, name);
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int VFS::mkdir(const char* pathname)
|
int VFS::mkdir(const char* pathname)
|
||||||
@ -224,24 +178,6 @@ int VFS::mkdir(const char* pathname)
|
|||||||
return result;
|
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)
|
bool VFS::exists(const char* pathname)
|
||||||
{
|
{
|
||||||
return resolve_path(pathname) != nullptr;
|
return resolve_path(pathname) != nullptr;
|
||||||
@ -273,34 +209,3 @@ VFS::Node* VFS::readdir(VFS::Node* dir, long offset)
|
|||||||
if (!dir->readdir_func) return 0;
|
if (!dir->readdir_func) return 0;
|
||||||
return dir->readdir_func(dir, offset);
|
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/stdlib.h"
|
||||||
#include "std/string.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* ConsoleDevice::create_new(const char* devname)
|
||||||
{
|
{
|
||||||
VFS::Node* dev = new VFS::Node;
|
VFS::Node* dev = new VFS::Node;
|
||||||
dev->write_func = ConsoleDevice::write;
|
dev->write_func = ConsoleDevice::write;
|
||||||
dev->read_func = ConsoleDevice::read;
|
|
||||||
dev->block_func = ConsoleDevice::would_block;
|
|
||||||
dev->inode = 0;
|
dev->inode = 0;
|
||||||
dev->length = 0;
|
dev->length = 0;
|
||||||
dev->type = VFS_DEVICE;
|
dev->type = VFS_DEVICE;
|
||||||
dev->flags = 0;
|
dev->flags = 0;
|
||||||
dev->tty = 1;
|
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));
|
strncpy(dev->name, devname, sizeof(dev->name));
|
||||||
return dev;
|
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);
|
TextRenderer::write(buffer, size);
|
||||||
return (ssize_t)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/DeviceFS.h"
|
||||||
#include "fs/devices/Console.h"
|
#include "fs/devices/Console.h"
|
||||||
#include "fs/devices/Framebuffer.h"
|
|
||||||
#include "fs/devices/Keyboard.h"
|
#include "fs/devices/Keyboard.h"
|
||||||
#include "fs/devices/NullDevice.h"
|
|
||||||
#include "fs/devices/Random.h"
|
#include "fs/devices/Random.h"
|
||||||
#include "fs/devices/Serial.h"
|
#include "fs/devices/Serial.h"
|
||||||
|
#include "fs/devices/Uptime.h"
|
||||||
#include "fs/devices/Version.h"
|
#include "fs/devices/Version.h"
|
||||||
#include "std/stdlib.h"
|
#include "std/stdlib.h"
|
||||||
#include "std/string.h"
|
#include "std/string.h"
|
||||||
@ -16,8 +15,6 @@ VFS::Node* devfs_root = nullptr;
|
|||||||
VFS::Node* devfs_files[DEVFS_MAX_FILES];
|
VFS::Node* devfs_files[DEVFS_MAX_FILES];
|
||||||
int devfs_file_count = 0;
|
int devfs_file_count = 0;
|
||||||
|
|
||||||
extern uint64_t clock_boot();
|
|
||||||
|
|
||||||
VFS::Node* DeviceFS::get()
|
VFS::Node* DeviceFS::get()
|
||||||
{
|
{
|
||||||
if (devfs_root) return devfs_root;
|
if (devfs_root) return devfs_root;
|
||||||
@ -27,9 +24,6 @@ VFS::Node* DeviceFS::get()
|
|||||||
devfs_root->type = VFS_DIRECTORY;
|
devfs_root->type = VFS_DIRECTORY;
|
||||||
devfs_root->find_func = DeviceFS::finddir;
|
devfs_root->find_func = DeviceFS::finddir;
|
||||||
devfs_root->readdir_func = DeviceFS::readdir;
|
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));
|
strncpy(devfs_root->name, "dev", sizeof(devfs_root->name));
|
||||||
|
|
||||||
devfs_files[devfs_file_count++] = VersionDevice::create_new("version");
|
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++] = SerialDevice::create_new("serial");
|
||||||
devfs_files[devfs_file_count++] = RandomDevice::create_new("random");
|
devfs_files[devfs_file_count++] = RandomDevice::create_new("random");
|
||||||
devfs_files[devfs_file_count++] = KeyboardDevice::create_new("kbd");
|
devfs_files[devfs_file_count++] = KeyboardDevice::create_new("kbd");
|
||||||
devfs_files[devfs_file_count++] = NullDevice::create_new("null");
|
devfs_files[devfs_file_count++] = UptimeDevice::create_new("uptime");
|
||||||
devfs_files[devfs_file_count++] = FramebufferDevice::create_new("fb0");
|
|
||||||
devfs_root->length = devfs_file_count;
|
devfs_root->length = devfs_file_count;
|
||||||
return devfs_root;
|
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;
|
return kbd_bufsize == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern uint64_t clock_boot();
|
|
||||||
|
|
||||||
VFS::Node* KeyboardDevice::create_new(const char* devname)
|
VFS::Node* KeyboardDevice::create_new(const char* devname)
|
||||||
{
|
{
|
||||||
VFS::Node* dev = new VFS::Node;
|
VFS::Node* dev = new VFS::Node;
|
||||||
@ -28,9 +26,6 @@ VFS::Node* KeyboardDevice::create_new(const char* devname)
|
|||||||
dev->type = VFS_DEVICE;
|
dev->type = VFS_DEVICE;
|
||||||
dev->flags = 0;
|
dev->flags = 0;
|
||||||
dev->tty = 1;
|
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));
|
strncpy(dev->name, devname, sizeof(dev->name));
|
||||||
return dev;
|
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/stdlib.h"
|
||||||
#include "std/string.h"
|
#include "std/string.h"
|
||||||
|
|
||||||
extern uint64_t clock_boot();
|
|
||||||
|
|
||||||
VFS::Node* RandomDevice::create_new(const char* devname)
|
VFS::Node* RandomDevice::create_new(const char* devname)
|
||||||
{
|
{
|
||||||
VFS::Node* dev = new VFS::Node;
|
VFS::Node* dev = new VFS::Node;
|
||||||
@ -16,9 +14,6 @@ VFS::Node* RandomDevice::create_new(const char* devname)
|
|||||||
dev->length = 0;
|
dev->length = 0;
|
||||||
dev->type = VFS_DEVICE;
|
dev->type = VFS_DEVICE;
|
||||||
dev->flags = 0;
|
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));
|
strncpy(dev->name, devname, sizeof(dev->name));
|
||||||
return dev;
|
return dev;
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,6 @@
|
|||||||
#include "std/stdlib.h"
|
#include "std/stdlib.h"
|
||||||
#include "std/string.h"
|
#include "std/string.h"
|
||||||
|
|
||||||
extern uint64_t clock_boot();
|
|
||||||
|
|
||||||
VFS::Node* SerialDevice::create_new(const char* devname)
|
VFS::Node* SerialDevice::create_new(const char* devname)
|
||||||
{
|
{
|
||||||
VFS::Node* dev = new VFS::Node;
|
VFS::Node* dev = new VFS::Node;
|
||||||
@ -15,9 +13,6 @@ VFS::Node* SerialDevice::create_new(const char* devname)
|
|||||||
dev->length = 0;
|
dev->length = 0;
|
||||||
dev->type = VFS_DEVICE;
|
dev->type = VFS_DEVICE;
|
||||||
dev->flags = 0;
|
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));
|
strncpy(dev->name, devname, sizeof(dev->name));
|
||||||
return dev;
|
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/stdlib.h"
|
||||||
#include "std/string.h"
|
#include "std/string.h"
|
||||||
|
|
||||||
extern uint64_t clock_boot();
|
|
||||||
|
|
||||||
VFS::Node* VersionDevice::create_new(const char* devname)
|
VFS::Node* VersionDevice::create_new(const char* devname)
|
||||||
{
|
{
|
||||||
VFS::Node* dev = new VFS::Node;
|
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->length = strlen(moon_version()) + 5;
|
||||||
dev->type = VFS_DEVICE;
|
dev->type = VFS_DEVICE;
|
||||||
dev->flags = 0;
|
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));
|
strncpy(dev->name, devname, sizeof(dev->name));
|
||||||
return dev;
|
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)
|
ssize_t VersionDevice::read(VFS::Node* node, size_t offset, size_t size, char* buffer)
|
||||||
{
|
{
|
||||||
if (!node) return -1;
|
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
|
snprintf(buffer, size + 1, "moon %s", moon_version()); // FIXME: Support offseting this read
|
||||||
return (ssize_t)size;
|
return (ssize_t)size;
|
||||||
}
|
}
|
@ -3,7 +3,7 @@
|
|||||||
#include "gdt/GDT.h"
|
#include "gdt/GDT.h"
|
||||||
#include "log/Log.h"
|
#include "log/Log.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include "std/ensure.h"
|
#include "std/assert.h"
|
||||||
#include "std/string.h"
|
#include "std/string.h"
|
||||||
#include <stdint.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)
|
static void set_limit(GDTEntry* entry, uint32_t limit)
|
||||||
{
|
{
|
||||||
ensure(limit <= 0xFFFFF);
|
ASSERT(limit <= 0xFFFFF);
|
||||||
entry->limit0 = limit & 0xFFFF;
|
entry->limit0 = limit & 0xFFFF;
|
||||||
entry->limit1_flags = (entry->limit1_flags & 0xF0) | ((limit >> 16) & 0xF);
|
entry->limit1_flags = (entry->limit1_flags & 0xF0) | ((limit >> 16) & 0xF);
|
||||||
}
|
}
|
||||||
|
@ -3,32 +3,29 @@
|
|||||||
#include "init/Init.h"
|
#include "init/Init.h"
|
||||||
#include "bootboot.h"
|
#include "bootboot.h"
|
||||||
#include "cpu/CPU.h"
|
#include "cpu/CPU.h"
|
||||||
#include "fs/InitRD.h"
|
#include "init/InitRD.h"
|
||||||
#include "interrupts/Interrupts.h"
|
#include "interrupts/Interrupts.h"
|
||||||
#include "io/Serial.h"
|
#include "io/Serial.h"
|
||||||
#include "log/Log.h"
|
#include "log/Log.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include "memory/PMM.h"
|
#include "memory/PMM.h"
|
||||||
#include "memory/VMM.h"
|
#include "memory/VMM.h"
|
||||||
#include "misc/MSR.h"
|
|
||||||
#include "misc/hang.h"
|
#include "misc/hang.h"
|
||||||
#include "rand/Init.h"
|
#include "rand/Init.h"
|
||||||
#include "rand/Mersenne.h"
|
#include "rand/Mersenne.h"
|
||||||
#include "render/Framebuffer.h"
|
#include "render/Framebuffer.h"
|
||||||
#include "render/TextRenderer.h"
|
#include "render/TextRenderer.h"
|
||||||
#include "std/ensure.h"
|
#include "std/assert.h"
|
||||||
#include "std/string.h"
|
#include "std/string.h"
|
||||||
#include "utils/Time.h"
|
|
||||||
|
|
||||||
extern BOOTBOOT bootboot;
|
extern BOOTBOOT bootboot;
|
||||||
extern "C" char environment[4096];
|
extern "C" char environment[4096];
|
||||||
extern uintptr_t fb;
|
|
||||||
|
|
||||||
uintptr_t __stack_chk_guard = 0xfeff34;
|
uintptr_t __stack_chk_guard = 0xfeff34;
|
||||||
|
|
||||||
void Init::check_magic()
|
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()
|
void Init::disable_smp()
|
||||||
@ -38,42 +35,6 @@ void Init::disable_smp()
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void asm_enable_sse();
|
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()
|
void Init::early_init()
|
||||||
{
|
{
|
||||||
@ -82,14 +43,11 @@ void Init::early_init()
|
|||||||
|
|
||||||
asm_enable_sse();
|
asm_enable_sse();
|
||||||
|
|
||||||
framebuffer0.init((void*)&fb, bootboot.fb_type, bootboot.fb_scanline, bootboot.fb_width, bootboot.fb_height);
|
framebuffer0.init((void*)bootboot.fb_ptr, bootboot.fb_type, bootboot.fb_scanline, bootboot.fb_width,
|
||||||
|
bootboot.fb_height);
|
||||||
check_and_enable_nx();
|
|
||||||
|
|
||||||
MemoryManager::init();
|
MemoryManager::init();
|
||||||
|
|
||||||
MemoryManager::protect_kernel_sections();
|
|
||||||
|
|
||||||
if (strstr(environment, "quiet=1"))
|
if (strstr(environment, "quiet=1"))
|
||||||
{
|
{
|
||||||
KernelLog::toggle_log_level(LogLevel::DEBUG);
|
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); }
|
else if (!strstr(environment, "verbose=1")) { KernelLog::toggle_log_level(LogLevel::DEBUG); }
|
||||||
|
|
||||||
clock_init();
|
|
||||||
|
|
||||||
InitRD::init();
|
InitRD::init();
|
||||||
|
|
||||||
Mersenne::init();
|
Mersenne::init();
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#define MODULE "initrd"
|
#define MODULE "initrd"
|
||||||
|
|
||||||
#include "fs/InitRD.h"
|
#include "init/InitRD.h"
|
||||||
#include "bootboot.h"
|
#include "bootboot.h"
|
||||||
#include "fs/VFS.h"
|
#include "fs/VFS.h"
|
||||||
#include "io/Serial.h"
|
#include "io/Serial.h"
|
||||||
@ -10,9 +10,6 @@
|
|||||||
#include "std/errno.h"
|
#include "std/errno.h"
|
||||||
#include "std/stdlib.h"
|
#include "std/stdlib.h"
|
||||||
#include "std/string.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;
|
extern BOOTBOOT bootboot;
|
||||||
|
|
||||||
@ -21,9 +18,6 @@ static bool initrd_initialized = false;
|
|||||||
|
|
||||||
static VFS::Node initrd_root;
|
static VFS::Node initrd_root;
|
||||||
|
|
||||||
extern uint64_t clock_boot(); // defined in sys/clock.cpp
|
|
||||||
extern uint64_t clock_now();
|
|
||||||
|
|
||||||
bool InitRD::is_initialized()
|
bool InitRD::is_initialized()
|
||||||
{
|
{
|
||||||
return initrd_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)
|
InitRD::File InitRD::get_file(TarHeader* header)
|
||||||
{
|
{
|
||||||
File result;
|
File result;
|
||||||
char null_terminated_size[13];
|
result.size = 0;
|
||||||
memcpy(null_terminated_size, header->size, 12);
|
|
||||||
null_terminated_size[12] = 0;
|
|
||||||
result.size = parse_octal(null_terminated_size);
|
|
||||||
memcpy(result.name, header->name, 100);
|
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.addr = (void*)((uint64_t)header + TAR_BLOCKSIZE);
|
||||||
result.size_in_blocks = Utilities::get_blocks_from_size(TAR_BLOCKSIZE, result.size);
|
result.size_in_blocks = Utilities::get_blocks_from_size(TAR_BLOCKSIZE, result.size);
|
||||||
result.mode = (mode_t)parse_octal(header->mode);
|
|
||||||
return result;
|
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
|
#define INITRD_MAX_FILES 64
|
||||||
|
|
||||||
namespace InitRD
|
namespace InitRD
|
||||||
@ -198,7 +195,7 @@ VFS::Node* initrd_read_dir(VFS::Node* node, long offset)
|
|||||||
return dir.files[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)
|
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.mkdir_func = initrd_mkdir;
|
||||||
new_node.length = 0;
|
new_node.length = 0;
|
||||||
new_node.type = VFS_DIRECTORY;
|
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));
|
strncpy(new_node.name, name, sizeof(new_node.name));
|
||||||
InitRD::Directory dir;
|
InitRD::Directory dir;
|
||||||
strncpy(dir.name, name, sizeof(dir.name));
|
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.mkdir_func = initrd_mkdir;
|
||||||
node.readdir_func = initrd_read_dir;
|
node.readdir_func = initrd_read_dir;
|
||||||
node.length = 0;
|
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(node.name, buffer, sizeof(node.name));
|
||||||
strncpy(dir.name, buffer, sizeof(dir.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.read_func = initrd_read;
|
||||||
node.length = f.size;
|
node.length = f.size;
|
||||||
node.type = VFS_FILE;
|
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(node.name, buffer, sizeof(node.name));
|
||||||
strncpy(f.name, buffer, sizeof(f.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()
|
static void initrd_scan()
|
||||||
{
|
{
|
||||||
initrd_for_each_dir([](InitRD::Directory& dir) {
|
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);
|
kwarnln("Failed to register directory %s: Too many directories in initrd", dir.name);
|
||||||
return;
|
return;
|
||||||
@ -380,7 +368,7 @@ static void initrd_scan()
|
|||||||
if (initrd_register_dir(dir, inode)) dirs[total_dirs++] = dir;
|
if (initrd_register_dir(dir, inode)) dirs[total_dirs++] = dir;
|
||||||
});
|
});
|
||||||
InitRD::for_each([](InitRD::File& f) {
|
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);
|
kwarnln("Failed to register file %s: Too many files in initrd", f.name);
|
||||||
return;
|
return;
|
||||||
@ -395,9 +383,6 @@ static void initrd_initialize_root()
|
|||||||
initrd_root.length = 0;
|
initrd_root.length = 0;
|
||||||
initrd_root.inode = 0;
|
initrd_root.inode = 0;
|
||||||
initrd_root.type |= VFS_DIRECTORY;
|
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];
|
InitRD::Directory& root = dirs[0];
|
||||||
total_dirs++;
|
total_dirs++;
|
||||||
strncpy(initrd_root.name, "initrd", sizeof(initrd_root.name));
|
strncpy(initrd_root.name, "initrd", sizeof(initrd_root.name));
|
@ -5,19 +5,17 @@
|
|||||||
#include "interrupts/Interrupts.h"
|
#include "interrupts/Interrupts.h"
|
||||||
#include "io/Serial.h"
|
#include "io/Serial.h"
|
||||||
#include "log/Log.h"
|
#include "log/Log.h"
|
||||||
#include "memory/VMM.h"
|
|
||||||
#include "misc/hang.h"
|
#include "misc/hang.h"
|
||||||
#include "panic/Panic.h"
|
#include "panic/Panic.h"
|
||||||
#include "std/ensure.h"
|
#include "std/assert.h"
|
||||||
#include "std/stdio.h"
|
#include "std/stdio.h"
|
||||||
#include "sys/Syscall.h"
|
#include "sys/Syscall.h"
|
||||||
#include "thread/Scheduler.h"
|
#include "thread/Scheduler.h"
|
||||||
#include "trace/StackTracer.h"
|
#include "trace/StackTracer.h"
|
||||||
#include "utils/PageFaultReason.h"
|
|
||||||
|
|
||||||
extern "C" void common_handler(Context* context)
|
extern "C" void common_handler(Context* context)
|
||||||
{
|
{
|
||||||
ensure(Interrupts::is_in_handler());
|
ASSERT(Interrupts::is_in_handler());
|
||||||
if (context->number >= 0x20 && context->number < 0x30)
|
if (context->number >= 0x20 && context->number < 0x30)
|
||||||
{
|
{
|
||||||
IRQ::interrupt_handler(context);
|
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"); }
|
if (context->cs == 0x8) { int_panic(context, "GPF in kernel task"); }
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
VMM::enter_syscall_context();
|
|
||||||
|
|
||||||
kerrorln("General protection fault at RIP %lx, cs %ld, ss %ld, RSP %lx, error code %ld", context->rip,
|
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);
|
context->cs, context->ss, context->rsp, context->error_code);
|
||||||
kinfoln("Stack trace:");
|
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"); }
|
if (context->cs == 0x8) { int_panic(context, "Page fault in kernel task"); }
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
VMM::enter_syscall_context();
|
|
||||||
|
|
||||||
kerrorln("Page fault in ring 3 (RIP %lx), while trying to access %lx, error code %ld", context->rip,
|
kerrorln("Page fault in ring 3 (RIP %lx), while trying to access %lx, error code %ld", context->rip,
|
||||||
context->cr2, context->error_code);
|
context->cr2, context->error_code);
|
||||||
kinfoln("Stack trace:");
|
kinfoln("Stack trace:");
|
||||||
@ -57,8 +51,6 @@ extern "C" void common_handler(Context* context)
|
|||||||
StackTracer tracer(context->rbp);
|
StackTracer tracer(context->rbp);
|
||||||
tracer.trace_with_ip(context->rip);
|
tracer.trace_with_ip(context->rip);
|
||||||
|
|
||||||
determine_user_page_fault_reason(context->cr2);
|
|
||||||
|
|
||||||
Scheduler::task_misbehave(context, -3);
|
Scheduler::task_misbehave(context, -3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include "interrupts/IDT.h"
|
#include "interrupts/IDT.h"
|
||||||
#include "log/Log.h"
|
#include "log/Log.h"
|
||||||
#include "std/ensure.h"
|
#include "std/assert.h"
|
||||||
|
|
||||||
struct IDTEntry
|
struct IDTEntry
|
||||||
{
|
{
|
||||||
@ -37,8 +37,8 @@ uint64_t IDTEntry::get_offset()
|
|||||||
|
|
||||||
void IDT::add_handler(short interrupt_number, void* handler, uint8_t type_attr)
|
void IDT::add_handler(short interrupt_number, void* handler, uint8_t type_attr)
|
||||||
{
|
{
|
||||||
ensure(handler != nullptr);
|
ASSERT(handler != nullptr);
|
||||||
ensure(interrupt_number < 256);
|
ASSERT(interrupt_number < 256);
|
||||||
IDTEntry* entry_for_handler = &entries[interrupt_number];
|
IDTEntry* entry_for_handler = &entries[interrupt_number];
|
||||||
entry_for_handler->selector = 0x08;
|
entry_for_handler->selector = 0x08;
|
||||||
entry_for_handler->type_attr = type_attr;
|
entry_for_handler->type_attr = type_attr;
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#define MODULE "irq"
|
#define MODULE "irq"
|
||||||
|
|
||||||
#include "interrupts/IRQ.h"
|
#include "interrupts/IRQ.h"
|
||||||
#include "fs/devices/Console.h"
|
|
||||||
#include "fs/devices/Keyboard.h"
|
#include "fs/devices/Keyboard.h"
|
||||||
#include "io/IO.h"
|
#include "io/IO.h"
|
||||||
#include "io/PIC.h"
|
#include "io/PIC.h"
|
||||||
@ -22,11 +21,10 @@ void IRQ::interrupt_handler(Context* context)
|
|||||||
break;
|
break;
|
||||||
case 1: {
|
case 1: {
|
||||||
unsigned char scancode = IO::inb(0x60);
|
unsigned char scancode = IO::inb(0x60);
|
||||||
KeyboardDevice::append((char)scancode);
|
|
||||||
bool ignore = false;
|
bool ignore = false;
|
||||||
char key = translate_scancode(scancode, &ignore);
|
char key = translate_scancode(scancode, &ignore);
|
||||||
if (ignore) break;
|
if (ignore) break;
|
||||||
ConsoleDevice::append(key);
|
KeyboardDevice::append(key);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: kwarnln("Unhandled IRQ: %ld", context->irq_number); break;
|
default: kwarnln("Unhandled IRQ: %ld", context->irq_number); break;
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
#include "memory/Memory.h"
|
#include "memory/Memory.h"
|
||||||
#include "memory/MemoryMap.h"
|
#include "memory/MemoryMap.h"
|
||||||
#include "misc/hang.h"
|
#include "misc/hang.h"
|
||||||
#include "std/ensure.h"
|
#include "std/assert.h"
|
||||||
#include "std/stdlib.h"
|
#include "std/stdlib.h"
|
||||||
#include "thread/PIT.h"
|
#include "thread/PIT.h"
|
||||||
#include "thread/Scheduler.h"
|
#include "thread/Scheduler.h"
|
||||||
@ -23,8 +23,8 @@
|
|||||||
|
|
||||||
extern "C" void _start()
|
extern "C" void _start()
|
||||||
{
|
{
|
||||||
Init::disable_smp(); // Put all other cores except the bootstrap one in an infinite loop
|
|
||||||
Init::check_magic();
|
Init::check_magic();
|
||||||
|
Init::disable_smp(); // Put all other cores except the bootstrap one in an infinite loop
|
||||||
Init::early_init();
|
Init::early_init();
|
||||||
|
|
||||||
kinfoln("Starting Moon %s", moon_version());
|
kinfoln("Starting Moon %s", moon_version());
|
||||||
@ -52,9 +52,9 @@ extern "C" void _start()
|
|||||||
kinfoln("Prepared scheduler");
|
kinfoln("Prepared scheduler");
|
||||||
|
|
||||||
#ifdef RUN_TEST_AS_INIT
|
#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
|
#else
|
||||||
ensure(Scheduler::load_user_task("/bin/init") > 0);
|
ASSERT(Scheduler::load_user_task("/bin/init") > 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Scheduler::add_kernel_task("[reaper]", []() {
|
Scheduler::add_kernel_task("[reaper]", []() {
|
||||||
@ -67,7 +67,7 @@ extern "C" void _start()
|
|||||||
|
|
||||||
kinfoln("Prepared scheduler tasks");
|
kinfoln("Prepared scheduler tasks");
|
||||||
|
|
||||||
ensure(VFS::mkdir("/dev") == 0);
|
ASSERT(VFS::mkdir("/dev") == 0);
|
||||||
VFS::mount("/dev", DeviceFS::get());
|
VFS::mount("/dev", DeviceFS::get());
|
||||||
|
|
||||||
Init::finish_kernel_boot();
|
Init::finish_kernel_boot();
|
||||||
@ -78,10 +78,5 @@ extern "C" void _start()
|
|||||||
|
|
||||||
Interrupts::enable();
|
Interrupts::enable();
|
||||||
|
|
||||||
while (1)
|
while (1) halt();
|
||||||
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.
|
|
||||||
}
|
}
|
@ -25,12 +25,9 @@ void AddressSpace::destroy()
|
|||||||
PageDirectoryEntry& pdp_pde = m_pml4->entries[i];
|
PageDirectoryEntry& pdp_pde = m_pml4->entries[i];
|
||||||
if (!pdp_pde.present) continue;
|
if (!pdp_pde.present) continue;
|
||||||
if (pdp_pde.larger_pages)
|
if (pdp_pde.larger_pages)
|
||||||
{
|
|
||||||
if (pdp_pde.owned_by_task)
|
|
||||||
{
|
{
|
||||||
pages_freed++;
|
pages_freed++;
|
||||||
PMM::free_page((void*)pdp_pde.get_address());
|
PMM::free_page((void*)pdp_pde.get_address());
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
PageTable* pdp = (PageTable*)pdp_pde.get_address();
|
PageTable* pdp = (PageTable*)pdp_pde.get_address();
|
||||||
@ -39,12 +36,9 @@ void AddressSpace::destroy()
|
|||||||
PageDirectoryEntry& pd_pde = pdp->entries[j];
|
PageDirectoryEntry& pd_pde = pdp->entries[j];
|
||||||
if (!pd_pde.present) continue;
|
if (!pd_pde.present) continue;
|
||||||
if (pd_pde.larger_pages)
|
if (pd_pde.larger_pages)
|
||||||
{
|
|
||||||
if (pd_pde.owned_by_task)
|
|
||||||
{
|
{
|
||||||
pages_freed++;
|
pages_freed++;
|
||||||
PMM::free_page((void*)pd_pde.get_address());
|
PMM::free_page((void*)pd_pde.get_address());
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
PageTable* pd = (PageTable*)pd_pde.get_address();
|
PageTable* pd = (PageTable*)pd_pde.get_address();
|
||||||
@ -53,12 +47,9 @@ void AddressSpace::destroy()
|
|||||||
PageDirectoryEntry& pt_pde = pd->entries[k];
|
PageDirectoryEntry& pt_pde = pd->entries[k];
|
||||||
if (!pt_pde.present) continue;
|
if (!pt_pde.present) continue;
|
||||||
if (pt_pde.larger_pages)
|
if (pt_pde.larger_pages)
|
||||||
{
|
|
||||||
if (pt_pde.owned_by_task)
|
|
||||||
{
|
{
|
||||||
pages_freed++;
|
pages_freed++;
|
||||||
PMM::free_page((void*)pt_pde.get_address());
|
PMM::free_page((void*)pt_pde.get_address());
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
PageTable* pt = (PageTable*)pt_pde.get_address();
|
PageTable* pt = (PageTable*)pt_pde.get_address();
|
||||||
@ -66,7 +57,6 @@ void AddressSpace::destroy()
|
|||||||
{
|
{
|
||||||
PageDirectoryEntry& pde = pt->entries[l];
|
PageDirectoryEntry& pde = pt->entries[l];
|
||||||
if (!pde.present) continue;
|
if (!pde.present) continue;
|
||||||
if (!pde.owned_by_task) continue;
|
|
||||||
pages_freed++;
|
pages_freed++;
|
||||||
PMM::free_page((void*)pde.get_address());
|
PMM::free_page((void*)pde.get_address());
|
||||||
}
|
}
|
||||||
@ -93,12 +83,9 @@ void AddressSpace::clear()
|
|||||||
PageDirectoryEntry& pdp_pde = m_pml4->entries[i];
|
PageDirectoryEntry& pdp_pde = m_pml4->entries[i];
|
||||||
if (!pdp_pde.present) continue;
|
if (!pdp_pde.present) continue;
|
||||||
if (pdp_pde.larger_pages)
|
if (pdp_pde.larger_pages)
|
||||||
{
|
|
||||||
if (pdp_pde.owned_by_task)
|
|
||||||
{
|
{
|
||||||
pages_freed++;
|
pages_freed++;
|
||||||
PMM::free_page((void*)pdp_pde.get_address());
|
PMM::free_page((void*)pdp_pde.get_address());
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
PageTable* pdp = (PageTable*)pdp_pde.get_address();
|
PageTable* pdp = (PageTable*)pdp_pde.get_address();
|
||||||
@ -107,12 +94,9 @@ void AddressSpace::clear()
|
|||||||
PageDirectoryEntry& pd_pde = pdp->entries[j];
|
PageDirectoryEntry& pd_pde = pdp->entries[j];
|
||||||
if (!pd_pde.present) continue;
|
if (!pd_pde.present) continue;
|
||||||
if (pd_pde.larger_pages)
|
if (pd_pde.larger_pages)
|
||||||
{
|
|
||||||
if (pd_pde.owned_by_task)
|
|
||||||
{
|
{
|
||||||
pages_freed++;
|
pages_freed++;
|
||||||
PMM::free_page((void*)pd_pde.get_address());
|
PMM::free_page((void*)pd_pde.get_address());
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
PageTable* pd = (PageTable*)pd_pde.get_address();
|
PageTable* pd = (PageTable*)pd_pde.get_address();
|
||||||
@ -121,12 +105,9 @@ void AddressSpace::clear()
|
|||||||
PageDirectoryEntry& pt_pde = pd->entries[k];
|
PageDirectoryEntry& pt_pde = pd->entries[k];
|
||||||
if (!pt_pde.present) continue;
|
if (!pt_pde.present) continue;
|
||||||
if (pt_pde.larger_pages)
|
if (pt_pde.larger_pages)
|
||||||
{
|
|
||||||
if (pt_pde.owned_by_task)
|
|
||||||
{
|
{
|
||||||
pages_freed++;
|
pages_freed++;
|
||||||
PMM::free_page((void*)pt_pde.get_address());
|
PMM::free_page((void*)pt_pde.get_address());
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
PageTable* pt = (PageTable*)pt_pde.get_address();
|
PageTable* pt = (PageTable*)pt_pde.get_address();
|
||||||
@ -134,7 +115,6 @@ void AddressSpace::clear()
|
|||||||
{
|
{
|
||||||
PageDirectoryEntry& pde = pt->entries[l];
|
PageDirectoryEntry& pde = pt->entries[l];
|
||||||
if (!pde.present) continue;
|
if (!pde.present) continue;
|
||||||
if (!pde.owned_by_task) continue;
|
|
||||||
pages_freed++;
|
pages_freed++;
|
||||||
PMM::free_page((void*)pde.get_address());
|
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.present) continue;
|
||||||
if (pdp_pde.larger_pages)
|
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());
|
void* cloned = try_clone_page_table((PageTable*)pdp_pde.get_address());
|
||||||
if (!cloned)
|
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.present) continue;
|
||||||
if (pd_pde.larger_pages)
|
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());
|
void* cloned = try_clone_page_table((PageTable*)pd_pde.get_address());
|
||||||
if (!cloned)
|
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.present) continue;
|
||||||
if (pt_pde.larger_pages)
|
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());
|
void* cloned = try_clone_page_table((PageTable*)pt_pde.get_address());
|
||||||
if (!cloned)
|
if (!cloned)
|
||||||
{
|
{
|
||||||
@ -258,11 +223,6 @@ AddressSpace AddressSpace::clone() // FIXME: Add out-of-memory checks to this fu
|
|||||||
{
|
{
|
||||||
PageDirectoryEntry& pde = pt->entries[l];
|
PageDirectoryEntry& pde = pt->entries[l];
|
||||||
PageDirectoryEntry& cloned_pde = cloned_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;
|
if (!pde.present) continue;
|
||||||
void* cloned = try_clone_page_table((PageTable*)pde.get_address());
|
void* cloned = try_clone_page_table((PageTable*)pde.get_address());
|
||||||
if (!cloned)
|
if (!cloned)
|
||||||
|
@ -35,6 +35,7 @@ static void bitmap_set(uint64_t index, bool value)
|
|||||||
void KernelHeap::clear()
|
void KernelHeap::clear()
|
||||||
{
|
{
|
||||||
memset(page_bitmap, 0, sizeof(page_bitmap));
|
memset(page_bitmap, 0, sizeof(page_bitmap));
|
||||||
|
kinfoln("page bitmap located at %p", (void*)page_bitmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t KernelHeap::request_virtual_page()
|
uint64_t KernelHeap::request_virtual_page()
|
||||||
|
@ -7,8 +7,7 @@
|
|||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include "memory/PMM.h"
|
#include "memory/PMM.h"
|
||||||
#include "memory/VMM.h"
|
#include "memory/VMM.h"
|
||||||
#include "misc/utils.h"
|
#include "std/assert.h"
|
||||||
#include "std/ensure.h"
|
|
||||||
|
|
||||||
void MemoryManager::init()
|
void MemoryManager::init()
|
||||||
{
|
{
|
||||||
@ -18,19 +17,6 @@ void MemoryManager::init()
|
|||||||
PMM::map_bitmap_to_virtual();
|
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)
|
void* MemoryManager::get_mapping(void* physicalAddress, int flags)
|
||||||
{
|
{
|
||||||
uint64_t virtualAddress = KernelHeap::request_virtual_page();
|
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)
|
void MemoryManager::release_page(void* page)
|
||||||
{
|
{
|
||||||
uint64_t physicalAddress = VMM::get_physical((uint64_t)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);
|
VMM::unmap((uint64_t)page);
|
||||||
PMM::free_page((void*)physicalAddress);
|
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));
|
void* page = (void*)((uint64_t)pages + (i * PAGE_SIZE));
|
||||||
uint64_t physicalAddress = VMM::get_physical((uint64_t)page);
|
uint64_t physicalAddress = VMM::get_physical((uint64_t)page);
|
||||||
ensure(physicalAddress != UINT64_MAX);
|
ASSERT(physicalAddress != UINT64_MAX);
|
||||||
VMM::unmap((uint64_t)page);
|
VMM::unmap((uint64_t)page);
|
||||||
PMM::free_page((void*)physicalAddress);
|
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); }
|
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/Memory.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include "misc/utils.h"
|
#include "misc/utils.h"
|
||||||
#include "std/ensure.h"
|
#include "std/assert.h"
|
||||||
#include "std/string.h"
|
#include "std/string.h"
|
||||||
|
|
||||||
extern BOOTBOOT bootboot;
|
extern BOOTBOOT bootboot;
|
||||||
@ -50,7 +50,7 @@ void PMM::init()
|
|||||||
|
|
||||||
bitmap_addr = (char*)biggest_chunk;
|
bitmap_addr = (char*)biggest_chunk;
|
||||||
virtual_bitmap_addr = bitmap_addr;
|
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;
|
bitmap_size = total_mem / PAGE_SIZE / 8 + 1;
|
||||||
memset(bitmap_addr, 0xFF, bitmap_size);
|
memset(bitmap_addr, 0xFF, bitmap_size);
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#include "log/Log.h"
|
#include "log/Log.h"
|
||||||
#include "memory/PMM.h"
|
#include "memory/PMM.h"
|
||||||
#include "misc/utils.h"
|
#include "misc/utils.h"
|
||||||
#include "std/ensure.h"
|
#include "std/assert.h"
|
||||||
#include "std/string.h"
|
#include "std/string.h"
|
||||||
#include "utils/Addresses.h"
|
#include "utils/Addresses.h"
|
||||||
#include "utils/Registers.h"
|
#include "utils/Registers.h"
|
||||||
@ -13,8 +13,6 @@ static PageTable* kernel_pml4;
|
|||||||
static PageTable* current_pml4;
|
static PageTable* current_pml4;
|
||||||
static AddressSpace* user_address_space;
|
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()
|
void VMM::switch_back_to_kernel_address_space()
|
||||||
{
|
{
|
||||||
if (current_pml4 != kernel_pml4) { current_pml4 = kernel_pml4; }
|
if (current_pml4 != kernel_pml4) { current_pml4 = kernel_pml4; }
|
||||||
@ -61,16 +59,6 @@ void VMM::init()
|
|||||||
{
|
{
|
||||||
kernel_pml4 = (PageTable*)read_cr3();
|
kernel_pml4 = (PageTable*)read_cr3();
|
||||||
current_pml4 = kernel_pml4;
|
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)
|
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);
|
if (flags & ReadWrite) propagate_read_write(current_pml4, vaddr);
|
||||||
else
|
else
|
||||||
pde->read_write = false;
|
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);
|
flush_tlb(vaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,13 +99,11 @@ uint64_t VMM::get_physical(uint64_t vaddr)
|
|||||||
uint64_t VMM::get_flags(uint64_t vaddr)
|
uint64_t VMM::get_flags(uint64_t vaddr)
|
||||||
{
|
{
|
||||||
PageDirectoryEntry* pde = find_pde(current_pml4, round_down_to_nearest_page(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;
|
uint64_t flags = 0;
|
||||||
if (pde->user) flags |= User;
|
if (pde->user) flags |= User;
|
||||||
if (pde->read_write) flags |= ReadWrite;
|
if (pde->read_write) flags |= ReadWrite;
|
||||||
if (!pde->no_execute) flags |= Execute;
|
|
||||||
if (pde->owned_by_task) flags |= OwnedByTask;
|
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +121,6 @@ void VMM::map(uint64_t vaddr, uint64_t paddr, int flags)
|
|||||||
{
|
{
|
||||||
unmap(vaddr);
|
unmap(vaddr);
|
||||||
pde = create_pde_if_not_exists(current_pml4, 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));
|
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);
|
if (flags & ReadWrite) propagate_read_write(current_pml4, vaddr);
|
||||||
else
|
else
|
||||||
pde->read_write = false;
|
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);
|
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 = [&]() {
|
auto pde_create_if_not_present = [&]() {
|
||||||
pt = (PageTable*)PMM::request_page();
|
pt = (PageTable*)PMM::request_page();
|
||||||
ensure(!(PMM_DID_FAIL(pt)));
|
ASSERT(!(PMM_DID_FAIL(pt)));
|
||||||
memset(pt, 0, PAGE_SIZE);
|
memset(pt, 0, PAGE_SIZE);
|
||||||
pde->set_address((uint64_t)pt);
|
pde->set_address((uint64_t)pt);
|
||||||
pde->present = true;
|
pde->present = true;
|
||||||
@ -273,44 +246,11 @@ void VMM::propagate_user(PageTable* root, uint64_t vaddr)
|
|||||||
pde->user = true;
|
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)
|
void VMM::flush_tlb(uint64_t addr)
|
||||||
{
|
{
|
||||||
asm volatile("invlpg (%0)" : : "r"(addr) : "memory");
|
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,
|
void VMM::decompose_vaddr(uint64_t vaddr, uint64_t& page_index, uint64_t& pt_index, uint64_t& pd_index,
|
||||||
uint64_t& pdp_index)
|
uint64_t& pdp_index)
|
||||||
{
|
{
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef MOON_MINOR
|
#ifndef MOON_MINOR
|
||||||
#define MOON_MINOR 14
|
#define MOON_MINOR 13
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef _MOON_SUFFIX
|
#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"
|
#define MODULE "panic"
|
||||||
|
|
||||||
#include "panic/Panic.h"
|
#include "panic/Panic.h"
|
||||||
#include "fs/InitRD.h"
|
#include "init/InitRD.h"
|
||||||
#include "interrupts/IDT.h"
|
#include "interrupts/IDT.h"
|
||||||
#include "io/PIC.h"
|
#include "io/PIC.h"
|
||||||
#include "log/Log.h"
|
#include "log/Log.h"
|
||||||
@ -16,7 +16,7 @@
|
|||||||
static bool g_is_in_panic = false;
|
static bool g_is_in_panic = false;
|
||||||
static bool g_is_in_double_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_master(0b11111101); // enable keyboard only
|
||||||
PIC::enable_slave(0b11111111);
|
PIC::enable_slave(0b11111111);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#define MODULE "rand"
|
#define MODULE "rand"
|
||||||
|
|
||||||
#include "rand/Mersenne.h"
|
#include "rand/Mersenne.h"
|
||||||
#include "std/ensure.h"
|
#include "std/assert.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
typedef uint64_t word_t;
|
typedef uint64_t word_t;
|
||||||
@ -47,7 +47,7 @@ uint64_t Mersenne::get()
|
|||||||
{
|
{
|
||||||
if (index >= STATE_SIZE)
|
if (index >= STATE_SIZE)
|
||||||
{
|
{
|
||||||
ensure(index == STATE_SIZE && "Mersenne generator was never seeded");
|
ASSERT(index == STATE_SIZE && "Mersenne generator was never seeded");
|
||||||
twist();
|
twist();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#include "render/TextRenderer.h"
|
#include "render/TextRenderer.h"
|
||||||
#include "bootboot.h"
|
#include "bootboot.h"
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
#include "fs/InitRD.h"
|
#include "init/InitRD.h"
|
||||||
#include "io/Serial.h"
|
#include "io/Serial.h"
|
||||||
#include "log/Log.h"
|
#include "log/Log.h"
|
||||||
#include "render/Framebuffer.h"
|
#include "render/Framebuffer.h"
|
||||||
@ -30,7 +30,7 @@ void TextRenderer::reset()
|
|||||||
#pragma GCC optimize("O0")
|
#pragma GCC optimize("O0")
|
||||||
|
|
||||||
static void putchar_at_offset(
|
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.
|
[[maybe_unused]] Color& bg) // FIXME: Rewrite this function to actually work with foreground and background colors.
|
||||||
{
|
{
|
||||||
uint8_t* glyph = &font[c * 16];
|
uint8_t* glyph = &font[c * 16];
|
||||||
@ -46,26 +46,10 @@ static void putchar_at_offset(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool g_escape_sequence = false;
|
|
||||||
|
|
||||||
#pragma GCC pop_options
|
#pragma GCC pop_options
|
||||||
|
|
||||||
void TextRenderer::putchar(char chr)
|
void TextRenderer::putchar(char chr)
|
||||||
{
|
{
|
||||||
if (g_escape_sequence)
|
|
||||||
{
|
|
||||||
g_escape_sequence = false;
|
|
||||||
switch (chr)
|
|
||||||
{
|
|
||||||
case '@':
|
|
||||||
reset();
|
|
||||||
framebuffer0.clear(Color::Black);
|
|
||||||
break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch (chr)
|
switch (chr)
|
||||||
{
|
{
|
||||||
case '\n': {
|
case '\n': {
|
||||||
@ -88,7 +72,6 @@ void TextRenderer::putchar(char chr)
|
|||||||
framebuffer0.paint_rect(xpos, ypos, FONT_WIDTH, FONT_HEIGHT, Color::Black);
|
framebuffer0.paint_rect(xpos, ypos, FONT_WIDTH, FONT_HEIGHT, Color::Black);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case '\033': g_escape_sequence = true; break;
|
|
||||||
default: {
|
default: {
|
||||||
putchar_at_offset(chr, xpos, ypos, fgColor, bgColor);
|
putchar_at_offset(chr, xpos, ypos, fgColor, bgColor);
|
||||||
xpos += FONT_WIDTH;
|
xpos += FONT_WIDTH;
|
||||||
@ -96,7 +79,7 @@ void TextRenderer::putchar(char chr)
|
|||||||
{
|
{
|
||||||
xpos = 0;
|
xpos = 0;
|
||||||
ypos += FONT_HEIGHT;
|
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),
|
memcpy((void*)bootboot.fb_ptr, (char*)bootboot.fb_ptr + (bootboot.fb_scanline * FONT_HEIGHT),
|
||||||
bootboot.fb_size - (bootboot.fb_scanline * FONT_HEIGHT));
|
bootboot.fb_size - (bootboot.fb_scanline * FONT_HEIGHT));
|
||||||
@ -107,7 +90,6 @@ void TextRenderer::putchar(char chr)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextRenderer::write(const char* str, size_t size)
|
void TextRenderer::write(const char* str, size_t size)
|
||||||
|
@ -228,7 +228,6 @@ int sprintf(char* __s, const char* fmt, ...)
|
|||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
if (__s) *__s = 0;
|
|
||||||
int written = internal_printf(
|
int written = internal_printf(
|
||||||
fmt,
|
fmt,
|
||||||
[&](const char* s) {
|
[&](const char* s) {
|
||||||
@ -243,7 +242,6 @@ int snprintf(char* __s, size_t max, const char* fmt, ...)
|
|||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
if (__s && max) *__s = 0;
|
|
||||||
int written = internal_printf(
|
int written = internal_printf(
|
||||||
fmt,
|
fmt,
|
||||||
[&](const char* s) {
|
[&](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)
|
int vsprintf(char* __s, const char* fmt, va_list ap)
|
||||||
{
|
{
|
||||||
*__s = 0;
|
|
||||||
return internal_printf(
|
return internal_printf(
|
||||||
fmt,
|
fmt,
|
||||||
[&](const char* s) {
|
[&](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)
|
int vsnprintf(char* __s, size_t max, const char* fmt, va_list ap)
|
||||||
{
|
{
|
||||||
if (max) *__s = 0;
|
|
||||||
return internal_printf(
|
return internal_printf(
|
||||||
fmt,
|
fmt,
|
||||||
[&](const char* s) {
|
[&](const char* s) {
|
||||||
|
@ -15,36 +15,27 @@ void Syscall::entry(Context* context)
|
|||||||
case SYS_yield: sys_yield(context); break;
|
case SYS_yield: sys_yield(context); break;
|
||||||
case SYS_sleep: sys_sleep(context, context->rdi); 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_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_getprocid: sys_getprocid(context, (int)context->rdi); break;
|
||||||
case SYS_mmap:
|
case SYS_mmap: sys_mmap(context, (void*)context->rdi, context->rsi, (int)context->rdx); break;
|
||||||
sys_mmap(context, (void*)context->rdi, context->rsi, (int)context->rdx, (int)context->r10, (off_t)context->r8);
|
|
||||||
break;
|
|
||||||
case SYS_munmap: sys_munmap(context, (void*)context->rdi, context->rsi); 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_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_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_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_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_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_clock: sys_clock(context); break;
|
||||||
case SYS_mkdir: sys_mkdir(context, (const char*)context->rdi, (mode_t)context->rsi); break;
|
case SYS_mkdir: sys_mkdir(context, (const char*)context->rdi); break;
|
||||||
case SYS_fork: sys_fork(context); 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_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_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_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_pstat: sys_pstat(context, (long)context->rdi, (struct pstat*)context->rsi); break;
|
||||||
case SYS_getdents:
|
case SYS_getdents:
|
||||||
sys_getdents(context, (int)context->rdi, (struct luna_dirent*)context->rsi, (size_t)context->rdx);
|
sys_getdents(context, (int)context->rdi, (struct luna_dirent*)context->rsi, (size_t)context->rdx);
|
||||||
break;
|
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;
|
default: context->rax = -ENOSYS; break;
|
||||||
}
|
}
|
||||||
VMM::exit_syscall_context();
|
VMM::exit_syscall_context();
|
||||||
|
@ -1,212 +1,10 @@
|
|||||||
#include "sys/UserMemory.h"
|
#include "sys/UserMemory.h"
|
||||||
#include "memory/Memory.h"
|
|
||||||
#include "memory/MemoryManager.h"
|
|
||||||
#include "std/stdlib.h"
|
|
||||||
#include "std/string.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;
|
uint64_t phys = VMM::get_physical((uint64_t)user_string);
|
||||||
long capacity;
|
if (phys == (uint64_t)-1) { return nullptr; }
|
||||||
long size;
|
return strdup((const char*)phys);
|
||||||
};
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
@ -1,83 +1,9 @@
|
|||||||
#include "bootboot.h"
|
|
||||||
#include "interrupts/Context.h"
|
#include "interrupts/Context.h"
|
||||||
#include "std/errno.h"
|
|
||||||
#include "sys/UserMemory.h"
|
|
||||||
#include "thread/PIT.h"
|
|
||||||
#include "thread/Scheduler.h"
|
#include "thread/Scheduler.h"
|
||||||
#include "utils/Time.h"
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
static uint64_t unix_boot_time;
|
void sys_clock(Context* context)
|
||||||
|
|
||||||
#define CLOCK_REALTIME 0
|
|
||||||
#define CLOCK_MONOTONIC 1
|
|
||||||
#define CLOCK_PROCTIME 2
|
|
||||||
|
|
||||||
struct timeval
|
|
||||||
{
|
{
|
||||||
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();
|
Task* current_task = Scheduler::current_task();
|
||||||
switch (clock)
|
context->rax = (long)current_task->cpu_time;
|
||||||
{
|
|
||||||
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;
|
|
||||||
return;
|
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"
|
#define MODULE "elf"
|
||||||
|
|
||||||
#include "sys/elf/ELFLoader.h"
|
#include "sys/elf/ELFLoader.h"
|
||||||
#include "fs/InitRD.h"
|
|
||||||
#include "fs/VFS.h"
|
#include "fs/VFS.h"
|
||||||
|
#include "init/InitRD.h"
|
||||||
#include "log/Log.h"
|
#include "log/Log.h"
|
||||||
#include "memory/Memory.h"
|
#include "memory/Memory.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include "memory/VMM.h"
|
#include "memory/VMM.h"
|
||||||
#include "misc/utils.h"
|
#include "misc/utils.h"
|
||||||
#include "std/ensure.h"
|
#include "std/assert.h"
|
||||||
#include "std/errno.h"
|
#include "std/errno.h"
|
||||||
#include "std/stdlib.h"
|
#include "std/stdlib.h"
|
||||||
#include "std/string.h"
|
#include "std/string.h"
|
||||||
@ -25,16 +25,6 @@ static const char* format_permissions(uint32_t flags)
|
|||||||
return perms;
|
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)
|
ELFImage* ELFLoader::load_elf_from_filesystem(const char* filename)
|
||||||
{
|
{
|
||||||
VFS::Node* node = VFS::resolve_path(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)
|
ELFImage* ELFLoader::load_elf_from_vfs(VFS::Node* node)
|
||||||
{
|
{
|
||||||
Elf64_Ehdr elf_ehdr;
|
Elf64_Ehdr elf_ehdr;
|
||||||
ensure(VFS::read(node, 0, sizeof(elf_ehdr), (char*)&elf_ehdr) >= 0);
|
ASSERT(VFS::read(node, 0, sizeof(elf_ehdr), (char*)&elf_ehdr) >= 0);
|
||||||
ensure(strncmp((const char*)elf_ehdr.e_ident, ELFMAG, SELFMAG) ==
|
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
|
0); // If you haven't checked the ELF executable with check_elf_image() first, then an assertion fail is your
|
||||||
// fault =D
|
// fault =D
|
||||||
ensure(elf_ehdr.e_ident[EI_CLASS] == ELFCLASS64);
|
ASSERT(elf_ehdr.e_ident[EI_CLASS] == ELFCLASS64);
|
||||||
ensure(elf_ehdr.e_ident[EI_DATA] == ELFDATA2LSB);
|
ASSERT(elf_ehdr.e_ident[EI_DATA] == ELFDATA2LSB);
|
||||||
ensure(elf_ehdr.e_type == ET_EXEC);
|
ASSERT(elf_ehdr.e_type == ET_EXEC);
|
||||||
ensure(elf_ehdr.e_machine == EM_MACH);
|
ASSERT(elf_ehdr.e_machine == EM_MACH);
|
||||||
ensure(elf_ehdr.e_phnum != 0);
|
ASSERT(elf_ehdr.e_phnum != 0);
|
||||||
ELFImage* image = (ELFImage*)kmalloc(sizeof(ELFImage) - sizeof(ELFSection));
|
ELFImage* image = (ELFImage*)kmalloc(sizeof(ELFImage) - sizeof(ELFSection));
|
||||||
memset(image, 0, sizeof(ELFImage) - sizeof(ELFSection));
|
memset(image, 0, sizeof(ELFImage) - sizeof(ELFSection));
|
||||||
image->entry = elf_ehdr.e_entry;
|
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,
|
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));
|
phdr.p_filesz, phdr.p_memsz, format_permissions(phdr.p_flags));
|
||||||
ensure(phdr.p_vaddr);
|
ASSERT(phdr.p_vaddr);
|
||||||
|
|
||||||
ensure(!(can_write_segment(phdr.p_flags) && can_execute_segment(phdr.p_flags)));
|
|
||||||
|
|
||||||
uint64_t pages = Utilities::get_blocks_from_size(PAGE_SIZE, (phdr.p_vaddr % PAGE_SIZE) + phdr.p_memsz);
|
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),
|
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::apply_address_space();
|
||||||
VMM::switch_to_previous_user_address_space();
|
VMM::switch_to_previous_user_address_space();
|
||||||
|
|
||||||
int new_flags = MAP_USER | MAP_AS_OWNED_BY_TASK;
|
MemoryManager::protect(buffer, pages, phdr.p_flags & 2 ? MAP_READ_WRITE | MAP_USER : MAP_USER);
|
||||||
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);
|
|
||||||
|
|
||||||
image = (ELFImage*)krealloc(image, (sizeof(ELFImage) - sizeof(ELFSection)) +
|
image = (ELFImage*)krealloc(image, (sizeof(ELFImage) - sizeof(ELFSection)) +
|
||||||
(image->section_count + 1) * 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"); }
|
else { kdbgln("skipping non-loadable segment"); }
|
||||||
}
|
}
|
||||||
ensure(image->section_count);
|
ASSERT(image->section_count);
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,11 +177,6 @@ long ELFLoader::check_elf_image(VFS::Node* node)
|
|||||||
kerrorln("trying to load ELF into kernel memory");
|
kerrorln("trying to load ELF into kernel memory");
|
||||||
return -ENOEXEC;
|
return -ENOEXEC;
|
||||||
}
|
}
|
||||||
if (can_write_segment(phdr.p_flags) && can_execute_segment(phdr.p_flags))
|
|
||||||
{
|
|
||||||
kwarnln("executable violates W^X");
|
|
||||||
return -ENOEXEC;
|
|
||||||
}
|
|
||||||
loadable_sections++;
|
loadable_sections++;
|
||||||
memusage += Utilities::get_blocks_from_size(PAGE_SIZE, phdr.p_memsz) * PAGE_SIZE;
|
memusage += Utilities::get_blocks_from_size(PAGE_SIZE, phdr.p_memsz) * PAGE_SIZE;
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,10 @@
|
|||||||
|
|
||||||
#include "interrupts/Interrupts.h"
|
#include "interrupts/Interrupts.h"
|
||||||
#include "log/Log.h"
|
#include "log/Log.h"
|
||||||
#include "memory/Memory.h"
|
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include "memory/PMM.h"
|
#include "memory/PMM.h"
|
||||||
#include "memory/VMM.h"
|
#include "memory/VMM.h"
|
||||||
#include "std/ensure.h"
|
#include "std/assert.h"
|
||||||
#include "std/errno.h"
|
#include "std/errno.h"
|
||||||
#include "std/stdlib.h"
|
#include "std/stdlib.h"
|
||||||
#include "std/string.h"
|
#include "std/string.h"
|
||||||
@ -45,11 +44,6 @@ void sys_fork(Context* context)
|
|||||||
|
|
||||||
child->ppid = parent->id;
|
child->ppid = parent->id;
|
||||||
|
|
||||||
child->uid = parent->uid;
|
|
||||||
child->euid = parent->euid;
|
|
||||||
child->gid = parent->gid;
|
|
||||||
child->egid = parent->egid;
|
|
||||||
|
|
||||||
child->regs.rax = 0;
|
child->regs.rax = 0;
|
||||||
context->rax = child->id;
|
context->rax = child->id;
|
||||||
|
|
||||||
@ -62,16 +56,7 @@ void sys_fork(Context* context)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_on_user_stack(uint64_t* rsp, char* value,
|
void sys_exec(Context* context, const char* pathname)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
char* kpathname = strdup_from_user(pathname);
|
char* kpathname = strdup_from_user(pathname);
|
||||||
if (!kpathname)
|
if (!kpathname)
|
||||||
@ -97,13 +82,6 @@ void sys_execv(Context* context, const char* pathname, char** argv)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!VFS::can_execute(program, Scheduler::current_task()->euid, Scheduler::current_task()->egid))
|
|
||||||
{
|
|
||||||
kfree(kpathname);
|
|
||||||
context->rax = -EACCES;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
long memusage;
|
long memusage;
|
||||||
if ((memusage = ELFLoader::check_elf_image(program)) < 0)
|
if ((memusage = ELFLoader::check_elf_image(program)) < 0)
|
||||||
{
|
{
|
||||||
@ -119,88 +97,11 @@ void sys_execv(Context* context, const char* pathname, char** argv)
|
|||||||
return;
|
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();
|
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();
|
Task* task = Scheduler::current_task();
|
||||||
ensure(task);
|
ASSERT(task);
|
||||||
|
|
||||||
// At this point, pretty much nothing can fail.
|
// 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->address_space.clear();
|
||||||
task->allocated_stack = (uint64_t)MemoryManager::get_pages_at(
|
task->allocated_stack = (uint64_t)MemoryManager::get_pages_at(
|
||||||
0x100000, TASK_PAGES_IN_STACK,
|
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
|
MAP_USER | MAP_READ_WRITE); // If we had enough space for the old stack, there should be enough space for the
|
||||||
// enough space for the new stack.
|
// new stack.
|
||||||
|
|
||||||
ELFImage* image = ELFLoader::load_elf_from_vfs(program);
|
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.
|
// 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));
|
strlcpy(task->name, kpathname, sizeof(task->name));
|
||||||
|
|
||||||
Scheduler::reset_task(task, image);
|
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(); }
|
if (file.close_on_exec()) { file.close(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint64_t i = 0; i <= kargc; i++)
|
task->restore_context(context);
|
||||||
{
|
|
||||||
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);
|
|
||||||
|
|
||||||
kfree(kpathname);
|
kfree(kpathname);
|
||||||
|
|
||||||
task->restore_context(context);
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
@ -1,13 +1,8 @@
|
|||||||
#include "std/errno.h"
|
#include "std/errno.h"
|
||||||
#include "thread/Scheduler.h"
|
#include "thread/Scheduler.h"
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
#define ID_PID 0
|
#define ID_PID 0
|
||||||
#define ID_PPID 1
|
#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)
|
void sys_getprocid(Context* context, int field)
|
||||||
{
|
{
|
||||||
@ -21,103 +16,9 @@ void sys_getprocid(Context* context, int field)
|
|||||||
context->rax = Scheduler::current_task()->ppid;
|
context->rax = Scheduler::current_task()->ppid;
|
||||||
return;
|
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
|
else
|
||||||
{
|
{
|
||||||
context->rax = -EINVAL;
|
context->rax = -EINVAL;
|
||||||
return;
|
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 "thread/Scheduler.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#define PROT_READ 1
|
#define MAP_READ 1
|
||||||
#define PROT_WRITE 2
|
#define MAP_WRITE 2
|
||||||
#define PROT_NONE 0
|
#define MAP_NONE 0
|
||||||
#define PROT_EXEC 4
|
|
||||||
|
|
||||||
#define MAP_FAIL(errno) 0xffffffffffffff00 | (unsigned char)(errno)
|
#define MAP_FAIL(errno) 0xffffffffffffff00 | (unsigned char)(errno)
|
||||||
|
|
||||||
static const char* format_prot(int prot)
|
static const char* format_prot(int prot)
|
||||||
{
|
{
|
||||||
static char prot_string[4];
|
static char prot_string[3];
|
||||||
prot_string[3] = 0;
|
prot_string[2] = 0;
|
||||||
prot_string[0] = ((prot & PROT_READ) > 0) ? 'r' : '-';
|
prot_string[0] = ((prot & MAP_READ) > 0) ? 'r' : '-';
|
||||||
prot_string[1] = ((prot & PROT_WRITE) > 0) ? 'w' : '-';
|
prot_string[1] = ((prot & MAP_WRITE) > 0) ? 'w' : '-';
|
||||||
prot_string[2] = ((prot & PROT_EXEC) > 0) ? 'x' : '-';
|
|
||||||
return prot_string;
|
return prot_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mman_flags_from_prot(int prot)
|
static int mman_flags_from_prot(int prot)
|
||||||
{
|
{
|
||||||
prot &= 0b111;
|
prot &= 0b11;
|
||||||
int flags = MAP_USER | MAP_AS_OWNED_BY_TASK;
|
if (prot == MAP_NONE) return 0;
|
||||||
if (prot == PROT_NONE) return MAP_AS_OWNED_BY_TASK;
|
if ((prot & MAP_WRITE) > 0) return MAP_USER | MAP_READ_WRITE;
|
||||||
if ((prot & PROT_WRITE) > 0) { flags |= MAP_READ_WRITE; }
|
return MAP_USER;
|
||||||
if ((prot & PROT_EXEC) > 0) { flags |= MAP_EXEC; }
|
|
||||||
return flags;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
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);
|
int real_flags = mman_flags_from_prot(prot);
|
||||||
if (address)
|
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))
|
if (Memory::is_kernel_address((uintptr_t)address))
|
||||||
{
|
{
|
||||||
kwarnln("munmap() failed: attempted to unmap a kernel page");
|
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);
|
context->rax = MAP_FAIL(ENOMEM);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uint64_t addr_offset = (uint64_t)address % PAGE_SIZE;
|
uint64_t offset = (uint64_t)address % PAGE_SIZE;
|
||||||
if (fd >= 0)
|
void* result = MemoryManager::get_pages_at((uint64_t)address - offset,
|
||||||
{
|
|
||||||
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,
|
|
||||||
Utilities::get_blocks_from_size(PAGE_SIZE, size), real_flags);
|
Utilities::get_blocks_from_size(PAGE_SIZE, size), real_flags);
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
@ -95,8 +79,7 @@ void sys_mmap(Context* context, void* address, size_t size, int prot, int fd, of
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
kdbgln("mmap(): %ld pages at any address, %s, fd %d", Utilities::get_blocks_from_size(PAGE_SIZE, size),
|
kdbgln("mmap(): %ld pages at any address, %s", Utilities::get_blocks_from_size(PAGE_SIZE, size), format_prot(prot));
|
||||||
format_prot(prot), fd);
|
|
||||||
uint64_t ptr =
|
uint64_t ptr =
|
||||||
Scheduler::current_task()->allocator.request_virtual_pages(Utilities::get_blocks_from_size(PAGE_SIZE, size));
|
Scheduler::current_task()->allocator.request_virtual_pages(Utilities::get_blocks_from_size(PAGE_SIZE, size));
|
||||||
if (!ptr)
|
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);
|
context->rax = MAP_FAIL(ENOMEM);
|
||||||
return;
|
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);
|
void* result = MemoryManager::get_pages_at(ptr, Utilities::get_blocks_from_size(PAGE_SIZE, size), real_flags);
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
@ -159,8 +130,8 @@ void sys_munmap(Context* context, void* address, size_t size)
|
|||||||
context->rax = -EINVAL;
|
context->rax = -EINVAL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uint64_t flags = VMM::get_flags((uint64_t)address);
|
uint64_t phys = VMM::get_physical((uint64_t)address);
|
||||||
if (flags == (uint64_t)-1)
|
if (phys == (uint64_t)-1)
|
||||||
{
|
{
|
||||||
kwarnln("munmap() failed: attempted to unmap a non-existent page");
|
kwarnln("munmap() failed: attempted to unmap a non-existent page");
|
||||||
context->rax = -EINVAL;
|
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;
|
uint64_t offset = (uint64_t)address % PAGE_SIZE;
|
||||||
Scheduler::current_task()->allocator.free_virtual_pages(((uint64_t)address - offset),
|
Scheduler::current_task()->allocator.free_virtual_pages(((uint64_t)address - offset),
|
||||||
Utilities::get_blocks_from_size(PAGE_SIZE, size));
|
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));
|
||||||
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));
|
|
||||||
kdbgln("munmap() succeeded");
|
kdbgln("munmap() succeeded");
|
||||||
context->rax = 0;
|
context->rax = 0;
|
||||||
return;
|
return;
|
||||||
@ -208,8 +174,8 @@ void sys_mprotect(Context* context, void* address, size_t size, int prot)
|
|||||||
context->rax = -EINVAL;
|
context->rax = -EINVAL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uint64_t flags = VMM::get_flags((uint64_t)address);
|
uint64_t phys = VMM::get_physical((uint64_t)address);
|
||||||
if (flags == (uint64_t)-1)
|
if (phys == (uint64_t)-1)
|
||||||
{
|
{
|
||||||
kwarnln("mprotect() failed: attempted to protect a non-existent page");
|
kwarnln("mprotect() failed: attempted to protect a non-existent page");
|
||||||
context->rax = -EINVAL;
|
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;
|
uint64_t offset = (uint64_t)address % PAGE_SIZE;
|
||||||
MemoryManager::protect((void*)((uint64_t)address - offset), Utilities::get_blocks_from_size(PAGE_SIZE, 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));
|
||||||
: mman_flags_from_prot(prot) & ~(MAP_AS_OWNED_BY_TASK));
|
|
||||||
kdbgln("mprotect() succeeded");
|
kdbgln("mprotect() succeeded");
|
||||||
context->rax = 0;
|
context->rax = 0;
|
||||||
return;
|
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 "fs/VFS.h"
|
||||||
#include "interrupts/Context.h"
|
#include "interrupts/Context.h"
|
||||||
#include "std/errno.h"
|
#include "std/errno.h"
|
||||||
#include "std/stdlib.h"
|
|
||||||
#include "sys/UserMemory.h"
|
#include "sys/UserMemory.h"
|
||||||
#include "thread/Scheduler.h"
|
#include "thread/Scheduler.h"
|
||||||
|
|
||||||
|
typedef unsigned long off_t;
|
||||||
typedef unsigned short mode_t;
|
typedef unsigned short mode_t;
|
||||||
typedef unsigned long ino_t;
|
typedef unsigned long ino_t;
|
||||||
|
|
||||||
@ -13,37 +13,8 @@ struct stat // FIXME: This struct is quite stubbed out.
|
|||||||
ino_t st_ino;
|
ino_t st_ino;
|
||||||
mode_t st_mode;
|
mode_t st_mode;
|
||||||
off_t st_size;
|
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)
|
void sys_fstat(Context* context, int fd, struct stat* buf)
|
||||||
{
|
{
|
||||||
Task* current_task = Scheduler::current_task();
|
Task* current_task = Scheduler::current_task();
|
||||||
@ -58,24 +29,16 @@ void sys_fstat(Context* context, int fd, struct stat* buf)
|
|||||||
context->rax = -EBADF;
|
context->rax = -EBADF;
|
||||||
return;
|
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();
|
VFS::Node* node = file.node();
|
||||||
return do_stat(context, node, buf);
|
kstat->st_ino = node->inode;
|
||||||
}
|
kstat->st_mode = (mode_t)node->type;
|
||||||
|
kstat->st_size = node->length;
|
||||||
void sys_stat(Context* context, const char* path, struct stat* buf)
|
release_user_ref(kstat);
|
||||||
{
|
context->rax = 0;
|
||||||
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);
|
|
||||||
}
|
}
|
@ -11,17 +11,12 @@
|
|||||||
#include "sys/UserMemory.h"
|
#include "sys/UserMemory.h"
|
||||||
#include "thread/Scheduler.h"
|
#include "thread/Scheduler.h"
|
||||||
#include "thread/Task.h"
|
#include "thread/Task.h"
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
#define OPEN_READ 1
|
#define OPEN_READ 1
|
||||||
#define OPEN_WRITE 2
|
#define OPEN_WRITE 2
|
||||||
#define OPEN_NONBLOCK 4
|
#define OPEN_NONBLOCK 4
|
||||||
#define OPEN_CLOEXEC 8
|
#define OPEN_CLOEXEC 8
|
||||||
#define OPEN_DIRECTORY 16
|
#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_SET 0
|
||||||
#define SEEK_CUR 1
|
#define SEEK_CUR 1
|
||||||
@ -29,64 +24,47 @@
|
|||||||
|
|
||||||
#define FCNTL_DUPFD 0
|
#define FCNTL_DUPFD 0
|
||||||
#define FCNTL_ISTTY 1
|
#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)
|
void sys_fcntl(Context* context, int fd, int command, uintptr_t arg)
|
||||||
{
|
{
|
||||||
Task* current_task = Scheduler::current_task();
|
if (fd >= TASK_MAX_FDS || fd < 0)
|
||||||
int err;
|
|
||||||
Descriptor* file = current_task->open_descriptor_from_fd(fd, err);
|
|
||||||
if (!file)
|
|
||||||
{
|
{
|
||||||
context->rax = -err;
|
context->rax = -EBADF;
|
||||||
return;
|
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)
|
if (command == FCNTL_DUPFD)
|
||||||
{
|
{
|
||||||
int minfd = (int)arg;
|
if ((int)arg < 0 || (int)arg >= TASK_MAX_FDS)
|
||||||
if (minfd < 0 || minfd >= TASK_MAX_FDS)
|
|
||||||
{
|
{
|
||||||
context->rax = -EINVAL;
|
context->rax = -EINVAL;
|
||||||
return;
|
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)
|
if (dupfd < 0)
|
||||||
{
|
{
|
||||||
context->rax = -EMFILE;
|
context->rax = -EMFILE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
current_task->files[dupfd] = *file;
|
current_task->files[dupfd] = file;
|
||||||
context->rax = dupfd;
|
context->rax = dupfd;
|
||||||
kdbgln("fcntl(F_DUPFD): duplicated fd %d, result is %d", fd, dupfd);
|
kdbgln("fcntl(F_DUPFD): duplicated fd %d, result is %d", fd, dupfd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (command == FCNTL_ISTTY)
|
else if (command == FCNTL_ISTTY)
|
||||||
{
|
{
|
||||||
VFS::Node* node = file->node();
|
VFS::Node* node = file.node();
|
||||||
if (node->tty) { context->rax = 1; }
|
if (node->tty) { context->rax = 1; }
|
||||||
else
|
else
|
||||||
context->rax = -ENOTTY;
|
context->rax = -ENOTTY;
|
||||||
return;
|
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
|
else
|
||||||
{
|
{
|
||||||
context->rax = -EINVAL;
|
context->rax = -EINVAL;
|
||||||
@ -101,19 +79,24 @@ void sys_seek(Context* context, int fd, long offset, int whence)
|
|||||||
context->rax = -EINVAL;
|
context->rax = -EINVAL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int err;
|
if (fd >= TASK_MAX_FDS || fd < 0)
|
||||||
Descriptor* file = Scheduler::current_task()->open_descriptor_from_fd(fd, err);
|
|
||||||
if (!file)
|
|
||||||
{
|
{
|
||||||
context->rax = -err;
|
context->rax = -EBADF;
|
||||||
return;
|
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;
|
long new_offset;
|
||||||
if (whence == SEEK_SET) new_offset = offset;
|
if (whence == SEEK_SET) new_offset = offset;
|
||||||
else if (whence == SEEK_CUR)
|
else if (whence == SEEK_CUR)
|
||||||
new_offset = offset + file->offset();
|
new_offset = offset + file.offset();
|
||||||
else if (whence == SEEK_END)
|
else if (whence == SEEK_END)
|
||||||
new_offset = file->length() + offset;
|
new_offset = file.length() + offset;
|
||||||
else
|
else
|
||||||
__builtin_unreachable();
|
__builtin_unreachable();
|
||||||
if (new_offset < 0)
|
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?
|
context->rax = -EINVAL; // FIXME: Is this the right error?
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (new_offset == file->offset())
|
if (new_offset == file.offset())
|
||||||
{
|
{
|
||||||
context->rax = new_offset;
|
context->rax = new_offset;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int result = file->seek(new_offset);
|
int result = file.seek(new_offset);
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
{
|
{
|
||||||
context->rax = result;
|
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)
|
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;
|
context->rax = -EFAULT;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int err;
|
if (fd >= TASK_MAX_FDS || fd < 0)
|
||||||
Descriptor* file = Scheduler::current_task()->open_descriptor_from_fd(fd, err);
|
|
||||||
if (!file)
|
|
||||||
{
|
|
||||||
context->rax = -err;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!file->can_write())
|
|
||||||
{
|
{
|
||||||
context->rax = -EBADF;
|
context->rax = -EBADF;
|
||||||
return;
|
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;
|
context->rax = (size_t)result;
|
||||||
return;
|
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();
|
Task* current_task = Scheduler::current_task();
|
||||||
int fd = current_task->alloc_fd();
|
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);
|
VFS::Node* node = VFS::resolve_path(kfilename);
|
||||||
if (!node)
|
if (!node)
|
||||||
{
|
{
|
||||||
bool create = (flags & OPEN_CREATE) > 0;
|
|
||||||
if (create) kwarnln("FIXME: open(O_CREAT) is not implemented");
|
|
||||||
kfree(kfilename);
|
kfree(kfilename);
|
||||||
context->rax = -ENOENT;
|
context->rax = -ENOENT;
|
||||||
return;
|
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_read = (flags & OPEN_READ) > 0;
|
||||||
bool can_write = (flags & OPEN_WRITE) > 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;
|
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 able_to_block = (flags & OPEN_NONBLOCK) == 0;
|
||||||
bool close_on_exec = (flags & OPEN_CLOEXEC) > 0;
|
bool close_on_exec = (flags & OPEN_CLOEXEC) > 0;
|
||||||
|
|
||||||
bool only_directory = (flags & OPEN_DIRECTORY) > 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)
|
if (only_directory && node->type != VFS_DIRECTORY)
|
||||||
{
|
{
|
||||||
kfree(kfilename);
|
kfree(kfilename);
|
||||||
@ -256,71 +202,68 @@ void sys_open(Context* context, const char* filename, int flags, mode_t) // FIXM
|
|||||||
|
|
||||||
kfree(kfilename);
|
kfree(kfilename);
|
||||||
current_task->files[fd].open(node, can_read, can_write, able_to_block, close_on_exec);
|
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;
|
context->rax = fd;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sys_read(Context* context, int fd, size_t size, char* buffer)
|
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;
|
context->rax = -EFAULT;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int err;
|
if (fd >= TASK_MAX_FDS || fd < 0)
|
||||||
Descriptor* file = Scheduler::current_task()->open_descriptor_from_fd(fd, err);
|
|
||||||
if (!file)
|
|
||||||
{
|
|
||||||
context->rax = -err;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!file->can_read())
|
|
||||||
{
|
{
|
||||||
context->rax = -EBADF;
|
context->rax = -EBADF;
|
||||||
return;
|
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;
|
context->rax = -EAGAIN;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Task* current_task = Scheduler::current_task();
|
|
||||||
current_task->state = current_task->Blocking;
|
current_task->state = current_task->Blocking;
|
||||||
current_task->block_reason = BlockReason::Reading;
|
|
||||||
current_task->blocking_read_info.fd = fd;
|
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;
|
current_task->blocking_read_info.size = size;
|
||||||
return Scheduler::task_yield(context);
|
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;
|
context->rax = (size_t)result;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sys_close(Context* context, int fd)
|
void sys_close(Context* context, int fd)
|
||||||
{
|
{
|
||||||
int err;
|
if (fd >= TASK_MAX_FDS || fd < 0)
|
||||||
Descriptor* file = Scheduler::current_task()->open_descriptor_from_fd(fd, err);
|
|
||||||
if (!file)
|
|
||||||
{
|
{
|
||||||
context->rax = -err;
|
context->rax = -EBADF;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Task* current_task = Scheduler::current_task();
|
||||||
|
if (!current_task->files[fd].is_open())
|
||||||
|
{
|
||||||
|
context->rax = -EBADF;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
kdbgln("close(): releasing file descriptor %d", fd);
|
kdbgln("close(): releasing file descriptor %d", fd);
|
||||||
file->close();
|
current_task->files[fd].close();
|
||||||
context->rax = 0;
|
context->rax = 0;
|
||||||
return;
|
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);
|
char* kfilename = strdup_from_user(filename);
|
||||||
if (!kfilename)
|
if (!kfilename)
|
||||||
@ -329,9 +272,7 @@ void sys_mkdir(Context* context, const char* filename, mode_t mode)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Task* current_task = Scheduler::current_task();
|
int rc = VFS::mkdir(kfilename);
|
||||||
|
|
||||||
int rc = VFS::do_mkdir(kfilename, current_task->euid, current_task->egid, mode & (~current_task->umask));
|
|
||||||
|
|
||||||
kfree(kfilename);
|
kfree(kfilename);
|
||||||
|
|
||||||
@ -346,44 +287,3 @@ void sys_access(Context* context, const char* path, int) // FIXME: Use the amode
|
|||||||
context->rax = 0;
|
context->rax = 0;
|
||||||
kfree(kpath);
|
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/reboot.h"
|
||||||
#include "misc/utils.h"
|
#include "misc/utils.h"
|
||||||
#include "panic/Panic.h"
|
#include "panic/Panic.h"
|
||||||
#include "std/ensure.h"
|
#include "std/assert.h"
|
||||||
#include "std/errno.h"
|
#include "std/errno.h"
|
||||||
#include "std/stdlib.h"
|
#include "std/stdlib.h"
|
||||||
#include "std/string.h"
|
#include "std/string.h"
|
||||||
@ -25,7 +25,7 @@ static uint64_t task_num = 0;
|
|||||||
|
|
||||||
static Task idle_task;
|
static Task idle_task;
|
||||||
|
|
||||||
static uint64_t free_pid = 0;
|
static uint64_t free_tid = 0;
|
||||||
|
|
||||||
static Task* sched_current_task;
|
static Task* sched_current_task;
|
||||||
static Task* base_task;
|
static Task* base_task;
|
||||||
@ -72,7 +72,7 @@ void Scheduler::append_task(Task* task)
|
|||||||
{
|
{
|
||||||
if (!base_task)
|
if (!base_task)
|
||||||
{
|
{
|
||||||
ensure(!end_task);
|
ASSERT(!end_task);
|
||||||
base_task = task;
|
base_task = task;
|
||||||
end_task = base_task;
|
end_task = base_task;
|
||||||
task->next_task = task;
|
task->next_task = task;
|
||||||
@ -91,7 +91,7 @@ void Scheduler::append_task(Task* task)
|
|||||||
void Scheduler::init()
|
void Scheduler::init()
|
||||||
{
|
{
|
||||||
memset(&idle_task, 0, sizeof(Task));
|
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.rip = (uint64_t)idle_task_function;
|
||||||
idle_task.regs.rsp = get_top_of_stack((uint64_t)MemoryManager::get_page(), 1);
|
idle_task.regs.rsp = get_top_of_stack((uint64_t)MemoryManager::get_page(), 1);
|
||||||
idle_task.regs.cs = 0x08;
|
idle_task.regs.cs = 0x08;
|
||||||
@ -99,7 +99,6 @@ void Scheduler::init()
|
|||||||
idle_task.regs.rflags = (1 << 21) | (1 << 9);
|
idle_task.regs.rflags = (1 << 21) | (1 << 9);
|
||||||
idle_task.task_sleep = 1000;
|
idle_task.task_sleep = 1000;
|
||||||
idle_task.user_task = false;
|
idle_task.user_task = false;
|
||||||
idle_task.block_reason = BlockReason::None;
|
|
||||||
idle_task.state = idle_task.Idle;
|
idle_task.state = idle_task.Idle;
|
||||||
|
|
||||||
strlcpy(idle_task.name, "[cpu-idle]", sizeof(idle_task.name));
|
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))
|
void Scheduler::add_kernel_task(const char* taskname, void (*task)(void))
|
||||||
{
|
{
|
||||||
Task* new_task = new Task;
|
Task* new_task = new Task;
|
||||||
ensure(new_task);
|
ASSERT(new_task);
|
||||||
new_task->user_task = false;
|
new_task->user_task = false;
|
||||||
new_task->id = free_pid++;
|
new_task->id = free_tid++;
|
||||||
new_task->ppid = 0;
|
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->regs.rip = (uint64_t)task;
|
||||||
new_task->allocated_stack =
|
new_task->allocated_stack =
|
||||||
(uint64_t)MemoryManager::get_pages(TASK_PAGES_IN_STACK); // 16 KB is enough for everyone, right?
|
(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;
|
new_task->cpu_time = 0;
|
||||||
strlcpy(new_task->name, taskname, sizeof(new_task->name));
|
strlcpy(new_task->name, taskname, sizeof(new_task->name));
|
||||||
append_task(new_task);
|
append_task(new_task);
|
||||||
new_task->block_reason = BlockReason::None;
|
|
||||||
new_task->state = new_task->Running;
|
new_task->state = new_task->Running;
|
||||||
task_num++;
|
task_num++;
|
||||||
kinfoln("Adding kernel task: %s, starts at %lx, PID %ld, stack at %lx, total tasks: %ld", new_task->name,
|
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;
|
if (!new_task) return nullptr;
|
||||||
memset(&new_task->regs, 0, sizeof(Context));
|
memset(&new_task->regs, 0, sizeof(Context));
|
||||||
new_task->user_task = true;
|
new_task->user_task = true;
|
||||||
new_task->id = free_pid++;
|
new_task->id = free_tid++;
|
||||||
new_task->ppid = 0;
|
new_task->ppid = 0;
|
||||||
new_task->task_sleep = 0;
|
new_task->task_sleep = 0;
|
||||||
new_task->task_time = 0;
|
new_task->task_time = 0;
|
||||||
new_task->cpu_time = 0;
|
new_task->cpu_time = 0;
|
||||||
new_task->block_reason = BlockReason::None;
|
|
||||||
append_task(new_task);
|
append_task(new_task);
|
||||||
task_num++;
|
task_num++;
|
||||||
return new_task;
|
return new_task;
|
||||||
@ -158,51 +154,42 @@ long Scheduler::load_user_task(const char* filename)
|
|||||||
{
|
{
|
||||||
kinfoln("Loading user task: %s", filename);
|
kinfoln("Loading user task: %s", filename);
|
||||||
Interrupts::push_and_disable();
|
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;
|
Task* new_task = new Task;
|
||||||
ensure(new_task);
|
ASSERT(new_task);
|
||||||
memset(&new_task->regs, 0, sizeof(Context));
|
memset(&new_task->regs, 0, sizeof(Context));
|
||||||
new_task->id = free_pid++;
|
new_task->id = free_tid++;
|
||||||
new_task->ppid = 0;
|
new_task->ppid = 0;
|
||||||
new_task->uid = new_task->euid = new_task->gid = new_task->egid = 0;
|
|
||||||
if (!new_task->allocator.init())
|
if (!new_task->allocator.init())
|
||||||
{
|
{
|
||||||
delete new_task;
|
delete new_task;
|
||||||
free_pid--;
|
free_tid--;
|
||||||
Interrupts::pop();
|
Interrupts::pop();
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
new_task->address_space = AddressSpace::create();
|
new_task->address_space = AddressSpace::create();
|
||||||
VMM::switch_to_user_address_space(new_task->address_space);
|
VMM::switch_to_user_address_space(new_task->address_space);
|
||||||
long result;
|
ELFImage* image = ELFLoader::load_elf_from_filesystem(
|
||||||
if ((result = ELFLoader::check_elf_image_from_filesystem(filename)) < 0)
|
filename); // FIXME: TOCTOU? Right now, impossible, since interrupts are disabled and SMP is not a thing. But in
|
||||||
{
|
// the future, it might be possible.
|
||||||
delete new_task;
|
ASSERT(image);
|
||||||
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);
|
|
||||||
new_task->user_task = true;
|
new_task->user_task = true;
|
||||||
new_task->regs.rip = image->entry;
|
new_task->regs.rip = image->entry;
|
||||||
new_task->image = image;
|
new_task->image = image;
|
||||||
new_task->allocated_stack = (uint64_t)MemoryManager::get_pages_at(
|
new_task->allocated_stack = (uint64_t)MemoryManager::get_pages_at(
|
||||||
0x100000, TASK_PAGES_IN_STACK,
|
0x100000, TASK_PAGES_IN_STACK, MAP_READ_WRITE | MAP_USER); // 16 KB is enough for everyone, right?
|
||||||
MAP_READ_WRITE | MAP_USER | MAP_AS_OWNED_BY_TASK); // 16 KB is enough for everyone, right?
|
|
||||||
if (!new_task->allocated_stack)
|
if (!new_task->allocated_stack)
|
||||||
{
|
{
|
||||||
new_task->address_space.destroy();
|
new_task->address_space.destroy();
|
||||||
delete new_task;
|
delete new_task;
|
||||||
free_pid--;
|
free_tid--;
|
||||||
ELFLoader::release_elf_image(image);
|
ELFLoader::release_elf_image(image);
|
||||||
VMM::switch_back_to_kernel_address_space();
|
VMM::switch_back_to_kernel_address_space();
|
||||||
Interrupts::pop();
|
Interrupts::pop();
|
||||||
@ -218,7 +205,6 @@ long Scheduler::load_user_task(const char* filename)
|
|||||||
new_task->cpu_time = 0;
|
new_task->cpu_time = 0;
|
||||||
strlcpy(new_task->name, filename, sizeof(new_task->name));
|
strlcpy(new_task->name, filename, sizeof(new_task->name));
|
||||||
append_task(new_task);
|
append_task(new_task);
|
||||||
new_task->block_reason = BlockReason::None;
|
|
||||||
new_task->state = new_task->Running;
|
new_task->state = new_task->Running;
|
||||||
task_num++;
|
task_num++;
|
||||||
kinfoln("Adding user task: %s, loaded at %lx, PID %ld, stack at %lx, total tasks: %ld", new_task->name,
|
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->regs.rflags = (1 << 21) | (1 << 9); // enable interrupts
|
||||||
task->task_sleep = 0;
|
task->task_sleep = 0;
|
||||||
task->cpu_time = 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,
|
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);
|
task->id, task->regs.rsp, task_num);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scheduler::reap_task(Task* task)
|
void Scheduler::reap_task(Task* task)
|
||||||
{
|
{
|
||||||
ensure(!Interrupts::is_in_handler());
|
ASSERT(!Interrupts::is_in_handler());
|
||||||
task_num--;
|
task_num--;
|
||||||
Task* exiting_task = task;
|
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())
|
if (exiting_task->is_user_task())
|
||||||
{
|
{
|
||||||
VMM::switch_back_to_kernel_address_space();
|
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,
|
kinfoln("reaping task %s, PID %ld, exited with code %ld", exiting_task->name, exiting_task->id,
|
||||||
exiting_task->exit_status);
|
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())
|
if (exiting_task->allocated_stack && !exiting_task->is_user_task())
|
||||||
MemoryManager::release_pages((void*)exiting_task->allocated_stack, TASK_PAGES_IN_STACK);
|
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())
|
if (exiting_task->is_user_task())
|
||||||
{
|
{
|
||||||
exiting_task->allocator.free();
|
exiting_task->allocator.free();
|
||||||
@ -274,6 +262,7 @@ void Scheduler::reap_task(Task* task)
|
|||||||
Interrupts::pop();
|
Interrupts::pop();
|
||||||
}
|
}
|
||||||
for (int i = 0; i < TASK_MAX_FDS; i++) { exiting_task->files[i].close(); }
|
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;
|
delete exiting_task;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,7 +281,6 @@ void sched_common_exit(Context* context, int64_t status)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
kinfoln("PID 1 exited with code %ld", status);
|
|
||||||
#ifndef RUN_TEST_AS_INIT
|
#ifndef RUN_TEST_AS_INIT
|
||||||
reboot();
|
reboot();
|
||||||
#else
|
#else
|
||||||
@ -304,7 +292,7 @@ void sched_common_exit(Context* context, int64_t status)
|
|||||||
|
|
||||||
void Scheduler::task_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,
|
kdbgln("exit: task %ld finished running, used %ld ms of cpu time", sched_current_task->id,
|
||||||
sched_current_task->cpu_time);
|
sched_current_task->cpu_time);
|
||||||
sched_common_exit(context, status);
|
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)
|
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);
|
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);
|
sched_common_exit(context, status);
|
||||||
}
|
}
|
||||||
@ -320,7 +308,7 @@ void Scheduler::task_misbehave(Context* context, int64_t status)
|
|||||||
void Scheduler::reap_tasks()
|
void Scheduler::reap_tasks()
|
||||||
{
|
{
|
||||||
Interrupts::disable();
|
Interrupts::disable();
|
||||||
ensure(!Interrupts::is_in_handler());
|
ASSERT(!Interrupts::is_in_handler());
|
||||||
Task* reap_base = nullptr;
|
Task* reap_base = nullptr;
|
||||||
Task* reap_end = nullptr;
|
Task* reap_end = nullptr;
|
||||||
Task* task = base_task;
|
Task* task = base_task;
|
||||||
@ -383,7 +371,7 @@ static void sched_decrement_sleep_times()
|
|||||||
|
|
||||||
void Scheduler::task_tick(Context* context)
|
void Scheduler::task_tick(Context* context)
|
||||||
{
|
{
|
||||||
ensure(Interrupts::is_in_handler());
|
ASSERT(Interrupts::is_in_handler());
|
||||||
Interrupts::disable();
|
Interrupts::disable();
|
||||||
sched_decrement_sleep_times();
|
sched_decrement_sleep_times();
|
||||||
sched_current_task->task_time -= frequency;
|
sched_current_task->task_time -= frequency;
|
||||||
@ -399,7 +387,7 @@ void Scheduler::task_tick(Context* context)
|
|||||||
|
|
||||||
void Scheduler::task_yield(Context* context)
|
void Scheduler::task_yield(Context* context)
|
||||||
{
|
{
|
||||||
ensure(Interrupts::is_in_handler());
|
ASSERT(Interrupts::is_in_handler());
|
||||||
Interrupts::disable();
|
Interrupts::disable();
|
||||||
sched_current_task->save_context(context);
|
sched_current_task->save_context(context);
|
||||||
bool was_idle = false;
|
bool was_idle = false;
|
||||||
@ -413,7 +401,11 @@ void Scheduler::task_yield(Context* context)
|
|||||||
sched_current_task = sched_current_task->next_task;
|
sched_current_task = sched_current_task->next_task;
|
||||||
if (sched_current_task->state == sched_current_task->Blocking)
|
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)
|
if (sched_current_task->state == sched_current_task->Running)
|
||||||
{
|
{
|
||||||
@ -469,10 +461,8 @@ Task* Scheduler::current_task()
|
|||||||
return sched_current_task;
|
return sched_current_task;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define WNOHANG 1
|
|
||||||
|
|
||||||
void sys_waitpid(Context* context, long pid, int* wstatus,
|
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;
|
Task* child = nullptr;
|
||||||
if (pid == -1)
|
if (pid == -1)
|
||||||
@ -486,103 +476,43 @@ void sys_waitpid(Context* context, long pid, int* wstatus,
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
if (!child)
|
if (!child)
|
||||||
{
|
|
||||||
if (options & WNOHANG)
|
|
||||||
{
|
{
|
||||||
context->rax = 0; // No child has exited, let's return 0.
|
context->rax = 0; // No child has exited, let's return 0.
|
||||||
return;
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
child = Scheduler::find_by_pid(pid);
|
child = Scheduler::find_by_pid(pid);
|
||||||
if (!child)
|
if (!child)
|
||||||
{
|
{
|
||||||
context->rax = -ECHILD;
|
context->rax = -ESRCH;
|
||||||
return;
|
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 = 0;
|
||||||
context->rax = -ECHILD;
|
|
||||||
return;
|
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;
|
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;
|
child->state = child->Exited;
|
||||||
context->rax = (long)child->id;
|
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
|
struct pstat
|
||||||
@ -592,14 +522,12 @@ struct pstat
|
|||||||
char pt_name[128];
|
char pt_name[128];
|
||||||
int pt_state;
|
int pt_state;
|
||||||
long pt_time;
|
long pt_time;
|
||||||
uid_t pt_uid;
|
|
||||||
gid_t pt_gid;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void sys_pstat(Context* context, long pid, struct pstat* buf)
|
void sys_pstat(Context* context, long pid, struct pstat* buf)
|
||||||
{
|
{
|
||||||
Task* task;
|
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)
|
else if (pid == 0)
|
||||||
task = &idle_task;
|
task = &idle_task;
|
||||||
else
|
else
|
||||||
@ -614,17 +542,21 @@ void sys_pstat(Context* context, long pid, struct pstat* buf)
|
|||||||
context->rax = -ESRCH;
|
context->rax = -ESRCH;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
context->rax = task->id;
|
|
||||||
if (buf)
|
if (buf)
|
||||||
{
|
{
|
||||||
struct pstat stat;
|
struct pstat* kpstat = obtain_user_ref(buf);
|
||||||
stat.pt_pid = task->id;
|
if (!kpstat)
|
||||||
stat.pt_ppid = task->ppid;
|
{
|
||||||
stat.pt_state = (int)task->state;
|
context->rax = -EFAULT;
|
||||||
stat.pt_time = (long)task->cpu_time;
|
return;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
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 "thread/Task.h"
|
||||||
#include "log/Log.h"
|
#include "log/Log.h"
|
||||||
#include "memory/VMM.h"
|
#include "memory/VMM.h"
|
||||||
#include "std/ensure.h"
|
|
||||||
#include "std/errno.h"
|
|
||||||
#include "std/string.h"
|
#include "std/string.h"
|
||||||
|
|
||||||
void Task::restore_context(Context* context)
|
void Task::restore_context(Context* context)
|
||||||
@ -73,68 +71,15 @@ bool Task::has_died()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Task::resume_read()
|
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::switch_back_to_kernel_address_space();
|
||||||
VMM::apply_address_space();
|
VMM::apply_address_space();
|
||||||
VMM::switch_to_user_address_space(address_space);
|
VMM::switch_to_previous_user_address_space();
|
||||||
switch (block_reason)
|
regs.rax = files[blocking_read_info.fd].read(blocking_read_info.size, blocking_read_info.buf);
|
||||||
{
|
|
||||||
case BlockReason::None: return;
|
|
||||||
case BlockReason::Reading: resume_read(); break;
|
|
||||||
case BlockReason::Waiting: resume_wait(); break;
|
|
||||||
|
|
||||||
default: ensure(false);
|
|
||||||
}
|
|
||||||
VMM::apply_address_space();
|
VMM::apply_address_space();
|
||||||
block_reason = BlockReason::None;
|
|
||||||
state = Running;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Task::is_still_blocking()
|
bool Task::is_still_blocking()
|
||||||
{
|
{
|
||||||
switch (block_reason)
|
return VFS::would_block(files[blocking_read_info.fd].node());
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
#include "trace/Resolve.h"
|
#include "trace/Resolve.h"
|
||||||
#include "fs/InitRD.h"
|
#include "init/InitRD.h"
|
||||||
#include "std/stdlib.h"
|
#include "std/stdlib.h"
|
||||||
#include "std/string.h"
|
#include "std/string.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
@ -7,7 +7,7 @@
|
|||||||
extern int kernel_start;
|
extern int kernel_start;
|
||||||
extern int kernel_end;
|
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)
|
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
|
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
|
CXXFLAGS := -fno-rtti -fno-exceptions -Wsign-promo -Wstrict-null-sentinel -Wctor-dtor-privacy
|
||||||
ASMFLAGS := -felf64
|
ASMFLAGS := -felf64
|
||||||
|
|
||||||
@ -21,62 +21,49 @@ OBJS += $(patsubst $(LIBC_SRC)/%.asm, $(LIBC_OBJ)/%.asm.o, $(ASM_SRC))
|
|||||||
|
|
||||||
$(LIBC_OBJ)/%.cpp.o: $(LIBC_SRC)/%.cpp
|
$(LIBC_OBJ)/%.cpp.o: $(LIBC_SRC)/%.cpp
|
||||||
@mkdir -p $(@D)
|
@mkdir -p $(@D)
|
||||||
@$(CXX) $(CFLAGS) $(CXXFLAGS) -o $@ -c $^
|
$(CXX) $(CFLAGS) $(CXXFLAGS) -o $@ -c $^
|
||||||
@echo " CXX $^"
|
|
||||||
|
|
||||||
$(LIBC_OBJ)/%.c.o: $(LIBC_SRC)/%.c
|
$(LIBC_OBJ)/%.c.o: $(LIBC_SRC)/%.c
|
||||||
@mkdir -p $(@D)
|
@mkdir -p $(@D)
|
||||||
@$(CC) $(CFLAGS) -o $@ -c $^
|
$(CC) $(CFLAGS) -o $@ -c $^
|
||||||
@echo " CC $^"
|
|
||||||
|
|
||||||
$(LIBC_OBJ)/%.asm.o: $(LIBC_SRC)/%.asm
|
$(LIBC_OBJ)/%.asm.o: $(LIBC_SRC)/%.asm
|
||||||
@mkdir -p $(@D)
|
@mkdir -p $(@D)
|
||||||
@$(ASM) $(ASMFLAGS) -o $@ $^
|
$(ASM) $(ASMFLAGS) -o $@ $^
|
||||||
@echo " ASM $^"
|
|
||||||
|
|
||||||
$(LIBC_BIN)/libc.a: $(OBJS)
|
$(LIBC_BIN)/libc.a: $(OBJS)
|
||||||
@mkdir -p $(@D)
|
@mkdir -p $(@D)
|
||||||
@$(AR) rcs $@ $(OBJS)
|
$(AR) rcs $@ $(OBJS)
|
||||||
@echo " AR $@"
|
|
||||||
|
|
||||||
$(LIBC_BIN)/crt0.o: $(LIBC_DIR)/crt0.asm
|
$(LIBC_BIN)/crt0.o: $(LIBC_DIR)/crt0.asm
|
||||||
@mkdir -p $(@D)
|
@mkdir -p $(@D)
|
||||||
@$(ASM) $(ASMFLAGS) -o $@ $^
|
$(ASM) $(ASMFLAGS) -o $@ $^
|
||||||
@echo " ASM $^"
|
|
||||||
|
|
||||||
$(LIBC_BIN)/crti.o: $(LIBC_DIR)/crti.asm
|
$(LIBC_BIN)/crti.o: $(LIBC_DIR)/crti.asm
|
||||||
@mkdir -p $(@D)
|
@mkdir -p $(@D)
|
||||||
@$(ASM) $(ASMFLAGS) -o $@ $^
|
$(ASM) $(ASMFLAGS) -o $@ $^
|
||||||
@echo " ASM $^"
|
|
||||||
|
|
||||||
$(LIBC_BIN)/crtn.o: $(LIBC_DIR)/crtn.asm
|
$(LIBC_BIN)/crtn.o: $(LIBC_DIR)/crtn.asm
|
||||||
@mkdir -p $(@D)
|
@mkdir -p $(@D)
|
||||||
@$(ASM) $(ASMFLAGS) -o $@ $^
|
$(ASM) $(ASMFLAGS) -o $@ $^
|
||||||
@echo " ASM $^"
|
|
||||||
|
|
||||||
build: $(LIBC_BIN)/crt0.o $(LIBC_BIN)/crti.o $(LIBC_BIN)/crtn.o $(LIBC_BIN)/libc.a
|
build: $(LIBC_BIN)/crt0.o $(LIBC_BIN)/crti.o $(LIBC_BIN)/crtn.o $(LIBC_BIN)/libc.a
|
||||||
|
|
||||||
$(DESTDIR)/libc.a: $(LIBC_BIN)/libc.a
|
$(DESTDIR)/libc.a: $(LIBC_BIN)/libc.a
|
||||||
@mkdir -p $(@D)
|
@mkdir -p $(@D)
|
||||||
@cp $^ $@
|
cp $^ $@
|
||||||
@rm -f $(DESTDIR)/libm.a
|
|
||||||
@ln -s $@ $(DESTDIR)/libm.a
|
|
||||||
@echo " INSTALL $^"
|
|
||||||
|
|
||||||
$(DESTDIR)/crt0.o: $(LIBC_BIN)/crt0.o
|
$(DESTDIR)/crt0.o: $(LIBC_BIN)/crt0.o
|
||||||
@mkdir -p $(@D)
|
@mkdir -p $(@D)
|
||||||
@cp $^ $@
|
cp $^ $@
|
||||||
@echo " INSTALL $^"
|
|
||||||
|
|
||||||
$(DESTDIR)/crti.o: $(LIBC_BIN)/crti.o
|
$(DESTDIR)/crti.o: $(LIBC_BIN)/crti.o
|
||||||
@mkdir -p $(@D)
|
@mkdir -p $(@D)
|
||||||
@cp $^ $@
|
cp $^ $@
|
||||||
@echo " INSTALL $^"
|
|
||||||
|
|
||||||
$(DESTDIR)/crtn.o: $(LIBC_BIN)/crtn.o
|
$(DESTDIR)/crtn.o: $(LIBC_BIN)/crtn.o
|
||||||
@mkdir -p $(@D)
|
@mkdir -p $(@D)
|
||||||
@cp $^ $@
|
cp $^ $@
|
||||||
@echo " INSTALL $^"
|
|
||||||
|
|
||||||
install: $(DESTDIR)/libc.a $(DESTDIR)/crt0.o $(DESTDIR)/crti.o $(DESTDIR)/crtn.o
|
install: $(DESTDIR)/libc.a $(DESTDIR)/crt0.o $(DESTDIR)/crti.o $(DESTDIR)/crtn.o
|
||||||
|
|
||||||
|
@ -6,6 +6,8 @@ extern _fini
|
|||||||
extern initialize_libc
|
extern initialize_libc
|
||||||
extern exit
|
extern exit
|
||||||
|
|
||||||
|
extern __argv
|
||||||
|
|
||||||
global _start
|
global _start
|
||||||
_start:
|
_start:
|
||||||
; Set up end of the stack frame linked list.
|
; Set up end of the stack frame linked list.
|
||||||
@ -14,15 +16,12 @@ _start:
|
|||||||
push rbp ; rbp=0
|
push rbp ; rbp=0
|
||||||
mov rbp, rsp
|
mov rbp, rsp
|
||||||
|
|
||||||
push rdi
|
|
||||||
push rsi
|
|
||||||
|
|
||||||
call initialize_libc
|
call initialize_libc
|
||||||
|
|
||||||
call _init
|
call _init
|
||||||
|
|
||||||
pop rsi ; argv
|
mov rdi, 0 ; argc = 0
|
||||||
pop rdi ; argc
|
mov rsi, __argv ; Dummy argv which is equal to {NULL}
|
||||||
|
|
||||||
call main
|
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
|
#ifdef NDEBUG
|
||||||
#define assert(expr) (void)0
|
#define assert(expr) (void)0
|
||||||
#else
|
#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
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -3,9 +3,5 @@
|
|||||||
|
|
||||||
#define ID_PID 0
|
#define ID_PID 0
|
||||||
#define ID_PPID 1
|
#define ID_PPID 1
|
||||||
#define ID_UID 2
|
|
||||||
#define ID_EUID 3
|
|
||||||
#define ID_GID 4
|
|
||||||
#define ID_EGID 5
|
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -4,9 +4,7 @@
|
|||||||
#define __lc_noreturn __attribute__((noreturn))
|
#define __lc_noreturn __attribute__((noreturn))
|
||||||
#define __lc_align(n) __attribute__((aligned(n)))
|
#define __lc_align(n) __attribute__((aligned(n)))
|
||||||
#define __lc_deprecated(msg) __attribute__((deprecated(msg)))
|
#define __lc_deprecated(msg) __attribute__((deprecated(msg)))
|
||||||
#define __lc_is_deprecated __attribute__((deprecated))
|
|
||||||
#define __lc_unreachable __builtin_unreachable
|
#define __lc_unreachable __builtin_unreachable
|
||||||
#define __lc_used __attribute__((used))
|
#define __lc_used __attribute__((used))
|
||||||
#define __lc_unused __attribute__((unused))
|
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -1,8 +1,6 @@
|
|||||||
#ifndef _CTYPE_H
|
#ifndef _CTYPE_H
|
||||||
#define _CTYPE_H
|
#define _CTYPE_H
|
||||||
|
|
||||||
#include <bits/macros.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
@ -53,10 +51,6 @@ extern "C"
|
|||||||
/* Returns the uppercase form of the specified character. */
|
/* Returns the uppercase form of the specified character. */
|
||||||
int toupper(int c);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
#include <luna/os-limits.h>
|
#include <luna/os-limits.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
/* An entry in a directory. */
|
|
||||||
struct dirent
|
struct dirent
|
||||||
{
|
{
|
||||||
ino_t d_ino;
|
ino_t d_ino;
|
||||||
@ -14,16 +13,6 @@ struct dirent
|
|||||||
char d_name[NAME_MAX];
|
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
|
typedef struct
|
||||||
{
|
{
|
||||||
int d_dirfd;
|
int d_dirfd;
|
||||||
|
@ -8,77 +8,20 @@ extern int errno;
|
|||||||
#define ENOENT 2 // No such file or directory
|
#define ENOENT 2 // No such file or directory
|
||||||
#define ESRCH 3 // No such process
|
#define ESRCH 3 // No such process
|
||||||
#define EINTR 4 // Interrupted system call. Not implemented.
|
#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 ENOEXEC 8 // Exec format error
|
||||||
#define EBADF 9 // Bad file descriptor
|
#define EBADF 9 // Bad file descriptor
|
||||||
#define ECHILD 10 // No child processes
|
|
||||||
#define EAGAIN 11 // Resource temporarily unavailable
|
#define EAGAIN 11 // Resource temporarily unavailable
|
||||||
#define EWOULDBLOCK 11 // Resource temporarily unavailable
|
|
||||||
#define ENOMEM 12 // Cannot allocate memory
|
#define ENOMEM 12 // Cannot allocate memory
|
||||||
#define EACCES 13 // Permission denied
|
|
||||||
#define EFAULT 14 // Bad address
|
#define EFAULT 14 // Bad address
|
||||||
#define EBUSY 16 // Device or resource busy. Not implemented.
|
|
||||||
#define EEXIST 17 // File exists
|
#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 ENOTDIR 20 // Not a directory
|
||||||
#define EISDIR 21 // Is a directory
|
#define EISDIR 21 // Is a directory
|
||||||
#define EINVAL 22 // Invalid argument
|
#define EINVAL 22 // Invalid argument
|
||||||
#define ENFILE 23 // Too many open files in system. Not implemented.
|
|
||||||
#define EMFILE 24 // Too many open files
|
#define EMFILE 24 // Too many open files
|
||||||
#define ENOTTY 25 // Inappropriate ioctl for device
|
#define ENOTTY 25 // Inappropriate ioctl for device
|
||||||
#define EFBIG 27 // File too large. Not implemented.
|
|
||||||
#define ENOSPC 28 // No space left on device
|
#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 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 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 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
|
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -13,26 +13,11 @@
|
|||||||
#define O_CLOEXEC 8
|
#define O_CLOEXEC 8
|
||||||
/* Refuse to open the file if it is not a directory. */
|
/* Refuse to open the file if it is not a directory. */
|
||||||
#define O_DIRECTORY 16
|
#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. */
|
/* Duplicate a file descriptor. */
|
||||||
#define F_DUPFD 0
|
#define F_DUPFD 0
|
||||||
/* Is a file descriptor a TTY? */
|
/* Is a file descriptor a TTY? */
|
||||||
#define F_ISTTY 1
|
#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
|
#ifdef __cplusplus
|
||||||
extern "C"
|
extern "C"
|
||||||
@ -40,7 +25,7 @@ extern "C"
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Opens the file specified by pathname. Returns a file descriptor on success, or -1 on error. */
|
/* 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. */
|
/* Performs an operation on the file descriptor fd determined by cmd. */
|
||||||
int fcntl(int fd, int cmd, ...);
|
int fcntl(int fd, int cmd, ...);
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user