[Pdbg] [PATCH] pdbg: implement 'log' command

Joel Stanley joel at jms.id.au
Fri May 18 17:27:28 AEST 2018


This command fetches the skiboot in-memory log from host RAM and
display it on stdout.

Signed-off-by: Joel Stanley <joel at jms.id.au>
---
Based on top of Balbir's logging patches.

Still a bit ghetto. Works, and is somewhat usable as long as you've got
the kernel backend speedups that benh has been working on.

Mostly reuses a kernel function for reading and parsing the memcons,
which I wrote, so we're fine to reappraise that here.
---
 Makefile.am |   2 +-
 src/log.c   | 220 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/main.c  |   3 +
 3 files changed, 224 insertions(+), 1 deletion(-)
 create mode 100644 src/log.c

diff --git a/Makefile.am b/Makefile.am
index 053acd09ceb4..4b5aa5678675 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -12,7 +12,7 @@ AM_CFLAGS = -I$(top_srcdir)/ccan/array_size -Wall -Werror -O2
 
 pdbg_SOURCES = \
 	src/main.c src/cfam.c src/scom.c src/reg.c src/mem.c src/thread.c \
-	src/ring.c src/htm.c src/progress.c src/options_ at ARCH@.c
+	src/ring.c src/htm.c src/progress.c src/log.c src/options_ at ARCH@.c
 
 pdbg_LDADD = fake.dtb.o p8-fsi.dtb.o p8-i2c.dtb.o p9w-fsi.dtb.o	p8-host.dtb.o \
 	p9z-fsi.dtb.o p9r-fsi.dtb.o p9-kernel.dtb.o libpdbg.la libfdt.la \
