Logo Search packages:      
Sourcecode: x86info version File versions

mptable.c

/*
 * Copyright (c) 1996, by Steve Passe
 * All rights reserved.
 *
 * hacked to make it work in userspace Linux by Ingo Molnar, same copyright
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. The name of the developer may NOT be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *      $Id: mptable.c,v 1.7 2002/11/11 19:54:56 davej Exp $
 */

#define MP_SIG                        0x5f504d5f        /* _MP_ */

#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>

#include "mptable.h"

#ifdef linux
typedef unsigned int vm_offset_t;
#else
#include <machine/types.h>
#endif

/* EBDA is @ 40:0e in real-mode terms */
#define EBDA_POINTER                0x040e              /* location of EBDA pointer */

/* CMOS 'top of mem' is @ 40:13 in real-mode terms */
#define TOPOFMEM_POINTER            0x0413              /* BIOS: base memory size */

#define DEFAULT_TOPOFMEM            0xa0000

#define BIOS_BASE                0xf0000
#define BIOS_BASE2                    0xe0000
#define BIOS_SIZE                0x10000
#define ONE_KBYTE                1024

#define GROPE_AREA1                  0x80000
#define GROPE_AREA2                  0x90000
#define GROPE_SIZE                    0x10000

#define PROCENTRY_FLAG_EN        0x01
#define PROCENTRY_FLAG_BP        0x02
#define IOAPICENTRY_FLAG_EN    0x01

#define MAXPNSTR                    132

typedef struct TABLE_ENTRY {
      u_char      type;
      u_char      length;
      char  name[32];
} tableEntry;

tableEntry basetableEntryTypes[] =
{
      { 0, 20, "Processor" },
      { 1,  8, "Bus" },
      { 2,  8, "I/O APIC" },
      { 3,  8, "I/O INT" },
      { 4,  8, "Local INT" }
};

/* MP Floating Pointer Structure */
typedef struct MPFPS {
      char  signature[4];
      void* pap;
      u_char      length;
      u_char      spec_rev;
      u_char      checksum;
      u_char      mpfb1;
      u_char      mpfb2;
      u_char      mpfb3;
      u_char      mpfb4;
      u_char      mpfb5;
} mpfps_t;

/* MP Configuration Table Header */
typedef struct MPCTH {
      char  signature[4];
      u_short     base_table_length;
      u_char      spec_rev;
      u_char      checksum;
      u_char      oem_id[8];
      u_char      product_id[12];
      void* oem_table_pointer;
      u_short     oem_table_size;
      u_short     entry_count;
      void* apic_address;
      u_short     extended_table_length;
      u_char      extended_table_checksum;
      u_char      reserved;
} mpcth_t;

typedef struct PROCENTRY {
      u_char      type;
      u_char      apicID;
      u_char      apicVersion;
      u_char      cpuFlags;
      u_long      cpuSignature;
      u_long      featureFlags;
      u_long      reserved1;
      u_long      reserved2;
} ProcEntry;

static void apic_probe(vm_offset_t* paddr, int* where);

static int MPConfigTableHeader(void* pap);

static int readType(void);
static void seekEntry(vm_offset_t addr);
static void readEntry(void* entry, int size);

static void processorEntry(void);

/* global data */
int   pfd;              /* physical /dev/mem fd */

int   busses[16];
int   apics[16];

int   ncpu;
int   nbus;
int   napic;
int   nintr;
int   verbose;

int issmp(int *numcpu, int verb)
{
      vm_offset_t paddr;
      mpfps_t mpfps;
      int where;
      int defaultConfig;

      verbose=verb;
      /* open physical memory for access to MP structures */
      if ((pfd = open("/dev/mem", O_RDONLY)) < 0) {
            fprintf(stderr, "issmp(): /dev/mem: %s\n", strerror(errno));
            return -1;
      }

      /* probe for MP structures */
      apic_probe(&paddr, &where);
      if (where <= 0) {
            if(numcpu) *numcpu=1;
            return SMP_NO;
      }

      /* read in mpfps structure*/
      seekEntry(paddr);
      readEntry(&mpfps, sizeof(mpfps_t));

      /* check whether an MP config table exists */
      if (! (defaultConfig = mpfps.mpfb1))
            MPConfigTableHeader(mpfps.pap);

      if(numcpu)
            *numcpu=ncpu;
      return SMP_YES;
}

/*
 * set PHYSICAL address of MP floating pointer structure
 */
