1/* $NetBSD: prom.c,v 1.47 2011/05/24 20:26:34 rmind 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.47 2011/05/24 20:26:34 rmind Exp $"); 31 32#include "opt_multiprocessor.h" 33 34#include <sys/param.h> 35#include <sys/systm.h> 36#include <sys/proc.h> 37#include <sys/cpu.h> 38 39#include <uvm/uvm_extern.h> 40 41#include <machine/rpb.h> 42#include <machine/alpha.h> 43#define ENABLEPROM 44#include <machine/prom.h> 45 46#include <dev/cons.h> 47 48/* XXX this is to fake out the console routines, while booting. */ 49struct consdev promcons = { NULL, NULL, promcngetc, promcnputc, 50 nullcnpollc, NULL, NULL, NULL, makedev(23,0), 1 }; 51 52struct rpb *hwrpb; 53int alpha_console; 54 55extern struct prom_vec prom_dispatch_v; 56 57static kmutex_t prom_lock; 58 59#ifdef _PMAP_MAY_USE_PROM_CONSOLE 60int prom_mapped = 1; /* Is PROM still mapped? */ 61 62pt_entry_t prom_pte, saved_pte[1]; /* XXX */ 63 64static pt_entry_t * 65prom_lev1map(void) 66{ 67 struct alpha_pcb *apcb; 68 69 /* 70 * Find the level 1 map that we're currently running on. 71 */ 72 apcb = (struct alpha_pcb *)ALPHA_PHYS_TO_K0SEG(curpcb); 73 74 return ((pt_entry_t *)ALPHA_PHYS_TO_K0SEG(apcb->apcb_ptbr << PGSHIFT)); 75} 76#endif /* _PMAP_MAY_USE_PROM_CONSOLE */ 77 78void 79init_prom_interface(struct rpb *rpb) 80{ 81 struct crb *c; 82 83 c = (struct crb *)((char *)rpb + rpb->rpb_crb_off); 84 85 prom_dispatch_v.routine_arg = c->crb_v_dispatch; 86 prom_dispatch_v.routine = c->crb_v_dispatch->entry_va; 87 88 mutex_init(&prom_lock, MUTEX_DEFAULT, IPL_HIGH); 89} 90 91void 92init_bootstrap_console(void) 93{ 94 char buf[4]; 95 96 init_prom_interface(hwrpb); 97 98 prom_getenv(PROM_E_TTY_DEV, buf, 4); 99 alpha_console = buf[0] - '0'; 100 101 /* XXX fake out the console routines, for now */ 102 cn_tab = &promcons; 103} 104 105#ifdef _PMAP_MAY_USE_PROM_CONSOLE 106static void prom_cache_sync(void); 107#endif 108 109void 110prom_enter(void) 111{ 112 113 mutex_enter(&prom_lock); 114 115#ifdef _PMAP_MAY_USE_PROM_CONSOLE 116 /* 117 * If we have not yet switched out of the PROM's context 118 * (i.e. the first one after alpha_init()), then the PROM 119 * is still mapped, regardless of the `prom_mapped' setting. 120 */ 121 if (prom_mapped == 0 && curpcb != 0) { 122 if (!pmap_uses_prom_console()) 123 panic("prom_enter"); 124 { 125 pt_entry_t *lev1map; 126 127 lev1map = prom_lev1map(); /* XXX */ 128 saved_pte[0] = lev1map[0]; /* XXX */ 129 lev1map[0] = prom_pte; /* XXX */ 130 } 131 prom_cache_sync(); /* XXX */ 132 } 133#endif 134} 135 136void 137prom_leave(void) 138{ 139 140#ifdef _PMAP_MAY_USE_PROM_CONSOLE 141 /* 142 * See comment above. 143 */ 144 if (prom_mapped == 0 && curpcb != 0) { 145 if (!pmap_uses_prom_console()) 146 panic("prom_leave"); 147 { 148 pt_entry_t *lev1map; 149 150 lev1map = prom_lev1map(); /* XXX */ 151 lev1map[0] = saved_pte[0]; /* XXX */ 152 } 153 prom_cache_sync(); /* XXX */ 154 } 155#endif 156 mutex_exit(&prom_lock); 157} 158 159#ifdef _PMAP_MAY_USE_PROM_CONSOLE 160static void 161prom_cache_sync(void) 162{ 163 ALPHA_TBIA(); 164 alpha_pal_imb(); 165} 166#endif 167 168/* 169 * promcnputc: 170 * 171 * Remap char before passing off to prom. 172 * 173 * Prom only takes 32 bit addresses. Copy char somewhere prom can 174 * find it. This routine will stop working after pmap_rid_of_console 175 * is called in alpha_init. This is due to the hard coded address 176 * of the console area. 177 */ 178void 179promcnputc(dev_t dev, int c) 180{ 181 prom_return_t ret; 182 unsigned char *to = (unsigned char *)0x20000000; 183 184 prom_enter(); 185 *to = c; 186 187 do { 188 ret.bits = prom_putstr(alpha_console, to, 1); 189 } while ((ret.u.retval & 1) == 0); 190 191 prom_leave(); 192} 193 194/* 195 * promcngetc: 196 * 197 * Wait for the prom to get a real char and pass it back. 198 */ 199int 200promcngetc(dev_t dev) 201{ 202 prom_return_t ret; 203 204 for (;;) { 205 prom_enter(); 206 ret.bits = prom_getc(alpha_console); 207 prom_leave(); 208 if (ret.u.status == 0 || ret.u.status == 1) 209 return (ret.u.retval); 210 } 211} 212 213/* 214 * promcnlookc: 215 * 216 * See if prom has a real char and pass it back. 217 */ 218int 219promcnlookc(dev_t dev, char *cp) 220{ 221 prom_return_t ret; 222 223 prom_enter(); 224 ret.bits = prom_getc(alpha_console); 225 prom_leave(); 226 if (ret.u.status == 0 || ret.u.status == 1) { 227 *cp = ret.u.retval; 228 return 1; 229 } else 230 return 0; 231} 232 233int 234prom_getenv(int id, char *buf, int len) 235{ 236 unsigned char *to = (unsigned char *)0x20000000; 237 prom_return_t ret; 238 239 prom_enter(); 240 ret.bits = prom_getenv_disp(id, to, len); 241 memcpy(buf, to, len); 242 prom_leave(); 243 244 if (ret.u.status & 0x4) 245 ret.u.retval = 0; 246 buf[ret.u.retval] = '\0'; 247 248 return (ret.bits); 249} 250 251void 252prom_halt(int halt) 253{ 254 struct pcs *p; 255 256 /* 257 * Turn off interrupts, for sanity. 258 */ 259 (void) splhigh(); 260 261 /* 262 * Set "boot request" part of the CPU state depending on what 263 * we want to happen when we halt. 264 */ 265 p = LOCATE_PCS(hwrpb, hwrpb->rpb_primary_cpu_id); 266 p->pcs_flags &= ~(PCS_RC | PCS_HALT_REQ); 267 if (halt) 268 p->pcs_flags |= PCS_HALT_STAY_HALTED; 269 else 270 p->pcs_flags |= PCS_HALT_WARM_BOOT; 271 272 /* 273 * Halt the machine. 274 */ 275 alpha_pal_halt(); 276} 277 278uint64_t 279hwrpb_checksum(void) 280{ 281 uint64_t *p, sum; 282 int i; 283 284 for (i = 0, p = (uint64_t *)hwrpb, sum = 0; 285 i < (offsetof(struct rpb, rpb_checksum) / sizeof (uint64_t)); 286 i++, p++) 287 sum += *p; 288 289 return (sum); 290} 291 292void 293hwrpb_primary_init(void) 294{ 295 struct pcb *pcb; 296 struct pcs *p; 297 298 p = LOCATE_PCS(hwrpb, hwrpb->rpb_primary_cpu_id); 299 300 /* Initialize the primary's HWPCB and the Virtual Page Table Base. */ 301 pcb = lwp_getpcb(&lwp0); 302 memcpy(p->pcs_hwpcb, &pcb->pcb_hw, sizeof(pcb->pcb_hw)); 303 hwrpb->rpb_vptb = VPTBASE; 304 305 hwrpb->rpb_checksum = hwrpb_checksum(); 306} 307 308void 309hwrpb_restart_setup(void) 310{ 311 struct pcs *p; 312 313 /* Clear bootstrap-in-progress flag since we're done bootstrapping */ 314 p = LOCATE_PCS(hwrpb, hwrpb->rpb_primary_cpu_id); 315 p->pcs_flags &= ~PCS_BIP; 316 317 /* when 'c'ontinuing from console halt, do a dump */ 318 hwrpb->rpb_rest_term = (uint64_t)&XentRestart; 319 hwrpb->rpb_rest_term_val = 0x1; 320 321 hwrpb->rpb_checksum = hwrpb_checksum(); 322 323 p->pcs_flags |= (PCS_RC | PCS_CV); 324} 325 326uint64_t 327console_restart(struct trapframe *framep) 328{ 329 struct pcs *p; 330 331 /* Clear restart-capable flag, since we can no longer restart. */ 332 p = LOCATE_PCS(hwrpb, hwrpb->rpb_primary_cpu_id); 333 p->pcs_flags &= ~PCS_RC; 334 335 /* Fill in the missing frame slots */ 336 337 framep->tf_regs[FRAME_PS] = p->pcs_halt_ps; 338 framep->tf_regs[FRAME_PC] = p->pcs_halt_pc; 339 framep->tf_regs[FRAME_T11] = p->pcs_halt_r25; 340 framep->tf_regs[FRAME_RA] = p->pcs_halt_r26; 341 framep->tf_regs[FRAME_T12] = p->pcs_halt_r27; 342 343 panic("user requested console halt"); 344 345 return (1); 346} 347