27 |
|
|
28 |
#if NCPUS > 1 |
#if NCPUS > 1 |
29 |
|
|
|
#error "??? this code is not ready!" |
|
|
|
|
30 |
#include <rtmk/vm-param.h> |
#include <rtmk/vm-param.h> |
31 |
#include <rtmk/vm-types.h> |
#include <rtmk/vm-types.h> |
32 |
|
|
33 |
#include "tm.h" |
#include "tm.h" |
34 |
#include "smp.h" |
#include "smp.h" |
35 |
#include "trace.h" |
#include "trace.h" |
36 |
#include "cpu-io.h" |
#include "i386-io.h" |
37 |
#include "cpu-regs.h" |
#include "i386-regs.h" |
38 |
#include "cpu-segment.h" |
#include "i386-segment.h" |
39 |
#include "cpu-trap.h" |
#include "i386-trap.h" |
40 |
#include "cpu-timer.h" |
#include "pc-clocks.h" |
41 |
#include "processor.h" |
#include "processor.h" |
42 |
#include "thread.h" |
#include "thread.h" |
43 |
|
|
58 |
unsigned int ioapic_physical_address = 0; |
unsigned int ioapic_physical_address = 0; |
59 |
unsigned int ioapic_virtual_address = 0; |
unsigned int ioapic_virtual_address = 0; |
60 |
|
|
61 |
|
unsigned int apic_timer_ticks_per_sec = 0; |
62 |
|
|
63 |
struct smp_scan_spots |
struct smp_scan_spots |
64 |
{ |
{ |
65 |
unsigned int start; |
unsigned int start; |
116 |
} |
} |
117 |
|
|
118 |
void |
void |
119 |
cpu_smp_interrupt (struct exception_frame *frame) |
apic_interrupt (int nr) |
120 |
{ |
{ |
121 |
|
trace_printf ("apic intr %d", nr); |
|
if (frame->trapno != 251) |
|
|
trace_printf ("apic interrupt %d on cpu %d", frame->trapno, CPU_CURRENT ()); |
|
|
|
|
|
if (frame->trapno == 251) |
|
|
{ |
|
|
timer_interrupt (0); |
|
|
apic_write (APIC_ICRT, 100); |
|
|
} |
|
|
apic_write (APIC_EOI, 0); |
|
122 |
} |
} |
123 |
|
|
124 |
/* Read the value of the PIT. */ |
/* Read the value of the PIT. */ |
134 |
counter = inb (0x40); |
counter = inb (0x40); |
135 |
counter = counter + (inb (0x40) << 8); |
counter = counter + (inb (0x40) << 8); |
136 |
SPLON (spl); |
SPLON (spl); |
|
trace_printf ("pit counter: %d", counter); |
|
137 |
return counter; |
return counter; |
138 |
} |
} |
139 |
|
|
187 |
|
|
188 |
loops_per_sec = 1 << 12; |
loops_per_sec = 1 << 12; |
189 |
|
|
|
printf ("Calibrating delay loop for CPU %d\n", CPU_CURRENT ()); |
|
|
|
|
190 |
while (loops_per_sec <<= 1) |
while (loops_per_sec <<= 1) |
191 |
{ |
{ |
192 |
outb (0x43, 0x30); /* one-shot mode. */ |
outb (0x43, 0x30); /* one-shot mode. */ |
224 |
/* Get loops per sec, instead of loops per 65535 - 64000 pit ticks. */ |
/* Get loops per sec, instead of loops per 65535 - 64000 pit ticks. */ |
225 |
loops_per_sec *= PIT_CLKNUM / (65535 - 64000); |
loops_per_sec *= PIT_CLKNUM / (65535 - 64000); |
226 |
|
|
227 |
printf ("ok - %lu.%02lu (%d) BogoMIPS\n", (loops_per_sec+2500)/500000, |
printf ("cpu #%d %u.%02u (%d) bogomips\n", CPU_CURRENT (), |
228 |
((loops_per_sec+2500)/5000) % 100, loops_per_sec); |
(loops_per_sec+2500)/500000, ((loops_per_sec+2500)/5000) % 100, loops_per_sec); |
229 |
} |
} |
230 |
|
|
231 |
|
|
232 |
static void |
static void |
233 |
calibrate_apic_timer (int this_cpu) |
calibrate_apic_timer (int this_cpu) |
234 |
{ |
{ |
248 |
outb (0x43, 0x34); // loop mode |
outb (0x43, 0x34); // loop mode |
249 |
outb (0x40, 0xff); |
outb (0x40, 0xff); |
250 |
outb (0x40, 0xff); |
outb (0x40, 0xff); |
251 |
|
|
252 |
|
#if 0 |
253 |
wait_pit_wrap (); |
wait_pit_wrap (); |
254 |
apic_write (APIC_TMICT, ~0); // Start APIC timer |
apic_write (APIC_TMICT, ~0); // Start APIC timer |
255 |
start_perf = read_pentium_clock(); |
start_perf = read_pentium_clock(); |
256 |
wait_pit_wrap(); |
wait_pit_wrap(); |
257 |
apic_count = apic_read (APIC_TMCCT); |
apic_count = apic_read (APIC_TMCCT); |
258 |
end_perf = read_pentium_clock(); |
end_perf = read_pentium_clock(); |
259 |
|
#endif |
260 |
|
|
261 |
bus_speed = |
bus_speed = |
262 |
(unsigned int) ((unsigned long long) PIT_CLKNUM |
(unsigned int) ((unsigned long long) PIT_CLKNUM |
265 |
(unsigned int) ((unsigned long long) PIT_CLKNUM |
(unsigned int) ((unsigned long long) PIT_CLKNUM |
266 |
* (end_perf - start_perf) / 0xffff); |
* (end_perf - start_perf) / 0xffff); |
267 |
|
|
268 |
trace_printf ("start perf = %d", start_perf & 0xffffffff); |
/* ??? hardcoded to 66 MHz, since the probe thing does not seem to work. */ |
269 |
trace_printf ("end perf = %d", end_perf & 0xffffffff); |
|
270 |
#if 0 |
bus_speed = core_speed = 66000000; |
271 |
trace_printf ("bus_speed = %d", bus_speed); |
apic_timer_ticks_per_sec = bus_speed; |
272 |
trace_printf ("core_speed = %d", core_speed); |
|
273 |
#endif |
printf ("cpu #%d runs at %d/%d MHz\n", this_cpu, |
|
printf ("CPU %d runs at %ld/%ld MHz\n", this_cpu, |
|
274 |
(bus_speed + 500000) / 1000000, (core_speed + 500000) / 1000000); |
(bus_speed + 500000) / 1000000, (core_speed + 500000) / 1000000); |
275 |
} |
} |
276 |
|
|
282 |
{ |
{ |
283 |
unsigned int config; |
unsigned int config; |
284 |
|
|
285 |
/* set spurious interrupt vector to 0xff */ |
/* Set spurious interrupt vector to 0xff */ |
286 |
config = apic_read (APIC_SIVR) & 0xfffffc00; |
config = apic_read (APIC_SIVR) & 0xfffffc00; |
287 |
config |= APIC_ENABLE | 0xff; |
config |= APIC_ENABLE | 0xff; |
288 |
apic_write (APIC_SIVR, config); |
apic_write (APIC_SIVR, config); |
289 |
|
|
290 |
#if 0 |
#if 0 |
291 |
/* setup LINT0 as ExtINT */ |
/* Setup LINT0 as ExtINT */ |
292 |
config = (apic_read (APIC_LINT0) & 0xffff1c00); |
config = (apic_read (APIC_LINT0) & 0xffff1c00); |
293 |
config |= APIC_LVT_DM_ExtINT | APIC_LVT_IIPP | APIC_LVT_TM; |
config |= APIC_LVT_DM_ExtINT | APIC_LVT_IIPP | APIC_LVT_TM; |
294 |
apic_write (APIC_LINT0, config); |
apic_write (APIC_LINT0, config); |
295 |
|
|
296 |
/* setup LINT1 as NMI */ |
/* Setup LINT1 as NMI */ |
297 |
config = (apic_read (APIC_LINT1) & 0xffff1c00); |
config = (apic_read (APIC_LINT1) & 0xffff1c00); |
298 |
config |= APIC_LVT_DM_NMI | APIC_LVT_IIPP; |
config |= APIC_LVT_DM_NMI | APIC_LVT_IIPP; |
299 |
apic_write (APIC_LINT1, config); |
apic_write (APIC_LINT1, config); |
300 |
#endif |
#endif |
301 |
|
|
|
/* setup timer */ |
|
|
config = apic_read (APIC_LVTT) & ~APIC_LVTT_MASK; |
|
|
config |= 0xfb | APIC_LVTT_M; // vector 0xfb, timer masked |
|
|
apic_write (APIC_LVTT, config); |
|
|
|
|
|
apic_write (APIC_ICRT, 0); // zero out the clock |
|
|
|
|
302 |
config = apic_read (APIC_TDCR) & ~0x0000000f; |
config = apic_read (APIC_TDCR) & ~0x0000000f; |
303 |
config |= APIC_TDCR_1; // clock division by 1 |
config |= APIC_TDCR_1; // clock division by 1 |
304 |
apic_write (APIC_TDCR, config); |
apic_write (APIC_TDCR, config); |
305 |
|
|
306 |
/* setup error vector to 0xfe */ |
/* Setup error vector to 0xfe */ |
307 |
config = (apic_read (APIC_LVT3) & 0xffffff00) | 0xfe; |
config = (apic_read (APIC_LVT3) & 0xffffff00) | 0xfe; |
308 |
apic_write(APIC_LVT3, config); |
apic_write(APIC_LVT3, config); |
309 |
|
|
310 |
/* accept all interrupts */ |
/* Accept all interrupts */ |
311 |
config = apic_read (APIC_TPRI) & 0xffffff00; |
config = apic_read (APIC_TPRI) & 0xffffff00; |
312 |
apic_write (APIC_TPRI, config); |
apic_write (APIC_TPRI, config); |
313 |
|
|
328 |
|
|
329 |
/* clear apic errors */ |
/* clear apic errors */ |
330 |
|
|
|
trace_printf ("booting cpu %d with apic id %d", |
|
|
ncpu, apicid); |
|
331 |
#if 1 |
#if 1 |
332 |
if (apic_version [ncpu] & 0xf0) |
if (apic_version [ncpu] & 0xf0) |
333 |
{ |
{ |
384 |
|
|
385 |
/* New CPU with new kernel stack. */ |
/* New CPU with new kernel stack. */ |
386 |
|
|
387 |
static void |
void |
388 |
new_cpu_with_new_stack (void) |
new_cpu_with_new_stack (void) |
389 |
{ |
{ |
390 |
struct processor *processor; |
struct processor *processor; |
391 |
int this_cpu; |
int tss_seg; |
392 |
|
|
393 |
/* Tell bootstrap CPU that we are done. */ |
/* Tell bootstrap CPU that we are done. */ |
394 |
|
|
401 |
trace_printf ("cpu %d ready", CPU_CURRENT ()); |
trace_printf ("cpu %d ready", CPU_CURRENT ()); |
402 |
spin_unlock (&cpuwait_lock); |
spin_unlock (&cpuwait_lock); |
403 |
|
|
404 |
apic_write(APIC_ICRT, 100); // start it up |
/* Initialize APIC timer, so that we can receive interrupts. */ |
405 |
|
apic_write (APIC_ICRT, apic_timer_ticks_per_sec / HZ); |
406 |
|
|
407 |
#if 0 |
/* Set kernel TSS. */ |
408 |
/* ??? switch to idle thread. */ |
tss_seg = KERNEL_TSS + (0x8 * CPU_CURRENT ()); |
409 |
processor = PROCESSOR_CURRENT (); |
__asm__ __volatile__ ("ltr %0" :: "rm" ((unsigned short) tss_seg)); |
|
|
|
|
#if 1 |
|
|
LOAD_CONTEXT (processor->idle_thread); |
|
|
#else |
|
|
for (;;) |
|
|
; |
|
|
#endif |
|
|
#else |
|
|
/* ??? switch to idle thread. */ |
|
|
processor = PROCESSOR_CURRENT (); |
|
410 |
|
|
411 |
LOAD_CONTEXT (thread_select (processor)); |
/* Load first thread into processor. */ |
|
for (;;) |
|
|
; |
|
|
#endif |
|
412 |
|
|
413 |
|
processor = PROCESSOR_CURRENT (); |
414 |
|
LOAD_CONTEXT ((struct thread *) thread_select (processor)); |
415 |
} |
} |
416 |
|
|
417 |
|
|
421 |
void |
void |
422 |
cpu_smp_cpu_in (void) |
cpu_smp_cpu_in (void) |
423 |
{ |
{ |
424 |
int this_cpu, reg; |
int this_cpu, reg, config; |
425 |
|
|
426 |
/* Switch to paged mode by loading CR3, set PG bit and jump |
/* Switch to paged mode by loading CR3, set PG bit and jump |
427 |
a step forward to flush insn queue. */ |
a step forward to flush insn queue. */ |
434 |
"1:" : : "r" (get_cr0() | 0x80000000)); |
"1:" : : "r" (get_cr0() | 0x80000000)); |
435 |
|
|
436 |
/* Setup local APIC. */ |
/* Setup local APIC. */ |
437 |
/* setup_apic (); */ |
setup_apic (); |
438 |
|
|
439 |
|
/* Setup timer */ |
440 |
|
config = apic_read (APIC_LVTT) & ~APIC_LVTT_MASK; |
441 |
|
config |= 0xfb | APIC_LVTT_TM; // vector 0xfb, timer masked |
442 |
|
apic_write (APIC_LVTT, config); |
443 |
|
|
444 |
reg = apic_read (APIC_SIVR); |
reg = apic_read (APIC_SIVR); |
445 |
reg |= (1 << 8); |
reg |= (1 << 8); |
446 |
apic_write (APIC_SIVR, reg); |
apic_write (APIC_SIVR, reg); |
549 |
/* Check signature, revision and length fields. */ |
/* Check signature, revision and length fields. */ |
550 |
if (flt->signature == IMPS_FPS_SIGNATURE |
if (flt->signature == IMPS_FPS_SIGNATURE |
551 |
&& (flt->mp_rev == 1 || flt->mp_rev == 4) && (flt->mpc_len == 1)) |
&& (flt->mp_rev == 1 || flt->mp_rev == 4) && (flt->mpc_len == 1)) |
552 |
{ |
return flt; |
|
trace_printf ("found floating pointer structure at %p\n", ptr); |
|
|
return flt; |
|
|
} |
|
553 |
} |
} |
554 |
return 0; |
return 0; |
555 |
} |
} |
557 |
/* First constructor; scan for floating pointer structure and parses |
/* First constructor; scan for floating pointer structure and parses |
558 |
the configuration table. */ |
the configuration table. */ |
559 |
|
|
560 |
static void CTOR_FN_ATTRIBUTE |
void |
561 |
initialize_config (void) |
smp_bootstrap (void) |
562 |
{ |
{ |
563 |
int i; |
int i; |
564 |
|
|
584 |
} |
} |
585 |
} |
} |
586 |
|
|
587 |
CONSTRUCTOR_FN (initialize_config, CTOR_LEVEL_ARCH); |
void |
588 |
|
smp_init_cpus (void) |
|
/* Second constructors; initializes all cpus. */ |
|
|
|
|
|
static void CTOR_FN_ATTRIBUTE |
|
|
initialize_cpus (void) |
|
589 |
{ |
{ |
590 |
extern void cpu_smp_startup_start (), cpu_smp_startup_end (); |
extern void cpu_smp_startup_start (), cpu_smp_startup_end (); |
591 |
unsigned char oldr; |
unsigned char oldr; |
605 |
ioapic_virtual_address = (unsigned int) |
ioapic_virtual_address = (unsigned int) |
606 |
PMAP_MAP_PHYSICAL (ioapic_physical_address, VM_PAGE_SIZE); |
PMAP_MAP_PHYSICAL (ioapic_physical_address, VM_PAGE_SIZE); |
607 |
|
|
|
trace_printf ("apic virtual address %x", apic_virtual_address); |
|
|
|
|
608 |
/* Initialize the APIC. */ |
/* Initialize the APIC. */ |
609 |
|
|
610 |
setup_apic (); |
setup_apic (); |
650 |
ap_kernel_stacks [i] = |
ap_kernel_stacks [i] = |
651 |
(vm_offset_t) PMAP_STEAL_MEMORY (KERNEL_STACK_SIZE); |
(vm_offset_t) PMAP_STEAL_MEMORY (KERNEL_STACK_SIZE); |
652 |
assert (ap_kernel_stacks [i]); |
assert (ap_kernel_stacks [i]); |
653 |
|
|
654 |
/* Start CPU. */ |
/* Start CPU. */ |
655 |
start_cpu (i); |
start_cpu (i); |
656 |
} |
} |
663 |
PMAP_ENTER (PMAP_KERNEL (), 0, 0, 0, true); |
PMAP_ENTER (PMAP_KERNEL (), 0, 0, 0, true); |
664 |
} |
} |
665 |
|
|
|
CONSTRUCTOR_FN (initialize_cpus, CTOR_LEVEL_BOOTSTRAP); |
|
|
|
|
666 |
/* Just releases the CPU wait lock. */ |
/* Just releases the CPU wait lock. */ |
667 |
|
|
668 |
void |
void |
669 |
cpu_smp_release_cpus (void) |
cpu_smp_release_cpus (void) |
670 |
{ |
{ |
|
#if 0 |
|
671 |
spin_unlock (&cpuwait_lock); |
spin_unlock (&cpuwait_lock); |
|
#endif |
|
672 |
} |
} |
673 |
|
|
674 |
/* Return current CPU number. ??? this should be optimized. */ |
/* Return current CPU number. ??? this should be optimized. */ |
684 |
return apic_id_to_cpu_map [apic_id]; |
return apic_id_to_cpu_map [apic_id]; |
685 |
} |
} |
686 |
|
|
687 |
|
/* Assert a interprocess interrupt on all CPU's, except the one |
688 |
|
that raises the interrupt. */ |
689 |
|
|
690 |
|
void |
691 |
|
smp_ipi_broadcast (void) |
692 |
|
{ |
693 |
|
unsigned int config; |
694 |
|
SPL_T spl; |
695 |
|
|
696 |
|
spl = SPLOFF (); |
697 |
|
|
698 |
|
config = apic_read (APIC_ICR1) & APIC_ICR1_WRITE_MASK; |
699 |
|
apic_write (APIC_ICR1, config | 0xfd | APIC_ICR1_DELMODE_FIXED |
700 |
|
| APIC_ICR1_DESTMODE_PHYS | APIC_ICR1_DEST_ALL_BUT_SELF); |
701 |
|
SPLON (spl); |
702 |
|
} |
703 |
|
|
704 |
|
/* Raise interprocess interrupt on TARGET_CPU. */ |
705 |
|
|
706 |
|
void |
707 |
|
smp_ipi_send (int target_cpu) |
708 |
|
{ |
709 |
|
unsigned int config; |
710 |
|
SPL_T spl; |
711 |
|
|
712 |
|
spl = SPLOFF (); |
713 |
|
|
714 |
|
config = apic_read(APIC_ICR2) & APIC_ICR2_MASK; |
715 |
|
apic_write(APIC_ICR2, config | cpu_id_to_apic_map [target_cpu] << 24); |
716 |
|
|
717 |
|
config = apic_read(APIC_ICR1) & APIC_ICR1_WRITE_MASK; |
718 |
|
apic_write(APIC_ICR1, config | 0xfd | APIC_ICR1_DELMODE_FIXED |
719 |
|
| APIC_ICR1_DESTMODE_PHYS | APIC_ICR1_DEST_FIELD); |
720 |
|
|
721 |
|
SPLON (spl); |
722 |
|
} |
723 |
|
|
724 |
|
|
725 |
#endif /* NCPUS > 1 */ |
#endif /* NCPUS > 1 */ |