git: 77fd18a8271e - stable/13 - kboot: add minmalist init functionality

From: Warner Losh <imp_at_FreeBSD.org>
Date: Tue, 24 Jan 2023 22:12:21 UTC
The branch stable/13 has been updated by imp:

URL: https://cgit.FreeBSD.org/src/commit/?id=77fd18a8271ea32db8acefeab6e3fbeb181bbfec

commit 77fd18a8271ea32db8acefeab6e3fbeb181bbfec
Author:     Warner Losh <imp@FreeBSD.org>
AuthorDate: 2022-09-01 17:06:43 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2023-01-24 21:49:33 +0000

    kboot: add minmalist init functionality
    
    It is desirable to run kboot as the first program in some LinuxBoot
    environments. This is the traditional "pid 1" or "init" program. When
    running as pid 1. rovide a minimal environment based on what sysvinit,
    u-root, initramfs-tools and other like projects do. We mount /dev, /sys,
    /proc, make symlinks from /dev/fd to /dev/proc, and create /tmp, /run,
    and /var. We also setup stdin/out/err to the console, set the tty
    characteristics of same and block the appropriate signals.
    
    This is indended as an environment that never does a fork/exec. If
    that's required, the process groups, session leaders and all things
    POSIX terminal handlers will need to be added.
    
    Unlike the general purpose linux projects in this area, no attempt is
    made to support very old kernels.
    
    When not pid 1, we skip all of the above.
    
    Sponsored by:           Netflix
    Differential Revision:  https://reviews.freebsd.org/D36368
    
    (cherry picked from commit 57f90cf81338ca9d1e403fdfeac16f21def72763)
---
 stand/kboot/Makefile |   1 +
 stand/kboot/init.c   | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++
 stand/kboot/kboot.h  |  12 +++++
 stand/kboot/main.c   |   7 ++-
 4 files changed, 147 insertions(+), 2 deletions(-)

diff --git a/stand/kboot/Makefile b/stand/kboot/Makefile
index 986e636a8c35..b8e71fd70dc7 100644
--- a/stand/kboot/Makefile
+++ b/stand/kboot/Makefile
@@ -19,6 +19,7 @@ INSTALLFLAGS=	-b
 
 # Architecture-specific loader code
 SRCS=		crt1.c conf.c vers.c main.c host_syscalls.c hostcons.c hostdisk.c kbootfdt.c gfx_fb_stub.c
+SRCS+=		init.c
 SRCS+=		termios.c
 
 CFLAGS.gfx_fb_stub.c += -I${SRCTOP}/contrib/pnglite -I${SRCTOP}/sys/teken
