1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2024 Andes Technology Corporation 4 */ 5 6 #include <kernel/semihosting.h> 7 #include <string.h> 8 9 /* 10 * ARM and RISC-V have defined the standard way to perform 11 * the semihosting operations. 12 * - Operation codes and open modes are identical. 13 * - The implementation of the low-level __do_semihosting() call is 14 * architecture-specific. 15 * - Arm semihosting interface: 16 * https://developer.arm.com/documentation/dui0471/g/Semihosting/The-semihosting-interface 17 * - RISC-V semihosting interface: 18 * https://github.com/riscv-non-isa/riscv-semihosting/blob/main/binary-interface.adoc 19 */ 20 21 /* An integer that specifies the file open mode */ 22 enum semihosting_open_mode { 23 SEMIHOSTING_OPEN_R = 0, 24 SEMIHOSTING_OPEN_RB = 1, 25 SEMIHOSTING_OPEN_RX = 2, 26 SEMIHOSTING_OPEN_RXB = 3, 27 SEMIHOSTING_OPEN_W = 4, 28 SEMIHOSTING_OPEN_WB = 5, 29 SEMIHOSTING_OPEN_WX = 6, 30 SEMIHOSTING_OPEN_WXB = 7, 31 SEMIHOSTING_OPEN_A = 8, 32 SEMIHOSTING_OPEN_AB = 9, 33 SEMIHOSTING_OPEN_AX = 10, 34 SEMIHOSTING_OPEN_AXB = 11, 35 }; 36 37 enum semihosting_sys_ops { 38 /* Regular operations */ 39 SEMIHOSTING_SYS_OPEN = 0x01, 40 SEMIHOSTING_SYS_CLOSE = 0x02, 41 SEMIHOSTING_SYS_WRITEC = 0x03, 42 SEMIHOSTING_SYS_WRITE = 0x05, 43 SEMIHOSTING_SYS_READ = 0x06, 44 SEMIHOSTING_SYS_READC = 0x07, 45 }; 46 47 struct semihosting_param_t { 48 uintptr_t param0; 49 uintptr_t param1; 50 uintptr_t param2; 51 }; 52 53 /** 54 * @brief Read one character byte from the semihosting host debug terminal 55 * 56 * @retval the character read from the semihosting host 57 */ 58 char semihosting_sys_readc(void) 59 { 60 return __do_semihosting(SEMIHOSTING_SYS_READC, 0); 61 } 62 63 /** 64 * @brief Write one character byte to the semihosting host debug terminal 65 * @param c: the character to be written 66 */ 67 void semihosting_sys_writec(char c) 68 { 69 __do_semihosting(SEMIHOSTING_SYS_WRITEC, (uintptr_t)&c); 70 } 71 72 /** 73 * @brief Request the semihosting host to open a file on the host system 74 * @param fname: the path or name of the file 75 * @param flags: sys/fcntl.h standard flags to open the file with 76 * 77 * @retval nonzero if OK, or -1 if fails 78 */ 79 int semihosting_open(const char *fname, int flags) 80 { 81 int semi_open_flags = 0; 82 const int flags_mask = O_RDONLY | O_WRONLY | O_RDWR | 83 O_CREAT | O_TRUNC | O_APPEND; 84 struct semihosting_param_t arg = { }; 85 86 /* Convert the flags to semihosting open. */ 87 switch (flags & flags_mask) { 88 case O_RDONLY: /* 'r' */ 89 semi_open_flags = SEMIHOSTING_OPEN_R; 90 break; 91 case O_WRONLY | O_CREAT | O_TRUNC: /* 'w' */ 92 semi_open_flags = SEMIHOSTING_OPEN_W; 93 break; 94 case O_WRONLY | O_CREAT | O_APPEND: /* 'a' */ 95 semi_open_flags = SEMIHOSTING_OPEN_A; 96 break; 97 case O_RDWR: /* 'r+' */ 98 semi_open_flags = SEMIHOSTING_OPEN_RX; 99 break; 100 case O_RDWR | O_CREAT | O_TRUNC: /* 'w+' */ 101 semi_open_flags = SEMIHOSTING_OPEN_WX; 102 break; 103 case O_RDWR | O_CREAT | O_APPEND: /* 'a+' */ 104 semi_open_flags = SEMIHOSTING_OPEN_AX; 105 break; 106 default: 107 return -1; 108 } 109 110 arg.param0 = (uintptr_t)fname; 111 arg.param1 = semi_open_flags; 112 arg.param2 = strlen(fname); 113 114 return (int)__do_semihosting(SEMIHOSTING_SYS_OPEN, (uintptr_t)&arg); 115 } 116 117 /** 118 * @brief Read data from a file on the semihosting host system 119 * @param fd: a handle for a file previously opened 120 * @param ptr: pointer to a buffer 121 * @param len: the number of bytes to read to the buffer from the file 122 * 123 * @retval zero if OK, the same value as @len if fails, smaller value than @len 124 * for partial success 125 */ 126 size_t semihosting_read(int fd, void *ptr, size_t len) 127 { 128 struct semihosting_param_t arg = { 129 .param0 = fd, 130 .param1 = (uintptr_t)ptr, 131 .param2 = len 132 }; 133 134 return __do_semihosting(SEMIHOSTING_SYS_READ, (uintptr_t)&arg); 135 } 136 137 /** 138 * @brief Write data into a file on the semihosting host system 139 * @param fd: a handle for a file previously opened 140 * @param ptr: pointer to a buffer 141 * @param len: the number of bytes to be written from the buffer to the file 142 * 143 * @retval zero if OK, otherwise the number of bytes that are not written 144 */ 145 size_t semihosting_write(int fd, const void *ptr, size_t len) 146 { 147 struct semihosting_param_t arg = { 148 .param0 = fd, 149 .param1 = (uintptr_t)ptr, 150 .param2 = len 151 }; 152 153 return __do_semihosting(SEMIHOSTING_SYS_WRITE, (uintptr_t)&arg); 154 } 155 156 /** 157 * @brief Close a file on the semihosting host system 158 * @param fd: a handle for a file previously opened 159 * 160 * @retval zero if OK, -1 if fails 161 */ 162 int semihosting_close(int fd) 163 { 164 struct semihosting_param_t arg = { 165 .param0 = fd, 166 }; 167 168 return (int)__do_semihosting(SEMIHOSTING_SYS_CLOSE, (uintptr_t)&arg); 169 } 170