xref: /xv6-public/console.c (revision 4f14d8d1)
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
printint(int xx,int base,int sign)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
cprintf(char * fmt,...)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
panic(char * s)107 panic(char *s)
108 {
109   int i;
110   uint pcs[10];
111 
112   cli();
113   cons.locking = 0;
114   // use lapiccpunum so that we can call panic from mycpu()
115   cprintf("lapicid %d: panic: ", lapicid());
116   cprintf(s);
117   cprintf("\n");
118   getcallerpcs(&s, pcs);
119   for(i=0; i<10; i++)
120     cprintf(" %p", pcs[i]);
121   panicked = 1; // freeze other CPU
122   for(;;)
123     ;
124 }
125 
126 //PAGEBREAK: 50
127 #define BACKSPACE 0x100
128 #define CRTPORT 0x3d4
129 static ushort *crt = (ushort*)P2V(0xb8000);  // CGA memory
130 
131 static void
cgaputc(int c)132 cgaputc(int c)
133 {
134   int pos;
135 
136   // Cursor position: col + 80*row.
137   outb(CRTPORT, 14);
138   pos = inb(CRTPORT+1) << 8;
139   outb(CRTPORT, 15);
140   pos |= inb(CRTPORT+1);
141 
142   if(c == '\n')
143     pos += 80 - pos%80;
144   else if(c == BACKSPACE){
145     if(pos > 0) --pos;
146   } else
147     crt[pos++] = (c&0xff) | 0x0700;  // black on white
148 
149   if(pos < 0 || pos > 25*80)
150     panic("pos under/overflow");
151 
152   if((pos/80) >= 24){  // Scroll up.
153     memmove(crt, crt+80, sizeof(crt[0])*23*80);
154     pos -= 80;
155     memset(crt+pos, 0, sizeof(crt[0])*(24*80 - pos));
156   }
157 
158   outb(CRTPORT, 14);
159   outb(CRTPORT+1, pos>>8);
160   outb(CRTPORT, 15);
161   outb(CRTPORT+1, pos);
162   crt[pos] = ' ' | 0x0700;
163 }
164 
165 void
consputc(int c)166 consputc(int c)
167 {
168   if(panicked){
169     cli();
170     for(;;)
171       ;
172   }
173 
174   if(c == BACKSPACE){
175     uartputc('\b'); uartputc(' '); uartputc('\b');
176   } else
177     uartputc(c);
178   cgaputc(c);
179 }
180 
181 #define INPUT_BUF 128
182 struct {
183   char buf[INPUT_BUF];
184   uint r;  // Read index
185   uint w;  // Write index
186   uint e;  // Edit index
187 } input;
188 
189 #define C(x)  ((x)-'@')  // Control-x
190 
191 void
consoleintr(int (* getc)(void))192 consoleintr(int (*getc)(void))
193 {
194   int c, doprocdump = 0;
195 
196   acquire(&cons.lock);
197   while((c = getc()) >= 0){
198     switch(c){
199     case C('P'):  // Process listing.
200       // procdump() locks cons.lock indirectly; invoke later
201       doprocdump = 1;
202       break;
203     case C('U'):  // Kill line.
204       while(input.e != input.w &&
205             input.buf[(input.e-1) % INPUT_BUF] != '\n'){
206         input.e--;
207         consputc(BACKSPACE);
208       }
209       break;
210     case C('H'): case '\x7f':  // Backspace
211       if(input.e != input.w){
212         input.e--;
213         consputc(BACKSPACE);
214       }
215       break;
216     default:
217       if(c != 0 && input.e-input.r < INPUT_BUF){
218         c = (c == '\r') ? '\n' : c;
219         input.buf[input.e++ % INPUT_BUF] = c;
220         consputc(c);
221         if(c == '\n' || c == C('D') || input.e == input.r+INPUT_BUF){
222           input.w = input.e;
223           wakeup(&input.r);
224         }
225       }
226       break;
227     }
228   }
229   release(&cons.lock);
230   if(doprocdump) {
231     procdump();  // now call procdump() wo. cons.lock held
232   }
233 }
234 
235 int
consoleread(struct inode * ip,char * dst,int n)236 consoleread(struct inode *ip, char *dst, int n)
237 {
238   uint target;
239   int c;
240 
241   iunlock(ip);
242   target = n;
243   acquire(&cons.lock);
244   while(n > 0){
245     while(input.r == input.w){
246       if(myproc()->killed){
247         release(&cons.lock);
248         ilock(ip);
249         return -1;
250       }
251       sleep(&input.r, &cons.lock);
252     }
253     c = input.buf[input.r++ % INPUT_BUF];
254     if(c == C('D')){  // EOF
255       if(n < target){
256         // Save ^D for next time, to make sure
257         // caller gets a 0-byte result.
258         input.r--;
259       }
260       break;
261     }
262     *dst++ = c;
263     --n;
264     if(c == '\n')
265       break;
266   }
267   release(&cons.lock);
268   ilock(ip);
269 
270   return target - n;
271 }
272 
273 int
consolewrite(struct inode * ip,char * buf,int n)274 consolewrite(struct inode *ip, char *buf, int n)
275 {
276   int i;
277 
278   iunlock(ip);
279   acquire(&cons.lock);
280   for(i = 0; i < n; i++)
281     consputc(buf[i] & 0xff);
282   release(&cons.lock);
283   ilock(ip);
284 
285   return n;
286 }
287 
288 void
consoleinit(void)289 consoleinit(void)
290 {
291   initlock(&cons.lock, "console");
292 
293   devsw[CONSOLE].write = consolewrite;
294   devsw[CONSOLE].read = consoleread;
295   cons.locking = 1;
296 
297   ioapicenable(IRQ_KBD, 0);
298 }
299 
300