Rename RISC-V_RV32_SiFive_HiFive1-FreedomStudio directory to RISC-V_RV32_SiFive_HiFive1-RevB-FreedomStudio as it targets Rev B of the hardware.

This commit is contained in:
Richard Barry 2020-01-01 22:05:35 +00:00
parent 4b943b35e0
commit dfc1bf8ec3
189 changed files with 0 additions and 0 deletions

View file

@ -0,0 +1,246 @@
/* Copyright (c) 2017-2018 SiFive Inc. All rights reserved.
This copyrighted material is made available to anyone wishing to use,
modify, copy, or redistribute it subject to the terms and conditions
of the FreeBSD License. This program is distributed in the hope that
it will be useful, but WITHOUT ANY WARRANTY expressed or implied,
including the implied warranties of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. A copy of this license is available at
http://www.opensource.org/licenses.
*/
/* crt0.S: Entry point for RISC-V METAL programs. */
.section .text.libgloss.start
.global _start
.type _start, @function
/* _start is defined by the METAL to have been called with the following
* arguments:
* a0: the hart ID of the currently executing hart. Harts can start at
* any arbitrary point, it's the C library's job to ensure the code is
* safe.
* a1: a pointer to a description of the machine on which this code is
* currently executing. This is probably 0 on an embedded system
* because they tend to not be dynamically portable. As such, newlib
* ignores this argument.
* a2: a pointer to a function that must be run after the envirnoment has
* been initialized, but before user code can be expected to be run.
* If this is 0 then there is no function to be run. */
_start:
.cfi_startproc
.cfi_undefined ra
/* This is a bit funky: it's not usually sane for _start to return, but in
* this case we actually want to in order to signal an error to the METAL. */
mv s0, ra
/* Before doing anything we must initialize the global pointer, as we cannot
* safely perform any access that may be relaxed without GP being set. This
* is done with relaxation disabled to avoid relaxing the address calculation
* to just "addi gp, gp, 0". */
.option push
.option norelax
la gp, __global_pointer$
.option pop
/* The METAL is designed for a bare-metal environment and therefor is expected
* to define its own stack pointer. We also align the stack pointer here
* because the only RISC-V ABI that's currently defined mandates 16-byte
* stack alignment. */
la sp, _sp
/* Increment by hartid number of stack sizes */
li t0, 0
la t1, __stack_size
1:
beq t0, a0, 1f
add sp, sp, t1
addi t0, t0, 1
j 1b
1:
andi sp, sp, -16
/* If we're not hart 0, skip the initialization work */
la t0, __metal_boot_hart
bne a0, t0, _skip_init
/* Embedded systems frequently require relocating the data segment before C
* code can be run -- for example, the data segment may exist in flash upon
* boot and then need to get relocated into a non-persistant writable memory
* before C code can execute. If this is the case we do so here. This step
* is optional: if the METAL provides an environment in which this relocation
* is not necessary then it must simply set metal_segment_data_source_start to
* be equal to metal_segment_data_target_start. */
la t0, metal_segment_data_source_start
la t1, metal_segment_data_target_start
la t2, metal_segment_data_target_end
beq t0, t1, 2f
bge t1, t2, 2f
1:
#if __riscv_xlen == 32
lw a0, 0(t0)
addi t0, t0, 4
sw a0, 0(t1)
addi t1, t1, 4
blt t1, t2, 1b
#else
ld a0, 0(t0)
addi t0, t0, 8
sd a0, 0(t1)
addi t1, t1, 8
blt t1, t2, 1b
#endif
2:
/* Copy the ITIM section */
la t0, metal_segment_itim_source_start
la t1, metal_segment_itim_target_start
la t2, metal_segment_itim_target_end
beq t0, t1, 2f
bge t1, t2, 2f
1:
#if __riscv_xlen == 32
lw a0, 0(t0)
addi t0, t0, 4
sw a0, 0(t1)
addi t1, t1, 4
blt t1, t2, 1b
#else
ld a0, 0(t0)
addi t0, t0, 8
sd a0, 0(t1)
addi t1, t1, 8
blt t1, t2, 1b
#endif
2:
/* Fence all subsequent instruction fetches until after the ITIM writes
complete */
fence.i
/* Zero the BSS segment. */
la t1, metal_segment_bss_target_start
la t2, metal_segment_bss_target_end
bge t1, t2, 2f
1:
#if __riscv_xlen == 32
sw x0, 0(t1)
addi t1, t1, 4
blt t1, t2, 1b
#else
sd x0, 0(t1)
addi t1, t1, 8
blt t1, t2, 1b
#endif
2:
/* 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. */
beqz a2, 1f
jalr a2
1:
/* The RISC-V port only uses new-style constructors and destructors. */
la a0, __libc_fini_array
call atexit
call __libc_init_array
_skip_init:
/* Synchronize harts so that secondary harts wait until hart 0 finishes
initializing */
call __metal_synchronize_harts
/* Check RISC-V isa and enable FS bits if Floating Point architecture. */
csrr a5, misa
li a4, 0x10028
and a5, a5, a4
beqz a5, 1f
csrr a5, mstatus
lui a4, 0x2
or a5, a5, a4
csrw mstatus, a5
csrwi fcsr, 0
1:
/* This is a C runtime, so main() is defined to have some arguments. Since
* there's nothing sane the METAL can pass we don't bother with that but
* instead just setup as close to a NOP as we can. */
li a0, 1 /* argc=1 */
la a1, argv /* argv = {"libgloss", NULL} */
la a2, envp /* envp = {NULL} */
call secondary_main
/* Call exit to handle libc's cleanup routines. Under normal contains this
* shouldn't even get called, but I'm still not using a tail call here
* because returning to the METAL is the right thing to do in pathological
* situations. */
call exit
/* And here's where we return. Again, it's a bit odd but the METAL defines
* this as a bad idea (ie, as opposed to leaving it undefined) and at this
* point it's really the only thing left to do. */
mv ra, s0
ret
.cfi_endproc
/* RISC-V systems always use __libc_{init,fini}_array, but for compatibility we
* define _{init,fini} to do nothing. */
.global _init
.type _init, @function
.global _fini
.type _fini, @function
_init:
_fini:
ret
.size _init, .-_init
.size _fini, .-_fini
/* By default, secondary_main will cause secondary harts to spin forever.
* Users can redefine secondary_main themselves to run code on secondary harts */
.weak secondary_main
.global secondary_main
.type secondary_main, @function
secondary_main:
addi sp, sp, -16
#if __riscv_xlen == 32
sw ra, 4(sp)
#else
sd ra, 8(sp)
#endif
csrr t0, mhartid
la t1, __metal_boot_hart
beq t0, t1, 2f
1:
wfi
j 1b
2:
call main
#if __riscv_xlen == 32
lw ra, 4(sp)
#else
ld ra, 8(sp)
#endif
addi sp, sp, 16
ret
/* This shim allows main() to be passed a set of arguments that can satisfy the
* requirements of the C API. */
.section .rodata.libgloss.start
argv:
.dc.a name
envp:
.dc.a 0
name:
.asciz "libgloss"

