2 * Copyright (c) 2001-2005 Jakub Jermar
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
29 /** @addtogroup ia32xen
40 #include <arch/smp/mps.h>
41 #include <arch/smp/apic.h>
42 #include <arch/smp/smp.h>
44 #include <arch/types.h>
48 #include <arch/bios/bios.h>
52 * MultiProcessor Specification detection code.
55 #define FS_SIGNATURE 0x5f504d5f
56 #define CT_SIGNATURE 0x504d4350
58 int mps_fs_check(uint8_t *base
);
59 int mps_ct_check(void);
61 int configure_via_ct(void);
62 int configure_via_default(uint8_t n
);
64 int ct_processor_entry(struct __processor_entry
*pr
);
65 void ct_bus_entry(struct __bus_entry
*bus
);
66 void ct_io_apic_entry(struct __io_apic_entry
*ioa
);
67 void ct_io_intr_entry(struct __io_intr_entry
*iointr
);
68 void ct_l_intr_entry(struct __l_intr_entry
*lintr
);
70 void ct_extended_entries(void);
72 static struct mps_fs
*fs
;
73 static struct mps_ct
*ct
;
75 struct __processor_entry
*processor_entries
= NULL
;
76 struct __bus_entry
*bus_entries
= NULL
;
77 struct __io_apic_entry
*io_apic_entries
= NULL
;
78 struct __io_intr_entry
*io_intr_entries
= NULL
;
79 struct __l_intr_entry
*l_intr_entries
= NULL
;
81 int processor_entry_cnt
= 0;
82 int bus_entry_cnt
= 0;
83 int io_apic_entry_cnt
= 0;
84 int io_intr_entry_cnt
= 0;
85 int l_intr_entry_cnt
= 0;
87 waitq_t ap_completion_wq
;
90 * Implementation of IA-32 SMP configuration interface.
92 static count_t
get_cpu_count(void);
93 static bool is_cpu_enabled(index_t i
);
94 static bool is_bsp(index_t i
);
95 static uint8_t get_cpu_apic_id(index_t i
);
96 static int mps_irq_to_pin(int irq
);
98 struct smp_config_operations mps_config_operations
= {
99 .cpu_count
= get_cpu_count
,
100 .cpu_enabled
= is_cpu_enabled
,
101 .cpu_bootstrap
= is_bsp
,
102 .cpu_apic_id
= get_cpu_apic_id
,
103 .irq_to_pin
= mps_irq_to_pin
106 count_t
get_cpu_count(void)
108 return processor_entry_cnt
;
111 bool is_cpu_enabled(index_t i
)
113 ASSERT(i
< processor_entry_cnt
);
114 return processor_entries
[i
].cpu_flags
& 0x1;
117 bool is_bsp(index_t i
)
119 ASSERT(i
< processor_entry_cnt
);
120 return processor_entries
[i
].cpu_flags
& 0x2;
123 uint8_t get_cpu_apic_id(index_t i
)
125 ASSERT(i
< processor_entry_cnt
);
126 return processor_entries
[i
].l_apic_id
;
131 * Used to check the integrity of the MP Floating Structure.
133 int mps_fs_check(uint8_t *base
)
138 for (i
= 0, sum
= 0; i
< 16; i
++)
145 * Used to check the integrity of the MP Configuration Table.
147 int mps_ct_check(void)
149 uint8_t *base
= (uint8_t *) ct
;
150 uint8_t *ext
= base
+ ct
->base_table_length
;
154 /* count the checksum for the base table */
155 for (i
=0,sum
=0; i
< ct
->base_table_length
; i
++)
161 /* count the checksum for the extended table */
162 for (i
=0,sum
=0; i
< ct
->ext_table_length
; i
++)
165 return sum
== ct
->ext_table_checksum
;
170 uint8_t *addr
[2] = { NULL
, (uint8_t *) PA2KA(0xf0000) };
171 int i
, j
, length
[2] = { 1024, 64*1024 };
175 * Find MP Floating Pointer Structure
176 * 1a. search first 1K of EBDA
177 * 1b. if EBDA is undefined, search last 1K of base memory
178 * 2. search 64K starting at 0xf0000
181 addr
[0] = (uint8_t *) PA2KA(ebda
? ebda
: 639 * 1024);
182 for (i
= 0; i
< 2; i
++) {
183 for (j
= 0; j
< length
[i
]; j
+= 16) {
184 if (*((uint32_t *) &addr
[i
][j
]) == FS_SIGNATURE
&& mps_fs_check(&addr
[i
][j
])) {
185 fs
= (struct mps_fs
*) &addr
[i
][j
];
194 printf("%p: MPS Floating Pointer Structure\n", fs
);
196 if (fs
->config_type
== 0 && fs
->configuration_table
) {
197 if (fs
->mpfib2
>> 7) {
198 printf("%s: PIC mode not supported\n", __FUNCTION__
);
202 ct
= (struct mps_ct
*)PA2KA((uintptr_t)fs
->configuration_table
);
203 config
.cpu_count
= configure_via_ct();
206 config
.cpu_count
= configure_via_default(fs
->config_type
);
211 int configure_via_ct(void)
216 if (ct
->signature
!= CT_SIGNATURE
) {
217 printf("%s: bad ct->signature\n", __FUNCTION__
);
220 if (!mps_ct_check()) {
221 printf("%s: bad ct checksum\n", __FUNCTION__
);
225 printf("%s: ct->oem_table not supported\n", __FUNCTION__
);
229 l_apic
= (uint32_t *)(uintptr_t)ct
->l_apic
;
232 cur
= &ct
->base_table
[0];
233 for (i
=0; i
< ct
->entry_count
; i
++) {
235 /* Processor entry */
237 processor_entries
= processor_entries
? processor_entries
: (struct __processor_entry
*) cur
;
238 processor_entry_cnt
++;
239 cnt
+= ct_processor_entry((struct __processor_entry
*) cur
);
245 bus_entries
= bus_entries
? bus_entries
: (struct __bus_entry
*) cur
;
247 ct_bus_entry((struct __bus_entry
*) cur
);
253 io_apic_entries
= io_apic_entries
? io_apic_entries
: (struct __io_apic_entry
*) cur
;
255 ct_io_apic_entry((struct __io_apic_entry
*) cur
);
259 /* I/O Interrupt Assignment */
261 io_intr_entries
= io_intr_entries
? io_intr_entries
: (struct __io_intr_entry
*) cur
;
263 ct_io_intr_entry((struct __io_intr_entry
*) cur
);
267 /* Local Interrupt Assignment */
269 l_intr_entries
= l_intr_entries
? l_intr_entries
: (struct __l_intr_entry
*) cur
;
271 ct_l_intr_entry((struct __l_intr_entry
*) cur
);
277 * Something is wrong. Fallback to UP mode.
280 printf("%s: ct badness\n", __FUNCTION__
);
286 * Process extended entries.
288 ct_extended_entries();
292 int configure_via_default(uint8_t n
)
295 * Not yet implemented.
297 printf("%s: not supported\n", __FUNCTION__
);
302 int ct_processor_entry(struct __processor_entry
*pr
)
305 * Ignore processors which are not marked enabled.
307 if ((pr
->cpu_flags
& (1<<0)) == 0)
310 apic_id_mask
|= (1<<pr
->l_apic_id
);
314 void ct_bus_entry(struct __bus_entry
*bus
)
318 memcpy((void *) buf
, (void *) bus
->bus_type
, 6);
320 printf("bus%d: %s\n", bus
->bus_id
, buf
);
324 void ct_io_apic_entry(struct __io_apic_entry
*ioa
)
326 static int io_apic_count
= 0;
328 /* this ioapic is marked unusable */
329 if ((ioa
->io_apic_flags
& 1) == 0)
332 if (io_apic_count
++ > 0) {
334 * Multiple IO APIC's are currently not supported.
339 io_apic
= (uint32_t *)(uintptr_t)ioa
->io_apic
;
342 //#define MPSCT_VERBOSE
343 void ct_io_intr_entry(struct __io_intr_entry
*iointr
)
346 switch (iointr
->intr_type
) {
347 case 0: printf("INT"); break;
348 case 1: printf("NMI"); break;
349 case 2: printf("SMI"); break;
350 case 3: printf("ExtINT"); break;
353 switch (iointr
->poel
&3) {
354 case 0: printf("bus-like"); break;
355 case 1: printf("active high"); break;
356 case 2: printf("reserved"); break;
357 case 3: printf("active low"); break;
360 switch ((iointr
->poel
>>2)&3) {
361 case 0: printf("bus-like"); break;
362 case 1: printf("edge-triggered"); break;
363 case 2: printf("reserved"); break;
364 case 3: printf("level-triggered"); break;
367 printf("bus%d,irq%d", iointr
->src_bus_id
, iointr
->src_bus_irq
);
369 printf("io_apic%d,pin%d", iointr
->dst_io_apic_id
, iointr
->dst_io_apic_pin
);
374 void ct_l_intr_entry(struct __l_intr_entry
*lintr
)
377 switch (lintr
->intr_type
) {
378 case 0: printf("INT"); break;
379 case 1: printf("NMI"); break;
380 case 2: printf("SMI"); break;
381 case 3: printf("ExtINT"); break;
384 switch (lintr
->poel
&3) {
385 case 0: printf("bus-like"); break;
386 case 1: printf("active high"); break;
387 case 2: printf("reserved"); break;
388 case 3: printf("active low"); break;
391 switch ((lintr
->poel
>>2)&3) {
392 case 0: printf("bus-like"); break;
393 case 1: printf("edge-triggered"); break;
394 case 2: printf("reserved"); break;
395 case 3: printf("level-triggered"); break;
398 printf("bus%d,irq%d", lintr
->src_bus_id
, lintr
->src_bus_irq
);
400 printf("l_apic%d,pin%d", lintr
->dst_l_apic_id
, lintr
->dst_l_apic_pin
);
405 void ct_extended_entries(void)
407 uint8_t *ext
= (uint8_t *) ct
+ ct
->base_table_length
;
410 for (cur
= ext
; cur
< ext
+ ct
->ext_table_length
; cur
+= cur
[CT_EXT_ENTRY_LEN
]) {
411 switch (cur
[CT_EXT_ENTRY_TYPE
]) {
413 printf("%p: skipping MP Configuration Table extended entry type %d\n", cur
, cur
[CT_EXT_ENTRY_TYPE
]);
419 int mps_irq_to_pin(int irq
)
423 for(i
=0;i
<io_intr_entry_cnt
;i
++) {
424 if (io_intr_entries
[i
].src_bus_irq
== irq
&& io_intr_entries
[i
].intr_type
== 0)
425 return io_intr_entries
[i
].dst_io_apic_pin
;
431 #endif /* CONFIG_SMP */