Skip to content

Commit

Permalink
Add few system calls like read, waitpid, exit
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
  • Loading branch information
mahavirj committed Mar 13, 2017
1 parent 4ab9394 commit 618b65f
Show file tree
Hide file tree
Showing 11 changed files with 218 additions and 42 deletions.
48 changes: 39 additions & 9 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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

Expand All @@ -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
Expand All @@ -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 $@
Expand Down
34 changes: 34 additions & 0 deletions app/forktest.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include <tinyos.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>

#define N 32

void forktest(void)
{
int n, pid;

printf("fork test\n");

for (n=0; n<N; n++) {
pid = fork();
if(pid < 0) {
break;
}
if(pid == 0) {
exit(0);
}
}

if (n == N) {
printf("fork claimed to work N times!\n", N);
}
}

int main(void)
{
forktest();
waitpid(-1, NULL, 0);
return 0;
}
12 changes: 3 additions & 9 deletions app/init.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#include <tinyos.h>
#include <unistd.h>

char a[] = "Hello World Parent!\n";
char b[] = "Hello World Child!\n";
#include <sys/wait.h>

int main(void)
{
Expand All @@ -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;
}
40 changes: 34 additions & 6 deletions app/shell.c
Original file line number Diff line number Diff line change
@@ -1,11 +1,39 @@
#include <tinyos.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>

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;
}
14 changes: 13 additions & 1 deletion boot/syscall.s
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 2 additions & 0 deletions include/kernel/keyboard.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@
#define __KEYBOARD_H__

void init_keyboard();
int sys_read();

#endif /* __KEYBOARD_H__ */
3 changes: 3 additions & 0 deletions include/kernel/task.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ enum task_state {
TASK_RUNNING = 2,
TASK_READY = 3,
TASK_SLEEPING = 4,
TASK_EXITED = 5,
};

/* Callee saved register context */
Expand Down Expand Up @@ -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();
Expand Down
72 changes: 56 additions & 16 deletions kernel/keyboard.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
#include <helper.h>
#include <keyboard.h>
#include <vga.h>
#include <sync.h>
#include <mem.h>
#include <syscall.h>
#include <string.h>

/* KBDUS means US Keyboard Layout. This is a scancode table
* used to layout a standard US keyboard. I have left some
Expand Down Expand Up @@ -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)
{
Expand All @@ -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;
}
5 changes: 4 additions & 1 deletion kernel/syscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@
#include <vga.h>
#include <helper.h>
#include <task.h>
#include <keyboard.h>

static registers_t *irqf;

static void *sys_handlers[] = {
sys_write,
sys_fork,
sys_exec,
//sys_read,
sys_read,
sys_exit,
sys_waitpid,
};

int argint(int n, int *p)
Expand Down
22 changes: 22 additions & 0 deletions kernel/task.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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) {
Expand Down
Loading

0 comments on commit 618b65f

Please sign in to comment.