Subversion Repositories HelenOS-historic

Rev

Rev 11 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 jermar 1
/*
2
 * Copyright (C) 2001-2004 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
#ifdef __SMP__
30
 
31
#include <arch/mp.h>
32
#include <arch/ap.h>
33
#include <arch/pm.h>
34
#include <config.h>
35
#include <print.h>
36
#include <panic.h>
37
#include <arch/apic.h>
38
#include <func.h>
39
#include <arch/types.h>
40
#include <typedefs.h>
41
#include <synch/waitq.h>
42
#include <time/delay.h>
43
#include <mm/heap.h>
44
#include <mm/page.h>
45
#include <mm/frame.h>
46
#include <cpu.h>
47
#include <arch/i8259.h>
48
#include <arch/asm.h>
49
 
50
/*
51
 * Multi-Processor Specification detection code.
52
 */
53
 
54
#define	FS_SIGNATURE	0x5f504d5f
55
#define CT_SIGNATURE 	0x504d4350
56
 
57
int mp_fs_check(__u8 *base);
58
int mp_ct_check(void);
59
 
60
int configure_via_ct(void);
61
int configure_via_default(__u8 n);
62
 
63
int ct_processor_entry(struct __processor_entry *pr);
64
void ct_bus_entry(struct __bus_entry *bus);
65
void ct_io_apic_entry(struct __io_apic_entry *ioa);
66
void ct_io_intr_entry(struct __io_intr_entry *iointr);
67
void ct_l_intr_entry(struct __l_intr_entry *lintr);
68
 
69
void ct_extended_entries(void);
70
 
71
static struct __mpfs *fs;
72
static struct __mpct *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
int processor_entry_cnt = 0;
81
int bus_entry_cnt = 0;
82
int io_apic_entry_cnt = 0;
83
int io_intr_entry_cnt = 0;
84
int l_intr_entry_cnt = 0;
85
 
86
waitq_t ap_completion_wq;
87
waitq_t kmp_completion_wq;
88
 
89
/*
90
 * Used to check the integrity of the MP Floating Structure.
91
 */
92
int mp_fs_check(__u8 *base)
93
{
94
	int i;
95
	__u8 sum;
96
 
97
	for (i = 0, sum = 0; i < 16; i++)
98
		sum += base[i];
99
 
100
	return !sum;
101
}
102
 
103
/*
104
 * Used to check the integrity of the MP Configuration Table.
105
 */
106
int mp_ct_check(void)
107
{
108
	__u8 *base = (__u8 *) ct;
109
	__u8 *ext = base + ct->base_table_length;
110
	__u8 sum;
111
	int i;	
112
 
113
	/* count the checksum for the base table */
114
	for (i=0,sum=0; i < ct->base_table_length; i++)
115
		sum += base[i];
116
 
117
	if (sum)
118
		return 0;
119
 
120
	/* count the checksum for the extended table */
121
	for (i=0,sum=0; i < ct->ext_table_length; i++)
122
		sum += ext[i];
123
 
124
	return !sum;
125
}
126
 
