diff options
Diffstat (limited to 'init')
-rw-r--r-- | init/init.c | 60 | ||||
-rw-r--r-- | init/log.c | 69 | ||||
-rw-r--r-- | init/subsys.c | 55 | ||||
-rw-r--r-- | init/util.c | 22 |
4 files changed, 206 insertions, 0 deletions
diff --git a/init/init.c b/init/init.c new file mode 100644 index 0000000..5363082 --- /dev/null +++ b/init/init.c @@ -0,0 +1,60 @@ +#include <signal.h> +#include <sys/wait.h> + +#include <init.h> +#include <util.h> + +/* For some reason, I get SIGSEGV'd when running because a random-ass + byte was inserted where it isnt supposed to be. Added a safety byte + because I cannot be asked to try to figure out how to do this cleanly. */ +static unsigned long __1bsafebuf + __attribute__((used)) __attribute__((section(".1bsafebuf.init"))) = 0; + +extern initcall_entry_t __initcall1_start[]; +extern initcall_entry_t __initcall2_start[]; +extern initcall_entry_t __initcall3_start[]; +extern initcall_entry_t __initcall4_start[]; +extern initcall_entry_t __initcall5_start[]; +extern initcall_entry_t __initcall_end[]; + +static initcall_entry_t *initcall_levels[] = { + __initcall1_start, + __initcall2_start, + __initcall3_start, + __initcall4_start, + __initcall5_start, + __initcall_end, +}; + +static void do_initcall_level(int level) +{ + initcall_entry_t *fn; + + for (fn = initcall_levels[level - 1]; fn < initcall_levels[level]; fn++) + initcall_from_entry(fn)(); +} + +static void do_initcalls(void) +{ + unsigned long level; + for (level = 1; level < ARRAY_SIZE(initcall_levels); level++) { + do_initcall_level(level); + } +} + +int main(void) +{ + do_initcalls(); + + static sigset_t set; + sigaddset(&set, SIGCHLD); + sigprocmask(SIG_BLOCK, &set, NULL); + + while(1) { + int sig; + sigwait(&set, &sig); + if(sig == SIGCHLD) + while(waitpid(0, NULL, WNOHANG) > 0) + ; + } +} diff --git a/init/log.c b/init/log.c new file mode 100644 index 0000000..3cdaa06 --- /dev/null +++ b/init/log.c @@ -0,0 +1,69 @@ +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <sys/file.h> +#include <unistd.h> + +#include <log.h> +#include <util.h> + +static const char *colors[] = { + [0] = ANSI_BLINK ANSI_REVERSE ANSI_BOLD ANSI_RED, + [1] = ANSI_REVERSE ANSI_BOLD ANSI_RED, + [2] = ANSI_BOLD ANSI_RED, + [3] = ANSI_RED, + [4] = ANSI_BOLD, + [5] = ANSI_BRIGHT_WHITE, + [6] = ANSI_RESET, + [7] = ANSI_ITALIC ANSI_BRIGHT_BLUE, +}; + +int console_lock = 0; + +int print(const char *fmt, ...) +{ + int loglevel = 5; + if(fmt[0] == LOG_SOH_ASCII) { + loglevel = (fmt[1] - 0x30) % 10; + fmt += 2; + } + + char buf[512]; + + va_list ap; + va_start(ap, fmt); + vsnprintf(buf, 512, fmt, ap); + va_end(ap); + buf[512 - 1] = '\0'; + + size_t colon = 0; + for(; colon < strlen(buf); ++colon) { + if(buf[colon] == ':') + break; + } + + /* spin lock, at the cost of architecture portability */ + __asm__(".spin_lock:"); + __asm__("mov rax, 1"); + __asm__("xchg rax, [console_lock]"); + __asm__("test rax, rax"); + __asm__("jnz .spin_lock"); + + if(buf[colon] == ':') { + writeputs(ANSI_RESET); + writeputs(colors[loglevel]); + writeputs(ANSI_YELLOW); + write(STDOUT_FILENO, buf, colon); + writeputs(ANSI_RESET); + } + writeputs(colors[loglevel]); + if(colon && *(buf + colon)) { + writeputs(buf + colon); + } else { + writeputs(buf); + } + writeputs(ANSI_RESET); + + console_lock = 0; + return 0; +} diff --git a/init/subsys.c b/init/subsys.c new file mode 100644 index 0000000..0435f1a --- /dev/null +++ b/init/subsys.c @@ -0,0 +1,55 @@ +#include <errno.h> +#include <sched.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/prctl.h> +#include <sys/syscall.h> +#include <sys/mman.h> +#include <unistd.h> + +#include <config.h> +#include <log.h> +#include <util.h> + +#define STACK_SIZE 8192 * 512 + +struct subsystem_info { + char *fn_name; + int (*fn)(void); +}; + +int __subsystem_entry(struct subsystem_info *info) +{ + + char *name = malloc(16 * sizeof(char)); + snprintf(name, 16, NAME_SHORTHAND ": %s", info->fn_name); + name[15] = '\0'; + prctl(PR_SET_NAME, name); + free(name); + + int ret = info->fn(); + + free(info); + + return ret; +} + +int __impl_start_subsystem(char *fn_name, int (*fn)(void)) +{ + void *stack = mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_GROWSDOWN | MAP_STACK | MAP_PRIVATE, -1, 0); + if((long)stack < 0) + die("subsys mmap:"); + + struct subsystem_info *info = malloc(sizeof(struct subsystem_info)); + info->fn_name = fn_name; + info->fn = fn; + + int pid = clone((int (*)(void *))__subsystem_entry, stack, CLONE_FILES | CLONE_VM, info); + if(pid < 0) { + munmap(stack, STACK_SIZE); + die("subsys clone:"); + } + + return 0; +} diff --git a/init/util.c b/init/util.c new file mode 100644 index 0000000..1a08234 --- /dev/null +++ b/init/util.c @@ -0,0 +1,22 @@ +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +void die(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + if(fmt[0] && fmt[strlen(fmt)-1] == ':') { + fputc(' ', stderr); + perror(NULL); + } else { + fputc('\n', stderr); + } + + exit(1); +} |