From 629ed9e43b33a7ffec4d00a3f637e8640c9a34b2 Mon Sep 17 00:00:00 2001 From: apio Date: Sat, 18 Mar 2023 19:23:18 +0100 Subject: [PATCH] libc: Start switching to /dev/console for console IO and add a proper init --- apps/CMakeLists.txt | 2 +- apps/app.c | 39 --------------------------- apps/init.c | 38 ++++++++++++++++++++++++++ kernel/src/main.cpp | 4 +-- libc/CMakeLists.txt | 1 + libc/include/stdio.h | 17 ++++++++++++ libc/include/unistd.h | 3 +++ libc/src/arch/x86_64/crt0.S | 3 +++ libc/src/init.cpp | 11 ++++++++ libc/src/stdio.cpp | 54 +++++++++++++++++++++++++++++++++---- 10 files changed, 125 insertions(+), 47 deletions(-) delete mode 100644 apps/app.c create mode 100644 apps/init.c create mode 100644 libc/src/init.cpp diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index 80c8a777..748f3695 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -6,5 +6,5 @@ function(luna_app SOURCE_FILE APP_NAME) install(TARGETS ${APP_NAME} DESTINATION ${LUNA_ROOT}/initrd/bin) endfunction() -luna_app(app.c app) +luna_app(init.c init) luna_app(hello.c hello) diff --git a/apps/app.c b/apps/app.c deleted file mode 100644 index b443fa34..00000000 --- a/apps/app.c +++ /dev/null @@ -1,39 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -void bye() -{ - printf("byeee!\n"); -} - -int main() -{ - atexit(bye); - printf("Welcome to %s from userspace (pid %d)!\n", "Luna", getpid()); - - FILE* f = fopen("/etc/motd", "r"); - if (!f) - { - perror("fopen"); - return 1; - } - - char buffer[512]; - size_t nread = fread(buffer, 1, sizeof(buffer), f); - buffer[nread] = 0; - - printf("/etc/motd says: %s", buffer); - - fclose(f); - - time_t now = time(NULL); - printf("date: %s", ctime(&now)); - - // FIXME: Add libc wrapper. - syscall(SYS_exec, "/bin/hello"); -} diff --git a/apps/init.c b/apps/init.c new file mode 100644 index 00000000..1af5ea58 --- /dev/null +++ b/apps/init.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include +#include +#include +#include + +#define xmknod(path, mode, maj, min) \ + if (mknod(path, mode, makedev(maj, min)) < 0) exit(255); + +// Too early for console logs (/dev/console is created here!), so we have to resort to exiting with a weird exit code in +// case of failure. +static void populate_devfs() +{ + if (mkdir("/dev", 0755) < 0 && errno != EEXIST) exit(255); + + xmknod("/dev/console", 0666, 1, 0); + xmknod("/dev/null", 0666, 2, 0); +} + +int main() +{ + if (getpid() != 1) + { + printf("error: init not running as PID 1.\n"); + return 1; + } + + populate_devfs(); + + // Before this point, we don't even have an stdout and stderr. Set it up now so that child processes (and us) can + // print stuff. + stdout = fopen("/dev/console", "w"); + stderr = fopen("/dev/console", "w"); + + fputs("Hello, world!", stderr); +} diff --git a/kernel/src/main.cpp b/kernel/src/main.cpp index 406307a9..cd158592 100644 --- a/kernel/src/main.cpp +++ b/kernel/src/main.cpp @@ -66,9 +66,9 @@ static void init_vfs() static Result try_init_userspace() { - auto app = TRY(VFS::resolve_path("/bin/app")); + auto init = TRY(VFS::resolve_path("/bin/init")); - TRY(Scheduler::new_userspace_thread(app)); + TRY(Scheduler::new_userspace_thread(init)); return {}; } diff --git a/libc/CMakeLists.txt b/libc/CMakeLists.txt index 4b707260..8e85fc1a 100644 --- a/libc/CMakeLists.txt +++ b/libc/CMakeLists.txt @@ -12,6 +12,7 @@ set(SOURCES src/atexit.cpp src/ctype.cpp src/time.cpp + src/init.cpp src/sys/stat.cpp src/sys/mman.cpp ) diff --git a/libc/include/stdio.h b/libc/include/stdio.h index 831d0069..8c8d7a49 100644 --- a/libc/include/stdio.h +++ b/libc/include/stdio.h @@ -16,7 +16,9 @@ typedef struct #define EOF -1 +extern FILE* stdout; extern FILE* stderr; +#define stdout stdout #define stderr stderr #ifdef __cplusplus @@ -29,6 +31,9 @@ extern "C" /* Open a file and binds a stream to it. */ FILE* fopen(const char* path, const char* mode); + /* Bind a stream to a file descriptor. */ + FILE* fdopen(int fd, const char* mode); + /* Close a file and frees up its stream. */ int fclose(FILE* stream); @@ -62,6 +67,18 @@ extern "C" /* Return whether the end-of-file indicator was set in stream. */ int feof(FILE* stream); + /* Write a character to stream. */ + int fputc(int c, FILE* stream); + + /* Write a character to stream. */ + int putc(int c, FILE* stream); + + /* Write a character to standard output. */ + int putchar(int c); + + /* Write a string to stream. */ + int fputs(const char* str, FILE* stream); + /* Clear the error and end-of-file indicators in stream. */ void clearerr(FILE* stream); diff --git a/libc/include/unistd.h b/libc/include/unistd.h index 8f15cf75..1782a796 100644 --- a/libc/include/unistd.h +++ b/libc/include/unistd.h @@ -10,6 +10,9 @@ #include #include +#define STDOUT_FILENO 0 +#define STDERR_FILENO 1 + #ifdef __cplusplus extern "C" { diff --git a/libc/src/arch/x86_64/crt0.S b/libc/src/arch/x86_64/crt0.S index cfebdc21..35f012a0 100644 --- a/libc/src/arch/x86_64/crt0.S +++ b/libc/src/arch/x86_64/crt0.S @@ -2,6 +2,7 @@ .global _start .extern exit +.extern libc_init _start: # Set up end of the stack frame linked list. movq $0, %rbp @@ -9,6 +10,8 @@ _start: pushq %rbp # rbp=0 movq %rsp, %rbp + call libc_init + # Run the global constructors. call _init diff --git a/libc/src/init.cpp b/libc/src/init.cpp new file mode 100644 index 00000000..1582945f --- /dev/null +++ b/libc/src/init.cpp @@ -0,0 +1,11 @@ +#include +#include + +extern "C" +{ + void libc_init() + { + stdout = fdopen(STDOUT_FILENO, "w"); + stderr = fdopen(STDERR_FILENO, "w"); + } +} diff --git a/libc/src/stdio.cpp b/libc/src/stdio.cpp index e6f3ff8e..e7f636f0 100644 --- a/libc/src/stdio.cpp +++ b/libc/src/stdio.cpp @@ -9,6 +9,7 @@ #include FILE* stderr = nullptr; +FILE* stdout = nullptr; static int fopen_parse_mode(const char* mode) { @@ -41,13 +42,13 @@ extern "C" if ((flags = fopen_parse_mode(mode)) < 0) return nullptr; - int fd = open(path, flags, 0666); - if (fd < 0) return nullptr; - FILE* f = (FILE*)malloc(sizeof(FILE)); - if (!f) + if (!f) { return nullptr; } + + int fd = open(path, flags, 0666); + if (fd < 0) { - close(fd); + free(f); return nullptr; } @@ -57,6 +58,25 @@ extern "C" return f; } + FILE* fdopen(int fd, const char* mode) + { + int flags; + + if ((flags = fopen_parse_mode(mode)) < 0) return nullptr; + + // FIXME: We do verify that fd is valid, but not that the mode is compatible. + long rc = lseek(fd, 0, SEEK_CUR); + if (rc < 0) return nullptr; + + FILE* f = (FILE*)malloc(sizeof(FILE)); + if (!f) { return nullptr; } + + f->_fd = fd; + clearerr(f); + + return f; + } + int fclose(FILE* stream) { if (close(stream->_fd) < 0) return EOF; @@ -148,6 +168,30 @@ extern "C" return stream->_eof; } + int fputc(int c, FILE* stream) + { + u8 value = (u8)c; + ssize_t rc = write(stream->_fd, &value, 1); + if (rc <= 0) return EOF; + return c; + } + + int putc(int c, FILE* stream) + { + return fputc(c, stream); + } + + int putchar(int c) + { + return fputc(c, stdout); + } + + int fputs(const char* str, FILE* stream) + { + ssize_t rc = write(stream->_fd, str, strlen(str)); + return (rc < 0) ? -1 : 0; + } + void clearerr(FILE* stream) { stream->_eof = stream->_err = 0;