From 61ba39a23786a7ae9694705af1d146c00a319144 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Sat, 5 Feb 2011 04:35:27 +0100 Subject: Getting rid of newlib, starting to implement a libc. Highly experimental, highly untested. --- FreeRTOS/Makefile | 1 + LICENSE.blurb.txt | 3 + Makefile | 15 +- arch/Makefile | 2 + arch/arm/lpc17xx/ldscript | 2 +- arch/arm/lpc17xx/setjmp.s | 33 ++ arch/arm/lpc17xx/specs | 184 ++++++++++ arch/arm/lpc17xx/startup.s | 4 +- arch/config.mk | 1 + config/general.mk | 1 + libc/LIB.status | 190 ++++++++++ libc/Makefile | 34 ++ libc/config.mk | 1 + libc/include/ctype.h | 20 + libc/include/errno.h | 140 +++++++ libc/include/malloc.h | 18 + libc/include/math.h | 4 + libc/include/reent.h | 16 + libc/include/setjmp.h | 13 + libc/include/stdio.h | 153 ++++++++ libc/include/stdlib.h | 12 + libc/include/string.h | 97 +++++ libc/include/unistd.h | 31 ++ libc/src/close.c | 12 + libc/src/exit.c | 65 ++++ libc/src/lseek.c | 24 ++ libc/src/malloc.c | 198 ++++++++++ libc/src/open.c | 17 + libc/src/read.c | 21 ++ libc/src/reent.c | 8 + libc/src/stdio.c | 9 + libc/src/write.c | 21 ++ libc/src/xprintf.c | 890 +++++++++++++++++++++++++++++++++++++++++++++ os/Makefile | 19 +- os/src/close.c | 14 - os/src/fclose.c | 8 - os/src/fflush.c | 7 - os/src/fio.c | 2 + os/src/fopen.c | 8 - os/src/fprintf.c | 14 - os/src/fread.c | 7 - os/src/free.c | 8 - os/src/fstat.c | 27 -- os/src/fwrite.c | 7 - os/src/init.c | 9 + os/src/isatty.c | 15 - os/src/lseek.c | 27 -- os/src/malloc.c | 23 -- os/src/open.c | 17 - os/src/printf.c | 14 - os/src/read.c | 24 -- os/src/romfs.c | 2 + os/src/sbrk.c | 21 +- os/src/semifs.c | 2 + os/src/sprintf.c | 14 - os/src/write.c | 24 -- target-rules.mk | 4 +- 57 files changed, 2254 insertions(+), 303 deletions(-) create mode 100644 arch/arm/lpc17xx/setjmp.s create mode 100644 arch/arm/lpc17xx/specs create mode 100644 libc/LIB.status create mode 100644 libc/Makefile create mode 100644 libc/config.mk create mode 100644 libc/include/ctype.h create mode 100644 libc/include/errno.h create mode 100644 libc/include/malloc.h create mode 100644 libc/include/math.h create mode 100644 libc/include/reent.h create mode 100644 libc/include/setjmp.h create mode 100644 libc/include/stdio.h create mode 100644 libc/include/stdlib.h create mode 100644 libc/include/string.h create mode 100644 libc/include/unistd.h create mode 100644 libc/src/close.c create mode 100644 libc/src/exit.c create mode 100644 libc/src/lseek.c create mode 100644 libc/src/malloc.c create mode 100644 libc/src/open.c create mode 100644 libc/src/read.c create mode 100644 libc/src/reent.c create mode 100644 libc/src/stdio.c create mode 100644 libc/src/write.c create mode 100644 libc/src/xprintf.c delete mode 100644 os/src/close.c delete mode 100644 os/src/fclose.c delete mode 100644 os/src/fflush.c delete mode 100644 os/src/fopen.c delete mode 100644 os/src/fprintf.c delete mode 100644 os/src/fread.c delete mode 100644 os/src/free.c delete mode 100644 os/src/fstat.c delete mode 100644 os/src/fwrite.c delete mode 100644 os/src/isatty.c delete mode 100644 os/src/lseek.c delete mode 100644 os/src/malloc.c delete mode 100644 os/src/open.c delete mode 100644 os/src/printf.c delete mode 100644 os/src/read.c delete mode 100644 os/src/sprintf.c delete mode 100644 os/src/write.c diff --git a/FreeRTOS/Makefile b/FreeRTOS/Makefile index 7c8149d..3da061d 100644 --- a/FreeRTOS/Makefile +++ b/FreeRTOS/Makefile @@ -6,6 +6,7 @@ include $(ROOTDIR)/common.mk include config.mk include $(ROOTDIR)/arch/config.mk include $(ROOTDIR)/os/config.mk +include $(ROOTDIR)/libc/config.mk TARGET_SRCS = Source/croutine.c Source/list.c Source/queue.c Source/tasks.c diff --git a/LICENSE.blurb.txt b/LICENSE.blurb.txt index db1c648..4840765 100644 --- a/LICENSE.blurb.txt +++ b/LICENSE.blurb.txt @@ -4,3 +4,6 @@ sure: you are allowed to use this project for free, in any commercial product, without tainting your commercial code's license in any way. However, you need to mention that this project is part of your product, and if you change the source code, you need to distribute the changes. + +TLDR: this is a non-reciprocal open source license, but you still have to +mention the fact you're using this project. diff --git a/Makefile b/Makefile index fa411dd..800541a 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ TARGET = demo.bin -LIBDEPS = FreeRTOS/libFreeRTOS.a arch/libarch.a os/libos.a -LIBS = -Wl,--start-group -lc $(LIBDEPS) -Wl,--end-group +LIBDEPS = FreeRTOS/libFreeRTOS.a arch/libarch.a os/libos.a libc/libc.a +LIBS = -Wl,--start-group $(LIBDEPS) -Wl,--end-group TARGET_SRCS = test-romfs.o @@ -14,16 +14,18 @@ clean: clean-generic $(Q)$(MAKE) $(MAKE_OPTS) -C FreeRTOS clean $(Q)$(MAKE) $(MAKE_OPTS) -C arch clean $(Q)$(MAKE) $(MAKE_OPTS) -C os clean + $(Q)$(MAKE) $(MAKE_OPTS) -C libc clean $(Q)$(MAKE) $(MAKE_OPTS) -C tools clean $(Q)rm -f test-romfs.bin -.PHONY: libs FreeRTOS arch os tools +.PHONY: libs FreeRTOS arch os libc tools FreeRTOS/libFreeRTOS.a: FreeRTOS arch/libarch.a: arch os/libos.a: os +libc/libc.a: libc -libs: FreeRTOS arch os +libs: FreeRTOS arch os libc FreeRTOS: $(E) "[MAKE] Entering FreeRTOS" @@ -37,6 +39,10 @@ os: $(E) "[MAKE] Entering os" $(Q)$(MAKE) $(MAKE_OPTS) -C os +libc: + $(E) "[MAKE] Entering libc" + $(Q)$(MAKE) $(MAKE_OPTS) -C libc + tools: $(E) "[MAKE] Entering tools" $(Q)$(MAKE) $(MAKE_OPTS) -C tools @@ -50,4 +56,5 @@ test-romfs.o: tools/mkromfs include FreeRTOS/config.mk include arch/config.mk include os/config.mk +include libc/config.mk include target-rules.mk diff --git a/arch/Makefile b/arch/Makefile index e8fcf20..e32a3ab 100644 --- a/arch/Makefile +++ b/arch/Makefile @@ -6,6 +6,7 @@ include $(ROOTDIR)/common.mk include config.mk include $(ROOTDIR)/FreeRTOS/config.mk include $(ROOTDIR)/os/config.mk +include $(ROOTDIR)/libc/config.mk ifeq ($(CPU),arm) TARGET_SRCS += arm/src/angel.s @@ -13,6 +14,7 @@ ifeq ($(CPU_FLAVOR),lpc1768) TARGET_SRCS += arm/lpc17xx/Core/CM3/DeviceSupport/NXP/LPC17xx/system_LPC17xx.c arm/lpc17xx/Core/CM3/CoreSupport/core_cm3.c TARGET_SRCS += $(addprefix arm/lpc17xx/Drivers/source/lpc17xx_, spi.c rit.c exti.c wdt.c uart.c dac.c rtc.c i2s.c pwm.c mcpwm.c pinsel.c nvic.c emac.c systick.c ssp.c can.c gpio.c libcfg_default.c i2c.c timer.c gpdma.c clkpwr.c qei.c adc.c) TARGET_SRCS += arm/lpc17xx/startup.s arm/lpc17xx/deinit-all.c arm/lpc17xx/handlers.c arm/lpc17xx/Drivers/source/debug_frmwrk.c arm/lpc17xx/mbed/BoardConsole.c arm/lpc17xx/mbed/BoardInit.c +TARGET_SRCS += arm/lpc17xx/setjmp.s endif endif diff --git a/arch/arm/lpc17xx/ldscript b/arch/arm/lpc17xx/ldscript index b8ca0b7..3962f02 100644 --- a/arch/arm/lpc17xx/ldscript +++ b/arch/arm/lpc17xx/ldscript @@ -18,7 +18,7 @@ OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") /*ENTRY(_start)*/ SEARCH_DIR(.) -GROUP(-lgcc -lc) +GROUP(-lgcc) MEMORY { diff --git a/arch/arm/lpc17xx/setjmp.s b/arch/arm/lpc17xx/setjmp.s new file mode 100644 index 0000000..9ffffc2 --- /dev/null +++ b/arch/arm/lpc17xx/setjmp.s @@ -0,0 +1,33 @@ +.cpu cortex-m3 +.syntax unified + +.section ".text.setjmp","x",%progbits +.align 2 +.thumb +.thumb_func +.globl setjmp +.type setjmp, %function +setjmp: +.fnstart + mov ip, sp + stmea a1!, {v1-v7, fp, ip, lr} + mov a1, #0 + bx lr +.fnend +.size setjmp,.-setjmp + +.section ".text.longjmp","x",%progbits +.align 2 +.thumb +.thumb_func +.globl longjmp +.type longjmp, %function +longjmp: +.fnstart + ldmfd a1!, {v1-v7, fp, ip, lr} + mov sp, ip + movs a1, a2 + it eq + moveq a1, #1 +.fnend +.size longjmp,.-longjmp diff --git a/arch/arm/lpc17xx/specs b/arch/arm/lpc17xx/specs new file mode 100644 index 0000000..1435a6b --- /dev/null +++ b/arch/arm/lpc17xx/specs @@ -0,0 +1,184 @@ +*asm: +%{mbig-endian:-EB} %{mlittle-endian:-EL} %{mcpu=*:-mcpu=%*} %{march=*:-march=%*} %{mapcs-*:-mapcs-%*} %(subtarget_asm_float_spec) %{mthumb-interwork:-mthumb-interwork} %{msoft-float:-mfloat-abi=soft} %{mhard-float:-mfloat-abi=hard} %{mfloat-abi=*} %{mfpu=*} %(subtarget_extra_asm_spec) + +*asm_debug: +%{!g0:%{gstabs*:--gstabs}%{!gstabs*:%{g*:--gdwarf2}}} %{fdebug-prefix-map=*:--debug-prefix-map %*} + +*asm_final: + + +*asm_options: +%{--target-help:%:print-asm-header()} %{v} %{w:-W} %{I*} %a %Y %{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O} + +*invoke_as: +%{!fwpa: %{fcompare-debug=*|fdump-final-insns=*:%:compare-debug-dump-opt()} %{!S:-o %|.s | + as %(asm_options) %m.s %A } } + +*cpp: +%(subtarget_cpp_spec) %{msoft-float:%{mhard-float: %e-msoft-float and -mhard_float may not be used together}} %{mbig-endian:%{mlittle-endian: %e-mbig-endian and -mlittle-endian may not be used together}} + +*cpp_options: +%(cpp_unique_options) %1 %{m*} %{std*&ansi&trigraphs} %{W*&pedantic*} %{w} %{f*} %{g*:%{!g0:%{g*} %{!fno-working-directory:-fworking-directory}}} %{O*} %{undef} %{save-temps*:-fpch-preprocess} + +*cpp_debug_options: +%{d*} + +*cpp_unique_options: +%{C|CC:%{!E:%eGCC does not support -C or -CC without -E}} %{!Q:-quiet} %{nostdinc*} %{C} %{CC} %{v} %{I*&F*} %{P} %I %{MD:-MD %{!o:%b.d}%{o*:%.d%*}} %{MMD:-MMD %{!o:%b.d}%{o*:%.d%*}} %{M} %{MM} %{MF*} %{MG} %{MP} %{MQ*} %{MT*} %{!E:%{!M:%{!MM:%{!MT:%{!MQ:%{MD|MMD:%{o*:-MQ %*}}}}}}} %{remap} %{g3|ggdb3|gstabs3|gcoff3|gxcoff3|gvms3:-dD} %{H} %C %{D*&U*&A*} %{i*} %Z %i %{fmudflap:-D_MUDFLAP -include mf-runtime.h} %{fmudflapth:-D_MUDFLAP -D_MUDFLAPTH -include mf-runtime.h} %{E|M|MM:%W{o*}} + +*trad_capable_cpp: +cc1 -E %{traditional|ftraditional|traditional-cpp:-traditional-cpp} + +*cc1: +%{mandroid: %(cc1_android) ; : %(cc1_default)} + +*cc1_options: +%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}} %1 %{!Q:-quiet} %{!dumpbase:-dumpbase %B} %{d*} %{m*} %{a*} %{fcompare-debug-second:%:compare-debug-auxbase-opt(%b)} %{!fcompare-debug-second:%{c|S:%{o*:-auxbase-strip %*}%{!o*:-auxbase %b}}}%{!c:%{!S:-auxbase %b}} %{g*} %{O*} %{W*&pedantic*} %{w} %{std*&ansi&trigraphs} %{v:-version} %{pg:-p} %{p} %{f*} %{undef} %{Qn:-fno-ident} %{--help:--help} %{--target-help:--target-help} %{--help=*:--help=%(VALUE)} %{!fsyntax-only:%{S:%W{o*}%{!o*:-o %b.s}}} %{fsyntax-only:-o %j} %{-param*} %{fmudflap|fmudflapth:-fno-builtin -fno-merge-constants} %{coverage:-fprofile-arcs -ftest-coverage} + +*cc1plus: +%{mandroid: %(cc1plus_android) ; : %(cc1plus_default)} + +*link_gcc_c_sequence: +--start-group %G %L --end-group + +*link_ssp: +%{fstack-protector|fstack-protector-all:-lssp_nonshared -lssp} + +*endfile: +%{mandroid: %(endfile_android) ; : %(endfile_default)} + +*link: +%{mandroid: %(link_android) ; : %(link_default)} + +*lib: +%{mandroid: %(lib_android) ; : %(lib_default)} + +*mfwrap: + %{static: %{fmudflap|fmudflapth: --wrap=malloc --wrap=free --wrap=calloc --wrap=realloc --wrap=mmap --wrap=munmap --wrap=alloca} %{fmudflapth: --wrap=pthread_create}} %{fmudflap|fmudflapth: --wrap=main} + +*mflib: +%{fmudflap|fmudflapth: -export-dynamic} + +*link_gomp: + + +*libgcc: +-lgcc + +*startfile: +%{mandroid: %(startfile_android) ; : %(startfile_default)} + +*switches_need_spaces: +o + +*cross_compile: +1 + +*version: +4.5.2 + +*multilib: +. !marm !mthumb !mfloat-abi=hard;arm marm !mthumb !mfloat-abi=hard;thumb !marm mthumb !mfloat-abi=hard;fpu !marm !mthumb mfloat-abi=hard;arm/fpu marm !mthumb mfloat-abi=hard; + +*multilib_defaults: +marm mlittle-endian msoft-float mno-thumb-interwork fno-leading-underscore + +*multilib_extra: + + +*multilib_matches: +marm marm;mthumb mthumb;mfloat-abi=hard mfloat-abi=hard; + +*multilib_exclusions: + + +*multilib_options: +marm/mthumb mfloat-abi=hard + +*linker: +collect2 + +*linker_plugin_file: + + +*lto_wrapper: + + +*lto_gcc: + + +*lto_libgcc: + + +*link_libgcc: +%D + +*md_exec_prefix: + + +*md_startfile_prefix: + + +*md_startfile_prefix_1: + + +*startfile_prefix_spec: + + +*sysroot_spec: +--sysroot=%R + +*sysroot_suffix_spec: + + +*sysroot_hdrs_suffix_spec: + + +*subtarget_cpp_spec: +-D__USES_INITFINI__ + +*subtarget_extra_asm_spec: +%{mabi=apcs-gnu|mabi=atpcs:-meabi=gnu;:-meabi=5} %{mcpu=arm8|mcpu=arm810|mcpu=strongarm*|march=armv4:--fix-v4bx} + +*subtarget_asm_float_spec: +%{mapcs-float:-mfloat} + +*link_android: +%{mbig-endian:-EB} %{mlittle-endian:-EL} %{static:-Bstatic} %{shared:-shared} %{symbolic:-Bsymbolic} %{!static:%{shared: -Bsymbolic} %{!shared:%{rdynamic:-export-dynamic} %{!dynamic-linker:-dynamic-linker /system/bin/linker}}} -X + +*link_default: +%{mbig-endian:-EB} %{mlittle-endian:-EL} %{static:-Bstatic} %{shared:-shared} %{symbolic:-Bsymbolic} -X %{mcpu=arm8|mcpu=arm810|mcpu=strongarm*|march=armv4:--fix-v4bx} %{mbig-endian:%{march=armv7-a|mcpu=cortex-a5|mcpu=cortex-a8|mcpu=cortex-a9:%{!r:--be8}}} + +*cc1_android: +%{!fexceptions:-fno-exceptions} + +*cc1_default: + + +*cc1plus_android: +%{!frtti:-fno-rtti} + +*cc1plus_default: + + +*lib_android: +-lc %{!static:-ldl} + +*lib_default: +%{!shared:%{g*:} %{!p:%{!pg:}}%{p:}%{pg:}} + +*startfile_android: +%{!shared:%{static: crtbegin_static%O%s ; : crtbegin_dynamic%O%s}} + +*startfile_default: + crti%O%s crtbegin%O%s + +*endfile_android: +%{!shared:crtend_android%O%s} + +*endfile_default: +crtend%O%s crtn%O%s + +*link_command: +%{!fsyntax-only:%{!c:%{!M:%{!MM:%{!E:%{!S: %(linker) %{fuse-linker-plugin: -plugin %(linker_plugin_file) -plugin-opt=%(lto_wrapper) -plugin-opt=%(lto_gcc) %{static|static-libgcc:-plugin-opt=-pass-through=%(lto_libgcc)} %{static:-plugin-opt=-pass-through=-lc} %{O*:-plugin-opt=-O%*} %{w:-plugin-opt=-w} %{f*:-plugin-opt=-f%*} %{m*:-plugin-opt=-m%*} %{v:-plugin-opt=-v} } %{flto} %{fwhopr} %l %{pie:-pie} %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r} %{s} %{t} %{u*} %{x} %{z} %{Z} %{!A:%{!nostdlib:%{!nostartfiles:%S}}} %{Wno-poison-system-directories:--no-poison-system-directories} %{Werror=poison-system-directories:--error-poison-system-directories} %{static:} %{L*} %(mfwrap) %(link_libgcc) %o %{fopenmp|ftree-parallelize-loops=*:%:include(libgomp.spec)%(link_gomp)} %(mflib) %{fprofile-arcs|fprofile-generate*|coverage:-lgcov} %{!nostdlib:%{!nodefaultlibs:%(link_ssp) %(link_gcc_c_sequence)}} %{!A:%{!nostdlib:%{!nostartfiles:%E}}} %{T*} }}}}}} + diff --git a/arch/arm/lpc17xx/startup.s b/arch/arm/lpc17xx/startup.s index 564c4d7..3a99753 100644 --- a/arch/arm/lpc17xx/startup.s +++ b/arch/arm/lpc17xx/startup.s @@ -189,12 +189,12 @@ __cs3_reset_cortex_m: MOV R1, R3 MOV R0, R2 MOV R2, R4 - BL memcpy + BL startup_memcpy LDR R0, =__bss_ram_begin MOV R1, #0 LDR R2, =__bss_ram_len - BL memset + BL startup_memset BL lpc17xx_deinit_all BL SystemInit diff --git a/arch/config.mk b/arch/config.mk index 94ea88e..caab7f3 100644 --- a/arch/config.mk +++ b/arch/config.mk @@ -3,5 +3,6 @@ TARGET_INCLUDES += $(ROOTDIR)/arch/arm/include ifeq ($(CPU_FLAVOR),lpc1768) TARGET_INCLUDES += $(ROOTDIR)/arch/arm/lpc17xx/Core/CM3/DeviceSupport/NXP/LPC17xx $(ROOTDIR)/arch/arm/lpc17xx/Core/CM3/CoreSupport $(ROOTDIR)/arch/arm/lpc17xx/Drivers/include $(ROOTDIR)/arch/arm/lpc17xx/mbed LDSCRIPT = $(ROOTDIR)/arch/arm/lpc17xx/ldscript +SPECS = $(ROOTDIR)/arch/arm/lpc17xx/specs endif endif diff --git a/config/general.mk b/config/general.mk index 293db96..58b277e 100644 --- a/config/general.mk +++ b/config/general.mk @@ -1,5 +1,6 @@ VERBOSE = false DEBUG = true +USE_FLOATINGPOINT = true ifneq ($(VERBOSE),true) MAKE_OPTS = --no-print-directory -s diff --git a/libc/LIB.status b/libc/LIB.status new file mode 100644 index 0000000..2ac97d3 --- /dev/null +++ b/libc/LIB.status @@ -0,0 +1,190 @@ +Stdlib: +------ + +What should stdlib contain, and current status. + +atof - missing +atoi - missing +atol - missing +strtod - missing +strtof - missing +strtold - missing (do we want to support long double anyway?) +strtol - missing +strtoul - missing +strtoq - missing +strtouq - missing +strtoll - missing (same as strtoq, different "standard") +strtoull - missing (same as strtouq, different "standard") + + +no locale function at all (__strtol_l, etc...) + + +random - missing +srandom - missing +initstate - missing +setstate - missing +rand - missing +srand - missing +drand48 - missing + +all *rand48 missing + +malloc, calloc, realloc, free, are missing + +abort - missing +atexit - ok +exit - ok + +getenv - missing +setenv - missing + +system - missing, and won't be here anyway I think... + +bsearch - missing +qsort - missing +abs - missing +labs - missing +llabs - missing +div - missing +ldiv - missing +lldiv - missing +frexp - missing +ldexp - missing + +ecvt - missing +fcvt - missing +gcvt - missing + +mblen, mbtowc, wctomb, mbstowcs, wcstombs - missing + + +Stdio/Unistd: +------------ + +stdin, stdout, stderr - ok + +Also, should have buffering... + +remove - missing +rename - missing +tmp* - missing +fclose - ok, inlined +fflush - ok, dummy function +fcloseall - missing, won't implement (we don't keep track of the FILE pointers) +fopen - ok, inlined +freopen - missing +fdopen - missing +setbuf - missing +setvbuf - missing + +*printf - ok (f, s, vf, v, vs, sn, vsn, vas, as) +*dprintf - missing +*scanf - missing (f, s, vf, v, vs) +*getc - missing +getchar - missing +*putc - missing +putchar - missing +{get,put}w - missing +*gets - missing +getdelim - missing, gnu replacement to gets +getline - missing, gnu replacement to gets +*puts - missing +ungetc - missing +fread - ok, inlined +fwrite - ok, inlined +fseek - missing +ftell - missing +rewind - missing +fgetpos - missing +fsetpos - missing +clearerr - missing +feof - missing +ferror - missing + +perror - missing +fileno - missing +pipe funcs - missing, can we make them ? +lock funcs - missing, can we make them ? + +mkdir - missing +rmdir - missing + +chdir - missing +getcwd - missing + +open - ok +close - ok +read - ok +write - ok +lseek - ok + + +String: +------ + +memcpy - ok, inlined +memmove - missing +memset - ok, inlined +memcmp - ok, inlined +memchr - missing + +strcpy - ok, inlined +strncpy - ok, inlined +strcat - ok, inlined +strncat - missing +strcmp - missing +strncmp - missing + +strcoll - missing +strxfrm - missing + +strdup - missing + +strchr - ok, inlined +strrchr - missing + +strcspn - missing +strspn - missing +strpbrk - missing +strstr - missing +strcasestr - missing +strtok - missing + +strlen - ok, inlined +strerror - missing + +bzero - missing +bcopy - missing +bcmp - missing +index - missing +rindex - missing + +stricmp - missing +strcasecmp - missing +strnicmp - missing +strncasecmp - missing + +isalnum - missing +iscntrl - missing +isdigit - missing +isgraph - missing +islower - missing +isprint - missing +ispunct - missing +isspace - missing +isupper - missing +isxdigit - missing + +asctime - missing +clock - missing +ctime - missing +difftime - missing +gmtime - missing +localtime - missing +mktime - missing + +longjmp - cortex-m3, untested +setjmp - cortex-m3, untested + +raise - missing, can we build signals ? diff --git a/libc/Makefile b/libc/Makefile new file mode 100644 index 0000000..64cfa5d --- /dev/null +++ b/libc/Makefile @@ -0,0 +1,34 @@ +TARGET_LIB = libc.a + +all: $(TARGET_LIB) + +include $(ROOTDIR)/common.mk +include config.mk +include $(ROOTDIR)/FreeRTOS/config.mk +include $(ROOTDIR)/arch/config.mk +include $(ROOTDIR)/os/config.mk + +ifneq ($(USE_FLOATINGPOINT),true) +TARGET_CPPFLAGS = -DNOFLOATINGPOINT +endif + +TARGET_SRCS = \ +src/close.c \ +src/lseek.c \ +src/open.c \ +src/read.c \ +src/write.c \ +\ +src/stdio.c \ +\ +src/reent.c \ +\ +src/exit.c \ +\ +src/malloc.c \ +\ +src/xprintf.c \ + +include $(ROOTDIR)/target-rules.mk + +clean: clean-generic diff --git a/libc/config.mk b/libc/config.mk new file mode 100644 index 0000000..1cee0f5 --- /dev/null +++ b/libc/config.mk @@ -0,0 +1 @@ +TARGET_INCLUDES += $(ROOTDIR)/libc/include diff --git a/libc/include/ctype.h b/libc/include/ctype.h new file mode 100644 index 0000000..22e3e81 --- /dev/null +++ b/libc/include/ctype.h @@ -0,0 +1,20 @@ +#ifndef __CTYPE_H__ +#define __CTYPE_H__ + +static inline int isascii(int c) { return (c & 0x80) == 0; } +static inline int isblank(int c) { return c == ' ' || c == '\t'; } +static inline int isdigit(int c) { return c >= '0' && c <= '9'; } +static inline int iscntrl(int c) { return c < 32; } +static inline int islower(int c) { return c >= 'a' && c <= 'z'; } +static inline int isspace(int c) { return c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v'; } +static inline int isupper(int c) { return c >= 'A' && c <= 'Z'; } +static inline int isxdigit(int c) { return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); } + +static inline int isalpha(int c) { return isupper(c) || islower(c); } +static inline int isalnum(int c) { return isalpha(c) || isdigit(c); } +static inline int isgraph(int c) { return !iscntrl(c) && !isspace(c); } +static inline int isprint(int c) { return !iscntrl(c); } +static inline int ispunct(int c) { return !iscntrl(c) && !isspace(c) && !isalnum(c); } + + +#endif diff --git a/libc/include/errno.h b/libc/include/errno.h new file mode 100644 index 0000000..c88ea64 --- /dev/null +++ b/libc/include/errno.h @@ -0,0 +1,140 @@ +#ifndef __ERRNO_H__ +#define __ERRNO_H__ + +enum errno_t { + ENOERROR = 0, + EPERM = 1, + ENOENT = 2, + ESRCH = 3, + EINTR = 4, + EIO = 5, + ENXIO = 6, + E2BIG = 7, + ENOEXEC = 8, + EBADF = 9, + ECHILD = 10, + EAGAIN = 11, + ENOMEM = 12, + EACCES = 13, + EFAULT = 14, + ENOTBLK = 15, + EBUSY = 16, + EEXIST = 17, + EXDEV = 18, + ENODEV = 19, + ENOTDIR = 20, + EISDIR = 21, + EINVAL = 22, + ENFILE = 23, + EMFILE = 24, + ENOTTY = 25, + ETXTBSY = 26, + EFBIG = 27, + ENOSPC = 28, + ESPIPE = 29, + EROFS = 30, + EMLINK = 31, + EPIPE = 32, + EDOM = 33, + ERANGE = 34, + EDEADLK = 35, + ENAMETOOLONG = 36, + ENOLCK = 37, + ENOSYS = 38, + ENOTEMPTY = 39, + ELOOP = 40, + EWOULDBLOCK = EAGAIN, + ENOMSG = 42, + EIDRM = 43, + ECHRNG = 44, + EL2NSYNC = 45, + EL3HLT = 46, + EL3RST = 47, + ELNRNG = 48, + EUNATCH = 49, + ENOCSI = 50, + EL2HLT = 51, + EBADE = 52, + EBADR = 53, + EXFULL = 54, + ENOANO = 55, + EBADRQC = 56, + EBADSLT = 57, + EDEADLOCK = EDEADLK, + EBFONT = 59, + ENOSTR = 60, + ENODATA = 61, + ETIME = 62, + ENOSR = 63, + ENONET = 64, + ENOPKG = 65, + EREMOTE = 66, + ENOLINK = 67, + EADV = 68, + ESRMNT = 69, + ECOMM = 70, + EPROTO = 71, + EMULTIHOP = 72, + EDOTDOT = 73, + EBADMSG = 74, + EOVERFLOW = 75, + ENOTUNIQ = 76, + EBADFD = 77, + EREMCHG = 78, + ELIBACC = 79, + ELIBBAD = 80, + ELIBSCN = 81, + ELIBMAX = 82, + ELIBEXEC = 83, + EILSEQ = 84, + ERESTART = 85, + ESTRPIPE = 86, + EUSERS = 87, + ENOTSOCK = 88, + EDESTADDRREQ = 89, + EMSGSIZE = 90, + EPROTOTYPE = 91, + ENOPROTOOPT = 92, + EPROTONOSUPPORT = 93, + ESOCKTNOSUPPORT = 94, + EOPNOTSUPP = 95, + EPFNOSUPPORT = 96, + EAFNOSUPPORT = 97, + EADDRINUSE = 98, + EADDRNOTAVAIL = 99, + ENETDOWN = 100, + ENETUNREACH = 101, + ENETRESET = 102, + ECONNABORTED = 103, + ECONNRESET = 104, + ENOBUFS = 105, + EISCONN = 106, + ENOTCONN = 107, + ESHUTDOWN = 108, + ETOOMANYREFS = 109, + ETIMEDOUT = 110, + ECONNREFUSED = 111, + EHOSTDOWN = 112, + EHOSTUNREACH = 113, + EALREADY = 114, + EINPROGRESS = 115, + ESTALE = 116, + EUCLEAN = 117, + ENOTNAM = 118, + ENAVAIL = 119, + EISNAM = 120, + EREMOTEIO = 121, + EDQUOT = 122, + ENOMEDIUM = 123, + EMEDIUMTYPE = 124, + ECANCELED = 125, + ENOKEY = 126, + EKEYEXPIRED = 127, + EKEYREVOKED = 128, + EKEYREJECTED = 129, + EOWNERDEAD = 130, + ENOTRECOVERABLE = 131, + ERFKILL = 132, +}; + +#endif diff --git a/libc/include/malloc.h b/libc/include/malloc.h new file mode 100644 index 0000000..8dbfc05 --- /dev/null +++ b/libc/include/malloc.h @@ -0,0 +1,18 @@ +#ifndef __MALLOC_H__ +#define __MALLOC_H__ + +#include +#include +#include + +void * malloc(size_t size); +void free(void *ptr); +void * realloc(void *ptr, size_t size); + +static inline void * calloc(size_t nmemb, size_t size) { + void * r = malloc(nmemb * size); + memset(r, 0, nmemb * size); + return r; +} + +#endif diff --git a/libc/include/math.h b/libc/include/math.h new file mode 100644 index 0000000..b41fee0 --- /dev/null +++ b/libc/include/math.h @@ -0,0 +1,4 @@ +#ifndef __MATH_H__ +#define __MATH_H__ + +#endif diff --git a/libc/include/reent.h b/libc/include/reent.h new file mode 100644 index 0000000..c3633ee --- /dev/null +++ b/libc/include/reent.h @@ -0,0 +1,16 @@ +#ifndef __RENT_H__ +#define __RENT_H__ + +#include + +struct _reent { + enum errno_t _errno; +}; + +static inline void _REENT_INIT_PTR(struct _reent * reent) { + reent->_errno = ENOERROR; +} + +extern struct _reent * _impure_ptr; + +#endif diff --git a/libc/include/setjmp.h b/libc/include/setjmp.h new file mode 100644 index 0000000..8fc8a12 --- /dev/null +++ b/libc/include/setjmp.h @@ -0,0 +1,13 @@ +#ifndef __SETJMP_H__ +#define __SETJMP_H__ + +#include + +typedef struct { + uint32_t buf[32]; +} jmp_buf; + +int setjmp(jmp_buf env); +void longjmp(jmp_buf env, int val); + +#endif diff --git a/libc/include/stdio.h b/libc/include/stdio.h new file mode 100644 index 0000000..1be0c6e --- /dev/null +++ b/libc/include/stdio.h @@ -0,0 +1,153 @@ +#ifndef __STDIO_H__ +#define __STDIO_H__ + +#include +#include +#include +#include +#include + +struct _FILE { + int fd; +}; + +typedef struct _FILE FILE; + +int printf(const char * format, ...); +int fprintf(FILE *stream, const char * format, ...); +int sprintf(char * str, const char * format, ...); +int snprintf(char * str, size_t size, const char * format, ...); +int asprintf(char ** strp, const char * format, ...); + +int vprintf(const char * format, va_list ap); +int vfprintf(FILE *stream, const char * format, va_list ap); +int vsprintf(char * str, const char * format, va_list ap); +int vsnprintf(char * str, size_t size, const char * format, va_list ap); +int vasprintf(char ** strp, const char * format, va_list ap); + +void __sinit(struct _reent *); + +// We don't even buffer, so... +static inline int fflush(FILE *stream) { return 0; } + +// hopefully, since all of the mode crap is static, gcc will optimize most of it away. +static inline FILE * fopen(const char * fname, const char * mode) { + FILE * r = NULL; + int flags = 0, plus = 0, append = 0, fd; + if (!mode || !mode[0]) { + _impure_ptr->_errno = EINVAL; + return NULL; + } + + if (mode[1] == 'b') { + plus = mode[2] == '+'; + } else if (mode[1]) { + if (mode[1] != '+') { + _impure_ptr->_errno = EINVAL; + return NULL; + } + plus = 1; + } + + switch (mode[0]) { + case 'r': + if (plus) { + flags = O_RDWR; + } else { + flags = O_RDONLY; + } + break; + case 'w': + if (plus) { + flags = O_RDWR | O_CREAT | O_TRUNC; + } else { + flags = O_WRONLY | O_CREAT | O_TRUNC; + } + break; + case 'a': + append = 1; + if (plus) { // won't be properly supported + flags = O_RDWR | O_CREAT; + } else { + flags = O_WRONLY | O_CREAT; + } + break; + default: + _impure_ptr->_errno = EINVAL; + return NULL; + } + + fd = open(fname, flags); + + if (fd >= 0) { + r = (FILE *) malloc(sizeof(FILE)); + r->fd = fd; + } + + return r; +} + +static inline int fclose(FILE * stream) { + int fd; + + if (!stream) { + _impure_ptr->_errno = EINVAL; + return -1; + } + + fd = stream->fd; + free(stream); + return close(fd); +} + +// Again, the compiler should do the right thing, and optimize depending on the values of size and nmemb. +// Luckily, we always will get into the short cases. +static inline size_t fread(void * _ptr, size_t size, size_t nmemb, FILE * stream) { + int i; + uint8_t * ptr = (uint8_t *) _ptr; + + if (!stream) { + _impure_ptr->_errno = EINVAL; + return -1; + } + + if (size == 1) + return read(stream->fd, ptr, nmemb); + + if (nmemb == 1) + return read(stream->fd, ptr, size) == size ? 1 : 0; + + for (i = 0; i < nmemb; i++) { + if (read(stream->fd, ptr + size * i, size) != size) + return i; + } + + return nmemb; +} + +static inline size_t fwrite(const void * _ptr, size_t size, size_t nmemb, FILE * stream) { + int i; + const uint8_t * ptr = (const uint8_t *) _ptr; + + if (!stream) { + _impure_ptr->_errno = EINVAL; + return -1; + } + + if (size == 1) + return write(stream->fd, ptr, nmemb); + + if (nmemb == 1) + return write(stream->fd, ptr, size) == size ? 1 : 0; + + for (i = 0; i < nmemb; i++) { + if (write(stream->fd, ptr + size * i, size) != size) + return i; + } + + return nmemb; +} + +extern FILE * stdin, * stdout, * stderr; + +#endif diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h new file mode 100644 index 0000000..1cfe6c4 --- /dev/null +++ b/libc/include/stdlib.h @@ -0,0 +1,12 @@ +#ifndef __STDLIB_H__ +#define __STDLIB_H__ + +#include +#include + +typedef void (*atexit_func_t)(void); + +void exit(int status) __attribute__((noreturn)); +int atexit(atexit_func_t); + +#endif diff --git a/libc/include/string.h b/libc/include/string.h new file mode 100644 index 0000000..2ec2a84 --- /dev/null +++ b/libc/include/string.h @@ -0,0 +1,97 @@ +#ifndef __STRING_H__ +#define __STRING_H__ + +#include +#include + +static inline void * memcpy(void * _s1, const void * _s2, size_t n) { + uint8_t * s1 = (uint8_t *) _s1; + const uint8_t * s2 = (uint8_t *) _s2; + size_t i; + + for (i = 0; i < n; i++) + *s1++ = *s2++; + + return _s1; +} + +static inline int memcmp(const void * _s1, const void * _s2, size_t n) { + uint8_t * s1 = (uint8_t *) _s1; + const uint8_t * s2 = (uint8_t *) _s2; + size_t i; + + for (i = 0; i < n; i++, s1++, s2++) { + if (*s1 < *s2) { + return -1; + } else if (*s1 > *s2) { + return 1; + } + } + + return 0; +} + +static inline void * memset(void * _s, int c, size_t n) { + uint8_t * s = (uint8_t *) _s; + size_t i; + + for (i = 0; i < n; i++) + *s++ = (uint8_t) c; + + return _s; +} + +static inline char * strcat(char * s1, const char * s2) { + char * r = s1; + + while (*s1) + s1++; + + while (*s2) + *s1++ = *s2++; + + *s1 = 0; + + return r; +} + +static inline char * strcpy(char * s1, const char * s2) { + char * r = s1; + + while ((*s1++ = *s2++)); + + return r; +} + +static inline char * strncpy(char * s1, const char * s2, size_t n) { + char * r = s1; + size_t i; + + for (i = 0; i < n; i++) { + if (*s2) { + *s1++ = *s2++; + } else { + *s1++ = 0; + } + } + + return r; +} + +static inline const char * strchr(const char * s, char c) { + while (*s) + if (*s++ == c) + return s; + return NULL; +} + +static inline size_t strlen(const char * s) { + size_t r = 0; + + while (*s++) + r++; + + return r; +} + +#endif diff --git a/libc/include/unistd.h b/libc/include/unistd.h new file mode 100644 index 0000000..8efd838 --- /dev/null +++ b/libc/include/unistd.h @@ -0,0 +1,31 @@ +#ifndef __UNISTD_H__ +#define __UNISTD_H__ + +#include +#include +#include + +typedef int32_t ssize_t; +typedef int32_t off_t; + +enum open_types_t { + O_RDONLY = 0, + O_WRONLY = 1, + O_RDWR = 2, + O_CREAT = 4, + O_TRUNC = 8, + O_APPEND = 16, +}; + +enum seek_wheels_t { + SEEK_SET = 0, + SEEK_CUR = 1, + SEEK_END = 2, +}; + +int open(const char *pathname, int flags); +int close(int fd); +ssize_t read(int fd, void *buf, size_t count); +ssize_t write(int fd, const void *buf, size_t count); + +#endif diff --git a/libc/src/close.c b/libc/src/close.c new file mode 100644 index 0000000..fd4256f --- /dev/null +++ b/libc/src/close.c @@ -0,0 +1,12 @@ +#include "reent.h" +#include "errno.h" +#include + +int close(int fd) { + if (!fio_is_open(fd)) { + _impure_ptr->_errno = EBADF; + return -1; + } + + return fio_close(fd); +} diff --git a/libc/src/exit.c b/libc/src/exit.c new file mode 100644 index 0000000..fc2446f --- /dev/null +++ b/libc/src/exit.c @@ -0,0 +1,65 @@ +#include +#include + +extern void (*__preinit_array_start []) (void) __attribute__((weak)); +extern void (*__preinit_array_end []) (void) __attribute__((weak)); +extern void (*__init_array_start []) (void) __attribute__((weak)); +extern void (*__init_array_end []) (void) __attribute__((weak)); +extern void (*__fini_array_start []) (void) __attribute__((weak)); +extern void (*__fini_array_end []) (void) __attribute__((weak)); + +void _init(); +void _fini(); +void _exit(int return_code) __attribute__((noreturn)); + + +void __libc_init_array() { + size_t count, i; + + count = __preinit_array_end - __preinit_array_start; + for (i = 0; i < count; i++) + __preinit_array_start[i](); + + _init(); + + count = __init_array_end - __init_array_start; + for (i = 0; i < count; i++) + __init_array_start[i](); +} + +void __libc_fini_array() { + size_t count, i; + + count = __preinit_array_end - __preinit_array_start; + for (i = count - 1; i >= 0; i--) + __fini_array_start[i](); + + _fini(); +} + +#define MAX_ATEXIT 32 + +static volatile uint8_t atexit_count = 0; +static volatile atexit_func_t atexit_funcs[MAX_ATEXIT]; + +int atexit(atexit_func_t func) { + uint8_t pos = __sync_fetch_and_add(&atexit_count, 1); + + if (pos >= MAX_ATEXIT) { + atexit_count = 32; + return -1; + } + + atexit_funcs[pos] = func; + return 0; +} + +void exit(int return_code) { + uint8_t i; + + for (i = 0; i < atexit_count; i++) { + atexit_funcs[i](); + } + + _exit(return_code); +} diff --git a/libc/src/lseek.c b/libc/src/lseek.c new file mode 100644 index 0000000..bffc81f --- /dev/null +++ b/libc/src/lseek.c @@ -0,0 +1,24 @@ +#include "reent.h" +#include "errno.h" +#include + +off_t lseek(int fd, off_t seek, int wheel) { + off_t r; + + if ((wheel != SEEK_SET) && (wheel != SEEK_CUR) && (wheel != SEEK_END)) { + _impure_ptr->_errno = EINVAL; + return -1; + } + + if (!fio_is_open(fd)) { + _impure_ptr->_errno = EBADF; + return -1; + } + + r = fio_seek(fd, seek, wheel); + + if (r < 0) + _impure_ptr->_errno = EINVAL; + + return r; +} diff --git a/libc/src/malloc.c b/libc/src/malloc.c new file mode 100644 index 0000000..95181ac --- /dev/null +++ b/libc/src/malloc.c @@ -0,0 +1,198 @@ +#include +#include +#include "malloc.h" + +void * sbrk(ptrdiff_t incr); + +typedef struct _heap_t { + void * ptr; + size_t size; + struct _heap_t * prev, * next; +} heap_t; + +static void * heap_base = NULL; +static heap_t * head = NULL, * tail = NULL; + +static heap_t * find_fit(heap_t * head, size_t size) { + heap_t * prev = head; + uintptr_t prev_top, next_bot; + + while (prev) { + if (prev->next) { + prev_top = (uintptr_t) prev->ptr + prev->size; + next_bot = (uintptr_t) prev->next - prev_top; + if (next_bot >= size) + return prev; + } + prev = prev->next; + } + + return prev; +} + +void * malloc(size_t size) { + void * ptr = NULL, * heap_ptr; + heap_t * new, * prev; + + size = (size + sizeof(heap_t) + 7) & ~7; + + // Nothing's initialized yet ? Let's just initialize the bottom of our heap, + // flag it as allocated. + if (!head) { + if (!heap_base) + heap_base = sbrk(0); + heap_ptr = sbrk(size); + + if (!heap_ptr) + return NULL; + + ptr = (void *) ((uintptr_t) heap_ptr + sizeof(heap_t)); + head = (heap_t *) heap_ptr; + head->ptr = ptr; + head->size = size - sizeof(heap_t); + head->prev = NULL; + head->next = NULL; + tail = head; + return ptr; + } + + // We *may* have the bottom of our heap that has shifted, because of a free. + // So let's check first if we have free space there, because I'm nervous + // about having an incomplete data structure. + if (((uintptr_t) heap_base + size) < (uintptr_t) head) { + new = (heap_t *) heap_base; + ptr = (void *) ((uintptr_t) new + sizeof(heap_t)); + + new->ptr = ptr; + new->size = size - sizeof(heap_t); + new->prev = NULL; + new->next = head; + head->prev = new; + head = new; + return ptr; + } + + // No luck at the beginning of the heap, let's walk the heap to find a fit. + prev = find_fit(head, size); + if (prev) { + new = (heap_t *) ((uintptr_t) prev->ptr + prev->size); + ptr = (void *) ((uintptr_t) new + sizeof(heap_t)); + + new->ptr = ptr; + new->size = size - sizeof(heap_t); + new->prev = prev; + new->next = prev->next; + new->next->prev = new; + prev->next = new; + return ptr; + } + + // Time to extend the size of the heap. + heap_ptr = sbrk(size); + if (!heap_ptr) + return NULL; + + ptr = (void *) ((uintptr_t) heap_ptr + sizeof(heap_t)); + new = (heap_t *) heap_ptr; + new->ptr = ptr; + new->size = size - sizeof(heap_t); + new->prev = tail; + new->next = NULL; + tail->next = new; + tail = new; + return ptr; +} + +void * realloc(void * ptr, size_t size) { + heap_t * prev; + void * new = NULL; + + if (!size && ptr) { + free(ptr); + return NULL; + } + + if (!ptr) + return malloc(size); + + size = (size + sizeof(heap_t) + 7) & ~7; + + prev = (heap_t *) ((uintptr_t) ptr - sizeof(heap_t)); + + // New memory block shorter ? + if (prev->size >= size) { + prev->size = size; + if (!prev->next) + sbrk(ptr + size - sbrk(0)); + + return ptr; + } + + // New memory block larger + // Is it the last one ? + if (!prev->next) { + new = sbrk(size - prev->size); + if (!new) + return NULL; + + prev->size = size; + return ptr; + } + + // Do we have free memory after it ? + if ((prev->next->ptr - ptr) > size) { + prev->size = size; + return ptr; + } + + // No luck. + new = malloc(size); + if (!new) + return NULL; + + memcpy(new, ptr, prev->size); + free(ptr); + return new; +} + +void free(void * ptr) { + heap_t * cur; + void * top; + size_t size; + + if (!ptr || !head) + return; + + if (ptr == head->ptr) { + size = head->size + (size_t) (head->ptr - (void *) head); + head = head->next; + + if (head) { + head->prev = NULL; + } else { + tail = NULL; + sbrk(-size); + } + + return; + } + + cur = head; + for (cur = head; ptr != cur->ptr; cur = cur->next) + if (!cur->next) + return; + + if (cur->next) { + cur->next->prev = cur->prev; + } else { + tail = cur->prev; + top = sbrk(0); + size = (uintptr_t) top - (uintptr_t) cur->prev->ptr + cur->prev->size; + sbrk(-size); + } + + cur->prev->next = cur->next; +} + +__attribute__((weak)) void * __builtin_new(size_t size) { return malloc(size); } +__attribute__((weak)) void __builtin_delete(void * ptr) { free(ptr); } diff --git a/libc/src/open.c b/libc/src/open.c new file mode 100644 index 0000000..71a96d1 --- /dev/null +++ b/libc/src/open.c @@ -0,0 +1,17 @@ +#include "stdio.h" +#include "reent.h" +#include "errno.h" +#include +#include + +int open(const char * path, int flags) { + int r; + + r = fs_open(path, flags, 0755); + + if (r >= 0) + return r; + + _impure_ptr->_errno = EACCES; + return -1; +} diff --git a/libc/src/read.c b/libc/src/read.c new file mode 100644 index 0000000..aeea537 --- /dev/null +++ b/libc/src/read.c @@ -0,0 +1,21 @@ +#include "reent.h" +#include "errno.h" +#include + +ssize_t read(int fd, void * buf, size_t size) { + ssize_t r; + + if (!fio_is_open(fd)) { + _impure_ptr->_errno = EBADF; + return -1; + } + + r = fio_read(fd, buf, size); + + if (r < 0) { + _impure_ptr->_errno = EINVAL; + return -1; + } + + return r; +} diff --git a/libc/src/reent.c b/libc/src/reent.c new file mode 100644 index 0000000..17de11d --- /dev/null +++ b/libc/src/reent.c @@ -0,0 +1,8 @@ +#include "reent.h" + +static struct _reent main_thread; +struct _reent * _impure_ptr = &main_thread; + +__attribute__((constructor)) static void init_main_thread() { + _REENT_INIT_PTR(_impure_ptr); +} diff --git a/libc/src/stdio.c b/libc/src/stdio.c new file mode 100644 index 0000000..eab9c7e --- /dev/null +++ b/libc/src/stdio.c @@ -0,0 +1,9 @@ +#include + +FILE * stdin, * stdout, * stderr; + +void __sinit(struct _reent * reent) { + stdin->fd = 0; + stdout->fd = 1; + stderr->fd = 2; +} diff --git a/libc/src/write.c b/libc/src/write.c new file mode 100644 index 0000000..e44806c --- /dev/null +++ b/libc/src/write.c @@ -0,0 +1,21 @@ +#include "reent.h" +#include "errno.h" +#include + +ssize_t write(int fd, const void * buf, size_t size) { + ssize_t r; + + if (!fio_is_open(fd)) { + _impure_ptr->_errno = EBADF; + return -1; + } + + r = fio_write(fd, buf, size); + + if (r < 0) { + _impure_ptr->_errno = EINVAL; + return -1; + } + + return r; +} diff --git a/libc/src/xprintf.c b/libc/src/xprintf.c new file mode 100644 index 0000000..30659f7 --- /dev/null +++ b/libc/src/xprintf.c @@ -0,0 +1,890 @@ +/* +** It turns out that the printf functions in the stock MIT pthread library +** is busted. It isn't thread safe. If two threads try to do a printf +** of a floating point value at the same time, a core-dump might result. +** So this code is substituted. +*/ +/* +** NAME: $Source: /open/anoncvs/cvs/src/lib/libpthread/stdio/Attic/xprintf.c,v $ +** VERSION: $Revision: 1.1 $ +** DATE: $Date: 1998/07/21 13:22:19 $ +** +** ONELINER: A replacement for formatted printing programs. +** +** COPYRIGHT: +** Copyright (c) 1990 by D. Richard Hipp. This code is an original +** work and has been prepared without reference to any prior +** implementations of similar functions. No part of this code is +** subject to licensing restrictions of any telephone company or +** university. +** +** This copyright was released and the code placed in the public domain +** by the author, D. Richard Hipp, on October 3, 1996. +** +** DESCRIPTION: +** This program is an enhanced replacement for the "printf" programs +** found in the standard library. The following enhancements are +** supported: +** +** + Additional functions. The standard set of "printf" functions +** includes printf, fprintf, sprintf, vprintf, vfprintf, and +** vsprintf. This module adds the following: +** +** * snprintf -- Works like sprintf, but has an extra argument +** which is the size of the buffer written to. +** +** * mprintf -- Similar to sprintf. Writes output to memory +** obtained from mem_alloc. +** +** * xprintf -- Calls a function to dispose of output. +** +** * nprintf -- No output, but returns the number of characters +** that would have been output by printf. +** +** * A v- version (ex: vsnprintf) of every function is also +** supplied. +** +** + A few extensions to the formatting notation are supported: +** +** * The "=" flag (similar to "-") causes the output to be +** be centered in the appropriately sized field. +** +** * The %b field outputs an integer in binary notation. +** +** * The %c field now accepts a precision. The character output +** is repeated by the number of times the precision specifies. +** +** * The %' field works like %c, but takes as its character the +** next character of the format string, instead of the next +** argument. For example, printf("%.78'-") prints 78 minus +** signs, the same as printf("%.78c",'-'). +** +** + When compiled using GCC on a SPARC, this version of printf is +** faster than the library printf for SUN OS 4.1. +** +** + All functions are fully reentrant. +** +*/ +/* +** Undefine COMPATIBILITY to make some slight changes in the way things +** work. I think the changes are an improvement, but they are not +** backwards compatible. +*/ +/* #define COMPATIBILITY / * Compatible with SUN OS 4.1 */ +#include "stdio.h" +#include +#include "ctype.h" +#include +#include "stdlib.h" +#include "string.h" +/* +** The maximum number of digits of accuracy in a floating-point conversion. +*/ +#define MAXDIG 20 + +/* +** Conversion types fall into various categories as defined by the +** following enumeration. +*/ +enum e_type { /* The type of the format field */ + RADIX, /* Integer types. %d, %x, %o, and so forth */ + FLOAT, /* Floating point. %f */ + EXP, /* Exponentional notation. %e and %E */ + GENERIC, /* Floating or exponential, depending on exponent. %g */ + SIZE, /* Return number of characters processed so far. %n */ + STRING, /* Strings. %s */ + PERCENT, /* Percent symbol. %% */ + CHAR, /* Characters. %c */ + ERROR, /* Used to indicate no such conversion type */ +/* The rest are extensions, not normally found in printf() */ + CHARLIT, /* Literal characters. %' */ + SEEIT, /* Strings with visible control characters. %S */ + MEM_STRING, /* A string which should be deleted after use. %z */ + ORDINAL, /* 1st, 2nd, 3rd and so forth */ +}; + +/* +** Each builtin conversion character (ex: the 'd' in "%d") is described +** by an instance of the following structure +*/ +typedef struct s_info { /* Information about each format field */ + int fmttype; /* The format field code letter */ + int base; /* The base for radix conversion */ + char *charset; /* The character set for conversion */ + int flag_signed; /* Is the quantity signed? */ + char *prefix; /* Prefix on non-zero values in alt format */ + enum e_type type; /* Conversion paradigm */ +} info; + +/* +** The following table is searched linearly, so it is good to put the +** most frequently used conversion types first. +*/ +static const info fmtinfo[] = { + { 'd', 10, "0123456789", 1, 0, RADIX, }, + { 's', 0, 0, 0, 0, STRING, }, + { 'S', 0, 0, 0, 0, SEEIT, }, + { 'z', 0, 0, 0, 0, MEM_STRING, }, + { 'c', 0, 0, 0, 0, CHAR, }, + { 'o', 8, "01234567", 0, "0", RADIX, }, + { 'u', 10, "0123456789", 0, 0, RADIX, }, + { 'x', 16, "0123456789abcdef", 0, "x0", RADIX, }, + { 'X', 16, "0123456789ABCDEF", 0, "X0", RADIX, }, + { 'r', 10, "0123456789", 0, 0, ORDINAL, }, + { 'f', 0, 0, 1, 0, FLOAT, }, + { 'e', 0, "e", 1, 0, EXP, }, + { 'E', 0, "E", 1, 0, EXP, }, + { 'g', 0, "e", 1, 0, GENERIC, }, + { 'G', 0, "E", 1, 0, GENERIC, }, + { 'i', 10, "0123456789", 1, 0, RADIX, }, + { 'n', 0, 0, 0, 0, SIZE, }, + { 'S', 0, 0, 0, 0, SEEIT, }, + { '%', 0, 0, 0, 0, PERCENT, }, + { 'b', 2, "01", 0, "b0", RADIX, }, /* Binary notation */ + { 'p', 10, "0123456789", 0, 0, RADIX, }, /* Pointers */ + { '\'', 0, 0, 0, 0, CHARLIT, }, /* Literal char */ +}; +#define NINFO (sizeof(fmtinfo)/sizeof(info)) /* Size of the fmtinfo table */ + +/* +** If NOFLOATINGPOINT is defined, then none of the floating point +** conversions will work. +*/ +#ifndef NOFLOATINGPOINT +/* +** "*val" is a double such that 0.1 <= *val < 10.0 +** Return the ascii code for the leading digit of *val, then +** multiply "*val" by 10.0 to renormalize. +** +** Example: +** input: *val = 3.14159 +** output: *val = 1.4159 function return = '3' +** +** The counter *cnt is incremented each time. After counter exceeds +** 16 (the number of significant digits in a 64-bit float) '0' is +** always returned. +*/ +static int getdigit(long double *val, int *cnt){ + int digit; + long double d; + if( (*cnt)++ >= MAXDIG ) return '0'; + digit = (int)*val; + d = digit; + digit += '0'; + *val = (*val - d)*10.0; + return digit; +} +#endif + +/* +** Setting the size of the BUFFER involves trade-offs. No %d or %f +** conversion can have more than BUFSIZE characters. If the field +** width is larger than BUFSIZE, it is silently shortened. On the +** other hand, this routine consumes more stack space with larger +** BUFSIZEs. If you have some threads for which you want to minimize +** stack space, you should keep BUFSIZE small. +*/ +#define BUFSIZE 100 /* Size of the output buffer */ + +/* +** The root program. All variations call this core. +** +** INPUTS: +** func This is a pointer to a function taking three arguments +** 1. A pointer to the list of characters to be output +** (Note, this list is NOT null terminated.) +** 2. An integer number of characters to be output. +** (Note: This number might be zero.) +** 3. A pointer to anything. Same as the "arg" parameter. +** +** arg This is the pointer to anything which will be passed as the +** third argument to "func". Use it for whatever you like. +** +** fmt This is the format string, as in the usual print. +** +** ap This is a pointer to a list of arguments. Same as in +** vfprint. +** +** OUTPUTS: +** The return value is the total number of characters sent to +** the function "func". Returns -1 on a error. +** +** Note that the order in which automatic variables are declared below +** seems to make a big difference in determining how fast this beast +** will run. +*/ +static int vxprintf(func,arg,format,ap) + void (*func)(const char*,int,void*); + void *arg; + const char *format; + va_list ap; +{ + register const char *fmt; /* The format string. */ + register int c; /* Next character in the format string */ + register char *bufpt; /* Pointer to the conversion buffer */ + register int precision; /* Precision of the current field */ + register int length; /* Length of the field */ + register int idx; /* A general purpose loop counter */ + int count; /* Total number of characters output */ + int width; /* Width of the current field */ + int flag_leftjustify; /* True if "-" flag is present */ + int flag_plussign; /* True if "+" flag is present */ + int flag_blanksign; /* True if " " flag is present */ + int flag_alternateform; /* True if "#" flag is present */ + int flag_zeropad; /* True if field width constant starts with zero */ + int flag_long; /* True if "l" flag is present */ + int flag_center; /* True if "=" flag is present */ + unsigned long longvalue; /* Value for integer types */ + long double realvalue; /* Value for real types */ + const info *infop; /* Pointer to the appropriate info structure */ + char buf[BUFSIZE]; /* Conversion buffer */ + char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */ + int errorflag = 0; /* True if an error is encountered */ + enum e_type xtype; /* Conversion paradigm */ + char *zMem = NULL; /* String to be freed */ + static const char spaces[] = + " "; +#define SPACESIZE (sizeof(spaces)-1) +#ifndef NOFLOATINGPOINT + int exp; /* exponent of real numbers */ + long double rounder; /* Used for rounding floating point values */ + int flag_dp; /* True if decimal point should be shown */ + int flag_rtz; /* True if trailing zeros should be removed */ + int flag_exp; /* True to force display of the exponent */ + int nsd; /* Number of significant digits returned */ +#endif + + fmt = format; /* Put in a register for speed */ + count = length = 0; + bufpt = 0; + for(; (c=(*fmt))!=0; ++fmt){ + if( c!='%' ){ + register int amt; + bufpt = (char *)fmt; + amt = 1; + while( (c=(*++fmt))!='%' && c!=0 ) amt++; + (*func)(bufpt,amt,arg); + count += amt; + if( c==0 ) break; + } + if( (c=(*++fmt))==0 ){ + errorflag = 1; + (*func)("%",1,arg); + count++; + break; + } + /* Find out what flags are present */ + flag_leftjustify = flag_plussign = flag_blanksign = + flag_alternateform = flag_zeropad = flag_center = 0; + do{ + switch( c ){ + case '-': flag_leftjustify = 1; c = 0; break; + case '+': flag_plussign = 1; c = 0; break; + case ' ': flag_blanksign = 1; c = 0; break; + case '#': flag_alternateform = 1; c = 0; break; + case '0': flag_zeropad = 1; c = 0; break; + case '=': flag_center = 1; c = 0; break; + default: break; + } + }while( c==0 && (c=(*++fmt))!=0 ); + if( flag_center ) flag_leftjustify = 0; + /* Get the field width */ + width = 0; + if( c=='*' ){ + width = va_arg(ap,int); + if( width<0 ){ + flag_leftjustify = 1; + width = -width; + } + c = *++fmt; + }else{ + while( isdigit(c) ){ + width = width*10 + c - '0'; + c = *++fmt; + } + } + if( width > BUFSIZE-10 ){ + width = BUFSIZE-10; + } + /* Get the precision */ + if( c=='.' ){ + precision = 0; + c = *++fmt; + if( c=='*' ){ + precision = va_arg(ap,int); +#ifndef COMPATIBILITY + /* This is sensible, but SUN OS 4.1 doesn't do it. */ + if( precision<0 ) precision = -precision; +#endif + c = *++fmt; + }else{ + while( isdigit(c) ){ + precision = precision*10 + c - '0'; + c = *++fmt; + } + } + /* Limit the precision to prevent overflowing buf[] during conversion */ + if( precision>BUFSIZE-40 ) precision = BUFSIZE-40; + }else{ + precision = -1; + } + /* Get the conversion type modifier */ + if( c=='l' ){ + flag_long = 1; + c = *++fmt; + }else{ + flag_long = 0; + } + /* Fetch the info entry for the field */ + infop = 0; + for(idx=0; idxtype; + } + + /* + ** At this point, variables are initialized as follows: + ** + ** flag_alternateform TRUE if a '#' is present. + ** flag_plussign TRUE if a '+' is present. + ** flag_leftjustify TRUE if a '-' is present or if the + ** field width was negative. + ** flag_zeropad TRUE if the width began with 0. + ** flag_long TRUE if the letter 'l' (ell) prefixed + ** the conversion character. + ** flag_blanksign TRUE if a ' ' is present. + ** width The specified field width. This is + ** always non-negative. Zero is the default. + ** precision The specified precision. The default + ** is -1. + ** xtype The class of the conversion. + ** infop Pointer to the appropriate info struct. + */ + switch( xtype ){ + case ORDINAL: + case RADIX: + if( flag_long ) longvalue = va_arg(ap,long); + else longvalue = va_arg(ap,int); +#ifdef COMPATIBILITY + /* For the format %#x, the value zero is printed "0" not "0x0". + ** I think this is stupid. */ + if( longvalue==0 ) flag_alternateform = 0; +#else + /* More sensible: turn off the prefix for octal (to prevent "00"), + ** but leave the prefix for hex. */ + if( longvalue==0 && infop->base==8 ) flag_alternateform = 0; +#endif + if( infop->flag_signed ){ + if( *(long*)&longvalue<0 ){ + longvalue = -*(long*)&longvalue; + prefix = '-'; + }else if( flag_plussign ) prefix = '+'; + else if( flag_blanksign ) prefix = ' '; + else prefix = 0; + }else prefix = 0; + if( flag_zeropad && precision3 || (b>10 && b<14) ){ + bufpt[0] = 't'; + bufpt[1] = 'h'; + }else if( a==1 ){ + bufpt[0] = 's'; + bufpt[1] = 't'; + }else if( a==2 ){ + bufpt[0] = 'n'; + bufpt[1] = 'd'; + }else if( a==3 ){ + bufpt[0] = 'r'; + bufpt[1] = 'd'; + } + } + { + register char *cset; /* Use registers for speed */ + register int base; + cset = infop->charset; + base = infop->base; + do{ /* Convert to ascii */ + *(--bufpt) = cset[longvalue%base]; + longvalue = longvalue/base; + }while( longvalue>0 ); + } + length = (int)(&buf[BUFSIZE]-bufpt); + for(idx=precision-length; idx>0; idx--){ + *(--bufpt) = '0'; /* Zero pad */ + } + if( prefix ) *(--bufpt) = prefix; /* Add sign */ + if( flag_alternateform && infop->prefix ){ /* Add "0" or "0x" */ + char *pre, x; + pre = infop->prefix; + if( *bufpt!=pre[0] ){ + for(pre=infop->prefix; (x=(*pre))!=0; pre++) *(--bufpt) = x; + } + } + length = (int)(&buf[BUFSIZE]-bufpt); + break; + case FLOAT: + case EXP: + case GENERIC: + realvalue = va_arg(ap,double); +#ifndef NOFLOATINGPOINT + if( precision<0 ) precision = 6; /* Set default precision */ + if( precision>BUFSIZE-10 ) precision = BUFSIZE-10; + if( realvalue<0.0 ){ + realvalue = -realvalue; + prefix = '-'; + }else{ + if( flag_plussign ) prefix = '+'; + else if( flag_blanksign ) prefix = ' '; + else prefix = 0; + } + if( infop->type==GENERIC && precision>0 ) precision--; + rounder = 0.0; +#ifdef COMPATIBILITY + /* Rounding works like BSD when the constant 0.4999 is used. Wierd! */ + for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1); +#else + /* It makes more sense to use 0.5 */ + if( precision>MAXDIG-1 ) idx = MAXDIG-1; + else idx = precision; + for(rounder=0.5; idx>0; idx--, rounder*=0.1); +#endif + if( infop->type==FLOAT ) realvalue += rounder; + /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */ + exp = 0; + if( realvalue>0.0 ){ + int k = 0; + while( realvalue>=1e8 && k++<100 ){ realvalue *= 1e-8; exp+=8; } + while( realvalue>=10.0 && k++<100 ){ realvalue *= 0.1; exp++; } + while( realvalue<1e-8 && k++<100 ){ realvalue *= 1e8; exp-=8; } + while( realvalue<1.0 && k++<100 ){ realvalue *= 10.0; exp--; } + if( k>=100 ){ + bufpt = "NaN"; + length = 3; + break; + } + } + bufpt = buf; + /* + ** If the field type is GENERIC, then convert to either EXP + ** or FLOAT, as appropriate. + */ + flag_exp = xtype==EXP; + if( xtype!=FLOAT ){ + realvalue += rounder; + if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; } + } + if( xtype==GENERIC ){ + flag_rtz = !flag_alternateform; + if( exp<-4 || exp>precision ){ + xtype = EXP; + }else{ + precision = precision - exp; + xtype = FLOAT; + } + }else{ + flag_rtz = 0; + } + /* + ** The "exp+precision" test causes output to be of type EXP if + ** the precision is too large to fit in buf[]. + */ + nsd = 0; + if( xtype==FLOAT && exp+precision0 || flag_alternateform); + if( prefix ) *(bufpt++) = prefix; /* Sign */ + if( exp<0 ) *(bufpt++) = '0'; /* Digits before "." */ + else for(; exp>=0; exp--) *(bufpt++) = getdigit(&realvalue,&nsd); + if( flag_dp ) *(bufpt++) = '.'; /* The decimal point */ + for(exp++; exp<0 && precision>0; precision--, exp++){ + *(bufpt++) = '0'; + } + while( (precision--)>0 ) *(bufpt++) = getdigit(&realvalue,&nsd); + *(bufpt--) = 0; /* Null terminate */ + if( flag_rtz && flag_dp ){ /* Remove trailing zeros and "." */ + while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0; + if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0; + } + bufpt++; /* point to next free slot */ + }else{ /* EXP or GENERIC */ + flag_dp = (precision>0 || flag_alternateform); + if( prefix ) *(bufpt++) = prefix; /* Sign */ + *(bufpt++) = getdigit(&realvalue,&nsd); /* First digit */ + if( flag_dp ) *(bufpt++) = '.'; /* Decimal point */ + while( (precision--)>0 ) *(bufpt++) = getdigit(&realvalue,&nsd); + bufpt--; /* point to last digit */ + if( flag_rtz && flag_dp ){ /* Remove tail zeros */ + while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0; + if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0; + } + bufpt++; /* point to next free slot */ + if( exp || flag_exp ){ + *(bufpt++) = infop->charset[0]; + if( exp<0 ){ *(bufpt++) = '-'; exp = -exp; } /* sign of exp */ + else { *(bufpt++) = '+'; } + if( exp>=100 ){ + *(bufpt++) = (exp/100)+'0'; /* 100's digit */ + exp %= 100; + } + *(bufpt++) = exp/10+'0'; /* 10's digit */ + *(bufpt++) = exp%10+'0'; /* 1's digit */ + } + } + /* The converted number is in buf[] and zero terminated. Output it. + ** Note that the number is in the usual order, not reversed as with + ** integer conversions. */ + length = (int)(bufpt-buf); + bufpt = buf; + + /* Special case: Add leading zeros if the flag_zeropad flag is + ** set and we are not left justified */ + if( flag_zeropad && !flag_leftjustify && length < width){ + int i; + int nPad = width - length; + for(i=width; i>=nPad; i--){ + bufpt[i] = bufpt[i-nPad]; + } + i = prefix!=0; + while( nPad-- ) bufpt[i++] = '0'; + length = width; + } +#endif + break; + case SIZE: + *(va_arg(ap,int*)) = count; + length = width = 0; + break; + case PERCENT: + buf[0] = '%'; + bufpt = buf; + length = 1; + break; + case CHARLIT: + case CHAR: + c = buf[0] = (xtype==CHAR ? va_arg(ap,int) : *++fmt); + if( precision>=0 ){ + for(idx=1; idx=0 && precision=0x7f ){ + buf[i++] = '^'; + buf[i] = (c&0x1f)+0x40; + }else{ + buf[i] = c; + } + } + bufpt = buf; + length = i; + if( precision>=0 && precision0 ){ + if( flag_center ){ + nspace = nspace/2; + width -= nspace; + flag_leftjustify = 1; + } + count += nspace; + while( nspace>=SPACESIZE ){ + (*func)(spaces,SPACESIZE,arg); + nspace -= SPACESIZE; + } + if( nspace>0 ) (*func)(spaces,nspace,arg); + } + } + if( length>0 ){ + (*func)(bufpt,length,arg); + count += length; + } + if( xtype==MEM_STRING && zMem ){ + free(zMem); + } + if( flag_leftjustify ){ + register int nspace; + nspace = width-length; + if( nspace>0 ){ + count += nspace; + while( nspace>=SPACESIZE ){ + (*func)(spaces,SPACESIZE,arg); + nspace -= SPACESIZE; + } + if( nspace>0 ) (*func)(spaces,nspace,arg); + } + } + }/* End for loop over the format string */ + return errorflag ? -1 : count; +} /* End of function */ + +/* +** This non-standard function is still occasionally useful.... +*/ +int xprintf( + void (*func)(char*,int,void*), + void *arg, + const char *format, + ... +){ + va_list ap; + va_start(ap,format); + return vxprintf(func,arg,format,ap); +} + +/* +** Now for string-print, also as found in any standard library. +** Add to this the snprint function which stops added characters +** to the string at a given length. +** +** Note that snprint returns the length of the string as it would +** be if there were no limit on the output. +*/ +struct s_strargument { /* Describes the string being written to */ + char *next; /* Next free slot in the string */ + char *last; /* Last available slot in the string */ +}; + +static void sout(txt,amt,arg) + char *txt; + int amt; + void *arg; +{ + register char *head; + register const char *t; + register int a; + register char *tail; + a = amt; + t = txt; + head = ((struct s_strargument*)arg)->next; + tail = ((struct s_strargument*)arg)->last; + if( tail ){ + while( a-- >0 && head0 ) *(head++) = *(t++); + } + *head = 0; + ((struct s_strargument*)arg)->next = head; +} + +int sprintf(char *buf, const char *fmt, ...){ + int rc; + va_list ap; + struct s_strargument arg; + + va_start(ap,fmt); + arg.next = buf; + arg.last = 0; + *arg.next = 0; + rc = vxprintf(sout,&arg,fmt,ap); + va_end(ap); + return rc; +} +int vsprintf(char *buf,const char *fmt,va_list ap){ + struct s_strargument arg; + arg.next = buf; + arg.last = 0; + *buf = 0; + return vxprintf(sout,&arg,fmt,ap); +} +int snprintf(char *buf, size_t n, const char *fmt, ...){ + int rc; + va_list ap; + struct s_strargument arg; + + va_start(ap,fmt); + arg.next = buf; + arg.last = &arg.next[n-1]; + *arg.next = 0; + rc = vxprintf(sout,&arg,fmt,ap); + va_end(ap); + return rc; +} +int vsnprintf(char *buf, size_t n, const char *fmt, va_list ap){ + struct s_strargument arg; + arg.next = buf; + arg.last = &buf[n-1]; + *buf = 0; + return vxprintf(sout,&arg,fmt,ap); +} + +/* +** The following section of code handles the mprintf routine, that +** writes to memory obtained from malloc(). +*/ + +/* This structure is used to store state information about the +** write in progress +*/ +struct sgMprintf { + char *zBase; /* A base allocation */ + char *zText; /* The string collected so far */ + int nChar; /* Length of the string so far */ + int nAlloc; /* Amount of space allocated in zText */ +}; + +/* The xprintf callback function. */ +static void mout(zNewText,nNewChar,arg) + char *zNewText; + int nNewChar; + void *arg; +{ + struct sgMprintf *pM = (struct sgMprintf*)arg; + if( pM->nChar + nNewChar + 1 > pM->nAlloc ){ + pM->nAlloc = pM->nChar + nNewChar*2 + 1; + if( pM->zText==pM->zBase ){ + pM->zText = malloc(pM->nAlloc); + if( pM->zText && pM->nChar ) memcpy(pM->zText,pM->zBase,pM->nChar); + }else{ + pM->zText = realloc(pM->zText, pM->nAlloc); + } + } + if( pM->zText ){ + memcpy(&pM->zText[pM->nChar], zNewText, nNewChar); + pM->nChar += nNewChar; + pM->zText[pM->nChar] = 0; + } +} + +/* +** mprintf() works like printf(), but allocations memory to hold the +** resulting string and returns a pointer to the allocated memory. +** +** We changed the name to TclMPrint() to conform with the Tcl private +** routine naming conventions. +*/ +int asprintf(char ** out, const char *zFormat, ...){ + va_list ap; + struct sgMprintf sMprintf; + char *zNew; + char zBuf[200]; + int r; + + va_start(ap,zFormat); + sMprintf.nChar = 0; + sMprintf.nAlloc = sizeof(zBuf); + sMprintf.zText = zBuf; + sMprintf.zBase = zBuf; + r = vxprintf(mout,&sMprintf,zFormat,ap); + va_end(ap); + if( sMprintf.zText==sMprintf.zBase ){ + zNew = malloc( sMprintf.nChar+1 ); + if( zNew ) strcpy(zNew,zBuf); + }else{ + zNew = realloc(sMprintf.zText,sMprintf.nChar+1); + } + + *out = zNew; + + return r; +} + +/* This is the varargs version of mprintf. +** +** The name is changed to TclVMPrintf() to conform with Tcl naming +** conventions. +*/ +int vasprintf(char ** out, const char *zFormat,va_list ap){ + struct sgMprintf sMprintf; + char zBuf[200]; + int r; + sMprintf.nChar = 0; + sMprintf.zText = zBuf; + sMprintf.nAlloc = sizeof(zBuf); + sMprintf.zBase = zBuf; + r = vxprintf(mout,&sMprintf,zFormat,ap); + if( sMprintf.zText==sMprintf.zBase ){ + sMprintf.zText = malloc( strlen(zBuf)+1 ); + if( sMprintf.zText ) strcpy(sMprintf.zText,zBuf); + }else{ + sMprintf.zText = realloc(sMprintf.zText,sMprintf.nChar+1); + } + *out = sMprintf.zText; + return r; +} + +/* +** The following section of code handles the standard fprintf routines +** for pthreads. +*/ + +/* The xprintf callback function. */ +static void fout(zNewText,nNewChar,arg) + char *zNewText; + int nNewChar; + void *arg; +{ + fwrite(zNewText,1,nNewChar,(FILE*)arg); +} + +/* The public interface routines */ +int fprintf(FILE *pOut, const char *zFormat, ...){ + va_list ap; + int retc; + + va_start(ap,zFormat); + retc = vxprintf(fout,pOut,zFormat,ap); + va_end(ap); + return retc; +} +int vfprintf(FILE *pOut, const char *zFormat, va_list ap){ + return vxprintf(fout,pOut,zFormat,ap); +} +int printf(const char *zFormat, ...){ + va_list ap; + int retc; + + va_start(ap,zFormat); + retc = vxprintf(fout,stdout,zFormat,ap); + va_end(ap); + return retc; +} +int vprintf(const char *zFormat, va_list ap){ + return vxprintf(fout,stdout,zFormat,ap); +} diff --git a/os/Makefile b/os/Makefile index 37dbf56..763f907 100644 --- a/os/Makefile +++ b/os/Makefile @@ -6,6 +6,7 @@ include $(ROOTDIR)/common.mk include config.mk include $(ROOTDIR)/FreeRTOS/config.mk include $(ROOTDIR)/arch/config.mk +include $(ROOTDIR)/libc/config.mk TARGET_SRCS = \ src/init.c \ @@ -17,25 +18,7 @@ src/hash-djb2.c \ src/osdebug.c \ src/romfs.c \ \ -src/close.c \ -src/fstat.c \ -src/isatty.c \ -src/lseek.c \ -src/open.c \ -src/read.c \ src/sbrk.c \ -src/write.c \ -\ -src/fclose.c \ -src/fflush.c \ -src/fopen.c \ -src/fprintf.c \ -src/fread.c \ -src/free.c \ -src/fwrite.c \ -src/malloc.c \ -src/printf.c \ -src/sprintf.c \ ifeq ($(CPU),arm) TARGET_SRCS += src/semifs.c diff --git a/os/src/close.c b/os/src/close.c deleted file mode 100644 index 5da8b2c..0000000 --- a/os/src/close.c +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include -#include "fio.h" -#include "osdebug.h" - -int _close_r(struct _reent * reent, int fd) { -// DBGOUT("_close_r(%p, %i)\r\n", reent, fd); - if (!fio_is_open(fd)) { - reent->_errno = EBADF; - return -1; - } - - return fio_close(fd); -} diff --git a/os/src/fclose.c b/os/src/fclose.c deleted file mode 100644 index 4c4c3fc..0000000 --- a/os/src/fclose.c +++ /dev/null @@ -1,8 +0,0 @@ -#include -#include -#include "osdebug.h" - -int fclose(FILE * fp) { -// DBGOUT("fclose(%p)\r\n", fp); - return _fclose_r(_impure_ptr, fp); -} diff --git a/os/src/fflush.c b/os/src/fflush.c deleted file mode 100644 index 84e2c67..0000000 --- a/os/src/fflush.c +++ /dev/null @@ -1,7 +0,0 @@ -#include -#include "osdebug.h" - -int fflush(FILE * file) { -// DBGOUT("fflush(%p)\r\n", file); - return _fflush_r(_impure_ptr, file); -} diff --git a/os/src/fio.c b/os/src/fio.c index 432f7e2..d579bf4 100644 --- a/os/src/fio.c +++ b/os/src/fio.c @@ -3,9 +3,11 @@ #include #include #include +#ifdef USE_NEWLIB #include #include #include +#endif #include "fio.h" #include "filesystem.h" #include "osdebug.h" diff --git a/os/src/fopen.c b/os/src/fopen.c deleted file mode 100644 index 22ac269..0000000 --- a/os/src/fopen.c +++ /dev/null @@ -1,8 +0,0 @@ -#include -#include -#include "osdebug.h" - -FILE * fopen(const char * path, const char * mode) { -// DBGOUT("fopen(\"%s\", \"%s\")\r\n", path, mode); - return _fopen_r(_impure_ptr, path, mode); -} diff --git a/os/src/fprintf.c b/os/src/fprintf.c deleted file mode 100644 index a56ed33..0000000 --- a/os/src/fprintf.c +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include -#include -#include "osdebug.h" - -int fprintf(FILE * file, const char * fmt, ...) { - int r; - va_list ap; -// DBGOUT("fprintf(%p, %p, ...)\r\n", file, fmt); - va_start(ap, fmt); - r = _vfprintf_r(_impure_ptr, file, fmt, ap); - va_end(ap); - return r; -} diff --git a/os/src/fread.c b/os/src/fread.c deleted file mode 100644 index 3f39c1e..0000000 --- a/os/src/fread.c +++ /dev/null @@ -1,7 +0,0 @@ -#include -#include "osdebug.h" - -size_t fread(void * ptr, size_t size, size_t nmemb, FILE * file) { -// DBGOUT("fread(%p, %i, %i, %p)\r\n", ptr, size, nmemb, file); - return _fread_r(_impure_ptr, ptr, size, nmemb, file); -} diff --git a/os/src/free.c b/os/src/free.c deleted file mode 100644 index a011077..0000000 --- a/os/src/free.c +++ /dev/null @@ -1,8 +0,0 @@ -#include -#include -#include "osdebug.h" - -void free(void * ptr) { -// DBGOUT("free(%p)\r\n", ptr); - _free_r(_impure_ptr, ptr); -} diff --git a/os/src/fstat.c b/os/src/fstat.c deleted file mode 100644 index a7c251f..0000000 --- a/os/src/fstat.c +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include -#include -#include -#include "fio.h" -#include "osdebug.h" - -int _fstat_r(struct _reent * reent, int fd, struct stat * buf) { - off_t c; -// DBGOUT("_fstat_r(%p, %i, %p)\r\n", reent, fd, buf); - memset(buf, 0, sizeof(struct stat)); - - if (!fio_is_open(fd)) { - reent->_errno = EBADF; - return -1; - } - - buf->st_mode = S_IFCHR; - buf->st_blksize = 1024; - c = fio_seek(fd, 0, SEEK_CUR); - if (c >= 0) { - buf->st_size = fio_seek(fd, 0, SEEK_END); - fio_seek(fd, c, SEEK_SET); - } - - return 0; -} diff --git a/os/src/fwrite.c b/os/src/fwrite.c deleted file mode 100644 index 6a10db0..0000000 --- a/os/src/fwrite.c +++ /dev/null @@ -1,7 +0,0 @@ -#include -#include "osdebug.h" - -size_t fwrite(const void * ptr, size_t size, size_t nmemb, FILE * file) { -// DBGOUT("fwrite(%p, %i, %i, %p)\r\n", ptr, size, nmemb, file); - return _fwrite_r(_impure_ptr, ptr, size, nmemb, file); -} diff --git a/os/src/init.c b/os/src/init.c index 5ab7899..edbae0a 100644 --- a/os/src/init.c +++ b/os/src/init.c @@ -1,4 +1,5 @@ #include +#include #include void __libc_init_array(); @@ -27,3 +28,11 @@ void _start() { atexit(__libc_fini_array); exit(main(0, NULL, NULL)); } + +void startup_memcpy(void * dest, const void * src, size_t n) { + memcpy(dest, src, n); +} + +void startup_memset(void * dest, int c, size_t n) { + memset(dest, c, n); +} diff --git a/os/src/isatty.c b/os/src/isatty.c deleted file mode 100644 index b37a9dc..0000000 --- a/os/src/isatty.c +++ /dev/null @@ -1,15 +0,0 @@ -#include -#include -#include -#include "fio.h" -#include "osdebug.h" - -int _isatty_r(struct _reent * reent, int fd) { -// DBGOUT("_isatty_r(%p, %i)\r\n", reent, fd); - if (!fio_is_open(fd)) { - reent->_errno = EBADF; - return 0; - } - reent->_errno = EINVAL; - return 0; -} diff --git a/os/src/lseek.c b/os/src/lseek.c deleted file mode 100644 index 1e904a5..0000000 --- a/os/src/lseek.c +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include -#include -#include "fio.h" -#include "osdebug.h" - -_off_t _lseek_r(struct _reent * reent, int fd, _off_t seek, int wheel) { - off_t r; -// DBGOUT("_lseek_r(%p, %i, %i, %i)\r\n", reent, fd, seek, wheel); - - if ((wheel != SEEK_SET) && (wheel != SEEK_CUR) && (wheel != SEEK_END)) { - reent->_errno = EINVAL; - return -1; - } - - if (!fio_is_open(fd)) { - reent->_errno = EBADF; - return -1; - } - - r = fio_seek(fd, seek, wheel); - - if (r < 0) - reent->_errno = EINVAL; - - return r; -} diff --git a/os/src/malloc.c b/os/src/malloc.c deleted file mode 100644 index 3d867d0..0000000 --- a/os/src/malloc.c +++ /dev/null @@ -1,23 +0,0 @@ -#include -#include -#include -#include -#include "osdebug.h" - -static xSemaphoreHandle malloc_sem = NULL; - -__attribute__((constructor)) static void malloc_init() { - malloc_sem = xSemaphoreCreateMutex(); -} - -void * malloc(size_t size) { - void * ptr; -// DBGOUT("malloc(%i)\r\n", size); - - if (malloc_sem) - xSemaphoreTake(malloc_sem, portMAX_DELAY); - ptr =_malloc_r(_impure_ptr, size); - if (malloc_sem) - xSemaphoreGive(malloc_sem); - return ptr; -} diff --git a/os/src/open.c b/os/src/open.c deleted file mode 100644 index 5298fd8..0000000 --- a/os/src/open.c +++ /dev/null @@ -1,17 +0,0 @@ -#include -#include -#include -#include "fio.h" -#include "filesystem.h" -#include "osdebug.h" - -int _open_r(struct _reent * reent, const char * path, int flags, int mode) { -// DBGOUT("_open_r(%p, \"%s\", flags, mode)\r\n", reent, path, flags, mode); - int r = fs_open(path, flags, mode); - - if (r >= 0) - return r; - - reent->_errno = EACCES; - return -1; -} diff --git a/os/src/printf.c b/os/src/printf.c deleted file mode 100644 index 80b6b94..0000000 --- a/os/src/printf.c +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include -#include -#include - -int printf(const char * fmt, ...) { - int r; - va_list ap; -// DBGOUT("printf(\"%p\", ...)\r\n", fmt); - va_start(ap, fmt); - r = _vprintf_r(_impure_ptr, fmt, ap); - va_end(ap); - return r; -} diff --git a/os/src/read.c b/os/src/read.c deleted file mode 100644 index 845092b..0000000 --- a/os/src/read.c +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include -#include -#include "fio.h" - -_ssize_t _read_r(struct _reent * reent, int fd, void * buf, size_t size) { - _ssize_t r; - -// DBGOUT("_read_r(%p, %i, %p, %i)\r\n", reent, fd, buf, size); - - if (!fio_is_open(fd)) { - reent->_errno = EBADF; - return -1; - } - - r = fio_read(fd, buf, size); - - if (r < 0) { - reent->_errno = EINVAL; - return -1; - } - - return r; -} diff --git a/os/src/romfs.c b/os/src/romfs.c index 2d11d96..df55f48 100644 --- a/os/src/romfs.c +++ b/os/src/romfs.c @@ -2,9 +2,11 @@ #include #include #include +#ifdef USE_NEWLIB #include #include #include +#endif #include "fio.h" #include "filesystem.h" #include "romfs.h" diff --git a/os/src/sbrk.c b/os/src/sbrk.c index 53efe1e..fcb6b7a 100644 --- a/os/src/sbrk.c +++ b/os/src/sbrk.c @@ -9,27 +9,15 @@ #include "osdebug.h" -// Mostly stolen from mbed-freertos - extern uintptr_t __heap_start; extern uintptr_t __stack_start; -/* Low-level bulk RAM allocator -- used by Newlib's Malloc */ -static void *heap_end = (void *) &__heap_start; - -static xSemaphoreHandle sbrk_sem = NULL; - -__attribute__((constructor)) static void sbrk_init() { - sbrk_sem = xSemaphoreCreateMutex(); -} +static void * heap_end = (void *) &__heap_start; -void *_sbrk_r(struct _reent *ptr, ptrdiff_t incr) { +void * sbrk(ptrdiff_t incr) { void *prev_heap_end, *next_heap_end, *ret; void *stack_min = (void *) &__stack_start; - if (sbrk_sem) - xSemaphoreTake(sbrk_sem, portMAX_DELAY); - prev_heap_end = heap_end; /* Align to always be on 8-byte boundaries */ @@ -37,15 +25,12 @@ void *_sbrk_r(struct _reent *ptr, ptrdiff_t incr) { /* Check if this allocation would exceed the end of the ram - would probably get into the stack first however */ if (next_heap_end > stack_min) { - ptr->_errno = ENOMEM; + _impure_ptr->_errno = ENOMEM; ret = NULL; } else { heap_end = next_heap_end; ret = (void *)prev_heap_end; } - if (sbrk_sem) - xSemaphoreGive(sbrk_sem); - return ret; } diff --git a/os/src/semifs.c b/os/src/semifs.c index fc7d0b1..1d92dc2 100644 --- a/os/src/semifs.c +++ b/os/src/semifs.c @@ -22,7 +22,9 @@ #include #include #include +#ifdef USE_NEWLIB #include +#endif #include diff --git a/os/src/sprintf.c b/os/src/sprintf.c deleted file mode 100644 index 755d780..0000000 --- a/os/src/sprintf.c +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include -#include -#include - -int sprintf(char * str, const char * fmt, ...) { - int r; - va_list ap; -// DBGOUT("sprintf(%p, %p, ...)\r\n", str, fmt); - va_start(ap, fmt); - r = _vsprintf_r(_impure_ptr, str, fmt, ap); - va_end(ap); - return r; -} diff --git a/os/src/write.c b/os/src/write.c deleted file mode 100644 index c54e304..0000000 --- a/os/src/write.c +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include -#include -#include "fio.h" - -_ssize_t _write_r(struct _reent * reent, int fd, const void * buf, size_t size) { - _ssize_t r; - -// DBGOUT("_write_r(%p, %i, %p, %i)\r\n", reent, fd, buf, size); - - if (!fio_is_open(fd)) { - reent->_errno = EBADF; - return -1; - } - - r = fio_write(fd, buf, size); - - if (r < 0) { - reent->_errno = EINVAL; - return -1; - } - - return r; -} diff --git a/target-rules.mk b/target-rules.mk index 3d73a5c..fe6b710 100644 --- a/target-rules.mk +++ b/target-rules.mk @@ -15,9 +15,9 @@ TARGET_MAP = $(addsuffix .map, $(basename $(TARGET))) TARGET_OBJS += $(addsuffix .o, $(basename $(TARGET))) endif -$(TARGET_ELF): $(TARGET_OBJS) $(LIBDEPS) $(LDSCRIPT) +$(TARGET_ELF): $(TARGET_OBJS) $(LIBDEPS) $(LDSCRIPT) $(SPECS) $(E) "[TL] Linking $@" - $(Q)$(TARGET_LD) -Wl,--gc-sections -Wl,-Map=$(TARGET_MAP) -o $@ $(TARGET_OBJS) $(TARGET_LDFLAGS) -g -T$(LDSCRIPT) $(LIBS) + $(Q)$(TARGET_LD) -Wl,--gc-sections -Wl,-Map=$(TARGET_MAP) -o $@ $(TARGET_OBJS) $(TARGET_LDFLAGS) -g -T$(LDSCRIPT) -specs=$(SPECS) $(LIBS) $(TARGET_MAP): $(TARGET_ELF) -- cgit v1.2.3