From 70b141b3af85771f36119165e072c1c45d64de84 Mon Sep 17 00:00:00 2001 From: Jake Mannens Date: Sun, 8 Jul 2018 01:44:13 +1000 Subject: Added a printf() function to the library under stdio.c which uses the vsprintf() function to render formatted strings and then the puts system call to output them. Moved the vsprintf() function from the kernel to the library. Furthermore, the prototype for the function has been moved from the kernel's headers, to the new header file stdio.h. Renamed the kernel's internal printf() function to printk() in order to avoid confusion with the library provided function. Renamed the sys_print system call to the more appropriate name, sys_puts. Added a new system call sys_time, which returns the system's uptime in seconds. This is mainly for testing the userspace binary and will not be permanent. Added the file time.c to the library which contains the caller for sys_time and a helper routine sleep() which delays execution for the specified number of seconds. The new header file time.h contains prototypes for both these functions as well as the definition for the type time_t. Fixed a bug in which the value of EAX was not properly passed to the system call handler, resulting in the wrong system call being executed. This was caused by the code in the SAVE macro not properly preserving the value. Fixed a bug in which the value of EAX was not preserved during a return from system call, but rather restored with the original EAX value prior to the call. As a result, system call return codes were not properly passed. This has been corrected by introducing a new macro RESTORE_SYS which carries out the same restore operations, but maintains EAX prior to the return. --- include/kernel/con.h | 5 +- include/kernel/sys.h | 7 ++- include/kernel/vsprintf.h | 14 ----- include/stdio.h | 10 +++ include/time.h | 15 +++++ include/unistd.h | 3 +- kernel/con.c | 8 +-- kernel/kmain.c | 4 +- kernel/sched.c | 14 ++--- kernel/sys.c | 12 +++- kernel/traps.s | 17 +++++- kernel/vsprintf.c | 153 ---------------------------------------------- lib/stdio.c | 18 ++++++ lib/time.c | 10 +++ lib/vsprintf.c | 153 ++++++++++++++++++++++++++++++++++++++++++++++ usrbin/Makefile | 4 +- usrbin/main.c | 11 ++-- usrbin/print.c | 3 - 18 files changed, 262 insertions(+), 199 deletions(-) delete mode 100644 include/kernel/vsprintf.h create mode 100644 include/stdio.h create mode 100644 include/time.h delete mode 100644 kernel/vsprintf.c create mode 100644 lib/stdio.c create mode 100644 lib/time.c create mode 100644 lib/vsprintf.c delete mode 100644 usrbin/print.c diff --git a/include/kernel/con.h b/include/kernel/con.h index 8777342..178a0d3 100644 --- a/include/kernel/con.h +++ b/include/kernel/con.h @@ -1,7 +1,7 @@ /* * con.h * - * Basic VGA text console. Implements printf() and puts(). + * Basic VGA text console. Implements printk() and puts(). */ #ifndef _CON_H @@ -11,7 +11,6 @@ void con_init(void); void con_clear(void); -int puts(char *s); -int printf(char*, ...); +int printk(char*, ...); #endif diff --git a/include/kernel/sys.h b/include/kernel/sys.h index ea54f14..7c129d2 100644 --- a/include/kernel/sys.h +++ b/include/kernel/sys.h @@ -1,11 +1,12 @@ typedef int (*syscall_t) (void); -extern int sys_print(void); +extern int sys_puts(void); +extern int sys_time(void); extern int sys_dummy(void); syscall_t call_table[256] = { - [0] = &sys_print, - [1] = &sys_dummy, + [0] = &sys_puts, + [1] = &sys_time, [2] = &sys_dummy, [3] = &sys_dummy, [4] = &sys_dummy, diff --git a/include/kernel/vsprintf.h b/include/kernel/vsprintf.h deleted file mode 100644 index 08297d6..0000000 --- a/include/kernel/vsprintf.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * vsprintf.h - * - * A very basic implmentation of thr vsprintf function - */ - -#ifndef _VSPRINTF_H -#define _VSPRINTF_H - -#include - -int vsprintf(char*, char*, va_list); - -#endif diff --git a/include/stdio.h b/include/stdio.h new file mode 100644 index 0000000..d37699a --- /dev/null +++ b/include/stdio.h @@ -0,0 +1,10 @@ +#ifndef _STDIO_H +#define _STDIO_H + +#include + +int printf(char*, ...); + +int vsprintf(char*, char*, va_list); + +#endif diff --git a/include/time.h b/include/time.h new file mode 100644 index 0000000..732d33f --- /dev/null +++ b/include/time.h @@ -0,0 +1,15 @@ +#ifndef _TIME_H +#define _TIME_H + +#include + +#ifndef _TIME_T +#define _TIME_T +typedef int32_t time_t; +#endif + +time_t time(void); + +void sleep(time_t); + +#endif diff --git a/include/unistd.h b/include/unistd.h index c63ac6a..ae46b16 100644 --- a/include/unistd.h +++ b/include/unistd.h @@ -1,7 +1,8 @@ #ifndef _UNISTD_H #define _UNISTD_H -#define __SYS_print 0 +#define __SYS_puts 0 +#define __SYS_time 1 #define _syscall0(type, name) \ type name(void) { \ diff --git a/kernel/con.c b/kernel/con.c index 69c34e1..c8be80b 100644 --- a/kernel/con.c +++ b/kernel/con.c @@ -1,13 +1,13 @@ /* * con.c * - * Basic VGA text console. Implements printf() and puts(). + * Basic VGA text console. Implements printk() and puts(). */ #include -#include #include #include +#include #define COLS 80 #define ROWS 25 @@ -64,7 +64,7 @@ void con_init(void) { } /* write a zero-terminated string to console */ -int puts(char *s) { +static int puts(char *s) { uint8_t *p = &vram[pos]; while(*s) { @@ -91,7 +91,7 @@ int puts(char *s) { return 0; } -int printf(char *fmt, ...) { +int printk(char *fmt, ...) { int ret; char buf[1024]; va_list ap; diff --git a/kernel/kmain.c b/kernel/kmain.c index 558df42..1828ad2 100644 --- a/kernel/kmain.c +++ b/kernel/kmain.c @@ -11,8 +11,8 @@ uint32_t ticks = 0; void kmain(void) { con_init(); - printf("Kernel booting...\n"); - printf("Kernel booted!\n\n"); + printk("Kernel booting...\n"); + printk("Kernel booted!\n\n"); userspace_init(); } diff --git a/kernel/sched.c b/kernel/sched.c index f0b79fc..3e25de0 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -57,19 +57,19 @@ void userspace_init(void) { * - stack table (1 page) */ p = alloc_physical_pages(totpages); - printf("Allocating %x pages for userspace process\n", totpages); + printk("Allocating %x pages for userspace process\n", totpages); if(p == NULL) { - printf("Failed to allocate memory for userspace!\n"); + printk("Failed to allocate memory for userspace!\n"); return; } getpage(pdir, p); getpage(stackt, p); getpage(stackp, p); - printf(" Page directory: 0x%08x\n", (uint32_t) pdir); - printf(" Stack table: 0x%08x\n", (uint32_t) stackt); - printf(" Stack page: 0x%08x\n", (uint32_t) stackp); - printf(" Page tables:\n"); + printk(" Page directory: 0x%08x\n", (uint32_t) pdir); + printk(" Stack table: 0x%08x\n", (uint32_t) stackt); + printk(" Stack page: 0x%08x\n", (uint32_t) stackp); + printk(" Page tables:\n"); /* populate the page directory */ c = npages; @@ -78,7 +78,7 @@ void userspace_init(void) { for(i = 0; i < ntables; i++) { /* add the table entry to the directory */ getpage(tab, p); - printf(" 0x%08x\n", (uint32_t) tab); + printk(" 0x%08x\n", (uint32_t) tab); map = map_page(pdir); ((uint32_t*) map)[i + (PGENT / 4)] = (uint32_t) tab | 0x007; diff --git a/kernel/sys.c b/kernel/sys.c index b648dd1..3748e2b 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1,8 +1,16 @@ #include #include +#include +#include -int sys_print(char *s) { - printf(s); +extern uint32_t ticks; + +int sys_puts(char *s) { + return printk(s); +} + +time_t sys_time(void) { + return ticks / 100; } int sys_dummy(void) { diff --git a/kernel/traps.s b/kernel/traps.s index 0381ee8..15e2640 100644 --- a/kernel/traps.s +++ b/kernel/traps.s @@ -23,7 +23,7 @@ extern register_isr mov fs, ax mov gs, ax ; restore EAX (needed for syscalls) - mov eax, [esp+44] + mov eax, [esp+30] %endmacro %macro SAVE_ERR 0 @@ -64,6 +64,19 @@ extern register_isr iret %endmacro +%macro RESTORE_SYS 0 + ; preserve our modified EAX (return value for syscalls) + mov [esp+30], eax + ; restore the data segment selectors + pop ax + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + popa + iret +%endmacro + traps: dd exc_div dd exc_debug @@ -230,7 +243,7 @@ syscall_handler: call [eax] add esp, 12 - RESTORE + RESTORE_SYS syscall_init: diff --git a/kernel/vsprintf.c b/kernel/vsprintf.c deleted file mode 100644 index a566b83..0000000 --- a/kernel/vsprintf.c +++ /dev/null @@ -1,153 +0,0 @@ -#include -#include -#include - -enum TYPE { - TYPE_INT = 1, - TYPE_UINT = 2, - TYPE_HEX = 3, - TYPE_STRING = 4, - TYPE_PERCENT = 5 -}; - -enum FLAGS { - FL_ZERO = 1, /* zero padded */ - FL_ALT = 2, /* alternate form (effect is type dependent) */ - FL_UPPER = 4 /* uppercase */ -}; - -static void hex(char **str, char flags, int fwidth, int size, int x) { - bool seen; - int i, y, len; - char c; - char *prefl = "0x"; - char *prefu = "0X"; - - /* print the prefix, if the alt flag is set */ - if(flags & FL_ALT) { - if(flags & FL_UPPER) { - while(*prefu) - *(*str)++ = *prefu++; - } else { - while(*prefl) - *(*str)++ = *prefl++; - } - } - - /* calculate the number of digits */ - len = 0; - y = x; - seen = false; - for(i = 0; i < sizeof(y) << 1; i++) { - c = ((unsigned int) y >> 28); - if(c) - seen = true; - if(c || seen) - len++; - y = y << 4; - } - - /* print the padding characters (if any) */ - c = ' '; - if(flags & FL_ZERO) - c = '0'; - for(i = 0; i < fwidth - len; i++) - *(*str)++ = c; - - /* actually print the digits */ - seen = false; - for(i = 0; i < sizeof(x) << 1; i++) { - c = ((unsigned int) x >> 28) + '0'; - if(c > '9') { - c += 0x27; - if(flags & FL_UPPER) - c -= 0x20; - } - - if(c != '0') - seen = true; - if(c != '0' || seen) - *(*str)++ = c; - - x = x << 4; - } -} - -int vsprintf(char *str, char *fmt, va_list ap) { - int x, fwidth; - char flags; - char *s; - char *start = str; - uint8_t type; - - while(*fmt) { - if(*fmt != '%') { - *str++ = *fmt++; - continue; - } - - type = 0; - flags = 0; - fwidth = 0; - - fmt++; - while(1) { - switch(*fmt) { - case '#': - flags |= FL_ALT; - break; - case '%': - type = TYPE_PERCENT; - goto done; - case 's': - type = TYPE_STRING; - goto done; - case 'x': - type = TYPE_HEX; - goto done; - case 'X': - type = TYPE_HEX; - flags |= FL_UPPER; - goto done; - default: - /* the first zero enables zero-padding */ - if(*fmt == '0' && !fwidth) { - flags |= FL_ZERO; - goto next; - } - - /* subsequent numbers indicate field width */ - if(*fmt >= '0' && *fmt <= '9') { - fwidth = (fwidth * 10) + (*fmt - '0'); - goto next; - } - - goto done; - } -next: - fmt++; - } - -done: - fmt++; - - switch(type) { - case TYPE_STRING: - s = va_arg(ap, char*); - while(*s) - *str++ = *s++; - break; - case TYPE_HEX: - x = va_arg(ap, int); - hex(&str, flags, fwidth, 4, x); - break; - case TYPE_PERCENT: - *str++ = '%'; - break; - } - } - - *str = 0; - - return (str - start); -} diff --git a/lib/stdio.c b/lib/stdio.c new file mode 100644 index 0000000..912fd17 --- /dev/null +++ b/lib/stdio.c @@ -0,0 +1,18 @@ +#include +#include +#include + +_syscall1(int, puts, char*, s); + +int printf(char *fmt, ...) { + int ret; + char buf[1024]; + va_list ap; + + va_start(ap, fmt); + ret = vsprintf(buf, fmt, ap); + va_end(ap); + + puts(buf); + return ret; +} diff --git a/lib/time.c b/lib/time.c new file mode 100644 index 0000000..42ee601 --- /dev/null +++ b/lib/time.c @@ -0,0 +1,10 @@ +#include +#include + +_syscall0(time_t, time); + +void sleep(time_t t) { + time_t start = time(); + + while(time() < start + t); +} diff --git a/lib/vsprintf.c b/lib/vsprintf.c new file mode 100644 index 0000000..a566b83 --- /dev/null +++ b/lib/vsprintf.c @@ -0,0 +1,153 @@ +#include +#include +#include + +enum TYPE { + TYPE_INT = 1, + TYPE_UINT = 2, + TYPE_HEX = 3, + TYPE_STRING = 4, + TYPE_PERCENT = 5 +}; + +enum FLAGS { + FL_ZERO = 1, /* zero padded */ + FL_ALT = 2, /* alternate form (effect is type dependent) */ + FL_UPPER = 4 /* uppercase */ +}; + +static void hex(char **str, char flags, int fwidth, int size, int x) { + bool seen; + int i, y, len; + char c; + char *prefl = "0x"; + char *prefu = "0X"; + + /* print the prefix, if the alt flag is set */ + if(flags & FL_ALT) { + if(flags & FL_UPPER) { + while(*prefu) + *(*str)++ = *prefu++; + } else { + while(*prefl) + *(*str)++ = *prefl++; + } + } + + /* calculate the number of digits */ + len = 0; + y = x; + seen = false; + for(i = 0; i < sizeof(y) << 1; i++) { + c = ((unsigned int) y >> 28); + if(c) + seen = true; + if(c || seen) + len++; + y = y << 4; + } + + /* print the padding characters (if any) */ + c = ' '; + if(flags & FL_ZERO) + c = '0'; + for(i = 0; i < fwidth - len; i++) + *(*str)++ = c; + + /* actually print the digits */ + seen = false; + for(i = 0; i < sizeof(x) << 1; i++) { + c = ((unsigned int) x >> 28) + '0'; + if(c > '9') { + c += 0x27; + if(flags & FL_UPPER) + c -= 0x20; + } + + if(c != '0') + seen = true; + if(c != '0' || seen) + *(*str)++ = c; + + x = x << 4; + } +} + +int vsprintf(char *str, char *fmt, va_list ap) { + int x, fwidth; + char flags; + char *s; + char *start = str; + uint8_t type; + + while(*fmt) { + if(*fmt != '%') { + *str++ = *fmt++; + continue; + } + + type = 0; + flags = 0; + fwidth = 0; + + fmt++; + while(1) { + switch(*fmt) { + case '#': + flags |= FL_ALT; + break; + case '%': + type = TYPE_PERCENT; + goto done; + case 's': + type = TYPE_STRING; + goto done; + case 'x': + type = TYPE_HEX; + goto done; + case 'X': + type = TYPE_HEX; + flags |= FL_UPPER; + goto done; + default: + /* the first zero enables zero-padding */ + if(*fmt == '0' && !fwidth) { + flags |= FL_ZERO; + goto next; + } + + /* subsequent numbers indicate field width */ + if(*fmt >= '0' && *fmt <= '9') { + fwidth = (fwidth * 10) + (*fmt - '0'); + goto next; + } + + goto done; + } +next: + fmt++; + } + +done: + fmt++; + + switch(type) { + case TYPE_STRING: + s = va_arg(ap, char*); + while(*s) + *str++ = *s++; + break; + case TYPE_HEX: + x = va_arg(ap, int); + hex(&str, flags, fwidth, 4, x); + break; + case TYPE_PERCENT: + *str++ = '%'; + break; + } + } + + *str = 0; + + return (str - start); +} diff --git a/usrbin/Makefile b/usrbin/Makefile index 9a40cbc..67e63fa 100644 --- a/usrbin/Makefile +++ b/usrbin/Makefile @@ -1,5 +1,7 @@ TARGET = usrbin_blob.o +LIB = ../lib/lib.a + SRCS = $(wildcard *.c) ASMS = $(wildcard *.s) OBJS = $(SRCS:.c=.o) $(ASMS:.s=.o) @@ -23,7 +25,7 @@ build: $(TARGET) $(CC) -c -o $*.o $^ $(TARGET): $(OBJS) - $(LD) -o usrbin.bin $(OBJS) + $(LD) -o usrbin.bin $(OBJS) $(LIB) objcopy -I binary -O elf32-i386 -B i386 usrbin.bin $(TARGET) \ --redefine-sym _binary_usrbin_bin_start=_usrbin_start \ --redefine-sym _binary_usrbin_bin_end=_usrbin_end \ diff --git a/usrbin/main.c b/usrbin/main.c index d2ea633..aa48450 100644 --- a/usrbin/main.c +++ b/usrbin/main.c @@ -1,9 +1,12 @@ #include - -extern int print(char*); +#include +#include void main(void) { - print("We did it ma!\n"); + printf("We did it ma!\n"); - char c = *((char*) 0x80BEEF); + while(1) { + sleep(1); + printf("1000ms tick!\n"); + } } diff --git a/usrbin/print.c b/usrbin/print.c deleted file mode 100644 index ea32cdf..0000000 --- a/usrbin/print.c +++ /dev/null @@ -1,3 +0,0 @@ -#include - -_syscall1(int, print, char*, s); -- cgit v1.3