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