Skip to contentSkip to conversation

2.6.0test1 broken /dev/mem mmap ?

DISCUSSION Dave Jones 1 participant 1 message Jul 16, 2003

lore
Share & tools
lore

Dave Jones

author
#0 lore raw

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