Skip to content

Commit

Permalink
Add metal-pico library [v3]
Browse files Browse the repository at this point in the history
This library hooks picolibc to libmetal, offering a small number of
APIs.

Signed-off-by: Keith Packard <keithp@keithp.com>

---

v2:

	Initialize TLS base register from __tls_base and __tdata_size

	    The RISC-V ABI sets the tp register between tls
	    initialized data and tls uninitialized data areas. The
	    linker sets __tls_base to the start of tls data and
	    __tdata_size to the size of the initialized data area, so
	    the correct tp value is the sum of these two symbols.

	libriscv__pico__metal.a → libmetal-pico.a

	    Use the name that freedom-e-sdk wants

	Use gloss/crt0.S and gloss/sys_exit.c for libmetal-pico.a

	    Share source code, especially the startup code, between
	    the two C library users to avoid duplicating work between
	    them.

	Expose sbrk/brk instead of _sbrk/_brk when compiled against picolibc

	    This changes the names of these two functions when using
	    picolibc instead of newlib. Otherwise, the implementation
	    is the same.

	Use gloss/sys_sbrk.c with picolibc

	    Instead of a separate copy with minor edits.

v3:
	Use correct TLS initialization value. Risc-V places TP
	at the base of TLS storage, not between data and BSS values.
  • Loading branch information
keith-packard committed Mar 30, 2020
1 parent a6eadeb commit c0fe921
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 11 deletions.
14 changes: 14 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,20 @@ libmetal_a_SOURCES = \
src/vector.S \
src/watchdog.c

########################################################
# libmetal-pico
########################################################

lib_LIBRARIES += libmetail-pico.a

libmetal_pico_a_SOURCES = \
gloss/crt0.S \
pico/iob.c \
gloss/sys_exit.c \
pico/times.c \
gloss/sys_sbrk.c \
pico/sysconf.c

########################################################
# libgloss
########################################################
Expand Down
62 changes: 57 additions & 5 deletions Makefile.in

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions gloss/crt0.S
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ _start:
#endif
2:

/* Set TLS pointer */
.weak __tls_base
la tp, __tls_base

/* At this point we're in an environment that can execute C code. The first
* thing to do is to make the callback to the parent environment if it's been
* requested to do so. */
Expand Down
17 changes: 11 additions & 6 deletions gloss/sys_sbrk.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,31 @@
* that's been allocated. */
extern char metal_segment_heap_target_start;
extern char metal_segment_heap_target_end;
static char *brk = &metal_segment_heap_target_start;
static char *__brk = &metal_segment_heap_target_start;

#ifdef _PICOLIBC__
#define _brk brk
#define _sbrk sbrk
#endif

int _brk(void *addr) {
brk = addr;
__brk = addr;
return 0;
}

char *_sbrk(ptrdiff_t incr) {
char *old = brk;
char *old = __brk;

/* If __heap_size == 0, we can't allocate memory on the heap */
if (&metal_segment_heap_target_start == &metal_segment_heap_target_end) {
return (void *)-1;
}

/* Don't move the break past the end of the heap */
if ((brk + incr) < &metal_segment_heap_target_end) {
brk += incr;
if ((__brk + incr) < &metal_segment_heap_target_end) {
__brk += incr;
} else {
brk = &metal_segment_heap_target_end;
__brk = &metal_segment_heap_target_end;
return (void *)-1;
}

Expand Down
44 changes: 44 additions & 0 deletions pico/iob.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright © 2019 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/

#include <metal/tty.h>
#include <stdio.h>

static int metal_putc(char c, FILE *file) {
(void)file;
metal_tty_putc(c);
return c;
}

static int metal_getc(FILE *file) {
int c;
(void)file;
metal_tty_getc(&c);
return c;
}

static int metal_flush(FILE *file) { return 0; }

static FILE __stdio =
FDEV_SETUP_STREAM(metal_putc, metal_getc, metal_flush, _FDEV_SETUP_RW);

FILE *const __iob[3] = {&__stdio, &__stdio, &__stdio};
16 changes: 16 additions & 0 deletions pico/sysconf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include <time.h>
#include <unistd.h>

/* Get configurable system variables. */

long sysconf(int name) {
unsigned long long timebase;

switch (name) {
case _SC_CLK_TCK:
metal_timer_get_timebase_frequency(0, &timebase);
return (long)timebase;
}

return -1;
}
17 changes: 17 additions & 0 deletions pico/times.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include <metal/timer.h>
#include <sys/time.h>
#include <sys/times.h>

/*
* Simple enough to return the tick count by
* just getting it from the hardware.
*/

clock_t times(struct tms *buf) {
unsigned long long mcc;
metal_timer_get_cyclecount(0, &mcc);
buf->tms_stime = 0;
buf->tms_cutime = 0;
buf->tms_cstime = 0;
return buf->tms_utime = mcc;
}

0 comments on commit c0fe921

Please sign in to comment.