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); _______________________________________________ SeaBIOS mailing list SeaBIOS@seabios.org http://www.seabios.org/mailman/listinfo/seabios