Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 8 Oct 2020 18:02:06 +0000 (UTC)
From:      Mitchell Horne <mhorne@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r366542 - in head/sys: amd64/amd64 arm/arm arm64/arm64 kern riscv/riscv sys
Message-ID:  <202010081802.098I26Rq052294@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mhorne
Date: Thu Oct  8 18:02:05 2020
New Revision: 366542
URL: https://svnweb.freebsd.org/changeset/base/366542

Log:
  Add a routine to dump boot metadata
  
  The boot metadata (also referred to as modinfo, or preload metadata)
  provides information about the size and location of the kernel,
  pre-loaded modules, and other metadata (e.g. the EFI framebuffer) to be
  consumed during by the kernel during early boot. It is encoded as a
  series of type-length-value entries and is usually constructed by
  loader(8) and passed to the kernel. It is also faked on some
  architectures when booted by other means.
  
  Although much of the module information is available via kldstat(8),
  there is no easy way to debug the metadata in its entirety. Add some
  routines to parse this data and allow it to be printed to the console
  during early boot or output via a sysctl.
  
  Since the output can be lengthly, printing to the console is gated
  behind the debug.dump_modinfo_at_boot kenv variable as well as the
  BOOTVERBOSE flag. The sysctl to print the metadata is named
  debug.dump_modinfo.
  
  Reviewed by:	tsoome
  Sponsored by:	NetApp, Inc.
  Sponsored by:	Klara, Inc.
  Differential Revision:	https://reviews.freebsd.org/D26687

Modified:
  head/sys/amd64/amd64/machdep.c
  head/sys/arm/arm/machdep.c
  head/sys/arm64/arm64/machdep.c
  head/sys/kern/subr_module.c
  head/sys/riscv/riscv/machdep.c
  head/sys/sys/linker.h

Modified: head/sys/amd64/amd64/machdep.c
==============================================================================
--- head/sys/amd64/amd64/machdep.c	Thu Oct  8 17:30:05 2020	(r366541)
+++ head/sys/amd64/amd64/machdep.c	Thu Oct  8 18:02:05 2020	(r366542)
@@ -1853,6 +1853,15 @@ hammer_time(u_int64_t modulep, u_int64_t physfree)
 	if (late_console)
 		cninit();
 
+	/*
+	 * Dump the boot metadata. We have to wait for cninit() since console
+	 * output is required. If it's grossly incorrect the kernel will never
+	 * make it this far.
+	 */
+	if ((boothowto & RB_VERBOSE) &&
+	    getenv_is_true("debug.dump_modinfo_at_boot"))
+		preload_dump();
+
 #ifdef DEV_ISA
 #ifdef DEV_ATPIC
 	elcr_probe();

Modified: head/sys/arm/arm/machdep.c
==============================================================================
--- head/sys/arm/arm/machdep.c	Thu Oct  8 17:30:05 2020	(r366541)
+++ head/sys/arm/arm/machdep.c	Thu Oct  8 18:02:05 2020	(r366542)
@@ -1027,6 +1027,15 @@ initarm(struct arm_boot_params *abp)
 	debugf(" dtbp = 0x%08x\n", (uint32_t)dtbp);
 	arm_print_kenv();
 
