| 1 |
/*
|
| 2 |
* Copyright (c) 2007, 2008 University of Tsukuba
|
| 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 are met:
|
| 7 |
*
|
| 8 |
* 1. Redistributions of source code must retain the above copyright notice,
|
| 9 |
* this list of conditions and the following disclaimer.
|
| 10 |
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
* this list of conditions and the following disclaimer in the documentation
|
| 12 |
* and/or other materials provided with the distribution.
|
| 13 |
* 3. Neither the name of the University of Tsukuba nor the names of its
|
| 14 |
* contributors may be used to endorse or promote products derived from
|
| 15 |
* this software without specific prior written permission.
|
| 16 |
*
|
| 17 |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
* POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
*/
|
| 29 |
/*
|
| 30 |
* Copyright (c) 2010-2012 Yuichi Watanabe
|
| 31 |
*/
|
| 32 |
|
| 33 |
#include <core/assert.h>
|
| 34 |
#include <core/linkage.h>
|
| 35 |
#include <core/spinlock.h>
|
| 36 |
#include <core/string.h>
|
| 37 |
#include <core/cpu.h>
|
| 38 |
#include <core/time.h>
|
| 39 |
#include "apic.h"
|
| 40 |
#include "constants.h"
|
| 41 |
#include "entry.h"
|
| 42 |
#include "int.h"
|
| 43 |
#include "mm.h"
|
| 44 |
#include "panic.h"
|
| 45 |
#include "seg.h"
|
| 46 |
#include "smp.h"
|
| 47 |
|
| 48 |
#define APINIT_ADDR ((APINIT_SEGMENT << 4) + APINIT_OFFSET)
|
| 49 |
#define APINIT_SIZE (cpuinit_end - cpuinit_start)
|
| 50 |
#define APINIT_POINTER(n) ((void *)(apinit + ((u8 *)&n - cpuinit_start)))
|
| 51 |
|
| 52 |
static void ap_start (void);
|
| 53 |
|
| 54 |
static int num_of_processors = 1;
|
| 55 |
static spinlock_t num_of_processors_lock;
|
| 56 |
static void (*bsp_main) (void), (*ap_main) (void);
|
| 57 |
static void *newstack_tmp;
|
| 58 |
static spinlock_t sync_lock;
|
| 59 |
volatile static u32 sync_id;
|
| 60 |
volatile static volatile u32 sync_count;
|
| 61 |
static spinlock_t *apinitlock;
|
| 62 |
volatile static bool all_cpu_started = false;
|
| 63 |
|
| 64 |
/* this function is called after starting AP and switching a stack */
|
| 65 |
/* unlock the spinlock because the stack is switched */
|
| 66 |
static asmlinkage void
|
| 67 |
apinitproc1 (void)
|
| 68 |
{
|
| 69 |
void *newstack;
|
| 70 |
|
| 71 |
newstack = newstack_tmp;
|
| 72 |
spinlock_unlock (apinitlock);
|
| 73 |
spinlock_lock (&num_of_processors_lock);
|
| 74 |
num_of_processors++;
|
| 75 |
spinlock_unlock (&num_of_processors_lock);
|
| 76 |
segment_init_ap();
|
| 77 |
currentcpu->stackaddr = newstack;
|
| 78 |
int_init_ap ();
|
| 79 |
for (;;) {
|
| 80 |
if (all_cpu_started) {
|
| 81 |
break;
|
| 82 |
}
|
| 83 |
cpu_relax();
|
| 84 |
}
|
| 85 |
ap_main ();
|
| 86 |
}
|
| 87 |
|
| 88 |
static asmlinkage void
|
| 89 |
bspinitproc1 (void)
|
| 90 |
{
|
| 91 |
ap_start ();
|
| 92 |
bsp_main ();
|
| 93 |
panic ("bspinitproc1");
|
| 94 |
}
|
| 95 |
|
| 96 |
/* this function is called on AP by entry.s */
|
| 97 |
/* other APs are waiting for spinlock */
|
| 98 |
/* the stack is cpuinit_tmpstack defined in entry.s */
|
| 99 |
/* this function allocates a stack and calls apinitproc1 with the new stack */
|
| 100 |
asmlinkage void
|
| 101 |
apinitproc0 (void)
|
| 102 |
{
|
| 103 |
void *newstack;
|
| 104 |
vmmerr_t err;
|
| 105 |
|
| 106 |
err = alloc_pages (&newstack, NULL, VMM_STACKSIZE / PAGESIZE);
|
| 107 |
if (err) {
|
| 108 |
panic("Failed to allocate pages for stack.");
|
| 109 |
}
|
| 110 |
newstack_tmp = newstack;
|
| 111 |
asm_wrrsp_and_jmp ((ulong)newstack + VMM_STACKSIZE, apinitproc1);
|
| 112 |
}
|
| 113 |
|
| 114 |
static void
|
| 115 |
ap_start (void)
|
| 116 |
{
|
| 117 |
volatile u32 *num;
|
| 118 |
u8 *apinit;
|
| 119 |
|
| 120 |
spinlock_init (&num_of_processors_lock);
|
| 121 |
spinlock_init (&sync_lock);
|
| 122 |
sync_id = 0;
|
| 123 |
sync_count = 0;
|
| 124 |
|
| 125 |
apinit = mapmem (MAPMEM_HPHYS | MAPMEM_WRITE, APINIT_ADDR,
|
| 126 |
APINIT_SIZE);
|
| 127 |
if (apinit == NULL) {
|
| 128 |
panic("Failed to map apinit area.");
|
| 129 |
}
|
| 130 |
memcpy (apinit, cpuinit_start, APINIT_SIZE);
|
| 131 |
num = (volatile u32 *)APINIT_POINTER (apinit_procs);
|
| 132 |
apinitlock = (spinlock_t *)APINIT_POINTER (apinit_lock);
|
| 133 |
*num = 1;
|
| 134 |
spinlock_init (apinitlock);
|
| 135 |
apic_start_ap(APINIT_ADDR);
|
| 136 |
for (;;) {
|
| 137 |
if (*num == get_number_of_processors ())
|
| 138 |
break;
|
| 139 |
cpu_relax();
|
| 140 |
}
|
| 141 |
all_cpu_started = true;
|
| 142 |
unmapmem ((void *)apinit, APINIT_SIZE);
|
| 143 |
}
|
| 144 |
|
| 145 |
static void
|
| 146 |
bspinitproc0 ()
|
| 147 |
{
|
| 148 |
void *newstack;
|
| 149 |
vmmerr_t err;
|
| 150 |
|
| 151 |
err = alloc_pages (&newstack, NULL, VMM_STACKSIZE / PAGESIZE);
|
| 152 |
if (err) {
|
| 153 |
panic("Failed to allocate pages for stack.");
|
| 154 |
}
|
| 155 |
currentcpu->stackaddr = newstack;
|
| 156 |
asm_wrrsp_and_jmp ((ulong)newstack + VMM_STACKSIZE, bspinitproc1);
|
| 157 |
}
|
| 158 |
|
| 159 |
void
|
| 160 |
panic_wakeup_all (void)
|
| 161 |
{
|
| 162 |
apic_broadcast_nmi();
|
| 163 |
}
|
| 164 |
|
| 165 |
void
|
| 166 |
sync_all_processors (void)
|
| 167 |
{
|
| 168 |
u32 saved_id;
|
| 169 |
bool ret = false;
|
| 170 |
int num;
|
| 171 |
u64 timeout = 0;
|
| 172 |
bool detect_lockup = time_initialized ();
|
| 173 |
|
| 174 |
num = get_number_of_processors ();
|
| 175 |
|
| 176 |
spinlock_lock (&sync_lock);
|
| 177 |
saved_id = sync_id;
|
| 178 |
sync_count++;
|
| 179 |
if (sync_count == num) {
|
| 180 |
sync_count = 0;
|
| 181 |
sync_id++;
|
| 182 |
ret = true;
|
| 183 |
}
|
| 184 |
spinlock_unlock (&sync_lock);
|
| 185 |
|
| 186 |
if (detect_lockup) {
|
| 187 |
timeout = get_cpu_time() + 30 * 1000 * 1000; /* 30 sec */
|
| 188 |
}
|
| 189 |
while (!ret) {
|
| 190 |
spinlock_lock (&sync_lock);
|
| 191 |
if (sync_id != saved_id) {
|
| 192 |
ret = true;
|
| 193 |
}
|
| 194 |
spinlock_unlock (&sync_lock);
|
| 195 |
if (detect_lockup) {
|
| 196 |
if (time_after (get_cpu_time (), timeout)) {
|
| 197 |
panic ("Other cpu does not come.");
|
| 198 |
}
|
| 199 |
}
|
| 200 |
cpu_relax();
|
| 201 |
}
|
| 202 |
}
|
| 203 |
|
| 204 |
void
|
| 205 |
start_all_processors (void (*bsp) (void), void (*ap) (void))
|
| 206 |
{
|
| 207 |
bsp_main = bsp;
|
| 208 |
ap_main = ap;
|
| 209 |
bspinitproc0();
|
| 210 |
}
|
| 211 |
|
| 212 |
int
|
| 213 |
get_number_of_processors ()
|
| 214 |
{
|
| 215 |
int num;
|
| 216 |
spinlock_lock (&num_of_processors_lock);
|
| 217 |
num = num_of_processors;
|
| 218 |
spinlock_unlock (&num_of_processors_lock);
|
| 219 |
return num;
|
| 220 |
}
|