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