2 * Copyright (c) 1996, by Steve Passe
5 * hacked to make it work in userspace Linux by Ingo Molnar, same copyright
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. The name of the developer may NOT be used to endorse or promote products
13 * derived from this software without specific prior written permission.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 #include <sys/types.h>
40 typedef unsigned long vm_offset_t;
42 /* EBDA is @ 40:0e in real-mode terms */
43 #define EBDA_POINTER 0x040e /* location of EBDA pointer */
45 /* CMOS 'top of mem' is @ 40:13 in real-mode terms */
46 #define TOPOFMEM_POINTER 0x0413 /* BIOS: base memory size */
48 #define DEFAULT_TOPOFMEM 0xa0000
50 #define BIOS_BASE 0xf0000
51 #define BIOS_BASE2 0xe0000
52 #define BIOS_SIZE 0x10000
53 #define ONE_KBYTE 1024
55 #define GROPE_AREA1 0x80000
56 #define GROPE_AREA2 0x90000
57 #define GROPE_SIZE 0x10000
59 #define PROCENTRY_FLAG_EN 0x01
60 #define PROCENTRY_FLAG_BP 0x02
61 #define IOAPICENTRY_FLAG_EN 0x01
66 static int pfd; /* physical /dev/mem fd */
68 static int busses[16];
77 typedef struct TABLE_ENTRY {
83 static tableEntry basetableEntryTypes[] =
85 { 0, 20, "Processor" },
92 /* MP Floating Pointer Structure */
93 typedef struct MPFPS {
106 /* MP Configuration Table Header */
107 typedef struct MPCTH {
109 u16 base_table_length;
114 u32 oem_table_pointer;
118 u16 extended_table_length;
119 u8 extended_table_checksum;
123 typedef struct PROCENTRY {
135 static void seekEntry(vm_offset_t addr)
137 if (lseek(pfd, (off_t)addr, SEEK_SET) < 0) {
138 perror("/dev/mem seek");
143 static int readEntry(void* entry, int size)
145 if (read(pfd, entry, size) != size) {
152 static int readType(void)
156 if (read(pfd, &type, sizeof(unsigned char)) != sizeof(unsigned char)) {
161 if (lseek(pfd, -1, SEEK_CUR) < 0) {
169 static void processorEntry(void)
172 int t, family, model;
174 /* read it into local memory */
175 if (readEntry(&entry, sizeof(entry)) < 0) {
176 printf("Error reading processor entry\n");
184 printf("#\t%2d", (int) entry.apicID);
185 printf("\t 0x%2x", (unsigned int) entry.apicVersion);
188 (entry.cpuFlags & PROCENTRY_FLAG_BP) ? "BSP" : "AP",
189 (entry.cpuFlags & PROCENTRY_FLAG_EN) ? "usable" : "unusable");
191 t = (int) entry.cpuSignature;
192 family = (t >> 8) & 0xf;
193 model = (t >> 4) & 0xf;
195 family += (t >> 20) & 0xff;
196 model += (t >> 12) & 0xf0;
199 printf("\t %d\t %d\t %d", family, model, t & 0xf);
200 printf("\t 0x%04x\n", entry.featureFlags);
205 static int MPConfigTableHeader(u32 pap)
214 printf("MP Configuration Table Header MISSING!\n");
218 /* convert physical address to virtual address */
219 paddr = (vm_offset_t)pap;
221 /* read in cth structure */
223 if(readEntry(&cth, sizeof(cth))) {
224 printf("error reading MP Config table header structure\n");
228 totalSize = cth.base_table_length - sizeof(struct MPCTH);
229 count = cth.entry_count;
231 /* initialize tables */
232 for (x = 0; x < 16; ++x)
233 busses[ x ] = apics[ x ] = 0xff;
240 /* process all the CPUs */
242 printf("MP Table:\n#\tAPIC ID\tVersion\tState\t\tFamily\tModel\tStep\tFlags\n");
243 for (c = count; c; c--) {
246 totalSize -= basetableEntryTypes[ 0 ].length;
257 * set PHYSICAL address of MP floating pointer structure
259 #define NEXT(X) ((X) += 4)
260 static int apic_probe(vm_offset_t* paddr)
265 unsigned int buffer[BIOS_SIZE];
266 const char MP_SIG[]="_MP_";
268 /* search Extended Bios Data Area, if present */
269 seekEntry((vm_offset_t)EBDA_POINTER);
270 if (readEntry(&segment, 2)) {
271 printf("error reading EBDA pointer\n");
275 printf("\nEBDA points to: %x\n", segment);
277 if (segment) { /* search EBDA */
278 target = (vm_offset_t)segment << 4;
281 printf("EBDA segment ptr: %lx\n", target);
282 if (readEntry(buffer, ONE_KBYTE)) {
283 printf("error reading 1K from %p\n", (void *)target);
288 for (x = 0; x < ONE_KBYTE / 4; NEXT(x)) {
289 if (!strncmp((char *)&buffer[x], MP_SIG, 4)) {
290 *paddr = (x*4) + target;
296 /* read CMOS for real top of mem */
297 seekEntry((vm_offset_t)TOPOFMEM_POINTER);
298 if (readEntry(&segment, 2)) {
299 printf("error reading CMOS for real top of mem (%p)\n", (void *) TOPOFMEM_POINTER);
303 --segment; /* less ONE_KBYTE */
304 target = segment * 1024;
306 if (readEntry(buffer, ONE_KBYTE)) {
307 printf("error reading 1KB from %p\n", (void *)target);
312 for (x = 0; x < ONE_KBYTE/4; NEXT(x)) {
313 if (!strncmp((char *)&buffer[x], MP_SIG, 4)) {
314 *paddr = (x*4) + target;
319 /* we don't necessarily believe CMOS, check base of the last 1K of 640K */
320 if (target != (DEFAULT_TOPOFMEM - 1024)) {
321 target = (DEFAULT_TOPOFMEM - 1024);
323 if (readEntry(buffer, ONE_KBYTE)) {
324 printf("error reading DEFAULT_TOPOFMEM - 1024 from %p\n", (void *) target);
328 for (x = 0; x < ONE_KBYTE/4; NEXT(x)) {
329 if (!strncmp((char *)&buffer[x], MP_SIG, 4)) {
330 *paddr = (x*4) + target;
336 /* search the BIOS */
337 seekEntry(BIOS_BASE);
338 if (readEntry(buffer, BIOS_SIZE)) {
339 printf("error reading BIOS_BASE from %p\n", (void *)BIOS_BASE);
344 for (x = 0; x < BIOS_SIZE/4; NEXT(x)) {
345 if (!strncmp((char *)&buffer[x], MP_SIG, 4)) {
346 *paddr = (x*4) + BIOS_BASE;
351 /* search the extended BIOS */
352 seekEntry(BIOS_BASE2);
353 if (readEntry(buffer, BIOS_SIZE)) {
354 printf("error reading BIOS_BASE2 from %p\n", (void *)BIOS_BASE2);
359 for (x = 0; x < BIOS_SIZE/4; NEXT(x)) {
360 if (!strncmp((char *)&buffer[x], MP_SIG, 4)) {
361 *paddr = (x*4) + BIOS_BASE2;
366 /* search additional memory */
367 target = GROPE_AREA1;
369 if (readEntry(buffer, GROPE_SIZE)) {
370 printf("error reading GROPE_AREA1 from %p\n", (void *)target);
375 for (x = 0; x < GROPE_SIZE/4; NEXT(x)) {
376 if (!strncmp((char *)&buffer[x], MP_SIG, 4)) {
377 *paddr = (x*4) + GROPE_AREA1;
382 target = GROPE_AREA2;
384 if (readEntry(buffer, GROPE_SIZE)) {
385 printf("error reading GROPE_AREA2 from %p\n", (void *)target);
390 for (x = 0; x < GROPE_SIZE/4; NEXT(x)) {
391 if (!strncmp((char *)&buffer[x], MP_SIG, 4)) {
392 *paddr = (x*4) + GROPE_AREA2;
397 *paddr = (vm_offset_t)0;
402 int enumerate_cpus(void)
409 /* open physical memory for access to MP structures */
410 if ((pfd = open("/dev/mem", O_RDONLY)) < 0) {
411 fprintf(stderr, "enumerate_cpus(): /dev/mem: %s\n", strerror(errno));
415 /* probe for MP structures */
416 if (apic_probe(&paddr) <= 0)
419 /* read in mpfps structure*/
421 if (readEntry(&mpfps, sizeof(mpfps_t))) {
422 printf("error reading mpfpsfrom %p\n", (void *)paddr);
427 /* check whether an MP config table exists */
429 if (MPConfigTableHeader(mpfps.pap) == SMP_YES)
435 void display_mptable()
442 /* open physical memory for access to MP structures */
443 if ((pfd = open("/dev/mem", O_RDONLY)) < 0) {
444 fprintf(stderr, "%s(): /dev/mem: %s\n", __func__, strerror(errno));
448 /* probe for MP structures */
449 if (apic_probe(&paddr) <= 0)
452 /* read in mpfps structure*/
454 if (readEntry(&mpfps, sizeof(mpfps_t))) {
455 printf("error reading mpfps from %p\n", (void *)paddr);
460 /* parse an MP config table if it exists */
462 (void) MPConfigTableHeader(mpfps.pap);