gxemul_cons.c revision 255212
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 255212 2013-09-04 20:34:36Z gonzo $"); 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 */ 102234920Srwatson 103255212Sgonzostatic inline vm_offset_t 104255212Sgonzomips_phys_to_uncached(vm_paddr_t phys) 105234920Srwatson{ 106234920Srwatson 107243422Sjmallett return (MIPS_PHYS_TO_DIRECT_UNCACHED(phys)); 108234920Srwatson} 109234920Srwatson 110234920Srwatsonstatic inline uint8_t 111255212Sgonzomips_ioread_uint8(vm_offset_t vaddr) 112234920Srwatson{ 113234920Srwatson uint8_t v; 114234920Srwatson 115234920Srwatson __asm__ __volatile__ ("lbu %0, 0(%1)" : "=r" (v) : "r" (vaddr)); 116234920Srwatson return (v); 117234920Srwatson} 118234920Srwatson 119234920Srwatsonstatic inline void 120255212Sgonzomips_iowrite_uint8(vm_offset_t vaddr, uint8_t v) 121234920Srwatson{ 122234920Srwatson 123234920Srwatson __asm__ __volatile__ ("sb %0, 0(%1)" : : "r" (v), "r" (vaddr)); 124234920Srwatson} 125234920Srwatson 126234920Srwatson/* 127234920Srwatson * gxemul-specific constants. 128234920Srwatson */ 129234920Srwatson#define GXEMUL_CONS_BASE 0x10000000 /* gxemul console device. */ 130234920Srwatson 131234920Srwatson/* 132234920Srwatson * Routines for interacting with the gxemul test console. Programming details 133234920Srwatson * are a result of manually inspecting the source code for gxemul's 134234920Srwatson * dev_cons.cc and dev_cons.h. 135234920Srwatson * 136234920Srwatson * Offsets of I/O channels relative to the base. 137234920Srwatson */ 138234920Srwatson#define GXEMUL_PUTGETCHAR_OFF 0x00000000 139234920Srwatson#define GXEMUL_CONS_HALT 0x00000010 140234920Srwatson 141234920Srwatson/* 142234920Srwatson * One-byte buffer as we can't check whether the console is readable without 143234920Srwatson * actually reading from it. 144234920Srwatson */ 145234920Srwatsonstatic char buffer_data; 146234920Srwatsonstatic int buffer_valid; 147234920Srwatson 148234920Srwatson/* 149234920Srwatson * Low-level read and write routines. 150234920Srwatson */ 151234920Srwatsonstatic inline uint8_t 152234920Srwatsongxemul_cons_data_read(void) 153234920Srwatson{ 154234920Srwatson 155234920Srwatson return (mips_ioread_uint8(mips_phys_to_uncached(GXEMUL_CONS_BASE + 156234920Srwatson GXEMUL_PUTGETCHAR_OFF))); 157234920Srwatson} 158234920Srwatson 159234920Srwatsonstatic inline void 160234920Srwatsongxemul_cons_data_write(uint8_t v) 161234920Srwatson{ 162234920Srwatson 163234920Srwatson mips_iowrite_uint8(mips_phys_to_uncached(GXEMUL_CONS_BASE + 164234920Srwatson GXEMUL_PUTGETCHAR_OFF), v); 165234920Srwatson} 166234920Srwatson 167234920Srwatsonstatic int 168234920Srwatsongxemul_cons_writable(void) 169234920Srwatson{ 170234920Srwatson 171234920Srwatson return (1); 172234920Srwatson} 173234920Srwatson 174234920Srwatsonstatic int 175234920Srwatsongxemul_cons_readable(void) 176234920Srwatson{ 177234920Srwatson uint32_t v; 178234920Srwatson 179234920Srwatson GC_LOCK_ASSERT(); 180234920Srwatson 181234920Srwatson if (buffer_valid) 182234920Srwatson return (1); 183234920Srwatson v = gxemul_cons_data_read(); 184234920Srwatson if (v != 0) { 185234920Srwatson buffer_valid = 1; 186234920Srwatson buffer_data = v; 187234920Srwatson return (1); 188234920Srwatson } 189234920Srwatson return (0); 190234920Srwatson} 191234920Srwatson 192234920Srwatsonstatic void 193234920Srwatsongxemul_cons_write(char ch) 194234920Srwatson{ 195234920Srwatson 196234920Srwatson GC_LOCK_ASSERT(); 197234920Srwatson 198234920Srwatson while (!gxemul_cons_writable()); 199234920Srwatson gxemul_cons_data_write(ch); 200234920Srwatson} 201234920Srwatson 202234920Srwatsonstatic char 203234920Srwatsongxemul_cons_read(void) 204234920Srwatson{ 205234920Srwatson 206234920Srwatson GC_LOCK_ASSERT(); 207234920Srwatson 208234920Srwatson while (!gxemul_cons_readable()); 209234920Srwatson buffer_valid = 0; 210234920Srwatson return (buffer_data); 211234920Srwatson} 212234920Srwatson 213234920Srwatson/* 214234920Srwatson * Implementation of a FreeBSD low-level, polled console driver. 215234920Srwatson */ 216234920Srwatsonstatic void 217234920Srwatsongxemul_cons_cnprobe(struct consdev *cp) 218234920Srwatson{ 219234920Srwatson 220239667Srwatson sprintf(cp->cn_name, "ttyu0"); 221239668Srwatson cp->cn_pri = (boothowto & RB_SERIAL) ? CN_REMOTE : CN_NORMAL; 222234920Srwatson} 223234920Srwatson 224234920Srwatsonstatic void 225234920Srwatsongxemul_cons_cninit(struct consdev *cp) 226234920Srwatson{ 227234920Srwatson 228234920Srwatson GC_LOCK_INIT(); 229234920Srwatson} 230234920Srwatson 231234920Srwatsonstatic void 232234920Srwatsongxemul_cons_cnterm(struct consdev *cp) 233234920Srwatson{ 234234920Srwatson 235234920Srwatson} 236234920Srwatson 237234920Srwatsonstatic int 238234920Srwatsongxemul_cons_cngetc(struct consdev *cp) 239234920Srwatson{ 240234920Srwatson int ret; 241234920Srwatson 242234920Srwatson GC_LOCK(); 243234920Srwatson ret = gxemul_cons_read(); 244234920Srwatson GC_UNLOCK(); 245234920Srwatson return (ret); 246234920Srwatson} 247234920Srwatson 248234920Srwatsonstatic void 249234920Srwatsongxemul_cons_cnputc(struct consdev *cp, int c) 250234920Srwatson{ 251234920Srwatson 252234920Srwatson GC_LOCK(); 253234920Srwatson gxemul_cons_write(c); 254234920Srwatson GC_UNLOCK(); 255234920Srwatson} 256234920Srwatson 257234920Srwatsonstatic void 258234920Srwatsongxemul_cons_cngrab(struct consdev *cp) 259234920Srwatson{ 260234920Srwatson 261234920Srwatson} 262234920Srwatson 263234920Srwatsonstatic void 264234920Srwatsongxemul_cons_cnungrab(struct consdev *cp) 265234920Srwatson{ 266234920Srwatson 267234920Srwatson} 268234920Srwatson 269234920SrwatsonCONSOLE_DRIVER(gxemul_cons); 270234920Srwatson 271234920Srwatson/* 272234920Srwatson * TTY-level functions for gxemul_cons. 273234920Srwatson */ 274234920Srwatsonstatic void 275234920Srwatsongxemul_cons_ttyinit(void *unused) 276234920Srwatson{ 277234920Srwatson struct tty *tp; 278234920Srwatson 279234920Srwatson tp = tty_alloc(&gxemul_cons_ttydevsw, NULL); 280234920Srwatson tty_init_console(tp, 0); 281239667Srwatson tty_makedev(tp, NULL, "%s", "ttyu0"); 282234920Srwatson callout_init(&gxemul_cons_callout, CALLOUT_MPSAFE); 283234920Srwatson callout_reset(&gxemul_cons_callout, gxemul_cons_polltime, 284234920Srwatson gxemul_cons_timeout, tp); 285234920Srwatson 286234920Srwatson} 287234920SrwatsonSYSINIT(gxemul_cons_ttyinit, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE, 288234920Srwatson gxemul_cons_ttyinit, NULL); 289234920Srwatson 290234920Srwatsonstatic void 291234920Srwatsongxemul_cons_outwakeup(struct tty *tp) 292234920Srwatson{ 293234920Srwatson int len; 294234920Srwatson u_char ch; 295234920Srwatson 296234920Srwatson /* 297234920Srwatson * XXXRW: Would be nice not to do blocking writes to the console here, 298234920Srwatson * rescheduling on our timer tick if work remains to be done.. 299234920Srwatson */ 300234920Srwatson for (;;) { 301234920Srwatson len = ttydisc_getc(tp, &ch, sizeof(ch)); 302234920Srwatson if (len == 0) 303234920Srwatson break; 304234920Srwatson GC_LOCK(); 305234920Srwatson gxemul_cons_write(ch); 306234920Srwatson GC_UNLOCK(); 307234920Srwatson } 308234920Srwatson} 309234920Srwatson 310234920Srwatsonstatic void 311234920Srwatsongxemul_cons_timeout(void *v) 312234920Srwatson{ 313234920Srwatson struct tty *tp; 314234920Srwatson int c; 315234920Srwatson 316234920Srwatson tp = v; 317234920Srwatson tty_lock(tp); 318234920Srwatson GC_LOCK(); 319234920Srwatson while (gxemul_cons_readable()) { 320234920Srwatson c = gxemul_cons_read(); 321234920Srwatson GC_UNLOCK(); 322234920Srwatson#ifdef KDB 323234920Srwatson kdb_alt_break(c, &gxemul_cons_alt_break_state); 324234920Srwatson#endif 325234920Srwatson ttydisc_rint(tp, c, 0); 326234920Srwatson GC_LOCK(); 327234920Srwatson } 328234920Srwatson GC_UNLOCK(); 329234920Srwatson ttydisc_rint_done(tp); 330234920Srwatson tty_unlock(tp); 331234920Srwatson callout_reset(&gxemul_cons_callout, gxemul_cons_polltime, 332234920Srwatson gxemul_cons_timeout, tp); 333234920Srwatson} 334