gxemul_cons.c revision 243422
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 243422 2012-11-23 04:28:13Z jmallett $"); 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 45243422Sjmallett#include <machine/cpuregs.h> 46243422Sjmallett 47234920Srwatson#define GC_LOCK_INIT() mtx_init(&gc_lock, "gc_lock", NULL, MTX_SPIN) 48234920Srwatson 49234920Srwatson#define GC_LOCK() do { \ 50234920Srwatson if (!kdb_active) \ 51234920Srwatson mtx_lock_spin(&gc_lock); \ 52234920Srwatson} while (0) 53234920Srwatson 54234920Srwatson#define GC_LOCK_ASSERT() do { \ 55234920Srwatson if (!kdb_active) \ 56234920Srwatson mtx_assert(&gc_lock, MA_OWNED); \ 57234920Srwatson} while (0) 58234920Srwatson 59234920Srwatson#define GC_UNLOCK() do { \ 60234920Srwatson if (!kdb_active) \ 61234920Srwatson mtx_unlock_spin(&gc_lock); \ 62234920Srwatson} while (0) 63234920Srwatson 64234920Srwatson 65234920Srwatsonstatic struct mtx gc_lock; 66234920Srwatson 67234920Srwatson/* 68234920Srwatson * Low-level console driver functions. 69234920Srwatson */ 70234920Srwatsonstatic cn_probe_t gxemul_cons_cnprobe; 71234920Srwatsonstatic cn_init_t gxemul_cons_cninit; 72234920Srwatsonstatic cn_term_t gxemul_cons_cnterm; 73234920Srwatsonstatic cn_getc_t gxemul_cons_cngetc; 74234920Srwatsonstatic cn_putc_t gxemul_cons_cnputc; 75234920Srwatsonstatic cn_grab_t gxemul_cons_cngrab; 76234920Srwatsonstatic cn_ungrab_t gxemul_cons_cnungrab; 77234920Srwatson 78234920Srwatson/* 79234920Srwatson * TTY-level fields. 80234920Srwatson */ 81234920Srwatsonstatic tsw_outwakeup_t gxemul_cons_outwakeup; 82234920Srwatson 83234920Srwatsonstatic struct ttydevsw gxemul_cons_ttydevsw = { 84234920Srwatson .tsw_flags = TF_NOPREFIX, 85234920Srwatson .tsw_outwakeup = gxemul_cons_outwakeup, 86234920Srwatson}; 87234920Srwatson 88234920Srwatsonstatic struct callout gxemul_cons_callout; 89234920Srwatsonstatic u_int gxemul_cons_polltime = 10; 90234920Srwatson#ifdef KDB 91234920Srwatsonstatic int gxemul_cons_alt_break_state; 92234920Srwatson#endif 93234920Srwatson 94234920Srwatsonstatic void gxemul_cons_timeout(void *); 95234920Srwatson 96234920Srwatson/* 97234920Srwatson * I/O routines lifted from Deimos. 98234920Srwatson * 99234920Srwatson * XXXRW: Should be using FreeBSD's bus routines here, but they are not 100234920Srwatson * available until later in the boot. 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 109243422Sjmallett return (MIPS_PHYS_TO_DIRECT_UNCACHED(phys)); 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