253 lines · 4.7 KB · C
RawDownload
#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "mp.h" #define dprint(...)	{if(debug) print(__VA_ARGS__); } typedef	struct	Madt	Madt;typedef	struct	Rsd	Rsd; struct Madt {				/* Multiple APIC DT */	uchar	sdthdr[36];		/* "MADT" + length[4] + [28] */	uchar	addr[4];			/* Local APIC Address */	uchar	flags[4];	uchar	structures[];}; struct Rsd {				/* Root System Description */	uchar	signature[8];		/* "RSD PTR " */	uchar	rchecksum;	uchar	oemid[6];	uchar	revision;	uchar	raddr[4];			/* RSDT */	uchar	length[4];	uchar	xaddr[8];			/* XSDT */	uchar	xchecksum;		/* XSDT */	uchar	pad[3];			/* reserved */}; static int debug = 1; static uchar*biosseg(uintptr a){	return KADDR(a<<4);} static ushortget16(uchar *p){	return p[1]<<8 | p[0];} static uintget32(uchar *p){	return p[3]<<24 | p[2]<<16 | p[1]<<8 | p[0];} static uvlongget64(uchar *p){	uvlong u; 	u = get32(p+4);	return u<<32 | get32(p);} extern	int	mpmachno; static voidacpiapic(void *v){	char *already;	uchar *p;	int i, l, n, f, np;	u32int lapicaddr;	Apic *apic;	Madt *madt; 	madt = v;	lapicaddr = get32(madt->addr);	dprint("APIC lapic addr %#.8ux, flags %#8.8ux\n",		lapicaddr, get32(madt->flags)); 	n = get32(&madt->sdthdr[4]);	p = madt->structures;	np = 0;	for(i = offsetof(Madt, structures[0]); i < n; i += l){		already = "";		switch(p[0]){		case 0:				/* processor lapic */			if((get32(p+4) & 1) == 0 || p[3] > MaxAPICNO)				break;			apic = mplapic + p[3];			f = (np++ == 0)*PcmpBP | PcmpEN;			if(apic->used){				already = "(mp)";				goto pr;			}			apic->used = 1;			apic->type = PcmpPROCESSOR;			apic->paddr = lapicaddr;			apic->apicno = p[3];			apic->flags = f;			apic->lintr[0] = ApicIMASK;			apic->lintr[1] = ApicIMASK;			/* botch! just enumerate */			if(apic->flags & PcmpBP)				apic->machno = 0;			else				apic->machno = ++mpmachno;			procvec[mpmachno] = apic;		pr:			dprint("apic proc %d/%d apicid %d %s\n", np-1, apic->machno, p[3], already);			break;		case 1:				/* i/o apic */			if(p[2] > MaxAPICNO)				break;			apic = mpioapic + p[2];			apic->gsibase = get32(p+8);		/* of global system interrupts */			if(apic->used){				already = "(mp)";				goto pr1;			}			apic->paddr = get32(p+4);			if((apic->addr = vmap(apic->paddr, 1024)) == nil){				print("apic %d: failed to map %#P\n", p[3], apic->paddr);				already = "(fail)";				goto pr1;			}			apic->used = 1;			apic->type = PcmpIOAPIC;			apic->apicno = p[2];			apic->flags = PcmpEN;		pr1:			dprint("ioapic %d ", p[2]);			dprint("addr %#P base %d %s\n", apic->paddr, apic->gsibase, already);			break;		}		l = p[1];		p += l;	}} static void*rsdchecksum(void* addr, int length){	uchar *p, sum; 	sum = 0;	for(p = addr; length-- > 0; p++)		sum += *p;	if(sum == 0)		return addr; 	return nil;} static void*rsdscan(uchar* addr, int len, char* signature){	int sl;	uchar *e, *p; 	e = addr+len;	sl = strlen(signature);	for(p = addr; p+sl < e; p += 16){		if(memcmp(p, signature, sl))			continue;		return p;	} 	return nil;} static void*rsdsearch(char* signature){	uintptr p;	uchar *bda;	Rsd *rsd; 	/*	 * Search for the data structure signature:	 * 1) in the first KB of the EBDA;	 * 2) in the BIOS ROM between 0xE0000 and 0xFFFFF.	 */	if(strncmp((char*)KADDR(0xFFFD9), "EISA", 4) == 0){		bda = biosseg(0x40);		if((p = (bda[0x0F]<<8)|bda[0x0E])){			if(rsd = rsdscan(KADDR(p), 1024, signature))				return rsd;		}	}	return rsdscan(biosseg(0xE000), 0x20000, signature);} voidmpacpi(void){	char buf[32];	uchar *p, *sdt;	int asize, i, l, n;	uintptr dhpa, sdtpa;	Rsd *rsd; 	if((rsd = rsdsearch("RSD PTR ")) == nil)		return;	snprint(buf, sizeof buf, "%.6s", (char*)rsd->oemid);	dprint("rsd %#p, physaddr %#ux length %ud %#llux rev %d oem %s\n",		rsd, get32(rsd->raddr), get32(rsd->length),		get64(rsd->xaddr), rsd->revision, buf); 	if(rsd->revision == 2){		if(rsdchecksum(rsd, 36) == nil)			return;		sdtpa = get64(rsd->xaddr);		asize = 8;	}	else{		if(rsdchecksum(rsd, 20) == nil)			return;		sdtpa = get32(rsd->raddr);		asize = 4;	}	if((sdt = vmap(sdtpa, 8)) == nil)		return;	if((sdt[0] != 'R' && sdt[0] != 'X') || memcmp(sdt+1, "SDT", 3) != 0){		vunmap(sdt, 8);		return;	} 	n = get32(sdt+4);	vunmap(sdt, 8);	if((sdt = vmap(sdtpa, n)) == nil)		return;	if(rsdchecksum(sdt, n) == nil){		vunmap(sdt, n);		return;	}	for(i = 36; i < n; i += asize){		if(asize == 8)			dhpa = get64(sdt+i);		else			dhpa = get32(sdt+i);		if((p = vmap(dhpa, 8)) == nil)			continue;		l = get32(p+4);		vunmap(p, 8);		if((p = vmap(dhpa, l)) == nil)			continue;		if(rsdchecksum(p, l) != nil){			if(memcmp(p, "APIC", 4) == 0)				acpiapic(p);		}		vunmap(p, l);	}	vunmap(sdt, n);}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t