summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHanjie Wu <hanjiew@andrew.cmu.edu>2023-04-23 15:16:14 -0400
committerHanjie Wu <hanjiew@andrew.cmu.edu>2023-04-23 15:16:14 -0400
commit4e6e2ced7f047a9a0439eb6d001b1a77daadfdff (patch)
treee9de52504f67fa819b7d1d9ca89b9de05e73e1e1
parentf5df2e1d666a943e17261d089456c9483bc9e998 (diff)
pts
-rw-r--r--config.mk4
-rw-r--r--kern/console.c189
-rw-r--r--kern/hvcall.c2
-rw-r--r--kern/inc/console.h136
-rw-r--r--kern/inc/kbd.h30
-rw-r--r--kern/inc/pts.h192
-rw-r--r--kern/inc/sched.h2
-rw-r--r--kern/kbd.c220
-rw-r--r--kern/kernel.c2
-rw-r--r--kern/pts.c363
-rw-r--r--kern/sched.c2
-rw-r--r--kern/syscall_io.c3
-rw-r--r--kern/toad.c2
-rw-r--r--kern/usermem.c2
14 files changed, 565 insertions, 584 deletions
diff --git a/config.mk b/config.mk
index 056f537..7870559 100644
--- a/config.mk
+++ b/config.mk
@@ -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>