Browse Source

ACPI: Final changes for making VMWare fusion work

They used some new tables that don't follow the basic ACPI standard, i.e. don't have
a length field. Further, ACPICA assumes that a map operation is a page size, and
hence when it asks you to map something for 0x200 bytes, it appears to assume that
the page is mapped, and it need not ask you again to map the remaining parts of the page,
so we need to accomodate that asssumption, even though in Harvey the AcpiOsMapMemory
function is a read operation on #P/acpimem. So it goes.

As a final bonus, you get SMP back. It's been off for a little while.

Signed-off-by: Ronald G. Minnich <rminnich@gmail.com>
Ronald G. Minnich 7 years ago
parent
commit
82beed2b8b

+ 1 - 0
sys/src/9/amd64/build.json

@@ -94,6 +94,7 @@
 				"fossil": "/$ARCH/bin/fossil/fossil",
 				"grep": "/$ARCH/bin/grep",
 				"ipconfig": "/$ARCH/bin/ip/ipconfig",
+				"crs": "/$ARCH/bin/acpi/crs",
 				"irq": "/$ARCH/bin/acpi/irq",
 				"ls": "/$ARCH/bin/ls",
 				"mount": "/$ARCH/bin/mount",

+ 29 - 10
sys/src/9/amd64/devacpi.c

@@ -124,17 +124,19 @@ static Acpilist *acpilists;
 
 /*
  * Given a base address, bind the list that contains it.
+ * It's possible and allowed for ACPICA to ask for a bigger region,
+ * so size matters.
  */
-static Acpilist *findlist(uintptr_t base)
+static Acpilist *findlist(uintptr_t base, uint size)
 {
 	Acpilist *a = acpilists;
 	//print("findlist: find %p\n", (void *)base);
 	for(; a; a = a->next){
-		if ((base >= a->base) && (base < (a->base + a->size))){
+		if ((base >= a->base) && ((base + size) < (a->base + a->size))){
 			return a;
 		}
 	}
-	print("Can't find list for %p\n", (void *)base);
+	//print("Can't find list for %p\n", (void *)base);
 	return nil;
 }
 /*
@@ -506,6 +508,20 @@ static void *sdtmap(uintptr_t pa, size_t want, size_t *n, int cksum)
 		print("sdtmap: nil pa\n");
 		return nil;
 	}
+	if (want) {
+		sdt = vmap(pa, want);
+		if (sdt == nil) {
+			print("acpi: vmap full table @%p/0x%x: nil\n", (void *)pa, want);
+			return nil;
+		}
+		/* realistically, we get a full page, and acpica seems to know that somehow. */
+		uintptr_t endaddress = (uintptr_t) sdt;
+		endaddress += want + 0xfff;
+		endaddress &= ~0xfff;
+		want = endaddress - (uintptr_t)sdt;
+		*n = want;
+	} else {
+
 	sdt = vmap(pa, sizeof(Sdthdr));
 	if (sdt == nil) {
 		print("acpi: vmap header@%p/%d: nil\n", (void *)pa, sizeof(Sdthdr));
@@ -520,13 +536,10 @@ static void *sdtmap(uintptr_t pa, size_t want, size_t *n, int cksum)
 		print("sdt has zero length: pa = %p, sig = %.4s\n", pa, sdt->sig);
 		return nil;
 	}
-	if (*n == 0x80000000) {
-		*n = want;
-		print("sdt has high bit set; weird vmware table? pa = %p\n", pa);
-	}
+
 	sdt = vmap(pa, *n);
 	if (sdt == nil) {
-		print("acpi: vmap full table @%p/%d: nil\n", (void *)pa, *n);
+		print("acpi: vmap full table @%p/0x%x: nil\n", (void *)pa, *n);
 		return nil;
 	}
 	//print("check it\n");
@@ -534,6 +547,7 @@ static void *sdtmap(uintptr_t pa, size_t want, size_t *n, int cksum)
 		print("acpi: SDT: bad checksum. pa = %p, len = %lu\n", pa, *n);
 		return nil;
 	}
+	}
 	//print("now mallocz\n");
 	p = mallocz(sizeof(Acpilist) + *n, 1);
 	//print("malloc'ed %p\n", p);
