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