summaryrefslogtreecommitdiff
path: root/kernel/console.c
diff options
context:
space:
mode:
authorRobert Morris <[email protected]>2019-06-11 09:57:14 -0400
committerRobert Morris <[email protected]>2019-06-11 09:57:14 -0400
commit5753553213df8f9de851adb68377db43faecb91f (patch)
tree3b629ff54897fca414146677532cb459a2ed11ba /kernel/console.c
parent91ba81110acd3163f7de3580b677eece0c57f5e7 (diff)
downloadxv6-labs-5753553213df8f9de851adb68377db43faecb91f.tar.gz
xv6-labs-5753553213df8f9de851adb68377db43faecb91f.tar.bz2
xv6-labs-5753553213df8f9de851adb68377db43faecb91f.zip
separate source into kernel/ user/ mkfs/
Diffstat (limited to 'kernel/console.c')
-rw-r--r--kernel/console.c271
1 files changed, 271 insertions, 0 deletions
diff --git a/kernel/console.c b/kernel/console.c
new file mode 100644
index 0000000..b20d4a9
--- /dev/null
+++ b/kernel/console.c
@@ -0,0 +1,271 @@
+// Console input and output.
+// Input is from the keyboard or serial port.
+// Output is written to the screen and serial port.
+
+#include <stdarg.h>
+
+#include "types.h"
+#include "param.h"
+#include "spinlock.h"
+#include "sleeplock.h"
+#include "fs.h"
+#include "file.h"
+#include "memlayout.h"
+#include "riscv.h"
+#include "defs.h"
+#include "proc.h"
+
+static void consputc(int);
+
+static volatile int panicked = 0;
+
+static struct {
+ struct spinlock lock;
+ int locking;
+} cons;
+
+static char digits[] = "0123456789abcdef";
+
+static void
+printint(int xx, int base, int sign)
+{
+ char buf[16];
+ int i;
+ uint x;
+
+ if(sign && (sign = xx < 0))
+ x = -xx;
+ else
+ x = xx;
+
+ i = 0;
+ do{
+ buf[i++] = digits[x % base];
+ }while((x /= base) != 0);
+
+ if(sign)
+ buf[i++] = '-';
+
+ while(--i >= 0)
+ consputc(buf[i]);
+}
+
+static void
+printptr(uint64 x) {
+ int i;
+ consputc('0');
+ consputc('x');
+ for (i = 0; i < (sizeof(uint64) * 2); i++, x <<= 4)
+ consputc(digits[x >> (sizeof(uint64) * 8 - 4)]);
+}
+
+
+//PAGEBREAK: 50
+
+// Print to the console. only understands %d, %x, %p, %s.
+void
+printf(char *fmt, ...)
+{
+ va_list ap;
+ int i, c, locking;
+ char *s;
+
+ locking = cons.locking;
+ if(locking)
+ acquire(&cons.lock);
+
+ if (fmt == 0)
+ panic("null fmt");
+
+ va_start(ap, fmt);
+ for(i = 0; (c = fmt[i] & 0xff) != 0; i++){
+ if(c != '%'){
+ consputc(c);
+ continue;
+ }
+ c = fmt[++i] & 0xff;
+ if(c == 0)
+ break;
+ switch(c){
+ case 'd':
+ printint(va_arg(ap, int), 10, 1);
+ break;
+ case 'x':
+ printint(va_arg(ap, int), 16, 1);
+ break;
+ case 'p':
+ printptr(va_arg(ap, uint64));
+ break;
+ case 's':
+ if((s = va_arg(ap, char*)) == 0)
+ s = "(null)";
+ for(; *s; s++)
+ consputc(*s);
+ break;
+ case '%':
+ consputc('%');
+ break;
+ default:
+ // Print unknown % sequence to draw attention.
+ consputc('%');
+ consputc(c);
+ break;
+ }
+ }
+
+ if(locking)
+ release(&cons.lock);
+}
+
+void
+panic(char *s)
+{
+ cons.locking = 0;
+ printf("panic: ");
+ printf(s);
+ printf("\n");
+ panicked = 1; // freeze other CPU
+ for(;;)
+ ;
+}
+
+#define BACKSPACE 0x100
+
+void
+consputc(int c)
+{
+ if(panicked){
+ for(;;)
+ ;
+ }
+
+ if(c == BACKSPACE){
+ uartputc('\b'); uartputc(' '); uartputc('\b');
+ } else
+ uartputc(c);
+}
+
+#define INPUT_BUF 128
+struct {
+ char buf[INPUT_BUF];
+ uint r; // Read index
+ uint w; // Write index
+ uint e; // Edit index
+} input;
+
+#define C(x) ((x)-'@') // Contro
+
+int
+consoleread(struct inode *ip, int user_dst, uint64 dst, int n)
+{
+ uint target;
+ int c;
+ char buf[1];
+
+ iunlock(ip);
+ target = n;
+ acquire(&cons.lock);
+ while(n > 0){
+ while(input.r == input.w){
+ if(myproc()->killed){
+ release(&cons.lock);
+ ilock(ip);
+ return -1;
+ }
+ sleep(&input.r, &cons.lock);
+ }
+ c = input.buf[input.r++ % INPUT_BUF];
+ if(c == C('D')){ // EOF
+ if(n < target){
+ // Save ^D for next time, to make sure
+ // caller gets a 0-byte result.
+ input.r--;
+ }
+ break;
+ }
+ buf[0] = c;
+ if(either_copyout(user_dst, dst, &buf[0], 1) == -1)
+ break;
+ dst++;
+ --n;
+ if(c == '\n')
+ break;
+ }
+ release(&cons.lock);
+ ilock(ip);
+
+ return target - n;
+}
+
+int
+consolewrite(struct inode *ip, int user_src, uint64 src, int n)
+{
+ int i;
+
+ iunlock(ip);
+ acquire(&cons.lock);
+ for(i = 0; i < n; i++){
+ char c;
+ if(either_copyin(&c, user_src, src+i, 1) == -1)
+ break;
+ consputc(c);
+ }
+ release(&cons.lock);
+ ilock(ip);
+
+ return n;
+}
+
+void
+consoleintr(int c)
+{
+ int doprocdump = 0;
+
+ acquire(&cons.lock);
+
+ switch(c){
+ case C('P'): // Process list.
+ // procdump() locks cons.lock indirectly; invoke later
+ doprocdump = 1;
+ break;
+ case C('U'): // Kill line.
+ while(input.e != input.w &&
+ input.buf[(input.e-1) % INPUT_BUF] != '\n'){
+ input.e--;
+ consputc(BACKSPACE);
+ }
+ break;
+ case C('H'): case '\x7f': // Backspace
+ if(input.e != input.w){
+ input.e--;
+ consputc(BACKSPACE);
+ }
+ break;
+ default:
+ if(c != 0 && input.e-input.r < INPUT_BUF){
+ c = (c == '\r') ? '\n' : c;
+ input.buf[input.e++ % INPUT_BUF] = c;
+ consputc(c);
+ if(c == '\n' || c == C('D') || input.e == input.r+INPUT_BUF){
+ input.w = input.e;
+ wakeup(&input.r);
+ }
+ }
+ break;
+ }
+
+ release(&cons.lock);
+
+ if(doprocdump)
+ procdump();
+}
+
+void
+consoleinit(void)
+{
+ initlock(&cons.lock, "console");
+
+ devsw[CONSOLE].write = consolewrite;
+ devsw[CONSOLE].read = consoleread;
+ cons.locking = 1;
+}