#define NEXT(X)         ((X) += 4)
static void
apic_probe(vm_offset_t* paddr, int* where)
{
      /*
       * c rewrite of apic_probe() by Jack F. Vogel
       */

      unsigned int x;
      u_short segment;
      vm_offset_t target;
      u_int buffer[ BIOS_SIZE / sizeof(int) ];

      /* search Extended Bios Data Area, if present */
      seekEntry((vm_offset_t)EBDA_POINTER);
      readEntry(&segment, 2);
      if (segment) {                      /* search EBDA */
            target = (vm_offset_t)segment << 4;
            seekEntry(target);
            readEntry(buffer, ONE_KBYTE);

            for (x = 0; x < ONE_KBYTE / sizeof (unsigned int); NEXT(x)) {
                  if (buffer[ x ] == MP_SIG) {
                        *where = 1;
                        *paddr = (x * sizeof(unsigned int)) + target;
                        return;
                  }
            }
      }

      /* read CMOS for real top of mem */
      seekEntry((vm_offset_t)TOPOFMEM_POINTER);
      readEntry(&segment, 2);
      --segment;                                  /* less ONE_KBYTE */
      target = segment * 1024;
      seekEntry(target);
      readEntry(buffer, ONE_KBYTE);

      for (x = 0; x < ONE_KBYTE / sizeof (unsigned int); NEXT(x)) {
            if (buffer[ x ] == MP_SIG) {
                  *where = 2;
                  *paddr = (x * sizeof(unsigned int)) + target;
                  return;
            }
      }

      /* we don't necessarily believe CMOS, check base of the last 1K of 640K */
      if (target != (DEFAULT_TOPOFMEM - 1024)) {
            target = (DEFAULT_TOPOFMEM - 1024);
            seekEntry(target);
            readEntry(buffer, ONE_KBYTE);

            for (x = 0; x < ONE_KBYTE / sizeof (unsigned int); NEXT(x)) {
                  if (buffer[ x ] == MP_SIG) {
                        *where = 3;
                        *paddr = (x * sizeof(unsigned int)) + target;
                        return;
                  }
            }
      }

      /* search the BIOS */
      seekEntry(BIOS_BASE);
      readEntry(buffer, BIOS_SIZE);

      for (x = 0; x < BIOS_SIZE / sizeof(unsigned int); NEXT(x)) {
            if (buffer[ x ] == MP_SIG) {
                  *where = 4;
                  *paddr = (x * sizeof(unsigned int)) + BIOS_BASE;
                  return;
            }
      }

      /* search the extended BIOS */
      seekEntry(BIOS_BASE2);
      readEntry(buffer, BIOS_SIZE);

      for (x = 0; x < BIOS_SIZE / sizeof(unsigned int); NEXT(x)) {
            if (buffer[ x ] == MP_SIG) {
                  *where = 5;
                  *paddr = (x * sizeof(unsigned int)) + BIOS_BASE2;
                  return;
            }
      }

      /* search additional memory */
      target = GROPE_AREA1;
      seekEntry(target);
      readEntry(buffer, GROPE_SIZE);

      for (x = 0; x < GROPE_SIZE / sizeof(unsigned int); NEXT(x)) {
            if (buffer[ x ] == MP_SIG) {
                  *where = 6;
                  *paddr = (x * sizeof(unsigned int)) + GROPE_AREA1;
                  return;
            }
      }

      target = GROPE_AREA2;
      seekEntry(target);
      readEntry(buffer, GROPE_SIZE);

      for (x = 0; x < GROPE_SIZE / sizeof(unsigned int); NEXT(x)) {
            if (buffer[ x ] == MP_SIG) {
                  *where = 7;
                  *paddr = (x * sizeof(unsigned int)) + GROPE_AREA2;
                  return;
            }
      }

      *where = 0;
      *paddr = (vm_offset_t)0;
}

static int MPConfigTableHeader(void* pap)
{
      vm_offset_t paddr;
      mpcth_t      cth;
      int x;
      int totalSize, t;
      int count, c;

      if (pap == 0) {
            printf("MP Configuration Table Header MISSING!\n");
            return SMP_NO;
      }

      /* convert physical address to virtual address */
      paddr = (vm_offset_t)pap;

      /* read in cth structure */
      seekEntry(paddr);
      readEntry(&cth, sizeof(cth));

      totalSize = cth.base_table_length - sizeof(struct MPCTH);
      count = cth.entry_count;

      /* initialze tables */
      for (x = 0; x < 16; ++x)
            busses[ x ] = apics[ x ] = 0xff;

      ncpu = 0;
      nbus = 0;
      napic = 0;
      nintr = 0;

      /* process all the CPUs */
      if (verbose)
            printf("MP Table:\n#\tAPIC ID\tVersion\tState\t\tFamily\tModel\tStep\tFlags\n");
      for (t = totalSize, c = count; c; c--) {
            if (readType() == 0)
                  processorEntry();
            totalSize -= basetableEntryTypes[ 0 ].length;
      }
      if (verbose)
            printf ("\n");
      
      return SMP_YES;
}

static int readType(void)
{
      u_char type;

      if (read(pfd, &type, sizeof(u_char)) != sizeof(u_char)) {
            perror("type read");
            exit(1);
      }

      if (lseek(pfd, -1, SEEK_CUR) < 0) {
            perror("type seek");
            exit(1);
      }

      return (int)type;
}

static void seekEntry(vm_offset_t addr)
{
      if (lseek(pfd, (off_t)addr, SEEK_SET) < 0) {
            perror("/dev/mem seek");
            exit(1);
      }
}

static void readEntry(void* entry, int size)
{
      if (read(pfd, entry, size) != size) {
            perror("readEntry");
            exit(1);
      }
}

static void processorEntry(void)
{
      ProcEntry entry;

      /* read it into local memory */
      readEntry(&entry, sizeof(entry));

      /* count it */
      ++ncpu;

      if(verbose)
      {
            printf("#\t%2d", entry.apicID);
            printf("\t 0x%2x", entry.apicVersion);
            
            printf("\t %s, %s",
                        (entry.cpuFlags & PROCENTRY_FLAG_BP) ? "BSP" : "AP",
                        (entry.cpuFlags & PROCENTRY_FLAG_EN) ? "usable" : "unusable");
            
            printf("\t %ld\t %ld\t %ld",
                        (entry.cpuSignature >> 8) & 0x0f,
                        (entry.cpuSignature >> 4) & 0x0f,
                        entry.cpuSignature & 0x0f);
            
            printf("\t 0x%04lx\n", entry.featureFlags);
      }
}

#ifdef STANDALONE
int main()
{
      int   numcpu, smp;

      smp=issmp(&numcpu, 1);
      printf("SMP: %d\nCPU: %d\n", smp, numcpu);
      return 0;
}
#endif

Generated by  Doxygen 1.6.0   Back to index