~jsvoboda/helenos/dnsr

« back to all changes in this revision

Viewing changes to kernel/arch/ia32/src/smp/mps.c

  • Committer: Martin Decky
  • Date: 2009-08-04 11:19:19 UTC
  • Revision ID: martin@uranus.dsrg.hide.ms.mff.cuni.cz-20090804111919-evyclddlr3v5lhmp
Initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 <arch/types.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    0x5f504d5f
 
55
#define CT_SIGNATURE    0x504d4350
 
56
 
 
57
static int mps_fs_check(uint8_t *base);
 
58
static int mps_ct_check(void);
 
59
 
 
60
static int configure_via_ct(void);
 
61
static int configure_via_default(uint8_t n);
 
62
 
 
63
static int ct_processor_entry(struct __processor_entry *pr);
 
64
static void ct_bus_entry(struct __bus_entry *bus);
 
65
static void ct_io_apic_entry(struct __io_apic_entry *ioa);
 
66
static void ct_io_intr_entry(struct __io_intr_entry *iointr);
 
67
static void ct_l_intr_entry(struct __l_intr_entry *lintr);
 
68
 
 
69
static void ct_extended_entries(void);
 
70
 
 
71
static struct mps_fs *fs;
 
72
static struct mps_ct *ct;
 
73
 
 
74
struct __processor_entry *processor_entries = NULL;
 
75
struct __bus_entry *bus_entries = NULL;
 
76
struct __io_apic_entry *io_apic_entries = NULL;
 
77
struct __io_intr_entry *io_intr_entries = NULL;
 
78
struct __l_intr_entry *l_intr_entries = NULL;
 
79
 
 
80
unsigned int processor_entry_cnt = 0;
 
81
unsigned int bus_entry_cnt = 0;
 
82
unsigned int io_apic_entry_cnt = 0;
 
83
unsigned int io_intr_entry_cnt = 0;
 
84
unsigned int l_intr_entry_cnt = 0;
 
85
 
 
86
/*
 
87
 * Implementation of IA-32 SMP configuration interface.
 
88
 */
 
89
static size_t get_cpu_count(void);
 
90
static bool is_cpu_enabled(size_t i);
 
91
static bool is_bsp(size_t i);
 
92
static uint8_t get_cpu_apic_id(size_t i);
 
93
static int mps_irq_to_pin(unsigned int irq);
 
94
 
 
95
struct smp_config_operations mps_config_operations = {
 
96
        .cpu_count = get_cpu_count,
 
97
        .cpu_enabled = is_cpu_enabled,
 
98
        .cpu_bootstrap = is_bsp,
 
99
        .cpu_apic_id = get_cpu_apic_id,
 
100
        .irq_to_pin = mps_irq_to_pin
 
101
};
 
102
 
 
103
size_t get_cpu_count(void)
 
104
{
 
105
        return processor_entry_cnt;
 
106
}
 
107
 
 
108
bool is_cpu_enabled(size_t i)
 
109
{
 
110
        ASSERT(i < processor_entry_cnt);
 
111
        return (bool) ((processor_entries[i].cpu_flags & 0x01) == 0x01);
 
112
}
 
113
 
 
114
bool is_bsp(size_t i)
 
115
{
 
116
        ASSERT(i < processor_entry_cnt);
 
117
        return (bool) ((processor_entries[i].cpu_flags & 0x02) == 0x02);
 
118
}
 
119
 
 
120
uint8_t get_cpu_apic_id(size_t i)
 
121
{
 
122
        ASSERT(i < processor_entry_cnt);
 
123
        return processor_entries[i].l_apic_id;
 
124
}
 
125
 
 
126
 
 
127
/*
 
128
 * Used to check the integrity of the MP Floating Structure.
 
129
 */
 
130
int mps_fs_check(uint8_t *base)
 
131
{
 
132
        unsigned int i;
 
133
        uint8_t sum;
 
134
        
 
135
        for (i = 0, sum = 0; i < 16; i++)
 
136
                sum = (uint8_t) (sum + base[i]);
 
137
        
 
138
        return !sum;
 
139
}
 
140
 
 
141
/*
 
142
 * Used to check the integrity of the MP Configuration Table.
 
143
 */
 
144
int mps_ct_check(void)
 
