Chameleon

Chameleon Svn Source Tree

Root/branches/cparm/i386/libsaio/smp-imps.c

1/*
2 * <Insert copyright here : it must be BSD-like so anyone can use it>
3 *
4 * Author: Erich Boleyn <erich@uruk.org> http://www.uruk.org/~erich/
5 *
6 * Source file implementing Intel MultiProcessor Specification (MPS)
7 * version 1.1 and 1.4 SMP hardware control for Intel Architecture CPUs,
8 * with hooks for running correctly on a standard PC without the hardware.
9 *
10 * This file was created from information in the Intel MPS version 1.4
11 * document, order number 242016-004, which can be ordered from the
12 * Intel literature center.
13 *
14 * General limitations of this code:
15 *
16 * (1) : This code has never been tested on an MPS-compatible system with
17 * 486 CPUs, but is expected to work.
18 * (2) : Presumes "int", "long", and "unsigned" are 32 bits in size, and
19 * that 32-bit pointers and memory addressing is used uniformly.
20 */
21#include "libsaio.h"
22
23#define _SMP_IMPS_C
24
25
26/*
27 * XXXXX The following absolutely must be defined!!!
28 *
29 * The "KERNEL_PRINT" could be made a null macro with no danger, of
30 * course, but pretty much nothing would work without the other
31 * ones defined.
32 */
33
34
35#if 0
36#define CMOS_WRITE_BYTE(x,y)/* write unsigned char "y" at CMOS loc "x" */
37#define CMOS_READ_BYTE(x)/* read unsigned char at CMOS loc "x" */
38//#define TEST_BOOTED(x)/* test bootaddr x to see if CPU started */
39#define READ_MSR_LO(x)/* Read MSR low function */
40#endif
41
42#ifndef DEBUG_SMP
43#define DEBUG_SMP 0
44#endif
45
46#if DEBUG_SMP== 2
47#define DBG(x...)printf(x)
48#elif DEBUG_SMP == 1
49#define DBG(x...)msglog(x)
50#else
51#define DBG(x...)
52#endif
53
54#define PHYS_TO_VIRTUAL(x)ptov(x) /* convert physical address "x" to virtual */
55#define VIRTUAL_TO_PHYS(x)vtop(x) /* convert virtual address "x" to physical */
56
57#define CMOS_WRITE_BYTE(x, y)cmos_write_byte(x, y)
58#define CMOS_READ_BYTE(x)cmos_read_byte(x)
59/*
60 * Includes here
61 */
62
63
64#include "apic.h"
65#include "smp-imps.h"
66
67/*
68 * Defines that are here so as not to be in the global header file.
69 */
70#define EBDA_SEG_ADDR0x40E
71#define BIOS_RESET_VECTOR0x467
72#define LAPIC_ADDR_DEFAULT0xFEE00000uL
73#define IOAPIC_ADDR_DEFAULT0xFEC00000uL
74#define CMOS_RESET_CODE0xF
75#defineCMOS_RESET_JUMP0xa
76#define CMOS_BASE_MEMORY0x15
77
78/*
79 * Static defines here for SMP use.
80 */
81
82#define DEF_ENTRIES23
83
84static int lapic_dummy = 0;
85static struct {
86imps_processor proc[2];
87imps_bus bus[2];
88imps_ioapic ioapic;
89imps_interrupt intin[16];
90imps_interrupt lintin[2];
91} defconfig = {
92{ { IMPS_BCT_PROCESSOR, 0, 0, 0, 0, 0},
93 { IMPS_BCT_PROCESSOR, 1, 0, 0, 0, 0} },
94{ { IMPS_BCT_BUS, 0, {'E', 'I', 'S', 'A', ' ', ' '}},
95 { 255, 1, {'P', 'C', 'I', ' ', ' ', ' '}} },
96{ IMPS_BCT_IOAPIC, 0, 0, IMPS_FLAG_ENABLED, IOAPIC_ADDR_DEFAULT },
97{ { IMPS_BCT_IO_INTERRUPT, IMPS_INT_EXTINT, 0, 0, 0, 0xFF, 0},
98 { IMPS_BCT_IO_INTERRUPT, IMPS_INT_INT, 0, 0, 1, 0xFF, 1},
99 { IMPS_BCT_IO_INTERRUPT, IMPS_INT_INT, 0, 0, 0, 0xFF, 2},
100 { IMPS_BCT_IO_INTERRUPT, IMPS_INT_INT, 0, 0, 3, 0xFF, 3},
101 { IMPS_BCT_IO_INTERRUPT, IMPS_INT_INT, 0, 0, 4, 0xFF, 4},
102 { IMPS_BCT_IO_INTERRUPT, IMPS_INT_INT, 0, 0, 5, 0xFF, 5},
103 { IMPS_BCT_IO_INTERRUPT, IMPS_INT_INT, 0, 0, 6, 0xFF, 6},
104 { IMPS_BCT_IO_INTERRUPT, IMPS_INT_INT, 0, 0, 7, 0xFF, 7},
105 { IMPS_BCT_IO_INTERRUPT, IMPS_INT_INT, 0, 0, 8, 0xFF, 8},
106 { IMPS_BCT_IO_INTERRUPT, IMPS_INT_INT, 0, 0, 9, 0xFF, 9},
107 { IMPS_BCT_IO_INTERRUPT, IMPS_INT_INT, 0, 0, 10, 0xFF, 10},
108 { IMPS_BCT_IO_INTERRUPT, IMPS_INT_INT, 0, 0, 11, 0xFF, 11},
109 { IMPS_BCT_IO_INTERRUPT, IMPS_INT_INT, 0, 0, 12, 0xFF, 12},
110 { IMPS_BCT_IO_INTERRUPT, IMPS_INT_INT, 0, 0, 13, 0xFF, 13},
111 { IMPS_BCT_IO_INTERRUPT, IMPS_INT_INT, 0, 0, 14, 0xFF, 14},
112 { IMPS_BCT_IO_INTERRUPT, IMPS_INT_INT, 0, 0, 15, 0xFF, 15} },
113{ { IMPS_BCT_LOCAL_INTERRUPT, IMPS_INT_EXTINT, 0, 0, 15, 0xFF, 0},
114 { IMPS_BCT_LOCAL_INTERRUPT, IMPS_INT_NMI, 0, 0, 15, 0xFF, 1} }
115};
116
117/*
118 * Exported globals here.
119 */
120
121volatile int imps_release_cpus = 0;
122int imps_enabled = 0;
123int imps_num_cpus = 1;
124unsigned imps_lapic_addr = ((unsigned)(&lapic_dummy)) - LAPIC_ID;
125unsigned char imps_cpu_apic_map[IMPS_MAX_CPUS];
126unsigned char imps_apic_cpu_map[IMPS_MAX_CPUS];
127
128typedef struct msr_struct
129{
130unsigned lo;
131unsigned hi;
132} msr_t;
133
134static int imps_scan(unsigned start, unsigned length);
135static void imps_read_bios(imps_fps *fps_ptr);
136static int imps_bad_bios(imps_fps *fps_ptr);
137static void imps_read_config_table(unsigned start, int count);
138static void add_ioapic(imps_ioapic *ioapic);
139static void add_bus(imps_bus *bus);
140static void add_processor(imps_processor *proc);
141static int get_checksum(unsigned start, int length);
142
143#if BOOT_CPU
144static int boot_cpu(imps_processor *proc);
145static int send_ipi(unsigned int dst, unsigned int v);
146#endif
147
148static inline __attribute__((always_inline)) msr_t rdmsr(unsigned val)
149{
150msr_t ret;
151__asm__ volatile(
152 "rdmsr"
153 : "=a" (ret.lo), "=d" (ret.hi)
154 : "c" (val)
155 );
156return ret;
157}
158
159static inline __attribute__((always_inline)) void wrmsr(unsigned val, msr_t msr)
160{
161__asm__ __volatile__ (
162 "wrmsr"
163 : /* No outputs */
164 : "c" (val), "a" (msr.lo), "d" (msr.hi)
165 );
166}
167
168/*
169 * MPS checksum function
170 *
171 * Function finished.
172 */
173
174static int
175get_checksum(unsigned start, int length)
176{
177unsigned sum = 0;
178
179while (length-- > 0) {
180sum += *((unsigned char *) (start++));
181}
182
183return (sum&0xFF);
184}
185
186#if BOOT_CPU
187#if 0
188static inline void
189cmos_write_byte (int loc, int val)
190{
191outb (0x70, loc);
192outb (0x71, val);
193}
194
195static inline unsigned
196cmos_read_byte (int loc)
197{
198outb (0x70, loc);
199return inb (0x71);
200}
201#endif
202/*
203 * APIC ICR write and status check function.
204 */
205
206static int
207send_ipi(unsigned int dst, unsigned int v)
208{
209int to, send_status;
210
211IMPS_LAPIC_WRITE(LAPIC_ICR+0x10, (dst << 24));
212IMPS_LAPIC_WRITE(LAPIC_ICR, v);
213
214/* Wait for send to finish */
215to = 0;
216do {
217delay(100);
218send_status = IMPS_LAPIC_READ(LAPIC_ICR) & LAPIC_ICR_STATUS_PEND;
219} while (send_status && (to++ < 1000));
220
221return (to < 1000);
222}
223
224
225/*
226 * Primary function for booting individual CPUs.
227 *
228 * This must be modified to perform whatever OS-specific initialization
229 * that is required.
230 */
231
232static int
233boot_cpu(imps_processor *proc)
234{
235int apicid = proc->apic_id, success = 1/*, to*/;
236unsigned bootaddr, accept_status;
237unsigned bios_reset_vector = PHYS_TO_VIRTUAL(BIOS_RESET_VECTOR);
238
239/*
240 * Copy boot code for secondary CPUs here. Find it in between
241 * "patch_code_start" and "patch_code_end" symbols. The other CPUs
242 * will start there in 16-bit real mode under the 1MB boundary.
243 * "patch_code_start" should be placed at a 4K-aligned address
244 * under the 1MB boundary.
245 */
246
247//extern char ???[];
248//bootaddr = (512-64)*1024; ???
249//memcpy((char *)bootaddr, ,??? );
250
251/*
252 * Generic CPU startup sequence starts here.
253 */
254
255/* set BIOS reset vector */
256CMOS_WRITE_BYTE(CMOS_RESET_CODE, CMOS_RESET_JUMP);
257*((volatile unsigned *) bios_reset_vector) = ((bootaddr & 0xFF000) << 12);
258
259/* clear the APIC error register */
260IMPS_LAPIC_WRITE(LAPIC_ESR, 0);
261accept_status = IMPS_LAPIC_READ(LAPIC_ESR);
262
263/* assert INIT IPI */
264send_ipi(apicid, LAPIC_ICR_TM_LEVEL | LAPIC_ICR_LEVELASSERT | LAPIC_ICR_DM_INIT);
265
266delay(10000);
267
268/* de-assert INIT IPI */
269send_ipi(apicid, LAPIC_ICR_TM_LEVEL | LAPIC_ICR_DM_INIT);
270
271delay(10000);
272
273/*
274 * Send Startup IPIs if not an old pre-integrated APIC.
275 */
276
277if (proc->apic_ver >= APIC_VER_NEW) {
278int i;
279for (i = 1; i <= 2; i++) {
280send_ipi(apicid, LAPIC_ICR_DM_SIPI | ((bootaddr >> 12) & 0xFF));
281delay(1000);
282}
283}
284
285/*
286 * Generic CPU startup sequence ends here, the rest is cleanup.
287 */
288
289/* clear the APIC error register */
290IMPS_LAPIC_WRITE(LAPIC_ESR, 0);
291accept_status = IMPS_LAPIC_READ(LAPIC_ESR);
292
293/* clean up BIOS reset vector */
294CMOS_WRITE_BYTE(CMOS_RESET_CODE, 0);
295*((volatile unsigned *) bios_reset_vector) = 0;
296
297DBG("\n");
298
299return success;
300}
301#endif
302
303/*
304 * read bios stuff and fill tables
305 */
306
307static void
308add_processor(imps_processor *proc)
309{
310int apicid = proc->apic_id;
311
312msglog(" Processor [APIC id %d ver %d]: ",
313 apicid, proc->apic_ver);
314if (!(proc->flags & IMPS_FLAG_ENABLED)) {
315msglog("DISABLED\n");
316return;
317}
318if (proc->flags & (IMPS_CPUFLAG_BOOT)) {
319msglog("#0 BootStrap Processor (BSP)\n");
320return;
321}
322#if BOOT_CPU
323if (boot_cpu(proc)) {
324
325/* XXXXX add OS-specific setup for secondary CPUs here */
326
327imps_cpu_apic_map[imps_num_cpus] = apicid;
328imps_apic_cpu_map[apicid] = imps_num_cpus;
329imps_num_cpus++;
330}
331#else
332imps_cpu_apic_map[imps_num_cpus] = apicid;
333imps_apic_cpu_map[apicid] = imps_num_cpus;
334imps_num_cpus++;
335#endif
336
337}
338
339
340static void
341add_bus(imps_bus *bus)
342{
343char str[8];
344
345memcpy(str, bus->bus_type, 6);
346str[6] = 0;
347DBG(" Bus id %d is %s\n", bus->id, str);
348
349/* XXXXX add OS-specific code here */
350}
351
352static void
353add_ioapic(imps_ioapic *ioapic)
354{
355msglog("\n I/O APIC id %d ver %d, address: 0x%x ",
356 ioapic->id, ioapic->ver, ioapic->addr);
357if (!(ioapic->flags & IMPS_FLAG_ENABLED)) {
358msglog("DISABLED\n");
359return;
360}
361msglog("\n");
362
363/* XXXXX add OS-specific code here */
364}
365
366
367static void
368imps_read_config_table(unsigned start, int count)
369{
370while (count-- > 0) {
371switch (*((unsigned char *)start)) {
372case IMPS_BCT_PROCESSOR:
373add_processor((imps_processor *)start);
374start += 12;/* 20 total */
375break;
376case IMPS_BCT_BUS:
377add_bus((imps_bus *)start);
378break;
379case IMPS_BCT_IOAPIC:
380add_ioapic((imps_ioapic *)start);
381break;
382#if 0/* XXXXX uncomment this if "add_io_interrupt" is implemented */
383case IMPS_BCT_IO_INTERRUPT:
384add_io_interrupt((imps_interrupt *)start);
385break;
386#endif
387#if 0/* XXXXX uncomment this if "add_local_interrupt" is implemented */
388case IMPS_BCT_LOCAL_INTERRUPT:
389add_local_interupt((imps_interrupt *)start);
390break;
391#endif
392default:
393break;
394}
395start += 8;
396}
397}
398
399
400static int
401imps_bad_bios(imps_fps *fps_ptr)
402{
403int sum;
404imps_cth *local_cth_ptr
405= (imps_cth *) PHYS_TO_VIRTUAL(fps_ptr->cth_ptr);
406
407if (fps_ptr->feature_info[0] > IMPS_FPS_DEFAULT_MAX) {
408DBG(" Invalid MP System Configuration type %d\n",
409 fps_ptr->feature_info[0]);
410return 1;
411}
412
413if (fps_ptr->cth_ptr) {
414sum = get_checksum((unsigned)local_cth_ptr,
415 local_cth_ptr->base_length);
416if (local_cth_ptr->sig != IMPS_CTH_SIGNATURE || sum) {
417DBG(" Bad MP Config Table sig 0x%x and/or checksum 0x%x\n", (unsigned)(fps_ptr->cth_ptr), sum);
418return 1;
419}
420if (local_cth_ptr->spec_rev != fps_ptr->spec_rev) {
421DBG(" Bad MP Config Table sub-revision # %d\n", local_cth_ptr->spec_rev);
422return 1;
423}
424if (local_cth_ptr->extended_length) {
425sum = (get_checksum(((unsigned)local_cth_ptr)
426 + local_cth_ptr->base_length,
427 local_cth_ptr->extended_length)
428 + local_cth_ptr->extended_checksum) & 0xFF;
429if (sum) {
430DBG(" Bad Extended MP Config Table checksum 0x%x\n", sum);
431return 1;
432}
433}
434} else if (!fps_ptr->feature_info[0]) {
435DBG(" Missing configuration information\n");
436return 1;
437}
438
439return 0;
440}
441
442
443static void
444imps_read_bios(imps_fps *fps_ptr)
445{
446int apicid;
447unsigned cth_start, cth_count;
448imps_cth *local_cth_ptr
449= (imps_cth *)PHYS_TO_VIRTUAL(fps_ptr->cth_ptr);
450char *str_ptr;
451
452/*
453 * Do all checking of errors which would definitely
454 * lead to failure of the SMP boot here.
455 */
456
457if (imps_bad_bios(fps_ptr)) {
458DBG(" Disabling MPS support\n");
459return;
460}
461
462verbose("Intel MultiProcessor Spec 1.%d BIOS support detected\n",
463 fps_ptr->spec_rev);
464
465if (fps_ptr->feature_info[1] & IMPS_FPS_IMCRP_BIT) {
466str_ptr = "IMCR and PIC";
467} else {
468str_ptr = "Virtual Wire";
469}
470if (fps_ptr->cth_ptr) {
471imps_lapic_addr = local_cth_ptr->lapic_addr;
472} else {
473imps_lapic_addr = LAPIC_ADDR_DEFAULT;
474}
475msglog(" APIC config: \"%s mode\" Local APIC address: 0x%x\n",
476 str_ptr, imps_lapic_addr);
477//msr_t msr32 = rdmsr(0x1b);
478if (imps_lapic_addr != (rdmsr(0x1b).lo & 0xFFFFF000)) {
479DBG("Inconsistent Local APIC address, Disabling SMP support\n");
480return;
481}
482imps_lapic_addr = PHYS_TO_VIRTUAL(imps_lapic_addr);
483
484/*
485 * Setup primary CPU.
486 */
487apicid = IMPS_LAPIC_READ(LAPIC_SPIV);
488IMPS_LAPIC_WRITE(LAPIC_SPIV, apicid|LAPIC_SPIV_ENABLE_APIC);
489apicid = APIC_ID(IMPS_LAPIC_READ(LAPIC_ID));
490imps_cpu_apic_map[0] = apicid;
491imps_apic_cpu_map[apicid] = 0;
492
493if (fps_ptr->cth_ptr) {
494char str1[16], str2[16];
495memcpy(str1, local_cth_ptr->oem_id, 8);
496str1[8] = 0;
497memcpy(str2, local_cth_ptr->prod_id, 12);
498str2[12] = 0;
499msglog(" OEM id: %s Product id: %s\n", str1, str2);
500cth_start = ((unsigned) local_cth_ptr) + sizeof(imps_cth);
501cth_count = local_cth_ptr->entry_count;
502} else {
503*((volatile unsigned *) IOAPIC_ADDR_DEFAULT) = IOAPIC_ID;
504defconfig.ioapic.id
505= APIC_ID(*((volatile unsigned *)
506 (IOAPIC_ADDR_DEFAULT+IOAPIC_RW)));
507*((volatile unsigned *) IOAPIC_ADDR_DEFAULT) = IOAPIC_VER;
508defconfig.ioapic.ver
509= APIC_VERSION(*((volatile unsigned *)
510 (IOAPIC_ADDR_DEFAULT+IOAPIC_RW)));
511defconfig.proc[apicid].flags
512 = IMPS_FLAG_ENABLED|IMPS_CPUFLAG_BOOT;
513defconfig.proc[!apicid].flags = IMPS_FLAG_ENABLED;
514imps_num_cpus = 2;
515if (fps_ptr->feature_info[0] == 1
516 || fps_ptr->feature_info[0] == 5) {
517memcpy(defconfig.bus[0].bus_type, "ISA ", 6);
518}
519if (fps_ptr->feature_info[0] == 4
520 || fps_ptr->feature_info[0] == 7) {
521memcpy(defconfig.bus[0].bus_type, "MCA ", 6);
522}
523if (fps_ptr->feature_info[0] > 4) {
524defconfig.proc[0].apic_ver = 0x10;
525defconfig.proc[1].apic_ver = 0x10;
526defconfig.bus[1].type = IMPS_BCT_BUS;
527}
528if (fps_ptr->feature_info[0] == 2) {
529defconfig.intin[2].type = 255;
530defconfig.intin[13].type = 255;
531}
532if (fps_ptr->feature_info[0] == 7) {
533defconfig.intin[0].type = 255;
534}
535cth_start = (unsigned) &defconfig;
536cth_count = DEF_ENTRIES;
537}
538imps_read_config_table(cth_start, cth_count);
539
540/* %%%%% ESB read extended entries here */
541
542imps_enabled = 1;
543}
544
545
546/*
547 * Given a region to check, this actually looks for the "MP Floating
548 * Pointer Structure". The return value indicates if the correct
549 * signature and checksum for a floating pointer structure of the
550 * appropriate spec revision was found. If so, then do not search
551 * further.
552 *
553 * NOTE: The memory scan will always be in the bottom 1 MB.
554 *
555 * This function presumes that "start" will always be aligned to a 16-bit
556 * boundary.
557 *
558 * Function finished.
559 */
560imps_fps *gfps_ptr;
561
562static int
563imps_scan(unsigned start, unsigned length)
564{
565DBG("Scanning from 0x%x for %d bytes\n",
566 start, length);
567
568while (length > 0) {
569gfps_ptr = (imps_fps *) PHYS_TO_VIRTUAL(start);
570
571if (gfps_ptr->sig == IMPS_FPS_SIGNATURE
572 && gfps_ptr->length == 1
573 && (gfps_ptr->spec_rev == 1 || gfps_ptr->spec_rev == 4)
574 && !get_checksum(start, 16)) {
575DBG("Found MP Floating Structure Pointer at %x\n", start);
576imps_read_bios(gfps_ptr);
577
578return 1;
579}
580
581length -= 16;
582start += 16;
583}
584
585return 0;
586}
587
588#if BOOT_CPU
589/*
590 * This is the primary function to "force" SMP support, with
591 * the assumption that you have consecutively numbered APIC ids.
592 */
593int
594imps_force(int ncpus)
595{
596int apicid, i;
597imps_processor p;
598
599DBG("Intel MultiProcessor \"Force\" Support\n");
600
601imps_lapic_addr = (rdmsr(0x1b).lo & 0xFFFFF000);
602imps_lapic_addr = PHYS_TO_VIRTUAL(imps_lapic_addr);
603
604/*
605 * Setup primary CPU.
606 */
607apicid = IMPS_LAPIC_READ(LAPIC_SPIV);
608IMPS_LAPIC_WRITE(LAPIC_SPIV, apicid|LAPIC_SPIV_ENABLE_APIC);
609apicid = APIC_ID(IMPS_LAPIC_READ(LAPIC_ID));
610imps_cpu_apic_map[0] = apicid;
611imps_apic_cpu_map[apicid] = 0;
612
613p.type = 0;
614p.apic_ver = 0x10;
615p.signature = p.features = 0;
616
617for (i = 0; i < ncpus; i++) {
618if (apicid == i) {
619p.flags = IMPS_FLAG_ENABLED | IMPS_CPUFLAG_BOOT;
620} else {
621p.flags = IMPS_FLAG_ENABLED;
622}
623p.apic_id = i;
624add_processor(&p);
625}
626
627return imps_num_cpus;
628}
629#endif
630
631/*
632 * This is the primary function for probing for MPS compatible hardware
633 * and BIOS information. Call this during the early stages of OS startup,
634 * before memory can be messed up.
635 *
636 * The probe looks for the "MP Floating Pointer Structure" at locations
637 * listed at the top of page 4-2 of the spec.
638 *
639 * Environment requirements from the OS to run:
640 *
641 * (1) : A non-linear virtual to physical memory mapping is probably OK,
642 * as (I think) the structures all fall within page boundaries,
643 * but a linear mapping is recommended. Currently assumes that
644 * the mapping will remain identical over time (which should be
645 * OK since it only accesses memory which shouldn't be munged
646 * by the OS anyway).
647 * (2) : The OS only consumes memory which the BIOS says is OK to use,
648 * and not any of the BIOS standard areas (the areas 0x400 to
649 * 0x600, the EBDA, 0xE0000 to 0xFFFFF, and unreported physical
650 * RAM). Sometimes a small amount of physical RAM is not
651 * reported by the BIOS, to be used to store MPS and other
652 * information.
653 * (3) : It must be possible to read the CMOS.
654 * (4) : There must be between 512K and 640K of lower memory (this is a
655 * sanity check).
656 *
657 * Function finished.
658 */
659
660void *
661imps_probe(int * num_cpus)
662{
663/*
664 * Determine possible address of the EBDA
665 */
666unsigned ebda_addr = *((unsigned short *)
667 PHYS_TO_VIRTUAL(EBDA_SEG_ADDR)) << 4;
668
669/*
670 * Determine amount of installed lower memory (not *available*
671 * lower memory).
672 *
673 * NOTE: This should work reliably as long as we verify the
674 * machine is at least a system that could possibly have
675 * MPS compatibility to begin with.
676 */
677unsigned mem_lower = ((CMOS_READ_BYTE(CMOS_BASE_MEMORY+1) << 8)
678 | CMOS_READ_BYTE(CMOS_BASE_MEMORY)) << 10;
679
680#ifdef DEBUG_SMP
681#if BOOT_CPU
682imps_enabled = 0;
683imps_num_cpus = 1;
684#endif
685#endif
686
687/*
688 * Sanity check : if this isn't reasonable, it is almost impossibly
689 * unlikely to be an MPS compatible machine, so return failure.
690 */
691if (mem_lower < 512*1024 || mem_lower > 640*1024) {
692return 0;
693}
694
695if (ebda_addr > mem_lower - 1024
696 || ebda_addr + *((unsigned char *) PHYS_TO_VIRTUAL(ebda_addr))
697 * 1024 > mem_lower) {
698ebda_addr = 0;
699}
700
701if (((ebda_addr && imps_scan(ebda_addr, 1024))
702 || (!ebda_addr && imps_scan(mem_lower - 1024, 1024))
703 || imps_scan(0xF0000, 0x10000)) && imps_enabled) {
704*num_cpus = imps_num_cpus;
705msglog("\n");
706return gfps_ptr;
707}
708
709/*
710 * If no BIOS info on MPS hardware is found, then return failure.
711 */
712*num_cpus = 0;
713msglog("\n");
714return NULL;
715}
716

Archive Download this file

Revision: HEAD