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