Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package librtas for openSUSE:Factory checked in at 2025-03-24 13:27:20 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/librtas (Old) and /work/SRC/openSUSE:Factory/.librtas.new.2696 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "librtas" Mon Mar 24 13:27:20 2025 rev:49 rq:1255092 version:2.0.5 Changes: -------- --- /work/SRC/openSUSE:Factory/librtas/librtas.changes 2024-02-01 18:06:03.696554208 +0100 +++ /work/SRC/openSUSE:Factory/.librtas.new.2696/librtas.changes 2025-03-24 13:27:21.655570662 +0100 @@ -1,0 +2,14 @@ +Thu Mar 20 14:41:36 UTC 2025 - Michal Suchanek <msucha...@suse.de> + +- Add support for more rtas call kernel interfaces (jsc#PED-10917) + * 0001-librtas-Move-platform-dump-rtas-call-code-to-separat.patch + * 0002-librtas-platform-dump-prefer-dev-papr-platform-dump-.patch + * 0003-librtas-move-get-set-indices-RTAS-calls-code-to-sepa.patch + * 0004-librtas-Add-kernel-uapi-header-papr-indices.h.patch + * 0005-librtas-Use-dev-papr-indices-when-available-for-ibm-.patch + * 0006-librtas-Use-dev-papr-indices-when-available-for-get-.patch + * 0007-librtas-Use-dev-papr-indices-when-available-for-set-.patch + * 0008-librtas-Move-physical-attestation-rtas-call-code-to-.patch + * 0009-librtas-Use-kernel-interface-when-available-for-ibm-.patch + +------------------------------------------------------------------- New: ---- 0001-librtas-Move-platform-dump-rtas-call-code-to-separat.patch 0002-librtas-platform-dump-prefer-dev-papr-platform-dump-.patch 0003-librtas-move-get-set-indices-RTAS-calls-code-to-sepa.patch 0004-librtas-Add-kernel-uapi-header-papr-indices.h.patch 0005-librtas-Use-dev-papr-indices-when-available-for-ibm-.patch 0006-librtas-Use-dev-papr-indices-when-available-for-get-.patch 0007-librtas-Use-dev-papr-indices-when-available-for-set-.patch 0008-librtas-Move-physical-attestation-rtas-call-code-to-.patch 0009-librtas-Use-kernel-interface-when-available-for-ibm-.patch BETA DEBUG BEGIN: New:- Add support for more rtas call kernel interfaces (jsc#PED-10917) * 0001-librtas-Move-platform-dump-rtas-call-code-to-separat.patch * 0002-librtas-platform-dump-prefer-dev-papr-platform-dump-.patch New: * 0001-librtas-Move-platform-dump-rtas-call-code-to-separat.patch * 0002-librtas-platform-dump-prefer-dev-papr-platform-dump-.patch * 0003-librtas-move-get-set-indices-RTAS-calls-code-to-sepa.patch New: * 0002-librtas-platform-dump-prefer-dev-papr-platform-dump-.patch * 0003-librtas-move-get-set-indices-RTAS-calls-code-to-sepa.patch * 0004-librtas-Add-kernel-uapi-header-papr-indices.h.patch New: * 0003-librtas-move-get-set-indices-RTAS-calls-code-to-sepa.patch * 0004-librtas-Add-kernel-uapi-header-papr-indices.h.patch * 0005-librtas-Use-dev-papr-indices-when-available-for-ibm-.patch New: * 0004-librtas-Add-kernel-uapi-header-papr-indices.h.patch * 0005-librtas-Use-dev-papr-indices-when-available-for-ibm-.patch * 0006-librtas-Use-dev-papr-indices-when-available-for-get-.patch New: * 0005-librtas-Use-dev-papr-indices-when-available-for-ibm-.patch * 0006-librtas-Use-dev-papr-indices-when-available-for-get-.patch * 0007-librtas-Use-dev-papr-indices-when-available-for-set-.patch New: * 0006-librtas-Use-dev-papr-indices-when-available-for-get-.patch * 0007-librtas-Use-dev-papr-indices-when-available-for-set-.patch * 0008-librtas-Move-physical-attestation-rtas-call-code-to-.patch New: * 0007-librtas-Use-dev-papr-indices-when-available-for-set-.patch * 0008-librtas-Move-physical-attestation-rtas-call-code-to-.patch * 0009-librtas-Use-kernel-interface-when-available-for-ibm-.patch New: * 0008-librtas-Move-physical-attestation-rtas-call-code-to-.patch * 0009-librtas-Use-kernel-interface-when-available-for-ibm-.patch BETA DEBUG END: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ librtas-doc.spec ++++++ --- /var/tmp/diff_new_pack.EFpsQk/_old 2025-03-24 13:27:22.511606329 +0100 +++ /var/tmp/diff_new_pack.EFpsQk/_new 2025-03-24 13:27:22.515606496 +0100 @@ -1,7 +1,7 @@ # # spec file for package librtas-doc # -# Copyright (c) 2024 SUSE LLC +# Copyright (c) 2025 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -33,6 +33,15 @@ Patch4: 0004-librtas-vendor-papr-miscdev.h.patch Patch5: 0005-librtas-vpd-prefer-dev-papr-vpd-when-available.patch Patch6: 0006-librtas-sysparm-prefer-dev-papr-sysparm-when-availab.patch +Patch7: 0001-librtas-Move-platform-dump-rtas-call-code-to-separat.patch +Patch8: 0002-librtas-platform-dump-prefer-dev-papr-platform-dump-.patch +Patch9: 0003-librtas-move-get-set-indices-RTAS-calls-code-to-sepa.patch +Patch10: 0004-librtas-Add-kernel-uapi-header-papr-indices.h.patch +Patch11: 0005-librtas-Use-dev-papr-indices-when-available-for-ibm-.patch +Patch12: 0006-librtas-Use-dev-papr-indices-when-available-for-get-.patch +Patch13: 0007-librtas-Use-dev-papr-indices-when-available-for-set-.patch +Patch14: 0008-librtas-Move-physical-attestation-rtas-call-code-to-.patch +Patch15: 0009-librtas-Use-kernel-interface-when-available-for-ibm-.patch BuildRequires: autoconf BuildRequires: automake BuildRequires: doxygen ++++++ librtas.spec ++++++ --- /var/tmp/diff_new_pack.EFpsQk/_old 2025-03-24 13:27:22.551607996 +0100 +++ /var/tmp/diff_new_pack.EFpsQk/_new 2025-03-24 13:27:22.559608330 +0100 @@ -1,7 +1,7 @@ # # spec file for package librtas # -# Copyright (c) 2024 SUSE LLC +# Copyright (c) 2025 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -35,6 +35,15 @@ Patch4: 0004-librtas-vendor-papr-miscdev.h.patch Patch5: 0005-librtas-vpd-prefer-dev-papr-vpd-when-available.patch Patch6: 0006-librtas-sysparm-prefer-dev-papr-sysparm-when-availab.patch +Patch7: 0001-librtas-Move-platform-dump-rtas-call-code-to-separat.patch +Patch8: 0002-librtas-platform-dump-prefer-dev-papr-platform-dump-.patch +Patch9: 0003-librtas-move-get-set-indices-RTAS-calls-code-to-sepa.patch +Patch10: 0004-librtas-Add-kernel-uapi-header-papr-indices.h.patch +Patch11: 0005-librtas-Use-dev-papr-indices-when-available-for-ibm-.patch +Patch12: 0006-librtas-Use-dev-papr-indices-when-available-for-get-.patch +Patch13: 0007-librtas-Use-dev-papr-indices-when-available-for-set-.patch +Patch14: 0008-librtas-Move-physical-attestation-rtas-call-code-to-.patch +Patch15: 0009-librtas-Use-kernel-interface-when-available-for-ibm-.patch BuildRequires: autoconf BuildRequires: automake BuildRequires: libtool ++++++ 0001-librtas-Move-platform-dump-rtas-call-code-to-separat.patch ++++++ >From d4f51bd310cfa82f26f71d22fec3b8e823faa587 Mon Sep 17 00:00:00 2001 From: Haren Myneni <ha...@linux.ibm.com> Date: Sun, 9 Mar 2025 16:29:07 -0700 Subject: [PATCH 1/9] librtas: Move platform-dump rtas call code to separate file New kernel interfaces to support system lockdown will be added for this RTAS call. So move the platform-dump rtas call code to separate file to add code for new interfaces. Signed-off-by: Haren Myneni <ha...@linux.ibm.com> --- Makefile.am | 1 + librtas_src/platform-dump.c | 95 +++++++++++++++++++++++++++++++++++++ librtas_src/syscall_calls.c | 74 ----------------------------- 3 files changed, 96 insertions(+), 74 deletions(-) create mode 100644 librtas_src/platform-dump.c diff --git a/Makefile.am b/Makefile.am index 67257e3..7997e46 100644 --- a/Makefile.am +++ b/Makefile.am @@ -29,6 +29,7 @@ lib_LTLIBRARIES += librtas.la librtas_la_LDFLAGS = -version-info $(LIBRTAS_LIBRARY_VERSION) -lpthread librtas_la_SOURCES = \ librtas_src/vpd.c \ + librtas_src/platform-dump.c \ librtas_src/ofdt.c \ librtas_src/syscall_calls.c \ librtas_src/syscall_rmo.c \ diff --git a/librtas_src/platform-dump.c b/librtas_src/platform-dump.c new file mode 100644 index 0000000..a54c4ee --- /dev/null +++ b/librtas_src/platform-dump.c @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later + +// Support for accessing IBM Power systems Vital Product Data (VPD) +// via /dev/papr-platform-dump or the legacy rtas() syscall. + +#include <errno.h> +#include <inttypes.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <linux/types.h> +#include <linux/unistd.h> +#include <sys/syscall.h> + +#include "internal.h" +#include "librtas.h" + + +/** + * 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) +{ + uint64_t elapsed = 0; + uint32_t kernbuf_pa = 0; + uint32_t next_hi, next_lo; + uint32_t bytes_hi, bytes_lo; + uint32_t dump_tag_hi, dump_tag_lo; + void *kernbuf = NULL; + int rc, status; + + rc = sanity_check(); + if (rc) + return rc; + + if (buffer) { + rc = rtas_get_rmo_buffer(length, &kernbuf, &kernbuf_pa); + if (rc) + return rc; + } + + /* Converting a 64bit host value to 32bit BE, _hi and _lo + * pair is tricky: we should convert the _hi and _lo 32bits + * of the 64bit host value. + */ + dump_tag_hi = htobe32(BITS32_HI(dump_tag)); + dump_tag_lo = htobe32(BITS32_LO(dump_tag)); + + next_hi = htobe32(BITS32_HI(sequence)); + next_lo = htobe32(BITS32_LO(sequence)); + + do { + rc = rtas_call_no_delay("ibm,platform-dump", 6, 5, dump_tag_hi, + dump_tag_lo, next_hi, next_lo, + htobe32(kernbuf_pa), htobe32(length), + &status, &next_hi, &next_lo, + &bytes_hi, &bytes_lo); + if (rc < 0) + break; + + sequence = BITS64(be32toh(next_hi), be32toh(next_lo)); + dbg("%s: seq_next = 0x%" PRIx64 "\n", __FUNCTION__, sequence); + + rc = handle_delay(status, &elapsed); + } while (rc == CALL_AGAIN); + + if (buffer && (rc == 0)) + memcpy(buffer, kernbuf, length); + + if (kernbuf) + (void)rtas_free_rmo_buffer(kernbuf, kernbuf_pa, length); + + *seq_next = sequence; + bytes_hi = be32toh(bytes_hi); + bytes_lo = be32toh(bytes_lo); + *bytes_ret = BITS64(bytes_hi, bytes_lo); + + dbg("(0x%"PRIx64", 0x%"PRIx64", %p, %zu, %p, %p) = %d, 0x%"PRIx64", 0x%"PRIx64"\n", + dump_tag, sequence, buffer, length, seq_next, bytes_ret, + rc ? rc : status, *seq_next, *bytes_ret); + return rc ? rc : status; +} + diff --git a/librtas_src/syscall_calls.c b/librtas_src/syscall_calls.c index 0f15827..9963588 100644 --- a/librtas_src/syscall_calls.c +++ b/librtas_src/syscall_calls.c @@ -768,80 +768,6 @@ int rtas_lpar_perftools(int subfunc, char *workarea, unsigned int length, length, sequence, seq_next, rc ? rc : status, *seq_next); return rc ? rc : status; } -/** - * 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) -{ - uint64_t elapsed = 0; - uint32_t kernbuf_pa = 0; - uint32_t next_hi, next_lo; - uint32_t bytes_hi, bytes_lo; - uint32_t dump_tag_hi, dump_tag_lo; - void *kernbuf = NULL; - int rc, status; - - rc = sanity_check(); - if (rc) - return rc; - - if (buffer) { - rc = rtas_get_rmo_buffer(length, &kernbuf, &kernbuf_pa); - if (rc) - return rc; - } - - /* Converting a 64bit host value to 32bit BE, _hi and _lo - * pair is tricky: we should convert the _hi and _lo 32bits - * of the 64bit host value. - */ - dump_tag_hi = htobe32(BITS32_HI(dump_tag)); - dump_tag_lo = htobe32(BITS32_LO(dump_tag)); - - next_hi = htobe32(BITS32_HI(sequence)); - next_lo = htobe32(BITS32_LO(sequence)); - - do { - rc = rtas_call_no_delay("ibm,platform-dump", 6, 5, dump_tag_hi, - dump_tag_lo, next_hi, next_lo, - htobe32(kernbuf_pa), htobe32(length), - &status, &next_hi, &next_lo, - &bytes_hi, &bytes_lo); - if (rc < 0) - break; - - sequence = BITS64(be32toh(next_hi), be32toh(next_lo)); - dbg("%s: seq_next = 0x%" PRIx64 "\n", __FUNCTION__, sequence); - - rc = handle_delay(status, &elapsed); - } while (rc == CALL_AGAIN); - - if (buffer && (rc == 0)) - memcpy(buffer, kernbuf, length); - - if (kernbuf) - (void)rtas_free_rmo_buffer(kernbuf, kernbuf_pa, length); - - *seq_next = sequence; - bytes_hi = be32toh(bytes_hi); - bytes_lo = be32toh(bytes_lo); - *bytes_ret = BITS64(bytes_hi, bytes_lo); - - dbg("(0x%"PRIx64", 0x%"PRIx64", %p, %zu, %p, %p) = %d, 0x%"PRIx64", 0x%"PRIx64"\n", - dump_tag, sequence, buffer, length, seq_next, bytes_ret, - rc ? rc : status, *seq_next, *bytes_ret); - return rc ? rc : status; -} /** * rtas_read_slot_reset -- 2.47.1 ++++++ 0002-librtas-platform-dump-prefer-dev-papr-platform-dump-.patch ++++++ >From 04fcd8b31f9243cec1cdc138363125cd2105be00 Mon Sep 17 00:00:00 2001 From: Haren Myneni <ha...@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 <ha...@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 ++++++ 0003-librtas-move-get-set-indices-RTAS-calls-code-to-sepa.patch ++++++ >From 40a2b52237cabdfd819e4f49b1161259b4644a8f Mon Sep 17 00:00:00 2001 From: Haren Myneni <ha...@linux.ibm.com> Date: Sun, 9 Mar 2025 16:29:09 -0700 Subject: [PATCH 3/9] librtas: move get/set indices RTAS calls code to separate file This code will gain the ability to access indices (indicator and sensor) using different interfaces exposed by newer kernels. This will involve adding a nontrivial amount of code, so move it out of syscall_calls.c. So moving the following RTAS calls code: ibm,get-indices ibm,set-dynamic-indicator ibm,get-dynamic-sensor-state Signed-off-by: Haren Myneni <ha...@linux.ibm.com> --- Makefile.am | 3 +- librtas_src/indices.c | 141 ++++++++++++++++++++++++++++++++++++ librtas_src/syscall_calls.c | 126 -------------------------------- 3 files changed, 143 insertions(+), 127 deletions(-) create mode 100644 librtas_src/indices.c diff --git a/Makefile.am b/Makefile.am index 156a68b..b67b93f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -33,7 +33,8 @@ librtas_la_SOURCES = \ librtas_src/ofdt.c \ librtas_src/syscall_calls.c \ librtas_src/syscall_rmo.c \ - librtas_src/sysparm.c + librtas_src/sysparm.c \ + librtas_src/indices.c library_include_HEADERS += librtas_src/librtas.h noinst_HEADERS += \ diff --git a/librtas_src/indices.c b/librtas_src/indices.c new file mode 100644 index 0000000..4dff67d --- /dev/null +++ b/librtas_src/indices.c @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later + +// Support for accessing IBM Power systems indices (indicator and sensor) +// data via /dev/papr-indices or the legacy rtas() syscalls. + +#include <stdint.h> +#include <string.h> +#include <errno.h> +#include <inttypes.h> +#include <linux/unistd.h> +#include <linux/types.h> +#include <sys/syscall.h> + +#include "internal.h" +#include "librtas.h" + +/** + * rtas_get_dynamic_sensor + * @brief Interface to ibm,get-dynamic-sensor-state rtas call + * + * On success the variable referenced by the state parameter will contain + * the state of the sensor + * + * @param sensor sensor to retrieve + * @param loc_code location code of the sensor + * @param state reference to state variable + * @return 0 on success, !0 otherwise + */ +int rtas_get_dynamic_sensor(int sensor, void *loc_code, int *state) +{ + uint32_t loc_pa = 0; + void *locbuf; + uint32_t size; + __be32 be_state; + int rc, status; + + rc = sanity_check(); + if (rc) + return rc; + + size = be32toh(*(uint32_t *)loc_code) + sizeof(uint32_t); + + rc = rtas_get_rmo_buffer(size, &locbuf, &loc_pa); + if (rc) + return rc; + + memcpy(locbuf, loc_code, size); + + rc = rtas_call("ibm,get-dynamic-sensor-state", 2, 2, + htobe32(sensor), htobe32(loc_pa), &status, &be_state); + + (void) rtas_free_rmo_buffer(locbuf, loc_pa, size); + + *state = be32toh(be_state); + + dbg("(%d, %s, %p) = %d, %d\n", sensor, (char *)loc_code, state, + rc ? rc : status, *state); + return rc ? rc : status; +} + +/** + * rtas_set_dynamic_indicator + * @brief Interface to the ibm,set-dynamic-indicator rtas call + * + * @param indicator indicator to set + * @param new_value value to set the indicator to + * @param loc_code + * @return 0 on success, !0 otherwise + */ +int rtas_set_dynamic_indicator(int indicator, int new_value, void *loc_code) +{ + uint32_t loc_pa = 0; + void *locbuf; + uint32_t size; + int rc, status; + + rc = sanity_check(); + if (rc) + return rc; + + size = be32toh(*(uint32_t *)loc_code) + sizeof(uint32_t); + + rc = rtas_get_rmo_buffer(size, &locbuf, &loc_pa); + if (rc) + return rc; + + memcpy(locbuf, loc_code, size); + + rc = rtas_call("ibm,set-dynamic-indicator", 3, 1, htobe32(indicator), + htobe32(new_value), htobe32(loc_pa), &status); + + (void) rtas_free_rmo_buffer(locbuf, loc_pa, size); + + dbg("(%d, %d, %s) = %d\n", indicator, new_value, (char *)loc_code, + rc ? rc : status); + return rc ? rc : status; +} + +/** + * rtas_get_indices + * @brief Interface to the ibm,get-indices rtas call + * + * @param is_sensor is this index a sensor? + * @param type + * @param workarea additional args to the rtas call + * @param size + * @param start + * @param next + * @return 0 on success, !0 otherwise + */ +int rtas_get_indices(int is_sensor, int type, char *workarea, size_t size, + int start, int *next) +{ + uint32_t kernbuf_pa; + __be32 be_next; + void *kernbuf; + int rc, status; + + rc = sanity_check(); + if (rc) + return rc; + + rc = rtas_get_rmo_buffer(size, &kernbuf, &kernbuf_pa); + if (rc) + return rc; + + rc = rtas_call("ibm,get-indices", 5, 2, htobe32(is_sensor), + htobe32(type), htobe32(kernbuf_pa), htobe32(size), + htobe32(start), &status, &be_next); + + if (rc == 0) + memcpy(workarea, kernbuf, size); + + (void)rtas_free_rmo_buffer(kernbuf, kernbuf_pa, size); + + *next = be32toh(be_next); + + dbg("(%d, %d, %p, %zu, %d, %p) = %d, %d\n", is_sensor, type, workarea, + size, start, next, rc ? rc : status, *next); + return rc ? rc : status; +} diff --git a/librtas_src/syscall_calls.c b/librtas_src/syscall_calls.c index 9963588..573a4c3 100644 --- a/librtas_src/syscall_calls.c +++ b/librtas_src/syscall_calls.c @@ -525,94 +525,6 @@ int rtas_get_config_addr_info2(uint32_t config_addr, uint64_t phb_id, return rc ? rc : status; } -/** - * rtas_get_dynamic_sensor - * @brief Interface to ibm,get-dynamic-sensor-state rtas call - * - * On success the variable referenced by the state parameter will contain - * the state of the sensor - * - * @param sensor sensor to retrieve - * @param loc_code location code of the sensor - * @param state reference to state variable - * @return 0 on success, !0 otherwise - */ -int rtas_get_dynamic_sensor(int sensor, void *loc_code, int *state) -{ - uint32_t loc_pa = 0; - void *locbuf; - uint32_t size; - __be32 be_state; - int rc, status; - - rc = sanity_check(); - if (rc) - return rc; - - size = be32toh(*(uint32_t *)loc_code) + sizeof(uint32_t); - - rc = rtas_get_rmo_buffer(size, &locbuf, &loc_pa); - if (rc) - return rc; - - memcpy(locbuf, loc_code, size); - - rc = rtas_call("ibm,get-dynamic-sensor-state", 2, 2, - htobe32(sensor), htobe32(loc_pa), &status, &be_state); - - (void) rtas_free_rmo_buffer(locbuf, loc_pa, size); - - *state = be32toh(be_state); - - dbg("(%d, %s, %p) = %d, %d\n", sensor, (char *)loc_code, state, - rc ? rc : status, *state); - return rc ? rc : status; -} - -/** - * rtas_get_indices - * @brief Interface to the ibm,get-indices rtas call - * - * @param is_sensor is this index a sensor? - * @param type - * @param workarea additional args to the rtas call - * @param size - * @param start - * @param next - * @return 0 on success, !0 otherwise - */ -int rtas_get_indices(int is_sensor, int type, char *workarea, size_t size, - int start, int *next) -{ - uint32_t kernbuf_pa; - __be32 be_next; - void *kernbuf; - int rc, status; - - rc = sanity_check(); - if (rc) - return rc; - - rc = rtas_get_rmo_buffer(size, &kernbuf, &kernbuf_pa); - if (rc) - return rc; - - rc = rtas_call("ibm,get-indices", 5, 2, htobe32(is_sensor), - htobe32(type), htobe32(kernbuf_pa), htobe32(size), - htobe32(start), &status, &be_next); - - if (rc == 0) - memcpy(workarea, kernbuf, size); - - (void)rtas_free_rmo_buffer(kernbuf, kernbuf_pa, size); - - *next = be32toh(be_next); - - dbg("(%d, %d, %p, %zu, %d, %p) = %d, %d\n", is_sensor, type, workarea, - size, start, next, rc ? rc : status, *next); - return rc ? rc : status; -} - /** * rtas_get_power_level * @brief Interface to the get-power-level rtas call @@ -848,44 +760,6 @@ int rtas_set_debug(int level) return 0; } -/** - * rtas_set_dynamic_indicator - * @brief Interface to the ibm,set-dynamic-indicator rtas call - * - * @param indicator indicator to set - * @param new_value value to set the indicator to - * @param loc_code - * @return 0 on success, !0 otherwise - */ -int rtas_set_dynamic_indicator(int indicator, int new_value, void *loc_code) -{ - uint32_t loc_pa = 0; - void *locbuf; - uint32_t size; - int rc, status; - - rc = sanity_check(); - if (rc) - return rc; - - size = be32toh(*(uint32_t *)loc_code) + sizeof(uint32_t); - - rc = rtas_get_rmo_buffer(size, &locbuf, &loc_pa); - if (rc) - return rc; - - memcpy(locbuf, loc_code, size); - - rc = rtas_call("ibm,set-dynamic-indicator", 3, 1, htobe32(indicator), - htobe32(new_value), htobe32(loc_pa), &status); - - (void) rtas_free_rmo_buffer(locbuf, loc_pa, size); - - dbg("(%d, %d, %s) = %d\n", indicator, new_value, (char *)loc_code, - rc ? rc : status); - return rc ? rc : status; -} - /** * rtas_set_eeh_option * @brief Inerface to the ibm,set-eeh-option rtas call -- 2.47.1 ++++++ 0004-librtas-Add-kernel-uapi-header-papr-indices.h.patch ++++++ >From da829098907b54627065073d90021e811696e0ee Mon Sep 17 00:00:00 2001 From: Haren Myneni <ha...@linux.ibm.com> Date: Sun, 9 Mar 2025 16:29:10 -0700 Subject: [PATCH 4/9] librtas: Add kernel uapi header papr-indices.h This header file provides ioctls for the following RTAS calls to use new kernel interfaces if /dev/papr-indices is available: ibm,get-indices ibm,set-dynamic-indicator ibm,get-dynamic-sensor-state Signed-off-by: Haren Myneni <ha...@linux.ibm.com> --- librtas_src/papr-indices.h | 42 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 librtas_src/papr-indices.h diff --git a/librtas_src/papr-indices.h b/librtas_src/papr-indices.h new file mode 100644 index 0000000..db47e65 --- /dev/null +++ b/librtas_src/papr-indices.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_PAPR_INDICES_H_ +#define _UAPI_PAPR_INDICES_H_ + +#include <linux/types.h> +#include <asm/ioctl.h> +#include "papr-miscdev.h" + +#define SZ_4K 0x00001000 +#define LOC_CODE_SIZE 80 +#define RTAS_GET_INDICES_BUF_SIZE SZ_4K + +struct papr_indices_io_block { + union { + struct { + __u8 is_sensor; /* 0 for indicator and 1 for sensor */ + __u32 indice_type; + } indices; + struct { + __u32 token; /* Sensor or indicator token */ + __u32 state; /* get / set state */ + /* + * PAPR+ 12.3.2.4 Converged Location Code Rules - + * Length Restrictions. 79 characters plus null. + */ + char location_code_str[LOC_CODE_SIZE]; /* location code */ + } dynamic_param; + }; +}; + +/* + * ioctls for /dev/papr-indices. + * PAPR_INDICES_IOC_GET: Returns a get-indices handle fd to read data + * PAPR_DYNAMIC_SENSOR_IOC_GET: Gets the state of the input sensor + * PAPR_DYNAMIC_INDICATOR_IOC_SET: Sets the new state for the input indicator + */ +#define PAPR_INDICES_IOC_GET _IOW(PAPR_MISCDEV_IOC_ID, 3, struct papr_indices_io_block) +#define PAPR_DYNAMIC_SENSOR_IOC_GET _IOWR(PAPR_MISCDEV_IOC_ID, 4, struct papr_indices_io_block) +#define PAPR_DYNAMIC_INDICATOR_IOC_SET _IOW(PAPR_MISCDEV_IOC_ID, 5, struct papr_indices_io_block) + + +#endif /* _UAPI_PAPR_INDICES_H_ */ -- 2.47.1 ++++++ 0005-librtas-Use-dev-papr-indices-when-available-for-ibm-.patch ++++++ >From ba01abea3ec5cb597b914c734d5ffdf7f6ce08fe Mon Sep 17 00:00:00 2001 From: Haren Myneni <ha...@linux.ibm.com> Date: Sun, 9 Mar 2025 16:29:11 -0700 Subject: [PATCH 5/9] librtas: Use /dev/papr-indices when available for ibm,get-indices rtas_get_indices() uses sys_rtas() call to obtain indices and location codes for a specified indicator or sensor token. But this RTAS function needs RMO buffer allocation which is prohibited under system lockdown. This patch adds changes to use new kernel interfaces such as open/ioctl/read when /dev/papr-indices is available. For the first execution of rtas_get_indices(), initialize an internal function pointer and use the new interfaces depends on the presence of above device node. Open /dev/papr-indices and obtain FD with PAPR_INDICES_IOC_GET ioctl command. The kernel obtained all indices data under ioctl() and exposed to user space with this file descriptor. The hypervisor returns indices data in certain format depends on the RTAS call buffer and the kernel expects the user space to parse this data. Hence the kernel returns RTAS_GET_INDICES_BUF_SIZE (4096) buffer for each read(). Then read() for each rtas_get_indices() continuous until the read() returns 0 which means end of kernel buffer. Signed-off-by: Haren Myneni <ha...@linux.ibm.com> --- Makefile.am | 3 +- librtas_src/indices.c | 116 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 117 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index b67b93f..02d6184 100644 --- a/Makefile.am +++ b/Makefile.am @@ -42,7 +42,8 @@ noinst_HEADERS += \ librtas_src/papr-miscdev.h \ librtas_src/papr-sysparm.h \ librtas_src/papr-vpd.h \ - librtas_src/papr-platform-dump.h + librtas_src/papr-platform-dump.h \ + librtas_src/papr-indices.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/indices.c b/librtas_src/indices.c index 4dff67d..67744c9 100644 --- a/librtas_src/indices.c +++ b/librtas_src/indices.c @@ -7,12 +7,20 @@ #include <string.h> #include <errno.h> #include <inttypes.h> +#include <fcntl.h> +#include <pthread.h> +#include <stdbool.h> #include <linux/unistd.h> #include <linux/types.h> #include <sys/syscall.h> +#include <sys/ioctl.h> +#include <sys/stat.h> #include "internal.h" #include "librtas.h" +#include "papr-indices.h" + +static const char indices_devpath[] = "/dev/papr-indices"; /** * rtas_get_dynamic_sensor @@ -108,7 +116,7 @@ int rtas_set_dynamic_indicator(int indicator, int new_value, void *loc_code) * @param next * @return 0 on success, !0 otherwise */ -int rtas_get_indices(int is_sensor, int type, char *workarea, size_t size, +int get_indices_fallback(int is_sensor, int type, char *workarea, size_t size, int start, int *next) { uint32_t kernbuf_pa; @@ -139,3 +147,109 @@ int rtas_get_indices(int is_sensor, int type, char *workarea, size_t size, size, start, next, rc ? rc : status, *next); return rc ? rc : status; } + +static int get_indices_fd_new(int is_sensor, int type) +{ + struct papr_indices_io_block buf = {}; + const int fd = open(indices_devpath, O_WRONLY); + int devfd = -1; + + if (fd < 0) + return -1; + + buf.indices.is_sensor = is_sensor; + buf.indices.indice_type = type; + devfd = ioctl(fd, PAPR_INDICES_IOC_GET, &buf); + close(fd); + + return devfd; +} + +static int get_indices_chardev(int is_sensor, int type, char *workarea, + size_t size, int start, int *next) +{ + int fd, rtas_status = 0; + ssize_t res; + + if (size != RTAS_GET_INDICES_BUF_SIZE) { + dbg("Invalid buffer size %lu expects %d\n", + size, RTAS_GET_INDICES_BUF_SIZE); + return -EINVAL; + } + + fd = (start == 1) ? get_indices_fd_new(is_sensor, type) + : (int)start; + /* + * Ensure we return a fd > 0 in seq_next. + */ + if (fd == 1) { + int newfd = dup(fd); + close(fd); + fd = newfd; + } + + if (fd < 0) + return -3; /* Synthesize ibm,get-vpd "parameter error" */ + + res = read(fd, workarea, size); + if (res < 0) { + /* Synthesize ibm,get-platfrom-dump "hardware error" */ + rtas_status = -1; + close(fd); + } else if (res == 0) { + /* + * read() returns 0 at the end of read + * So reset the first 32 bit value (number of indices) + * in the buffer which tells no data available to the + * caller of rtas_get_indices(). + */ + *(uint32_t *)workarea = 0; + rtas_status = 0; /* Done with sequence, no more data */ + close(fd); + if (next) + *next = 1; + } else { + rtas_status = 1; /* More data available, call again */ + if (next) + *next = fd; + } + + return rtas_status; +} + +static bool indices_can_use_chardev(void) +{ + struct stat statbuf; + + if (stat(indices_devpath, &statbuf)) + return false; + + if (!S_ISCHR(statbuf.st_mode)) + return false; + + if (close(open(indices_devpath, O_RDONLY))) + return false; + + return true; +} + +static int (*get_indices_fn)(int is_sensor, int type, char *workarea, + size_t size, int start, int *next); + +static void indices_fn_setup(void) +{ + const bool use_chardev = indices_can_use_chardev(); + + get_indices_fn = use_chardev ? + get_indices_chardev : get_indices_fallback; +} + +static pthread_once_t indices_fn_setup_once = PTHREAD_ONCE_INIT; + +int rtas_get_indices(int is_sensor, int type, char *workarea, size_t size, + int start, int *next) +{ + pthread_once(&indices_fn_setup_once, indices_fn_setup); + return get_indices_fn(is_sensor, type, workarea, size, + start, next); +} -- 2.47.1 ++++++ 0006-librtas-Use-dev-papr-indices-when-available-for-get-.patch ++++++ >From ba73b7e26a517396bc0b053e1e3dab658cbde890 Mon Sep 17 00:00:00 2001 From: Haren Myneni <ha...@linux.ibm.com> Date: Sun, 9 Mar 2025 16:29:12 -0700 Subject: [PATCH 6/9] librtas: Use /dev/papr-indices when available for get-dynamic-sensor-state The current rtas_get_dynamic_sensor() allocates RTAS work area and invokes sys_rtas() in the user space. But this interface will not work under system lockdown due to restricted access to /dev/mem. This patch add changes to use new kernel interface provided by /dev/papr-indices entry with PAPR_DYNAMIC_SENSOR_IOC_GET ioctl. The new state of sensor token will be returned from the user passed papr_indices_io_block to the ioctl. If /dev/papr-indices entry is available, the new kernel interface is used with the following programming model: fd = open("/dev/papr-indices", O_RDWR); copy location-code to papr_indices_io_block.dynamic_param.location_code_str papr_indices_io_block.dynamic_param.token = token-val; ret = ioctl(fd, PAPR_DYNAMIC_SENSOR_IOC_GET, papr_indices_io_block); state = papr_indices_io_block.dynamic_param.state Signed-off-by: Haren Myneni <ha...@linux.ibm.com> --- librtas_src/indices.c | 90 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/librtas_src/indices.c b/librtas_src/indices.c index 67744c9..27d537c 100644 --- a/librtas_src/indices.c +++ b/librtas_src/indices.c @@ -34,7 +34,7 @@ static const char indices_devpath[] = "/dev/papr-indices"; * @param state reference to state variable * @return 0 on success, !0 otherwise */ -int rtas_get_dynamic_sensor(int sensor, void *loc_code, int *state) +int get_dynamic_sensor_fallback(int sensor, void *loc_code, int *state) { uint32_t loc_pa = 0; void *locbuf; @@ -217,6 +217,85 @@ static int get_indices_chardev(int is_sensor, int type, char *workarea, return rtas_status; } +/* + * Only to be used when converting an actual error from a syscall. + */ +static int chardev_backconvert_errno(int saved_errno) +{ + const struct { + int linux_errno; + int rtas_status; + } map[] = { +#define errno_to_status(e, s) { .linux_errno = (e), .rtas_status = (s), } + errno_to_status(EINVAL, -9999), + errno_to_status(EPERM, -9002), + errno_to_status(EOPNOTSUPP, -3), + errno_to_status(EIO, -1), + errno_to_status(EFAULT, -1), +#undef errno_to_status + }; + + for (size_t i = 0; i < sizeof(map) / sizeof(map[0]); ++i) + if (map[i].linux_errno == saved_errno) + return map[i].rtas_status; + return -1; +} + +static int dynamic_common_io_setup(unsigned long ioctalval, + void *loc_code, + struct papr_indices_io_block *buf) +{ + size_t length; + char *loc_str; + int fd, ret = -EINVAL; + + fd = open(indices_devpath, O_RDWR); + if (fd < 0) { + /* + * Should not be here. May be /dev/papr-indices removed + */ + return -1; + } + + length = be32toh(*(uint32_t *)loc_code); + + if (length < 1) { + dbg("Invalid length(%lu) of location code string\n", length); + goto out; + } + + loc_str = (char *)((char *)loc_code + sizeof(uint32_t)); + if (strlen(loc_str) != (length - 1)) { + dbg("location code string length is not matched with the passed length(%lu)\n", length); + goto out; + } + + memcpy(&buf->dynamic_param.location_code_str, loc_str, length); + + ret = ioctl(fd, ioctalval, buf); + if (ret != 0) + ret = chardev_backconvert_errno(errno); +out: + close(fd); + return ret; +} + +static int get_dynamic_sensor_chardev(int sensor, void *loc_code, int *state) +{ + struct papr_indices_io_block buf = {}; + int ret; + + buf.dynamic_param.token = sensor; + ret = dynamic_common_io_setup(PAPR_DYNAMIC_SENSOR_IOC_GET, + loc_code, &buf); + if (ret != 0) + return ret; + + *state = buf.dynamic_param.state; + + return 0; +} + static bool indices_can_use_chardev(void) { struct stat statbuf; @@ -235,6 +314,7 @@ static bool indices_can_use_chardev(void) static int (*get_indices_fn)(int is_sensor, int type, char *workarea, size_t size, int start, int *next); +static int (*get_dynamic_sensor_fn)(int sensor, void *loc_code, int *state); static void indices_fn_setup(void) { @@ -242,6 +322,8 @@ static void indices_fn_setup(void) get_indices_fn = use_chardev ? get_indices_chardev : get_indices_fallback; + get_dynamic_sensor_fn = use_chardev ? + get_dynamic_sensor_chardev : get_dynamic_sensor_fallback; } static pthread_once_t indices_fn_setup_once = PTHREAD_ONCE_INIT; @@ -253,3 +335,9 @@ int rtas_get_indices(int is_sensor, int type, char *workarea, size_t size, return get_indices_fn(is_sensor, type, workarea, size, start, next); } + +int rtas_get_dynamic_sensor(int sensor, void *loc_code, int *state) +{ + pthread_once(&indices_fn_setup_once, indices_fn_setup); + return get_dynamic_sensor_fn(sensor, loc_code, state); +} -- 2.47.1 ++++++ 0007-librtas-Use-dev-papr-indices-when-available-for-set-.patch ++++++ >From 8a4ddb00328b7cde9ff20d9c321dad1e094128d9 Mon Sep 17 00:00:00 2001 From: Haren Myneni <ha...@linux.ibm.com> Date: Sun, 9 Mar 2025 16:29:13 -0700 Subject: [PATCH 7/9] librtas: Use /dev/papr-indices when available for set-dynamic-indicator Changes for rtas_set_dynamic_indicator() to use new kernel interface provided by /dev/papr-indices entry. The kernel provides PAPR_DYNAMIC_INDICATOR_IOC_SET ioctl for /dev/papr-indices to execute ibm,set-dynamic-indicator RTAS Call. If /dev/papr-indices entry is available, the new kernel interface is used with the following programming model: fd = open("/dev/papr-indices", O_RDWR); copy location-code to papr_indices_io_block.dynamic_param.location_code_str papr_indices_io_block.dynamic_param.token = token-val; papr_indices_io_block.dynamic_param.state = new-state; ret = ioctl(fd, PAPR_DYNAMIC_INDICATOR_IOC_SET, papr_indices_io_block); Signed-off-by: Haren Myneni <ha...@linux.ibm.com> --- librtas_src/indices.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/librtas_src/indices.c b/librtas_src/indices.c index 27d537c..875c576 100644 --- a/librtas_src/indices.c +++ b/librtas_src/indices.c @@ -75,7 +75,7 @@ int get_dynamic_sensor_fallback(int sensor, void *loc_code, int *state) * @param loc_code * @return 0 on success, !0 otherwise */ -int rtas_set_dynamic_indicator(int indicator, int new_value, void *loc_code) +int set_dynamic_indicator_fallback(int indicator, int new_value, void *loc_code) { uint32_t loc_pa = 0; void *locbuf; @@ -296,6 +296,20 @@ static int get_dynamic_sensor_chardev(int sensor, void *loc_code, int *state) return 0; } +static int set_dynamic_indicator_chardev(int indicator, int new_value, + void *loc_code) +{ + struct papr_indices_io_block buf = {}; + int ret; + + buf.dynamic_param.token = indicator; + buf.dynamic_param.state = new_value; + ret = dynamic_common_io_setup(PAPR_DYNAMIC_INDICATOR_IOC_SET, + loc_code, &buf); + + return ret; +} + static bool indices_can_use_chardev(void) { struct stat statbuf; @@ -315,6 +329,8 @@ static bool indices_can_use_chardev(void) static int (*get_indices_fn)(int is_sensor, int type, char *workarea, size_t size, int start, int *next); static int (*get_dynamic_sensor_fn)(int sensor, void *loc_code, int *state); +static int (*set_dynamic_indicator_fn)(int indicator, int new_value, + void *loc_code); static void indices_fn_setup(void) { @@ -324,6 +340,9 @@ static void indices_fn_setup(void) get_indices_chardev : get_indices_fallback; get_dynamic_sensor_fn = use_chardev ? get_dynamic_sensor_chardev : get_dynamic_sensor_fallback; + set_dynamic_indicator_fn = use_chardev ? + set_dynamic_indicator_chardev : set_dynamic_indicator_fallback; + } static pthread_once_t indices_fn_setup_once = PTHREAD_ONCE_INIT; @@ -341,3 +360,9 @@ int rtas_get_dynamic_sensor(int sensor, void *loc_code, int *state) pthread_once(&indices_fn_setup_once, indices_fn_setup); return get_dynamic_sensor_fn(sensor, loc_code, state); } + +int rtas_set_dynamic_indicator(int indicator, int new_value, void *loc_code) +{ + pthread_once(&indices_fn_setup_once, indices_fn_setup); + return set_dynamic_indicator_fn(indicator, new_value, loc_code); +} -- 2.47.1 ++++++ 0008-librtas-Move-physical-attestation-rtas-call-code-to-.patch ++++++ >From b213c977f8c5652b89ffe86f5a94d0b94d99a5be Mon Sep 17 00:00:00 2001 From: Haren Myneni <ha...@linux.ibm.com> Date: Sun, 9 Mar 2025 16:29:14 -0700 Subject: [PATCH 8/9] librtas: Move physical-attestation rtas call code to separate file New kernel interfaces to support system lockdown will be added for this RTAS call. So move the physical-attestation rtas call code to separate file to add code for new interfaces. Signed-off-by: Haren Myneni <ha...@linux.ibm.com> --- Makefile.am | 3 +- librtas_src/physical-attestation.c | 78 ++++++++++++++++++++++++++++++ librtas_src/syscall_calls.c | 63 ------------------------ 3 files changed, 80 insertions(+), 64 deletions(-) create mode 100644 librtas_src/physical-attestation.c diff --git a/Makefile.am b/Makefile.am index 02d6184..e605d98 100644 --- a/Makefile.am +++ b/Makefile.am @@ -34,7 +34,8 @@ librtas_la_SOURCES = \ librtas_src/syscall_calls.c \ librtas_src/syscall_rmo.c \ librtas_src/sysparm.c \ - librtas_src/indices.c + librtas_src/indices.c \ + librtas_src/physical-attestation.c library_include_HEADERS += librtas_src/librtas.h noinst_HEADERS += \ diff --git a/librtas_src/physical-attestation.c b/librtas_src/physical-attestation.c new file mode 100644 index 0000000..3e36af3 --- /dev/null +++ b/librtas_src/physical-attestation.c @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later + +// Support for accessing ibm,physical-attestation data +// via /dev/papr-phy-attestation or the legacy rtas() syscall. + +#include <stdarg.h> +#include <string.h> +#include <errno.h> +#include <inttypes.h> +#include <sys/syscall.h> +#include <linux/unistd.h> +#include <linux/types.h> +#include "internal.h" +#include "librtas.h" + +/** + * rtas_physical_attestation + * @brief Interface for ibm,physical-attestation rtas call. + * + * @param workarea input/output work area for rtas call + * @param seq_num sequence number of the rtas call + * @param next_seq_num next sequence number + * @param work_area_bytes size of work area + * @return 0 on success, !0 on failure + */ +int rtas_physical_attestation(char *workarea, int seq_num, int *next_seq_num, + int *work_area_bytes) +{ + uint32_t workarea_pa; + uint64_t elapsed = 0; + void *kernbuf; + int kbuf_sz = WORK_AREA_SIZE; + int rc, status; + int resp_bytes = *work_area_bytes; + + rc = sanity_check(); + if (rc) + return rc; + + /* Caller provided more data than FW can handle */ + if (*work_area_bytes == 0 || + *work_area_bytes > kbuf_sz) + return RTAS_IO_ASSERT; + + rc = rtas_get_rmo_buffer(kbuf_sz, &kernbuf, &workarea_pa); + if (rc) + return rc; + memcpy(kernbuf, workarea, *work_area_bytes); + + do { + rc = rtas_call("ibm,physical-attestation", 3, 3, + htobe32(workarea_pa), htobe32(kbuf_sz), + htobe32(seq_num), + &status, next_seq_num, &resp_bytes); + if (rc < 0) + break; + + rc = handle_delay(status, &elapsed); + } while (rc == CALL_AGAIN); + + *next_seq_num = be32toh(*next_seq_num); + + /* FW returned more data than we can handle */ + if (be32toh(resp_bytes) > (unsigned int)*work_area_bytes) { + (void)rtas_free_rmo_buffer(kernbuf, workarea_pa, kbuf_sz); + return RTAS_IO_ASSERT; + } + + *work_area_bytes = be32toh(resp_bytes); + + if (rc == 0) + memcpy(workarea, kernbuf, *work_area_bytes); + + (void)rtas_free_rmo_buffer(kernbuf, workarea_pa, kbuf_sz); + + return rc ? rc : status; +} + diff --git a/librtas_src/syscall_calls.c b/librtas_src/syscall_calls.c index 573a4c3..c1d3a9c 100644 --- a/librtas_src/syscall_calls.c +++ b/librtas_src/syscall_calls.c @@ -990,66 +990,3 @@ int rtas_update_properties(char *workarea, unsigned int scope) dbg("(%p) %u = %d\n", workarea, scope, rc ? rc : status); return rc ? rc : status; } - -/** - * rtas_physical_attestation - * @brief Interface for ibm,physical-attestation rtas call. - * - * @param workarea input/output work area for rtas call - * @param seq_num sequence number of the rtas call - * @param next_seq_num next sequence number - * @param work_area_bytes size of work area - * @return 0 on success, !0 on failure - */ -int rtas_physical_attestation(char *workarea, int seq_num, int *next_seq_num, - int *work_area_bytes) -{ - uint32_t workarea_pa; - uint64_t elapsed = 0; - void *kernbuf; - int kbuf_sz = WORK_AREA_SIZE; - int rc, status; - int resp_bytes = *work_area_bytes; - - rc = sanity_check(); - if (rc) - return rc; - - /* Caller provided more data than FW can handle */ - if (*work_area_bytes == 0 || - *work_area_bytes > kbuf_sz) - return RTAS_IO_ASSERT; - - rc = rtas_get_rmo_buffer(kbuf_sz, &kernbuf, &workarea_pa); - if (rc) - return rc; - memcpy(kernbuf, workarea, *work_area_bytes); - - do { - rc = rtas_call("ibm,physical-attestation", 3, 3, - htobe32(workarea_pa), htobe32(kbuf_sz), - htobe32(seq_num), - &status, next_seq_num, &resp_bytes); - if (rc < 0) - break; - - rc = handle_delay(status, &elapsed); - } while (rc == CALL_AGAIN); - - *next_seq_num = be32toh(*next_seq_num); - - /* FW returned more data than we can handle */ - if (be32toh(resp_bytes) > (unsigned int)*work_area_bytes) { - (void)rtas_free_rmo_buffer(kernbuf, workarea_pa, kbuf_sz); - return RTAS_IO_ASSERT; - } - - *work_area_bytes = be32toh(resp_bytes); - - if (rc == 0) - memcpy(workarea, kernbuf, *work_area_bytes); - - (void)rtas_free_rmo_buffer(kernbuf, workarea_pa, kbuf_sz); - - return rc ? rc : status; -} -- 2.47.1 ++++++ 0009-librtas-Use-kernel-interface-when-available-for-ibm-.patch ++++++ >From edd705db27f14c393618ddd68c1b41c43985726a Mon Sep 17 00:00:00 2001 From: Haren Myneni <ha...@linux.ibm.com> Date: Sun, 9 Mar 2025 16:29:15 -0700 Subject: [PATCH 9/9] librtas: Use kernel interface when available for ibm,physical-attestation rtas_physical_attestation() uses sys_rtas() to obtain response buffer for each attestation command. This RTAS function passes RTAS work area to send input attestation command and to retrieve response buffer. But the allocation of work area is prohibited under system lockdown. This patch adds changes to use new kernel ABI if /dev/papr-physical-attestation is available. First execution of rtas_physical_attestation() sets the new API if the device node is available, otherise execute user space interface. Open /dev/papr-physical-attestation and obtain FD with PAPR_PHY_ATTEST_IOC_HANDLE ioctl. The kernel completes the RTAS sequence in this ioctl and exposes the reponse buffer with this FD. The user space reads the complete buffer with read() calls. Signed-off-by: Haren Myneni <ha...@linux.ibm.com> --- Makefile.am | 3 +- librtas_src/papr-physical-attestation.h | 31 ++++++ librtas_src/physical-attestation.c | 137 +++++++++++++++++++++++- 3 files changed, 166 insertions(+), 5 deletions(-) create mode 100644 librtas_src/papr-physical-attestation.h diff --git a/Makefile.am b/Makefile.am index e605d98..ccd7ee7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -44,7 +44,8 @@ noinst_HEADERS += \ librtas_src/papr-sysparm.h \ librtas_src/papr-vpd.h \ librtas_src/papr-platform-dump.h \ - librtas_src/papr-indices.h + librtas_src/papr-indices.h \ + librtas_src/papr-physical-attestation.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-physical-attestation.h b/librtas_src/papr-physical-attestation.h new file mode 100644 index 0000000..32b4bae --- /dev/null +++ b/librtas_src/papr-physical-attestation.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_PAPR_PHYSICAL_ATTESTATION_H_ +#define _UAPI_PAPR_PHYSICAL_ATTESTATION_H_ + +#include <linux/types.h> +#include <asm/ioctl.h> +#include "papr-miscdev.h" + +#define PAPR_PHYATTEST_MAX_INPUT 4084 /* Max 4K buffer: 4K-12 */ + +/* + * Defined in PAPR 2.13+ 21.6 Attestation Command Structures. + * User space pass this struct and the max size should be 4K. + */ +struct papr_phy_attest_io_block { + __u8 version; + __u8 command; + __u8 TCG_major_ver; + __u8 TCG_minor_ver; + __be32 length; + __be32 correlator; + __u8 payload[PAPR_PHYATTEST_MAX_INPUT]; +}; + +/* + * ioctl for /dev/papr-physical-attestation. Returns a attestation + * command fd handle + */ +#define PAPR_PHY_ATTEST_IOC_HANDLE _IOW(PAPR_MISCDEV_IOC_ID, 8, struct papr_phy_attest_io_block) + +#endif /* _UAPI_PAPR_PHYSICAL_ATTESTATION_H_ */ diff --git a/librtas_src/physical-attestation.c b/librtas_src/physical-attestation.c index 3e36af3..48108a0 100644 --- a/librtas_src/physical-attestation.c +++ b/librtas_src/physical-attestation.c @@ -1,21 +1,27 @@ // SPDX-License-Identifier: LGPL-2.1-or-later - + // Support for accessing ibm,physical-attestation data // via /dev/papr-phy-attestation or the legacy rtas() syscall. #include <stdarg.h> #include <string.h> #include <errno.h> +#include <fcntl.h> +#include <pthread.h> #include <inttypes.h> +#include <stdbool.h> +#include <stdlib.h> #include <sys/syscall.h> +#include <sys/stat.h> +#include <sys/ioctl.h> #include <linux/unistd.h> #include <linux/types.h> #include "internal.h" #include "librtas.h" +#include "papr-physical-attestation.h" /** - * rtas_physical_attestation - * @brief Interface for ibm,physical-attestation rtas call. + * ibm,physical-attestation RTAS call from user space * * @param workarea input/output work area for rtas call * @param seq_num sequence number of the rtas call @@ -23,7 +29,7 @@ * @param work_area_bytes size of work area * @return 0 on success, !0 on failure */ -int rtas_physical_attestation(char *workarea, int seq_num, int *next_seq_num, +int phy_attestation_user(char *workarea, int seq_num, int *next_seq_num, int *work_area_bytes) { uint32_t workarea_pa; @@ -76,3 +82,126 @@ int rtas_physical_attestation(char *workarea, int seq_num, int *next_seq_num, return rc ? rc : status; } +static bool phy_attest_can_use_chardev(void) +{ + struct stat statbuf; + + if (stat("/dev/papr-physical-attestation", &statbuf)) + return false; + + if (!S_ISCHR(statbuf.st_mode)) + return false; + + if (close(open("/dev/papr-physical-attestation", O_RDONLY))) + return false; + + return true; +} + +#define DEVPATH "/dev/papr-physical-attestation" + +static int phy_attest_fd_new(const char *attest_cmd, unsigned int size) +{ + const int devfd = open(DEVPATH, O_WRONLY); + struct papr_phy_attest_io_block cmd = {}; + int fd = -1; + + if (devfd < 0) + return -1; + + /* + * Size of each command struct has to be the buffer size + * (WORK_AREA_SIZE - 4K) passed by the user. + */ + if (size != sizeof(struct papr_phy_attest_io_block)) { + fd = RTAS_IO_ASSERT; + goto close_devfd; + } + + memcpy(&cmd, attest_cmd, sizeof(struct papr_phy_attest_io_block)); + fd = ioctl(devfd, PAPR_PHY_ATTEST_IOC_HANDLE, &cmd); + +close_devfd: + close(devfd); + return fd; +} + +static int +phy_attestation_kernel(char *workarea, int seq_num, int *next_seq_num, + int *work_area_bytes) +{ + int size = *work_area_bytes; + int fd = (seq_num == 1) ? phy_attest_fd_new(workarea, size) + : (int)seq_num; + + /* + * Ensure we return a fd > 0 in next_seq_num. + */ + if (fd == 1) { + int newfd = dup(fd); + close(fd); + fd = newfd; + } + + if (fd < 0) + return -3; /* Synthesize ibm,get-vpd "parameter error" */ + + /* Caller provided more data than FW can handle */ + if (size == 0 || size > WORK_AREA_SIZE) { + close(fd); + return RTAS_IO_ASSERT; + } + + + int rtas_status = 0; + ssize_t res = read(fd, workarea, *work_area_bytes); + if (res < 0) { + rtas_status = -1; /* Synthesize ibm,get-vpd "hardware error" */ + close(fd); + } else if (res == 0 || res < (ssize_t)size) { + rtas_status = 0; /* Done with sequence, no more data */ + close(fd); + if (next_seq_num) + *next_seq_num = 1; + if (work_area_bytes) + *work_area_bytes = res; + } else { + rtas_status = 1; /* More data available, call again */ + if (next_seq_num) + *next_seq_num = fd; + if (work_area_bytes) + *work_area_bytes = res; + } + + return rtas_status; +} + +static int (*phy_attestation_fn)(char *workarea, int seq_num, + int *next_seq_num, int *work_area_bytes); + +static void phy_attestation_fn_setup(void) +{ + phy_attestation_fn = phy_attest_can_use_chardev() ? + phy_attestation_kernel : phy_attestation_user; +} + +/** + * rtas_physical_attestation + * @brief Interface for ibm,physical-attestation rtas call. + * + * @param workarea input/output work area for rtas call + * @param seq_num sequence number of the rtas call + * @param next_seq_num next sequence number + * @param work_area_bytes size of input/output work area + * @return 0 on success, !0 on failure + */ +int rtas_physical_attestation(char *workarea, int seq_num, int *next_seq_num, + int *work_area_bytes) +{ + static pthread_once_t phy_attestation_fn_once = PTHREAD_ONCE_INIT; + + pthread_once(&phy_attestation_fn_once, phy_attestation_fn_setup); + + return phy_attestation_fn(workarea, seq_num, next_seq_num, + work_area_bytes); +} -- 2.47.1