1 /* $NetBSD: cpu.c,v 1.67 2012/01/15 10:45:03 jmcneill Exp $ */ 2 3 /*- 4 * Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include "opt_cpu.h" 30 #include "opt_hz.h" 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.67 2012/01/15 10:45:03 jmcneill Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/conf.h> 37 #include <sys/proc.h> 38 #include <sys/systm.h> 39 #include <sys/device.h> 40 #include <sys/reboot.h> 41 #include <sys/lwp.h> 42 #include <sys/cpu.h> 43 #include <sys/mbuf.h> 44 #include <sys/msgbuf.h> 45 #include <sys/kmem.h> 46 #include <sys/kernel.h> 47 #include <sys/mount.h> 48 49 #include <dev/cons.h> 50 51 #include <machine/cpu.h> 52 #include <machine/mainbus.h> 53 #include <machine/pcb.h> 54 #include <machine/machdep.h> 55 #include <machine/thunk.h> 56 57 #include <uvm/uvm_extern.h> 58 #include <uvm/uvm_page.h> 59 60 #if __GNUC_PREREQ__(4,4) 61 #define cpu_unreachable() __builtin_unreachable() 62 #else 63 #define cpu_unreachable() do { thunk_abort(); } while (0) 64 #endif 65 66 static int cpu_match(device_t, cfdata_t, void *); 67 static void cpu_attach(device_t, device_t, void *); 68 69 struct cpu_info cpu_info_primary = { 70 .ci_dev = 0, 71 .ci_self = &cpu_info_primary, 72 .ci_idepth = -1, 73 .ci_curlwp = &lwp0, 74 }; 75 76 char cpu_model[48] = "virtual processor"; 77 78 typedef struct cpu_softc { 79 device_t sc_dev; 80 struct cpu_info *sc_ci; 81 } cpu_softc_t; 82 83 84 /* statics */ 85 static struct pcb lwp0pcb; 86 static void *um_msgbuf; 87 88 89 /* attachment */ 90 CFATTACH_DECL_NEW(cpu, sizeof(cpu_softc_t), cpu_match, cpu_attach, NULL, NULL); 91 92 static int 93 cpu_match(device_t parent, cfdata_t match, void *opaque) 94 { 95 struct thunkbus_attach_args *taa = opaque; 96 97 if (taa->taa_type != THUNKBUS_TYPE_CPU) 98 return 0; 99 100 return 1; 101 } 102 103 static void 104 cpu_attach(device_t parent, device_t self, void *opaque) 105 { 106 cpu_softc_t *sc = device_private(self); 107 108 aprint_naive("\n"); 109 aprint_normal("\n"); 110 111 sc->sc_dev = self; 112 sc->sc_ci = &cpu_info_primary; 113 } 114 115 void 116 cpu_configure(void) 117 { 118 if (config_rootfound("mainbus", NULL) == NULL) 119 panic("configure: mainbus not configured"); 120 121 spl0(); 122 } 123 124 125 /* main guts */ 126 void 127 cpu_reboot(int howto, char *bootstr) 128 { 129 extern void usermode_reboot(void); 130 131 if (cold) 132 howto |= RB_HALT; 133 134 if ((howto & RB_NOSYNC) == 0) 135 vfs_shutdown(); 136 else 137 suspendsched(); 138 139 doshutdownhooks(); 140 pmf_system_shutdown(boothowto); 141 142 if ((howto & RB_POWERDOWN) == RB_POWERDOWN) 143 thunk_exit(0); 144 145 splhigh(); 146 147 if (howto & RB_DUMP) 148 thunk_abort(); 149 150 if (howto & RB_HALT) { 151 printf("\n"); 152 printf("The operating system has halted.\n"); 153 printf("Please press any key to reboot.\n\n"); 154 cnpollc(1); 155 cngetc(); 156 cnpollc(0); 157 } 158 159 printf("rebooting...\n"); 160 161 usermode_reboot(); 162 163 /* NOTREACHED */ 164 cpu_unreachable(); 165 } 166 167 void 168 cpu_need_resched(struct cpu_info *ci, int flags) 169 { 170 ci->ci_want_resched |= flags; 171 aston(ci); 172 } 173 174 void 175 cpu_need_proftick(struct lwp *l) 176 { 177 } 178 179 lwp_t * 180 cpu_switchto(lwp_t *oldlwp, lwp_t *newlwp, bool returning) 181 { 182 struct pcb *oldpcb = oldlwp ? lwp_getpcb(oldlwp) : NULL; 183 struct pcb *newpcb = lwp_getpcb(newlwp); 184 struct cpu_info *ci = curcpu(); 185 186 #ifdef CPU_DEBUG 187 thunk_printf_debug("cpu_switchto [%s,pid=%d,lid=%d] -> [%s,pid=%d,lid=%d]\n", 188 oldlwp ? oldlwp->l_name : "none", 189 oldlwp ? oldlwp->l_proc->p_pid : -1, 190 oldlwp ? oldlwp->l_lid : -1, 191 newlwp ? newlwp->l_name : "none", 192 newlwp ? newlwp->l_proc->p_pid : -1, 193 newlwp ? newlwp->l_lid : -1); 194 if (oldpcb) { 195 thunk_printf_debug(" oldpcb uc_link=%p, uc_stack.ss_sp=%p, " 196 "uc_stack.ss_size=%d\n", 197 oldpcb->pcb_ucp.uc_link, 198 oldpcb->pcb_ucp.uc_stack.ss_sp, 199 (int)oldpcb->pcb_ucp.uc_stack.ss_size); 200 } 201 if (newpcb) { 202 thunk_printf_debug(" newpcb uc_link=%p, uc_stack.ss_sp=%p, " 203 "uc_stack.ss_size=%d\n", 204 newpcb->pcb_ucp.uc_link, 205 newpcb->pcb_ucp.uc_stack.ss_sp, 206 (int)newpcb->pcb_ucp.uc_stack.ss_size); 207 } 208 #endif /* !CPU_DEBUG */ 209 210 ci->ci_stash = oldlwp; 211 212 if (oldpcb) { 213 oldpcb->pcb_errno = thunk_geterrno(); 214 thunk_seterrno(newpcb->pcb_errno); 215 curlwp = newlwp; 216 if (thunk_swapcontext(&oldpcb->pcb_ucp, &newpcb->pcb_ucp)) 217 panic("swapcontext failed"); 218 } else { 219 thunk_seterrno(newpcb->pcb_errno); 220 curlwp = newlwp; 221 if (thunk_setcontext(&newpcb->pcb_ucp)) 222 panic("setcontext failed"); 223 } 224 225 #ifdef CPU_DEBUG 226 thunk_printf_debug("cpu_switchto: returning %p (was %p)\n", ci->ci_stash, oldlwp); 227 #endif 228 return ci->ci_stash; 229 } 230 231 void 232 cpu_dumpconf(void) 233 { 234 #ifdef CPU_DEBUG 235 thunk_printf_debug("cpu_dumpconf\n"); 236 #endif 237 } 238 239 void 240 cpu_signotify(struct lwp *l) 241 { 242 } 243 244 void 245 cpu_getmcontext(struct lwp *l, mcontext_t *mcp, unsigned int *flags) 246 { 247 struct pcb *pcb = lwp_getpcb(l); 248 ucontext_t *ucp = &pcb->pcb_userret_ucp; 249 250 #ifdef CPU_DEBUG 251 thunk_printf_debug("cpu_getmcontext\n"); 252 #endif 253 memcpy(mcp, &ucp->uc_mcontext, sizeof(mcontext_t)); 254 return; 255 } 256 257 int 258 cpu_setmcontext(struct lwp *l, const mcontext_t *mcp, unsigned int flags) 259 { 260 struct pcb *pcb = lwp_getpcb(l); 261 ucontext_t *ucp = &pcb->pcb_userret_ucp; 262 263 #ifdef CPU_DEBUG 264 thunk_printf_debug("cpu_setmcontext\n"); 265 #endif 266 memcpy(&ucp->uc_mcontext, mcp, sizeof(mcontext_t)); 267 return 0; 268 } 269 270 void 271 cpu_idle(void) 272 { 273 struct cpu_info *ci = curcpu(); 274 275 if (ci->ci_want_resched) 276 return; 277 278 thunk_idle(); 279 } 280 281 void 282 cpu_lwp_free(struct lwp *l, int proc) 283 { 284 #ifdef CPU_DEBUG 285 thunk_printf_debug("cpu_lwp_free (dummy)\n"); 286 #endif 287 } 288 289 void 290 cpu_lwp_free2(struct lwp *l) 291 { 292 struct pcb *pcb = lwp_getpcb(l); 293 294 #ifdef CPU_DEBUG 295 thunk_printf_debug("cpu_lwp_free2\n"); 296 #endif 297 298 if (pcb == NULL) 299 return; 300 /* XXX nothing to do? */ 301 } 302 303 static void 304 cpu_lwp_trampoline(ucontext_t *ucp, void (*func)(void *), void *arg) 305 { 306 #ifdef CPU_DEBUG 307 thunk_printf_debug("cpu_lwp_trampoline called with func %p, arg %p\n", (void *) func, arg); 308 #endif 309 /* init lwp */ 310 lwp_startup(curcpu()->ci_stash, curlwp); 311 312 /* actual jump */ 313 thunk_makecontext(ucp, (void (*)(void)) func, 1, arg, NULL, NULL); 314 thunk_setcontext(ucp); 315 } 316 317 void 318 cpu_lwp_fork(struct lwp *l1, struct lwp *l2, void *stack, size_t stacksize, 319 void (*func)(void *), void *arg) 320 { 321 struct pcb *pcb1 = lwp_getpcb(l1); 322 struct pcb *pcb2 = lwp_getpcb(l2); 323 324 #ifdef CPU_DEBUG 325 thunk_printf_debug("cpu_lwp_fork [%s/%p] -> [%s/%p] stack=%p stacksize=%d\n", 326 l1 ? l1->l_name : "none", l1, 327 l2 ? l2->l_name : "none", l2, 328 stack, (int)stacksize); 329 #endif 330 331 if (stack) 332 panic("%s: stack passed, can't handle\n", __func__); 333 334 /* copy the PCB and its switchframes from parent */ 335 memcpy(pcb2, pcb1, sizeof(struct pcb)); 336 337 /* refresh context */ 338 if (thunk_getcontext(&pcb2->pcb_ucp)) 339 panic("getcontext failed"); 340 341 /* recalculate the system stack top */ 342 pcb2->sys_stack_top = pcb2->sys_stack + TRAPSTACKSIZE; 343 344 /* get l2 its own stack */ 345 pcb2->pcb_ucp.uc_stack.ss_sp = pcb2->sys_stack; 346 pcb2->pcb_ucp.uc_stack.ss_size = pcb2->sys_stack_top - pcb2->sys_stack; 347 pcb2->pcb_ucp.uc_flags = _UC_STACK | _UC_CPU; 348 pcb2->pcb_ucp.uc_link = &pcb2->pcb_userret_ucp; 349 thunk_makecontext(&pcb2->pcb_ucp, 350 (void (*)(void)) cpu_lwp_trampoline, 351 3, &pcb2->pcb_ucp, func, arg); 352 } 353 354 void 355 cpu_initclocks(void) 356 { 357 extern timer_t clock_timerid; 358 359 thunk_timer_start(clock_timerid, HZ); 360 } 361 362 void 363 cpu_startup(void) 364 { 365 vaddr_t minaddr, maxaddr; 366 size_t msgbufsize = 32 * 1024; 367 368 /* get ourself a message buffer */ 369 um_msgbuf = kmem_zalloc(msgbufsize, KM_SLEEP); 370 if (um_msgbuf == NULL) 371 panic("couldn't allocate msgbuf"); 372 initmsgbuf(um_msgbuf, msgbufsize); 373 374 /* allocate a submap for physio, 1Mb enough? */ 375 minaddr = 0; 376 phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, 377 1024 * 1024, 0, false, NULL); 378 379 /* say hi! */ 380 banner(); 381 382 /* init lwp0 */ 383 memset(&lwp0pcb, 0, sizeof(lwp0pcb)); 384 thunk_getcontext(&lwp0pcb.pcb_ucp); 385 uvm_lwp_setuarea(&lwp0, (vaddr_t) &lwp0pcb); 386 memcpy(&lwp0pcb.pcb_userret_ucp, &lwp0pcb.pcb_ucp, sizeof(ucontext_t)); 387 388 /* set stack top */ 389 lwp0pcb.sys_stack_top = lwp0pcb.sys_stack + TRAPSTACKSIZE; 390 } 391 392 void 393 cpu_rootconf(void) 394 { 395 extern char *usermode_root_device; 396 device_t rdev; 397 398 if (usermode_root_device != NULL) { 399 rdev = device_find_by_xname(usermode_root_device); 400 } else { 401 rdev = device_find_by_xname("ld0"); 402 if (rdev == NULL) 403 rdev = device_find_by_xname("md0"); 404 } 405 406 aprint_normal("boot device: %s\n", 407 rdev ? device_xname(rdev) : "<unknown>"); 408 setroot(rdev, 0); 409 } 410 411 bool 412 cpu_intr_p(void) 413 { 414 int idepth; 415 416 kpreempt_disable(); 417 idepth = curcpu()->ci_idepth; 418 kpreempt_enable(); 419 420 return (idepth >= 0); 421 } 422