1/* 2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* 29 * @OSF_FREE_COPYRIGHT@ 30 * 31 */ 32 33/* Intercept mach console output and supply it to a user application */ 34 35#include <mach_kdb.h> 36 37#include <types.h> 38#include <device/buf.h> 39#include <device/conf.h> 40#include <device/errno.h> 41#include <device/misc_protos.h> 42#include <device/ds_routines.h> 43#include <device/cirbuf.h> 44#include <ppc/console_feed_entries.h> 45#include <ppc/serial_io.h> 46 47#if MACH_KDB 48#include <ppc/db_machdep.h> 49#endif /* MACH_KDB */ 50 51static struct cirbuf cons_feed_cb; 52static int cons_feed_count = 0; 53io_req_t cons_feed_queued = 0; 54 55/* console feed lock should be taken at splhigh */ 56decl_simple_lock_data(,cons_feed_lock) 57 58boolean_t cons_feed_read_done(io_req_t ior); 59 60io_return_t 61console_feed_open( 62 dev_t dev, 63 dev_mode_t flag, 64 io_req_t ior) 65{ 66 spl_t s; 67 68 simple_lock_init(&cons_feed_lock, 0); 69#if MACH_KDB 70 if (console_is_serial()) { 71 return D_DEVICE_DOWN; 72 } 73#endif /* MACH_KDB */ 74 cb_alloc(&cons_feed_cb, CONSOLE_FEED_BUFSIZE); 75 s = splhigh(); 76 simple_lock(&cons_feed_lock); 77 cons_feed_count++; 78 simple_unlock(&cons_feed_lock); 79 splx(s); 80 return D_SUCCESS; 81} 82 83void 84console_feed_close( 85 dev_t dev) 86{ 87 spl_t s; 88 89 s = splhigh(); 90 simple_lock(&cons_feed_lock); 91 cons_feed_count--; 92 simple_unlock(&cons_feed_lock); 93 splx(s); 94 95 console_feed_cancel_and_flush(); 96 cb_free(&cons_feed_cb); 97 98 return; 99} 100 101/* A routine that can be called from a panic or other problem 102 * situation. It switches off the console feed and dumps any 103 * remaining buffered information to the original console 104 * (usually the screen). It doesn't free up the buffer, since 105 * it tries to be as minimal as possible 106 */ 107 108void console_feed_cancel_and_flush(void) 109{ 110 int c; 111 spl_t s; 112 113#if NCONSFEED > 0 114#if MACH_KDB 115 if (console_is_serial()) { 116 return; 117 } 118#endif /* MACH_KDB */ 119 120 s = splhigh(); 121 simple_lock(&cons_feed_lock); 122 if (cons_feed_count == 0) { 123 simple_unlock(&cons_feed_lock); 124 splx(s); 125 return; 126 } 127 cons_feed_count = 0; 128 simple_unlock(&cons_feed_lock); 129 splx(s); 130 131 do { 132 c = getc(&cons_feed_cb); 133 if (c == -1) 134 break; 135 cnputc(c); 136 } while (1); 137#endif /* NCONSFEED > 0 */ 138} 139 140io_return_t 141console_feed_read( 142 dev_t dev, 143 io_req_t ior) 144{ 145 spl_t s; 146 kern_return_t rc; 147 int count; 148 149 rc = device_read_alloc(ior, (vm_size_t) ior->io_count); 150 if (rc != KERN_SUCCESS) 151 return rc; 152 153 s = splhigh(); 154 simple_lock(&cons_feed_lock); 155 156 ior->io_residual = ior->io_count; 157 158 count = q_to_b(&cons_feed_cb, (char *) ior->io_data, ior->io_count); 159 if (count == 0) { 160 if (ior->io_mode & D_NOWAIT) { 161 rc = D_WOULD_BLOCK; 162 } 163 if (cons_feed_queued == NULL) { 164 ior->io_done = cons_feed_read_done; 165 cons_feed_queued = ior; 166 rc = D_IO_QUEUED; 167 } else { 168 /* Can't queue multiple read requests yet */ 169 rc = D_INVALID_OPERATION; 170 } 171 simple_unlock(&cons_feed_lock); 172 splx(s); 173 return rc; 174 } 175 176 simple_unlock(&cons_feed_lock); 177 splx(s); 178 179 ior->io_residual -= count; 180 181 iodone(ior); 182 183 if (ior->io_op & IO_SYNC) { 184 iowait(ior); 185 } 186 187 return D_SUCCESS; 188} 189 190/* Called when data is ready and there's a queued-up read waiting */ 191boolean_t cons_feed_read_done(io_req_t ior) 192{ 193 spl_t s; 194 int count; 195 196 s = splhigh(); 197 simple_lock(&cons_feed_lock); 198 199 count = q_to_b(&cons_feed_cb, (char *) ior->io_data, ior->io_count); 200 if (count == 0) { 201 if (cons_feed_queued == NULL) { 202 ior->io_done = cons_feed_read_done; 203 cons_feed_queued = ior; 204 } 205 simple_unlock(&cons_feed_lock); 206 splx(s); 207 return FALSE; 208 } 209 210 simple_unlock(&cons_feed_lock); 211 splx(s); 212 213 ior->io_residual -= count; 214 ds_read_done(ior); 215 216 return TRUE; 217} 218 219/* This routine is called from putc() - it should return TRUE if 220 * the character should be passed on to a physical console, FALSE 221 * if the feed has intercepted the character. It may be called from 222 * under interrupt (even splhigh) 223 */ 224 225boolean_t console_feed_putc(char c) 226{ 227 spl_t s; 228 io_req_t ior; 229 boolean_t retval; 230 231#if MACH_KDB 232 if (db_active) { 233 return TRUE; 234 } 235#endif /* MACH_KDB */ 236 237 retval=TRUE; /* TRUE : character should be displayed now */ 238 if (!cons_feed_count) { 239 return TRUE; 240 } 241 s = splhigh(); 242 simple_lock(&cons_feed_lock); 243 if (!cons_feed_count) { 244 simple_unlock(&cons_feed_lock); 245 splx(s); 246 return TRUE; 247 } 248 /* queue up the data if we can */ 249 if (!putc(c, &cons_feed_cb)) { 250 /* able to stock the character */ 251 retval = FALSE; 252 } 253 if (cons_feed_queued != NULL) { 254 /* Queued up request - service it */ 255 ior = cons_feed_queued; 256 cons_feed_queued = NULL; 257 simple_unlock(&cons_feed_lock); 258 splx(s); 259 iodone(ior); 260 retval=FALSE; 261 } else { 262 simple_unlock(&cons_feed_lock); 263 splx(s); 264 } 265 return retval; 266} 267