diff mbox series

[v2,2/4] discover: Add helper functions to read ELF notes

Message ID 20190923223024.995-3-maxiwell@linux.ibm.com
State Under Review
Headers show
Series Check if the kernel image has Ultravisor support | expand

Commit Message

Maxiwell S. Garcia Sept. 23, 2019, 10:30 p.m. UTC
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
diff mbox series

Patch

diff --git a/discover/Makefile.am b/discover/Makefile.am
index e2d0e93..2339203 100644
--- a/discover/Makefile.am
+++ b/discover/Makefile.am
@@ -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
diff --git a/discover/elf.c b/discover/elf.c
new file mode 100644
index 0000000..8c2711e
--- /dev/null
+++ b/discover/elf.c
@@ -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;
+}
+
diff --git a/discover/elf.h b/discover/elf.h
new file mode 100644
index 0000000..742b791
--- /dev/null
+++ b/discover/elf.h
@@ -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 */