resetting manifest requested domain to floor
[platform/upstream/x86info.git] / mptable.c
1 /*
2  * Copyright (c) 1996, by Steve Passe
3  * All rights reserved.
4  *
5  * hacked to make it work in userspace Linux by Ingo Molnar, same copyright
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
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.
14  *
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
25  * SUCH DAMAGE.
26  */
27
28
29 #include <stdio.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <sys/types.h>
36
37 #include "mptable.h"
38 #include "x86info.h"
39
40 typedef unsigned long vm_offset_t;
41
42 /* EBDA is @ 40:0e in real-mode terms */
43 #define EBDA_POINTER                    0x040e            /* location of EBDA pointer */
44
45 /* CMOS 'top of mem' is @ 40:13 in real-mode terms */
46 #define TOPOFMEM_POINTER                0x0413            /* BIOS: base memory size */
47
48 #define DEFAULT_TOPOFMEM                0xa0000
49
50 #define BIOS_BASE                       0xf0000
51 #define BIOS_BASE2                      0xe0000
52 #define BIOS_SIZE                       0x10000
53 #define ONE_KBYTE                       1024
54
55 #define GROPE_AREA1                     0x80000
56 #define GROPE_AREA2                     0x90000
57 #define GROPE_SIZE                      0x10000
58
59 #define PROCENTRY_FLAG_EN       0x01
60 #define PROCENTRY_FLAG_BP       0x02
61 #define IOAPICENTRY_FLAG_EN     0x01
62
63 #define MAXPNSTR                132
64
65 /* global data */
66 static int pfd;                 /* physical /dev/mem fd */
67
68 static int      busses[16];
69 static int      apics[16];
70
71 static int      ncpu;
72 static int      nbus;
73 static int      napic;
74 static int      nintr;
75 static int      silent;
76
77 typedef struct TABLE_ENTRY {
78         u8      type;
79         u8      length;
80         char    name[32];
81 } tableEntry;
82
83 static tableEntry basetableEntryTypes[] =
84 {
85         { 0, 20, "Processor" },
86         { 1,  8, "Bus" },
87         { 2,  8, "I/O APIC" },
88         { 3,  8, "I/O INT" },
89         { 4,  8, "Local INT" }
90 };
91
92 /* MP Floating Pointer Structure */
93 typedef struct MPFPS {
94         char    signature[4];
95         u32     pap;
96         u8      length;
97         u8      spec_rev;
98         u8      checksum;
99         u8      mpfb1;
100         u8      mpfb2;
101         u8      mpfb3;
102         u8      mpfb4;
103         u8      mpfb5;
104 } mpfps_t;
105
106 /* MP Configuration Table Header */
107 typedef struct MPCTH {
108         char    signature[4];
109         u16     base_table_length;
110         u8      spec_rev;
111         u8      checksum;
112         u8      oem_id[8];
113         u8      product_id[12];
114         u32     oem_table_pointer;
115         u16     oem_table_size;
116         u16     entry_count;
117         u32     apic_address;
118         u16     extended_table_length;
119         u8      extended_table_checksum;
120         u8      reserved;
121 } mpcth_t;
122
123 typedef struct PROCENTRY {
124         u8      type;
125         u8      apicID;
126         u8      apicVersion;
127         u8      cpuFlags;
128         u32     cpuSignature;
129         u32     featureFlags;
130         u32     reserved1;
131         u32     reserved2;
132 } ProcEntry;
133
134
135 static void seekEntry(vm_offset_t addr)
136 {
137         if (lseek(pfd, (off_t)addr, SEEK_SET) < 0) {
138                 perror("/dev/mem seek");
139                 exit(EXIT_FAILURE);
140         }
141 }
142
143 static int readEntry(void* entry, int size)
144 {
145         if (read(pfd, entry, size) != size) {
146                 perror("readEntry");
147                 return -1;
148         }
149         return 0;
150 }
151
152 static int readType(void)
153 {
154         unsigned char type;
155
156         if (read(pfd, &type, sizeof(unsigned char)) != sizeof(unsigned char)) {
157                 perror("type read");
158                 exit(EXIT_FAILURE);
159         }
160
161         if (lseek(pfd, -1, SEEK_CUR) < 0) {
162                 perror("type seek");
163                 exit(EXIT_FAILURE);
164         }
165
166         return (int)type;
167 }
168
169 static void processorEntry(void)
170 {
171         ProcEntry entry;
172         int t, family, model;
173
174         /* read it into local memory */
175         if (readEntry(&entry, sizeof(entry)) < 0) {
176                 printf("Error reading processor entry\n");
177                 exit(EXIT_FAILURE);
178         }
179
180         /* count it */
181         ++ncpu;
182
183         if (!silent) {
184                 printf("#\t%2d", (int) entry.apicID);
185                 printf("\t 0x%2x", (unsigned int) entry.apicVersion);
186
187                 printf("\t %s, %s",
188                         (entry.cpuFlags & PROCENTRY_FLAG_BP) ? "BSP" : "AP",
189                         (entry.cpuFlags & PROCENTRY_FLAG_EN) ? "usable" : "unusable");
190
191                 t = (int) entry.cpuSignature;
192                 family = (t >> 8) & 0xf;
193                 model = (t >> 4) & 0xf;
194                 if (family == 0xf) {
195                         family += (t >> 20) & 0xff;
196                         model += (t >> 12) & 0xf0;
197                 }
198
199                 printf("\t %d\t %d\t %d", family, model, t & 0xf);
200                 printf("\t 0x%04x\n", entry.featureFlags);
201         }
202 }
203
204
205 static int MPConfigTableHeader(u32 pap)
206 {
207         vm_offset_t paddr;
208         mpcth_t cth;
209         int x;
210         int totalSize;
211         int count, c;
212
213         if (pap == 0) {
214                 printf("MP Configuration Table Header MISSING!\n");
215                 return SMP_NO;
216         }
217
218         /* convert physical address to virtual address */
219         paddr = (vm_offset_t)pap;
220
221         /* read in cth structure */
222         seekEntry(paddr);
223         if(readEntry(&cth, sizeof(cth))) {
224                 printf("error reading MP Config table header structure\n");
225                 exit(EXIT_FAILURE);
226         }
227
228         totalSize = cth.base_table_length - sizeof(struct MPCTH);
229         count = cth.entry_count;
230
231         /* initialize tables */
232         for (x = 0; x < 16; ++x)
233                 busses[ x ] = apics[ x ] = 0xff;
234
235         ncpu = 0;
236         nbus = 0;
237         napic = 0;
238         nintr = 0;
239
240         /* process all the CPUs */
241         if (!silent)
242                 printf("MP Table:\n#\tAPIC ID\tVersion\tState\t\tFamily\tModel\tStep\tFlags\n");
243         for (c = count; c; c--) {
244                 if (readType() == 0)
245                         processorEntry();
246                 totalSize -= basetableEntryTypes[ 0 ].length;
247         }
248         if (!silent)
249                 printf("\n");
250
251         return SMP_YES;
252 }
253
254
255
256 /*
257  * set PHYSICAL address of MP floating pointer structure
258  */
259 #define NEXT(X)         ((X) += 4)
260 static int apic_probe(vm_offset_t* paddr)
261 {
262         unsigned int x;
263         u16 segment;
264         vm_offset_t target;
265         unsigned int buffer[BIOS_SIZE];
266         const char MP_SIG[]="_MP_";
267
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");
272                 exit(EXIT_FAILURE);
273         }
274         if (debug)
275                 printf("\nEBDA points to: %x\n", segment);
276
277         if (segment) {                          /* search EBDA */
278                 target = (vm_offset_t)segment << 4;
279                 seekEntry(target);
280                 if (debug)
281                         printf("EBDA segment ptr: %lx\n", target);
282                 if (readEntry(buffer, ONE_KBYTE)) {
283                         printf("error reading 1K from %p\n", (void *)target);
284                         exit(EXIT_FAILURE);
285                 }
286
287
288                 for (x = 0; x < ONE_KBYTE / 4; NEXT(x)) {
289                         if (!strncmp((char *)&buffer[x], MP_SIG, 4)) {
290                                 *paddr = (x*4) + target;
291                                 return 1;
292                         }
293                 }
294         }
295
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);
300                 exit(EXIT_FAILURE);
301         }
302
303         --segment;                              /* less ONE_KBYTE */
304         target = segment * 1024;
305         seekEntry(target);
306         if (readEntry(buffer, ONE_KBYTE)) {
307                 printf("error reading 1KB from %p\n", (void *)target);
308                 exit(EXIT_FAILURE);
309         }
310
311
312         for (x = 0; x < ONE_KBYTE/4; NEXT(x)) {
313                 if (!strncmp((char *)&buffer[x], MP_SIG, 4)) {
314                         *paddr = (x*4) + target;
315                         return 2;
316                 }
317         }
318
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);
322                 seekEntry(target);
323                 if (readEntry(buffer, ONE_KBYTE)) {
324                         printf("error reading DEFAULT_TOPOFMEM - 1024 from %p\n", (void *) target);
325                         exit(EXIT_FAILURE);
326                 }
327
328                 for (x = 0; x < ONE_KBYTE/4; NEXT(x)) {
329                         if (!strncmp((char *)&buffer[x], MP_SIG, 4)) {
330                                 *paddr = (x*4) + target;
331                                 return 3;
332                         }
333                 }
334         }
335
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);
340                 exit(EXIT_FAILURE);
341         }
342
343
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;
347                         return 4;
348                 }
349         }
350
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);
355                 exit(EXIT_FAILURE);
356         }
357
358
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;
362                         return 4;
363                 }
364         }
365
366         /* search additional memory */
367         target = GROPE_AREA1;
368         seekEntry(target);
369         if (readEntry(buffer, GROPE_SIZE)) {
370                 printf("error reading GROPE_AREA1 from %p\n", (void *)target);
371                 exit(EXIT_FAILURE);
372         }
373
374
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;
378                         return 5;
379                 }
380         }
381
382         target = GROPE_AREA2;
383         seekEntry(target);
384         if (readEntry(buffer, GROPE_SIZE)) {
385                 printf("error reading GROPE_AREA2 from %p\n", (void *)target);
386                 exit(EXIT_FAILURE);
387         }
388
389
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;
393                         return 6;
394                 }
395         }
396
397         *paddr = (vm_offset_t)0;
398         return 0;
399 }
400
401
402 int enumerate_cpus(void)
403 {
404         vm_offset_t paddr;
405         mpfps_t mpfps;
406
407         silent = 1;
408
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));
412                 return -1;
413         }
414
415         /* probe for MP structures */
416         if (apic_probe(&paddr) <= 0)
417                 return 1;
418
419         /* read in mpfps structure*/
420         seekEntry(paddr);
421         if (readEntry(&mpfps, sizeof(mpfps_t))) {
422                 printf("error reading mpfpsfrom %p\n", (void *)paddr);
423                 exit(EXIT_FAILURE);
424         }
425
426
427         /* check whether an MP config table exists */
428         if (!mpfps.mpfb1)
429                 if (MPConfigTableHeader(mpfps.pap) == SMP_YES)
430                         return ncpu;
431
432         return 1;
433 }
434
435 void display_mptable()
436 {
437         vm_offset_t paddr;
438         mpfps_t mpfps;
439
440         silent = 0;
441
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));
445                 return;
446         }
447
448         /* probe for MP structures */
449         if (apic_probe(&paddr) <= 0)
450                 return;
451
452         /* read in mpfps structure*/
453         seekEntry(paddr);
454         if (readEntry(&mpfps, sizeof(mpfps_t))) {
455                 printf("error reading mpfps from %p\n", (void *)paddr);
456                 exit(EXIT_FAILURE);
457         }
458
459
460         /* parse an MP config table if it exists */
461         if (!mpfps.mpfb1)
462                 (void) MPConfigTableHeader(mpfps.pap);
463 }