xref: /netbsd/sys/arch/alpha/alpha/prom.c (revision bf9ec67e)
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