diff --git a/src/log.c b/src/log.c
new file mode 100644
index 000000000000..337ef6a323fe
--- /dev/null
+++ b/src/log.c
@@ -0,0 +1,220 @@
+/* Copyright 2018 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * 	http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <operations.h>
+#include <target.h>
+#include <debug.h>
+#include "progress.h"
+
+/*
+ * TODO
+ * - Clean up and verify the error paths
+ * - Allow a number of bytes to be specified
+ * - Allow a number of lines to be specified (harder)
+ * - Show the log starting from the end (requires one of the above)
+ * - Do log debug level filtering
+ * - Register the kernel log with skiboot so we can fetch it too
+ * - Similar for SBE, OCC, hostboot trace buffers
+ */
+
+#include "main.h"
+
+#define INMEM_CON_LEN		0x100000
+#define MEMCONS_DESC		0x300eb000
+
+/* OPAL in-memory console. Defined in OPAL source at core/console.c */
+struct memcons {
+        uint64_t magic;
+#define MEMCONS_MAGIC		0x6630696567726173L
+        uint64_t obuf_phys;
+        uint64_t ibuf_phys;
+        uint32_t obuf_size;
+        uint32_t ibuf_size;
+        uint32_t out_pos;
+#define MEMCONS_OUT_POS_WRAP	0x80000000u
+#define MEMCONS_OUT_POS_MASK	0x00ffffffu
+        uint32_t in_prod;
+        uint32_t in_cons;
+} __packed;
+
+/* OPAL debug descriptor (minus the traces) */
+struct debug_descriptor {
+	uint8_t		eye_catcher[8]; /* "OPALdbug" */
+#define DEBUG_DESC_VERSION      1
+	uint32_t	version;
+	uint8_t		console_log_levels;     /* high 4 bits in memory,
+						 * low 4 bits driver (e.g. uart). */
+	uint8_t		state_flags; /* various state flags - OPAL_BOOT_COMPLETE etc */ 
+	uint16_t	reserved2;
+	uint32_t	reserved[2];
+
+	/* Memory console */
+	uint64_t	memcons_phys;
+	uint32_t	memcons_tce;
+	uint32_t	memcons_obuf_tce;
+	uint32_t	memcons_ibuf_tce;
+} __packed;
+
+ssize_t adu_read_from_buffer(struct pdbg_target *target, void *to, size_t count,
+			     loff_t *ppos, uint64_t from, size_t available)
+{
+	loff_t pos = *ppos;
+	int rc;
+
+	if (pos < 0)
+		return -EINVAL;
+	if (pos >= available)
+		return 0;
+	if (count > available - pos)
+		count = available - pos;
+
+	pdbg_set_progress_tick(progress_tick);
+	progress_init();
+	rc = adu_getmem(target, from + pos, to, count);
+	if (rc < 0) {
+		PR_ERROR("unable to read memory");
+		return rc;
+	}
+	progress_end();
+
+	*ppos = pos + count;
+
+	return count;
+}
+
+ssize_t msglog_copy(struct pdbg_target *target, uint64_t memcons_addr,
+		    char *to, loff_t pos, size_t count)
+{
+	struct memcons mc;
+	uint64_t conbuf;
+	ssize_t ret;
+	size_t first_read = 0;
+	uint32_t out_pos, avail;
+
+	ret = adu_getmem(target, memcons_addr, (uint8_t *)&mc, sizeof(mc));
+	if (ret < 0) {
+		PR_ERROR("unable to read memory\n");
+		return -1;
+	}
+
+	if (be64toh(mc.magic) != MEMCONS_MAGIC) {
+                PR_ERROR("memory console version is invalid: %016"PRIx64"\n", be64toh(mc.magic));
+                return -1;
+        }
+
+	out_pos = be32toh(mc.out_pos);
+	conbuf = be64toh(mc.obuf_phys);
+
+	/* When the buffer has wrapped, read from the out_pos marker to the end
+	 * of the buffer, and then read the remaining data as in the un-wrapped
+	 * case. */
+	if (out_pos & MEMCONS_OUT_POS_WRAP) {
+
+		out_pos &= MEMCONS_OUT_POS_MASK;
+		avail = be64toh(mc.obuf_size) - out_pos;
+
+		ret = adu_read_from_buffer(target, to, count, &pos,
+				conbuf + out_pos, avail);
+		if (ret < 0)
+			goto out;
+
+		first_read = ret;
+		to += first_read;
+		count -= first_read;
+		pos -= avail;
+
+		if (count <= 0)
+			goto out;
+	}
+
+	/* Sanity check. The firmware should not do this to us. */
+	if (out_pos > be64toh(mc.obuf_size)) {
+		PR_ERROR("memory console corruption. Aborting read.\n");
+		return -EINVAL;
+	}
+
+	ret = adu_read_from_buffer(target, to, count, &pos, conbuf, out_pos);
+	if (ret < 0)
+		goto out;
+
+	progress_end();
+
+	ret += first_read;
+out:
+	return ret;
+}
+
+
+int display_log(struct pdbg_target *target, uint64_t memcons, int skip_bytes)
+{
+	char *buf = calloc(INMEM_CON_LEN, 1);
+	int ret;
+
+	ret = msglog_copy(target, memcons, buf, skip_bytes, INMEM_CON_LEN); 
+	if (ret < 0)
+		return ret;
+
+	printf("%s\n", buf);
+	free(buf);
+
+	return 0;
+}
+
+int handle_log(int optind, int argc, char *argv[])
+{
+	struct pdbg_target *target;
+	struct debug_descriptor dd;
+	uint64_t dd_addr;
+	int skip_bytes = 24;
+	int ret;
+
+	pdbg_for_each_class_target("adu", target) {
+		if (!target_selected(target->parent))
+			continue;
+		if (pdbg_target_probe(target) != PDBG_TARGET_ENABLED)
+			continue;
+		break;
+	};
+	assert(target);
+
+	ret = adu_getmem(target, 0x30000080, (uint8_t *)&dd_addr, sizeof(dd_addr));
+	if (ret < 0) {
+		PR_ERROR("unable to read memory\n");
+		return ret;
+	}
+	dd_addr = be64toh(dd_addr);
+
+	ret = adu_getmem(target, dd_addr, (uint8_t *)&dd, sizeof(dd));
+	if (ret < 0) {
+		PR_ERROR("unable to read memory\n");
+		return ret;
+	}
+
+	ret = display_log(target, be64toh(dd.memcons_phys), skip_bytes);
+	if (ret < 0) {
+		PR_ERROR("unable to display log\n");
+		return ret;
+	}
+	return 0;
+}
diff --git a/src/main.c b/src/main.c
index 82a20c9dd3fc..14c038ef730f 100644
--- a/src/main.c
+++ b/src/main.c
@@ -31,6 +31,7 @@
 #include <config.h>
 
 #include <libpdbg.h>
+#include <debug.h>
 
 #include "main.h"
 #include "bitutils.h"
@@ -41,6 +42,7 @@
 #include "mem.h"
 #include "thread.h"
 #include "htm.h"
+#include "log.h"
 #include "options.h"
 
 #define THREADS_PER_CORE	8
@@ -103,6 +105,7 @@ static struct action actions[] = {
 	{ "threadstatus", "", "Print the status of a thread", &thread_status_print },
 	{ "sreset",  "", "Reset", &thread_sreset },
 	{ "regs",  "", "State", &thread_state },
+	{ "log", "[-n <lines>]", "Display skiboot log", &handle_log },
 };
 
 
-- 
2.17.0



More information about the Pdbg mailing list