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