Compare commits

..

120 Commits

Author SHA1 Message Date
185757e2a7 600th commit!
1. Update the bc patch to remove an unnecessary line.
2. Update README.md to mention the port system.
3. Improve the port system!!
2022-10-23 17:15:38 +02:00
1a82bbb234 ports: Add a port system
The only port right now is bc, which works... kind of.
It compiles, and runs, but is really janky. At least it runs!!
2022-10-23 16:44:50 +02:00
865018e7f8 libc: Implement dirfd, rewinddir, telldir and seekdir 2022-10-23 14:59:06 +02:00
e457b88b04 Kernel, libc: Implement O_DIRECTORY and use that in dirent.h 2022-10-23 14:46:27 +02:00
8bf2904d74 libc: Implement a basic subset of dirent.h 2022-10-23 14:41:45 +02:00
32db366781 apps: Add a little ls utility that lists the files in /bin 2022-10-23 14:06:11 +02:00
14367f07b5 Kernel: Add support for getdents() to DeviceFS 2022-10-23 14:05:55 +02:00
78d72c2f0c Kernel, libc: Add a getdents() system call
This is meant to be a low-level interface to implement dirent.h on top of.
2022-10-23 14:03:46 +02:00
19ee21ae5a libc: Make string_to_integer_type static 2022-10-23 12:28:25 +02:00
35616993f8 libc: Add div(), ldiv(), and lldiv() 2022-10-23 12:26:48 +02:00
51bd7de17b libc: Patch mman.h so libgcov builds 2022-10-23 12:10:05 +02:00
43180b777e libc: Stub out qsort() 2022-10-23 11:19:08 +02:00
9dc8bfbdce libc: Define a dummy FILENAME_MAX 2022-10-23 11:17:22 +02:00
bd8825231a libc: Stub out sscanf() 2022-10-23 11:16:36 +02:00
d82238b485 libc: Add return value to ungetc() 2022-10-23 11:14:18 +02:00
d75de5f423 libc: Partially implement ungetc 2022-10-23 11:12:54 +02:00
51580bb846 libc: Add abs(), labs() and llabs()
Just needed to alias them to GCC builtins.
2022-10-23 11:10:26 +02:00
c02f2e128d libc: Stub out ungetc() 2022-10-23 10:34:49 +02:00
f0eeaa25a3 libc: More inttypes.h 2022-10-23 10:31:56 +02:00
0c33fcdff2 libc: Stub out setvbuf, and add S_ISREG 2022-10-23 10:09:20 +02:00
fa35e883d7 libc: Stub out strftime 2022-10-23 10:01:03 +02:00
8f17578e2e Update README.md 2022-10-22 21:43:55 +02:00
06f9ffc184 libc: Add EXIT_SUCCESS, EXIT_FAILURE, RAND_MAX and BUFSIZ 2022-10-22 21:39:51 +02:00
dd9b90d69d compilation fix :) 2022-10-22 21:16:51 +02:00
7600bc5582 libc: Add strings.h 2022-10-22 21:13:22 +02:00
433b307cb2 libc: Add strcoll()
No locale support, this just calls strcmp()
2022-10-22 21:00:59 +02:00
6d4d2579ab Tests: Add tests for strchrnul, strdup and strndup 2022-10-22 20:36:28 +02:00
cf94ca2a4e Kernel: Update libk's string.h 2022-10-22 19:06:06 +02:00
437f51add7 Kernel: move over the mem* functions from libc 2022-10-22 19:04:35 +02:00
4725538aa7 Tests: Add tests for memmove and memcmp + correct our memcmp implementation 2022-10-22 19:04:19 +02:00
8908faf6e2 libc: Add strchrnul()
Another GNU extension, it's ok.
2022-10-22 18:37:02 +02:00
bfbe8e847b Tests: Add tests for memset, memcpy and memchr 2022-10-22 18:33:28 +02:00
766b6d26c8 Tests: add test for strpbrk() 2022-10-22 18:09:43 +02:00
ea96c5f47b Tests: Add tests for calloc() and realloc() 2022-10-22 18:06:01 +02:00
c3828dd357 Tests: add tests for strchr() and strrchr() 2022-10-22 17:58:54 +02:00
503a04f0e9 libc: Add strpbrk() 2022-10-22 17:54:33 +02:00
4d71c0ef04 libc: Implement strndup() 2022-10-22 17:49:44 +02:00
20429929dd InitRD: Bump up the filesystem limits 2022-10-22 17:23:22 +02:00
58ca030711 initrd: warn when failing to register stuff 2022-10-22 17:21:34 +02:00
26324259f2 uname: Use fgets() 2022-10-22 15:43:21 +02:00
a1a1157151 sh: update it 2022-10-22 15:09:09 +02:00
4aa979bd87 sh: remove duplicate code 2022-10-22 15:08:27 +02:00
fef7dd5867 Rename [moon-reaper] to [reaper] 2022-10-22 14:43:41 +02:00
ac8a23d733 wrong type :) 2022-10-22 14:40:30 +02:00
189986d23f libc: Rename pstname() to pstatname()
To avoid confusion with ptsname().
2022-10-22 14:30:41 +02:00
727e227b09 apps: Add ps (uses pstat) 2022-10-22 14:26:59 +02:00
6ac57a2f5c libc: Add support for pstat() 2022-10-22 14:26:42 +02:00
bcdcfc4b45 Kernel: Add a pstat() system call
Not part of C or POSIX, but since there is no procfs right now, I thought it would be nice to have an interface to query process information.
It works like this: you pass the process ID and a pointer to a struct pstat (can be null).
If the process ID is -1, the kernel picks the process with the highest PID.
Then, if the pointer to a pstat struct is not null, the kernel fills it in with the process's information, and returns the process's PID.
2022-10-22 14:26:29 +02:00
31e0f0efed uptime: Use fgets() 2022-10-22 14:23:34 +02:00
a4eed362b6 libc: Implement fseeko() and ftello() 2022-10-22 12:41:15 +02:00
759c8a8cab libc: Make fpos_t no longer a struct 2022-10-22 12:39:37 +02:00
9bbb5d0c07 libc: Implement strspn (with a test) 2022-10-22 12:36:31 +02:00
551d731627 libc: Add FIXME 2022-10-22 12:30:30 +02:00
063e2d5e7a libc: Add more spacing to stdio.cpp 2022-10-22 12:21:04 +02:00
6dc51abfc8 libc: Add remove() stub 2022-10-22 12:20:05 +02:00
81c337cf9a libc: Add struct tm and localtime(), gmtime() stubs 2022-10-22 12:17:48 +02:00
91969d4d48 libc: strtoul's endptr must not be const 2022-10-22 12:12:52 +02:00
6e01323e84 Tests: Add tests for srand, atol and atoll 2022-10-22 12:10:19 +02:00
59d5e9789e Tests: Add a test for atoi() 2022-10-22 12:03:10 +02:00
1f5f6a5e3b libc: Add strcspn (with a test) 2022-10-22 11:57:25 +02:00
6816a5b11f Scheduler: do not reboot on PID 1 exit if we are in a test 2022-10-22 11:56:08 +02:00
27a18a608c libc: Implement fgets, fgetc, getc, getchar (with buffered read IO) 2022-10-22 11:38:16 +02:00
51e024588e libc: Update inttypes.h
Turns out it was incorrect.
2022-10-22 11:23:12 +02:00
0faabe02e5 Kernel, libc: Implement O_CLOEXEC 2022-10-22 10:28:02 +02:00
fb88459263 libc: Add all missing errors to strerror() 2022-10-22 10:14:40 +02:00
b2f5a0502f Kernel, libc: Implement O_NONBLOCK 2022-10-21 21:51:03 +02:00
da61e3648f Kernel: Implement blocking reads
This is a huge step forward!! bc actually runs now, without echo or backspace, but it runs!!
2022-10-21 21:26:19 +02:00
43073cfdbb Add new __lc_used macro 2022-10-21 18:39:46 +02:00
fcd6d9b9f5 Add FIXME 2022-10-21 18:37:18 +02:00
bef9158450 Kernel, libc: Add isatty() and F_ISTTY to fcntl() 2022-10-21 18:34:31 +02:00
93207820b3 libc: Add a few errors to errno.h
As well as ino_t, which I forgot in the fstat() commit :)
2022-10-21 18:34:01 +02:00
62fa773b27 libc: Add dummy argv 2022-10-21 18:33:06 +02:00
6d7a8a0d0b libc: Add very basic strtoul()
As well as returning NULL in getenv() instead of aborting.
2022-10-21 18:32:46 +02:00
bf026d0dea libc: Add bad time() function
It's just an alias for clock(). Which is not good. But it's a stub, that's the point.
2022-10-21 18:32:01 +02:00
c8a37eaf70 libc: Add SIGINT define 2022-10-21 18:31:19 +02:00
fcf191aa7a Kernel, libc: Add fstat() 2022-10-21 18:31:09 +02:00
0720b3245b sh: Do not backspace if command is empty 2022-10-20 19:32:32 +02:00
b69fbd46bf init: Add a Message of the Day 2022-10-20 19:27:37 +02:00
bd4c587409 sh: Try to execute programs in /bin if they are not found 2022-10-20 19:12:17 +02:00
a06e1c5a21 VFS: Remove warning when file is not found
That is a common ocurrence.
2022-10-20 19:11:50 +02:00
f7cf395f71 Kernel, libc: Add access() 2022-10-20 19:03:24 +02:00
27448611b3 UserMemory: do not map refs into kernel memory
This is bad design. But it fails if mapped, since something overwrites KernelHeap.
2022-10-20 18:50:07 +02:00
712f4f5e51 KernelHeap: Add more debug logging 2022-10-20 18:49:33 +02:00
9d0dfbaedf PMM: Log invalid frees 2022-10-20 18:49:12 +02:00
073c90e948 InitRD: leak an unused pointer so kmalloc() doesn't map memory all the time 2022-10-20 18:49:00 +02:00
7d71bd192d Tools: Add a fast-run.sh script which does not build, only run 2022-10-20 18:48:25 +02:00
de167c3c67 sh: Show last command' exit status in prompt if non-zero 2022-10-20 08:21:18 +02:00
cd9ecc1746 Kernel: Return EFAULT when the kernel believes the wstatus pointer is invalid 2022-10-20 08:20:56 +02:00
44bd93b8b4 apps: Add a hello app 2022-10-19 21:13:47 +02:00
f682258fc9 sym: do not sleep 2022-10-19 21:13:38 +02:00
2c813f5901 apps: Add more simple apps
Now that we can start them at will from the command line, bring them on!!
2022-10-19 21:11:38 +02:00
47bdfecedb Devices: Add /dev/uptime
This file contains how many milliseconds have passed since boot at the time of reading it :)
2022-10-19 21:11:12 +02:00
1938a059a2 Kernel: Free the last spawned thread's PID on exit 2022-10-19 20:51:54 +02:00
aebd860947 libc: Add stdin
Aka keyboard :)
2022-10-19 20:43:04 +02:00
ba57f32f39 init: wait less before starting sh 2022-10-19 20:36:27 +02:00
a815beacfb sh: add builtins 2022-10-19 20:34:10 +02:00
20db8eaba6 Init: exit if the primary child process exits 2022-10-19 20:33:59 +02:00
51665a04b7 Kernel: Restart if init exits 2022-10-19 20:33:41 +02:00
7e9744419e sh: Improve it 2022-10-19 20:16:21 +02:00
3c5c92c7c3 sh: Add a simple interactive shell 2022-10-19 19:42:05 +02:00
7ec221c36d libc: Move __luna_syscall* declarations to asm 2022-10-19 17:50:09 +02:00
5816f54293 libc: Move SYS_* constants to sys/syscall.h 2022-10-19 17:49:55 +02:00
b035795eb3 Kernel: Move errno.h and (k)assert.h out of the main include directory
This is mostly so IDEs don't pick them up instead of the userspace headers :)
2022-10-19 17:41:23 +02:00
aa90e4a8d9 libc: Implement freopen() 2022-10-19 17:32:59 +02:00
f3af3e252b Kernel: refresh task_misbehave()
That function was severely outdated.
2022-10-19 17:26:36 +02:00
ef8ba3dec4 Kernel: Do not hang when a user task misbehaves
This was for testing/debugging. But we DEFINITELY don't want that.
2022-10-19 17:25:56 +02:00
656667812a Kernel: reparent child processes to PID 1 when their parent exits 2022-10-19 17:16:01 +02:00
a29f7f8df2 Kernel: waitpid: support -1 as PID (wait for any child) 2022-10-19 17:15:30 +02:00
48d4a5910a Kernel: Add a few convenience functions to manipulate userland memory 2022-10-19 17:13:16 +02:00
755242719c VMM: Add a few memsets
This seems to fix exec() making weird page tables!!
2022-10-19 07:56:08 +02:00
671f2a2de3 Kernel, libc: Implement waitpid()
FIXME: exec() is now doing weird page table stuff. But at least it works, no panics :)
2022-10-18 21:30:52 +02:00
bb00e3c112 Kernel: Guard against recursive panics
Previously, when we panicked (page-fault for example) while dumping a kernel panic, it would just loop over and over again.

Now, we check if we were already in a panic, and limit the dump:
- No stack trace.
- Only a few registers.
- Only serial (since we can page fault while writing to the framebuffer)

This should make recursive panics much more difficult to achieve.
If we page-fault while writing to console, we don't even see a panic (not even in serial) and eventually triple-fault.
So this patch is actually more user-friendly.
2022-10-18 21:08:21 +02:00
59506b8852 Kernel: Show current_task's name in the log 2022-10-18 18:41:17 +02:00
f1bfa6bec8 Build system: more cflags + stripping 2022-10-18 18:28:28 +02:00
01564cb905 libc: Adapt libc to getprocid() + add getppid() 2022-10-18 17:36:33 +02:00
52d391507d Kernel: Rename the getpid() syscall to getprocid()
Now, we have one single system call to fetch all sorts of identifiers:
PID, PPID, UID, GID; EUID, EGID, and more...
2022-10-18 17:36:17 +02:00
a9d3bdba6f Kernel: Keep track of a task's PPID 2022-10-18 17:18:37 +02:00
bdf1bb15a1 StackTracer: only show kernel addresses for now, until there are more checks 2022-10-18 17:14:09 +02:00
48d68a3e31 Kernel: Switch back to kernel address space on kernel panic 2022-10-18 17:13:43 +02:00
92d8c9d4d5 Next version! 2022-10-17 21:28:35 +02:00
121 changed files with 3415 additions and 531 deletions

3
.gitignore vendored
View File

@ -11,3 +11,6 @@ tests/**/bin/**
base/usr/include/**
base/usr/lib/**
**/*.a
ports/**/workdir/**
ports/ports.list
**/*.pkg.tar.xz

View File

@ -23,3 +23,4 @@ install:
@$(MAKE) -C kernel install
@$(MAKE) -C libs install
@$(MAKE) -C apps install
@tools/install-built-ports.sh

View File