127
void mp_init(void)
128
{
129
	__address addr, frame;
130
	int cnt, n;
131
 
132
 
133
	/*
134
	 * First place to search the MP Floating Pointer Structure is the Extended
135
	 * BIOS Data Area. We have to read EBDA segment address from the BIOS Data
136
	 * Area. Unfortunatelly, this memory is in page 0, which has intentionally no
137
	 * mapping.
138
	 */
139
	frame = frame_alloc(FRAME_KA);
140
	map_page_to_frame(frame,0,PAGE_CACHEABLE,0);
141
	addr = *((__u16 *) (frame + 0x40e)) * 16;
142
	map_page_to_frame(frame,frame,PAGE_CACHEABLE,0);
143
	frame_free(frame);	
144
 
145
	/*
146
	 * EBDA can be undefined. In that case addr would be 0. 
147
	 */
148
	if (addr >= 0x1000) {
149
		cnt = 1024;
150
		while (addr = __u32_search(addr,cnt,FS_SIGNATURE)) {
151
			if (mp_fs_check((__u8 *) addr))
152
				goto fs_found;
153
			addr++;
154
			cnt--;
155
		}
156
	}
157
 
158
	/*
159
	 * Second place where the MP Floating Pointer Structure may live is the last
160
	 * kilobyte of base memory.
161
	 */
162
	addr = 639*1024;
163
	cnt = 1024;
164
	while (addr = __u32_search(addr,cnt,FS_SIGNATURE)) {
165
		if (mp_fs_check((__u8 *) addr))
166
			goto fs_found;
167
		addr++;
168
		cnt--;
169
	}
170
 
171
	/*
172
	 * As the last resort, MP Floating Pointer Structure is searched in the BIOS
173
	 * ROM.
174
	 */
175
	addr = 0xf0000;
176
	cnt = 64*1024;
177
	while (addr = __u32_search(addr,cnt,FS_SIGNATURE)) {
178
		if (mp_fs_check((__u8 *) addr))
179
			goto fs_found;
180
		addr++;
181
		cnt--;
182
	}
183
 
184
	return;
185
 
186
fs_found:
187
	printf("%L: MP Floating Pointer Structure\n", addr);
188
 
189
	fs = (struct __mpfs *) addr;
190
	frame_not_free((__address) fs);
191
 
192
	if (fs->config_type == 0 && fs->configuration_table) {
193
		if (fs->mpfib2 >> 7) {
194
			printf("mp_init: PIC mode not supported\n");
195
			return;
196
		}
197
 
198
		ct = fs->configuration_table;
199
		frame_not_free((__address) ct);
200
		config.cpu_count = configure_via_ct();
201
	} 
202
	else
203
		config.cpu_count = configure_via_default(fs->config_type);
204
 
205
	if (config.cpu_count > 1) {
206
		map_page_to_frame((__address) l_apic, (__address) l_apic, PAGE_NOT_CACHEABLE, 0);
207
 	}		
208
 
209
 
210
	/*
211
	 * Must be initialized outside the kmp thread, since it is waited
212
	 * on before the kmp thread is created.
213
	 */
214
	waitq_initialize(&kmp_completion_wq);
215
	return;
216
}
217
 
218
int configure_via_ct(void)
219
{
220
	__u8 *cur;
221
	int i, cnt;
222
 
223
	if (ct->signature != CT_SIGNATURE) {
224
		printf("configure_via_ct: bad ct->signature\n");
225
		return 1;
226
	}
227
	if (!mp_ct_check()) {
228
		printf("configure_via_ct: bad ct checksum\n");
229
		return 1;
230
	}
231
	if (ct->oem_table) {
232
		printf("configure_via_ct: ct->oem_table not supported\n");
233
		return 1;
234
	}
235
 
236
	l_apic = ct->l_apic;
237
 
238
	cnt = 0;
239
	cur = &ct->base_table[0];
240
	for (i=0; i < ct->entry_count; i++) {
241
		switch (*cur) {
242
			/* Processor entry */
243
			case 0:	
244
				processor_entries = processor_entries ? processor_entries : (struct __processor_entry *) cur;
245
				processor_entry_cnt++;
246
				cnt += ct_processor_entry((struct __processor_entry *) cur);
247
				cur += 20;
248
				break;
249
 
250
			/* Bus entry */
251
			case 1:
252
				bus_entries = bus_entries ? bus_entries : (struct __bus_entry *) cur;
253
				bus_entry_cnt++;
254
				ct_bus_entry((struct __bus_entry *) cur);
255
				cur += 8;
256
				break;
257
 
258
			/* I/O Apic */
259
			case 2:
260
				io_apic_entries = io_apic_entries ? io_apic_entries : (struct __io_apic_entry *) cur;
261
				io_apic_entry_cnt++;
262
				ct_io_apic_entry((struct __io_apic_entry *) cur);
263
				cur += 8;
264
				break;
265
 
266
			/* I/O Interrupt Assignment */
267
			case 3:
268
				io_intr_entries = io_intr_entries ? io_intr_entries : (struct __io_intr_entry *) cur;
269
				io_intr_entry_cnt++;
270
				ct_io_intr_entry((struct __io_intr_entry *) cur);
271
				cur += 8;
272
				break;
273
 
274
			/* Local Interrupt Assignment */
275
			case 4:
276
				l_intr_entries = l_intr_entries ? l_intr_entries : (struct __l_intr_entry *) cur;
277
				l_intr_entry_cnt++;
278
				ct_l_intr_entry((struct __l_intr_entry *) cur);
279
		    		cur += 8;
280
				break;
281
 
282
			default:
283
				/*
284
				 * Something is wrong. Fallback to UP mode.
285
				 */
286
 
287
				printf("configure_via_ct: ct badness\n");
288
				return 1;
289
		}
290
	}
291
 
292
	/*
293
	 * Process extended entries.
294
	 */
295
	ct_extended_entries();
296
	return cnt;
297
}
298
 
