Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 3 Feb 2023 15:50:37 GMT
From:      Warner Losh <imp@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 33e5b27254e7 - main - kboot: Add parsing of /proc/iomem into seg.c
Message-ID:  <202302031550.313Fobuk022956@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by imp:

URL: https://cgit.FreeBSD.org/src/commit/?id=33e5b27254e78c45a3cb728243709c16100fac36

commit 33e5b27254e78c45a3cb728243709c16100fac36
Author:     Warner Losh <imp@FreeBSD.org>
AuthorDate: 2023-02-03 15:38:14 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2023-02-03 15:41:39 +0000

    kboot: Add parsing of /proc/iomem into seg.c
    
    We'll be using this code for most / all of the platforms since iomem is
    the only interface that can tell us of the reserved to the linux kernel
    areas that we cannot place the new kernel into, but that we are free to
    use once we hit trampoline. aarch64 will use this shortly, and similar
    code in amd64 will be refactored when I make that platform work.
    
    Sponsored by:           Netflix
    Reviewed by:            tsoome
    Differential Revision:  https://reviews.freebsd.org/D38309
---
 stand/kboot/kboot.h |   2 +
 stand/kboot/seg.c   | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 151 insertions(+)

diff --git a/stand/kboot/kboot.h b/stand/kboot/kboot.h
index 2d89933b51aa..dcf1487ce404 100644
--- a/stand/kboot/kboot.h
+++ b/stand/kboot/kboot.h
@@ -36,12 +36,14 @@ void hostdisk_zfs_probe(void);
 bool hostdisk_zfs_find_default(void);
 
 /* seg.c */
+#define SYSTEM_RAM 1
 void init_avail(void);
 void need_avail(int n);
 void add_avail(uint64_t start, uint64_t end, uint64_t type);
 void remove_avail(uint64_t start, uint64_t end, uint64_t type);
 uint64_t first_avail(uint64_t align, uint64_t min_size, uint64_t type);
 void print_avail(void);
+bool populate_avail_from_iomem(void);
 
 /* util.c */
 bool file2str(const char *fn, char *buffer, size_t buflen);
diff --git a/stand/kboot/seg.c b/stand/kboot/seg.c
index 41ded9b4083c..8cf3b833c9d1 100644
--- a/stand/kboot/seg.c
+++ b/stand/kboot/seg.c
@@ -195,3 +195,152 @@ first_avail(uint64_t align, uint64_t min_size, uint64_t memtype)
 
 	return (0);
 }
+
+enum types {
+	system_ram = SYSTEM_RAM,
+	firmware_reserved,
+	linux_code,
+	linux_data,
+	linux_bss,
+	unknown,
+};
+
+static struct kv
+{
+	uint64_t	type;
+	char *		name;
+	int		flags;
+#define KV_KEEPER 1
+} str2type_kv[] = {
+	{ linux_code,		"Kernel code", KV_KEEPER },
+	{ linux_data,		"Kernel data", KV_KEEPER },
+	{ linux_bss,		"Kernel bss", KV_KEEPER },
+	{ firmware_reserved,	"reserved" },
+	{ 0, NULL },
+};
+
+static const char *
+parse_line(const char *line, uint64_t *startp, uint64_t *endp)
+{
+	const char *walker;
+	char *next;
+	uint64_t start, end;
+
+	/*
+	 * Each line is a range followed by a descriptoin of the form:
+	 * <hex-number><dash><hex-number><space><colon><space><string>
+	 * Bail if we have any parsing errors.
+	 */
+	walker = line;
+	start = strtoull(walker, &next, 16);
+	if (start == ULLONG_MAX || walker == next)
+		return (NULL);
+	walker = next;
+	if (*walker != '-')
+		return (NULL);
+	walker++;
+	end = strtoull(walker, &next, 16);
+	if (end == ULLONG_MAX || walker == next)
+		return (NULL);
+	walker = next;
+	/* Now eat the ' : ' in front of the string we want to return */
+	if (strncmp(walker, " : ", 3) != 0)
+		return (NULL);
+	*startp = start;
+	*endp = end;
+	return (walker + 3);
+}
+
+static struct kv *
+kvlookup(const char *str, struct kv *kvs, size_t nkv)
+{
+	for (int i = 0; i < nkv; i++)
+		if (strcmp(kvs[i].name, str) == 0)
+			return (&kvs[i]);
+
+	return (NULL);
+}
+
+/* Trim trailing whitespace */
+static void
+chop(char *line)
+{
+	char *ep = line + strlen(line) - 1;
+
+	while (ep >= line && isspace(*ep))
+		*ep-- = '\0';
+}
+
+#define SYSTEM_RAM_STR "System RAM"
+#define RESERVED "reserved"
+
+bool
+populate_avail_from_iomem(void)
+{
+	int fd;
+	char buf[128];
+	const char *str;
+	uint64_t start, end;
+	struct kv *kv;
+
+	fd = open("host:/proc/iomem", O_RDONLY);
+	if (fd == -1) {
+		printf("Can't get memory map\n");
+		return false;
+	}
+
+	if (fgetstr(buf, sizeof(buf), fd) < 0)
+		goto out;	/* Nothing to do ???? */
+	init_avail();
+	chop(buf);
+	while (true) {
+		/*
+		 * Look for top level items we understand.  Skip anything that's
+		 * a continuation, since we don't care here. If we care, we'll
+		 * consume them all when we recognize that top level item.
+		 */
+		if (buf[0] == ' ')	/* Continuation lines? Ignore */
+			goto next_line;
+		str = parse_line(buf, &start, &end);
+		if (str == NULL)	/* Malformed -> ignore */
+			goto next_line;
+		/*
+		 * All we care about is System RAM
+		 */
+		if (strncmp(str, SYSTEM_RAM_STR, sizeof(SYSTEM_RAM_STR) - 1) == 0)
+			add_avail(start, end, system_ram);
+		else if (strncmp(str, RESERVED, sizeof(RESERVED) - 1) == 0)
+			add_avail(start, end, firmware_reserved);
+		else
+			goto next_line;	/* Ignore hardware */
+		while (fgetstr(buf, sizeof(buf), fd) >= 0 && buf[0] == ' ') {
+			chop(buf);
+			str = parse_line(buf, &start, &end);
+			if (str == NULL)
+				break;
+			kv = kvlookup(str, str2type_kv, nitems(str2type_kv));
+			if (kv == NULL) /* failsafe for new types: igonre */
+				remove_avail(start, end, unknown);
+			else if ((kv->flags & KV_KEEPER) == 0)
+				remove_avail(start, end, kv->type);
+			/* Else no need to adjust since it's a keeper */
+		}
+
+		/*
+		 * if buf[0] == ' ' then we know that the fgetstr failed and we
+		 * should break. Otherwise fgetstr succeeded and we have a
+		 * buffer we need to examine for being a top level item.
+		 */
+		if (buf[0] == ' ')
+			break;
+		chop(buf);
+		continue; /* buf has next top level line to parse */
+next_line:
+		if (fgetstr(buf, sizeof(buf), fd) < 0)
+			break;
+	}
+
+out:
+	close(fd);
+	return true;
+}



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