2 Copyright © 1995-2014, The AROS Development Team. All rights reserved.
6 #include <aros/atomic.h>
8 #include <exec/execbase.h>
9 #include <exec/memory.h>
10 #include <proto/exec.h>
12 #include "kernel_base.h"
13 #include "kernel_debug.h"
14 #include "kernel_intern.h"
15 #include "kernel_syscall.h"
17 #include "smpbootstrap.h"
22 extern const void *_binary_smpbootstrap_start
;
23 extern const void *_binary_smpbootstrap_size
;
25 static void smp_Entry(volatile UBYTE
*apicready
)
28 * This is the entry point for secondary cores.
29 * KernelBase is already set up by the primary CPU, so we can use it.
35 /* Find out ourselves */
36 _APICBase
= core_APIC_GetBase();
37 _APICID
= core_APIC_GetID(_APICBase
);
38 _APICNO
= core_APIC_GetNumber(KernelBase
->kb_PlatformData
->kb_APIC
);
40 D(bug("[SMP] smp_Entry[0x%02X]: APIC base @ 0x%p\n", _APICID
, _APICBase
));
41 D(bug("[SMP] smp_Entry[0x%02X]: Ready lock 0x%p\n", _APICID
, apicready
));
43 bug("[SMP] APIC #%u of %u Going IDLE (Halting)...\n", _APICNO
+ 1, KernelBase
->kb_PlatformData
->kb_APIC
->count
);
45 /* Signal the bootstrap core that we are running */
49 * Unfortunately at the moment we have nothing more to do.
50 * The rest of AROS is not SMP-capable. :-(
52 while (1) asm volatile("hlt");
57 struct PlatformData
*pdata
= KernelBase
->kb_PlatformData
;
58 /* Low memory header is in the tail of memory list - see kernel_startup.c */
59 struct MemHeader
*lowmem
= (struct MemHeader
*)SysBase
->MemList
.lh_TailPred
;
61 struct SMPBootstrap
*bs
;
64 * Allocate space for SMP bootstrap code in low memory. Its address must be page-aligned.
65 * Every CPU starts up in real mode (DAMN CRAP!!!)
67 smpboot
= Allocate(lowmem
, (unsigned long)&_binary_smpbootstrap_size
+ PAGE_SIZE
- 1);
70 D(bug("[SMP] Failed to allocate space for SMP bootstrap\n"));
74 /* Install SMP bootstrap code */
75 bs
= (APTR
)AROS_ROUNDUP2((IPTR
)smpboot
, PAGE_SIZE
);
76 CopyMem(&_binary_smpbootstrap_start
, bs
, (unsigned long)&_binary_smpbootstrap_size
);
77 pdata
->kb_APIC_TrampolineBase
= bs
;
79 D(bug("[SMP] Copied APIC bootstrap code to 0x%p\n", bs
));
86 * Here we wake up our secondary cores.
90 struct PlatformData
*pdata
= KernelBase
->kb_PlatformData
;
91 struct SMPBootstrap
*bs
= pdata
->kb_APIC_TrampolineBase
;
92 struct APICData
*apic
= pdata
->kb_APIC
;
96 volatile UBYTE apicready
;
98 D(bug("[SMP] Ready spinlock at 0x%p\n", &apicready
));
100 /* Core number 0 is our bootstrap core, so we start from No 1 */
101 for (i
= 1; i
< apic
->count
; i
++)
103 UBYTE apic_id
= apic
->cores
[i
].lapicID
;
105 D(bug("[SMP] Launching APIC #%u (ID 0x%02X)\n", i
+ 1, apic_id
));
107 /* First we need to allocate a stack for our CPU. */
108 _APICStackBase
= AllocMem(STACK_SIZE
, MEMF_CLEAR
);
109 D(bug("[SMP] Allocated STACK for APIC ID 0x%02X @ 0x%p\n", apic_id
, _APICStackBase
));
113 /* Give the stack to the CPU */
114 bs
->Arg1
= (IPTR
)&apicready
;
115 bs
->SP
= _APICStackBase
+ STACK_SIZE
;
117 /* Initialize 'ready' flag to zero before launching the core */
120 /* Start IPI sequence */
121 wakeresult
= core_APIC_Wake(bs
, apic_id
, apic
->lapicBase
);
122 /* wakeresult != 0 means error */
126 * Before we proceed we need to make sure that the core has picked up
127 * its stack and we can reload bootstrap argument area with another one.
128 * We use a very simple spinlock in order to perform this waiting.
129 * Previously we have set apicready to 0. When the core starts up,
132 DWAKE(bug("[SMP] Waiting for APIC #%u to initialise .. ", i
+ 1));
135 D(bug("[SMP] APIC #%u started up\n", i
+ 1));
137 D(else bug("[SMP] APIC wake() failed, status 0x%p\n", wakeresult
));
140 D(bug("[SMP] Done\n"));