diff --git a/librtas-01-lockdown-compatible-abi-phase.patch b/librtas-01-lockdown-compatible-abi-phase.patch new file mode 100644 index 0000000..eb64f34 --- /dev/null +++ b/librtas-01-lockdown-compatible-abi-phase.patch @@ -0,0 +1,211 @@ +commit 07f499240d0a373fac8e025dace5f84673811d6d +Author: Haren Myneni +Date: Tue Apr 29 20:10:11 2025 -0700 + + 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 + Signed-off-by: Tyrel Datwyler + +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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 diff --git a/librtas-02-lockdown-compatible-abi-phase.patch b/librtas-02-lockdown-compatible-abi-phase.patch new file mode 100644 index 0000000..ab5315b --- /dev/null +++ b/librtas-02-lockdown-compatible-abi-phase.patch @@ -0,0 +1,241 @@ +commit 0102c576d73e7cfa3d61128ce39d42833a45a987 +Author: Haren Myneni +Date: Tue Apr 29 20:10:12 2025 -0700 + + 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 + Signed-off-by: Tyrel Datwyler + +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..56d509d +--- /dev/null ++++ b/librtas_src/papr-platform-dump.h +@@ -0,0 +1,19 @@ ++// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note ++#ifndef _UAPI_PAPR_PLATFORM_DUMP_H_ ++#define _UAPI_PAPR_PLATFORM_DUMP_H_ ++ ++#include ++#include ++#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 + #include ++#include ++#include ++#include ++#include + #include + #include + #include +@@ -13,10 +17,12 @@ + #include + #include + #include ++#include ++#include + + #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); ++} ++ diff --git a/librtas-03-lockdown-compatible-abi-phase.patch b/librtas-03-lockdown-compatible-abi-phase.patch new file mode 100644 index 0000000..7c18fcc --- /dev/null +++ b/librtas-03-lockdown-compatible-abi-phase.patch @@ -0,0 +1,324 @@ +commit ef255a3cb550db36c4ea4940a29ca01029e33c49 +Author: Haren Myneni +Date: Tue Apr 29 20:10:13 2025 -0700 + + 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 + Signed-off-by: Tyrel Datwyler + +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 ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 diff --git a/librtas-04-lockdown-compatible-abi-phase.patch b/librtas-04-lockdown-compatible-abi-phase.patch new file mode 100644 index 0000000..272441d --- /dev/null +++ b/librtas-04-lockdown-compatible-abi-phase.patch @@ -0,0 +1,63 @@ +commit 73c32586614f2476d97356928eaacba8a978a196 +Author: Haren Myneni +Date: Tue Apr 29 20:10:14 2025 -0700 + + 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 + Signed-off-by: Tyrel Datwyler + +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 ++#include ++#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_ */ diff --git a/librtas-05-lockdown-compatible-abi-phase.patch b/librtas-05-lockdown-compatible-abi-phase.patch new file mode 100644 index 0000000..855bdbf --- /dev/null +++ b/librtas-05-lockdown-compatible-abi-phase.patch @@ -0,0 +1,187 @@ +commit 1e254ede1c2268d2dbf03e2b602a04af2c8ad8c6 +Author: Haren Myneni +Date: Tue Apr 29 20:10:15 2025 -0700 + + 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 + Signed-off-by: Tyrel Datwyler + +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 + #include + #include ++#include ++#include ++#include + #include + #include + #include ++#include ++#include + + #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); ++} diff --git a/librtas-06-lockdown-compatible-abi-phase.patch b/librtas-06-lockdown-compatible-abi-phase.patch new file mode 100644 index 0000000..95f759c --- /dev/null +++ b/librtas-06-lockdown-compatible-abi-phase.patch @@ -0,0 +1,155 @@ +commit 259d52de329dca27ec6f0a8495c90183339bbfd1 +Author: Haren Myneni +Date: Tue Apr 29 20:10:16 2025 -0700 + + 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 + Signed-off-by: Tyrel Datwyler + +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); ++} diff --git a/librtas-07-lockdown-compatible-abi-phase.patch b/librtas-07-lockdown-compatible-abi-phase.patch new file mode 100644 index 0000000..453354b --- /dev/null +++ b/librtas-07-lockdown-compatible-abi-phase.patch @@ -0,0 +1,88 @@ +commit 5ce468a9219367ea3f1f9e2c87eb3431a6cba55f +Author: Haren Myneni +Date: Tue Apr 29 20:10:17 2025 -0700 + + 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 + Signed-off-by: Tyrel Datwyler + +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); ++} diff --git a/librtas-08-lockdown-compatible-abi-phase.patch b/librtas-08-lockdown-compatible-abi-phase.patch new file mode 100644 index 0000000..0efc8af --- /dev/null +++ b/librtas-08-lockdown-compatible-abi-phase.patch @@ -0,0 +1,182 @@ +commit dfdcb41449832bf8a10d0e21fc79435a87192712 +Author: Haren Myneni +Date: Tue Apr 29 20:10:18 2025 -0700 + + 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 + Signed-off-by: Tyrel Datwyler + +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 ++#include ++#include ++#include ++#include ++#include ++#include ++#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; +-} diff --git a/librtas-09-end-lockdown-compatible-abi-phase.patch b/librtas-09-end-lockdown-compatible-abi-phase.patch new file mode 100644 index 0000000..de78f8f --- /dev/null +++ b/librtas-09-end-lockdown-compatible-abi-phase.patch @@ -0,0 +1,247 @@ +commit cac1c292be56aa9aa89d96490801285c707005c7 +Author: Haren Myneni +Date: Tue Apr 29 20:10:19 2025 -0700 + + 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 + Signed-off-by: Tyrel Datwyler + +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 ++#include ++#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 + #include + #include ++#include ++#include + #include ++#include ++#include + #include ++#include ++#include + #include + #include + #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); ++} diff --git a/librtas-check-warning-null-pointer.patch b/librtas-check-warning-null-pointer.patch new file mode 100644 index 0000000..ea424f1 --- /dev/null +++ b/librtas-check-warning-null-pointer.patch @@ -0,0 +1,63 @@ +commit d871069621209a6acc0c2ff6eaaba88c8583d6b1 +Author: Tyrel Datwyler +Date: Fri Jun 20 16:46:29 2025 -0700 + + physical-attestation: check work_area_bytes for null prior to dereference + + CI static checker warns of possible NULL pointer dereference. + + librtas_src/physical-attestation.c:133:14: warning: Either the condition 'work_area_bytes' is redundant or there is possible null pointer dereference: work_area_bytes. [nullPointerRedundantCheck] + int size = *work_area_bytes; + ^ + librtas_src/physical-attestation.c:166:7: note: Assuming that condition 'work_area_bytes' is not redundant + if (work_area_bytes) + ^ + librtas_src/physical-attestation.c:133:14: note: Null pointer dereference + int size = *work_area_bytes; + ^ + librtas_src/physical-attestation.c:157:36: warning: Either the condition 'work_area_bytes' is redundant or there is possible null pointer dereference: work_area_bytes. [nullPointerRedundantCheck] + ssize_t res = read(fd, workarea, *work_area_bytes); + ^ + librtas_src/physical-attestation.c:166:7: note: Assuming that condition 'work_area_bytes' is not redundant + if (work_area_bytes) + ^ + librtas_src/physical-attestation.c:157:36: note: Null pointer dereference + ssize_t res = read(fd, workarea, *work_area_bytes); + + Fix by testing work_area_bytes prior to the first pointer dereference. + The later pointer checks are redundant and can be removed as size=0 will + result in RTAS_IO_ASSERT error being returned prior. + + Fixes: cac1c292be56a ("librtas: Use kernel interface when available for ibm,physical-attestation") + Signed-off-by: Tyrel Datwyler + +diff --git a/librtas_src/physical-attestation.c b/librtas_src/physical-attestation.c +index 48108a0..0d3975c 100644 +--- a/librtas_src/physical-attestation.c ++++ b/librtas_src/physical-attestation.c +@@ -130,7 +130,7 @@ static int + phy_attestation_kernel(char *workarea, int seq_num, int *next_seq_num, + int *work_area_bytes) + { +- int size = *work_area_bytes; ++ int size = (work_area_bytes) ? *work_area_bytes : 0; + int fd = (seq_num == 1) ? phy_attest_fd_new(workarea, size) + : (int)seq_num; + +@@ -163,14 +163,12 @@ phy_attestation_kernel(char *workarea, int seq_num, int *next_seq_num, + close(fd); + if (next_seq_num) + *next_seq_num = 1; +- if (work_area_bytes) +- *work_area_bytes = res; ++ *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; ++ *work_area_bytes = res; + } + + return rtas_status; diff --git a/librtas-format-mismatch-size_t.patch b/librtas-format-mismatch-size_t.patch new file mode 100644 index 0000000..0b00382 --- /dev/null +++ b/librtas-format-mismatch-size_t.patch @@ -0,0 +1,45 @@ +commit 828d2061f784a6bfc3ddfb05b1ec1b3a45603c46 +Author: Tyrel Datwyler +Date: Fri Jun 20 16:35:16 2025 -0700 + + librtas: fix format specifier mismatch for size_t in indices.c + + CI complains of several %lu format specifier mismatches to arguments of + size_t in indices.c. This is a result of size_t being either 4 bytes or + 8 bytes depending on if the packages is built on a 32bit or 64bit + architecture respectively. + + Fix this by using the printf size_t format specifier %zu instead. + + Fixes: 1e254ede1c226 ("librtas: Use /dev/papr-indices when available for ibm,get-indices") + Signed-off-by: Tyrel Datwyler + +diff --git a/librtas_src/indices.c b/librtas_src/indices.c +index 875c576..25a0b11 100644 +--- a/librtas_src/indices.c ++++ b/librtas_src/indices.c +@@ -172,7 +172,7 @@ static int get_indices_chardev(int is_sensor, int type, char *workarea, + ssize_t res; + + if (size != RTAS_GET_INDICES_BUF_SIZE) { +- dbg("Invalid buffer size %lu expects %d\n", ++ dbg("Invalid buffer size %zu expects %d\n", + size, RTAS_GET_INDICES_BUF_SIZE); + return -EINVAL; + } +@@ -260,13 +260,13 @@ static int dynamic_common_io_setup(unsigned long ioctalval, + length = be32toh(*(uint32_t *)loc_code); + + if (length < 1) { +- dbg("Invalid length(%lu) of location code string\n", length); ++ dbg("Invalid length(%zu) 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); ++ dbg("location code string length is not matched with the passed length(%zu)\n", length); + goto out; + } + diff --git a/librtas.spec b/librtas.spec index b3496de..5e6e293 100644 --- a/librtas.spec +++ b/librtas.spec @@ -1,12 +1,25 @@ Summary: Libraries to provide access to RTAS calls and RTAS events Name: librtas Version: 2.0.6 -Release: 3%{?dist} +Release: 4%{?dist} URL: https://github.com/ibm-power-utilities/librtas License: LGPL-2.0-or-later Source0: https://github.com/ibm-power-utilities/%{name}/archive/v%{version}/%{name}-%{version}.tar.gz +# upstream fixes for Lockdown-compatible ABI +Patch1: librtas-01-lockdown-compatible-abi-phase.patch +Patch2: librtas-02-lockdown-compatible-abi-phase.patch +Patch3: librtas-03-lockdown-compatible-abi-phase.patch +Patch4: librtas-04-lockdown-compatible-abi-phase.patch +Patch5: librtas-05-lockdown-compatible-abi-phase.patch +Patch6: librtas-06-lockdown-compatible-abi-phase.patch +Patch7: librtas-07-lockdown-compatible-abi-phase.patch +Patch8: librtas-08-lockdown-compatible-abi-phase.patch +Patch9: librtas-09-end-lockdown-compatible-abi-phase.patch +Patch10: librtas-check-warning-null-pointer.patch +Patch11: librtas-format-mismatch-size_t.patch + BuildRequires: autoconf BuildRequires: libtool BuildRequires: make @@ -64,6 +77,11 @@ rm -f %{buildroot}/%{_docdir}/librtas/* %{_includedir}/librtasevent_v6.h %changelog +* Tue Nov 11 2025 Than Ngo - 2.0.6-4 +- Use new lockdown-compatible ABI when available +- Add plan for CI test + Resolves: RHEL-101976 + * Tue Oct 29 2024 Troy Dawson - 2.0.6-3 - Bump release for October 2024 mass rebuild: Resolves: RHEL-64018