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

Last change on this file was c5429fe, checked in by Jakub Jermar <jakub@…>, 7 years ago

Disambiguate architecture specific doxygroups

  • Property mode set to 100644
File size: 10.4 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 kernel_ia32
30 * @{
31 */
32/** @file
33 */
34
35#ifdef CONFIG_SMP
36
37#include <config.h>
38#include <log.h>
39#include <arch/smp/mps.h>
40#include <arch/smp/apic.h>
41#include <arch/smp/smp.h>
42#include <assert.h>
43#include <halt.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 ((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 ((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 log(LF_ARCH, LVL_DEBUG, "MPS: bus=%" PRIu8 " (%s)", 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 log_begin(LF_ARCH, LVL_DEBUG);
208 log_printf("MPS: ");
209
210 switch (iointr->intr_type) {
211 case 0:
212 log_printf("INT");
213 break;
214 case 1:
215 log_printf("NMI");
216 break;
217 case 2:
218 log_printf("SMI");
219 break;
220 case 3:
221 log_printf("ExtINT");
222 break;
223 }
224
225 log_printf(", ");
226
227 switch (iointr->poel & 3) {
228 case 0:
229 log_printf("bus-like");
230 break;
231 case 1:
232 log_printf("active high");
233 break;
234 case 2:
235 log_printf("reserved");
236 break;
237 case 3:
238 log_printf("active low");
239 break;
240 }
241
242 log_printf(", ");
243
244 switch ((iointr->poel >> 2) & 3) {
245 case 0:
246 log_printf("bus-like");
247 break;
248 case 1:
249 log_printf("edge-triggered");
250 break;
251 case 2:
252 log_printf("reserved");
253 break;
254 case 3:
255 log_printf("level-triggered");
256 break;
257 }
258
259 log_printf(", bus=%" PRIu8 " irq=%" PRIu8 " io_apic=%" PRIu8 " pin=%"
260 PRIu8, iointr->src_bus_id, iointr->src_bus_irq,
261 iointr->dst_io_apic_id, iointr->dst_io_apic_pin);
262 log_end();
263#endif
264}
265
266static void ct_l_intr_entry(struct __l_intr_entry *lintr
267 __attribute__((unused)))
268{
269#ifdef MPSCT_VERBOSE
270 log_begin(LF_ARCH, LVL_DEBUG);
271 log_printf("MPS: ");
272
273 switch (lintr->intr_type) {
274 case 0:
275 log_printf("INT");
276 break;
277 case 1:
278 log_printf("NMI");
279 break;
280 case 2:
281 log_printf("SMI");
282 break;
283 case 3:
284 log_printf("ExtINT");
285 break;
286 }
287
288 log_printf(", ");
289
290 switch (lintr->poel & 3) {
291 case 0:
292 log_printf("bus-like");
293 break;
294 case 1:
295 log_printf("active high");
296 break;
297 case 2:
298 log_printf("reserved");
299 break;
300 case 3:
301 log_printf("active low");
302 break;
303 }
304
305 log_printf(", ");
306
307 switch ((lintr->poel >> 2) & 3) {
308 case 0:
309 log_printf("bus-like");
310 break;
311 case 1:
312 log_printf("edge-triggered");
313 break;
314 case 2:
315 log_printf("reserved");
316 break;
317 case 3:
318 log_printf("level-triggered");
319 break;
320 }
321
322 log_printf(", bus=%" PRIu8 " irq=%" PRIu8 " l_apic=%" PRIu8 " pin=%"
323 PRIu8, lintr->src_bus_id, lintr->src_bus_irq,
324 lintr->dst_l_apic_id, lintr->dst_l_apic_pin);
325 log_end();
326#endif
327}
328
329static void ct_extended_entries(void)
330{
331 uint8_t *ext = (uint8_t *) ct + ct->base_table_length;
332 uint8_t *cur;
333
334 for (cur = ext; cur < ext + ct->ext_table_length;
335 cur += cur[CT_EXT_ENTRY_LEN]) {
336 switch (cur[CT_EXT_ENTRY_TYPE]) {
337 default:
338 log(LF_ARCH, LVL_NOTE, "MPS: Skipping MP Configuration"
339 " Table extended entry type %" PRIu8,
340 cur[CT_EXT_ENTRY_TYPE]);
341 }
342 }
343}
344
345static void configure_via_ct(void)
346{
347 if (ct->signature != CT_SIGNATURE) {
348 log(LF_ARCH, LVL_WARN, "MPS: Wrong ct->signature");
349 return;
350 }
351
352 if (!mps_ct_check()) {
353 log(LF_ARCH, LVL_WARN, "MPS: Wrong ct checksum");
354 return;
355 }
356
357 if (ct->oem_table) {
358 log(LF_ARCH, LVL_WARN, "MPS: ct->oem_table not supported");
359 return;
360 }
361
362 l_apic = (uint32_t *) (uintptr_t) ct->l_apic;
363
364 uint8_t *cur = &ct->base_table[0];
365 uint16_t i;
366
367 for (i = 0; i < ct->entry_count; i++) {
368 switch (*cur) {
369 case 0: /* Processor entry */
370 processor_entries = processor_entries ?
371 processor_entries :
372 (struct __processor_entry *) cur;
373 processor_entry_cnt++;
374 ct_processor_entry((struct __processor_entry *) cur);
375 cur += 20;
376 break;
377 case 1: /* Bus entry */
378 bus_entries = bus_entries ?
379 bus_entries : (struct __bus_entry *) cur;
380 bus_entry_cnt++;
381 ct_bus_entry((struct __bus_entry *) cur);
382 cur += 8;
383 break;
384 case 2: /* I/O APIC */
385 io_apic_entries = io_apic_entries ?
386 io_apic_entries : (struct __io_apic_entry *) cur;
387 io_apic_entry_cnt++;
388 ct_io_apic_entry((struct __io_apic_entry *) cur);
389 cur += 8;
390 break;
391 case 3: /* I/O Interrupt Assignment */
392 io_intr_entries = io_intr_entries ?
393 io_intr_entries : (struct __io_intr_entry *) cur;
394 io_intr_entry_cnt++;
395 ct_io_intr_entry((struct __io_intr_entry *) cur);
396 cur += 8;
397 break;
398 case 4: /* Local Interrupt Assignment */
399 l_intr_entries = l_intr_entries ?
400 l_intr_entries : (struct __l_intr_entry *) cur;
401 l_intr_entry_cnt++;
402 ct_l_intr_entry((struct __l_intr_entry *) cur);
403 cur += 8;
404 break;
405 default:
406 /*
407 * Something is wrong. Fallback to UP mode.
408 */
409 log(LF_ARCH, LVL_WARN, "MPS: ct badness %" PRIu8, *cur);
410 return;
411 }
412 }
413
414 /*
415 * Process extended entries.
416 */
417 ct_extended_entries();
418}
419
420static void configure_via_default(uint8_t n __attribute__((unused)))
421{
422 /*
423 * Not yet implemented.
424 */
425 log(LF_ARCH, LVL_WARN, "MPS: Default configuration not supported");
426}
427
428void mps_init(void)
429{
430 uint8_t *addr[2] = { NULL, (uint8_t *) PA2KA(0xf0000) };
431 unsigned int i;
432 unsigned int j;
433 unsigned int length[2] = { 1024, 64 * 1024 };
434
435 /*
436 * Find MP Floating Pointer Structure
437 * 1a. search first 1K of EBDA
438 * 1b. if EBDA is undefined, search last 1K of base memory
439 * 2. search 64K starting at 0xf0000
440 */
441
442 addr[0] = (uint8_t *) PA2KA(ebda ? ebda : 639 * 1024);
443 for (i = 0; i < 2; i++) {
444 for (j = 0; j < length[i]; j += 16) {
445 if ((*((uint32_t *) &addr[i][j]) ==
446 FS_SIGNATURE) && (mps_fs_check(&addr[i][j]))) {
447 fs = (struct mps_fs *) &addr[i][j];
448 goto fs_found;
449 }
450 }
451 }
452
453 return;
454
455fs_found:
456 log(LF_ARCH, LVL_NOTE, "%p: MPS Floating Pointer Structure", fs);
457
458 if ((fs->config_type == 0) && (fs->configuration_table)) {
459 if (fs->mpfib2 >> 7) {
460 log(LF_ARCH, LVL_WARN, "MPS: PIC mode not supported\n");
461 return;
462 }
463
464 ct = (struct mps_ct *) PA2KA((uintptr_t) fs->configuration_table);
465 configure_via_ct();
466 } else
467 configure_via_default(fs->config_type);
468
469 if (processor_entry_cnt > 0)
470 config.cpu_count = processor_entry_cnt;
471}
472
473#endif /* CONFIG_SMP */
474
475/** @}
476 */
Note: See TracBrowser for help on using the repository browser.