1/* 2 **************************************************************************** 3 * (C) 2006 - Grzegorz Milos - Cambridge University 4 **************************************************************************** 5 * 6 * File: console.h 7 * Author: Grzegorz Milos 8 * Changes: 9 * 10 * Date: Mar 2006 11 * 12 * Environment: Xen Minimal OS 13 * Description: Console interface. 14 * 15 * Handles console I/O. Defines printk. 16 * 17 **************************************************************************** 18 * Permission is hereby granted, free of charge, to any person obtaining a copy 19 * of this software and associated documentation files (the "Software"), to 20 * deal in the Software without restriction, including without limitation the 21 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 22 * sell copies of the Software, and to permit persons to whom the Software is 23 * furnished to do so, subject to the following conditions: 24 * 25 * The above copyright notice and this permission notice shall be included in 26 * all copies or substantial portions of the Software. 27 * 28 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 29 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 30 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 31 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 32 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 33 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 34 * DEALINGS IN THE SOFTWARE. 35 */ 36 37#include <mini-os/types.h> 38#include <mini-os/wait.h> 39#include <mini-os/mm.h> 40#include <mini-os/hypervisor.h> 41#include <mini-os/events.h> 42#include <mini-os/os.h> 43#include <mini-os/lib.h> 44#include <mini-os/xenbus.h> 45#include <xen/io/console.h> 46 47#include <bmk-core/string.h> 48#define _BMK_PRINTF_VA 49#include <bmk-core/printf.h> 50 51/* Copies all print output to the Xen emergency console apart 52 of standard dom0 handled console */ 53#define USE_XEN_CONSOLE 54 55 56/* If console not initialised the printk will be sent to xen serial line 57 NOTE: you need to enable verbose in xen/Rules.mk for it to work. */ 58static int console_initialised = 0; 59 60 61void xencons_rx(char *buf, unsigned len, struct pt_regs *regs) 62{ 63 if(len > 0) 64 { 65 /* Just repeat what's written */ 66 buf[len] = '\0'; 67 minios_printk("%s", buf); 68 69 if(buf[len-1] == '\r') 70 minios_printk("\nNo console input handler.\n"); 71 } 72} 73 74void xencons_tx(void) 75{ 76 /* Do nothing, handled by _rx */ 77} 78 79 80void minios_console_print(struct consfront_dev *dev, char *data, int length) 81{ 82 char *curr_char, saved_char; 83 char copied_str[length+1]; 84 char *copied_ptr; 85 int part_len; 86 int (*ring_send_fn)(struct consfront_dev *dev, const char *data, unsigned length); 87 int sent; 88 89 if(!console_initialised) 90 ring_send_fn = xencons_ring_send_no_notify; 91 else 92 ring_send_fn = xencons_ring_send; 93 94 copied_ptr = copied_str; 95 bmk_memcpy(copied_ptr, data, length); 96 for(curr_char = copied_ptr; curr_char < copied_ptr+length-1; curr_char++) 97 { 98 if(*curr_char == '\n') 99 { 100 *curr_char = '\r'; 101 saved_char = *(curr_char+1); 102 *(curr_char+1) = '\n'; 103 part_len = curr_char - copied_ptr + 2; 104 ring_send_fn(dev, copied_ptr, part_len); 105 *(curr_char+1) = saved_char; 106 copied_ptr = curr_char+1; 107 length -= part_len - 1; 108 } 109 } 110 111 if (copied_ptr[length-1] == '\n') { 112 copied_ptr[length-1] = '\r'; 113 copied_ptr[length] = '\n'; 114 length++; 115 } 116 117 /* 118 * we assume that the lower layer loops until it manages to 119 * send everything. XXX is this the best place to do "buffering"? 120 */ 121 sent = ring_send_fn(dev, copied_ptr, length); 122 ASSERT(ring_send_fn == xencons_ring_send_no_notify || sent == length); 123} 124 125static void print(int direct, const char *fmt, va_list args) 126{ 127 static char buf[1024]; 128 129 bmk_vsnprintf(buf, sizeof(buf), fmt, args); 130 131 if(direct) 132 { 133 (void)HYPERVISOR_console_io(CONSOLEIO_write, bmk_strlen(buf), buf); 134 return; 135 } else { 136#ifndef USE_XEN_CONSOLE 137 if(!console_initialised) 138#endif 139 (void)HYPERVISOR_console_io(CONSOLEIO_write, bmk_strlen(buf), buf); 140 141 minios_console_print(NULL, buf, bmk_strlen(buf)); 142 } 143} 144 145/* XXX: should use a putc/flush combo ... later */ 146void minios_putc(int c) 147{ 148 149 minios_printk("%c", c); 150} 151 152void minios_printk(const char *fmt, ...) 153{ 154 va_list args; 155 va_start(args, fmt); 156 print(0, fmt, args); 157 va_end(args); 158} 159 160void xprintk(const char *fmt, ...) 161{ 162 va_list args; 163 va_start(args, fmt); 164 print(1, fmt, args); 165 va_end(args); 166} 167void init_console(void) 168{ 169 minios_printk("Initialising console ... "); 170 xencons_ring_init(); 171 console_initialised = 1; 172 /* This is also required to notify the daemon */ 173 minios_printk("done.\n"); 174} 175