@@ -1999,9 +2013,14 @@ static int tlen;
 static int32_t
 acpimemread(Chan *c, void *a, int32_t n, int64_t off)
 {
+	Proc *up = externup();
 	Acpilist *l;
 	int ret;
 
+	/* due to vmap limitations, you have to be on core 0. Make
+	 * it easy for them. */
+	procwired(up, 0);
+
 	/* This is horribly insecure but, for now,
 	 * focus on getting it to work.
 	 * The only read allowed at 0 is sizeof(*rsd).
@@ -2023,7 +2042,7 @@ acpimemread(Chan *c, void *a, int32_t n, int64_t off)
 		return readmem(0, a, n, rsd, sizeof(*rsd));
 	}
 
-	l = findlist(off);
+	l = findlist(off, n);
 	/* we don't load all the lists, so this may be a new one. */
 	if (! l) {
 		size_t _;
@@ -2032,7 +2051,7 @@ acpimemread(Chan *c, void *a, int32_t n, int64_t off)
 			snprint(msg, sizeof(msg), "unable to map acpi@%p/%d", off, n);
 			error(msg);
 		}
-		l = findlist(off);
+		l = findlist(off, n);
 	}
 	/* we really need to improve on plan 9 error message handling. */
 	if (! l){

+ 1 - 1
sys/src/9/amd64/ioapic.c

@@ -297,7 +297,7 @@ static int acpi_make_rdt(Vctl *v, int tbdf, int irq, int busno, int devno)
 			todo[(tbdf>>11)&0x1fff].v = *v;
 			todo[(tbdf>>11)&0x1fff].lo = lo | TMlevel | IPlow | Im;
 			todo[(tbdf>>11)&0x1fff].valid = 1;
-			print("Set TOOD[0x%x] to valid\n", (tbdf>>11)&0x1fff);
+			print("Set todo[0x%x] to valid\n", (tbdf>>11)&0x1fff);
 			return -1;
 		}
 	}

+ 2 - 2
sys/src/9/amd64/main.c

@@ -54,7 +54,7 @@ static int numtcs = 32;		/* initial # of TCs */
 char dbgflg[256];
 static int vflag = 1;
 
-int nosmp = 1;
+int nosmp;
 int acpionly = 1;
 
 void*
@@ -605,7 +605,6 @@ main(uint32_t mbmagic, uint32_t mbaddress)
 if (1){	acpiinit(); hi("	acpiinit();\n");}
 
 	umeminit();
-	trapinit();
 
 	/*
 	 * This is necessary with GRUB and QEMU.
@@ -618,6 +617,7 @@ if (1){	acpiinit(); hi("	acpiinit();\n");}
 	procinit0();
 	print("before mpacpi, maxcores %d\n", maxcores);
 	mpacpi(maxcores);
+	trapinit();
 	apiconline();
 	/* Forcing to single core if desired */
 	if(!nosmp) {

+ 1 - 1
sys/src/9/amd64/trap.c

@@ -280,7 +280,7 @@ trapinit(void)
 	trapenable(VectorBPT, debugbpt, 0, "#BP");
 	trapenable(VectorPF, faultamd64, 0, "#PF");
 	trapenable(Vector2F, doublefault, 0, "#DF");
-	//intrenable(IdtIPI, expected, 0, BUSUNKNOWN, "#IPI");
+	intrenable(IdtIPI, expected, 0, BUSUNKNOWN, "#IPI");
 	trapenable(Vector15, unexpected, 0, "#15");
 	nmienable();
 

+ 1 - 0
sys/src/cmd/acpi/build.json

@@ -13,6 +13,7 @@
 		    "alltables.c"
 		],
 		"SourceFilesCmd": [
+			"crs.c",
 			"irq.c"
 		]
 	}

+ 204 - 0
sys/src/cmd/acpi/crs.c