+	/*
+	 * Dump the boot metadata. We have to wait for cninit() since console
+	 * output is required. If it's grossly incorrect the kernel will never
+	 * make it this far.
+	 */
+	if ((boothowto & RB_VERBOSE) &&
+	    getenv_is_true("debug.dump_modinfo_at_boot"))
+		preload_dump();
+
 	env = kern_getenv("kernelname");
 	if (env != NULL) {
 		strlcpy(kernelname, env, sizeof(kernelname));

Modified: head/sys/arm64/arm64/machdep.c
==============================================================================
--- head/sys/arm64/arm64/machdep.c	Thu Oct  8 17:30:05 2020	(r366541)
+++ head/sys/arm64/arm64/machdep.c	Thu Oct  8 18:02:05 2020	(r366542)
@@ -1242,6 +1242,15 @@ initarm(struct arm64_bootparams *abp)
 		panic("Invalid bus configuration: %s",
 		    kern_getenv("kern.cfg.order"));
 
+	/*
+	 * Dump the boot metadata. We have to wait for cninit() since console
+	 * output is required. If it's grossly incorrect the kernel will never
+	 * make it this far.
+	 */
+	if ((boothowto & RB_VERBOSE) &&
+	    getenv_is_true("debug.dump_modinfo_at_boot"))
+		preload_dump();
+
 	init_proc0(abp->kern_stack);
 	msgbufinit(msgbufp, msgbufsize);
 	mutex_init();

Modified: head/sys/kern/subr_module.c
==============================================================================
--- head/sys/kern/subr_module.c	Thu Oct  8 17:30:05 2020	(r366541)
+++ head/sys/kern/subr_module.c	Thu Oct  8 18:02:05 2020	(r366542)
@@ -3,6 +3,8 @@
  *
  * Copyright (c) 1998 Michael Smith
  * All rights reserved.
+ * Copyright (c) 2020 NetApp Inc.
+ * Copyright (c) 2020 Klara Inc.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -32,7 +34,11 @@ __FBSDID("$FreeBSD$");
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/linker.h>
+#include <sys/sbuf.h>
+#include <sys/sysctl.h>
 
+#include <machine/metadata.h>
+
 #include <vm/vm.h>
 #include <vm/vm_extern.h>
 
@@ -304,3 +310,249 @@ preload_bootstrap_relocate(vm_offset_t offset)
 	}
     }
 }
