xv6-cs450/mp.c

140 lines
3 KiB
C
Raw Normal View History

2006-06-21 03:53:07 +02:00
#include "types.h"
#include "mp.h"
#include "defs.h"
#include "memlayout.h"
static struct _MP_* _mp_; /* The MP floating point structure */
static int ncpu;
static struct _MP_*
mp_scan(uint8_t *addr, int len)
{
uint8_t *e, *p, sum;
int i;
cprintf("scanning: 0x%x\n", (uint32_t)addr);
e = addr+len;
for(p = addr; p < e; p += sizeof(struct _MP_)){
if(memcmp(p, "_MP_", 4))
continue;
sum = 0;
for(i = 0; i < sizeof(struct _MP_); i++)
sum += p[i];
if(sum == 0)
return (struct _MP_ *)p;
}
return 0;
}
static struct _MP_*
mp_search(void)
{
uint8_t *bda;
uint32_t p;
struct _MP_ *mp;
/*
* Search for the MP Floating Pointer Structure, which according to the
* spec is in one of the following three locations:
* 1) in the first KB of the EBDA;
* 2) in the last KB of system base memory;
* 3) in the BIOS ROM between 0xE0000 and 0xFFFFF.
*/
bda = KADDR(0x400);
if((p = (bda[0x0F]<<8)|bda[0x0E])){
if((mp = mp_scan(KADDR(p), 1024)))
return mp;
}
else{
p = ((bda[0x14]<<8)|bda[0x13])*1024;
if((mp = mp_scan(KADDR(p-1024), 1024)))
return mp;
}
return mp_scan(KADDR(0xF0000), 0x10000);
}
static int
mp_detect(void)
{
struct PCMP *pcmp;
uint8_t *p, sum;
uint32_t length;
/*
* Search for an MP configuration table. For now,
* don't accept the default configurations (physaddr == 0).
* Check for correct signature, calculate the checksum and,
* if correct, check the version.
* To do: check extended table checksum.
*/
if((_mp_ = mp_search()) == 0 || _mp_->physaddr == 0)
return 1;
pcmp = KADDR(_mp_->physaddr);
if(memcmp(pcmp, "PCMP", 4))
return 2;
length = pcmp->length;
sum = 0;
for(p = (uint8_t*)pcmp; length; length--)
sum += *p++;
if(sum || (pcmp->version != 1 && pcmp->version != 4))
return 3;
cprintf("MP spec rev #: %x\n", _mp_->specrev);
return 0;
}
void
mpinit()
{
int r;
uint8_t *p, *e;
struct PCMP *pcmp;
ncpu = 0;
if ((r = mp_detect()) != 0) return;
cprintf ("This computer is multiprocessor!\n");
/*
* Run through the table saving information needed for starting
* application processors and initialising any I/O APICs. The table
* is guaranteed to be in order such that only one pass is necessary.
*/
pcmp = KADDR(_mp_->physaddr);
p = ((uint8_t*)pcmp)+sizeof(struct PCMP);
e = ((uint8_t*)pcmp)+pcmp->length;
while(p < e) {
switch(*p){
case PcmpPROCESSOR:
cprintf("a processor\n");
ncpu++;
p += sizeof(struct PCMPprocessor);
continue;
case PcmpBUS:
cprintf("a bus\n");
p += sizeof(struct PCMPbus);
continue;
case PcmpIOAPIC:
cprintf("an IO APIC\n");
p += sizeof(struct PCMPioapic);
continue;
case PcmpIOINTR:
cprintf("an IO interrupt assignment\n");
p += sizeof(struct PCMPintr);
continue;
default:
cprintf("mpinit: unknown PCMP type 0x%x (e-p 0x%x)\n", *p, e-p);
while(p < e){
cprintf("%uX ", *p);
p++;
}
break;
}
}
cprintf("ncpu: %d\n", ncpu);
}