diff options
| author | Hanjie Wu <hanjiew@andrew.cmu.edu> | 2023-04-23 15:16:14 -0400 |
|---|---|---|
| committer | Hanjie Wu <hanjiew@andrew.cmu.edu> | 2023-04-23 15:16:14 -0400 |
| commit | 4e6e2ced7f047a9a0439eb6d001b1a77daadfdff (patch) | |
| tree | e9de52504f67fa819b7d1d9ca89b9de05e73e1e1 | |
| parent | f5df2e1d666a943e17261d089456c9483bc9e998 (diff) | |
pts
| -rw-r--r-- | config.mk | 4 | ||||
| -rw-r--r-- | kern/console.c | 189 | ||||
| -rw-r--r-- | kern/hvcall.c | 2 | ||||
| -rw-r--r-- | kern/inc/console.h | 136 | ||||
| -rw-r--r-- | kern/inc/kbd.h | 30 | ||||
| -rw-r--r-- | kern/inc/pts.h | 192 | ||||
| -rw-r--r-- | kern/inc/sched.h | 2 | ||||
| -rw-r--r-- | kern/kbd.c | 220 | ||||
| -rw-r--r-- | kern/kernel.c | 2 | ||||
| -rw-r--r-- | kern/pts.c | 363 | ||||
| -rw-r--r-- | kern/sched.c | 2 | ||||
| -rw-r--r-- | kern/syscall_io.c | 3 | ||||
| -rw-r--r-- | kern/toad.c | 2 | ||||
| -rw-r--r-- | kern/usermem.c | 2 |
14 files changed, 565 insertions, 584 deletions
@@ -161,11 +161,11 @@ AUTOSTACK_OBJS = autostack.o # # Kernel object files you provide in from kern/ # -KERNEL_OBJS = console.o kernel.o loader.o malloc_wrappers.o sync_asm.o \ +KERNEL_OBJS = pts.o kernel.o loader.o malloc_wrappers.o sync_asm.o \ mm.o asm_instr.o sched.o sched_asm.o syscall_asm.o interrupt.o \ paging.o timer.o interrupt_asm.o usermem.o syscall_process.o \ syscall_memory.o syscall_thread.o common.o sync.o syscall_io.o \ - usermem_asm.o syscall_misc.o kbd.o pv.o hvcall.o toad.o + usermem_asm.o syscall_misc.o pv.o hvcall.o toad.o ########################################################################### # WARNING: Do not put **test** programs into the REQPROGS variables. Your diff --git a/kern/console.c b/kern/console.c deleted file mode 100644 index 716ee50..0000000 --- a/kern/console.c +++ /dev/null @@ -1,189 +0,0 @@ -/** @file console.c - * - * @brief Console driver implementation. - * - * @author Hanjie Wu (hanjiew) - * @bug No functional bugs - */ - -#include <stdbool.h> -#include <stddef.h> -#include <stdint.h> -#include <string.h> - -#include <x86/asm.h> -#include <x86/video_defines.h> - -#include <console.h> -#include <sched.h> - -/** index of the register to start displaying cursor */ -#define CRTC_CURSOR_START 10 -/** bit to start displaying cursor */ -#define CURSOR_ENABLE_BIT 0x20 - -/** pointer to the viedo memory at B800h */ -a_char_on_screen_t (*console_mem)[CONSOLE_WIDTH] = - (a_char_on_screen_t(*)[CONSOLE_WIDTH])CONSOLE_MEM_BASE; - -/** the char used to produce blank */ -#define BLANK_CH ' ' -/** initial color of the cursor */ -#define DEFAULT_COLOR (FGND_WHITE | BGND_BLACK) - -pts_t* active_pts = NULL; -spl_t pts_lock = SPL_INIT; -queue_t* all_pts = NULL; - -void pts_init(pts_t* pts) { - pts->cur_x = pts->cur_y = 0; - pts->cur_color = DEFAULT_COLOR; - pts->cur_shown = 1; - pts->lock = MUTEX_INIT; - pts->refcount = 0; - queue_insert_head(&all_pts, &pts->pts_link); -} - -/** - * @brief Move the cursor to a position. Position is checked before calling this - * function - * @param x x - * @param y y - */ -static inline void move_cursor(pts_t* pts, int x, int y) { - pts->cur_x = x; - pts->cur_y = y; - int old_if = spl_lock(&pts_lock); - if (active_pts == pts) { - int pos = y * CONSOLE_WIDTH + x; - outb(CRTC_IDX_REG, CRTC_CURSOR_LSB_IDX); - outb(CRTC_DATA_REG, pos & 0xff); - outb(CRTC_IDX_REG, CRTC_CURSOR_MSB_IDX); - outb(CRTC_DATA_REG, pos >> 8); - } - spl_unlock(&pts_lock, old_if); -} - -/** - * @brief Scroll the console by one line and clean the last line - */ -static inline void scroll_page(pts_t* pts) { - /* move all but last line forward */ - memmove(pts->mem[0], pts->mem[1], - sizeof(a_char_on_screen_t) * CONSOLE_WIDTH * (CONSOLE_HEIGHT - 1)); - int i; - for (i = 0; i < CONSOLE_WIDTH; i++) { - pts->mem[CONSOLE_HEIGHT - 1][i] = - (a_char_on_screen_t){BLANK_CH, pts->cur_color}; - } - int old_if = spl_lock(&pts_lock); - if (active_pts == pts) { - memmove( - console_mem[0], console_mem[1], - sizeof(a_char_on_screen_t) * CONSOLE_WIDTH * (CONSOLE_HEIGHT - 1)); - int i; - for (i = 0; i < CONSOLE_WIDTH; i++) { - console_mem[CONSOLE_HEIGHT - 1][i] = - (a_char_on_screen_t){BLANK_CH, pts->cur_color}; - } - } - spl_unlock(&pts_lock, old_if); -} - -static inline void draw_char(pts_t* pts, - int row, - int col, - a_char_on_screen_t ch) { - pts->mem[row][col] = ch; - int old_if = spl_lock(&pts_lock); - if (active_pts == pts) { - console_mem[row][col] = ch; - } - spl_unlock(&pts_lock, old_if); -} - -int putbyte(char ch) { - return pts_putbyte(get_current()->pts, ch); -} - -int pts_putbyte(pts_t* pts, char ch) { - if (ch == '\n') { - if (pts->cur_y < CONSOLE_HEIGHT - 1) { - move_cursor(pts, 0, pts->cur_y + 1); - } else { - scroll_page(pts); - move_cursor(pts, 0, pts->cur_y); - } - return ch; - } - if (ch == '\r') { - move_cursor(pts, 0, pts->cur_y); - return ch; - } - if (ch == '\b') { - if (pts->cur_x > 0) { - move_cursor(pts, pts->cur_x - 1, pts->cur_y); - - } else if (pts->cur_y > 0) { - move_cursor(pts, CONSOLE_WIDTH - 1, pts->cur_y - 1); - } - a_char_on_screen_t c = {BLANK_CH, pts->cur_color}; - draw_char(pts, pts->cur_y, pts->cur_x, c); - return ch; - } - /* save the position where we should show the char */ - int prev_x = pts->cur_x, prev_y = pts->cur_y; - if (pts->cur_x < CONSOLE_WIDTH - 1) { - /* move forward */ - move_cursor(pts, pts->cur_x + 1, pts->cur_y); - } else if (pts->cur_y < CONSOLE_HEIGHT - 1) { - /* go to next line */ - move_cursor(pts, 0, pts->cur_y + 1); - } else { - /* scroll and go to beginning of the line */ - scroll_page(pts); - move_cursor(pts, 0, pts->cur_y); - prev_y -= 1; - } - a_char_on_screen_t c = {ch, pts->cur_color}; - draw_char(pts, prev_y, prev_x, c); - return ch; -} - -void pts_putbytes(pts_t* pts, const char* s, int len) { - if (s == NULL || len <= 0) { - return; - } - int i; - for (i = 0; i < len; i++) { - pts_putbyte(pts, s[i]); - } -} - -int pts_set_term_color(pts_t* pts, int color) { - if (color > 0xff || color < 0) { - return -1; - } - pts->cur_color = (char)color; - return 0; -} - -void pts_get_term_color(pts_t* pts, int* color) { - *color = pts->cur_color; -} - -int pts_set_cursor(pts_t* pts, int row, int col) { - if (row >= CONSOLE_HEIGHT || row < 0) { - return -1; - } - if (col >= CONSOLE_WIDTH || col < 0) { - return -1; - } - move_cursor(pts, col, row); - return 0; -} - -void pts_get_cursor(pts_t* pts, int* row, int* col) { - *row = pts->cur_y; - *col = pts->cur_x; -} diff --git a/kern/hvcall.c b/kern/hvcall.c index 65f3e42..e1f7f93 100644 --- a/kern/hvcall.c +++ b/kern/hvcall.c @@ -24,7 +24,7 @@ #include <asm_instr.h> #include <assert.h> -#include <console.h> +#include <pts.h> #include <loader.h> #include <malloc.h> #include <mm.h> diff --git a/kern/inc/console.h b/kern/inc/console.h index 0d65922..dbfdbb0 100644 --- a/kern/inc/console.h +++ b/kern/inc/console.h @@ -1,20 +1,3 @@ -/* - * - * # # - * ## # #### ##### # #### ###### - * # # # # # # # # # # - * # # # # # # # # ##### - * # # # # # # # # # - * # ## # # # # # # # - * # # #### # # #### ###### - * - * Now that it's P3 instead of P1 you are allowed - * to edit this file if it suits you. - * - * Please delete this notice. - * - */ - /** @file console.h * * @brief console functions. @@ -26,123 +9,6 @@ #ifndef _CONSOLE_H #define _CONSOLE_H -#include <stdbool.h> -#include <stddef.h> -#include <stdint.h> -#include <string.h> - -#include <x86/asm.h> -#include <x86/video_defines.h> - -#include <common.h> -#include <sync.h> - -/** - * Someone is not satisfied with the type name char_t so we use this - * to reperesent a char on screen so that nobody will mistake it with 'char' - */ -typedef struct a_char_on_screen_s { - uint8_t ch; /** char */ - uint8_t color; /** color */ -} a_char_on_screen_t; - -typedef struct pts_s { - queue_t pts_link; - int refcount; - mutex_t lock; - a_char_on_screen_t mem[CONSOLE_HEIGHT][CONSOLE_WIDTH]; - int cur_x; - int cur_y; - char cur_color; - int cur_shown; -} pts_t; - -extern pts_t* active_pts; -extern spl_t pts_lock; - -void pts_init(pts_t* pts); - int putbyte(char ch); -/** @brief Prints character ch at the current location - * of the cursor. - * - * If the character is a newline ('\n'), the cursor is - * be moved to the beginning of the next line (scrolling if necessary). If - * the character is a carriage return ('\r'), the cursor - * is immediately reset to the beginning of the current - * line, causing any future output to overwrite any existing - * output on the line. If backsapce ('\b') is encountered, - * the previous character is erased. See the main console.c description - * for more backspace behavior. - * - * @param ch the character to print - * @return The input character - */ -int pts_putbyte(pts_t* pts, char ch); - -/** @brief Prints the string s, starting at the current - * location of the cursor. - * - * If the string is longer than the current line, the - * string fills up the current line and then - * continues on the next line. If the string exceeds - * available space on the entire console, the screen - * scrolls up one line, and then the string - * continues on the new line. If '\n', '\r', and '\b' are - * encountered within the string, they are handled - * as per putbyte. If len is not a positive integer or s - * is null, the function has no effect. - * - * @param s The string to be printed. - * @param len The length of the string s. - * @return Void. - */ -void pts_putbytes(pts_t* pts, const char* s, int len); - -/** @brief Changes the foreground and background color - * of future characters printed on the console. - * - * If the color code is invalid, the function has no effect. - * - * @param color The new color code. - * @return 0 on success or integer error code less than 0 if - * color code is invalid. - */ -int pts_set_term_color(pts_t* pts, int color); - -/** @brief Writes the current foreground and background - * color of characters printed on the console - * into the argument color. - * @param color The address to which the current color - * information will be written. - * @return Void. - */ -void pts_get_term_color(pts_t* pts, int* color); - -/** @brief Sets the position of the cursor to the - * position (row, col). - * - * Subsequent calls to putbytes should cause the console - * output to begin at the new position. If the cursor is - * currently hidden, a call to set_cursor() does not show - * the cursor. - * - * @param row The new row for the cursor. - * @param col The new column for the cursor. - * @return 0 on success or integer error code less than 0 if - * cursor location is invalid. - */ -int pts_set_cursor(pts_t* pts, int row, int col); - -/** @brief Writes the current position of the cursor - * into the arguments row and col. - * @param row The address to which the current cursor - * row will be written. - * @param col The address to which the current cursor - * column will be written. - * @return Void. - */ -void pts_get_cursor(pts_t* pts, int* row, int* col); - -#endif /* _CONSOLE_H */ +#endif diff --git a/kern/inc/kbd.h b/kern/inc/kbd.h deleted file mode 100644 index a7350b6..0000000 --- a/kern/inc/kbd.h +++ /dev/null @@ -1,30 +0,0 @@ -/** @file kbd.h - * - * @brief keyboard functions. - * - * @author Hanjie Wu (hanjiew) - * @bug No functional bugs - */ - -#ifndef _KBD_H_ -#define _KBD_H_ - -#include <common.h> -#include <sched.h> -#include <sync.h> - -/** - * @brief read a line to userspace - * @param len max length to read - * @param buf buffer - * @return size on success, -1 on failure - */ -int do_readline(int len, va_t buf); - -/** - * @brief read a char - * @return char read - */ -int do_getchar(); - -#endif diff --git a/kern/inc/pts.h b/kern/inc/pts.h new file mode 100644 index 0000000..c300fb9 --- /dev/null +++ b/kern/inc/pts.h @@ -0,0 +1,192 @@ +/* + * + * # # + * ## # #### ##### # #### ###### + * # # # # # # # # # # + * # # # # # # # # ##### + * # # # # # # # # # + * # ## # # # # # # # + * # # #### # # #### ###### + * + * Now that it's P3 instead of P1 you are allowed + * to edit this file if it suits you. + * + * Please delete this notice. + * + */ + +/** @file pts.h + * + * @brief console and keyboard functions. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ + +#ifndef _PTS_H +#define _PTS_H + +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> +#include <string.h> + +#include <x86/asm.h> +#include <x86/interrupt_defines.h> +#include <x86/keyhelp.h> +#include <x86/video_defines.h> + +#include <pv.h> +#include <sync.h> + +/** + * Someone is not satisfied with the type name char_t so we use this + * to reperesent a char on screen so that nobody will mistake it with 'char' + */ +typedef struct a_char_on_screen_s { + uint8_t ch; /** char */ + uint8_t color; /** color */ +} a_char_on_screen_t; + +/** a node in queue of threads requesting keyboard access */ +typedef struct kbd_request_s { + thread_t* t; + queue_t node; +} kbd_request_t; + +/** size of scancode ring buffer, a big buffer enough for someone pressing + * keyboard fast */ +#define KH_RING_SIZE PAGE_SIZE +/** size of character ring buffer, a big buffer enough for someone pressing + * keyboard fast */ +#define CHR_RING_SIZE PAGE_SIZE +/** maximum readline size */ +#define MAX_READLINE (CHR_RING_SIZE - 1) + +typedef struct pts_s { + queue_t pts_link; + int refcount; + mutex_t lock; + + a_char_on_screen_t mem[CONSOLE_HEIGHT][CONSOLE_WIDTH]; + int cur_x; + int cur_y; + char cur_color; + int cur_shown; + + queue_t* reqs; + mutex_t kbd_request_lock; + cv_t kbd_request_cv; + mutex_t input_lock; + cv_t input_cv; + unsigned char kh_ring[KH_RING_SIZE]; + int kh_r_pos; + int kh_w_pos; + char chr_ring[CHR_RING_SIZE]; + int chr_r_pos; + int chr_w_pos; +} pts_t; + +extern pts_t* active_pts; +extern spl_t pts_lock; + +void pts_init(pts_t* pts); + +int putbyte(char ch); + +/** @brief Prints character ch at the current location + * of the cursor. + * + * If the character is a newline ('\n'), the cursor is + * be moved to the beginning of the next line (scrolling if necessary). If + * the character is a carriage return ('\r'), the cursor + * is immediately reset to the beginning of the current + * line, causing any future output to overwrite any existing + * output on the line. If backsapce ('\b') is encountered, + * the previous character is erased. See the main console.c description + * for more backspace behavior. + * + * @param ch the character to print + * @return The input character + */ +int pts_putbyte(pts_t* pts, char ch); + +/** @brief Prints the string s, starting at the current + * location of the cursor. + * + * If the string is longer than the current line, the + * string fills up the current line and then + * continues on the next line. If the string exceeds + * available space on the entire console, the screen + * scrolls up one line, and then the string + * continues on the new line. If '\n', '\r', and '\b' are + * encountered within the string, they are handled + * as per putbyte. If len is not a positive integer or s + * is null, the function has no effect. + * + * @param s The string to be printed. + * @param len The length of the string s. + * @return Void. + */ +void pts_putbytes(pts_t* pts, const char* s, int len); + +/** @brief Changes the foreground and background color + * of future characters printed on the console. + * + * If the color code is invalid, the function has no effect. + * + * @param color The new color code. + * @return 0 on success or integer error code less than 0 if + * color code is invalid. + */ +int pts_set_term_color(pts_t* pts, int color); + +/** @brief Writes the current foreground and background + * color of characters printed on the console + * into the argument color. + * @param color The address to which the current color + * information will be written. + * @return Void. + */ +void pts_get_term_color(pts_t* pts, int* color); + +/** @brief Sets the position of the cursor to the + * position (row, col). + * + * Subsequent calls to putbytes should cause the console + * output to begin at the new position. If the cursor is + * currently hidden, a call to set_cursor() does not show + * the cursor. + * + * @param row The new row for the cursor. + * @param col The new column for the cursor. + * @return 0 on success or integer error code less than 0 if + * cursor location is invalid. + */ +int pts_set_cursor(pts_t* pts, int row, int col); + +/** @brief Writes the current position of the cursor + * into the arguments row and col. + * @param row The address to which the current cursor + * row will be written. + * @param col The address to which the current cursor + * column will be written. + * @return Void. + */ +void pts_get_cursor(pts_t* pts, int* row, int* col); + +/** + * @brief read a line to userspace + * @param len max length to read + * @param buf buffer + * @return size on success, -1 on failure + */ +int do_readline(int len, va_t buf); + +/** + * @brief read a char + * @return char read + */ +int do_getchar(); + +#endif /* _PTS_H */ diff --git a/kern/inc/sched.h b/kern/inc/sched.h index 718fdae..754567e 100644 --- a/kern/inc/sched.h +++ b/kern/inc/sched.h @@ -16,7 +16,7 @@ #include <x86/seg.h> #include <common.h> -#include <console.h> +#include <pts.h> #include <paging.h> #include <pv.h> #include <sync.h> diff --git a/kern/kbd.c b/kern/kbd.c deleted file mode 100644 index d933293..0000000 --- a/kern/kbd.c +++ /dev/null @@ -1,220 +0,0 @@ -/** @file kbd.c - * - * @brief Keyboard handler implementation. - * - * @author Hanjie Wu (hanjiew) - * @bug No functional bugs. - */ - -#include <stdbool.h> -#include <stddef.h> -#include <stdint.h> -#include <string.h> - -#include <x86/asm.h> -#include <x86/interrupt_defines.h> -#include <x86/keyhelp.h> - -#include <console.h> -#include <interrupt.h> -#include <kbd.h> -#include <paging.h> -#include <pv.h> -#include <sync.h> -#include <usermem.h> - -/** a node in queue of threads requesting keyboard access */ -typedef struct kbd_request_s { - thread_t* t; - queue_t node; -} kbd_request_t; - -/** size of scancode ring buffer, a big buffer enough for someone pressing - * keyboard fast */ -#define KH_RING_SIZE PAGE_SIZE -/** size of character ring buffer, a big buffer enough for someone pressing - * keyboard fast */ -#define CHR_RING_SIZE PAGE_SIZE -/** maximum readline size */ -#define MAX_READLINE (CHR_RING_SIZE - 1) - -/** queue of threads requesting keyboard access */ -static queue_t* inputs = NULL; - -/** mutex for keyboard request queue */ -static mutex_t kbd_request_lock = MUTEX_INIT; -/** signal for a thread leaving request queue */ -static cv_t kbd_request_cv = CV_INIT; - -/** mutex for new scancode input */ -static mutex_t input_lock = MUTEX_INIT; -/** signal for new scancode input */ -static cv_t input_cv = CV_INIT; - -/** augchar buffer */ -static unsigned char kh_ring[KH_RING_SIZE]; -/** read pointer of augchar ring buffer */ -static int kh_r_pos = 0; -/** write pointer of augchar ring buffer */ -static int kh_w_pos = 0; - -/** character ring buffer */ -static char chr_ring[CHR_RING_SIZE]; -/** read pointer of character ring buffer */ -static int chr_r_pos = 0; -/** write pointer of character ring buffer */ -static int chr_w_pos = 0; - -/** - * @brief keyboard inturrupt handler - */ -void kbd_handler_real(stack_frame_t* f) { - unsigned char sc = inb(KEYBOARD_PORT); - pic_acknowledge(KBD_IRQ); - kh_type kh = process_scancode(sc); - if (pv_inject_irq(f, KEY_IDT_ENTRY, kh) == 0) { - return; - } - if (KH_HASDATA(kh) && KH_ISMAKE(kh)) { - int next_w_pos = (kh_w_pos + 1) % KH_RING_SIZE; - if (next_w_pos != kh_r_pos) { - kh_ring[kh_w_pos] = kh; - kh_w_pos = next_w_pos; - } - } - cv_signal(&input_cv); -} - -/** - * @brief process scancode until a char is produced - * @return char produced - */ -static int sc_process(); - -/** - * @brief flush a line to user buffer - * @param len length of buffer - * @param buf buffer - * @return size of chars flushed, -1: buf invalid - */ -static int flush_line(int len, va_t buf); - -int do_readline(int len, va_t buf) { - if (len < 0 || len > MAX_READLINE) { - return -1; - } - if (len == 0) { - return 0; - } - kbd_request_t req; - req.t = get_current(); - /* wait until our turn */ - mutex_lock(&kbd_request_lock); - queue_insert_tail(&inputs, &req.node); - while (inputs != &req.node) { - cv_wait(&kbd_request_cv, &kbd_request_lock); - } - mutex_unlock(&kbd_request_lock); - int should_flush = 0; - if (chr_r_pos != chr_w_pos) { - int i; - for (i = chr_r_pos; i != chr_w_pos; i = (i + 1) % CHR_RING_SIZE) { - if (chr_ring[i] == '\n') { - should_flush = 1; - break; - } - } - /* check if ring is full */ - if (chr_r_pos == (chr_w_pos + 1) % CHR_RING_SIZE) { - should_flush = 1; - } - } - while (should_flush == 0) { - /* wait for more chars */ - char c = sc_process(); - if (c == '\b') { - if (chr_w_pos != chr_r_pos) { - putbyte(c); - chr_w_pos = (chr_w_pos + CHR_RING_SIZE - 1) % CHR_RING_SIZE; - } - } else { - chr_ring[chr_w_pos] = c; - chr_w_pos = (chr_w_pos + 1) % CHR_RING_SIZE; - putbyte(c); - should_flush = - (c == '\n') || (chr_r_pos == (chr_w_pos + 1) % CHR_RING_SIZE); - } - } - int result = flush_line(len, buf); - mutex_lock(&kbd_request_lock); - queue_detach(&inputs, &req.node); - cv_signal(&kbd_request_cv); - mutex_unlock(&kbd_request_lock); - return result; -} - -int do_getchar() { - kbd_request_t req; - req.t = get_current(); - mutex_lock(&kbd_request_lock); - queue_insert_tail(&inputs, &req.node); - while (inputs != &req.node) { - cv_wait(&kbd_request_cv, &kbd_request_lock); - } - mutex_unlock(&kbd_request_lock); - int result; - if (chr_r_pos != chr_w_pos) { - result = chr_ring[chr_r_pos]; - chr_r_pos = (chr_r_pos + 1) % CHR_RING_SIZE; - } else { - result = sc_process(); - } - mutex_lock(&kbd_request_lock); - queue_detach(&inputs, &req.node); - cv_signal(&kbd_request_cv); - mutex_unlock(&kbd_request_lock); - return result; -} - -static int flush_line(int len, va_t buf) { - int size = 0, i; - for (i = chr_r_pos; i != chr_w_pos; i = (i + 1) % CHR_RING_SIZE) { - size++; - if (chr_ring[i] == '\n') { - break; - } - } - if (size > len) { - size = len; - } - int end_pos = (chr_r_pos + size) % CHR_RING_SIZE; - if (end_pos > chr_r_pos) { - if (copy_to_user(buf, size, &chr_ring[chr_r_pos]) != 0) { - return -1; - } - } else { - int size_1 = (CHR_RING_SIZE - chr_r_pos); - if (copy_to_user(buf, size_1, &chr_ring[chr_r_pos]) != 0) { - return -1; - } - if (copy_to_user(buf + size_1, end_pos, &chr_ring[0]) != 0) { - return -1; - } - } - chr_r_pos = end_pos; - return size; -} - -static int sc_process() { - while (1) { - /* wait for more scancode */ - mutex_lock(&input_lock); - while (kh_r_pos == kh_w_pos) { - cv_wait(&input_cv, &input_lock); - } - kh_type kh = kh_ring[kh_r_pos]; - kh_r_pos = (kh_r_pos + 1) % KH_RING_SIZE; - mutex_unlock(&input_lock); - return KH_GETCHAR(kh); - } -} diff --git a/kern/kernel.c b/kern/kernel.c index 5599e95..c5b60c7 100644 --- a/kern/kernel.c +++ b/kern/kernel.c @@ -24,7 +24,7 @@ #include <assert.h> #include <common.h> -#include <console.h> +#include <pts.h> #include <interrupt.h> #include <mm.h> #include <paging.h> diff --git a/kern/pts.c b/kern/pts.c new file mode 100644 index 0000000..2d51620 --- /dev/null +++ b/kern/pts.c @@ -0,0 +1,363 @@ +/** @file console.c + * + * @brief Console driver implementation. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ + +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> +#include <string.h> + +#include <x86/asm.h> +#include <x86/video_defines.h> + +#include <interrupt.h> +#include <paging.h> +#include <pts.h> +#include <pv.h> +#include <sched.h> +#include <sync.h> +#include <usermem.h> + +/** index of the register to start displaying cursor */ +#define CRTC_CURSOR_START 10 +/** bit to start displaying cursor */ +#define CURSOR_ENABLE_BIT 0x20 + +/** pointer to the viedo memory at B800h */ +a_char_on_screen_t (*console_mem)[CONSOLE_WIDTH] = + (a_char_on_screen_t(*)[CONSOLE_WIDTH])CONSOLE_MEM_BASE; + +/** the char used to produce blank */ +#define BLANK_CH ' ' +/** initial color of the cursor */ +#define DEFAULT_COLOR (FGND_WHITE | BGND_BLACK) + +pts_t* active_pts = NULL; +spl_t pts_lock = SPL_INIT; +queue_t* all_pts = NULL; + +void pts_init(pts_t* pts) { + pts->cur_x = pts->cur_y = 0; + pts->cur_color = DEFAULT_COLOR; + pts->cur_shown = 1; + + pts->reqs = NULL; + pts->kbd_request_lock = MUTEX_INIT; + pts->kbd_request_cv = CV_INIT; + pts->input_lock = MUTEX_INIT; + pts->input_cv = CV_INIT; + pts->kh_r_pos = pts->kh_w_pos = 0; + pts->chr_r_pos = pts->chr_w_pos = 0; + + pts->lock = MUTEX_INIT; + pts->refcount = 0; + queue_insert_head(&all_pts, &pts->pts_link); +} + +/** + * @brief Move the cursor to a position. Position is checked before calling this + * function + * @param x x + * @param y y + */ +static inline void move_cursor(pts_t* pts, int x, int y) { + pts->cur_x = x; + pts->cur_y = y; + int old_if = spl_lock(&pts_lock); + if (active_pts == pts) { + int pos = y * CONSOLE_WIDTH + x; + outb(CRTC_IDX_REG, CRTC_CURSOR_LSB_IDX); + outb(CRTC_DATA_REG, pos & 0xff); + outb(CRTC_IDX_REG, CRTC_CURSOR_MSB_IDX); + outb(CRTC_DATA_REG, pos >> 8); + } + spl_unlock(&pts_lock, old_if); +} + +/** + * @brief Scroll the console by one line and clean the last line + */ +static inline void scroll_page(pts_t* pts) { + /* move all but last line forward */ + memmove(pts->mem[0], pts->mem[1], + sizeof(a_char_on_screen_t) * CONSOLE_WIDTH * (CONSOLE_HEIGHT - 1)); + int i; + for (i = 0; i < CONSOLE_WIDTH; i++) { + pts->mem[CONSOLE_HEIGHT - 1][i] = + (a_char_on_screen_t){BLANK_CH, pts->cur_color}; + } + int old_if = spl_lock(&pts_lock); + if (active_pts == pts) { + memmove( + console_mem[0], console_mem[1], + sizeof(a_char_on_screen_t) * CONSOLE_WIDTH * (CONSOLE_HEIGHT - 1)); + int i; + for (i = 0; i < CONSOLE_WIDTH; i++) { + console_mem[CONSOLE_HEIGHT - 1][i] = + (a_char_on_screen_t){BLANK_CH, pts->cur_color}; + } + } + spl_unlock(&pts_lock, old_if); +} + +static inline void draw_char(pts_t* pts, + int row, + int col, + a_char_on_screen_t ch) { + pts->mem[row][col] = ch; + int old_if = spl_lock(&pts_lock); + if (active_pts == pts) { + console_mem[row][col] = ch; + } + spl_unlock(&pts_lock, old_if); +} + +int putbyte(char ch) { + return pts_putbyte(get_current()->pts, ch); +} + +int pts_putbyte(pts_t* pts, char ch) { + if (ch == '\n') { + if (pts->cur_y < CONSOLE_HEIGHT - 1) { + move_cursor(pts, 0, pts->cur_y + 1); + } else { + scroll_page(pts); + move_cursor(pts, 0, pts->cur_y); + } + return ch; + } + if (ch == '\r') { + move_cursor(pts, 0, pts->cur_y); + return ch; + } + if (ch == '\b') { + if (pts->cur_x > 0) { + move_cursor(pts, pts->cur_x - 1, pts->cur_y); + + } else if (pts->cur_y > 0) { + move_cursor(pts, CONSOLE_WIDTH - 1, pts->cur_y - 1); + } + a_char_on_screen_t c = {BLANK_CH, pts->cur_color}; + draw_char(pts, pts->cur_y, pts->cur_x, c); + return ch; + } + /* save the position where we should show the char */ + int prev_x = pts->cur_x, prev_y = pts->cur_y; + if (pts->cur_x < CONSOLE_WIDTH - 1) { + /* move forward */ + move_cursor(pts, pts->cur_x + 1, pts->cur_y); + } else if (pts->cur_y < CONSOLE_HEIGHT - 1) { + /* go to next line */ + move_cursor(pts, 0, pts->cur_y + 1); + } else { + /* scroll and go to beginning of the line */ + scroll_page(pts); + move_cursor(pts, 0, pts->cur_y); + prev_y -= 1; + } + a_char_on_screen_t c = {ch, pts->cur_color}; + draw_char(pts, prev_y, prev_x, c); + return ch; +} + +void pts_putbytes(pts_t* pts, const char* s, int len) { + if (s == NULL || len <= 0) { + return; + } + int i; + for (i = 0; i < len; i++) { + pts_putbyte(pts, s[i]); + } +} + +int pts_set_term_color(pts_t* pts, int color) { + if (color > 0xff || color < 0) { + return -1; + } + pts->cur_color = (char)color; + return 0; +} + +void pts_get_term_color(pts_t* pts, int* color) { + *color = pts->cur_color; +} + +int pts_set_cursor(pts_t* pts, int row, int col) { + if (row >= CONSOLE_HEIGHT || row < 0) { + return -1; + } + if (col >= CONSOLE_WIDTH || col < 0) { + return -1; + } + move_cursor(pts, col, row); + return 0; +} + +void pts_get_cursor(pts_t* pts, int* row, int* col) { + *row = pts->cur_y; + *col = pts->cur_x; +} + +/** + * @brief keyboard inturrupt handler + */ +void kbd_handler_real(stack_frame_t* f) { + unsigned char sc = inb(KEYBOARD_PORT); + pic_acknowledge(KBD_IRQ); + kh_type kh = process_scancode(sc); + if (pv_inject_irq(f, KEY_IDT_ENTRY, kh) == 0) { + return; + } + pts_t* pts = active_pts; + if (KH_HASDATA(kh) && KH_ISMAKE(kh)) { + int next_w_pos = (pts->kh_w_pos + 1) % KH_RING_SIZE; + if (next_w_pos != pts->kh_r_pos) { + pts->kh_ring[pts->kh_w_pos] = kh; + pts->kh_w_pos = next_w_pos; + } + } + cv_signal(&pts->input_cv); +} + +/** + * @brief process scancode until a char is produced + * @return char produced + */ +static int sc_process(pts_t* pts); + +/** + * @brief flush a line to user buffer + * @param len length of buffer + * @param buf buffer + * @return size of chars flushed, -1: buf invalid + */ +static int flush_line(pts_t* pts, int len, va_t buf); + +int do_readline(int len, va_t buf) { + if (len < 0 || len > MAX_READLINE) { + return -1; + } + if (len == 0) { + return 0; + } + pts_t* pts = get_current()->pts; + kbd_request_t req; + req.t = get_current(); + /* wait until our turn */ + mutex_lock(&pts->kbd_request_lock); + queue_insert_tail(&pts->reqs, &req.node); + while (pts->reqs != &req.node) { + cv_wait(&pts->kbd_request_cv, &pts->kbd_request_lock); + } + mutex_unlock(&pts->kbd_request_lock); + int should_flush = 0; + if (pts->chr_r_pos != pts->chr_w_pos) { + int i; + for (i = pts->chr_r_pos; i != pts->chr_w_pos; + i = (i + 1) % CHR_RING_SIZE) { + if (pts->chr_ring[i] == '\n') { + should_flush = 1; + break; + } + } + /* check if ring is full */ + if (pts->chr_r_pos == (pts->chr_w_pos + 1) % CHR_RING_SIZE) { + should_flush = 1; + } + } + while (should_flush == 0) { + /* wait for more chars */ + char c = sc_process(pts); + if (c == '\b') { + if (pts->chr_w_pos != pts->chr_r_pos) { + pts_putbyte(pts, c); + pts->chr_w_pos = + (pts->chr_w_pos + CHR_RING_SIZE - 1) % CHR_RING_SIZE; + } + } else { + pts->chr_ring[pts->chr_w_pos] = c; + pts->chr_w_pos = (pts->chr_w_pos + 1) % CHR_RING_SIZE; + pts_putbyte(pts, c); + should_flush = + (c == '\n') || + (pts->chr_r_pos == (pts->chr_w_pos + 1) % CHR_RING_SIZE); + } + } + int result = flush_line(pts, len, buf); + mutex_lock(&pts->kbd_request_lock); + queue_detach(&pts->reqs, &req.node); + cv_signal(&pts->kbd_request_cv); + mutex_unlock(&pts->kbd_request_lock); + return result; +} + +int do_getchar() { + pts_t* pts = get_current()->pts; + kbd_request_t req; + req.t = get_current(); + mutex_lock(&pts->kbd_request_lock); + queue_insert_tail(&pts->reqs, &req.node); + while (pts->reqs != &req.node) { + cv_wait(&pts->kbd_request_cv, &pts->kbd_request_lock); + } + mutex_unlock(&pts->kbd_request_lock); + int result; + if (pts->chr_r_pos != pts->chr_w_pos) { + result = pts->chr_ring[pts->chr_r_pos]; + pts->chr_r_pos = (pts->chr_r_pos + 1) % CHR_RING_SIZE; + } else { + result = sc_process(pts); + } + mutex_lock(&pts->kbd_request_lock); + queue_detach(&pts->reqs, &req.node); + cv_signal(&pts->kbd_request_cv); + mutex_unlock(&pts->kbd_request_lock); + return result; +} + +static int flush_line(pts_t* pts, int len, va_t buf) { + int size = 0, i; + for (i = pts->chr_r_pos; i != pts->chr_w_pos; i = (i + 1) % CHR_RING_SIZE) { + size++; + if (pts->chr_ring[i] == '\n') { + break; + } + } + if (size > len) { + size = len; + } + int end_pos = (pts->chr_r_pos + size) % CHR_RING_SIZE; + if (end_pos > pts->chr_r_pos) { + if (copy_to_user(buf, size, &pts->chr_ring[pts->chr_r_pos]) != 0) { + return -1; + } + } else { + int size_1 = (CHR_RING_SIZE - pts->chr_r_pos); + if (copy_to_user(buf, size_1, &pts->chr_ring[pts->chr_r_pos]) != 0) { + return -1; + } + if (copy_to_user(buf + size_1, end_pos, &pts->chr_ring[0]) != 0) { + return -1; + } + } + pts->chr_r_pos = end_pos; + return size; +} + +static int sc_process(pts_t* pts) { + while (1) { + /* wait for more scancode */ + mutex_lock(&pts->input_lock); + while (pts->kh_r_pos == pts->kh_w_pos) { + cv_wait(&pts->input_cv, &pts->input_lock); + } + kh_type kh = pts->kh_ring[pts->kh_r_pos]; + pts->kh_r_pos = (pts->kh_r_pos + 1) % KH_RING_SIZE; + mutex_unlock(&pts->input_lock); + return KH_GETCHAR(kh); + } +} diff --git a/kern/sched.c b/kern/sched.c index 396c31d..35e8a58 100644 --- a/kern/sched.c +++ b/kern/sched.c @@ -15,7 +15,7 @@ #include <x86/seg.h> #include <asm_instr.h> -#include <console.h> +#include <pts.h> #include <loader.h> #include <malloc.h> #include <mm.h> diff --git a/kern/syscall_io.c b/kern/syscall_io.c index fafc4cb..6ebc2b5 100644 --- a/kern/syscall_io.c +++ b/kern/syscall_io.c @@ -16,8 +16,7 @@ #include <x86/eflags.h> #include <x86/seg.h> -#include <console.h> -#include <kbd.h> +#include <pts.h> #include <malloc.h> #include <mm.h> #include <paging.h> diff --git a/kern/toad.c b/kern/toad.c index 86ce9c6..96cf60f 100644 --- a/kern/toad.c +++ b/kern/toad.c @@ -1,4 +1,4 @@ -#include <console.h> +#include <pts.h> #include <sched.h> const char toad[] = diff --git a/kern/usermem.c b/kern/usermem.c index 2d7c7b6..5e6b1e3 100644 --- a/kern/usermem.c +++ b/kern/usermem.c @@ -13,7 +13,7 @@ #include <x86/asm.h> #include <x86/seg.h> -#include <console.h> +#include <pts.h> #include <mm.h> #include <paging.h> #include <sched.h> |