View file

@ -0,0 +1,9 @@
#include <errno.h>
#include <sys/time.h>
int
nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
{
errno = ENOSYS;
return -1;
}

View file

@ -0,0 +1,59 @@
/* Copyright 2019 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#include <metal/machine.h>
#include <metal/machine/platform.h>
#include <metal/io.h>
#include <metal/cpu.h>
#define METAL_REG(base, offset) (((unsigned long)(base) + (offset)))
#define METAL_REGW(base, offset) (__METAL_ACCESS_ONCE((__metal_io_u32 *)METAL_REG((base), (offset))))
#define METAL_MSIP(base, hart) (METAL_REGW((base),4*(hart)))
/*
* _synchronize_harts() is called by crt0.S to cause harts > 0 to wait for
* hart 0 to finish copying the datat section, zeroing the BSS, and running
* the libc contstructors.
*/
void _synchronize_harts() {
#if __METAL_DT_MAX_HARTS > 1
int hart = metal_cpu_get_current_hartid();
uintptr_t msip_base = 0;
/* Get the base address of the MSIP registers */
#ifdef __METAL_DT_RISCV_CLINT0_HANDLE
msip_base = __metal_driver_sifive_clint0_control_base(__METAL_DT_RISCV_CLINT0_HANDLE);
msip_base += METAL_RISCV_CLINT0_MSIP_BASE;
#elif __METAL_DT_RISCV_CLIC0_HANDLE
msip_base = __metal_driver_sifive_clic0_control_base(__METAL_DT_RISCV_CLIC0_HANDLE);
msip_base += METAL_RISCV_CLIC0_MSIP_BASE;
#else
#warning No handle for CLINT or CLIC found, harts may be unsynchronized after init!
#endif
/* Disable machine interrupts as a precaution */
__asm__ volatile("csrc mstatus, %0" :: "r" (METAL_MSTATUS_MIE));
if (hart == 0) {
/* Hart 0 waits for all harts to set their MSIP bit */
for (int i = 1 ; i < __METAL_DT_MAX_HARTS; i++) {
while (METAL_MSIP(msip_base, i) == 0) ;
}
/* Hart 0 clears everyone's MSIP bit */
for (int i = 1 ; i < __METAL_DT_MAX_HARTS; i++) {
METAL_MSIP(msip_base, i) = 0;
}
} else {
/* Other harts set their MSIP bit to indicate they're ready */
METAL_MSIP(msip_base, hart) = 1;
__asm__ volatile ("fence w,rw");
/* Wait for hart 0 to clear the MSIP bit */
while (METAL_MSIP(msip_base, hart) == 1) ;
}
#endif /* __METAL_DT_MAX_HARTS > 1 */
}

