// TODO: CHECK/REPLACE/UPDATE OLD CODE (this file is based on xv6) // // Console input and output, to the uart. // Reads are line at a time. // Implements special input characters: // newline -- end of line // control-h -- backspace // control-u -- kill line // control-d -- end of file // control-p -- print process list // #include "types.h" #include "param.h" #include "sched.h" #include "fs.h" #include "file.h" #include "memlayout.h" #include "riscv.h" #include "defs.h" #include "proc.h" #define BACKSPACE 0x100 #define C(x) ((x)-'@') // Control-x // // send one character to the uart. // called by printf(), and to echo input characters, // but not from write(). // void consputc(int c) { if(c == BACKSPACE){ // if the user typed backspace, overwrite with a space. uartputc_sync('\b'); uartputc_sync(' '); uartputc_sync('\b'); } else { uartputc_sync(c); } } sched_spinlock_t conslock; // input #define INPUT_BUF_SIZE 128 char consbuf[INPUT_BUF_SIZE]; uint consr; // Read index uint consw; // Write index uint conse; // Edit index // // user write()s to the console go here. // int consolewrite(int user_src, uint64 src, int n) { int i; for(i = 0; i < n; i++){ char c; if(either_copyin(&c, user_src, src+i, 1) == -1) break; uartputc(c); } return i; } // // user read()s from the console go here. // copy (up to) a whole input line to dst. // user_dist indicates whether dst is a user // or kernel address. // int consoleread(int user_dst, uint64 dst, int n) { uint target; int c; char cbuf; target = n; acquire(&conslock); while(n > 0){ // wait until interrupt handler has put some // input into cons.buffer. while(consr == consw){ if(killed(myproc())){ release(&conslock); return -1; } sleep(&consr, &conslock); } c = consbuf[consr++ % INPUT_BUF_SIZE]; if(c == C('D')){ // end-of-file if(n < target){ // Save ^D for next time, to make sure // caller gets a 0-byte result. consr--; } break; } // copy the input byte to the user-space buffer. cbuf = c; if(either_copyout(user_dst, dst, &cbuf, 1) == -1) break; dst++; --n; if(c == '\n'){ // a whole line has arrived, return to // the user-level read(). break; } } release(&conslock); return target - n; } // // the console input interrupt handler. // uartintr() calls this for input character. // do erase/kill processing, append to cons.buf, // wake up consoleread() if a whole line has arrived. // void consoleintr(int c) { acquire(&conslock); switch(c){ case C('P'): // Print process list. sched_dumpstatus(); break; case C('U'): // Kill line. while(conse != consw && consbuf[(conse-1) % INPUT_BUF_SIZE] != '\n'){ conse--; consputc(BACKSPACE); } break; case C('H'): // Backspace case '\x7f': // Delete key if(conse != consw){ conse--; consputc(BACKSPACE); } break; default: if(c != 0 && conse-consr < INPUT_BUF_SIZE){ c = (c == '\r') ? '\n' : c; // echo back to the user. consputc(c); // store for consumption by consoleread(). consbuf[conse++ % INPUT_BUF_SIZE] = c; if(c == '\n' || c == C('D') || conse-consr == INPUT_BUF_SIZE){ // wake up consoleread() if a whole line (or end-of-file) // has arrived. consw = conse; sched_wake(&consr); } } break; } release(&conslock); } void consoleinit(void) { initlock(&conslock, "cons"); uartinit(); // connect read and write system calls // to consoleread and consolewrite. devsw[CONSOLE].read = &consoleread; devsw[CONSOLE].write = &consolewrite; }