Skip to content
Snippets Groups Projects
mp.c 4.65 KiB
Newer Older
#include "types.h"
#include "mp.h"
#include "defs.h"
kaashoek's avatar
kaashoek committed
#include "traps.h"
rtm's avatar
rtm committed
#include "proc.h"
rsc's avatar
rsc committed
static char *buses[] = {
  "CBUSI ",
  "CBUSII",
  "EISA  ",
  "FUTURE",
  "INTERN",
  "ISA   ",
  "MBI   ",
  "MBII  ",
  "MCA   ",
  "MPI   ",
  "MPSA  ",
  "NUBUS ",
  "PCI   ",
  "PCMCIA",
  "TC    ",
  "VL    ",
  "VME   ",
  "XPRESS",
  0,
kaashoek's avatar
kaashoek committed
};

rtm's avatar
rtm committed
struct cpu cpus[NCPU];
rtm's avatar
rtm committed
int ncpu;
rsc's avatar
rsc committed
static struct mp *mp;  // The MP floating point structure
static struct mp*
rtm's avatar
rtm committed
mp_scan(uchar *addr, int len)
rtm's avatar
rtm committed
  uchar *e, *p, sum;
  int i;

  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)
rsc's avatar
rsc committed
      return (struct mp*)p;
rsc's avatar
rsc committed
// 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.
static struct mp*
mp_search(void)
{
rtm's avatar
rtm committed
  uchar *bda;
  uint p;
  struct mp *mp;
rtm's avatar
rtm committed
  bda = (uchar*) 0x400;
  if((p = (bda[0x0F]<<8)|bda[0x0E])){
rtm's avatar
rtm committed
    if((mp = mp_scan((uchar*) p, 1024)))
      return mp;
  }
  else{
    p = ((bda[0x14]<<8)|bda[0x13])*1024;
rtm's avatar
rtm committed
    if((mp = mp_scan((uchar*)p-1024, 1024)))
      return mp;
  }
rtm's avatar
rtm committed
  return mp_scan((uchar*)0xF0000, 0x10000);
rsc's avatar
rsc committed
// 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.
rsc's avatar
rsc committed
static int
mp_detect(void)
{
  struct mpctb *pcmp;
rtm's avatar
rtm committed
  uchar *p, sum;
  uint length;
  if((mp = mp_search()) == 0 || mp->physaddr == 0)
rsc's avatar
rsc committed
  pcmp = (struct mpctb*) mp->physaddr;
  if(memcmp(pcmp, "PCMP", 4))
    return 2;

  length = pcmp->length;
  sum = 0;
rtm's avatar
rtm committed
  for(p = (uchar*)pcmp; length; length--)
    sum += *p++;

  if(sum || (pcmp->version != 1 && pcmp->version != 4))
    return 3;

  return 0;
}

void
rsc's avatar
rsc committed
mp_init(void)
rtm's avatar
rtm committed
  uchar *p, *e;
  struct mpctb *mpctb;
  struct mppe *proc;
  struct mpbe *bus;
  struct mpioapic *ioapic;
  struct mpie *intr;
kaashoek's avatar
kaashoek committed
  int i;
  if((r = mp_detect()) != 0) {
rsc's avatar
rsc committed
    return;
rsc's avatar
rsc committed

  // 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.
rsc's avatar
rsc committed
  mpctb = (struct mpctb*) mp->physaddr;
  lapicaddr = (uint*) mpctb->lapicaddr;
rtm's avatar
rtm committed
  p = ((uchar*)mpctb)+sizeof(struct mpctb);
  e = ((uchar*)mpctb)+mpctb->length;

  while(p < e) {
    switch(*p){
rsc's avatar
rsc committed
      proc = (struct mppe*) p;
rtm's avatar
rtm committed
      cpus[ncpu].apicid = proc->apicid;
rsc's avatar
rsc committed
      if(proc->flags & MPBP) {
        bcpu = &cpus[ncpu];
      ncpu++;
      p += sizeof(struct mppe);
      continue;
rsc's avatar
rsc committed
      bus = (struct mpbe*) p;
kaashoek's avatar
kaashoek committed
      for(i = 0; buses[i]; i++){
        if(strncmp(buses[i], bus->string, sizeof(bus->string)) == 0)
          break;
kaashoek's avatar
kaashoek committed
      }
      p += sizeof(struct mpbe);
      continue;
rsc's avatar
rsc committed
      ioapic = (struct mpioapic*) p;
      ioapic_id = ioapic->apicno;
      p += sizeof(struct mpioapic);
      continue;
rsc's avatar
rsc committed
      intr = (struct mpie*) p;
      p += sizeof(struct mpie);
      continue;
    default:
      cprintf("mp_init: unknown PCMP type 0x%x (e-p 0x%x)\n", *p, e-p);
      while(p < e){
        cprintf("%uX ", *p);
        p++;
rsc's avatar
rsc committed
  if(mp->imcrp) {
    // It appears that Bochs doesn't support IMCR, so 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
kaashoek's avatar
kaashoek committed
int
mp_bcpu(void)
{
rsc's avatar
rsc committed
  if(ismp)
    return bcpu-cpus;
rsc's avatar
rsc committed
  return 0;
extern void mpmain(void);

rsc's avatar
rsc committed
// Write bootstrap code to unused memory at 0x7000.
#define APBOOTCODE 0x7000
rsc's avatar
rsc committed
mp_startthem(void)
rtm's avatar
rtm committed
  extern uchar _binary_bootother_start[], _binary_bootother_size[];
  extern int main();
  int c;

rsc's avatar
rsc committed
  memmove((void*) APBOOTCODE,_binary_bootother_start,
          (uint) _binary_bootother_size);
  for(c = 0; c < ncpu; c++){
rsc's avatar
rsc committed
    // Our current cpu has already started.
rsc's avatar
rsc committed
    if(c == cpu())
      continue;
rsc's avatar
rsc committed

    // Set target %esp
    *(uint*)(APBOOTCODE-4) = (uint) (cpus[c].mpstack) + MPSTACK;

    // Set target %eip
    *(uint*)(APBOOTCODE-8) = (uint)mpmain;

    // Go!
rtm's avatar
rtm committed
    lapic_startap(cpus[c].apicid, (uint) APBOOTCODE);
rsc's avatar
rsc committed

    // Wait for cpu to get through bootstrap.
    while(cpus[c].booted == 0)
      ;