145
{
 
146
        uint8_t *base = (uint8_t *) ct;
 
147
        uint8_t *ext = base + ct->base_table_length;
 
148
        uint8_t sum;
 
149
        int i;  
 
150
        
 
151
        /* count the checksum for the base table */
 
152
        for (i = 0,sum = 0; i < ct->base_table_length; i++)
 
153
                sum = (uint8_t) (sum + base[i]);
 
154
                
 
155
        if (sum)
 
156
                return 0;
 
157
                
 
158
        /* count the checksum for the extended table */
 
159
        for (i = 0, sum = 0; i < ct->ext_table_length; i++)
 
160
                sum = (uint8_t) (sum + ext[i]);
 
161
                
 
162
        return sum == ct->ext_table_checksum;
 
163
}
 
164
 
 
165
void mps_init(void)
 
166
{
 
167
        uint8_t *addr[2] = { NULL, (uint8_t *) PA2KA(0xf0000) };
 
168
        unsigned int i, j, length[2] = { 1024, 64 * 1024 };
 
169
        
 
170
 
 
171
        /*
 
172
         * Find MP Floating Pointer Structure
 
173
         * 1a. search first 1K of EBDA
 
174
         * 1b. if EBDA is undefined, search last 1K of base memory
 
175
         *  2. search 64K starting at 0xf0000
 
176
         */
 
177
 
 
178
        addr[0] = (uint8_t *) PA2KA(ebda ? ebda : 639 * 1024);
 
179
        for (i = 0; i < 2; i++) {
 
180
                for (j = 0; j < length[i]; j += 16) {
 
181
                        if (*((uint32_t *) &addr[i][j]) ==
 
182
                            FS_SIGNATURE && mps_fs_check(&addr[i][j])) {
 
183
                                fs = (struct mps_fs *) &addr[i][j];
 
184
                                goto fs_found;
 
185
                        }
 
186
                }
 
187
        }
 
188
 
 
189
        return;
 
190
        
 
191
fs_found:
 
192
        printf("%p: MPS Floating Pointer Structure\n", fs);
 
193
 
 
194
        if (fs->config_type == 0 && fs->configuration_table) {
 
195
                if (fs->mpfib2 >> 7) {
 
196
                        printf("%s: PIC mode not supported\n", __func__);
 
197
                        return;
 
198
                }
 
199
 
 
200
                ct = (struct mps_ct *)PA2KA((uintptr_t)fs->configuration_table);
 
201
                config.cpu_count = configure_via_ct();
 
202
        } 
 
203
        else
 
204
                config.cpu_count = configure_via_default(fs->config_type);
 
205
 
 
206
        return;
 
207
}
 
208
 
 
209
int configure_via_ct(void)
 