+
+/*
+ * Parse the modinfo type and append to the provided sbuf.
+ */
+static void
+preload_modinfo_type(struct sbuf *sbp, int type)
+{
+
+	if ((type & MODINFO_METADATA) == 0) {
+		switch (type) {
+		case MODINFO_END:
+			sbuf_cat(sbp, "MODINFO_END");
+			break;
+		case MODINFO_NAME:
+			sbuf_cat(sbp, "MODINFO_NAME");
+			break;
+		case MODINFO_TYPE:
+			sbuf_cat(sbp, "MODINFO_TYPE");
+			break;
+		case MODINFO_ADDR:
+			sbuf_cat(sbp, "MODINFO_ADDR");
+			break;
+		case MODINFO_SIZE:
+			sbuf_cat(sbp, "MODINFO_SIZE");
+			break;
+		case MODINFO_EMPTY:
+			sbuf_cat(sbp, "MODINFO_EMPTY");
+			break;
+		case MODINFO_ARGS:
+			sbuf_cat(sbp, "MODINFO_ARGS");
+			break;
+		default:
+			sbuf_cat(sbp, "unrecognized modinfo attribute");
+		}
+
+		return;
+	}
+
+	sbuf_cat(sbp, "MODINFO_METADATA | ");
+	switch (type & ~MODINFO_METADATA) {
+	case MODINFOMD_ELFHDR:
+		sbuf_cat(sbp, "MODINFOMD_ELFHDR");
+		break;
+	case MODINFOMD_SSYM:
+		sbuf_cat(sbp, "MODINFOMD_SSYM");
+		break;
+	case MODINFOMD_ESYM:
+		sbuf_cat(sbp, "MODINFOMD_ESYM");
+		break;
+	case MODINFOMD_DYNAMIC:
+		sbuf_cat(sbp, "MODINFOMD_DYNAMIC");
+		break;
+	case MODINFOMD_ENVP:
+		sbuf_cat(sbp, "MODINFOMD_ENVP");
+		break;
+	case MODINFOMD_HOWTO:
+		sbuf_cat(sbp, "MODINFOMD_HOWTO");
+		break;
+	case MODINFOMD_KERNEND:
+		sbuf_cat(sbp, "MODINFOMD_KERNEND");
+		break;
+	case MODINFOMD_SHDR:
+		sbuf_cat(sbp, "MODINFOMD_SHDR");
+		break;
+	case MODINFOMD_CTORS_ADDR:
+		sbuf_cat(sbp, "MODINFOMD_CTORS_ADDR");
+		break;
+	case MODINFOMD_CTORS_SIZE:
+		sbuf_cat(sbp, "MODINFOMD_CTORS_SIZE");
+		break;
+	case MODINFOMD_FW_HANDLE:
+		sbuf_cat(sbp, "MODINFOMD_FW_HANDLE");
+		break;
+	case MODINFOMD_KEYBUF:
+		sbuf_cat(sbp, "MODINFOMD_KEYBUF");
+		break;
+#ifdef MODINFOMD_SMAP
+	case MODINFOMD_SMAP:
+		sbuf_cat(sbp, "MODINFOMD_SMAP");
+		break;
+#endif
+#ifdef MODINFOMD_SMAP_XATTR
+	case MODINFOMD_SMAP_XATTR:
+		sbuf_cat(sbp, "MODINFOMD_SMAP_XATTR");
+		break;
+#endif
+#ifdef MODINFOMD_DTBP
+	case MODINFOMD_DTBP:
+		sbuf_cat(sbp, "MODINFOMD_DTBP");
+		break;
+#endif
+#ifdef MODINFOMD_EFI_MAP
+	case MODINFOMD_EFI_MAP:
+		sbuf_cat(sbp, "MODINFOMD_EFI_MAP");
+		break;
+#endif
+#ifdef MODINFOMD_EFI_FB
+	case MODINFOMD_EFI_FB:
+		sbuf_cat(sbp, "MODINFOMD_EFI_FB");
+		break;
+#endif
+#ifdef MODINFOMD_MODULEP
+	case MODINFOMD_MODULEP:
+		sbuf_cat(sbp, "MODINFOMD_MODULEP");
+		break;
+#endif
+	default:
+		sbuf_cat(sbp, "unrecognized metadata type");
+	}
+}
+
+/*
+ * Print the modinfo value, depending on type.
+ */
+static void
+preload_modinfo_value(struct sbuf *sbp, uint32_t *bptr, int type, int len)
+{
+#ifdef __LP64__
+#define sbuf_print_vmoffset(sb, o)	sbuf_printf(sb, "0x%016lx", o);
+#else
+#define sbuf_print_vmoffset(sb, o)	sbuf_printf(sb, "0x%08x", o);
+#endif
+
+	switch (type) {
+	case MODINFO_NAME:
+	case MODINFO_TYPE:
+	case MODINFO_ARGS:
+		sbuf_printf(sbp, "%s", (char *)bptr);
+		break;
+	case MODINFO_SIZE:
+	case MODINFO_METADATA | MODINFOMD_CTORS_SIZE:
+		sbuf_printf(sbp, "%lu", *(u_long *)bptr);
+		break;
+	case MODINFO_ADDR:
+	case MODINFO_METADATA | MODINFOMD_SSYM:
+	case MODINFO_METADATA | MODINFOMD_ESYM:
+	case MODINFO_METADATA | MODINFOMD_DYNAMIC:
+	case MODINFO_METADATA | MODINFOMD_KERNEND:
+	case MODINFO_METADATA | MODINFOMD_ENVP:
+	case MODINFO_METADATA | MODINFOMD_CTORS_ADDR:
+#ifdef MODINFOMD_SMAP
+	case MODINFO_METADATA | MODINFOMD_SMAP:
+#endif
+#ifdef MODINFOMD_SMAP_XATTR
+	case MODINFO_METADATA | MODINFOMD_SMAP_XATTR:
+#endif
+#ifdef MODINFOMD_DTBP
+	case MODINFO_METADATA | MODINFOMD_DTBP:
+#endif
+#ifdef MODINFOMD_EFI_FB
+	case MODINFO_METADATA | MODINFOMD_EFI_FB:
+#endif
+		sbuf_print_vmoffset(sbp, *(vm_offset_t *)bptr);
+		break;
+	case MODINFO_METADATA | MODINFOMD_HOWTO:
+		sbuf_printf(sbp, "0x%08x", *bptr);
+		break;
+	case MODINFO_METADATA | MODINFOMD_SHDR:
+	case MODINFO_METADATA | MODINFOMD_ELFHDR:
+	case MODINFO_METADATA | MODINFOMD_FW_HANDLE:
+	case MODINFO_METADATA | MODINFOMD_KEYBUF:
+#ifdef MODINFOMD_EFI_MAP
+	case MODINFO_METADATA | MODINFOMD_EFI_MAP:
+#endif
+		/* Don't print data buffers. */
+		sbuf_cat(sbp, "buffer contents omitted");
+		break;
+	default:
+		break;
+	}
+#undef sbuf_print_vmoffset
+}
+
+static void
+preload_dump_internal(struct sbuf *sbp)
+{
+	uint32_t *bptr, type, len;
+
+	KASSERT(preload_metadata != NULL,
+	    ("%s called without setting up preload_metadata", __func__));
+
+	/*
+	 * Iterate through the TLV-encoded sections.
+	 */
+	bptr = (uint32_t *)preload_metadata;
+	sbuf_putc(sbp, '\n');
+	while (bptr[0] != MODINFO_END || bptr[0] != MODINFO_END) {
+		sbuf_printf(sbp, " %p:\n", bptr);
+		type = *bptr++;
+		len = *bptr++;
+
+		sbuf_printf(sbp, "\ttype:\t(%#04x) ", type);
+		preload_modinfo_type(sbp, type);
+		sbuf_putc(sbp, '\n');
+		sbuf_printf(sbp, "\tlen:\t%u\n", len);
+		sbuf_cat(sbp, "\tvalue:\t");
+		preload_modinfo_value(sbp, bptr, type, len);
+		sbuf_putc(sbp, '\n');
+
+		bptr += roundup(len, sizeof(u_long)) / sizeof(uint32_t);
+	}
+}
+
+/*
+ * Print the preloaded data to the console. Called from the machine-dependent
+ * initialization routines, e.g. hammer_time().
+ */
+void
+preload_dump(void)
+{
+	char buf[512];
+	struct sbuf sb;
+
+	/*
+	 * This function is expected to be called before malloc is available,
+	 * so use a static buffer and struct sbuf.
+	 */
+	sbuf_new(&sb, buf, sizeof(buf), SBUF_FIXEDLEN);
+	sbuf_set_drain(&sb, sbuf_printf_drain, NULL);
+	preload_dump_internal(&sb);
+
+	sbuf_finish(&sb);
+	sbuf_delete(&sb);
+}
+
+static int
+sysctl_preload_dump(SYSCTL_HANDLER_ARGS)
+{
+	struct sbuf sb;
+	int error;
+
+	if (preload_metadata == NULL)
+		return (EINVAL);
+
+	sbuf_new_for_sysctl(&sb, NULL, 512, req);
+	preload_dump_internal(&sb);
+
+	error = sbuf_finish(&sb);
+	sbuf_delete(&sb);
+
+	return (error);
+}
+SYSCTL_PROC(_debug, OID_AUTO, dump_modinfo,
+    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
+    NULL, 0, sysctl_preload_dump, "A",
+    "pretty-print the bootloader metadata");

