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