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