diff options
| author | Jake Mannens <jake72360@gmail.com> | 2018-08-22 06:00:39 +1000 |
|---|---|---|
| committer | Jake Mannens <jake72360@gmail.com> | 2018-08-22 06:00:39 +1000 |
| commit | dafb5464fe8b9a3f8ff41de233f9ff6cd21162ea (patch) | |
| tree | 21e45b1d2910d34f673ea9a6676ff09cbc1c0ddd /kernel | |
| parent | 228de16e2976abb9a15edb41c9b10dbfd309481f (diff) | |
Added the header file limits.h which contains one definition for
SSIZE_MAX which is needed to limit the number of bytes read() will
transfer.
Laid the foundation for a TTY subsystem. This works by taking the
previously used buffer and r/w pointers concept and implements it as a
'tty_queue' struct. The struct 'tty_struct' is used to represent a TTY
device. This struct currently contains three elements; a read queue for
data flowing from the device to the user, a write queue for data flowing
from the user to the device and a function pointer to an init function.
The latter element will reduce complexity by allowing the TTY subsystem
to initialize each TTY device driver (when it's ready), rather than each
driver having to be initialized during bootup. Each TTY device is
implemented as a pointer to a tty_struct. The structures are defined
separately by each driver as well as tracked and maintained by pointers
in the table 'ttys' in tty.c.
Modified the RS232 serial driver to make use of the new TTY subsystem
for transferring data to the user. Currently, write calls are still
handled manually through the rsputs() function though this will change
in future.
Modified the read() system call to direct read calls to the TTY
subsystem which will further direct the call to the appropriate TTY
device driver.
The serial driver's interrupt routine now uses the wake_up() function to
wake processes blocking for serial data. This is to ensure the scheduler
is notified of the wakeup. This function is the preferred method for
waking processes since accessing the task state field directly may not
be possible in the future and is discouraged. The reason for this is
that the scheduler's behaviour may change to require being notified of
task wakeup events in the future.
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/boot.s | 4 | ||||
| -rw-r--r-- | kernel/serial.c | 58 | ||||
| -rw-r--r-- | kernel/sys.c | 10 | ||||
| -rw-r--r-- | kernel/tty.c | 86 |
4 files changed, 103 insertions, 55 deletions
diff --git a/kernel/boot.s b/kernel/boot.s index d609611..ac7e0e3 100644 --- a/kernel/boot.s +++ b/kernel/boot.s @@ -8,10 +8,10 @@ extern hd_init extern kmain extern paging_init extern printk -extern serial_init extern syscall_init extern timer_init extern traps_init +extern tty_init %define NRTASKS 64 @@ -42,7 +42,7 @@ kboot: call printk add esp, 4 ; initialize secondary subsystems - call serial_init + call tty_init call hd_init ; last minute setup, then transfer to kmain call timer_init diff --git a/kernel/serial.c b/kernel/serial.c index f5610f5..39c5ee0 100644 --- a/kernel/serial.c +++ b/kernel/serial.c @@ -3,6 +3,8 @@ #include <errno.h> #include <kernel/con.h> #include <kernel/sched.h> +#include <kernel/serial.h> +#include <kernel/tty.h> #include <sys/types.h> #include <unistd.h> @@ -25,11 +27,11 @@ extern void rs_isr(void); -static char present; +struct tty_struct tty_rs = { + .init = &serial_init +}; -static char rxbuf[256]; -static unsigned rxread, rxwrite; -static struct task_struct *waiting_task; +static char present; int rsputs(char *s) { if(!present) @@ -80,53 +82,19 @@ void serial_init(void) { rsputs("[kernel] Serial monitor initialized!\n\r"); printk("[rs] Serial port COM0 initialized!\n"); - rxread = 0; - rxwrite = 1; - waiting_task = NULL; present = 1; } -ssize_t rsread(void *buf, size_t len) { - ssize_t n = len; - char *b = buf; - - if(!present) - return -ENXIO; - - if(len == 0) - return 0; - - while(n--) { - /* check if the buffer's empty and if so, go to sleep */ - cli(); - if(rxread == rxwrite) - interruptible_sleep_on(&waiting_task); - - /* check again to see if anything was read, or we were interrupted */ - if(rxread == rxwrite) { - sti(); - return -EINTR; - } - - sti(); - - *b++ = rxbuf[rxread]; - rxread = rxread + 1 % sizeof(rxbuf); - } - - return len; -} - void rs_handler(void) { + struct tty_queue *q = &tty_rs.rqueue; + if((inb(RSLINES) & 1) == 0) return; - if(rxwrite == (rxread - 1 % sizeof(rxbuf))) + if(q->pwrite == (q->pread - 1 % sizeof(q->buf))) return; - rxbuf[rxwrite] = inb(RSDATA); - rxwrite = rxwrite + 1 % sizeof(rxbuf); - if(waiting_task != NULL) { - waiting_task->state = TSTATE_RUNNING; - waiting_task = NULL; - } + q->buf[q->pwrite] = inb(RSDATA); + q->pwrite = q->pwrite + 1 % sizeof(q->buf); + + wake_up(&q->waiting); } diff --git a/kernel/sys.c b/kernel/sys.c index cfe9483..6127f58 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -2,6 +2,7 @@ #include <kernel/con.h> #include <kernel/sched.h> #include <kernel/serial.h> +#include <kernel/tty.h> #include <signal.h> #include <stdint.h> #include <stdio.h> @@ -80,14 +81,7 @@ int sys_ctty(int ctty) { } ssize_t sys_read(void *buf, size_t len) { - switch(ctask->ctty) { - case 1: - return rsread(buf, len); - break; - default: - return -EBADF; - break; - } + return tty_read(ctask->ctty, buf, len); } int sys_dummy(void) { diff --git a/kernel/tty.c b/kernel/tty.c new file mode 100644 index 0000000..1946110 --- /dev/null +++ b/kernel/tty.c @@ -0,0 +1,86 @@ +#include <asm/interrupt.h> +#include <errno.h> +#include <kernel/sched.h> +#include <kernel/serial.h> +#include <kernel/tty.h> +#include <limits.h> +#include <string.h> +#include <sys/types.h> +#include <unistd.h> + +#define NRTTY \ + (sizeof(ttys) / sizeof(struct tty_struct*)) + +static struct tty_struct *ttys[] = { + NULL, + &tty_rs +}; + +/* check if the buffer's empty and if so, go to sleep */ +static int sleep_while_empty(struct tty_queue *q) { + if(q->pread != q->pwrite) + return 0; + + cli(); + while(1) { + if(q->pread == q->pwrite) + interruptible_sleep_on(&q->waiting); + + /* check again to see if anything was read, or we were interrupted */ + if(q->pread == q->pwrite) { + sti(); + return -1; + } + + sti(); + return 0; + } +} + +ssize_t tty_read(unsigned tty, void *buf, size_t len) { + size_t i; + char *b = buf; + struct tty_queue *q = &ttys[tty]->rqueue; + + if(tty > NRTTY || ttys[tty] == NULL) + return -1; + + if(len == 0) + return 0; + + if(len > SSIZE_MAX) + len = SSIZE_MAX; + + for(i = 0; i < len; i++) { + /* check if the buffer's empty and if so, go to sleep */ + if(sleep_while_empty(q) < 0) { + if(i == 0) + return -EINTR; + + return i; + } + + *b++ = q->buf[q->pread]; + q->pread = q->pread + 1 % TTY_BUF_SIZE; + } + + return len; +} + +void tty_init(void) { + int i; + + for(i = 0; i < NRTTY; i++) { + if(!ttys[i]) + continue; + + memset(&ttys[i]->rqueue, 0, sizeof(struct tty_queue)); + memset(&ttys[i]->wqueue, 0, sizeof(struct tty_queue)); + + ttys[i]->rqueue.pwrite = 1; + ttys[i]->wqueue.pwrite = 1; + + if(ttys[i]->init) + ttys[i]->init(); + } +} |