@ -2,16 +2,15 @@
A simple kernel and userspace for the x86_64 platform, written mostly in C++.
## Features
Not so much at the moment.
- x86_64-compatible [kernel](kernel/).
- Keeps track of which [memory](kernel/src/memory/) is used and which memory is free, and can allocate memory for itself and [user programs](kernel/src/sys/mem.cpp).
- Can load files from a [virtual file system](kernel/src/fs/) supporting an initial ramdisk, device pseudo-filesystems... but no hard disks yet.
- Basic preemptive multitasking, round-robin [scheduler](kernel/src/thread/) that can switch between tasks.
- Can [load userspace ELF programs](kernel/src/sys/elf/) from the file system as user tasks.
- [System call](kernel/src/sys/) interface and simple [C Library](libs/libc/), aiming to be POSIX-compatible.
- Some very simple [example programs](apps/), written in C, that then can get loaded and executed by the kernel.
- 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.
- Very simple [command-line shell](apps/src/sh.c), allowing interactive use of the system.
## Setup
To build and run Luna, you will need to build a [GCC Cross-Compiler](https://wiki.osdev.org/Why_do_I_need_a_Cross_Compiler%3F) and cross-binutils for `x86_64-luna`. (Yes, Luna is advanced enough that it can use its own [OS-Specific Toolchain](https://wiki.osdev.org/OS_Specific_Toolchain), instead of a bare metal target like `x86_64-elf`. It is the first of my OS projects to be able to do so. The patches for Binutils and GCC are [binutils.patch](tools/binutils.patch) and [gcc.patch](tools/gcc.patch)).
@ -71,5 +70,24 @@ Prebuilt ISO images for every version can be found at [pub.cloudapio.eu](https:/
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.
## Is there third-party software I can use on Luna?
Yes, actually! Check out the [ports](ports/) directory.
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.
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!
Port usage:
`ports/add-port.sh <port-name>` will build and add a port to the list of installed ports, and the built port will automatically get installed into the system root every time you run Luna.
`ports/remove-port.sh <port-name>` will remove the port from the list of installed ports, remove built files from the system root, as well as the build directory.
`ports/make-package.sh <port-name>` will compile the port and make a package archive from it, which may be used in the future with a package manager :)
## License
Luna is open-source and free software under the [BSD-2 License](LICENSE).

View File

@ -1,4 +1,4 @@
APPS := init sym
APPS := init sym sh crash uname uptime hello ps ls
APPS_DIR := $(LUNA_ROOT)/apps
APPS_SRC := $(APPS_DIR)/src
@ -6,7 +6,7 @@ APPS_BIN := $(APPS_DIR)/bin
REAL_APPS := $(patsubst %, $(APPS_BIN)/%, $(APPS))
CFLAGS := -Wall -Wextra -Werror -Os
CFLAGS := -Wall -Wextra -Werror -Os -fno-asynchronous-unwind-tables
$(APPS_BIN)/%: $(APPS_SRC)/%.c
@mkdir -p $(@D)

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

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

6
apps/src/hello.c Normal file
View File

@ -0,0 +1,6 @@
#include <stdio.h>
int main()
{
puts("Hello, world!");
}

View File

@ -1,40 +1,33 @@
#include <errno.h>
#include <luna.h>
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
int print_version()
void show_motd()
{
char version[4096];
FILE* fp = fopen("/dev/version", "r");
FILE* fp = fopen("/etc/motd", "r");
if (!fp)
{
perror("fopen");
return 1;
if (errno != ENOENT) { perror("fopen"); }
return;
}
size_t nread = fread(version, 4096, 1, fp);
char buf[4096];
size_t nread = fread(buf, sizeof(buf) - 1, 1, fp);
if (ferror(fp))
{
perror("fread");
return 1;
fclose(fp);
return;
}
buf[nread] = 0;
version[nread] = 0;
puts(buf);
if (fclose(fp) < 0)
{
perror("fclose");
return 1;
}
fclose(fp);
printf("Your kernel version is %s\n\n", version);
return 0;
putchar('\n');
}
int main()
@ -45,116 +38,11 @@ int main()
return 1;
}
FILE* serial = fopen("/dev/serial", "r");
if (!serial)
{
perror("fopen");
return 1;
}
if (fputs("Hello from init!\n", serial) < 0)
{
perror("fputs");
return 1;
}
if (fclose(serial) < 0)
{
perror("fclose");
return 1;
}
show_motd();
printf("Welcome to Luna!\n");
printf("Running as PID %ld\n\n", getpid());
sleep(1);
if (print_version()) return 1;
sleep(2);
const char* filename = "/sys/config";
printf("Opening %s for reading...\n", filename);
FILE* config = fopen(filename, "r");
if (!config)
{
perror("fopen");
return 1;
}
if (fseek(config, 0, SEEK_END) < 0)
{
perror("fseek");
return 1;
}
long offset = ftell(config);
if (offset < 0)
{
perror("ftell");
return 1;
}
printf("%s is %ld bytes long\n", filename, offset);
rewind(config);
char buf[4096];
size_t nread = fread(buf, sizeof(buf), 1, config);
if (ferror(config)) { perror("fread"); }
else
{
buf[nread] = 0;
printf("Read %zd bytes\n\n", nread);
printf("%s", buf);
}
if (fclose(config) < 0) { perror("fclose"); }
printf("\n\nGot random number %d\n\n", rand());
sleep(2);
printf("Press any key to restart.\n\n");
int stderr_fd = fileno(stderr);
int new_stderr_fd = dup(stderr_fd);
if (new_stderr_fd < 0)
{
perror("dup");
return 1;
}
FILE* new_stderr = fdopen(new_stderr_fd, "rw");
if (!new_stderr)
{
perror("fdopen");
return 1;
}
fprintf(new_stderr, "Bye!\n\n");
fclose(new_stderr);
const char* pathname = "/etc";
printf("Creating directory %s\n", pathname);
if (mkdir(pathname, 0) < 0)
{
perror("mkdir");
return 1;
}
printf("Success!!\n");
printf("Forking...\n");
msleep(200);
pid_t child = fork();
if (child < 0)
{
perror("fork");
@ -162,22 +50,19 @@ int main()
}
if (child == 0)
{
msleep(500);
printf("I am the child, who is my parent?\n");
execv("/bin/sym", NULL);
execv("/bin/sh", NULL);
perror("execv");
return 1;
}
else { printf("Success!! Got PID %ld\n", child); }
jmp_buf env;
int val = setjmp(env);
if (val == 0) { printf("Returning from setjmp!\n"); }
else
pid_t result;
for (;;)
{
printf("Returning from longjmp! val=%d\n", val);
return 0;
while ((result = wait(NULL)) == 0) // No child has exited yet
{
msleep(100);
}
if (result == child) { return 0; }
}
longjmp(env, 3);
}

22
apps/src/ls.c Normal file
View File

@ -0,0 +1,22 @@
#include <dirent.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
DIR* dp = opendir("/bin");
if (!dp)
{
perror("opendir");
return 1;
}
do {
struct dirent* ent = readdir(dp);
if (!ent) break;
printf("%s\n", ent->d_name);
} while (1);
closedir(dp);
return 0;
}

44
apps/src/ps.c Normal file
View File

@ -0,0 +1,44 @@
#include <errno.h>
#include <luna/pstat.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
pid_t get_current_max_threads()
{
pid_t result = pstat(-1, NULL);
if (result < 0)
{
perror("pstat(-1)");
exit(1);
}
return result;
}
void display_process(struct pstat* pstatbuf)
{
printf("%ld %ld %s %s (%ld ms)\n", pstatbuf->pt_pid, pstatbuf->pt_ppid, pstatbuf->pt_name, pstatname(pstatbuf),
pstatbuf->pt_time);
}
int try_pstat(pid_t pid, struct pstat* pstatbuf)
{
pid_t result = pstat(pid, pstatbuf);
if (result < 0)
{
if (errno == ESRCH) return 0;
perror("pstat");
exit(1);
}
return 1;
}
int main()
{
struct pstat pst;
pid_t max = get_current_max_threads();
for (pid_t pid = 0; pid <= max; pid++)
{
if (try_pstat(pid, &pst)) { display_process(&pst); }
}
}

194
apps/src/sh.c Normal file
View File

@ -0,0 +1,194 @@
#include <assert.h>
#include <errno.h>
#include <luna.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
static int status = 0;
typedef struct
{
char* buffer;
size_t size;
size_t capacity;
} command;
void show_prompt()
{
if (WEXITSTATUS(status)) { printf("%d [%ld]> ", WEXITSTATUS(status), getpid()); }
else
printf("[%ld]> ", getpid());
}
int command_matches(command* cmd, const char* string)
{
if (cmd->size <= strlen(string)) // cmd->size includes null terminator
return 0;
return strncmp(cmd->buffer, string, strlen(string)) == 0;
}
int command_matches_exactly(command* cmd, const char* string)
{
if (cmd->size <= strlen(string)) // cmd->size includes null terminator
return 0;
if (cmd->size > (strlen(string) + 1)) return 0;
return strncmp(cmd->buffer, string, strlen(string)) == 0;
}
int command_match_builtins(command* cmd)
{
if (command_matches(cmd, "exit ")) { exit(atoi(cmd->buffer + 5)); }
if (command_matches_exactly(cmd, "exit")) { exit(0); }
if (command_matches_exactly(cmd, "pid"))
{
printf("pid %ld, ppid %ld\n", getpid(), getppid());
return 1;
}
return 0;
}
void command_expand(command* cmd, long new_capacity)
{
char* buffer = realloc(cmd->buffer, new_capacity);
if (!buffer)
{
perror("realloc");
exit(1);
}
cmd->buffer = buffer;
cmd->capacity = new_capacity;
}
void command_push(command* cmd, char c)
{
if (cmd->size == cmd->capacity) command_expand(cmd, cmd->capacity + 8);
cmd->buffer[cmd->size] = c;
cmd->size++;
}
void command_pop(command* cmd)
{
cmd->size--;
}
void command_init(command* cmd)
{
cmd->buffer = malloc(5);
cmd->capacity = 5;
cmd->size = 0;
}
void command_clear(command* cmd)
{
free(cmd->buffer);
return command_init(cmd);
}
void command_execute(command* cmd)
{
command_push(cmd, '\0');
if (command_match_builtins(cmd))
{
command_clear(cmd);
show_prompt();
return;
}
pid_t child = fork();
if (child < 0)
{
perror(cmd->buffer);
command_clear(cmd);
show_prompt();
return;
}
if (child == 0)
{
if (cmd->buffer[0] != '/' && access(cmd->buffer, F_OK) < 0) // FIXME: Race condition.
{
if (errno == ENOENT)
{ // Try in /bin
char* buf = malloc(cmd->size + 6);
strlcpy(buf, "/bin/", 6);
strncat(buf, cmd->buffer, cmd->size);
execv(buf, NULL);
}
}
else
execv(cmd->buffer, NULL);
perror(cmd->buffer);
exit(127);
}
pid_t result;
while ((result = waitpid(child, &status, 0)) == 0) { msleep(20); }
if (result < 0)
{
perror("waitpid");
command_clear(cmd);
show_prompt();
return;
}
int exit_status = WEXITSTATUS(status);
if (exit_status == -2 || exit_status == -3) printf("(PID %ld) Segmentation fault\n", result);
command_clear(cmd);
show_prompt();
}
void command_concat_char(command* cmd, char c)
{
if (c == '\b')
{
if (cmd->size != 0)
{
putchar(c);
command_pop(cmd);
}
}
else if (c == '\n')
{
putchar(c);
if (cmd->size == 0) show_prompt();
else
command_execute(cmd);
}
else
{
putchar(c);
command_push(cmd, c);
}
}
void command_concat(command* cmd, const char* str)
{
while (*str)
{
command_concat_char(cmd, *str);
str++;
}
}
int main()
{
show_prompt();
command shell_command;
command_init(&shell_command);
while (1)
{
int c = getchar();
if (c == EOF)
{
if (ferror(stdin))
{
perror("getchar");
return 1;
}
if (feof(stdin)) { return 0; }
assert(false); // we should never get here
}
command_concat_char(&shell_command, (char)c);
}
}

View File

@ -4,8 +4,6 @@
int main()
{
sleep(2);
FILE* syms = fopen("/sys/moon.sym", "r");
if (!syms)
{

18
apps/src/uname.c Normal file
View File

@ -0,0 +1,18 @@
#include <stdio.h>
int main()
{
FILE* fp = fopen("/dev/version", "r");
if (!fp)
{
perror("fopen");
return 1;
}
char buf[BUFSIZ];
fgets(buf, sizeof(buf), fp);
printf("%s\n", buf);
fclose(fp);
}

27
apps/src/uptime.c Normal file
View File

@ -0,0 +1,27 @@
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE* fp = fopen("/dev/uptime", "r");
if (!fp)
{
perror("fopen");
return 1;
}
char buf[BUFSIZ];
fgets(buf, sizeof(buf), fp);
if (ferror(fp))
{
perror("fgets");
return 1;
}
long ms_uptime = atol(buf);
printf("up for %ld seconds\n", ms_uptime / 1000);
fclose(fp);
}

3
initrd/etc/motd Normal file
View File

@ -0,0 +1,3 @@
Welcome to Luna!
Tip of the day: Type 'help' to get started!

View File

@ -24,10 +24,15 @@ struct Descriptor
m_is_open = false;
}
VFS::Node* node()
{
return m_node;
}
ssize_t read(size_t size, char* buffer);
ssize_t write(size_t size, const char* buffer);
void open(VFS::Node* node, bool can_read, bool can_write);
void open(VFS::Node* node, bool can_read, bool can_write, bool able_to_block, bool close_on_exec);
int seek(long offset);
long offset()
@ -40,6 +45,16 @@ struct Descriptor
return m_node->length;
}
bool able_to_block()
{
return m_able_to_block;
}
bool close_on_exec()
{
return m_close_on_exec;
}
Descriptor(const Descriptor& other);
Descriptor();
@ -49,6 +64,8 @@ struct Descriptor
bool m_is_open;
bool m_can_read;
bool m_can_write;
bool m_able_to_block;
bool m_close_on_exec;
VFS::Node* m_node;
uint64_t m_offset;
};

View File

@ -10,6 +10,8 @@ typedef long ssize_t;
#define VFS_MOUNTPOINT 0x1
#define NAME_MAX 64
namespace VFS
{
struct Node;
@ -18,18 +20,23 @@ namespace VFS
typedef ssize_t (*node_write)(Node*, size_t, size_t, const char*);
typedef Node* (*node_finddir)(Node*, const char*);
typedef int (*node_mkdir)(Node*, const char*);
typedef int (*node_block)(Node*);
typedef Node* (*node_readdir)(Node*, long);
struct Node
{
char name[64];
char name[NAME_MAX];
uint64_t inode;
uint64_t length;
int type;
int flags;
node_read read_func;
node_finddir find_func;
node_readdir readdir_func;
node_mkdir mkdir_func;
node_write write_func;
node_block block_func;
int tty = 0;
Node* link;
};
@ -38,6 +45,8 @@ namespace VFS
int mkdir(const char* path, const char* name);
int mkdir(const char* pathname);
int would_block(Node* node);
void mount_root(Node* root);
Node* resolve_path(const char* filename, Node* root = nullptr);
@ -50,4 +59,6 @@ namespace VFS
void unmount(Node* mountpoint);
Node* root();
Node* readdir(Node* dir, long offset);
}

View File

@ -6,4 +6,5 @@ namespace DeviceFS
VFS::Node* get();
VFS::Node* finddir(VFS::Node* node, const char* filename);
VFS::Node* readdir(VFS::Node* node, long offset);
}

View File

@ -0,0 +1,13 @@
#pragma once
#include "fs/VFS.h"
namespace KeyboardDevice
{
VFS::Node* create_new(const char* devname);
ssize_t read(VFS::Node* node, size_t offset, size_t size, char* buffer);
int would_block(VFS::Node* node);
void append(char c);
}

View File

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

View File

@ -8,4 +8,8 @@ namespace KernelHeap
void free_virtual_page(uint64_t address);
void free_virtual_pages(uint64_t address, uint64_t count);
void clear();
void dump_usage();
}

View File

@ -0,0 +1,6 @@
#pragma once
// This should only be used for a keyboard TTY interface. Userspace should translate keyboard scancodes by themselves.
char translate_scancode(unsigned char scancode, bool* ignore);
bool scancode_filter_released(unsigned char* scancode);

View File

@ -2,8 +2,11 @@
#define EPERM 1
#define ENOENT 2
#define ESRCH 3
#define EINTR 4
#define ENOEXEC 8
#define EBADF 9
#define EAGAIN 11
#define ENOMEM 12
#define EFAULT 14
#define EEXIST 17
@ -11,6 +14,7 @@
#define EISDIR 21
#define EINVAL 22
#define EMFILE 24
#define ENOTTY 25
#define ENOSPC 28
#define ENOSYS 38
#define ENOTSUP 95

View File

@ -17,7 +17,7 @@ char* strstr(char* haystack, const char* needle);
void* memcpy(void* dest, const void* src, size_t n);
void* memset(void* dest, int c, size_t n);
int memcmp(const void* a, const void* b, size_t n);
void* memmove(void* dest, void* src, size_t n);
void* memmove(void* dest, const void* src, size_t n);
char* strdup(const char* src);
char* strrchr(const char* str, int c);

View File

@ -7,7 +7,7 @@
#define SYS_sleep 2
#define SYS_write 3
#define SYS_paint 4
#define SYS_getpid 5
#define SYS_getprocid 5
#define SYS_mmap 6
#define SYS_munmap 7
#define SYS_open 8
@ -20,12 +20,19 @@
#define SYS_clock 15
#define SYS_mkdir 16
#define SYS_fork 17
#define SYS_waitpid 18
#define SYS_access 19
#define SYS_fstat 20
#define SYS_pstat 21
#define SYS_getdents 22
struct stat;
struct pstat;
struct luna_dirent;
namespace Syscall
{
void entry(Context* context);
char* strdup_from_user(const char* user_string);
}
void sys_exit(Context* context, int status);
@ -33,7 +40,7 @@ void sys_yield(Context* context);
void sys_sleep(Context* context, uint64_t ms);
void sys_write(Context* context, int fd, size_t size, const char* addr);
void sys_paint(Context* context, uint64_t x, uint64_t y, uint64_t w, uint64_t h, uint64_t col);
void sys_getpid(Context* context);
void sys_getprocid(Context* context, int field);
void sys_mmap(Context* context, void* address, size_t size, int prot);
void sys_munmap(Context* context, void* address, size_t size);
void sys_open(Context* context, const char* filename, int flags);
@ -46,3 +53,8 @@ void sys_mprotect(Context* context, void* address, size_t size, int prot);
void sys_clock(Context* context);
void sys_mkdir(Context* context, const char* filename);
void sys_fork(Context* context);
void sys_waitpid(Context* context, long pid, int* wstatus, int options);
void sys_access(Context* context, const char* path, int amode);
void sys_fstat(Context* context, int fd, struct stat* buf);
void sys_pstat(Context* context, long pid, struct pstat* buf);
void sys_getdents(Context* context, int fd, struct luna_dirent* buf, size_t count);

View File

