CS350 COS
COS
Loading...
Searching...
No Matches
mp.c
Go to the documentation of this file.
1
2#include <stdbool.h>
3#include <stdint.h>
4#include <string.h>
5
6#include <sys/kassert.h>
7#include <sys/kconfig.h>
8#include <sys/kdebug.h>
9#include <sys/kmem.h>
10#include <sys/ktime.h>
11#include <sys/mp.h>
12
13#include <machine/amd64.h>
14#include <machine/amd64op.h>
15#include <machine/pmap.h>
16#include <machine/lapic.h>
17#include <machine/mp.h>
18#include <machine/trap.h>
19
20extern uint8_t mpstart_begin[];
21extern uint8_t mpstart_end[];
22
23extern AS systemAS;
24
25#define MP_WAITTIME 250000000ULL
26
27typedef struct CrossCallFrame {
29 void *arg;
30 volatile int count;
31 volatile int done[MAX_CPUS];
32 volatile int status[MAX_CPUS];
34
35const char *CPUStateToString[] = {
36 "NOT PRESENT",
37 "BOOTED",
38 "HALTED",
39};
40
41typedef struct CPUState {
42 int state;
46
47volatile static bool booted;
48volatile static int lastCPU;
49volatile static CPUState cpus[MAX_CPUS];
50
51static int
52MPBootAP(int procNo)
53{
54 UnixEpochNS startTS, stopTS;
55 /*
56 * Arguments to mpstart are stored at 0x6F00
57 * arg[0] = CR3
58 * arg[1] = RSP
59 */
60 volatile uint64_t *args = (uint64_t *)DMPA2VA(0x6F00);
61
62 kprintf("Starting processor %d\n", procNo);
64
65 args[0] = DMVA2PA((uint64_t)systemAS.root);
66 args[1] = PGSIZE + (uint64_t)PAlloc_AllocPage();
67
68 kprintf("CR3: %016llx RSP: %016llx\n", args[0], args[1]);
69
70 booted = 0;
71 LAPIC_StartAP(procNo, 0x7000);
72
73 startTS = KTime_GetEpochNS();
74 while (1) {
75 if (booted == 1)
76 break;
77
78 stopTS = KTime_GetEpochNS();
79 if ((stopTS - startTS) > MP_WAITTIME) {
80 kprintf("Processor %d did not respond in %d ms\n",
81 procNo, MP_WAITTIME / 1000000ULL);
82 PAlloc_Release((void *)(args[1] - PGSIZE));
83 return -1;
84 }
85 }
86
87 return 0;
88}
89
90void
92{
93 int i;
94 kprintf("Booting on CPU %u\n", CPU());
95
97 cpus[CPU()].frame = NULL;
98
99 for (i = 1; i < MAX_CPUS; i++) {
101 cpus[i].frame = NULL;
102 }
103
104 /*
105 * XXX: We really should read from the MP Table, but this appears to be
106 * reliable for now.
107 */
108 lastCPU = 0;
109 for (i = 1; i < MAX_CPUS; i++) {
110 if (MPBootAP(i) < 0)
111 break;
112
113 lastCPU = i;
114 }
115 lastCPU++;
116}
117
118void
120{
121 kprintf("AP %d booted!\n", CPU());
123 booted = 1;
124}
125
126void
127MP_SetState(int state)
128{
129 ASSERT(state > 0 && state <= CPUSTATE_MAX);
130 cpus[CPU()].state = state;
131}
132
133int
135{
136 return lastCPU;
137}
138
139void
141{
142 int c;
143
144 cpuid(0, 0, 0, 0, 0);
145
147
148 for (c = 0; c <= lastCPU; c++) {
149 CrossCallFrame *frame = cpus[c].frame;
150 if (frame == NULL)
151 continue;
152
153 if (frame->done[CPU()] == 1)
154 continue;
155
156 frame->status[CPU()] = (frame->cb)(frame->arg);
157 frame->done[CPU()] = 1;
158
159 // Increment
160 __sync_add_and_fetch(&frame->count, 1);
161 }
162
164}
165
166// XXX: The thread should not be migrated in the middle of this call.
167int
169{
170 volatile CrossCallFrame frame;
171
172 // Setup frame
173 memset((void *)&frame, 0, sizeof(frame));
174 frame.cb = cb;
175 frame.arg = arg;
176 frame.count = 1;
177
179
180 cpus[CPU()].frame = (CrossCallFrame *)&frame;
181 cpuid(0, 0, 0, 0, 0);
182
184 return -1;
185
186 // Run on the local CPU
187 frame.status[CPU()] = cb(arg);
188 frame.done[CPU()] = 1;
189
190 // Wait for all to respond
191 while (frame.count < lastCPU) {
192 // Check for timeout
193
194 // XXX: Should dump the crosscall frame
195 }
196 cpus[CPU()].frame = NULL;
197 cpuid(0, 0, 0, 0, 0);
198
200
201 return 0;
202}
203
204static int
205MPPing(void *arg)
206{
207 //kprintf("CPU %d Ack\n", CPU());
208 return 0;
209}
210
211static void
212Debug_CrossCall(int argc, const char *argv[])
213{
214 int i;
215 UnixEpochNS startTS, stopTS;
216
217 startTS = KTime_GetEpochNS();
218 for (i = 0; i < 32; i++) {
220 }
221 stopTS = KTime_GetEpochNS();
222
223 // XXX: Print min and max
224 kprintf("Average CrossCall Latency: %llu ns\n",
225 (stopTS - startTS) / 32ULL);
226
227 return;
228}
229
230REGISTER_DBGCMD(crosscall, "Ping crosscall", Debug_CrossCall);
231
232static void
233Debug_CPUS(int argc, const char *argv[])
234{
235 int c;
236
237 for (c = 0; c < MAX_CPUS; c++) {
238 if (cpus[c].state != CPUSTATE_NOT_PRESENT) {
239 kprintf("CPU %d: %s\n", c, CPUStateToString[cpus[c].state]);
240 }
241 }
242}
243
244REGISTER_DBGCMD(cpus, "Show MP information", Debug_CPUS);
245
246static void
247Debug_CPU(int argc, const char *argv[])
248{
249 kprintf("CPU %d\n", CPU());
250}
251
252REGISTER_DBGCMD(cpu, "Current CPU number", Debug_CPU);
253
#define CPUSTATE_NOT_PRESENT
Definition: mp.h:5
#define CPUSTATE_MAX
Definition: mp.h:8
int(* CrossCallCB)(void *)
Definition: mp.h:16
#define CPUSTATE_BOOTED
Definition: mp.h:6
static INLINE void cpuid(uint32_t info, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
Definition: amd64op.h:85
void Critical_Exit()
Definition: critical.c:35
void Critical_Enter()
Definition: critical.c:28
#define CPU
Definition: mp.h:7
#define ASSERT(_x)
Definition: kassert.h:8
int kprintf(const char *fmt,...)
Definition: printf.c:210
#define MAX_CPUS
Definition: kconfig.h:8
#define REGISTER_DBGCMD(_NAME, _DESC, _FUNC)
Definition: kdebug.h:11
void PAlloc_Release(void *pg)
Definition: palloc.c:265
void * PAlloc_AllocPage()
Definition: palloc.c:188
UnixEpochNS KTime_GetEpochNS()
Definition: ktime.c:194
uint64_t UnixEpochNS
Definition: ktime.h:19
int LAPIC_Broadcast(int vector)
Definition: lapic.c:143
void LAPIC_StartAP(uint8_t apicid, uint32_t addr)
Definition: lapic.c:116
#define PGSIZE
Definition: malloc.c:21
static volatile int lastCPU
Definition: mp.c:48
int MP_GetCPUs()
Definition: mp.c:134
void MP_CrossCallTrap()
Definition: mp.c:140
static int MPPing(void *arg)
Definition: mp.c:205
static volatile bool booted
Definition: mp.c:47
static volatile CPUState cpus[MAX_CPUS]
Definition: mp.c:49
volatile int status[MAX_CPUS]
Definition: mp.c:32
static void Debug_CPU(int argc, const char *argv[])
Definition: mp.c:247
AS systemAS
Definition: pmap.c:15
volatile int done[MAX_CPUS]
Definition: mp.c:31
UnixEpochNS heartbeat
Definition: mp.c:43
const char * CPUStateToString[]
Definition: mp.c:35
void MP_InitAP()
Definition: mp.c:119
void MP_SetState(int state)
Definition: mp.c:127
volatile int count
Definition: mp.c:30
int state
Definition: mp.c:42
uint8_t mpstart_begin[]
#define MP_WAITTIME
Definition: mp.c:25
void * arg
Definition: mp.c:29
static void Debug_CPUS(int argc, const char *argv[])
Definition: mp.c:233
static int MPBootAP(int procNo)
Definition: mp.c:52
static void Debug_CrossCall(int argc, const char *argv[])
Definition: mp.c:212
uint8_t mpstart_end[]
CrossCallFrame * frame
Definition: mp.c:44
int MP_CrossCall(CrossCallCB cb, void *arg)
Definition: mp.c:168
void MP_Init()
Definition: mp.c:91
CrossCallCB cb
Definition: mp.c:28
Definition: mp.c:41
#define DMVA2PA(dmva)
Definition: pmap.h:47
PageTable * root
Definition: pmap.h:53
#define DMPA2VA(pa)
Definition: pmap.h:48
Definition: pmap.h:52
#define NULL
Definition: stddef.h:6
void * memset(void *dst, int c, size_t len)
Definition: string.c:164
void * memcpy(void *dst, const void *src, size_t len)
Definition: string.c:177
#define T_CROSSCALL
Definition: trap.h:43
unsigned long uint64_t
Definition: types.h:13
unsigned char uint8_t
Definition: types.h:10