]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/gxemul/cons/gxemul_cons.c
MFV r357163:
[FreeBSD/FreeBSD.git] / sys / dev / gxemul / cons / gxemul_cons.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2011-2012 Robert N. M. Watson
5  * All rights reserved.
6  *
7  * This software was developed by SRI International and the University of
8  * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
9  * ("CTSRD"), as part of the DARPA CRASH research programme.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 #include <sys/param.h>
37 #include <sys/cons.h>
38 #include <sys/endian.h>
39 #include <sys/kdb.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/reboot.h>
43 #include <sys/tty.h>
44
45 #include <ddb/ddb.h>
46
47 #include <machine/cpuregs.h>
48
49 #define GC_LOCK_INIT()          mtx_init(&gc_lock, "gc_lock", NULL, MTX_SPIN)
50
51 #define GC_LOCK() do {                                                  \
52         if (!kdb_active)                                                \
53                 mtx_lock_spin(&gc_lock);                                \
54 } while (0)
55
56 #define GC_LOCK_ASSERT() do {                                           \
57         if (!kdb_active)                                                \
58                 mtx_assert(&gc_lock, MA_OWNED);                         \
59 } while (0)
60
61 #define GC_UNLOCK() do {                                                \
62         if (!kdb_active)                                                \
63                 mtx_unlock_spin(&gc_lock);                              \
64 } while (0)
65
66
67 static struct mtx       gc_lock;
68
69 /*
70  * Low-level console driver functions.
71  */
72 static cn_probe_t       gxemul_cons_cnprobe;
73 static cn_init_t        gxemul_cons_cninit;
74 static cn_term_t        gxemul_cons_cnterm;
75 static cn_getc_t        gxemul_cons_cngetc;
76 static cn_putc_t        gxemul_cons_cnputc;
77 static cn_grab_t        gxemul_cons_cngrab;
78 static cn_ungrab_t      gxemul_cons_cnungrab;
79
80 /*
81  * TTY-level fields.
82  */
83 static tsw_outwakeup_t  gxemul_cons_outwakeup;
84
85 static struct ttydevsw gxemul_cons_ttydevsw = {
86         .tsw_flags      = TF_NOPREFIX,
87         .tsw_outwakeup  = gxemul_cons_outwakeup,
88 };
89
90 static struct callout   gxemul_cons_callout;
91 static u_int            gxemul_cons_polltime = 10;
92 #ifdef KDB
93 static int              gxemul_cons_alt_break_state;
94 #endif
95
96 static void             gxemul_cons_timeout(void *);
97
98 /*
99  * I/O routines lifted from Deimos.
100  *
101  * XXXRW: Should be using FreeBSD's bus routines here, but they are not
102  * available until later in the boot.
103  */
104
105 static inline vm_offset_t
106 mips_phys_to_uncached(vm_paddr_t phys)            
107 {
108
109         return (MIPS_PHYS_TO_DIRECT_UNCACHED(phys));
110 }
111
112 static inline uint8_t
113 mips_ioread_uint8(vm_offset_t vaddr)
114 {
115         uint8_t v;
116
117         __asm__ __volatile__ ("lbu %0, 0(%1)" : "=r" (v) : "r" (vaddr));
118         return (v);
119 }
120
121 static inline void
122 mips_iowrite_uint8(vm_offset_t vaddr, uint8_t v)
123 {
124
125         __asm__ __volatile__ ("sb %0, 0(%1)" : : "r" (v), "r" (vaddr));
126 }
127
128 /*
129  * gxemul-specific constants.
130  */
131 #define GXEMUL_CONS_BASE        0x10000000      /* gxemul console device. */
132
133 /*
134  * Routines for interacting with the gxemul test console.  Programming details
135  * are a result of manually inspecting the source code for gxemul's
136  * dev_cons.cc and dev_cons.h.
137  *
138  * Offsets of I/O channels relative to the base.
139  */
140 #define GXEMUL_PUTGETCHAR_OFF           0x00000000
141 #define GXEMUL_CONS_HALT                0x00000010
142
143 /*
144  * One-byte buffer as we can't check whether the console is readable without
145  * actually reading from it.
146  */
147 static char     buffer_data;
148 static int      buffer_valid;
149
150 /*
151  * Low-level read and write routines.
152  */
153 static inline uint8_t
154 gxemul_cons_data_read(void)
155 {
156
157         return (mips_ioread_uint8(mips_phys_to_uncached(GXEMUL_CONS_BASE +
158             GXEMUL_PUTGETCHAR_OFF)));
159 }
160
161 static inline void
162 gxemul_cons_data_write(uint8_t v)
163 {
164
165         mips_iowrite_uint8(mips_phys_to_uncached(GXEMUL_CONS_BASE +
166             GXEMUL_PUTGETCHAR_OFF), v);
167 }
168
169 static int
170 gxemul_cons_writable(void)
171 {
172
173         return (1);
174 }
175
176 static int
177 gxemul_cons_readable(void)
178 {
179         uint32_t v;
180
181         GC_LOCK_ASSERT();
182
183         if (buffer_valid)
184                 return (1);
185         v = gxemul_cons_data_read();
186         if (v != 0) {
187                 buffer_valid = 1;
188                 buffer_data = v;
189                 return (1);
190         }
191         return (0);
192 }
193
194 static void
195 gxemul_cons_write(char ch)
196 {
197
198         GC_LOCK_ASSERT();
199
200         while (!gxemul_cons_writable());
201         gxemul_cons_data_write(ch);
202 }
203
204 static char
205 gxemul_cons_read(void)
206 {
207
208         GC_LOCK_ASSERT();
209
210         while (!gxemul_cons_readable());
211         buffer_valid = 0;
212         return (buffer_data);
213 }
214
215 /*
216  * Implementation of a FreeBSD low-level, polled console driver.
217  */
218 static void
219 gxemul_cons_cnprobe(struct consdev *cp)
220 {
221
222         sprintf(cp->cn_name, "ttyu0");
223         cp->cn_pri = (boothowto & RB_SERIAL) ? CN_REMOTE : CN_NORMAL;
224 }
225
226 static void
227 gxemul_cons_cninit(struct consdev *cp)
228 {
229
230         GC_LOCK_INIT();
231 }
232
233 static void
234 gxemul_cons_cnterm(struct consdev *cp)
235 {
236
237 }
238
239 static int
240 gxemul_cons_cngetc(struct consdev *cp)
241 {
242         int ret;
243
244         GC_LOCK();
245         ret = gxemul_cons_read();
246         GC_UNLOCK();
247         return (ret);
248 }
249
250 static void
251 gxemul_cons_cnputc(struct consdev *cp, int c)
252 {
253
254         GC_LOCK();
255         gxemul_cons_write(c);
256         GC_UNLOCK();
257 }
258
259 static void
260 gxemul_cons_cngrab(struct consdev *cp)
261 {
262
263 }
264
265 static void
266 gxemul_cons_cnungrab(struct consdev *cp)
267 {
268
269 }
270
271 CONSOLE_DRIVER(gxemul_cons);
272
273 /*
274  * TTY-level functions for gxemul_cons.
275  */
276 static void
277 gxemul_cons_ttyinit(void *unused)
278 {
279         struct tty *tp;
280
281         tp = tty_alloc(&gxemul_cons_ttydevsw, NULL);
282         tty_init_console(tp, 0);
283         tty_makedev(tp, NULL, "%s", "ttyu0");
284         callout_init(&gxemul_cons_callout, 1);
285         callout_reset(&gxemul_cons_callout, gxemul_cons_polltime,
286             gxemul_cons_timeout, tp);
287
288 }
289 SYSINIT(gxemul_cons_ttyinit, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE,
290     gxemul_cons_ttyinit, NULL);
291
292 static void
293 gxemul_cons_outwakeup(struct tty *tp)
294 {
295         int len;
296         u_char ch;
297
298         /*
299          * XXXRW: Would be nice not to do blocking writes to the console here,
300          * rescheduling on our timer tick if work remains to be done..
301          */
302         for (;;) {
303                 len = ttydisc_getc(tp, &ch, sizeof(ch));
304                 if (len == 0)
305                         break;
306                 GC_LOCK();
307                 gxemul_cons_write(ch);
308                 GC_UNLOCK();
309         }
310 }
311
312 static void
313 gxemul_cons_timeout(void *v)
314 {
315         struct tty *tp;
316         int c;
317
318         tp = v;
319         tty_lock(tp);
320         GC_LOCK();
321         while (gxemul_cons_readable()) {
322                 c = gxemul_cons_read();
323                 GC_UNLOCK();
324 #ifdef KDB
325                 kdb_alt_break(c, &gxemul_cons_alt_break_state);
326 #endif
327                 ttydisc_rint(tp, c, 0);
328                 GC_LOCK();
329         }
330         GC_UNLOCK();
331         ttydisc_rint_done(tp);
332         tty_unlock(tp);
333         callout_reset(&gxemul_cons_callout, gxemul_cons_polltime,
334             gxemul_cons_timeout, tp);
335 }