210
{
 
211
        uint8_t *cur;
 
212
        unsigned int i, cnt;
 
213
                
 
214
        if (ct->signature != CT_SIGNATURE) {
 
215
                printf("%s: bad ct->signature\n", __func__);
 
216
                return 1;
 
217
        }
 
218
        if (!mps_ct_check()) {
 
219
                printf("%s: bad ct checksum\n", __func__);
 
220
                return 1;
 
221
        }
 
222
        if (ct->oem_table) {
 
223
                printf("%s: ct->oem_table not supported\n", __func__);
 
224
                return 1;
 
225
        }
 
226
        
 
227
        l_apic = (uint32_t *)(uintptr_t)ct->l_apic;
 
228
 
 
229
        cnt = 0;
 
230
        cur = &ct->base_table[0];
 
231
        for (i = 0; i < ct->entry_count; i++) {
 
232
                switch (*cur) {
 
233
                /* Processor entry */
 
234
                case 0: 
 
235
                        processor_entries = processor_entries ?
 
236
                            processor_entries :
 
237
                            (struct __processor_entry *) cur;
 
238
                        processor_entry_cnt++;
 
239
                        cnt += ct_processor_entry((struct __processor_entry *)
 
240
                            cur);
 
241
                        cur += 20;
 
242
                        break;
 
243
 
 
244
                /* Bus entry */
 
245
                case 1:
 
246
                        bus_entries = bus_entries ?
 
247
                            bus_entries : (struct __bus_entry *) cur;
 
248
                        bus_entry_cnt++;
 
249
                        ct_bus_entry((struct __bus_entry *) cur);
 
250
                        cur += 8;
 
251
                        break;
 
252
                                
 
253
                /* I/O Apic */
 
254
                case 2:
 
255
                        io_apic_entries = io_apic_entries ?
 
256
                            io_apic_entries : (struct __io_apic_entry *) cur;
 
257
                                io_apic_entry_cnt++;
 
258
                        ct_io_apic_entry((struct __io_apic_entry *) cur);
 
259
                        cur += 8;
 
260
                        break;
 
261
                                
 
262
                /* I/O Interrupt Assignment */
 
263
                case 3:
 
264
                        io_intr_entries = io_intr_entries ?
 
265
                            io_intr_entries : (struct __io_intr_entry *) cur;
 
266
                        io_intr_entry_cnt++;
 
267
                        ct_io_intr_entry((struct __io_intr_entry *) cur);
 
268
                        cur += 8;
 
269
                        break;
 
270
 
 
271
                /* Local Interrupt Assignment */
 
272
                case 4:
 
273
                        l_intr_entries = l_intr_entries ?
 
274
                            l_intr_entries : (struct __l_intr_entry *) cur;
 
275
                        l_intr_entry_cnt++;
 
276
                        ct_l_intr_entry((struct __l_intr_entry *) cur);
 
277
                        cur += 8;
 
278
                        break;
 
279
 
 
280
                default:
 
281
                        /*
 
282
                         * Something is wrong. Fallback to UP mode.
 
283
                         */
 
284
 
 
285
                        printf("%s: ct badness\n", __func__);
 
286
                        return 1;
 
287
                }
 
288
        }
 
289
        
 
290
        /*
 
291
         * Process extended entries.
 
292
         */
 
293
        ct_extended_entries();
 
294
        return cnt;
 
295
}
 
296
 
 
297
int configure_via_default(uint8_t n __attribute__((unused)))
 
298
{
 
299
        /*
 
300
         * Not yet implemented.
 
301
         */
 
302
        printf("%s: not supported\n", __func__);
 
303
        return 1;
 
304
}
 
305
 
 
306
 
 
307
int ct_processor_entry(struct __processor_entry *pr __attribute__((unused)))
 
308
{
 
309
        /*
 
310
         * Ignore processors which are not marked enabled.
 
311
         */
 
312
        if ((pr->cpu_flags & (1 << 0)) == 0)
 
313
                return 0;
 
314
        
 
315
        apic_id_mask |= (1 << pr->l_apic_id); 
 
316
        return 1;
 
317
}
 
318
 
 
319
void ct_bus_entry(struct __bus_entry *bus __attribute__((unused)))
 
320
{
 
321
#ifdef MPSCT_VERBOSE
 
322
        char buf[7];
 
323
        memcpy((void *) buf, (void *) bus->bus_type, 6);
 
324
        buf[6] = 0;
 
325
        printf("bus%d: %s\n", bus->bus_id, buf);
 
326
#endif
 
327
}
 
328
 
 
329
void ct_io_apic_entry(struct __io_apic_entry *ioa)
 
330
{
 
331
        static unsigned int io_apic_count = 0;
 
332
 
 
333
        /* this ioapic is marked unusable */
 
334
        if ((ioa->io_apic_flags & 1) == 0)
 
335
                return;
 
336
        
 
337
        if (io_apic_count++ > 0) {
 
338
                /*
 
339
                 * Multiple IO APIC's are currently not supported.
 
340
                 */
 
341
                return;
 
342
        }
 
343
        
 
344
        io_apic = (uint32_t *)(uintptr_t)ioa->io_apic;
 
345
}
 
346
 
 
347
//#define MPSCT_VERBOSE
 
348
void ct_io_intr_entry(struct __io_intr_entry *iointr __attribute__((unused)))
 