diff --git a/stand/kboot/init.c b/stand/kboot/init.c
new file mode 100644
index 000000000000..e707f65096d7
--- /dev/null
+++ b/stand/kboot/init.c
@@ -0,0 +1,129 @@
+/*-
+ * Copyright (c) 2022, Netflix, Inc.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+/*
+ * Mini-init(8) so we can run as init/pid 1 in a LinuxBoot environment.
+ */
+
+#include "stand.h"
+#include "host_syscall.h"
+#include "kboot.h"
+
+/*
+ * Create a 'standard' early boot environment. Cribbed from the things that
+ * sysvinit, u-root, and initramfs-tools do. This is a minimal environment
+ * for modern Linux systems, though the /tmp, /run and /var stuff can likely
+ * be done inside the initrd image itself (as can creating the mount points
+ * for /proc, /dev and /sys).
+ *
+ * Note: We ignore errors here. There's no stderr to report them to yet. These
+ * operations generally can't fail, but if they do, we may not have the ability
+ * to report them later.
+ */
+static void
+init_fs_env(void)
+{
+	/*
+	 * Create directories for mandatory filesystems and mount them.
+	 */
+	host_mkdir("/proc", 0555);
+	host_mount("proc", "/proc", "proc", MS_RELATIME, "");
+	host_mkdir("/sys", 0555);
+	host_mount("sysfs", "/sys", "sysfs", MS_RELATIME, "");
+	host_mkdir("/dev", 0755);
+	host_mount("devtmpfs", "/dev", "devtmpfs", MS_RELATIME,
+	    "mode=0755,nr_inodes=0");
+
+	/*
+	 * Create compat links: /dev/fd lives in /proc, and needs some help to
+	 * get setup.
+	 */
+	host_symlink("/proc/self/fd", "/dev/fd");
+	host_symlink("fd/0", "/dev/stdin");
+	host_symlink("fd/1", "/dev/stdout");
+	host_symlink("fd/2", "/dev/stderr");
+
+
+	/*
+	 * Unsure if we need this, but create a sane /tmp just in case that's useful.
+	 * and point /run over to it.
+	 */
+	host_mkdir("/tmp", 01777);
+	host_mount("tmpfs", "/tmp", "tmpfs", MS_RELATIME, "size=10%,mode=1777");
+	host_symlink("/tmp", "/run");
+
+	/*
+	 * Unsure the loader needs /var and /var/log, but they are easy to
+	 * create.
+	 */
+	host_mkdir("/var", 0555);
+	host_mkdir("/var/lock", 0555);
+	host_symlink("/tmp", "/var/tmp");
+}
+
+static void
+init_tty(void)
+{
+	int fd;
+
+	/*
+	 * sysvinit asks the linux kernel to convert the CTRL-ALT-DEL to a SIGINT,
+	 * but we skip that.
+	 */
+
+	/*
+	 * Setup /dev/console as stdin/out/err
+	 */
+	host_close(0);
+	host_close(1);
+	host_close(2);
+	fd = host_open("/dev/console", HOST_O_RDWR | HOST_O_NOCTTY, 0);
+	host_dup(fd);
+	host_dup(fd);
+#if 0
+	/*
+	 * I think we may need to put it in 'raw' mode, but maybe not. Linux
+	 * sysvinit sets it into 'sane' mode with several tweaks. Not enabled at
+	 * the moment since host console initialization seems sufficient.
+	 */
+	struct host_termios tty;
+
+	host_cfmakeraw(&tty);
+	host_tcsetattr(fd, HOST_TCANOW, &tty);
+	host_tcflush(fd, HOST_TCIOFLUSH)
+#endif
+}
+
+static void
+init_sig(void)
+{
+	/*
+	 * since we're running as init, we need to catch some signals
+	 */
+
+	/*
+	 * setup signals here
+	 *
+	 * sysvinit catches a lot of signals, but the boot loader needn't catch
+	 * so many since we don't do as much as it does. If we need to, put the
+	 * signal catching / ignoring code here. If we implement a 'shell'
+	 * function to spawn a sub-shell, we'll likely need to do a lot more.
+	 */
+}
+
+void
+do_init(void)
+{
+	/*
+	 * Only pid 1 is init
+	 */
+	if (host_getpid() != 1)
+		return;
+
+	init_fs_env();
+	init_tty();
+	init_sig();
+}
diff --git a/stand/kboot/kboot.h b/stand/kboot/kboot.h
new file mode 100644
index 000000000000..01de346234f3
--- /dev/null
+++ b/stand/kboot/kboot.h
@@ -0,0 +1,12 @@
+/*-
+ * Copyright (c) 2022, Netflix, Inc.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef KBOOT_H
+#define KBOOT_H
+
+void do_init(void);
+
+#endif /* KBOOT_H */
diff --git a/stand/kboot/main.c b/stand/kboot/main.c
index 5d40e2c3b582..be08528049e6 100644
--- a/stand/kboot/main.c
+++ b/stand/kboot/main.c
@@ -34,7 +34,7 @@ __FBSDID("$FreeBSD$");
 #include <machine/cpufunc.h>
 #include <bootstrap.h>
 #include "host_syscall.h"
-
+#include "kboot.h"
 
 struct arch_switch	archsw;
 extern void *_end;
@@ -261,8 +261,11 @@ main(int argc, const char **argv)
 	const size_t heapsize = 15*1024*1024;
 	const char *bootdev;
 
+	/* Give us a sane world if we're running as init */
+	do_init();
+
 	/*
-	 * Set the heap to one page after the end of the loader.
+	 * Setup the heap 15MB should be plenty
 	 */
 	heapbase = host_getmem(heapsize);
 	setheap(heapbase, heapbase + heapsize);