1 /*- 2 * Copyright (c) 2015-2017 Ruslan Bukin <br@bsdpad.com> 3 * All rights reserved. 4 * 5 * Portions of this software were developed by SRI International and the 6 * University of Cambridge Computer Laboratory under DARPA/AFRL contract 7 * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme. 8 * 9 * Portions of this software were developed by the University of Cambridge 10 * Computer Laboratory as part of the CTSRD Project, with support from the 11 * UK Higher Education Innovation Fund (HEIF). 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include <sys/param.h> 36 #include <sys/kdb.h> 37 #include <sys/kernel.h> 38 #include <sys/priv.h> 39 #include <sys/systm.h> 40 #include <sys/types.h> 41 #include <sys/conf.h> 42 #include <sys/cons.h> 43 #include <sys/consio.h> 44 #include <sys/tty.h> 45 #include <sys/bus.h> 46 #include <sys/module.h> 47 #include <sys/rman.h> 48 49 #include <dev/ofw/openfirm.h> 50 #include <ddb/ddb.h> 51 52 #include <vm/vm.h> 53 #include <vm/pmap.h> 54 55 #include <dev/fdt/fdt_common.h> 56 #include <dev/ofw/openfirm.h> 57 #include <dev/ofw/ofw_bus.h> 58 #include <dev/ofw/ofw_bus_subr.h> 59 60 #include <machine/bus.h> 61 #include <machine/cpu.h> 62 #include <machine/intr.h> 63 #include <machine/asm.h> 64 #include <machine/trap.h> 65 #include <machine/vmparam.h> 66 #include <machine/sbi.h> 67 68 /* bus softc */ 69 struct rcons_softc { 70 struct resource *res[1]; 71 void *ihl[1]; 72 device_t dev; 73 }; 74 75 /* CN Console interface */ 76 77 static tsw_outwakeup_t riscvtty_outwakeup; 78 79 static struct ttydevsw riscv_ttydevsw = { 80 .tsw_flags = TF_NOPREFIX, 81 .tsw_outwakeup = riscvtty_outwakeup, 82 }; 83 84 static int polltime; 85 static struct callout riscv_callout; 86 static struct tty *tp = NULL; 87 88 #if defined(KDB) 89 static int alt_break_state; 90 #endif 91 92 static void riscv_timeout(void *); 93 94 static cn_probe_t riscv_cnprobe; 95 static cn_init_t riscv_cninit; 96 static cn_term_t riscv_cnterm; 97 static cn_getc_t riscv_cngetc; 98 static cn_putc_t riscv_cnputc; 99 static cn_grab_t riscv_cngrab; 100 static cn_ungrab_t riscv_cnungrab; 101 102 CONSOLE_DRIVER(riscv); 103 104 #define MAX_BURST_LEN 1 105 106 static void 107 riscv_putc(int c) 108 { 109 110 sbi_console_putchar(c); 111 } 112 113 #if CHECK_EARLY_PRINTF(sbi) 114 early_putc_t *early_putc = riscv_putc; 115 #endif 116 117 static void 118 cn_drvinit(void *unused) 119 { 120 121 if (riscv_consdev.cn_pri != CN_DEAD && 122 riscv_consdev.cn_name[0] != '\0') { 123 tp = tty_alloc(&riscv_ttydevsw, NULL); 124 tty_init_console(tp, 0); 125 tty_makedev(tp, NULL, "%s", "rcons"); 126 127 polltime = 1; 128 129 callout_init(&riscv_callout, 1); 130 callout_reset(&riscv_callout, polltime, riscv_timeout, NULL); 131 } 132 } 133 134 SYSINIT(cndev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE, cn_drvinit, NULL); 135 136 static void 137 riscvtty_outwakeup(struct tty *tp) 138 { 139 u_char buf[MAX_BURST_LEN]; 140 int len; 141 int i; 142 143 for (;;) { 144 len = ttydisc_getc(tp, buf, sizeof(buf)); 145 if (len == 0) 146 break; 147 148 KASSERT(len == 1, ("tty error")); 149 150 for (i = 0; i < len; i++) 151 riscv_putc(buf[i]); 152 } 153 } 154 155 static void 156 riscv_timeout(void *v) 157 { 158 int c; 159 160 tty_lock(tp); 161 while ((c = riscv_cngetc(NULL)) != -1) 162 ttydisc_rint(tp, c, 0); 163 ttydisc_rint_done(tp); 164 tty_unlock(tp); 165 166 callout_reset(&riscv_callout, polltime, riscv_timeout, NULL); 167 } 168 169 static void 170 riscv_cnprobe(struct consdev *cp) 171 { 172 173 cp->cn_pri = CN_NORMAL; 174 } 175 176 static void 177 riscv_cninit(struct consdev *cp) 178 { 179 180 strcpy(cp->cn_name, "rcons"); 181 } 182 183 static void 184 riscv_cnterm(struct consdev *cp) 185 { 186 187 } 188 189 static void 190 riscv_cngrab(struct consdev *cp) 191 { 192 193 } 194 195 static void 196 riscv_cnungrab(struct consdev *cp) 197 { 198 199 } 200 201 static int 202 riscv_cngetc(struct consdev *cp) 203 { 204 int ch; 205 206 ch = sbi_console_getchar(); 207 if (ch > 0 && ch < 0xff) { 208 #if defined(KDB) 209 kdb_alt_break(ch, &alt_break_state); 210 #endif 211 return (ch); 212 } 213 214 return (-1); 215 } 216 217 static void 218 riscv_cnputc(struct consdev *cp, int c) 219 { 220 221 riscv_putc(c); 222 } 223 224 /* Bus interface */ 225 226 static int 227 rcons_probe(device_t dev) 228 { 229 230 device_set_desc(dev, "RISC-V console"); 231 232 return (BUS_PROBE_DEFAULT); 233 } 234 235 static int 236 rcons_attach(device_t dev) 237 { 238 struct rcons_softc *sc; 239 240 if (device_get_unit(dev) != 0) 241 return (ENXIO); 242 243 sc = device_get_softc(dev); 244 sc->dev = dev; 245 246 bus_generic_attach(sc->dev); 247 248 return (0); 249 } 250 251 static device_method_t rcons_methods[] = { 252 DEVMETHOD(device_probe, rcons_probe), 253 DEVMETHOD(device_attach, rcons_attach), 254 255 DEVMETHOD_END 256 }; 257 258 static driver_t rcons_driver = { 259 "rcons", 260 rcons_methods, 261 sizeof(struct rcons_softc) 262 }; 263 264 DRIVER_MODULE(rcons, nexus, rcons_driver, 0, 0); 265