349
{
 
350
#ifdef MPSCT_VERBOSE
 
351
        switch (iointr->intr_type) {
 
352
        case 0:
 
353
                printf("INT");
 
354
                break;
 
355
        case 1:
 
356
                printf("NMI");
 
357
                break;
 
358
        case 2:
 
359
                printf("SMI");
 
360
                break;
 
361
        case 3:
 
362
                printf("ExtINT");
 
363
                break;
 
364
        }
 
365
        putchar(',');
 
366
        switch (iointr->poel & 3) {
 
367
        case 0:
 
368
                printf("bus-like");
 
369
                break;
 
370
        case 1:
 
371
                printf("active high");
 
372
                break;
 
373
        case 2:
 
374
                printf("reserved");
 
375
                break;
 
376
        case 3:
 
377
                printf("active low");
 
378
                break;
 
379
        }
 
380
        putchar(',');
 
381
        switch ((iointr->poel >> 2) & 3) {
 
382
        case 0:
 
383
                printf("bus-like");
 
384
                break;
 
385
        case 1:
 
386
                printf("edge-triggered");
 
387
                break;
 
388
        case 2:
 
389
                printf("reserved");
 
390
                break;
 
391
        case 3:
 
392
                printf("level-triggered");
 
393
                break;
 
394
        }
 
395
        putchar(',');
 
396
        printf("bus%d,irq%d", iointr->src_bus_id, iointr->src_bus_irq);
 
397
        putchar(',');
 
398
        printf("io_apic%d,pin%d", iointr->dst_io_apic_id,
 
399
            iointr->dst_io_apic_pin);
 
400
        putchar('\n');  
 
401
#endif
 
402
}
 
403
 
 
404
void ct_l_intr_entry(struct __l_intr_entry *lintr __attribute__((unused)))
 
405
{
 
406
#ifdef MPSCT_VERBOSE
 
407
        switch (lintr->intr_type) {
 
408
        case 0:
 
409
            printf("INT");
 
410
            break;
 
411
        case 1:
 
412
            printf("NMI");
 
413
            break;
 
414
        case 2:
 
415
            printf("SMI");
 
416
            break;
 
417
        case 3:
 
418
            printf("ExtINT");
 
419
            break;
 
420
        }
 
421
        putchar(',');
 
422
        switch (lintr->poel & 3) {
 
423
        case 0:
 
424
            printf("bus-like");
 
425
            break;
 
426
        case 1:
 
427
            printf("active high");
 
428
            break;
 
429
        case 2:
 
430
            printf("reserved");
 
431
            break;
 
432
        case 3:
 
433
            printf("active low");
 
434
            break;
 
435
        }
 
436
        putchar(',');
 
437
        switch ((lintr->poel >> 2) & 3) {
 
438
        case 0:
 
439
            printf("bus-like");
 
440
            break;
 
441
        case 1:
 
442
            printf("edge-triggered");
 
443
            break;
 
444
        case 2:
 
445
            printf("reserved");
 
446
            break;
 
447
        case 3:
 
448
            printf("level-triggered");
 
449
            break;
 
450
        }
 
451
        putchar(',');
 
452
        printf("bus%d,irq%d", lintr->src_bus_id, lintr->src_bus_irq);
 
453
        putchar(',');
 
454
        printf("l_apic%d,pin%d", lintr->dst_l_apic_id, lintr->dst_l_apic_pin);
 
455
        putchar('\n');
 
456
#endif
 
457
}
 
458
 
 
459
void ct_extended_entries(void)
 
460
{
 
461
        uint8_t *ext = (uint8_t *) ct + ct->base_table_length;
 
462
        uint8_t *cur;
 
463
 
 
464
        for (cur = ext; cur < ext + ct->ext_table_length;
 
465
            cur += cur[CT_EXT_ENTRY_LEN]) {
 
466
                switch (cur[CT_EXT_ENTRY_TYPE]) {
 
467
                default:
 
468
                        printf("%p: skipping MP Configuration Table extended "
 
469
                            "entry type %d\n", cur, cur[CT_EXT_ENTRY_TYPE]);
 
470
                        break;
 
471
                }
 
472
        }
 
473
}
 
474
 
 
475
int mps_irq_to_pin(unsigned int irq)
 
476
{
 
477
        unsigned int i;
 
478
        
 
479
        for (i = 0; i < io_intr_entry_cnt; i++) {
 
480
                if (io_intr_entries[i].src_bus_irq == irq &&
 
481
                    io_intr_entries[i].intr_type == 0)
 
482
                        return io_intr_entries[i].dst_io_apic_pin;
 
483
        }
 
484
        
 
485
        return -1;
 
486
}
 
487
 
 
488
#endif /* CONFIG_SMP */
 
489
 
 
490
/** @}
 
491
 */