source: mainline/kernel/arch/ia32/src/smp/mps.c@ 2ee1ccc

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 2ee1ccc was dc0b964, checked in by Martin Decky <martin@…>, 15 years ago
  • do not hardwire PRI??? formatting macros in the sources, use autotool to detect the correct values
  • use autotool to detect correct values for integer literal macros (UINT32_C, etc.)
  • start using portable UINT??_C style macros for integer constants
  • Property mode set to 100644
File size: 10.2 KB
Line 
1/*
2 * Copyright (c) 2008 Jakub Jermar
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 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup ia32
30 * @{
31 */
32/** @file
33 */
34
35#ifdef CONFIG_SMP
36
37#include <config.h>
38#include <print.h>
39#include <debug.h>
40#include <arch/smp/mps.h>
41#include <arch/smp/apic.h>
42#include <arch/smp/smp.h>
43#include <func.h>
44#include <typedefs.h>
45#include <cpu.h>
46#include <arch/asm.h>
47#include <arch/bios/bios.h>
48#include <mm/frame.h>
49
50/*
51 * MultiProcessor Specification detection code.
52 */
53
54#define FS_SIGNATURE UINT32_C(0x5f504d5f)
55#define CT_SIGNATURE UINT32_C(0x504d4350)
56
57static struct mps_fs *fs;
58static struct mps_ct *ct;
59
60static struct __processor_entry *processor_entries = NULL;
61static struct __bus_entry *bus_entries = NULL;
62static struct __io_apic_entry *io_apic_entries = NULL;
63static struct __io_intr_entry *io_intr_entries = NULL;
64static struct __l_intr_entry *l_intr_entries = NULL;
65
66static size_t io_apic_cnt = 0;
67
68static size_t processor_entry_cnt = 0;
69static size_t bus_entry_cnt = 0;
70static size_t io_apic_entry_cnt = 0;
71static size_t io_intr_entry_cnt = 0;
72static size_t l_intr_entry_cnt = 0;
73
74static uint8_t mps_cpu_apic_id(size_t i)
75{
76 ASSERT(i < processor_entry_cnt);
77
78 return processor_entries[i].l_apic_id;
79}
80
81static bool mps_cpu_enabled(size_t i)
82{
83 ASSERT(i < processor_entry_cnt);
84
85 /*
86 * FIXME: The current local APIC driver limits usable
87 * CPU IDs to 8.
88 *
89 */
90 if (i > 7)
91 return false;
92
93 return (bool) ((processor_entries[i].cpu_flags & 0x01) == 0x01);
94}
95
96static bool mps_cpu_bootstrap(size_t i)
97{
98 ASSERT(i < processor_entry_cnt);
99
100 return (bool) ((processor_entries[i].cpu_flags & 0x02) == 0x02);
101}
102
103static int mps_irq_to_pin(unsigned int irq)
104{
105 size_t i;
106
107 for (i = 0; i < io_intr_entry_cnt; i++) {
108 if (io_intr_entries[i].src_bus_irq == irq &&
109 io_intr_entries[i].intr_type == 0)
110 return io_intr_entries[i].dst_io_apic_pin;
111 }
112
113 return -1;
114}
115
116/** Implementation of IA-32 SMP configuration interface.
117 *
118 */
119struct smp_config_operations mps_config_operations = {
120 .cpu_enabled = mps_cpu_enabled,
121 .cpu_bootstrap = mps_cpu_bootstrap,
122 .cpu_apic_id = mps_cpu_apic_id,
123 .irq_to_pin = mps_irq_to_pin
124};
125
126/** Check the integrity of the MP Floating Structure.
127 *
128 */
129static bool mps_fs_check(uint8_t *base)
130{
131 unsigned int i;
132 uint8_t sum;
133
134 for (i = 0, sum = 0; i < 16; i++)
135 sum = (uint8_t) (sum + base[i]);
136
137 return (sum == 0);
138}
139
140/** Check the integrity of the MP Configuration Table.
141 *
142 */
143static bool mps_ct_check(void)
144{
145 uint8_t *base = (uint8_t *) ct;
146 uint8_t *ext = base + ct->base_table_length;
147 uint8_t sum;
148 uint16_t i;
149
150 /* Compute the checksum for the base table */
151 for (i = 0, sum = 0; i < ct->base_table_length; i++)
152 sum = (uint8_t) (sum + base[i]);
153
154 if (sum)
155 return false;
156
157 /* Compute the checksum for the extended table */
158 for (i = 0, sum = 0; i < ct->ext_table_length; i++)
159 sum = (uint8_t) (sum + ext[i]);
160
161 return (sum == ct->ext_table_checksum);
162}
163
164static void ct_processor_entry(struct __processor_entry *pr)
165{
166 /*
167 * Ignore processors which are not marked enabled.
168 */
169 if ((pr->cpu_flags & (1 << 0)) == 0)
170 return;
171
172 apic_id_mask |= (1 << pr->l_apic_id);
173}
174
175static void ct_bus_entry(struct __bus_entry *bus __attribute__((unused)))
176{
177#ifdef MPSCT_VERBOSE
178 char buf[7];
179
180 memcpy((void *) buf, (void *) bus->bus_type, 6);
181 buf[6] = 0;
182
183 printf("MPS: bus=%" PRIu8 " (%s)\n", bus->bus_id, buf);
184#endif
185}
186
187static void ct_io_apic_entry(struct __io_apic_entry *ioa)
188{
189 /* This I/O APIC is marked unusable */
190 if ((ioa->io_apic_flags & 1) == 0)
191 return;
192
193 if (io_apic_cnt++ > 0) {
194 /*
195 * Multiple I/O APICs are currently not supported.
196 */
197 return;
198 }
199
200 io_apic = (uint32_t *) (uintptr_t) ioa->io_apic;
201}
202
203static void ct_io_intr_entry(struct __io_intr_entry *iointr
204 __attribute__((unused)))
205{
206#ifdef MPSCT_VERBOSE
207 printf("MPS: ");
208
209 switch (iointr->intr_type) {
210 case 0:
211 printf("INT");
212 break;
213 case 1:
214 printf("NMI");
215 break;
216 case 2:
217 printf("SMI");
218 break;
219 case 3:
220 printf("ExtINT");
221 break;
222 }
223
224 printf(", ");
225
226 switch (iointr->poel & 3) {
227 case 0:
228 printf("bus-like");
229 break;
230 case 1:
231 printf("active high");
232 break;
233 case 2:
234 printf("reserved");
235 break;
236 case 3:
237 printf("active low");
238 break;
239 }
240
241 printf(", ");
242
243 switch ((iointr->poel >> 2) & 3) {
244 case 0:
245 printf("bus-like");
246 break;
247 case 1:
248 printf("edge-triggered");
249 break;
250 case 2:
251 printf("reserved");
252 break;
253 case 3:
254 printf("level-triggered");
255 break;
256 }
257
258 printf(", bus=%" PRIu8 " irq=%" PRIu8 " io_apic=%" PRIu8" pin=%"
259 PRIu8 "\n", iointr->src_bus_id, iointr->src_bus_irq,
260 iointr->dst_io_apic_id, iointr->dst_io_apic_pin);
261#endif
262}
263
264static void ct_l_intr_entry(struct __l_intr_entry *lintr
265 __attribute__((unused)))
266{
267#ifdef MPSCT_VERBOSE
268 printf("MPS: ");
269
270 switch (lintr->intr_type) {
271 case 0:
272 printf("INT");
273 break;
274 case 1:
275 printf("NMI");
276 break;
277 case 2:
278 printf("SMI");
279 break;
280 case 3:
281 printf("ExtINT");
282 break;
283 }
284
285 printf(", ");
286
287 switch (lintr->poel & 3) {
288 case 0:
289 printf("bus-like");
290 break;
291 case 1:
292 printf("active high");
293 break;
294 case 2:
295 printf("reserved");
296 break;
297 case 3:
298 printf("active low");
299 break;
300 }
301
302 printf(", ");
303
304 switch ((lintr->poel >> 2) & 3) {
305 case 0:
306 printf("bus-like");
307 break;
308 case 1:
309 printf("edge-triggered");
310 break;
311 case 2:
312 printf("reserved");
313 break;
314 case 3:
315 printf("level-triggered");
316 break;
317 }
318
319 printf(", bus=%" PRIu8 " irq=%" PRIu8 " l_apic=%" PRIu8" pin=%"
320 PRIu8 "\n", lintr->src_bus_id, lintr->src_bus_irq,
321 lintr->dst_l_apic_id, lintr->dst_l_apic_pin);
322#endif
323}
324
325static void ct_extended_entries(void)
326{
327 uint8_t *ext = (uint8_t *) ct + ct->base_table_length;
328 uint8_t *cur;
329
330 for (cur = ext; cur < ext + ct->ext_table_length;
331 cur += cur[CT_EXT_ENTRY_LEN]) {
332 switch (cur[CT_EXT_ENTRY_TYPE]) {
333 default:
334 printf("MPS: Skipping MP Configuration Table extended "
335 "entry type %" PRIu8 "\n", cur[CT_EXT_ENTRY_TYPE]);
336 }
337 }
338}
339
340static void configure_via_ct(void)
341{
342 if (ct->signature != CT_SIGNATURE) {
343 printf("MPS: Wrong ct->signature\n");
344 return;
345 }
346
347 if (!mps_ct_check()) {
348 printf("MPS: Wrong ct checksum\n");
349 return;
350 }
351
352 if (ct->oem_table) {
353 printf("MPS: ct->oem_table not supported\n");
354 return;
355 }
356
357 l_apic = (uint32_t *) (uintptr_t) ct->l_apic;
358
359 uint8_t *cur = &ct->base_table[0];
360 uint16_t i;
361
362 for (i = 0; i < ct->entry_count; i++) {
363 switch (*cur) {
364 case 0: /* Processor entry */
365 processor_entries = processor_entries ?
366 processor_entries :
367 (struct __processor_entry *) cur;
368 processor_entry_cnt++;
369 ct_processor_entry((struct __processor_entry *) cur);
370 cur += 20;
371 break;
372 case 1: /* Bus entry */
373 bus_entries = bus_entries ?
374 bus_entries : (struct __bus_entry *) cur;
375 bus_entry_cnt++;
376 ct_bus_entry((struct __bus_entry *) cur);
377 cur += 8;
378 break;
379 case 2: /* I/O APIC */
380 io_apic_entries = io_apic_entries ?
381 io_apic_entries : (struct __io_apic_entry *) cur;
382 io_apic_entry_cnt++;
383 ct_io_apic_entry((struct __io_apic_entry *) cur);
384 cur += 8;
385 break;
386 case 3: /* I/O Interrupt Assignment */
387 io_intr_entries = io_intr_entries ?
388 io_intr_entries : (struct __io_intr_entry *) cur;
389 io_intr_entry_cnt++;
390 ct_io_intr_entry((struct __io_intr_entry *) cur);
391 cur += 8;
392 break;
393 case 4: /* Local Interrupt Assignment */
394 l_intr_entries = l_intr_entries ?
395 l_intr_entries : (struct __l_intr_entry *) cur;
396 l_intr_entry_cnt++;
397 ct_l_intr_entry((struct __l_intr_entry *) cur);
398 cur += 8;
399 break;
400 default:
401 /*
402 * Something is wrong. Fallback to UP mode.
403 */
404 printf("MPS: ct badness %" PRIu8 "\n", *cur);
405 return;
406 }
407 }
408
409 /*
410 * Process extended entries.
411 */
412 ct_extended_entries();
413}
414
415static void configure_via_default(uint8_t n __attribute__((unused)))
416{
417 /*
418 * Not yet implemented.
419 */
420 printf("MPS: Default configuration not supported\n");
421}
422
423void mps_init(void)
424{
425 uint8_t *addr[2] = { NULL, (uint8_t *) PA2KA(0xf0000) };
426 unsigned int i;
427 unsigned int j;
428 unsigned int length[2] = { 1024, 64 * 1024 };
429
430 /*
431 * Find MP Floating Pointer Structure
432 * 1a. search first 1K of EBDA
433 * 1b. if EBDA is undefined, search last 1K of base memory
434 * 2. search 64K starting at 0xf0000
435 */
436
437 addr[0] = (uint8_t *) PA2KA(ebda ? ebda : 639 * 1024);
438 for (i = 0; i < 2; i++) {
439 for (j = 0; j < length[i]; j += 16) {
440 if ((*((uint32_t *) &addr[i][j]) ==
441 FS_SIGNATURE) && (mps_fs_check(&addr[i][j]))) {
442 fs = (struct mps_fs *) &addr[i][j];
443 goto fs_found;
444 }
445 }
446 }
447
448 return;
449
450fs_found:
451 printf("%p: MPS Floating Pointer Structure\n", fs);
452
453 if ((fs->config_type == 0) && (fs->configuration_table)) {
454 if (fs->mpfib2 >> 7) {
455 printf("MPS: PIC mode not supported\n");
456 return;
457 }
458
459 ct = (struct mps_ct *) PA2KA((uintptr_t) fs->configuration_table);
460 configure_via_ct();
461 } else
462 configure_via_default(fs->config_type);
463
464 if (processor_entry_cnt > 0)
465 config.cpu_count = processor_entry_cnt;
466}
467
468#endif /* CONFIG_SMP */
469
470/** @}
471 */
Note: See TracBrowser for help on using the repository browser.