@ -0,0 +1,43 @@
#pragma once
#ifndef MODULE
#define MODULE "mem"
#endif
#include "log/Log.h"
#include "memory/MemoryManager.h"
#include "memory/VMM.h"
#include "misc/utils.h"
char* strdup_from_user(const char* user_string);
// 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.
template <typename T, unsigned long S = sizeof(T), typename V> T* user_address_to_typed_pointer(V address)
{
uint64_t phys = VMM::get_physical((uint64_t)address);
if (phys == (uint64_t)-1)
{
kinfoln("warning: user pointer is not mapped in its address space");
return nullptr;
}
// return (T*)MemoryManager::get_unaligned_mappings((void*)phys, Utilities::get_blocks_from_size(PAGE_SIZE, S),
// MAP_READ_WRITE);
return (T*)phys;
}
template <typename T, unsigned long S = sizeof(T)> void free_user_typed_pointer(T*)
{
// MemoryManager::release_unaligned_mappings(ptr, Utilities::get_blocks_from_size(PAGE_SIZE, S));
}
template <typename T> T* obtain_user_ref(T* user_ptr)
{
return user_address_to_typed_pointer<T>(user_ptr);
}
template <typename T> void release_user_ref(T* ptr)
{
return free_user_typed_pointer(ptr);
}

View File

@ -14,10 +14,13 @@ struct Task
Idle,
Running,
Sleeping,
Dying,
Blocking,
Exited
};
uint64_t id;
uint64_t ppid;
Context regs;
int64_t task_sleep = 0;
@ -65,4 +68,15 @@ struct Task
bool has_died();
char name[128];
struct
{
size_t size;
int fd;
char* buf;
} blocking_read_info;
void resume_read();
bool is_still_blocking();
};

View File

@ -1,20 +1,23 @@
#include "fs/FileDescriptor.h"
#include "errno.h"
#include "std/errno.h"
Descriptor::Descriptor() : m_is_open(false)
{
}
Descriptor::Descriptor(const Descriptor& other)
: m_is_open(other.m_is_open), m_can_read(other.m_can_read), m_can_write(other.m_can_write), m_node(other.m_node),
: m_is_open(other.m_is_open), m_can_read(other.m_can_read), m_can_write(other.m_can_write),
m_able_to_block(other.m_able_to_block), m_close_on_exec(other.m_close_on_exec), m_node(other.m_node),
m_offset(other.m_offset)
{
}
void Descriptor::open(VFS::Node* node, bool can_read, bool can_write)
void Descriptor::open(VFS::Node* node, bool can_read, bool can_write, bool able_to_block, bool close_on_exec)
{
m_can_read = can_read;
m_can_write = can_write;
m_able_to_block = able_to_block;
m_close_on_exec = close_on_exec;
m_node = node;
m_offset = 0;
m_is_open = true;
@ -36,7 +39,7 @@ ssize_t Descriptor::write(size_t size, const char* buffer)
int Descriptor::seek(long offset)
{
if (m_node->type != VFS_DEVICE && (uint64_t)offset > m_node->length)
if (m_node->type == VFS_FILE && (uint64_t)offset > m_node->length)
return -EINVAL; // FIXME: Support seeking beyond the current file's length.
m_offset = (uint64_t)offset;
return 0;
@ -49,5 +52,7 @@ const Descriptor& Descriptor::operator=(const Descriptor& other)
m_can_write = other.m_can_write;
m_offset = other.m_offset;
m_node = other.m_node;
m_able_to_block = other.m_able_to_block;
m_close_on_exec = other.m_close_on_exec;
return other;
}

View File

@ -1,14 +1,21 @@
#define MODULE "vfs"
#include "fs/VFS.h"
#include "errno.h"
#include "log/Log.h"
#include "std/errno.h"
#include "std/libgen.h"
#include "std/stdlib.h"
#include "std/string.h"
static VFS::Node* vfs_root;
int VFS::would_block(Node* node)
{
if (!node) { return 0; }
if (!node->block_func) { return 0; }
return node->block_func(node);
}
ssize_t VFS::read(Node* node, size_t offset, size_t length, char* buffer)
{
if (!node)
@ -104,11 +111,7 @@ VFS::Node* VFS::resolve_path(const char* filename, Node* root)
return 0;
}
Node* child = current_node->find_func(current_node, buffer);
if (!child)
{
kwarnln("Current node did not find our target node");
return 0;
}
if (!child) { return 0; }
if (child->flags & VFS_MOUNTPOINT)
{
if (!child->link)
@ -199,3 +202,10 @@ void VFS::unmount(Node* mountpoint)
if (!(mountpoint->flags & VFS_MOUNTPOINT)) return;
mountpoint->flags &= ~VFS_MOUNTPOINT;
}
VFS::Node* VFS::readdir(VFS::Node* dir, long offset)
{
if (!dir) return 0;
if (!dir->readdir_func) return 0;
return dir->readdir_func(dir, offset);
}

View File

@ -13,6 +13,7 @@ VFS::Node* ConsoleDevice::create_new(const char* devname)
dev->length = 0;
dev->type = VFS_DEVICE;
dev->flags = 0;
dev->tty = 1;
strncpy(dev->name, devname, sizeof(dev->name));
return dev;
}

View File

@ -1,7 +1,9 @@
#include "fs/devices/DeviceFS.h"
#include "fs/devices/Console.h"
#include "fs/devices/Keyboard.h"
#include "fs/devices/Random.h"
#include "fs/devices/Serial.h"
#include "fs/devices/Uptime.h"
#include "fs/devices/Version.h"
#include "std/stdlib.h"
#include "std/string.h"
@ -21,12 +23,16 @@ VFS::Node* DeviceFS::get()
devfs_root->inode = 0;
devfs_root->type = VFS_DIRECTORY;
devfs_root->find_func = DeviceFS::finddir;
devfs_root->readdir_func = DeviceFS::readdir;
strncpy(devfs_root->name, "dev", sizeof(devfs_root->name));
devfs_files[devfs_file_count++] = VersionDevice::create_new("version");
devfs_files[devfs_file_count++] = ConsoleDevice::create_new("console");
devfs_files[devfs_file_count++] = SerialDevice::create_new("serial");
devfs_files[devfs_file_count++] = RandomDevice::create_new("random");
devfs_files[devfs_file_count++] = KeyboardDevice::create_new("kbd");
devfs_files[devfs_file_count++] = UptimeDevice::create_new("uptime");
devfs_root->length = devfs_file_count;
return devfs_root;
}
@ -39,3 +45,10 @@ VFS::Node* DeviceFS::finddir(VFS::Node* node, const char* filename)
}
return 0;
}
VFS::Node* DeviceFS::readdir(VFS::Node* node, long offset)
{
if (!node) return 0;
if (offset >= devfs_file_count) return 0;
return devfs_files[offset];
}

View File

@ -0,0 +1,51 @@
#define MODULE "kbd"
#include "fs/devices/Keyboard.h"
#include "config.h"
#include "log/Log.h"
#include "render/TextRenderer.h"
#include "std/stdio.h"
#include "std/stdlib.h"
#include "std/string.h"
char* kbd_buffer = nullptr;
uint64_t kbd_bufsize = 0;
int KeyboardDevice::would_block(VFS::Node*)
{
return kbd_bufsize == 0;
}
VFS::Node* KeyboardDevice::create_new(const char* devname)
{
VFS::Node* dev = new VFS::Node;
dev->read_func = KeyboardDevice::read;
dev->block_func = KeyboardDevice::would_block;
dev->inode = 0;
dev->length = 0;
dev->type = VFS_DEVICE;
dev->flags = 0;
dev->tty = 1;
strncpy(dev->name, devname, sizeof(dev->name));
return dev;
}
ssize_t KeyboardDevice::read(VFS::Node* node, size_t, size_t size, char* buffer)
{
if (!node) return -1;
if (!kbd_buffer) return 0;
if (size > kbd_bufsize) size = kbd_bufsize;
memcpy(buffer, kbd_buffer, size);
memmove(kbd_buffer, kbd_buffer + size, kbd_bufsize - size);
kbd_bufsize -= size;
kbd_buffer = (char*)krealloc(kbd_buffer, kbd_bufsize);
return (ssize_t)size;
}
void KeyboardDevice::append(char c)
{
kbd_bufsize++;
kbd_buffer = (char*)krealloc(
kbd_buffer, kbd_bufsize); // FIXME: We should probably not be calling realloc every time a key is pressed.
kbd_buffer[kbd_bufsize - 1] = c;
}

View File

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

View File

@ -1,9 +1,9 @@
#define MODULE "gdt"
#include "gdt/GDT.h"
#include "kassert.h"
#include "log/Log.h"
#include "memory/MemoryManager.h"
#include "std/assert.h"
#include "std/string.h"
#include <stdint.h>

View File

@ -6,7 +6,6 @@
#include "init/InitRD.h"
#include "interrupts/Interrupts.h"
#include "io/Serial.h"
#include "kassert.h"
#include "log/Log.h"
#include "memory/MemoryManager.h"
#include "memory/PMM.h"
@ -16,6 +15,7 @@
#include "rand/Mersenne.h"
#include "render/Framebuffer.h"
#include "render/TextRenderer.h"
#include "std/assert.h"
#include "std/string.h"
extern BOOTBOOT bootboot;

View File

@ -2,12 +2,12 @@
#include "init/InitRD.h"
#include "bootboot.h"
#include "errno.h"
#include "fs/VFS.h"
#include "io/Serial.h"
#include "log/Log.h"
#include "memory/MemoryManager.h"
#include "misc/utils.h"
#include "std/errno.h"
#include "std/stdlib.h"
#include "std/string.h"
@ -116,8 +116,8 @@ void InitRD::for_each(void (*callback)(File& f))
}
}
#define INITRD_MAX_FILES_IN_DIR 8
#define INITRD_MAX_FILES 32
#define INITRD_MAX_FILES_IN_DIR 16
#define INITRD_MAX_FILES 64
namespace InitRD
{
@ -154,13 +154,13 @@ void initrd_for_each_dir(void (*callback)(InitRD::Directory& f))
}
}
static InitRD::File files[32];
static InitRD::File files[INITRD_MAX_FILES];
static uint32_t total_files = 0;
static InitRD::Directory dirs[32];
static InitRD::Directory dirs[INITRD_MAX_FILES];
static uint32_t total_dirs = 0;
static VFS::Node nodes[63]; // One of the dirs is the initrd_root
static VFS::Node nodes[INITRD_MAX_FILES + (INITRD_MAX_FILES - 1)]; // One of the dirs is the initrd_root
static uint32_t total_nodes = 0;
ssize_t initrd_read(VFS::Node* node, size_t offset, size_t length, char* buffer)
@ -186,6 +186,15 @@ VFS::Node* initrd_scan_dir(VFS::Node* node, const char* filename)
return 0;
}
VFS::Node* initrd_read_dir(VFS::Node* node, long offset)
{
if (!node) return 0;
if (node->inode >= total_dirs) return 0;
InitRD::Directory dir = dirs[node->inode];
if (offset >= dir.entries) return 0;
return dir.files[offset];
}
int initrd_mkdir(VFS::Node* node, const char* name) // FIXME: Return proper error numbers.
{
if (total_dirs >= 32)
@ -222,6 +231,7 @@ int initrd_mkdir(VFS::Node* node, const char* name) // FIXME: Return proper erro
dir.entries = 0;
dirs[total_dirs++] = dir; // FIXME: Right now this isn't of worry, but there is a possibility for a TOCTOU bug here.
// Should use a spinlock or something.
node->length++;
parent.files[parent.entries++] = &new_node;
return 0;
}
@ -270,10 +280,13 @@ static bool initrd_register_dir(InitRD::Directory& dir, uint64_t inode)
node.length = 0;
node.type = VFS_DIRECTORY;
node.mkdir_func = initrd_mkdir;
node.readdir_func = initrd_read_dir;
node.length = 0;
strncpy(node.name, buffer, sizeof(node.name));
strncpy(dir.name, buffer, sizeof(dir.name));
parent.files[parent.entries++] = &node;
current_node->length++;
kfree(buffer);
return true;
@ -332,6 +345,7 @@ static bool initrd_register_file(InitRD::File& f, uint64_t inode)
strncpy(f.name, buffer, sizeof(f.name));
parent.files[parent.entries++] = &node;
current_node->length++;
kfree(buffer);
return true;
}
@ -345,12 +359,20 @@ static bool initrd_register_file(InitRD::File& f, uint64_t inode)
static void initrd_scan()
{
initrd_for_each_dir([](InitRD::Directory& dir) {
if (total_dirs >= 32) return;
if (total_dirs >= 32)
{
kwarnln("Failed to register directory %s: Too many directories in initrd", dir.name);
return;
}
uint64_t inode = total_dirs;
if (initrd_register_dir(dir, inode)) dirs[total_dirs++] = dir;
});
InitRD::for_each([](InitRD::File& f) {
if (total_files >= 32) return;
if (total_files >= 32)
{
kwarnln("Failed to register file %s: Too many files in initrd", f.name);
return;
}
uint64_t inode = total_files;
if (initrd_register_file(f, inode)) files[total_files++] = f;
});
@ -367,6 +389,7 @@ static void initrd_initialize_root()
strncpy(root.name, "initrd", sizeof(root.name));
initrd_root.find_func = initrd_scan_dir;
initrd_root.mkdir_func = initrd_mkdir;
initrd_root.readdir_func = initrd_read_dir;
}
void InitRD::init()
@ -375,8 +398,10 @@ void InitRD::init()
(void*)bootboot.initrd_ptr, Utilities::get_blocks_from_size(PAGE_SIZE, bootboot.initrd_size));
kdbgln("physical base at %lx, size %lx, mapped to %p", bootboot.initrd_ptr, bootboot.initrd_size, initrd_base);
kdbgln("total blocks: %ld", get_total_blocks());
void* leak = kmalloc(4); // leak some memory so that kmalloc doesn't continously allocate and free pages
initrd_initialize_root();
initrd_scan();
VFS::mount_root(&initrd_root);
initrd_initialized = true;
kfree(leak);
}

View File

@ -4,10 +4,10 @@
#include "interrupts/IRQ.h"
#include "interrupts/Interrupts.h"
#include "io/Serial.h"
#include "kassert.h"
#include "log/Log.h"
#include "misc/hang.h"
#include "panic/Panic.h"
#include "std/assert.h"
#include "std/stdio.h"
#include "sys/Syscall.h"
#include "thread/Scheduler.h"
@ -51,8 +51,6 @@ extern "C" void common_handler(Context* context)
StackTracer tracer(context->rbp);
tracer.trace_with_ip(context->rip);
hang(); // FIXME: Remove this when multiple address spaces are working.
Scheduler::task_misbehave(context, -3);
}
}

View File

