On Mon, Apr 22, 2013 at 08:42:18PM -0400, Kevin O'Connor wrote:
On Mon, Apr 22, 2013 at 08:23:39PM +0300, Michael S. Tsirkin wrote:
@@ -0,0 +1,28 @@ +#include "types.h" // u8 +#include "util.h" // romfile_s
+/* ROM file linker interface. Linker uses little endian format */ +struct linker_entry_s {
- u8 size; /* size in bytes including the header */
- u8 bytes; /* How many bytes to change. Can be 1,2,4 or 8. */
- u8 type;
- u8 format;
- u32 reserved;
- u64 src_offset; /* Offset in source. Little endian format. */
src_offset is not needed: host can pre-fill destination table with the offset value. Will probably drop it.
- u64 dst_offset; /* Offset in destination. Little endian format. */
- /* Followed by source and destination
Add "file names"
, optionally padded by
* 0, up to the total of entry_len - 4 bytes.
* Strings are 0-terminated. */
- char src_dst[];
+} PACKED;
+enum linker_entry_type {
Documentation:
ADD: increment value in DST by the address of SRC useful e.g. to fill in pointer values in ACPI tables SUB: decrement value in DST by the address of SRC useful e.g. to fix up checksum values in ACPI tables
I don't see how one could implement a checksum with just a subtraction. If the table is at 0x12345678 the checksum isn't (oldcksum-0x12345678), it's (oldcksum-0x12-0x34-0x56-0x78).
-Kevin
So here's the version with shift, that should do it correctly. Add mere 8 lines of code. I'll look into alignment and fseg now.
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..a1f473d --- /dev/null +++ b/src/linker.c @@ -0,0 +1,79 @@ +#include "linker.h" +#include "byteorder.h" // le64_to_cpu + +void linker_link(const char *name) +{ + struct linker_entry_s *entry; + int offset = 0; + int size, lsrc; + void *data = romfile_loadfile(name, &size); + struct romfile_s *src, *dst; + u32 dst_offset; + u64 val, buf; + if (!data) + return; + + for (offset = 0; offset < size; offset += entry->size) { + entry = data + offset; + /* Entry must have some data. If not - skip it. */ + if (entry->size <= sizeof *entry) + continue; + /* Check that entry fits in buffer. */ + if (offset + entry->size > size) { + warn_internalerror(); + break; + } + /* Skip any command that we don't recognize. */ + if (entry->reserved1 || entry->reserved2) + continue; + if (entry->bytes != 1 && + entry->bytes != 2 && + entry->bytes != 4 && + entry->bytes != 8) + continue; + if (entry->shift > 63) + continue; + if (entry->type != LINKER_ENTRY_TYPE_ADD && + entry->type != LINKER_ENTRY_TYPE_SUB) + continue; + if (entry->format != LINKER_ENTRY_FORMAT_LE) + continue; + /* Last byte must be 0 */ + if (entry->src_dst[entry->size - 1]) { + warn_internalerror(); + continue; + } + lsrc = strlen(entry->src_dst); + if (!lsrc || lsrc + 1 + sizeof *entry >= entry->size) { + warn_internalerror(); + continue; + } + src = romfile_find(entry->src_dst); + dst = romfile_find(entry->src_dst + lsrc + 1); + if (!src || !dst) { + warn_internalerror(); + continue; + } + if (!src->data || !dst->data) { + warn_internalerror(); + continue; + } + dst_offset = le32_to_cpu(entry->dst_offset); + if (dst->size < dst_offset + entry->bytes) { + warn_internalerror(); + continue; + } + buf = 0; + memcpy(&buf, dst->data + dst_offset, entry->bytes); + val = ((u64)(unsigned long)src->data) >> entry->shift; + buf = le64_to_cpu(buf); + if (entry->type == LINKER_ENTRY_TYPE_ADD) + buf += val; + else + buf -= val; + buf = cpu_to_le64(val); + memcpy(dst->data + dst_offset, &buf, entry->bytes); + } + + free(data); +} diff --git a/src/linker.h b/src/linker.h new file mode 100644 index 0000000..2bb376d --- /dev/null +++ b/src/linker.h @@ -0,0 +1,29 @@ +#include "types.h" // u8 +#include "util.h" // romfile_s + +/* ROM file linker interface. Linker uses little endian format */ +struct linker_entry_s { + u8 size; /* size in bytes including the header */ + u8 bytes; /* How many bytes to change. Can be 1,2,4 or 8. */ + u8 shift; /* Shift source address right by this many bits. 0-63. */ + u8 type; + u8 format; + u8 reserved1; + u16 reserved2; + u64 dst_offset; /* Offset in destination. Little endian format. */ + /* Followed by source and destination, optionally padded by + * 0, up to the total of entry_len - 4 bytes. + * Strings are 0-terminated. */ + char src_dst[]; +} PACKED; + +enum linker_entry_type { + LINKER_ENTRY_TYPE_ADD = 0x0, + LINKER_ENTRY_TYPE_SUB = 0x1, +}; + +enum linker_entry_format { + LINKER_ENTRY_FORMAT_LE = 0x0, +}; + +void linker_link(const char *name); 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);