@@ -0,0 +1,204 @@
+/*
+ * This file is part of the UCB release of Plan 9. It is subject to the license
+ * terms in the LICENSE file found in the top-level directory of this
+ * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
+ * part of the UCB release of Plan 9, including this file, may be copied,
+ * modified, propagated, or distributed except according to the terms contained
+ * in the LICENSE file.
+ */
+
+#include <acpi.h>
+
+#define CHECK_STATUS(fmt, ...) do { if (ACPI_FAILURE(status)) { \
+	printf("ACPI failed (%d): " fmt "\n", status, ## __VA_ARGS__); \
+	goto failed; \
+	} } while(0)
+
+extern void *ACPIRootPointer;
+extern int ACPITableSize;
+extern UINT32 AcpiDbgLevel;
+
+void hexdump(void *v, int length)
+{
+	int i;
+	uint8_t *m = v;
+	uintptr_t memory = (uintptr_t) v;
+	int all_zero = 0;
+	print("hexdump: %p, %u\n", v, length);
+	for (i = 0; i < length; i += 16) {
+		int j;
+
+		all_zero++;
+		for (j = 0; (j < 16) && (i + j < length); j++) {
+			if (m[i + j] != 0) {
+				all_zero = 0;
+				break;
+			}
+		}
+
+		if (all_zero < 2) {
+			print("%p:", (void *)(memory + i));
+			for (j = 0; j < 16; j++)
+				print(" %02x", m[i + j]);
+			print("  ");
+			for (j = 0; j < 16; j++)
+				print("%c", isprint(m[i + j]) ? m[i + j] : '.');
+			print("\n");
+		} else if (all_zero == 2) {
+			print("...\n");
+		}
+	}
+}
+
+/* these go somewhere else, someday. */
+ACPI_STATUS FindIOAPICs(int *pic_mode);
+
+static void DumpResource(ACPI_RESOURCE* resource)
+{
+	while (resource->Type != ACPI_RESOURCE_TYPE_END_TAG) {
+		printf("Got resource type %d\n", resource->Type);
+		ACPI_RESOURCE_ADDRESS64 addr64;
+		ACPI_STATUS status = AcpiResourceToAddress64(resource, &addr64);
+		printf("Processed and got type 0x%x\n",  addr64.ResourceType);
+
+		if (status == AE_OK && addr64.ResourceType == ACPI_BUS_NUMBER_RANGE)
+		{
+			printf("RouteIRQ: Root bridge bus range %#x..%#x\n",
+			       addr64.Address.Minimum,
+					addr64.Address.Maximum);
+			break;
+		}
+		resource = ACPI_NEXT_RESOURCE(resource);
+	}
+}
+
+static ACPI_STATUS PrintAcpiDevice(ACPI_HANDLE Device)
+{
+	ACPI_BUFFER buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+	ACPI_DEVICE_INFO* info = NULL;
+	ACPI_STATUS status = AcpiGetObjectInfo(Device, &info);
+	ACPI_STATUS crs;
+	if (!ACPI_SUCCESS(status))
+		return AE_OK;
+	//ResetBuffer(&buffer);
+	status = AcpiGetCurrentResources(Device, &buffer);
+	if (!ACPI_SUCCESS(status))
+		return AE_OK;
+	//ACPI_FREE(info);
+	//return_ACPI_STATUS(status);
+	printf("Device %p type %#x\n", Device, info->Type);
+	DumpResource((ACPI_RESOURCE*)buffer.Pointer);
+	AcpiRsDumpResourceList((ACPI_RESOURCE*)buffer.Pointer);
+	return AE_OK;
+}
+
+
+static ACPI_STATUS PrintDeviceCallback(ACPI_HANDLE Device, UINT32 Depth, void *Context, void** ReturnValue)
+{
+	return PrintAcpiDevice(Device);
+}
+
+// PNP0C0F = PCI Interrupt Link Device
+// PNP0A03 = PCI Root Bridge
+static ACPI_STATUS PrintCRS(void) {
+	ACPI_STATUS status = AE_OK;
+
+	printf("Searching for PNP0A03\n");
+	status = AcpiGetDevices(NULL/*"PNP0A03"*/, PrintDeviceCallback, NULL, NULL);
+#if 0
+	CHECK_STATUS("AcpiGetDevices PNP0A03");
+	if (DBGFLG) printf("Searching for PNP0C0F\n");
+	status = AcpiGetDevices("PNP0C0F", PrintDeviceCallback, NULL, NULL);
+	CHECK_STATUS("AcpiGetDevices PNP0C0F");
+#endif
+
+	return status;
+}
+
+void
+main(int argc, char *argv[])
+{
+	int set = -1, enable = -1;
+	int seg = 0, bus = 0, dev = 2, fn = 0, pin = 0;
+	ACPI_STATUS status;
+	int verbose = 0;
+	AcpiDbgLevel = ACPI_LV_VERBOSE | ACPI_LV_RESOURCES | ACPI_LV_VERBOSITY2;
+	AcpiDbgLayer = ACPI_RESOURCES | ACPI_EXECUTER;
+	if (0) AcpiDbgLayer |= ACPI_ALL_COMPONENTS;
+
+	ARGBEGIN{
+	case 'v':
+		AcpiDbgLevel |= ACPI_LV_VERBOSITY1 | ACPI_LV_FUNCTIONS;
+		verbose++;
+		break;
+	case 's':
+		set = open("#P/irqmap", OWRITE);
+		if (set < 0)
+			sysfatal("%r");
+		break;
+	default:
+		sysfatal("usage: acpi/irq [-v] [-s]");
+		break;
+	}ARGEND;
+
+	status = AcpiInitializeSubsystem();
+	if (ACPI_FAILURE(status)) {
+		sysfatal("Error %d\n", status);
+	}
+        status = AcpiInitializeTables(NULL, 0, FALSE);
+        if (ACPI_FAILURE(status))
+		sysfatal("can't set up acpi tables: %d", status);
+
+	if (verbose)
+		print("init dables\n"); 
+        status = AcpiLoadTables();
+        if (ACPI_FAILURE(status))
+		sysfatal("Can't load ACPI tables: %d", status);
+
+	/* from acpi: */
+    	/* If the Hardware Reduced flag is set, machine is always in acpi mode */
+	AcpiGbl_ReducedHardware = 1;
+	if (verbose) 
+		print("LOADED TABLES.\n");
+        status = AcpiEnableSubsystem(0);
+        if (ACPI_FAILURE(status))
+		print("Probably does not matter: Can't enable ACPI subsystem");
+
+	if (verbose)
+		print("enabled subsystem.\n");
+        status = AcpiInitializeObjects(0);
+        if (ACPI_FAILURE(status))
+		sysfatal("Can't Initialize ACPI objects");
+
+	int picmode;
+	status = FindIOAPICs(&picmode);
+
+	if (picmode == 0)
+		sysfatal("PANIC: Can't handle picmode 0!");
+	ACPI_STATUS ExecuteOSI(int pic_mode);
+	if (verbose)
+		print("FindIOAPICs returns status %d picmode %d\n", status, picmode);
+	status = ExecuteOSI(picmode);
+	CHECK_STATUS("ExecuteOSI");
+failed:
+	if (verbose)
+		print("inited objects.\n");
+	if (verbose)
+		AcpiDbgLevel |= ACPI_LV_VERBOSITY1 | ACPI_LV_FUNCTIONS;
+
+	status = AcpiInitializeDebugger();
+	if (ACPI_FAILURE(status)) {
+		sysfatal("Error %d\n", status);
+	}
+	int GetPRT();
+	status = GetPRT();
+	if (ACPI_FAILURE(status)) {
+		sysfatal("Error %d\n", status);
+	}
+
+	printf("Searching for PNP0A03\n");
+	status = PrintCRS(); //AcpiGetDevices(NULL/*"PNP0A03"*/, CRSCallBack, NULL, NULL);
+	CHECK_STATUS("AcpiGetDevices PNP0A03");
+	exits(0);
+}
+

+ 1 - 1
sys/src/libacpi/harvey.c

@@ -337,7 +337,7 @@ AcpiOsMapMemory(ACPI_PHYSICAL_ADDRESS Where, ACPI_SIZE Length)
 		return nil;
 	}
 	//hexdump(v, Length);
-	hexdump(v, 36);
+	//hexdump(v, 36);
 	return v;
 }
 

+ 1 - 1
util/GO9PCPU

@@ -17,7 +17,7 @@ if [ "$(uname)" = "Linux" ] && [ -e /dev/kvm ]; then
 fi
 
 read -r cmd <<EOF
-$kvmdo qemu-system-x86_64 -s -cpu Opteron_G1 -smp 1 -m 2048 $kvmflag \
+$kvmdo qemu-system-x86_64 -s -cpu Opteron_G1 -smp 4 -m 2048 $kvmflag \
 -serial stdio \
 --machine pc,accel=kvm \
 -net nic,model=rtl8139 \