1 /*
2 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include "pico/stdio/driver.h"
8 #include "pico/stdio_semihosting.h"
9 #include "pico/binary_info.h"
10
stdio_semihosting_out_chars(const char * buf,int length)11 static void stdio_semihosting_out_chars(const char *buf, int length) {
12 // must be volatile or the buffer gets put in registers & optimized away
13 volatile struct {
14 // https://developer.arm.com/documentation/dui0375/g/What-is-Semihosting-/SYS-WRITE--0x05-
15 // arguments, in order:
16 // word 0 = file handle (1 = stdout)
17 // word 1 = pointer to buffer
18 // word 2 = length of buffer
19 size_t fd;
20 const char *buf;
21 size_t len;
22 } args;
23
24 args.fd = 1; // 1 = stdout
25 args.buf = buf;
26 args.len = length;
27
28 pico_default_asm (
29 #ifdef __riscv
30 // a0 encodes the semihosting call number, 0x05 = SYS_WRITE
31 "li a0, 0x05\n"
32 // a1 points to the arguments
33 "mv a1, %[args]\n"
34 // Magic three-instruction sequence, containing a breakpoint. Note the
35 // RISC-V unpriv spec implies the final instruction might encode the
36 // call number (passed in a1) but openocd source shows this is just a
37 // constant value of 0x07. These instructions must be uncompressed:
38 ".option push\n"
39 ".option norvc\n"
40 "slli x0, x0, 0x1f\n"
41 "ebreak\n"
42 "srai x0, x0, 0x07\n"
43 ".option pop\n"
44 :
45 : [args] "r" (&args)
46 : "a0", "a1"
47 #else
48 // r1 must contain a pointer to the arguments
49 "movs r1, %[args]\n"
50 // semihosting call number 0x05 = SYS_WRITE
51 "movs r0, #5\n"
52 // make the semihosting call: https://developer.arm.com/documentation/dui0375/g/What-is-Semihosting-/The-semihosting-interface
53 "bkpt 0xab\n"
54 :
55 : [args] "r" (&args)
56 : "r0", "r1", "cc", "memory"
57 #endif
58 );
59 }
60
61 stdio_driver_t stdio_semihosting = {
62 .out_chars = stdio_semihosting_out_chars,
63 #if PICO_STDIO_ENABLE_CRLF_SUPPORT
64 .crlf_enabled = PICO_STDIO_SEMIHOSTING_DEFAULT_CRLF
65 #endif
66 };
67
stdio_semihosting_init(void)68 void stdio_semihosting_init(void) {
69 #if !PICO_NO_BI_STDIO_SEMIHOSTING
70 bi_decl_if_func_used(bi_program_feature("semihosting stdout"));
71 #endif
72 stdio_set_driver_enabled(&stdio_semihosting, true);
73 }
74
stdio_semihosting_deinit(void)75 void stdio_semihosting_deinit(void) {
76 stdio_set_driver_enabled(&stdio_semihosting, false);
77 }
78