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_globals.h"
15 #include "kernel_intern.h"
16 #include "kernel_syscall.h"
23 extern const void *_binary_smpbootstrap_start
;
24 extern const void *_binary_smpbootstrap_size
;
26 static void smp_Entry(IPTR stackBase
, volatile UBYTE
*apicready
, struct KernelBase
*KernelBase
)
29 * This is the entry point for secondary cores.
30 * KernelBase is already set up by the primary CPU, so we can use it.
36 /* Enable fxsave/fxrstor */
37 wrcr(cr4
, rdcr(cr4
) | _CR4_OSFXSR
| _CR4_OSXMMEXCPT
);
39 /* Find out ourselves */
40 _APICBase
= core_APIC_GetBase();
41 _APICID
= core_APIC_GetID(_APICBase
);
42 _APICNO
= core_APIC_GetNumber(KernelBase
->kb_PlatformData
->kb_APIC
);
44 D(bug("[SMP] smp_Entry[0x%02X]: launching on AP APIC ID 0x%02X, base @ 0x%p\n", _APICID
, _APICID
, _APICBase
));
45 D(bug("[SMP] smp_Entry[0x%02X]: KernelBootPrivate 0x%p, stack base 0x%p\n", _APICID
, __KernBootPrivate
, stackBase
));
46 D(bug("[SMP] smp_Entry[0x%02X]: Stack base 0x%p, ready lock 0x%p\n", _APICID
, stackBase
, apicready
));
48 /* Set up GDT and LDT for our core */
49 core_CPUSetup(_APICID
, stackBase
);
51 bug("[SMP] APIC #%u of %u Going IDLE (Halting)...\n", _APICNO
+ 1, KernelBase
->kb_PlatformData
->kb_APIC
->count
);
53 /* Signal the bootstrap core that we are running */
57 * Unfortunately at the moment we have nothing more to do.
58 * The rest of AROS is not SMP-capable. :-(
60 while (1) asm volatile("hlt");
63 static int smp_Setup(struct KernelBase
*KernelBase
)
65 struct PlatformData
*pdata
= KernelBase
->kb_PlatformData
;
66 /* Low memory header is in the tail of memory list - see kernel_startup.c */
67 struct MemHeader
*lowmem
= (struct MemHeader
*)SysBase
->MemList
.lh_TailPred
;
69 struct SMPBootstrap
*bs
;
71 D(bug("[SMP] Setup\n"));
74 * Allocate space for SMP bootstrap code in low memory. Its address must be page-aligned.
75 * Every CPU starts up in real mode (DAMN CRAP!!!)
77 smpboot
= Allocate(lowmem
, (unsigned long)&_binary_smpbootstrap_size
+ PAGE_SIZE
- 1);
80 D(bug("[SMP] Failed to allocate space for SMP bootstrap\n"));
84 /* Install SMP bootstrap code */
85 bs
= (APTR
)AROS_ROUNDUP2((IPTR
)smpboot
, PAGE_SIZE
);
86 CopyMem(&_binary_smpbootstrap_start
, bs
, (unsigned long)&_binary_smpbootstrap_size
);
87 pdata
->kb_APIC_TrampolineBase
= bs
;
89 D(bug("[SMP] Copied APIC bootstrap code to 0x%p\n", bs
));
92 * Store constant arguments in bootstrap's data area
93 * WARNING!!! The bootstrap code assumes PML4 is placed in a 32-bit memory,
94 * and there seem to be no easy way to fix this.
95 * If AROS kickstart is ever loaded into high memory, we would need to take
96 * a special care about it.
98 bs
->Arg3
= (IPTR
)KernelBase
;
99 bs
->PML4
= __KernBootPrivate
->PML4
;
106 * Here we wake up our secondary cores.
108 static int smp_Wake(struct KernelBase
*KernelBase
)
110 struct PlatformData
*pdata
= KernelBase
->kb_PlatformData
;
111 struct SMPBootstrap
*bs
= pdata
->kb_APIC_TrampolineBase
;
112 struct APICData
*apic
= pdata
->kb_APIC
;
116 volatile UBYTE apicready
;
118 D(bug("[SMP] Ready spinlock at 0x%p\n", &apicready
));
120 /* Core number 0 is our bootstrap core, so we start from No 1 */
121 for (i
= 1; i
< apic
->count
; i
++)
123 UBYTE apic_id
= apic
->cores
[i
].lapicID
;
125 D(bug("[SMP] Launching APIC #%u (ID 0x%02X)\n", i
+ 1, apic_id
));
128 * First we need to allocate a stack for our CPU.
129 * We allocate the same three stacks as in core_CPUSetup().
131 _APICStackBase
= AllocMem(STACK_SIZE
* 3, MEMF_CLEAR
);
132 D(bug("[SMP] Allocated STACK for APIC ID 0x%02X @ 0x%p ..\n", apic_id
, _APICStackBase
));
136 /* Give the stack to the CPU */
137 bs
->Arg1
= (IPTR
)_APICStackBase
;
138 bs
->Arg2
= (IPTR
)&apicready
;
139 bs
->SP
= _APICStackBase
+ STACK_SIZE
;
141 /* Initialize 'ready' flag to zero before launching the core */
144 /* Start IPI sequence */
145 wakeresult
= core_APIC_Wake(bs
, apic_id
, apic
->lapicBase
);
146 /* wakeresult != 0 means error */
150 * Before we proceed we need to make sure that the core has picked up
151 * its stack and we can reload bootstrap argument area with another one.
152 * We use a very simple spinlock in order to perform this waiting.
153 * Previously we have set apicready to 0. When the core starts up,
156 DWAKE(bug("[SMP] Waiting for APIC #%u to initialise .. ", i
+ 1));
159 D(bug("[SMP] APIC #%u started up\n", i
+ 1));
161 D(else bug("[SMP] core_APIC_Wake() failed, status 0x%p\n", wakeresult
));
164 D(bug("[SMP] Done\n"));
169 int smp_Initialize(void)
171 struct KernelBase
*KernelBase
= getKernelBase();
172 struct PlatformData
*pdata
= KernelBase
->kb_PlatformData
;
174 if (pdata
->kb_APIC
&& (pdata
->kb_APIC
->count
> 1))
176 if (!smp_Setup(KernelBase
))
178 D(bug("[SMP] Failed to prepare the environment!\n"));
180 pdata
->kb_APIC
->count
= 1; /* We have only one workinng CPU */
184 return smp_Wake(KernelBase
);
187 /* This is not an SMP machine, but it's okay */