shithub: riscv

Download patch

ref: f0c9bb979fd6d8481462aed68828094e202916cd
parent: a5488ad1e64e34f8a2f2e604ca5bcd2a0b750f67
author: cinap_lenrek <cinap_lenrek@gmx.de>
date: Fri Jun 7 14:03:44 EDT 2013

archacpi: handle multiple SSDT tables

we cannot assume theres only one instance of an acpi table. some
bios have multiple SSDT tables and we would only find the first
one.

now, we keep a second array to record the physical address of
the table visited by maptable(). load all instances to the
SSDT.

--- a/sys/src/9/pc/archacpi.c
+++ b/sys/src/9/pc/archacpi.c
@@ -38,9 +38,15 @@
 };
 
 static Rsd *rsd;
-static int ntbltab;
-static Tbl *tbltab[64];
 
+/* physical addresses visited by maptable() */
+static int ntblpa;
+static uintptr tblpa[64];
+
+/* successfully mapped tables */
+static int ntblmap;
+static Tbl *tblmap[64];
+
 void*
 amlalloc(int n){
 	void *p;
@@ -79,16 +85,6 @@
 	return get32(t->len) - sizeof(Tbl);
 }
 
-
-static Tbl*
-findtable(void *sig){
-	int i;
-	for(i=0; i<ntbltab; i++)
-		if(memcmp(tbltab[i]->sig, sig, 4) == 0)
-			return tbltab[i];
-	return nil;
-}
-
 static void
 maptable(uvlong xpa)
 {
@@ -96,16 +92,24 @@
 	uintptr pa;
 	u32int l;
 	Tbl *t;
+	int i;
 
 	pa = xpa;
 	if((uvlong)pa != xpa || pa == 0)
 		return;
-	if(ntbltab >= nelem(tbltab))
+	if(ntblpa >= nelem(tblpa) || ntblmap >= nelem(tblmap))
 		return;
+
+	for(i=0; i<ntblpa; i++){
+		if(pa == tblpa[i])
+			return;
+	}
+	tblpa[ntblpa++] = pa;
+
 	if((t = vmap(pa, 8)) == nil)
 		return;
 	l = get32(t->len);
-	if(l < sizeof(Tbl) || findtable(t->sig)){
+	if(l < sizeof(Tbl)){
 		vunmap(t, 8);
 		return;
 	}
@@ -116,9 +120,8 @@
 		vunmap(t, l);
 		return;
 	}
+	tblmap[ntblmap++] = t;
 
-	tbltab[ntbltab++] = t;
-
 	p = (uchar*)t;
 	e = p + l;
 	if(memcmp("RSDT", t->sig, 4) == 0){
@@ -145,7 +148,7 @@
 static void
 maptables(void)
 {
-	if(rsd == nil || ntbltab > 0)
+	if(rsd == nil || ntblmap > 0 || ntblpa > 0)
 		return;
 	if(!checksum(rsd, 20))
 		maptable(get32(rsd->raddr));
@@ -340,17 +343,34 @@
 
 	amlinit();
 
-	if(t = findtable("DSDT"))
-		amlload(t->data, tbldlen(t));
-	if(t = findtable("SSDT"))
-		amlload(t->data, tbldlen(t));
+	/* load DSDT */
+	for(i=0; i<ntblmap; i++){
+		t = tblmap[i];
+		if(memcmp(t->sig, "DSDT", 4) == 0){
+			amlload(t->data, tbldlen(t));
+			break;
+		}
+	}
 
+	/* load SSDT, there can be multiple tables */
+	for(i=0; i<ntblmap; i++){
+		t = tblmap[i];
+		if(memcmp(t->sig, "SSDT", 4) == 0)
+			amlload(t->data, tbldlen(t));
+	}
+
 	/* set APIC mode */
 	amleval(amlwalk(amlroot, "_PIC"), "i", 1, nil);
 
-	if((t = findtable("APIC")) == nil)
-		panic("acpiinit: no MADT table");
+	for(i=0; i<ntblmap; i++){
+		t = tblmap[i];
+		if(memcmp(t->sig, "APIC", 4) == 0)
+			goto Foundapic;
+	}
+	panic("acpiinit: no MADT (APIC) table");
+	return;
 
+Foundapic:
 	p = t->data;
 	e = p + tbldlen(t);
 	lapicbase = get32(p); p += 8;
@@ -461,8 +481,8 @@
 	maptables();
 
 	p = v;
-	for(i=0; n > 0 && i < ntbltab; i++){
-		t = tbltab[i];
+	for(i=0; n > 0 && i < ntblmap; i++){
+		t = tblmap[i];
 		l = get32(t->len);
 		if(o >= l){
 			o -= l;
--