gxemul_cons.c revision 239668
1234920Srwatson/*-
2234920Srwatson * Copyright (c) 2011-2012 Robert N. M. Watson
3234920Srwatson * All rights reserved.
4234920Srwatson *
5234920Srwatson * This software was developed by SRI International and the University of
6234920Srwatson * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
7234920Srwatson * ("CTSRD"), as part of the DARPA CRASH research programme.
8234920Srwatson *
9234920Srwatson * Redistribution and use in source and binary forms, with or without
10234920Srwatson * modification, are permitted provided that the following conditions
11234920Srwatson * are met:
12234920Srwatson * 1. Redistributions of source code must retain the above copyright
13234920Srwatson *    notice, this list of conditions and the following disclaimer.
14234920Srwatson * 2. Redistributions in binary form must reproduce the above copyright
15234920Srwatson *    notice, this list of conditions and the following disclaimer in the
16234920Srwatson *    documentation and/or other materials provided with the distribution.
17234920Srwatson *
18234920Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19234920Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20234920Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21234920Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22234920Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23234920Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24234920Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25234920Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26234920Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27234920Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28234920Srwatson * SUCH DAMAGE.
29234920Srwatson */
30234920Srwatson
31234920Srwatson#include <sys/cdefs.h>
32234920Srwatson__FBSDID("$FreeBSD: head/sys/dev/gxemul/cons/gxemul_cons.c 239668 2012-08-25 07:48:52Z rwatson $");
33234920Srwatson
34234920Srwatson#include <sys/param.h>
35234920Srwatson#include <sys/cons.h>
36234920Srwatson#include <sys/endian.h>
37234920Srwatson#include <sys/kdb.h>
38234920Srwatson#include <sys/systm.h>
39234920Srwatson#include <sys/kernel.h>
40239668Srwatson#include <sys/reboot.h>
41234920Srwatson#include <sys/tty.h>
42234920Srwatson
43234920Srwatson#include <ddb/ddb.h>
44234920Srwatson
45234920Srwatson#define	GC_LOCK_INIT()		mtx_init(&gc_lock, "gc_lock", NULL, MTX_SPIN)
46234920Srwatson
47234920Srwatson#define	GC_LOCK() do {							\
48234920Srwatson	if (!kdb_active)						\
49234920Srwatson		mtx_lock_spin(&gc_lock);				\
50234920Srwatson} while (0)
51234920Srwatson
52234920Srwatson#define	GC_LOCK_ASSERT() do {						\
53234920Srwatson	if (!kdb_active)						\
54234920Srwatson		mtx_assert(&gc_lock, MA_OWNED);				\
55234920Srwatson} while (0)
56234920Srwatson
57234920Srwatson#define	GC_UNLOCK() do {						\
58234920Srwatson	if (!kdb_active)						\
59234920Srwatson		mtx_unlock_spin(&gc_lock);				\
60234920Srwatson} while (0)
61234920Srwatson
62234920Srwatson
63234920Srwatsonstatic struct mtx	gc_lock;
64234920Srwatson
65234920Srwatson/*
66234920Srwatson * Low-level console driver functions.
67234920Srwatson */
68234920Srwatsonstatic cn_probe_t	gxemul_cons_cnprobe;
69234920Srwatsonstatic cn_init_t	gxemul_cons_cninit;
70234920Srwatsonstatic cn_term_t	gxemul_cons_cnterm;
71234920Srwatsonstatic cn_getc_t	gxemul_cons_cngetc;
72234920Srwatsonstatic cn_putc_t	gxemul_cons_cnputc;
73234920Srwatsonstatic cn_grab_t	gxemul_cons_cngrab;
74234920Srwatsonstatic cn_ungrab_t	gxemul_cons_cnungrab;
75234920Srwatson
76234920Srwatson/*
77234920Srwatson * TTY-level fields.
78234920Srwatson */
79234920Srwatsonstatic tsw_outwakeup_t	gxemul_cons_outwakeup;
80234920Srwatson
81234920Srwatsonstatic struct ttydevsw gxemul_cons_ttydevsw = {
82234920Srwatson	.tsw_flags	= TF_NOPREFIX,
83234920Srwatson	.tsw_outwakeup	= gxemul_cons_outwakeup,
84234920Srwatson};
85234920Srwatson
86234920Srwatsonstatic struct callout	gxemul_cons_callout;
87234920Srwatsonstatic u_int		gxemul_cons_polltime = 10;
88234920Srwatson#ifdef KDB
89234920Srwatsonstatic int		gxemul_cons_alt_break_state;
90234920Srwatson#endif
91234920Srwatson
92234920Srwatsonstatic void		gxemul_cons_timeout(void *);
93234920Srwatson
94234920Srwatson/*
95234920Srwatson * I/O routines lifted from Deimos.
96234920Srwatson *
97234920Srwatson * XXXRW: Should be using FreeBSD's bus routines here, but they are not
98234920Srwatson * available until later in the boot.
99234920Srwatson */
100234920Srwatson#define	MIPS_XKPHYS_UNCACHED_BASE	0x9000000000000000
101234920Srwatson
102234920Srwatsontypedef	uint64_t	paddr_t;
103234920Srwatsontypedef	uint64_t	vaddr_t;
104234920Srwatson
105234920Srwatsonstatic inline vaddr_t
106234920Srwatsonmips_phys_to_uncached(paddr_t phys)
107234920Srwatson{
108234920Srwatson
109234920Srwatson	return (phys | MIPS_XKPHYS_UNCACHED_BASE);
110234920Srwatson}
111234920Srwatson
112234920Srwatsonstatic inline uint8_t
113234920Srwatsonmips_ioread_uint8(vaddr_t vaddr)
114234920Srwatson{
115234920Srwatson	uint8_t v;
116234920Srwatson
117234920Srwatson	__asm__ __volatile__ ("lbu %0, 0(%1)" : "=r" (v) : "r" (vaddr));
118234920Srwatson	return (v);
119234920Srwatson}
120234920Srwatson
121234920Srwatsonstatic inline void
122234920Srwatsonmips_iowrite_uint8(vaddr_t vaddr, uint8_t v)
123234920Srwatson{
124234920Srwatson
125234920Srwatson	__asm__ __volatile__ ("sb %0, 0(%1)" : : "r" (v), "r" (vaddr));
126234920Srwatson}
127234920Srwatson
128234920Srwatson/*
129234920Srwatson * gxemul-specific constants.
130234920Srwatson */
131234920Srwatson#define	GXEMUL_CONS_BASE	0x10000000	/* gxemul console device. */
132234920Srwatson
133234920Srwatson/*
134234920Srwatson * Routines for interacting with the gxemul test console.  Programming details
135234920Srwatson * are a result of manually inspecting the source code for gxemul's
136234920Srwatson * dev_cons.cc and dev_cons.h.
137234920Srwatson *
138234920Srwatson * Offsets of I/O channels relative to the base.
139234920Srwatson */
140234920Srwatson#define	GXEMUL_PUTGETCHAR_OFF		0x00000000
141234920Srwatson#define	GXEMUL_CONS_HALT		0x00000010
142234920Srwatson
143234920Srwatson/*
144234920Srwatson * One-byte buffer as we can't check whether the console is readable without
145234920Srwatson * actually reading from it.
146234920Srwatson */
147234920Srwatsonstatic char	buffer_data;
148234920Srwatsonstatic int	buffer_valid;
149234920Srwatson
150234920Srwatson/*
151234920Srwatson * Low-level read and write routines.
152234920Srwatson */
153234920Srwatsonstatic inline uint8_t
154234920Srwatsongxemul_cons_data_read(void)
155234920Srwatson{
156234920Srwatson
157234920Srwatson	return (mips_ioread_uint8(mips_phys_to_uncached(GXEMUL_CONS_BASE +
158234920Srwatson	    GXEMUL_PUTGETCHAR_OFF)));
159234920Srwatson}
160234920Srwatson
161234920Srwatsonstatic inline void
162234920Srwatsongxemul_cons_data_write(uint8_t v)
163234920Srwatson{
164234920Srwatson
165234920Srwatson	mips_iowrite_uint8(mips_phys_to_uncached(GXEMUL_CONS_BASE +
166234920Srwatson	    GXEMUL_PUTGETCHAR_OFF), v);
167234920Srwatson}
168234920Srwatson
169234920Srwatsonstatic int
170234920Srwatsongxemul_cons_writable(void)
171234920Srwatson{
172234920Srwatson
173234920Srwatson	return (1);
174234920Srwatson}
175234920Srwatson
176234920Srwatsonstatic int
177234920Srwatsongxemul_cons_readable(void)
178234920Srwatson{
179234920Srwatson	uint32_t v;
180234920Srwatson
181234920Srwatson	GC_LOCK_ASSERT();
182234920Srwatson
183234920Srwatson	if (buffer_valid)
184234920Srwatson		return (1);
185234920Srwatson	v = gxemul_cons_data_read();
186234920Srwatson	if (v != 0) {
187234920Srwatson		buffer_valid = 1;
188234920Srwatson		buffer_data = v;
189234920Srwatson		return (1);
190234920Srwatson	}
191234920Srwatson	return (0);
192234920Srwatson}
193234920Srwatson
194234920Srwatsonstatic void
195234920Srwatsongxemul_cons_write(char ch)
196234920Srwatson{
197234920Srwatson
198234920Srwatson	GC_LOCK_ASSERT();
199234920Srwatson
200234920Srwatson	while (!gxemul_cons_writable());
201234920Srwatson	gxemul_cons_data_write(ch);
202234920Srwatson}
203234920Srwatson
204234920Srwatsonstatic char
205234920Srwatsongxemul_cons_read(void)
206234920Srwatson{
207234920Srwatson
208234920Srwatson	GC_LOCK_ASSERT();
209234920Srwatson
210234920Srwatson	while (!gxemul_cons_readable());
211234920Srwatson	buffer_valid = 0;
212234920Srwatson	return (buffer_data);
213234920Srwatson}
214234920Srwatson
215234920Srwatson/*
216234920Srwatson * Implementation of a FreeBSD low-level, polled console driver.
217234920Srwatson */
218234920Srwatsonstatic void
219234920Srwatsongxemul_cons_cnprobe(struct consdev *cp)
220234920Srwatson{
221234920Srwatson
222239667Srwatson	sprintf(cp->cn_name, "ttyu0");
223239668Srwatson	cp->cn_pri = (boothowto & RB_SERIAL) ? CN_REMOTE : CN_NORMAL;
224234920Srwatson}
225234920Srwatson
226234920Srwatsonstatic void
227234920Srwatsongxemul_cons_cninit(struct consdev *cp)
228234920Srwatson{
229234920Srwatson
230234920Srwatson	GC_LOCK_INIT();
231234920Srwatson}
232234920Srwatson
233234920Srwatsonstatic void
234234920Srwatsongxemul_cons_cnterm(struct consdev *cp)
235234920Srwatson{
236234920Srwatson
237234920Srwatson}
238234920Srwatson
239234920Srwatsonstatic int
240234920Srwatsongxemul_cons_cngetc(struct consdev *cp)
241234920Srwatson{
242234920Srwatson	int ret;
243234920Srwatson
244234920Srwatson	GC_LOCK();
245234920Srwatson	ret = gxemul_cons_read();
246234920Srwatson	GC_UNLOCK();
247234920Srwatson	return (ret);
248234920Srwatson}
249234920Srwatson
250234920Srwatsonstatic void
251234920Srwatsongxemul_cons_cnputc(struct consdev *cp, int c)
252234920Srwatson{
253234920Srwatson
254234920Srwatson	GC_LOCK();
255234920Srwatson	gxemul_cons_write(c);
256234920Srwatson	GC_UNLOCK();
257234920Srwatson}
258234920Srwatson
259234920Srwatsonstatic void
260234920Srwatsongxemul_cons_cngrab(struct consdev *cp)
261234920Srwatson{
262234920Srwatson
263234920Srwatson}
264234920Srwatson
265234920Srwatsonstatic void
266234920Srwatsongxemul_cons_cnungrab(struct consdev *cp)
267234920Srwatson{
268234920Srwatson
269234920Srwatson}
270234920Srwatson
271234920SrwatsonCONSOLE_DRIVER(gxemul_cons);
272234920Srwatson
273234920Srwatson/*
274234920Srwatson * TTY-level functions for gxemul_cons.
275234920Srwatson */
276234920Srwatsonstatic void
277234920Srwatsongxemul_cons_ttyinit(void *unused)
278234920Srwatson{
279234920Srwatson	struct tty *tp;
280234920Srwatson
281234920Srwatson	tp = tty_alloc(&gxemul_cons_ttydevsw, NULL);
282234920Srwatson	tty_init_console(tp, 0);
283239667Srwatson	tty_makedev(tp, NULL, "%s", "ttyu0");
284234920Srwatson	callout_init(&gxemul_cons_callout, CALLOUT_MPSAFE);
285234920Srwatson	callout_reset(&gxemul_cons_callout, gxemul_cons_polltime,
286234920Srwatson	    gxemul_cons_timeout, tp);
287234920Srwatson
288234920Srwatson}
289234920SrwatsonSYSINIT(gxemul_cons_ttyinit, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE,
290234920Srwatson    gxemul_cons_ttyinit, NULL);
291234920Srwatson
292234920Srwatsonstatic void
293234920Srwatsongxemul_cons_outwakeup(struct tty *tp)
294234920Srwatson{
295234920Srwatson	int len;
296234920Srwatson	u_char ch;
297234920Srwatson
298234920Srwatson	/*
299234920Srwatson	 * XXXRW: Would be nice not to do blocking writes to the console here,
300234920Srwatson	 * rescheduling on our timer tick if work remains to be done..
301234920Srwatson	 */
302234920Srwatson	for (;;) {
303234920Srwatson		len = ttydisc_getc(tp, &ch, sizeof(ch));
304234920Srwatson		if (len == 0)
305234920Srwatson			break;
306234920Srwatson		GC_LOCK();
307234920Srwatson		gxemul_cons_write(ch);
308234920Srwatson		GC_UNLOCK();
309234920Srwatson	}
310234920Srwatson}
311234920Srwatson
312234920Srwatsonstatic void
313234920Srwatsongxemul_cons_timeout(void *v)
314234920Srwatson{
315234920Srwatson	struct tty *tp;
316234920Srwatson	int c;
317234920Srwatson
318234920Srwatson	tp = v;
319234920Srwatson	tty_lock(tp);
320234920Srwatson	GC_LOCK();
321234920Srwatson	while (gxemul_cons_readable()) {
322234920Srwatson		c = gxemul_cons_read();
323234920Srwatson		GC_UNLOCK();
324234920Srwatson#ifdef KDB
325234920Srwatson		kdb_alt_break(c, &gxemul_cons_alt_break_state);
326234920Srwatson#endif
327234920Srwatson		ttydisc_rint(tp, c, 0);
328234920Srwatson		GC_LOCK();
329234920Srwatson	}
330234920Srwatson	GC_UNLOCK();
331234920Srwatson	ttydisc_rint_done(tp);
332234920Srwatson	tty_unlock(tp);
333234920Srwatson	callout_reset(&gxemul_cons_callout, gxemul_cons_polltime,
334234920Srwatson	    gxemul_cons_timeout, tp);
335234920Srwatson}
336