1 /* $NetBSD: cpu.c,v 1.4 2009/10/21 16:06:59 snj 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 <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.4 2009/10/21 16:06:59 snj Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/conf.h> 34 #include <sys/proc.h> 35 #include <sys/user.h> 36 #include <sys/systm.h> 37 #include <sys/device.h> 38 #include <sys/reboot.h> 39 #include <sys/lwp.h> 40 #include <sys/cpu.h> 41 #include <sys/mbuf.h> 42 43 #include <dev/cons.h> 44 45 #include <machine/cpu.h> 46 #include <machine/mainbus.h> 47 48 #include <uvm/uvm_extern.h> 49 #include <uvm/uvm_page.h> 50 51 /* #define CPU_DEBUG */ 52 53 static int cpu_match(device_t, cfdata_t, void *); 54 static void cpu_attach(device_t, device_t, void *); 55 56 struct cpu_info cpu_info_primary; 57 char cpu_model[48] = "virtual processor"; 58 59 typedef struct cpu_softc { 60 device_t sc_dev; 61 struct cpu_info *sc_ci; 62 } cpu_softc_t; 63 64 CFATTACH_DECL_NEW(cpu, sizeof(cpu_softc_t), cpu_match, cpu_attach, NULL, NULL); 65 66 static int 67 cpu_match(device_t parent, cfdata_t match, void *opaque) 68 { 69 struct thunkbus_attach_args *taa = opaque; 70 71 if (taa->taa_type != THUNKBUS_TYPE_CPU) 72 return 0; 73 74 return 1; 75 } 76 77 static void 78 cpu_attach(device_t parent, device_t self, void *opaque) 79 { 80 cpu_softc_t *sc = device_private(self); 81 82 aprint_naive("\n"); 83 aprint_normal("\n"); 84 85 sc->sc_dev = self; 86 sc->sc_ci = &cpu_info_primary; 87 sc->sc_ci->ci_dev = 0; 88 sc->sc_ci->ci_self = &cpu_info_primary; 89 #if notyet 90 sc->sc_ci->ci_curlwp = &lwp0; 91 #endif 92 } 93 94 void 95 cpu_configure(void) 96 { 97 if (config_rootfound("mainbus", NULL) == NULL) 98 panic("configure: mainbus not configured"); 99 100 spl0(); 101 } 102 103 void 104 cpu_reboot(int howto, char *bootstr) 105 { 106 extern void exit(int); 107 extern void abort(void); 108 109 splhigh(); 110 111 if ((howto & RB_POWERDOWN) == RB_POWERDOWN) 112 exit(0); 113 114 if (howto & RB_HALT) { 115 printf("\n"); 116 printf("The operating system has halted.\n"); 117 printf("Please press any key to reboot.\n\n"); 118 cnpollc(1); 119 cngetc(); 120 cnpollc(0); 121 } 122 123 printf("rebooting...\n"); 124 125 /* 126 * XXXJDM If we've panic'd, make sure we dump a core 127 */ 128 abort(); 129 130 /* NOTREACHED */ 131 } 132 133 void 134 cpu_need_resched(struct cpu_info *ci, int flags) 135 { 136 ci->ci_want_resched = 1; 137 } 138 139 void 140 cpu_need_proftick(struct lwp *l) 141 { 142 } 143 144 lwp_t * 145 cpu_switchto(lwp_t *oldlwp, lwp_t *newlwp, bool returning) 146 { 147 extern int errno; 148 struct pcb *oldpcb = (struct pcb *)(oldlwp ? oldlwp->l_addr : NULL); 149 struct pcb *newpcb = (struct pcb *)newlwp->l_addr; 150 struct cpu_info *ci = curcpu(); 151 152 #ifdef CPU_DEBUG 153 printf("cpu_switchto [%s] -> [%s]\n", 154 oldlwp ? oldlwp->l_name : "none", 155 newlwp ? newlwp->l_name : "none"); 156 if (oldpcb) { 157 printf(" oldpcb uc_link=%p, uc_stack.ss_sp=%p, " 158 "uc_stack.ss_size=%d\n", 159 oldpcb->pcb_ucp.uc_link, 160 oldpcb->pcb_ucp.uc_stack.ss_sp, 161 (int)oldpcb->pcb_ucp.uc_stack.ss_size); 162 } 163 if (newpcb) { 164 printf(" newpcb uc_link=%p, uc_stack.ss_sp=%p, " 165 "uc_stack.ss_size=%d\n", 166 newpcb->pcb_ucp.uc_link, 167 newpcb->pcb_ucp.uc_stack.ss_sp, 168 (int)newpcb->pcb_ucp.uc_stack.ss_size); 169 } 170 #endif /* !CPU_DEBUG */ 171 172 ci->ci_stash = oldlwp; 173 curlwp = newlwp; 174 if (oldpcb) { 175 if (swapcontext(&oldpcb->pcb_ucp, &newpcb->pcb_ucp)) 176 panic("swapcontext failed: %d", errno); 177 } else { 178 if (setcontext(&newpcb->pcb_ucp)) 179 panic("setcontext failed: %d", errno); 180 } 181 182 #ifdef CPU_DEBUG 183 printf("cpu_switchto: returning %p (was %p)\n", ci->ci_stash, oldlwp); 184 #endif 185 return ci->ci_stash; 186 } 187 188 void 189 cpu_dumpconf(void) 190 { 191 #ifdef CPU_DEBUG 192 printf("cpu_dumpconf\n"); 193 #endif 194 } 195 196 void 197 cpu_signotify(struct lwp *l) 198 { 199 #ifdef CPU_DEBUG 200 printf("cpu_signotify\n"); 201 #endif 202 } 203 204 void 205 cpu_getmcontext(struct lwp *l, mcontext_t *mcp, unsigned int *flags) 206 { 207 #ifdef CPU_DEBUG 208 printf("cpu_getmcontext\n"); 209 #endif 210 } 211 212 int 213 cpu_setmcontext(struct lwp *l, const mcontext_t *mcp, unsigned int flags) 214 { 215 #ifdef CPU_DEBUG 216 printf("cpu_setmcontext\n"); 217 #endif 218 return 0; 219 } 220 221 void 222 cpu_idle(void) 223 { 224 extern int usleep(useconds_t); 225 struct cpu_info *ci = curcpu(); 226 227 if (ci->ci_want_resched) 228 return; 229 230 #if notyet 231 usleep(10000); 232 #endif 233 } 234 235 void 236 cpu_lwp_free(struct lwp *l, int proc) 237 { 238 #ifdef CPU_DEBUG 239 printf("cpu_lwp_free\n"); 240 #endif 241 } 242 243 void 244 cpu_lwp_free2(struct lwp *l) 245 { 246 struct pcb *pcb = (struct pcb *)l->l_addr; 247 248 #ifdef CPU_DEBUG 249 printf("cpu_lwp_free2\n"); 250 #endif 251 252 if (pcb == NULL) 253 return; 254 255 if (pcb->pcb_needfree) { 256 free(pcb->pcb_ucp.uc_stack.ss_sp, M_TEMP); 257 pcb->pcb_ucp.uc_stack.ss_sp = NULL; 258 pcb->pcb_ucp.uc_stack.ss_size = 0; 259 pcb->pcb_needfree = false; 260 } 261 } 262 263 static void 264 cpu_lwp_trampoline(void (*func)(void *), void *arg) 265 { 266 lwp_startup(curcpu()->ci_stash, curlwp); 267 268 func(arg); 269 } 270 271 void 272 cpu_lwp_fork(struct lwp *l1, struct lwp *l2, void *stack, size_t stacksize, 273 void (*func)(void *), void *arg) 274 { 275 extern int errno; 276 struct pcb *pcb = (struct pcb *)l2->l_addr; 277 278 #ifdef CPU_DEBUG 279 printf("cpu_lwp_fork [%s/%p] -> [%s/%p] stack=%p stacksize=%d\n", 280 l1 ? l1->l_name : "none", l1, 281 l2 ? l2->l_name : "none", l2, 282 stack, (int)stacksize); 283 #endif 284 285 /* XXXJDM */ 286 if (stack == NULL) { 287 stack = malloc(PAGE_SIZE, M_TEMP, M_NOWAIT); 288 stacksize = PAGE_SIZE; 289 pcb->pcb_needfree = true; 290 } else 291 pcb->pcb_needfree = false; 292 293 if (getcontext(&pcb->pcb_ucp)) 294 panic("getcontext failed: %d", errno); 295 pcb->pcb_ucp.uc_stack.ss_sp = stack; 296 pcb->pcb_ucp.uc_stack.ss_size = stacksize; 297 pcb->pcb_ucp.uc_link = NULL; 298 pcb->pcb_ucp.uc_flags = _UC_STACK | _UC_CPU; 299 makecontext(&pcb->pcb_ucp, (void (*)(void))cpu_lwp_trampoline, 300 2, func, arg); 301 } 302 303 void 304 cpu_initclocks(void) 305 { 306 } 307 308 void 309 cpu_startup(void) 310 { 311 extern struct vm_map *mb_map; 312 vaddr_t minaddr, maxaddr; 313 char pbuf[9]; 314 315 printf("%s%s", copyright, version); 316 format_bytes(pbuf, sizeof(pbuf), ptoa(physmem)); 317 printf("total memory = %s\n", pbuf); 318 319 minaddr = 0; 320 mb_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, 321 nmbclusters * mclbytes, VM_MAP_INTRSAFE, false, NULL); 322 323 format_bytes(pbuf, sizeof(pbuf), ptoa(uvmexp.free)); 324 printf("avail memory = %s\n", pbuf); 325 } 326 327 void 328 cpu_rootconf(void) 329 { 330 device_t rdev; 331 332 rdev = device_find_by_xname("md0"); 333 334 setroot(rdev, 0); 335 } 336 337 bool 338 cpu_intr_p(void) 339 { 340 printf("cpu_intr_p\n"); 341 return false; 342 } 343