@@ -80,7 +80,9 @@ discover_platform_ro_SOURCES = \
discover/ipmi.h \
discover/dt.c \
discover/dt.h \
- discover/hostboot.h
+ discover/hostboot.h \
+ discover/elf.c \
+ discover/elf.h
if PLATFORM_ARM64
discover_platform_ro_SOURCES += discover/platform-arm64.c
new file mode 100644
@@ -0,0 +1,86 @@
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include <log/log.h>
+#include "elf.h"
+
+Elf *elf_open_image(const char *image)
+{
+ int fd;
+ Elf *elf = NULL;
+ int err;
+
+ if (!image) {
+ pb_log_fn("kernel image path is null\n");
+ return NULL;
+ }
+
+ if ((elf_version(EV_CURRENT) == EV_NONE) ||
+ ((fd = open(image, O_RDONLY, 0)) == -1) ||
+ (!(elf = elf_begin(fd, ELF_C_READ, NULL)))) {
+ err = elf_errno();
+ if (err)
+ pb_log_fn("failed to read %s elf: %s\n",
+ image, elf_errmsg(err));
+ }
+
+ return elf;
+}
+
+static bool elf_getnote_offset(Elf_Data * const edata,
+ const char *namespace,
+ const uint32_t type, GElf_Nhdr *nhdr,
+ size_t *n_off, size_t *d_off)
+{
+ size_t off = 0;
+ size_t next;
+
+ /* Iterate through notes */
+ while ((next = gelf_getnote(edata, off, nhdr, n_off, d_off)) > 0) {
+ char *note_ns = (char *) edata->d_buf + (*n_off);
+ if ((strcmp(note_ns, namespace) == 0) && (nhdr->n_type == type))
+ return true;
+
+ off = next;
+ }
+ return false;
+}
+
+void *elf_getnote_desc(Elf *elf,
+ const char *namespace,
+ uint32_t type)
+{
+ Elf_Scn *scn = NULL;
+ Elf_Data *edata = NULL;
+ GElf_Shdr shdr;
+ GElf_Nhdr nhdr;
+
+ size_t n_off;
+ size_t d_off;
+ void *desc = NULL;
+
+ if (!elf || !namespace)
+ return NULL;
+
+ /* Iterate through sections */
+ while ((scn = elf_nextscn(elf, scn))) {
+ gelf_getshdr(scn, &shdr);
+
+ /* ELF might have more than one SHT_NOTE section but
+ only one has the 'namespace' note */
+ if (shdr.sh_type == SHT_NOTE) {
+ edata = elf_getdata(scn, NULL);
+ if (elf_getnote_offset(edata, namespace, type,
+ &nhdr, &n_off, &d_off)) {
+ desc = calloc(nhdr.n_descsz, sizeof(char));
+ memcpy(desc, edata->d_buf + d_off,
+ nhdr.n_descsz);
+ break;
+ }
+ }
+ }
+
+ return desc;
+}
+
new file mode 100644
@@ -0,0 +1,29 @@
+#ifndef _PB_ELF_H
+#define _PB_ELF_H
+
+#include <elfutils/libdw.h>
+#include <libelf.h>
+
+/*
+ * The PowerPC namespace in an ELF Note of the kernel binary is used to store
+ * capabilities and information which can be used by a bootloader or userland
+ *
+ * docs: Documentation/powerpc/elfnote.rst
+ */
+#define POWERPC_ELFNOTE_NAMESPACE "PowerPC"
+
+/*
+ * The capabilities supported/required by the kernel
+ * This type uses a bitmap as "desc" field.
+ */
+#define PPC_ELFNOTE_CAPABILITIES 0x1
+
+/* bitmap fields: */
+#define PPCCAP_ULTRAVISOR_BIT 0x1
+
+Elf *elf_open_image(const char *image);
+void *elf_getnote_desc(Elf *elf,
+ const char *namespace,
+ uint32_t type);
+
+#endif /* _PB_ELF_H */
The libelf has low level functions to access the ELF structures. This commit adds two external higher level functions: elf_open_image(): - Get the ELF structure from a binary; elf_getnote_desc() - Get the ELF note 'descriptor' using both namespace and ELF type. The definitions used in the 'elf.h' was taken from linux source code: - arch/powerpc/include/asm/elfnote.h - arch/powerpc/kernel/note.S Signed-off-by: Maxiwell S. Garcia <maxiwell@linux.ibm.com> --- discover/Makefile.am | 4 ++- discover/elf.c | 86 ++++++++++++++++++++++++++++++++++++++++++++ discover/elf.h | 29 +++++++++++++++ 3 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 discover/elf.c create mode 100644 discover/elf.h