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