console.c (5439B)
1 // Console input and output. 2 // Input is from the keyboard or serial port. 3 // Output is written to the screen and serial port. 4 5 #include <stdarg.h> 6 7 #include "types.h" 8 #include "defs.h" 9 #include "param.h" 10 #include "traps.h" 11 #include "spinlock.h" 12 #include "fs.h" 13 #include "file.h" 14 #include "memlayout.h" 15 #include "mmu.h" 16 #include "proc.h" 17 #include "x86.h" 18 19 static void consputc(int); 20 21 static int panicked = 0; 22 23 static struct { 24 struct spinlock lock; 25 int locking; 26 } cons; 27 28 static char digits[] = "0123456789abcdef"; 29 30 static void 31 printptr(uintp x) { 32 int i; 33 for (i = 0; i < (sizeof(uintp) * 2); i++, x <<= 4) 34 consputc(digits[x >> (sizeof(uintp) * 8 - 4)]); 35 } 36 37 static void 38 printint(int xx, int base, int sign) 39 { 40 char buf[16]; 41 int i; 42 uint x; 43 44 if(sign && (sign = xx < 0)) 45 x = -xx; 46 else 47 x = xx; 48 49 i = 0; 50 do{ 51 buf[i++] = digits[x % base]; 52 }while((x /= base) != 0); 53 54 if(sign) 55 buf[i++] = '-'; 56 57 while(--i >= 0) 58 consputc(buf[i]); 59 } 60 //PAGEBREAK: 50 61 62 // Print to the console. only understands %d, %x, %p, %s. 63 void 64 cprintf(char *fmt, ...) 65 { 66 va_list ap; 67 int i, c, locking; 68 char *s; 69 70 va_start(ap, fmt); 71 72 locking = cons.locking; 73 if(locking) 74 acquire(&cons.lock); 75 76 if (fmt == 0) 77 panic("null fmt"); 78 79 for(i = 0; (c = fmt[i] & 0xff) != 0; i++){ 80 if(c != '%'){ 81 consputc(c); 82 continue; 83 } 84 c = fmt[++i] & 0xff; 85 if(c == 0) 86 break; 87 switch(c){ 88 case 'd': 89 printint(va_arg(ap, int), 10, 1); 90 break; 91 case 'x': 92 printint(va_arg(ap, int), 16, 0); 93 break; 94 case 'p': 95 printptr(va_arg(ap, uintp)); 96 break; 97 case 's': 98 if((s = va_arg(ap, char*)) == 0) 99 s = "(null)"; 100 for(; *s; s++) 101 consputc(*s); 102 break; 103 case '%': 104 consputc('%'); 105 break; 106 default: 107 // Print unknown % sequence to draw attention. 108 consputc('%'); 109 consputc(c); 110 break; 111 } 112 } 113 114 if(locking) 115 release(&cons.lock); 116 } 117 118 void 119 panic(char *s) 120 { 121 int i; 122 uintp pcs[10]; 123 124 cli(); 125 cons.locking = 0; 126 cprintf("cpu%d: panic: ", cpu->id); 127 cprintf(s); 128 cprintf("\n"); 129 getcallerpcs(&s, pcs); 130 for(i=0; i<10; i++) 131 cprintf(" %p", pcs[i]); 132 panicked = 1; // freeze other CPU 133 for(;;) 134 ; 135 } 136 137 //PAGEBREAK: 50 138 #define BACKSPACE 0x100 139 #define CRTPORT 0x3d4 140 static ushort *crt = (ushort*)P2V(0xb8000); // CGA memory 141 142 static void 143 cgaputc(int c) 144 { 145 int pos; 146 147 // Cursor position: col + 80*row. 148 outb(CRTPORT, 14); 149 pos = inb(CRTPORT+1) << 8; 150 outb(CRTPORT, 15); 151 pos |= inb(CRTPORT+1); 152 153 if(c == '\n') 154 pos += 80 - pos%80; 155 else if(c == BACKSPACE){ 156 if(pos > 0) --pos; 157 } else 158 crt[pos++] = (c&0xff) | 0x0700; // black on white 159 160 if((pos/80) >= 24){ // Scroll up. 161 memmove(crt, crt+80, sizeof(crt[0])*23*80); 162 pos -= 80; 163 memset(crt+pos, 0, sizeof(crt[0])*(24*80 - pos)); 164 } 165 166 outb(CRTPORT, 14); 167 outb(CRTPORT+1, pos>>8); 168 outb(CRTPORT, 15); 169 outb(CRTPORT+1, pos); 170 crt[pos] = ' ' | 0x0700; 171 } 172 173 void 174 consputc(int c) 175 { 176 if(panicked){ 177 cli(); 178 for(;;) 179 ; 180 } 181 182 if(c == BACKSPACE){ 183 uartputc('\b'); uartputc(' '); uartputc('\b'); 184 } else 185 uartputc(c); 186 cgaputc(c); 187 } 188 189 #define INPUT_BUF 128 190 struct { 191 struct spinlock lock; 192 char buf[INPUT_BUF]; 193 uint r; // Read index 194 uint w; // Write index 195 uint e; // Edit index 196 } input; 197 198 #define C(x) ((x)-'@') // Control-x 199 200 void 201 consoleintr(int (*getc)(void)) 202 { 203 int c; 204 205 acquire(&input.lock); 206 while((c = getc()) >= 0){ 207 switch(c){ 208 case C('Z'): // reboot 209 lidt(0,0); 210 break; 211 case C('P'): // Process listing. 212 procdump(); 213 break; 214 case C('U'): // Kill line. 215 while(input.e != input.w && 216 input.buf[(input.e-1) % INPUT_BUF] != '\n'){ 217 input.e--; 218 consputc(BACKSPACE); 219 } 220 break; 221 case C('H'): case '\x7f': // Backspace 222 if(input.e != input.w){ 223 input.e--; 224 consputc(BACKSPACE); 225 } 226 break; 227 default: 228 if(c != 0 && input.e-input.r < INPUT_BUF){ 229 c = (c == '\r') ? '\n' : c; 230 input.buf[input.e++ % INPUT_BUF] = c; 231 consputc(c); 232 if(c == '\n' || c == C('D') || input.e == input.r+INPUT_BUF){ 233 input.w = input.e; 234 wakeup(&input.r); 235 } 236 } 237 break; 238 } 239 } 240 release(&input.lock); 241 } 242 243 int 244 consoleread(struct inode *ip, char *dst, int n) 245 { 246 uint target; 247 int c; 248 249 iunlock(ip); 250 target = n; 251 acquire(&input.lock); 252 while(n > 0){ 253 while(input.r == input.w){ 254 if(proc->killed){ 255 release(&input.lock); 256 ilock(ip); 257 return -1; 258 } 259 sleep(&input.r, &input.lock); 260 } 261 c = input.buf[input.r++ % INPUT_BUF]; 262 if(c == C('D')){ // EOF 263 if(n < target){ 264 // Save ^D for next time, to make sure 265 // caller gets a 0-byte result. 266 input.r--; 267 } 268 break; 269 } 270 *dst++ = c; 271 --n; 272 if(c == '\n') 273 break; 274 } 275 release(&input.lock); 276 ilock(ip); 277 278 return target - n; 279 } 280 281 int 282 consolewrite(struct inode *ip, char *buf, int n) 283 { 284 int i; 285 286 iunlock(ip); 287 acquire(&cons.lock); 288 for(i = 0; i < n; i++) 289 consputc(buf[i] & 0xff); 290 release(&cons.lock); 291 ilock(ip); 292 293 return n; 294 } 295 296 void 297 consoleinit(void) 298 { 299 initlock(&cons.lock, "console"); 300 initlock(&input.lock, "input"); 301 302 devsw[CONSOLE].write = consolewrite; 303 devsw[CONSOLE].read = consoleread; 304 cons.locking = 1; 305 306 picenable(IRQ_KBD); 307 ioapicenable(IRQ_KBD, 0); 308 } 309