1#include <linux/console.h> 2#include <linux/kernel.h> 3#include <linux/init.h> 4#include <linux/string.h> 5#include <linux/screen_info.h> 6#include <asm/io.h> 7#include <asm/processor.h> 8#include <asm/fcntl.h> 9 10/* Simple VGA output */ 11 12#ifdef __i386__ 13#include <asm/setup.h> 14#else 15#include <asm/bootsetup.h> 16#endif 17#define VGABASE (__ISA_IO_base + 0xb8000) 18 19static int max_ypos = 25, max_xpos = 80; 20static int current_ypos = 25, current_xpos = 0; 21 22static void early_vga_write(struct console *con, const char *str, unsigned n) 23{ 24 char c; 25 int i, k, j; 26 27 while ((c = *str++) != '\0' && n-- > 0) { 28 if (current_ypos >= max_ypos) { 29 /* scroll 1 line up */ 30 for (k = 1, j = 0; k < max_ypos; k++, j++) { 31 for (i = 0; i < max_xpos; i++) { 32 writew(readw(VGABASE+2*(max_xpos*k+i)), 33 VGABASE + 2*(max_xpos*j + i)); 34 } 35 } 36 for (i = 0; i < max_xpos; i++) 37 writew(0x720, VGABASE + 2*(max_xpos*j + i)); 38 current_ypos = max_ypos-1; 39 } 40 if (c == '\n') { 41 current_xpos = 0; 42 current_ypos++; 43 } else if (c != '\r') { 44 writew(((0x7 << 8) | (unsigned short) c), 45 VGABASE + 2*(max_xpos*current_ypos + 46 current_xpos++)); 47 if (current_xpos >= max_xpos) { 48 current_xpos = 0; 49 current_ypos++; 50 } 51 } 52 } 53} 54 55static struct console early_vga_console = { 56 .name = "earlyvga", 57 .write = early_vga_write, 58 .flags = CON_PRINTBUFFER, 59 .index = -1, 60}; 61 62/* Serial functions loosely based on a similar package from Klaus P. Gerlicher */ 63 64static int early_serial_base = 0x3f8; /* ttyS0 */ 65 66#define XMTRDY 0x20 67 68#define DLAB 0x80 69 70#define TXR 0 /* Transmit register (WRITE) */ 71#define RXR 0 /* Receive register (READ) */ 72#define IER 1 /* Interrupt Enable */ 73#define IIR 2 /* Interrupt ID */ 74#define FCR 2 /* FIFO control */ 75#define LCR 3 /* Line control */ 76#define MCR 4 /* Modem control */ 77#define LSR 5 /* Line Status */ 78#define MSR 6 /* Modem Status */ 79#define DLL 0 /* Divisor Latch Low */ 80#define DLH 1 /* Divisor latch High */ 81 82static int early_serial_putc(unsigned char ch) 83{ 84 unsigned timeout = 0xffff; 85 while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout) 86 cpu_relax(); 87 outb(ch, early_serial_base + TXR); 88 return timeout ? 0 : -1; 89} 90 91static void early_serial_write(struct console *con, const char *s, unsigned n) 92{ 93 while (*s && n-- > 0) { 94 if (*s == '\n') 95 early_serial_putc('\r'); 96 early_serial_putc(*s); 97 s++; 98 } 99} 100 101#define DEFAULT_BAUD 9600 102 103static __init void early_serial_init(char *s) 104{ 105 unsigned char c; 106 unsigned divisor; 107 unsigned baud = DEFAULT_BAUD; 108 char *e; 109 110 if (*s == ',') 111 ++s; 112 113 if (*s) { 114 unsigned port; 115 if (!strncmp(s,"0x",2)) { 116 early_serial_base = simple_strtoul(s, &e, 16); 117 } else { 118 static int bases[] = { 0x3f8, 0x2f8 }; 119 120 if (!strncmp(s,"ttyS",4)) 121 s += 4; 122 port = simple_strtoul(s, &e, 10); 123 if (port > 1 || s == e) 124 port = 0; 125 early_serial_base = bases[port]; 126 } 127 s += strcspn(s, ","); 128 if (*s == ',') 129 s++; 130 } 131 132 outb(0x3, early_serial_base + LCR); /* 8n1 */ 133 outb(0, early_serial_base + IER); /* no interrupt */ 134 outb(0, early_serial_base + FCR); /* no fifo */ 135 outb(0x3, early_serial_base + MCR); /* DTR + RTS */ 136 137 if (*s) { 138 baud = simple_strtoul(s, &e, 0); 139 if (baud == 0 || s == e) 140 baud = DEFAULT_BAUD; 141 } 142 143 divisor = 115200 / baud; 144 c = inb(early_serial_base + LCR); 145 outb(c | DLAB, early_serial_base + LCR); 146 outb(divisor & 0xff, early_serial_base + DLL); 147 outb((divisor >> 8) & 0xff, early_serial_base + DLH); 148 outb(c & ~DLAB, early_serial_base + LCR); 149} 150 151static struct console early_serial_console = { 152 .name = "earlyser", 153 .write = early_serial_write, 154 .flags = CON_PRINTBUFFER, 155 .index = -1, 156}; 157 158/* Console interface to a host file on AMD's SimNow! */ 159 160static int simnow_fd; 161 162enum { 163 MAGIC1 = 0xBACCD00A, 164 MAGIC2 = 0xCA110000, 165 XOPEN = 5, 166 XWRITE = 4, 167}; 168 169static noinline long simnow(long cmd, long a, long b, long c) 170{ 171 long ret; 172 asm volatile("cpuid" : 173 "=a" (ret) : 174 "b" (a), "c" (b), "d" (c), "0" (MAGIC1), "D" (cmd + MAGIC2)); 175 return ret; 176} 177 178static void __init simnow_init(char *str) 179{ 180 char *fn = "klog"; 181 if (*str == '=') 182 fn = ++str; 183 /* error ignored */ 184 simnow_fd = simnow(XOPEN, (unsigned long)fn, O_WRONLY|O_APPEND|O_CREAT, 0644); 185} 186 187static void simnow_write(struct console *con, const char *s, unsigned n) 188{ 189 simnow(XWRITE, simnow_fd, (unsigned long)s, n); 190} 191 192static struct console simnow_console = { 193 .name = "simnow", 194 .write = simnow_write, 195 .flags = CON_PRINTBUFFER, 196 .index = -1, 197}; 198 199/* Direct interface for emergencies */ 200struct console *early_console = &early_vga_console; 201static int early_console_initialized = 0; 202 203void early_printk(const char *fmt, ...) 204{ 205 char buf[512]; 206 int n; 207 va_list ap; 208 209 va_start(ap,fmt); 210 n = vscnprintf(buf,512,fmt,ap); 211 early_console->write(early_console,buf,n); 212 va_end(ap); 213} 214 215static int __initdata keep_early; 216 217static int __init setup_early_printk(char *buf) 218{ 219 if (!buf) 220 return 0; 221 222 if (early_console_initialized) 223 return 0; 224 early_console_initialized = 1; 225 226 if (strstr(buf, "keep")) 227 keep_early = 1; 228 229 if (!strncmp(buf, "serial", 6)) { 230 early_serial_init(buf + 6); 231 early_console = &early_serial_console; 232 } else if (!strncmp(buf, "ttyS", 4)) { 233 early_serial_init(buf); 234 early_console = &early_serial_console; 235 } else if (!strncmp(buf, "vga", 3) 236 && SCREEN_INFO.orig_video_isVGA == 1) { 237 max_xpos = SCREEN_INFO.orig_video_cols; 238 max_ypos = SCREEN_INFO.orig_video_lines; 239 current_ypos = SCREEN_INFO.orig_y; 240 early_console = &early_vga_console; 241 } else if (!strncmp(buf, "simnow", 6)) { 242 simnow_init(buf + 6); 243 early_console = &simnow_console; 244 keep_early = 1; 245 } 246 247 if (keep_early) 248 early_console->flags &= ~CON_BOOT; 249 else 250 early_console->flags |= CON_BOOT; 251 register_console(early_console); 252 return 0; 253} 254early_param("earlyprintk", setup_early_printk); 255