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

Michael S. Tsirkin mst at redhat.com
Tue Apr 23 19:23:44 CEST 2013


On Mon, Apr 22, 2013 at 08:38:58PM -0400, Kevin O'Connor wrote:
> On Mon, Apr 22, 2013 at 10:03:01AM +0300, Michael S. Tsirkin wrote:
> > On Sun, Apr 21, 2013 at 08:39:41PM -0400, Kevin O'Connor wrote:
> > > On Sun, Apr 21, 2013 at 11:41:48PM +0300, Michael S. Tsirkin wrote:
> > > > Okay I'm pretty close to posting some patches
> > > > that advance this project further, but wanted to
> > > > check something beforehand: there are several tables
> > > > that point to other tables (for example: FADT points
> > > > to DSDT). What I did is provide a list of fixups
> > > > such that bios can patch in pointers without
> > > > any need to understand what's what.
> > > > Thoughts?
> > > 
> > > For the RSDP, RSDT, and FADT I think SeaBIOS should just update those
> > > tables to set the pointers within them and then recalculate the
> > > checksum.  I don't think anything complex is needed - it's easy for
> > > SeaBIOS to recognize those special tables and modify them.
> > 
> > True, that's simple enough.  My worry is we can add more such tables.
> > For example, we can decide to switch to XSDT in the future.
> 
> I know of the following quirks that would have to be handled:
> 
> 1 - the RSDP must be in the f-segment (where as all other tables can
> go into "high" memory).
> 
> 2 - the RSDP has a checksum in a different location from the other
> tables and (with an XSDT) it can have two checksums.
> 
> 3 - the RSDP has a pointer to the RSDT (and to the XSDT if present).
> 
> 4 - the RSDT (and XSDT if present) has pointers to all the other
> tables (except RSDP, RSDT, DSDT, and FACS).  The FADT pointer must be
> first in the list.
> 
> 5 - the FADT table has pointers to DSDT and FACS.
> 
> 6 - the FACS table must be 64 byte aligned.
> 
> So, will a generic scheme really be able to handle all of the above
> quirks, or will we just be mixing some hardcoded quirks with some
> generic quirks?  And, will the code to handle the above quirks in a
> generic fashion be of a higher complexity than simply hard-coding it?
> 
> -Kevin

-->

So here's an implementation for align and FSEG.
Not a big deal as you see.

I really have doubts about it however: BIOS still must be able to parse
get the resume vector in FACS in order to support wakeup, right? So this
means that we need to be able to parse RSDP and FACT.  These happen to
be the only things that need anything not addressed by ADD and SUB so
... maybe a couple of hardcoded quirks just to allocate these correctly
is cleaner.

Signed-off-by: Michael S. Tsirkin <mst at redhat.com>

---

diff --git a/src/linker.c b/src/linker.c
index a1f473d..22a0dff 100644
--- a/src/linker.c
+++ b/src/linker.c
@@ -34,7 +34,9 @@ void linker_link(const char *name)
 	if (entry->shift > 63)
             continue;
         if (entry->type != LINKER_ENTRY_TYPE_ADD &&
-            entry->type != LINKER_ENTRY_TYPE_SUB)
+            entry->type != LINKER_ENTRY_TYPE_SUB &&
+            entry->type != LINKER_ENTRY_TYPE_ALIGN &&
+            entry->type != LINKER_ENTRY_TYPE_FSEG)
             continue;
         if (entry->format != LINKER_ENTRY_FORMAT_LE)
             continue;
@@ -44,17 +46,55 @@ void linker_link(const char *name)
             continue;
         }
         lsrc = strlen(entry->src_dst);
-        if (!lsrc || lsrc + 1 +  sizeof *entry >= entry->size) {
+        if (!lsrc) {
             warn_internalerror();
             continue;
         }
         src = romfile_find(entry->src_dst);
+        if (!src) {
+            warn_internalerror();
+            continue;
+        }
+        if (!src->data) {
+            warn_internalerror();
+            continue;
+        }
+	if (entry->type == LINKER_ENTRY_TYPE_ALIGN ||
+	    entry->type == LINKER_ENTRY_TYPE_FSEG) {
+		void *data;
+		u32 align;
+		struct zone_s *zone;
+
+		if (entry->shift > 31) {
+			warn_internalerror();
+			continue;
+		}
+		align = 0x1 << entry->shift;
+		if (align < MALLOC_MIN_ALIGN)
+			align = MALLOC_MIN_ALIGN;
+		zone = entry->type == LINKER_ENTRY_TYPE_FSEG ?
+			&ZoneFSeg : &ZoneHigh;
+		data = pmm_malloc(zone, PMM_DEFAULT_HANDLE, src->size, align);
+		if (!data) {
+			warn_internalerror();
+			continue;
+		}
+		memcpy(data, src->data, src->size);
+		free(src->data);
+		src->data = data;
+		continue;
+	}
+
+        if (lsrc + 1 +  sizeof *entry >= entry->size) {
+            warn_internalerror();
+            continue;
+        }
         dst = romfile_find(entry->src_dst + lsrc + 1);
-        if (!src || !dst) {
+        if (!dst) {
             warn_internalerror();
             continue;
         }
-        if (!src->data || !dst->data) {
+        if (!dst->data) {
             warn_internalerror();
             continue;
         }
diff --git a/src/linker.h b/src/linker.h
index 2bb376d..b0cc536 100644
--- a/src/linker.h
+++ b/src/linker.h
@@ -17,9 +17,12 @@ struct linker_entry_s {
     char src_dst[];
 } PACKED;
 
+/* Note: align types must appear before all other types. */
 enum linker_entry_type {
     LINKER_ENTRY_TYPE_ADD = 0x0,
     LINKER_ENTRY_TYPE_SUB = 0x1,
+    LINKER_ENTRY_TYPE_ALIGN = 0x2, /* Align source to shift bits. Must come first. */
+    LINKER_ENTRY_TYPE_FSEG  = 0x3, /* Align source to shift bits in FSEG memory. */
 };
 
 enum linker_entry_format {



More information about the SeaBIOS mailing list