git: 94503b830b6d - stable/13 - kboot: Rework _start

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

URL: https://cgit.FreeBSD.org/src/commit/?id=94503b830b6d6b587fad63f2943fec40895b3320

commit 94503b830b6d6b587fad63f2943fec40895b3320
Author:     Warner Losh <imp@FreeBSD.org>
AuthorDate: 2022-07-14 03:41:17 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2023-01-24 21:49:23 +0000

    kboot: Rework _start
    
    Split _start into _start and _start_c (inspired by musl and the powerpc
    impl is copied from there). This allows us to actually get the command
    line arguments on all the platforms. We have a very simplified startup
    that supports only static linking.
    
    Sponsored by:           Netflix
    
    (cherry picked from commit f5ed1b0f84bf06839f0947981ebdb3646c3c433a)
---
 stand/kboot/Makefile                    |  3 +-
 stand/kboot/arch/amd64/start_arch.h     | 34 +++++++++++++++
 stand/kboot/arch/powerpc64/start_arch.h | 30 +++++++++++++
 stand/kboot/crt1.c                      | 74 +++++++++++++++++++++++++++++++++
 stand/kboot/main.c                      |  6 ---
 5 files changed, 140 insertions(+), 7 deletions(-)

diff --git a/stand/kboot/Makefile b/stand/kboot/Makefile
index 24ab77af66db..ce0868264acf 100644
--- a/stand/kboot/Makefile
+++ b/stand/kboot/Makefile
@@ -1,5 +1,6 @@
 # $FreeBSD$
 
+LOADER_DISK_SUPPORT?=	yes
 LOADER_CD9660_SUPPORT?=	yes
 LOADER_MSDOS_SUPPORT?=	no
 LOADER_EXT2FS_SUPPORT?=	yes
@@ -17,7 +18,7 @@ NEWVERSWHAT=	"kboot loader" ${MACHINE_ARCH}
 INSTALLFLAGS=	-b
 
 # Architecture-specific loader code
-SRCS=		vers.c main.c host_syscalls.c hostcons.c hostdisk.c kbootfdt.c gfx_fb_stub.c
+SRCS=		crt1.c vers.c main.c host_syscalls.c hostcons.c hostdisk.c kbootfdt.c gfx_fb_stub.c
 
 CFLAGS.gfx_fb_stub.c += -I${SRCTOP}/contrib/pnglite -I${SRCTOP}/sys/teken
 
