From bea3449b11c5aa4b31aac5b367245ec937ffa6da Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Sun, 24 Jan 2021 23:51:21 +0100 Subject: [PATCH] Implement vsnprintf and use it --- arch/x86/exception_handler.c | 7 +- arch/x86/irq_handler.c | 2 +- core/klibc.c | 229 ++++++++++++++++++++++++----------- core/klibc.h | 1 + core/main.c | 2 +- drivers/vga.c | 71 +++++------ drivers/vga.h | 4 +- tests/test.c | 8 ++ 8 files changed, 203 insertions(+), 121 deletions(-) diff --git a/arch/x86/exception_handler.c b/arch/x86/exception_handler.c index d22b12d..0414fcd 100644 --- a/arch/x86/exception_handler.c +++ b/arch/x86/exception_handler.c @@ -11,9 +11,7 @@ ulong error_code) \ { \ int intNbInt = int_nb; \ - printStringDetails("EXCEPTION ", RED, BLACK, 0, VGA_HEIGHT - 1); \ - printIntDetails(intNbInt, RED, BLACK, 11, VGA_HEIGHT - 1); \ - printIntDetails(error_code, RED, BLACK, 14, VGA_HEIGHT - 1); \ + VGAprintf(RED, BLACK, 0, VGA_HEIGHT - 1, "EXCEPTION %d %d", intNbInt, error_code); \ printf("Exception %d (Err %d) at 0x%x\n", int_nb, error_code, frame->eip); \ asm("hlt"); \ } @@ -64,8 +62,7 @@ __attribute__((interrupt)) void pagefault_handler(struct interrupt_frame *frame, struct kthread *current = getCurrentThread(); printf("page fault while in thread %s\n", current->name); - printStringDetails("PAGE FAULT", RED, BLACK, 0, VGA_HEIGHT - 1); - printIntDetails(error_code, RED, BLACK, 11, VGA_HEIGHT - 1); + VGAprintf(RED, BLACK, 0, VGA_HEIGHT - 1, "PAGE FAULT %d", error_code); (void)faulting_address; (void)frame; (void)error_code; diff --git a/arch/x86/irq_handler.c b/arch/x86/irq_handler.c index aa242d0..ca8c0b4 100644 --- a/arch/x86/irq_handler.c +++ b/arch/x86/irq_handler.c @@ -18,7 +18,7 @@ __attribute__((interrupt)) void timer_handler(struct interrupt_frame *frame) { static int timeCnt = 0; EOIIrq(IRQ_TIMER); - printIntDetails(timeCnt++, RED, BLACK, 20, VGA_HEIGHT - 1); + VGAprintf(RED, BLACK, 20, VGA_HEIGHT - 1, "IRQ %d", timeCnt++); (void)frame; } diff --git a/core/klibc.c b/core/klibc.c index c229352..ffd2bc2 100644 --- a/core/klibc.c +++ b/core/klibc.c @@ -156,95 +156,133 @@ int putc(const char c) return (unsigned char)c; } -int printInt64(long long int integer) +// int max is 2^(sizeof(int)*8) which is (2^3)^(sizeof(int)*8/3) +// = 8^(sizeof(int)*8/3) ~ 10^(sizeof(int)*8/3) +#define PRINT_INT(name, type) \ + int print##name(type integer, char *str, size_t size) \ + { \ + char num[sizeof(integer) * 3]; \ + int i = 0; \ + int c = 0; \ + int ret = 0; \ + \ + if (integer < 0) { \ + if (str) { \ + if (size) { \ + str[c++] = '-'; \ + size--; \ + ret++; \ + } else { \ + return ret; \ + } \ + } else { \ + ret++; \ + } \ + } \ + \ + do { \ + int digit = integer % 10; \ + num[i++] = (digit > 0) ? digit : -digit; \ + integer = integer / 10; \ + } while (integer != 0); \ + \ + for (i = i - 1; i >= 0; i--) { \ + if (str) { \ + if (size) { \ + str[c++] = num[i] + '0'; \ + size--; \ + ret++; \ + } else { \ + return ret; \ + } \ + } else { \ + ret++; \ + } \ + } \ + return ret; \ + } + +PRINT_INT(Int, int); +PRINT_INT(Int64, long long int); + +int vsnprintf(char *str, size_t size, const char *format, va_list ap) { - char num[sizeof(integer) * - 3]; // int max is 2^(sizeof(int)*8) which is (2^3)^(sizeof(int)*8/3) - // = 8^(sizeof(int)*8/3) ~ 10^(sizeof(int)*8/3) - int i = 0; int ret = 0; - - if (integer < 0) { - putc('-'); - ret++; - } - - do { - int digit = integer % 10; - num[i++] = (digit > 0) ? digit : -digit; - integer = integer / 10; - } while (integer != 0); - - for (i = i - 1; i >= 0; i--) { - putc(num[i] + '0'); - ret++; - } - return ret; -} - -int printInt(int integer) -{ - char num[sizeof(integer) * - 3]; // int max is 2^(sizeof(int)*8) which is (2^3)^(sizeof(int)*8/3) - // = 8^(sizeof(int)*8/3) ~ 10^(sizeof(int)*8/3) int i = 0; - int ret = 0; + int c = 0; - if (integer < 0) { - putc('-'); - ret++; - } - - do { - int digit = integer % 10; - num[i++] = (digit > 0) ? digit : -digit; - integer = integer / 10; - } while (integer != 0); - - for (i = i - 1; i >= 0; i--) { - putc(num[i] + '0'); - ret++; - } - return ret; -} - -int vprintf(const char *format, va_list ap) -{ - int i = 0; - int ret = 0; - while (format[i] != '\0') { + while (format[i] != '\0' && size) { switch (format[i]) { case '%': switch (format[i + 1]) { case 'i': case 'd': { + int s; int d = va_arg(ap, int); - ret += printInt(d); + if (str) + s = printInt(d, &str[c], size); + else + s = printInt(d, NULL, size); + + size -= s; + c += s; + ret += s; break; } case 'p': case 'x': { char val[sizeof(int) * 2]; - int d = va_arg(ap, int); + unsigned int valIdx = 0; + int d = va_arg(ap, int); itoa(d, val, 16); - ret += puts(val); + if (str) { + while (val[valIdx]) { + if (size) { + str[c++] = val[valIdx++]; + size--; + ret++; + } else { + return ret; + } + } + } else { + ret += strlen(val); + } break; } case 'c': { - int c = va_arg(ap, int); - putc((char)c); + if (str) { + int ch = va_arg(ap, int); + str[c++] = ch; + size--; + } ret++; break; } case 's': { - char *str = va_arg(ap, char *); - if (!str) - str = "[NULL STR]"; - ret += puts(str); + char *stri = va_arg(ap, char *); + if (!stri) + stri = "[NULL STR]"; + if (str) { + while (*stri) { + if (size) { + str[c++] = *(stri++); + size--; + ret++; + } else { + return ret; + } + } + } else { + ret += strlen(stri); + } break; } case '%': - putc('%'); + if (str) { + str[c++] = '%'; + size--; + } ret++; break; case 'l': @@ -252,16 +290,37 @@ int vprintf(const char *format, va_list ap) case 'l': switch (format[i + 3]) { case 'd': { + int s; long long int d = va_arg(ap, long long int); - ret += printInt64(d); + if (str) + s = printInt64(d, &str[c], size); + else + s = printInt64(d, NULL, size); + + size -= s; + c += s; + ret += s; break; } case 'p': case 'x': { char val[sizeof(long long int) * 2]; - long long int d = va_arg(ap, long long int); + unsigned int valIdx = 0; + long long int d = va_arg(ap, long long int); itoa(d, val, 16); - ret += puts(val); + if (str) { + while (val[valIdx]) { + if (size) { + str[c++] = val[valIdx++]; + size--; + ret++; + } else { + return ret; + } + } + } else { + ret += strlen(val); + } break; } } @@ -269,8 +328,16 @@ int vprintf(const char *format, va_list ap) break; case 'i': case 'd': { + int s; long int d = va_arg(ap, long int); - ret += printInt64(d); + if (str) + s = printInt64(d, &str[c], size); + else + s = printInt64(d, NULL, size); + + size -= s; + c += s; + ret += s; break; } } @@ -281,10 +348,36 @@ int vprintf(const char *format, va_list ap) break; default: - putc(format[i]); + if (str) { + str[c++] = format[i]; + size--; + } ret++; } i++; } + + if (str) { + if (size) { + str[c++] = '\0'; + size--; + } else { + if (c > 0) { + str[c - 1] = '\0'; + } + } + } + + return ret; +} + +int vprintf(const char *fmt, va_list ap) +{ + char tmp[256]; + int idx = 0; + int ret = vsnprintf(tmp, sizeof(tmp), fmt, ap); + while (ret > 0 && tmp[idx]) { + putc(tmp[idx++]); + } return ret; } diff --git a/core/klibc.h b/core/klibc.h index f3b4e06..913ba91 100644 --- a/core/klibc.h +++ b/core/klibc.h @@ -21,6 +21,7 @@ int strcmp(const char s1[], const char s2[]); char *strzcpy(char *dst, const char *src, int len); int puts(const char *str); int putc(const char str); +int vsnprintf(char *str, size_t size, const char *format, va_list ap); int vprintf(const char *format, va_list ap); int printf(const char *format, ...); diff --git a/core/main.c b/core/main.c index 4f4336f..4974925 100644 --- a/core/main.c +++ b/core/main.c @@ -27,7 +27,7 @@ void idleThread(void *arg) { (void)arg; while (1) { - printIntDetails((jiffies / HZ), GREEN, BLACK, 0, VGA_HEIGHT - 1); + VGAprintf(GREEN, BLACK, 0, VGA_HEIGHT - 1, "%d", (jiffies / HZ)); kthreadYield(); } } diff --git a/drivers/vga.c b/drivers/vga.c index 1558316..6cd950d 100644 --- a/drivers/vga.c +++ b/drivers/vga.c @@ -1,26 +1,28 @@ #include "vga.h" #include "io.h" -#include "klibc.h" #include "irq.h" +#include "klibc.h" static uint vgaBgColor; static uint vgaColor; static int line, col; +static volatile short *vga = (short *)VGA_ADDR; +static void clearScreen(uint bgColor); + int VGASetup(uint bgColor, uint color) { vgaBgColor = bgColor; vgaColor = color; + line = 0; + col = 0; clearScreen(bgColor); - line = 0; - col = 0; return 0; } -void clearScreen(uint bgColor) +static void clearScreen(uint bgColor) { uint32_t flags; - volatile short *vga = (short *)VGA_ADDR; long int colorAttr = bgColor << 12; disable_IRQs(flags); @@ -33,9 +35,11 @@ void clearScreen(uint bgColor) void clearScreenLine(uint bgColor, uint line) { uint32_t flags; - volatile short *vga = (short *)VGA_ADDR; long int colorAttr = bgColor << 12; + if (line >= VGA_HEIGHT) + return; + disable_IRQs(flags); for (uint i = VGA_WIDTH * line; i < VGA_WIDTH * (line + 1); i++) { vga[i] = colorAttr; @@ -43,31 +47,29 @@ void clearScreenLine(uint bgColor, uint line) restore_IRQs(flags); } -void printIntDetails(int integer, uint color, uint bgColor, int startX, int startY) +void VGAprintf(uint color, uint bgColor, int startX, int startY, const char *format, ...) { - char num[sizeof(int) * 3]; // int max is 2^(sizeof(int)*8) which is (2^3)^(sizeof(int)*8/3) - // = 8^(sizeof(int)*8/3) ~ 10^(sizeof(int)*8/3) - int x = startX; - int i = 0, k = 0; - if (integer < 0) { - printCharDetails('-', color, bgColor, x++, startY); - } - if (integer == 0) { - num[i++] = 0; - } - while (integer != 0) { - int digit = integer % 10; - num[i++] = (digit > 0) ? digit : -digit; - integer = integer / 10; - } - for (k = i - 1; k >= 0; k--) { - printCharDetails(num[k] + '0', color, bgColor, x++, startY); + int flags; + char tmp[VGA_WIDTH]; + int idx = 0; + + disable_IRQs(flags); + + va_list ap; + va_start(ap, format); + + int ret = vsnprintf(tmp, sizeof(tmp), format, ap); + while (ret > 0 && tmp[idx]) { + printCharDetails(tmp[idx++], color, bgColor, startX++, startY); } + va_end(ap); + + + restore_IRQs(flags); } void printCharDetails(const char str, uint color, uint bgColor, int startX, int startY) { - volatile short *vga = (short *)VGA_ADDR; long int colorAttr = (bgColor << 4 | (color & 0x0f)) << 8; vga[VGA_WIDTH * startY + startX] = colorAttr | str; } @@ -75,7 +77,6 @@ void printCharDetails(const char str, uint color, uint bgColor, int startX, int void vgaScrollUp(void) { long int colorAttr = vgaBgColor << 12; - volatile short *vga = (short *)VGA_ADDR; int flags; disable_IRQs(flags); @@ -121,26 +122,11 @@ void VGAputc(const char str) line--; } } + cursorMove(col, line); restore_IRQs(flags); } -void printStringDetails(const char *str, uint color, uint bgColor, int startX, int startY) -{ - uint32_t flags; - volatile short *vga = (short *)VGA_ADDR; - int i = 0; - long int colorAttr = (bgColor << 4 | (color & 0x0f)) << 8; - - disable_IRQs(flags); - while (*str) { - vga[VGA_WIDTH * startY + startX + i] = colorAttr | *str; - str++; - i++; - } - restore_IRQs(flags); -} - void cursorEnable(uint8_t cursor_start, uint8_t cursor_end) { outb(0x3D4, 0x0A); @@ -158,7 +144,6 @@ void cursorDisable(void) void cursorMove(int x, int y) { - volatile short *vga = (short *)VGA_ADDR; long int colorAttr = (vgaBgColor << 4 | (vgaColor & 0x0f)) << 8; uint16_t pos = y * VGA_WIDTH + x; vga[pos] = colorAttr; diff --git a/drivers/vga.h b/drivers/vga.h index 7bc6d8d..a861b3c 100644 --- a/drivers/vga.h +++ b/drivers/vga.h @@ -19,11 +19,9 @@ int VGASetup(uint bgColor, uint color); void VGAputc(const char str); -void clearScreen(uint bgColor); +void VGAprintf(uint color, uint bgColor, int startX, int startY, const char *format, ...); void clearScreenLine(uint bgColor, uint line); -void printIntDetails(int integer, uint color, uint bgColor, int startX, int startY); void printCharDetails(char str, uint color, uint bgColor, int startX, int startY); -void printStringDetails(const char *str, uint color, uint bgColor, int startX, int startY); void vgaScrollUp(void); void cursorEnable(uint8_t cursor_start, uint8_t cursor_end); void cursorDisable(void); diff --git a/tests/test.c b/tests/test.c index a4e610b..6b4637a 100644 --- a/tests/test.c +++ b/tests/test.c @@ -312,6 +312,14 @@ void testKthread() void run_test(void) { + int test = 1000; + long long int test64 = 0x100000000; + assert(printf("hello") == 5); + assert(printf("hello\n") == 6); + assert(printf("hello %d\n", test) == 11); + assert(printf("hello %llx\n", test64) == 16); + assert(printf("hello %c\n", 'a') == 8); + assert(printf("hello %s\n", "world") == 12); testPaging(); printf("Testing Serial\n"); serialPutc('h');