From 618b65f75bdc70d3ae72b1da68766bafa2e6b18a Mon Sep 17 00:00:00 2001 From: Mahavir Jain Date: Mon, 13 Mar 2017 19:18:13 +0530 Subject: [PATCH] Add few system calls like read, waitpid, exit * First shell implementation, requires waitpid, read and exit system calls * User entry point changed to _start, that also call `exit` on return from application * User input is stored in circular buffer, and `read` is blocked on this buffer, interrupt handler wakes up thread * Added forktest user app Signed-off-by: Mahavir Jain --- Makefile | 48 +++++++++++++++++++++----- app/forktest.c | 34 ++++++++++++++++++ app/init.c | 12 ++----- app/shell.c | 40 ++++++++++++++++++---- boot/syscall.s | 14 +++++++- include/kernel/keyboard.h | 2 ++ include/kernel/task.h | 3 ++ kernel/keyboard.c | 72 ++++++++++++++++++++++++++++++--------- kernel/syscall.c | 5 ++- kernel/task.c | 22 ++++++++++++ stdlib/crt.c | 8 +++++ 11 files changed, 218 insertions(+), 42 deletions(-) create mode 100644 app/forktest.c create mode 100644 stdlib/crt.c diff --git a/Makefile b/Makefile index 6dd4ac7..0aec599 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ OBJCOPY := objcopy AR := ar # Tiny OS version -VERSION := 0.1 +VERSION := 0.2 # Verbose build pass verbose=1 ifeq ($(verbose),1) @@ -32,14 +32,40 @@ app_src_dir := app app_obj_dir := $(objdir)/$(app_src_dir) -c_srcs := $(foreach dir, $(kernel_src_dir), $(wildcard $(dir)/*.c)) -asm_srcs := $(foreach dir, $(boot_src_dir), $(wildcard $(dir)/*.s)) +c_srcs := kernel/cpio_parser.c \ + kernel/gdt.c \ + kernel/idt.c \ + kernel/isr.c \ + kernel/keyboard.c \ + kernel/main.c \ + kernel/mem.c \ + kernel/sync.c \ + kernel/syscall.c \ + kernel/task.c \ + kernel/timer.c \ + kernel/vm.c \ + kernel/wait_queue.c \ + drivers/vga.c \ + stdlib/stdlib.c \ + stdlib/printk.c \ + +asm_srcs := boot/boot.s \ + boot/helper.s \ + boot/isr.s \ + boot/swtch.s \ + boot/sync.s \ + c_objs := $(c_srcs:%.c=$(objdir)/%.o) asm_objs := $(asm_srcs:%.s=$(objdir)/%.o) -app_lib_objs := $(objdir)/$(boot_src_dir)/syscall.o \ - $(objdir)/stdlib/stdlib.o \ - $(objdir)/stdlib/printf.o \ +app_lib_srcs := stdlib/crt.c \ + stdlib/stdlib.c \ + stdlib/printf.c \ + +app_asm_srcs := boot/syscall.s \ + +app_lib_objs := $(app_lib_srcs:%.c=$(objdir)/%.o) +app_asm_objs := $(app_asm_srcs:%.s=$(objdir)/%.o) app_lib := $(objdir)/lib_helper.a @@ -51,7 +77,7 @@ LDSCRIPT = -T ldscript/linker.ld APP_LDSCRIPT = -T app/linker.ld LDFLAGS = -nostdlib -Wl,--build-id=none APP_CFLAGS := -g -O2 -m32 -static -fno-pic -Wall -Wextra -ffreestanding -I app/ -APP_LDFLAGS := -nostdlib -Ttext 0x100000 -e main -Wl,--build-id=none +APP_LDFLAGS := -nostdlib -Ttext 0x100000 -Wl,--build-id=none ASFLAGS = -f elf define make-repo @@ -63,13 +89,17 @@ endef all: pre-build $(kernel) $(os_image) -ramfs.obj: $(app_lib) $(app_obj_dir)/init $(app_obj_dir)/shell +ramfs.obj: $(app_lib) $(app_obj_dir)/init $(app_obj_dir)/shell $(app_obj_dir)/forktest $(V)cd $(app_obj_dir) && find . | cpio -o -H newc > ../ramfs.cpio $(V)cd $(objdir) && $(OBJCOPY) -I binary -O elf32-i386 -B i386 ramfs.cpio $@ -$(app_lib): $(app_lib_objs) +$(app_lib): $(app_lib_objs) $(app_asm_objs) $(V)$(AR) cru $@ $^ +$(app_obj_dir)/forktest: $(app_src_dir)/forktest.c + @echo " APP $<" + $(V)$(CC) $(APP_CFLAGS) $(APP_LDFLAGS) $< $(app_lib) -o $@ + $(app_obj_dir)/init: $(app_src_dir)/init.c @echo " APP $<" $(V)$(CC) $(APP_CFLAGS) $(APP_LDFLAGS) $< $(app_lib) -o $@ diff --git a/app/forktest.c b/app/forktest.c new file mode 100644 index 0000000..db353ab --- /dev/null +++ b/app/forktest.c @@ -0,0 +1,34 @@ +#include +#include +#include +#include + +#define N 32 + +void forktest(void) +{ + int n, pid; + + printf("fork test\n"); + + for (n=0; n #include - -char a[] = "Hello World Parent!\n"; -char b[] = "Hello World Child!\n"; +#include int main(void) { @@ -12,12 +10,8 @@ int main(void) if (ret == 0) { execve("shell", &argv, NULL); } else { - for (;;) { - printf("%s", a); - volatile int a = 1 << 23; - while (a--) - ; - } + waitpid(-1, NULL, 0); + printf("Bye! Init exiting\n"); } return 0; } diff --git a/app/shell.c b/app/shell.c index e086a4f..c6b03f0 100644 --- a/app/shell.c +++ b/app/shell.c @@ -1,11 +1,39 @@ #include +#include +#include +#include -int a = 0xa5a5; int main() { - if (a == 0xa5a5) - printf("I am shell\n"); - else - printf("I lost you\n"); - for(;;); + int ret; + int c; + char buf[32]; + int index = 0; + + printf("\nStarting sh\n"); + printf("Type `help` for commands\n"); + printf("# "); + for (;;) { + ret = read(0, &c, 1); + if (!ret) + continue; + buf[index++] = c; + if (c == '\n') { + buf[--index] = '\0'; + ret = fork(); + if (ret == 0) { + if (!strcmp(buf, "help")) + printf("Available commands 'forktest'\n"); + else + execve(buf, (char **) &ret, NULL); + return -1; + } else { + waitpid(-1, NULL, 0); + index = 0; + printf("# "); + } + } + } + printf("Bye! Shell exiting\n"); + return 0; } diff --git a/boot/syscall.s b/boot/syscall.s index cb450d7..e48ecc6 100644 --- a/boot/syscall.s +++ b/boot/syscall.s @@ -17,7 +17,19 @@ execve: ret [GLOBAL read] -sleep: +read: mov eax, 3 int 64 ret + +[GLOBAL exit] +exit: + mov eax, 4 + int 64 + ret + +[GLOBAL waitpid] +waitpid: + mov eax, 5 + int 64 + ret diff --git a/include/kernel/keyboard.h b/include/kernel/keyboard.h index 643f083..963f54b 100644 --- a/include/kernel/keyboard.h +++ b/include/kernel/keyboard.h @@ -2,4 +2,6 @@ #define __KEYBOARD_H__ void init_keyboard(); +int sys_read(); + #endif /* __KEYBOARD_H__ */ diff --git a/include/kernel/task.h b/include/kernel/task.h index 90a599e..9974eea 100644 --- a/include/kernel/task.h +++ b/include/kernel/task.h @@ -8,6 +8,7 @@ enum task_state { TASK_RUNNING = 2, TASK_READY = 3, TASK_SLEEPING = 4, + TASK_EXITED = 5, }; /* Callee saved register context */ @@ -47,6 +48,8 @@ void tiny_schedule(void); int create_init_task(void); int sys_fork(void); int sys_exec(void); +int sys_exit(void); +int sys_waitpid(void); void swtch(struct context **old, struct context *new); void yield(); void sched(); diff --git a/kernel/keyboard.c b/kernel/keyboard.c index 6ac220a..5e15584 100644 --- a/kernel/keyboard.c +++ b/kernel/keyboard.c @@ -2,6 +2,10 @@ #include #include #include +#include +#include +#include +#include /* KBDUS means US Keyboard Layout. This is a scancode table * used to layout a standard US keyboard. I have left some @@ -48,6 +52,26 @@ unsigned char kbdus[128] = 0, /* All other keys are undefined */ }; +#define MAX_SIZE 32 + +#define WRAP(x) \ + ((x + 1) & (MAX_SIZE - 1)) + +#define CIRC_BUF_EMPTY(x) \ + (x->rindex == x->windex) + +#define CIRC_BUF_FULL(x) \ + (x->rindex == WRAP(x->windex + 1)) + +struct circ_buf { + struct spinlock lock; + char buf[MAX_SIZE]; + int rindex; + int windex; +}; + +static struct circ_buf *circ_buf; + /* Handles the keyboard interrupt */ void keyboard_handler(registers_t *r) { @@ -59,31 +83,47 @@ void keyboard_handler(registers_t *r) /* If the top bit of the byte we read from the keyboard is * set, that means that a key has just been released */ - if (scancode & 0x80) - { - /* You can use this one to see if the user released the - * shift, alt, or control keys... */ - } - else - { + if (scancode & 0x80) { + /* Special keyboard chars */ + } else { /* Here, a key was just pressed. Please note that if you * hold a key down, you will get repeated key press * interrupts. */ - - /* Just to show you how this works, we simply translate - * the keyboard scancode into an ASCII value, and then - * display it to the screen. You can get creative and - * use some flags to see if a shift is pressed and use a - * different layout, or you can add another 128 entries - * to the above layout to correspond to 'shift' being - * held. If shift is held using the larger lookup table, - * you would add 128 to the scancode when you look for it */ sys_write_char(kbdus[scancode]); + if (!CIRC_BUF_FULL(circ_buf)) { + circ_buf->buf[circ_buf->windex] = kbdus[scancode]; + circ_buf->windex = WRAP(circ_buf->windex); + wakeup(&circ_buf->lock); + } } } void init_keyboard() { + circ_buf = kcalloc(sizeof(struct circ_buf)); + if (!circ_buf) { + printk("malloc failed\n"); + return; + } /* Installs 'keyboard_handler' to IRQ1 */ irq_install_handler(IRQ1, keyboard_handler); } + +int sys_read() +{ + char *buf; + int len; + int read_bytes = 0; + + argstr(1, &buf); + argint(2, &len); + + if (CIRC_BUF_EMPTY(circ_buf)) + sleep(circ_buf, &circ_buf->lock); + + while (!CIRC_BUF_EMPTY(circ_buf) && (read_bytes < len)) { + buf[read_bytes++] = circ_buf->buf[circ_buf->rindex]; + circ_buf->rindex = WRAP(circ_buf->rindex); + } + return read_bytes; +} diff --git a/kernel/syscall.c b/kernel/syscall.c index 2f6548d..caf8a59 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -2,6 +2,7 @@ #include #include #include +#include static registers_t *irqf; @@ -9,7 +10,9 @@ static void *sys_handlers[] = { sys_write, sys_fork, sys_exec, - //sys_read, + sys_read, + sys_exit, + sys_waitpid, }; int argint(int n, int *p) diff --git a/kernel/task.c b/kernel/task.c index 9a61395..e146cf5 100644 --- a/kernel/task.c +++ b/kernel/task.c @@ -267,8 +267,27 @@ int sys_exec() return 0; } +int sys_exit() +{ + /* FIXME: Resources should be freed from IDLE task context */ + current_task->state = TASK_EXITED; + task_wakeup(current_task->parent); + sched(); + return 0; +} + +int sys_waitpid() +{ + task_sleep(current_task); + sched(); + return 0; +} + void task_sleep(void *resource) { + if (!resource) + return; + cli(); current_task->wait_resource = resource; current_task->state = TASK_SLEEPING; @@ -277,6 +296,9 @@ void task_sleep(void *resource) void task_wakeup(void *resource) { + if (!resource) + return; + cli(); list_head_t *node; list_for_each(node, task_list) { diff --git a/stdlib/crt.c b/stdlib/crt.c new file mode 100644 index 0000000..581da0d --- /dev/null +++ b/stdlib/crt.c @@ -0,0 +1,8 @@ +extern int main(); +extern int exit(); + +void _start() +{ + main(); + exit(); +}