1 // See LICENSE for license details.
12 #define SYS_stats 1234
14 // initialized in crt.S
17 volatile uint64_t tohost
__attribute__((aligned(64)));
18 volatile uint64_t fromhost
__attribute__((aligned(64)));
20 static long handle_frontend_syscall(long which
, long arg0
, long arg1
, long arg2
)
22 volatile uint64_t magic_mem
[8] __attribute__((aligned(64)));
29 tohost
= (uintptr_t)magic_mem
;
38 // In setStats, we might trap reading uarch-specific counters.
39 // The trap handler will skip over the instruction and write 0,
40 // but only if a0 is the destination register.
41 #define read_csr_safe(reg) ({ register long __tmp asm("a0"); \
42 asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \
45 #define NUM_COUNTERS 18
46 static long counters
[NUM_COUNTERS
];
47 static char* counter_names
[NUM_COUNTERS
];
48 static int handle_stats(int enable
)
51 #define READ_CTR(name) do { \
52 while (i >= NUM_COUNTERS) ; \
53 long csr = read_csr_safe(name); \
54 if (!enable) { csr -= counters[i]; counter_names[i] = #name; } \
55 counters[i++] = csr; \
57 READ_CTR(mcycle
); READ_CTR(minstret
);
58 READ_CTR(0xcc0); READ_CTR(0xcc1); READ_CTR(0xcc2); READ_CTR(0xcc3);
59 READ_CTR(0xcc4); READ_CTR(0xcc5); READ_CTR(0xcc6); READ_CTR(0xcc7);
60 READ_CTR(0xcc8); READ_CTR(0xcc9); READ_CTR(0xcca); READ_CTR(0xccb);
61 READ_CTR(0xccc); READ_CTR(0xccd); READ_CTR(0xcce); READ_CTR(0xccf);
66 void tohost_exit(long code
)
68 tohost
= (code
<< 1) | 1;
72 long handle_trap(long cause
, long epc
, long regs
[32])
75 asm ("jal %0, 1f; csrr a0, 0xcc0; 1:" : "=r"(csr_insn
));
78 if (cause
== CAUSE_ILLEGAL_INSTRUCTION
&&
79 (*(int*)epc
& *csr_insn
) == *csr_insn
)
81 else if (cause
!= CAUSE_MACHINE_ECALL
)
83 else if (regs
[17] == SYS_exit
)
84 tohost_exit(regs
[10]);
85 else if (regs
[17] == SYS_stats
)
86 sys_ret
= handle_stats(regs
[10]);
88 sys_ret
= handle_frontend_syscall(regs
[17], regs
[10], regs
[11], regs
[12]);
94 static long syscall(long num
, long arg0
, long arg1
, long arg2
)
96 register long a7
asm("a7") = num
;
97 register long a0
asm("a0") = arg0
;
98 register long a1
asm("a1") = arg1
;
99 register long a2
asm("a2") = arg2
;
100 asm volatile ("scall" : "+r"(a0
) : "r"(a1
), "r"(a2
), "r"(a7
));
106 syscall(SYS_exit
, code
, 0, 0);
110 void setStats(int enable
)
112 syscall(SYS_stats
, enable
, 0, 0);
115 void printstr(const char* s
)
117 syscall(SYS_write
, 1, (long)s
, strlen(s
));
120 void __attribute__((weak
)) thread_entry(int cid
, int nc
)
122 // multi-threaded programs override this function.
123 // for the case of single-threaded programs, only let core 0 proceed.
127 int __attribute__((weak
)) main(int argc
, char** argv
)
129 // single-threaded programs override this function.
130 printstr("Implement main(), foo!\n");
134 static void init_tls()
136 register void* thread_pointer
asm("tp");
137 extern char _tls_data
;
138 extern __thread
char _tdata_begin
, _tdata_end
, _tbss_end
;
139 size_t tdata_size
= &_tdata_end
- &_tdata_begin
;
140 memcpy(thread_pointer
, &_tls_data
, tdata_size
);
141 size_t tbss_size
= &_tbss_end
- &_tdata_end
;
142 memset(thread_pointer
+ tdata_size
, 0, tbss_size
);
145 void _init(int cid
, int nc
)
148 thread_entry(cid
, nc
);
150 // only single-threaded programs should ever get here.
151 int ret
= main(0, 0);
153 char buf
[NUM_COUNTERS
* 32] __attribute__((aligned(64)));
155 for (int i
= 0; i
< NUM_COUNTERS
; i
++)
157 pbuf
+= sprintf(pbuf
, "%s = %d\n", counter_names
[i
], counters
[i
]);
167 static __thread
char buf
[64] __attribute__((aligned(64)));
168 static __thread
int buflen
= 0;
172 if (ch
== '\n' || buflen
== sizeof(buf
))
174 syscall(SYS_write
, 1, (long)buf
, buflen
);
181 void printhex(uint64_t x
)
185 for (i
= 0; i
< 16; i
++)
187 str
[15-i
] = (x
& 0xF) + ((x
& 0xF) < 10 ? '0' : 'a'-10);
195 static inline void printnum(void (*putch
)(int, void**), void **putdat
,
196 unsigned long long num
, unsigned base
, int width
, int padc
)
198 unsigned digs
[sizeof(num
)*CHAR_BIT
];
203 digs
[pos
++] = num
% base
;
209 while (width
-- > pos
)
213 putch(digs
[pos
] + (digs
[pos
] >= 10 ? 'a' - 10 : '0'), putdat
);
216 static unsigned long long getuint(va_list *ap
, int lflag
)
219 return va_arg(*ap
, unsigned long long);
221 return va_arg(*ap
, unsigned long);
223 return va_arg(*ap
, unsigned int);
226 static long long getint(va_list *ap
, int lflag
)
229 return va_arg(*ap
, long long);
231 return va_arg(*ap
, long);
233 return va_arg(*ap
, int);
236 static void vprintfmt(void (*putch
)(int, void**), void **putdat
, const char *fmt
, va_list ap
)
238 register const char* p
;
239 const char* last_fmt
;
240 register int ch
, err
;
241 unsigned long long num
;
242 int base
, lflag
, width
, precision
, altflag
;
246 while ((ch
= *(unsigned char *) fmt
) != '%') {
254 // Process a %-escape sequence
262 switch (ch
= *(unsigned char *) fmt
++) {
264 // flag to pad on the right
269 // flag to pad with 0's instead of spaces
284 for (precision
= 0; ; ++fmt
) {
285 precision
= precision
* 10 + ch
- '0';
287 if (ch
< '0' || ch
> '9')
290 goto process_precision
;
293 precision
= va_arg(ap
, int);
294 goto process_precision
;
307 width
= precision
, precision
= -1;
310 // long flag (doubled for long long)
317 putch(va_arg(ap
, int), putdat
);
322 if ((p
= va_arg(ap
, char *)) == NULL
)
324 if (width
> 0 && padc
!= '-')
325 for (width
-= strnlen(p
, precision
); width
> 0; width
--)
327 for (; (ch
= *p
) != '\0' && (precision
< 0 || --precision
>= 0); width
--) {
331 for (; width
> 0; width
--)
337 num
= getint(&ap
, lflag
);
338 if ((long long) num
< 0) {
340 num
= -(long long) num
;
348 goto unsigned_number
;
352 // should do something with padding so it's always 3 octits
354 goto unsigned_number
;
358 static_assert(sizeof(long) == sizeof(void*));
362 /* fall through to 'x' */
364 // (unsigned) hexadecimal
368 num
= getuint(&ap
, lflag
);
370 printnum(putch
, putdat
, num
, base
, width
, padc
);
373 // escaped '%' character
378 // unrecognized escape sequence - just print it literally
387 int printf(const char* fmt
, ...)
392 vprintfmt((void*)putchar
, 0, fmt
, ap
);
395 return 0; // incorrect return value, but who cares, anyway?
398 int sprintf(char* str
, const char* fmt
, ...)
404 void sprintf_putch(int ch
, void** data
)
406 char** pstr
= (char**)data
;
411 vprintfmt(sprintf_putch
, (void**)&str
, fmt
, ap
);
418 void* memcpy(void* dest
, const void* src
, size_t len
)
420 if ((((uintptr_t)dest
| (uintptr_t)src
| len
) & (sizeof(uintptr_t)-1)) == 0) {
421 const uintptr_t* s
= src
;
423 while (d
< (uintptr_t*)(dest
+ len
))
428 while (d
< (char*)(dest
+ len
))
434 void* memset(void* dest
, int byte
, size_t len
)
436 if ((((uintptr_t)dest
| len
) & (sizeof(uintptr_t)-1)) == 0) {
437 uintptr_t word
= byte
& 0xFF;
440 word
|= word
<< 16 << 16;
443 while (d
< (uintptr_t*)(dest
+ len
))
447 while (d
< (char*)(dest
+ len
))
453 size_t strlen(const char *s
)
461 size_t strnlen(const char *s
, size_t n
)
469 int strcmp(const char* s1
, const char* s2
)
471 unsigned char c1
, c2
;
476 } while (c1
!= 0 && c1
== c2
);
481 char* strcpy(char* dest
, const char* src
)
484 while ((*d
++ = *src
++))
489 long atol(const char* str
)
497 if (*str
== '-' || *str
== '+') {
507 return sign
? -res
: res
;