gxemul_cons.c revision 234920
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 234920 2012-05-02 08:10:15Z 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> 40234920Srwatson#include <sys/tty.h> 41234920Srwatson 42234920Srwatson#include <ddb/ddb.h> 43234920Srwatson 44234920Srwatson#define GC_LOCK_INIT() mtx_init(&gc_lock, "gc_lock", NULL, MTX_SPIN) 45234920Srwatson 46234920Srwatson#define GC_LOCK() do { \ 47234920Srwatson if (!kdb_active) \ 48234920Srwatson mtx_lock_spin(&gc_lock); \ 49234920Srwatson} while (0) 50234920Srwatson 51234920Srwatson#define GC_LOCK_ASSERT() do { \ 52234920Srwatson if (!kdb_active) \ 53234920Srwatson mtx_assert(&gc_lock, MA_OWNED); \ 54234920Srwatson} while (0) 55234920Srwatson 56234920Srwatson#define GC_UNLOCK() do { \ 57234920Srwatson if (!kdb_active) \ 58234920Srwatson mtx_unlock_spin(&gc_lock); \ 59234920Srwatson} while (0) 60234920Srwatson 61234920Srwatson 62234920Srwatsonstatic struct mtx gc_lock; 63234920Srwatson 64234920Srwatson/* 65234920Srwatson * Low-level console driver functions. 66234920Srwatson */ 67234920Srwatsonstatic cn_probe_t gxemul_cons_cnprobe; 68234920Srwatsonstatic cn_init_t gxemul_cons_cninit; 69234920Srwatsonstatic cn_term_t gxemul_cons_cnterm; 70234920Srwatsonstatic cn_getc_t gxemul_cons_cngetc; 71234920Srwatsonstatic cn_putc_t gxemul_cons_cnputc; 72234920Srwatsonstatic cn_grab_t gxemul_cons_cngrab; 73234920Srwatsonstatic cn_ungrab_t gxemul_cons_cnungrab; 74234920Srwatson 75234920Srwatson/* 76234920Srwatson * TTY-level fields. 77234920Srwatson */ 78234920Srwatsonstatic tsw_outwakeup_t gxemul_cons_outwakeup; 79234920Srwatson 80234920Srwatsonstatic struct ttydevsw gxemul_cons_ttydevsw = { 81234920Srwatson .tsw_flags = TF_NOPREFIX, 82234920Srwatson .tsw_outwakeup = gxemul_cons_outwakeup, 83234920Srwatson}; 84234920Srwatson 85234920Srwatsonstatic struct callout gxemul_cons_callout; 86234920Srwatsonstatic u_int gxemul_cons_polltime = 10; 87234920Srwatson#ifdef KDB 88234920Srwatsonstatic int gxemul_cons_alt_break_state; 89234920Srwatson#endif 90234920Srwatson 91234920Srwatsonstatic void gxemul_cons_timeout(void *); 92234920Srwatson 93234920Srwatson/* 94234920Srwatson * I/O routines lifted from Deimos. 95234920Srwatson * 96234920Srwatson * XXXRW: Should be using FreeBSD's bus routines here, but they are not 97234920Srwatson * available until later in the boot. 98234920Srwatson */ 99234920Srwatson#define MIPS_XKPHYS_UNCACHED_BASE 0x9000000000000000 100234920Srwatson 101234920Srwatsontypedef uint64_t paddr_t; 102234920Srwatsontypedef uint64_t vaddr_t; 103234920Srwatson 104234920Srwatsonstatic inline vaddr_t 105234920Srwatsonmips_phys_to_uncached(paddr_t phys) 106234920Srwatson{ 107234920Srwatson 108234920Srwatson return (phys | MIPS_XKPHYS_UNCACHED_BASE); 109234920Srwatson} 110234920Srwatson 111234920Srwatsonstatic inline uint8_t 112234920Srwatsonmips_ioread_uint8(vaddr_t vaddr) 113234920Srwatson{ 114234920Srwatson uint8_t v; 115234920Srwatson 116234920Srwatson __asm__ __volatile__ ("lbu %0, 0(%1)" : "=r" (v) : "r" (vaddr)); 117234920Srwatson return (v); 118234920Srwatson} 119234920Srwatson 120234920Srwatsonstatic inline void 121234920Srwatsonmips_iowrite_uint8(vaddr_t vaddr, uint8_t v) 122234920Srwatson{ 123234920Srwatson 124234920Srwatson __asm__ __volatile__ ("sb %0, 0(%1)" : : "r" (v), "r" (vaddr)); 125234920Srwatson} 126234920Srwatson 127234920Srwatson/* 128234920Srwatson * gxemul-specific constants. 129234920Srwatson */ 130234920Srwatson#define GXEMUL_CONS_BASE 0x10000000 /* gxemul console device. */ 131234920Srwatson 132234920Srwatson/* 133234920Srwatson * Routines for interacting with the gxemul test console. Programming details 134234920Srwatson * are a result of manually inspecting the source code for gxemul's 135234920Srwatson * dev_cons.cc and dev_cons.h. 136234920Srwatson * 137234920Srwatson * Offsets of I/O channels relative to the base. 138234920Srwatson */ 139234920Srwatson#define GXEMUL_PUTGETCHAR_OFF 0x00000000 140234920Srwatson#define GXEMUL_CONS_HALT 0x00000010 141234920Srwatson 142234920Srwatson/* 143234920Srwatson * One-byte buffer as we can't check whether the console is readable without 144234920Srwatson * actually reading from it. 145234920Srwatson */ 146234920Srwatsonstatic char buffer_data; 147234920Srwatsonstatic int buffer_valid; 148234920Srwatson 149234920Srwatson/* 150234920Srwatson * Low-level read and write routines. 151234920Srwatson */ 152234920Srwatsonstatic inline uint8_t 153234920Srwatsongxemul_cons_data_read(void) 154234920Srwatson{ 155234920Srwatson 156234920Srwatson return (mips_ioread_uint8(mips_phys_to_uncached(GXEMUL_CONS_BASE + 157234920Srwatson GXEMUL_PUTGETCHAR_OFF))); 158234920Srwatson} 159234920Srwatson 160234920Srwatsonstatic inline void 161234920Srwatsongxemul_cons_data_write(uint8_t v) 162234920Srwatson{ 163234920Srwatson 164234920Srwatson mips_iowrite_uint8(mips_phys_to_uncached(GXEMUL_CONS_BASE + 165234920Srwatson GXEMUL_PUTGETCHAR_OFF), v); 166234920Srwatson} 167234920Srwatson 168234920Srwatsonstatic int 169234920Srwatsongxemul_cons_writable(void) 170234920Srwatson{ 171234920Srwatson 172234920Srwatson return (1); 173234920Srwatson} 174234920Srwatson 175234920Srwatsonstatic int 176234920Srwatsongxemul_cons_readable(void) 177234920Srwatson{ 178234920Srwatson uint32_t v; 179234920Srwatson 180234920Srwatson GC_LOCK_ASSERT(); 181234920Srwatson 182234920Srwatson if (buffer_valid) 183234920Srwatson return (1); 184234920Srwatson v = gxemul_cons_data_read(); 185234920Srwatson if (v != 0) { 186234920Srwatson buffer_valid = 1; 187234920Srwatson buffer_data = v; 188234920Srwatson return (1); 189234920Srwatson } 190234920Srwatson return (0); 191234920Srwatson} 192234920Srwatson 193234920Srwatsonstatic void 194234920Srwatsongxemul_cons_write(char ch) 195234920Srwatson{ 196234920Srwatson 197234920Srwatson GC_LOCK_ASSERT(); 198234920Srwatson 199234920Srwatson while (!gxemul_cons_writable()); 200234920Srwatson gxemul_cons_data_write(ch); 201234920Srwatson} 202234920Srwatson 203234920Srwatsonstatic char 204234920Srwatsongxemul_cons_read(void) 205234920Srwatson{ 206234920Srwatson 207234920Srwatson GC_LOCK_ASSERT(); 208234920Srwatson 209234920Srwatson while (!gxemul_cons_readable()); 210234920Srwatson buffer_valid = 0; 211234920Srwatson return (buffer_data); 212234920Srwatson} 213234920Srwatson 214234920Srwatson/* 215234920Srwatson * Implementation of a FreeBSD low-level, polled console driver. 216234920Srwatson */ 217234920Srwatsonstatic void 218234920Srwatsongxemul_cons_cnprobe(struct consdev *cp) 219234920Srwatson{ 220234920Srwatson 221234920Srwatson sprintf(cp->cn_name, "gxcons"); 222234920Srwatson cp->cn_pri = CN_NORMAL; 223234920Srwatson} 224234920Srwatson 225234920Srwatsonstatic void 226234920Srwatsongxemul_cons_cninit(struct consdev *cp) 227234920Srwatson{ 228234920Srwatson 229234920Srwatson GC_LOCK_INIT(); 230234920Srwatson} 231234920Srwatson 232234920Srwatsonstatic void 233234920Srwatsongxemul_cons_cnterm(struct consdev *cp) 234234920Srwatson{ 235234920Srwatson 236234920Srwatson} 237234920Srwatson 238234920Srwatsonstatic int 239234920Srwatsongxemul_cons_cngetc(struct consdev *cp) 240234920Srwatson{ 241234920Srwatson int ret; 242234920Srwatson 243234920Srwatson GC_LOCK(); 244234920Srwatson ret = gxemul_cons_read(); 245234920Srwatson GC_UNLOCK(); 246234920Srwatson return (ret); 247234920Srwatson} 248234920Srwatson 249234920Srwatsonstatic void 250234920Srwatsongxemul_cons_cnputc(struct consdev *cp, int c) 251234920Srwatson{ 252234920Srwatson 253234920Srwatson GC_LOCK(); 254234920Srwatson gxemul_cons_write(c); 255234920Srwatson GC_UNLOCK(); 256234920Srwatson} 257234920Srwatson 258234920Srwatsonstatic void 259234920Srwatsongxemul_cons_cngrab(struct consdev *cp) 260234920Srwatson{ 261234920Srwatson 262234920Srwatson} 263234920Srwatson 264234920Srwatsonstatic void 265234920Srwatsongxemul_cons_cnungrab(struct consdev *cp) 266234920Srwatson{ 267234920Srwatson 268234920Srwatson} 269234920Srwatson 270234920SrwatsonCONSOLE_DRIVER(gxemul_cons); 271234920Srwatson 272234920Srwatson/* 273234920Srwatson * TTY-level functions for gxemul_cons. 274234920Srwatson */ 275234920Srwatsonstatic void 276234920Srwatsongxemul_cons_ttyinit(void *unused) 277234920Srwatson{ 278234920Srwatson struct tty *tp; 279234920Srwatson 280234920Srwatson tp = tty_alloc(&gxemul_cons_ttydevsw, NULL); 281234920Srwatson tty_init_console(tp, 0); 282234920Srwatson tty_makedev(tp, NULL, "%s", "gxcons"); 283234920Srwatson callout_init(&gxemul_cons_callout, CALLOUT_MPSAFE); 284234920Srwatson callout_reset(&gxemul_cons_callout, gxemul_cons_polltime, 285234920Srwatson gxemul_cons_timeout, tp); 286234920Srwatson 287234920Srwatson} 288234920SrwatsonSYSINIT(gxemul_cons_ttyinit, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE, 289234920Srwatson gxemul_cons_ttyinit, NULL); 290234920Srwatson 291234920Srwatsonstatic void 292234920Srwatsongxemul_cons_outwakeup(struct tty *tp) 293234920Srwatson{ 294234920Srwatson int len; 295234920Srwatson u_char ch; 296234920Srwatson 297234920Srwatson /* 298234920Srwatson * XXXRW: Would be nice not to do blocking writes to the console here, 299234920Srwatson * rescheduling on our timer tick if work remains to be done.. 300234920Srwatson */ 301234920Srwatson for (;;) { 302234920Srwatson len = ttydisc_getc(tp, &ch, sizeof(ch)); 303234920Srwatson if (len == 0) 304234920Srwatson break; 305234920Srwatson GC_LOCK(); 306234920Srwatson gxemul_cons_write(ch); 307234920Srwatson GC_UNLOCK(); 308234920Srwatson } 309234920Srwatson} 310234920Srwatson 311234920Srwatsonstatic void 312234920Srwatsongxemul_cons_timeout(void *v) 313234920Srwatson{ 314234920Srwatson struct tty *tp; 315234920Srwatson int c; 316234920Srwatson 317234920Srwatson tp = v; 318234920Srwatson tty_lock(tp); 319234920Srwatson GC_LOCK(); 320234920Srwatson while (gxemul_cons_readable()) { 321234920Srwatson c = gxemul_cons_read(); 322234920Srwatson GC_UNLOCK(); 323234920Srwatson#ifdef KDB 324234920Srwatson kdb_alt_break(c, &gxemul_cons_alt_break_state); 325234920Srwatson#endif 326234920Srwatson ttydisc_rint(tp, c, 0); 327234920Srwatson GC_LOCK(); 328234920Srwatson } 329234920Srwatson GC_UNLOCK(); 330234920Srwatson ttydisc_rint_done(tp); 331234920Srwatson tty_unlock(tp); 332234920Srwatson callout_reset(&gxemul_cons_callout, gxemul_cons_polltime, 333234920Srwatson gxemul_cons_timeout, tp); 334234920Srwatson} 335