View file

@ -0,0 +1,8 @@
#include <errno.h>
int
_access(const char *file, int mode)
{
errno = ENOSYS;
return -1;
}

View file

@ -0,0 +1,8 @@
#include <errno.h>
int
_chdir(const char *path)
{
errno = ENOSYS;
return -1;
}

View file

@ -0,0 +1,9 @@
#include <errno.h>
#include <sys/types.h>
int
_chmod(const char *path, mode_t mode)
{
errno = ENOSYS;
return -1;
}

View file

@ -0,0 +1,9 @@
#include <sys/types.h>
#include <errno.h>
int
_chown(const char *path, uid_t owner, gid_t group)
{
errno = ENOSYS;
return -1;
}

View file

@ -0,0 +1,8 @@
#include <errno.h>
int
_close(int file)
{
errno = ENOSYS;
return -1;
}

View file

@ -0,0 +1,8 @@
#include <errno.h>
int
_execve(const char *name, char *const argv[], char *const env[])
{
errno = ENOMEM;
return -1;
}

View file

@ -0,0 +1,8 @@
#include <metal/shutdown.h>
void
_exit(int exit_status)
{
metal_shutdown(exit_status);
while (1);
}

View file

@ -0,0 +1,8 @@
#include <errno.h>
int
_faccessat(int dirfd, const char *file, int mode, int flags)
{
errno = ENOSYS;
return -1;
}

View file

@ -0,0 +1,8 @@
#include <errno.h>
int
_fork()
{
errno = ENOSYS;
return -1;
}

View file

@ -0,0 +1,9 @@
#include <errno.h>
#include <sys/stat.h>
int
_fstat(int file, struct stat *st)
{
errno = -ENOSYS;
return -1;
}

View file

@ -0,0 +1,9 @@
#include <errno.h>
#include <sys/stat.h>
int
_fstatat(int dirfd, const char *file, struct stat *st, int flags)
{
errno = ENOSYS;
return -1;
}

View file

@ -0,0 +1,9 @@
#include <errno.h>
#include <sys/timeb.h>
int
_ftime(struct timeb *tp)
{
errno = ENOSYS;
return -1;
}

View file

@ -0,0 +1,8 @@
#include <errno.h>
char *
_getcwd(char *buf, size_t size)
{
errno = -ENOSYS;
return NULL;
}

View file

@ -0,0 +1,7 @@
#include <errno.h>
int
_getpid()
{
return 1;
}

View file

@ -0,0 +1,21 @@
#include <errno.h>
#include <metal/timer.h>
#include <sys/time.h>
int
_gettimeofday(struct timeval *tp, void *tzp)
{
int rv;
unsigned long long mcc, timebase;
rv = metal_timer_get_cyclecount(0, &mcc);
if (rv != 0) {
return -1;
}
rv = metal_timer_get_timebase_frequency(0, &timebase);
if (rv != 0) {
return -1;
}
tp->tv_sec = mcc / timebase;
tp->tv_usec = mcc % timebase * 1000000 / timebase;
return 0;
}

View file

@ -0,0 +1,7 @@
#include <unistd.h>
int
_isatty(int file)
{
return (file == STDOUT_FILENO);
}

View file

@ -0,0 +1,8 @@
#include <errno.h>
int
_kill(int pid, int sig)
{
errno = ENOSYS;
return -1;
}

View file

@ -0,0 +1,7 @@
#include <errno.h>
int _link(const char *old_name, const char *new_name)
{
errno = ENOSYS;
return -1;
}

