summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJake Mannens <jake72360@gmail.com>2018-08-06 00:32:06 +1000
committerJake Mannens <jake72360@gmail.com>2018-08-06 00:32:06 +1000
commit3ed830019561a06b0cb98f792cc447a157fd4ef2 (patch)
tree08d6bcd81a84881a8158752e73a144f2989253f8
parent8e933fac9fd068343bb602f13175c8d70a6c5768 (diff)
Defined ssize_t in unistd.h.
Added the _syscall2 macro to unistd.h to facilitate system calls that require two arguments to be passed. Modified the ATA driver to simply abort initialisation if a drive is not found, or cannot be configured. This will allow the kernel to function on a diskless system without invoking panic() unnecessarily. Added the functions irq_enable() and irq_disable() to asm/interrupt.h to make it easier for C code to mask and unmask IRQ's on each PIC. Moved the declaration for rsputs() from kernel/con.h to the new kernel/serial.h file since this is a function provided by the serial driver. Implemented a basic I/O input framework. This involves the new system call sys_read, which takes an I/O read request and directs it to the appropriate kernel handler function depending on the calling process' ctty value. This mechanism is identical to the sys_puts system call. Added the rsread() function to service sys_read calls from processes whose ctty value is equal to 1. This function will continually copy data from the serial buffer to the location specified. If there is not a sufficient amount of new data in the buffer to satisfy the request, the process is put into the TSTATE_UNINTERRUPTIBLE state and the scheduler is called to switch tasks. Prior to calling the scheduler, the function will set the waiting_task pointer to the calling process. This pointer will later be used by the interrupt handler to wake the process when new data arrives. Added an interrupt handler to service the IRQ4 (UART) interrupt. This subroutine is a stub which will save the machine's state then transfer control to rs_handler() in serial.c which will read bytes from the serial port and place them in a buffer. Before returning, rs_handler() checks the waiting_task pointer to see if a task is waiting for the newly received data and if so, it sets the task's state to TSTATE_RUNNING before resetting the pointer to NULL and returning. Ideally, the scheduler should be invoked at this point to select another task but since our basic round-robin scheduler currently has no concept of task priorities (and for the sake of simplicity), we will avoid invoking the scheduler in response to interrupts for now.
-rw-r--r--Makefile2
-rw-r--r--include/asm/interrupt.h27
-rw-r--r--include/kernel/con.h2
-rw-r--r--include/kernel/serial.h10
-rw-r--r--include/kernel/sys.h3
-rw-r--r--include/stdio.h4
-rw-r--r--include/unistd.h21
-rw-r--r--kernel/hd.c4
-rw-r--r--kernel/rs.s25
-rw-r--r--kernel/serial.c60
-rw-r--r--kernel/sys.c17
-rw-r--r--kernel/timer.s2
-rw-r--r--lib/stdio.c2
-rw-r--r--usrbin/main.c20
14 files changed, 174 insertions, 25 deletions
diff --git a/Makefile b/Makefile
index f043bea..391597f 100644
--- a/Makefile
+++ b/Makefile
@@ -21,7 +21,7 @@ clean:
rm -f $(TARGET)
run: $(TARGET)
- qemu-system-x86_64 -s -kernel $(TARGET) -drive file=hd.img,format=raw
+ qemu-system-x86_64 -s -kernel $(TARGET) -drive file=hd.img,format=raw -serial stdio
#qemu-system-x86_64 -s -S -kernel $(TARGET) -drive file=hd.img,format=raw
.FORCE:
diff --git a/include/asm/interrupt.h b/include/asm/interrupt.h
index d1ea6c1..1187fef 100644
--- a/include/asm/interrupt.h
+++ b/include/asm/interrupt.h
@@ -1,2 +1,29 @@
+#include <stdint.h>
+
+#define irq_enable(n) \
+ __asm__ volatile ( \
+ "inb $0xA1, %%al\n" \
+ "shl $8, %%ax\n" \
+ "inb $0x21, %%al\n" \
+ "xor $0xFFFF, %%bx\n" \
+ "and %%bx, %%ax\n" \
+ "outb %%al, $0x21\n" \
+ "shr $8, %%ax\n" \
+ "outb %%al, $0xA1\n" \
+ :: "b" (n) \
+ );
+
+#define irq_disable(n) \
+ __asm__ volatile ( \
+ "inb $0xA1, %%al\n" \
+ "shl $8, %%ax\n" \
+ "inb $0x21, %%al\n" \
+ "or %%bx, %%ax\n" \
+ "outb %%al, $0x21\n" \
+ "shr $8, %%ax\n" \
+ "outb %%al, $0xA1\n" \
+ :: "b" (n) \
+ );
+
void register_isr(uint8_t n, uint8_t dpl, void *handler);
void register_trap(uint8_t n, uint8_t dpl, void *handler);
diff --git a/include/kernel/con.h b/include/kernel/con.h
index d28daff..9dd9dbe 100644
--- a/include/kernel/con.h
+++ b/include/kernel/con.h
@@ -13,6 +13,4 @@ void con_clear(void);
int printk(char*, ...);
-int rsputs(char*);
-
#endif
diff --git a/include/kernel/serial.h b/include/kernel/serial.h
new file mode 100644
index 0000000..dbfa7f2
--- /dev/null
+++ b/include/kernel/serial.h
@@ -0,0 +1,10 @@
+#ifndef _SERIAL_H
+#define _SERIAL_H
+
+#include <sys/types.h>
+
+int rsputs(char*);
+
+ssize_t rsread(void*, size_t);
+
+#endif
diff --git a/include/kernel/sys.h b/include/kernel/sys.h
index 32788b1..c428c72 100644
--- a/include/kernel/sys.h
+++ b/include/kernel/sys.h
@@ -8,6 +8,7 @@ extern int sys_signal(void);
extern int sys_alarm(void);
extern int sys_pause(void);
extern int sys_ctty(void);
+extern int sys_read(void);
extern int sys_dummy(void);
syscall_t call_table[256] = {
@@ -19,7 +20,7 @@ syscall_t call_table[256] = {
[5] = &sys_alarm,
[6] = &sys_pause,
[7] = &sys_ctty,
- [8] = &sys_dummy,
+ [8] = &sys_read,
[9] = &sys_dummy,
[10] = &sys_dummy,
[11] = &sys_dummy,
diff --git a/include/stdio.h b/include/stdio.h
index 824eb31..f94e783 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -2,6 +2,8 @@
#define _STDIO_H
#include <stdarg.h>
+#include <sys/types.h>
+#include <unistd.h>
#define EOF -1
@@ -12,6 +14,8 @@ int sprintf(char*, char*, ...);
int vsprintf(char*, char*, va_list);
+ssize_t read(void *buf, size_t len);
+
int ctty(int ctty);
#endif
diff --git a/include/unistd.h b/include/unistd.h
index 746c829..ef6d059 100644
--- a/include/unistd.h
+++ b/include/unistd.h
@@ -3,6 +3,11 @@
#include <stdint.h>
+#ifndef _SSIZE_T
+#define _SSIZE_T
+typedef int32_t ssize_t;
+#endif
+
typedef uint16_t pid_t;
#define __SYS_puts 0
@@ -13,6 +18,7 @@ typedef uint16_t pid_t;
#define __SYS_alarm 5
#define __SYS_pause 6
#define __SYS_ctty 7
+#define __SYS_read 8
#define _syscall0(type, name) \
type name(void) { \
@@ -21,7 +27,7 @@ typedef uint16_t pid_t;
"int $0x80" \
: "=a" (__res) \
: "a" (__SYS_##name) \
- :); \
+ ); \
return __res; \
}
@@ -32,7 +38,18 @@ typedef uint16_t pid_t;
"int $0x80" \
: "=a" (__res) \
: "a" (__SYS_##name), "b" (a) \
- :); \
+ ); \
+ return __res; \
+ }
+
+#define _syscall2(type, name, atype, a, btype, b) \
+ type name(atype a, btype b) { \
+ type __res; \
+ __asm__ volatile ( \
+ "int $0x80" \
+ : "=a" (__res) \
+ : "a" (__SYS_##name), "b" (a), "c" (b) \
+ ); \
return __res; \
}
diff --git a/kernel/hd.c b/kernel/hd.c
index 706d503..65ebfd7 100644
--- a/kernel/hd.c
+++ b/kernel/hd.c
@@ -27,13 +27,13 @@ void hd_init(void) {
s = inb(0x1F7);
if(!s) {
printk("[hd] Master drive not detected on primary bus!\n");
- panic();
+ return;
}
if(s & ST_ERR) {
if(!inb(0x1F4) && !inb(0x1F5))
continue;
printk("[hd] IDENTIFY command error!\n");
- panic();
+ return;
}
if(s & ST_DRQ && !(s & ST_ERR))
break;
diff --git a/kernel/rs.s b/kernel/rs.s
new file mode 100644
index 0000000..9f3d4a6
--- /dev/null
+++ b/kernel/rs.s
@@ -0,0 +1,25 @@
+global rs_isr
+extern rs_handler
+extern rsputs
+
+rs_isr:
+ pusha
+ mov ax, ds
+ push ax
+ mov ax, 0x10
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+
+ call rs_handler
+ mov al, 0x20
+ out 0x20, al
+
+ pop ax
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ popa
+ iret
diff --git a/kernel/serial.c b/kernel/serial.c
index 86bbd87..d96359b 100644
--- a/kernel/serial.c
+++ b/kernel/serial.c
@@ -1,5 +1,9 @@
+#include <asm/interrupt.h>
#include <asm/io.h>
#include <kernel/con.h>
+#include <kernel/sched.h>
+#include <sys/types.h>
+#include <unistd.h>
/* 115200 baud */
#define DIVISOR 1
@@ -18,10 +22,16 @@
#define rswait()\
while((inb(RSLINES) & 0x20) == 0);
+extern void rs_isr(void);
+
+static char rxbuf[256];
+static unsigned rxread, rxwrite;
+static struct task_struct *waiting_task;
+
int rsputs(char *s) {
while(*s) {
rswait();
- if(*s == '\n') {
+ if(*s == '\n' || *s == '\r') {
outb(RSDATA, '\n');
rswait();
outb(RSDATA, '\r');
@@ -50,9 +60,55 @@ void serial_init(void) {
/* restore access to the divisor */
outb(RSLINEC, inb(RSLINEC) & 0x7F);
/* configure port parameters */
+ outb(RSFIFOC, 0x06);
outb(RSLINEC, 0x03);
- outb(RSINTEN, 0x00);
+ outb(RSMODEMC, 0x0B);
+ outb(RSINTEN, 0x01);
+ inb(RSDATA);
+ /* register the interrupt handler */
+ register_isr(0x24, 0, &rs_isr);
+ irq_enable(0x10);
rsputs("[kernel] Serial monitor initialized!\n\r");
printk("[rs] Serial port COM0 initialized!\n");
+
+ rxread = 0;
+ rxwrite = 1;
+ waiting_task = NULL;
+}
+
+ssize_t rsread(void *buf, size_t len) {
+ ssize_t n = len;
+ char *b = buf;
+
+ if(len == 0)
+ return 0;
+
+ while(n--) {
+ if(rxread == rxwrite) {
+ /* put the current task to sleep */
+ waiting_task = ctask;
+ ctask->state = TSTATE_UNINTERRUPTIBLE;
+ reschedule();
+ }
+
+ *b++ = rxbuf[rxread];
+ rxread = rxread + 1 % sizeof(rxbuf);
+ }
+
+ return len;
+}
+
+void rs_handler(void) {
+ if((inb(RSLINES) & 1) == 0)
+ return;
+ if(rxwrite == (rxread - 1 % sizeof(rxbuf)))
+ return;
+ rxbuf[rxwrite] = inb(RSDATA);
+ rxwrite = rxwrite + 1 % sizeof(rxbuf);
+
+ if(waiting_task != NULL) {
+ waiting_task->state = TSTATE_RUNNING;
+ waiting_task = NULL;
+ }
}
diff --git a/kernel/sys.c b/kernel/sys.c
index 986c4dd..cfe9483 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1,6 +1,7 @@
#include <errno.h>
#include <kernel/con.h>
#include <kernel/sched.h>
+#include <kernel/serial.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
@@ -10,14 +11,15 @@
int sys_puts(char *s) {
char buf[8];
- sprintf(buf, "[%04x] ", ctask->pid);
if(ctask->ctty < 0)
return EOF;
+ sprintf(buf, "[%04x] ", ctask->pid);
+
switch(ctask->ctty) {
case 1:
- rsputs(buf);
+ /* rsputs(buf); */
return rsputs(s);
break;
default:
@@ -77,6 +79,17 @@ int sys_ctty(int ctty) {
return 0;
}
+ssize_t sys_read(void *buf, size_t len) {
+ switch(ctask->ctty) {
+ case 1:
+ return rsread(buf, len);
+ break;
+ default:
+ return -EBADF;
+ break;
+ }
+}
+
int sys_dummy(void) {
return -ENOSYS;
}
diff --git a/kernel/timer.s b/kernel/timer.s
index 6d95281..e6da428 100644
--- a/kernel/timer.s
+++ b/kernel/timer.s
@@ -55,7 +55,7 @@ timer_init:
push dword 0x20
call register_isr
add esp, 12
- ; initialize the pit
+ ; initialize the PIT
mov ax, 0x36
out 0x43, al
mov ax, 0x2E9C ; 10ms tick interval
diff --git a/lib/stdio.c b/lib/stdio.c
index 67f0a54..7eac64c 100644
--- a/lib/stdio.c
+++ b/lib/stdio.c
@@ -1,9 +1,11 @@
#include <stdarg.h>
#include <stdio.h>
+#include <sys/types.h>
#include <unistd.h>
_syscall1(int, puts, char*, s);
_syscall1(int, ctty, int, ctty);
+_syscall2(ssize_t, read, void*, buf, size_t, len);
int printf(char *fmt, ...) {
int ret;
diff --git a/usrbin/main.c b/usrbin/main.c
index 68f1a5c..31d38c1 100644
--- a/usrbin/main.c
+++ b/usrbin/main.c
@@ -4,21 +4,17 @@
#include <time.h>
#include <unistd.h>
-void sighandler(int sig) {
- printf("Caught SIGALRM!\n");
-}
-
void pid1(void) {
- printf("We did it ma!\n");
+ ssize_t in;
+ char buf[2] = { 0, 0 };
- signal(SIGALRM, &sighandler);
- alarm(2);
- pause();
- printf("Alarm expired!\n");
- pause();
+ printf("We did it ma!\n");
- while(1)
- printf("It's didn't work!\n");
+ while(1) {
+ in = read(buf, 1);
+ if(in > 0)
+ puts(buf);
+ }
}
void pid2(void) {