Rename kcpuset_copybits() to kcpuset_export_u32() and thus be more specific about the interface.diff -r1.83 -r1.84 src/sys/arch/arm/arm32/arm32_machdep.c
(rmind)
--- src/sys/arch/arm/arm32/arm32_machdep.c 2012/08/31 23:59:51 1.83
+++ src/sys/arch/arm/arm32/arm32_machdep.c 2012/09/16 22:09:33 1.84
@@ -1,563 +1,563 @@ | @@ -1,563 +1,563 @@ | |||
1 | /* $NetBSD: arm32_machdep.c,v 1.83 2012/08/31 23:59:51 matt Exp $ */ | 1 | /* $NetBSD: arm32_machdep.c,v 1.84 2012/09/16 22:09:33 rmind Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1994-1998 Mark Brinicombe. | 4 | * Copyright (c) 1994-1998 Mark Brinicombe. | |
5 | * Copyright (c) 1994 Brini. | 5 | * Copyright (c) 1994 Brini. | |
6 | * All rights reserved. | 6 | * All rights reserved. | |
7 | * | 7 | * | |
8 | * This code is derived from software written for Brini by Mark Brinicombe | 8 | * This code is derived from software written for Brini by Mark Brinicombe | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | 15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | 16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | 17 | * documentation and/or other materials provided with the distribution. | |
18 | * 3. All advertising materials mentioning features or use of this software | 18 | * 3. All advertising materials mentioning features or use of this software | |
19 | * must display the following acknowledgement: | 19 | * must display the following acknowledgement: | |
20 | * This product includes software developed by Mark Brinicombe | 20 | * This product includes software developed by Mark Brinicombe | |
21 | * for the NetBSD Project. | 21 | * for the NetBSD Project. | |
22 | * 4. The name of the company nor the name of the author may be used to | 22 | * 4. The name of the company nor the name of the author may be used to | |
23 | * endorse or promote products derived from this software without specific | 23 | * endorse or promote products derived from this software without specific | |
24 | * prior written permission. | 24 | * prior written permission. | |
25 | * | 25 | * | |
26 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED | 26 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED | |
27 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | 27 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
28 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | 28 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
29 | * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | 29 | * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | |
30 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 30 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
31 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | 31 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
32 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 32 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
33 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 33 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
34 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 34 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
35 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 35 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
36 | * SUCH DAMAGE. | 36 | * SUCH DAMAGE. | |
37 | * | 37 | * | |
38 | * Machine dependent functions for kernel setup | 38 | * Machine dependent functions for kernel setup | |
39 | * | 39 | * | |
40 | * Created : 17/09/94 | 40 | * Created : 17/09/94 | |
41 | * Updated : 18/04/01 updated for new wscons | 41 | * Updated : 18/04/01 updated for new wscons | |
42 | */ | 42 | */ | |
43 | 43 | |||
44 | #include <sys/cdefs.h> | 44 | #include <sys/cdefs.h> | |
45 | __KERNEL_RCSID(0, "$NetBSD: arm32_machdep.c,v 1.83 2012/08/31 23:59:51 matt Exp $"); | 45 | __KERNEL_RCSID(0, "$NetBSD: arm32_machdep.c,v 1.84 2012/09/16 22:09:33 rmind Exp $"); | |
46 | 46 | |||
47 | #include "opt_modular.h" | 47 | #include "opt_modular.h" | |
48 | #include "opt_md.h" | 48 | #include "opt_md.h" | |
49 | #include "opt_pmap_debug.h" | 49 | #include "opt_pmap_debug.h" | |
50 | 50 | |||
51 | #include <sys/param.h> | 51 | #include <sys/param.h> | |
52 | #include <sys/systm.h> | 52 | #include <sys/systm.h> | |
53 | #include <sys/reboot.h> | 53 | #include <sys/reboot.h> | |
54 | #include <sys/proc.h> | 54 | #include <sys/proc.h> | |
55 | #include <sys/kauth.h> | 55 | #include <sys/kauth.h> | |
56 | #include <sys/kernel.h> | 56 | #include <sys/kernel.h> | |
57 | #include <sys/mbuf.h> | 57 | #include <sys/mbuf.h> | |
58 | #include <sys/mount.h> | 58 | #include <sys/mount.h> | |
59 | #include <sys/buf.h> | 59 | #include <sys/buf.h> | |
60 | #include <sys/msgbuf.h> | 60 | #include <sys/msgbuf.h> | |
61 | #include <sys/device.h> | 61 | #include <sys/device.h> | |
62 | #include <sys/sysctl.h> | 62 | #include <sys/sysctl.h> | |
63 | #include <sys/cpu.h> | 63 | #include <sys/cpu.h> | |
64 | #include <sys/intr.h> | 64 | #include <sys/intr.h> | |
65 | #include <sys/module.h> | 65 | #include <sys/module.h> | |
66 | #include <sys/atomic.h> | 66 | #include <sys/atomic.h> | |
67 | #include <sys/xcall.h> | 67 | #include <sys/xcall.h> | |
68 | 68 | |||
69 | #include <uvm/uvm_extern.h> | 69 | #include <uvm/uvm_extern.h> | |
70 | 70 | |||
71 | #include <dev/cons.h> | 71 | #include <dev/cons.h> | |
72 | #include <dev/mm.h> | 72 | #include <dev/mm.h> | |
73 | 73 | |||
74 | #include <arm/arm32/katelib.h> | 74 | #include <arm/arm32/katelib.h> | |
75 | #include <arm/arm32/machdep.h> | 75 | #include <arm/arm32/machdep.h> | |
76 | 76 | |||
77 | #include <machine/bootconfig.h> | 77 | #include <machine/bootconfig.h> | |
78 | #include <machine/pcb.h> | 78 | #include <machine/pcb.h> | |
79 | 79 | |||
80 | void (*cpu_reset_address)(void); /* Used by locore */ | 80 | void (*cpu_reset_address)(void); /* Used by locore */ | |
81 | paddr_t cpu_reset_address_paddr; /* Used by locore */ | 81 | paddr_t cpu_reset_address_paddr; /* Used by locore */ | |
82 | 82 | |||
83 | struct vm_map *phys_map = NULL; | 83 | struct vm_map *phys_map = NULL; | |
84 | 84 | |||
85 | #if defined(MEMORY_DISK_HOOKS) && !defined(MEMORY_DISK_ROOT_SIZE) | 85 | #if defined(MEMORY_DISK_HOOKS) && !defined(MEMORY_DISK_ROOT_SIZE) | |
86 | extern size_t md_root_size; /* Memory disc size */ | 86 | extern size_t md_root_size; /* Memory disc size */ | |
87 | #endif /* MEMORY_DISK_HOOKS && !MEMORY_DISK_ROOT_SIZE */ | 87 | #endif /* MEMORY_DISK_HOOKS && !MEMORY_DISK_ROOT_SIZE */ | |
88 | 88 | |||
89 | pv_addr_t kernelstack; | 89 | pv_addr_t kernelstack; | |
90 | pv_addr_t abtstack; | 90 | pv_addr_t abtstack; | |
91 | pv_addr_t fiqstack; | 91 | pv_addr_t fiqstack; | |
92 | pv_addr_t irqstack; | 92 | pv_addr_t irqstack; | |
93 | pv_addr_t undstack; | 93 | pv_addr_t undstack; | |
94 | pv_addr_t idlestack; | 94 | pv_addr_t idlestack; | |
95 | 95 | |||
96 | void * msgbufaddr; | 96 | void * msgbufaddr; | |
97 | extern paddr_t msgbufphys; | 97 | extern paddr_t msgbufphys; | |
98 | 98 | |||
99 | int kernel_debug = 0; | 99 | int kernel_debug = 0; | |
100 | 100 | |||
101 | /* exported variable to be filled in by the bootloaders */ | 101 | /* exported variable to be filled in by the bootloaders */ | |
102 | char *booted_kernel; | 102 | char *booted_kernel; | |
103 | 103 | |||
104 | /* Prototypes */ | 104 | /* Prototypes */ | |
105 | 105 | |||
106 | void data_abort_handler(trapframe_t *frame); | 106 | void data_abort_handler(trapframe_t *frame); | |
107 | void prefetch_abort_handler(trapframe_t *frame); | 107 | void prefetch_abort_handler(trapframe_t *frame); | |
108 | extern void configure(void); | 108 | extern void configure(void); | |
109 | 109 | |||
110 | /* | 110 | /* | |
111 | * arm32_vector_init: | 111 | * arm32_vector_init: | |
112 | * | 112 | * | |
113 | * Initialize the vector page, and select whether or not to | 113 | * Initialize the vector page, and select whether or not to | |
114 | * relocate the vectors. | 114 | * relocate the vectors. | |
115 | * | 115 | * | |
116 | * NOTE: We expect the vector page to be mapped at its expected | 116 | * NOTE: We expect the vector page to be mapped at its expected | |
117 | * destination. | 117 | * destination. | |
118 | */ | 118 | */ | |
119 | void | 119 | void | |
120 | arm32_vector_init(vaddr_t va, int which) | 120 | arm32_vector_init(vaddr_t va, int which) | |
121 | { | 121 | { | |
122 | if (CPU_IS_PRIMARY(curcpu())) { | 122 | if (CPU_IS_PRIMARY(curcpu())) { | |
123 | extern unsigned int page0[], page0_data[]; | 123 | extern unsigned int page0[], page0_data[]; | |
124 | unsigned int *vectors = (int *) va; | 124 | unsigned int *vectors = (int *) va; | |
125 | unsigned int *vectors_data = vectors + (page0_data - page0); | 125 | unsigned int *vectors_data = vectors + (page0_data - page0); | |
126 | int vec; | 126 | int vec; | |
127 | 127 | |||
128 | /* | 128 | /* | |
129 | * Loop through the vectors we're taking over, and copy the | 129 | * Loop through the vectors we're taking over, and copy the | |
130 | * vector's insn and data word. | 130 | * vector's insn and data word. | |
131 | */ | 131 | */ | |
132 | for (vec = 0; vec < ARM_NVEC; vec++) { | 132 | for (vec = 0; vec < ARM_NVEC; vec++) { | |
133 | if ((which & (1 << vec)) == 0) { | 133 | if ((which & (1 << vec)) == 0) { | |
134 | /* Don't want to take over this vector. */ | 134 | /* Don't want to take over this vector. */ | |
135 | continue; | 135 | continue; | |
136 | } | 136 | } | |
137 | vectors[vec] = page0[vec]; | 137 | vectors[vec] = page0[vec]; | |
138 | vectors_data[vec] = page0_data[vec]; | 138 | vectors_data[vec] = page0_data[vec]; | |
139 | } | 139 | } | |
140 | 140 | |||
141 | /* Now sync the vectors. */ | 141 | /* Now sync the vectors. */ | |
142 | cpu_icache_sync_range(va, (ARM_NVEC * 2) * sizeof(u_int)); | 142 | cpu_icache_sync_range(va, (ARM_NVEC * 2) * sizeof(u_int)); | |
143 | 143 | |||
144 | vector_page = va; | 144 | vector_page = va; | |
145 | } | 145 | } | |
146 | 146 | |||
147 | if (va == ARM_VECTORS_HIGH) { | 147 | if (va == ARM_VECTORS_HIGH) { | |
148 | /* | 148 | /* | |
149 | * Assume the MD caller knows what it's doing here, and | 149 | * Assume the MD caller knows what it's doing here, and | |
150 | * really does want the vector page relocated. | 150 | * really does want the vector page relocated. | |
151 | * | 151 | * | |
152 | * Note: This has to be done here (and not just in | 152 | * Note: This has to be done here (and not just in | |
153 | * cpu_setup()) because the vector page needs to be | 153 | * cpu_setup()) because the vector page needs to be | |
154 | * accessible *before* cpu_startup() is called. | 154 | * accessible *before* cpu_startup() is called. | |
155 | * Think ddb(9) ... | 155 | * Think ddb(9) ... | |
156 | * | 156 | * | |
157 | * NOTE: If the CPU control register is not readable, | 157 | * NOTE: If the CPU control register is not readable, | |
158 | * this will totally fail! We'll just assume that | 158 | * this will totally fail! We'll just assume that | |
159 | * any system that has high vector support has a | 159 | * any system that has high vector support has a | |
160 | * readable CPU control register, for now. If we | 160 | * readable CPU control register, for now. If we | |
161 | * ever encounter one that does not, we'll have to | 161 | * ever encounter one that does not, we'll have to | |
162 | * rethink this. | 162 | * rethink this. | |
163 | */ | 163 | */ | |
164 | cpu_control(CPU_CONTROL_VECRELOC, CPU_CONTROL_VECRELOC); | 164 | cpu_control(CPU_CONTROL_VECRELOC, CPU_CONTROL_VECRELOC); | |
165 | } | 165 | } | |
166 | } | 166 | } | |
167 | 167 | |||
168 | /* | 168 | /* | |
169 | * Debug function just to park the CPU | 169 | * Debug function just to park the CPU | |
170 | */ | 170 | */ | |
171 | 171 | |||
172 | void | 172 | void | |
173 | halt(void) | 173 | halt(void) | |
174 | { | 174 | { | |
175 | while (1) | 175 | while (1) | |
176 | cpu_sleep(0); | 176 | cpu_sleep(0); | |
177 | } | 177 | } | |
178 | 178 | |||
179 | 179 | |||
180 | /* Sync the discs and unmount the filesystems */ | 180 | /* Sync the discs and unmount the filesystems */ | |
181 | 181 | |||
182 | void | 182 | void | |
183 | bootsync(void) | 183 | bootsync(void) | |
184 | { | 184 | { | |
185 | static bool bootsyncdone = false; | 185 | static bool bootsyncdone = false; | |
186 | 186 | |||
187 | if (bootsyncdone) return; | 187 | if (bootsyncdone) return; | |
188 | 188 | |||
189 | bootsyncdone = true; | 189 | bootsyncdone = true; | |
190 | 190 | |||
191 | /* Make sure we can still manage to do things */ | 191 | /* Make sure we can still manage to do things */ | |
192 | if (GetCPSR() & I32_bit) { | 192 | if (GetCPSR() & I32_bit) { | |
193 | /* | 193 | /* | |
194 | * If we get here then boot has been called without RB_NOSYNC | 194 | * If we get here then boot has been called without RB_NOSYNC | |
195 | * and interrupts were disabled. This means the boot() call | 195 | * and interrupts were disabled. This means the boot() call | |
196 | * did not come from a user process e.g. shutdown, but must | 196 | * did not come from a user process e.g. shutdown, but must | |
197 | * have come from somewhere in the kernel. | 197 | * have come from somewhere in the kernel. | |
198 | */ | 198 | */ | |
199 | IRQenable; | 199 | IRQenable; | |
200 | printf("Warning IRQ's disabled during boot()\n"); | 200 | printf("Warning IRQ's disabled during boot()\n"); | |
201 | } | 201 | } | |
202 | 202 | |||
203 | vfs_shutdown(); | 203 | vfs_shutdown(); | |
204 | } | 204 | } | |
205 | 205 | |||
206 | /* | 206 | /* | |
207 | * void cpu_startup(void) | 207 | * void cpu_startup(void) | |
208 | * | 208 | * | |
209 | * Machine dependent startup code. | 209 | * Machine dependent startup code. | |
210 | * | 210 | * | |
211 | */ | 211 | */ | |
212 | void | 212 | void | |
213 | cpu_startup(void) | 213 | cpu_startup(void) | |
214 | { | 214 | { | |
215 | vaddr_t minaddr; | 215 | vaddr_t minaddr; | |
216 | vaddr_t maxaddr; | 216 | vaddr_t maxaddr; | |
217 | u_int loop; | 217 | u_int loop; | |
218 | char pbuf[9]; | 218 | char pbuf[9]; | |
219 | 219 | |||
220 | /* | 220 | /* | |
221 | * Until we better locking, we have to live under the kernel lock. | 221 | * Until we better locking, we have to live under the kernel lock. | |
222 | */ | 222 | */ | |
223 | //KERNEL_LOCK(1, NULL); | 223 | //KERNEL_LOCK(1, NULL); | |
224 | 224 | |||
225 | /* Set the CPU control register */ | 225 | /* Set the CPU control register */ | |
226 | cpu_setup(boot_args); | 226 | cpu_setup(boot_args); | |
227 | 227 | |||
228 | /* Lock down zero page */ | 228 | /* Lock down zero page */ | |
229 | vector_page_setprot(VM_PROT_READ); | 229 | vector_page_setprot(VM_PROT_READ); | |
230 | 230 | |||
231 | /* | 231 | /* | |
232 | * Give pmap a chance to set up a few more things now the vm | 232 | * Give pmap a chance to set up a few more things now the vm | |
233 | * is initialised | 233 | * is initialised | |
234 | */ | 234 | */ | |
235 | pmap_postinit(); | 235 | pmap_postinit(); | |
236 | 236 | |||
237 | /* | 237 | /* | |
238 | * Initialize error message buffer (at end of core). | 238 | * Initialize error message buffer (at end of core). | |
239 | */ | 239 | */ | |
240 | 240 | |||
241 | /* msgbufphys was setup during the secondary boot strap */ | 241 | /* msgbufphys was setup during the secondary boot strap */ | |
242 | for (loop = 0; loop < btoc(MSGBUFSIZE); ++loop) | 242 | for (loop = 0; loop < btoc(MSGBUFSIZE); ++loop) | |
243 | pmap_kenter_pa((vaddr_t)msgbufaddr + loop * PAGE_SIZE, | 243 | pmap_kenter_pa((vaddr_t)msgbufaddr + loop * PAGE_SIZE, | |
244 | msgbufphys + loop * PAGE_SIZE, | 244 | msgbufphys + loop * PAGE_SIZE, | |
245 | VM_PROT_READ|VM_PROT_WRITE, 0); | 245 | VM_PROT_READ|VM_PROT_WRITE, 0); | |
246 | pmap_update(pmap_kernel()); | 246 | pmap_update(pmap_kernel()); | |
247 | initmsgbuf(msgbufaddr, round_page(MSGBUFSIZE)); | 247 | initmsgbuf(msgbufaddr, round_page(MSGBUFSIZE)); | |
248 | 248 | |||
249 | /* | 249 | /* | |
250 | * Identify ourselves for the msgbuf (everything printed earlier will | 250 | * Identify ourselves for the msgbuf (everything printed earlier will | |
251 | * not be buffered). | 251 | * not be buffered). | |
252 | */ | 252 | */ | |
253 | printf("%s%s", copyright, version); | 253 | printf("%s%s", copyright, version); | |
254 | 254 | |||
255 | format_bytes(pbuf, sizeof(pbuf), arm_ptob(physmem)); | 255 | format_bytes(pbuf, sizeof(pbuf), arm_ptob(physmem)); | |
256 | printf("total memory = %s\n", pbuf); | 256 | printf("total memory = %s\n", pbuf); | |
257 | 257 | |||
258 | minaddr = 0; | 258 | minaddr = 0; | |
259 | 259 | |||
260 | /* | 260 | /* | |
261 | * Allocate a submap for physio | 261 | * Allocate a submap for physio | |
262 | */ | 262 | */ | |
263 | phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, | 263 | phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, | |
264 | VM_PHYS_SIZE, 0, false, NULL); | 264 | VM_PHYS_SIZE, 0, false, NULL); | |
265 | 265 | |||
266 | format_bytes(pbuf, sizeof(pbuf), ptoa(uvmexp.free)); | 266 | format_bytes(pbuf, sizeof(pbuf), ptoa(uvmexp.free)); | |
267 | printf("avail memory = %s\n", pbuf); | 267 | printf("avail memory = %s\n", pbuf); | |
268 | 268 | |||
269 | struct lwp * const l = &lwp0; | 269 | struct lwp * const l = &lwp0; | |
270 | struct pcb * const pcb = lwp_getpcb(l); | 270 | struct pcb * const pcb = lwp_getpcb(l); | |
271 | pcb->pcb_sp = uvm_lwp_getuarea(l) + USPACE_SVC_STACK_TOP; | 271 | pcb->pcb_sp = uvm_lwp_getuarea(l) + USPACE_SVC_STACK_TOP; | |
272 | lwp_settrapframe(l, (struct trapframe *)pcb->pcb_sp - 1); | 272 | lwp_settrapframe(l, (struct trapframe *)pcb->pcb_sp - 1); | |
273 | } | 273 | } | |
274 | 274 | |||
275 | /* | 275 | /* | |
276 | * machine dependent system variables. | 276 | * machine dependent system variables. | |
277 | */ | 277 | */ | |
278 | static int | 278 | static int | |
279 | sysctl_machdep_booted_device(SYSCTLFN_ARGS) | 279 | sysctl_machdep_booted_device(SYSCTLFN_ARGS) | |
280 | { | 280 | { | |
281 | struct sysctlnode node; | 281 | struct sysctlnode node; | |
282 | 282 | |||
283 | if (booted_device == NULL) | 283 | if (booted_device == NULL) | |
284 | return (EOPNOTSUPP); | 284 | return (EOPNOTSUPP); | |
285 | 285 | |||
286 | node = *rnode; | 286 | node = *rnode; | |
287 | node.sysctl_data = booted_device->dv_xname; | 287 | node.sysctl_data = booted_device->dv_xname; | |
288 | node.sysctl_size = strlen(booted_device->dv_xname) + 1; | 288 | node.sysctl_size = strlen(booted_device->dv_xname) + 1; | |
289 | return (sysctl_lookup(SYSCTLFN_CALL(&node))); | 289 | return (sysctl_lookup(SYSCTLFN_CALL(&node))); | |
290 | } | 290 | } | |
291 | 291 | |||
292 | static int | 292 | static int | |
293 | sysctl_machdep_booted_kernel(SYSCTLFN_ARGS) | 293 | sysctl_machdep_booted_kernel(SYSCTLFN_ARGS) | |
294 | { | 294 | { | |
295 | struct sysctlnode node; | 295 | struct sysctlnode node; | |
296 | 296 | |||
297 | if (booted_kernel == NULL || booted_kernel[0] == '\0') | 297 | if (booted_kernel == NULL || booted_kernel[0] == '\0') | |
298 | return (EOPNOTSUPP); | 298 | return (EOPNOTSUPP); | |
299 | 299 | |||
300 | node = *rnode; | 300 | node = *rnode; | |
301 | node.sysctl_data = booted_kernel; | 301 | node.sysctl_data = booted_kernel; | |
302 | node.sysctl_size = strlen(booted_kernel) + 1; | 302 | node.sysctl_size = strlen(booted_kernel) + 1; | |
303 | return (sysctl_lookup(SYSCTLFN_CALL(&node))); | 303 | return (sysctl_lookup(SYSCTLFN_CALL(&node))); | |
304 | } | 304 | } | |
305 | 305 | |||
306 | static int | 306 | static int | |
307 | sysctl_machdep_powersave(SYSCTLFN_ARGS) | 307 | sysctl_machdep_powersave(SYSCTLFN_ARGS) | |
308 | { | 308 | { | |
309 | struct sysctlnode node = *rnode; | 309 | struct sysctlnode node = *rnode; | |
310 | int error, newval; | 310 | int error, newval; | |
311 | 311 | |||
312 | newval = cpu_do_powersave; | 312 | newval = cpu_do_powersave; | |
313 | node.sysctl_data = &newval; | 313 | node.sysctl_data = &newval; | |
314 | if (cpufuncs.cf_sleep == (void *) cpufunc_nullop) | 314 | if (cpufuncs.cf_sleep == (void *) cpufunc_nullop) | |
315 | node.sysctl_flags &= ~CTLFLAG_READWRITE; | 315 | node.sysctl_flags &= ~CTLFLAG_READWRITE; | |
316 | error = sysctl_lookup(SYSCTLFN_CALL(&node)); | 316 | error = sysctl_lookup(SYSCTLFN_CALL(&node)); | |
317 | if (error || newp == NULL || newval == cpu_do_powersave) | 317 | if (error || newp == NULL || newval == cpu_do_powersave) | |
318 | return (error); | 318 | return (error); | |
319 | 319 | |||
320 | if (newval < 0 || newval > 1) | 320 | if (newval < 0 || newval > 1) | |
321 | return (EINVAL); | 321 | return (EINVAL); | |
322 | cpu_do_powersave = newval; | 322 | cpu_do_powersave = newval; | |
323 | 323 | |||
324 | return (0); | 324 | return (0); | |
325 | } | 325 | } | |
326 | 326 | |||
327 | SYSCTL_SETUP(sysctl_machdep_setup, "sysctl machdep subtree setup") | 327 | SYSCTL_SETUP(sysctl_machdep_setup, "sysctl machdep subtree setup") | |
328 | { | 328 | { | |
329 | 329 | |||
330 | sysctl_createv(clog, 0, NULL, NULL, | 330 | sysctl_createv(clog, 0, NULL, NULL, | |
331 | CTLFLAG_PERMANENT, | 331 | CTLFLAG_PERMANENT, | |
332 | CTLTYPE_NODE, "machdep", NULL, | 332 | CTLTYPE_NODE, "machdep", NULL, | |
333 | NULL, 0, NULL, 0, | 333 | NULL, 0, NULL, 0, | |
334 | CTL_MACHDEP, CTL_EOL); | 334 | CTL_MACHDEP, CTL_EOL); | |
335 | 335 | |||
336 | sysctl_createv(clog, 0, NULL, NULL, | 336 | sysctl_createv(clog, 0, NULL, NULL, | |
337 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, | 337 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, | |
338 | CTLTYPE_INT, "debug", NULL, | 338 | CTLTYPE_INT, "debug", NULL, | |
339 | NULL, 0, &kernel_debug, 0, | 339 | NULL, 0, &kernel_debug, 0, | |
340 | CTL_MACHDEP, CPU_DEBUG, CTL_EOL); | 340 | CTL_MACHDEP, CPU_DEBUG, CTL_EOL); | |
341 | sysctl_createv(clog, 0, NULL, NULL, | 341 | sysctl_createv(clog, 0, NULL, NULL, | |
342 | CTLFLAG_PERMANENT, | 342 | CTLFLAG_PERMANENT, | |
343 | CTLTYPE_STRING, "booted_device", NULL, | 343 | CTLTYPE_STRING, "booted_device", NULL, | |
344 | sysctl_machdep_booted_device, 0, NULL, 0, | 344 | sysctl_machdep_booted_device, 0, NULL, 0, | |
345 | CTL_MACHDEP, CPU_BOOTED_DEVICE, CTL_EOL); | 345 | CTL_MACHDEP, CPU_BOOTED_DEVICE, CTL_EOL); | |
346 | sysctl_createv(clog, 0, NULL, NULL, | 346 | sysctl_createv(clog, 0, NULL, NULL, | |
347 | CTLFLAG_PERMANENT, | 347 | CTLFLAG_PERMANENT, | |
348 | CTLTYPE_STRING, "booted_kernel", NULL, | 348 | CTLTYPE_STRING, "booted_kernel", NULL, | |
349 | sysctl_machdep_booted_kernel, 0, NULL, 0, | 349 | sysctl_machdep_booted_kernel, 0, NULL, 0, | |
350 | CTL_MACHDEP, CPU_BOOTED_KERNEL, CTL_EOL); | 350 | CTL_MACHDEP, CPU_BOOTED_KERNEL, CTL_EOL); | |
351 | sysctl_createv(clog, 0, NULL, NULL, | 351 | sysctl_createv(clog, 0, NULL, NULL, | |
352 | CTLFLAG_PERMANENT, | 352 | CTLFLAG_PERMANENT, | |
353 | CTLTYPE_STRUCT, "console_device", NULL, | 353 | CTLTYPE_STRUCT, "console_device", NULL, | |
354 | sysctl_consdev, 0, NULL, sizeof(dev_t), | 354 | sysctl_consdev, 0, NULL, sizeof(dev_t), | |
355 | CTL_MACHDEP, CPU_CONSDEV, CTL_EOL); | 355 | CTL_MACHDEP, CPU_CONSDEV, CTL_EOL); | |
356 | sysctl_createv(clog, 0, NULL, NULL, | 356 | sysctl_createv(clog, 0, NULL, NULL, | |
357 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, | 357 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, | |
358 | CTLTYPE_INT, "powersave", NULL, | 358 | CTLTYPE_INT, "powersave", NULL, | |
359 | sysctl_machdep_powersave, 0, &cpu_do_powersave, 0, | 359 | sysctl_machdep_powersave, 0, &cpu_do_powersave, 0, | |
360 | CTL_MACHDEP, CPU_POWERSAVE, CTL_EOL); | 360 | CTL_MACHDEP, CPU_POWERSAVE, CTL_EOL); | |
361 | } | 361 | } | |
362 | 362 | |||
363 | void | 363 | void | |
364 | parse_mi_bootargs(char *args) | 364 | parse_mi_bootargs(char *args) | |
365 | { | 365 | { | |
366 | int integer; | 366 | int integer; | |
367 | 367 | |||
368 | if (get_bootconf_option(args, "single", BOOTOPT_TYPE_BOOLEAN, &integer) | 368 | if (get_bootconf_option(args, "single", BOOTOPT_TYPE_BOOLEAN, &integer) | |
369 | || get_bootconf_option(args, "-s", BOOTOPT_TYPE_BOOLEAN, &integer)) | 369 | || get_bootconf_option(args, "-s", BOOTOPT_TYPE_BOOLEAN, &integer)) | |
370 | if (integer) | 370 | if (integer) | |
371 | boothowto |= RB_SINGLE; | 371 | boothowto |= RB_SINGLE; | |
372 | if (get_bootconf_option(args, "kdb", BOOTOPT_TYPE_BOOLEAN, &integer) | 372 | if (get_bootconf_option(args, "kdb", BOOTOPT_TYPE_BOOLEAN, &integer) | |
373 | || get_bootconf_option(args, "-k", BOOTOPT_TYPE_BOOLEAN, &integer)) | 373 | || get_bootconf_option(args, "-k", BOOTOPT_TYPE_BOOLEAN, &integer)) | |
374 | if (integer) | 374 | if (integer) | |
375 | boothowto |= RB_KDB; | 375 | boothowto |= RB_KDB; | |
376 | if (get_bootconf_option(args, "ask", BOOTOPT_TYPE_BOOLEAN, &integer) | 376 | if (get_bootconf_option(args, "ask", BOOTOPT_TYPE_BOOLEAN, &integer) | |
377 | || get_bootconf_option(args, "-a", BOOTOPT_TYPE_BOOLEAN, &integer)) | 377 | || get_bootconf_option(args, "-a", BOOTOPT_TYPE_BOOLEAN, &integer)) | |
378 | if (integer) | 378 | if (integer) | |
379 | boothowto |= RB_ASKNAME; | 379 | boothowto |= RB_ASKNAME; | |
380 | 380 | |||
381 | #ifdef PMAP_DEBUG | 381 | #ifdef PMAP_DEBUG | |
382 | if (get_bootconf_option(args, "pmapdebug", BOOTOPT_TYPE_INT, &integer)) { | 382 | if (get_bootconf_option(args, "pmapdebug", BOOTOPT_TYPE_INT, &integer)) { | |
383 | pmap_debug_level = integer; | 383 | pmap_debug_level = integer; | |
384 | pmap_debug(pmap_debug_level); | 384 | pmap_debug(pmap_debug_level); | |
385 | } | 385 | } | |
386 | #endif /* PMAP_DEBUG */ | 386 | #endif /* PMAP_DEBUG */ | |
387 | 387 | |||
388 | /* if (get_bootconf_option(args, "nbuf", BOOTOPT_TYPE_INT, &integer)) | 388 | /* if (get_bootconf_option(args, "nbuf", BOOTOPT_TYPE_INT, &integer)) | |
389 | bufpages = integer;*/ | 389 | bufpages = integer;*/ | |
390 | 390 | |||
391 | #if defined(MEMORY_DISK_HOOKS) && !defined(MEMORY_DISK_ROOT_SIZE) | 391 | #if defined(MEMORY_DISK_HOOKS) && !defined(MEMORY_DISK_ROOT_SIZE) | |
392 | if (get_bootconf_option(args, "memorydisc", BOOTOPT_TYPE_INT, &integer) | 392 | if (get_bootconf_option(args, "memorydisc", BOOTOPT_TYPE_INT, &integer) | |
393 | || get_bootconf_option(args, "memorydisk", BOOTOPT_TYPE_INT, &integer)) { | 393 | || get_bootconf_option(args, "memorydisk", BOOTOPT_TYPE_INT, &integer)) { | |
394 | md_root_size = integer; | 394 | md_root_size = integer; | |
395 | md_root_size *= 1024; | 395 | md_root_size *= 1024; | |
396 | if (md_root_size < 32*1024) | 396 | if (md_root_size < 32*1024) | |
397 | md_root_size = 32*1024; | 397 | md_root_size = 32*1024; | |
398 | if (md_root_size > 2048*1024) | 398 | if (md_root_size > 2048*1024) | |
399 | md_root_size = 2048*1024; | 399 | md_root_size = 2048*1024; | |
400 | } | 400 | } | |
401 | #endif /* MEMORY_DISK_HOOKS && !MEMORY_DISK_ROOT_SIZE */ | 401 | #endif /* MEMORY_DISK_HOOKS && !MEMORY_DISK_ROOT_SIZE */ | |
402 | 402 | |||
403 | if (get_bootconf_option(args, "quiet", BOOTOPT_TYPE_BOOLEAN, &integer) | 403 | if (get_bootconf_option(args, "quiet", BOOTOPT_TYPE_BOOLEAN, &integer) | |
404 | || get_bootconf_option(args, "-q", BOOTOPT_TYPE_BOOLEAN, &integer)) | 404 | || get_bootconf_option(args, "-q", BOOTOPT_TYPE_BOOLEAN, &integer)) | |
405 | if (integer) | 405 | if (integer) | |
406 | boothowto |= AB_QUIET; | 406 | boothowto |= AB_QUIET; | |
407 | if (get_bootconf_option(args, "verbose", BOOTOPT_TYPE_BOOLEAN, &integer) | 407 | if (get_bootconf_option(args, "verbose", BOOTOPT_TYPE_BOOLEAN, &integer) | |
408 | || get_bootconf_option(args, "-v", BOOTOPT_TYPE_BOOLEAN, &integer)) | 408 | || get_bootconf_option(args, "-v", BOOTOPT_TYPE_BOOLEAN, &integer)) | |
409 | if (integer) | 409 | if (integer) | |
410 | boothowto |= AB_VERBOSE; | 410 | boothowto |= AB_VERBOSE; | |
411 | } | 411 | } | |
412 | 412 | |||
413 | #ifdef __HAVE_FAST_SOFTINTS | 413 | #ifdef __HAVE_FAST_SOFTINTS | |
414 | #if IPL_SOFTSERIAL != IPL_SOFTNET + 1 | 414 | #if IPL_SOFTSERIAL != IPL_SOFTNET + 1 | |
415 | #error IPLs are screwed up | 415 | #error IPLs are screwed up | |
416 | #elif IPL_SOFTNET != IPL_SOFTBIO + 1 | 416 | #elif IPL_SOFTNET != IPL_SOFTBIO + 1 | |
417 | #error IPLs are screwed up | 417 | #error IPLs are screwed up | |
418 | #elif IPL_SOFTBIO != IPL_SOFTCLOCK + 1 | 418 | #elif IPL_SOFTBIO != IPL_SOFTCLOCK + 1 | |
419 | #error IPLs are screwed up | 419 | #error IPLs are screwed up | |
420 | #elif !(IPL_SOFTCLOCK > IPL_NONE) | 420 | #elif !(IPL_SOFTCLOCK > IPL_NONE) | |
421 | #error IPLs are screwed up | 421 | #error IPLs are screwed up | |
422 | #elif (IPL_NONE != 0) | 422 | #elif (IPL_NONE != 0) | |
423 | #error IPLs are screwed up | 423 | #error IPLs are screwed up | |
424 | #endif | 424 | #endif | |
425 | 425 | |||
426 | #ifndef __HAVE_PIC_FAST_SOFTINTS | 426 | #ifndef __HAVE_PIC_FAST_SOFTINTS | |
427 | #define SOFTINT2IPLMAP \ | 427 | #define SOFTINT2IPLMAP \ | |
428 | (((IPL_SOFTSERIAL - IPL_SOFTCLOCK) << (SOFTINT_SERIAL * 4)) | \ | 428 | (((IPL_SOFTSERIAL - IPL_SOFTCLOCK) << (SOFTINT_SERIAL * 4)) | \ | |
429 | ((IPL_SOFTNET - IPL_SOFTCLOCK) << (SOFTINT_NET * 4)) | \ | 429 | ((IPL_SOFTNET - IPL_SOFTCLOCK) << (SOFTINT_NET * 4)) | \ | |
430 | ((IPL_SOFTBIO - IPL_SOFTCLOCK) << (SOFTINT_BIO * 4)) | \ | 430 | ((IPL_SOFTBIO - IPL_SOFTCLOCK) << (SOFTINT_BIO * 4)) | \ | |
431 | ((IPL_SOFTCLOCK - IPL_SOFTCLOCK) << (SOFTINT_CLOCK * 4))) | 431 | ((IPL_SOFTCLOCK - IPL_SOFTCLOCK) << (SOFTINT_CLOCK * 4))) | |
432 | #define SOFTINT2IPL(l) ((SOFTINT2IPLMAP >> ((l) * 4)) & 0x0f) | 432 | #define SOFTINT2IPL(l) ((SOFTINT2IPLMAP >> ((l) * 4)) & 0x0f) | |
433 | 433 | |||
434 | /* | 434 | /* | |
435 | * This returns a mask of softint IPLs that be dispatch at <ipl> | 435 | * This returns a mask of softint IPLs that be dispatch at <ipl> | |
436 | * SOFTIPLMASK(IPL_NONE) = 0x0000000f | 436 | * SOFTIPLMASK(IPL_NONE) = 0x0000000f | |
437 | * SOFTIPLMASK(IPL_SOFTCLOCK) = 0x0000000e | 437 | * SOFTIPLMASK(IPL_SOFTCLOCK) = 0x0000000e | |
438 | * SOFTIPLMASK(IPL_SOFTBIO) = 0x0000000c | 438 | * SOFTIPLMASK(IPL_SOFTBIO) = 0x0000000c | |
439 | * SOFTIPLMASK(IPL_SOFTNET) = 0x00000008 | 439 | * SOFTIPLMASK(IPL_SOFTNET) = 0x00000008 | |
440 | * SOFTIPLMASK(IPL_SOFTSERIAL) = 0x00000000 | 440 | * SOFTIPLMASK(IPL_SOFTSERIAL) = 0x00000000 | |
441 | */ | 441 | */ | |
442 | #define SOFTIPLMASK(ipl) ((0x0f << (ipl)) & 0x0f) | 442 | #define SOFTIPLMASK(ipl) ((0x0f << (ipl)) & 0x0f) | |
443 | 443 | |||
444 | void softint_switch(lwp_t *, int); | 444 | void softint_switch(lwp_t *, int); | |
445 | 445 | |||
446 | void | 446 | void | |
447 | softint_trigger(uintptr_t mask) | 447 | softint_trigger(uintptr_t mask) | |
448 | { | 448 | { | |
449 | curcpu()->ci_softints |= mask; | 449 | curcpu()->ci_softints |= mask; | |
450 | } | 450 | } | |
451 | 451 | |||
452 | void | 452 | void | |
453 | softint_init_md(lwp_t *l, u_int level, uintptr_t *machdep) | 453 | softint_init_md(lwp_t *l, u_int level, uintptr_t *machdep) | |
454 | { | 454 | { | |
455 | lwp_t ** lp = &l->l_cpu->ci_softlwps[level]; | 455 | lwp_t ** lp = &l->l_cpu->ci_softlwps[level]; | |
456 | KASSERT(*lp == NULL || *lp == l); | 456 | KASSERT(*lp == NULL || *lp == l); | |
457 | *lp = l; | 457 | *lp = l; | |
458 | *machdep = 1 << SOFTINT2IPL(level); | 458 | *machdep = 1 << SOFTINT2IPL(level); | |
459 | KASSERT(level != SOFTINT_CLOCK || *machdep == (1 << (IPL_SOFTCLOCK - IPL_SOFTCLOCK))); | 459 | KASSERT(level != SOFTINT_CLOCK || *machdep == (1 << (IPL_SOFTCLOCK - IPL_SOFTCLOCK))); | |
460 | KASSERT(level != SOFTINT_BIO || *machdep == (1 << (IPL_SOFTBIO - IPL_SOFTCLOCK))); | 460 | KASSERT(level != SOFTINT_BIO || *machdep == (1 << (IPL_SOFTBIO - IPL_SOFTCLOCK))); | |
461 | KASSERT(level != SOFTINT_NET || *machdep == (1 << (IPL_SOFTNET - IPL_SOFTCLOCK))); | 461 | KASSERT(level != SOFTINT_NET || *machdep == (1 << (IPL_SOFTNET - IPL_SOFTCLOCK))); | |
462 | KASSERT(level != SOFTINT_SERIAL || *machdep == (1 << (IPL_SOFTSERIAL - IPL_SOFTCLOCK))); | 462 | KASSERT(level != SOFTINT_SERIAL || *machdep == (1 << (IPL_SOFTSERIAL - IPL_SOFTCLOCK))); | |
463 | } | 463 | } | |
464 | 464 | |||
465 | void | 465 | void | |
466 | dosoftints(void) | 466 | dosoftints(void) | |
467 | { | 467 | { | |
468 | struct cpu_info * const ci = curcpu(); | 468 | struct cpu_info * const ci = curcpu(); | |
469 | const int opl = ci->ci_cpl; | 469 | const int opl = ci->ci_cpl; | |
470 | const uint32_t softiplmask = SOFTIPLMASK(opl); | 470 | const uint32_t softiplmask = SOFTIPLMASK(opl); | |
471 | 471 | |||
472 | splhigh(); | 472 | splhigh(); | |
473 | for (;;) { | 473 | for (;;) { | |
474 | u_int softints = ci->ci_softints & softiplmask; | 474 | u_int softints = ci->ci_softints & softiplmask; | |
475 | KASSERT((softints != 0) == ((ci->ci_softints >> opl) != 0)); | 475 | KASSERT((softints != 0) == ((ci->ci_softints >> opl) != 0)); | |
476 | KASSERT(opl == IPL_NONE || (softints & (1 << (opl - IPL_SOFTCLOCK))) == 0); | 476 | KASSERT(opl == IPL_NONE || (softints & (1 << (opl - IPL_SOFTCLOCK))) == 0); | |
477 | if (softints == 0) { | 477 | if (softints == 0) { | |
478 | splx(opl); | 478 | splx(opl); | |
479 | return; | 479 | return; | |
480 | } | 480 | } | |
481 | #define DOSOFTINT(n) \ | 481 | #define DOSOFTINT(n) \ | |
482 | if (ci->ci_softints & (1 << (IPL_SOFT ## n - IPL_SOFTCLOCK))) { \ | 482 | if (ci->ci_softints & (1 << (IPL_SOFT ## n - IPL_SOFTCLOCK))) { \ | |
483 | ci->ci_softints &= \ | 483 | ci->ci_softints &= \ | |
484 | ~(1 << (IPL_SOFT ## n - IPL_SOFTCLOCK)); \ | 484 | ~(1 << (IPL_SOFT ## n - IPL_SOFTCLOCK)); \ | |
485 | softint_switch(ci->ci_softlwps[SOFTINT_ ## n], \ | 485 | softint_switch(ci->ci_softlwps[SOFTINT_ ## n], \ | |
486 | IPL_SOFT ## n); \ | 486 | IPL_SOFT ## n); \ | |
487 | continue; \ | 487 | continue; \ | |
488 | } | 488 | } | |
489 | DOSOFTINT(SERIAL); | 489 | DOSOFTINT(SERIAL); | |
490 | DOSOFTINT(NET); | 490 | DOSOFTINT(NET); | |
491 | DOSOFTINT(BIO); | 491 | DOSOFTINT(BIO); | |
492 | DOSOFTINT(CLOCK); | 492 | DOSOFTINT(CLOCK); | |
493 | panic("dosoftints wtf (softints=%u?, ipl=%d)", softints, opl); | 493 | panic("dosoftints wtf (softints=%u?, ipl=%d)", softints, opl); | |
494 | } | 494 | } | |
495 | } | 495 | } | |
496 | #endif /* !__HAVE_PIC_FAST_SOFTINTS */ | 496 | #endif /* !__HAVE_PIC_FAST_SOFTINTS */ | |
497 | #endif /* __HAVE_FAST_SOFTINTS */ | 497 | #endif /* __HAVE_FAST_SOFTINTS */ | |
498 | 498 | |||
499 | #ifdef MODULAR | 499 | #ifdef MODULAR | |
500 | /* | 500 | /* | |
501 | * Push any modules loaded by the boot loader. | 501 | * Push any modules loaded by the boot loader. | |
502 | */ | 502 | */ | |
503 | void | 503 | void | |
504 | module_init_md(void) | 504 | module_init_md(void) | |
505 | { | 505 | { | |
506 | } | 506 | } | |
507 | #endif /* MODULAR */ | 507 | #endif /* MODULAR */ | |
508 | 508 | |||
509 | int | 509 | int | |
510 | mm_md_physacc(paddr_t pa, vm_prot_t prot) | 510 | mm_md_physacc(paddr_t pa, vm_prot_t prot) | |
511 | { | 511 | { | |
512 | 512 | |||
513 | return (pa < ctob(physmem)) ? 0 : EFAULT; | 513 | return (pa < ctob(physmem)) ? 0 : EFAULT; | |
514 | } | 514 | } | |
515 | 515 | |||
516 | #ifdef __HAVE_CPU_UAREA_ALLOC_IDLELWP | 516 | #ifdef __HAVE_CPU_UAREA_ALLOC_IDLELWP | |
517 | vaddr_t | 517 | vaddr_t | |
518 | cpu_uarea_alloc_idlelwp(struct cpu_info *ci) | 518 | cpu_uarea_alloc_idlelwp(struct cpu_info *ci) | |
519 | { | 519 | { | |
520 | const vaddr_t va = idlestack.pv_va + ci->ci_cpuid * USPACE; | 520 | const vaddr_t va = idlestack.pv_va + ci->ci_cpuid * USPACE; | |
521 | // printf("%s: %s: va=%lx\n", __func__, ci->ci_data.cpu_name, va); | 521 | // printf("%s: %s: va=%lx\n", __func__, ci->ci_data.cpu_name, va); | |
522 | return va; | 522 | return va; | |
523 | } | 523 | } | |
524 | #endif | 524 | #endif | |
525 | 525 | |||
526 | #ifdef MULTIPROCESSOR | 526 | #ifdef MULTIPROCESSOR | |
527 | void | 527 | void | |
528 | cpu_boot_secondary_processors(void) | 528 | cpu_boot_secondary_processors(void) | |
529 | { | 529 | { | |
530 | uint32_t mbox; | 530 | uint32_t mbox; | |
531 | kcpuset_copybits(kcpuset_attached, &mbox, sizeof(mbox)); | 531 | kcpuset_export_u32(kcpuset_attached, &mbox, sizeof(mbox)); | |
532 | atomic_swap_32(&arm_cpu_mbox, mbox); | 532 | atomic_swap_32(&arm_cpu_mbox, mbox); | |
533 | membar_producer(); | 533 | membar_producer(); | |
534 | #ifdef _ARM_ARCH_7 | 534 | #ifdef _ARM_ARCH_7 | |
535 | __asm __volatile("sev; sev; sev"); | 535 | __asm __volatile("sev; sev; sev"); | |
536 | #endif | 536 | #endif | |
537 | } | 537 | } | |
538 | 538 | |||
539 | void | 539 | void | |
540 | xc_send_ipi(struct cpu_info *ci) | 540 | xc_send_ipi(struct cpu_info *ci) | |
541 | { | 541 | { | |
542 | KASSERT(kpreempt_disabled()); | 542 | KASSERT(kpreempt_disabled()); | |
543 | KASSERT(curcpu() != ci); | 543 | KASSERT(curcpu() != ci); | |
544 | 544 | |||
545 | 545 | |||
546 | if (ci) { | 546 | if (ci) { | |
547 | /* Unicast, remote CPU */ | 547 | /* Unicast, remote CPU */ | |
548 | printf("%s: -> %s", __func__, ci->ci_data.cpu_name); | 548 | printf("%s: -> %s", __func__, ci->ci_data.cpu_name); | |
549 | intr_ipi_send(ci->ci_kcpuset, IPI_XCALL); | 549 | intr_ipi_send(ci->ci_kcpuset, IPI_XCALL); | |
550 | } else { | 550 | } else { | |
551 | printf("%s: -> !%s", __func__, ci->ci_data.cpu_name); | 551 | printf("%s: -> !%s", __func__, ci->ci_data.cpu_name); | |
552 | /* Broadcast to all but ourselves */ | 552 | /* Broadcast to all but ourselves */ | |
553 | kcpuset_t *kcp; | 553 | kcpuset_t *kcp; | |
554 | kcpuset_create(&kcp, (ci != NULL)); | 554 | kcpuset_create(&kcp, (ci != NULL)); | |
555 | KASSERT(kcp != NULL); | 555 | KASSERT(kcp != NULL); | |
556 | kcpuset_copy(kcp, kcpuset_running); | 556 | kcpuset_copy(kcp, kcpuset_running); | |
557 | kcpuset_clear(kcp, cpu_index(ci)); | 557 | kcpuset_clear(kcp, cpu_index(ci)); | |
558 | intr_ipi_send(kcp, IPI_XCALL); | 558 | intr_ipi_send(kcp, IPI_XCALL); | |
559 | kcpuset_destroy(kcp); | 559 | kcpuset_destroy(kcp); | |
560 | } | 560 | } | |
561 | printf("\n"); | 561 | printf("\n"); | |
562 | } | 562 | } | |
563 | #endif /* MULTIPROCESSOR */ | 563 | #endif /* MULTIPROCESSOR */ |
--- src/sys/arch/arm/cortex/gic.c 2012/09/14 03:52:50 1.2
+++ src/sys/arch/arm/cortex/gic.c 2012/09/16 22:09:34 1.3
@@ -1,577 +1,577 @@ | @@ -1,577 +1,577 @@ | |||
1 | /* $NetBSD: gic.c,v 1.2 2012/09/14 03:52:50 matt Exp $ */ | 1 | /* $NetBSD: gic.c,v 1.3 2012/09/16 22:09:34 rmind Exp $ */ | |
2 | /*- | 2 | /*- | |
3 | * Copyright (c) 2012 The NetBSD Foundation, Inc. | 3 | * Copyright (c) 2012 The NetBSD Foundation, Inc. | |
4 | * All rights reserved. | 4 | * All rights reserved. | |
5 | * | 5 | * | |
6 | * This code is derived from software contributed to The NetBSD Foundation | 6 | * This code is derived from software contributed to The NetBSD Foundation | |
7 | * by Matt Thomas of 3am Software Foundry. | 7 | * by Matt Thomas of 3am Software Foundry. | |
8 | * | 8 | * | |
9 | * Redistribution and use in source and binary forms, with or without | 9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | 10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | 11 | * are met: | |
12 | * 1. Redistributions of source code must retain the above copyright | 12 | * 1. Redistributions of source code must retain the above copyright | |
13 | * notice, this list of conditions and the following disclaimer. | 13 | * notice, this list of conditions and the following disclaimer. | |
14 | * 2. Redistributions in binary form must reproduce the above copyright | 14 | * 2. Redistributions in binary form must reproduce the above copyright | |
15 | * notice, this list of conditions and the following disclaimer in the | 15 | * notice, this list of conditions and the following disclaimer in the | |
16 | * documentation and/or other materials provided with the distribution. | 16 | * documentation and/or other materials provided with the distribution. | |
17 | * | 17 | * | |
18 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | 18 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |
19 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | 19 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
20 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 20 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
21 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | 21 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
22 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 22 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
28 | * POSSIBILITY OF SUCH DAMAGE. | 28 | * POSSIBILITY OF SUCH DAMAGE. | |
29 | */ | 29 | */ | |
30 | 30 | |||
31 | #define _INTR_PRIVATE | 31 | #define _INTR_PRIVATE | |
32 | 32 | |||
33 | #include <sys/cdefs.h> | 33 | #include <sys/cdefs.h> | |
34 | __KERNEL_RCSID(0, "$NetBSD: gic.c,v 1.2 2012/09/14 03:52:50 matt Exp $"); | 34 | __KERNEL_RCSID(0, "$NetBSD: gic.c,v 1.3 2012/09/16 22:09:34 rmind Exp $"); | |
35 | 35 | |||
36 | #include <sys/param.h> | 36 | #include <sys/param.h> | |
37 | #include <sys/bus.h> | 37 | #include <sys/bus.h> | |
38 | #include <sys/device.h> | 38 | #include <sys/device.h> | |
39 | #include <sys/evcnt.h> | 39 | #include <sys/evcnt.h> | |
40 | #include <sys/intr.h> | 40 | #include <sys/intr.h> | |
41 | #include <sys/proc.h> | 41 | #include <sys/proc.h> | |
42 | #include <sys/xcall.h> /* for xc_ipi_handler */ | 42 | #include <sys/xcall.h> /* for xc_ipi_handler */ | |
43 | 43 | |||
44 | #include <arm/armreg.h> | 44 | #include <arm/armreg.h> | |
45 | #include <arm/cpufunc.h> | 45 | #include <arm/cpufunc.h> | |
46 | #include <arm/atomic.h> | 46 | #include <arm/atomic.h> | |
47 | 47 | |||
48 | #include <arm/cortex/gic_reg.h> | 48 | #include <arm/cortex/gic_reg.h> | |
49 | #include <arm/cortex/mpcore_var.h> | 49 | #include <arm/cortex/mpcore_var.h> | |
50 | 50 | |||
51 | #define ARMGIC_SGI_IPIBASE (16 - NIPI) | 51 | #define ARMGIC_SGI_IPIBASE (16 - NIPI) | |
52 | 52 | |||
53 | static int armgic_match(device_t, cfdata_t, void *); | 53 | static int armgic_match(device_t, cfdata_t, void *); | |
54 | static void armgic_attach(device_t, device_t, void *); | 54 | static void armgic_attach(device_t, device_t, void *); | |
55 | 55 | |||
56 | static void armgic_set_priority(struct pic_softc *, int); | 56 | static void armgic_set_priority(struct pic_softc *, int); | |
57 | static void armgic_unblock_irqs(struct pic_softc *, size_t, uint32_t); | 57 | static void armgic_unblock_irqs(struct pic_softc *, size_t, uint32_t); | |
58 | static void armgic_block_irqs(struct pic_softc *, size_t, uint32_t); | 58 | static void armgic_block_irqs(struct pic_softc *, size_t, uint32_t); | |
59 | static void armgic_establish_irq(struct pic_softc *, struct intrsource *); | 59 | static void armgic_establish_irq(struct pic_softc *, struct intrsource *); | |
60 | #if 0 | 60 | #if 0 | |
61 | static void armgic_source_name(struct pic_softc *, int, char *, size_t); | 61 | static void armgic_source_name(struct pic_softc *, int, char *, size_t); | |
62 | #endif | 62 | #endif | |
63 | 63 | |||
64 | #ifdef MULTIPROCESSOR | 64 | #ifdef MULTIPROCESSOR | |
65 | static void armgic_cpu_init(struct pic_softc *, struct cpu_info *); | 65 | static void armgic_cpu_init(struct pic_softc *, struct cpu_info *); | |
66 | static void armgic_ipi_send(struct pic_softc *, const kcpuset_t *, u_long); | 66 | static void armgic_ipi_send(struct pic_softc *, const kcpuset_t *, u_long); | |
67 | #endif | 67 | #endif | |
68 | 68 | |||
69 | static const struct pic_ops armgic_picops = { | 69 | static const struct pic_ops armgic_picops = { | |
70 | .pic_unblock_irqs = armgic_unblock_irqs, | 70 | .pic_unblock_irqs = armgic_unblock_irqs, | |
71 | .pic_block_irqs = armgic_block_irqs, | 71 | .pic_block_irqs = armgic_block_irqs, | |
72 | .pic_establish_irq = armgic_establish_irq, | 72 | .pic_establish_irq = armgic_establish_irq, | |
73 | #if 0 | 73 | #if 0 | |
74 | .pic_source_name = armgic_source_name, | 74 | .pic_source_name = armgic_source_name, | |
75 | #endif | 75 | #endif | |
76 | .pic_set_priority = armgic_set_priority, | 76 | .pic_set_priority = armgic_set_priority, | |
77 | #ifdef MULTIPROCESSOR | 77 | #ifdef MULTIPROCESSOR | |
78 | .pic_cpu_init = armgic_cpu_init, | 78 | .pic_cpu_init = armgic_cpu_init, | |
79 | .pic_ipi_send = armgic_ipi_send, | 79 | .pic_ipi_send = armgic_ipi_send, | |
80 | #endif | 80 | #endif | |
81 | }; | 81 | }; | |
82 | 82 | |||
83 | #define PICTOSOFTC(pic) ((struct armgic_softc *)(pic)) | 83 | #define PICTOSOFTC(pic) ((struct armgic_softc *)(pic)) | |
84 | 84 | |||
85 | static struct armgic_softc { | 85 | static struct armgic_softc { | |
86 | struct pic_softc sc_pic; | 86 | struct pic_softc sc_pic; | |
87 | device_t sc_dev; | 87 | device_t sc_dev; | |
88 | bus_space_tag_t sc_memt; | 88 | bus_space_tag_t sc_memt; | |
89 | bus_space_handle_t sc_memh; | 89 | bus_space_handle_t sc_memh; | |
90 | size_t sc_gic_lines; | 90 | size_t sc_gic_lines; | |
91 | uint32_t sc_gic_type; | 91 | uint32_t sc_gic_type; | |
92 | uint32_t sc_gic_valid_lines[1024/32]; | 92 | uint32_t sc_gic_valid_lines[1024/32]; | |
93 | uint32_t sc_enabled_local; | 93 | uint32_t sc_enabled_local; | |
94 | } armgic_softc = { | 94 | } armgic_softc = { | |
95 | .sc_pic = { | 95 | .sc_pic = { | |
96 | .pic_ops = &armgic_picops, | 96 | .pic_ops = &armgic_picops, | |
97 | .pic_name = "armgic", | 97 | .pic_name = "armgic", | |
98 | }, | 98 | }, | |
99 | }; | 99 | }; | |
100 | 100 | |||
101 | static struct intrsource armgic_dummy_source; | 101 | static struct intrsource armgic_dummy_source; | |
102 | 102 | |||
103 | __CTASSERT(NIPL == 8); | 103 | __CTASSERT(NIPL == 8); | |
104 | 104 | |||
105 | /* | 105 | /* | |
106 | * GIC register are always in little-endian. | 106 | * GIC register are always in little-endian. | |
107 | */ | 107 | */ | |
108 | static inline uint32_t | 108 | static inline uint32_t | |
109 | gicc_read(struct armgic_softc *sc, bus_size_t o) | 109 | gicc_read(struct armgic_softc *sc, bus_size_t o) | |
110 | { | 110 | { | |
111 | uint32_t v = bus_space_read_4(sc->sc_memt, sc->sc_memh, GICC_BASE + o); | 111 | uint32_t v = bus_space_read_4(sc->sc_memt, sc->sc_memh, GICC_BASE + o); | |
112 | return le32toh(v); | 112 | return le32toh(v); | |
113 | } | 113 | } | |
114 | 114 | |||
115 | static inline void | 115 | static inline void | |
116 | gicc_write(struct armgic_softc *sc, bus_size_t o, uint32_t v) | 116 | gicc_write(struct armgic_softc *sc, bus_size_t o, uint32_t v) | |
117 | { | 117 | { | |
118 | v = htole32(v); | 118 | v = htole32(v); | |
119 | bus_space_write_4(sc->sc_memt, sc->sc_memh, GICC_BASE + o, v); | 119 | bus_space_write_4(sc->sc_memt, sc->sc_memh, GICC_BASE + o, v); | |
120 | } | 120 | } | |
121 | 121 | |||
122 | static inline uint32_t | 122 | static inline uint32_t | |
123 | gicd_read(struct armgic_softc *sc, bus_size_t o) | 123 | gicd_read(struct armgic_softc *sc, bus_size_t o) | |
124 | { | 124 | { | |
125 | uint32_t v = bus_space_read_4(sc->sc_memt, sc->sc_memh, GICD_BASE + o); | 125 | uint32_t v = bus_space_read_4(sc->sc_memt, sc->sc_memh, GICD_BASE + o); | |
126 | return le32toh(v); | 126 | return le32toh(v); | |
127 | } | 127 | } | |
128 | 128 | |||
129 | static inline void | 129 | static inline void | |
130 | gicd_write(struct armgic_softc *sc, bus_size_t o, uint32_t v) | 130 | gicd_write(struct armgic_softc *sc, bus_size_t o, uint32_t v) | |
131 | { | 131 | { | |
132 | v = htole32(v); | 132 | v = htole32(v); | |
133 | bus_space_write_4(sc->sc_memt, sc->sc_memh, GICD_BASE + o, v); | 133 | bus_space_write_4(sc->sc_memt, sc->sc_memh, GICD_BASE + o, v); | |
134 | } | 134 | } | |
135 | 135 | |||
136 | /* | 136 | /* | |
137 | * In the GIC prioritization scheme, lower numbers have higher priority. | 137 | * In the GIC prioritization scheme, lower numbers have higher priority. | |
138 | */ | 138 | */ | |
139 | static inline uint32_t | 139 | static inline uint32_t | |
140 | armgic_ipl_to_priority(int ipl) | 140 | armgic_ipl_to_priority(int ipl) | |
141 | { | 141 | { | |
142 | return (IPL_HIGH - ipl) * GICC_PMR_PRIORITIES / NIPL; | 142 | return (IPL_HIGH - ipl) * GICC_PMR_PRIORITIES / NIPL; | |
143 | } | 143 | } | |
144 | 144 | |||
145 | static inline int | 145 | static inline int | |
146 | armgic_priority_to_ipl(uint32_t priority) | 146 | armgic_priority_to_ipl(uint32_t priority) | |
147 | { | 147 | { | |
148 | return IPL_HIGH - priority * NIPL / GICC_PMR_PRIORITIES; | 148 | return IPL_HIGH - priority * NIPL / GICC_PMR_PRIORITIES; | |
149 | } | 149 | } | |
150 | 150 | |||
151 | static void | 151 | static void | |
152 | armgic_unblock_irqs(struct pic_softc *pic, size_t irq_base, uint32_t irq_mask) | 152 | armgic_unblock_irqs(struct pic_softc *pic, size_t irq_base, uint32_t irq_mask) | |
153 | { | 153 | { | |
154 | struct armgic_softc * const sc = PICTOSOFTC(pic); | 154 | struct armgic_softc * const sc = PICTOSOFTC(pic); | |
155 | const size_t group = irq_base / 32; | 155 | const size_t group = irq_base / 32; | |
156 | 156 | |||
157 | if (group == 0) | 157 | if (group == 0) | |
158 | sc->sc_enabled_local |= irq_mask; | 158 | sc->sc_enabled_local |= irq_mask; | |
159 | 159 | |||
160 | gicd_write(sc, GICD_ISENABLERn(group), irq_mask); | 160 | gicd_write(sc, GICD_ISENABLERn(group), irq_mask); | |
161 | } | 161 | } | |
162 | 162 | |||
163 | static void | 163 | static void | |
164 | armgic_block_irqs(struct pic_softc *pic, size_t irq_base, uint32_t irq_mask) | 164 | armgic_block_irqs(struct pic_softc *pic, size_t irq_base, uint32_t irq_mask) | |
165 | { | 165 | { | |
166 | struct armgic_softc * const sc = PICTOSOFTC(pic); | 166 | struct armgic_softc * const sc = PICTOSOFTC(pic); | |
167 | const size_t group = irq_base / 32; | 167 | const size_t group = irq_base / 32; | |
168 | 168 | |||
169 | if (group == 0) | 169 | if (group == 0) | |
170 | sc->sc_enabled_local &= ~irq_mask; | 170 | sc->sc_enabled_local &= ~irq_mask; | |
171 | 171 | |||
172 | gicd_write(sc, GICD_ICENABLERn(group), irq_mask); | 172 | gicd_write(sc, GICD_ICENABLERn(group), irq_mask); | |
173 | } | 173 | } | |
174 | 174 | |||
175 | static uint32_t armgic_last_priority; | 175 | static uint32_t armgic_last_priority; | |
176 | 176 | |||
177 | static void | 177 | static void | |
178 | armgic_set_priority(struct pic_softc *pic, int ipl) | 178 | armgic_set_priority(struct pic_softc *pic, int ipl) | |
179 | { | 179 | { | |
180 | struct armgic_softc * const sc = PICTOSOFTC(pic); | 180 | struct armgic_softc * const sc = PICTOSOFTC(pic); | |
181 | 181 | |||
182 | const uint32_t priority = armgic_ipl_to_priority(ipl); | 182 | const uint32_t priority = armgic_ipl_to_priority(ipl); | |
183 | gicc_write(sc, GICC_PMR, priority); | 183 | gicc_write(sc, GICC_PMR, priority); | |
184 | armgic_last_priority = priority; | 184 | armgic_last_priority = priority; | |
185 | } | 185 | } | |
186 | 186 | |||
187 | #ifdef __HAVE_PIC_FAST_SOFTINTS | 187 | #ifdef __HAVE_PIC_FAST_SOFTINTS | |
188 | void | 188 | void | |
189 | softint_init_md(lwp_t *l, u_int level, uintptr_t *machdep_p) | 189 | softint_init_md(lwp_t *l, u_int level, uintptr_t *machdep_p) | |
190 | { | 190 | { | |
191 | lwp_t **lp = &l->l_cpu->ci_softlwps[level]; | 191 | lwp_t **lp = &l->l_cpu->ci_softlwps[level]; | |
192 | KASSERT(*lp == NULL || *lp == l); | 192 | KASSERT(*lp == NULL || *lp == l); | |
193 | *lp = l; | 193 | *lp = l; | |
194 | /* | 194 | /* | |
195 | * Really easy. Just tell it to trigger the local CPU. | 195 | * Really easy. Just tell it to trigger the local CPU. | |
196 | */ | 196 | */ | |
197 | *machdep_p = GICD_SGIR_TargetListFilter_Me | 197 | *machdep_p = GICD_SGIR_TargetListFilter_Me | |
198 | | __SHIFTIN(level, GICD_SGIR_SGIINTID); | 198 | | __SHIFTIN(level, GICD_SGIR_SGIINTID); | |
199 | } | 199 | } | |
200 | 200 | |||
201 | void | 201 | void | |
202 | softint_trigger(uintptr_t machdep) | 202 | softint_trigger(uintptr_t machdep) | |
203 | { | 203 | { | |
204 | 204 | |||
205 | gicd_write(&armgic_softc, GICD_SGIR, machdep); | 205 | gicd_write(&armgic_softc, GICD_SGIR, machdep); | |
206 | } | 206 | } | |
207 | #endif | 207 | #endif | |
208 | 208 | |||
209 | void | 209 | void | |
210 | armgic_irq_handler(void *tf) | 210 | armgic_irq_handler(void *tf) | |
211 | { | 211 | { | |
212 | struct cpu_info * const ci = curcpu(); | 212 | struct cpu_info * const ci = curcpu(); | |
213 | struct armgic_softc * const sc = &armgic_softc; | 213 | struct armgic_softc * const sc = &armgic_softc; | |
214 | const int old_ipl = ci->ci_cpl; | 214 | const int old_ipl = ci->ci_cpl; | |
215 | #ifdef DIAGNOSTIC | 215 | #ifdef DIAGNOSTIC | |
216 | const int old_mtx_count = ci->ci_mtx_count; | 216 | const int old_mtx_count = ci->ci_mtx_count; | |
217 | const int old_l_biglocks = ci->ci_curlwp->l_biglocks; | 217 | const int old_l_biglocks = ci->ci_curlwp->l_biglocks; | |
218 | #endif | 218 | #endif | |
219 | #ifdef DEBUG | 219 | #ifdef DEBUG | |
220 | size_t n = 0; | 220 | size_t n = 0; | |
221 | #endif | 221 | #endif | |
222 | 222 | |||
223 | ci->ci_data.cpu_nintr++; | 223 | ci->ci_data.cpu_nintr++; | |
224 | 224 | |||
225 | KASSERTMSG(old_ipl != IPL_HIGH, "old_ipl %d pmr %#x hppir %#x", | 225 | KASSERTMSG(old_ipl != IPL_HIGH, "old_ipl %d pmr %#x hppir %#x", | |
226 | old_ipl, gicc_read(sc, GICC_PMR), gicc_read(sc, GICC_HPPIR)); | 226 | old_ipl, gicc_read(sc, GICC_PMR), gicc_read(sc, GICC_HPPIR)); | |
227 | #if 0 | 227 | #if 0 | |
228 | printf("%s(enter): %s: pmr=%u hppir=%u\n", | 228 | printf("%s(enter): %s: pmr=%u hppir=%u\n", | |
229 | __func__, ci->ci_data.cpu_name, | 229 | __func__, ci->ci_data.cpu_name, | |
230 | gicc_read(sc, GICC_PMR), | 230 | gicc_read(sc, GICC_PMR), | |
231 | gicc_read(sc, GICC_HPPIR)); | 231 | gicc_read(sc, GICC_HPPIR)); | |
232 | #elif 0 | 232 | #elif 0 | |
233 | printf("(%u:%d", ci->ci_index, old_ipl); | 233 | printf("(%u:%d", ci->ci_index, old_ipl); | |
234 | #endif | 234 | #endif | |
235 | 235 | |||
236 | for (;;) { | 236 | for (;;) { | |
237 | uint32_t iar = gicc_read(sc, GICC_IAR); | 237 | uint32_t iar = gicc_read(sc, GICC_IAR); | |
238 | uint32_t irq = __SHIFTOUT(iar, GICC_IAR_IRQ); | 238 | uint32_t irq = __SHIFTOUT(iar, GICC_IAR_IRQ); | |
239 | //printf(".%u", irq); | 239 | //printf(".%u", irq); | |
240 | if (irq == GICC_IAR_IRQ_SPURIOUS) { | 240 | if (irq == GICC_IAR_IRQ_SPURIOUS) { | |
241 | iar = gicc_read(sc, GICC_IAR); | 241 | iar = gicc_read(sc, GICC_IAR); | |
242 | irq = __SHIFTOUT(iar, GICC_IAR_IRQ); | 242 | irq = __SHIFTOUT(iar, GICC_IAR_IRQ); | |
243 | if (irq == GICC_IAR_IRQ_SPURIOUS) | 243 | if (irq == GICC_IAR_IRQ_SPURIOUS) | |
244 | break; | 244 | break; | |
245 | //printf(".%u", irq); | 245 | //printf(".%u", irq); | |
246 | } | 246 | } | |
247 | 247 | |||
248 | //const uint32_t cpuid = __SHIFTOUT(iar, GICC_IAR_CPUID_MASK); | 248 | //const uint32_t cpuid = __SHIFTOUT(iar, GICC_IAR_CPUID_MASK); | |
249 | struct intrsource * const is = sc->sc_pic.pic_sources[irq]; | 249 | struct intrsource * const is = sc->sc_pic.pic_sources[irq]; | |
250 | KASSERT(is != &armgic_dummy_source); | 250 | KASSERT(is != &armgic_dummy_source); | |
251 | 251 | |||
252 | /* | 252 | /* | |
253 | * GIC has asserted IPL for us so we can just update ci_cpl. | 253 | * GIC has asserted IPL for us so we can just update ci_cpl. | |
254 | * | 254 | * | |
255 | * But it's not that simple. We may have already bumped ci_cpl | 255 | * But it's not that simple. We may have already bumped ci_cpl | |
256 | * due to a high priority interrupt and now we are about to | 256 | * due to a high priority interrupt and now we are about to | |
257 | * dispatch one lower than the previous. It's possible for | 257 | * dispatch one lower than the previous. It's possible for | |
258 | * that previous interrupt to have deferred some interrupts | 258 | * that previous interrupt to have deferred some interrupts | |
259 | * so we need deal with those when lowering to the current | 259 | * so we need deal with those when lowering to the current | |
260 | * interrupt's ipl. | 260 | * interrupt's ipl. | |
261 | * | 261 | * | |
262 | * However, if are just raising ipl, we can just update ci_cpl. | 262 | * However, if are just raising ipl, we can just update ci_cpl. | |
263 | */ | 263 | */ | |
264 | #if 0 | 264 | #if 0 | |
265 | const int ipl = armgic_priority_to_ipl(gicc_read(sc, GICC_RPR)); | 265 | const int ipl = armgic_priority_to_ipl(gicc_read(sc, GICC_RPR)); | |
266 | KASSERTMSG(panicstr != NULL || ipl == is->is_ipl, | 266 | KASSERTMSG(panicstr != NULL || ipl == is->is_ipl, | |
267 | "%s: irq %d: running ipl %d != source ipl %u", | 267 | "%s: irq %d: running ipl %d != source ipl %u", | |
268 | ci->ci_data.cpu_name, irq, ipl, is->is_ipl); | 268 | ci->ci_data.cpu_name, irq, ipl, is->is_ipl); | |
269 | #else | 269 | #else | |
270 | const int ipl = is->is_ipl; | 270 | const int ipl = is->is_ipl; | |
271 | #endif | 271 | #endif | |
272 | if (__predict_false(ipl < ci->ci_cpl)) { | 272 | if (__predict_false(ipl < ci->ci_cpl)) { | |
273 | //printf("<"); | 273 | //printf("<"); | |
274 | pic_do_pending_ints(I32_bit, ipl, tf); | 274 | pic_do_pending_ints(I32_bit, ipl, tf); | |
275 | KASSERT(ci->ci_cpl == ipl); | 275 | KASSERT(ci->ci_cpl == ipl); | |
276 | } else { | 276 | } else { | |
277 | KASSERTMSG(ipl > ci->ci_cpl, "ipl %d cpl %d hw-ipl %#x", | 277 | KASSERTMSG(ipl > ci->ci_cpl, "ipl %d cpl %d hw-ipl %#x", | |
278 | ipl, ci->ci_cpl, | 278 | ipl, ci->ci_cpl, | |
279 | gicc_read(sc, GICC_PMR)); | 279 | gicc_read(sc, GICC_PMR)); | |
280 | //printf(">"); | 280 | //printf(">"); | |
281 | gicc_write(sc, GICC_PMR, armgic_ipl_to_priority(ipl)); | 281 | gicc_write(sc, GICC_PMR, armgic_ipl_to_priority(ipl)); | |
282 | ci->ci_cpl = ipl; | 282 | ci->ci_cpl = ipl; | |
283 | } | 283 | } | |
284 | //printf("$"); | 284 | //printf("$"); | |
285 | cpsie(I32_bit); | 285 | cpsie(I32_bit); | |
286 | pic_dispatch(is, tf); | 286 | pic_dispatch(is, tf); | |
287 | cpsid(I32_bit); | 287 | cpsid(I32_bit); | |
288 | gicc_write(sc, GICC_EOIR, iar); | 288 | gicc_write(sc, GICC_EOIR, iar); | |
289 | #ifdef DEBUG | 289 | #ifdef DEBUG | |
290 | n++; | 290 | n++; | |
291 | KDASSERTMSG(n < 5, "%s: processed too many (%zu)", | 291 | KDASSERTMSG(n < 5, "%s: processed too many (%zu)", | |
292 | ci->ci_data.cpu_name, n); | 292 | ci->ci_data.cpu_name, n); | |
293 | #endif | 293 | #endif | |
294 | } | 294 | } | |
295 | 295 | |||
296 | // printf("%s(%p): exit (%zu dispatched)\n", __func__, tf, n); | 296 | // printf("%s(%p): exit (%zu dispatched)\n", __func__, tf, n); | |
297 | /* | 297 | /* | |
298 | * Now handle any pending ints. | 298 | * Now handle any pending ints. | |
299 | */ | 299 | */ | |
300 | //printf("!"); | 300 | //printf("!"); | |
301 | KASSERT(old_ipl != IPL_HIGH); | 301 | KASSERT(old_ipl != IPL_HIGH); | |
302 | pic_do_pending_ints(I32_bit, old_ipl, tf); | 302 | pic_do_pending_ints(I32_bit, old_ipl, tf); | |
303 | KASSERTMSG(ci->ci_cpl == old_ipl, "ci_cpl %d old_ipl %d", ci->ci_cpl, old_ipl); | 303 | KASSERTMSG(ci->ci_cpl == old_ipl, "ci_cpl %d old_ipl %d", ci->ci_cpl, old_ipl); | |
304 | KASSERT(old_mtx_count == ci->ci_mtx_count); | 304 | KASSERT(old_mtx_count == ci->ci_mtx_count); | |
305 | KASSERT(old_l_biglocks == ci->ci_curlwp->l_biglocks); | 305 | KASSERT(old_l_biglocks == ci->ci_curlwp->l_biglocks); | |
306 | #if 0 | 306 | #if 0 | |
307 | printf("%s(exit): %s(%d): pmr=%u hppir=%u\n", | 307 | printf("%s(exit): %s(%d): pmr=%u hppir=%u\n", | |
308 | __func__, ci->ci_data.cpu_name, ci->ci_cpl, | 308 | __func__, ci->ci_data.cpu_name, ci->ci_cpl, | |
309 | gicc_read(sc, GICC_PMR), | 309 | gicc_read(sc, GICC_PMR), | |
310 | gicc_read(sc, GICC_HPPIR)); | 310 | gicc_read(sc, GICC_HPPIR)); | |
311 | #elif 0 | 311 | #elif 0 | |
312 | printf("->%#x)", ((struct trapframe *)tf)->tf_pc); | 312 | printf("->%#x)", ((struct trapframe *)tf)->tf_pc); | |
313 | #endif | 313 | #endif | |
314 | } | 314 | } | |
315 | 315 | |||
316 | void | 316 | void | |
317 | armgic_establish_irq(struct pic_softc *pic, struct intrsource *is) | 317 | armgic_establish_irq(struct pic_softc *pic, struct intrsource *is) | |
318 | { | 318 | { | |
319 | struct armgic_softc * const sc = PICTOSOFTC(pic); | 319 | struct armgic_softc * const sc = PICTOSOFTC(pic); | |
320 | const size_t group = is->is_irq / 32; | 320 | const size_t group = is->is_irq / 32; | |
321 | const u_int irq = is->is_irq & 31; | 321 | const u_int irq = is->is_irq & 31; | |
322 | const u_int byte_shift = 8 * (irq & 3); | 322 | const u_int byte_shift = 8 * (irq & 3); | |
323 | const u_int twopair_shift = 2 * (irq & 15); | 323 | const u_int twopair_shift = 2 * (irq & 15); | |
324 | 324 | |||
325 | KASSERTMSG(sc->sc_gic_valid_lines[group] & __BIT(irq), | 325 | KASSERTMSG(sc->sc_gic_valid_lines[group] & __BIT(irq), | |
326 | "irq %u: not valid (group[%zu]=0x%08x [0x%08x])", | 326 | "irq %u: not valid (group[%zu]=0x%08x [0x%08x])", | |
327 | is->is_irq, group, sc->sc_gic_valid_lines[group], | 327 | is->is_irq, group, sc->sc_gic_valid_lines[group], | |
328 | (uint32_t)__BIT(irq)); | 328 | (uint32_t)__BIT(irq)); | |
329 | 329 | |||
330 | KASSERTMSG(is->is_type == IST_LEVEL || is->is_type == IST_EDGE, | 330 | KASSERTMSG(is->is_type == IST_LEVEL || is->is_type == IST_EDGE, | |
331 | "irq %u: type %u unsupported", is->is_irq, is->is_type); | 331 | "irq %u: type %u unsupported", is->is_irq, is->is_type); | |
332 | 332 | |||
333 | const bus_size_t targets_reg = GICD_ITARGETSRn(is->is_irq / 4); | 333 | const bus_size_t targets_reg = GICD_ITARGETSRn(is->is_irq / 4); | |
334 | const bus_size_t cfg_reg = GICD_ICFGRn(is->is_irq / 16); | 334 | const bus_size_t cfg_reg = GICD_ICFGRn(is->is_irq / 16); | |
335 | uint32_t targets = gicd_read(sc, targets_reg); | 335 | uint32_t targets = gicd_read(sc, targets_reg); | |
336 | uint32_t cfg = gicd_read(sc, cfg_reg); | 336 | uint32_t cfg = gicd_read(sc, cfg_reg); | |
337 | 337 | |||
338 | if (group > 0) { | 338 | if (group > 0) { | |
339 | /* | 339 | /* | |
340 | * There are 4 irqs per TARGETS register. For now bind | 340 | * There are 4 irqs per TARGETS register. For now bind | |
341 | * to the primary cpu. | 341 | * to the primary cpu. | |
342 | */ | 342 | */ | |
343 | targets &= ~(0xff << byte_shift); | 343 | targets &= ~(0xff << byte_shift); | |
344 | targets |= 1 << byte_shift; | 344 | targets |= 1 << byte_shift; | |
345 | gicd_write(sc, targets_reg, targets); | 345 | gicd_write(sc, targets_reg, targets); | |
346 | 346 | |||
347 | /* | 347 | /* | |
348 | * There are 16 irqs per CFG register. 10=EDGE 00=LEVEL | 348 | * There are 16 irqs per CFG register. 10=EDGE 00=LEVEL | |
349 | */ | 349 | */ | |
350 | uint32_t new_cfg = cfg; | 350 | uint32_t new_cfg = cfg; | |
351 | uint32_t old_cfg = (cfg >> twopair_shift) & 3; | 351 | uint32_t old_cfg = (cfg >> twopair_shift) & 3; | |
352 | if (is->is_type == IST_LEVEL && (old_cfg & 2) != 0) { | 352 | if (is->is_type == IST_LEVEL && (old_cfg & 2) != 0) { | |
353 | new_cfg &= ~(3 << twopair_shift); | 353 | new_cfg &= ~(3 << twopair_shift); | |
354 | } else if (is->is_type == IST_EDGE && (old_cfg & 2) == 0) { | 354 | } else if (is->is_type == IST_EDGE && (old_cfg & 2) == 0) { | |
355 | new_cfg |= 2 << twopair_shift; | 355 | new_cfg |= 2 << twopair_shift; | |
356 | } | 356 | } | |
357 | if (new_cfg != cfg) { | 357 | if (new_cfg != cfg) { | |
358 | gicd_write(sc, cfg_reg, cfg); | 358 | gicd_write(sc, cfg_reg, cfg); | |
359 | #if 0 | 359 | #if 0 | |
360 | printf("%s: irq %u: cfg changed from %#x to %#x\n", | 360 | printf("%s: irq %u: cfg changed from %#x to %#x\n", | |
361 | pic->pic_name, is->is_irq, cfg, new_cfg); | 361 | pic->pic_name, is->is_irq, cfg, new_cfg); | |
362 | #endif | 362 | #endif | |
363 | } | 363 | } | |
364 | } | 364 | } | |
365 | 365 | |||
366 | /* | 366 | /* | |
367 | * There are 4 irqs per PRIORITY register. Map the IPL | 367 | * There are 4 irqs per PRIORITY register. Map the IPL | |
368 | * to GIC priority. | 368 | * to GIC priority. | |
369 | */ | 369 | */ | |
370 | const bus_size_t priority_reg = GICD_IPRIORITYRn(is->is_irq / 4); | 370 | const bus_size_t priority_reg = GICD_IPRIORITYRn(is->is_irq / 4); | |
371 | uint32_t priority = gicd_read(sc, priority_reg); | 371 | uint32_t priority = gicd_read(sc, priority_reg); | |
372 | priority &= ~(0xff << byte_shift); | 372 | priority &= ~(0xff << byte_shift); | |
373 | priority |= armgic_ipl_to_priority(is->is_ipl) << byte_shift; | 373 | priority |= armgic_ipl_to_priority(is->is_ipl) << byte_shift; | |
374 | gicd_write(sc, priority_reg, priority); | 374 | gicd_write(sc, priority_reg, priority); | |
375 | 375 | |||
376 | #if 0 | 376 | #if 0 | |
377 | printf("%s: irq %u: target %#x cfg %u priority %#x (%u)\n", | 377 | printf("%s: irq %u: target %#x cfg %u priority %#x (%u)\n", | |
378 | pic->pic_name, is->is_irq, (targets >> byte_shift) & 0xff, | 378 | pic->pic_name, is->is_irq, (targets >> byte_shift) & 0xff, | |
379 | (cfg >> twopair_shift) & 3, (priority >> byte_shift) & 0xff, | 379 | (cfg >> twopair_shift) & 3, (priority >> byte_shift) & 0xff, | |
380 | is->is_ipl); | 380 | is->is_ipl); | |
381 | #endif | 381 | #endif | |
382 | } | 382 | } | |
383 | 383 | |||
384 | #ifdef MULTIPROCESSOR | 384 | #ifdef MULTIPROCESSOR | |
385 | static void | 385 | static void | |
386 | armgic_cpu_init_priorities(struct armgic_softc *sc) | 386 | armgic_cpu_init_priorities(struct armgic_softc *sc) | |
387 | { | 387 | { | |
388 | uint32_t enabled = sc->sc_enabled_local; | 388 | uint32_t enabled = sc->sc_enabled_local; | |
389 | for (size_t i = 0; i < 32; i += 4, enabled >>= 4) { | 389 | for (size_t i = 0; i < 32; i += 4, enabled >>= 4) { | |
390 | /* | 390 | /* | |
391 | * If there are no enabled interrupts for the priority register, | 391 | * If there are no enabled interrupts for the priority register, | |
392 | * don't bother changing it. | 392 | * don't bother changing it. | |
393 | */ | 393 | */ | |
394 | if ((enabled & 0x0f) == 0) | 394 | if ((enabled & 0x0f) == 0) | |
395 | continue; | 395 | continue; | |
396 | /* | 396 | /* | |
397 | * Since priorities are in 3210 order, it' | 397 | * Since priorities are in 3210 order, it' | |
398 | */ | 398 | */ | |
399 | const bus_size_t priority_reg = GICD_IPRIORITYRn(i / 4); | 399 | const bus_size_t priority_reg = GICD_IPRIORITYRn(i / 4); | |
400 | uint32_t priority = gicd_read(sc, priority_reg); | 400 | uint32_t priority = gicd_read(sc, priority_reg); | |
401 | uint32_t byte_mask = 0xff; | 401 | uint32_t byte_mask = 0xff; | |
402 | size_t byte_shift = 0; | 402 | size_t byte_shift = 0; | |
403 | for (size_t j = 0; j < 4; j++, byte_mask <<= 8, byte_shift += 8) { | 403 | for (size_t j = 0; j < 4; j++, byte_mask <<= 8, byte_shift += 8) { | |
404 | struct intrsource * const is = sc->sc_pic.pic_sources[i+j]; | 404 | struct intrsource * const is = sc->sc_pic.pic_sources[i+j]; | |
405 | if (is == NULL || is == &armgic_dummy_source) | 405 | if (is == NULL || is == &armgic_dummy_source) | |
406 | continue; | 406 | continue; | |
407 | priority &= ~byte_mask; | 407 | priority &= ~byte_mask; | |
408 | priority |= armgic_ipl_to_priority(is->is_ipl) << byte_shift; | 408 | priority |= armgic_ipl_to_priority(is->is_ipl) << byte_shift; | |
409 | } | 409 | } | |
410 | gicd_write(sc, priority_reg, priority); | 410 | gicd_write(sc, priority_reg, priority); | |
411 | } | 411 | } | |
412 | } | 412 | } | |
413 | 413 | |||
414 | void | 414 | void | |
415 | armgic_cpu_init(struct pic_softc *pic, struct cpu_info *ci) | 415 | armgic_cpu_init(struct pic_softc *pic, struct cpu_info *ci) | |
416 | { | 416 | { | |
417 | struct armgic_softc * const sc = PICTOSOFTC(pic); | 417 | struct armgic_softc * const sc = PICTOSOFTC(pic); | |
418 | if (!CPU_IS_PRIMARY(ci) && sc->sc_enabled_local) { | 418 | if (!CPU_IS_PRIMARY(ci) && sc->sc_enabled_local) { | |
419 | armgic_cpu_init_priorities(sc); | 419 | armgic_cpu_init_priorities(sc); | |
420 | } | 420 | } | |
421 | KASSERTMSG(ci->ci_cpl == IPL_HIGH, "ipl %d not IPL_HIGH", ci->ci_cpl); | 421 | KASSERTMSG(ci->ci_cpl == IPL_HIGH, "ipl %d not IPL_HIGH", ci->ci_cpl); | |
422 | gicc_write(sc, GICC_PMR, armgic_ipl_to_priority(ci->ci_cpl)); // set PMR | 422 | gicc_write(sc, GICC_PMR, armgic_ipl_to_priority(ci->ci_cpl)); // set PMR | |
423 | gicc_write(sc, GICC_CTRL, GICC_CTRL_V1_Enable); // enable interrupt | 423 | gicc_write(sc, GICC_CTRL, GICC_CTRL_V1_Enable); // enable interrupt | |
424 | if (!CPU_IS_PRIMARY(ci) && sc->sc_enabled_local) | 424 | if (!CPU_IS_PRIMARY(ci) && sc->sc_enabled_local) | |
425 | gicd_write(sc, GICD_ISENABLERn(0), sc->sc_enabled_local); | 425 | gicd_write(sc, GICD_ISENABLERn(0), sc->sc_enabled_local); | |
426 | cpsie(I32_bit); // allow IRQ exceptions | 426 | cpsie(I32_bit); // allow IRQ exceptions | |
427 | } | 427 | } | |
428 | 428 | |||
429 | void | 429 | void | |
430 | armgic_ipi_send(struct pic_softc *pic, const kcpuset_t *kcp, u_long ipi) | 430 | armgic_ipi_send(struct pic_softc *pic, const kcpuset_t *kcp, u_long ipi) | |
431 | { | 431 | { | |
432 | struct armgic_softc * const sc = PICTOSOFTC(pic); | 432 | struct armgic_softc * const sc = PICTOSOFTC(pic); | |
433 | 433 | |||
434 | if (ipi == IPI_NOP) { | 434 | if (ipi == IPI_NOP) { | |
435 | __asm __volatile("sev"); | 435 | __asm __volatile("sev"); | |
436 | return; | 436 | return; | |
437 | } | 437 | } | |
438 | 438 | |||
439 | uint32_t targets; | 439 | uint32_t targets; | |
440 | kcpuset_copybits(kcp, &targets, sizeof(targets)); | 440 | kcpuset_export_u32(kcp, &targets, sizeof(targets)); | |
441 | uint32_t sgir = __SHIFTOUT(ARMGIC_SGI_IPIBASE + ipi, GICD_SGIR_SGIINTID); | 441 | uint32_t sgir = __SHIFTOUT(ARMGIC_SGI_IPIBASE + ipi, GICD_SGIR_SGIINTID); | |
442 | sgir |= __SHIFTOUT(targets, GICD_SGIR_TargetList); | 442 | sgir |= __SHIFTOUT(targets, GICD_SGIR_TargetList); | |
443 | 443 | |||
444 | printf("%s: %s: %#x", __func__, curcpu()->ci_data.cpu_name, sgir); | 444 | printf("%s: %s: %#x", __func__, curcpu()->ci_data.cpu_name, sgir); | |
445 | gicd_write(sc, GICD_SGIR, sgir); | 445 | gicd_write(sc, GICD_SGIR, sgir); | |
446 | printf("\n"); | 446 | printf("\n"); | |
447 | } | 447 | } | |
448 | #endif | 448 | #endif | |
449 | 449 | |||
450 | int | 450 | int | |
451 | armgic_match(device_t parent, cfdata_t cf, void *aux) | 451 | armgic_match(device_t parent, cfdata_t cf, void *aux) | |
452 | { | 452 | { | |
453 | struct mpcore_attach_args * const mpcaa = aux; | 453 | struct mpcore_attach_args * const mpcaa = aux; | |
454 | 454 | |||
455 | if (strcmp(cf->cf_name, mpcaa->mpcaa_name) != 0) | 455 | if (strcmp(cf->cf_name, mpcaa->mpcaa_name) != 0) | |
456 | return 0; | 456 | return 0; | |
457 | if (!CPU_ID_CORTEX_P(cputype)) | 457 | if (!CPU_ID_CORTEX_P(cputype)) | |
458 | return 0; | 458 | return 0; | |
459 | if (CPU_ID_CORTEX_A8_P(cputype)) | 459 | if (CPU_ID_CORTEX_A8_P(cputype)) | |
460 | return 0; | 460 | return 0; | |
461 | 461 | |||
462 | return 1; | 462 | return 1; | |
463 | } | 463 | } | |
464 | 464 | |||
465 | void | 465 | void | |
466 | armgic_attach(device_t parent, device_t self, void *aux) | 466 | armgic_attach(device_t parent, device_t self, void *aux) | |
467 | { | 467 | { | |
468 | struct armgic_softc * const sc = &armgic_softc; | 468 | struct armgic_softc * const sc = &armgic_softc; | |
469 | struct mpcore_attach_args * const mpcaa = aux; | 469 | struct mpcore_attach_args * const mpcaa = aux; | |
470 | 470 | |||
471 | sc->sc_dev = self; | 471 | sc->sc_dev = self; | |
472 | self->dv_private = sc; | 472 | self->dv_private = sc; | |
473 | 473 | |||
474 | sc->sc_memt = mpcaa->mpcaa_memt; /* provided for us */ | 474 | sc->sc_memt = mpcaa->mpcaa_memt; /* provided for us */ | |
475 | sc->sc_memh = mpcaa->mpcaa_memh; /* provided for us */ | 475 | sc->sc_memh = mpcaa->mpcaa_memh; /* provided for us */ | |
476 | 476 | |||
477 | sc->sc_gic_type = gicd_read(sc, GICD_TYPER); | 477 | sc->sc_gic_type = gicd_read(sc, GICD_TYPER); | |
478 | sc->sc_pic.pic_maxsources = GICD_TYPER_LINES(sc->sc_gic_type); | 478 | sc->sc_pic.pic_maxsources = GICD_TYPER_LINES(sc->sc_gic_type); | |
479 | 479 | |||
480 | gicc_write(sc, GICC_CTRL, 0); /* disable all interrupts */ | 480 | gicc_write(sc, GICC_CTRL, 0); /* disable all interrupts */ | |
481 | gicd_write(sc, GICD_CTRL, 0); /* disable all interrupts */ | 481 | gicd_write(sc, GICD_CTRL, 0); /* disable all interrupts */ | |
482 | 482 | |||
483 | gicc_write(sc, GICC_PMR, 0xff); | 483 | gicc_write(sc, GICC_PMR, 0xff); | |
484 | uint32_t pmr = gicc_read(sc, GICC_PMR); | 484 | uint32_t pmr = gicc_read(sc, GICC_PMR); | |
485 | u_int priorities = 1 << popcount32(pmr); | 485 | u_int priorities = 1 << popcount32(pmr); | |
486 | 486 | |||
487 | /* | 487 | /* | |
488 | * Let's find out how many real sources we have. | 488 | * Let's find out how many real sources we have. | |
489 | */ | 489 | */ | |
490 | for (size_t i = 0, group = 0; | 490 | for (size_t i = 0, group = 0; | |
491 | i < sc->sc_pic.pic_maxsources; | 491 | i < sc->sc_pic.pic_maxsources; | |
492 | i += 32, group++) { | 492 | i += 32, group++) { | |
493 | /* | 493 | /* | |
494 | * To figure what sources are real, one enables all interrupts | 494 | * To figure what sources are real, one enables all interrupts | |
495 | * and then reads back the enable mask so which ones really | 495 | * and then reads back the enable mask so which ones really | |
496 | * got enabled. | 496 | * got enabled. | |
497 | */ | 497 | */ | |
498 | gicd_write(sc, GICD_ISENABLERn(group), 0xffffffff); | 498 | gicd_write(sc, GICD_ISENABLERn(group), 0xffffffff); | |
499 | uint32_t valid = gicd_read(sc, GICD_ISENABLERn(group)); | 499 | uint32_t valid = gicd_read(sc, GICD_ISENABLERn(group)); | |
500 | 500 | |||
501 | /* | 501 | /* | |
502 | * Now disable (clear enable) them again. | 502 | * Now disable (clear enable) them again. | |
503 | */ | 503 | */ | |
504 | gicd_write(sc, GICD_ICENABLERn(group), valid); | 504 | gicd_write(sc, GICD_ICENABLERn(group), valid); | |
505 | 505 | |||
506 | /* | 506 | /* | |
507 | * Count how many are valid. | 507 | * Count how many are valid. | |
508 | */ | 508 | */ | |
509 | sc->sc_gic_lines += popcount32(valid); | 509 | sc->sc_gic_lines += popcount32(valid); | |
510 | sc->sc_gic_valid_lines[group] = valid; | 510 | sc->sc_gic_valid_lines[group] = valid; | |
511 | } | 511 | } | |
512 | 512 | |||
513 | pic_add(&sc->sc_pic, 0); | 513 | pic_add(&sc->sc_pic, 0); | |
514 | 514 | |||
515 | /* | 515 | /* | |
516 | * Force the GICD to IPL_HIGH and then enable interrupts. | 516 | * Force the GICD to IPL_HIGH and then enable interrupts. | |
517 | */ | 517 | */ | |
518 | struct cpu_info * const ci = curcpu(); | 518 | struct cpu_info * const ci = curcpu(); | |
519 | KASSERTMSG(ci->ci_cpl == IPL_HIGH, "ipl %d not IPL_HIGH", ci->ci_cpl); | 519 | KASSERTMSG(ci->ci_cpl == IPL_HIGH, "ipl %d not IPL_HIGH", ci->ci_cpl); | |
520 | armgic_set_priority(&sc->sc_pic, ci->ci_cpl); // set PMR | 520 | armgic_set_priority(&sc->sc_pic, ci->ci_cpl); // set PMR | |
521 | gicd_write(sc, GICD_CTRL, GICD_CTRL_Enable); // enable Distributer | 521 | gicd_write(sc, GICD_CTRL, GICD_CTRL_Enable); // enable Distributer | |
522 | gicc_write(sc, GICC_CTRL, GICC_CTRL_V1_Enable); // enable CPU interrupts | 522 | gicc_write(sc, GICC_CTRL, GICC_CTRL_V1_Enable); // enable CPU interrupts | |
523 | cpsie(I32_bit); // allow interrupt exceptions | 523 | cpsie(I32_bit); // allow interrupt exceptions | |
524 | 524 | |||
525 | /* | 525 | /* | |
526 | * For each line that isn't valid, we set the intrsource for it to | 526 | * For each line that isn't valid, we set the intrsource for it to | |
527 | * point at a dummy source so that pic_intr_establish will fail for it. | 527 | * point at a dummy source so that pic_intr_establish will fail for it. | |
528 | */ | 528 | */ | |
529 | for (size_t i = 0, group = 0; | 529 | for (size_t i = 0, group = 0; | |
530 | i < sc->sc_pic.pic_maxsources; | 530 | i < sc->sc_pic.pic_maxsources; | |
531 | i += 32, group++) { | 531 | i += 32, group++) { | |
532 | uint32_t invalid = ~sc->sc_gic_valid_lines[group]; | 532 | uint32_t invalid = ~sc->sc_gic_valid_lines[group]; | |
533 | for (size_t j = 0; invalid && j < 32; j++, invalid >>= 1) { | 533 | for (size_t j = 0; invalid && j < 32; j++, invalid >>= 1) { | |
534 | if (invalid & 1) { | 534 | if (invalid & 1) { | |
535 | sc->sc_pic.pic_sources[i + j] = | 535 | sc->sc_pic.pic_sources[i + j] = | |
536 | &armgic_dummy_source; | 536 | &armgic_dummy_source; | |
537 | } | 537 | } | |
538 | } | 538 | } | |
539 | } | 539 | } | |
540 | #ifdef __HAVE_PIC_FAST_SOFTINTS | 540 | #ifdef __HAVE_PIC_FAST_SOFTINTS | |
541 | intr_establish(SOFTINT_BIO, IPL_SOFTBIO, IST_EDGE, | 541 | intr_establish(SOFTINT_BIO, IPL_SOFTBIO, IST_EDGE, | |
542 | pic_handle_softint, (void *)SOFTINT_BIO); | 542 | pic_handle_softint, (void *)SOFTINT_BIO); | |
543 | intr_establish(SOFTINT_CLOCK, IPL_SOFTCLOCK, IST_EDGE, | 543 | intr_establish(SOFTINT_CLOCK, IPL_SOFTCLOCK, IST_EDGE, | |
544 | pic_handle_softint, (void *)SOFTINT_CLOCK); | 544 | pic_handle_softint, (void *)SOFTINT_CLOCK); | |
545 | intr_establish(SOFTINT_NET, IPL_SOFTNET, IST_EDGE, | 545 | intr_establish(SOFTINT_NET, IPL_SOFTNET, IST_EDGE, | |
546 | pic_handle_softint, (void *)SOFTINT_NET); | 546 | pic_handle_softint, (void *)SOFTINT_NET); | |
547 | intr_establish(SOFTINT_SERIAL, IPL_SOFTSERIAL, IST_EDGE, | 547 | intr_establish(SOFTINT_SERIAL, IPL_SOFTSERIAL, IST_EDGE, | |
548 | pic_handle_softint, (void *)SOFTINT_SERIAL); | 548 | pic_handle_softint, (void *)SOFTINT_SERIAL); | |
549 | #endif | 549 | #endif | |
550 | #ifdef MULTIPROCESSOR | 550 | #ifdef MULTIPROCESSOR | |
551 | intr_establish(ARMGIC_SGI_IPIBASE + IPI_AST, IPL_VM, IST_EDGE, | 551 | intr_establish(ARMGIC_SGI_IPIBASE + IPI_AST, IPL_VM, IST_EDGE, | |
552 | pic_ipi_nop, (void *)-1); | 552 | pic_ipi_nop, (void *)-1); | |
553 | intr_establish(ARMGIC_SGI_IPIBASE + IPI_XCALL, IPL_VM, IST_EDGE, | 553 | intr_establish(ARMGIC_SGI_IPIBASE + IPI_XCALL, IPL_VM, IST_EDGE, | |
554 | pic_ipi_xcall, (void *)-1); | 554 | pic_ipi_xcall, (void *)-1); | |
555 | #if 0 /* Not needed */ | 555 | #if 0 /* Not needed */ | |
556 | intr_establish(ARMGIC_SGI_IPIBASE + IPI_NOP, IPL_VM, IST_EDGE, | 556 | intr_establish(ARMGIC_SGI_IPIBASE + IPI_NOP, IPL_VM, IST_EDGE, | |
557 | pic_ipi_nop, (void *)-1); | 557 | pic_ipi_nop, (void *)-1); | |
558 | #endif | 558 | #endif | |
559 | #ifdef __HAVE_PREEMPTION | 559 | #ifdef __HAVE_PREEMPTION | |
560 | intr_establish(ARMGIC_SGI_IPIBASE + IPI_KPREEMPT, IPL_VM, IST_EDGE, | 560 | intr_establish(ARMGIC_SGI_IPIBASE + IPI_KPREEMPT, IPL_VM, IST_EDGE, | |
561 | pic_ipi_nop, (void *)-1); | 561 | pic_ipi_nop, (void *)-1); | |
562 | #endif | 562 | #endif | |
563 | armgic_cpu_init(&sc->sc_pic, curcpu()); | 563 | armgic_cpu_init(&sc->sc_pic, curcpu()); | |
564 | #endif | 564 | #endif | |
565 | 565 | |||
566 | aprint_normal(": Generic Interrupt Controller, " | 566 | aprint_normal(": Generic Interrupt Controller, " | |
567 | "%zu sources (%zu valid)\n", | 567 | "%zu sources (%zu valid)\n", | |
568 | sc->sc_pic.pic_maxsources, sc->sc_gic_lines); | 568 | sc->sc_pic.pic_maxsources, sc->sc_gic_lines); | |
569 | 569 | |||
570 | const u_int ppis = popcount32(sc->sc_gic_valid_lines[0] >> 16); | 570 | const u_int ppis = popcount32(sc->sc_gic_valid_lines[0] >> 16); | |
571 | const u_int sgis = popcount32(sc->sc_gic_valid_lines[0] & 0xffff); | 571 | const u_int sgis = popcount32(sc->sc_gic_valid_lines[0] & 0xffff); | |
572 | aprint_normal_dev(sc->sc_dev, "%u Priorities, %zu SPIs, %u PPIs, %u SGIs\n", | 572 | aprint_normal_dev(sc->sc_dev, "%u Priorities, %zu SPIs, %u PPIs, %u SGIs\n", | |
573 | priorities, sc->sc_gic_lines - ppis - sgis, ppis, sgis); | 573 | priorities, sc->sc_gic_lines - ppis - sgis, ppis, sgis); | |
574 | } | 574 | } | |
575 | 575 | |||
576 | CFATTACH_DECL_NEW(armgic, 0, | 576 | CFATTACH_DECL_NEW(armgic, 0, | |
577 | armgic_match, armgic_attach, NULL, NULL); | 577 | armgic_match, armgic_attach, NULL, NULL); |
--- src/sys/arch/xen/x86/x86_xpmap.c 2012/08/21 09:06:02 1.48
+++ src/sys/arch/xen/x86/x86_xpmap.c 2012/09/16 22:09:34 1.49
@@ -1,1114 +1,1114 @@ | @@ -1,1114 +1,1114 @@ | |||
1 | /* $NetBSD: x86_xpmap.c,v 1.48 2012/08/21 09:06:02 bouyer Exp $ */ | 1 | /* $NetBSD: x86_xpmap.c,v 1.49 2012/09/16 22:09:34 rmind Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 2006 Mathieu Ropert <mro@adviseo.fr> | 4 | * Copyright (c) 2006 Mathieu Ropert <mro@adviseo.fr> | |
5 | * | 5 | * | |
6 | * Permission to use, copy, modify, and distribute this software for any | 6 | * Permission to use, copy, modify, and distribute this software for any | |
7 | * purpose with or without fee is hereby granted, provided that the above | 7 | * purpose with or without fee is hereby granted, provided that the above | |
8 | * copyright notice and this permission notice appear in all copies. | 8 | * copyright notice and this permission notice appear in all copies. | |
9 | * | 9 | * | |
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
17 | */ | 17 | */ | |
18 | 18 | |||
19 | /* | 19 | /* | |
20 | * Copyright (c) 2006, 2007 Manuel Bouyer. | 20 | * Copyright (c) 2006, 2007 Manuel Bouyer. | |
21 | * | 21 | * | |
22 | * Redistribution and use in source and binary forms, with or without | 22 | * Redistribution and use in source and binary forms, with or without | |
23 | * modification, are permitted provided that the following conditions | 23 | * modification, are permitted provided that the following conditions | |
24 | * are met: | 24 | * are met: | |
25 | * 1. Redistributions of source code must retain the above copyright | 25 | * 1. Redistributions of source code must retain the above copyright | |
26 | * notice, this list of conditions and the following disclaimer. | 26 | * notice, this list of conditions and the following disclaimer. | |
27 | * 2. Redistributions in binary form must reproduce the above copyright | 27 | * 2. Redistributions in binary form must reproduce the above copyright | |
28 | * notice, this list of conditions and the following disclaimer in the | 28 | * notice, this list of conditions and the following disclaimer in the | |
29 | * documentation and/or other materials provided with the distribution. | 29 | * documentation and/or other materials provided with the distribution. | |
30 | * | 30 | * | |
31 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | 31 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
32 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | 32 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
33 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | 33 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
34 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | 34 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
35 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | 35 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
36 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 36 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
37 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 37 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
38 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 38 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
39 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 39 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
40 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 40 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
41 | * | 41 | * | |
42 | */ | 42 | */ | |
43 | 43 | |||
44 | /* | 44 | /* | |
45 | * | 45 | * | |
46 | * Copyright (c) 2004 Christian Limpach. | 46 | * Copyright (c) 2004 Christian Limpach. | |
47 | * All rights reserved. | 47 | * All rights reserved. | |
48 | * | 48 | * | |
49 | * Redistribution and use in source and binary forms, with or without | 49 | * Redistribution and use in source and binary forms, with or without | |
50 | * modification, are permitted provided that the following conditions | 50 | * modification, are permitted provided that the following conditions | |
51 | * are met: | 51 | * are met: | |
52 | * 1. Redistributions of source code must retain the above copyright | 52 | * 1. Redistributions of source code must retain the above copyright | |
53 | * notice, this list of conditions and the following disclaimer. | 53 | * notice, this list of conditions and the following disclaimer. | |
54 | * 2. Redistributions in binary form must reproduce the above copyright | 54 | * 2. Redistributions in binary form must reproduce the above copyright | |
55 | * notice, this list of conditions and the following disclaimer in the | 55 | * notice, this list of conditions and the following disclaimer in the | |
56 | * documentation and/or other materials provided with the distribution. | 56 | * documentation and/or other materials provided with the distribution. | |
57 | * | 57 | * | |
58 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | 58 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
59 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | 59 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
60 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | 60 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
61 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | 61 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
62 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | 62 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
63 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 63 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
64 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 64 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
65 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 65 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
66 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 66 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
67 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 67 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
68 | */ | 68 | */ | |
69 | 69 | |||
70 | 70 | |||
71 | #include <sys/cdefs.h> | 71 | #include <sys/cdefs.h> | |
72 | __KERNEL_RCSID(0, "$NetBSD: x86_xpmap.c,v 1.48 2012/08/21 09:06:02 bouyer Exp $"); | 72 | __KERNEL_RCSID(0, "$NetBSD: x86_xpmap.c,v 1.49 2012/09/16 22:09:34 rmind Exp $"); | |
73 | 73 | |||
74 | #include "opt_xen.h" | 74 | #include "opt_xen.h" | |
75 | #include "opt_ddb.h" | 75 | #include "opt_ddb.h" | |
76 | #include "ksyms.h" | 76 | #include "ksyms.h" | |
77 | 77 | |||
78 | #include <sys/param.h> | 78 | #include <sys/param.h> | |
79 | #include <sys/systm.h> | 79 | #include <sys/systm.h> | |
80 | #include <sys/mutex.h> | 80 | #include <sys/mutex.h> | |
81 | #include <sys/cpu.h> | 81 | #include <sys/cpu.h> | |
82 | 82 | |||
83 | #include <uvm/uvm.h> | 83 | #include <uvm/uvm.h> | |
84 | 84 | |||
85 | #include <x86/pmap.h> | 85 | #include <x86/pmap.h> | |
86 | #include <machine/gdt.h> | 86 | #include <machine/gdt.h> | |
87 | #include <xen/xenfunc.h> | 87 | #include <xen/xenfunc.h> | |
88 | 88 | |||
89 | #include <dev/isa/isareg.h> | 89 | #include <dev/isa/isareg.h> | |
90 | #include <machine/isa_machdep.h> | 90 | #include <machine/isa_machdep.h> | |
91 | 91 | |||
92 | #undef XENDEBUG | 92 | #undef XENDEBUG | |
93 | /* #define XENDEBUG_SYNC */ | 93 | /* #define XENDEBUG_SYNC */ | |
94 | /* #define XENDEBUG_LOW */ | 94 | /* #define XENDEBUG_LOW */ | |
95 | 95 | |||
96 | #ifdef XENDEBUG | 96 | #ifdef XENDEBUG | |
97 | #define XENPRINTF(x) printf x | 97 | #define XENPRINTF(x) printf x | |
98 | #define XENPRINTK(x) printk x | 98 | #define XENPRINTK(x) printk x | |
99 | #define XENPRINTK2(x) /* printk x */ | 99 | #define XENPRINTK2(x) /* printk x */ | |
100 | 100 | |||
101 | static char XBUF[256]; | 101 | static char XBUF[256]; | |
102 | #else | 102 | #else | |
103 | #define XENPRINTF(x) | 103 | #define XENPRINTF(x) | |
104 | #define XENPRINTK(x) | 104 | #define XENPRINTK(x) | |
105 | #define XENPRINTK2(x) | 105 | #define XENPRINTK2(x) | |
106 | #endif | 106 | #endif | |
107 | #define PRINTF(x) printf x | 107 | #define PRINTF(x) printf x | |
108 | #define PRINTK(x) printk x | 108 | #define PRINTK(x) printk x | |
109 | 109 | |||
110 | volatile shared_info_t *HYPERVISOR_shared_info; | 110 | volatile shared_info_t *HYPERVISOR_shared_info; | |
111 | /* Xen requires the start_info struct to be page aligned */ | 111 | /* Xen requires the start_info struct to be page aligned */ | |
112 | union start_info_union start_info_union __aligned(PAGE_SIZE); | 112 | union start_info_union start_info_union __aligned(PAGE_SIZE); | |
113 | unsigned long *xpmap_phys_to_machine_mapping; | 113 | unsigned long *xpmap_phys_to_machine_mapping; | |
114 | kmutex_t pte_lock; | 114 | kmutex_t pte_lock; | |
115 | 115 | |||
116 | void xen_failsafe_handler(void); | 116 | void xen_failsafe_handler(void); | |
117 | 117 | |||
118 | #define HYPERVISOR_mmu_update_self(req, count, success_count) \ | 118 | #define HYPERVISOR_mmu_update_self(req, count, success_count) \ | |
119 | HYPERVISOR_mmu_update((req), (count), (success_count), DOMID_SELF) | 119 | HYPERVISOR_mmu_update((req), (count), (success_count), DOMID_SELF) | |
120 | 120 | |||
121 | /* | 121 | /* | |
122 | * kcpuset internally uses an array of uint32_t while xen uses an array of | 122 | * kcpuset internally uses an array of uint32_t while xen uses an array of | |
123 | * u_long. As we're little-endian we can cast one to the other. | 123 | * u_long. As we're little-endian we can cast one to the other. | |
124 | */ | 124 | */ | |
125 | typedef union { | 125 | typedef union { | |
126 | #ifdef _LP64 | 126 | #ifdef _LP64 | |
127 | uint32_t xcpum_km[2]; | 127 | uint32_t xcpum_km[2]; | |
128 | #else | 128 | #else | |
129 | uint32_t xcpum_km[1]; | 129 | uint32_t xcpum_km[1]; | |
130 | #endif | 130 | #endif | |
131 | u_long xcpum_xm; | 131 | u_long xcpum_xm; | |
132 | } xcpumask_t; | 132 | } xcpumask_t; | |
133 | 133 | |||
134 | void | 134 | void | |
135 | xen_failsafe_handler(void) | 135 | xen_failsafe_handler(void) | |
136 | { | 136 | { | |
137 | 137 | |||
138 | panic("xen_failsafe_handler called!\n"); | 138 | panic("xen_failsafe_handler called!\n"); | |
139 | } | 139 | } | |
140 | 140 | |||
141 | 141 | |||
142 | void | 142 | void | |
143 | xen_set_ldt(vaddr_t base, uint32_t entries) | 143 | xen_set_ldt(vaddr_t base, uint32_t entries) | |
144 | { | 144 | { | |
145 | vaddr_t va; | 145 | vaddr_t va; | |
146 | vaddr_t end; | 146 | vaddr_t end; | |
147 | pt_entry_t *ptp; | 147 | pt_entry_t *ptp; | |
148 | int s; | 148 | int s; | |
149 | 149 | |||
150 | #ifdef __x86_64__ | 150 | #ifdef __x86_64__ | |
151 | end = base + (entries << 3); | 151 | end = base + (entries << 3); | |
152 | #else | 152 | #else | |
153 | end = base + entries * sizeof(union descriptor); | 153 | end = base + entries * sizeof(union descriptor); | |
154 | #endif | 154 | #endif | |
155 | 155 | |||
156 | for (va = base; va < end; va += PAGE_SIZE) { | 156 | for (va = base; va < end; va += PAGE_SIZE) { | |
157 | KASSERT(va >= VM_MIN_KERNEL_ADDRESS); | 157 | KASSERT(va >= VM_MIN_KERNEL_ADDRESS); | |
158 | ptp = kvtopte(va); | 158 | ptp = kvtopte(va); | |
159 | XENPRINTF(("xen_set_ldt %#" PRIxVADDR " %d %p\n", | 159 | XENPRINTF(("xen_set_ldt %#" PRIxVADDR " %d %p\n", | |
160 | base, entries, ptp)); | 160 | base, entries, ptp)); | |
161 | pmap_pte_clearbits(ptp, PG_RW); | 161 | pmap_pte_clearbits(ptp, PG_RW); | |
162 | } | 162 | } | |
163 | s = splvm(); | 163 | s = splvm(); | |
164 | xpq_queue_set_ldt(base, entries); | 164 | xpq_queue_set_ldt(base, entries); | |
165 | splx(s); | 165 | splx(s); | |
166 | } | 166 | } | |
167 | 167 | |||
168 | #ifdef XENDEBUG | 168 | #ifdef XENDEBUG | |
169 | void xpq_debug_dump(void); | 169 | void xpq_debug_dump(void); | |
170 | #endif | 170 | #endif | |
171 | 171 | |||
172 | #define XPQUEUE_SIZE 2048 | 172 | #define XPQUEUE_SIZE 2048 | |
173 | static mmu_update_t xpq_queue_array[MAXCPUS][XPQUEUE_SIZE]; | 173 | static mmu_update_t xpq_queue_array[MAXCPUS][XPQUEUE_SIZE]; | |
174 | static int xpq_idx_array[MAXCPUS]; | 174 | static int xpq_idx_array[MAXCPUS]; | |
175 | 175 | |||
176 | #ifdef i386 | 176 | #ifdef i386 | |
177 | extern union descriptor tmpgdt[]; | 177 | extern union descriptor tmpgdt[]; | |
178 | #endif /* i386 */ | 178 | #endif /* i386 */ | |
179 | void | 179 | void | |
180 | xpq_flush_queue(void) | 180 | xpq_flush_queue(void) | |
181 | { | 181 | { | |
182 | int i, ok = 0, ret; | 182 | int i, ok = 0, ret; | |
183 | 183 | |||
184 | mmu_update_t *xpq_queue = xpq_queue_array[curcpu()->ci_cpuid]; | 184 | mmu_update_t *xpq_queue = xpq_queue_array[curcpu()->ci_cpuid]; | |
185 | int xpq_idx = xpq_idx_array[curcpu()->ci_cpuid]; | 185 | int xpq_idx = xpq_idx_array[curcpu()->ci_cpuid]; | |
186 | 186 | |||
187 | XENPRINTK2(("flush queue %p entries %d\n", xpq_queue, xpq_idx)); | 187 | XENPRINTK2(("flush queue %p entries %d\n", xpq_queue, xpq_idx)); | |
188 | for (i = 0; i < xpq_idx; i++) | 188 | for (i = 0; i < xpq_idx; i++) | |
189 | XENPRINTK2(("%d: 0x%08" PRIx64 " 0x%08" PRIx64 "\n", i, | 189 | XENPRINTK2(("%d: 0x%08" PRIx64 " 0x%08" PRIx64 "\n", i, | |
190 | xpq_queue[i].ptr, xpq_queue[i].val)); | 190 | xpq_queue[i].ptr, xpq_queue[i].val)); | |
191 | 191 | |||
192 | retry: | 192 | retry: | |
193 | ret = HYPERVISOR_mmu_update_self(xpq_queue, xpq_idx, &ok); | 193 | ret = HYPERVISOR_mmu_update_self(xpq_queue, xpq_idx, &ok); | |
194 | 194 | |||
195 | if (xpq_idx != 0 && ret < 0) { | 195 | if (xpq_idx != 0 && ret < 0) { | |
196 | struct cpu_info *ci; | 196 | struct cpu_info *ci; | |
197 | CPU_INFO_ITERATOR cii; | 197 | CPU_INFO_ITERATOR cii; | |
198 | 198 | |||
199 | printf("xpq_flush_queue: %d entries (%d successful) on " | 199 | printf("xpq_flush_queue: %d entries (%d successful) on " | |
200 | "cpu%d (%ld)\n", | 200 | "cpu%d (%ld)\n", | |
201 | xpq_idx, ok, curcpu()->ci_index, curcpu()->ci_cpuid); | 201 | xpq_idx, ok, curcpu()->ci_index, curcpu()->ci_cpuid); | |
202 | 202 | |||
203 | if (ok != 0) { | 203 | if (ok != 0) { | |
204 | xpq_queue += ok; | 204 | xpq_queue += ok; | |
205 | xpq_idx -= ok; | 205 | xpq_idx -= ok; | |
206 | ok = 0; | 206 | ok = 0; | |
207 | goto retry; | 207 | goto retry; | |
208 | } | 208 | } | |
209 | 209 | |||
210 | for (CPU_INFO_FOREACH(cii, ci)) { | 210 | for (CPU_INFO_FOREACH(cii, ci)) { | |
211 | xpq_queue = xpq_queue_array[ci->ci_cpuid]; | 211 | xpq_queue = xpq_queue_array[ci->ci_cpuid]; | |
212 | xpq_idx = xpq_idx_array[ci->ci_cpuid]; | 212 | xpq_idx = xpq_idx_array[ci->ci_cpuid]; | |
213 | printf("cpu%d (%ld):\n", ci->ci_index, ci->ci_cpuid); | 213 | printf("cpu%d (%ld):\n", ci->ci_index, ci->ci_cpuid); | |
214 | for (i = 0; i < xpq_idx; i++) { | 214 | for (i = 0; i < xpq_idx; i++) { | |
215 | printf(" 0x%016" PRIx64 ": 0x%016" PRIx64 "\n", | 215 | printf(" 0x%016" PRIx64 ": 0x%016" PRIx64 "\n", | |
216 | xpq_queue[i].ptr, xpq_queue[i].val); | 216 | xpq_queue[i].ptr, xpq_queue[i].val); | |
217 | } | 217 | } | |
218 | #ifdef __x86_64__ | 218 | #ifdef __x86_64__ | |
219 | for (i = 0; i < PDIR_SLOT_PTE; i++) { | 219 | for (i = 0; i < PDIR_SLOT_PTE; i++) { | |
220 | if (ci->ci_kpm_pdir[i] == 0) | 220 | if (ci->ci_kpm_pdir[i] == 0) | |
221 | continue; | 221 | continue; | |
222 | printf(" kpm_pdir[%d]: 0x%" PRIx64 "\n", | 222 | printf(" kpm_pdir[%d]: 0x%" PRIx64 "\n", | |
223 | i, ci->ci_kpm_pdir[i]); | 223 | i, ci->ci_kpm_pdir[i]); | |
224 | } | 224 | } | |
225 | #endif | 225 | #endif | |
226 | } | 226 | } | |
227 | panic("HYPERVISOR_mmu_update failed, ret: %d\n", ret); | 227 | panic("HYPERVISOR_mmu_update failed, ret: %d\n", ret); | |
228 | } | 228 | } | |
229 | xpq_idx_array[curcpu()->ci_cpuid] = 0; | 229 | xpq_idx_array[curcpu()->ci_cpuid] = 0; | |
230 | } | 230 | } | |
231 | 231 | |||
232 | static inline void | 232 | static inline void | |
233 | xpq_increment_idx(void) | 233 | xpq_increment_idx(void) | |
234 | { | 234 | { | |
235 | 235 | |||
236 | if (__predict_false(++xpq_idx_array[curcpu()->ci_cpuid] == XPQUEUE_SIZE)) | 236 | if (__predict_false(++xpq_idx_array[curcpu()->ci_cpuid] == XPQUEUE_SIZE)) | |
237 | xpq_flush_queue(); | 237 | xpq_flush_queue(); | |
238 | } | 238 | } | |
239 | 239 | |||
240 | void | 240 | void | |
241 | xpq_queue_machphys_update(paddr_t ma, paddr_t pa) | 241 | xpq_queue_machphys_update(paddr_t ma, paddr_t pa) | |
242 | { | 242 | { | |
243 | 243 | |||
244 | mmu_update_t *xpq_queue = xpq_queue_array[curcpu()->ci_cpuid]; | 244 | mmu_update_t *xpq_queue = xpq_queue_array[curcpu()->ci_cpuid]; | |
245 | int xpq_idx = xpq_idx_array[curcpu()->ci_cpuid]; | 245 | int xpq_idx = xpq_idx_array[curcpu()->ci_cpuid]; | |
246 | 246 | |||
247 | XENPRINTK2(("xpq_queue_machphys_update ma=0x%" PRIx64 " pa=0x%" PRIx64 | 247 | XENPRINTK2(("xpq_queue_machphys_update ma=0x%" PRIx64 " pa=0x%" PRIx64 | |
248 | "\n", (int64_t)ma, (int64_t)pa)); | 248 | "\n", (int64_t)ma, (int64_t)pa)); | |
249 | 249 | |||
250 | xpq_queue[xpq_idx].ptr = ma | MMU_MACHPHYS_UPDATE; | 250 | xpq_queue[xpq_idx].ptr = ma | MMU_MACHPHYS_UPDATE; | |
251 | xpq_queue[xpq_idx].val = pa >> PAGE_SHIFT; | 251 | xpq_queue[xpq_idx].val = pa >> PAGE_SHIFT; | |
252 | xpq_increment_idx(); | 252 | xpq_increment_idx(); | |
253 | #ifdef XENDEBUG_SYNC | 253 | #ifdef XENDEBUG_SYNC | |
254 | xpq_flush_queue(); | 254 | xpq_flush_queue(); | |
255 | #endif | 255 | #endif | |
256 | } | 256 | } | |
257 | 257 | |||
258 | void | 258 | void | |
259 | xpq_queue_pte_update(paddr_t ptr, pt_entry_t val) | 259 | xpq_queue_pte_update(paddr_t ptr, pt_entry_t val) | |
260 | { | 260 | { | |
261 | 261 | |||
262 | mmu_update_t *xpq_queue = xpq_queue_array[curcpu()->ci_cpuid]; | 262 | mmu_update_t *xpq_queue = xpq_queue_array[curcpu()->ci_cpuid]; | |
263 | int xpq_idx = xpq_idx_array[curcpu()->ci_cpuid]; | 263 | int xpq_idx = xpq_idx_array[curcpu()->ci_cpuid]; | |
264 | 264 | |||
265 | KASSERT((ptr & 3) == 0); | 265 | KASSERT((ptr & 3) == 0); | |
266 | xpq_queue[xpq_idx].ptr = (paddr_t)ptr | MMU_NORMAL_PT_UPDATE; | 266 | xpq_queue[xpq_idx].ptr = (paddr_t)ptr | MMU_NORMAL_PT_UPDATE; | |
267 | xpq_queue[xpq_idx].val = val; | 267 | xpq_queue[xpq_idx].val = val; | |
268 | xpq_increment_idx(); | 268 | xpq_increment_idx(); | |
269 | #ifdef XENDEBUG_SYNC | 269 | #ifdef XENDEBUG_SYNC | |
270 | xpq_flush_queue(); | 270 | xpq_flush_queue(); | |
271 | #endif | 271 | #endif | |
272 | } | 272 | } | |
273 | 273 | |||
274 | void | 274 | void | |
275 | xpq_queue_pt_switch(paddr_t pa) | 275 | xpq_queue_pt_switch(paddr_t pa) | |
276 | { | 276 | { | |
277 | struct mmuext_op op; | 277 | struct mmuext_op op; | |
278 | xpq_flush_queue(); | 278 | xpq_flush_queue(); | |
279 | 279 | |||
280 | XENPRINTK2(("xpq_queue_pt_switch: 0x%" PRIx64 " 0x%" PRIx64 "\n", | 280 | XENPRINTK2(("xpq_queue_pt_switch: 0x%" PRIx64 " 0x%" PRIx64 "\n", | |
281 | (int64_t)pa, (int64_t)pa)); | 281 | (int64_t)pa, (int64_t)pa)); | |
282 | op.cmd = MMUEXT_NEW_BASEPTR; | 282 | op.cmd = MMUEXT_NEW_BASEPTR; | |
283 | op.arg1.mfn = pa >> PAGE_SHIFT; | 283 | op.arg1.mfn = pa >> PAGE_SHIFT; | |
284 | if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0) | 284 | if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0) | |
285 | panic("xpq_queue_pt_switch"); | 285 | panic("xpq_queue_pt_switch"); | |
286 | } | 286 | } | |
287 | 287 | |||
288 | void | 288 | void | |
289 | xpq_queue_pin_table(paddr_t pa, int lvl) | 289 | xpq_queue_pin_table(paddr_t pa, int lvl) | |
290 | { | 290 | { | |
291 | struct mmuext_op op; | 291 | struct mmuext_op op; | |
292 | 292 | |||
293 | xpq_flush_queue(); | 293 | xpq_flush_queue(); | |
294 | 294 | |||
295 | XENPRINTK2(("xpq_queue_pin_l%d_table: %#" PRIxPADDR "\n", | 295 | XENPRINTK2(("xpq_queue_pin_l%d_table: %#" PRIxPADDR "\n", | |
296 | lvl + 1, pa)); | 296 | lvl + 1, pa)); | |
297 | 297 | |||
298 | op.arg1.mfn = pa >> PAGE_SHIFT; | 298 | op.arg1.mfn = pa >> PAGE_SHIFT; | |
299 | op.cmd = lvl; | 299 | op.cmd = lvl; | |
300 | 300 | |||
301 | if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0) | 301 | if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0) | |
302 | panic("xpq_queue_pin_table"); | 302 | panic("xpq_queue_pin_table"); | |
303 | } | 303 | } | |
304 | 304 | |||
305 | void | 305 | void | |
306 | xpq_queue_unpin_table(paddr_t pa) | 306 | xpq_queue_unpin_table(paddr_t pa) | |
307 | { | 307 | { | |
308 | struct mmuext_op op; | 308 | struct mmuext_op op; | |
309 | 309 | |||
310 | xpq_flush_queue(); | 310 | xpq_flush_queue(); | |
311 | 311 | |||
312 | XENPRINTK2(("xpq_queue_unpin_table: %#" PRIxPADDR "\n", pa)); | 312 | XENPRINTK2(("xpq_queue_unpin_table: %#" PRIxPADDR "\n", pa)); | |
313 | op.arg1.mfn = pa >> PAGE_SHIFT; | 313 | op.arg1.mfn = pa >> PAGE_SHIFT; | |
314 | op.cmd = MMUEXT_UNPIN_TABLE; | 314 | op.cmd = MMUEXT_UNPIN_TABLE; | |
315 | if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0) | 315 | if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0) | |
316 | panic("xpq_queue_unpin_table"); | 316 | panic("xpq_queue_unpin_table"); | |
317 | } | 317 | } | |
318 | 318 | |||
319 | void | 319 | void | |
320 | xpq_queue_set_ldt(vaddr_t va, uint32_t entries) | 320 | xpq_queue_set_ldt(vaddr_t va, uint32_t entries) | |
321 | { | 321 | { | |
322 | struct mmuext_op op; | 322 | struct mmuext_op op; | |
323 | 323 | |||
324 | xpq_flush_queue(); | 324 | xpq_flush_queue(); | |
325 | 325 | |||
326 | XENPRINTK2(("xpq_queue_set_ldt\n")); | 326 | XENPRINTK2(("xpq_queue_set_ldt\n")); | |
327 | KASSERT(va == (va & ~PAGE_MASK)); | 327 | KASSERT(va == (va & ~PAGE_MASK)); | |
328 | op.cmd = MMUEXT_SET_LDT; | 328 | op.cmd = MMUEXT_SET_LDT; | |
329 | op.arg1.linear_addr = va; | 329 | op.arg1.linear_addr = va; | |
330 | op.arg2.nr_ents = entries; | 330 | op.arg2.nr_ents = entries; | |
331 | if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0) | 331 | if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0) | |
332 | panic("xpq_queue_set_ldt"); | 332 | panic("xpq_queue_set_ldt"); | |
333 | } | 333 | } | |
334 | 334 | |||
335 | void | 335 | void | |
336 | xpq_queue_tlb_flush(void) | 336 | xpq_queue_tlb_flush(void) | |
337 | { | 337 | { | |
338 | struct mmuext_op op; | 338 | struct mmuext_op op; | |
339 | 339 | |||
340 | xpq_flush_queue(); | 340 | xpq_flush_queue(); | |
341 | 341 | |||
342 | XENPRINTK2(("xpq_queue_tlb_flush\n")); | 342 | XENPRINTK2(("xpq_queue_tlb_flush\n")); | |
343 | op.cmd = MMUEXT_TLB_FLUSH_LOCAL; | 343 | op.cmd = MMUEXT_TLB_FLUSH_LOCAL; | |
344 | if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0) | 344 | if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0) | |
345 | panic("xpq_queue_tlb_flush"); | 345 | panic("xpq_queue_tlb_flush"); | |
346 | } | 346 | } | |
347 | 347 | |||
348 | void | 348 | void | |
349 | xpq_flush_cache(void) | 349 | xpq_flush_cache(void) | |
350 | { | 350 | { | |
351 | struct mmuext_op op; | 351 | struct mmuext_op op; | |
352 | int s = splvm(), err; | 352 | int s = splvm(), err; | |
353 | 353 | |||
354 | xpq_flush_queue(); | 354 | xpq_flush_queue(); | |
355 | 355 | |||
356 | XENPRINTK2(("xpq_queue_flush_cache\n")); | 356 | XENPRINTK2(("xpq_queue_flush_cache\n")); | |
357 | op.cmd = MMUEXT_FLUSH_CACHE; | 357 | op.cmd = MMUEXT_FLUSH_CACHE; | |
358 | if ((err = HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF)) < 0) { | 358 | if ((err = HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF)) < 0) { | |
359 | panic("xpq_flush_cache, err %d", err); | 359 | panic("xpq_flush_cache, err %d", err); | |
360 | } | 360 | } | |
361 | splx(s); /* XXX: removeme */ | 361 | splx(s); /* XXX: removeme */ | |
362 | } | 362 | } | |
363 | 363 | |||
364 | void | 364 | void | |
365 | xpq_queue_invlpg(vaddr_t va) | 365 | xpq_queue_invlpg(vaddr_t va) | |
366 | { | 366 | { | |
367 | struct mmuext_op op; | 367 | struct mmuext_op op; | |
368 | xpq_flush_queue(); | 368 | xpq_flush_queue(); | |
369 | 369 | |||
370 | XENPRINTK2(("xpq_queue_invlpg %#" PRIxVADDR "\n", va)); | 370 | XENPRINTK2(("xpq_queue_invlpg %#" PRIxVADDR "\n", va)); | |
371 | op.cmd = MMUEXT_INVLPG_LOCAL; | 371 | op.cmd = MMUEXT_INVLPG_LOCAL; | |
372 | op.arg1.linear_addr = (va & ~PAGE_MASK); | 372 | op.arg1.linear_addr = (va & ~PAGE_MASK); | |
373 | if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0) | 373 | if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0) | |
374 | panic("xpq_queue_invlpg"); | 374 | panic("xpq_queue_invlpg"); | |
375 | } | 375 | } | |
376 | 376 | |||
377 | void | 377 | void | |
378 | xen_mcast_invlpg(vaddr_t va, kcpuset_t *kc) | 378 | xen_mcast_invlpg(vaddr_t va, kcpuset_t *kc) | |
379 | { | 379 | { | |
380 | xcpumask_t xcpumask; | 380 | xcpumask_t xcpumask; | |
381 | mmuext_op_t op; | 381 | mmuext_op_t op; | |
382 | 382 | |||
383 | kcpuset_copybits(kc, &xcpumask.xcpum_km[0], sizeof(xcpumask)); | 383 | kcpuset_export_u32(kc, &xcpumask.xcpum_km[0], sizeof(xcpumask)); | |
384 | 384 | |||
385 | /* Flush pending page updates */ | 385 | /* Flush pending page updates */ | |
386 | xpq_flush_queue(); | 386 | xpq_flush_queue(); | |
387 | 387 | |||
388 | op.cmd = MMUEXT_INVLPG_MULTI; | 388 | op.cmd = MMUEXT_INVLPG_MULTI; | |
389 | op.arg1.linear_addr = va; | 389 | op.arg1.linear_addr = va; | |
390 | op.arg2.vcpumask = &xcpumask.xcpum_xm; | 390 | op.arg2.vcpumask = &xcpumask.xcpum_xm; | |
391 | 391 | |||
392 | if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0) { | 392 | if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0) { | |
393 | panic("xpq_queue_invlpg_all"); | 393 | panic("xpq_queue_invlpg_all"); | |
394 | } | 394 | } | |
395 | 395 | |||
396 | return; | 396 | return; | |
397 | } | 397 | } | |
398 | 398 | |||
399 | void | 399 | void | |
400 | xen_bcast_invlpg(vaddr_t va) | 400 | xen_bcast_invlpg(vaddr_t va) | |
401 | { | 401 | { | |
402 | mmuext_op_t op; | 402 | mmuext_op_t op; | |
403 | 403 | |||
404 | /* Flush pending page updates */ | 404 | /* Flush pending page updates */ | |
405 | xpq_flush_queue(); | 405 | xpq_flush_queue(); | |
406 | 406 | |||
407 | op.cmd = MMUEXT_INVLPG_ALL; | 407 | op.cmd = MMUEXT_INVLPG_ALL; | |
408 | op.arg1.linear_addr = va; | 408 | op.arg1.linear_addr = va; | |
409 | 409 | |||
410 | if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0) { | 410 | if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0) { | |
411 | panic("xpq_queue_invlpg_all"); | 411 | panic("xpq_queue_invlpg_all"); | |
412 | } | 412 | } | |
413 | 413 | |||
414 | return; | 414 | return; | |
415 | } | 415 | } | |
416 | 416 | |||
417 | /* This is a synchronous call. */ | 417 | /* This is a synchronous call. */ | |
418 | void | 418 | void | |
419 | xen_mcast_tlbflush(kcpuset_t *kc) | 419 | xen_mcast_tlbflush(kcpuset_t *kc) | |
420 | { | 420 | { | |
421 | xcpumask_t xcpumask; | 421 | xcpumask_t xcpumask; | |
422 | mmuext_op_t op; | 422 | mmuext_op_t op; | |
423 | 423 | |||
424 | kcpuset_copybits(kc, &xcpumask.xcpum_km[0], sizeof(xcpumask)); | 424 | kcpuset_export_u32(kc, &xcpumask.xcpum_km[0], sizeof(xcpumask)); | |
425 | 425 | |||
426 | /* Flush pending page updates */ | 426 | /* Flush pending page updates */ | |
427 | xpq_flush_queue(); | 427 | xpq_flush_queue(); | |
428 | 428 | |||
429 | op.cmd = MMUEXT_TLB_FLUSH_MULTI; | 429 | op.cmd = MMUEXT_TLB_FLUSH_MULTI; | |
430 | op.arg2.vcpumask = &xcpumask.xcpum_xm; | 430 | op.arg2.vcpumask = &xcpumask.xcpum_xm; | |
431 | 431 | |||
432 | if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0) { | 432 | if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0) { | |
433 | panic("xpq_queue_invlpg_all"); | 433 | panic("xpq_queue_invlpg_all"); | |
434 | } | 434 | } | |
435 | 435 | |||
436 | return; | 436 | return; | |
437 | } | 437 | } | |
438 | 438 | |||
439 | /* This is a synchronous call. */ | 439 | /* This is a synchronous call. */ | |
440 | void | 440 | void | |
441 | xen_bcast_tlbflush(void) | 441 | xen_bcast_tlbflush(void) | |
442 | { | 442 | { | |
443 | mmuext_op_t op; | 443 | mmuext_op_t op; | |
444 | 444 | |||
445 | /* Flush pending page updates */ | 445 | /* Flush pending page updates */ | |
446 | xpq_flush_queue(); | 446 | xpq_flush_queue(); | |
447 | 447 | |||
448 | op.cmd = MMUEXT_TLB_FLUSH_ALL; | 448 | op.cmd = MMUEXT_TLB_FLUSH_ALL; | |
449 | 449 | |||
450 | if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0) { | 450 | if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0) { | |
451 | panic("xpq_queue_invlpg_all"); | 451 | panic("xpq_queue_invlpg_all"); | |
452 | } | 452 | } | |
453 | 453 | |||
454 | return; | 454 | return; | |
455 | } | 455 | } | |
456 | 456 | |||
457 | /* This is a synchronous call. */ | 457 | /* This is a synchronous call. */ | |
458 | void | 458 | void | |
459 | xen_vcpu_mcast_invlpg(vaddr_t sva, vaddr_t eva, kcpuset_t *kc) | 459 | xen_vcpu_mcast_invlpg(vaddr_t sva, vaddr_t eva, kcpuset_t *kc) | |
460 | { | 460 | { | |
461 | KASSERT(eva > sva); | 461 | KASSERT(eva > sva); | |
462 | 462 | |||
463 | /* Flush pending page updates */ | 463 | /* Flush pending page updates */ | |
464 | xpq_flush_queue(); | 464 | xpq_flush_queue(); | |
465 | 465 | |||
466 | /* Align to nearest page boundary */ | 466 | /* Align to nearest page boundary */ | |
467 | sva &= ~PAGE_MASK; | 467 | sva &= ~PAGE_MASK; | |
468 | eva &= ~PAGE_MASK; | 468 | eva &= ~PAGE_MASK; | |
469 | 469 | |||
470 | for ( ; sva <= eva; sva += PAGE_SIZE) { | 470 | for ( ; sva <= eva; sva += PAGE_SIZE) { | |
471 | xen_mcast_invlpg(sva, kc); | 471 | xen_mcast_invlpg(sva, kc); | |
472 | } | 472 | } | |
473 | 473 | |||
474 | return; | 474 | return; | |
475 | } | 475 | } | |
476 | 476 | |||
477 | /* This is a synchronous call. */ | 477 | /* This is a synchronous call. */ | |
478 | void | 478 | void | |
479 | xen_vcpu_bcast_invlpg(vaddr_t sva, vaddr_t eva) | 479 | xen_vcpu_bcast_invlpg(vaddr_t sva, vaddr_t eva) | |
480 | { | 480 | { | |
481 | KASSERT(eva > sva); | 481 | KASSERT(eva > sva); | |
482 | 482 | |||
483 | /* Flush pending page updates */ | 483 | /* Flush pending page updates */ | |
484 | xpq_flush_queue(); | 484 | xpq_flush_queue(); | |
485 | 485 | |||
486 | /* Align to nearest page boundary */ | 486 | /* Align to nearest page boundary */ | |
487 | sva &= ~PAGE_MASK; | 487 | sva &= ~PAGE_MASK; | |
488 | eva &= ~PAGE_MASK; | 488 | eva &= ~PAGE_MASK; | |
489 | 489 | |||
490 | for ( ; sva <= eva; sva += PAGE_SIZE) { | 490 | for ( ; sva <= eva; sva += PAGE_SIZE) { | |
491 | xen_bcast_invlpg(sva); | 491 | xen_bcast_invlpg(sva); | |
492 | } | 492 | } | |
493 | 493 | |||
494 | return; | 494 | return; | |
495 | } | 495 | } | |
496 | 496 | |||
497 | int | 497 | int | |
498 | xpq_update_foreign(paddr_t ptr, pt_entry_t val, int dom) | 498 | xpq_update_foreign(paddr_t ptr, pt_entry_t val, int dom) | |
499 | { | 499 | { | |
500 | mmu_update_t op; | 500 | mmu_update_t op; | |
501 | int ok; | 501 | int ok; | |
502 | 502 | |||
503 | xpq_flush_queue(); | 503 | xpq_flush_queue(); | |
504 | 504 | |||
505 | op.ptr = ptr; | 505 | op.ptr = ptr; | |
506 | op.val = val; | 506 | op.val = val; | |
507 | if (HYPERVISOR_mmu_update(&op, 1, &ok, dom) < 0) | 507 | if (HYPERVISOR_mmu_update(&op, 1, &ok, dom) < 0) | |
508 | return EFAULT; | 508 | return EFAULT; | |
509 | return (0); | 509 | return (0); | |
510 | } | 510 | } | |
511 | 511 | |||
512 | #ifdef XENDEBUG | 512 | #ifdef XENDEBUG | |
513 | void | 513 | void | |
514 | xpq_debug_dump(void) | 514 | xpq_debug_dump(void) | |
515 | { | 515 | { | |
516 | int i; | 516 | int i; | |
517 | 517 | |||
518 | mmu_update_t *xpq_queue = xpq_queue_array[curcpu()->ci_cpuid]; | 518 | mmu_update_t *xpq_queue = xpq_queue_array[curcpu()->ci_cpuid]; | |
519 | int xpq_idx = xpq_idx_array[curcpu()->ci_cpuid]; | 519 | int xpq_idx = xpq_idx_array[curcpu()->ci_cpuid]; | |
520 | 520 | |||
521 | XENPRINTK2(("idx: %d\n", xpq_idx)); | 521 | XENPRINTK2(("idx: %d\n", xpq_idx)); | |
522 | for (i = 0; i < xpq_idx; i++) { | 522 | for (i = 0; i < xpq_idx; i++) { | |
523 | snprintf(XBUF, sizeof(XBUF), "%" PRIx64 " %08" PRIx64, | 523 | snprintf(XBUF, sizeof(XBUF), "%" PRIx64 " %08" PRIx64, | |
524 | xpq_queue[i].ptr, xpq_queue[i].val); | 524 | xpq_queue[i].ptr, xpq_queue[i].val); | |
525 | if (++i < xpq_idx) | 525 | if (++i < xpq_idx) | |
526 | snprintf(XBUF + strlen(XBUF), | 526 | snprintf(XBUF + strlen(XBUF), | |
527 | sizeof(XBUF) - strlen(XBUF), | 527 | sizeof(XBUF) - strlen(XBUF), | |
528 | "%" PRIx64 " %08" PRIx64, | 528 | "%" PRIx64 " %08" PRIx64, | |
529 | xpq_queue[i].ptr, xpq_queue[i].val); | 529 | xpq_queue[i].ptr, xpq_queue[i].val); | |
530 | if (++i < xpq_idx) | 530 | if (++i < xpq_idx) | |
531 | snprintf(XBUF + strlen(XBUF), | 531 | snprintf(XBUF + strlen(XBUF), | |
532 | sizeof(XBUF) - strlen(XBUF), | 532 | sizeof(XBUF) - strlen(XBUF), | |
533 | "%" PRIx64 " %08" PRIx64, | 533 | "%" PRIx64 " %08" PRIx64, | |
534 | xpq_queue[i].ptr, xpq_queue[i].val); | 534 | xpq_queue[i].ptr, xpq_queue[i].val); | |
535 | if (++i < xpq_idx) | 535 | if (++i < xpq_idx) | |
536 | snprintf(XBUF + strlen(XBUF), | 536 | snprintf(XBUF + strlen(XBUF), | |
537 | sizeof(XBUF) - strlen(XBUF), | 537 | sizeof(XBUF) - strlen(XBUF), | |
538 | "%" PRIx64 " %08" PRIx64, | 538 | "%" PRIx64 " %08" PRIx64, | |
539 | xpq_queue[i].ptr, xpq_queue[i].val); | 539 | xpq_queue[i].ptr, xpq_queue[i].val); | |
540 | XENPRINTK2(("%d: %s\n", xpq_idx, XBUF)); | 540 | XENPRINTK2(("%d: %s\n", xpq_idx, XBUF)); | |
541 | } | 541 | } | |
542 | } | 542 | } | |
543 | #endif | 543 | #endif | |
544 | 544 | |||
545 | 545 | |||
546 | extern volatile struct xencons_interface *xencons_interface; /* XXX */ | 546 | extern volatile struct xencons_interface *xencons_interface; /* XXX */ | |
547 | extern struct xenstore_domain_interface *xenstore_interface; /* XXX */ | 547 | extern struct xenstore_domain_interface *xenstore_interface; /* XXX */ | |
548 | 548 | |||
549 | static void xen_bt_set_readonly (vaddr_t); | 549 | static void xen_bt_set_readonly (vaddr_t); | |
550 | static void xen_bootstrap_tables (vaddr_t, vaddr_t, int, int, int); | 550 | static void xen_bootstrap_tables (vaddr_t, vaddr_t, int, int, int); | |
551 | 551 | |||
552 | /* How many PDEs ? */ | 552 | /* How many PDEs ? */ | |
553 | #if L2_SLOT_KERNBASE > 0 | 553 | #if L2_SLOT_KERNBASE > 0 | |
554 | #define TABLE_L2_ENTRIES (2 * (NKL2_KIMG_ENTRIES + 1)) | 554 | #define TABLE_L2_ENTRIES (2 * (NKL2_KIMG_ENTRIES + 1)) | |
555 | #else | 555 | #else | |
556 | #define TABLE_L2_ENTRIES (NKL2_KIMG_ENTRIES + 1) | 556 | #define TABLE_L2_ENTRIES (NKL2_KIMG_ENTRIES + 1) | |
557 | #endif | 557 | #endif | |
558 | 558 | |||
559 | /* | 559 | /* | |
560 | * Construct and switch to new pagetables | 560 | * Construct and switch to new pagetables | |
561 | * first_avail is the first vaddr we can use after | 561 | * first_avail is the first vaddr we can use after | |
562 | * we get rid of Xen pagetables | 562 | * we get rid of Xen pagetables | |
563 | */ | 563 | */ | |
564 | 564 | |||
565 | vaddr_t xen_pmap_bootstrap (void); | 565 | vaddr_t xen_pmap_bootstrap (void); | |
566 | 566 | |||
567 | /* | 567 | /* | |
568 | * Function to get rid of Xen bootstrap tables | 568 | * Function to get rid of Xen bootstrap tables | |
569 | */ | 569 | */ | |
570 | 570 | |||
571 | /* How many PDP do we need: */ | 571 | /* How many PDP do we need: */ | |
572 | #ifdef PAE | 572 | #ifdef PAE | |
573 | /* | 573 | /* | |
574 | * For PAE, we consider a single contigous L2 "superpage" of 4 pages, | 574 | * For PAE, we consider a single contigous L2 "superpage" of 4 pages, | |
575 | * all of them mapped by the L3 page. We also need a shadow page | 575 | * all of them mapped by the L3 page. We also need a shadow page | |
576 | * for L3[3]. | 576 | * for L3[3]. | |
577 | */ | 577 | */ | |
578 | static const int l2_4_count = 6; | 578 | static const int l2_4_count = 6; | |
579 | #elif defined(__x86_64__) | 579 | #elif defined(__x86_64__) | |
580 | static const int l2_4_count = PTP_LEVELS; | 580 | static const int l2_4_count = PTP_LEVELS; | |
581 | #else | 581 | #else | |
582 | static const int l2_4_count = PTP_LEVELS - 1; | 582 | static const int l2_4_count = PTP_LEVELS - 1; | |
583 | #endif | 583 | #endif | |
584 | 584 | |||
585 | vaddr_t | 585 | vaddr_t | |
586 | xen_pmap_bootstrap(void) | 586 | xen_pmap_bootstrap(void) | |
587 | { | 587 | { | |
588 | int count, oldcount; | 588 | int count, oldcount; | |
589 | long mapsize; | 589 | long mapsize; | |
590 | vaddr_t bootstrap_tables, init_tables; | 590 | vaddr_t bootstrap_tables, init_tables; | |
591 | 591 | |||
592 | memset(xpq_idx_array, 0, sizeof xpq_idx_array); | 592 | memset(xpq_idx_array, 0, sizeof xpq_idx_array); | |
593 | 593 | |||
594 | xpmap_phys_to_machine_mapping = | 594 | xpmap_phys_to_machine_mapping = | |
595 | (unsigned long *)xen_start_info.mfn_list; | 595 | (unsigned long *)xen_start_info.mfn_list; | |
596 | init_tables = xen_start_info.pt_base; | 596 | init_tables = xen_start_info.pt_base; | |
597 | __PRINTK(("xen_arch_pmap_bootstrap init_tables=0x%lx\n", init_tables)); | 597 | __PRINTK(("xen_arch_pmap_bootstrap init_tables=0x%lx\n", init_tables)); | |
598 | 598 | |||
599 | /* Space after Xen boostrap tables should be free */ | 599 | /* Space after Xen boostrap tables should be free */ | |
600 | bootstrap_tables = xen_start_info.pt_base + | 600 | bootstrap_tables = xen_start_info.pt_base + | |
601 | (xen_start_info.nr_pt_frames * PAGE_SIZE); | 601 | (xen_start_info.nr_pt_frames * PAGE_SIZE); | |
602 | 602 | |||
603 | /* | 603 | /* | |
604 | * Calculate how many space we need | 604 | * Calculate how many space we need | |
605 | * first everything mapped before the Xen bootstrap tables | 605 | * first everything mapped before the Xen bootstrap tables | |
606 | */ | 606 | */ | |
607 | mapsize = init_tables - KERNTEXTOFF; | 607 | mapsize = init_tables - KERNTEXTOFF; | |
608 | /* after the tables we'll have: | 608 | /* after the tables we'll have: | |
609 | * - UAREA | 609 | * - UAREA | |
610 | * - dummy user PGD (x86_64) | 610 | * - dummy user PGD (x86_64) | |
611 | * - HYPERVISOR_shared_info | 611 | * - HYPERVISOR_shared_info | |
612 | * - early_zerop | 612 | * - early_zerop | |
613 | * - ISA I/O mem (if needed) | 613 | * - ISA I/O mem (if needed) | |
614 | */ | 614 | */ | |
615 | mapsize += UPAGES * NBPG; | 615 | mapsize += UPAGES * NBPG; | |
616 | #ifdef __x86_64__ | 616 | #ifdef __x86_64__ | |
617 | mapsize += NBPG; | 617 | mapsize += NBPG; | |
618 | #endif | 618 | #endif | |
619 | mapsize += NBPG; | 619 | mapsize += NBPG; | |
620 | mapsize += NBPG; | 620 | mapsize += NBPG; | |
621 | 621 | |||
622 | #ifdef DOM0OPS | 622 | #ifdef DOM0OPS | |
623 | if (xendomain_is_dom0()) { | 623 | if (xendomain_is_dom0()) { | |
624 | /* space for ISA I/O mem */ | 624 | /* space for ISA I/O mem */ | |
625 | mapsize += IOM_SIZE; | 625 | mapsize += IOM_SIZE; | |
626 | } | 626 | } | |
627 | #endif | 627 | #endif | |
628 | /* at this point mapsize doens't include the table size */ | 628 | /* at this point mapsize doens't include the table size */ | |
629 | 629 | |||
630 | #ifdef __x86_64__ | 630 | #ifdef __x86_64__ | |
631 | count = TABLE_L2_ENTRIES; | 631 | count = TABLE_L2_ENTRIES; | |
632 | #else | 632 | #else | |
633 | count = (mapsize + (NBPD_L2 -1)) >> L2_SHIFT; | 633 | count = (mapsize + (NBPD_L2 -1)) >> L2_SHIFT; | |
634 | #endif /* __x86_64__ */ | 634 | #endif /* __x86_64__ */ | |
635 | 635 | |||
636 | /* now compute how many L2 pages we need exactly */ | 636 | /* now compute how many L2 pages we need exactly */ | |
637 | XENPRINTK(("bootstrap_final mapsize 0x%lx count %d\n", mapsize, count)); | 637 | XENPRINTK(("bootstrap_final mapsize 0x%lx count %d\n", mapsize, count)); | |
638 | while (mapsize + (count + l2_4_count) * PAGE_SIZE + KERNTEXTOFF > | 638 | while (mapsize + (count + l2_4_count) * PAGE_SIZE + KERNTEXTOFF > | |
639 | ((long)count << L2_SHIFT) + KERNBASE) { | 639 | ((long)count << L2_SHIFT) + KERNBASE) { | |
640 | count++; | 640 | count++; | |
641 | } | 641 | } | |
642 | #ifndef __x86_64__ | 642 | #ifndef __x86_64__ | |
643 | /* | 643 | /* | |
644 | * one more L2 page: we'll alocate several pages after kva_start | 644 | * one more L2 page: we'll alocate several pages after kva_start | |
645 | * in pmap_bootstrap() before pmap_growkernel(), which have not been | 645 | * in pmap_bootstrap() before pmap_growkernel(), which have not been | |
646 | * counted here. It's not a big issue to allocate one more L2 as | 646 | * counted here. It's not a big issue to allocate one more L2 as | |
647 | * pmap_growkernel() will be called anyway. | 647 | * pmap_growkernel() will be called anyway. | |
648 | */ | 648 | */ | |
649 | count++; | 649 | count++; | |
650 | nkptp[1] = count; | 650 | nkptp[1] = count; | |
651 | #endif | 651 | #endif | |
652 | 652 | |||
653 | /* | 653 | /* | |
654 | * install bootstrap pages. We may need more L2 pages than will | 654 | * install bootstrap pages. We may need more L2 pages than will | |
655 | * have the final table here, as it's installed after the final table | 655 | * have the final table here, as it's installed after the final table | |
656 | */ | 656 | */ | |
657 | oldcount = count; | 657 | oldcount = count; | |
658 | 658 | |||
659 | bootstrap_again: | 659 | bootstrap_again: | |
660 | XENPRINTK(("bootstrap_again oldcount %d\n", oldcount)); | 660 | XENPRINTK(("bootstrap_again oldcount %d\n", oldcount)); | |
661 | /* | 661 | /* | |
662 | * Xen space we'll reclaim may not be enough for our new page tables, | 662 | * Xen space we'll reclaim may not be enough for our new page tables, | |
663 | * move bootstrap tables if necessary | 663 | * move bootstrap tables if necessary | |
664 | */ | 664 | */ | |
665 | if (bootstrap_tables < init_tables + ((count + l2_4_count) * PAGE_SIZE)) | 665 | if (bootstrap_tables < init_tables + ((count + l2_4_count) * PAGE_SIZE)) | |
666 | bootstrap_tables = init_tables + | 666 | bootstrap_tables = init_tables + | |
667 | ((count + l2_4_count) * PAGE_SIZE); | 667 | ((count + l2_4_count) * PAGE_SIZE); | |
668 | /* make sure we have enough to map the bootstrap_tables */ | 668 | /* make sure we have enough to map the bootstrap_tables */ | |
669 | if (bootstrap_tables + ((oldcount + l2_4_count) * PAGE_SIZE) > | 669 | if (bootstrap_tables + ((oldcount + l2_4_count) * PAGE_SIZE) > | |
670 | ((long)oldcount << L2_SHIFT) + KERNBASE) { | 670 | ((long)oldcount << L2_SHIFT) + KERNBASE) { | |
671 | oldcount++; | 671 | oldcount++; | |
672 | goto bootstrap_again; | 672 | goto bootstrap_again; | |
673 | } | 673 | } | |
674 | 674 | |||
675 | /* Create temporary tables */ | 675 | /* Create temporary tables */ | |
676 | xen_bootstrap_tables(xen_start_info.pt_base, bootstrap_tables, | 676 | xen_bootstrap_tables(xen_start_info.pt_base, bootstrap_tables, | |
677 | xen_start_info.nr_pt_frames, oldcount, 0); | 677 | xen_start_info.nr_pt_frames, oldcount, 0); | |
678 | 678 | |||
679 | /* Create final tables */ | 679 | /* Create final tables */ | |
680 | xen_bootstrap_tables(bootstrap_tables, init_tables, | 680 | xen_bootstrap_tables(bootstrap_tables, init_tables, | |
681 | oldcount + l2_4_count, count, 1); | 681 | oldcount + l2_4_count, count, 1); | |
682 | 682 | |||
683 | /* zero out free space after tables */ | 683 | /* zero out free space after tables */ | |
684 | memset((void *)(init_tables + ((count + l2_4_count) * PAGE_SIZE)), 0, | 684 | memset((void *)(init_tables + ((count + l2_4_count) * PAGE_SIZE)), 0, | |
685 | (UPAGES + 1) * NBPG); | 685 | (UPAGES + 1) * NBPG); | |
686 | 686 | |||
687 | /* Finally, flush TLB. */ | 687 | /* Finally, flush TLB. */ | |
688 | xpq_queue_tlb_flush(); | 688 | xpq_queue_tlb_flush(); | |
689 | 689 | |||
690 | return (init_tables + ((count + l2_4_count) * PAGE_SIZE)); | 690 | return (init_tables + ((count + l2_4_count) * PAGE_SIZE)); | |
691 | } | 691 | } | |
692 | 692 | |||
693 | /* | 693 | /* | |
694 | * Build a new table and switch to it | 694 | * Build a new table and switch to it | |
695 | * old_count is # of old tables (including PGD, PDTPE and PDE) | 695 | * old_count is # of old tables (including PGD, PDTPE and PDE) | |
696 | * new_count is # of new tables (PTE only) | 696 | * new_count is # of new tables (PTE only) | |
697 | * we assume areas don't overlap | 697 | * we assume areas don't overlap | |
698 | */ | 698 | */ | |
699 | static void | 699 | static void | |
700 | xen_bootstrap_tables (vaddr_t old_pgd, vaddr_t new_pgd, | 700 | xen_bootstrap_tables (vaddr_t old_pgd, vaddr_t new_pgd, | |
701 | int old_count, int new_count, int final) | 701 | int old_count, int new_count, int final) | |
702 | { | 702 | { | |
703 | pd_entry_t *pdtpe, *pde, *pte; | 703 | pd_entry_t *pdtpe, *pde, *pte; | |
704 | pd_entry_t *cur_pgd, *bt_pgd; | 704 | pd_entry_t *cur_pgd, *bt_pgd; | |
705 | paddr_t addr; | 705 | paddr_t addr; | |
706 | vaddr_t page, avail, text_end, map_end; | 706 | vaddr_t page, avail, text_end, map_end; | |
707 | int i; | 707 | int i; | |
708 | extern char __data_start; | 708 | extern char __data_start; | |
709 | extern char *early_zerop; /* from pmap.c */ | 709 | extern char *early_zerop; /* from pmap.c */ | |
710 | 710 | |||
711 | __PRINTK(("xen_bootstrap_tables(%#" PRIxVADDR ", %#" PRIxVADDR "," | 711 | __PRINTK(("xen_bootstrap_tables(%#" PRIxVADDR ", %#" PRIxVADDR "," | |
712 | " %d, %d)\n", | 712 | " %d, %d)\n", | |
713 | old_pgd, new_pgd, old_count, new_count)); | 713 | old_pgd, new_pgd, old_count, new_count)); | |
714 | text_end = ((vaddr_t)&__data_start) & ~PAGE_MASK; | 714 | text_end = ((vaddr_t)&__data_start) & ~PAGE_MASK; | |
715 | /* | 715 | /* | |
716 | * size of R/W area after kernel text: | 716 | * size of R/W area after kernel text: | |
717 | * xencons_interface (if present) | 717 | * xencons_interface (if present) | |
718 | * xenstore_interface (if present) | 718 | * xenstore_interface (if present) | |
719 | * table pages (new_count + l2_4_count entries) | 719 | * table pages (new_count + l2_4_count entries) | |
720 | * extra mappings (only when final is true): | 720 | * extra mappings (only when final is true): | |
721 | * UAREA | 721 | * UAREA | |
722 | * dummy user PGD (x86_64 only)/gdt page (i386 only) | 722 | * dummy user PGD (x86_64 only)/gdt page (i386 only) | |
723 | * HYPERVISOR_shared_info | 723 | * HYPERVISOR_shared_info | |
724 | * early_zerop | 724 | * early_zerop | |
725 | * ISA I/O mem (if needed) | 725 | * ISA I/O mem (if needed) | |
726 | */ | 726 | */ | |
727 | map_end = new_pgd + ((new_count + l2_4_count) * NBPG); | 727 | map_end = new_pgd + ((new_count + l2_4_count) * NBPG); | |
728 | if (final) { | 728 | if (final) { | |
729 | map_end += (UPAGES + 1) * NBPG; | 729 | map_end += (UPAGES + 1) * NBPG; | |
730 | HYPERVISOR_shared_info = (shared_info_t *)map_end; | 730 | HYPERVISOR_shared_info = (shared_info_t *)map_end; | |
731 | map_end += NBPG; | 731 | map_end += NBPG; | |
732 | early_zerop = (char *)map_end; | 732 | early_zerop = (char *)map_end; | |
733 | map_end += NBPG; | 733 | map_end += NBPG; | |
734 | } | 734 | } | |
735 | /* | 735 | /* | |
736 | * we always set atdevbase, as it's used by init386 to find the first | 736 | * we always set atdevbase, as it's used by init386 to find the first | |
737 | * available VA. map_end is updated only if we are dom0, so | 737 | * available VA. map_end is updated only if we are dom0, so | |
738 | * atdevbase -> atdevbase + IOM_SIZE will be mapped only in | 738 | * atdevbase -> atdevbase + IOM_SIZE will be mapped only in | |
739 | * this case. | 739 | * this case. | |
740 | */ | 740 | */ | |
741 | if (final) | 741 | if (final) | |
742 | atdevbase = map_end; | 742 | atdevbase = map_end; | |
743 | #ifdef DOM0OPS | 743 | #ifdef DOM0OPS | |
744 | if (final && xendomain_is_dom0()) { | 744 | if (final && xendomain_is_dom0()) { | |
745 | /* ISA I/O mem */ | 745 | /* ISA I/O mem */ | |
746 | map_end += IOM_SIZE; | 746 | map_end += IOM_SIZE; | |
747 | } | 747 | } | |
748 | #endif /* DOM0OPS */ | 748 | #endif /* DOM0OPS */ | |
749 | 749 | |||
750 | __PRINTK(("xen_bootstrap_tables text_end 0x%lx map_end 0x%lx\n", | 750 | __PRINTK(("xen_bootstrap_tables text_end 0x%lx map_end 0x%lx\n", | |
751 | text_end, map_end)); | 751 | text_end, map_end)); | |
752 | __PRINTK(("console %#lx ", xen_start_info.console_mfn)); | 752 | __PRINTK(("console %#lx ", xen_start_info.console_mfn)); | |
753 | __PRINTK(("xenstore %#" PRIx32 "\n", xen_start_info.store_mfn)); | 753 | __PRINTK(("xenstore %#" PRIx32 "\n", xen_start_info.store_mfn)); | |
754 | 754 | |||
755 | /* | 755 | /* | |
756 | * Create bootstrap page tables | 756 | * Create bootstrap page tables | |
757 | * What we need: | 757 | * What we need: | |
758 | * - a PGD (level 4) | 758 | * - a PGD (level 4) | |
759 | * - a PDTPE (level 3) | 759 | * - a PDTPE (level 3) | |
760 | * - a PDE (level2) | 760 | * - a PDE (level2) | |
761 | * - some PTEs (level 1) | 761 | * - some PTEs (level 1) | |
762 | */ | 762 | */ | |
763 | 763 | |||
764 | cur_pgd = (pd_entry_t *) old_pgd; | 764 | cur_pgd = (pd_entry_t *) old_pgd; | |
765 | bt_pgd = (pd_entry_t *) new_pgd; | 765 | bt_pgd = (pd_entry_t *) new_pgd; | |
766 | memset (bt_pgd, 0, PAGE_SIZE); | 766 | memset (bt_pgd, 0, PAGE_SIZE); | |
767 | avail = new_pgd + PAGE_SIZE; | 767 | avail = new_pgd + PAGE_SIZE; | |
768 | #if PTP_LEVELS > 3 | 768 | #if PTP_LEVELS > 3 | |
769 | /* per-cpu L4 PD */ | 769 | /* per-cpu L4 PD */ | |
770 | pd_entry_t *bt_cpu_pgd = bt_pgd; | 770 | pd_entry_t *bt_cpu_pgd = bt_pgd; | |
771 | /* pmap_kernel() "shadow" L4 PD */ | 771 | /* pmap_kernel() "shadow" L4 PD */ | |
772 | bt_pgd = (pd_entry_t *) avail; | 772 | bt_pgd = (pd_entry_t *) avail; | |
773 | memset(bt_pgd, 0, PAGE_SIZE); | 773 | memset(bt_pgd, 0, PAGE_SIZE); | |
774 | avail += PAGE_SIZE; | 774 | avail += PAGE_SIZE; | |
775 | 775 | |||
776 | /* Install level 3 */ | 776 | /* Install level 3 */ | |
777 | pdtpe = (pd_entry_t *) avail; | 777 | pdtpe = (pd_entry_t *) avail; | |
778 | memset (pdtpe, 0, PAGE_SIZE); | 778 | memset (pdtpe, 0, PAGE_SIZE); | |
779 | avail += PAGE_SIZE; | 779 | avail += PAGE_SIZE; | |
780 | 780 | |||
781 | addr = ((u_long) pdtpe) - KERNBASE; | 781 | addr = ((u_long) pdtpe) - KERNBASE; | |
782 | bt_pgd[pl4_pi(KERNTEXTOFF)] = bt_cpu_pgd[pl4_pi(KERNTEXTOFF)] = | 782 | bt_pgd[pl4_pi(KERNTEXTOFF)] = bt_cpu_pgd[pl4_pi(KERNTEXTOFF)] = | |
783 | xpmap_ptom_masked(addr) | PG_k | PG_RW | PG_V; | 783 | xpmap_ptom_masked(addr) | PG_k | PG_RW | PG_V; | |
784 | 784 | |||
785 | __PRINTK(("L3 va %#lx pa %#" PRIxPADDR " entry %#" PRIxPADDR | 785 | __PRINTK(("L3 va %#lx pa %#" PRIxPADDR " entry %#" PRIxPADDR | |
786 | " -> L4[%#x]\n", | 786 | " -> L4[%#x]\n", | |
787 | pdtpe, addr, bt_pgd[pl4_pi(KERNTEXTOFF)], pl4_pi(KERNTEXTOFF))); | 787 | pdtpe, addr, bt_pgd[pl4_pi(KERNTEXTOFF)], pl4_pi(KERNTEXTOFF))); | |
788 | #else | 788 | #else | |
789 | pdtpe = bt_pgd; | 789 | pdtpe = bt_pgd; | |
790 | #endif /* PTP_LEVELS > 3 */ | 790 | #endif /* PTP_LEVELS > 3 */ | |
791 | 791 | |||
792 | #if PTP_LEVELS > 2 | 792 | #if PTP_LEVELS > 2 | |
793 | /* Level 2 */ | 793 | /* Level 2 */ | |
794 | pde = (pd_entry_t *) avail; | 794 | pde = (pd_entry_t *) avail; | |
795 | memset(pde, 0, PAGE_SIZE); | 795 | memset(pde, 0, PAGE_SIZE); | |
796 | avail += PAGE_SIZE; | 796 | avail += PAGE_SIZE; | |
797 | 797 | |||
798 | addr = ((u_long) pde) - KERNBASE; | 798 | addr = ((u_long) pde) - KERNBASE; | |
799 | pdtpe[pl3_pi(KERNTEXTOFF)] = | 799 | pdtpe[pl3_pi(KERNTEXTOFF)] = | |
800 | xpmap_ptom_masked(addr) | PG_k | PG_V | PG_RW; | 800 | xpmap_ptom_masked(addr) | PG_k | PG_V | PG_RW; | |
801 | __PRINTK(("L2 va %#lx pa %#" PRIxPADDR " entry %#" PRIxPADDR | 801 | __PRINTK(("L2 va %#lx pa %#" PRIxPADDR " entry %#" PRIxPADDR | |
802 | " -> L3[%#x]\n", | 802 | " -> L3[%#x]\n", | |
803 | pde, addr, pdtpe[pl3_pi(KERNTEXTOFF)], pl3_pi(KERNTEXTOFF))); | 803 | pde, addr, pdtpe[pl3_pi(KERNTEXTOFF)], pl3_pi(KERNTEXTOFF))); | |
804 | #elif defined(PAE) | 804 | #elif defined(PAE) | |
805 | /* our PAE-style level 2: 5 contigous pages (4 L2 + 1 shadow) */ | 805 | /* our PAE-style level 2: 5 contigous pages (4 L2 + 1 shadow) */ | |
806 | pde = (pd_entry_t *) avail; | 806 | pde = (pd_entry_t *) avail; | |
807 | memset(pde, 0, PAGE_SIZE * 5); | 807 | memset(pde, 0, PAGE_SIZE * 5); | |
808 | avail += PAGE_SIZE * 5; | 808 | avail += PAGE_SIZE * 5; | |
809 | addr = ((u_long) pde) - KERNBASE; | 809 | addr = ((u_long) pde) - KERNBASE; | |
810 | /* | 810 | /* | |
811 | * enter L2 pages in the L3. | 811 | * enter L2 pages in the L3. | |
812 | * The real L2 kernel PD will be the last one (so that | 812 | * The real L2 kernel PD will be the last one (so that | |
813 | * pde[L2_SLOT_KERN] always point to the shadow). | 813 | * pde[L2_SLOT_KERN] always point to the shadow). | |
814 | */ | 814 | */ | |
815 | for (i = 0; i < 3; i++, addr += PAGE_SIZE) { | 815 | for (i = 0; i < 3; i++, addr += PAGE_SIZE) { | |
816 | /* | 816 | /* | |
817 | * Xen doesn't want R/W mappings in L3 entries, it'll add it | 817 | * Xen doesn't want R/W mappings in L3 entries, it'll add it | |
818 | * itself. | 818 | * itself. | |
819 | */ | 819 | */ | |
820 | pdtpe[i] = xpmap_ptom_masked(addr) | PG_k | PG_V; | 820 | pdtpe[i] = xpmap_ptom_masked(addr) | PG_k | PG_V; | |
821 | __PRINTK(("L2 va %#lx pa %#" PRIxPADDR " entry %#" PRIxPADDR | 821 | __PRINTK(("L2 va %#lx pa %#" PRIxPADDR " entry %#" PRIxPADDR | |
822 | " -> L3[%#x]\n", | 822 | " -> L3[%#x]\n", | |
823 | (vaddr_t)pde + PAGE_SIZE * i, addr, pdtpe[i], i)); | 823 | (vaddr_t)pde + PAGE_SIZE * i, addr, pdtpe[i], i)); | |
824 | } | 824 | } | |
825 | addr += PAGE_SIZE; | 825 | addr += PAGE_SIZE; | |
826 | pdtpe[3] = xpmap_ptom_masked(addr) | PG_k | PG_V; | 826 | pdtpe[3] = xpmap_ptom_masked(addr) | PG_k | PG_V; | |
827 | __PRINTK(("L2 va %#lx pa %#" PRIxPADDR " entry %#" PRIxPADDR | 827 | __PRINTK(("L2 va %#lx pa %#" PRIxPADDR " entry %#" PRIxPADDR | |
828 | " -> L3[%#x]\n", | 828 | " -> L3[%#x]\n", | |
829 | (vaddr_t)pde + PAGE_SIZE * 4, addr, pdtpe[3], 3)); | 829 | (vaddr_t)pde + PAGE_SIZE * 4, addr, pdtpe[3], 3)); | |
830 | 830 | |||
831 | #else /* PAE */ | 831 | #else /* PAE */ | |
832 | pde = bt_pgd; | 832 | pde = bt_pgd; | |
833 | #endif /* PTP_LEVELS > 2 */ | 833 | #endif /* PTP_LEVELS > 2 */ | |
834 | 834 | |||
835 | /* Level 1 */ | 835 | /* Level 1 */ | |
836 | page = KERNTEXTOFF; | 836 | page = KERNTEXTOFF; | |
837 | for (i = 0; i < new_count; i ++) { | 837 | for (i = 0; i < new_count; i ++) { | |
838 | vaddr_t cur_page = page; | 838 | vaddr_t cur_page = page; | |
839 | 839 | |||
840 | pte = (pd_entry_t *) avail; | 840 | pte = (pd_entry_t *) avail; | |
841 | avail += PAGE_SIZE; | 841 | avail += PAGE_SIZE; | |
842 | 842 | |||
843 | memset(pte, 0, PAGE_SIZE); | 843 | memset(pte, 0, PAGE_SIZE); | |
844 | while (pl2_pi(page) == pl2_pi (cur_page)) { | 844 | while (pl2_pi(page) == pl2_pi (cur_page)) { | |
845 | if (page >= map_end) { | 845 | if (page >= map_end) { | |
846 | /* not mapped at all */ | 846 | /* not mapped at all */ | |
847 | pte[pl1_pi(page)] = 0; | 847 | pte[pl1_pi(page)] = 0; | |
848 | page += PAGE_SIZE; | 848 | page += PAGE_SIZE; | |
849 | continue; | 849 | continue; | |
850 | } | 850 | } | |
851 | pte[pl1_pi(page)] = xpmap_ptom_masked(page - KERNBASE); | 851 | pte[pl1_pi(page)] = xpmap_ptom_masked(page - KERNBASE); | |
852 | if (page == (vaddr_t)HYPERVISOR_shared_info) { | 852 | if (page == (vaddr_t)HYPERVISOR_shared_info) { | |
853 | pte[pl1_pi(page)] = xen_start_info.shared_info; | 853 | pte[pl1_pi(page)] = xen_start_info.shared_info; | |
854 | __PRINTK(("HYPERVISOR_shared_info " | 854 | __PRINTK(("HYPERVISOR_shared_info " | |
855 | "va %#lx pte %#" PRIxPADDR "\n", | 855 | "va %#lx pte %#" PRIxPADDR "\n", | |
856 | HYPERVISOR_shared_info, pte[pl1_pi(page)])); | 856 | HYPERVISOR_shared_info, pte[pl1_pi(page)])); | |
857 | } | 857 | } | |
858 | if ((xpmap_ptom_masked(page - KERNBASE) >> PAGE_SHIFT) | 858 | if ((xpmap_ptom_masked(page - KERNBASE) >> PAGE_SHIFT) | |
859 | == xen_start_info.console.domU.mfn) { | 859 | == xen_start_info.console.domU.mfn) { | |
860 | xencons_interface = (void *)page; | 860 | xencons_interface = (void *)page; | |
861 | pte[pl1_pi(page)] = xen_start_info.console_mfn; | 861 | pte[pl1_pi(page)] = xen_start_info.console_mfn; | |
862 | pte[pl1_pi(page)] <<= PAGE_SHIFT; | 862 | pte[pl1_pi(page)] <<= PAGE_SHIFT; | |
863 | __PRINTK(("xencons_interface " | 863 | __PRINTK(("xencons_interface " | |
864 | "va %#lx pte %#" PRIxPADDR "\n", | 864 | "va %#lx pte %#" PRIxPADDR "\n", | |
865 | xencons_interface, pte[pl1_pi(page)])); | 865 | xencons_interface, pte[pl1_pi(page)])); | |
866 | } | 866 | } | |
867 | if ((xpmap_ptom_masked(page - KERNBASE) >> PAGE_SHIFT) | 867 | if ((xpmap_ptom_masked(page - KERNBASE) >> PAGE_SHIFT) | |
868 | == xen_start_info.store_mfn) { | 868 | == xen_start_info.store_mfn) { | |
869 | xenstore_interface = (void *)page; | 869 | xenstore_interface = (void *)page; | |
870 | pte[pl1_pi(page)] = xen_start_info.store_mfn; | 870 | pte[pl1_pi(page)] = xen_start_info.store_mfn; | |
871 | pte[pl1_pi(page)] <<= PAGE_SHIFT; | 871 | pte[pl1_pi(page)] <<= PAGE_SHIFT; | |
872 | __PRINTK(("xenstore_interface " | 872 | __PRINTK(("xenstore_interface " | |
873 | "va %#lx pte %#" PRIxPADDR "\n", | 873 | "va %#lx pte %#" PRIxPADDR "\n", | |
874 | xenstore_interface, pte[pl1_pi(page)])); | 874 | xenstore_interface, pte[pl1_pi(page)])); | |
875 | } | 875 | } | |
876 | #ifdef DOM0OPS | 876 | #ifdef DOM0OPS | |
877 | if (page >= (vaddr_t)atdevbase && | 877 | if (page >= (vaddr_t)atdevbase && | |
878 | page < (vaddr_t)atdevbase + IOM_SIZE) { | 878 | page < (vaddr_t)atdevbase + IOM_SIZE) { | |
879 | pte[pl1_pi(page)] = | 879 | pte[pl1_pi(page)] = | |
880 | IOM_BEGIN + (page - (vaddr_t)atdevbase); | 880 | IOM_BEGIN + (page - (vaddr_t)atdevbase); | |
881 | } | 881 | } | |
882 | #endif | 882 | #endif | |
883 | pte[pl1_pi(page)] |= PG_k | PG_V; | 883 | pte[pl1_pi(page)] |= PG_k | PG_V; | |
884 | if (page < text_end) { | 884 | if (page < text_end) { | |
885 | /* map kernel text RO */ | 885 | /* map kernel text RO */ | |
886 | pte[pl1_pi(page)] |= 0; | 886 | pte[pl1_pi(page)] |= 0; | |
887 | } else if (page >= old_pgd | 887 | } else if (page >= old_pgd | |
888 | && page < old_pgd + (old_count * PAGE_SIZE)) { | 888 | && page < old_pgd + (old_count * PAGE_SIZE)) { | |
889 | /* map old page tables RO */ | 889 | /* map old page tables RO */ | |
890 | pte[pl1_pi(page)] |= 0; | 890 | pte[pl1_pi(page)] |= 0; | |
891 | } else if (page >= new_pgd && | 891 | } else if (page >= new_pgd && | |
892 | page < new_pgd + ((new_count + l2_4_count) * PAGE_SIZE)) { | 892 | page < new_pgd + ((new_count + l2_4_count) * PAGE_SIZE)) { | |
893 | /* map new page tables RO */ | 893 | /* map new page tables RO */ | |
894 | pte[pl1_pi(page)] |= 0; | 894 | pte[pl1_pi(page)] |= 0; | |
895 | #ifdef i386 | 895 | #ifdef i386 | |
896 | } else if (page == (vaddr_t)tmpgdt) { | 896 | } else if (page == (vaddr_t)tmpgdt) { | |
897 | /* | 897 | /* | |
898 | * Map bootstrap gdt R/O. Later, we | 898 | * Map bootstrap gdt R/O. Later, we | |
899 | * will re-add this to page to uvm | 899 | * will re-add this to page to uvm | |
900 | * after making it writable. | 900 | * after making it writable. | |
901 | */ | 901 | */ | |
902 | 902 | |||
903 | pte[pl1_pi(page)] = 0; | 903 | pte[pl1_pi(page)] = 0; | |
904 | page += PAGE_SIZE; | 904 | page += PAGE_SIZE; | |
905 | continue; | 905 | continue; | |
906 | #endif /* i386 */ | 906 | #endif /* i386 */ | |
907 | } else { | 907 | } else { | |
908 | /* map page RW */ | 908 | /* map page RW */ | |
909 | pte[pl1_pi(page)] |= PG_RW; | 909 | pte[pl1_pi(page)] |= PG_RW; | |
910 | } | 910 | } | |
911 | 911 | |||
912 | if ((page >= old_pgd && page < old_pgd + (old_count * PAGE_SIZE)) | 912 | if ((page >= old_pgd && page < old_pgd + (old_count * PAGE_SIZE)) | |
913 | || page >= new_pgd) { | 913 | || page >= new_pgd) { | |
914 | __PRINTK(("va %#lx pa %#lx " | 914 | __PRINTK(("va %#lx pa %#lx " | |
915 | "entry 0x%" PRIxPADDR " -> L1[%#x]\n", | 915 | "entry 0x%" PRIxPADDR " -> L1[%#x]\n", | |
916 | page, page - KERNBASE, | 916 | page, page - KERNBASE, | |
917 | pte[pl1_pi(page)], pl1_pi(page))); | 917 | pte[pl1_pi(page)], pl1_pi(page))); | |
918 | } | 918 | } | |
919 | page += PAGE_SIZE; | 919 | page += PAGE_SIZE; | |
920 | } | 920 | } | |
921 | 921 | |||
922 | addr = ((u_long) pte) - KERNBASE; | 922 | addr = ((u_long) pte) - KERNBASE; | |
923 | pde[pl2_pi(cur_page)] = | 923 | pde[pl2_pi(cur_page)] = | |
924 | xpmap_ptom_masked(addr) | PG_k | PG_RW | PG_V; | 924 | xpmap_ptom_masked(addr) | PG_k | PG_RW | PG_V; | |
925 | __PRINTK(("L1 va %#lx pa %#" PRIxPADDR " entry %#" PRIxPADDR | 925 | __PRINTK(("L1 va %#lx pa %#" PRIxPADDR " entry %#" PRIxPADDR | |
926 | " -> L2[%#x]\n", | 926 | " -> L2[%#x]\n", | |
927 | pte, addr, pde[pl2_pi(cur_page)], pl2_pi(cur_page))); | 927 | pte, addr, pde[pl2_pi(cur_page)], pl2_pi(cur_page))); | |
928 | /* Mark readonly */ | 928 | /* Mark readonly */ | |
929 | xen_bt_set_readonly((vaddr_t) pte); | 929 | xen_bt_set_readonly((vaddr_t) pte); | |
930 | } | 930 | } | |
931 | 931 | |||
932 | /* Install recursive page tables mapping */ | 932 | /* Install recursive page tables mapping */ | |
933 | #ifdef PAE | 933 | #ifdef PAE | |
934 | /* | 934 | /* | |
935 | * we need a shadow page for the kernel's L2 page | 935 | * we need a shadow page for the kernel's L2 page | |
936 | * The real L2 kernel PD will be the last one (so that | 936 | * The real L2 kernel PD will be the last one (so that | |
937 | * pde[L2_SLOT_KERN] always point to the shadow. | 937 | * pde[L2_SLOT_KERN] always point to the shadow. | |
938 | */ | 938 | */ | |
939 | memcpy(&pde[L2_SLOT_KERN + NPDPG], &pde[L2_SLOT_KERN], PAGE_SIZE); | 939 | memcpy(&pde[L2_SLOT_KERN + NPDPG], &pde[L2_SLOT_KERN], PAGE_SIZE); | |
940 | cpu_info_primary.ci_kpm_pdir = &pde[L2_SLOT_KERN + NPDPG]; | 940 | cpu_info_primary.ci_kpm_pdir = &pde[L2_SLOT_KERN + NPDPG]; | |
941 | cpu_info_primary.ci_kpm_pdirpa = | 941 | cpu_info_primary.ci_kpm_pdirpa = | |
942 | (vaddr_t) cpu_info_primary.ci_kpm_pdir - KERNBASE; | 942 | (vaddr_t) cpu_info_primary.ci_kpm_pdir - KERNBASE; | |
943 | 943 | |||
944 | /* | 944 | /* | |
945 | * We don't enter a recursive entry from the L3 PD. Instead, | 945 | * We don't enter a recursive entry from the L3 PD. Instead, | |
946 | * we enter the first 4 L2 pages, which includes the kernel's L2 | 946 | * we enter the first 4 L2 pages, which includes the kernel's L2 | |
947 | * shadow. But we have to entrer the shadow after switching | 947 | * shadow. But we have to entrer the shadow after switching | |
948 | * %cr3, or Xen will refcount some PTE with the wrong type. | 948 | * %cr3, or Xen will refcount some PTE with the wrong type. | |
949 | */ | 949 | */ | |
950 | addr = (u_long)pde - KERNBASE; | 950 | addr = (u_long)pde - KERNBASE; | |
951 | for (i = 0; i < 3; i++, addr += PAGE_SIZE) { | 951 | for (i = 0; i < 3; i++, addr += PAGE_SIZE) { | |
952 | pde[PDIR_SLOT_PTE + i] = xpmap_ptom_masked(addr) | PG_k | PG_V; | 952 | pde[PDIR_SLOT_PTE + i] = xpmap_ptom_masked(addr) | PG_k | PG_V; | |
953 | __PRINTK(("pde[%d] va %#" PRIxVADDR " pa %#" PRIxPADDR | 953 | __PRINTK(("pde[%d] va %#" PRIxVADDR " pa %#" PRIxPADDR | |
954 | " entry %#" PRIxPADDR "\n", | 954 | " entry %#" PRIxPADDR "\n", | |
955 | (int)(PDIR_SLOT_PTE + i), pde + PAGE_SIZE * i, | 955 | (int)(PDIR_SLOT_PTE + i), pde + PAGE_SIZE * i, | |
956 | addr, pde[PDIR_SLOT_PTE + i])); | 956 | addr, pde[PDIR_SLOT_PTE + i])); | |
957 | } | 957 | } | |
958 | #if 0 | 958 | #if 0 | |
959 | addr += PAGE_SIZE; /* point to shadow L2 */ | 959 | addr += PAGE_SIZE; /* point to shadow L2 */ | |
960 | pde[PDIR_SLOT_PTE + 3] = xpmap_ptom_masked(addr) | PG_k | PG_V; | 960 | pde[PDIR_SLOT_PTE + 3] = xpmap_ptom_masked(addr) | PG_k | PG_V; | |
961 | __PRINTK(("pde[%d] va 0x%lx pa 0x%lx entry 0x%" PRIx64 "\n", | 961 | __PRINTK(("pde[%d] va 0x%lx pa 0x%lx entry 0x%" PRIx64 "\n", | |
962 | (int)(PDIR_SLOT_PTE + 3), pde + PAGE_SIZE * 4, (long)addr, | 962 | (int)(PDIR_SLOT_PTE + 3), pde + PAGE_SIZE * 4, (long)addr, | |
963 | (int64_t)pde[PDIR_SLOT_PTE + 3])); | 963 | (int64_t)pde[PDIR_SLOT_PTE + 3])); | |
964 | #endif | 964 | #endif | |
965 | /* Mark tables RO, and pin the kernel's shadow as L2 */ | 965 | /* Mark tables RO, and pin the kernel's shadow as L2 */ | |
966 | addr = (u_long)pde - KERNBASE; | 966 | addr = (u_long)pde - KERNBASE; | |
967 | for (i = 0; i < 5; i++, addr += PAGE_SIZE) { | 967 | for (i = 0; i < 5; i++, addr += PAGE_SIZE) { | |
968 | xen_bt_set_readonly(((vaddr_t)pde) + PAGE_SIZE * i); | 968 | xen_bt_set_readonly(((vaddr_t)pde) + PAGE_SIZE * i); | |
969 | if (i == 2 || i == 3) | 969 | if (i == 2 || i == 3) | |
970 | continue; | 970 | continue; | |
971 | #if 0 | 971 | #if 0 | |
972 | __PRINTK(("pin L2 %d addr 0x%" PRIx64 "\n", i, (int64_t)addr)); | 972 | __PRINTK(("pin L2 %d addr 0x%" PRIx64 "\n", i, (int64_t)addr)); | |
973 | xpq_queue_pin_l2_table(xpmap_ptom_masked(addr)); | 973 | xpq_queue_pin_l2_table(xpmap_ptom_masked(addr)); | |
974 | #endif | 974 | #endif | |
975 | } | 975 | } | |
976 | if (final) { | 976 | if (final) { | |
977 | addr = (u_long)pde - KERNBASE + 3 * PAGE_SIZE; | 977 | addr = (u_long)pde - KERNBASE + 3 * PAGE_SIZE; | |
978 | __PRINTK(("pin L2 %d addr %#" PRIxPADDR "\n", 2, addr)); | 978 | __PRINTK(("pin L2 %d addr %#" PRIxPADDR "\n", 2, addr)); | |
979 | xpq_queue_pin_l2_table(xpmap_ptom_masked(addr)); | 979 | xpq_queue_pin_l2_table(xpmap_ptom_masked(addr)); | |
980 | } | 980 | } | |
981 | #if 0 | 981 | #if 0 | |
982 | addr = (u_long)pde - KERNBASE + 2 * PAGE_SIZE; | 982 | addr = (u_long)pde - KERNBASE + 2 * PAGE_SIZE; | |
983 | __PRINTK(("pin L2 %d addr 0x%" PRIx64 "\n", 2, (int64_t)addr)); | 983 | __PRINTK(("pin L2 %d addr 0x%" PRIx64 "\n", 2, (int64_t)addr)); | |
984 | xpq_queue_pin_l2_table(xpmap_ptom_masked(addr)); | 984 | xpq_queue_pin_l2_table(xpmap_ptom_masked(addr)); | |
985 | #endif | 985 | #endif | |
986 | #else /* PAE */ | 986 | #else /* PAE */ | |
987 | /* recursive entry in higher-level per-cpu PD and pmap_kernel() */ | 987 | /* recursive entry in higher-level per-cpu PD and pmap_kernel() */ | |
988 | bt_pgd[PDIR_SLOT_PTE] = xpmap_ptom_masked((paddr_t)bt_pgd - KERNBASE) | PG_k | PG_V; | 988 | bt_pgd[PDIR_SLOT_PTE] = xpmap_ptom_masked((paddr_t)bt_pgd - KERNBASE) | PG_k | PG_V; | |
989 | #ifdef __x86_64__ | 989 | #ifdef __x86_64__ | |
990 | bt_cpu_pgd[PDIR_SLOT_PTE] = | 990 | bt_cpu_pgd[PDIR_SLOT_PTE] = | |
991 | xpmap_ptom_masked((paddr_t)bt_cpu_pgd - KERNBASE) | PG_k | PG_V; | 991 | xpmap_ptom_masked((paddr_t)bt_cpu_pgd - KERNBASE) | PG_k | PG_V; | |
992 | #endif /* __x86_64__ */ | 992 | #endif /* __x86_64__ */ | |
993 | __PRINTK(("bt_pgd[PDIR_SLOT_PTE] va %#" PRIxVADDR " pa %#" PRIxPADDR | 993 | __PRINTK(("bt_pgd[PDIR_SLOT_PTE] va %#" PRIxVADDR " pa %#" PRIxPADDR | |
994 | " entry %#" PRIxPADDR "\n", new_pgd, (paddr_t)new_pgd - KERNBASE, | 994 | " entry %#" PRIxPADDR "\n", new_pgd, (paddr_t)new_pgd - KERNBASE, | |
995 | bt_pgd[PDIR_SLOT_PTE])); | 995 | bt_pgd[PDIR_SLOT_PTE])); | |
996 | /* Mark tables RO */ | 996 | /* Mark tables RO */ | |
997 | xen_bt_set_readonly((vaddr_t) pde); | 997 | xen_bt_set_readonly((vaddr_t) pde); | |
998 | #endif | 998 | #endif | |
999 | #if PTP_LEVELS > 2 || defined(PAE) | 999 | #if PTP_LEVELS > 2 || defined(PAE) | |
1000 | xen_bt_set_readonly((vaddr_t) pdtpe); | 1000 | xen_bt_set_readonly((vaddr_t) pdtpe); | |
1001 | #endif | 1001 | #endif | |
1002 | #if PTP_LEVELS > 3 | 1002 | #if PTP_LEVELS > 3 | |
1003 | xen_bt_set_readonly(new_pgd); | 1003 | xen_bt_set_readonly(new_pgd); | |
1004 | #endif | 1004 | #endif | |
1005 | /* Pin the PGD */ | 1005 | /* Pin the PGD */ | |
1006 | __PRINTK(("pin PGD: %"PRIxVADDR"\n", new_pgd - KERNBASE)); | 1006 | __PRINTK(("pin PGD: %"PRIxVADDR"\n", new_pgd - KERNBASE)); | |
1007 | #ifdef __x86_64__ | 1007 | #ifdef __x86_64__ | |
1008 | xpq_queue_pin_l4_table(xpmap_ptom_masked(new_pgd - KERNBASE)); | 1008 | xpq_queue_pin_l4_table(xpmap_ptom_masked(new_pgd - KERNBASE)); | |
1009 | #elif PAE | 1009 | #elif PAE | |
1010 | xpq_queue_pin_l3_table(xpmap_ptom_masked(new_pgd - KERNBASE)); | 1010 | xpq_queue_pin_l3_table(xpmap_ptom_masked(new_pgd - KERNBASE)); | |
1011 | #else | 1011 | #else | |
1012 | xpq_queue_pin_l2_table(xpmap_ptom_masked(new_pgd - KERNBASE)); | 1012 | xpq_queue_pin_l2_table(xpmap_ptom_masked(new_pgd - KERNBASE)); | |
1013 | #endif | 1013 | #endif | |
1014 | 1014 | |||
1015 | /* Save phys. addr of PDP, for libkvm. */ | 1015 | /* Save phys. addr of PDP, for libkvm. */ | |
1016 | #ifdef PAE | 1016 | #ifdef PAE | |
1017 | PDPpaddr = (u_long)pde - KERNBASE; /* PDP is the L2 with PAE */ | 1017 | PDPpaddr = (u_long)pde - KERNBASE; /* PDP is the L2 with PAE */ | |
1018 | #else | 1018 | #else | |
1019 | PDPpaddr = (u_long)bt_pgd - KERNBASE; | 1019 | PDPpaddr = (u_long)bt_pgd - KERNBASE; | |
1020 | #endif | 1020 | #endif | |
1021 | 1021 | |||
1022 | /* Switch to new tables */ | 1022 | /* Switch to new tables */ | |
1023 | __PRINTK(("switch to PGD\n")); | 1023 | __PRINTK(("switch to PGD\n")); | |
1024 | xpq_queue_pt_switch(xpmap_ptom_masked(new_pgd - KERNBASE)); | 1024 | xpq_queue_pt_switch(xpmap_ptom_masked(new_pgd - KERNBASE)); | |
1025 | __PRINTK(("bt_pgd[PDIR_SLOT_PTE] now entry %#" PRIxPADDR "\n", | 1025 | __PRINTK(("bt_pgd[PDIR_SLOT_PTE] now entry %#" PRIxPADDR "\n", | |
1026 | bt_pgd[PDIR_SLOT_PTE])); | 1026 | bt_pgd[PDIR_SLOT_PTE])); | |
1027 | 1027 | |||
1028 | #ifdef PAE | 1028 | #ifdef PAE | |
1029 | if (final) { | 1029 | if (final) { | |
1030 | /* save the address of the L3 page */ | 1030 | /* save the address of the L3 page */ | |
1031 | cpu_info_primary.ci_pae_l3_pdir = pdtpe; | 1031 | cpu_info_primary.ci_pae_l3_pdir = pdtpe; | |
1032 | cpu_info_primary.ci_pae_l3_pdirpa = (new_pgd - KERNBASE); | 1032 | cpu_info_primary.ci_pae_l3_pdirpa = (new_pgd - KERNBASE); | |
1033 | 1033 | |||
1034 | /* now enter kernel's PTE mappings */ | 1034 | /* now enter kernel's PTE mappings */ | |
1035 | addr = (u_long)pde - KERNBASE + PAGE_SIZE * 3; | 1035 | addr = (u_long)pde - KERNBASE + PAGE_SIZE * 3; | |
1036 | xpq_queue_pte_update( | 1036 | xpq_queue_pte_update( | |
1037 | xpmap_ptom(((vaddr_t)&pde[PDIR_SLOT_PTE + 3]) - KERNBASE), | 1037 | xpmap_ptom(((vaddr_t)&pde[PDIR_SLOT_PTE + 3]) - KERNBASE), | |
1038 | xpmap_ptom_masked(addr) | PG_k | PG_V); | 1038 | xpmap_ptom_masked(addr) | PG_k | PG_V); | |
1039 | xpq_flush_queue(); | 1039 | xpq_flush_queue(); | |
1040 | } | 1040 | } | |
1041 | #elif defined(__x86_64__) | 1041 | #elif defined(__x86_64__) | |
1042 | if (final) { | 1042 | if (final) { | |
1043 | /* save the address of the real per-cpu L4 pgd page */ | 1043 | /* save the address of the real per-cpu L4 pgd page */ | |
1044 | cpu_info_primary.ci_kpm_pdir = bt_cpu_pgd; | 1044 | cpu_info_primary.ci_kpm_pdir = bt_cpu_pgd; | |
1045 | cpu_info_primary.ci_kpm_pdirpa = ((paddr_t) bt_cpu_pgd - KERNBASE); | 1045 | cpu_info_primary.ci_kpm_pdirpa = ((paddr_t) bt_cpu_pgd - KERNBASE); | |
1046 | } | 1046 | } | |
1047 | #endif | 1047 | #endif | |
1048 | 1048 | |||
1049 | /* Now we can safely reclaim space taken by old tables */ | 1049 | /* Now we can safely reclaim space taken by old tables */ | |
1050 | 1050 | |||
1051 | __PRINTK(("unpin old PGD\n")); | 1051 | __PRINTK(("unpin old PGD\n")); | |
1052 | /* Unpin old PGD */ | 1052 | /* Unpin old PGD */ | |
1053 | xpq_queue_unpin_table(xpmap_ptom_masked(old_pgd - KERNBASE)); | 1053 | xpq_queue_unpin_table(xpmap_ptom_masked(old_pgd - KERNBASE)); | |
1054 | /* Mark old tables RW */ | 1054 | /* Mark old tables RW */ | |
1055 | page = old_pgd; | 1055 | page = old_pgd; | |
1056 | addr = (paddr_t) pde[pl2_pi(page)] & PG_FRAME; | 1056 | addr = (paddr_t) pde[pl2_pi(page)] & PG_FRAME; | |
1057 | addr = xpmap_mtop(addr); | 1057 | addr = xpmap_mtop(addr); | |
1058 | pte = (pd_entry_t *) ((u_long)addr + KERNBASE); | 1058 | pte = (pd_entry_t *) ((u_long)addr + KERNBASE); | |
1059 | pte += pl1_pi(page); | 1059 | pte += pl1_pi(page); | |
1060 | __PRINTK(("*pde %#" PRIxPADDR " addr %#" PRIxPADDR " pte %#lx\n", | 1060 | __PRINTK(("*pde %#" PRIxPADDR " addr %#" PRIxPADDR " pte %#lx\n", | |
1061 | pde[pl2_pi(page)], addr, (long)pte)); | 1061 | pde[pl2_pi(page)], addr, (long)pte)); | |
1062 | while (page < old_pgd + (old_count * PAGE_SIZE) && page < map_end) { | 1062 | while (page < old_pgd + (old_count * PAGE_SIZE) && page < map_end) { | |
1063 | addr = xpmap_ptom(((u_long) pte) - KERNBASE); | 1063 | addr = xpmap_ptom(((u_long) pte) - KERNBASE); | |
1064 | XENPRINTK(("addr %#" PRIxPADDR " pte %#lx " | 1064 | XENPRINTK(("addr %#" PRIxPADDR " pte %#lx " | |
1065 | "*pte %#" PRIxPADDR "\n", | 1065 | "*pte %#" PRIxPADDR "\n", | |
1066 | addr, (long)pte, *pte)); | 1066 | addr, (long)pte, *pte)); | |
1067 | xpq_queue_pte_update(addr, *pte | PG_RW); | 1067 | xpq_queue_pte_update(addr, *pte | PG_RW); | |
1068 | page += PAGE_SIZE; | 1068 | page += PAGE_SIZE; | |
1069 | /* | 1069 | /* | |
1070 | * Our ptes are contiguous | 1070 | * Our ptes are contiguous | |
1071 | * so it's safe to just "++" here | 1071 | * so it's safe to just "++" here | |
1072 | */ | 1072 | */ | |
1073 | pte++; | 1073 | pte++; | |
1074 | } | 1074 | } | |
1075 | xpq_flush_queue(); | 1075 | xpq_flush_queue(); | |
1076 | } | 1076 | } | |
1077 | 1077 | |||
1078 | 1078 | |||
1079 | /* | 1079 | /* | |
1080 | * Bootstrap helper functions | 1080 | * Bootstrap helper functions | |
1081 | */ | 1081 | */ | |
1082 | 1082 | |||
1083 | /* | 1083 | /* | |
1084 | * Mark a page readonly | 1084 | * Mark a page readonly | |
1085 | * XXX: assuming vaddr = paddr + KERNBASE | 1085 | * XXX: assuming vaddr = paddr + KERNBASE | |
1086 | */ | 1086 | */ | |
1087 | 1087 | |||
1088 | static void | 1088 | static void | |
1089 | xen_bt_set_readonly (vaddr_t page) | 1089 | xen_bt_set_readonly (vaddr_t page) | |
1090 | { | 1090 | { | |
1091 | pt_entry_t entry; | 1091 | pt_entry_t entry; | |
1092 | 1092 | |||
1093 | entry = xpmap_ptom_masked(page - KERNBASE); | 1093 | entry = xpmap_ptom_masked(page - KERNBASE); | |
1094 | entry |= PG_k | PG_V; | 1094 | entry |= PG_k | PG_V; | |
1095 | 1095 | |||
1096 | HYPERVISOR_update_va_mapping (page, entry, UVMF_INVLPG); | 1096 | HYPERVISOR_update_va_mapping (page, entry, UVMF_INVLPG); | |
1097 | } | 1097 | } | |
1098 | 1098 | |||
1099 | #ifdef __x86_64__ | 1099 | #ifdef __x86_64__ | |
1100 | void | 1100 | void | |
1101 | xen_set_user_pgd(paddr_t page) | 1101 | xen_set_user_pgd(paddr_t page) | |
1102 | { | 1102 | { | |
1103 | struct mmuext_op op; | 1103 | struct mmuext_op op; | |
1104 | int s = splvm(); | 1104 | int s = splvm(); | |
1105 | 1105 | |||
1106 | xpq_flush_queue(); | 1106 | xpq_flush_queue(); | |
1107 | op.cmd = MMUEXT_NEW_USER_BASEPTR; | 1107 | op.cmd = MMUEXT_NEW_USER_BASEPTR; | |
1108 | op.arg1.mfn = xpmap_ptom_masked(page) >> PAGE_SHIFT; | 1108 | op.arg1.mfn = xpmap_ptom_masked(page) >> PAGE_SHIFT; | |
1109 | if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0) | 1109 | if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0) | |
1110 | panic("xen_set_user_pgd: failed to install new user page" | 1110 | panic("xen_set_user_pgd: failed to install new user page" | |
1111 | " directory %#" PRIxPADDR, page); | 1111 | " directory %#" PRIxPADDR, page); | |
1112 | splx(s); | 1112 | splx(s); | |
1113 | } | 1113 | } | |
1114 | #endif /* __x86_64__ */ | 1114 | #endif /* __x86_64__ */ |
--- src/sys/kern/subr_kcpuset.c 2012/08/20 22:01:29 1.7
+++ src/sys/kern/subr_kcpuset.c 2012/09/16 22:09:33 1.8
@@ -1,462 +1,462 @@ | @@ -1,462 +1,462 @@ | |||
1 | /* $NetBSD: subr_kcpuset.c,v 1.7 2012/08/20 22:01:29 rmind Exp $ */ | 1 | /* $NetBSD: subr_kcpuset.c,v 1.8 2012/09/16 22:09:33 rmind Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2011 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2011 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to The NetBSD Foundation | 7 | * This code is derived from software contributed to The NetBSD Foundation | |
8 | * by Mindaugas Rasiukevicius. | 8 | * by Mindaugas Rasiukevicius. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | 15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | 16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | 17 | * documentation and/or other materials provided with the distribution. | |
18 | * | 18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
29 | * POSSIBILITY OF SUCH DAMAGE. | 29 | * POSSIBILITY OF SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | /* | 32 | /* | |
33 | * Kernel CPU set implementation. | 33 | * Kernel CPU set implementation. | |
34 | * | 34 | * | |
35 | * Interface can be used by kernel subsystems as a unified dynamic CPU | 35 | * Interface can be used by kernel subsystems as a unified dynamic CPU | |
36 | * bitset implementation handling many CPUs. Facility also supports early | 36 | * bitset implementation handling many CPUs. Facility also supports early | |
37 | * use by MD code on boot, as it fixups bitsets on further boot. | 37 | * use by MD code on boot, as it fixups bitsets on further boot. | |
38 | * | 38 | * | |
39 | * TODO: | 39 | * TODO: | |
40 | * - Handle "reverse" bitset on fixup/grow. | 40 | * - Handle "reverse" bitset on fixup/grow. | |
41 | */ | 41 | */ | |
42 | 42 | |||
43 | #include <sys/cdefs.h> | 43 | #include <sys/cdefs.h> | |
44 | __KERNEL_RCSID(0, "$NetBSD: subr_kcpuset.c,v 1.7 2012/08/20 22:01:29 rmind Exp $"); | 44 | __KERNEL_RCSID(0, "$NetBSD: subr_kcpuset.c,v 1.8 2012/09/16 22:09:33 rmind Exp $"); | |
45 | 45 | |||
46 | #include <sys/param.h> | 46 | #include <sys/param.h> | |
47 | #include <sys/types.h> | 47 | #include <sys/types.h> | |
48 | 48 | |||
49 | #include <sys/atomic.h> | 49 | #include <sys/atomic.h> | |
50 | #include <sys/sched.h> | 50 | #include <sys/sched.h> | |
51 | #include <sys/kcpuset.h> | 51 | #include <sys/kcpuset.h> | |
52 | #include <sys/pool.h> | 52 | #include <sys/pool.h> | |
53 | 53 | |||
54 | /* Number of CPUs to support. */ | 54 | /* Number of CPUs to support. */ | |
55 | #define KC_MAXCPUS roundup2(MAXCPUS, 32) | 55 | #define KC_MAXCPUS roundup2(MAXCPUS, 32) | |
56 | 56 | |||
57 | /* | 57 | /* | |
58 | * Structure of dynamic CPU set in the kernel. | 58 | * Structure of dynamic CPU set in the kernel. | |
59 | */ | 59 | */ | |
60 | struct kcpuset { | 60 | struct kcpuset { | |
61 | uint32_t bits[0]; | 61 | uint32_t bits[0]; | |
62 | }; | 62 | }; | |
63 | 63 | |||
64 | typedef struct kcpuset_impl { | 64 | typedef struct kcpuset_impl { | |
65 | /* Reference count. */ | 65 | /* Reference count. */ | |
66 | u_int kc_refcnt; | 66 | u_int kc_refcnt; | |
67 | /* Next to free, if non-NULL (used when multiple references). */ | 67 | /* Next to free, if non-NULL (used when multiple references). */ | |
68 | struct kcpuset * kc_next; | 68 | struct kcpuset * kc_next; | |
69 | /* Actual variable-sized field of bits. */ | 69 | /* Actual variable-sized field of bits. */ | |
70 | struct kcpuset kc_field; | 70 | struct kcpuset kc_field; | |
71 | } kcpuset_impl_t; | 71 | } kcpuset_impl_t; | |
72 | 72 | |||
73 | #define KC_BITS_OFF (offsetof(struct kcpuset_impl, kc_field)) | 73 | #define KC_BITS_OFF (offsetof(struct kcpuset_impl, kc_field)) | |
74 | #define KC_GETSTRUCT(b) ((kcpuset_impl_t *)((char *)(b) - KC_BITS_OFF)) | 74 | #define KC_GETSTRUCT(b) ((kcpuset_impl_t *)((char *)(b) - KC_BITS_OFF)) | |
75 | 75 | |||
76 | /* Sizes of a single bitset. */ | 76 | /* Sizes of a single bitset. */ | |
77 | #define KC_SHIFT 5 | 77 | #define KC_SHIFT 5 | |
78 | #define KC_MASK 31 | 78 | #define KC_MASK 31 | |
79 | 79 | |||
80 | /* An array of noted early kcpuset creations and data. */ | 80 | /* An array of noted early kcpuset creations and data. */ | |
81 | #define KC_SAVE_NITEMS 8 | 81 | #define KC_SAVE_NITEMS 8 | |
82 | 82 | |||
83 | /* Structures for early boot mechanism (must be statically initialised). */ | 83 | /* Structures for early boot mechanism (must be statically initialised). */ | |
84 | static kcpuset_t ** kc_noted_early[KC_SAVE_NITEMS]; | 84 | static kcpuset_t ** kc_noted_early[KC_SAVE_NITEMS]; | |
85 | static uint32_t kc_bits_early[KC_SAVE_NITEMS]; | 85 | static uint32_t kc_bits_early[KC_SAVE_NITEMS]; | |
86 | static int kc_last_idx = 0; | 86 | static int kc_last_idx = 0; | |
87 | static bool kc_initialised = false; | 87 | static bool kc_initialised = false; | |
88 | 88 | |||
89 | #define KC_BITSIZE_EARLY sizeof(kc_bits_early[0]) | 89 | #define KC_BITSIZE_EARLY sizeof(kc_bits_early[0]) | |
90 | #define KC_NFIELDS_EARLY 1 | 90 | #define KC_NFIELDS_EARLY 1 | |
91 | 91 | |||
92 | /* | 92 | /* | |
93 | * The size of whole bitset fields and amount of fields. | 93 | * The size of whole bitset fields and amount of fields. | |
94 | * The whole size must statically initialise for early case. | 94 | * The whole size must statically initialise for early case. | |
95 | */ | 95 | */ | |
96 | static size_t kc_bitsize __read_mostly = KC_BITSIZE_EARLY; | 96 | static size_t kc_bitsize __read_mostly = KC_BITSIZE_EARLY; | |
97 | static size_t kc_nfields __read_mostly = KC_NFIELDS_EARLY; | 97 | static size_t kc_nfields __read_mostly = KC_NFIELDS_EARLY; | |
98 | 98 | |||
99 | static pool_cache_t kc_cache __read_mostly; | 99 | static pool_cache_t kc_cache __read_mostly; | |
100 | 100 | |||
101 | static kcpuset_t * kcpuset_create_raw(bool); | 101 | static kcpuset_t * kcpuset_create_raw(bool); | |
102 | 102 | |||
103 | /* | 103 | /* | |
104 | * kcpuset_sysinit: initialize the subsystem, transfer early boot cases | 104 | * kcpuset_sysinit: initialize the subsystem, transfer early boot cases | |
105 | * to dynamically allocated sets. | 105 | * to dynamically allocated sets. | |
106 | */ | 106 | */ | |
107 | void | 107 | void | |
108 | kcpuset_sysinit(void) | 108 | kcpuset_sysinit(void) | |
109 | { | 109 | { | |
110 | kcpuset_t *kc_dynamic[KC_SAVE_NITEMS], *kcp; | 110 | kcpuset_t *kc_dynamic[KC_SAVE_NITEMS], *kcp; | |
111 | int i, s; | 111 | int i, s; | |
112 | 112 | |||
113 | /* Set a kcpuset_t sizes. */ | 113 | /* Set a kcpuset_t sizes. */ | |
114 | kc_nfields = (KC_MAXCPUS >> KC_SHIFT); | 114 | kc_nfields = (KC_MAXCPUS >> KC_SHIFT); | |
115 | kc_bitsize = sizeof(uint32_t) * kc_nfields; | 115 | kc_bitsize = sizeof(uint32_t) * kc_nfields; | |
116 | KASSERT(kc_nfields != 0 && kc_bitsize != 0); | 116 | KASSERT(kc_nfields != 0 && kc_bitsize != 0); | |
117 | 117 | |||
118 | kc_cache = pool_cache_init(sizeof(kcpuset_impl_t) + kc_bitsize, | 118 | kc_cache = pool_cache_init(sizeof(kcpuset_impl_t) + kc_bitsize, | |
119 | coherency_unit, 0, 0, "kcpuset", NULL, IPL_NONE, NULL, NULL, NULL); | 119 | coherency_unit, 0, 0, "kcpuset", NULL, IPL_NONE, NULL, NULL, NULL); | |
120 | 120 | |||
121 | /* First, pre-allocate kcpuset entries. */ | 121 | /* First, pre-allocate kcpuset entries. */ | |
122 | for (i = 0; i < kc_last_idx; i++) { | 122 | for (i = 0; i < kc_last_idx; i++) { | |
123 | kcp = kcpuset_create_raw(true); | 123 | kcp = kcpuset_create_raw(true); | |
124 | kc_dynamic[i] = kcp; | 124 | kc_dynamic[i] = kcp; | |
125 | } | 125 | } | |
126 | 126 | |||
127 | /* | 127 | /* | |
128 | * Prepare to convert all early noted kcpuset uses to dynamic sets. | 128 | * Prepare to convert all early noted kcpuset uses to dynamic sets. | |
129 | * All processors, except the one we are currently running (primary), | 129 | * All processors, except the one we are currently running (primary), | |
130 | * must not be spinned yet. Since MD facilities can use kcpuset, | 130 | * must not be spinned yet. Since MD facilities can use kcpuset, | |
131 | * raise the IPL to high. | 131 | * raise the IPL to high. | |
132 | */ | 132 | */ | |
133 | KASSERT(mp_online == false); | 133 | KASSERT(mp_online == false); | |
134 | 134 | |||
135 | s = splhigh(); | 135 | s = splhigh(); | |
136 | for (i = 0; i < kc_last_idx; i++) { | 136 | for (i = 0; i < kc_last_idx; i++) { | |
137 | /* | 137 | /* | |
138 | * Transfer the bits from early static storage to the kcpuset. | 138 | * Transfer the bits from early static storage to the kcpuset. | |
139 | */ | 139 | */ | |
140 | KASSERT(kc_bitsize >= KC_BITSIZE_EARLY); | 140 | KASSERT(kc_bitsize >= KC_BITSIZE_EARLY); | |
141 | memcpy(kc_dynamic[i], &kc_bits_early[i], KC_BITSIZE_EARLY); | 141 | memcpy(kc_dynamic[i], &kc_bits_early[i], KC_BITSIZE_EARLY); | |
142 | 142 | |||
143 | /* | 143 | /* | |
144 | * Store the new pointer, pointing to the allocated kcpuset. | 144 | * Store the new pointer, pointing to the allocated kcpuset. | |
145 | * Note: we are not in an interrupt context and it is the only | 145 | * Note: we are not in an interrupt context and it is the only | |
146 | * CPU running - thus store is safe (e.g. no need for pointer | 146 | * CPU running - thus store is safe (e.g. no need for pointer | |
147 | * variable to be volatile). | 147 | * variable to be volatile). | |
148 | */ | 148 | */ | |
149 | *kc_noted_early[i] = kc_dynamic[i]; | 149 | *kc_noted_early[i] = kc_dynamic[i]; | |
150 | } | 150 | } | |
151 | kc_initialised = true; | 151 | kc_initialised = true; | |
152 | kc_last_idx = 0; | 152 | kc_last_idx = 0; | |
153 | splx(s); | 153 | splx(s); | |
154 | } | 154 | } | |
155 | 155 | |||
156 | /* | 156 | /* | |
157 | * kcpuset_early_ptr: note an early boot use by saving the pointer and | 157 | * kcpuset_early_ptr: note an early boot use by saving the pointer and | |
158 | * returning a pointer to a static, temporary bit field. | 158 | * returning a pointer to a static, temporary bit field. | |
159 | */ | 159 | */ | |
160 | static kcpuset_t * | 160 | static kcpuset_t * | |
161 | kcpuset_early_ptr(kcpuset_t **kcptr) | 161 | kcpuset_early_ptr(kcpuset_t **kcptr) | |
162 | { | 162 | { | |
163 | kcpuset_t *kcp; | 163 | kcpuset_t *kcp; | |
164 | int s; | 164 | int s; | |
165 | 165 | |||
166 | s = splhigh(); | 166 | s = splhigh(); | |
167 | if (kc_last_idx < KC_SAVE_NITEMS) { | 167 | if (kc_last_idx < KC_SAVE_NITEMS) { | |
168 | /* | 168 | /* | |
169 | * Save the pointer, return pointer to static early field. | 169 | * Save the pointer, return pointer to static early field. | |
170 | * Need to zero it out. | 170 | * Need to zero it out. | |
171 | */ | 171 | */ | |
172 | kc_noted_early[kc_last_idx] = kcptr; | 172 | kc_noted_early[kc_last_idx] = kcptr; | |
173 | kcp = (kcpuset_t *)&kc_bits_early[kc_last_idx]; | 173 | kcp = (kcpuset_t *)&kc_bits_early[kc_last_idx]; | |
174 | kc_last_idx++; | 174 | kc_last_idx++; | |
175 | memset(kcp, 0, KC_BITSIZE_EARLY); | 175 | memset(kcp, 0, KC_BITSIZE_EARLY); | |
176 | KASSERT(kc_bitsize == KC_BITSIZE_EARLY); | 176 | KASSERT(kc_bitsize == KC_BITSIZE_EARLY); | |
177 | } else { | 177 | } else { | |
178 | panic("kcpuset(9): all early-use entries exhausted; " | 178 | panic("kcpuset(9): all early-use entries exhausted; " | |
179 | "increase KC_SAVE_NITEMS\n"); | 179 | "increase KC_SAVE_NITEMS\n"); | |
180 | } | 180 | } | |
181 | splx(s); | 181 | splx(s); | |
182 | 182 | |||
183 | return kcp; | 183 | return kcp; | |
184 | } | 184 | } | |
185 | 185 | |||
186 | /* | 186 | /* | |
187 | * Routines to create or destroy the CPU set. | 187 | * Routines to create or destroy the CPU set. | |
188 | * Early boot case is handled. | 188 | * Early boot case is handled. | |
189 | */ | 189 | */ | |
190 | 190 | |||
191 | static kcpuset_t * | 191 | static kcpuset_t * | |
192 | kcpuset_create_raw(bool zero) | 192 | kcpuset_create_raw(bool zero) | |
193 | { | 193 | { | |
194 | kcpuset_impl_t *kc; | 194 | kcpuset_impl_t *kc; | |
195 | 195 | |||
196 | kc = pool_cache_get(kc_cache, PR_WAITOK); | 196 | kc = pool_cache_get(kc_cache, PR_WAITOK); | |
197 | kc->kc_refcnt = 1; | 197 | kc->kc_refcnt = 1; | |
198 | kc->kc_next = NULL; | 198 | kc->kc_next = NULL; | |
199 | 199 | |||
200 | if (zero) { | 200 | if (zero) { | |
201 | memset(&kc->kc_field, 0, kc_bitsize); | 201 | memset(&kc->kc_field, 0, kc_bitsize); | |
202 | } | 202 | } | |
203 | 203 | |||
204 | /* Note: return pointer to the actual field of bits. */ | 204 | /* Note: return pointer to the actual field of bits. */ | |
205 | KASSERT((uint8_t *)kc + KC_BITS_OFF == (uint8_t *)&kc->kc_field); | 205 | KASSERT((uint8_t *)kc + KC_BITS_OFF == (uint8_t *)&kc->kc_field); | |
206 | return &kc->kc_field; | 206 | return &kc->kc_field; | |
207 | } | 207 | } | |
208 | 208 | |||
209 | void | 209 | void | |
210 | kcpuset_create(kcpuset_t **retkcp, bool zero) | 210 | kcpuset_create(kcpuset_t **retkcp, bool zero) | |
211 | { | 211 | { | |
212 | if (__predict_false(!kc_initialised)) { | 212 | if (__predict_false(!kc_initialised)) { | |
213 | /* Early boot use - special case. */ | 213 | /* Early boot use - special case. */ | |
214 | *retkcp = kcpuset_early_ptr(retkcp); | 214 | *retkcp = kcpuset_early_ptr(retkcp); | |
215 | return; | 215 | return; | |
216 | } | 216 | } | |
217 | *retkcp = kcpuset_create_raw(zero); | 217 | *retkcp = kcpuset_create_raw(zero); | |
218 | } | 218 | } | |
219 | 219 | |||
220 | void | 220 | void | |
221 | kcpuset_destroy(kcpuset_t *kcp) | 221 | kcpuset_destroy(kcpuset_t *kcp) | |
222 | { | 222 | { | |
223 | kcpuset_impl_t *kc; | 223 | kcpuset_impl_t *kc; | |
224 | 224 | |||
225 | KASSERT(kc_initialised); | 225 | KASSERT(kc_initialised); | |
226 | KASSERT(kcp != NULL); | 226 | KASSERT(kcp != NULL); | |
227 | 227 | |||
228 | do { | 228 | do { | |
229 | kc = KC_GETSTRUCT(kcp); | 229 | kc = KC_GETSTRUCT(kcp); | |
230 | kcp = kc->kc_next; | 230 | kcp = kc->kc_next; | |
231 | pool_cache_put(kc_cache, kc); | 231 | pool_cache_put(kc_cache, kc); | |
232 | } while (kcp); | 232 | } while (kcp); | |
233 | } | 233 | } | |
234 | 234 | |||
235 | /* | 235 | /* | |
236 | * Routines to reference/unreference the CPU set. | 236 | * Routines to reference/unreference the CPU set. | |
237 | * Note: early boot case is not supported by these routines. | 237 | * Note: early boot case is not supported by these routines. | |
238 | */ | 238 | */ | |
239 | 239 | |||
240 | void | 240 | void | |
241 | kcpuset_use(kcpuset_t *kcp) | 241 | kcpuset_use(kcpuset_t *kcp) | |
242 | { | 242 | { | |
243 | kcpuset_impl_t *kc = KC_GETSTRUCT(kcp); | 243 | kcpuset_impl_t *kc = KC_GETSTRUCT(kcp); | |
244 | 244 | |||
245 | KASSERT(kc_initialised); | 245 | KASSERT(kc_initialised); | |
246 | atomic_inc_uint(&kc->kc_refcnt); | 246 | atomic_inc_uint(&kc->kc_refcnt); | |
247 | } | 247 | } | |
248 | 248 | |||
249 | void | 249 | void | |
250 | kcpuset_unuse(kcpuset_t *kcp, kcpuset_t **lst) | 250 | kcpuset_unuse(kcpuset_t *kcp, kcpuset_t **lst) | |
251 | { | 251 | { | |
252 | kcpuset_impl_t *kc = KC_GETSTRUCT(kcp); | 252 | kcpuset_impl_t *kc = KC_GETSTRUCT(kcp); | |
253 | 253 | |||
254 | KASSERT(kc_initialised); | 254 | KASSERT(kc_initialised); | |
255 | KASSERT(kc->kc_refcnt > 0); | 255 | KASSERT(kc->kc_refcnt > 0); | |
256 | 256 | |||
257 | if (atomic_dec_uint_nv(&kc->kc_refcnt) != 0) { | 257 | if (atomic_dec_uint_nv(&kc->kc_refcnt) != 0) { | |
258 | return; | 258 | return; | |
259 | } | 259 | } | |
260 | KASSERT(kc->kc_next == NULL); | 260 | KASSERT(kc->kc_next == NULL); | |
261 | if (lst == NULL) { | 261 | if (lst == NULL) { | |
262 | kcpuset_destroy(kcp); | 262 | kcpuset_destroy(kcp); | |
263 | return; | 263 | return; | |
264 | } | 264 | } | |
265 | kc->kc_next = *lst; | 265 | kc->kc_next = *lst; | |
266 | *lst = kcp; | 266 | *lst = kcp; | |
267 | } | 267 | } | |
268 | 268 | |||
269 | /* | 269 | /* | |
270 | * Routines to transfer the CPU set from / to userspace. | 270 | * Routines to transfer the CPU set from / to userspace. | |
271 | * Note: early boot case is not supported by these routines. | 271 | * Note: early boot case is not supported by these routines. | |
272 | */ | 272 | */ | |
273 | 273 | |||
274 | int | 274 | int | |
275 | kcpuset_copyin(const cpuset_t *ucp, kcpuset_t *kcp, size_t len) | 275 | kcpuset_copyin(const cpuset_t *ucp, kcpuset_t *kcp, size_t len) | |
276 | { | 276 | { | |
277 | kcpuset_impl_t *kc __unused = KC_GETSTRUCT(kcp); | 277 | kcpuset_impl_t *kc __unused = KC_GETSTRUCT(kcp); | |
278 | 278 | |||
279 | KASSERT(kc_initialised); | 279 | KASSERT(kc_initialised); | |
280 | KASSERT(kc->kc_refcnt > 0); | 280 | KASSERT(kc->kc_refcnt > 0); | |
281 | KASSERT(kc->kc_next == NULL); | 281 | KASSERT(kc->kc_next == NULL); | |
282 | 282 | |||
283 | if (len > kc_bitsize) { /* XXX */ | 283 | if (len > kc_bitsize) { /* XXX */ | |
284 | return EINVAL; | 284 | return EINVAL; | |
285 | } | 285 | } | |
286 | return copyin(ucp, kcp, len); | 286 | return copyin(ucp, kcp, len); | |
287 | } | 287 | } | |
288 | 288 | |||
289 | int | 289 | int | |
290 | kcpuset_copyout(kcpuset_t *kcp, cpuset_t *ucp, size_t len) | 290 | kcpuset_copyout(kcpuset_t *kcp, cpuset_t *ucp, size_t len) | |
291 | { | 291 | { | |
292 | kcpuset_impl_t *kc __unused = KC_GETSTRUCT(kcp); | 292 | kcpuset_impl_t *kc __unused = KC_GETSTRUCT(kcp); | |
293 | 293 | |||
294 | KASSERT(kc_initialised); | 294 | KASSERT(kc_initialised); | |
295 | KASSERT(kc->kc_refcnt > 0); | 295 | KASSERT(kc->kc_refcnt > 0); | |
296 | KASSERT(kc->kc_next == NULL); | 296 | KASSERT(kc->kc_next == NULL); | |
297 | 297 | |||
298 | if (len > kc_bitsize) { /* XXX */ | 298 | if (len > kc_bitsize) { /* XXX */ | |
299 | return EINVAL; | 299 | return EINVAL; | |
300 | } | 300 | } | |
301 | return copyout(kcp, ucp, len); | 301 | return copyout(kcp, ucp, len); | |
302 | } | 302 | } | |
303 | 303 | |||
304 | void | 304 | void | |
305 | kcpuset_copybits(const kcpuset_t *kcp, uint32_t *bitfield, size_t len) | 305 | kcpuset_export_u32(const kcpuset_t *kcp, uint32_t *bitfield, size_t len) | |
306 | { | 306 | { | |
307 | size_t rlen = MIN(kc_bitsize, len); | 307 | size_t rlen = MIN(kc_bitsize, len); | |
308 | 308 | |||
309 | KASSERT(kcp != NULL); | 309 | KASSERT(kcp != NULL); | |
310 | memcpy(bitfield, kcp->bits, rlen); | 310 | memcpy(bitfield, kcp->bits, rlen); | |
311 | } | 311 | } | |
312 | 312 | |||
313 | /* | 313 | /* | |
314 | * Routines to change bit field - zero, fill, copy, set, unset, etc. | 314 | * Routines to change bit field - zero, fill, copy, set, unset, etc. | |
315 | */ | 315 | */ | |
316 | 316 | |||
317 | void | 317 | void | |
318 | kcpuset_zero(kcpuset_t *kcp) | 318 | kcpuset_zero(kcpuset_t *kcp) | |
319 | { | 319 | { | |
320 | 320 | |||
321 | KASSERT(!kc_initialised || KC_GETSTRUCT(kcp)->kc_refcnt > 0); | 321 | KASSERT(!kc_initialised || KC_GETSTRUCT(kcp)->kc_refcnt > 0); | |
322 | KASSERT(!kc_initialised || KC_GETSTRUCT(kcp)->kc_next == NULL); | 322 | KASSERT(!kc_initialised || KC_GETSTRUCT(kcp)->kc_next == NULL); | |
323 | memset(kcp, 0, kc_bitsize); | 323 | memset(kcp, 0, kc_bitsize); | |
324 | } | 324 | } | |
325 | 325 | |||
326 | void | 326 | void | |
327 | kcpuset_fill(kcpuset_t *kcp) | 327 | kcpuset_fill(kcpuset_t *kcp) | |
328 | { | 328 | { | |
329 | 329 | |||
330 | KASSERT(!kc_initialised || KC_GETSTRUCT(kcp)->kc_refcnt > 0); | 330 | KASSERT(!kc_initialised || KC_GETSTRUCT(kcp)->kc_refcnt > 0); | |
331 | KASSERT(!kc_initialised || KC_GETSTRUCT(kcp)->kc_next == NULL); | 331 | KASSERT(!kc_initialised || KC_GETSTRUCT(kcp)->kc_next == NULL); | |
332 | memset(kcp, ~0, kc_bitsize); | 332 | memset(kcp, ~0, kc_bitsize); | |
333 | } | 333 | } | |
334 | 334 | |||
335 | void | 335 | void | |
336 | kcpuset_copy(kcpuset_t *dkcp, kcpuset_t *skcp) | 336 | kcpuset_copy(kcpuset_t *dkcp, kcpuset_t *skcp) | |
337 | { | 337 | { | |
338 | 338 | |||
339 | KASSERT(!kc_initialised || KC_GETSTRUCT(dkcp)->kc_refcnt > 0); | 339 | KASSERT(!kc_initialised || KC_GETSTRUCT(dkcp)->kc_refcnt > 0); | |
340 | KASSERT(!kc_initialised || KC_GETSTRUCT(dkcp)->kc_next == NULL); | 340 | KASSERT(!kc_initialised || KC_GETSTRUCT(dkcp)->kc_next == NULL); | |
341 | memcpy(dkcp, skcp, kc_bitsize); | 341 | memcpy(dkcp, skcp, kc_bitsize); | |
342 | } | 342 | } | |
343 | 343 | |||
344 | void | 344 | void | |
345 | kcpuset_set(kcpuset_t *kcp, cpuid_t i) | 345 | kcpuset_set(kcpuset_t *kcp, cpuid_t i) | |
346 | { | 346 | { | |
347 | const size_t j = i >> KC_SHIFT; | 347 | const size_t j = i >> KC_SHIFT; | |
348 | 348 | |||
349 | KASSERT(!kc_initialised || KC_GETSTRUCT(kcp)->kc_next == NULL); | 349 | KASSERT(!kc_initialised || KC_GETSTRUCT(kcp)->kc_next == NULL); | |
350 | KASSERT(j < kc_nfields); | 350 | KASSERT(j < kc_nfields); | |
351 | 351 | |||
352 | kcp->bits[j] |= 1 << (i & KC_MASK); | 352 | kcp->bits[j] |= 1 << (i & KC_MASK); | |
353 | } | 353 | } | |
354 | 354 | |||
355 | void | 355 | void | |
356 | kcpuset_clear(kcpuset_t *kcp, cpuid_t i) | 356 | kcpuset_clear(kcpuset_t *kcp, cpuid_t i) | |
357 | { | 357 | { | |
358 | const size_t j = i >> KC_SHIFT; | 358 | const size_t j = i >> KC_SHIFT; | |
359 | 359 | |||
360 | KASSERT(!kc_initialised || KC_GETSTRUCT(kcp)->kc_next == NULL); | 360 | KASSERT(!kc_initialised || KC_GETSTRUCT(kcp)->kc_next == NULL); | |
361 | KASSERT(j < kc_nfields); | 361 | KASSERT(j < kc_nfields); | |
362 | 362 | |||
363 | kcp->bits[j] &= ~(1 << (i & KC_MASK)); | 363 | kcp->bits[j] &= ~(1 << (i & KC_MASK)); | |
364 | } | 364 | } | |
365 | 365 | |||
366 | bool | 366 | bool | |
367 | kcpuset_isset(kcpuset_t *kcp, cpuid_t i) | 367 | kcpuset_isset(kcpuset_t *kcp, cpuid_t i) | |
368 | { | 368 | { | |
369 | const size_t j = i >> KC_SHIFT; | 369 | const size_t j = i >> KC_SHIFT; | |
370 | 370 | |||
371 | KASSERT(kcp != NULL); | 371 | KASSERT(kcp != NULL); | |
372 | KASSERT(!kc_initialised || KC_GETSTRUCT(kcp)->kc_refcnt > 0); | 372 | KASSERT(!kc_initialised || KC_GETSTRUCT(kcp)->kc_refcnt > 0); | |
373 | KASSERT(!kc_initialised || KC_GETSTRUCT(kcp)->kc_next == NULL); | 373 | KASSERT(!kc_initialised || KC_GETSTRUCT(kcp)->kc_next == NULL); | |
374 | KASSERT(j < kc_nfields); | 374 | KASSERT(j < kc_nfields); | |
375 | 375 | |||
376 | return ((1 << (i & KC_MASK)) & kcp->bits[j]) != 0; | 376 | return ((1 << (i & KC_MASK)) & kcp->bits[j]) != 0; | |
377 | } | 377 | } | |
378 | 378 | |||
379 | bool | 379 | bool | |
380 | kcpuset_isotherset(kcpuset_t *kcp, cpuid_t i) | 380 | kcpuset_isotherset(kcpuset_t *kcp, cpuid_t i) | |
381 | { | 381 | { | |
382 | const size_t j2 = i >> KC_SHIFT; | 382 | const size_t j2 = i >> KC_SHIFT; | |
383 | const uint32_t mask = ~(1 << (i & KC_MASK)); | 383 | const uint32_t mask = ~(1 << (i & KC_MASK)); | |
384 | 384 | |||
385 | for (size_t j = 0; j < kc_nfields; j++) { | 385 | for (size_t j = 0; j < kc_nfields; j++) { | |
386 | const uint32_t bits = kcp->bits[j]; | 386 | const uint32_t bits = kcp->bits[j]; | |
387 | if (bits && (j != j2 || (bits & mask) != 0)) { | 387 | if (bits && (j != j2 || (bits & mask) != 0)) { | |
388 | return true; | 388 | return true; | |
389 | } | 389 | } | |
390 | } | 390 | } | |
391 | return false; | 391 | return false; | |
392 | } | 392 | } | |
393 | 393 | |||
394 | bool | 394 | bool | |
395 | kcpuset_iszero(kcpuset_t *kcp) | 395 | kcpuset_iszero(kcpuset_t *kcp) | |
396 | { | 396 | { | |
397 | 397 | |||
398 | for (size_t j = 0; j < kc_nfields; j++) { | 398 | for (size_t j = 0; j < kc_nfields; j++) { | |
399 | if (kcp->bits[j] != 0) { | 399 | if (kcp->bits[j] != 0) { | |
400 | return false; | 400 | return false; | |
401 | } | 401 | } | |
402 | } | 402 | } | |
403 | return true; | 403 | return true; | |
404 | } | 404 | } | |
405 | 405 | |||
406 | bool | 406 | bool | |
407 | kcpuset_match(const kcpuset_t *kcp1, const kcpuset_t *kcp2) | 407 | kcpuset_match(const kcpuset_t *kcp1, const kcpuset_t *kcp2) | |
408 | { | 408 | { | |
409 | 409 | |||
410 | return memcmp(kcp1, kcp2, kc_bitsize) == 0; | 410 | return memcmp(kcp1, kcp2, kc_bitsize) == 0; | |
411 | } | 411 | } | |
412 | 412 | |||
413 | void | 413 | void | |
414 | kcpuset_merge(kcpuset_t *kcp1, kcpuset_t *kcp2) | 414 | kcpuset_merge(kcpuset_t *kcp1, kcpuset_t *kcp2) | |
415 | { | 415 | { | |
416 | 416 | |||
417 | for (size_t j = 0; j < kc_nfields; j++) { | 417 | for (size_t j = 0; j < kc_nfields; j++) { | |
418 | kcp1->bits[j] |= kcp2->bits[j]; | 418 | kcp1->bits[j] |= kcp2->bits[j]; | |
419 | } | 419 | } | |
420 | } | 420 | } | |
421 | 421 | |||
422 | void | 422 | void | |
423 | kcpuset_intersect(kcpuset_t *kcp1, kcpuset_t *kcp2) | 423 | kcpuset_intersect(kcpuset_t *kcp1, kcpuset_t *kcp2) | |
424 | { | 424 | { | |
425 | 425 | |||
426 | for (size_t j = 0; j < kc_nfields; j++) { | 426 | for (size_t j = 0; j < kc_nfields; j++) { | |
427 | kcp1->bits[j] &= kcp2->bits[j]; | 427 | kcp1->bits[j] &= kcp2->bits[j]; | |
428 | } | 428 | } | |
429 | } | 429 | } | |
430 | 430 | |||
431 | int | 431 | int | |
432 | kcpuset_countset(kcpuset_t *kcp) | 432 | kcpuset_countset(kcpuset_t *kcp) | |
433 | { | 433 | { | |
434 | int count = 0; | 434 | int count = 0; | |
435 | 435 | |||
436 | for (size_t j = 0; j < kc_nfields; j++) { | 436 | for (size_t j = 0; j < kc_nfields; j++) { | |
437 | count += popcount32(kcp->bits[j]); | 437 | count += popcount32(kcp->bits[j]); | |
438 | } | 438 | } | |
439 | return count; | 439 | return count; | |
440 | } | 440 | } | |
441 | 441 | |||
442 | /* | 442 | /* | |
443 | * Routines to set/clear the flags atomically. | 443 | * Routines to set/clear the flags atomically. | |
444 | */ | 444 | */ | |
445 | 445 | |||
446 | void | 446 | void | |
447 | kcpuset_atomic_set(kcpuset_t *kcp, cpuid_t i) | 447 | kcpuset_atomic_set(kcpuset_t *kcp, cpuid_t i) | |
448 | { | 448 | { | |
449 | const size_t j = i >> KC_SHIFT; | 449 | const size_t j = i >> KC_SHIFT; | |
450 | 450 | |||
451 | KASSERT(j < kc_nfields); | 451 | KASSERT(j < kc_nfields); | |
452 | atomic_or_32(&kcp->bits[j], 1 << (i & KC_MASK)); | 452 | atomic_or_32(&kcp->bits[j], 1 << (i & KC_MASK)); | |
453 | } | 453 | } | |
454 | 454 | |||
455 | void | 455 | void | |
456 | kcpuset_atomic_clear(kcpuset_t *kcp, cpuid_t i) | 456 | kcpuset_atomic_clear(kcpuset_t *kcp, cpuid_t i) | |
457 | { | 457 | { | |
458 | const size_t j = i >> KC_SHIFT; | 458 | const size_t j = i >> KC_SHIFT; | |
459 | 459 | |||
460 | KASSERT(j < kc_nfields); | 460 | KASSERT(j < kc_nfields); | |
461 | atomic_and_32(&kcp->bits[j], ~(1 << (i & KC_MASK))); | 461 | atomic_and_32(&kcp->bits[j], ~(1 << (i & KC_MASK))); | |
462 | } | 462 | } |
--- src/sys/sys/kcpuset.h 2012/08/20 22:01:30 1.7
+++ src/sys/sys/kcpuset.h 2012/09/16 22:09:33 1.8
@@ -1,73 +1,74 @@ | @@ -1,73 +1,74 @@ | |||
1 | /* $NetBSD: kcpuset.h,v 1.7 2012/08/20 22:01:30 rmind Exp $ */ | 1 | /* $NetBSD: kcpuset.h,v 1.8 2012/09/16 22:09:33 rmind Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2008, 2011 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2008, 2011 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to The NetBSD Foundation | 7 | * This code is derived from software contributed to The NetBSD Foundation | |
8 | * by Christos Zoulas and Mindaugas Rasiukevicius. | 8 | * by Christos Zoulas and Mindaugas Rasiukevicius. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | 15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | 16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | 17 | * documentation and/or other materials provided with the distribution. | |
18 | * | 18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
29 | * POSSIBILITY OF SUCH DAMAGE. | 29 | * POSSIBILITY OF SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | #ifndef _SYS_KCPUSET_H_ | 32 | #ifndef _SYS_KCPUSET_H_ | |
33 | #define _SYS_KCPUSET_H_ | 33 | #define _SYS_KCPUSET_H_ | |
34 | 34 | |||
35 | struct kcpuset; | 35 | struct kcpuset; | |
36 | typedef struct kcpuset kcpuset_t; | 36 | typedef struct kcpuset kcpuset_t; | |
37 | 37 | |||
38 | #ifdef _KERNEL | 38 | #ifdef _KERNEL | |
39 | 39 | |||
40 | #include <sys/sched.h> | 40 | #include <sys/sched.h> | |
41 | 41 | |||
42 | void kcpuset_sysinit(void); | 42 | void kcpuset_sysinit(void); | |
43 | 43 | |||
44 | void kcpuset_create(kcpuset_t **, bool); | 44 | void kcpuset_create(kcpuset_t **, bool); | |
45 | void kcpuset_destroy(kcpuset_t *); | 45 | void kcpuset_destroy(kcpuset_t *); | |
46 | void kcpuset_copy(kcpuset_t *, kcpuset_t *); | 46 | void kcpuset_copy(kcpuset_t *, kcpuset_t *); | |
47 | 47 | |||
48 | void kcpuset_use(kcpuset_t *); | 48 | void kcpuset_use(kcpuset_t *); | |
49 | void kcpuset_unuse(kcpuset_t *, kcpuset_t **); | 49 | void kcpuset_unuse(kcpuset_t *, kcpuset_t **); | |
50 | 50 | |||
51 | int kcpuset_copyin(const cpuset_t *, kcpuset_t *, size_t); | 51 | int kcpuset_copyin(const cpuset_t *, kcpuset_t *, size_t); | |
52 | int kcpuset_copyout(kcpuset_t *, cpuset_t *, size_t); | 52 | int kcpuset_copyout(kcpuset_t *, cpuset_t *, size_t); | |
53 | void kcpuset_copybits(const kcpuset_t *, uint32_t *, size_t); | |||
54 | 53 | |||
55 | void kcpuset_zero(kcpuset_t *); | 54 | void kcpuset_zero(kcpuset_t *); | |
56 | void kcpuset_fill(kcpuset_t *); | 55 | void kcpuset_fill(kcpuset_t *); | |
57 | void kcpuset_set(kcpuset_t *, cpuid_t); | 56 | void kcpuset_set(kcpuset_t *, cpuid_t); | |
58 | void kcpuset_clear(kcpuset_t *, cpuid_t); | 57 | void kcpuset_clear(kcpuset_t *, cpuid_t); | |
59 | 58 | |||
60 | bool kcpuset_isset(kcpuset_t *, cpuid_t); | 59 | bool kcpuset_isset(kcpuset_t *, cpuid_t); | |
61 | bool kcpuset_isotherset(kcpuset_t *, cpuid_t); | 60 | bool kcpuset_isotherset(kcpuset_t *, cpuid_t); | |
62 | bool kcpuset_iszero(kcpuset_t *); | 61 | bool kcpuset_iszero(kcpuset_t *); | |
63 | bool kcpuset_match(const kcpuset_t *, const kcpuset_t *); | 62 | bool kcpuset_match(const kcpuset_t *, const kcpuset_t *); | |
64 | void kcpuset_merge(kcpuset_t *, kcpuset_t *); | 63 | void kcpuset_merge(kcpuset_t *, kcpuset_t *); | |
65 | void kcpuset_intersect(kcpuset_t *, kcpuset_t *); | 64 | void kcpuset_intersect(kcpuset_t *, kcpuset_t *); | |
66 | int kcpuset_countset(kcpuset_t *); | 65 | int kcpuset_countset(kcpuset_t *); | |
67 | 66 | |||
68 | void kcpuset_atomic_set(kcpuset_t *, cpuid_t); | 67 | void kcpuset_atomic_set(kcpuset_t *, cpuid_t); | |
69 | void kcpuset_atomic_clear(kcpuset_t *, cpuid_t); | 68 | void kcpuset_atomic_clear(kcpuset_t *, cpuid_t); | |
70 | 69 | |||
70 | void kcpuset_export_u32(const kcpuset_t *, uint32_t *, size_t); | |||
71 | ||||
71 | #endif | 72 | #endif | |
72 | 73 | |||
73 | #endif /* _SYS_KCPUSET_H_ */ | 74 | #endif /* _SYS_KCPUSET_H_ */ |