[PATCH 1/2] Adding a LittleFS-based self-contained target to libgloss

Corinna Vinschen vinschen@redhat.com
Wed Aug 9 10:04:19 GMT 2023


Ping Jeff.

On Aug  1 16:54, Dan Petrisko wrote:
> Co-authored-by: Bandhav Veluri <bandhav.veluri00@gmail.com>
> Co-authored-by: farzamgl <farzamgl@uw.edu>
> Co-authored-by: taylor-bsg <taylor-bsg@users.noreply.github.com>
> ---
> 
> Hello, this is my first time submitting a patch, so let me know of any etiquete errors in addition
> to code errors...
> 
> This patch adds support for *-*-*-dramfs targets, which is a kind of pseudo-BSP which allows you to
> support a filesystem without any I/O hardware support. This is very useful for folks
> developing their own processor cores, or bringing up systems without another host managing a shim
> layer. It relies on ARM LittleFS to create a DRAM-based file system which is prepopulated by the
> user compiling the program. However, once it is created the user is able to use open, write, read
> etc. calls like normal.
> 
> The tool for creating the filesystem (dramfs_mklfs) is included in this
> patch, although it would be reasonable to extract it to its own repo if folks think it's orthogonal
> enough.
> 
> It also adds LittleFS as a submodule to newlib, which I would guess is undesired. However, it's
> required as part of the build process, so not sure what's the preferred way of dealing with that.
> 
> More info is available at: https://github.com/bespoke-silicon-group/bsg_newlib_dramfs/tree/dramfs
> 
> Thanks!
> 
>  .gitmodules                             |   3 +
>  COPYING.LIBGLOSS                        |  27 +++
>  libgloss/dramfs/Makefile.in             | 304 ++++++++++++++++++++++++++++++++
>  libgloss/dramfs/README.md               | 207 ++++++++++++++++++++++
>  libgloss/dramfs/configure.in            |  45 +++++
>  libgloss/dramfs/dramfs/dramfs_fdtable.c |  62 +++++++
>  libgloss/dramfs/dramfs/dramfs_fdtable.h |  23 +++
>  libgloss/dramfs/dramfs/dramfs_fs.c      |  35 ++++
>  libgloss/dramfs/dramfs/dramfs_fs.h      |  32 ++++
>  libgloss/dramfs/dramfs/dramfs_mklfs.c   | 154 ++++++++++++++++
>  libgloss/dramfs/dramfs/dramfs_util.c    | 101 +++++++++++
>  libgloss/dramfs/dramfs/dramfs_util.h    |  13 ++
>  libgloss/dramfs/dramfs/littlefs         |   1 +
>  libgloss/dramfs/sys_close.c             |  14 ++
>  libgloss/dramfs/sys_execve.c            |  13 ++
>  libgloss/dramfs/sys_exit.c              |  14 ++
>  libgloss/dramfs/sys_fork.c              |  12 ++
>  libgloss/dramfs/sys_fstat.c             |  21 +++
>  libgloss/dramfs/sys_getpid.c            |   9 +
>  libgloss/dramfs/sys_gettimeofday.c      |  13 ++
>  libgloss/dramfs/sys_isatty.c            |   9 +
>  libgloss/dramfs/sys_kill.c              |  13 ++
>  libgloss/dramfs/sys_link.c              |  11 ++
>  libgloss/dramfs/sys_lseek.c             |  17 ++
>  libgloss/dramfs/sys_open.c              |  37 ++++
>  libgloss/dramfs/sys_read.c              |  40 +++++
>  libgloss/dramfs/sys_sbrk.c              |  22 +++
>  libgloss/dramfs/sys_stat.c              |  23 +++
>  libgloss/dramfs/sys_times.c             |   8 +
>  libgloss/dramfs/sys_unlink.c            |  12 ++
>  libgloss/dramfs/sys_wait.c              |  12 ++
>  libgloss/dramfs/sys_write.c             |  25 +++
>  32 files changed, 1332 insertions(+)
>  create mode 100644 .gitmodules
>  create mode 100644 libgloss/dramfs/Makefile.in
>  create mode 100644 libgloss/dramfs/README.md
>  create mode 100644 libgloss/dramfs/configure.in
>  create mode 100644 libgloss/dramfs/dramfs/dramfs_fdtable.c
>  create mode 100644 libgloss/dramfs/dramfs/dramfs_fdtable.h
>  create mode 100644 libgloss/dramfs/dramfs/dramfs_fs.c
>  create mode 100644 libgloss/dramfs/dramfs/dramfs_fs.h
>  create mode 100644 libgloss/dramfs/dramfs/dramfs_mklfs.c
>  create mode 100644 libgloss/dramfs/dramfs/dramfs_util.c
>  create mode 100644 libgloss/dramfs/dramfs/dramfs_util.h
>  create mode 160000 libgloss/dramfs/dramfs/littlefs
>  create mode 100644 libgloss/dramfs/sys_close.c
>  create mode 100644 libgloss/dramfs/sys_execve.c
>  create mode 100644 libgloss/dramfs/sys_exit.c
>  create mode 100644 libgloss/dramfs/sys_fork.c
>  create mode 100644 libgloss/dramfs/sys_fstat.c
>  create mode 100644 libgloss/dramfs/sys_getpid.c
>  create mode 100644 libgloss/dramfs/sys_gettimeofday.c
>  create mode 100644 libgloss/dramfs/sys_isatty.c
>  create mode 100644 libgloss/dramfs/sys_kill.c
>  create mode 100644 libgloss/dramfs/sys_link.c
>  create mode 100644 libgloss/dramfs/sys_lseek.c
>  create mode 100644 libgloss/dramfs/sys_open.c
>  create mode 100644 libgloss/dramfs/sys_read.c
>  create mode 100644 libgloss/dramfs/sys_sbrk.c
>  create mode 100644 libgloss/dramfs/sys_stat.c
>  create mode 100644 libgloss/dramfs/sys_times.c
>  create mode 100644 libgloss/dramfs/sys_unlink.c
>  create mode 100644 libgloss/dramfs/sys_wait.c
>  create mode 100644 libgloss/dramfs/sys_write.c
> 
> diff --git a/.gitmodules b/.gitmodules
> new file mode 100644
> index 000000000..4692df17b
> --- /dev/null
> +++ b/.gitmodules
> @@ -0,0 +1,3 @@
> +[submodule "libgloss/dramfs/dramfs/littlefs"]
> +	path = libgloss/dramfs/dramfs/littlefs
> +	url = https://github.com/littlefs-project/littlefs.git
> diff --git a/COPYING.LIBGLOSS b/COPYING.LIBGLOSS
> index c7a4c2924..0b30092a2 100644
> --- a/COPYING.LIBGLOSS
> +++ b/COPYING.LIBGLOSS
> @@ -425,3 +425,30 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
>  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
>  POSSIBILITY OF SUCH DAMAGE.
>  
> +(21) - University of Washington (*-*-*-dramfs targets)
> +
> +Copyright (c) 2023, University of Washington
> +All rights reserved.
> +
> +Redistribution and use in source and binary forms, with or without
> +modification, are permitted provided that the following conditions are met:
> +    * Redistributions of source code must retain the above copyright
> +      notice, this list of conditions and the following disclaimer.
> +    * Redistributions in binary form must reproduce the above copyright
> +      notice, this list of conditions and the following disclaimer in the
> +      documentation and/or other materials provided with the distribution.
> +    * Neither the name of the University of Washington nor the
> +      names of its contributors may be used to endorse or promote products
> +      derived from this software without specific prior written permission.
> +
> +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
> +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
> +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> +DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY
> +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
> +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
> +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
> +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
> +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> +
> diff --git a/libgloss/dramfs/Makefile.in b/libgloss/dramfs/Makefile.in
> new file mode 100644
> index 000000000..a0d8b99a9
> --- /dev/null
> +++ b/libgloss/dramfs/Makefile.in
> @@ -0,0 +1,304 @@
> +#----------------------------------------------------------------------
> +# Newlib File System sources
> +#----------------------------------------------------------------------
> +
> +dramfs_incs = \
> +	-I@srcdir@/dramfs \
> +	-I@srcdir@/dramfs/littlefs/lfs \
> +	-I@srcdir@/dramfs/littlefs/bd
> +
> +dramfs_srcs = \
> +	lfs_mem.c \
> +	dramfs_fs.c \
> +	dramfs_fdtable.c \
> +	lfs.c \
> +	lfs_util.c \
> +	lfs_bd.c
> +
> +dramfs_hdrs = \
> +	dramfs/dramfs_fs.h \
> +	dramfs/dramfs_fdtable.h \
> +	dramfs/littlefs/lfs/lfs.h \
> +	dramfs/littlefs/bd/lfs_bd.h
> +
> +dramfs_mkfs_srcs = \
> +	dramfs_mklfs.c \
> +	dramfs_util.c \
> +	lfs.c \
> +	lfs_util.c \
> +	lfs_bd.c
> +
> +dramfs_mkfs_bin = \
> +	dramfs_mklfs
> +
> +#-------------------------------------------------------------------------
> +# Source files
> +#-------------------------------------------------------------------------
> +gloss_srcs = \
> +	sys_close.c \
> +	sys_execve.c \
> +	sys_exit.c \
> +	sys_fork.c \
> +	sys_fstat.c \
> +	sys_getpid.c \
> +	sys_gettimeofday.c \
> +	sys_isatty.c \
> +	sys_kill.c \
> +	sys_link.c \
> +	sys_lseek.c \
> +	sys_open.c \
> +	sys_read.c \
> +	sys_sbrk.c \
> +	sys_stat.c \
> +	sys_times.c \
> +	sys_unlink.c \
> +	sys_wait.c \
> +	sys_write.c
> +
> +# Extra files
> +
> +crt0_asm      = crt0.S
> +
> +# Multilib support variables.
> +# TOP is used instead of MULTI{BUILD,SRC}TOP.
> +
> +MULTIDIRS =
> +MULTISUBDIR =
> +MULTIDO = true
> +MULTICLEAN = true
> +
> +#-------------------------------------------------------------------------
> +# Basic setup
> +#-------------------------------------------------------------------------
> +
> +# Remove all default implicit rules since they can cause subtle bugs
> +# and they just make things run slower
> +
> +.SUFFIXES:
> +% : %,v
> +% : RCS/%,v
> +% : RCS/%
> +% : s.%
> +% : SCCS/s.%
> +
> +# Default is to build the prereqs of the all target (defined at bottom)
> +
> +default : all
> +.PHONY : default
> +
> +# Source directory
> +
> +obj_dir := .
> +src_dir := @srcdir@
> +VPATH   := $(src_dir) $(src_dir)/machine
> +
> +# Installation directories
> +
> +prefix  := @prefix@
> +DESTDIR ?= $(prefix)
> +
> +install_hdrs_dir := $(DESTDIR)$(prefix)/$(target_alias)/include/machine
> +install_libs_dir  = $(DESTDIR)$(prefix)/$(target_alias)/lib${MULTISUBDIR}
> +install_bins_dir := $(DESTDIR)$(prefix)/$(target_alias)/bin
> +
> +#-------------------------------------------------------------------------
> +# NEWLIB FS build rules 
> +#-------------------------------------------------------------------------
> +
> +dramfs_objs = $(patsubst %.c, %.o, $(dramfs_srcs))
> +
> +vpath %.c @srcdir@/dramfs @srcdir@/dramfs/littlefs/lfs @srcdir@/dramfs/littlefs/bd
> +
> +DRAMFS_CC     = @CC@
> +DRAMFS_CFLAGS = -O1
> +DRAMFS_CFLAGS += $(dramfs_incs)
> +DRAMFS_CFLAGS += -std=c99 -mcmodel=medany
> +DRAMFS_CFLAGS += -DLFS_NO_ASSERT -DLFS_NO_DEBUG \
> +                        -DLFS_NO_WARN -DLFS_NO_ERROR -DLFS_NO_INTRINSICS
> +
> +$(dramfs_objs): %.o : %.c
> +	$(DRAMFS_CC) $(DRAMFS_CFLAGS) -c $< -o $@
> +
> +gloss_hdrs += $(dramfs_hdrs)
> +gloss_objs += $(dramfs_objs)
> +junk += $(dramfs_objs)
> +
> +#-------------------------------------------------------------------------
> +# NEWLIB mkfs rules 
> +#-------------------------------------------------------------------------
> +
> +dramfs_mkfs_objs = $(patsubst %.c, %_host.o, $(dramfs_mkfs_srcs))
> +
> +DRAMFS_MKFS_CC     = gcc
> +DRAMFS_MKFS_CFLAGS = -O1
> +DRAMFS_MKFS_CFLAGS += $(dramfs_incs)
> +DRAMFS_MKFS_CFLAGS += -std=gnu99
> +
> +$(dramfs_mkfs_objs): %_host.o : %.c
> +	$(DRAMFS_MKFS_CC) $(DRAMFS_MKFS_CFLAGS) -c $< -o $@
> +
> +$(dramfs_mkfs_bin): $(dramfs_mkfs_objs)
> +	$(DRAMFS_MKFS_CC) $(dramfs_mkfs_objs) -o $@
> +
> +gloss_bins += $(dramfs_mkfs_bin)
> +
> +#-------------------------------------------------------------------------
> +# Programs and flags 
> +#-------------------------------------------------------------------------
> +
> +# C compiler
> +
> +CC            := @CC@
> +CFLAGS        := @CFLAGS@
> +CFLAGS        += -mcmodel=medany
> +CPPFLAGS      := -I$(obj_dir) -I$(src_dir) $(dramfs_incs) -mcmodel=medany
> +COMPILE       := $(CC) -MMD -MP $(CPPFLAGS) $(CFLAGS)
> +
> +# Library creation
> +
> +AR            := @AR@
> +RANLIB        := @RANLIB@
> +
> +# Installation
> +
> +INSTALL       := @INSTALL@
> +INSTALL_DATA  := @INSTALL_DATA@
> +
> +#-------------------------------------------------------------------------
> +# Build Object Files from C Source
> +#-------------------------------------------------------------------------
> +
> +gloss_c_srcs = $(filter %.c, $(gloss_srcs))
> +gloss_c_objs = $(patsubst %.c, %.o, $(notdir $(gloss_c_srcs)))
> +gloss_c_deps = $(patsubst %.c, %.d, $(notdir $(gloss_c_srcs)))
> +
> +$(gloss_c_objs) : %.o : %.c
> +	$(COMPILE) -c $<
> +
> +gloss_objs += $(gloss_c_objs)
> +deps += $(gloss_c_deps)
> +junk += $(gloss_c_deps) $(gloss_c_objs)
> +
> +#-------------------------------------------------------------------------
> +# Build Object Files from Assembly Source
> +#-------------------------------------------------------------------------
> +
> +gloss_asm_srcs = $(filter %.S, $(gloss_srcs))
> +gloss_asm_objs = $(patsubst %.S, %.o, $(notdir $(gloss_asm_srcs)))
> +gloss_asm_deps = $(patsubst %.S, %.d, $(notdir $(gloss_asm_srcs)))
> +
> +$(gloss_asm_objs) : %.o : %.S
> +	$(COMPILE) -c -o $@ $<
> +
> +gloss_objs += $(gloss_asm_objs)
> +deps += $(gloss_asm_deps)
> +junk += $(gloss_asm_deps) $(gloss_asm_objs)
> +
> +#-------------------------------------------------------------------------
> +# Build libgloss.a
> +#-------------------------------------------------------------------------
> +
> +gloss_lib  = libgloss.a
> +$(gloss_lib) : $(gloss_objs)
> +	$(AR) rcv $@ $^
> +	$(RANLIB) $@
> +
> +junk += $(gloss_lib)
> +
> +install_hdrs += $(gloss_hdrs)
> +install_libs += $(gloss_lib)
> +install_specs += $(gloss_specs)
> +install_bins += $(gloss_bins)
> +
> +#-------------------------------------------------------------------------
> +# Build crt0.o
> +#-------------------------------------------------------------------------
> +
> +crt0_obj  = $(patsubst %.S, %.o, $(crt0_asm))
> +crt0_deps = $(patsubst %.S, %.d, $(crt0_asm))
> +
> +$(crt0_obj) : %.o : %.S
> +	$(COMPILE) -c $<
> +
> +deps += $(crt0_deps)
> +junk += $(crt0_deps) $(crt0_obj)
> +
> +install_libs += $(crt0_obj)
> +
> +#-------------------------------------------------------------------------
> +# Autodependency files
> +#-------------------------------------------------------------------------
> +
> +-include $(deps)
> +
> +deps : $(deps)
> +.PHONY : deps
> +
> +#-------------------------------------------------------------------------
> +# Installation
> +#-------------------------------------------------------------------------
> +
> +install_hdrs_wdir += $(addprefix $(src_dir)/, $(install_hdrs))
> +install-hdrs : $(install_hdrs_wdir)
> +	test -d $(install_hdrs_dir) || mkdir -p $(install_hdrs_dir)
> +	for file in $^; do \
> +		$(INSTALL_DATA) $$file $(install_hdrs_dir)/; \
> +	done
> +
> +install-libs : $(install_libs)
> +	test -d $(install_libs_dir) || mkdir -p $(install_libs_dir)
> +	for file in $^; do \
> +		$(INSTALL_DATA) $$file $(install_libs_dir)/$$file; \
> +	done
> +
> +install-specs : $(install_specs)
> +	test -d $(install_libs_dir) || mkdir -p $(install_libs_dir)
> +	for file in $^; do \
> +		$(INSTALL_DATA) $$file $(install_libs_dir)/; \
> +	done
> +
> +install-bins : $(install_bins)
> +	test -d $(install_bins_dir) || mkdir -p $(install_bins_dir)
> +	for file in $^; do \
> +		$(INSTALL) $$file $(install_bins_dir)/; \
> +	done
> +
> +install : install-hdrs install-libs install-specs install-bins
> +.PHONY : install install-hdrs install-libs
> +
> +#-------------------------------------------------------------------------
> +# Regenerate configure information
> +#-------------------------------------------------------------------------
> +
> +configure_prereq = \
> +  $(src_dir)/configure.in \
> +
> +$(src_dir)/configure : $(configure_prereq)
> +	cd $(src_dir) && autoconf
> +
> +config.status : $(src_dir)/configure
> +	./config.status --recheck
> +
> +Makefile : $(src_dir)/Makefile.in config.status
> +	./config.status
> +
> +dist_junk += config.status Makefile config.log
> +
> +#-------------------------------------------------------------------------
> +# Default
> +#-------------------------------------------------------------------------
> +
> +all : $(install_libs) $(install_bins)
> +.PHONY : all
> +
> +#-------------------------------------------------------------------------
> +# Clean up junk
> +#-------------------------------------------------------------------------
> +
> +clean :
> +	rm -rf *~ \#* $(junk)
> +
> +distclean :
> +	rm -rf *~ \#* $(junk) $(dist_junk)
> +
> +.PHONY : clean distclean
> diff --git a/libgloss/dramfs/README.md b/libgloss/dramfs/README.md
> new file mode 100644
> index 000000000..77c482779
> --- /dev/null
> +++ b/libgloss/dramfs/README.md
> @@ -0,0 +1,207 @@
> +# Newlib/DRAMFS  
> +###### Bandhav Veluri and Michael Taylor, Bespoke Silicon Group UW  
> +
> +Note: Mirror changes to this file to https://github.com/bespoke-silicon-group/bsg_newlib_dramfs/blob/dramfs/README.md
> +
> +## Introduction
> +
> +Newlib is a light-weight C standard library implementation for embedded systems. It elegantly separates system specific functionality (system calls) into an easily portable portion called Libgloss. Libgloss contains system call implementations for different architectures/systems in it. Porting Newlib to an architecture/system essentially involves porting these system call implementations in Libgloss. Complete guide for porting Newlib can be found in [5].
> +
> +Running POSIX programs on bare metal systems require some sort of implementation for file i/o and malloc. Malloc depends on just one system-call called sbrk, which essentially increments or decrements heap pointer as and when requested. Whereas, file i/o requires an actual file system, or an interface that can mimic a file system. This Newlib port uses an open-source lightweight file-system designed for embedded flash file systems by ARM called LittleFS (LFS). LittleFS also supports a DRAM-based file system, which is the one we use. 
> +
> +The idea is to implement file i/o syscalls by simply translating them to LFS function calls, which in turn will operate on memory, rather than trying to use a more complex I/O emulation facility, like proxy kernels, that package up I/O calls and ship them over to a host. This allows for more reproducible I/O emulation, since the host is no longer an asynchronous process. It also eliminates the infrastructure pain caused by mapping these proxy-IO calls to different embodiments of the design -- simulator, VCS, verilator, FPGA emulation, ASIC testboard, and PCI-e hosted chip.
> +
> +## Installation
> +
> +Newlib/Dramfs is intended to be a separate Board Support Package (BSP) in Newlib. Newlib can be configured to install this BSP by setting the target to end with `dramfs`:
> +
> +```
> +$ ./configure --target=<AnyArchiteture>-<AnyVendor>-<AnyString>dramfs [<other options>]
> +```
> +
> +Since this BSP works with any ISA, architecture field could be anything!
> +
> +## Porting
> +
> +Porting Newlib/Dramfs requires following four steps:
> +1. Implement `dramfs_exit(int)` (routine to exit the execution environment). 
> +2. Implement `dramfs_sendchar(char)` (routine to output non-file I/O (for debugging etc)).
> +3. Implment C-runtime initiation including a call to `dramfs_fs_init()` in it.
> +4. Implement linker command script including definition of `_end` symbol (heap pointer) in it.
> +
> +#### 1, 2. Interfacing functions:
> +```
> +/*
> + * dramfs_intf.c
> + * 
> + * Sample Implementation of Newlib/DRAMFS interface
> + */
> +
> +#include <stdlib.h>
> +#include <machine/dramfs_fs.h> // This header is installed with this BSP!
> +
> +void dramfs_exit(int exit_status) {
> +  if(exit_status == EXIT_SUCCESS) {
> +    // Exit the environment successfully
> +    
> +    // Replace this with code to exit
> +    // successfully on your system.
> +  } else {
> +    // Exit the environment with failure
> +    
> +    // Replace this with code to exit
> +    // with failure on your system.
> +  }
> +
> +  // do nothing until we exit
> +  while(1);
> +}
> +
> +void dramfs_sendchar(char ch) {
> +  // code to display ‘ch’
> +  // in many cases you may just want to have a memory
> +  // mapped I/O location that you write to
> +  // whether that is simulator magic, a NOC, a UART, or PCIe.
> +}
> +```
> +
> +#### 3. Adding `dramfs_fs_init` call to C-runtime initialization code:
> +
> +The function `dramfs_fs_init` (implemented in this BSP) has to called before calling the main. This step mounts the LittleFS image using a tiny block device driver implemeted by us. A sample C-runtime initialization is provided below:
> +
> +```
> +# Sample crt.S
> +# 
> +# This is architecture specific; hence user would implement this code
> +# Following example is for a RISC-V system.
> +
> +.section .crtbegin,"a"
> +
> +.globl _start
> +_start:
> +
> +  # initialize global pointer
> +  la gp, _gp
> +
> +  # initialize stack pointer
> +  la sp, _sp
> +
> +  call dramfs_fs_init # initialize dramfs
> +  lw a0, 0(sp)        # argc
> +  lw a1, -4(sp)       # argv
> +  li a2, 0            # envp = NULL
> +  call main
> +  tail exit
> +
> +2:
> +  # Should never this point
> +  j 2b
> +```
> +
> +#### 4. Defining `_end` symbol in the linker command file:
> +
> +This can be done as shown in the sample linker script below:
> +
> +```
> +/* link.ld */
> +/* Sample linker command file */
> +
> +SECTIONS
> +{
> +  . = 0x80000000; /* text and data start at 0x80000000 */
> +
> +  .text : {
> +     *(.crtbegin)
> +     *(.text)
> +     *(.text.startup)
> +     *(.text.*)
> +  }
> +
> +  .data : {
> +    *(.data*)
> +    *(.rodata*)
> +    *(.sdata .sdata.* .srodata*)
> +  }
> +
> +  /* global pointer */
> +  _gp = .;
> +
> +  .bss : {
> +    *(.bss*)
> +    *(.sbss*)
> +  }
> +
> +  /* Initial heap pointer */
> +  _end = . ;
> + 
> +  /* Initial stack pointer */
> +  _sp = 0x81000000;
> +}
> +```
> +
> +## Usage
> +
> +Running a program with Newlib/Dramfs requires user to link an additional file consisting of initial LittleFS image with input files to the program. LittleFS image can be automatically generated by a tool called `dramfs_mklfs` that has already been installed with this BSP! The tool needs two parameters `lfs_block_size` and `lfs_block_count`. Total size of the file-system would be `lfs_block_size*lfs_block_count`. See [2] for information about how to play with these parameters to improve performance.
> +
> +Usage of `dramfs_mklfs`:
> +```
> +dramfs_mklfs <lfs_block_size> <lfs_block_count> <inputfile1> <inputdir1> <inputfile2> ...
> +```
> +
> +After installation and porting, the procedure for running programs with Newlib/Dramfs is summarized by a sample program below. Let's say we want to run a file i/o program on a bare metal system which takes `hello.txt` as input.
> +
> +```
> +$ cat fhello.c 
> +/*
> + * fhello.c
> + */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +
> +int main() {
> +  int c;
> +
> +  /* Open hello.txt for reading */
> +  FILE *hello = fopen("hello.txt", "r");
> +  if(hello == NULL)
> +    return -1;
> +
> +
> +  /* Iterate through the entire file
> +   * and print the contents to stdout
> +   */
> +
> +  putchar('\n');
> +
> +  while((c = fgetc(hello)) != EOF) {
> +    putchar(c);
> +  }
> +
> +  fclose(hello);
> +  return 0;
> +}
> +$ cat hello.txt 
> +Hello! This is Little FS!
> +$ dramfs_mklfs 128 256 hello.txt > lfs_mem.c
> +$ <xxx>-<xxx>-<xxx>dramfs-gcc -c crt.S lfs_mem.c dramfs_intf.c fhello.c
> +$ <xxx>-<xxx>-<xxx>dramfs-gcc -nostartfiles -T link.ld lfs_mem.o crt.o dramfs_intf.o fhello.o  -o fhello
> +$ <Your system's runtime executable> fhello
> +
> +Hello! This is Little FS!
> +```
> +
> +## Notes
> +
> +- Newlib is implemented on top of a set of operating system syscalls listed in [4]. Newlib/dramfs currently implements `sbrk`, `open`, `close`, `read`, `write`, `exit`, `lseek`, `stat` and `fstat`. These are sufficient to handle the vast majority of newlib POSIX calls. For those that are not supported, they return setting appropriate error number. We plan to increase this set over time, and also encourage your pull requests.
> +- Block size and count can be tweaked to improve performance depending on your system. More on this can be understood from [2].
> +- Current implementations of syscalls are *not* thread-safe. So, this can only be used for single threaded programs as of now.
> +
> +## References
> +
> +[1] Bootstrapping Idea: https://drive.google.com/open?id=1_Ie94nZvyvMjEb1GQTPzfcBNaVs6xfVXZ_bHTH5_z3k  
> +[2] LittleFS: https://github.com/ARMmbed/littlefs  
> +[3] RISC-V BSP: https://github.com/riscv/riscv-newlib/tree/riscv-newlib-3.1.0/libgloss/riscv  
> +[4] Newlib OS interface: https://sourceware.org/newlib/libc.html#Syscalls  
> +[5] Newlib porting guide: https://www.embecosm.com/appnotes/ean9/ean9-howto-newlib-1.0.html 
> diff --git a/libgloss/dramfs/configure.in b/libgloss/dramfs/configure.in
> new file mode 100644
> index 000000000..5694013d4
> --- /dev/null
> +++ b/libgloss/dramfs/configure.in
> @@ -0,0 +1,45 @@
> +#=========================================================================
> +# configure.ac for riscv libgloss and crt0
> +#=========================================================================
> +
> +#-------------------------------------------------------------------------
> +# Setup
> +#-------------------------------------------------------------------------
> +
> +AC_INIT([crt0.S])
> +AC_CONFIG_SRCDIR([crt0.S])
> +AC_CONFIG_AUX_DIR([${srcdir}/../..])
> +
> +#-------------------------------------------------------------------------
> +# Checks for programs
> +#-------------------------------------------------------------------------
> +
> +LIB_AC_PROG_CC
> +AC_CHECK_TOOL([AR],[ar])
> +AC_CHECK_TOOL([RANLIB],[ranlib])
> +AC_PROG_INSTALL
> +
> +#-------------------------------------------------------------------------
> +# Output
> +#-------------------------------------------------------------------------
> +
> +if test "$srcdir" = "." ; then
> +  if test "${with_target_subdir}" != "." ; then
> +    libgloss_topdir="${srcdir}/${with_multisrctop}../../.."
> +  else
> +    libgloss_topdir="${srcdir}/${with_multisrctop}../.."
> +  fi
> +else
> +  libgloss_topdir="${srcdir}/../.."
> +fi
> +AC_CONFIG_AUX_DIR($libgloss_topdir)
> +AC_CONFIG_FILES(Makefile,
> +. ${libgloss_topdir}/config-ml.in,
> +srcdir=${srcdir}
> +target=${target}
> +with_multisubdir=${with_multisubdir}
> +ac_configure_args="${ac_configure_args} --enable-multilib"
> +CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
> +libgloss_topdir=${libgloss_topdir}
> +)
> +AC_OUTPUT
> diff --git a/libgloss/dramfs/dramfs/dramfs_fdtable.c b/libgloss/dramfs/dramfs/dramfs_fdtable.c
> new file mode 100644
> index 000000000..32cfb28f9
> --- /dev/null
> +++ b/libgloss/dramfs/dramfs/dramfs_fdtable.c
> @@ -0,0 +1,62 @@
> +#include "dramfs_fdtable.h"
> +#include "dramfs_fs.h"
> +
> +typedef struct dramfs_fd_entry {
> +  int used;
> +  int nonblock;
> +  lfs_file_t file;
> +} dramfs_fd_entry_t;
> +
> +static dramfs_fd_entry_t dramfs_fdtable[DRAMFS_MAX_FDS];
> +
> +void dramfs_init_fdtable(void) {
> +  for(int i=0; i<DRAMFS_MAX_FDS; i++) {
> +    dramfs_fdtable[i].used = 0;
> +    dramfs_fdtable[i].nonblock = 0;
> +  }
> +}
> +
> +int dramfs_check_fd(int fd) {
> +  if(fd < 0 || fd >= DRAMFS_MAX_FDS || dramfs_fdtable[fd].used == 0) {
> +    errno = EBADF;
> +    return -1;
> +  }
> +
> +  return 0;
> +}
> +
> +int dramfs_nonblock_fd(int fd) {
> +  if(dramfs_fdtable[fd].nonblock == 1) {
> +    return 1;
> +  }
> +
> +  return 0;
> +}
> +
> +int dramfs_reserve_fd(void) {
> +  int fd = 0;
> +
> +  for(;fd < DRAMFS_MAX_FDS; fd++) {
> +    if(dramfs_fdtable[fd].used == 0) {
> +      dramfs_fdtable[fd].used = 1;
> +      return fd;
> +    }
> +  }
> +
> +  errno = ENFILE;
> +  return -1;
> +}
> +
> +lfs_file_t *dramfs_get_file(int fd) {
> +  return &dramfs_fdtable[fd].file;
> +}
> +
> +int dramfs_free_fd(int fd) {
> +  if (dramfs_fdtable[fd].used == 1) {
> +    lfs_file_t *fptr = dramfs_get_file(fd);
> +    dramfs_fdtable[fd].used = 0;
> +    return lfs_file_close(&dramfs_fs, fptr);
> +  } else {
> +    return 0;
> +  }
> +}
> diff --git a/libgloss/dramfs/dramfs/dramfs_fdtable.h b/libgloss/dramfs/dramfs/dramfs_fdtable.h
> new file mode 100644
> index 000000000..f26fd7613
> --- /dev/null
> +++ b/libgloss/dramfs/dramfs/dramfs_fdtable.h
> @@ -0,0 +1,23 @@
> +#ifndef DRAMFS_FDTABLE_H
> +#define DRAMFS_FDTABLE_H
> +
> +#include <errno.h>
> +#include "lfs.h"
> +
> +#ifndef DRAMFS_MAX_FDS
> +#define DRAMFS_MAX_FDS 20
> +#endif
> +
> +void dramfs_init_fdtable(void);
> +
> +int dramfs_check_fd(int fd);
> +
> +int dramfs_nonblock_fd(int fd);
> +
> +int dramfs_reserve_fd(void);
> +
> +int dramfs_free_fd(int fd);
> +
> +lfs_file_t *dramfs_get_file(int fd);
> +
> +#endif // DRAMFS_FDTABLE_H
> diff --git a/libgloss/dramfs/dramfs/dramfs_fs.c b/libgloss/dramfs/dramfs/dramfs_fs.c
> new file mode 100644
> index 000000000..b4d6c51ae
> --- /dev/null
> +++ b/libgloss/dramfs/dramfs/dramfs_fs.c
> @@ -0,0 +1,35 @@
> +#include <unistd.h>
> +#include <fcntl.h>
> +#include "lfs.h"
> +#include "lfs_bd.h"
> +#include "dramfs_fs.h"
> +#include "dramfs_fdtable.h"
> +
> +// File system memory pointer
> +uint8_t* lfs_ptr = lfs_mem;
> +
> +// Init routine for Newlib FS
> +int dramfs_fs_init() {
> +  // initiate fdtable
> +  dramfs_init_fdtable();
> +
> +	// mount the file system
> +	if(lfs_mount(&dramfs_fs, &dramfs_fs_cfg) < 0) {
> +		return -1;
> +	}
> +
> +  // Open stdio files
> +  if(open("stdin", O_RDONLY) != 0) { 
> +    return -1;
> +  }
> +
> +  if(open("stdout", O_WRONLY) != 1) {
> +    return -1;
> +  }
> +
> +  if(open("stderr", O_WRONLY) != 2) {
> +    return -1;
> +  }
> +
> +	return 0;
> +}
> diff --git a/libgloss/dramfs/dramfs/dramfs_fs.h b/libgloss/dramfs/dramfs/dramfs_fs.h
> new file mode 100644
> index 000000000..94f38d37d
> --- /dev/null
> +++ b/libgloss/dramfs/dramfs/dramfs_fs.h
> @@ -0,0 +1,32 @@
> +#ifndef DRAMFS_FS_H
> +#define DRAMFS_FS_H
> +
> +#include "lfs.h"
> +
> +// Toplevel filesystem struct
> +extern lfs_t dramfs_fs;
> +
> +// File system configuration structure
> +// Initalized externally and can be generated by dramfs_mklfs
> +extern struct lfs_config dramfs_fs_cfg;
> +
> +// Array with initial LFS image
> +// Initialized externally and can be generated by dramfs_mklfs
> +extern uint8_t lfs_mem[];
> +
> +// Exit routine: exit() calls this routine
> +// Definition provided externally by user
> +extern void dramfs_exit(int);
> +
> +// Utility to print a char to console
> +// Definition provided externally by user
> +extern void dramfs_sendchar(char);
> +
> +// Utility to get a char from console
> +// Definition provided externally by user
> +extern int dramfs_getchar(void);
> +
> +// LFS init routine: Should be called before calling main
> +int dramfs_fs_init(void) __attribute__((weak));
> +
> +#endif // DRAMFS_FS_H
> diff --git a/libgloss/dramfs/dramfs/dramfs_mklfs.c b/libgloss/dramfs/dramfs/dramfs_mklfs.c
> new file mode 100644
> index 000000000..1bdf7d0f5
> --- /dev/null
> +++ b/libgloss/dramfs/dramfs/dramfs_mklfs.c
> @@ -0,0 +1,154 @@
> +// Program to create littlefs image comprising of input files/dirs
> +//
> +// Bandhav Veluri
> +// 03-07-2019
> +
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include "lfs.h"
> +#include "lfs_bd.h"
> +#include "dramfs_util.h"
> +
> +// Main file system struct
> +lfs_t lfs;
> +
> +// LFS configuration
> +struct lfs_config lfs_cfg = {
> +    // block device operations: lfs_bd.h
> +    .read  = lfs_read,
> +    .prog  = lfs_prog,
> +    .erase = lfs_erase,
> +    .sync  = lfs_sync,
> +
> +    // block device default configuration
> +    .read_size   = 32,
> +    .prog_size   = 32,
> +    .block_size  = 0,
> +    .block_count = 0,
> +    .lookahead   = 32
> +};
> +
> +// Pointer to filesystem memory
> +// lfs_bd uses this allocation as block device
> +uint8_t *lfs_ptr;
> +
> +int main(int argc, char *argv[]) {
> +  int block_size;
> +  int block_count;
> +  FILE *img; // output fs image file handler
> +
> +  if(argc < 3) {
> +    printf("Usage: dramfs_mklfs <block_size> <block_count> [input file(s)/dir(s)]\n");
> +    return -1;
> +  }
> +
> +  block_size = atoi(argv[1]);
> +  block_count = atoi(argv[2]);
> +
> +
> +  //+------------------------------------------------------
> +  //| Allocate memory for building Little FS image
> +  //+------------------------------------------------------
> +
> +  // memory allocation for lfs
> +  lfs_ptr = (char *) malloc(block_size*block_count);
> +
> +  // configure the size
> +  lfs_cfg.block_size = block_size;
> +  lfs_cfg.block_count = block_count;
> +
> +  // format the fs
> +  if(lfs_format(&lfs, &lfs_cfg) < 0) {
> +    printf("LFS format error\n");
> +    return -1;
> +  }
> +
> +  // mount the file system
> +  if(lfs_mount(&lfs, &lfs_cfg) < 0) {
> +    printf("LFS mount error\n");
> +    return -1;
> +  }
> +  
> +
> +  //+-------------------------------------------------------
> +  //| Create stdin, stdout and stderr files in the littlefs
> +  //+-------------------------------------------------------
> +    
> +  lfs_file_t lfs_stdin, lfs_stdout, lfs_stderr;
> +
> +  // Create stdio files
> +  lfs_file_open(&lfs, &lfs_stdin, "stdin", LFS_O_WRONLY | LFS_O_CREAT);
> +  lfs_file_open(&lfs, &lfs_stdout, "stdout", LFS_O_WRONLY | LFS_O_CREAT);
> +  lfs_file_open(&lfs, &lfs_stderr, "stderr", LFS_O_WRONLY | LFS_O_CREAT);
> +
> +  // Close stdio files
> +  lfs_file_close(&lfs, &lfs_stdin);
> +  lfs_file_close(&lfs, &lfs_stdout);
> +  lfs_file_close(&lfs, &lfs_stderr);
> +
> +
> +  //+-------------------------------------------------------
> +  //| Copy input files/dirs to LFS image
> +  //+-------------------------------------------------------
> +
> +  for(int i = 3; i < argc; i++) {
> +    if(lfs_cp(argv[i], &lfs) < 0)
> +      return -1;
> +  }
> +
> +  // Unmount lfs
> +  if(lfs_unmount(&lfs) < 0){
> +    printf("LFS unmounting error\n");
> +    return -1;
> +  }
> +
> +
> +  //+------------------------------------------------------
> +  //| Print the LFS image as a C array
> +  //+------------------------------------------------------
> +
> +  printf("// Newlib File System Initialization\n");
> +  printf("//\n");
> +  printf("// Autogenerated by dramfs_mkfs utility\n");
> +  printf("\n");
> +  printf("#include <sys/types.h>\n");
> +  printf("#include <machine/lfs.h>\n");
> +  printf("#include <machine/lfs_bd.h>\n");
> +  printf("\n");
> +
> +  printf( "// LFS configuration\n"
> +          "struct lfs_config dramfs_fs_cfg = {\n"
> +          "    // block device operations: lfs_bd.h\n"
> +          "    .read  = lfs_read,\n"
> +          "    .prog  = lfs_prog,\n"
> +          "    .erase = lfs_erase,\n"
> +          "    .sync  = lfs_sync,\n"
> +          "\n"
> +          "    // block device default configuration\n"
> +          "    .read_size   = 32,\n"
> +          "    .prog_size   = 32,\n"
> +          "    .block_size  = %d,\n"
> +          "    .block_count = %d,\n"
> +          "    .lookahead   = 32\n"
> +          "};\n\n", block_size, block_count);
> +
> +  printf("lfs_t dramfs_fs;\n");
> +
> +  printf("uint8_t lfs_mem[] = {\n");
> +  
> +  // dump fs memory to stdout in C array format
> +  for(int i=0; i < block_size*block_count; i++) {
> +    printf("0x%0x", lfs_ptr[i]);
> +
> +    if(i != (block_size*block_count) - 1)
> +      putchar(',');
> +
> +    putchar('\n');
> +  }
> +
> +  printf("};");
> +
> +  return 0;
> +}
> diff --git a/libgloss/dramfs/dramfs/dramfs_util.c b/libgloss/dramfs/dramfs/dramfs_util.c
> new file mode 100644
> index 000000000..3b5e4aed9
> --- /dev/null
> +++ b/libgloss/dramfs/dramfs/dramfs_util.c
> @@ -0,0 +1,101 @@
> +// Newlib utility functions
> +//
> +// Bandhav Veluri
> +// 08/15/2019
> +
> +#include <stdio.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <unistd.h>
> +#include <dirent.h>
> +#include <string.h>
> +#include "dramfs_util.h"
> +
> +int is_file(const char* path) {
> +	struct stat s;
> +	stat(path, &s);
> +	return S_ISREG(s.st_mode);
> +}
> +
> +int is_dir(const char* path) {
> +	struct stat s;
> +	stat(path, &s);
> +	return S_ISDIR(s.st_mode);
> +}
> +
> +int cp_file_to_lfs(const char* path, lfs_t* lfs) {
> +	if(!is_file(path)) {
> +		return -1;
> +	}
> +
> +  // open input file for reading
> +  FILE *infile = fopen(path, "r");
> +  if(infile == NULL) {
> +  	fprintf(stderr, "Error opening input file %s\n", path);
> +  	return -1;
> +  }
> +
> +  // create a lfs file for writing
> +  lfs_file_t lfs_file;
> +  if(lfs_file_open(lfs, &lfs_file, path, LFS_O_WRONLY | LFS_O_CREAT) < 0) {
> +  	fprintf(stderr, "LFS file open error %s\n", path);
> +  	return -1;
> +  }
> +
> +  int c = fgetc(infile);
> +  while (c != EOF) {
> +  	lfs_file_write(lfs, &lfs_file, &c, 1);
> +  	c = fgetc(infile);
> +  }
> +
> +  fclose(infile);
> +  lfs_file_close(lfs, &lfs_file);
> +
> +	return 0;
> +}
> +
> +int lfs_cp(const char* path, lfs_t* lfs) {
> +	if(is_file(path)) {
> +		return cp_file_to_lfs(path, lfs);
> +	} else if(is_dir(path)) {
> +		DIR* dir;
> +		struct dirent* ent;
> +
> +		if(dir = opendir(path)) {
> +			if(lfs_mkdir(lfs, path) < 0) {
> +				fprintf(stderr, "LFS COPY: Error creating %s in lfs\n", path);
> +				return -1;
> +			}
> +
> +			while(ent = readdir(dir)) {
> +				// Build the full path of file or dir
> +				char sep[] = "/";
> +				char* ent_full_path = (char*) malloc(strlen(path)+strlen(sep)+strlen(ent->d_name)+1);
> +				strcpy(ent_full_path, path);
> +				strcat(ent_full_path, sep);
> +				strcat(ent_full_path, ent->d_name);
> +
> +				if((strcmp(ent->d_name, ".") == 0) | (strcmp(ent->d_name, "..")==0)) {
> +					continue;
> +				} else {
> +					if(ent->d_type == DT_REG) {
> +						if(cp_file_to_lfs(ent_full_path, lfs) < 0) 
> +							return -1;
> +					} else if(ent->d_type == DT_DIR) {
> +						// Recursively copy the dir
> +						if(lfs_cp(ent_full_path, lfs) < 0)
> +							return -1;
> +					}
> +				}
> +			}
> +
> +			return 0;
> +		} else {
> +			fprintf(stderr, "LFS COPY: Error opening directory %s\n", path);
> +			return -1;
> +		}
> +	}
> +
> +	fprintf(stderr, "LFS COPY: argument should be a file or directory\n");
> +	return -1;
> +}
> diff --git a/libgloss/dramfs/dramfs/dramfs_util.h b/libgloss/dramfs/dramfs/dramfs_util.h
> new file mode 100644
> index 000000000..3c68c46d7
> --- /dev/null
> +++ b/libgloss/dramfs/dramfs/dramfs_util.h
> @@ -0,0 +1,13 @@
> +#include "lfs.h"
> +
> +// Check if a path is a regular file
> +int is_file(const char*);
> +
> +// Check if a path is a directory
> +int is_dir(const char*);
> +
> +// Copy a file to lfs struct
> +int cp_file_to_lfs(const char*, lfs_t*);
> +
> +// Copy a file/directory recursively to lfs struct
> +int lfs_cp(const char*, lfs_t*);
> diff --git a/libgloss/dramfs/dramfs/littlefs b/libgloss/dramfs/dramfs/littlefs
> new file mode 160000
> index 000000000..611c9b20d
> --- /dev/null
> +++ b/libgloss/dramfs/dramfs/littlefs
> @@ -0,0 +1 @@
> +Subproject commit 611c9b20db2b99faee261daa7cc9bbe175d3eaca
> diff --git a/libgloss/dramfs/sys_close.c b/libgloss/dramfs/sys_close.c
> new file mode 100644
> index 000000000..864a3beed
> --- /dev/null
> +++ b/libgloss/dramfs/sys_close.c
> @@ -0,0 +1,14 @@
> +#include <errno.h>
> +#include "dramfs_fdtable.h"
> +#include "dramfs_fs.h"
> +
> +/* Close a file.  */
> +int
> +_close(int fd)
> +{
> +  if(dramfs_check_fd(fd) < 0) {
> +    return -1;
> +  }
> +
> +  return dramfs_free_fd(fd);
> +}
> diff --git a/libgloss/dramfs/sys_execve.c b/libgloss/dramfs/sys_execve.c
> new file mode 100644
> index 000000000..d4a298b2e
> --- /dev/null
> +++ b/libgloss/dramfs/sys_execve.c
> @@ -0,0 +1,13 @@
> +#include <errno.h>
> +
> +#undef errno
> +extern int errno;
> +
> +/* Transfer control to a new process. Minimal implementation for a
> +   system without processes from newlib documentation.  */
> +int
> +_execve(const char *name, char *const argv[], char *const env[])
> +{
> +  errno = ENOMEM;
> +  return -1;
> +}
> diff --git a/libgloss/dramfs/sys_exit.c b/libgloss/dramfs/sys_exit.c
> new file mode 100644
> index 000000000..6be34a868
> --- /dev/null
> +++ b/libgloss/dramfs/sys_exit.c
> @@ -0,0 +1,14 @@
> +#include <unistd.h>
> +#include "dramfs_fs.h"
> +
> +/* Exit a program without cleaning up files.  */
> +void
> +_exit(int exit_status) {
> +  // close stdio
> +  close(0);
> +  close(1);
> +  close(2);
> +
> +  dramfs_exit(exit_status);
> +  while(1);
> +}
> diff --git a/libgloss/dramfs/sys_fork.c b/libgloss/dramfs/sys_fork.c
> new file mode 100644
> index 000000000..db808492f
> --- /dev/null
> +++ b/libgloss/dramfs/sys_fork.c
> @@ -0,0 +1,12 @@
> +#include <errno.h>
> +
> +#undef errno
> +extern int errno;
> +
> +/* Create a new process. Minimal implementation for a system without
> +   processes from newlib documentation.  */
> +int _fork()
> +{
> +  errno = EAGAIN;
> +  return -1;
> +}
> diff --git a/libgloss/dramfs/sys_fstat.c b/libgloss/dramfs/sys_fstat.c
> new file mode 100644
> index 000000000..df5ded6df
> --- /dev/null
> +++ b/libgloss/dramfs/sys_fstat.c
> @@ -0,0 +1,21 @@
> +#include <sys/stat.h>
> +#include <dramfs_fs.h>
> +#include <dramfs_fdtable.h>
> +
> +int
> +_fstat(int file, struct stat *st)
> +{
> +  lfs_file_t *fptr;
> +  struct lfs_info finfo;
> +
> +  if(dramfs_check_fd(file) < 0)
> +    return -1;
> +  else
> +    fptr = dramfs_get_file(file);
> +
> +  st->st_mode = S_IFREG;
> +  st->st_size = (off_t) fptr->size;
> +  st->st_blksize = (blksize_t) dramfs_fs_cfg.block_size;
> +  st->st_blocks  = (blkcnt_t) dramfs_fs_cfg.block_count;
> +  return 0;
> +}
> diff --git a/libgloss/dramfs/sys_getpid.c b/libgloss/dramfs/sys_getpid.c
> new file mode 100644
> index 000000000..dc0ae9272
> --- /dev/null
> +++ b/libgloss/dramfs/sys_getpid.c
> @@ -0,0 +1,9 @@
> +/* Get process id. This is sometimes used to generate strings unlikely
> +   to conflict with other processes. Minimal implementation for a
> +   system without processes just returns 1.  */
> +
> +int
> +_getpid()
> +{
> +  return 1;
> +}
> diff --git a/libgloss/dramfs/sys_gettimeofday.c b/libgloss/dramfs/sys_gettimeofday.c
> new file mode 100644
> index 000000000..c362ef182
> --- /dev/null
> +++ b/libgloss/dramfs/sys_gettimeofday.c
> @@ -0,0 +1,13 @@
> +#include <sys/time.h>
> +#include <errno.h>
> +
> +#undef errno
> +extern int errno;
> +
> +/* Get the current time.  Only relatively correct.  */
> +int
> +_gettimeofday(struct timeval *tp, void *tzp)
> +{
> +  errno = EINVAL;
> +  return -1;
> +}
> diff --git a/libgloss/dramfs/sys_isatty.c b/libgloss/dramfs/sys_isatty.c
> new file mode 100644
> index 000000000..479291135
> --- /dev/null
> +++ b/libgloss/dramfs/sys_isatty.c
> @@ -0,0 +1,9 @@
> +/* Query whether output stream is a terminal. For consistency with the
> +   other minimal implementations, which only support output to stdout,
> +   this minimal implementation is suggested by the newlib docs.  */
> +
> +int
> +_isatty(int file)
> +{
> +  return 1;
> +}
> diff --git a/libgloss/dramfs/sys_kill.c b/libgloss/dramfs/sys_kill.c
> new file mode 100644
> index 000000000..32c4d2422
> --- /dev/null
> +++ b/libgloss/dramfs/sys_kill.c
> @@ -0,0 +1,13 @@
> +#include <errno.h>
> +
> +#undef errno
> +extern int errno;
> +
> +/* Send a signal. Minimal implementation for a system without processes
> +   just causes an error.  */
> +int
> +_kill(int pid, int sig)
> +{
> +  errno = EINVAL;
> +  return -1;
> +}
> diff --git a/libgloss/dramfs/sys_link.c b/libgloss/dramfs/sys_link.c
> new file mode 100644
> index 000000000..3c33977be
> --- /dev/null
> +++ b/libgloss/dramfs/sys_link.c
> @@ -0,0 +1,11 @@
> +#include <errno.h>
> +
> +#undef errno
> +extern int errno;
> +
> +/* Establish a new name for an existing file. Minimal implementation */
> +int _link(const char *old_name, const char *new_name)
> +{
> +  errno = EMLINK;
> +  return -1;
> +}
> diff --git a/libgloss/dramfs/sys_lseek.c b/libgloss/dramfs/sys_lseek.c
> new file mode 100644
> index 000000000..746041759
> --- /dev/null
> +++ b/libgloss/dramfs/sys_lseek.c
> @@ -0,0 +1,17 @@
> +#include <sys/types.h>
> +#include <dramfs_fs.h>
> +#include <dramfs_fdtable.h>
> +
> +/* Set position in a file.  */
> +off_t
> +_lseek(int file, off_t ptr, int dir)
> +{
> +  lfs_file_t *fptr;
> +
> +  if(dramfs_check_fd(file) < 0)
> +    return -1;
> +  else
> +    fptr = dramfs_get_file(file);
> +
> +  return lfs_file_seek(&dramfs_fs, fptr, ptr, dir);
> +}
> diff --git a/libgloss/dramfs/sys_open.c b/libgloss/dramfs/sys_open.c
> new file mode 100644
> index 000000000..48a4830cd
> --- /dev/null
> +++ b/libgloss/dramfs/sys_open.c
> @@ -0,0 +1,37 @@
> +#include <errno.h>
> +#include <fcntl.h>
> +#include "dramfs_fdtable.h"
> +#include "dramfs_fs.h"
> +
> +/* Open a file.  */
> +int
> +_open(const char *name, int flags, int mode)
> +{
> +  int fd = dramfs_reserve_fd();
> +  int lfs_flags = 0;
> +
> +  // File open flags mapping
> +  lfs_flags |= (flags & O_RDONLY  ) ? LFS_O_RDONLY   : 0;
> +  lfs_flags |= (flags & O_WRONLY  ) ? LFS_O_WRONLY   : 0;
> +  lfs_flags |= (flags & O_RDWR    ) ? LFS_O_RDWR     : 0;
> +  lfs_flags |= (flags & O_APPEND  ) ? LFS_O_APPEND   : 0;
> +  lfs_flags |= (flags & O_CREAT   ) ? LFS_O_CREAT    : 0;
> +  lfs_flags |= (flags & O_TRUNC   ) ? LFS_O_TRUNC    : 0;
> +  lfs_flags |= (flags & O_EXCL    ) ? LFS_O_EXCL     : 0;
> +  lfs_flags |= (flags & O_NONBLOCK) ? LFS_O_NONBLOCK : 0;
> +
> +  if(fd < 0) {
> +    return -1;
> +  } else {
> +    lfs_file_t *fptr = dramfs_get_file(fd);
> +
> +    int ret = lfs_file_open(&dramfs_fs, fptr, name, lfs_flags);
> +
> +    if(ret < 0) {
> +      errno = ret;
> +      return -1;
> +    } else {
> +      return fd;
> +    }
> +  }
> +}
> diff --git a/libgloss/dramfs/sys_read.c b/libgloss/dramfs/sys_read.c
> new file mode 100644
> index 000000000..d5a382c38
> --- /dev/null
> +++ b/libgloss/dramfs/sys_read.c
> @@ -0,0 +1,40 @@
> +#include <errno.h>
> +#include <sys/types.h>
> +#include "dramfs_fdtable.h"
> +#include "dramfs_fs.h"
> +
> +/* Read from a file.  */
> +ssize_t _read(int fd, void *ptr, size_t len)
> +{
> +  if(dramfs_check_fd(fd) < 0) {
> +    return -1;
> +  }
> +
> +  if(fd == 0) {
> +    uint8_t *data = (uint8_t *)ptr;
> +
> +    // Return early on len == 0
> +    if (len == 0) return (ssize_t) 0;
> +
> +    int ch;
> +    if (dramfs_nonblock_fd(fd) == 0) {
> +      // Block to read just 1 character to start
> +      while ((ch = dramfs_getchar()) == -1);
> +    } else {
> +      // Read the first character, and return immediately if it's EOF
> +      if ((ch = dramfs_getchar()) == -1) return (ssize_t) 0;
> +    }
> +
> +    // Keep reading until new
> +    int i = 0;
> +    do {
> +      data[i++] = ch;
> +      if (i == len) break;
> +    } while ((ch = dramfs_getchar()) != -1);
> +
> +    return (ssize_t) i;
> +  }
> +
> +  lfs_file_t *fptr = dramfs_get_file(fd);
> +  return (ssize_t) lfs_file_read(&dramfs_fs, fptr, ptr, (lfs_size_t) len);
> +}
> diff --git a/libgloss/dramfs/sys_sbrk.c b/libgloss/dramfs/sys_sbrk.c
> new file mode 100644
> index 000000000..8c2eea688
> --- /dev/null
> +++ b/libgloss/dramfs/sys_sbrk.c
> @@ -0,0 +1,22 @@
> +// Dynamic allocation in the dram
> +// TODO: add mutex
> +extern char _end[]; /* _end is set in the linker command file */
> +
> +char *heap_ptr = _end;
> +
> +/*
> + * sbrk -- changes heap size size. Get nbytes more
> + *         RAM. We just increment a pointer in what's
> + *         left of memory on the board.
> + */
> +char *
> +_sbrk (nbytes)
> +     int nbytes;
> +{
> +  char        *base;
> +  
> +  base = heap_ptr;
> +  heap_ptr += nbytes;
> +
> +  return base;
> +}
> diff --git a/libgloss/dramfs/sys_stat.c b/libgloss/dramfs/sys_stat.c
> new file mode 100644
> index 000000000..a9d6ad4d3
> --- /dev/null
> +++ b/libgloss/dramfs/sys_stat.c
> @@ -0,0 +1,23 @@
> +#include <errno.h>
> +#include <sys/stat.h>
> +#include <dramfs_fs.h>
> +
> +/* Status of a file (by name).  */
> +
> +int
> +_stat(const char *file, struct stat *st)
> +{
> +  struct lfs_info finfo;
> +
> +  int res = lfs_stat(&dramfs_fs, file, &finfo);
> +  if(res < 0) {
> +    errno = res;
> +    return -1;
> +  } else {
> +    st->st_mode = S_IFREG;
> +    st->st_size = (off_t) finfo.size;
> +    st->st_blksize = (blksize_t) dramfs_fs_cfg.block_size;
> +    st->st_blocks  = (blkcnt_t) dramfs_fs_cfg.block_count;
> +    return 0;
> +  }
> +}
> diff --git a/libgloss/dramfs/sys_times.c b/libgloss/dramfs/sys_times.c
> new file mode 100644
> index 000000000..4856817bb
> --- /dev/null
> +++ b/libgloss/dramfs/sys_times.c
> @@ -0,0 +1,8 @@
> +#include <sys/times.h>
> +
> +/* Timing info for current process. Minimal implementation */
> +clock_t
> +_times(struct tms *buf)
> +{
> +  return -1;
> +}
> diff --git a/libgloss/dramfs/sys_unlink.c b/libgloss/dramfs/sys_unlink.c
> new file mode 100644
> index 000000000..677b81603
> --- /dev/null
> +++ b/libgloss/dramfs/sys_unlink.c
> @@ -0,0 +1,12 @@
> +#include <errno.h>
> +
> +#undef errno
> +extern int errno;
> +
> +/* Remove a file's directory entry.  */
> +int
> +_unlink(const char *name)
> +{
> +  errno = ENOENT;
> +  return -1;
> +}
> diff --git a/libgloss/dramfs/sys_wait.c b/libgloss/dramfs/sys_wait.c
> new file mode 100644
> index 000000000..44a3512fb
> --- /dev/null
> +++ b/libgloss/dramfs/sys_wait.c
> @@ -0,0 +1,12 @@
> +#include <errno.h>
> +
> +#undef errno
> +extern int errno;
> +
> +/* Wait for a child process. Minimal implementation for a system without
> +   processes just causes an error.  */
> +int _wait(int *status)
> +{
> +  errno = ECHILD;
> +  return -1;
> +}
> diff --git a/libgloss/dramfs/sys_write.c b/libgloss/dramfs/sys_write.c
> new file mode 100644
> index 000000000..76370331d
> --- /dev/null
> +++ b/libgloss/dramfs/sys_write.c
> @@ -0,0 +1,25 @@
> +#include <errno.h>
> +#include <sys/types.h>
> +#include "dramfs_fdtable.h"
> +#include "dramfs_fs.h"
> +
> +/* Write to a file.  */
> +ssize_t
> +_write(int fd, const void *ptr, size_t len)
> +{
> +  if(dramfs_check_fd(fd) < 0) {
> +    return -1;
> +  }
> +
> +  // write to console if it's stdout
> +  if(fd == 1 || fd==2) {
> +    for(int i=0; i<len; i++){
> +      char* cp = (char*) ptr;
> +      dramfs_sendchar(cp[i]);
> +    }
> +    return len;
> +  }
> +
> +  lfs_file_t *fptr = dramfs_get_file(fd);
> +  return (ssize_t) lfs_file_write(&dramfs_fs, fptr, ptr, (lfs_size_t) len);
> +}
> -- 
> 2.16.5



More information about the Newlib mailing list