flashrom: Update test status to TEST_OK_PREW for ST M50FLW080A and SST49LF008A
[coreboot.git] / util / mptable / mptable.c
1 /*
2  * Copyright (c) 1996, by Steve Passe
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. The name of the developer may NOT be used to endorse or promote products
11  *    derived from this software without specific prior written permission.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25
26 /*
27  * mptable.c
28  */
29
30 #ifndef lint
31 static const char rcsid[] =
32         "$Id$";
33 #endif /* not lint */
34
35 #define VMAJOR                  2
36 #define VMINOR                  0
37 #define VDELTA                  15
38
39 /*
40  * this will cause the raw mp table to be dumped to /tmp/mpdump
41  *
42 #define RAW_DUMP
43  */
44
45 #define MP_SIG                  0x5f504d5f      /* _MP_ */
46 #define EXTENDED_PROCESSING_READY
47 #define OEM_PROCESSING_READY_NOT
48
49 #include <sys/types.h>
50 #include <err.h>
51 #include <fcntl.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <unistd.h>
56
57 #define SEP_LINE \
58 "\n-------------------------------------------------------------------------------\n"
59
60 #define SEP_LINE2 \
61 "\n===============================================================================\n"
62
63 /* EBDA is @ 40:0e in real-mode terms */
64 #define EBDA_POINTER            0x040e          /* location of EBDA pointer */
65
66 /* CMOS 'top of mem' is @ 40:13 in real-mode terms */
67 #define TOPOFMEM_POINTER        0x0413          /* BIOS: base memory size */
68
69 #define DEFAULT_TOPOFMEM        0xa0000
70
71 #define BIOS_BASE               0xf0000
72 #define BIOS_BASE2              0xe0000
73 #define BIOS_SIZE               0x10000
74 #define ONE_KBYTE               1024
75
76 #define GROPE_AREA1             0x80000
77 #define GROPE_AREA2             0x90000
78 #define GROPE_SIZE              0x10000
79
80 #define PROCENTRY_FLAG_EN       0x01
81 #define PROCENTRY_FLAG_BP       0x02
82 #define IOAPICENTRY_FLAG_EN     0x01
83
84 #define MAXPNSTR                132
85
86 #define COREBOOT_MP_TABLE      0
87
88 enum busTypes {
89     CBUS = 1,
90     CBUSII = 2,
91     EISA = 3,
92     ISA = 6,
93     PCI = 13,
94     XPRESS = 18,
95     MAX_BUSTYPE = 18,
96     UNKNOWN_BUSTYPE = 0xff
97 };
98
99 typedef struct BUSTYPENAME {
100     u_char      type;
101     char        name[ 7 ];
102 } busTypeName;
103
104 static busTypeName busTypeTable[] =
105 {
106     { CBUS,             "CBUS"   },
107     { CBUSII,           "CBUSII" },
108     { EISA,             "EISA"   },
109     { UNKNOWN_BUSTYPE,  "---"    },
110     { UNKNOWN_BUSTYPE,  "---"    },
111     { ISA,              "ISA"    },
112     { UNKNOWN_BUSTYPE,  "---"    },
113     { UNKNOWN_BUSTYPE,  "---"    },
114     { UNKNOWN_BUSTYPE,  "---"    },
115     { UNKNOWN_BUSTYPE,  "---"    },
116     { UNKNOWN_BUSTYPE,  "---"    },
117     { UNKNOWN_BUSTYPE,  "---"    },
118     { PCI,              "PCI"    },
119     { UNKNOWN_BUSTYPE,  "---"    },
120     { UNKNOWN_BUSTYPE,  "---"    },
121     { UNKNOWN_BUSTYPE,  "---"    },
122     { UNKNOWN_BUSTYPE,  "---"    },
123     { UNKNOWN_BUSTYPE,  "---"    },
124     { UNKNOWN_BUSTYPE,  "---"    }
125 };
126
127 char* whereStrings[] = {
128     "Extended BIOS Data Area",
129     "BIOS top of memory",
130     "Default top of memory",
131     "BIOS",
132     "Extended BIOS",
133     "GROPE AREA #1",
134     "GROPE AREA #2"
135 };
136
137 typedef struct TABLE_ENTRY {
138     u_char      type;
139     u_char      length;
140     char        name[ 32 ];
141 } tableEntry;
142
143 tableEntry basetableEntryTypes[] =
144 {
145     { 0, 20, "Processor" },
146     { 1,  8, "Bus" },
147     { 2,  8, "I/O APIC" },
148     { 3,  8, "I/O INT" },
149     { 4,  8, "Local INT" }
150 };
151
152 tableEntry extendedtableEntryTypes[] =
153 {
154     { 128, 20, "System Address Space" },
155     { 129,  8, "Bus Heirarchy" },
156     { 130,  8, "Compatibility Bus Address" }
157 };
158
159 /* MP Floating Pointer Structure */
160 typedef struct MPFPS {
161     char        signature[ 4 ];
162     void*       pap;
163     u_char      length;
164     u_char      spec_rev;
165     u_char      checksum;
166     u_char      mpfb1;
167     u_char      mpfb2;
168     u_char      mpfb3;
169     u_char      mpfb4;
170     u_char      mpfb5;
171 } mpfps_t;
172
173 /* MP Configuration Table Header */
174 typedef struct MPCTH {
175     char        signature[ 4 ];
176     u_short     base_table_length;
177     u_char      spec_rev;
178     u_char      checksum;
179     u_char      oem_id[ 8 ];
180     u_char      product_id[ 12 ];
181     void*       oem_table_pointer;
182     u_short     oem_table_size;
183     u_short     entry_count;
184     void*       apic_address;
185     u_short     extended_table_length;
186     u_char      extended_table_checksum;
187     u_char      reserved;
188 } mpcth_t;
189
190
191 typedef struct PROCENTRY {
192     u_char      type;
193     u_char      apicID;
194     u_char      apicVersion;
195     u_char      cpuFlags;
196     u_long      cpuSignature;
197     u_long      featureFlags;
198     u_long      reserved1;
199     u_long      reserved2;
200 } ProcEntry;
201
202 typedef struct BUSENTRY {
203     u_char      type;
204     u_char      busID;
205     char        busType[ 6 ];
206 } BusEntry;
207
208 typedef struct IOAPICENTRY {
209     u_char      type;
210     u_char      apicID;
211     u_char      apicVersion;
212     u_char      apicFlags;
213     void*       apicAddress;
214 } IOApicEntry;
215
216 typedef struct INTENTRY {
217     u_char      type;
218     u_char      intType;
219     u_short     intFlags;
220     u_char      srcBusID;
221     u_char      srcBusIRQ;
222     u_char      dstApicID;
223     u_char      dstApicINT;
224 } IntEntry;
225
226
227 /*
228  * extended entry type structures
229  */
230
231 typedef struct SASENTRY {
232     u_char      type;
233     u_char      length;
234     u_char      busID;
235     u_char      addressType;
236     u_int64_t   addressBase;
237     u_int64_t   addressLength;
238 } SasEntry;
239
240
241 typedef struct BHDENTRY {
242     u_char      type;
243     u_char      length;
244     u_char      busID;
245     u_char      busInfo;
246     u_char      busParent;
247     u_char      reserved[ 3 ];
248 } BhdEntry;
249
250
251 typedef struct CBASMENTRY {
252     u_char      type;
253     u_char      length;
254     u_char      busID;
255     u_char      addressMod;
256     u_int       predefinedRange;
257 } CbasmEntry;
258
259
260 typedef unsigned long vm_offset_t;
261
262 static void apic_probe( vm_offset_t* paddr, int* where );
263
264 static void MPConfigDefault( int featureByte );
265
266 static void MPFloatingPointer( vm_offset_t paddr, int where, mpfps_t* mpfps );
267 static void MPConfigTableHeader( void* pap );
268
269 static int readType( void );
270 static void seekEntry( vm_offset_t addr );
271 static void readEntry( void* entry, int size );
272
273 static void processorEntry( void );
274 static void busEntry( void );
275 static void ioApicEntry( void );
276 static void intEntry( void );
277 static void lintEntry( void );
278
279 static void sasEntry( void );
280 static void bhdEntry( void );
281 static void cbasmEntry( void );
282
283 static void doOptionList( void );
284 static void doDmesg( void );
285 static void pnstr( char* s, int c );
286
287 /* global data */
288 int     pfd;            /* physical /dev/mem fd */
289
290 int     busses[ 16 ];
291 int     apics[ 16 ];
292
293 int     ncpu;
294 int     nbus;
295 int     napic;
296 int     nintr;
297
298 int     dmesg = 0;
299 int     grope = 0;
300 int     verbose = 0;
301 int     noisy = 0;
302 /* preamble to the mptable. This is fixed for all coreboots */
303  
304 char *preamble[] = {
305 "#include <console/console.h>",
306 "#include <arch/smp/mpspec.h>",
307 "#include <device/pci.h>",
308 "#include <string.h>",
309 "#include <stdint.h>",
310 "",
311 "void *smp_write_config_table(void *v)",
312 "{",
313 "        static const char sig[4] = \"PCMP\";",
314 "        static const char oem[8] = \"LNXI    \";",
315 "        static const char productid[12] = \"P4DPE       \";",
316 "        struct mp_config_table *mc;",
317 "",
318 "        mc = (void *)(((char *)v) + SMP_FLOATING_TABLE_LEN);",
319 "        memset(mc, 0, sizeof(*mc));",
320 "",
321 "        memcpy(mc->mpc_signature, sig, sizeof(sig));",
322 "        mc->mpc_length = sizeof(*mc); /* initially just the header */",
323 "        mc->mpc_spec = 0x04;",
324 "        mc->mpc_checksum = 0; /* not yet computed */",
325 "        memcpy(mc->mpc_oem, oem, sizeof(oem));",
326 "        memcpy(mc->mpc_productid, productid, sizeof(productid));",
327 "        mc->mpc_oemptr = 0;",
328 "        mc->mpc_oemsize = 0;",
329 "        mc->mpc_entry_count = 0; /* No entries yet... */",
330 "        mc->mpc_lapic = LAPIC_ADDR;",
331 "        mc->mpe_length = 0;",
332 "        mc->mpe_checksum = 0;",
333 "        mc->reserved = 0;",
334 "",
335 "        smp_write_processors(mc);",
336 "",
337 "",
338 0
339 };
340
341 char *postamble[] = {
342 "       /* There is no extension information... */",
343 "",
344 "       /* Compute the checksums */",
345 "       mc->mpe_checksum = smp_compute_checksum(smp_next_mpc_entry(mc), mc->mpe_length);",
346 "       mc->mpc_checksum = smp_compute_checksum(mc, mc->mpc_length);",
347 "       printk_debug(\"Wrote the mp table end at: %p - %p\\n\",",
348 "               mc, smp_next_mpe_entry(mc));",
349 "       return smp_next_mpe_entry(mc);",
350 "}",
351 "",
352 "unsigned long write_smp_table(unsigned long addr)",
353 "{",
354 "       void *v;",
355 "       v = smp_write_floating_table(addr);",
356 "       return (unsigned long)smp_write_config_table(v);",
357 "}",
358 0
359 };
360
361 char *ioapic_code[] = {
362 "       smp_write_ioapic(mc, 2, 0x20, 0xfec00000);",
363 "       {",
364 "               device_t dev;",
365 "               struct resource *res;",
366 "               dev = dev_find_slot(1, PCI_DEVFN(0x1e,0));",
367 "               if (dev) {",
368 "                       res = find_resource(dev, PCI_BASE_ADDRESS_0);",
369 "                       if (res) {",
370 "                               smp_write_ioapic(mc, 3, 0x20, res->base);",
371 "                       }",
372 "               }",
373 "               dev = dev_find_slot(1, PCI_DEVFN(0x1c,0));",
374 "               if (dev) {",
375 "                       res = find_resource(dev, PCI_BASE_ADDRESS_0);",
376 "                       if (res) {",
377 "                               smp_write_ioapic(mc, 4, 0x20, res->base);",
378 "                       }",
379 "               }",
380 "                dev = dev_find_slot(4, PCI_DEVFN(0x1e,0));",
381 "                if (dev) {",
382 "                       res = find_resource(dev, PCI_BASE_ADDRESS_0);",
383 "                       if (res) {",
384 "                               smp_write_ioapic(mc, 5, 0x20, res->base);",
385 "                       }",
386 "                }",
387 "                dev = dev_find_slot(4, PCI_DEVFN(0x1c,0));",
388 "                if (dev) {",
389 "                       res = find_resource(dev, PCI_BASE_ADDRESS_0);",
390 "                       if (res) {",
391 "                               smp_write_ioapic(mc, 8, 0x20, res->base);",
392 "                       }",
393 "                }",
394 "       }",
395 0
396 };
397 static void
398 usage( void )
399 {
400     fprintf( stderr, "usage: mptable [-dmesg] [-verbose] [-grope] [-help]\n" );
401     exit( 0 );
402 }
403
404 void
405 write_code(char **code)
406 {
407   while (*code)
408         printf("%s\n", *code++);
409 }
410 /*
411  * 
412  */
413 int
414 main( int argc, char *argv[] )
415 {
416     vm_offset_t paddr;
417     int         where;
418     mpfps_t     mpfps;
419     int         defaultConfig;
420
421     extern int  optreset;
422     int         ch;
423
424     /* announce ourselves */
425     
426     if (verbose) puts( SEP_LINE2 );
427
428     printf( "/* generated by MPTable, version %d.%d.%d*/\n", VMAJOR, VMINOR, VDELTA );
429     printf("/* as modified by RGM for coreboot */\n");
430     write_code(preamble);
431
432     /* Ron hates getopt() */
433
434     for(argc--, argv++; argc; argc--, argv++){
435       char *optarg = argv[0];
436       if ( strcmp( optarg, "-dmesg") == 0 ) {
437         dmesg = 1;
438       } else 
439         if ( strcmp( optarg, "-help") == 0 )
440           {
441             usage();
442           } else
443             if ( strcmp( optarg, "-grope") == 0 ){
444               grope = 1;
445             } else  if ( strcmp( optarg, "-verbose") == 0 )
446               verbose = 1;
447             else  if ( strcmp( optarg, "-noisy") == 0 )
448               noisy = 1;
449             else usage();
450     }
451
452     /* open physical memory for access to MP structures */
453     if ( (pfd = open( "/dev/mem", O_RDONLY )) < 0 )
454         err( 1, "mem open" );
455
456     /* probe for MP structures */
457     apic_probe( &paddr, &where );
458     if ( where <= 0 ) {
459         fprintf( stderr, "\n MP FPS NOT found,\n" );
460         fprintf( stderr, " suggest trying -grope option!!!\n\n" );
461         return 1;
462     }
463
464     if ( verbose )
465         printf( "\n MP FPS found in %s @ physical addr: 0x%08x\n",
466               whereStrings[ where - 1 ], paddr );
467
468     if (verbose) puts( SEP_LINE );
469
470     /* analyze the MP Floating Pointer Structure */
471     MPFloatingPointer( paddr, where, &mpfps );
472
473     if (verbose) puts( SEP_LINE );
474
475     /* check whether an MP config table exists */
476     if ( (defaultConfig = mpfps.mpfb1) )
477         MPConfigDefault( defaultConfig );
478     else
479         MPConfigTableHeader( mpfps.pap );
480
481     /* build "options" entries for the kernel config file */
482     if (noisy)
483       doOptionList();
484
485     write_code(postamble);
486     /* do a dmesg output */
487     if ( dmesg )
488         doDmesg();
489
490     if (verbose) puts( SEP_LINE2 );
491
492     return 0;
493 }
494
495
496 /*
497  * set PHYSICAL address of MP floating pointer structure
498  */
499 #define NEXT(X)         ((X) += 4)
500 static void
501 apic_probe( vm_offset_t* paddr, int* where )
502 {
503     /*
504      * c rewrite of apic_probe() by Jack F. Vogel
505      */
506
507     int         x;
508     u_short     segment;
509     vm_offset_t target;
510     u_int       buffer[ BIOS_SIZE / sizeof( int ) ];
511
512     if ( verbose )
513         printf( "\n" );
514
515     /* search Extended Bios Data Area, if present */
516     if ( verbose )
517         printf( " looking for EBDA pointer @ 0x%04x, ", EBDA_POINTER );
518     seekEntry( (vm_offset_t)EBDA_POINTER );
519     readEntry( &segment, 2 );
520     if ( segment ) {                /* search EBDA */
521         target = (vm_offset_t)segment << 4;
522         if ( verbose )
523             printf( "found, searching EBDA @ 0x%08x\n", target );
524         seekEntry( target );
525         readEntry( buffer, ONE_KBYTE );
526
527         for ( x = 0; x < ONE_KBYTE / sizeof ( unsigned int ); NEXT(x) ) {
528             if ( buffer[ x ] == MP_SIG ) {
529                 *where = 1;
530                 *paddr = (x * sizeof( unsigned int )) + target;
531                 return;
532             }
533         }
534     }
535     else {
536         if ( verbose )
537             printf( "NOT found\n" );
538     }
539
540     target = 0;
541     segment = 0;
542     if ( verbose )
543         printf( " searching for coreboot MP table  @ 0x%08x (%dK)\n",
544                 target, segment );
545     seekEntry( target );
546     readEntry( buffer, ONE_KBYTE );
547
548     for ( x = 0; x < ONE_KBYTE / sizeof ( unsigned int ); NEXT(x) ) {
549         if ( buffer[ x ] == MP_SIG ) {
550             *where = 2;
551             *paddr = (x * sizeof( unsigned int )) + target;
552             return;
553         }
554     }
555
556
557     /* read CMOS for real top of mem */
558     seekEntry( (vm_offset_t)TOPOFMEM_POINTER );
559     readEntry( &segment, 2 );
560     --segment;                                          /* less ONE_KBYTE */
561     target = segment * 1024;
562     if ( verbose )
563         printf( " searching CMOS 'top of mem' @ 0x%08x (%dK)\n",
564                 target, segment );
565     seekEntry( target );
566     readEntry( buffer, ONE_KBYTE );
567
568     for ( x = 0; x < ONE_KBYTE / sizeof ( unsigned int ); NEXT(x) ) {
569         if ( buffer[ x ] == MP_SIG ) {
570             *where = 2;
571             *paddr = (x * sizeof( unsigned int )) + target;
572             return;
573         }
574     }
575
576     /* we don't necessarily believe CMOS, check base of the last 1K of 640K */
577     if ( target != (DEFAULT_TOPOFMEM - 1024)) {
578         target = (DEFAULT_TOPOFMEM - 1024);
579         if ( verbose )
580             printf( " searching default 'top of mem' @ 0x%08x (%dK)\n",
581                     target, (target / 1024) );
582         seekEntry( target );
583         readEntry( buffer, ONE_KBYTE );
584
585         for ( x = 0; x < ONE_KBYTE / sizeof ( unsigned int ); NEXT(x) ) {
586             if ( buffer[ x ] == MP_SIG ) {
587                 *where = 3;
588                 *paddr = (x * sizeof( unsigned int )) + target;
589                 return;
590             }
591         }
592     }
593
594     /* search the BIOS */
595     if ( verbose )
596         printf( " searching BIOS @ 0x%08x\n", BIOS_BASE );
597     seekEntry( BIOS_BASE );
598     readEntry( buffer, BIOS_SIZE );
599
600     for ( x = 0; x < BIOS_SIZE / sizeof( unsigned int ); NEXT(x) ) {
601         if ( buffer[ x ] == MP_SIG ) {
602             *where = 4;
603             *paddr = (x * sizeof( unsigned int )) + BIOS_BASE;
604             return;
605         }
606     }
607
608     /* search the extended BIOS */
609     if ( verbose )
610         printf( " searching extended BIOS @ 0x%08x\n", BIOS_BASE2 );
611     seekEntry( BIOS_BASE2 );
612     readEntry( buffer, BIOS_SIZE );
613
614     for ( x = 0; x < BIOS_SIZE / sizeof( unsigned int ); NEXT(x) ) {
615         if ( buffer[ x ] == MP_SIG ) {
616             *where = 5;
617             *paddr = (x * sizeof( unsigned int )) + BIOS_BASE2;
618             return;
619         }
620     }
621
622     if ( grope ) {
623         /* search additional memory */
624         target = GROPE_AREA1;
625         if ( verbose )
626             printf( " groping memory @ 0x%08x\n", target );
627         seekEntry( target );
628         readEntry( buffer, GROPE_SIZE );
629
630         for ( x = 0; x < GROPE_SIZE / sizeof( unsigned int ); NEXT(x) ) {
631             if ( buffer[ x ] == MP_SIG ) {
632                 *where = 6;
633                 *paddr = (x * sizeof( unsigned int )) + GROPE_AREA1;
634                 return;
635             }
636         }
637
638         target = GROPE_AREA2;
639         if ( verbose )
640             printf( " groping memory @ 0x%08x\n", target );
641         seekEntry( target );
642         readEntry( buffer, GROPE_SIZE );
643
644         for ( x = 0; x < GROPE_SIZE / sizeof( unsigned int ); NEXT(x) ) {
645             if ( buffer[ x ] == MP_SIG ) {
646                 *where = 7;
647                 *paddr = (x * sizeof( unsigned int )) + GROPE_AREA2;
648                 return;
649             }
650         }
651     }
652
653     *where = 0;
654     *paddr = (vm_offset_t)0;
655 }
656
657
658 /*
659  * 
660  */
661 static void
662 MPFloatingPointer( vm_offset_t paddr, int where, mpfps_t* mpfps )
663 {
664
665     /* read in mpfps structure*/
666     seekEntry( paddr );
667     readEntry( mpfps, sizeof( mpfps_t ) );
668
669     /* show its contents */
670     if (verbose) {
671     printf( "MP Floating Pointer Structure:\n\n" );
672
673     printf( "  location:\t\t\t" );
674     switch ( where )
675     {
676     case 1:
677         printf( "EBDA\n" );
678         break;
679     case 2:
680         printf( "BIOS base memory\n" );
681         break;
682     case 3:
683         printf( "DEFAULT base memory (639K)\n" );
684         break;
685     case 4:
686         printf( "BIOS\n" );
687         break;
688     case 5:
689         printf( "Extended BIOS\n" );
690         break;
691
692     case 0:
693         printf( "NOT found!\n" );
694         exit( 1 );
695     default:
696         printf( "BOGUS!\n" );
697         exit( 1 );
698     }
699     printf( "  physical address:\t\t0x%08x\n", paddr );
700
701     printf( "  signature:\t\t\t'" );
702     pnstr( mpfps->signature, 4 );
703     printf( "'\n" );
704
705     printf( "  length:\t\t\t%d bytes\n", mpfps->length * 16 );
706     printf( "  version:\t\t\t1.%1d\n", mpfps->spec_rev );
707     printf( "  checksum:\t\t\t0x%02x\n", mpfps->checksum );
708
709     /* bits 0:6 are RESERVED */
710     if ( mpfps->mpfb2 & 0x7f ) {
711         printf( " warning, MP feature byte 2: 0x%02x\n", mpfps->mpfb2 );
712     }
713
714     /* bit 7 is IMCRP */
715     printf( "  mode:\t\t\t\t%s\n", (mpfps->mpfb2 & 0x80) ?
716             "PIC" : "Virtual Wire" );
717
718     /* MP feature bytes 3-5 are expected to be ZERO */
719     if ( mpfps->mpfb3 )
720         printf( " warning, MP feature byte 3 NONZERO!\n" );
721     if ( mpfps->mpfb4 )
722         printf( " warning, MP feature byte 4 NONZERO!\n" );
723     if ( mpfps->mpfb5 )
724         printf( " warning, MP feature byte 5 NONZERO!\n" );
725     }
726 }
727
728
729 /*
730  * 
731  */
732 static void
733 MPConfigDefault( int featureByte )
734 {
735     printf( "  MP default config type: %d\n\n", featureByte );
736     switch ( featureByte ) {
737     case 1:
738         printf( "   bus: ISA, APIC: 82489DX\n" );
739         break;
740     case 2:
741         printf( "   bus: EISA, APIC: 82489DX\n" );
742         break;
743     case 3:
744         printf( "   bus: EISA, APIC: 82489DX\n" );
745         break;
746     case 4:
747         printf( "   bus: MCA, APIC: 82489DX\n" );
748         break;
749     case 5:
750         printf( "   bus: ISA+PCI, APIC: Integrated\n" );
751         break;
752     case 6:
753         printf( "   bus: EISA+PCI, APIC: Integrated\n" );
754         break;
755     case 7:
756         printf( "   bus: MCA+PCI, APIC: Integrated\n" );
757         break;
758     default:
759         printf( "   future type\n" );
760         break;
761     }
762
763     switch ( featureByte ) {
764     case 1:
765     case 2:
766     case 3:
767     case 4:
768         nbus = 1;
769         break;
770     case 5:
771     case 6:
772     case 7:
773         nbus = 2;
774         break;
775     default:
776         printf( "   future type\n" );
777         break;
778     }
779
780     ncpu = 2;
781     napic = 1;
782     nintr = 16;
783 }
784
785
786 /*
787  * 
788  */
789 static void
790 MPConfigTableHeader( void* pap )
791 {
792     vm_offset_t paddr;
793     mpcth_t     cth;
794     int         x;
795     int         totalSize, t;
796     int         count, c;
797     int         type;
798
799     if ( pap == 0 ) {
800         printf( "MP Configuration Table Header MISSING!\n" );
801         exit( 1 );
802     }
803
804     /* convert physical address to virtual address */
805     paddr = (vm_offset_t)pap;
806
807     /* read in cth structure */
808     seekEntry( paddr );
809     readEntry( &cth, sizeof( cth ) );
810
811     if (verbose) {
812     printf( "MP Config Table Header:\n\n" );
813
814     printf( "  physical address:\t\t0x%08x\n", pap );
815
816     printf( "  signature:\t\t\t'" );
817     pnstr( cth.signature, 4 );
818     printf( "'\n" );
819
820     printf( "  base table length:\t\t%d\n", cth.base_table_length );
821
822     printf( "  version:\t\t\t1.%1d\n", cth.spec_rev );
823     printf( "  checksum:\t\t\t0x%02x\n", cth.checksum );
824
825     printf( "  OEM ID:\t\t\t'" );
826     pnstr( cth.oem_id, 8 );
827     printf( "'\n" );
828
829     printf( "  Product ID:\t\t\t'" );
830     pnstr( cth.product_id, 12 );
831     printf( "'\n" );
832
833     printf( "  OEM table pointer:\t\t0x%08x\n", cth.oem_table_pointer );
834     printf( "  OEM table size:\t\t%d\n", cth.oem_table_size );
835
836     printf( "  entry count:\t\t\t%d\n", cth.entry_count );
837
838     printf( "  local APIC address:\t\t0x%08x\n", cth.apic_address );
839
840     printf( "  extended table length:\t%d\n", cth.extended_table_length );
841     printf( "  extended table checksum:\t%d\n", cth.extended_table_checksum );
842     }
843
844     totalSize = cth.base_table_length - sizeof( struct MPCTH );
845     count = cth.entry_count;
846
847     if (verbose) {
848     if (verbose) puts( SEP_LINE );
849
850     printf( "MP Config Base Table Entries:\n\n" );
851     }
852
853     /* initialze tables */
854     for ( x = 0; x < 16; ++x ) {
855         busses[ x ] = apics[ x ] = 0xff;
856     }
857
858     ncpu = 0;
859     nbus = 0;
860     napic = 0;
861     nintr = 0;
862
863     /* process all the CPUs */
864     if (verbose) {
865     printf( "--\nProcessors:\tAPIC ID\tVersion\tState"
866             "\t\tFamily\tModel\tStep\tFlags\n" );
867     }
868     for ( t = totalSize, c = count; c; c-- ) {
869         if ( readType() == 0 )
870             processorEntry();
871         totalSize -= basetableEntryTypes[ 0 ].length;
872     }
873
874     /* process all the busses */
875     printf( "/*Bus:\t\tBus ID\tType*/\n" );
876     for ( t = totalSize, c = count; c; c-- ) {
877         if ( readType() == 1 )
878             busEntry();
879         totalSize -= basetableEntryTypes[ 1 ].length;
880     }
881
882     /* process all the apics */
883     printf( "/*I/O APICs:\tAPIC ID\tVersion\tState\t\tAddress*/\n" );
884     for ( t = totalSize, c = count; c; c-- ) {
885         if ( readType() == 2 )
886             ioApicEntry();
887         totalSize -= basetableEntryTypes[ 2 ].length;
888     }
889
890     write_code(ioapic_code);
891
892     /* process all the I/O Ints */
893     printf( "/*I/O Ints:\tType\tPolarity    Trigger\tBus ID\t IRQ\tAPIC ID\tPIN#\n*/" );
894     for ( t = totalSize, c = count; c; c-- ) {
895         if ( readType() == 3 )
896             intEntry();
897         totalSize -= basetableEntryTypes[ 3 ].length;
898     }
899
900     /* process all the Local Ints */
901     printf( "/*Local Ints:\tType\tPolarity    Trigger\tBus ID\t IRQ\tAPIC ID\tPIN#*/\n" );
902     for ( t = totalSize, c = count; c; c-- ) {
903         if ( readType() == 4 )
904             lintEntry();
905         totalSize -= basetableEntryTypes[ 4 ].length;
906     }
907
908
909 #if defined( EXTENDED_PROCESSING_READY )
910     /* process any extended data */
911     if ( (totalSize = cth.extended_table_length) ) {
912         if (verbose) puts( SEP_LINE );
913
914         printf( "MP Config Extended Table Entries:\n\n" );
915
916         while ( totalSize > 0 ) {
917             switch ( type = readType() ) {
918             case 128:
919                 sasEntry();
920                 break;
921             case 129:
922                 bhdEntry();
923                 break;
924             case 130:
925                 cbasmEntry();
926                 break;
927             default:
928                 printf( "Extended Table HOSED!\n" );
929                 exit( 1 );
930             }
931
932             totalSize -= extendedtableEntryTypes[ type-128 ].length;
933         }
934     }
935 #endif  /* EXTENDED_PROCESSING_READY */
936
937     /* process any OEM data */
938     if ( cth.oem_table_pointer && (cth.oem_table_size > 0) ) {
939 #if defined( OEM_PROCESSING_READY )
940 # error your on your own here!
941         /* convert OEM table pointer to virtual address */
942         poemtp = (vm_offset_t)cth.oem_table_pointer;
943
944         /* read in oem table structure */
945         if ( (oemdata = (void*)malloc( cth.oem_table_size )) == NULL )
946             err( 1, "oem malloc" );
947
948         seekEntry( poemtp );
949         readEntry( oemdata, cth.oem_table_size );
950
951         /** process it */
952
953         free( oemdata );
954 #else
955         printf( "\nyou need to modify the source to handle OEM data!\n\n" );
956 #endif  /* OEM_PROCESSING_READY */
957     }
958
959     fflush( stdout );
960
961 #if defined( RAW_DUMP )
962 {
963     int         ofd;
964     u_char      dumpbuf[ 4096 ];
965
966     ofd = open( "/tmp/mpdump", O_CREAT | O_RDWR );
967     seekEntry( paddr );
968     readEntry( dumpbuf, 1024 );
969     write( ofd, dumpbuf, 1024 );
970     close( ofd );
971 }
972 #endif /* RAW_DUMP */
973 }
974
975
976 /*
977  * 
978  */
979 static int
980 readType( void )
981 {
982     u_char      type;
983
984     if ( read( pfd, &type, sizeof( u_char ) ) != sizeof( u_char ) )
985         err( 1, "type read; pfd: %d", pfd );
986
987     if ( lseek( pfd, -1, SEEK_CUR ) < 0 )
988         err( 1, "type seek" );
989
990     return (int)type;
991 }
992
993
994 /*
995  * 
996  */
997 static void
998 seekEntry( vm_offset_t addr )
999 {
1000     if ( lseek( pfd, (off_t)addr, SEEK_SET ) < 0 )
1001         err( 1, "/dev/mem seek" );
1002 }
1003
1004
1005 /*
1006  * 
1007  */
1008 static void
1009 readEntry( void* entry, int size )
1010 {
1011     if ( read( pfd, entry, size ) != size )
1012         err( 1, "readEntry" );
1013 }
1014
1015
1016 static void
1017 processorEntry( void )
1018 {
1019     ProcEntry   entry;
1020
1021     /* read it into local memory */
1022     readEntry( &entry, sizeof( entry ) );
1023
1024     /* count it */
1025     ++ncpu;
1026     if (noisy) {
1027     printf( "\t\t%2d", entry.apicID );
1028     printf( "\t 0x%2x", entry.apicVersion );
1029
1030     printf( "\t %s, %s",
1031             (entry.cpuFlags & PROCENTRY_FLAG_BP) ? "BSP" : "AP",
1032             (entry.cpuFlags & PROCENTRY_FLAG_EN) ? "usable" : "unusable" );
1033
1034     printf( "\t %d\t %d\t %d",
1035             (entry.cpuSignature >> 8) & 0x0f,
1036             (entry.cpuSignature >> 4) & 0x0f,
1037             entry.cpuSignature & 0x0f );
1038
1039     printf( "\t 0x%04x\n", entry.featureFlags );
1040     }
1041 }
1042
1043
1044 /*
1045  * 
1046  */
1047 static int
1048 lookupBusType( char* name )
1049 {
1050     int x;
1051
1052     for ( x = 0; x < MAX_BUSTYPE; ++x )
1053         if ( strcmp( busTypeTable[ x ].name, name ) == 0 )
1054             return busTypeTable[ x ].type;
1055
1056     return UNKNOWN_BUSTYPE;
1057 }
1058
1059
1060 static void
1061 busEntry( void )
1062 {
1063     int         x;
1064     char        name[ 8 ];
1065     char        c;
1066     BusEntry    entry;
1067
1068     /* read it into local memory */
1069     readEntry( &entry, sizeof( entry ) );
1070
1071     /* count it */
1072     ++nbus;
1073
1074     if (verbose)  {
1075     printf( "\t\t%2d", entry.busID );
1076     printf( "\t " ); pnstr( entry.busType, 6 ); printf( "\n" );
1077     }
1078
1079     for ( x = 0; x < 6; ++x ) {
1080 //      if ( (c = entry.busType[ x ]) == ' ' )
1081             //break;
1082         name[ x ] = c;
1083     }
1084     name[ x ] = '\0';
1085     busses[ entry.busID ] = lookupBusType( name );
1086     printf("\tsmp_write_bus(mc, %d, \"", entry.busID);
1087     pnstr( entry.busType, 6 );
1088     printf("\");\n");
1089 }
1090
1091
1092 static void
1093 ioApicEntry( void )
1094 {
1095     IOApicEntry entry;
1096
1097     /* read it into local memory */
1098     readEntry( &entry, sizeof( entry ) );
1099
1100     /* count it */
1101     ++napic;
1102
1103     if (noisy) {
1104     printf( "\t\t%2d", entry.apicID );
1105     printf( "\t 0x%02x", entry.apicVersion );
1106     printf( "\t %s",
1107             (entry.apicFlags & IOAPICENTRY_FLAG_EN) ? "usable" : "unusable" );
1108     printf( "\t\t 0x%x\n", entry.apicAddress );
1109     }
1110
1111     apics[ entry.apicID ] = entry.apicID;
1112
1113     // the numbering and setup of ioapics is so irrational
1114     // that for now we will punt. 
1115 #if 0
1116     if (entry.apicFlags & IOAPICENTRY_FLAG_EN)
1117       printf("\tsmp_write_ioapic(mc, 0x%x, 0x%x, 0x%x);\n",
1118              entry.apicID, entry.apicVersion, entry.apicAddress);
1119 #endif
1120     
1121 }
1122
1123
1124 char* intTypes[] = {
1125     "mp_INT", "mp_NMI", "mp_SMI", "mp_ExtINT"
1126 };
1127
1128 char* polarityMode[] = {
1129     "MP_IRQ_POLARITY_DEFAULT", "MP_IRQ_POLARITY_HIGH", "reserved", "MP_IRQ_POLARITY_LOW"
1130 };
1131 char* triggerMode[] = {
1132     "MP_IRQ_TRIGGER_DEFAULT", "MP_IRQ_TRIGGER_EDGE", "reserved", "MP_IRQ_TRIGGER_LEVEL"
1133 };
1134
1135 static void
1136 intEntry( void )
1137 {
1138     IntEntry    entry;
1139
1140     /* read it into local memory */
1141     readEntry( &entry, sizeof( entry ) );
1142
1143     /* count it */
1144     if ( (int)entry.type == 3 )
1145         ++nintr;
1146
1147     if (noisy) {
1148     printf( "\n\t\t%s", intTypes[ (int)entry.intType ] );
1149
1150     printf( "\t%9s", polarityMode[ (int)entry.intFlags & 0x03 ] );
1151     printf( "%12s", triggerMode[ ((int)entry.intFlags >> 2) & 0x03 ] );
1152
1153     printf( "\t %5d", (int)entry.srcBusID );
1154     if ( busses[ (int)entry.srcBusID ] == PCI )
1155         printf( "\t%2d:%c", 
1156                 ((int)entry.srcBusIRQ >> 2) & 0x1f,
1157                 ((int)entry.srcBusIRQ & 0x03) + 'A' );
1158     else
1159         printf( "\t 0x%x:0x%x(0x%x)", 
1160                                 (int)entry.srcBusIRQ>>2,
1161                                 (int)entry.srcBusIRQ & 3,
1162                                 (int)entry.srcBusIRQ );
1163     printf( "\t %6d", (int)entry.dstApicID );
1164     printf( "\t %3d\n", (int)entry.dstApicINT );
1165     }
1166     printf("\tsmp_write_intsrc(mc, %s, %s|%s, 0x%x, 0x%x, 0x%x, 0x%x);\n",
1167            intTypes[ (int)entry.intType ],
1168            triggerMode[ ((int)entry.intFlags >> 2) & 0x03 ] ,
1169            polarityMode[ (int)entry.intFlags & 0x03 ],
1170            (int)entry.srcBusID,
1171            (int)entry.srcBusIRQ,
1172            (int)entry.dstApicID ,
1173            (int)entry.dstApicINT );
1174            
1175 }
1176
1177 static void
1178 lintEntry( void )
1179 {
1180     IntEntry    entry;
1181
1182     /* read it into local memory */
1183     readEntry( &entry, sizeof( entry ) );
1184
1185     /* count it */
1186     if ( (int)entry.type == 3 )
1187         ++nintr;
1188
1189     if (noisy) {
1190     printf( "\t\t%s", intTypes[ (int)entry.intType ] );
1191
1192     printf( "\t%9s", polarityMode[ (int)entry.intFlags & 0x03 ] );
1193     printf( "%12s", triggerMode[ ((int)entry.intFlags >> 2) & 0x03 ] );
1194
1195     printf( "\t %5d", (int)entry.srcBusID );
1196     if ( busses[ (int)entry.srcBusID ] == PCI )
1197         printf( "\t%2d:%c", 
1198                 ((int)entry.srcBusIRQ >> 2) & 0x1f,
1199                 ((int)entry.srcBusIRQ & 0x03) + 'A' );
1200     else
1201         printf( "\t %3d", (int)entry.srcBusIRQ );
1202     printf( "\t %6d", (int)entry.dstApicID );
1203     printf( "\t %3d\n", (int)entry.dstApicINT );
1204     }
1205     printf("\tsmp_write_intsrc(mc, %s, %s|%s, 0x%x, 0x%x, MP_APIC_ALL, 0x%x);\n",
1206            intTypes[ (int)entry.intType ],
1207            triggerMode[ ((int)entry.intFlags >> 2) & 0x03 ] ,
1208            polarityMode[ (int)entry.intFlags & 0x03 ],
1209            (int)entry.srcBusID,
1210            (int)entry.srcBusIRQ,
1211            (int)entry.dstApicINT );
1212            
1213 }
1214
1215
1216 static void
1217 sasEntry( void )
1218 {
1219     SasEntry    entry;
1220
1221     /* read it into local memory */
1222     readEntry( &entry, sizeof( entry ) );
1223
1224     printf( "--\n%s\n", extendedtableEntryTypes[ entry.type - 128 ].name );
1225     printf( " bus ID: %d", entry.busID );
1226     printf( " address type: " );
1227     switch ( entry.addressType ) {
1228     case 0:
1229         printf( "I/O address\n" );
1230         break;
1231     case 1:
1232         printf( "memory address\n" );
1233         break;
1234     case 2:
1235         printf( "prefetch address\n" );
1236         break;
1237     default:
1238         printf( "UNKNOWN type\n" );
1239         break;
1240     }
1241
1242     printf( " address base: 0x%qx\n", entry.addressBase );
1243     printf( " address range: 0x%qx\n", entry.addressLength );
1244 }
1245
1246
1247 static void
1248 bhdEntry( void )
1249 {
1250     BhdEntry    entry;
1251
1252     /* read it into local memory */
1253     readEntry( &entry, sizeof( entry ) );
1254
1255     printf( "--\n%s\n", extendedtableEntryTypes[ entry.type - 128 ].name );
1256     printf( " bus ID: %d", entry.busID );
1257     printf( " bus info: 0x%02x", entry.busInfo );
1258     printf( " parent bus ID: %d", entry.busParent );
1259 }
1260
1261
1262 static void
1263 cbasmEntry( void )
1264 {
1265     CbasmEntry  entry;
1266
1267     /* read it into local memory */
1268     readEntry( &entry, sizeof( entry ) );
1269
1270     printf( "--\n%s\n", extendedtableEntryTypes[ entry.type - 128 ].name );
1271     printf( " bus ID: %d", entry.busID );
1272     printf( " address modifier: %s\n", (entry.addressMod & 0x01) ?
1273                                         "subtract" : "add" );
1274     printf( " predefined range: 0x%08x", entry.predefinedRange );
1275 }
1276
1277
1278 /*
1279  * do a dmesg output
1280  */
1281 static void
1282 doDmesg( void )
1283 {
1284     if (verbose) puts( SEP_LINE );
1285
1286     printf( "dmesg output:\n\n" );
1287     fflush( stdout );
1288     system( "dmesg" );
1289 }
1290
1291
1292 /*
1293  *  build "options" entries for the kernel config file
1294  */
1295 static void
1296 doOptionList( void )
1297 {
1298     if (verbose) puts( SEP_LINE );
1299
1300     printf( "# SMP kernel config file options:\n\n" );
1301     printf( "\n# Required:\n" );
1302     printf( "options            SMP\t\t\t# Symmetric MultiProcessor Kernel\n" );
1303     printf( "options            APIC_IO\t\t\t# Symmetric (APIC) I/O\n" );
1304
1305     printf( "\n# Optional (built-in defaults will work in most cases):\n" );
1306     printf( "#options           NCPU=%d\t\t\t# number of CPUs\n", ncpu );
1307     printf( "#options           NBUS=%d\t\t\t# number of busses\n", nbus );
1308     printf( "#options           NAPIC=%d\t\t\t# number of IO APICs\n", napic );
1309     printf( "#options           NINTR=%d\t\t# number of INTs\n",
1310                 (nintr < 24) ? 24 : nintr );
1311 }
1312
1313
1314 /*
1315  * 
1316  */
1317 static void
1318 pnstr( char* s, int c )
1319 {
1320     char string[ MAXPNSTR + 1 ];
1321
1322     if ( c > MAXPNSTR )
1323         c = MAXPNSTR;
1324     strncpy( string, s, c );
1325     string[ c ] = '\0';
1326     printf( "%s", string );
1327 }