From: "Michael S. Tsirkin" <mst@redhat.com>
To: seabios@seabios.org
Cc: qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH v2 1/5] linker: utility to patch in-memory ROM files
Date: Sun, 7 Jul 2013 18:42:35 +0300 [thread overview]
Message-ID: <1373211589-8097-2-git-send-email-mst@redhat.com> (raw)
In-Reply-To: <1373211589-8097-1-git-send-email-mst@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, we get:
Before:
Total size: 127880 Fixed: 59060 Free: 3192 (used 97.6% of 128KiB rom)
After:
Total size: 128776 Fixed: 59100 Free: 2296 (used 98.2% of 128KiB rom)
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
Makefile | 2 +-
src/linker.c | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/linker.h | 72 +++++++++++++++++++++++++++++++
src/paravirt.c | 2 +
src/util.h | 1 +
5 files changed, 208 insertions(+), 1 deletion(-)
create mode 100644 src/linker.c
create mode 100644 src/linker.h
diff --git a/Makefile b/Makefile
index 759bbbb..020fb2f 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 pmm.c coreboot.c boot.c \
acpi.c smm.c mptable.c pirtable.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 csm.c
+ biostables.c xen.c bmp.c romfile.c csm.c linker.c
SRC32SEG=util.c output.c pci.c pcibios.c apm.c stacks.c
# Default compiler flags
diff --git a/src/linker.c b/src/linker.c
new file mode 100644
index 0000000..3caa97b
--- /dev/null
+++ b/src/linker.c
@@ -0,0 +1,132 @@
+#include "linker.h"
+#include "byteorder.h" // leXX_to_cpu/cpu_to_leXX
+#include "util.h" // checksum
+
+static struct romfile_s *linker_loader_find(const char *name)
+{
+ if (name[LINKER_LOADER_FILESZ - 1])
+ return NULL;
+ return romfile_find(name);
+}
+
+static void linker_loader_allocate(struct linker_loader_entry_s *entry)
+{
+ struct zone_s *zone;
+ struct romfile_s *file;
+ 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 LINKER_LOADER_ALLOC_ZONE_HIGH:
+ zone = &ZoneHigh;
+ break;
+ case LINKER_LOADER_ALLOC_ZONE_FSEG:
+ zone = &ZoneFSeg;
+ break;
+ default:
+ goto err;
+ }
+ if (alloc_align < MALLOC_MIN_ALIGN)
+ alloc_align = MALLOC_MIN_ALIGN;
+ file = linker_loader_find(entry->alloc_file);
+ if (!file || file->data)
+ goto err;
+ if (!file->size)
+ return;
+ data = pmm_malloc(zone, PMM_DEFAULT_HANDLE, file->size, alloc_align);
+ if (!data) {
+ warn_noalloc();
+ return;
+ }
+ ret = file->copy(file, data, file->size);
+ if (ret != file->size)
+ goto file_err;
+ file->data = data;
+ return;
+
+file_err:
+ free(data);
+err:
+ warn_internalerror();
+}
+
+static void linker_loader_add_pointer(struct linker_loader_entry_s *entry)
+{
+ struct romfile_s *dest_file = linker_loader_find(entry->pointer_dest_file);
+ struct romfile_s *src_file = linker_loader_find(entry->pointer_src_file);
+ unsigned offset = le32_to_cpu(entry->pointer_offset);
+ u64 pointer = 0;
+
+ if (!dest_file || !src_file || !dest_file->data || !src_file->data ||
+ offset + entry->pointer_size < offset ||
+ offset + entry->pointer_size > dest_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 linker_loader_add_checksum(struct linker_loader_entry_s *entry)
+{
+ struct romfile_s *file = linker_loader_find(entry->cksum_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;
+ if (!file || !file->data || offset >= file->size ||
+ start + len < start || start + len > file->size)
+ goto err;
+
+ data = file->data + offset;
+ *data -= checksum(file->data + start, len);
+
+ return;
+err:
+ warn_internalerror();
+}
+
+void linker_loader_execute(const char *name)
+{
+ struct linker_loader_entry_s *entry;
+ int size, offset = 0;
+ void *data = romfile_loadfile(name, &size);
+ if (!data)
+ return;
+
+ for (offset = 0; offset < size; offset += sizeof *entry) {
+ entry = data + offset;
+ /* Check that entry fits in buffer. */
+ if (offset + sizeof *entry > size) {
+ warn_internalerror();
+ break;
+ }
+ switch (le32_to_cpu(entry->command)) {
+ case LINKER_LOADER_COMMAND_ALLOCATE:
+ linker_loader_allocate(entry);
+ break;
+ case LINKER_LOADER_COMMAND_ADD_POINTER:
+ linker_loader_add_pointer(entry);
+ break;
+ case LINKER_LOADER_COMMAND_ADD_CHECKSUM:
+ linker_loader_add_checksum(entry);
+ default:
+ /* Skip commands that we don't recognize. */
+ break;
+ }
+ }
+
+ free(data);
+}
diff --git a/src/linker.h b/src/linker.h
new file mode 100644
index 0000000..0c374e5
--- /dev/null
+++ b/src/linker.h
@@ -0,0 +1,72 @@
+#ifndef __LINKER_H
+#define __LINKER_H
+
+#include "types.h" // u8
+#include "util.h" // romfile_s
+
+#define LINKER_LOADER_FILESZ 56
+
+/* ROM file linker/loader interface. Linker uses little endian format */
+struct linker_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[LINKER_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[LINKER_LOADER_FILESZ];
+ char pointer_src_file[LINKER_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[LINKER_LOADER_FILESZ];
+ u32 cksum_offset;
+ u32 cksum_start;
+ u32 cksum_length;
+ };
+
+ /* padding */
+ char pad[124];
+ };
+};
+
+enum {
+ LINKER_LOADER_COMMAND_ALLOCATE = 0x1,
+ LINKER_LOADER_COMMAND_ADD_POINTER = 0x2,
+ LINKER_LOADER_COMMAND_ADD_CHECKSUM = 0x3,
+};
+
+enum {
+ LINKER_LOADER_ALLOC_ZONE_HIGH = 0x1,
+ LINKER_LOADER_ALLOC_ZONE_FSEG = 0x2,
+};
+
+void linker_loader_execute(const char *name);
+
+#endif
diff --git a/src/paravirt.c b/src/paravirt.c
index d1a5d3e..9dd229d 100644
--- a/src/paravirt.c
+++ b/src/paravirt.c
@@ -327,6 +327,8 @@ void qemu_cfg_init(void)
for (e = 0; e < count; e++) {
struct QemuCfgFile qfile;
qemu_cfg_read(&qfile, sizeof(qfile));
+ if (!*qfile.name)
+ return;
qemu_romfile_add(qfile.name, be16_to_cpu(qfile.select)
, 0, be32_to_cpu(qfile.size));
}
diff --git a/src/util.h b/src/util.h
index 996c29a..7b50c38 100644
--- a/src/util.h
+++ b/src/util.h
@@ -436,6 +436,7 @@ struct romfile_s {
char name[128];
u32 size;
int (*copy)(struct romfile_s *file, void *dest, u32 maxlen);
+ void *data;
};
void romfile_add(struct romfile_s *file);
struct romfile_s *romfile_findprefix(const char *prefix, struct romfile_s *prev);
--
MST
next prev parent reply other threads:[~2013-07-07 15:41 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-07-07 15:42 [Qemu-devel] [PATCH v2 0/5] seabios: load acpi tables from qemu Michael S. Tsirkin
2013-07-07 15:42 ` Michael S. Tsirkin [this message]
2013-07-14 18:24 ` [Qemu-devel] [SeaBIOS] [PATCH v2 1/5] linker: utility to patch in-memory ROM files Kevin O'Connor
2013-07-15 8:01 ` Michael S. Tsirkin
2013-07-25 12:55 ` Michael S. Tsirkin
2013-07-26 0:06 ` Kevin O'Connor
2013-09-22 10:49 ` Michael S. Tsirkin
2013-09-22 11:18 ` Michael S. Tsirkin
2013-09-22 13:44 ` Michael S. Tsirkin
2013-07-07 15:42 ` [Qemu-devel] [PATCH v2 2/5] pmm: add a way to test whether memory is in FSEG Michael S. Tsirkin
2013-07-07 15:42 ` [Qemu-devel] [PATCH v2 3/5] acpi: pack rsdp Michael S. Tsirkin
2013-07-07 15:42 ` [Qemu-devel] [PATCH v2 4/5] acpi: load and link tables from /etc/acpi/ Michael S. Tsirkin
2013-07-14 18:27 ` [Qemu-devel] [SeaBIOS] " Kevin O'Connor
2013-07-15 8:11 ` Michael S. Tsirkin
2013-07-15 9:58 ` Michael S. Tsirkin
2013-07-07 15:42 ` [Qemu-devel] [PATCH v2 5/5] acpi: add an option to disable builtin tables Michael S. Tsirkin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1373211589-8097-2-git-send-email-mst@redhat.com \
--to=mst@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=seabios@seabios.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).