SHA256
8
0
forked from pool/librtas
Files
librtas/0002-librtas-platform-dump-prefer-dev-papr-platform-dump-.patch

249 lines
7.4 KiB
Diff
Raw Permalink Normal View History

From 04fcd8b31f9243cec1cdc138363125cd2105be00 Mon Sep 17 00:00:00 2001
From: Haren Myneni <haren@linux.ibm.com>
Date: Sun, 9 Mar 2025 16:29:08 -0700
Subject: [PATCH 2/9] librtas/platform-dump: prefer /dev/papr-platform-dump
when available
rtas_platform_dump() uses sys_rtas() call to obtain platform dump.
But it needs /dev/mem access in the user space which is restricted
under system lockdown. So this patch adds changes to use new kernel
ABI for system lockdown feature.
Kernel provides new interfaces such as open/ioctl/read with
/dev/papr-platform-dump char based driver. For the first invocation
of rtas_platform_dump() call, initialize an internal function
pointer depends on the presence of above device node. If not
fallback to the the current implementation. pthread_once() is used
to this setup is done only once.
Open /dev/papr-platform-dump and obtain FD with
PAPR_PLATFORM_DUMP_IOC_CREATE_HANDLE ioctl command. This file
descriptor is reference to the dump sequence obtained with the
specified dump tag. Then read() call for each rtas_platform_dump()
with the FD retrieves the dump data as a sequence until the read()
returns 0.
The hypervisor uses sequence number passed with ibm,platform-dump
RTAS call to make sure the complete dump is transferred. First
RTAS call is invoked with sequence number 0 to start obtaining the
dump and then RTAS advances the sequence number by a fixed interval
on each call in a sequence until the dump is completed. The current
implementation in the user space tracks this sequence number
returned for each RTAS and passes to the next RTAS. Whereas with
the new ABI, the kernel uses it internally for the corresponding
dump tag and librtas uses it as a FD for the subsequent read calls.
Also added the copy of kernel uapi header papr-platform-dump.h.
Signed-off-by: Haren Myneni <haren@linux.ibm.com>
---
Makefile.am | 3 +-
librtas_src/papr-platform-dump.h | 18 +++++
librtas_src/platform-dump.c | 130 ++++++++++++++++++++++++++++++-
3 files changed, 148 insertions(+), 3 deletions(-)
create mode 100644 librtas_src/papr-platform-dump.h
diff --git a/Makefile.am b/Makefile.am
index 7997e46..156a68b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -40,7 +40,8 @@ noinst_HEADERS += \
librtas_src/internal.h \
librtas_src/papr-miscdev.h \
librtas_src/papr-sysparm.h \
- librtas_src/papr-vpd.h
+ librtas_src/papr-vpd.h \
+ librtas_src/papr-platform-dump.h
# See "Updating library version information" in the libtool manual for
# how to maintain these values. They are *not* tied to the release
diff --git a/librtas_src/papr-platform-dump.h b/librtas_src/papr-platform-dump.h
new file mode 100644
index 0000000..4ee8ab1
--- /dev/null
+++ b/librtas_src/papr-platform-dump.h
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+#ifndef _UAPI_PAPR_PLATFORM_DUMP_H_
+#define _UAPI_PAPR_PLATFORM_DUMP_H_
+
+#include <asm/ioctl.h>
+#include "papr-miscdev.h"
+
+/*
+ * ioctl for /dev/papr-platform-dump. Returns a platform-dump handle
+ * fd corresponding to the dump tag
+ */
+#define PAPR_PLATFORM_DUMP_IOC_CREATE_HANDLE _IOW(PAPR_MISCDEV_IOC_ID, 6, __u64)
+/*
+ * ioctl for /dev/papr-platform-dump to invalidate platform dump
+ * after dump completed. Uses FD returned from the above ioctl.
+ */
+#define PAPR_PLATFORM_DUMP_IOC_INVALIDATE _IOW(PAPR_MISCDEV_IOC_ID, 7, __u64)
+#endif /* _UAPI_PAPR_PLATFORM_DUMP_H_ */
diff --git a/librtas_src/platform-dump.c b/librtas_src/platform-dump.c
index a54c4ee..d456445 100644
--- a/librtas_src/platform-dump.c
+++ b/librtas_src/platform-dump.c
@@ -5,6 +5,10 @@
#include <errno.h>
#include <inttypes.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <pthread.h>
+#include <search.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdlib.h>
@@ -13,10 +17,12 @@
#include <linux/types.h>
#include <linux/unistd.h>
#include <sys/syscall.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
#include "internal.h"
#include "librtas.h"
-
+#include "papr-platform-dump.h"
/**
* rtas_platform_dump
@@ -30,7 +36,7 @@
* @param bytes_ret
* @return 0 on success, !0 othwerwise
*/
-int rtas_platform_dump(uint64_t dump_tag, uint64_t sequence, void *buffer,
+int platform_dump_user(uint64_t dump_tag, uint64_t sequence, void *buffer,
size_t length, uint64_t *seq_next, uint64_t *bytes_ret)
{
uint64_t elapsed = 0;
@@ -93,3 +99,123 @@ int rtas_platform_dump(uint64_t dump_tag, uint64_t sequence, void *buffer,
return rc ? rc : status;
}
+static bool platform_dump_can_use_chardev(void)
+{
+ struct stat statbuf;
+
+ if (stat("/dev/papr-platform-dump", &statbuf))
+ return false;
+
+ if (!S_ISCHR(statbuf.st_mode))
+ return false;
+
+ if (close(open("/dev/papr-platform-dump", O_RDONLY)))
+ return false;
+
+ return true;
+}
+
+#define DEVPATH "/dev/papr-platform-dump"
+
+static int platform_dump_fd_new(uint64_t dump_tag)
+{
+ const int devfd = open(DEVPATH, O_WRONLY);
+ int fd = -1;
+
+ if (devfd < 0)
+ return -1;
+
+ fd = ioctl(devfd, PAPR_PLATFORM_DUMP_IOC_CREATE_HANDLE, &dump_tag);
+
+ close(devfd);
+ return fd;
+}
+
+int platform_dump_kernel(uint64_t dump_tag, uint64_t sequence, void *buffer,
+ size_t length, uint64_t *seq_next, uint64_t *bytes_ret)
+{
+ int fd = (sequence == 0) ? platform_dump_fd_new(dump_tag)
+ : (int)sequence;
+ int rtas_status = 0;
+ ssize_t size;
+
+ /* Synthesize ibm,get-platfrom-dump "parameter error" */
+ if (fd < 0)
+ return -3;
+
+ /*
+ * rtas_platform_dump() is called with buf = NULL and length = 0
+ * for "dump complete" RTAS call to invalidate dump.
+ * For kernel interface, read() will be continued until the
+ * return value = 0. Means kernel API will return this value only
+ * after the kernel RTAS call returned "dump complete" status
+ * and the hypervisor expects last RTAS call to invalidate dump.
+ * So issue the following ioctl API which invalidates the dump
+ * with the last RTAS call.
+ */
+ if (buffer == NULL) {
+ rtas_status = ioctl(fd, PAPR_PLATFORM_DUMP_IOC_INVALIDATE,
+ &dump_tag);
+ close(fd);
+ return rtas_status;
+ }
+
+ /*
+ * Ensure we return a fd > 0 in seq_next.
+ */
+ if (fd == 0) {
+ int newfd = dup(fd);
+ close(fd);
+ fd = newfd;
+ }
+
+ size = read(fd, buffer, length);
+ if (size < 0) {
+ /* Synthesize ibm,get-platfrom-dump "hardware error" */
+ close(fd);
+ return -1;
+ } else if (size > 0) {
+ rtas_status = 1; /* More data available, call again */
+ }
+
+ if (seq_next)
+ *seq_next = fd;
+ if (bytes_ret)
+ *bytes_ret = size;
+
+ return rtas_status;
+}
+
+static int (*platform_dump_fn)(uint64_t dump_tag, uint64_t sequence,
+ void *buffer, size_t length,
+ uint64_t *seq_next, uint64_t *bytes_ret);
+
+static void platform_dump_fn_setup(void)
+{
+ platform_dump_fn = platform_dump_can_use_chardev() ?
+ platform_dump_kernel : platform_dump_user;
+}
+
+/**
+ * rtas_platform_dump
+ * Interface to the ibm,platform-dump rtas call
+ *
+ * @param dump_tag
+ * @param sequence
+ * @param buffer buffer to write dump to
+ * @param length buffer length
+ * @param next_seq
+ * @param bytes_ret
+ * @return 0 on success, !0 othwerwise
+ */
+int rtas_platform_dump(uint64_t dump_tag, uint64_t sequence, void *buffer,
+ size_t length, uint64_t *seq_next, uint64_t *bytes_ret)
+{
+ static pthread_once_t platform_dump_fn_once = PTHREAD_ONCE_INIT;
+
+ pthread_once(&platform_dump_fn_once, platform_dump_fn_setup);
+
+ return platform_dump_fn(dump_tag, sequence, buffer, length, seq_next,
+ bytes_ret);
+}
+
--
2.47.1