From de76acd7c790f0f29582a49f2bf4510d0c8fc989 Mon Sep 17 00:00:00 2001 From: jbltx Date: Fri, 29 Nov 2019 22:50:11 -0500 Subject: [PATCH] Add kernel libc --- build/Makefile | 9 +- include/stdio.h | 9 +- include/string.h | 1 - src/kernel/k_libc/k_printf.c | 192 +++++++++++++++++++++++++++++++++++ src/kernel/k_libc/k_stdio.c | 8 ++ src/kernel/k_libc/k_stdio.h | 9 ++ src/kernel/k_libc/k_stdlib.c | 30 ++++++ src/kernel/k_libc/k_stdlib.h | 6 ++ src/kernel/k_libc/k_string.c | 11 ++ src/kernel/k_libc/k_string.h | 8 ++ src/libc/stdio.c | 6 +- src/libc/stdlib.c | 15 +-- src/libc/string.c | 25 +---- 13 files changed, 280 insertions(+), 49 deletions(-) create mode 100644 src/kernel/k_libc/k_printf.c create mode 100644 src/kernel/k_libc/k_stdio.c create mode 100644 src/kernel/k_libc/k_stdio.h create mode 100644 src/kernel/k_libc/k_stdlib.c create mode 100644 src/kernel/k_libc/k_stdlib.h create mode 100644 src/kernel/k_libc/k_string.c create mode 100644 src/kernel/k_libc/k_string.h diff --git a/build/Makefile b/build/Makefile index 5e632ac..30efdce 100644 --- a/build/Makefile +++ b/build/Makefile @@ -64,13 +64,16 @@ endif # FILES AND DIRS # ################## +rwildcard=$(foreach d,$(wildcard $(1:=/*)),$(call rwildcard,$d,$2) $(filter $(subst *,%,$2),$d)) + BUILD_DIR = . OBJ_DIR = $(BUILD_DIR)/obj SRC_DIR = ../src INCLUDE_DIR = $(BUILD_DIR)/../include +K_LIBC_DIR = $(SRC_DIR)/kernel/k_libc -KERNEL_C_FILES = $(wildcard $(SRC_DIR)/kernel/*.c) +KERNEL_C_FILES = $(call rwildcard, $(SRC_DIR)/kernel, *.c) LIBC_C_FILES = $(wildcard $(SRC_DIR)/libc/*.c) KERNEL_S_FILES = $(wildcard $(SRC_DIR)/$(ARCH)/*.S) @@ -97,11 +100,11 @@ clean: # Compile C files $(OBJ_DIR)/kernel/%_c.o: $(SRC_DIR)/kernel/%.c @mkdir -p $(@D) - $(CC) $(CFLAGS) -I$(INCLUDE_DIR) -c $< -o $@ + $(CC) $(CFLAGS) -I$(INCLUDE_DIR) -I$(K_LIBC_DIR) -c $< -o $@ $(OBJ_DIR)/libc/%_c.o: $(SRC_DIR)/libc/%.c @mkdir -p $(@D) - $(CC) $(CFLAGS) -I$(INCLUDE_DIR) -c $< -o $@ + $(CC) $(CFLAGS) -I$(INCLUDE_DIR) -I$(K_LIBC_DIR) -c $< -o $@ # Compile S files $(OBJ_DIR)/$(ARCH)/%_S.o: $(SRC_DIR)/$(ARCH)/%.S diff --git a/include/stdio.h b/include/stdio.h index 2443bd7..a6c9bc0 100644 --- a/include/stdio.h +++ b/include/stdio.h @@ -8,15 +8,10 @@ extern "C" { #endif -char getc(void); -void putc(char c); +char getchar(void); +void putcchar(char c); void puts(const char * s); -uint32_t strlen(char * s); -void strrev(char * s); -void itoa(int n, char * s); - - #ifdef __cplusplus } #endif diff --git a/include/string.h b/include/string.h index 38b6724..701f383 100644 --- a/include/string.h +++ b/include/string.h @@ -8,7 +8,6 @@ extern "C" { #endif uint32_t strlen(char * s); -void strrev(char * s); #ifdef __cplusplus } diff --git a/src/kernel/k_libc/k_printf.c b/src/kernel/k_libc/k_printf.c new file mode 100644 index 0000000..fa97901 --- /dev/null +++ b/src/kernel/k_libc/k_printf.c @@ -0,0 +1,192 @@ +/* + Copyright 2001-2019 Georges Menie + https://www.menie.org/georges/embedded/small_printf_source_code.html + stdarg version contributed by Christian Ettinger + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include "k_stdio.h" + +#include + +static void printchar(char **str, int c) +{ + if (str) { + **str = c; + ++(*str); + } + else (void)k_putchar(c); +} + +#define PAD_RIGHT 1 +#define PAD_ZERO 2 + +static int prints(char **out, const char *string, int width, int pad) +{ + register int pc = 0, padchar = ' '; + + if (width > 0) { + register int len = 0; + register const char *ptr; + for (ptr = string; *ptr; ++ptr) ++len; + if (len >= width) width = 0; + else width -= len; + if (pad & PAD_ZERO) padchar = '0'; + } + if (!(pad & PAD_RIGHT)) { + for ( ; width > 0; --width) { + printchar (out, padchar); + ++pc; + } + } + for ( ; *string ; ++string) { + printchar (out, *string); + ++pc; + } + for ( ; width > 0; --width) { + printchar (out, padchar); + ++pc; + } + + return pc; +} + +/* the following should be enough for 32 bit int */ +#define PRINT_BUF_LEN 12 + +static int printi(char **out, int i, int b, int sg, int width, int pad, int letbase) +{ + char print_buf[PRINT_BUF_LEN]; + register char *s; + register int t, neg = 0, pc = 0; + register unsigned int u = i; + + if (i == 0) { + print_buf[0] = '0'; + print_buf[1] = '\0'; + return prints (out, print_buf, width, pad); + } + + if (sg && b == 10 && i < 0) { + neg = 1; + u = -i; + } + + s = print_buf + PRINT_BUF_LEN-1; + *s = '\0'; + + while (u) { + t = u % b; + if( t >= 10 ) + t += letbase - '0' - 10; + *--s = t + '0'; + u /= b; + } + + if (neg) { + if( width && (pad & PAD_ZERO) ) { + printchar (out, '-'); + ++pc; + --width; + } + else { + *--s = '-'; + } + } + + return pc + prints (out, s, width, pad); +} + +static int print(char **out, const char *format, va_list args ) +{ + register int width, pad; + register int pc = 0; + char scr[2]; + + for (; *format != 0; ++format) { + if (*format == '%') { + ++format; + width = pad = 0; + if (*format == '\0') break; + if (*format == '%') goto out; + if (*format == '-') { + ++format; + pad = PAD_RIGHT; + } + while (*format == '0') { + ++format; + pad |= PAD_ZERO; + } + for ( ; *format >= '0' && *format <= '9'; ++format) { + width *= 10; + width += *format - '0'; + } + if( *format == 's' ) { + register char *s = (char *)va_arg( args, int ); + pc += prints (out, s?s:"(null)", width, pad); + continue; + } + if( *format == 'd' ) { + pc += printi (out, va_arg( args, int ), 10, 1, width, pad, 'a'); + continue; + } + if( *format == 'x' ) { + pc += printi (out, va_arg( args, int ), 16, 0, width, pad, 'a'); + continue; + } + if( *format == 'X' ) { + pc += printi (out, va_arg( args, int ), 16, 0, width, pad, 'A'); + continue; + } + if( *format == 'u' ) { + pc += printi (out, va_arg( args, int ), 10, 0, width, pad, 'a'); + continue; + } + if( *format == 'c' ) { + /* char are converted to int then pushed on the stack */ + scr[0] = (char)va_arg( args, int ); + scr[1] = '\0'; + pc += prints (out, scr, width, pad); + continue; + } + } + else { + out: + printchar (out, *format); + ++pc; + } + } + if (out) **out = '\0'; + va_end( args ); + return pc; +} + +int k_printf(const char *format, ...) +{ + va_list args; + + va_start( args, format ); + return print( 0, format, args ); +} + +int k_sprintf(char *out, const char *format, ...) +{ + va_list args; + + va_start( args, format ); + return print( &out, format, args ); +} diff --git a/src/kernel/k_libc/k_stdio.c b/src/kernel/k_libc/k_stdio.c new file mode 100644 index 0000000..0d1ab6a --- /dev/null +++ b/src/kernel/k_libc/k_stdio.c @@ -0,0 +1,8 @@ +#include "k_stdio.h" + +#include "../uart.h" + +void k_putchar(char c) +{ + uart_putc(c); +} \ No newline at end of file diff --git a/src/kernel/k_libc/k_stdio.h b/src/kernel/k_libc/k_stdio.h new file mode 100644 index 0000000..fcf6818 --- /dev/null +++ b/src/kernel/k_libc/k_stdio.h @@ -0,0 +1,9 @@ +#ifndef __K_STDIO_H__ +#define __K_STDIO_H__ + +void k_putchar(char c); + +int k_printf(const char *format, ...); +int k_sprintf(char *out, const char *format, ...); + +#endif // __K_STDIO_H__ \ No newline at end of file diff --git a/src/kernel/k_libc/k_stdlib.c b/src/kernel/k_libc/k_stdlib.c new file mode 100644 index 0000000..0921b40 --- /dev/null +++ b/src/kernel/k_libc/k_stdlib.c @@ -0,0 +1,30 @@ +#include "k_stdlib.h" +#include "k_string.h" + +static void strrev(char * s) +{ + uint32_t i, j; + char c; + + for (i = 0, j = k_strlen(s)-1; i 0); + if (sign < 0) + s[i++] = '-'; + s[i] = '\0'; + strrev(s); +} \ No newline at end of file diff --git a/src/kernel/k_libc/k_stdlib.h b/src/kernel/k_libc/k_stdlib.h new file mode 100644 index 0000000..787f832 --- /dev/null +++ b/src/kernel/k_libc/k_stdlib.h @@ -0,0 +1,6 @@ +#ifndef __K_STDLIB_H__ +#define __K_STDLIB_H__ + +void k_itoa(int n, char * s); + +#endif // __K_STDLIB_H__ \ No newline at end of file diff --git a/src/kernel/k_libc/k_string.c b/src/kernel/k_libc/k_string.c new file mode 100644 index 0000000..0da94b6 --- /dev/null +++ b/src/kernel/k_libc/k_string.c @@ -0,0 +1,11 @@ +#include "k_string.h" + +uint32_t k_strlen(char * s) +{ + uint32_t n = 0; + while (s[n] != '\0') + { + n++; + } + return n; +} \ No newline at end of file diff --git a/src/kernel/k_libc/k_string.h b/src/kernel/k_libc/k_string.h new file mode 100644 index 0000000..cfd8a44 --- /dev/null +++ b/src/kernel/k_libc/k_string.h @@ -0,0 +1,8 @@ +#ifndef __K_STRING_H__ +#define __K_STRING_H__ + +#include + +uint32_t k_strlen(char * s); + +#endif // __K_STRING_H__ \ No newline at end of file diff --git a/src/libc/stdio.c b/src/libc/stdio.c index a7d17a9..89328d5 100644 --- a/src/libc/stdio.c +++ b/src/libc/stdio.c @@ -3,16 +3,16 @@ /* For the moment standard IO uses UART methods ... */ #include "../kernel/uart.h" -char getc(void) { +char getchar(void) { return uart_getc(); } -void putc(char c) { +void putchar(char c) { uart_putc(c); } void puts(const char * str) { int i; for (i = 0; str[i] != '\0'; i ++) - putc(str[i]); + putchar(str[i]); } diff --git a/src/libc/stdlib.c b/src/libc/stdlib.c index 8a72c62..77de312 100644 --- a/src/libc/stdlib.c +++ b/src/libc/stdlib.c @@ -1,18 +1,7 @@ #include -#include +#include void itoa(int n, char * s) { - int i, sign; - - if ((sign = n) < 0) - n = -n; - i = 0; - do { - s[i++] = n % 10 + '0'; - } while ((n /= 10) > 0); - if (sign < 0) - s[i++] = '-'; - s[i] = '\0'; - strrev(s); + return k_itoa(n, s); } \ No newline at end of file diff --git a/src/libc/string.c b/src/libc/string.c index d0692cf..3d02794 100644 --- a/src/libc/string.c +++ b/src/libc/string.c @@ -1,26 +1,7 @@ #include - -#include +#include uint32_t strlen(char * s) { - uint32_t n = 0; - while (*s != '\0') - { - s++; - n++; - } - return n; -} - -void strrev(char * s) -{ - uint32_t i, j; - char c; - - for (i = 0, j = strlen(s)-1; i