lkml.org 
[lkml]   [2003]   [Jul]   [15]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    Date
    From
    Subject2.6.0test1 broken /dev/mem mmap ?
    The attached program works fine on some boxes, but not
    all in 2.6.0test1. It also works fine in 2.4, and up
    until recently, in all 2.5's.

    Ideas?

    Dave

    /*
    * 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.
    */

    #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>


    #define SMP_NO 0
    #define SMP_YES 1

    typedef unsigned int vm_offset_t;


    /* 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 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;

    /*
    * 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);

    /*
    * GOES SPLAT HERE ON A 2.6 KERNEL. --davej
    */
    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;
    }


    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;
    }


    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);
    }
    }


    int main()
    {
    int numcpu, smp;

    smp=issmp(&numcpu, 1);
    printf("SMP: %d\nCPU: %d\n", smp, numcpu);
    return 0;
    }
    \
     
     \ /
      Last update: 2005-03-22 13:46    [W:2.361 / U:0.008 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site