From b841f263ee4264333fcb571fcc4f7769040df90b Mon Sep 17 00:00:00 2001
Message-Id: <b841f263ee4264333fcb571fcc4f7769040df90b.1387280747.git.minovotn@redhat.com>
In-Reply-To: <c2d55efd8a9a156fe14fd477924fadb765ac9438.1387280747.git.minovotn@redhat.com>
References: <c2d55efd8a9a156fe14fd477924fadb765ac9438.1387280747.git.minovotn@redhat.com>
From: "Michael S. Tsirkin" <mst@redhat.com>
Date: Wed, 11 Dec 2013 15:16:35 +0100
Subject: [PATCH 2/3] romfile_loader: utility to patch in-memory ROM files
RH-Author: Michael S. Tsirkin <mst@redhat.com>
Message-id: <1386774929-25693-3-git-send-email-mst@redhat.com>
Patchwork-id: 56225
O-Subject: [RHEL7.0 seabios PATCH 2/3] romfile_loader: utility to patch in-memory ROM files
Bugzilla: 1034877
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
RH-Acked-by: Gerd Hoffmann <kraxel@redhat.com>
RH-Acked-by: Marcel Apfelbaum <marcel.a@redhat.com>
Add ability for a ROM file to point to
it's image in memory. When file is in memory,
add utility that can patch it, storing
pointers to one file within another file.
This is not a lot of code: together with the follow-up patch to load
ACPI tables from ROM, it's about 1K extra.
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry-picked from commit 4a02768fbbd33e263122bf5deb54382de56c1cfe)
---
Makefile | 2 +-
src/romfile_loader.h | 72 +++++++++++++++++++++
src/romfile_loader.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 246 insertions(+), 1 deletion(-)
create mode 100644 src/romfile_loader.h
create mode 100644 src/romfile_loader.c
Signed-off-by: Michal Novotny <minovotn@redhat.com>
---
Makefile | 2 +-
src/romfile_loader.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++++++
src/romfile_loader.h | 72 +++++++++++++++++++++
3 files changed, 246 insertions(+), 1 deletion(-)
create mode 100644 src/romfile_loader.c
create mode 100644 src/romfile_loader.h
diff --git a/Makefile b/Makefile
index f28d86c..9125ea0 100644
--- a/Makefile
+++ b/Makefile
@@ -18,7 +18,7 @@ SRC16=$(SRCBOTH) system.c disk.c font.c
SRC32FLAT=$(SRCBOTH) post.c shadow.c memmap.c coreboot.c boot.c \
acpi.c smm.c mptable.c smbios.c pciinit.c optionroms.c mtrr.c \
lzmadecode.c bootsplash.c jpeg.c usb-hub.c paravirt.c \
- biostables.c xen.c bmp.c romfile.c
+ biostables.c xen.c bmp.c romfile.c romfile_loader.c
SRC32SEG=util.c output.c pci.c pcibios.c apm.c stacks.c
# Default compiler flags
diff --git a/src/romfile_loader.c b/src/romfile_loader.c
new file mode 100644
index 0000000..cae3cc3
--- /dev/null
+++ b/src/romfile_loader.c
@@ -0,0 +1,173 @@
+#include "romfile_loader.h"
+#include "byteorder.h" // leXX_to_cpu/cpu_to_leXX
+#include "util.h"
+
+struct romfile_loader_file {
+ struct romfile_s *file;
+ void *data;
+};
+struct romfile_loader_files {
+ int nfiles;
+ struct romfile_loader_file files[];
+};
+
+static struct romfile_loader_file *
+romfile_loader_find(const char *name,
+ struct romfile_loader_files *files)
+{
+ int i;
+ if (name[ROMFILE_LOADER_FILESZ - 1])
+ return NULL;
+ for (i = 0; i < files->nfiles; ++i)
+ if (!strcmp(files->files[i].file->name, name))
+ return &files->files[i];
+ return NULL;
+}
+
+static void romfile_loader_allocate(struct romfile_loader_entry_s *entry,
+ struct romfile_loader_files *files)
+{
+ struct zone_s *zone;
+ struct romfile_loader_file *file = &files->files[files->nfiles];
+ void *data;
+ int ret;
+ unsigned alloc_align = le32_to_cpu(entry->alloc_align);
+
+ if (alloc_align & (alloc_align - 1))
+ goto err;
+
+ switch (entry->alloc_zone) {
+ case ROMFILE_LOADER_ALLOC_ZONE_HIGH:
+ zone = &ZoneHigh;
+ break;
+ case ROMFILE_LOADER_ALLOC_ZONE_FSEG:
+ zone = &ZoneFSeg;
+ break;
+ default:
+ goto err;
+ }
+ if (alloc_align < MALLOC_MIN_ALIGN)
+ alloc_align = MALLOC_MIN_ALIGN;
+ if (entry->alloc_file[ROMFILE_LOADER_FILESZ - 1])
+ goto err;
+ file->file = romfile_find(entry->alloc_file);
+ if (!file->file || !file->file->size)
+ return;
+ data = pmm_malloc(zone, PMM_DEFAULT_HANDLE, file->file->size, alloc_align);
+ if (!data) {
+ warn_noalloc();
+ return;
+ }
+ ret = file->file->copy(file->file, data, file->file->size);
+ if (ret != file->file->size)
+ goto file_err;
+ file->data = data;
+ files->nfiles++;
+ return;
+
+file_err:
+ free(data);
+err:
+ warn_internalerror();
+}
+
+static void romfile_loader_add_pointer(struct romfile_loader_entry_s *entry,
+ struct romfile_loader_files *files)
+{
+ struct romfile_loader_file *dest_file;
+ struct romfile_loader_file *src_file;
+ unsigned offset = le32_to_cpu(entry->pointer_offset);
+ u64 pointer = 0;
+
+ dest_file = romfile_loader_find(entry->pointer_dest_file, files);
+ src_file = romfile_loader_find(entry->pointer_src_file, files);
+
+ if (!dest_file || !src_file || !dest_file->data || !src_file->data ||
+ offset + entry->pointer_size < offset ||
+ offset + entry->pointer_size > dest_file->file->size ||
+ entry->pointer_size < 1 || entry->pointer_size > 8 ||
+ entry->pointer_size & (entry->pointer_size - 1))
+ goto err;
+
+ memcpy(&pointer, dest_file->data + offset, entry->pointer_size);
+ pointer = le64_to_cpu(pointer);
+ pointer += (unsigned long)src_file->data;
+ pointer = cpu_to_le64(pointer);
+ memcpy(dest_file->data + offset, &pointer, entry->pointer_size);
+
+ return;
+err:
+ warn_internalerror();
+}
+
+static void romfile_loader_add_checksum(struct romfile_loader_entry_s *entry,
+ struct romfile_loader_files *files)
+{
+ struct romfile_loader_file *file;
+ unsigned offset = le32_to_cpu(entry->cksum_offset);
+ unsigned start = le32_to_cpu(entry->cksum_start);
+ unsigned len = le32_to_cpu(entry->cksum_length);
+ u8 *data;
+
+ file = romfile_loader_find(entry->cksum_file, files);
+
+ if (!file || !file->data || offset >= file->file->size ||
+ start + len < start || start + len > file->file->size)
+ goto err;
+
+ data = file->data + offset;
+ *data -= checksum(file->data + start, len);
+
+ return;
+err:
+ warn_internalerror();
+}
+
+int romfile_loader_execute(const char *name)
+{
+ struct romfile_loader_entry_s *entry;
+ int size, offset = 0, nfiles;
+ struct romfile_loader_files *files;
+ void *data = romfile_loadfile(name, &size);
+ if (!data)
+ return -1;
+
+ if (size % sizeof(*entry)) {
+ warn_internalerror();
+ goto err;
+ }
+
+ /* (over)estimate the number of files to load. */
+ nfiles = size / sizeof(*entry);
+ files = malloc_tmp(sizeof(*files) + nfiles * sizeof(files->files[0]));
+ if (!files) {
+ warn_noalloc();
+ goto err;
+ }
+ files->nfiles = 0;
+
+ for (offset = 0; offset < size; offset += sizeof(*entry)) {
+ entry = data + offset;
+ switch (le32_to_cpu(entry->command)) {
+ case ROMFILE_LOADER_COMMAND_ALLOCATE:
+ romfile_loader_allocate(entry, files);
+ break;
+ case ROMFILE_LOADER_COMMAND_ADD_POINTER:
+ romfile_loader_add_pointer(entry, files);
+ break;
+ case ROMFILE_LOADER_COMMAND_ADD_CHECKSUM:
+ romfile_loader_add_checksum(entry, files);
+ default:
+ /* Skip commands that we don't recognize. */
+ break;
+ }
+ }
+
+ free(files);
+ free(data);
+ return 0;
+
+err:
+ free(data);
+ return -1;
+}
diff --git a/src/romfile_loader.h b/src/romfile_loader.h
new file mode 100644
index 0000000..15eab2a
--- /dev/null
+++ b/src/romfile_loader.h
@@ -0,0 +1,72 @@
+#ifndef __ROMFILE_LOADER_H
+#define __ROMFILE_LOADER_H
+
+#include "types.h" // u8
+#include "util.h" // romfile_s
+
+#define ROMFILE_LOADER_FILESZ 56
+
+/* ROM file linker/loader interface. Linker uses little endian format */
+struct romfile_loader_entry_s {
+ u32 command;
+ union {
+ /*
+ * COMMAND_ALLOCATE - allocate a table from @alloc_file
+ * subject to @alloc_align alignment (must be power of 2)
+ * and @alloc_zone (can be HIGH or FSEG) requirements.
+ *
+ * Must appear exactly once for each file, and before
+ * this file is referenced by any other command.
+ */
+ struct {
+ char alloc_file[ROMFILE_LOADER_FILESZ];
+ u32 alloc_align;
+ u8 alloc_zone;
+ };
+
+ /*
+ * COMMAND_ADD_POINTER - patch the table (originating from
+ * @dest_file) at @pointer_offset, by adding a pointer to the table
+ * originating from @src_file. 1,2,4 or 8 byte unsigned
+ * addition is used depending on @pointer_size.
+ */
+ struct {
+ char pointer_dest_file[ROMFILE_LOADER_FILESZ];
+ char pointer_src_file[ROMFILE_LOADER_FILESZ];
+ u32 pointer_offset;
+ u8 pointer_size;
+ };
+
+ /*
+ * COMMAND_ADD_CHECKSUM - calculate checksum of the range specified by
+ * @cksum_start and @cksum_length fields,
+ * and then add the value at @cksum_offset.
+ * Checksum simply sums -X for each byte X in the range
+ * using 8-bit math.
+ */
+ struct {
+ char cksum_file[ROMFILE_LOADER_FILESZ];
+ u32 cksum_offset;
+ u32 cksum_start;
+ u32 cksum_length;
+ };
+
+ /* padding */
+ char pad[124];
+ };
+};
+
+enum {
+ ROMFILE_LOADER_COMMAND_ALLOCATE = 0x1,
+ ROMFILE_LOADER_COMMAND_ADD_POINTER = 0x2,
+ ROMFILE_LOADER_COMMAND_ADD_CHECKSUM = 0x3,
+};
+
+enum {
+ ROMFILE_LOADER_ALLOC_ZONE_HIGH = 0x1,
+ ROMFILE_LOADER_ALLOC_ZONE_FSEG = 0x2,
+};
+
+int romfile_loader_execute(const char *name);
+
+#endif
--
1.7.11.7