summaryrefslogtreecommitdiff
path: root/test/tx/cmake/riscv/bsp/syscalls.c
blob: 802fe8afacf60010c10fe0c34ccf19b066742cbe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/***************************************************************************
 * Copyright (c) 2026 10xEngineers
 *
 * This program and the accompanying materials are made available under the
 * terms of the MIT License which is available at
 * https://opensource.org/licenses/MIT.
 *
 * SPDX-License-Identifier: MIT
 **************************************************************************/

/* Newlib system call stubs for RISC-V QEMU virt regression tests.
   Provides _write (UART output for printf), _exit (QEMU test finisher),
   and other minimal stubs needed by newlib. */

#include <sys/stat.h>
#include <errno.h>
#include <stdint.h>

#define UART0_THR   (*(volatile unsigned char *)0x10000000L)
#define UART0_LSR   (*(volatile unsigned char *)0x10000005L)
#define LSR_TX_IDLE (1 << 5)

/* QEMU virt sifive_test device for clean exit. */
#define VIRT_TEST       (*(volatile uint32_t *)0x100000L)
#define VIRT_TEST_PASS  0x5555u
#define VIRT_TEST_FAIL  0x3333u

/* Called by testcontrol.c when EXTERNAL_EXIT is defined. */
__attribute__((noreturn)) void external_exit(unsigned int code)
{
    if (code == 0)
        VIRT_TEST = VIRT_TEST_PASS;
    else
        VIRT_TEST = (code << 16) | VIRT_TEST_FAIL;

    /* Should not reach here, but halt if it does. */
    while (1)
        ;
}

int _write(int fd, const char *buf, int count)
{
    (void)fd;
    for (int i = 0; i < count; i++)
    {
        while ((UART0_LSR & LSR_TX_IDLE) == 0)
            ;
        UART0_THR = (unsigned char)buf[i];
    }
    return count;
}

extern char _end[];
static char *heap_ptr = 0;

void *_sbrk(int incr)
{
    if (heap_ptr == 0)
        heap_ptr = _end;

    char *prev = heap_ptr;
    heap_ptr += incr;
    return prev;
}

int _close(int fd)
{
    (void)fd;
    errno = EBADF;
    return -1;
}

int _fstat(int fd, struct stat *st)
{
    (void)fd;
    st->st_mode = S_IFCHR;
    return 0;
}

int _isatty(int fd)
{
    (void)fd;
    return 1;
}

int _lseek(int fd, int offset, int whence)
{
    (void)fd;
    (void)offset;
    (void)whence;
    errno = ESPIPE;
    return -1;
}

int _read(int fd, char *buf, int count)
{
    (void)fd;
    (void)buf;
    (void)count;
    return 0;
}

__attribute__((noreturn)) void _exit(int code)
{
    external_exit((unsigned int)code);
}

/* Override newlib's exit() to avoid pulling in __call_exitprocs and
   __stdio_exit_handler (compiled with mcmodel=medlow). */
__attribute__((noreturn)) void exit(int code)
{
    external_exit((unsigned int)code);
}

/* Minimal rand/srand to avoid pulling newlib's version which uses
   _impure_ptr (compiled with mcmodel=medlow, unreachable on RV64). */
static unsigned long rand_seed = 1;

int rand(void)
{
    rand_seed = rand_seed * 1103515245UL + 12345UL;
    return (int)((rand_seed >> 16) & 0x7fff);
}

void srand(unsigned int seed)
{
    rand_seed = seed;
}