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