140 lines
3 KiB
C
140 lines
3 KiB
C
|
#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);
|
||
|
}
|