aboutsummaryrefslogtreecommitdiffstats
path: root/init
diff options
context:
space:
mode:
Diffstat (limited to 'init')
-rw-r--r--init/init.c60
-rw-r--r--init/log.c69
-rw-r--r--init/subsys.c55
-rw-r--r--init/util.c22
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);
+}