1 /* $NetBSD: prom.c,v 1.42 2001/07/12 23:35:43 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1992, 1994, 1995, 1996 Carnegie Mellon University 5 * All Rights Reserved. 6 * 7 * Permission to use, copy, modify and distribute this software and its 8 * documentation is hereby granted, provided that both the copyright 9 * notice and this permission notice appear in all copies of the 10 * software, derivative works or modified versions, and any portions 11 * thereof, and that both notices appear in supporting documentation. 12 * 13 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 14 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 15 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 16 * 17 * Carnegie Mellon requests users of this software to return to 18 * 19 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 20 * School of Computer Science 21 * Carnegie Mellon University 22 * Pittsburgh PA 15213-3890 23 * 24 * any improvements or extensions that they make and grant Carnegie Mellon 25 * the rights to redistribute these changes. 26 */ 27 28 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 29 30 __KERNEL_RCSID(0, "$NetBSD: prom.c,v 1.42 2001/07/12 23:35:43 thorpej Exp $"); 31 32 #include "opt_multiprocessor.h" 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/lock.h> 37 #include <sys/proc.h> 38 #include <sys/user.h> 39 40 #include <uvm/uvm_extern.h> 41 42 #include <machine/cpu.h> 43 #include <machine/rpb.h> 44 #include <machine/alpha.h> 45 #define ENABLEPROM 46 #include <machine/prom.h> 47 48 #include <dev/cons.h> 49 50 /* XXX this is to fake out the console routines, while booting. */ 51 struct consdev promcons = { NULL, NULL, promcngetc, promcnputc, 52 nullcnpollc, NULL, makedev(23,0), 1 }; 53 54 struct rpb *hwrpb; 55 int alpha_console; 56 57 extern struct prom_vec prom_dispatch_v; 58 59 struct simplelock prom_slock; 60 61 #ifdef _PMAP_MAY_USE_PROM_CONSOLE 62 int prom_mapped = 1; /* Is PROM still mapped? */ 63 64 pt_entry_t prom_pte, saved_pte[1]; /* XXX */ 65 66 static pt_entry_t * 67 prom_lev1map(void) 68 { 69 struct alpha_pcb *apcb; 70 71 /* 72 * Find the level 1 map that we're currently running on. 73 */ 74 apcb = (struct alpha_pcb *)ALPHA_PHYS_TO_K0SEG(curpcb); 75 76 return ((pt_entry_t *)ALPHA_PHYS_TO_K0SEG(apcb->apcb_ptbr << PGSHIFT)); 77 } 78 #endif /* _PMAP_MAY_USE_PROM_CONSOLE */ 79 80 void 81 init_prom_interface(struct rpb *rpb) 82 { 83 struct crb *c; 84 85 c = (struct crb *)((char *)rpb + rpb->rpb_crb_off); 86 87 prom_dispatch_v.routine_arg = c->crb_v_dispatch; 88 prom_dispatch_v.routine = c->crb_v_dispatch->entry_va; 89 90 simple_lock_init(&prom_slock); 91 } 92 93 void 94 init_bootstrap_console(void) 95 { 96 char buf[4]; 97 98 init_prom_interface(hwrpb); 99 100 prom_getenv(PROM_E_TTY_DEV, buf, 4); 101 alpha_console = buf[0] - '0'; 102 103 /* XXX fake out the console routines, for now */ 104 cn_tab = &promcons; 105 } 106 107 #ifdef _PMAP_MAY_USE_PROM_CONSOLE 108 static void prom_cache_sync(void); 109 #endif 110 111 int 112 prom_enter(void) 113 { 114 int s; 115 116 s = splhigh(); 117 simple_lock(&prom_slock); 118 119 #ifdef _PMAP_MAY_USE_PROM_CONSOLE 120 /* 121 * If we have not yet switched out of the PROM's context 122 * (i.e. the first one after alpha_init()), then the PROM 123 * is still mapped, regardless of the `prom_mapped' setting. 124 */ 125 if (prom_mapped == 0 && curpcb != 0) { 126 if (!pmap_uses_prom_console()) 127 panic("prom_enter"); 128 { 129 pt_entry_t *lev1map; 130 131 lev1map = prom_lev1map(); /* XXX */ 132 saved_pte[0] = lev1map[0]; /* XXX */ 133 lev1map[0] = prom_pte; /* XXX */ 134 } 135 prom_cache_sync(); /* XXX */ 136 } 137 #endif 138 return s; 139 } 140 141 void 142 prom_leave(int s) 143 { 144 145 #ifdef _PMAP_MAY_USE_PROM_CONSOLE 146 /* 147 * See comment above. 148 */ 149 if (prom_mapped == 0 && curpcb != 0) { 150 if (!pmap_uses_prom_console()) 151 panic("prom_leave"); 152 { 153 pt_entry_t *lev1map; 154 155 lev1map = prom_lev1map(); /* XXX */ 156 lev1map[0] = saved_pte[0]; /* XXX */ 157 } 158 prom_cache_sync(); /* XXX */ 159 } 160 #endif 161 simple_unlock(&prom_slock); 162 splx(s); 163 } 164 165 #ifdef _PMAP_MAY_USE_PROM_CONSOLE 166 static void 167 prom_cache_sync(void) 168 { 169 ALPHA_TBIA(); 170 alpha_pal_imb(); 171 } 172 #endif 173 174 /* 175 * promcnputc: 176 * 177 * Remap char before passing off to prom. 178 * 179 * Prom only takes 32 bit addresses. Copy char somewhere prom can 180 * find it. This routine will stop working after pmap_rid_of_console 181 * is called in alpha_init. This is due to the hard coded address 182 * of the console area. 183 */ 184 void 185 promcnputc(dev_t dev, int c) 186 { 187 prom_return_t ret; 188 unsigned char *to = (unsigned char *)0x20000000; 189 int s; 190 191 s = prom_enter(); /* splhigh() and map prom */ 192 *to = c; 193 194 do { 195 ret.bits = prom_putstr(alpha_console, to, 1); 196 } while ((ret.u.retval & 1) == 0); 197 198 prom_leave(s); /* unmap prom and splx(s) */ 199 } 200 201 /* 202 * promcngetc: 203 * 204 * Wait for the prom to get a real char and pass it back. 205 */ 206 int 207 promcngetc(dev_t dev) 208 { 209 prom_return_t ret; 210 int s; 211 212 for (;;) { 213 s = prom_enter(); 214 ret.bits = prom_getc(alpha_console); 215 prom_leave(s); 216 if (ret.u.status == 0 || ret.u.status == 1) 217 return (ret.u.retval); 218 } 219 } 220 221 /* 222 * promcnlookc: 223 * 224 * See if prom has a real char and pass it back. 225 */ 226 int 227 promcnlookc(dev_t dev, char *cp) 228 { 229 prom_return_t ret; 230 int s; 231 232 s = prom_enter(); 233 ret.bits = prom_getc(alpha_console); 234 prom_leave(s); 235 if (ret.u.status == 0 || ret.u.status == 1) { 236 *cp = ret.u.retval; 237 return 1; 238 } else 239 return 0; 240 } 241 242 int 243 prom_getenv(int id, char *buf, int len) 244 { 245 unsigned char *to = (unsigned char *)0x20000000; 246 prom_return_t ret; 247 int s; 248 249 s = prom_enter(); 250 ret.bits = prom_getenv_disp(id, to, len); 251 memcpy(buf, to, len); 252 prom_leave(s); 253 254 if (ret.u.status & 0x4) 255 ret.u.retval = 0; 256 buf[ret.u.retval] = '\0'; 257 258 return (ret.bits); 259 } 260 261 void 262 prom_halt(int halt) 263 { 264 struct pcs *p; 265 266 /* 267 * Turn off interrupts, for sanity. 268 */ 269 (void) splhigh(); 270 271 /* 272 * Set "boot request" part of the CPU state depending on what 273 * we want to happen when we halt. 274 */ 275 p = LOCATE_PCS(hwrpb, hwrpb->rpb_primary_cpu_id); 276 p->pcs_flags &= ~(PCS_RC | PCS_HALT_REQ); 277 if (halt) 278 p->pcs_flags |= PCS_HALT_STAY_HALTED; 279 else 280 p->pcs_flags |= PCS_HALT_WARM_BOOT; 281 282 /* 283 * Halt the machine. 284 */ 285 alpha_pal_halt(); 286 } 287 288 u_int64_t 289 hwrpb_checksum(void) 290 { 291 u_int64_t *p, sum; 292 int i; 293 294 for (i = 0, p = (u_int64_t *)hwrpb, sum = 0; 295 i < (offsetof(struct rpb, rpb_checksum) / sizeof (u_int64_t)); 296 i++, p++) 297 sum += *p; 298 299 return (sum); 300 } 301 302 void 303 hwrpb_primary_init(void) 304 { 305 struct pcs *p; 306 307 p = LOCATE_PCS(hwrpb, hwrpb->rpb_primary_cpu_id); 308 309 /* Initialize the primary's HWPCB and the Virtual Page Table Base. */ 310 memcpy(p->pcs_hwpcb, &proc0.p_addr->u_pcb.pcb_hw, 311 sizeof proc0.p_addr->u_pcb.pcb_hw); 312 hwrpb->rpb_vptb = VPTBASE; 313 314 hwrpb->rpb_checksum = hwrpb_checksum(); 315 } 316 317 void 318 hwrpb_restart_setup(void) 319 { 320 struct pcs *p; 321 322 /* Clear bootstrap-in-progress flag since we're done bootstrapping */ 323 p = LOCATE_PCS(hwrpb, hwrpb->rpb_primary_cpu_id); 324 p->pcs_flags &= ~PCS_BIP; 325 326 /* when 'c'ontinuing from console halt, do a dump */ 327 hwrpb->rpb_rest_term = (u_int64_t)&XentRestart; 328 hwrpb->rpb_rest_term_val = 0x1; 329 330 hwrpb->rpb_checksum = hwrpb_checksum(); 331 332 p->pcs_flags |= (PCS_RC | PCS_CV); 333 } 334 335 u_int64_t 336 console_restart(struct trapframe *framep) 337 { 338 struct pcs *p; 339 340 /* Clear restart-capable flag, since we can no longer restart. */ 341 p = LOCATE_PCS(hwrpb, hwrpb->rpb_primary_cpu_id); 342 p->pcs_flags &= ~PCS_RC; 343 344 /* Fill in the missing frame slots */ 345 346 framep->tf_regs[FRAME_PS] = p->pcs_halt_ps; 347 framep->tf_regs[FRAME_PC] = p->pcs_halt_pc; 348 framep->tf_regs[FRAME_T11] = p->pcs_halt_r25; 349 framep->tf_regs[FRAME_RA] = p->pcs_halt_r26; 350 framep->tf_regs[FRAME_T12] = p->pcs_halt_r27; 351 352 panic("user requested console halt"); 353 354 return (1); 355 } 356