From: David Devecsery Date: Tue, 19 May 2020 19:51:53 +0000 (-0400) Subject: Updated printing functionality X-Git-Url: https://git.devinivas.org/?a=commitdiff_plain;h=99a2f4613051dcd8594179f3af6888331043474c;p=cs3210-lab1.git Updated printing functionality --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 65345c3..f40b91a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ endif() project(xv6) #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-pic -static -fno-builtin -fno-strict-aliasing -Wall -MD -gstabs+ -Werror -fno-omit-frame-pointer -fno-stack-protector") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-strict-aliasing -Wall -gstabs -Werror -fno-omit-frame-pointer -fno-stack-protector") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-strict-aliasing -Wall -gstabs -Wno-builtin-declaration-mismatch -fno-omit-frame-pointer -fno-stack-protector") set(CMAKE_C_FLAGS_RELEASE "-O2 -DNDEBUG") set(CMAKE_C_FLAGS_DEBUG "-O0 -gstabs") diff --git a/include/error.h b/include/error.h new file mode 100644 index 0000000..7f01ffd --- /dev/null +++ b/include/error.h @@ -0,0 +1,19 @@ +/* See COPYRIGHT for copyright information. */ + +#ifndef JOS_INC_ERROR_H +#define JOS_INC_ERROR_H + +enum { + // Kernel error codes -- keep in sync with list in lib/printfmt.c. + E_UNSPECIFIED = 1, // Unspecified or unknown problem + E_BAD_ENV, // Environment doesn't exist or otherwise + // cannot be used in requested action + E_INVAL, // Invalid parameter + E_NO_MEM, // Request failed due to memory shortage + E_NO_FREE_ENV, // Attempt to create a new environment beyond + // the maximum allowed + E_FAULT, // Memory fault + MAXERROR +}; + +#endif // !JOS_INC_ERROR_H */ diff --git a/include/stdarg.h b/include/stdarg.h new file mode 100644 index 0000000..b05304d --- /dev/null +++ b/include/stdarg.h @@ -0,0 +1,14 @@ +/* $NetBSD: stdarg.h,v 1.12 1995/12/25 23:15:31 mycroft Exp $ */ + +#ifndef INCLUDE_STDARG_h_ +#define INCLUDE_STDARG_h_ + +typedef __builtin_va_list va_list; + +#define va_start(ap, last) __builtin_va_start(ap, last) + +#define va_arg(ap, type) __builtin_va_arg(ap, type) + +#define va_end(ap) __builtin_va_end(ap) + +#endif // INCLUDE_STDARG_h_ diff --git a/include/stdio.h b/include/stdio.h new file mode 100644 index 0000000..7162092 --- /dev/null +++ b/include/stdio.h @@ -0,0 +1,28 @@ +#ifndef INCLUDE_STDIO_h_ +#define INCLUDE_STDIO_h_ + +#include "stdarg.h" + +#ifndef NULL +#define NULL ((void*)0) +#endif /* !NULL */ + +void cputchar(int c); +int getchar(void); +int iscons(int fd); + +void printfmt(void (*putch)(int, void*), void *putdat, const char *fmt, ...); +void vprintfmt(void (*putch)(int, void*), void *putdat, const char *fmt, va_list); +int snprintf(char *str, int size, const char *fmt, ...); +int vsnprintf(char *str, int size, const char *fmt, va_list); + +int cprintf(const char *fmt, ...); +int vcprintf(const char *fmt, va_list); + +//int printf(const char *fmt, ...); +int fprintf(int fd, const char *fmt, ...); +int vfprintf(int fd, const char *fmt, va_list); + +char* readline(const char *prompt); + +#endif // INCLUDE_STDIO_h_ diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 0608770..f0c4c2a 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -2,12 +2,33 @@ project(kernel ASM) include_directories(include) -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -static -fno-builtin -fno-pic -m32") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -static -fno-pic -m32") set(CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS}") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -m elf_i386") include(Sources.cmake) +# Get libgcc... +execute_process(COMMAND gcc -m32 -print-libgcc-file-name + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + OUTPUT_VARIABLE GCC_LIBRARY + OUTPUT_STRIP_TRAILING_WHITESPACE) + +message(STATUS "GOT RES ${GCC_RES}") +message(STATUS "GOT GCCVAR ${GCC_LIBRARY}") +message(STATUS "GOT ERROR ${GCC_ERROR}") + + +set (git_cmd "git") +set (git_arg "--version") +message(STATUS "git cmd: ${git_cmd}") +execute_process(COMMAND ${git_cmd} ${git_arg} + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + RESULT_VARIABLE git_result + OUTPUT_VARIABLE git_ver) + +message(STATUS "git ver[${git_result}]: ${git_ver}") + add_custom_command( OUTPUT gen/vectors.S COMMAND mkdir -p gen && ${CMAKE_CURRENT_SOURCE_DIR}/tools/vectors.pl > gen/vectors.S @@ -68,7 +89,7 @@ add_custom_command( add_custom_command( OUTPUT kernel - COMMAND ld -m elf_i386 -nostdlib -T ${CMAKE_CURRENT_SOURCE_DIR}/kernel.ld -o kernel ${kernel_OBJECTS} -b binary initcode entryother + COMMAND ld -m elf_i386 -T ${CMAKE_CURRENT_SOURCE_DIR}/kernel.ld -o kernel ${kernel_OBJECTS} ${GCC_LIBRARY} -b binary initcode entryother DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/kernel.ld $ $ ${CMAKE_CURRENT_BINARY_DIR}/initcode ${CMAKE_CURRENT_BINARY_DIR}/entryother) add_custom_command( diff --git a/kernel/Sources.cmake b/kernel/Sources.cmake index cb6d6cc..5b5ed1a 100644 --- a/kernel/Sources.cmake +++ b/kernel/Sources.cmake @@ -26,6 +26,7 @@ set(kernel_SOURCES src/picirq.c src/pipe.c src/proc.c + src/printfmt.c src/sleeplock.c src/spinlock.c src/stab.c diff --git a/kernel/include/defs.h b/kernel/include/defs.h index 85c8636..1e91224 100644 --- a/kernel/include/defs.h +++ b/kernel/include/defs.h @@ -18,7 +18,6 @@ void bwrite(struct buf*); // console.c void consoleinit(void); -void cprintf(char*, ...); void consoleintr(int(*)(void)); void panic(char*) __attribute__((noreturn)); diff --git a/kernel/include/proc.h b/kernel/include/proc.h index 59e4580..21db00a 100644 --- a/kernel/include/proc.h +++ b/kernel/include/proc.h @@ -4,6 +4,7 @@ #include #include "param.h" +#include "mmu.h" // Per-CPU state struct cpu { diff --git a/kernel/src/console.c b/kernel/src/console.c index 2658003..d79ca55 100644 --- a/kernel/src/console.c +++ b/kernel/src/console.c @@ -4,6 +4,9 @@ #include "asm/x86.h" +#include "stdio.h" +#include "stdarg.h" + #include "types.h" #include "defs.h" #include "param.h" @@ -13,10 +16,16 @@ #include "fs.h" #include "file.h" #include "memlayout.h" +#include "proc.h" #include "mmu.h" #include "proc.h" #include "string.h" +int uartgetc(void); +int kbdgetc(void); + +void cputchar(int); + static void consputc(int); static int panicked = 0; @@ -27,31 +36,36 @@ static struct { } cons; static void -printint(int xx, int base, int sign) +putch(int ch, int *cnt) { - static char digits[] = "0123456789abcdef"; - char buf[16]; - int i; - uint x; + cputchar(ch); + // This was imported from old cs3210 lab -- it doesn't do anything... so I + // removed it + // *cnt++; +} - if(sign && (sign = xx < 0)) - x = -xx; - else - x = xx; +int +vcprintf(const char *fmt, va_list ap) +{ + int cnt = 0; - i = 0; - do{ - buf[i++] = digits[x % base]; - }while((x /= base) != 0); + vprintfmt((void*)putch, &cnt, fmt, ap); + return cnt; +} - if(sign) - buf[i++] = '-'; +int +cprintf(const char *fmt, ...) +{ + va_list ap; + int cnt; - while(--i >= 0) - consputc(buf[i]); -} -//PAGEBREAK: 50 + va_start(ap, fmt); + cnt = vcprintf(fmt, ap); + va_end(ap); + return cnt; +} +/* // Print to the console. only understands %d, %x, %p, %s. void cprintf(char *fmt, ...) @@ -81,7 +95,6 @@ cprintf(char *fmt, ...) printint(*argp++, 10, 1); break; case 'x': - case 'X': case 'p': printint(*argp++, 16, 0); break; @@ -105,7 +118,7 @@ cprintf(char *fmt, ...) if(locking) release(&cons.lock); } - +*/ void panic(char *s) { @@ -114,8 +127,7 @@ panic(char *s) cli(); cons.locking = 0; - // use lapiccpunum so that we can call panic from mycpu() - cprintf("lapicid %d: panic: ", lapicid()); + cprintf("cpu with apicid %d: panic: ", lapicid()); cprintf(s); cprintf("\n"); getcallerpcs(&s, pcs); @@ -191,6 +203,34 @@ struct { #define C(x) ((x)-'@') // Control-x + +// return the next input character from the console, or 0 if none waiting +int +cons_getc(void) +{ + int c; + + // poll for any pending input characters, + // so that this function works even when interrupts are disabled + // (e.g., when called from the kernel monitor). + consoleintr(uartgetc); + consoleintr(kbdgetc); + acquire(&cons.lock); + + // grab the next character from the input buffer. + if (input.r != input.w) { + c = input.buf[input.r++]; + if (input.r == INPUT_BUF) + input.r = 0; + release(&cons.lock); + return c; + } + release(&cons.lock); + return 0; +} + + + void consoleintr(int (*getc)(void)) { @@ -238,7 +278,7 @@ consoleintr(int (*getc)(void)) int consoleread(struct inode *ip, char *dst, int n) { - int target; + uint target; int c; iunlock(ip); @@ -300,3 +340,25 @@ consoleinit(void) ioapicenable(IRQ_KBD, 0); } +void +cputchar(int c) +{ + consputc(c); +} + +int +getchar(void) +{ + int c; + + while ((c = cons_getc()) == 0) + /* do nothing */; + return c; +} + +int +iscons(int fdnum) +{ + // used by readline + return 1; +} diff --git a/kernel/src/exec.c b/kernel/src/exec.c index 42a1d6d..bf535f9 100644 --- a/kernel/src/exec.c +++ b/kernel/src/exec.c @@ -1,5 +1,7 @@ #include "asm/x86.h" +#include "stdio.h" + #include "types.h" #include "param.h" #include "memlayout.h" diff --git a/kernel/src/fs.c b/kernel/src/fs.c index 0bd4a0c..3e7a00f 100644 --- a/kernel/src/fs.c +++ b/kernel/src/fs.c @@ -21,6 +21,7 @@ #include "buf.h" #include "file.h" #include "string.h" +#include "stdio.h" #define min(a, b) ((a) < (b) ? (a) : (b)) static void itrunc(struct inode*); diff --git a/kernel/src/ioapic.c b/kernel/src/ioapic.c index cb0f015..69a750a 100644 --- a/kernel/src/ioapic.c +++ b/kernel/src/ioapic.c @@ -5,6 +5,7 @@ #include "types.h" #include "defs.h" #include "traps.h" +#include "stdio.h" #define IOAPIC 0xFEC00000 // Default physical address of IO APIC diff --git a/kernel/src/main.c b/kernel/src/main.c index 30a5354..3e22d26 100644 --- a/kernel/src/main.c +++ b/kernel/src/main.c @@ -8,6 +8,7 @@ #include "mmu.h" #include "proc.h" #include "string.h" +#include "stdio.h" static void startothers(void); static void mpmain(void) __attribute__((noreturn)); diff --git a/kernel/src/printfmt.c b/kernel/src/printfmt.c new file mode 100644 index 0000000..58ccd20 --- /dev/null +++ b/kernel/src/printfmt.c @@ -0,0 +1,300 @@ +// Stripped-down primitive printf-style formatting routines, +// used in common by printf, sprintf, fprintf, etc. +// This code is also used by both the kernel and user programs. + +#include "types.h" +#include "stdio.h" +#include "string.h" +#include "stdarg.h" +#include "error.h" + +/* + * Space or zero padding and a field width are supported for the numeric + * formats only. + * + * The special format %e takes an integer error code + * and prints a string describing the error. + * The integer may be positive or negative, + * so that -E_NO_MEM and E_NO_MEM are equivalent. + */ + +static const char * const error_string[MAXERROR] = +{ + [E_UNSPECIFIED] = "unspecified error", + [E_BAD_ENV] = "bad environment", + [E_INVAL] = "invalid parameter", + [E_NO_MEM] = "out of memory", + [E_NO_FREE_ENV] = "out of environments", + [E_FAULT] = "segmentation fault", +}; + +/* + * Print a number (base <= 16) in reverse order, + * using specified putch function and associated pointer putdat. + */ +static void +printnum(void (*putch)(int, void*), void *putdat, + unsigned long long num, unsigned base, int width, int padc) +{ + // first recursively print all preceding (more significant) digits + if (num >= base) + printnum(putch, putdat, num / base, base, width - 1, padc); + else { + // print any needed pad characters before first digit + while (--width > 0) + putch(padc, putdat); + } + + // then print this (the least significant) digit + putch("0123456789abcdef"[num % base], putdat); +} + +// Get an unsigned int of various possible sizes from a varargs list, +// depending on the lflag parameter. +static unsigned long long +getuint(va_list *ap, int lflag) +{ + if (lflag >= 2) + return va_arg(*ap, unsigned long long); + else if (lflag) + return va_arg(*ap, unsigned long); + else + return va_arg(*ap, unsigned int); +} + +// Same as getuint but signed - can't use getuint +// because of sign extension +static long long +getint(va_list *ap, int lflag) +{ + if (lflag >= 2) + return va_arg(*ap, long long); + else if (lflag) + return va_arg(*ap, long); + else + return va_arg(*ap, int); +} + + +// Main function to format and print a string. +void printfmt(void (*putch)(int, void*), void *putdat, const char *fmt, ...); + +void +vprintfmt(void (*putch)(int, void*), void *putdat, const char *fmt, va_list ap) +{ + register const char *p; + register int ch, err; + unsigned long long num; + int base, lflag, width, precision, altflag; + char padc; + + while (1) { + while ((ch = *(unsigned char*)fmt++) != '%') { + if (ch == '\0') + return; + putch(ch, putdat); + } + + // Process a %-escape sequence + padc = ' '; + width = -1; + precision = -1; + lflag = 0; + altflag = 0; +reswitch: + switch (ch = *(unsigned char*)fmt++) { + + // flag to pad on the right + case '-': + padc = '-'; + goto reswitch; + + // flag to pad with 0's instead of spaces + case '0': + padc = '0'; + goto reswitch; + + // width field + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + for (precision = 0;; ++fmt) { + precision = precision * 10 + ch - '0'; + ch = *fmt; + if (ch < '0' || ch > '9') + break; + } + goto process_precision; + + case '*': + precision = va_arg(ap, int); + goto process_precision; + + case '.': + if (width < 0) + width = 0; + goto reswitch; + + case '#': + altflag = 1; + goto reswitch; + +process_precision: + if (width < 0) + width = precision, precision = -1; + goto reswitch; + + // long flag (doubled for long long) + case 'l': + lflag++; + goto reswitch; + + // character + case 'c': + putch(va_arg(ap, int), putdat); + break; + + // error message + case 'e': + err = va_arg(ap, int); + if (err < 0) + err = -err; + if (err >= MAXERROR || (p = error_string[err]) == NULL) + printfmt(putch, putdat, "error %d", err); + else + printfmt(putch, putdat, "%s", p); + break; + + // string + case 's': + if ((p = va_arg(ap, char *)) == NULL) + p = "(null)"; + if (width > 0 && padc != '-') + for (width -= strnlen(p, precision); width > 0; width--) + putch(padc, putdat); + for (; (ch = *p++) != '\0' && (precision < 0 || --precision >= 0); width--) + if (altflag && (ch < ' ' || ch > '~')) + putch('?', putdat); + else + putch(ch, putdat); + for (; width > 0; width--) + putch(' ', putdat); + break; + + // (signed) decimal + case 'd': + num = getint(&ap, lflag); + if ((long long)num < 0) { + putch('-', putdat); + num = -(long long)num; + } + base = 10; + goto number; + + // unsigned decimal + case 'u': + num = getuint(&ap, lflag); + base = 10; + goto number; + + // (unsigned) octal + case 'o': + // Replace this with your code + putch('X', putdat); + putch('X', putdat); + putch('X', putdat); + break; + + // pointer + case 'p': + putch('0', putdat); + putch('x', putdat); + num = (unsigned long long) + (uint)va_arg(ap, void *); + base = 16; + goto number; + + // (unsigned) hexadecimal + case 'x': + num = getuint(&ap, lflag); + base = 16; +number: + printnum(putch, putdat, num, base, width, padc); + break; + + // escaped '%' character + case '%': + putch(ch, putdat); + break; + + // unrecognized escape sequence - just print it literally + default: + putch('%', putdat); + for (fmt--; fmt[-1] != '%'; fmt--) + /* do nothing */; + break; + } + } +} + +void +printfmt(void (*putch)(int, void*), void *putdat, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vprintfmt(putch, putdat, fmt, ap); + va_end(ap); +} + +struct sprintbuf { + char *buf; + char *ebuf; + int cnt; +}; + +static void +sprintputch(int ch, struct sprintbuf *b) +{ + b->cnt++; + if (b->buf < b->ebuf) + *b->buf++ = ch; +} + +int +vsnprintf(char *buf, int n, const char *fmt, va_list ap) +{ + struct sprintbuf b = { buf, buf+n-1, 0 }; + + if (buf == NULL || n < 1) + return -E_INVAL; + + // print the string to the buffer + vprintfmt((void*)sprintputch, &b, fmt, ap); + + // null terminate the buffer + *b.buf = '\0'; + + return b.cnt; +} + +int +snprintf(char *buf, int n, const char *fmt, ...) +{ + va_list ap; + int rc; + + va_start(ap, fmt); + rc = vsnprintf(buf, n, fmt, ap); + va_end(ap); + + return rc; +} + + diff --git a/kernel/src/proc.c b/kernel/src/proc.c index 90f286b..c140f40 100644 --- a/kernel/src/proc.c +++ b/kernel/src/proc.c @@ -7,6 +7,7 @@ #include "proc.h" #include "spinlock.h" #include "string.h" +#include "stdio.h" struct { struct spinlock lock; diff --git a/kernel/src/string.c b/kernel/src/string.c index 3446c12..a399304 100644 --- a/kernel/src/string.c +++ b/kernel/src/string.c @@ -1,5 +1,5 @@ -#include "asm/x86.h" #include "types.h" +#include "asm/x86.h" void* memset(void *dst, int c, uint n) @@ -78,6 +78,18 @@ strncpy(char *s, const char *t, int n) return os; } + int + strnlen(const char *s, uint size) + { + int n; + + for (n = 0; size > 0 && *s != '\0'; s++, size--) + n++; + return n; + } + + + // Like strncpy but guaranteed to NUL-terminate. char* safestrcpy(char *s, const char *t, int n) @@ -103,17 +115,32 @@ strlen(const char *s) return n; } -// Return a pointer to the first occurrence of 'c' in 's', -// or a pointer to the string-ending null character if the string has no 'c'. -char * -strfind(const char *s, char c) + +int +strcmp(const char *p, const char *q) { - for (; *s; s++) - { - if (*s == c) - { - break; - } - } - return (char*)s; + while(*p && *p == *q) + p++, q++; + return (uchar)*p - (uchar)*q; } + +char* +strchr(const char *s, char c) +{ + for(; *s; s++) + if(*s == c) + return (char*)s; + return 0; +} + +// Return a pointer to the first occurrence of 'c' in 's', + // or a pointer to the string-ending null character if the string has no 'c'. + char * + strfind(const char *s, char c) + { + for (; *s; s++) + if (*s == c) + break; + return (char*)s; + } + diff --git a/kernel/src/syscall.c b/kernel/src/syscall.c index 59ba22f..8be3959 100644 --- a/kernel/src/syscall.c +++ b/kernel/src/syscall.c @@ -6,6 +6,7 @@ #include "mmu.h" #include "proc.h" #include "syscall.h" +#include "stdio.h" // User code makes a system call with INT T_SYSCALL. // System call number in %eax. diff --git a/kernel/src/trap.c b/kernel/src/trap.c index 327e85d..8e2d9ba 100644 --- a/kernel/src/trap.c +++ b/kernel/src/trap.c @@ -6,6 +6,7 @@ #include "mmu.h" #include "proc.h" #include "traps.h" +#include "stdio.h" #include "spinlock.h" // Interrupt descriptor table (shared by all CPUs). diff --git a/kernel/src/uart.c b/kernel/src/uart.c index 90d262d..07d5306 100644 --- a/kernel/src/uart.c +++ b/kernel/src/uart.c @@ -60,7 +60,7 @@ uartputc(int c) outb(COM1+0, c); } -static int +int uartgetc(void) { if(!uart) diff --git a/kernel/src/vm.c b/kernel/src/vm.c index a78e8b3..fe01481 100644 --- a/kernel/src/vm.c +++ b/kernel/src/vm.c @@ -7,6 +7,7 @@ #include "proc.h" #include "elf.h" #include "string.h" +#include "stdio.h" extern char data[]; // defined by kernel.ld pde_t *kpgdir; // for use in scheduler()