Modified: head/sys/riscv/riscv/machdep.c
==============================================================================
--- head/sys/riscv/riscv/machdep.c	Thu Oct  8 17:30:05 2020	(r366541)
+++ head/sys/riscv/riscv/machdep.c	Thu Oct  8 18:02:05 2020	(r366542)
@@ -949,6 +949,15 @@ initriscv(struct riscv_bootparams *rvbp)
 
 	cninit();
 
+	/*
+	 * Dump the boot metadata. We have to wait for cninit() since console
+	 * output is required. If it's grossly incorrect the kernel will never
+	 * make it this far.
+	 */
+	if ((boothowto & RB_VERBOSE) &&
+	    getenv_is_true("debug.dump_modinfo_at_boot"))
+		preload_dump();
+
 	init_proc0(rvbp->kern_stack);
 
 	msgbufinit(msgbufp, msgbufsize);

Modified: head/sys/sys/linker.h
==============================================================================
--- head/sys/sys/linker.h	Thu Oct  8 17:30:05 2020	(r366541)
+++ head/sys/sys/linker.h	Thu Oct  8 18:02:05 2020	(r366542)
@@ -257,6 +257,7 @@ extern caddr_t		preload_search_next_name(caddr_t _base
 extern caddr_t		preload_search_info(caddr_t _mod, int _inf);
 extern void		preload_delete_name(const char *_name);
 extern void		preload_bootstrap_relocate(vm_offset_t _offset);
+extern void		preload_dump(void);
 
 #ifdef KLD_DEBUG
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202010081802.098I26Rq052294>