This source file includes following definitions.
- cpu_init_first
- cpu_match
- cpu_attach
- cpu_init
- cpu_boot_secondary_processors
- cpu_init_idle_pcbs
- cpu_boot_secondary
- cpu_hatch
- cpu_copy_trampoline
- cpu_init_tss
- cpu_set_tss_gates
- mp_cpu_start
- mp_cpu_start_cleanup
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74 #include "lapic.h"
75 #include "ioapic.h"
76
77 #include <sys/param.h>
78 #include <sys/proc.h>
79 #include <sys/user.h>
80 #include <sys/systm.h>
81 #include <sys/device.h>
82
83 #include <uvm/uvm_extern.h>
84
85 #include <machine/cpu.h>
86 #include <machine/cpufunc.h>
87 #include <machine/cpuvar.h>
88 #include <machine/pmap.h>
89 #include <machine/vmparam.h>
90 #include <machine/mpbiosvar.h>
91 #include <machine/npx.h>
92 #include <machine/pcb.h>
93 #include <machine/specialreg.h>
94 #include <machine/segments.h>
95 #include <machine/gdt.h>
96 #include <machine/pio.h>
97
98 #if NLAPIC > 0
99 #include <machine/apicvar.h>
100 #include <machine/i82489reg.h>
101 #include <machine/i82489var.h>
102 #endif
103
104 #if NIOAPIC > 0
105 #include <machine/i82093reg.h>
106 #include <machine/i82093var.h>
107 #endif
108
109 #include <dev/ic/mc146818reg.h>
110 #include <i386/isa/nvram.h>
111 #include <dev/isa/isareg.h>
112
113 int cpu_match(struct device *, void *, void *);
114 void cpu_attach(struct device *, struct device *, void *);
115
116 #ifdef MULTIPROCESSOR
117 int mp_cpu_start(struct cpu_info *);
118 void mp_cpu_start_cleanup(struct cpu_info *);
119 struct cpu_functions mp_cpu_funcs =
120 { mp_cpu_start, NULL, mp_cpu_start_cleanup };
121 #endif
122
123
124
125
126
127
128 struct cpu_info cpu_info_primary;
129 struct cpu_info *cpu_info_list = &cpu_info_primary;
130
131 void cpu_init_tss(struct i386tss *, void *, void *);
132 void cpu_set_tss_gates(struct cpu_info *);
133
134 #ifdef MULTIPROCESSOR
135
136
137
138
139
140 struct cpu_info *cpu_info[I386_MAXPROCS] = { &cpu_info_primary };
141
142 void cpu_hatch(void *);
143 void cpu_boot_secondary(struct cpu_info *);
144 void cpu_copy_trampoline(void);
145
146
147
148
149
150
151 void
152 cpu_init_first()
153 {
154 int cpunum = lapic_cpu_number();
155
156 if (cpunum != 0) {
157 cpu_info[0] = NULL;
158 cpu_info[cpunum] = &cpu_info_primary;
159 }
160
161 cpu_copy_trampoline();
162 }
163 #endif
164
165 struct cfattach cpu_ca = {
166 sizeof(struct cpu_info), cpu_match, cpu_attach
167 };
168
169 struct cfdriver cpu_cd = {
170 NULL, "cpu", DV_DULL
171 };
172
173 int
174 cpu_match(struct device *parent, void *matchv, void *aux)
175 {
176 struct cfdata *match = (struct cfdata *)matchv;
177 struct cpu_attach_args *caa = (struct cpu_attach_args *)aux;
178
179 if (strcmp(caa->caa_name, match->cf_driver->cd_name) == 0)
180 return (1);
181 return (0);
182 }
183
184 void
185 cpu_attach(struct device *parent, struct device *self, void *aux)
186 {
187 struct cpu_info *ci = (struct cpu_info *)self;
188 struct cpu_attach_args *caa = (struct cpu_attach_args *)aux;
189
190 #ifdef MULTIPROCESSOR
191 int cpunum = caa->cpu_number;
192 vaddr_t kstack;
193 struct pcb *pcb;
194
195 if (caa->cpu_role != CPU_ROLE_AP) {
196 if (cpunum != lapic_cpu_number()) {
197 panic("%s: running cpu is at apic %d"
198 " instead of at expected %d",
199 self->dv_xname, lapic_cpu_number(), cpunum);
200 }
201
202 ci = &cpu_info_primary;
203 bcopy(self, &ci->ci_dev, sizeof *self);
204
205
206 if (cpu_info[cpunum] == &cpu_info_primary) {
207 cpu_info[cpunum] = NULL;
208 }
209 }
210 if (cpu_info[cpunum] != NULL)
211 panic("cpu at apic id %d already attached?", cpunum);
212
213 cpu_info[cpunum] = ci;
214 #endif
215
216 ci->ci_self = ci;
217 ci->ci_apicid = caa->cpu_number;
218 #ifdef MULTIPROCESSOR
219 ci->ci_cpuid = ci->ci_apicid;
220 #else
221 ci->ci_cpuid = 0;
222 #endif
223 ci->ci_signature = caa->cpu_signature;
224 ci->ci_feature_flags = caa->feature_flags;
225 ci->ci_func = caa->cpu_func;
226
227 #ifdef MULTIPROCESSOR
228
229
230
231
232 kstack = uvm_km_alloc(kernel_map, USPACE);
233 if (kstack == 0) {
234 if (cpunum == 0) {
235 panic("cpu_attach: unable to allocate idle stack for"
236 " primary");
237 }
238 printf("%s: unable to allocate idle stack\n",
239 ci->ci_dev.dv_xname);
240 return;
241 }
242 pcb = ci->ci_idle_pcb = (struct pcb *)kstack;
243 memset(pcb, 0, USPACE);
244
245 pcb->pcb_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL);
246 pcb->pcb_tss.tss_esp0 = kstack + USPACE - 16 -
247 sizeof (struct trapframe);
248 pcb->pcb_tss.tss_esp = kstack + USPACE - 16 -
249 sizeof (struct trapframe);
250 pcb->pcb_pmap = pmap_kernel();
251 pcb->pcb_cr3 = pcb->pcb_pmap->pm_pdirpa;
252
253
254 cpu_default_ldt(ci);
255 #endif
256
257
258
259
260 #ifdef MULTIPROCESSOR
261 printf(": ");
262
263 switch (caa->cpu_role) {
264 case CPU_ROLE_SP:
265 printf("(uniprocessor)\n");
266 ci->ci_flags |= CPUF_PRESENT | CPUF_SP | CPUF_PRIMARY;
267 identifycpu(ci);
268 cpu_init(ci);
269 break;
270
271 case CPU_ROLE_BP:
272 printf("apid %d (boot processor)\n", caa->cpu_number);
273 ci->ci_flags |= CPUF_PRESENT | CPUF_BSP | CPUF_PRIMARY;
274 identifycpu(ci);
275 cpu_init(ci);
276
277 #if NLAPIC > 0
278
279
280
281 lapic_enable();
282 lapic_calibrate_timer(ci);
283 #endif
284 #if NIOAPIC > 0
285 ioapic_bsp_id = caa->cpu_number;
286 #endif
287 break;
288
289 case CPU_ROLE_AP:
290
291
292
293 printf("apid %d (application processor)\n", caa->cpu_number);
294 gdt_alloc_cpu(ci);
295 cpu_alloc_ldt(ci);
296 ci->ci_flags |= CPUF_PRESENT | CPUF_AP;
297 identifycpu(ci);
298 ci->ci_next = cpu_info_list->ci_next;
299 cpu_info_list->ci_next = ci;
300 ncpus++;
301 break;
302
303 default:
304 panic("unknown processor type??");
305 }
306
307
308 if (ci->ci_apicid < IOAPIC_ID_MAX)
309 ioapic_id_map &= ~(1 << ci->ci_apicid);
310
311 if (mp_verbose) {
312 printf("%s: kstack at 0x%lx for %d bytes\n",
313 ci->ci_dev.dv_xname, kstack, USPACE);
314 printf("%s: idle pcb at %p, idle sp at 0x%x\n",
315 ci->ci_dev.dv_xname, pcb, pcb->pcb_esp);
316 }
317 #else
318 printf("\n");
319 #endif
320 }
321
322
323
324
325
326 #ifdef MULTIPROCESSOR
327 void
328 cpu_init(struct cpu_info *ci)
329 {
330
331 if (ci->cpu_setup != NULL)
332 (*ci->cpu_setup)(ci);
333
334
335
336
337
338 lcr0(rcr0() | CR0_WP);
339
340 if (cpu_feature & CPUID_PGE)
341 lcr4(rcr4() | CR4_PGE);
342
343 ci->ci_flags |= CPUF_RUNNING;
344 #if defined(I686_CPU)
345
346
347
348 if (cpu_feature & CPUID_FXSR) {
349 lcr4(rcr4() | CR4_OSFXSR);
350
351
352
353
354 if (cpu_feature & (CPUID_SSE|CPUID_SSE2))
355 lcr4(rcr4() | CR4_OSXMMEXCPT);
356 }
357 #endif
358 }
359
360 void
361 cpu_boot_secondary_processors()
362 {
363 struct cpu_info *ci;
364 u_long i;
365
366 for (i = 0; i < I386_MAXPROCS; i++) {
367 ci = cpu_info[i];
368 if (ci == NULL)
369 continue;
370 if (ci->ci_idle_pcb == NULL)
371 continue;
372 if ((ci->ci_flags & CPUF_PRESENT) == 0)
373 continue;
374 if (ci->ci_flags & (CPUF_BSP|CPUF_SP|CPUF_PRIMARY))
375 continue;
376 cpu_boot_secondary(ci);
377 }
378 }
379
380 void
381 cpu_init_idle_pcbs()
382 {
383 struct cpu_info *ci;
384 u_long i;
385
386 for (i=0; i < I386_MAXPROCS; i++) {
387 ci = cpu_info[i];
388 if (ci == NULL)
389 continue;
390 if (ci->ci_idle_pcb == NULL)
391 continue;
392 if ((ci->ci_flags & CPUF_PRESENT) == 0)
393 continue;
394 i386_init_pcb_tss_ldt(ci);
395 }
396 }
397
398 void
399 cpu_boot_secondary(struct cpu_info *ci)
400 {
401 struct pcb *pcb;
402 int i;
403 struct pmap *kpm = pmap_kernel();
404 extern u_int32_t mp_pdirpa;
405
406 if (mp_verbose)
407 printf("%s: starting", ci->ci_dev.dv_xname);
408
409
410 mp_pdirpa = kpm->pm_pdirpa;
411
412 pcb = ci->ci_idle_pcb;
413
414 if (mp_verbose)
415 printf(", init idle stack ptr is 0x%x\n", pcb->pcb_esp);
416
417 CPU_STARTUP(ci);
418
419
420
421
422 for (i = 100000; (!(ci->ci_flags & CPUF_RUNNING)) && i > 0; i--) {
423 delay(10);
424 }
425 if (!(ci->ci_flags & CPUF_RUNNING)) {
426 printf("%s failed to become ready\n", ci->ci_dev.dv_xname);
427 #ifdef DDB
428 Debugger();
429 #endif
430 }
431
432 CPU_START_CLEANUP(ci);
433 }
434
435
436
437
438
439
440 void
441 cpu_hatch(void *v)
442 {
443 struct cpu_info *ci = (struct cpu_info *)v;
444 int s;
445
446 cpu_init_idt();
447 lapic_enable();
448 lapic_initclocks();
449 lapic_set_lvt();
450 gdt_init_cpu(ci);
451 cpu_init_ldt(ci);
452 npxinit(ci);
453
454 lldt(GSEL(GLDT_SEL, SEL_KPL));
455
456 cpu_init(ci);
457
458 s = splhigh();
459 lapic_tpr = 0;
460 enable_intr();
461 if (mp_verbose)
462 printf("%s: CPU at apid %ld running\n",
463 ci->ci_dev.dv_xname, ci->ci_cpuid);
464 microuptime(&ci->ci_schedstate.spc_runtime);
465 splx(s);
466 }
467
468 void
469 cpu_copy_trampoline()
470 {
471
472
473
474 extern u_char cpu_spinup_trampoline[];
475 extern u_char cpu_spinup_trampoline_end[];
476
477 pmap_kenter_pa((vaddr_t)MP_TRAMPOLINE,
478 (paddr_t)MP_TRAMPOLINE,
479 VM_PROT_ALL);
480 bcopy(cpu_spinup_trampoline, (caddr_t)MP_TRAMPOLINE,
481 cpu_spinup_trampoline_end - cpu_spinup_trampoline);
482 }
483
484 #endif
485
486 #ifdef notyet
487 void
488 cpu_init_tss(struct i386tss *tss, void *stack, void *func)
489 {
490 memset(tss, 0, sizeof *tss);
491 tss->tss_esp0 = tss->tss_esp = (int)((char *)stack + USPACE - 16);
492 tss->tss_ss0 = GSEL(GDATA_SEL, SEL_KPL);
493 tss->__tss_cs = GSEL(GCODE_SEL, SEL_KPL);
494 tss->tss_fs = GSEL(GCPU_SEL, SEL_KPL);
495 tss->tss_gs = tss->__tss_es = tss->__tss_ds =
496 tss->__tss_ss = GSEL(GDATA_SEL, SEL_KPL);
497 tss->tss_cr3 = pmap_kernel()->pm_pdirpa;
498 tss->tss_esp = (int)((char *)stack + USPACE - 16);
499 tss->tss_ldt = GSEL(GLDT_SEL, SEL_KPL);
500 tss->__tss_eflags = PSL_MBO | PSL_NT;
501 tss->__tss_eip = (int)func;
502 }
503
504
505 #define IDTVEC(name) __CONCAT(X, name)
506 typedef void (vector)(void);
507 extern vector IDTVEC(tss_trap08);
508 #ifdef DDB
509 extern vector Xintrddbipi;
510 extern int ddb_vec;
511 #endif
512
513 void
514 cpu_set_tss_gates(struct cpu_info *ci)
515 {
516 struct segment_descriptor sd;
517
518 ci->ci_doubleflt_stack = (char *)uvm_km_alloc(kernel_map, USPACE);
519 cpu_init_tss(&ci->ci_doubleflt_tss, ci->ci_doubleflt_stack,
520 IDTVEC(tss_trap08));
521 setsegment(&sd, &ci->ci_doubleflt_tss, sizeof(struct i386tss) - 1,
522 SDT_SYS386TSS, SEL_KPL, 0, 0);
523 ci->ci_gdt[GTRAPTSS_SEL].sd = sd;
524 setgate(&idt[8], NULL, 0, SDT_SYSTASKGT, SEL_KPL,
525 GSEL(GTRAPTSS_SEL, SEL_KPL));
526
527 #if defined(DDB) && defined(MULTIPROCESSOR)
528
529
530
531
532
533
534
535 ci->ci_ddbipi_stack = (char *)uvm_km_alloc(kernel_map, USPACE);
536 cpu_init_tss(&ci->ci_ddbipi_tss, ci->ci_ddbipi_stack,
537 Xintrddbipi);
538
539 setsegment(&sd, &ci->ci_ddbipi_tss, sizeof(struct i386tss) - 1,
540 SDT_SYS386TSS, SEL_KPL, 0, 0);
541 ci->ci_gdt[GIPITSS_SEL].sd = sd;
542
543 setgate(&idt[ddb_vec], NULL, 0, SDT_SYSTASKGT, SEL_KPL,
544 GSEL(GIPITSS_SEL, SEL_KPL));
545 #endif
546 }
547 #endif
548
549 #ifdef MULTIPROCESSOR
550 int
551 mp_cpu_start(struct cpu_info *ci)
552 {
553 #if NLAPIC > 0
554 int error;
555 #endif
556 unsigned short dwordptr[2];
557
558
559
560
561
562 outb(IO_RTC, NVRAM_RESET);
563 outb(IO_RTC+1, NVRAM_RESET_JUMP);
564
565
566
567
568
569
570 dwordptr[0] = 0;
571 dwordptr[1] = MP_TRAMPOLINE >> 4;
572
573 pmap_kenter_pa(0, 0, VM_PROT_READ|VM_PROT_WRITE);
574 memcpy((u_int8_t *)0x467, dwordptr, 4);
575 pmap_kremove(0, PAGE_SIZE);
576
577 #if NLAPIC > 0
578
579
580
581
582 if (ci->ci_flags & CPUF_AP) {
583 if ((error = i386_ipi_init(ci->ci_apicid)) != 0)
584 return (error);
585
586 delay(10000);
587
588 if (cpu_feature & CPUID_APIC) {
589 if ((error = i386_ipi(MP_TRAMPOLINE / PAGE_SIZE,
590 ci->ci_apicid, LAPIC_DLMODE_STARTUP)) != 0)
591 return (error);
592 delay(200);
593
594 if ((error = i386_ipi(MP_TRAMPOLINE / PAGE_SIZE,
595 ci->ci_apicid, LAPIC_DLMODE_STARTUP)) != 0)
596 return (error);
597 delay(200);
598 }
599 }
600 #endif
601 return (0);
602 }
603
604 void
605 mp_cpu_start_cleanup(struct cpu_info *ci)
606 {
607
608
609
610
611 outb(IO_RTC, NVRAM_RESET);
612 outb(IO_RTC+1, NVRAM_RESET_RST);
613 }
614 #endif