@ -1,8 +1,8 @@
#define MODULE "idt"
#include "interrupts/IDT.h"
#include "kassert.h"
#include "log/Log.h"
#include "std/assert.h"
struct IDTEntry
{

View File

@ -1,10 +1,11 @@
#define MODULE "irq"
#include "interrupts/IRQ.h"
#include "fs/devices/Keyboard.h"
#include "io/IO.h"
#include "io/PIC.h"
#include "log/Log.h"
#include "misc/reboot.h"
#include "misc/Scancodes.h"
#include "rand/Init.h"
#include "std/stdio.h"
#include "thread/PIT.h"
@ -19,10 +20,11 @@ void IRQ::interrupt_handler(Context* context)
Scheduler::task_tick(context);
break;
case 1: {
[[maybe_unused]] volatile unsigned char scancode = IO::inb(0x60);
kdbgln("Keyboard key pressed/released, seconds since boot: %ld.%ld", PIT::ms_since_boot / 1000,
PIT::ms_since_boot % 1000);
reboot();
unsigned char scancode = IO::inb(0x60);
bool ignore = false;
char key = translate_scancode(scancode, &ignore);
if (ignore) break;
KeyboardDevice::append(key);
break;
}
default: kwarnln("Unhandled IRQ: %ld", context->irq_number); break;

View File

@ -2,6 +2,7 @@
#include "io/Serial.h"
#include "std/stdio.h"
#include "thread/PIT.h"
#include "thread/Scheduler.h"
#include <stdarg.h>
static int level_mask = 15;
@ -22,7 +23,13 @@ static void log_backend_serial(const char* function, LogLevel level, const char*
va_list ap;
va_copy(ap, origin);
Serial::reset_color();
printf("[%ld.%ld] %s: ", PIT::ms_since_boot / 1000, PIT::ms_since_boot % 1000, function);
if (Scheduler::current_task() && Scheduler::current_task()->id)
{
Task* current_task = Scheduler::current_task();
printf("[%ld.%ld] (%s %ld) %s: ", PIT::ms_since_boot / 1000, PIT::ms_since_boot % 1000, current_task->name,
current_task->id, function);
}
else { printf("[%ld.%ld] (kernel) %s: ", PIT::ms_since_boot / 1000, PIT::ms_since_boot % 1000, function); }
switch (level)
{
case LogLevel::WARN: Serial::set_color(Color::Yellow); break;

View File

@ -9,11 +9,11 @@
#include "interrupts/Install.h"
#include "interrupts/Interrupts.h"
#include "io/PIC.h"
#include "kassert.h"
#include "log/Log.h"
#include "memory/Memory.h"
#include "memory/MemoryMap.h"
#include "misc/hang.h"
#include "std/assert.h"
#include "std/stdlib.h"
#include "thread/PIT.h"
#include "thread/Scheduler.h"
@ -57,7 +57,7 @@ extern "C" void _start()
ASSERT(Scheduler::load_user_task("/bin/init") > 0);
#endif
Scheduler::add_kernel_task("[moon-reaper]", []() {
Scheduler::add_kernel_task("[reaper]", []() {
while (1)
{
sleep(400);

View File

@ -12,6 +12,7 @@ AddressSpace AddressSpace::create()
{
AddressSpace result;
result.m_pml4 = (PageTable*)PMM::request_page();
memset(result.m_pml4, 0, PAGE_SIZE);
VMM::install_kernel_page_directory_into_address_space(result);
return move(result);
}
@ -126,16 +127,26 @@ void AddressSpace::clear()
pages_freed++;
PMM::free_page(pdp);
}
memset(m_pml4, 0, PAGE_SIZE);
VMM::install_kernel_page_directory_into_address_space(*this);
kdbgln("Reclaimed %ld pages from address space!", pages_freed);
}
static PageTable* try_clone_page_table(PageTable* source)
{
PageTable* dst = (PageTable*)PMM::request_page();
if (PMM_DID_FAIL(dst)) { return 0; }
memcpy(dst, source, sizeof(PageTable));
return dst;
}
AddressSpace AddressSpace::clone() // FIXME: Add out-of-memory checks to this function.
{
AddressSpace result;
result.m_pml4 = (PageTable*)PMM::request_page();
result.m_pml4 = try_clone_page_table(m_pml4);
if (!result.m_pml4) return result;
memcpy(result.m_pml4, m_pml4, PAGE_SIZE);
for (int i = 0; i < 512; i++)
{
PageDirectoryEntry& pdp_pde = m_pml4->entries[i];
@ -143,14 +154,22 @@ AddressSpace AddressSpace::clone() // FIXME: Add out-of-memory checks to this fu
if (!pdp_pde.present) continue;
if (pdp_pde.larger_pages)
{
void* cloned = PMM::request_page();
memcpy(cloned, (void*)pdp_pde.get_address(), PAGE_SIZE);
void* cloned = try_clone_page_table((PageTable*)pdp_pde.get_address());
if (!cloned)
{
cloned_pdp_pde.present = false;
continue;
}
cloned_pdp_pde.set_address((uint64_t)cloned);
continue;
}
PageTable* pdp = (PageTable*)pdp_pde.get_address();
PageTable* cloned_pdp = (PageTable*)PMM::request_page();
memcpy(cloned_pdp, pdp, PAGE_SIZE);
PageTable* cloned_pdp = try_clone_page_table(pdp);
if (!cloned_pdp)
{
cloned_pdp_pde.present = false;
continue;
}
cloned_pdp_pde.set_address((uint64_t)cloned_pdp);
for (int j = 0; j < 511; j++) // skip the last page directory, it's the kernel one
{
@ -159,14 +178,22 @@ AddressSpace AddressSpace::clone() // FIXME: Add out-of-memory checks to this fu
if (!pd_pde.present) continue;
if (pd_pde.larger_pages)
{
void* cloned = PMM::request_page();
memcpy(cloned, (void*)pd_pde.get_address(), PAGE_SIZE);
void* cloned = try_clone_page_table((PageTable*)pd_pde.get_address());
if (!cloned)
{
cloned_pd_pde.present = false;
continue;
}
cloned_pd_pde.set_address((uint64_t)cloned);
continue;
}
PageTable* pd = (PageTable*)pd_pde.get_address();
PageTable* cloned_pd = (PageTable*)PMM::request_page();
memcpy(cloned_pd, pd, PAGE_SIZE);
PageTable* cloned_pd = try_clone_page_table(pd);
if (!cloned_pd)
{
cloned_pd_pde.present = false;
continue;
}
cloned_pd_pde.set_address((uint64_t)cloned_pd);
for (int k = 0; k < 512; k++)
{
@ -175,22 +202,34 @@ AddressSpace AddressSpace::clone() // FIXME: Add out-of-memory checks to this fu
if (!pt_pde.present) continue;
if (pt_pde.larger_pages)
{
void* cloned = PMM::request_page();
memcpy(cloned, (void*)pt_pde.get_address(), PAGE_SIZE);
void* cloned = try_clone_page_table((PageTable*)pt_pde.get_address());
if (!cloned)
{
cloned_pt_pde.present = false;
continue;
}
cloned_pt_pde.set_address((uint64_t)cloned);
continue;
}
PageTable* pt = (PageTable*)pt_pde.get_address();
PageTable* cloned_pt = (PageTable*)PMM::request_page();
memcpy(cloned_pt, pt, PAGE_SIZE);
PageTable* cloned_pt = try_clone_page_table(pt);
if (!cloned_pt)
{
cloned_pt_pde.present = false;
continue;
}
cloned_pt_pde.set_address((uint64_t)cloned_pt);
for (int l = 0; l < 512; l++)
{
PageDirectoryEntry& pde = pt->entries[l];
PageDirectoryEntry& cloned_pde = cloned_pt->entries[l];
if (!pde.present) continue;
void* cloned = PMM::request_page();
memcpy(cloned, (void*)pde.get_address(), PAGE_SIZE);
void* cloned = try_clone_page_table((PageTable*)pde.get_address());
if (!cloned)
{
cloned_pde.present = false;
continue;
}
cloned_pde.set_address((uint64_t)cloned);
continue;
}

View File

@ -2,6 +2,8 @@
#include "memory/KernelHeap.h"
#include "assert.h"
#include "log/Log.h"
#include "std/string.h"
#ifndef PAGE_SIZE
#define PAGE_SIZE 4096
@ -9,10 +11,13 @@
static uint8_t page_bitmap[2048];
static int64_t kheap_free = sizeof(page_bitmap) * 8 * PAGE_SIZE;
static int64_t kheap_used = 0;
#define ALLOC_BASE 0xfffffffff8000000
#define ALLOC_END 0xfffffffffc000000
static uint64_t start_index = 0;
// static uint64_t start_index = 0;
static bool bitmap_read(uint64_t index)
{
@ -27,13 +32,28 @@ static void bitmap_set(uint64_t index, bool value)
if (value) { page_bitmap[byteIndex] |= bitIndexer; }
}
void KernelHeap::clear()
{
memset(page_bitmap, 0, sizeof(page_bitmap));
kinfoln("page bitmap located at %p", (void*)page_bitmap);
}
uint64_t KernelHeap::request_virtual_page()
{
for (uint64_t index = start_index; index < sizeof(page_bitmap) * 8; index++)
for (uint64_t index = 0; index < sizeof(page_bitmap) * 8; index++)
{
if (bitmap_read(index)) continue;
bitmap_set(index, true);
start_index = index + 1;
// start_index = index + 1;
#ifdef KHEAP_DEBUG
kinfoln("allocating one page for caller %p, returning %lx", __builtin_return_address(0),
ALLOC_BASE + (index * PAGE_SIZE));
#endif
kheap_free -= PAGE_SIZE;
kheap_used += PAGE_SIZE;
#ifdef KHEAP_DEBUG
dump_usage();
#endif
return ALLOC_BASE + (index * PAGE_SIZE);
}
@ -44,7 +64,7 @@ uint64_t KernelHeap::request_virtual_pages(uint64_t count)
{
uint64_t contiguous = 0;
uint64_t contiguous_start = 0;
for (uint64_t index = start_index; index < sizeof(page_bitmap) * 8; index++)
for (uint64_t index = 0; index < sizeof(page_bitmap) * 8; index++)
{
if (bitmap_read(index))
{
@ -61,6 +81,15 @@ uint64_t KernelHeap::request_virtual_pages(uint64_t count)
if (contiguous == count)
{
for (uint64_t i = 0; i < count; i++) bitmap_set(contiguous_start + i, true);
#ifdef KHEAP_DEBUG
kinfoln("allocating %lu pages for caller %p, returning %lx", count, __builtin_return_address(0),
ALLOC_BASE + (contiguous_start * PAGE_SIZE));
#endif
kheap_free -= (count * PAGE_SIZE);
kheap_used += (count * PAGE_SIZE);
#ifdef KHEAP_DEBUG
dump_usage();
#endif
return ALLOC_BASE + (contiguous_start * PAGE_SIZE);
}
}
@ -73,7 +102,15 @@ void KernelHeap::free_virtual_page(uint64_t address)
if (address < ALLOC_BASE || address >= ALLOC_END) return;
uint64_t index = (address - ALLOC_BASE) / PAGE_SIZE;
bitmap_set(index, false);
if (start_index > index) start_index = index;
#ifdef KHEAP_DEBUG
kinfoln("releasing one page for caller %p, %lx", __builtin_return_address(0), address);
#endif
kheap_free += PAGE_SIZE;
kheap_used -= PAGE_SIZE;
#ifdef KHEAP_DEBUG
dump_usage();
#endif
// if (start_index > index) start_index = index;
}
void KernelHeap::free_virtual_pages(uint64_t address, uint64_t count)
@ -81,5 +118,19 @@ void KernelHeap::free_virtual_pages(uint64_t address, uint64_t count)
if (address < ALLOC_BASE || address >= ALLOC_END) return;
uint64_t index = (address - ALLOC_BASE) / PAGE_SIZE;
for (uint64_t i = 0; i < count; i++) { bitmap_set(index + i, false); }
if (start_index > index) start_index = index;
#ifdef KHEAP_DEBUG
kinfoln("releasing %lu pages for caller %p, %lx", count, __builtin_return_address(0), address);
#endif
kheap_free += (count * PAGE_SIZE);
kheap_used -= (count * PAGE_SIZE);
#ifdef KHEAP_DEBUG
dump_usage();
#endif
// if (start_index > index) start_index = index;
}
void KernelHeap::dump_usage()
{
kinfoln("Used: %ld KB", kheap_used / 1024);
kinfoln("Free: %ld KB", kheap_free / 1024);
}

View File

@ -3,14 +3,15 @@
#include "log/Log.h"
#endif
#include "kassert.h"
#include "memory/KernelHeap.h"
#include "memory/MemoryManager.h"
#include "memory/PMM.h"
#include "memory/VMM.h"
#include "std/assert.h"
void MemoryManager::init()
{
KernelHeap::clear();
PMM::init();
VMM::init();
PMM::map_bitmap_to_virtual();
@ -24,6 +25,7 @@ void* MemoryManager::get_mapping(void* physicalAddress, int flags)
#ifdef MM_DEBUG
kwarnln("No kernel heap space (virtual address space from -128M to -64M) left");
#endif
KernelHeap::dump_usage();
return 0;
}
VMM::map(virtualAddress, (uint64_t)physicalAddress, flags);
@ -39,6 +41,7 @@ void* MemoryManager::get_unaligned_mapping(void* physicalAddress, int flags)
#ifdef MM_DEBUG
kwarnln("No kernel heap space (virtual address space from -128M to -64M) left");
#endif
KernelHeap::dump_usage();
return 0;
}
VMM::map(virtualAddress, (uint64_t)physicalAddress - offset, flags);
@ -58,6 +61,7 @@ void* MemoryManager::get_unaligned_mappings(void* physicalAddress, uint64_t coun
"-64M)",
count);
#endif
KernelHeap::dump_usage();
return 0;
}
for (uint64_t i = 0; i < count; i++)
@ -97,6 +101,7 @@ void* MemoryManager::get_page(int flags)
#ifdef MM_DEBUG
kwarnln("No kernel heap space (virtual address space from -128M to -64M) left");
#endif
KernelHeap::dump_usage();
return 0;
}
return get_page_at(virtualAddress, flags);
@ -137,6 +142,7 @@ void* MemoryManager::get_pages(uint64_t count, int flags)
#ifdef MM_DEBUG
kwarnln("No kernel heap space (virtual address space from -128M to -64M) left");
#endif
KernelHeap::dump_usage();
return 0; // Out of virtual address in the kernel heap range (-128M to -64M). This should be difficult to
// achieve...
}
@ -163,9 +169,6 @@ void* MemoryManager::get_pages_at(uint64_t addr, uint64_t count, int flags)
return 0;
}
VMM::map(addr + (i * PAGE_SIZE), (uint64_t)physicalAddress, flags);
#ifdef MM_DEBUG
kdbgln("allocating virtual %lx, physical %p", addr + (i * PAGE_SIZE), physicalAddress);
#endif
}
return (void*)addr;
}
@ -183,9 +186,6 @@ void MemoryManager::release_pages(void* pages, uint64_t count)
uint64_t physicalAddress = VMM::get_physical((uint64_t)page);
ASSERT(physicalAddress != UINT64_MAX);
VMM::unmap((uint64_t)page);
#ifdef MM_DEBUG
kdbgln("releasing virtual %p, physical %lx", page, physicalAddress);
#endif
PMM::free_page((void*)physicalAddress);
}
KernelHeap::free_virtual_pages((uint64_t)pages, count);

View File

@ -2,10 +2,11 @@
#include "memory/PMM.h"
#include "bootboot.h"
#include "kassert.h"
#include "log/Log.h"
#include "memory/Memory.h"
#include "memory/MemoryManager.h"
#include "misc/utils.h"
#include "std/assert.h"
#include "std/string.h"
extern BOOTBOOT bootboot;
@ -130,6 +131,11 @@ void* PMM::request_pages(uint64_t count)
void PMM::free_page(void* address)
{
uint64_t index = (uint64_t)address / PAGE_SIZE;
if (index > (bitmap_size * 8))
{
kinfoln("attempt to free out-of-range address %p", address);
return;
}
if (!bitmap_read(index)) return;
bitmap_set(index, false);
used_mem -= PAGE_SIZE;

View File

@ -1,10 +1,10 @@
#define MODULE "vmm"
#include "memory/VMM.h"
#include "kassert.h"
#include "log/Log.h"
#include "memory/PMM.h"
#include "misc/utils.h"
#include "std/assert.h"
#include "std/string.h"
#include "utils/Addresses.h"
#include "utils/Registers.h"
@ -281,7 +281,8 @@ void VMM::install_kernel_page_directory_into_address_space(AddressSpace& space)
if (!space_last_pdp_pde.present)
{
space_last_pdp = (PageTable*)PMM::request_page();
space_last_pdp = (PageTable*)PMM::request_page(); // FIXME: Add out-of-memory checks.
memset(space_last_pdp, 0, PAGE_SIZE);
space_last_pdp_pde.present = true;
space_last_pdp_pde.read_write = true;

View File

@ -0,0 +1,168 @@
#include "misc/Scancodes.h"
#define SCANCODE_EXTENDED 0xE0
bool scancode_filter_released(unsigned char* scancode)
{
if (*scancode > 0x80)
{
*scancode -= 0x80;
return true;
}
return false;
}
static bool next_key_ignored = false; // FIXME: Do not ignore extended scancodes.
static bool left_shifted = false;
static bool right_shifted = false;
static bool capslock = false;
static bool should_shift()
{
if (capslock) return !(left_shifted || right_shifted);
return left_shifted || right_shifted;
}
#define SCANCODE_LEFT_SHIFT 0x2A
#define SCANCODE_RIGHT_SHIFT 0x36
#define SCANCODE_CAPS_LOCK 0x3A
#define SCANCODE_LEFT_CONTROL 0x1D
#define SCANCODE_TAB 0x0F
#define SCANCODE_LEFT_ALT 0x38
#define SCANCODE_F11 0x57
#define SCANCODE_F12 0x58
static bool should_ignore_key(char scancode)
{
return (scancode > 0x3A && scancode < 0x47) || scancode == SCANCODE_LEFT_CONTROL || scancode == SCANCODE_TAB ||
scancode == SCANCODE_LEFT_ALT || scancode == SCANCODE_F11 || scancode == SCANCODE_F12;
}
char keys_normal[] = {
'\0',
'\1', // escape
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',
'\0', // tab
'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
'\0', // left ctrl
'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`',
'\0', // left shift
'\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/',
'\0', // right shift
'*', // keypad *
'\0', // left alt
' ',
'\0', // caps lock
'\0', // f1
'\0', // f2
'\0', // f3
'\0', // f4
'\0', // f5
'\0', // f6
'\0', // f7
'\0', // f8
'\0', // f9
'\0', // f10
'\0', // num lock
'\0', // scroll lock
'7', // keypad 7
'8', // keypad 8
'9', // keypad 9
'-', // keypad -
'4', // keypad 4
'5', // keypad 5
'6', // keypad 6
'+', // keypad +
'1', // keypad 1
'2', // keypad 2
'3', // keypad 3
'0', // keypad 0
'.', // keypad .
};
char keys_shifted[] = {
'\0',
'\1', // escape
'!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b',
'\0', // tab
'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n',
'\0', // left ctrl
'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~',
'\0', // left shift
'|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?',
'\0', // right shift
'*', // keypad *
'\0', // left alt
' ',
'\0', // caps lock
'\0', // f1
'\0', // f2
'\0', // f3
'\0', // f4
'\0', // f5
'\0', // f6
'\0', // f7
'\0', // f8
'\0', // f9
'\0', // f10
'\0', // num lock
'\0', // scroll lock
'7', // keypad 7
'8', // keypad 8
'9', // keypad 9
'-', // keypad -
'4', // keypad 4
'5', // keypad 5
'6', // keypad 6
'+', // keypad +
'1', // keypad 1
'2', // keypad 2
'3', // keypad 3
'0', // keypad 0
'.', // keypad .
};
char translate_scancode(unsigned char scancode, bool* ignore)
{
if (next_key_ignored)
{
next_key_ignored = false;
*ignore = true;
return 0;
}
if (scancode == SCANCODE_EXTENDED)
{
next_key_ignored = true;
*ignore = true;
return 0;
}
bool released = scancode_filter_released(&scancode);
if (scancode == SCANCODE_CAPS_LOCK)
{
if (!released) { capslock = !capslock; }
*ignore = true;
return 0;
}
if (scancode == SCANCODE_LEFT_SHIFT)
{
left_shifted = !released;
*ignore = true;
return 0;
}
if (scancode == SCANCODE_RIGHT_SHIFT)
{
right_shifted = !released;
*ignore = true;
return 0;
}
if (released || should_ignore_key(scancode))
{
*ignore = true;
return 0;
}
*ignore = false;
if (should_shift()) { return keys_shifted[scancode]; }
return keys_normal[scancode];
}

View File

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

View File

@ -5,12 +5,34 @@
#include "interrupts/IDT.h"
#include "io/PIC.h"
#include "log/Log.h"
#include "memory/VMM.h"
#include "misc/MSR.h"
#include "render/Framebuffer.h"
#include "render/TextRenderer.h"
#include "std/stdio.h"
#include "thread/Scheduler.h"
#include "trace/StackTracer.h"
static bool g_is_in_panic = false;
static bool g_is_in_double_panic = false;
static void panic_prepare_keyboard_triple_fault()
{
PIC::enable_master(0b11111101); // enable keyboard only
PIC::enable_slave(0b11111111);
IDTR idtr;
idtr.limit = 0x0000;
idtr.offset = 0x0000;
asm volatile(
"lidt %0"
:
: "m"(
idtr)); // when an interrupt arrives, triple-fault (the only interrupt that should come is the keyboard one)
asm volatile("sti");
}
void dump_registers(Context* context)
{
kinfoln("-- Registers:");
@ -23,8 +45,36 @@ void dump_registers(Context* context)
kinfoln("ia32_efer: %lx", MSR::read_from(IA32_EFER_MSR));
}
void fatal_dump_registers(Context* context)
{
printf("-- Possibly Relevant Registers:\n");
printf("rbp: %lx, rsp: %lx, rip: %lx, cs: %lx, ss: %lx, rflags: %lx, cr2: %lx, error code: %lx\n", context->rbp,
context->rsp, context->rip, context->cs, context->ss, context->rflags, context->cr2, context->error_code);
}
[[noreturn]] void __panic_fatal_stub(Context* context)
{
if (context) fatal_dump_registers(context);
printf("-- No stack trace available\n");
KernelLog::enable_log_backend(Backend::Console);
KernelLog::toggle_log_backend(
Backend::Console); // disable console logging, as we can page fault while writing to the framebuffer.
Scheduler::current_task()->id = 0; // we're panicking, we don't even care anymore. This is so KernelLog shows
// (kernel) instead of (taskname: PID) in the log.
panic_prepare_keyboard_triple_fault();
printf("Press any key to restart.\n");
while (1) asm volatile("hlt");
}
[[noreturn]] void __panic_stub(Context* context)
{
VMM::switch_back_to_kernel_address_space();
VMM::apply_address_space();
if (context) dump_registers(context);
if (InitRD::is_initialized())
@ -46,21 +96,7 @@ void dump_registers(Context* context)
}
else { kinfoln("-- No stack trace available"); }
PIC::enable_master(0b11111101); // enable keyboard only
PIC::enable_slave(0b11111111);
IDTR idtr;
idtr.limit = 0x0000;
idtr.offset = 0x0000;
asm volatile(
"lidt %0"
:
: "m"(
idtr)); // when an interrupt arrives, triple-fault (the only interrupt that should come is the keyboard one)
asm volatile("sti");
kinfoln("Press any key to restart.");
panic_prepare_keyboard_triple_fault();
while (1) asm volatile("hlt");
}
@ -69,10 +105,28 @@ extern "C" [[noreturn]] bool __do_int_panic(Context* context, const char* file,
{
asm volatile("cli");
if (g_is_in_double_panic)
{
panic_prepare_keyboard_triple_fault();
while (1) asm volatile("hlt");
}
if (g_is_in_panic)
{
g_is_in_double_panic = true;
printf("Kernel panic while panicking (showing vital information only) at %s, line %d: %s\n", file, line,
message);
__panic_fatal_stub(context);
}
g_is_in_panic = true;
KernelLog::enable_log_backend(Backend::Console);
TextRenderer::reset();
framebuffer0.clear(Color::Black);
if (context->number >= 0x20 && context->number < 0x30) { PIC::send_eoi((uint8_t)(context->irq_number & 0xFF)); }
Task* task;
@ -89,10 +143,28 @@ extern "C" [[noreturn]] bool __do_panic(const char* file, int line, const char*
{
asm volatile("cli");
if (g_is_in_double_panic)
{
panic_prepare_keyboard_triple_fault();
while (1) asm volatile("hlt");
}
if (g_is_in_panic)
{
g_is_in_double_panic = true;
printf("Kernel panic while panicking (showing vital information only) at %s, line %d: %s\n", file, line,
message);
__panic_fatal_stub(nullptr);
}
g_is_in_panic = true;
KernelLog::enable_log_backend(Backend::Console);
TextRenderer::reset();
framebuffer0.clear(Color::Black);
Task* task;
if ((task = Scheduler::current_task()))
{

View File

@ -1,7 +1,7 @@
#define MODULE "rand"
#include "rand/Mersenne.h"
#include "kassert.h"
#include "std/assert.h"
#include <stddef.h>
typedef uint64_t word_t;

View File

@ -111,34 +111,32 @@ void* memcpy(void* dest, const void* src, size_t n)
return dest;
}
void* memset(void* dest, int c, size_t n)
void* memset(void* buf, int c, size_t n)
{
for (size_t i = 0; i < n; ++i) { *((char*)dest + i) = (char)c; }
return dest;
for (size_t i = 0; i < n; ++i) { *((char*)buf + i) = (char)c; }
return buf;
}
int memcmp(const void* a, const void* b, size_t n)
{
const char* _a = (const char*)a;
const char* _b = (const char*)b;
for (; n && _a == _b; n--, _a++, _b++)
;
if (!n) return 0;
if (*_a > *_b) return 1;
return -1;
const unsigned char* ap = (const unsigned char*)a;
const unsigned char* bp = (const unsigned char*)b;
while (--n && *ap == *bp)
{
ap++;
bp++;
}
return *ap - *bp;
}
void* memmove(void* dest, void* src, size_t n)
void* memmove(void* dest, const void* src, size_t n)
{
if (dest == src) return dest;
if (dest > src)
{
for (long i = n - 1; i >= 0; i++) { *((char*)dest + i) = *((char*)src + i); }
}
for (long i = n - 1; i >= 0; i++) { *((char*)dest + i) = *((const char*)src + i); }
else
{
for (long i = 0; i < (long)n; i++) { *((char*)dest + i) = *((char*)src + i); }
}
for (long i = 0; i < (long)n; i++) { *((char*)dest + i) = *((const char*)src + i); }
return dest;
}

View File

@ -1,7 +1,7 @@
#include "sys/Syscall.h"
#include "errno.h"
#include "io/Serial.h"
#include "memory/VMM.h"
#include "std/errno.h"
#include "std/string.h"
#include "thread/Scheduler.h"
@ -16,7 +16,7 @@ void Syscall::entry(Context* context)
case SYS_sleep: sys_sleep(context, context->rdi); break;
case SYS_write: sys_write(context, (int)context->rdi, context->rsi, (const char*)context->rdx); break;
case SYS_paint: sys_paint(context, context->rdi, context->rsi, context->rdx, context->r10, context->r8); break;
case SYS_getpid: sys_getpid(context); break;
case SYS_getprocid: sys_getprocid(context, (int)context->rdi); break;
case SYS_mmap: sys_mmap(context, (void*)context->rdi, context->rsi, (int)context->rdx); 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); break;
@ -29,14 +29,14 @@ void Syscall::entry(Context* context)
case SYS_clock: sys_clock(context); break;
case SYS_mkdir: sys_mkdir(context, (const char*)context->rdi); break;
case SYS_fork: sys_fork(context); break;
case SYS_waitpid: sys_waitpid(context, (long)context->rdi, (int*)context->rsi, (int)context->rdx); break;
case SYS_access: sys_access(context, (const char*)context->rdi, (int)context->rsi); break;
case SYS_fstat: sys_fstat(context, (int)context->rdi, (struct stat*)context->rsi); break;
case SYS_pstat: sys_pstat(context, (long)context->rdi, (struct pstat*)context->rsi); break;
case SYS_getdents:
sys_getdents(context, (int)context->rdi, (struct luna_dirent*)context->rsi, (size_t)context->rdx);
break;
default: context->rax = -ENOSYS; break;
}
VMM::exit_syscall_context();
}
char* Syscall::strdup_from_user(const char* user_string) // FIXME: This function is a little hacky.
{
uint64_t phys = VMM::get_physical((uint64_t)user_string);
if (phys == (uint64_t)-1) { return nullptr; }
return strdup((const char*)phys);
}

View File

@ -0,0 +1,10 @@
#include "sys/UserMemory.h"
#include "std/string.h"
char* strdup_from_user(
const char* user_string) // FIXME: This function is a little hacky. Use the obtain_user_ref and similar functions.
{
uint64_t phys = VMM::get_physical((uint64_t)user_string);
if (phys == (uint64_t)-1) { return nullptr; }
return strdup((const char*)phys);
}

61
kernel/src/sys/dirent.cpp Normal file
View File

@ -0,0 +1,61 @@
#define MODULE "dir"
#include "luna/dirent.h"
#include "fs/VFS.h"
#include "interrupts/Context.h"
#include "std/errno.h"
#include "std/string.h"
#include "sys/UserMemory.h"
#include "thread/Scheduler.h"
void sys_getdents(Context* context, int fd, struct luna_dirent* buf, size_t count)
{
if (fd < 0 || fd > TASK_MAX_FDS)
{
context->rax = -EBADF;
return;
}
Task* current_task = Scheduler::current_task();
if (!current_task->files[fd].is_open())
{
context->rax = -EBADF;
return;
}
Descriptor& dir = current_task->files[fd];
VFS::Node* node = dir.node();
if (node->type != VFS_DIRECTORY)
{
context->rax = -ENOTDIR;
return;
}
size_t nread = 0;
while (count)
{
VFS::Node* entry = VFS::readdir(node, dir.offset());
if (!entry)
{
context->rax = nread;
return;
}
auto* kdirent = obtain_user_ref(buf);
if (!kdirent)
{
context->rax = -EFAULT;
return;
}
kdirent->total = node->length;
kdirent->offset = dir.offset();
kdirent->inode = entry->inode;
strlcpy(kdirent->name, entry->name, sizeof(kdirent->name));
release_user_ref(kdirent);
dir.seek(dir.offset() + 1);
buf++;
nread++;
count--;
}
context->rax = nread;
}

View File

@ -1,15 +1,15 @@
#define MODULE "elf"
#include "sys/elf/ELFLoader.h"
#include "errno.h"
#include "fs/VFS.h"
#include "init/InitRD.h"
#include "kassert.h"
#include "log/Log.h"
#include "memory/Memory.h"
#include "memory/MemoryManager.h"
#include "memory/VMM.h"
#include "misc/utils.h"
#include "std/assert.h"
#include "std/errno.h"
#include "std/stdlib.h"
#include "std/string.h"
#include "sys/elf/ELF.h"

View File

@ -1,15 +1,16 @@
#define MODULE "exec"
#include "errno.h"
#include "interrupts/Interrupts.h"
#include "kassert.h"
#include "log/Log.h"
#include "memory/MemoryManager.h"
#include "memory/PMM.h"
#include "memory/VMM.h"
#include "std/assert.h"
#include "std/errno.h"
#include "std/stdlib.h"
#include "std/string.h"
#include "sys/Syscall.h"
#include "sys/UserMemory.h"
#include "sys/elf/ELFLoader.h"
#include "thread/Scheduler.h"
@ -41,6 +42,8 @@ void sys_fork(Context* context)
child->address_space = parent->address_space.clone();
child->ppid = parent->id;
child->regs.rax = 0;
context->rax = child->id;
@ -55,7 +58,7 @@ void sys_fork(Context* context)
void sys_exec(Context* context, const char* pathname)
{
char* kpathname = Syscall::strdup_from_user(pathname);
char* kpathname = strdup_from_user(pathname);
if (!kpathname)
{
context->rax = -EFAULT;
@ -120,6 +123,12 @@ void sys_exec(Context* context, const char* pathname)
Scheduler::reset_task(task, image);
for (int i = 0; i < TASK_MAX_FDS; i++)
{
Descriptor& file = task->files[i];
if (file.close_on_exec()) { file.close(); }
}
task->restore_context(context);
kfree(kpathname);

24
kernel/src/sys/id.cpp Normal file
View File

@ -0,0 +1,24 @@
#include "std/errno.h"
#include "thread/Scheduler.h"
#define ID_PID 0
#define ID_PPID 1
void sys_getprocid(Context* context, int field)
{
if (field == ID_PID)
{
context->rax = Scheduler::current_task()->id;
return;
}
else if (field == ID_PPID)
{
context->rax = Scheduler::current_task()->ppid;
return;
}
else
{
context->rax = -EINVAL;
return;
}
}

View File

@ -1,12 +1,12 @@
#define MODULE "mem"
#include "errno.h"
#include "interrupts/Context.h"
#include "log/Log.h"
#include "memory/Memory.h"
#include "memory/MemoryManager.h"
#include "memory/VMM.h"
#include "misc/utils.h"
#include "std/errno.h"
#include "thread/Scheduler.h"
#include <stddef.h>

View File

@ -1,7 +1,7 @@
#include "bootboot.h"
#include "errno.h"
#include "interrupts/Context.h"
#include "render/Framebuffer.h"
#include "std/errno.h"
#include <stdint.h>
extern BOOTBOOT bootboot;

View File

@ -1,3 +1,6 @@
#include "memory/VMM.h"
#include "std/errno.h"
#include "sys/UserMemory.h"
#include "thread/Scheduler.h"
void sys_exit(Context* context, int status)
@ -19,8 +22,3 @@ void sys_sleep(Context* context, uint64_t ms)
task->state = task->Sleeping;
Scheduler::task_yield(context);
}
void sys_getpid(Context* context)
{
context->rax = Scheduler::current_task()->id;
}

44
kernel/src/sys/stat.cpp Normal file
View File

@ -0,0 +1,44 @@
#include "fs/VFS.h"
#include "interrupts/Context.h"
#include "std/errno.h"
#include "sys/UserMemory.h"
#include "thread/Scheduler.h"
typedef unsigned long off_t;
typedef unsigned short mode_t;
typedef unsigned long ino_t;
struct stat // FIXME: This struct is quite stubbed out.
{
ino_t st_ino;
mode_t st_mode;
off_t st_size;
};
void sys_fstat(Context* context, int fd, struct stat* buf)
{
Task* current_task = Scheduler::current_task();
if (fd < 0 || fd >= TASK_MAX_FDS)
{
context->rax = -EBADF;
return;
}
Descriptor& file = current_task->files[fd];
if (!file.is_open())
{
context->rax = -EBADF;
return;
}
struct stat* kstat = obtain_user_ref(buf);
if (!kstat)
{
context->rax = -EFAULT; // FIXME: The manual doesn't say fstat can return EFAULT, but it seems logical here...
return;
}
VFS::Node* node = file.node();
kstat->st_ino = node->inode;
kstat->st_mode = (mode_t)node->type;
kstat->st_size = node->length;
release_user_ref(kstat);
context->rax = 0;
}

View File

@ -1,24 +1,29 @@
#define MODULE "stdio"
#include "errno.h"
#include "interrupts/Context.h"
#include "io/Serial.h"
#include "log/Log.h"
#include "memory/VMM.h"
#include "render/TextRenderer.h"
#include "std/errno.h"
#include "std/stdlib.h"
#include "sys/Syscall.h"
#include "sys/UserMemory.h"
#include "thread/Scheduler.h"
#include "thread/Task.h"
#define OPEN_READ 1
#define OPEN_WRITE 2
#define OPEN_NONBLOCK 4
#define OPEN_CLOEXEC 8
#define OPEN_DIRECTORY 16
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
#define FNCTL_DUPFD 0
#define FCNTL_DUPFD 0
#define FCNTL_ISTTY 1
void sys_fcntl(Context* context, int fd, int command, uintptr_t arg)
{
@ -34,7 +39,7 @@ void sys_fcntl(Context* context, int fd, int command, uintptr_t arg)
return;
}
Descriptor& file = current_task->files[fd];
if (command == FNCTL_DUPFD)
if (command == FCNTL_DUPFD)
{
if ((int)arg < 0 || (int)arg >= TASK_MAX_FDS)
{
@ -52,6 +57,14 @@ void sys_fcntl(Context* context, int fd, int command, uintptr_t arg)
kdbgln("fcntl(F_DUPFD): duplicated fd %d, result is %d", fd, dupfd);
return;
}
else if (command == FCNTL_ISTTY)
{
VFS::Node* node = file.node();
if (node->tty) { context->rax = 1; }
else
context->rax = -ENOTTY;
return;
}
else
{
context->rax = -EINVAL;
@ -145,17 +158,17 @@ void sys_open(Context* context, const char* filename, int flags)
return;
}
char* kernel_filename = Syscall::strdup_from_user(filename);
if (!kernel_filename)
char* kfilename = strdup_from_user(filename);
if (!kfilename)
{
context->rax = -EFAULT;
return;
}
VFS::Node* node = VFS::resolve_path(kernel_filename);
VFS::Node* node = VFS::resolve_path(kfilename);
if (!node)
{
kfree(kernel_filename);
kfree(kfilename);
context->rax = -ENOENT;
return;
}
@ -164,19 +177,31 @@ void sys_open(Context* context, const char* filename, int flags)
bool can_write = (flags & OPEN_WRITE) > 0;
if (!can_read && !can_write)
{
kfree(kernel_filename);
kfree(kfilename);
context->rax = -EINVAL;
return;
}
kdbgln("open(): opening %s %s, allocated file descriptor %d", kernel_filename,
bool able_to_block = (flags & OPEN_NONBLOCK) == 0;
bool close_on_exec = (flags & OPEN_CLOEXEC) > 0;
bool only_directory = (flags & OPEN_DIRECTORY) > 0;
if (only_directory && node->type != VFS_DIRECTORY)
{
kfree(kfilename);
context->rax = -ENOTDIR;
return;
}
kdbgln("open(): opening %s %s, allocated file descriptor %d", kfilename,
(can_read && can_write) ? "rw"
: can_read ? "r-"
: "-w",
fd);
kfree(kernel_filename);
current_task->files[fd].open(node, can_read, can_write);
kfree(kfilename);
current_task->files[fd].open(node, can_read, can_write, able_to_block, close_on_exec);
context->rax = fd;
return;
}
@ -199,7 +224,22 @@ void sys_read(Context* context, int fd, size_t size, char* buffer)
context->rax = -EBADF;
return;
}
ssize_t result = current_task->files[fd].read(size, (char*)VMM::get_physical((uint64_t)buffer));
if (VFS::would_block(current_task->files[fd].node()))
{
if (!current_task->files[fd].able_to_block())
{
context->rax = -EAGAIN;
return;
}
current_task->state = current_task->Blocking;
current_task->blocking_read_info.fd = fd;
current_task->blocking_read_info.buf = (char*)VMM::get_physical((uint64_t)buffer); // FIXME: Handle errors.
current_task->blocking_read_info.size = size;
return Scheduler::task_yield(context);
}
ssize_t result = current_task->files[fd].read(
size, (char*)VMM::get_physical((uint64_t)buffer)); // FIXME: Handle errors, and big buffers which may not be
// across continuous physical pages.
context->rax = (size_t)result;
return;
}
@ -225,7 +265,7 @@ void sys_close(Context* context, int fd)
void sys_mkdir(Context* context, const char* filename)
{
char* kfilename = Syscall::strdup_from_user(filename);
char* kfilename = strdup_from_user(filename);
if (!kfilename)
{
context->rax = -EFAULT;
@ -238,3 +278,12 @@ void sys_mkdir(Context* context, const char* filename)
context->rax = rc;
}
void sys_access(Context* context, const char* path, int) // FIXME: Use the amode argument.
{
char* kpath = strdup_from_user(path);
if (!VFS::exists(kpath)) { context->rax = -ENOENT; }
else
context->rax = 0;
kfree(kpath);
}

View File

@ -1,18 +1,20 @@
#define MODULE "sched"
#include "thread/Scheduler.h"
#include "errno.h"
#include "interrupts/Interrupts.h"
#include "kassert.h"
#include "log/Log.h"
#include "memory/MemoryManager.h"
#include "memory/PMM.h"
#include "memory/VMM.h"
#include "misc/hang.h"
#include "misc/reboot.h"
#include "misc/utils.h"
#include "panic/Panic.h"
#include "std/assert.h"
#include "std/errno.h"
#include "std/stdlib.h"
#include "std/string.h"
#include "sys/UserMemory.h"
#include "sys/elf/ELFLoader.h"
#include "thread/PIT.h"
#include "thread/Task.h"
@ -44,6 +46,14 @@ template <typename Callback> void sched_for_each_task(Callback callback)
} while (task != base_task);
}
template <typename Callback> void sched_for_each_child(Task* task, Callback callback)
{
sched_for_each_task([&](Task* child) {
if (child->ppid == task->id) { return callback(child); }
return true;
});
}
Task* Scheduler::find_by_pid(uint64_t pid)
{
Task* result = nullptr;
@ -91,6 +101,8 @@ void Scheduler::init()
idle_task.user_task = false;
idle_task.state = idle_task.Idle;
strlcpy(idle_task.name, "[cpu-idle]", sizeof(idle_task.name));
sched_current_task = &idle_task;
frequency = 1000 / PIT::frequency();
@ -102,6 +114,7 @@ void Scheduler::add_kernel_task(const char* taskname, void (*task)(void))
ASSERT(new_task);
new_task->user_task = false;
new_task->id = free_tid++;
new_task->ppid = 0;
new_task->regs.rip = (uint64_t)task;
new_task->allocated_stack =
(uint64_t)MemoryManager::get_pages(TASK_PAGES_IN_STACK); // 16 KB is enough for everyone, right?
@ -128,6 +141,7 @@ Task* Scheduler::create_user_task()
memset(&new_task->regs, 0, sizeof(Context));
new_task->user_task = true;
new_task->id = free_tid++;
new_task->ppid = 0;
new_task->task_sleep = 0;
new_task->task_time = 0;
new_task->cpu_time = 0;
@ -152,9 +166,11 @@ long Scheduler::load_user_task(const char* filename)
ASSERT(new_task);
memset(&new_task->regs, 0, sizeof(Context));
new_task->id = free_tid++;
new_task->ppid = 0;
if (!new_task->allocator.init())
{
delete new_task;
free_tid--;
Interrupts::pop();
return -ENOMEM;
}
@ -173,6 +189,7 @@ long Scheduler::load_user_task(const char* filename)
{
new_task->address_space.destroy();
delete new_task;
free_tid--;
ELFLoader::release_elf_image(image);
VMM::switch_back_to_kernel_address_space();
Interrupts::pop();
@ -245,26 +262,47 @@ void Scheduler::reap_task(Task* task)
Interrupts::pop();
}
for (int i = 0; i < TASK_MAX_FDS; i++) { exiting_task->files[i].close(); }
if (exiting_task->id == (free_tid - 1)) free_tid--; // If we are the last spawned thread, free our PID.
delete exiting_task;
}
void sched_common_exit(Context* context, int64_t status)
{
if (sched_current_task->id == 1) sched_current_task->state = sched_current_task->Exited;
else
sched_current_task->state = sched_current_task->Dying;
sched_current_task->exit_status = status;
if (sched_current_task->id != 1)
{
sched_for_each_child(sched_current_task, [](Task* child) {
if (child->state != child->Exited) child->ppid = 1;
return true;
});
}
else
{
#ifndef RUN_TEST_AS_INIT
reboot();
#else
hang();
#endif
}
Scheduler::task_yield(context);
}
void Scheduler::task_exit(Context* context, int64_t status)
{
ASSERT(Interrupts::is_in_handler());
kdbgln("exit: task %ld finished running, used %ld ms of cpu time", sched_current_task->id,
sched_current_task->cpu_time);
sched_current_task->state = sched_current_task->Exited;
sched_current_task->exit_status = status;
task_yield(context);
sched_common_exit(context, status);
}
void Scheduler::task_misbehave(Context* context, int64_t status)
{
ASSERT(Interrupts::is_in_handler());
kdbgln("exit: task %ld misbehaved, used %ld ms of cpu time", sched_current_task->id, sched_current_task->cpu_time);
sched_current_task->state = sched_current_task->Exited;
sched_current_task->exit_status = status;
task_yield(context);
sched_common_exit(context, status);
}
void Scheduler::reap_tasks()
@ -336,10 +374,10 @@ void Scheduler::task_tick(Context* context)
ASSERT(Interrupts::is_in_handler());
Interrupts::disable();
sched_decrement_sleep_times();
if (sched_current_task->id == 0) return task_yield(context);
sched_current_task->task_time -= frequency;
sched_current_task->cpu_time += frequency;
if (sched_current_task->task_time < 0)
if (sched_current_task->id == 0) return task_yield(context);
if (sched_current_task->task_time <= 0)
{
sched_current_task->task_time = 0;
task_yield(context);
@ -361,6 +399,14 @@ void Scheduler::task_yield(Context* context)
Task* original_task = sched_current_task;
do {
sched_current_task = sched_current_task->next_task;
if (sched_current_task->state == sched_current_task->Blocking)
{
if (!sched_current_task->is_still_blocking())
{
sched_current_task->resume_read();
sched_current_task->state = sched_current_task->Running;
}
}
if (sched_current_task->state == sched_current_task->Running)
{
if (sched_current_task->id != original_task->id || was_idle)
@ -414,3 +460,103 @@ Task* Scheduler::current_task()
{
return sched_current_task;
}
void sys_waitpid(Context* context, long pid, int* wstatus,
int) // FIXME: Use the value in options and block if WNOHANG has not been specified.
{
Task* child = nullptr;
if (pid == -1)
{
sched_for_each_child(sched_current_task, [&](Task* task) {
if (task->state == task->Dying)
{
child = task;
return false;
}
return true;
});
if (!child)
{
context->rax = 0; // No child has exited, let's return 0.
return;
}
}
else
{
child = Scheduler::find_by_pid(pid);
if (!child)
{
context->rax = -ESRCH;
return;
}
}
if (child->state != child->Dying) // FIXME: This should block if WNOHANG has not been specified.
{
context->rax = 0;
return;
}
if (wstatus)
{
int* kwstatus = obtain_user_ref(wstatus);
if (kwstatus)
{
*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;
}
}
child->state = child->Exited;
context->rax = (long)child->id;
}
struct pstat
{
long pt_pid;
long pt_ppid;
char pt_name[128];
int pt_state;
long pt_time;
};
void sys_pstat(Context* context, long pid, struct pstat* buf)
{
Task* task;
if (pid == -1) task = Scheduler::find_by_pid(free_tid - 1);
else if (pid == 0)
task = &idle_task;
else
task = Scheduler::find_by_pid(pid);
if (!task)
{
context->rax = -ESRCH;
return;
}
if (task->state == task->Exited) // we're just waiting for the reaper to reap it
{
context->rax = -ESRCH;
return;
}
if (buf)
{
struct pstat* kpstat = obtain_user_ref(buf);
if (!kpstat)
{
context->rax = -EFAULT;
return;
}
kpstat->pt_pid = task->id;
kpstat->pt_ppid = task->ppid;
kpstat->pt_state = (int)task->state;
kpstat->pt_time = (long)task->cpu_time;
strlcpy(kpstat->pt_name, task->name, sizeof(kpstat->pt_name));
release_user_ref(kpstat);
}
context->rax = task->id;
return;
}

View File

@ -1,4 +1,7 @@
#define MODULE "sched"
#include "thread/Task.h"
#include "log/Log.h"
#include "memory/VMM.h"
#include "std/string.h"
@ -66,3 +69,17 @@ bool Task::has_died()
{
return state == Exited;
}
void Task::resume_read()
{
VMM::switch_back_to_kernel_address_space();
VMM::apply_address_space();
VMM::switch_to_previous_user_address_space();
regs.rax = files[blocking_read_info.fd].read(blocking_read_info.size, blocking_read_info.buf);
VMM::apply_address_space();
}
bool Task::is_still_blocking()
{
return VFS::would_block(files[blocking_read_info.fd].node());
}

View File

@ -24,7 +24,7 @@ typedef struct stackframe
void StackTracer::trace()
{
stackframe* frame = (stackframe*)m_base_pointer;
while (frame && frame->instruction)
while (frame && frame->instruction && Memory::is_kernel_address(frame->instruction))
{
char symbol_name[512];
get_symbol_name(frame->instruction - sizeof(uintptr_t), symbol_name, sizeof(symbol_name));

View File

@ -5,7 +5,7 @@ LIBC_BIN := $(LIBC_DIR)/bin
DESTDIR ?= $(LUNA_BASE)/usr/lib
CFLAGS := -Os -nostdlib -fno-omit-frame-pointer -pedantic -Wall -Wextra -Werror -Wfloat-equal -Wdisabled-optimization -Wformat=2 -Winit-self -Wmissing-include-dirs -Wswitch-default -Wcast-qual -Wundef -Wcast-align -Wwrite-strings -Wlogical-op -Wredundant-decls -Wshadow -Wconversion
CFLAGS := -Os -nostdlib -fno-asynchronous-unwind-tables -fno-omit-frame-pointer -pedantic -Wall -Wextra -Werror -Wfloat-equal -Wdisabled-optimization -Wformat=2 -Winit-self -Wmissing-include-dirs -Wswitch-default -Wcast-qual -Wundef -Wcast-align -Wwrite-strings -Wlogical-op -Wredundant-decls -Wshadow -Wconversion
CXXFLAGS := -fno-rtti -fno-exceptions -Wsign-promo -Wstrict-null-sentinel -Wctor-dtor-privacy
ASMFLAGS := -felf64

View File

@ -6,6 +6,8 @@ extern _fini
extern initialize_libc
extern exit
extern __argv
global _start
_start:
; Set up end of the stack frame linked list.
@ -19,7 +21,7 @@ _start:
call _init
mov rdi, 0 ; argc = 0
mov rsi, 0 ; argv = 0
mov rsi, __argv ; Dummy argv which is equal to {NULL}
call main

View File

@ -0,0 +1,7 @@
#ifndef _BITS_GETPROCID_H
#define _BITS_GETPROCID_H
#define ID_PID 0
#define ID_PPID 1
#endif

View File

@ -5,5 +5,6 @@
#define __lc_align(n) __attribute__((aligned(n)))
#define __lc_deprecated(msg) __attribute__((deprecated(msg)))
#define __lc_unreachable __builtin_unreachable
#define __lc_used __attribute__((used))
#endif

View File

@ -0,0 +1,55 @@
#ifndef _DIRENT_H
#define _DIRENT_H
#include <luna/os-limits.h>
#include <sys/types.h>
struct dirent
{
ino_t d_ino;
off_t d_off;
unsigned short d_reclen;
unsigned char d_type;
char d_name[NAME_MAX];
};
typedef struct
{
int d_dirfd;
} DIR;
#ifdef __cplusplus
extern "C"
{
#endif
/* Opens the directory at path and returns a handle to it, or NULL on error. */
DIR* opendir(const char* path);
/* Returns a new directory handle associated with the file descriptor fd. */
DIR* fdopendir(int fd);
/* Closes the directory stream. */
int closedir(DIR* stream);
/* Reads an entry from the directory stream. The contents of the pointer returned may be overwritten by subsequent
* calls to readdir(). */
struct dirent* readdir(DIR* stream);
/* Returns the file descriptor associated with stream. */
int dirfd(DIR* stream);
/* Positions stream's offset at the start of the directory. */
void rewinddir(DIR* stream);
/* Returns the current offset position for stream. */
long telldir(DIR* stream);
/* Moves stream's read offset to offset, which should be the return value of a previous call to telldir(). */
void seekdir(DIR* stream, long offset);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -6,8 +6,11 @@ extern int errno;
#define EPERM 1 // Operation not permitted
#define ENOENT 2 // No such file or directory
#define ESRCH 3 // No such process
#define EINTR 4 // Interrupted system call. Not implemented.
#define ENOEXEC 8 // Exec format error
#define EBADF 9 // Bad file descriptor
#define EAGAIN 11 // Resource temporarily unavailable
#define ENOMEM 12 // Cannot allocate memory
#define EFAULT 14 // Bad address
#define EEXIST 17 // File exists
@ -15,9 +18,10 @@ extern int errno;
#define EISDIR 21 // Is a directory
#define EINVAL 22 // Invalid argument
#define EMFILE 24 // Too many open files
#define ENOTTY 25 // Inappropriate ioctl for device
#define ENOSPC 28 // No space left on device
#define EPIPE 32 // Broken pipe. Not implemented.
#define ENOSYS 38 // Function not implemented
#define ENOTSUP 95 // Operation not supported.
#define ENOTSUP 95 // Operation not supported
#endif

View File

@ -7,9 +7,17 @@
#define O_WRONLY 2
/* Open for reading and writing. */
#define O_RDWR 3
/* Open without blocking. */
#define O_NONBLOCK 4
/* Close the opened file descriptor on a call to execve(). */
#define O_CLOEXEC 8
/* Refuse to open the file if it is not a directory. */
#define O_DIRECTORY 16
/* Duplicate a file descriptor. */
#define F_DUPFD 0
/* Is a file descriptor a TTY? */
#define F_ISTTY 1
#ifdef __cplusplus
extern "C"

View File

@ -3,61 +3,69 @@
#include <stdint.h>
#define PRId8 "%d"
#define PRId16 "%d"
#define PRId32 "%d"
#define PRId64 "%ld"
#define PRIdLEAST8 "%d"
#define PRIdLEAST16 "%d"
#define PRIdLEAST32 "%d"
#define PRIdLEAST64 "%ld"
#define PRIdFAST8 "%d"
#define PRIdFAST16 "%d"
#define PRIdFAST32 "%d"
#define PRIdFAST64 "%ld"
#define PRIdMAX "%ld"
#define PRIdPTR "%ld"
#define PRIi8 "%d"
#define PRIi16 "%d"
#define PRIi32 "%d"
#define PRIi64 "%ld"
#define PRIiLEAST8 "%d"
#define PRIiLEAST16 "%d"
#define PRIiLEAST32 "%d"
#define PRIiLEAST64 "%ld"
#define PRIiFAST8 "%d"
#define PRIiFAST16 "%d"
#define PRIiFAST32 "%d"
#define PRIiFAST64 "%ld"
#define PRIiMAX "%ld"
#define PRIiPTR "%ld"
#define PRIu8 "%u"
#define PRIu16 "%u"
#define PRIu32 "%u"
#define PRIu64 "%lu"
#define PRIuLEAST8 "%u"
#define PRIuLEAST16 "%u"
#define PRIuLEAST32 "%u"
#define PRIuLEAST64 "%lu"
#define PRIuFAST8 "%u"
#define PRIuFAST16 "%u"
#define PRIuFAST32 "%u"
#define PRIuFAST64 "%lu"
#define PRIuMAX "%lu"
#define PRIuPTR "%lu"
#define PRIx8 "%x"
#define PRIx16 "%x"
#define PRIx32 "%x"
#define PRIx64 "%lx"
#define PRIxLEAST8 "%x"
#define PRIxLEAST16 "%x"
#define PRIxLEAST32 "%x"
#define PRIxLEAST64 "%lx"
#define PRIxFAST8 "%x"
#define PRIxFAST16 "%x"
#define PRIxFAST32 "%x"
#define PRIxFAST64 "%lx"
#define PRIxMAX "%lx"
#define PRIxPTR "%lx"
#define __PRI64_PREFIX "l"
#define PRId8 "d"
#define PRId16 "d"
#define PRId32 "d"
#define PRId64 __PRI64_PREFIX "d"
#define PRIdLEAST8 "d"
#define PRIdLEAST16 "d"
#define PRIdLEAST32 "d"
#define PRIdLEAST64 __PRI64_PREFIX "d"
#define PRIdFAST8 "d"
#define PRIdFAST16 "d"
#define PRIdFAST32 "d"
#define PRIdFAST64 __PRI64_PREFIX "d"
#define PRIdMAX __PRI64_PREFIX "d"
#define PRIdPTR __PRI64_PREFIX "d"
#define PRIi8 "d"
#define PRIi16 "d"
#define PRIi32 "d"
#define PRIi64 __PRI64_PREFIX "d"
#define PRIiLEAST8 "d"
#define PRIiLEAST16 "d"
#define PRIiLEAST32 "d"
#define PRIiLEAST64 __PRI64_PREFIX "d"
#define PRIiFAST8 "d"
#define PRIiFAST16 "d"
#define PRIiFAST32 "d"
#define PRIiFAST64 __PRI64_PREFIX "d"
#define PRIiMAX __PRI64_PREFIX "d"
#define PRIiPTR __PRI64_PREFIX "d"
#define PRIu8 "u"
#define PRIu16 "u"
#define PRIu32 "u"
#define PRIu64 __PRI64_PREFIX "u"
#define PRIuLEAST8 "u"
#define PRIuLEAST16 "u"
#define PRIuLEAST32 "u"
#define PRIuLEAST64 __PRI64_PREFIX "u"
#define PRIuFAST8 "u"
#define PRIuFAST16 "u"
#define PRIuFAST32 "u"
#define PRIuFAST64 __PRI64_PREFIX "u"
#define PRIuMAX __PRI64_PREFIX "u"
#define PRIuPTR __PRI64_PREFIX "u"
#define PRIx8 "x"
#define PRIx16 "x"
#define PRIx32 "x"
#define PRIx64 __PRI64_PREFIX "x"
#define PRIxLEAST8 "x"
#define PRIxLEAST16 "x"
#define PRIxLEAST32 "x"
#define PRIxLEAST64 __PRI64_PREFIX "x"
#define PRIxFAST8 "x"
#define PRIxFAST16 "x"
#define PRIxFAST32 "x"
#define PRIxFAST64 __PRI64_PREFIX "x"
#define PRIxMAX __PRI64_PREFIX "x"
#define PRIxPTR __PRI64_PREFIX "x"
#define PRIX8 PRIx8
#define PRIX16 PRIx16
#define PRIX32 PRIx32
#define PRIX64 PRIx64
#define PRIXMAX PRIxMAX
#define PRIXPTR PRIxPTR
#endif

View File

@ -1,6 +1,7 @@
#ifndef _LUNA_H
#define _LUNA_H
#include <bits/getprocid.h>
#include <bits/macros.h>
#include <sys/types.h>
@ -9,6 +10,9 @@ extern "C"
{
#endif
/* Returns a numeric identifier associated with the current process, depending on field. */
long getprocid(int field);
/* Sleeps for ms milliseconds. */
unsigned int msleep(unsigned int ms);

View File

@ -0,0 +1,27 @@
#ifndef _LUNA_DIRENT_H
#define _LUNA_DIRENT_H
#include <luna/os-limits.h>
#include <sys/types.h>
struct luna_dirent
{
ino_t inode;
char name[NAME_MAX];
size_t total;
off_t offset;
};
#ifdef __cplusplus
extern "C"
{
#endif
/* Retrieve directory entries from the kernel. This is the raw interface, use readdir() instead. */
ssize_t getdents(int fd, struct luna_dirent* buf, size_t count);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -4,6 +4,8 @@
#define OPEN_MAX 32
#define ATEXIT_MAX 32
#define NAME_MAX 64
#define PAGESIZE 4096
#define PAGE_SIZE 4096

View File

@ -0,0 +1,36 @@
#ifndef _LUNA_PSTAT_H
#define _LUNA_PSTAT_H
#include <sys/types.h>
struct pstat
{
pid_t pt_pid;
pid_t pt_ppid;
char pt_name[128];
int pt_state;
long pt_time;
};
#define PT_IDLE 0
#define PT_RUNNING 1
#define PT_SLEEPING 2
#define PT_ZOMBIE 3
#define PT_WAITING 4
#ifdef __cplusplus
extern "C"
{
#endif
/* Returns information about the process with PID pid in buf, if buf is non-null. Luna-specific. */
pid_t pstat(pid_t pid, struct pstat* buf);
/* Returns a string representation of the process state in buf. */
const char* pstatname(struct pstat* buf);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,42 +1,21 @@
#ifndef _LUNA_SYSCALL_H
#define _LUNA_SYSCALL_H
#define SYS_exit 0
#define SYS_yield 1
#define SYS_sleep 2
#define SYS_write 3
#define SYS_paint 4
#define SYS_getpid 5
#define SYS_mmap 6
#define SYS_munmap 7
#define SYS_open 8
#define SYS_read 9
#define SYS_close 10
#define SYS_seek 11
#define SYS_exec 12
#define SYS_fcntl 13
#define SYS_mprotect 14
#define SYS_clock 15
#define SYS_mkdir 16
#define SYS_fork 17
#ifndef __want_syscalls
#ifdef __cplusplus
extern "C"
{
#endif
long int __luna_syscall0(long int sys_num);
long int __luna_syscall1(long int sys_num, unsigned long int arg0);
long int __luna_syscall2(long int sys_num, unsigned long int arg0, unsigned long int arg1);
long int __luna_syscall3(long int sys_num, unsigned long int arg0, unsigned long int arg1, unsigned long int arg2);
long int __luna_syscall4(long int sys_num, unsigned long int arg0, unsigned long int arg1, unsigned long int arg2,
unsigned long int arg3);
long int __luna_syscall5(long int sys_num, unsigned long int arg0, unsigned long int arg1, unsigned long int arg2,
unsigned long int arg3, unsigned long int arg4);
long __luna_syscall0(long sys_num);
long __luna_syscall1(long sys_num, unsigned long arg0);
long __luna_syscall2(long sys_num, unsigned long arg0, unsigned long arg1);
long __luna_syscall3(long sys_num, unsigned long arg0, unsigned long arg1, unsigned long arg2);
long __luna_syscall4(long sys_num, unsigned long arg0, unsigned long arg1, unsigned long arg2, unsigned long arg3);
long __luna_syscall5(long sys_num, unsigned long arg0, unsigned long arg1, unsigned long arg2, unsigned long arg3,
unsigned long arg4);
#ifdef __cplusplus
}
#endif
#endif
#endif

View File

@ -0,0 +1,8 @@
#ifndef _LUNA_VFS_H
#define _LUNA_VFS_H
#define __VFS_FILE 0x0
#define __VFS_DIRECTORY 0x1
#define __VFS_DEVICE 0x2
#endif

View File

@ -1,7 +1,9 @@
#ifndef _SIGNAL_H
#define _SIGNAL_H
typedef int sig_atomic_t; // FIXME: Implement signals (I'm trying to build bc, this header is only to satisfy it) and
// use a proper atomic integer type.
typedef int sig_atomic_t; // On the x86, writes to aligned 32-bit and 64-bit integers are always atomic. (Or that's what
// I understood)
#define SIGINT 1 // Not implemented.
#endif

View File

@ -3,27 +3,39 @@
#include <stdarg.h>
#include <stddef.h>
#include <sys/types.h>
#include <bits/seek.h>
#define FOPEN_MAX 32
#define BUFSIZ 32
#define FILENAME_MAX 1024 // Dummy value, we don't have a limit for filenames right now.
typedef struct
{
int f_fd;
int f_eof;
int f_err;
char* f_buf;
long f_bufsize;
long f_bufoff;
long f_bufrsize;
} FILE;
extern FILE* stderr;
extern FILE* stdout;
extern FILE* stdin;
#define stdin stdin
#define stdout stdout
#define stderr stderr
typedef struct
{
long f_offset;
} fpos_t;
#define EOF -1
#define _IONBF 0
#define _IOLBF 1
#define _IOFBF 2
typedef off_t fpos_t;
#ifdef __cplusplus
extern "C"
@ -42,6 +54,9 @@ extern "C"
/* Returns a new file associated with the file descriptor fd. */
FILE* fdopen(int fd, const char* mode);
/* Opens the file specified by pathname and points the file handle stream to it. */
FILE* freopen(const char* pathname, const char* mode, FILE* stream);
/* Returns the file descriptor associated with the file stream. */
int fileno(FILE* stream);
@ -54,12 +69,18 @@ extern "C"
/* Moves stream's read/write offset by offset, depending on whence. */
int fseek(FILE* stream, long offset, int whence);
/* Moves stream's read/write offset by offset, depending on whence. */
int fseeko(FILE* stream, off_t offset, int whence);
/* Moves stream's read/write offset to the offset stored in the pos structure. */
int fsetpos(FILE* stream, const fpos_t* pos);
/* Returns the current offset for stream. */
long ftell(FILE* stream);
/* Returns the current offset for stream. */
off_t ftello(FILE* stream);
/* Stores the current offset for stream in the pos structure. */
int fgetpos(FILE* stream, fpos_t* pos);
@ -69,6 +90,20 @@ extern "C"
/* Writes nmemb items of size size from buf into the file stream. */
size_t fwrite(const void* buf, size_t size, size_t nmemb, FILE* stream);
/* Reads a line from stream into buf. */
char* fgets(char* buf, int size, FILE* stream);
/* Retrieves a character from stream. */
int fgetc(FILE* stream);
/* Retrieves a character from stream. */
int getc(FILE* stream);
int ungetc(int, FILE*); // Not implemented.
/* Retrieves a character from standard input. */
int getchar();
/* Returns nonzero if the error flag in stream was set. */
int ferror(FILE* stream);
@ -79,6 +114,7 @@ extern "C"
void clearerr(FILE* stream);
void setbuf(FILE*, char*); // Not implemented.
int setvbuf(FILE*, char*, int, size_t); // Not implemented.
/* Writes formatted output according to the string format to the file stream. */
int vfprintf(FILE* stream, const char* format, va_list ap);
@ -103,6 +139,8 @@ extern "C"
/* Writes at most max bytes of formatted output according to the string format to the string str. */
int vsnprintf(char* str, size_t max, const char* format, va_list ap);
int sscanf(const char*, const char*, ...); // Not implemented.
/* Writes the string str followed by a trailing newline to stdout. */
int puts(const char* str);
@ -122,6 +160,8 @@ extern "C"
* of the last error encountered during a call to a system or library function. */
void perror(const char* str);
int remove(const char* pathname); // Not implemented.
#ifdef __cplusplus
}
#endif

View File

@ -2,8 +2,32 @@
#define _STDLIB_H
#include <bits/macros.h>
#include <limits.h>
#include <stddef.h>
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
#define RAND_MAX INT_MAX
typedef struct
{
int quot;
int rem;
} div_t;
typedef struct
{
long quot;
long rem;
} ldiv_t;
typedef struct
{
long long quot;
long long rem;
} lldiv_t;
#ifdef __cplusplus
extern "C"
{
@ -30,6 +54,12 @@ extern "C"
/* Returns an integer (of type long long) parsed from the string str. */
long long atoll(const char* str);
/* Returns an integer (of type unsigned long) parsed from the string str. */
unsigned long strtoul(const char* str, char** endptr, int base);
/* Returns an integer (of type long) parsed from the string str. */
long strtol(const char* str, char** endptr, int base);
/* Not implemented. */
char* getenv(const char*);
@ -56,6 +86,26 @@ extern "C"
/* Seeds the random number generator with the specified seed. */
void srand(unsigned int seed);
/* Returns the absolute value of an integer. */
int abs(int val);
/* Returns the absolute value of an integer. */
long labs(long val);
/* Returns the absolute value of an integer. */
long long llabs(long long val);
/* Returns the result of dividing a by b. */
div_t div(int a, int b);
/* Returns the result of dividing a by b. */
ldiv_t ldiv(long a, long b);
/* Returns the result of dividing a by b. */
lldiv_t lldiv(long long a, long long b);
void qsort(void*, size_t, size_t, int (*)(const void*, const void*)); // Not implemented.
#ifdef __cplusplus
}
#endif

View File

@ -27,6 +27,10 @@ extern "C"
/* Returns a heap-allocated copy of the string str. Should be freed when it is not used anymore. */
char* strdup(const char* str);
/* Returns a heap-allocated copy of the string str, copying at maximum max bytes. Should be freed when it is not
* used anymore. */
char* strndup(const char* str, size_t max);
/* Returns the length of the string str. */
size_t strlen(const char* str);
@ -45,24 +49,37 @@ extern "C"
/* Returns a pointer to the last occurrence of the character c in str, or NULL if it is not found. */
char* strrchr(const char* str, int c);
/* Returns a pointer to the first occurrence of the character c in str, or a pointer to the terminating null byte of
* str if it is not found. */
char* strchrnul(const char* str, int c);
/* Concatenates at most max bytes of the string src into dest. */
char* strncat(char* dest, const char* src, size_t max);
/* Returns the length of the initial segment of str which consists entirely of bytes not in reject. */
size_t strcspn(const char* str, const char* reject);
/* Returns the length of the initial segment of str which consists entirely of bytes in accept. */
size_t strspn(const char* str, const char* accept);
/* Returns a pointer to the first occurrence of any character of b in a. */
char* strpbrk(const char* a, const char* b);
/* Compares strings a and b. You might prefer to use the safer strncmp function. */
int strcmp(const char* a, const char* b);
/* Compares at most max bytes of the strings a and b. */
int strncmp(const char* a, const char* b, size_t max);
/* Compares a and b based on the current locale. */
int strcoll(const char* a, const char* b);
/* Searches for the needle string in the haystack string. */
char* strstr(const char* haystack, const char* needle);
/* Returns the error string associated with the error number err. */
char* strerror(int err);
/* Clears n bytes of buf. */
void* bzero(void* buf, size_t n);
/* Copies the string src into dest. This function is unsafe, use strlcpy instead. */
__lc_deprecated("strcpy is unsafe and should not be used; use strlcpy instead") char* strcpy(char* dest,
const char* src);

View File

@ -0,0 +1,27 @@
#ifndef _STRINGS_H
#define _STRINGS_H
#include <stddef.h>
#ifdef __cplusplus
extern "C"
{
#endif
/* Clears n bytes of buf. */
void bzero(void* buf, size_t n);
/* Copies n bytes of src into dest. */
void bcopy(void* dest, const void* src, size_t n);
/* Compares strings a and b while treating uppercase and lowercase characters as the same. */
int strcasecmp(const char* a, const char* b);
/* Compares at most max bytes of strings a and b while treating uppercase and lowercase characters as the same. */
int strncasecmp(const char* a, const char* b, size_t max);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -13,6 +13,10 @@
#define PAGE_SIZE 4096
#define MAP_PRIVATE 0
#define MAP_SHARED 1
#define MAP_ANONYMOUS 2
#ifdef __cplusplus
extern "C"
{
@ -26,7 +30,7 @@ extern "C"
* address space. */
int munmap(void* addr, size_t size);
/* Protects size bytes of memory according to the prot argument. */
/* Changes the permissions of size bytes of memory at addr zaccording to the prot argument. */
int mprotect(void* addr, size_t size, int prot);
#ifdef __cplusplus

View File

@ -1,8 +1,19 @@
#ifndef _SYS_STAT_H
#define _SYS_STAT_H
#include <luna/vfs.h>
#include <sys/types.h>
struct stat // FIXME: This struct is quite stubbed out.
{
ino_t st_ino;
mode_t st_mode;
off_t st_size;
};
#define S_ISDIR(mode) (((mode)&0xf) == __VFS_DIRECTORY)
#define S_ISREG(mode) (((mode)&0xf) == __VFS_FILE)
#ifdef __cplusplus
extern "C"
{
@ -11,6 +22,9 @@ extern "C"
/* Creates a new directory at the path pathname. FIXME: For now, mode is ignored. */
int mkdir(const char* pathname, mode_t mode);
/* Returns information about the file pointed to by fd in buf. */
int fstat(int fd, struct stat* buf);
#ifdef __cplusplus
}
#endif

View File

@ -1,9 +1,28 @@
#ifndef _SYS_SYSCALL_H
#define _SYS_SYSCALL_H
#define __want_syscalls
#include <luna/syscall.h>
#undef __want_syscalls
#undef _LUNA_SYSCALL_H
#define SYS_exit 0
#define SYS_yield 1
#define SYS_sleep 2
#define SYS_write 3
#define SYS_paint 4
#define SYS_getprocid 5
#define SYS_mmap 6
#define SYS_munmap 7
#define SYS_open 8
#define SYS_read 9
#define SYS_close 10
#define SYS_seek 11
#define SYS_exec 12
#define SYS_fcntl 13
#define SYS_mprotect 14
#define SYS_clock 15
#define SYS_mkdir 16
#define SYS_fork 17
#define SYS_waitpid 18
#define SYS_access 19
#define SYS_fstat 20
#define SYS_pstat 21
#define SYS_getdents 22
#endif

View File

@ -16,4 +16,7 @@ typedef long int off_t;
/* The type of a file's mode. */
typedef unsigned short mode_t;
/* The type of a filesystem inode. */
typedef unsigned long ino_t;
#endif

View File

@ -0,0 +1,27 @@
#ifndef _SYS_WAIT_H
#define _SYS_WAIT_H
#include <sys/types.h>
/* Has the child process exited by calling exit() or _exit()? */
#define WIFEXITED(status) ((status) || 1)
/* What was the child's exit status? */
#define WEXITSTATUS(status) (char)((status)&0xff)
#ifdef __cplusplus
extern "C"
{
#endif
/* Waits for the child process to finish running. */
pid_t waitpid(pid_t pid, int* wstatus, int options);
/* Waits for any child process to finish running. */
pid_t wait(int* wstatus);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,9 +1,27 @@
#ifndef _TIME_H
#define _TIME_H
#include <stddef.h>
typedef long int clock_t;
typedef long int time_t;
struct tm
{
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
long tm_gmtoff;
const char* tm_zone;
};
#define CLOCKS_PER_SEC 1000
#ifdef __cplusplus
@ -15,6 +33,13 @@ extern "C"
* get the value in seconds. */
clock_t clock(void);
/* FIXME: For now, is an alias for clock(), but in seconds. */
time_t time(time_t* tloc);
struct tm* localtime(const time_t* timep); // Not implemented.
struct tm* gmtime(const time_t* timep); // Not implemented.
size_t strftime(char* str, size_t max, const char* format, const struct tm* time); // Not implemented.
#ifdef __cplusplus
}
#endif

View File

@ -6,8 +6,14 @@
#include <luna/os-limits.h>
#include <sys/types.h>
#define STDOUT_FILENO 0
#define STDERR_FILENO 1
#define STDIN_FILENO 0 // The standard input stream.
#define STDOUT_FILENO 1 // The standard output stream.
#define STDERR_FILENO 2 // The standard error stream.
#define F_OK 0 // Check for a file's existence.
#define R_OK 1 // Check whether a file is readable.
#define W_OK 2 // Check whether a file is writable.
#define X_OK 4 // Check whether a file is executable.
#ifdef __cplusplus
extern "C"
@ -27,9 +33,12 @@ extern "C"
* the parent. */
pid_t fork(void);
/* Returns the current process's process ID. */
/* Returns the current process' process ID. */
pid_t getpid(void);
/* Returns the current process' parent's process ID. */
pid_t getppid(void);
/* Terminates the program with the status code status. */
__lc_noreturn void _exit(int status);
@ -54,6 +63,12 @@ extern "C"
/* Returns a copy of the file descriptor fd. */
int dup(int fd);
/* Checks if the current program can access the file or directory at path. */
int access(const char* path, int amode);
/* Checks if the file descriptor fd refers to a terminal. */
int isatty(int fd);
#ifdef __cplusplus
}
#endif

73
libs/libc/src/dirent.cpp Normal file
View File

@ -0,0 +1,73 @@
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <luna/dirent.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
extern "C"
{
DIR* opendir(const char* path)
{
int fd = open(path, O_RDONLY | O_DIRECTORY);
if (fd < 0) return NULL;
return fdopendir(fd);
}
DIR* fdopendir(int fd)
{
if (fd < 0) return NULL;
DIR* result = (DIR*)malloc(sizeof(DIR));
if (!result) return NULL;
result->d_dirfd = fd;
return result;
}
int closedir(DIR* stream)
{
int status = close(stream->d_dirfd);
if (status < 0)
{
int savederr = errno;
free(stream);
errno = savederr; // free might reset errno. We don't want that.
}
else { free(stream); }
return status;
}
struct dirent* readdir(DIR* stream)
{
static struct dirent result;
struct luna_dirent ent;
ssize_t nread = getdents(stream->d_dirfd, &ent, 1); // FIXME: Use a buffer to avoid too many system calls.
if (nread <= 0) return NULL; // Either EOF or error.
result.d_ino = ent.inode;
result.d_reclen = sizeof(result);
result.d_off = ent.offset;
result.d_type = 0;
strlcpy(result.d_name, ent.name, NAME_MAX);
return &result;
}
int dirfd(DIR* stream)
{
return stream->d_dirfd;
}
void rewinddir(DIR* stream)
{
lseek(stream->d_dirfd, 0, SEEK_SET);
}
long telldir(DIR* stream)
{
return lseek(stream->d_dirfd, 0, SEEK_CUR);
}
void seekdir(DIR* stream, long offset)
{
lseek(stream->d_dirfd, offset, SEEK_SET);
}
}

View File

@ -7,11 +7,35 @@
FILE* stderr;
FILE* stdout;
FILE* stdin;
void file_read_buf(FILE* stream)
{
if (!stream->f_buf)
{
stream->f_buf = (char*)malloc(BUFSIZ); // FIXME: Handle errors.
stream->f_bufrsize = BUFSIZ;
}
stream->f_bufoff = 0;
ssize_t nread = read(stream->f_fd, stream->f_buf, stream->f_bufrsize);
if (nread < 0)
{
stream->f_err = 1;
return;
}
if (nread == 0)
{
stream->f_eof = 1;
return;
}
stream->f_bufsize = nread;
}
extern "C"
{
int fclose(FILE* stream)
{
if (stream->f_buf) free(stream->f_buf);
int status = close(stream->f_fd);
if (status < 0)
{
@ -46,6 +70,23 @@ extern "C"
}
FILE* stream = (FILE*)malloc(sizeof(FILE));
if (!stream) { return 0; }
stream->f_fd = fd;
clearerr(stream);
stream->f_buf = 0;
stream->f_bufoff = 0;
stream->f_bufsize = 0;
return stream;
}
FILE* freopen(const char* pathname, const char*,
FILE* stream) // FIXME: If pathname is NULL, open the original file with the new mode.
{
int fd = open(pathname, O_RDWR); // FIXME: Use the mode string.
if (fd < 0) { return 0; }
fflush(stream); // To make it future-proof.
fclose(stream);
stream->f_fd = fd;
clearerr(stream);
return stream;
@ -58,7 +99,9 @@ extern "C"
size_t fread(void* buf, size_t size, size_t nmemb, FILE* stream)
{
ssize_t status = read(stream->f_fd, buf, size * nmemb);
ssize_t status =
read(stream->f_fd, buf,
size * nmemb); // FIXME: This function should use file_read_buf() to not conflict with fgets().
if (status < 0)
{
stream->f_err = 1;
@ -68,6 +111,79 @@ extern "C"
return (size_t)status;
}
char* fgets(char* buf, int size, FILE* stream)
{
char* s = buf;
int original_size = size;
while (size > 1)
{
if (stream->f_bufoff < stream->f_bufsize)
{
*buf = *(stream->f_buf + stream->f_bufoff);
stream->f_bufoff++;
if (*buf == '\n')
{
buf++;
break;
}
buf++;
size--;
}
else
{
file_read_buf(stream);
if (ferror(stream)) return NULL;
if (feof(stream)) break;
}
}
if (size == original_size && feof(stream)) return NULL; // EOF while reading the first character
*buf = 0;
return s;
}
int fgetc(FILE* stream)
{
char result;
read:
if (stream->f_bufoff < stream->f_bufsize)
{
result = *(stream->f_buf + stream->f_bufoff);
stream->f_bufoff++;
}
else
{
file_read_buf(stream);
if (ferror(stream)) return EOF;
if (feof(stream)) return EOF;
goto read;
}
return (int)result;
}
int getc(FILE* stream)
{
return fgetc(stream);
}
int getchar()
{
return fgetc(stdin);
}
int ungetc(int c, FILE* stream)
{
if (stream->f_bufoff > 0)
{
stream->f_bufoff--;
stream->f_buf[stream->f_bufoff] = (char)c;
return c;
}
else
{
return EOF; // FIXME: Handle this case properly.
}
}
int ferror(FILE* stream)
{
return stream->f_err;
@ -90,9 +206,14 @@ extern "C"
return 0;
}
int fseeko(FILE* stream, off_t offset, int whence)
{
return fseek(stream, offset, whence);
}
int fsetpos(FILE* stream, const fpos_t* pos)
{
return fseek(stream, pos->f_offset, SEEK_SET);
return fseek(stream, *pos, SEEK_SET);
}
long ftell(FILE* stream)
@ -102,11 +223,16 @@ extern "C"
// maybe? We'd have to update this value in fread() and fwrite() as well...
}
off_t ftello(FILE* stream)
{
return ftell(stream);
}
int fgetpos(FILE* stream, fpos_t* pos)
{
long result = ftell(stream);
if (result < 0) { return -1; }
pos->f_offset = result;
*pos = result;
return 0;
}
@ -132,4 +258,9 @@ extern "C"
{
NOT_IMPLEMENTED("setbuf");
}
int setvbuf(FILE*, char*, int, size_t)
{
NOT_IMPLEMENTED("setvbuf");
}
}

View File

@ -4,10 +4,13 @@
#include <stdlib.h>
#include <unistd.h>
__lc_used const char* __argv[] = {NULL}; // For now.
static void terminate_libc()
{
fclose(stdout);
fclose(stderr);
fclose(stdin);
}
static void initialize_random()
@ -52,6 +55,7 @@ static void check_for_file(int fd, FILE** target_stream, const char* path, const
extern "C" void initialize_libc()
{
check_for_file(STDIN_FILENO, &stdin, "/dev/kbd", "r");
check_for_file(STDOUT_FILENO, &stdout, "/dev/console", "rw");
check_for_file(STDERR_FILENO, &stderr, "/dev/console", "rw");

View File

@ -7,6 +7,11 @@
extern "C"
{
long getprocid(int field)
{
return syscall(SYS_getprocid, field);
}
unsigned int msleep(unsigned int ms)
{
return (unsigned int)syscall(SYS_sleep, ms);

View File

@ -0,0 +1,11 @@
#include <luna/dirent.h>
#include <sys/syscall.h>
#include <unistd.h>
extern "C"
{
ssize_t getdents(int fd, struct luna_dirent* buf, size_t count)
{
return syscall(SYS_getdents, fd, buf, count);
}
}

View File

@ -0,0 +1,24 @@
#include <luna/pstat.h>
#include <sys/syscall.h>
#include <unistd.h>
extern "C"
{
pid_t pstat(pid_t pid, struct pstat* buf)
{
return syscall(SYS_pstat, pid, buf);
}
const char* pstatname(struct pstat* buf)
{
switch (buf->pt_state)
{
case PT_IDLE: return "Idle";
case PT_RUNNING: return "Running";
case PT_SLEEPING: return "Sleeping";
case PT_WAITING: return "Waiting";
case PT_ZOMBIE: return "Zombie";
default: return "Unknown";
}
}
}

View File

@ -0,0 +1,50 @@
global __luna_syscall0
__luna_syscall0:
mov rax, rdi
int 0x42
ret
global __luna_syscall1
__luna_syscall1:
mov rax, rdi
mov rdi, rsi
int 0x42
ret
global __luna_syscall2
__luna_syscall2:
mov rax, rdi
mov rdi, rsi
mov rsi, rdx
int 0x42
ret
global __luna_syscall3
__luna_syscall3:
mov rax, rdi
mov rdi, rsi
mov rsi, rdx
mov rdx, rcx
int 0x42
ret
global __luna_syscall4
__luna_syscall4:
mov rax, rdi
mov rdi, rsi
mov rsi, rdx
mov rdx, rcx
mov r10, r8
int 0x42
ret
global __luna_syscall5
__luna_syscall5:
mov rax, rdi
mov rdi, rsi
mov rsi, rdx
mov rdx, rcx
mov r10, r8
mov r8, r9
int 0x42
ret

View File

@ -1,48 +0,0 @@
#include <luna/syscall.h>
long int __luna_syscall0(long int sys_num)
{
long int result;
asm volatile("int $0x42" : "=a"(result) : "a"(sys_num));
return result;
}
long int __luna_syscall1(long int sys_num, unsigned long int arg0)
{
long int result;
asm volatile("int $0x42" : "=a"(result) : "a"(sys_num), "D"(arg0));
return result;
}
long int __luna_syscall2(long int sys_num, unsigned long int arg0, unsigned long int arg1)
{
long int result;
asm volatile("int $0x42" : "=a"(result) : "a"(sys_num), "D"(arg0), "S"(arg1));
return result;
}
long int __luna_syscall3(long int sys_num, unsigned long int arg0, unsigned long int arg1, unsigned long int arg2)
{
long int result;
asm volatile("int $0x42" : "=a"(result) : "a"(sys_num), "D"(arg0), "S"(arg1), "d"(arg2));
return result;
}
long int __luna_syscall4(long int sys_num, unsigned long int arg0, unsigned long int arg1, unsigned long int arg2,
unsigned long int arg3)
{
long int result;
register unsigned long int value0 asm("r10") = arg3;
asm volatile("int $0x42" : "=a"(result) : "a"(sys_num), "D"(arg0), "S"(arg1), "d"(arg2), "r"(value0));
return result;
}
long int __luna_syscall5(long int sys_num, unsigned long int arg0, unsigned long int arg1, unsigned long int arg2,
unsigned long int arg3, unsigned long int arg4)
{
long int result;
register unsigned long int value0 asm("r10") = arg3;
register unsigned long int value1 asm("r8") = arg4;
asm volatile("int $0x42" : "=a"(result) : "a"(sys_num), "D"(arg0), "S"(arg1), "d"(arg2), "r"(value0), "r"(value1));
return result;
}

View File

@ -15,12 +15,14 @@ extern "C"
if (putchar('\n') < 0) return -1;
return nwritten + 1;
}
int fputs(const char* s, FILE* stream)
{
int result = (int)fwrite(s, strlen(s), 1, stream);
if (ferror(stream)) return -1;
return result;
}
int fputc(int c, FILE* stream)
{
char chr = (char)c;
@ -28,14 +30,17 @@ extern "C"
if (ferror(stream)) { return -1; }
return c;
}
int putc(int c, FILE* stream)
{
return fputc(c, stream);
}
int putchar(int c)
{
return fputc(c, stdout);
}
void perror(const char* s)
{
int savederr =
@ -43,4 +48,14 @@ extern "C"
if (s && *s) { fprintf(stderr, "%s: ", s); }
fprintf(stderr, "%s\n", strerror(savederr));
}
int remove(const char*)
{
NOT_IMPLEMENTED("remove");
}
int sscanf(const char*, const char*, ...)
{
NOT_IMPLEMENTED("sscanf");
}
}

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