1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6
7 #include "apic.h"
8 #include "sipi.h"
9
10 #define SIPIHANDLER (KZERO+0x3000)
11
12 /*
13 * Parameters are passed to the bootstrap code via a vector
14 * in low memory indexed by the APIC number of the processor.
15 * The layout, size, and location have to be kept in sync
16 * with the handler code in l64sipi.s.
17 */
18 typedef struct Sipi Sipi;
19 struct Sipi {
20 u32int pml4;
21 u32int _4_;
22 uintptr stack;
23 Mach* mach;
24 uintptr pc;
25 };
26
27 void
sipi(void)28 sipi(void)
29 {
30 Apic *apic;
31 Mach *mach;
32 Sipi *sipi;
33 int apicno, i;
34 u8int *sipiptr;
35 uintmem sipipa;
36 u8int *alloc, *p;
37 extern void squidboy(int);
38
39 /*
40 * Move the startup code into place,
41 * must be aligned properly.
42 */
43 sipipa = mmuphysaddr(SIPIHANDLER);
44 if((sipipa & (4*KiB - 1)) || sipipa > (1*MiB - 2*4*KiB))
45 return;
46 sipiptr = UINT2PTR(SIPIHANDLER);
47 memmove(sipiptr, sipihandler, sizeof(sipihandler));
48 memset(sipiptr+4*KiB, 0, sizeof(Sipi)*Napic);
49
50 /*
51 * Notes:
52 * The Universal Startup Algorithm described in the MP Spec. 1.4.
53 * The data needed per-processor is the sum of the stack, page
54 * table pages, vsvm page and the Mach page. The layout is similar
55 * to that described in data.h for the bootstrap processor, but
56 * with any unused space elided.
57 */
58 for(apicno = 0; apicno < Napic; apicno++){
59 apic = &xapic[apicno];
60 if(!apic->useable || apic->addr || apic->machno == 0)
61 continue;
62 sipi = &((Sipi*)(sipiptr+4*KiB))[apicno];
63
64 /*
65 * NOTE: for now, share the page tables with the
66 * bootstrap processor, until this code is worked out,
67 * so only the Mach and stack portions are used below.
68 */
69 alloc = mallocalign(MACHSTKSZ+4*PTSZ+4*KiB+MACHSZ, 4096, 0, 0);
70 if(alloc == nil)
71 continue;
72 memset(alloc, 0, MACHSTKSZ+4*PTSZ+4*KiB+MACHSZ);
73 p = alloc+MACHSTKSZ;
74
75 sipi->pml4 = cr3get();
76 sipi->stack = PTR2UINT(p);
77
78 p += 4*PTSZ+4*KiB;
79
80 /*
81 * Committed. If the AP startup fails, can't safely
82 * release the resources, who knows what mischief
83 * the AP is up to. Perhaps should try to put it
84 * back into the INIT state?
85 */
86 mach = (Mach*)p;
87 sipi->mach = mach;
88 mach->machno = apic->machno; /* NOT one-to-one... */
89 mach->splpc = PTR2UINT(squidboy);
90 sipi->pc = mach->splpc;
91 mach->apicno = apicno;
92 mach->stack = PTR2UINT(alloc);
93 mach->vsvm = alloc+MACHSTKSZ+4*PTSZ;
94 mach->pml4 = m->pml4;
95
96 p = KADDR(0x467);
97 *p++ = sipipa;
98 *p++ = sipipa>>8;
99 *p++ = 0;
100 *p = 0;
101
102 nvramwrite(0x0f, 0x0a);
103 apicsipi(apicno, sipipa);
104
105 for(i = 0; i < 1000; i++){
106 if(mach->splpc == 0)
107 break;
108 millidelay(5);
109 }
110 nvramwrite(0x0f, 0x00);
111
112 DBG("apicno%d: machno %d mach %#p (%#p) %dMHz\n",
113 apicno, mach->machno,
114 mach, sys->machptr[mach->machno],
115 mach->cpumhz);
116 }
117 }
118