299
int configure_via_default(__u8 n)
300
{
301
	/*
302
	 * Not yet implemented.
303
	 */
304
	printf("configure_via_default: not supported\n");
305
	return 1;
306
}
307
 
308
 
309
int ct_processor_entry(struct __processor_entry *pr)
310
{
311
	/*
312
	 * Ignore processors which are not marked enabled.
313
	 */
314
	if ((pr->cpu_flags & (1<<0)) == 0)
315
		return 0;
316
 
317
	apic_id_mask |= (1<<pr->l_apic_id); 
318
	return 1;
319
}
320
 
321
void ct_bus_entry(struct __bus_entry *bus)
322
{
323
#ifdef MPCT_VERBOSE
324
	char buf[7];
325
	memcopy((__address) bus->bus_type, (__address) buf,6);
326
	buf[6] = 0;
327
	printf("bus%d: %s\n", bus->bus_id, buf);
328
#endif
329
}
330
 
331
void ct_io_apic_entry(struct __io_apic_entry *ioa)
332
{
333
	static int io_apic_count = 0;
334
 
335
	/* this ioapic is marked unusable */
336
	if (ioa->io_apic_flags & 1 == 0)
337
		return;
338
 
339
	if (io_apic_count++ > 0) {
340
		/*
341
		 * Multiple IO APIC's are currently not supported.
342
		 */
343
		return;
344
	}
345
 
346
	map_page_to_frame((__address) ioa->io_apic, (__address) ioa->io_apic, PAGE_NOT_CACHEABLE, 0);
347
 
348
	io_apic = ioa->io_apic;
349
}
350
 
351
//#define MPCT_VERBOSE
352
void ct_io_intr_entry(struct __io_intr_entry *iointr)
353
{
354
#ifdef MPCT_VERBOSE
355
	switch (iointr->intr_type) {
356
	    case 0: printf("INT"); break;
357
	    case 1: printf("NMI"); break;
358
	    case 2: printf("SMI"); break;
359
	    case 3: printf("ExtINT"); break;
360
	}
361
	putchar(',');
362
	switch (iointr->poel&3) {
363
	    case 0: printf("bus-like"); break;
364
	    case 1: printf("active high"); break;
365
	    case 2: printf("reserved"); break;
366
	    case 3: printf("active low"); break;
367
	}
368
	putchar(',');
369
	switch ((iointr->poel>>2)&3) {
370
	    case 0: printf("bus-like"); break;
371
	    case 1: printf("edge-triggered"); break;
372
	    case 2: printf("reserved"); break;
373
	    case 3: printf("level-triggered"); break;
374
	}
375
	putchar(',');
376
	printf("bus%d,irq%d", iointr->src_bus_id, iointr->src_bus_irq);
377
	putchar(',');
378
	printf("io_apic%d,pin%d", iointr->dst_io_apic_id, iointr->dst_io_apic_pin);
379
	putchar('\n');	
380
#endif
381
}
382
 
383
void ct_l_intr_entry(struct __l_intr_entry *lintr)
384
{
385
#ifdef MPCT_VERBOSE
386
	switch (lintr->intr_type) {
387
	    case 0: printf("INT"); break;
388
	    case 1: printf("NMI"); break;
389
	    case 2: printf("SMI"); break;
390
	    case 3: printf("ExtINT"); break;
391
	}
392
	putchar(',');
393
	switch (lintr->poel&3) {
394
	    case 0: printf("bus-like"); break;
395
	    case 1: printf("active high"); break;
396
	    case 2: printf("reserved"); break;
397
	    case 3: printf("active low"); break;
398
	}
399
	putchar(',');
400
	switch ((lintr->poel>>2)&3) {
401
	    case 0: printf("bus-like"); break;
402
	    case 1: printf("edge-triggered"); break;
403
	    case 2: printf("reserved"); break;
404
	    case 3: printf("level-triggered"); break;
405
	}
406
	putchar(',');
407
	printf("bus%d,irq%d", lintr->src_bus_id, lintr->src_bus_irq);
408
	putchar(',');
409
	printf("l_apic%d,pin%d", lintr->dst_l_apic_id, lintr->dst_l_apic_pin);
410
	putchar('\n');
411
#endif
412
}
413
 
