added base src
[xv6-db.git] / console.c
blob6ca47680f21f38f3f0040ac6fc8c1186d42c9b7e
1 // Console input and output.
2 // Input is from the keyboard or serial port.
3 // Output is written to the screen and serial port.
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"
16 static void consputc(int);
18 static int panicked = 0;
20 static struct {
21 struct spinlock lock;
22 int locking;
23 } cons;
25 static void
26 printint(int xx, int base, int sign)
28 static char digits[] = "0123456789abcdef";
29 char buf[16];
30 int i;
31 uint x;
33 if(sign && (sign = xx < 0))
34 x = -xx;
35 else
36 x = xx;
38 i = 0;
39 do{
40 buf[i++] = digits[x % base];
41 }while((x /= base) != 0);
43 if(sign)
44 buf[i++] = '-';
46 while(--i >= 0)
47 consputc(buf[i]);
50 // Print to the console. only understands %d, %x, %p, %s.
51 void
52 cprintf(char *fmt, ...)
54 int i, c, state, locking;
55 uint *argp;
56 char *s;
58 locking = cons.locking;
59 if(locking)
60 acquire(&cons.lock);
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;
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;
97 if(locking)
98 release(&cons.lock);
101 void
102 panic(char *s)
104 int i;
105 uint pcs[10];
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(;;)
120 #define BACKSPACE 0x100
121 #define CRTPORT 0x3d4
122 static ushort *crt = (ushort*)0xb8000; // CGA memory
124 static void
125 cgaputc(int c)
127 int pos;
129 // Cursor position: col + 80*row.
130 outb(CRTPORT, 14);
131 pos = inb(CRTPORT+1) << 8;
132 outb(CRTPORT, 15);
133 pos |= inb(CRTPORT+1);
135 if(c == '\n')
136 pos += 80 - pos%80;
137 else if(c == BACKSPACE){
138 if(pos > 0) --pos;
139 } else
140 crt[pos++] = (c&0xff) | 0x0700; // black on white
142 if((pos/80) >= 24){ // Scroll up.
143 memmove(crt, crt+80, sizeof(crt[0])*23*80);
144 pos -= 80;
145 memset(crt+pos, 0, sizeof(crt[0])*(24*80 - pos));
148 outb(CRTPORT, 14);
149 outb(CRTPORT+1, pos>>8);
150 outb(CRTPORT, 15);
151 outb(CRTPORT+1, pos);
152 crt[pos] = ' ' | 0x0700;
155 void
156 consputc(int c)
158 if(panicked){
159 cli();
160 for(;;)
164 if(c == BACKSPACE){
165 uartputc('\b'); uartputc(' '); uartputc('\b');
166 } else
167 uartputc(c);
168 cgaputc(c);
171 #define INPUT_BUF 128
172 struct {
173 struct spinlock lock;
174 char buf[INPUT_BUF];
175 uint r; // Read index
176 uint w; // Write index
177 uint e; // Edit index
178 } input;
180 #define C(x) ((x)-'@') // Control-x
182 void
183 consoleintr(int (*getc)(void))
185 int c;
187 acquire(&input.lock);
188 while((c = getc()) >= 0){
189 switch(c){
190 case C('P'): // Process listing.
191 procdump();
192 break;
193 case C('U'): // Kill line.
194 while(input.e != input.w &&
195 input.buf[(input.e-1) % INPUT_BUF] != '\n'){
196 input.e--;
197 consputc(BACKSPACE);
199 break;
200 case C('H'): case '\x7f': // Backspace
201 if(input.e != input.w){
202 input.e--;
203 consputc(BACKSPACE);
205 break;
206 default:
207 if(c != 0 && input.e-input.r < INPUT_BUF){
208 c = (c == '\r') ? '\n' : c;
209 input.buf[input.e++ % INPUT_BUF] = c;
210 consputc(c);
211 if(c == '\n' || c == C('D') || input.e == input.r+INPUT_BUF){
212 input.w = input.e;
213 wakeup(&input.r);
216 break;
219 release(&input.lock);
223 consoleread(struct inode *ip, char *dst, int n)
225 uint target;
226 int c;
228 iunlock(ip);
229 target = n;
230 acquire(&input.lock);
231 while(n > 0){
232 while(input.r == input.w){
233 if(proc->killed){
234 release(&input.lock);
235 ilock(ip);
236 return -1;
238 sleep(&input.r, &input.lock);
240 c = input.buf[input.r++ % INPUT_BUF];
241 if(c == C('D')){ // EOF
242 if(n < target){
243 // Save ^D for next time, to make sure
244 // caller gets a 0-byte result.
245 input.r--;
247 break;
249 *dst++ = c;
250 --n;
251 if(c == '\n')
252 break;
254 release(&input.lock);
255 ilock(ip);
257 return target - n;
261 consolewrite(struct inode *ip, char *buf, int n)
263 int i;
265 iunlock(ip);
266 acquire(&cons.lock);
267 for(i = 0; i < n; i++)
268 consputc(buf[i] & 0xff);
269 release(&cons.lock);
270 ilock(ip);
272 return n;
275 void
276 consoleinit(void)
278 initlock(&cons.lock, "console");
279 initlock(&input.lock, "input");
281 devsw[CONSOLE].write = consolewrite;
282 devsw[CONSOLE].read = consoleread;
283 cons.locking = 1;
285 picenable(IRQ_KBD);
286 ioapicenable(IRQ_KBD, 0);