mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-09-02 12:24:07 -04:00
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:
parent
4b943b35e0
commit
dfc1bf8ec3
189 changed files with 0 additions and 0 deletions
|
@ -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"
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
#include <errno.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
int
|
||||
nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
|
@ -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 */
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
#include <errno.h>
|
||||
|
||||
int
|
||||
_access(const char *file, int mode)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#include <errno.h>
|
||||
|
||||
int
|
||||
_chdir(const char *path)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
int
|
||||
_chmod(const char *path, mode_t mode)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#include <errno.h>
|
||||
|
||||
int
|
||||
_close(int file)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#include <errno.h>
|
||||
|
||||
int
|
||||
_execve(const char *name, char *const argv[], char *const env[])
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#include <metal/shutdown.h>
|
||||
|
||||
void
|
||||
_exit(int exit_status)
|
||||
{
|
||||
metal_shutdown(exit_status);
|
||||
while (1);
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#include <errno.h>
|
||||
|
||||
int
|
||||
_faccessat(int dirfd, const char *file, int mode, int flags)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#include <errno.h>
|
||||
|
||||
int
|
||||
_fork()
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
int
|
||||
_fstat(int file, struct stat *st)
|
||||
{
|
||||
errno = -ENOSYS;
|
||||
return -1;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#include <errno.h>
|
||||
#include <sys/timeb.h>
|
||||
|
||||
int
|
||||
_ftime(struct timeb *tp)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#include <errno.h>
|
||||
|
||||
char *
|
||||
_getcwd(char *buf, size_t size)
|
||||
{
|
||||
errno = -ENOSYS;
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#include <errno.h>
|
||||
|
||||
int
|
||||
_getpid()
|
||||
{
|
||||
return 1;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#include <unistd.h>
|
||||
|
||||
int
|
||||
_isatty(int file)
|
||||
{
|
||||
return (file == STDOUT_FILENO);
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#include <errno.h>
|
||||
|
||||
int
|
||||
_kill(int pid, int sig)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#include <errno.h>
|
||||
|
||||
int _link(const char *old_name, const char *new_name)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
int _lstat(const char *file, struct stat *st)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#include <errno.h>
|
||||
|
||||
int
|
||||
_open(const char *name, int flags, int mode)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#include <errno.h>
|
||||
|
||||
int
|
||||
_openat(int dirfd, const char *name, int flags, int mode)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
int
|
||||
_stat(const char *file, struct stat *st)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#include <errno.h>
|
||||
|
||||
int
|
||||
_unlink(const char *name)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#include <errno.h>
|
||||
struct utimbuf;
|
||||
|
||||
int
|
||||
_utime(const char *path, const struct utimbuf *times)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#include <errno.h>
|
||||
|
||||
int _wait(int *status)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
|
@ -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;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue