Started adding pthread code to spawn the "CPUs". Added some debugging
[dragonfly/vkernel-mp.git] / sys / platform / vkernel / i386 / mp.c
blobdbef199c3cd6957a795ef6b15fdb596abb34b26a
1 /*
2 * Copyright (c) 2007 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
34 * $DragonFly: src/sys/platform/vkernel/i386/mp.c,v 1.1 2007/06/18 18:57:12 josepht Exp $
38 #include <sys/interrupt.h>
39 #include <sys/tls.h>
40 #include <sys/types.h>
42 #include <vm/vm_extern.h>
43 #include <vm/vm_kern.h>
44 #include <vm/vm_object.h>
45 #include <vm/vm_page.h>
47 #include <machine/cpufunc.h>
48 #include <machine/globaldata.h>
49 #include <machine/md_var.h>
50 #include <machine/pmap.h>
51 #include <machine/smp.h>
52 #include <machine/tls.h>
54 #include <unistd.h>
55 #include <pthread.h>
57 extern pt_entry_t *KPTphys;
59 volatile u_int stopped_cpus;
60 cpumask_t smp_active_mask = 1; /* which cpus are ready for IPIs etc? */
61 static int mp_capable;
62 static int boot_address;
63 static cpumask_t smp_startup_mask = 1; /* which cpus have been started */
64 int mp_naps; /* # of Applications processors */
66 pt_entry_t *SMPpt;
68 /* AP uses this during bootstrap. Do not staticize. */
69 char *bootSTK;
70 static int bootAP;
73 /* XXX these need to go into the appropriate header file */
74 static int start_all_aps(u_int);
75 void init_secondary(void);
76 void *start_ap(void *);
78 #if 0
79 u_int mp_lock;
80 #endif
82 void *
83 start_ap(void *arg)
85 int ap_id = *(int *)arg;
86 kprintf("mycpu->gd_cpuid: %d\n", mycpu->gd_cpuid);
88 init_secondary();
89 get_mplock();
90 kprintf("mycpu->gd_cpuid: %d\n", mycpu->gd_cpuid);
91 rel_mplock();
93 kprintf("start_ap %d\n", ap_id);
94 bootstrap_idle();
97 /* storage for AP thread IDs */
98 pthread_t ap_tids[MAXCPU];
100 void
101 mp_start(void)
103 int shift;
105 /* XXX testing 2 cpus */
106 ncpus = 2;
108 mp_naps = ncpus - 1;
110 /* ncpus2 -- ncpus rounded down to the nearest power of 2 */
111 for (shift = 0; (1 << shift) <= ncpus; ++shift)
113 --shift;
114 ncpus2_shift = shift;
115 ncpus2 = 1 << shift;
116 ncpus2_mask = ncpus2 - 1;
118 /* ncpus_fit -- ncpus rounded up to the nearest power of 2 */
119 if ((1 << shift) < ncpus)
120 ++shift;
121 ncpus_fit = 1 << shift;
122 ncpus_fit_mask = ncpus_fit - 1;
124 /* build our map of 'other' CPUs */
125 mycpu->gd_other_cpus = smp_startup_mask & ~(1 << mycpu->gd_cpuid);
126 mycpu->gd_ipiq = (void *)kmem_alloc(&kernel_map, sizeof(lwkt_ipiq) * ncpus);
127 bzero(mycpu->gd_ipiq, sizeof(lwkt_ipiq) * ncpus);
129 start_all_aps(boot_address);
133 void
134 mp_announce(void)
136 int x;
138 kprintf("DragonFly/MP: Multiprocessor\n");
139 kprintf(" cpu0 (BSP)\n");
141 for (x = 1; x <= mp_naps; ++x)
142 kprintf(" cpu%d (AP)\n", x);
145 void
146 forward_fastint_remote(void *arg)
148 panic("XXX forward_fastint_remote()");
151 void
152 cpu_send_ipiq(int dcpu)
154 kprintf("cpu_send_ipiq(%d)\n", dcpu);
155 /* panic("XXX cpu_send_ipiq()"); */
158 void
159 smp_invltlb(void)
161 #ifdef SMP
162 panic("XXX smp_invltlb()");
163 #endif
167 stop_cpus(u_int map)
169 panic("XXX stop_cpus()");
173 restart_cpus(u_int map)
175 panic("XXX restart_cpus()");
178 void
179 ap_init(void)
181 panic("XXX ap_init()");
184 void
185 init_secondary(void)
187 int myid = bootAP;
188 struct mdglobaldata *md;
189 struct privatespace *ps;
191 ps = &CPU_prvspace[myid];
193 #if 0
194 gdt_segs[GPRIV_SEL].ssd_base = (int)ps;
195 gdt_segs[GPROC0_SEL].ssd_base =
196 (int) &ps->mdglobaldata.gd_common_tss;
197 #endif
198 ps->mdglobaldata.mi.gd_prvspace = ps;
201 * Setup the %gs for cpu #n. The mycpu macro works after this
202 * point.
204 tls_set_fs(&CPU_prvspace[myid], sizeof(struct privatespace));
206 #if 0
207 for (x = 0; x < NGDT; x++) {
208 ssdtosd(&gdt_segs[x], &gdt[myid * NGDT + x].sd);
211 r_gdt.rd_limit = NGDT * sizeof(gdt[0]) - 1;
212 r_gdt.rd_base = (int) &gdt[myid * NGDT];
213 lgdt(&r_gdt); /* does magic intra-segment return */
215 lidt(&r_idt);
217 lldt(_default_ldt);
218 mdcpu->gd_currentldt = _default_ldt;
220 gsel_tss = GSEL(GPROC0_SEL, SEL_KPL);
221 gdt[myid * NGDT + GPROC0_SEL].sd.sd_type = SDT_SYS386TSS;
223 #endif
224 md = mdcpu; /* loaded through %fs:0 (mdglobaldata.mi.gd_prvspace)*/
226 md->gd_common_tss.tss_esp0 = 0; /* not used until after switch */
227 md->gd_common_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL);
228 md->gd_common_tss.tss_ioopt = (sizeof md->gd_common_tss) << 16;
229 #if 0
230 md->gd_tss_gdt = &gdt[myid * NGDT + GPROC0_SEL].sd;
231 md->gd_common_tssd = *md->gd_tss_gdt;
232 ltr(gsel_tss);
233 #endif
236 * Set to a known state:
237 * Set by mpboot.s: CR0_PG, CR0_PE
238 * Set by cpu_setregs: CR0_NE, CR0_MP, CR0_TS, CR0_WP, CR0_AM
240 #if 0
241 cr0 = rcr0();
242 cr0 &= ~(CR0_CD | CR0_NW | CR0_EM);
243 load_cr0(cr0);
244 pmap_set_opt(); /* PSE/4MB pages, etc */
246 /* set up CPU registers and state */
247 cpu_setregs();
249 /* set up FPU state on the AP */
250 npxinit(__INITIAL_NPXCW__);
252 /* set up SSE registers */
253 enable_sse();
254 #endif
258 static int
259 start_all_aps(u_int boot_addr)
261 int x, i, pg, count;
262 struct mdglobaldata *gd;
263 struct privatespace *ps;
264 char *stack;
265 vm_page_t m;
266 vm_offset_t va;
267 struct lwp_params params;
268 int *arg;
269 int arg2;
271 /* store the mappings so we can populate gd_CMAP[0-2] and gd_PMAP3 */
272 vpte_t *SMPpt2[4];
274 for (x = 1; x <= mp_naps; x++)
276 count = 0;
278 /* Allocate space for the CPU's private space. */
279 va = (vm_offset_t)&CPU_prvspace[x];
280 for (i = 0; i < sizeof(struct mdglobaldata); i += PAGE_SIZE) {
281 va =(vm_offset_t)&CPU_prvspace[x].mdglobaldata + i;
282 m = vm_page_alloc(&kernel_object, va, VM_ALLOC_SYSTEM);
283 pmap_kenter_quick(va, m->phys_addr);
284 KKASSERT(count < 4);
285 SMPpt2[count] = pmap_kpte(va);
288 for (i = 0; i < sizeof(CPU_prvspace[0].idlestack); i += PAGE_SIZE) {
289 va =(vm_offset_t)&CPU_prvspace[x].idlestack + i;
290 m = vm_page_alloc(&kernel_object, va, VM_ALLOC_SYSTEM);
291 pmap_kenter_quick(va, m->phys_addr);
294 #if 0
295 /* first page of AP's private space */
296 pg = x * i386_btop(sizeof(struct privatespace));
298 kprintf("pg: %d, PAGE_SIZE: %d\n", pg, PAGE_SIZE);
299 /* allocate new private data page(s) */
300 gd = (struct mdglobaldata *)kmem_alloc(&kernel_map,
301 MDGLOBALDATA_BASEALLOC_SIZE);
302 kprintf("added gd: %p, x: %d, sizeof(gd): %x\n", gd, x,
303 sizeof(struct mdglobaldata));
304 /* wire it into the private page table page */
305 for (i = 0; i < MDGLOBALDATA_BASEALLOC_SIZE; i += PAGE_SIZE) {
306 SMPpt[pg + i / PAGE_SIZE] = (pt_entry_t)
307 (PG_V | PG_RW | vtophys_pte((char *)gd + i));
309 pg += MDGLOBALDATA_BASEALLOC_PAGES;
311 SMPpt[pg + 0] = 0; /* *gd_CMAP1 */
312 SMPpt[pg + 1] = 0; /* *gd_CMAP2 */
313 SMPpt[pg + 2] = 0; /* *gd_CMAP3 */
314 SMPpt[pg + 3] = 0; /* *gd_PMAP1 */
316 /* allocate and set up an idle stack data page */
317 stack = (char *)kmem_alloc(&kernel_map, UPAGES*PAGE_SIZE);
318 for (i = 0; i < UPAGES; i++) {
319 SMPpt[pg + 4 + i] = (pt_entry_t)
320 (PG_V | PG_RW | vtophys_pte(PAGE_SIZE * i + stack));
322 #endif
324 gd = &CPU_prvspace[x].mdglobaldata; /* official location */
325 bzero(gd, sizeof(*gd));
326 gd->mi.gd_prvspace = ps = &CPU_prvspace[x];
328 /* prime data page for it to use */
329 mi_gdinit(&gd->mi, x);
330 cpu_gdinit(gd, x);
331 #if 0
332 gd->gd_CMAP1 = &SMPpt[pg + 0];
333 gd->gd_CMAP2 = &SMPpt[pg + 1];
334 gd->gd_CMAP3 = &SMPpt[pg + 2];
335 gd->gd_PMAP1 = &SMPpt[pg + 3];
336 #endif
337 gd->gd_CMAP1 = SMPpt2[0];
338 gd->gd_CMAP2 = SMPpt2[1];
339 gd->gd_CMAP3 = SMPpt2[2];
340 gd->gd_PMAP1 = SMPpt2[3];
341 gd->gd_CADDR1 = ps->CPAGE1;
342 gd->gd_CADDR2 = ps->CPAGE2;
343 gd->gd_CADDR3 = ps->CPAGE3;
344 gd->gd_PADDR1 = (unsigned *)ps->PPAGE1;
345 gd->mi.gd_ipiq = (void *)kmem_alloc(&kernel_map, sizeof(lwkt_ipiq) * (mp_naps + 1));
346 bzero(gd->mi.gd_ipiq, sizeof(lwkt_ipiq) * (mp_naps + 1));
348 #if 0
350 /* setup a vector to our boot code */
351 *((volatile u_short *) WARMBOOT_OFF) = WARMBOOT_TARGET;
352 *((volatile u_short *) WARMBOOT_SEG) = (boot_addr >> 4);
353 outb(CMOS_REG, BIOS_RESET);
354 outb(CMOS_DATA, BIOS_WARM); /* 'warm-start' */
355 #endif
358 * Setup the AP boot stack
360 bootSTK = &ps->idlestack[UPAGES*PAGE_SIZE/2];
361 bootAP = x;
364 * Setup the AP's lwp, this is the 'cpu'
366 arg = (int *)kmem_alloc(&kernel_map, sizeof(int));
367 bzero(arg, sizeof(int));
368 *arg = x;
369 #if 0
370 arg2 = x;
371 params.func = start_ap;
372 params.arg = &arg2;
373 params.stack = &CPU_prvspace[x].idlestack;
374 params.tid1 = &ap_tids[x];
375 params.tid2 = &ap_tids[x];
376 lwp_create(&params);
377 #endif
378 kprintf("arg: %p, value = %d\n", arg, *arg);
379 pthread_create(&ap_tids[x], NULL, start_ap, arg);
382 return(ncpus - 1);