diff --git a/stand/kboot/arch/amd64/start_arch.h b/stand/kboot/arch/amd64/start_arch.h
new file mode 100644
index 000000000000..57c514daf019
--- /dev/null
+++ b/stand/kboot/arch/amd64/start_arch.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2022, Netflix, Inc.
+ *
+ * SPDX-Licnse-Identifier: BSD-2-Clause
+ */
+
+/*
+ * Provides a _start routine that calls a _start_c routine that takes a pointer
+ * to the stack as documented in crt1.c. We skip the pointer to _DYNAMIC since
+ * we don't support dynamic libraries, at all. And while _start_c is our own
+ * thing, we comport to the calling conventions that glibc and musl have and
+ * make sure the second argument (%esi) is 0 for _DYNAMIC placeholder.  We
+ * likely could call main directly with only a few more lines of code, but this
+ * is simple enough and concentrates all the expressable in C stuff there.  We
+ * also generate eh_frames should we need to debug things (it doesn't change the
+ * genreated code, but leaves enough breadcrumbs to keep gdb happy).
+ */
+
+__asm__(
+".text\n"			/* ENTRY(_start) */
+".p2align 4,0x90\n"
+".global _start\n"
+".type _start, @function\n"
+"_start:\n"
+".cfi_startproc\n"
+"	xor	%rbp, %rbp\n"		/* Clear out the stack frame pointer */
+"	mov	%rsp, %rdi\n"		/* Pass pointer to current stack with argc, argv and envp on it */
+"	xor	%rsi, %rsi\n"		/* No dynamic pointer for us, to keep it simple */
+"	andq	$-16, %rsp\n"		/* Align stack to 16-byte boundary */
+"	call	_start_c\n"		/* Our MI code takes it from here and won't return */
+/* NORETURN */
+".size _start, . - _start\n"	/* END(_start) */
+".cfi_endproc"
+);
diff --git a/stand/kboot/arch/powerpc64/start_arch.h b/stand/kboot/arch/powerpc64/start_arch.h
new file mode 100644
index 000000000000..cd2fad433cde
--- /dev/null
+++ b/stand/kboot/arch/powerpc64/start_arch.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2022 Netflix, Inc
+ *
+ * SPDX-Licnse-Identifier: BSD-2-Clause
+ */
+
+/*
+ * Due to the PowerPC ABI, We can call main directly from here, so do so.
+ *
+ * Note: there may be some static initializers that aren't called, but we don't
+ * worry about that elsewhere. This is a stripped down environment.
+ *
+ * I think we could also do something like
+ *
+ * mflr		r0
+ * stw		r0,4(r1)
+ * stwu		r1,-16(r1)
+ * b		_start_c
+ *
+ * But my powerpc assembler fu is quite lacking...
+ */
+
+#define __unused __attribute__((__unused__))
+
+void
+_start(int argc, const char **argv, char **env, void *obj __unused,
+    void (*cleanup)(void) __unused)
+{
+	main(argc, argv, env);
+}
diff --git a/stand/kboot/crt1.c b/stand/kboot/crt1.c
new file mode 100644
index 000000000000..c4525ad6c35e
--- /dev/null
+++ b/stand/kboot/crt1.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2022, Netflix, Inc.
+ *
+ * SPDX-Licnse-Identifier: BSD-2-Clause
+ */
+
+/*
+ * MI part of the C startup code. We take a long * pointer (we assume long is
+ * the same size as a pointer, as the Linux world is wont to do). We get a
+ * pointer to the stack with the main args on it. We don't bother decoding the
+ * aux vector, but may need to do so in the future.
+ *
+ * The long *p points to:
+ *
+ * +--------------------+
+ * | argc               | Small address
+ * +--------------------+
+ * | argv[0]            | argv
+ * +--------------------+
+ * | argv[1]            |
+ * +--------------------+
+ *  ...
+ * +--------------------+
+ * | NULL               | &argv[argc]
+ * +--------------------+
+ * | envp[0]            | envp
+ * +--------------------+
+ * | envp[1]            |
+ * +--------------------+
+ *  ...
+ * +--------------------+
+ * | NULL               |
+ * +--------------------+
+ * | aux type           | AT_xxxx
+ * +--------------------+
+ * | aux value          |
+ * +--------------------+
+ * | aux type           | AT_xxxx
+ * +--------------------+
+ * | aux value          |
+ * +--------------------+
+ * | aux type           | AT_xxxx
+ * +--------------------+
+ * | aux value          |
+ * +--------------------+
+ *...
+ * +--------------------+
+ * | NULL               |
+ * +--------------------+
+ *
+ * The AUX vector contains additional information for the process to know from
+ * the kernel (not parsed currently). AT_xxxx constants are small (< 50).
+ */
+
+extern void _start_c(long *);
+extern int main(int, const char **, char **);
+
+#include "start_arch.h"
+
+void
+_start_c(long *p)
+{
+	int argc;
+	const char **argv;
+	char **envp;
+
+	argc = p[0];
+	argv = (const char **)(p + 1);
+	envp = (char **)argv + argc + 1;
+
+	/* Note: we don't ensure that fd 0, 1, and 2 are sane at this level */
+	/* Also note: we expect main to exit, not return off the end */
+	main(argc, argv, envp);
+}
diff --git a/stand/kboot/main.c b/stand/kboot/main.c
index 9b99c859070b..90b31a611476 100644
--- a/stand/kboot/main.c
+++ b/stand/kboot/main.c
@@ -479,12 +479,6 @@ kboot_kseg_get(int *nseg, void **ptr)
 	*ptr = &loaded_segments[0];
 }
 
-void
-_start(int argc, const char **argv, char **env)
-{
-	main(argc, argv);
-}
-
 /*
  * Since proper fdt command handling function is defined in fdt_loader_cmd.c,
  * and declaring it as extern is in contradiction with COMMAND_SET() macro