View file

@ -0,0 +1,9 @@
#include <sys/types.h>
#include <errno.h>
off_t
_lseek(int file, off_t ptr, int dir)
{
errno = ENOSYS;
return -1;
}

View file

@ -0,0 +1,8 @@
#include <errno.h>
#include <sys/stat.h>
int _lstat(const char *file, struct stat *st)
{
errno = ENOSYS;
return -1;
}

View file

@ -0,0 +1,8 @@
#include <errno.h>
int
_open(const char *name, int flags, int mode)
{
errno = ENOSYS;
return -1;
}

View file

@ -0,0 +1,8 @@
#include <errno.h>
int
_openat(int dirfd, const char *name, int flags, int mode)
{
errno = ENOSYS;
return -1;
}

View file

@ -0,0 +1,9 @@
#include <sys/types.h>
#include <errno.h>
ssize_t
_read(int file, void *ptr, size_t len)
{
errno = ENOSYS;
return -1;
}

View file

@ -0,0 +1,39 @@
#include <sys/types.h>
/* brk is handled entirely within the C library. This limits METAL programs that
* use the C library to be disallowed from dynamically allocating memory
* without talking to the C library, but that sounds like a sane way to go
* about it. Note that there is no error checking anywhere in this file, users
* will simply get the relevant error when actually trying to use the memory
* 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;
int
_brk(void *addr)
{
brk = addr;
return 0;
}
char *
_sbrk(ptrdiff_t incr)
{
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;
} else {
brk = &metal_segment_heap_target_end;
return (void *)-1;
}
return old;
}

View file

@ -0,0 +1,9 @@
#include <errno.h>
#include <sys/stat.h>
int
_stat(const char *file, struct stat *st)
{
errno = ENOSYS;
return -1;
}

View file

@ -0,0 +1,16 @@
#include <unistd.h>
#include <time.h>
/* Get configurable system variables. */
long
_sysconf(int name)
{
switch (name)
{
case _SC_CLK_TCK:
return CLOCKS_PER_SEC;
}
return -1;
}

View file

@ -0,0 +1,42 @@
#include <sys/times.h>
#include <sys/time.h>
#include <metal/timer.h>
#include <errno.h>
extern int _gettimeofday(struct timeval *, void *);
/* Timing information for current process. From
newlib/libc/include/sys/times.h the tms struct fields are as follows:
- clock_t tms_utime : user clock ticks
- clock_t tms_stime : system clock ticks
- clock_t tms_cutime : children's user clock ticks
- clock_t tms_cstime : children's system clock ticks
Since maven does not currently support processes we set both of the
children's times to zero. Eventually we might want to separately
account for user vs system time, but for now we just return the total
number of cycles since starting the program. */
clock_t
_times(struct tms *buf)
{
int rv;
// when called for the first time, initialize t0
static struct timeval t0;
if (t0.tv_sec == 0 && t0.tv_usec == 0)
_gettimeofday (&t0, 0);
struct timeval t;
_gettimeofday (&t, 0);
unsigned long long timebase;
rv = metal_timer_get_timebase_frequency(0, &timebase);
if (rv != 0) {
return -1;
}
long long utime = (t.tv_sec - t0.tv_sec) * 1000000 + (t.tv_usec - t0.tv_usec);
buf->tms_utime = utime * timebase / 1000000;
buf->tms_stime = buf->tms_cstime = buf->tms_cutime = 0;
return 0;
}

View file

@ -0,0 +1,8 @@
#include <errno.h>
int
_unlink(const char *name)
{
errno = ENOSYS;
return -1;
}

View file

@ -0,0 +1,9 @@
#include <errno.h>
struct utimbuf;
int
_utime(const char *path, const struct utimbuf *times)
{
errno = ENOSYS;
return -1;
}

View file

@ -0,0 +1,7 @@
#include <errno.h>
int _wait(int *status)
{
errno = ENOSYS;
return -1;
}

View file

@ -0,0 +1,19 @@
#include <metal/tty.h>
#include <sys/types.h>
#include <errno.h>
#include <unistd.h>
/* Write to a file. */
ssize_t
_write(int file, const void *ptr, size_t len)
{
if (file != STDOUT_FILENO) {
errno = ENOSYS;
return -1;
}
const char *bptr = ptr;
for (size_t i = 0; i < len; ++i)
metal_tty_putc(bptr[i]);
return 0;
}