414
void ct_extended_entries(void)
415
{
416
	/*
417
	 * Not yet implemented.
418
	 */
419
	if (ct->ext_table_length)
420
		panic("ct_extended_entries: not supported\n");
421
}
422
 
423
/*
424
 * Kernel thread for bringing up application processors. It becomes clear
425
 * that we need an arrangement like this (AP's being initialized by a kernel
426
 * thread), for a thread has its dedicated stack. (The stack used during the
427
 * BSP initialization (prior the very first call to scheduler()) will be used
428
 * as an initialization stack for each AP.)
429
 */
430
void kmp(void *arg)
431
{
432
	struct __processor_entry *pr;
433
	__address src, dst;
434
	__address frame;
435
	int i;
436
 
437
	waitq_initialize(&ap_completion_wq);
438
 
439
	/*
440
	 * Processor entries immediately follow the configuration table header.
441
	 */
442
	pr = processor_entries;
443
 
444
	/*
445
	 * Grab a frame and map its address to page 0. This is a hack which
446
	 * accesses data in frame 0. Note that page 0 is not present because
447
	 * of nil reference bug catching.
448
	 */
449
	frame = frame_alloc(FRAME_KA);
450
	map_page_to_frame(frame,0,PAGE_CACHEABLE,0);
451
 
452
	/*
453
	 * Set the warm-reset vector to the real-mode address of 4K-aligned ap_boot()
454
	 */
455
	*((__u16 *) (frame + 0x467+0)) =  ((__address) ap_boot) >> 4;	/* segment */
456
	*((__u16 *) (frame + 0x467+2)) =  0x0;	/* offset */
457
 
458
	/*
459
	 * Give back the borrowed frame and restore identity mapping for it.
460
	 */
461
	map_page_to_frame(frame,frame,PAGE_CACHEABLE,0);
462
	frame_free(frame);
463
 
464
	/*
465
	 * Save 0xa to address 0xf of the CMOS RAM.
466
	 * BIOS will not do the POST after the INIT signal.
467
	 */
468
	outb(0x70,0xf);
469
	outb(0x71,0xa);
470
 
471
	cpu_priority_high();
472
 
473
	pic_disable_irqs(0xffff);
474
	apic_init();
475
 
476
	for (i = 0; i < processor_entry_cnt; i++) {
477
		struct descriptor *gdt_new;
478
 
479
		/*
480
		 * Skip processors marked unusable.
481
		 */
482
		if (pr[i].cpu_flags & (1<<0) == 0)
483
			continue;
484
 
485
		/*
486
		 * The bootstrap processor is already up.
487
		 */
488
		if (pr[i].cpu_flags & (1<<1))
489
			continue;
490
 
491
		/*
492
		 * Prepare new GDT for CPU in question.
493
		 */
494
		if (!(gdt_new = (struct descriptor *) malloc(GDT_ITEMS*sizeof(struct descriptor))))
495
			panic(PANIC "couldn't allocate memory for GDT\n");
496
 
497
		memcopy(gdt, gdt_new, GDT_ITEMS*sizeof(struct descriptor));
498
		gdtr.base = (__address) gdt_new;
499
 
500
		if (l_apic_send_init_ipi(pr[i].l_apic_id)) {
501
			/*
502
		         * There may be just one AP being initialized at
503
			 * the time. After it comes completely up, it is
504
			 * supposed to wake us up.
505
		         */
506
			waitq_sleep(&ap_completion_wq);
507
			cpu_priority_high();
508
		}
509
		else {
510
			printf("INIT IPI for l_apic%d failed\n", pr[i].l_apic_id);
511
		}
512
	}
513
 
514
	/*
515
	 * Wakeup the kinit thread so that
516
	 * system initialization can go on.
517
	 */
518
	waitq_wakeup(&kmp_completion_wq, WAKEUP_FIRST);
519
}
520
 
521
int mp_irq_to_pin(int irq)
522
{
523
	int i;
524
 
525
	for(i=0;i<io_intr_entry_cnt;i++) {
526
		if (io_intr_entries[i].src_bus_irq == irq && io_intr_entries[i].intr_type == 0)
527
			return io_intr_entries[i].dst_io_apic_pin;
528
	}
529
 
530
	return -1;
531
}
532
 
533
#endif /* __SMP__ */