[SeaBIOS] [PATCH 2/2] accept MADT over fw_cfg

Michael S. Tsirkin mst at redhat.com
Tue Apr 23 17:22:12 CEST 2013


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);



More information about the SeaBIOS mailing list