2006-06-21 03:53:07 +02:00
# include "types.h"
# include "mp.h"
# include "defs.h"
2006-06-22 03:28:57 +02:00
# include "param.h"
# include "x86.h"
2006-06-28 18:35:03 +02:00
# include "traps.h"
2006-06-22 03:28:57 +02:00
# include "mmu.h"
2006-07-01 23:26:01 +02:00
# include "proc.h"
2006-06-21 03:53:07 +02:00
2006-07-05 22:00:14 +02:00
static char * buses [ ] = {
" CBUSI " ,
" CBUSII " ,
" EISA " ,
" FUTURE " ,
" INTERN " ,
" ISA " ,
" MBI " ,
" MBII " ,
" MCA " ,
" MPI " ,
" MPSA " ,
" NUBUS " ,
" PCI " ,
" PCMCIA " ,
" TC " ,
" VL " ,
" VME " ,
" XPRESS " ,
0 ,
} ;
2006-07-01 23:26:01 +02:00
struct cpu cpus [ NCPU ] ;
int ncpu ;
2006-08-04 20:12:31 +02:00
uchar ioapic_id ;
2006-06-22 03:28:57 +02:00
static struct cpu * bcpu ;
2006-08-04 20:12:31 +02:00
static struct mp * mp ; // The MP floating point structure
2006-06-22 03:28:57 +02:00
2006-07-17 03:58:13 +02:00
static struct mp *
2006-07-20 11:07:53 +02:00
mp_scan ( uchar * addr , int len )
2006-06-21 03:53:07 +02:00
{
2006-07-20 11:07:53 +02:00
uchar * e , * p , sum ;
2006-06-21 03:53:07 +02:00
int i ;
2006-07-20 11:07:53 +02:00
cprintf ( " scanning: 0x%x \n " , ( uint ) addr ) ;
2006-06-21 03:53:07 +02:00
e = addr + len ;
2006-07-17 03:58:13 +02:00
for ( p = addr ; p < e ; p + = sizeof ( struct mp ) ) {
2006-06-21 03:53:07 +02:00
if ( memcmp ( p , " _MP_ " , 4 ) )
continue ;
sum = 0 ;
2006-07-17 03:58:13 +02:00
for ( i = 0 ; i < sizeof ( struct mp ) ; i + + )
2006-06-21 03:53:07 +02:00
sum + = p [ i ] ;
if ( sum = = 0 )
2006-07-17 03:58:13 +02:00
return ( struct mp * ) p ;
2006-06-21 03:53:07 +02:00
}
return 0 ;
}
2006-07-17 03:58:13 +02:00
static struct mp *
2006-06-21 03:53:07 +02:00
mp_search ( void )
{
2006-07-20 11:07:53 +02:00
uchar * bda ;
uint p ;
2006-07-17 03:58:13 +02:00
struct mp * mp ;
2006-06-21 03:53:07 +02:00
/*
* 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 .
*/
2006-07-20 11:07:53 +02:00
bda = ( uchar * ) 0x400 ;
2006-06-21 03:53:07 +02:00
if ( ( p = ( bda [ 0x0F ] < < 8 ) | bda [ 0x0E ] ) ) {
2006-07-20 11:07:53 +02:00
if ( ( mp = mp_scan ( ( uchar * ) p , 1024 ) ) )
2006-06-21 03:53:07 +02:00
return mp ;
}
else {
p = ( ( bda [ 0x14 ] < < 8 ) | bda [ 0x13 ] ) * 1024 ;
2006-07-20 11:07:53 +02:00
if ( ( mp = mp_scan ( ( uchar * ) p - 1024 , 1024 ) ) )
2006-06-21 03:53:07 +02:00
return mp ;
}
2006-07-20 11:07:53 +02:00
return mp_scan ( ( uchar * ) 0xF0000 , 0x10000 ) ;
2006-06-21 03:53:07 +02:00
}
static int
mp_detect ( void )
{
2006-07-17 03:58:13 +02:00
struct mpctb * pcmp ;
2006-07-20 11:07:53 +02:00
uchar * p , sum ;
uint length ;
2006-06-21 03:53:07 +02:00
/*
* 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 .
*/
2006-06-22 03:28:57 +02:00
if ( ( mp = mp_search ( ) ) = = 0 | | mp - > physaddr = = 0 )
2006-06-21 03:53:07 +02:00
return 1 ;
2006-07-17 03:58:13 +02:00
pcmp = ( struct mpctb * ) mp - > physaddr ;
2006-06-21 03:53:07 +02:00
if ( memcmp ( pcmp , " PCMP " , 4 ) )
return 2 ;
length = pcmp - > length ;
sum = 0 ;
2006-07-20 11:07:53 +02:00
for ( p = ( uchar * ) pcmp ; length ; length - - )
2006-06-21 03:53:07 +02:00
sum + = * p + + ;
if ( sum | | ( pcmp - > version ! = 1 & & pcmp - > version ! = 4 ) )
return 3 ;
return 0 ;
}
void
2006-07-17 03:25:22 +02:00
mp_init ( void )
2006-06-21 03:53:07 +02:00
{
int r ;
2006-07-20 11:07:53 +02:00
uchar * p , * e ;
2006-07-17 03:58:13 +02:00
struct mpctb * mpctb ;
struct mppe * proc ;
struct mpbe * bus ;
2006-08-04 20:12:31 +02:00
struct mpioapic * ioapic ;
struct mpie * intr ;
2006-07-05 22:00:14 +02:00
int i ;
2006-08-04 20:12:31 +02:00
uchar byte ;
2006-06-21 03:53:07 +02:00
ncpu = 0 ;
if ( ( r = mp_detect ( ) ) ! = 0 ) return ;
2006-06-22 03:28:57 +02:00
2006-08-04 20:12:31 +02:00
cprintf ( " Mp spec rev #: %x imcrp 0x%x \n " , mp - > specrev , mp - > imcrp ) ;
2006-06-21 03:53:07 +02:00
/*
* 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 .
*/
2006-07-17 03:58:13 +02:00
mpctb = ( struct mpctb * ) mp - > physaddr ;
2006-07-20 11:07:53 +02:00
lapicaddr = ( uint * ) mpctb - > lapicaddr ;
2006-06-22 03:28:57 +02:00
cprintf ( " apicaddr: %x \n " , lapicaddr ) ;
2006-07-20 11:07:53 +02:00
p = ( ( uchar * ) mpctb ) + sizeof ( struct mpctb ) ;
e = ( ( uchar * ) mpctb ) + mpctb - > length ;
2006-06-21 03:53:07 +02:00
while ( p < e ) {
switch ( * p ) {
2006-06-22 03:28:57 +02:00
case MPPROCESSOR :
2006-07-17 03:58:13 +02:00
proc = ( struct mppe * ) p ;
2006-06-22 22:47:23 +02:00
cpus [ ncpu ] . apicid = proc - > apicid ;
cprintf ( " a processor %x \n " , cpus [ ncpu ] . apicid ) ;
2006-06-22 03:28:57 +02:00
if ( proc - > flags & MPBP ) {
2006-06-22 22:47:23 +02:00
bcpu = & cpus [ ncpu ] ;
2006-06-22 03:28:57 +02:00
}
2006-06-21 03:53:07 +02:00
ncpu + + ;
2006-07-17 03:58:13 +02:00
p + = sizeof ( struct mppe ) ;
2006-06-21 03:53:07 +02:00
continue ;
2006-06-22 03:28:57 +02:00
case MPBUS :
2006-07-17 03:58:13 +02:00
bus = ( struct mpbe * ) p ;
2006-07-05 22:00:14 +02:00
for ( i = 0 ; buses [ i ] ; i + + ) {
if ( strncmp ( buses [ i ] , bus - > string , sizeof ( bus - > string ) ) = = 0 )
break ;
}
cprintf ( " a bus %d \n " , i ) ;
2006-07-17 03:58:13 +02:00
p + = sizeof ( struct mpbe ) ;
2006-06-21 03:53:07 +02:00
continue ;
2006-06-22 03:28:57 +02:00
case MPIOAPIC :
2006-08-04 20:12:31 +02:00
ioapic = ( struct mpioapic * ) p ;
cprintf ( " an I/O APIC: id %d %x \n " , ioapic - > apicno , ioapic - > flags ) ;
ioapic_id = ioapic - > apicno ;
2006-07-17 03:58:13 +02:00
p + = sizeof ( struct mpioapic ) ;
2006-06-21 03:53:07 +02:00
continue ;
2006-06-22 03:28:57 +02:00
case MPIOINTR :
2006-08-04 20:12:31 +02:00
intr = ( struct mpie * ) p ;
// cprintf("an I/O intr: type %d flags 0x%x bus %d souce bus irq %d dest ioapic id %d dest ioapic intin %d\n", intr->intr, intr->flags, intr->busno, intr->irq, intr->apicno, intr->intin);
2006-07-17 03:58:13 +02:00
p + = sizeof ( struct mpie ) ;
2006-06-21 03:53:07 +02:00
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 ;
}
}
2006-08-04 20:12:31 +02:00
if ( mp - > imcrp ) { // it appears that bochs doesn't support IMCR, and code won't run
outb ( 0x22 , 0x70 ) ; /* select IMCR */
byte = inb ( 0x23 ) ; /* current contents */
byte | = 0x01 ; /* mask external INTR */
outb ( 0x23 , byte ) ; /* disconnect 8259s/NMI */
}
2006-06-22 22:47:23 +02:00
cprintf ( " ncpu: %d boot %d \n " , ncpu , bcpu - cpus ) ;
2006-07-12 13:15:38 +02:00
}
2006-06-21 03:53:07 +02:00
2006-08-04 20:12:31 +02:00
2006-07-12 19:00:54 +02:00
int
mp_bcpu ( void )
{
return bcpu - cpus ;
}
2006-07-16 17:50:13 +02:00
extern void mpmain ( void ) ;
2006-08-04 20:12:31 +02:00
# define APBOOTCODE 0x7000 // XXX hack
2006-07-12 13:15:38 +02:00
void
2006-07-17 03:25:22 +02:00
mp_startthem ( void )
2006-07-12 13:15:38 +02:00
{
2006-07-20 11:07:53 +02:00
extern uchar _binary_bootother_start [ ] , _binary_bootother_size [ ] ;
2006-07-12 13:15:38 +02:00
extern int main ( ) ;
int c ;
2006-06-25 00:47:06 +02:00
memmove ( ( void * ) APBOOTCODE , _binary_bootother_start ,
2006-07-20 11:07:53 +02:00
( uint ) _binary_bootother_size ) ;
2006-06-22 03:28:57 +02:00
2006-06-25 00:47:06 +02:00
for ( c = 0 ; c < ncpu ; c + + ) {
2006-07-12 13:15:38 +02:00
if ( c = = cpu ( ) ) continue ;
2006-08-08 21:58:06 +02:00
cprintf ( " cpu%d: starting processor %d \n " , cpu ( ) , c ) ;
2006-07-17 03:52:13 +02:00
* ( uint * ) ( APBOOTCODE - 4 ) = ( uint ) ( cpus [ c ] . mpstack ) + MPSTACK ; // tell it what to use for %esp
* ( uint * ) ( APBOOTCODE - 8 ) = ( uint ) mpmain ; // tell it where to jump to
2006-07-20 11:07:53 +02:00
lapic_startap ( cpus [ c ] . apicid , ( uint ) APBOOTCODE ) ;
2006-08-08 21:58:06 +02:00
while ( cpus [ c ] . booted = = 0 )
;
2006-06-22 03:28:57 +02:00
}
2006-06-21 03:53:07 +02:00
}