bellard | a4f8197 | 2005-04-23 18:25:41 +0000 | [diff] [blame] | 1 | /* |
Keith Packard | 0bb446d | 2021-01-08 22:42:49 +0000 | [diff] [blame] | 2 | * Semihosting support for systems modeled on the Arm "Angel" |
Keith Packard | a10b9d9 | 2021-01-08 22:42:52 +0000 | [diff] [blame] | 3 | * semihosting syscalls design. This includes Arm and RISC-V processors |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 4 | * |
pbrook | 8e71621 | 2007-01-20 17:12:09 +0000 | [diff] [blame] | 5 | * Copyright (c) 2005, 2007 CodeSourcery. |
Alex Bennée | 4cb28db | 2019-05-14 12:08:39 +0100 | [diff] [blame] | 6 | * Copyright (c) 2019 Linaro |
pbrook | 8e71621 | 2007-01-20 17:12:09 +0000 | [diff] [blame] | 7 | * Written by Paul Brook. |
bellard | a4f8197 | 2005-04-23 18:25:41 +0000 | [diff] [blame] | 8 | * |
Keith Packard | 0bb446d | 2021-01-08 22:42:49 +0000 | [diff] [blame] | 9 | * Copyright © 2020 by Keith Packard <keithp@keithp.com> |
| 10 | * Adapted for systems other than ARM, including RISC-V, by Keith Packard |
| 11 | * |
bellard | a4f8197 | 2005-04-23 18:25:41 +0000 | [diff] [blame] | 12 | * This program is free software; you can redistribute it and/or modify |
| 13 | * it under the terms of the GNU General Public License as published by |
| 14 | * the Free Software Foundation; either version 2 of the License, or |
| 15 | * (at your option) any later version. |
| 16 | * |
| 17 | * This program is distributed in the hope that it will be useful, |
| 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 20 | * GNU General Public License for more details. |
| 21 | * |
| 22 | * You should have received a copy of the GNU General Public License |
Blue Swirl | 8167ee8 | 2009-07-16 20:47:01 +0000 | [diff] [blame] | 23 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
Alex Bennée | 4cb28db | 2019-05-14 12:08:39 +0100 | [diff] [blame] | 24 | * |
| 25 | * ARM Semihosting is documented in: |
| 26 | * Semihosting for AArch32 and AArch64 Release 2.0 |
Alex Bennée | 424d5ec | 2022-09-29 12:42:21 +0100 | [diff] [blame] | 27 | * https://github.com/ARM-software/abi-aa/blob/main/semihosting/semihosting.rst |
Keith Packard | a10b9d9 | 2021-01-08 22:42:52 +0000 | [diff] [blame] | 28 | * |
| 29 | * RISC-V Semihosting is documented in: |
| 30 | * RISC-V Semihosting |
| 31 | * https://github.com/riscv/riscv-semihosting-spec/blob/main/riscv-semihosting-spec.adoc |
bellard | a4f8197 | 2005-04-23 18:25:41 +0000 | [diff] [blame] | 32 | */ |
| 33 | |
Peter Maydell | 74c21bd | 2015-12-07 16:23:44 +0000 | [diff] [blame] | 34 | #include "qemu/osdep.h" |
Richard Henderson | 5b3f39c | 2022-04-28 01:44:28 -0700 | [diff] [blame] | 35 | #include "qemu/timer.h" |
| 36 | #include "exec/gdbstub.h" |
Alex Bennée | c566080 | 2023-03-02 18:57:57 -0800 | [diff] [blame] | 37 | #include "gdbstub/syscalls.h" |
Philippe Mathieu-Daudé | 6b5fe13 | 2021-03-05 13:54:49 +0000 | [diff] [blame] | 38 | #include "semihosting/semihost.h" |
| 39 | #include "semihosting/console.h" |
| 40 | #include "semihosting/common-semi.h" |
Richard Henderson | 1c6ff72 | 2022-04-27 21:38:02 -0700 | [diff] [blame] | 41 | #include "semihosting/guestfd.h" |
Richard Henderson | 5b3f39c | 2022-04-28 01:44:28 -0700 | [diff] [blame] | 42 | #include "semihosting/syscalls.h" |
Richard Henderson | 1c6ff72 | 2022-04-27 21:38:02 -0700 | [diff] [blame] | 43 | |
pbrook | 8e71621 | 2007-01-20 17:12:09 +0000 | [diff] [blame] | 44 | #ifdef CONFIG_USER_ONLY |
bellard | a4f8197 | 2005-04-23 18:25:41 +0000 | [diff] [blame] | 45 | #include "qemu.h" |
| 46 | |
Keith Packard | 3c37cfe | 2021-01-08 22:42:50 +0000 | [diff] [blame] | 47 | #define COMMON_SEMI_HEAP_SIZE (128 * 1024 * 1024) |
pbrook | 8e71621 | 2007-01-20 17:12:09 +0000 | [diff] [blame] | 48 | #else |
Veronia Bahaa | f348b6d | 2016-03-20 19:16:19 +0200 | [diff] [blame] | 49 | #include "qemu/cutils.h" |
Alex Bennée | 5fc983a | 2022-02-25 17:20:20 +0000 | [diff] [blame] | 50 | #include "hw/loader.h" |
Paolo Bonzini | 6e504a9 | 2020-10-28 06:18:20 -0400 | [diff] [blame] | 51 | #include "hw/boards.h" |
pbrook | 8e71621 | 2007-01-20 17:12:09 +0000 | [diff] [blame] | 52 | #endif |
bellard | a4f8197 | 2005-04-23 18:25:41 +0000 | [diff] [blame] | 53 | |
Stefan Weil | 3881725 | 2012-04-28 05:07:47 +0000 | [diff] [blame] | 54 | #define TARGET_SYS_OPEN 0x01 |
| 55 | #define TARGET_SYS_CLOSE 0x02 |
| 56 | #define TARGET_SYS_WRITEC 0x03 |
| 57 | #define TARGET_SYS_WRITE0 0x04 |
| 58 | #define TARGET_SYS_WRITE 0x05 |
| 59 | #define TARGET_SYS_READ 0x06 |
| 60 | #define TARGET_SYS_READC 0x07 |
Keith Packard | 767ba04 | 2021-01-08 22:42:56 +0000 | [diff] [blame] | 61 | #define TARGET_SYS_ISERROR 0x08 |
Stefan Weil | 3881725 | 2012-04-28 05:07:47 +0000 | [diff] [blame] | 62 | #define TARGET_SYS_ISTTY 0x09 |
| 63 | #define TARGET_SYS_SEEK 0x0a |
| 64 | #define TARGET_SYS_FLEN 0x0c |
| 65 | #define TARGET_SYS_TMPNAM 0x0d |
| 66 | #define TARGET_SYS_REMOVE 0x0e |
| 67 | #define TARGET_SYS_RENAME 0x0f |
| 68 | #define TARGET_SYS_CLOCK 0x10 |
| 69 | #define TARGET_SYS_TIME 0x11 |
| 70 | #define TARGET_SYS_SYSTEM 0x12 |
| 71 | #define TARGET_SYS_ERRNO 0x13 |
| 72 | #define TARGET_SYS_GET_CMDLINE 0x15 |
| 73 | #define TARGET_SYS_HEAPINFO 0x16 |
| 74 | #define TARGET_SYS_EXIT 0x18 |
Peter Maydell | e9ebfbf | 2015-09-07 10:39:28 +0100 | [diff] [blame] | 75 | #define TARGET_SYS_SYNCCACHE 0x19 |
Peter Maydell | 22a43bb | 2019-09-16 15:15:43 +0100 | [diff] [blame] | 76 | #define TARGET_SYS_EXIT_EXTENDED 0x20 |
Keith Packard | 4d83403 | 2021-01-08 22:42:54 +0000 | [diff] [blame] | 77 | #define TARGET_SYS_ELAPSED 0x30 |
| 78 | #define TARGET_SYS_TICKFREQ 0x31 |
bellard | a4f8197 | 2005-04-23 18:25:41 +0000 | [diff] [blame] | 79 | |
Liviu Ionescu | 1ecc3a2 | 2014-12-11 12:07:48 +0000 | [diff] [blame] | 80 | /* ADP_Stopped_ApplicationExit is used for exit(0), |
| 81 | * anything else is implemented as exit(1) */ |
| 82 | #define ADP_Stopped_ApplicationExit (0x20026) |
| 83 | |
bellard | a4f8197 | 2005-04-23 18:25:41 +0000 | [diff] [blame] | 84 | #ifndef O_BINARY |
| 85 | #define O_BINARY 0 |
| 86 | #endif |
| 87 | |
pbrook | a2d1eba | 2007-01-28 03:10:55 +0000 | [diff] [blame] | 88 | static int gdb_open_modeflags[12] = { |
| 89 | GDB_O_RDONLY, |
Richard Henderson | a1a2a3e | 2022-06-07 10:50:43 -0700 | [diff] [blame] | 90 | GDB_O_RDONLY, |
pbrook | a2d1eba | 2007-01-28 03:10:55 +0000 | [diff] [blame] | 91 | GDB_O_RDWR, |
Richard Henderson | a1a2a3e | 2022-06-07 10:50:43 -0700 | [diff] [blame] | 92 | GDB_O_RDWR, |
pbrook | a2d1eba | 2007-01-28 03:10:55 +0000 | [diff] [blame] | 93 | GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC, |
Richard Henderson | a1a2a3e | 2022-06-07 10:50:43 -0700 | [diff] [blame] | 94 | GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC, |
pbrook | a2d1eba | 2007-01-28 03:10:55 +0000 | [diff] [blame] | 95 | GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC, |
Richard Henderson | a1a2a3e | 2022-06-07 10:50:43 -0700 | [diff] [blame] | 96 | GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC, |
pbrook | a2d1eba | 2007-01-28 03:10:55 +0000 | [diff] [blame] | 97 | GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND, |
Richard Henderson | a1a2a3e | 2022-06-07 10:50:43 -0700 | [diff] [blame] | 98 | GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND, |
pbrook | a2d1eba | 2007-01-28 03:10:55 +0000 | [diff] [blame] | 99 | GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND, |
Richard Henderson | a1a2a3e | 2022-06-07 10:50:43 -0700 | [diff] [blame] | 100 | GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND, |
pbrook | a2d1eba | 2007-01-28 03:10:55 +0000 | [diff] [blame] | 101 | }; |
| 102 | |
Keith Packard | 095f8c0 | 2021-01-08 22:42:51 +0000 | [diff] [blame] | 103 | #ifndef CONFIG_USER_ONLY |
Alex Bennée | 5fc983a | 2022-02-25 17:20:20 +0000 | [diff] [blame] | 104 | |
| 105 | /** |
| 106 | * common_semi_find_bases: find information about ram and heap base |
| 107 | * |
| 108 | * This function attempts to provide meaningful numbers for RAM and |
| 109 | * HEAP base addresses. The rambase is simply the lowest addressable |
| 110 | * RAM position. For the heapbase we ask the loader to scan the |
| 111 | * address space and the largest available gap by querying the "ROM" |
| 112 | * regions. |
| 113 | * |
| 114 | * Returns: a structure with the numbers we need. |
Keith Packard | 095f8c0 | 2021-01-08 22:42:51 +0000 | [diff] [blame] | 115 | */ |
Alex Bennée | 5fc983a | 2022-02-25 17:20:20 +0000 | [diff] [blame] | 116 | |
| 117 | typedef struct LayoutInfo { |
| 118 | target_ulong rambase; |
| 119 | size_t ramsize; |
| 120 | hwaddr heapbase; |
| 121 | hwaddr heaplimit; |
| 122 | } LayoutInfo; |
| 123 | |
| 124 | static bool find_ram_cb(Int128 start, Int128 len, const MemoryRegion *mr, |
| 125 | hwaddr offset_in_region, void *opaque) |
Keith Packard | 095f8c0 | 2021-01-08 22:42:51 +0000 | [diff] [blame] | 126 | { |
Alex Bennée | 5fc983a | 2022-02-25 17:20:20 +0000 | [diff] [blame] | 127 | LayoutInfo *info = (LayoutInfo *) opaque; |
| 128 | uint64_t size = int128_get64(len); |
| 129 | |
| 130 | if (!mr->ram || mr->readonly) { |
| 131 | return false; |
| 132 | } |
| 133 | |
| 134 | if (size > info->ramsize) { |
| 135 | info->rambase = int128_get64(start); |
| 136 | info->ramsize = size; |
| 137 | } |
| 138 | |
| 139 | /* search exhaustively for largest RAM */ |
| 140 | return false; |
| 141 | } |
| 142 | |
| 143 | static LayoutInfo common_semi_find_bases(CPUState *cs) |
| 144 | { |
| 145 | FlatView *fv; |
| 146 | LayoutInfo info = { 0, 0, 0, 0 }; |
| 147 | |
| 148 | RCU_READ_LOCK_GUARD(); |
| 149 | |
| 150 | fv = address_space_to_flatview(cs->as); |
| 151 | flatview_for_each_range(fv, find_ram_cb, &info); |
Keith Packard | 095f8c0 | 2021-01-08 22:42:51 +0000 | [diff] [blame] | 152 | |
| 153 | /* |
Alex Bennée | 5fc983a | 2022-02-25 17:20:20 +0000 | [diff] [blame] | 154 | * If we have found the RAM lets iterate through the ROM blobs to |
| 155 | * work out the best place for the remainder of RAM and split it |
| 156 | * equally between stack and heap. |
Keith Packard | 095f8c0 | 2021-01-08 22:42:51 +0000 | [diff] [blame] | 157 | */ |
Alex Bennée | 5fc983a | 2022-02-25 17:20:20 +0000 | [diff] [blame] | 158 | if (info.rambase || info.ramsize > 0) { |
| 159 | RomGap gap = rom_find_largest_gap_between(info.rambase, info.ramsize); |
| 160 | info.heapbase = gap.base; |
| 161 | info.heaplimit = gap.base + gap.size; |
Keith Packard | 095f8c0 | 2021-01-08 22:42:51 +0000 | [diff] [blame] | 162 | } |
Alex Bennée | 5fc983a | 2022-02-25 17:20:20 +0000 | [diff] [blame] | 163 | |
| 164 | return info; |
Keith Packard | 095f8c0 | 2021-01-08 22:42:51 +0000 | [diff] [blame] | 165 | } |
Alex Bennée | 5fc983a | 2022-02-25 17:20:20 +0000 | [diff] [blame] | 166 | |
Keith Packard | 095f8c0 | 2021-01-08 22:42:51 +0000 | [diff] [blame] | 167 | #endif |
| 168 | |
Richard Henderson | 1b3b769 | 2022-06-07 10:31:22 -0700 | [diff] [blame] | 169 | #include "common-semi-target.h" |
Keith Packard | a10b9d9 | 2021-01-08 22:42:52 +0000 | [diff] [blame] | 170 | |
Peter Maydell | 35e9a0a | 2019-09-16 15:15:33 +0100 | [diff] [blame] | 171 | /* |
Richard Henderson | 3753b00 | 2022-04-28 11:40:14 -0700 | [diff] [blame] | 172 | * Read the input value from the argument block; fail the semihosting |
| 173 | * call if the memory read fails. Eventually we could use a generic |
| 174 | * CPUState helper function here. |
Peter Maydell | fed49cd | 2022-07-25 15:05:15 +0100 | [diff] [blame] | 175 | * Note that GET_ARG() handles memory access errors by jumping to |
| 176 | * do_fault, so must be used as the first thing done in handling a |
| 177 | * semihosting call, to avoid accidentally leaking allocated resources. |
| 178 | * SET_ARG(), since it unavoidably happens late, instead returns an |
| 179 | * error indication (0 on success, non-0 for error) which the caller |
| 180 | * should check. |
Richard Henderson | 3753b00 | 2022-04-28 11:40:14 -0700 | [diff] [blame] | 181 | */ |
| 182 | |
| 183 | #define GET_ARG(n) do { \ |
| 184 | if (is_64bit_semihosting(env)) { \ |
| 185 | if (get_user_u64(arg ## n, args + (n) * 8)) { \ |
| 186 | goto do_fault; \ |
| 187 | } \ |
| 188 | } else { \ |
| 189 | if (get_user_u32(arg ## n, args + (n) * 4)) { \ |
| 190 | goto do_fault; \ |
| 191 | } \ |
| 192 | } \ |
| 193 | } while (0) |
| 194 | |
| 195 | #define SET_ARG(n, val) \ |
| 196 | (is_64bit_semihosting(env) ? \ |
| 197 | put_user_u64(val, args + (n) * 8) : \ |
| 198 | put_user_u32(val, args + (n) * 4)) |
| 199 | |
| 200 | |
| 201 | /* |
Peter Maydell | 6ed6845 | 2019-09-16 15:15:34 +0100 | [diff] [blame] | 202 | * The semihosting API has no concept of its errno being thread-safe, |
| 203 | * as the API design predates SMP CPUs and was intended as a simple |
| 204 | * real-hardware set of debug functionality. For QEMU, we make the |
Philippe Mathieu-Daudé | f14eced | 2023-10-04 11:06:23 +0200 | [diff] [blame] | 205 | * errno be per-thread in linux-user mode; in system-mode it is a simple |
Peter Maydell | 6ed6845 | 2019-09-16 15:15:34 +0100 | [diff] [blame] | 206 | * global, and we assume that the guest takes care of avoiding any races. |
| 207 | */ |
| 208 | #ifndef CONFIG_USER_ONLY |
Peter Maydell | 1b00382 | 2019-09-16 15:15:30 +0100 | [diff] [blame] | 209 | static target_ulong syscall_err; |
| 210 | |
Philippe Mathieu-Daudé | f14eced | 2023-10-04 11:06:23 +0200 | [diff] [blame] | 211 | #include "semihosting/uaccess.h" |
Peter Maydell | 6ed6845 | 2019-09-16 15:15:34 +0100 | [diff] [blame] | 212 | #endif |
| 213 | |
Keith Packard | 3c37cfe | 2021-01-08 22:42:50 +0000 | [diff] [blame] | 214 | static inline uint32_t get_swi_errno(CPUState *cs) |
Peter Maydell | 6ed6845 | 2019-09-16 15:15:34 +0100 | [diff] [blame] | 215 | { |
| 216 | #ifdef CONFIG_USER_ONLY |
Ilya Leoshkevich | e4e5cb4 | 2024-03-05 12:09:39 +0000 | [diff] [blame] | 217 | TaskState *ts = get_task_state(cs); |
Peter Maydell | 6ed6845 | 2019-09-16 15:15:34 +0100 | [diff] [blame] | 218 | |
| 219 | return ts->swi_errno; |
| 220 | #else |
| 221 | return syscall_err; |
pbrook | 8e71621 | 2007-01-20 17:12:09 +0000 | [diff] [blame] | 222 | #endif |
Peter Maydell | 6ed6845 | 2019-09-16 15:15:34 +0100 | [diff] [blame] | 223 | } |
bellard | a4f8197 | 2005-04-23 18:25:41 +0000 | [diff] [blame] | 224 | |
Richard Henderson | 64c8c6a | 2022-04-29 16:21:43 -0700 | [diff] [blame] | 225 | static void common_semi_cb(CPUState *cs, uint64_t ret, int err) |
pbrook | a2d1eba | 2007-01-28 03:10:55 +0000 | [diff] [blame] | 226 | { |
Richard Henderson | 709fe27 | 2022-04-29 12:32:24 -0700 | [diff] [blame] | 227 | if (err) { |
Richard Henderson | 5aadd18 | 2022-05-16 19:25:19 -0700 | [diff] [blame] | 228 | #ifdef CONFIG_USER_ONLY |
Ilya Leoshkevich | e4e5cb4 | 2024-03-05 12:09:39 +0000 | [diff] [blame] | 229 | TaskState *ts = get_task_state(cs); |
Richard Henderson | 5aadd18 | 2022-05-16 19:25:19 -0700 | [diff] [blame] | 230 | ts->swi_errno = err; |
| 231 | #else |
| 232 | syscall_err = err; |
| 233 | #endif |
pbrook | a2d1eba | 2007-01-28 03:10:55 +0000 | [diff] [blame] | 234 | } |
Richard Henderson | 5aadd18 | 2022-05-16 19:25:19 -0700 | [diff] [blame] | 235 | common_semi_set_ret(cs, ret); |
Peter Maydell | faacc04 | 2015-09-07 10:39:28 +0100 | [diff] [blame] | 236 | } |
| 237 | |
Richard Henderson | 3c820dd | 2022-04-29 13:59:52 -0700 | [diff] [blame] | 238 | /* |
Richard Henderson | 5d77289 | 2022-05-01 17:55:20 -0700 | [diff] [blame] | 239 | * Use 0xdeadbeef as the return value when there isn't a defined |
| 240 | * return value for the call. |
| 241 | */ |
| 242 | static void common_semi_dead_cb(CPUState *cs, uint64_t ret, int err) |
| 243 | { |
| 244 | common_semi_set_ret(cs, 0xdeadbeef); |
| 245 | } |
| 246 | |
| 247 | /* |
Richard Henderson | af0484b | 2022-04-28 11:40:41 -0700 | [diff] [blame] | 248 | * SYS_READ and SYS_WRITE always return the number of bytes not read/written. |
| 249 | * There is no error condition, other than returning the original length. |
| 250 | */ |
Richard Henderson | 64c8c6a | 2022-04-29 16:21:43 -0700 | [diff] [blame] | 251 | static void common_semi_rw_cb(CPUState *cs, uint64_t ret, int err) |
Richard Henderson | af0484b | 2022-04-28 11:40:41 -0700 | [diff] [blame] | 252 | { |
| 253 | /* Recover the original length from the third argument. */ |
Richard Henderson | b77af26 | 2023-09-13 17:22:49 -0700 | [diff] [blame] | 254 | CPUArchState *env G_GNUC_UNUSED = cpu_env(cs); |
Richard Henderson | af0484b | 2022-04-28 11:40:41 -0700 | [diff] [blame] | 255 | target_ulong args = common_semi_arg(cs, 1); |
| 256 | target_ulong arg2; |
| 257 | GET_ARG(2); |
| 258 | |
| 259 | if (err) { |
| 260 | do_fault: |
| 261 | ret = 0; /* error: no bytes transmitted */ |
| 262 | } |
| 263 | common_semi_set_ret(cs, arg2 - ret); |
| 264 | } |
| 265 | |
| 266 | /* |
Richard Henderson | a221247 | 2022-04-28 12:31:25 -0700 | [diff] [blame] | 267 | * Convert from Posix ret+errno to Arm SYS_ISTTY return values. |
| 268 | * With gdbstub, err is only ever set for protocol errors to EIO. |
| 269 | */ |
Richard Henderson | 64c8c6a | 2022-04-29 16:21:43 -0700 | [diff] [blame] | 270 | static void common_semi_istty_cb(CPUState *cs, uint64_t ret, int err) |
Richard Henderson | a221247 | 2022-04-28 12:31:25 -0700 | [diff] [blame] | 271 | { |
| 272 | if (err) { |
| 273 | ret = (err == ENOTTY ? 0 : -1); |
| 274 | } |
| 275 | common_semi_cb(cs, ret, err); |
| 276 | } |
| 277 | |
| 278 | /* |
Richard Henderson | 9a89470 | 2022-04-28 12:04:44 -0700 | [diff] [blame] | 279 | * SYS_SEEK returns 0 on success, not the resulting offset. |
| 280 | */ |
Richard Henderson | 64c8c6a | 2022-04-29 16:21:43 -0700 | [diff] [blame] | 281 | static void common_semi_seek_cb(CPUState *cs, uint64_t ret, int err) |
Richard Henderson | 9a89470 | 2022-04-28 12:04:44 -0700 | [diff] [blame] | 282 | { |
| 283 | if (!err) { |
| 284 | ret = 0; |
| 285 | } |
| 286 | common_semi_cb(cs, ret, err); |
| 287 | } |
| 288 | |
| 289 | /* |
Richard Henderson | 3c820dd | 2022-04-29 13:59:52 -0700 | [diff] [blame] | 290 | * Return an address in target memory of 64 bytes where the remote |
| 291 | * gdb should write its stat struct. (The format of this structure |
| 292 | * is defined by GDB's remote protocol and is not target-specific.) |
| 293 | * We put this on the guest's stack just below SP. |
| 294 | */ |
Keith Packard | 3c37cfe | 2021-01-08 22:42:50 +0000 | [diff] [blame] | 295 | static target_ulong common_semi_flen_buf(CPUState *cs) |
Peter Maydell | faacc04 | 2015-09-07 10:39:28 +0100 | [diff] [blame] | 296 | { |
Richard Henderson | 3c820dd | 2022-04-29 13:59:52 -0700 | [diff] [blame] | 297 | target_ulong sp = common_semi_stack_bottom(cs); |
Peter Maydell | faacc04 | 2015-09-07 10:39:28 +0100 | [diff] [blame] | 298 | return sp - 64; |
pbrook | a2d1eba | 2007-01-28 03:10:55 +0000 | [diff] [blame] | 299 | } |
| 300 | |
Keith Packard | 3c37cfe | 2021-01-08 22:42:50 +0000 | [diff] [blame] | 301 | static void |
Richard Henderson | 64c8c6a | 2022-04-29 16:21:43 -0700 | [diff] [blame] | 302 | common_semi_flen_fstat_cb(CPUState *cs, uint64_t ret, int err) |
pbrook | 33d9cc8 | 2007-06-09 14:44:00 +0000 | [diff] [blame] | 303 | { |
Richard Henderson | 84ca0df | 2022-05-16 19:34:06 -0700 | [diff] [blame] | 304 | if (!err) { |
Richard Henderson | cd7f29e | 2022-04-29 14:55:21 -0700 | [diff] [blame] | 305 | /* The size is always stored in big-endian order, extract the value. */ |
| 306 | uint64_t size; |
Richard Henderson | a6300ed | 2022-04-29 09:05:36 -0700 | [diff] [blame] | 307 | if (cpu_memory_rw_debug(cs, common_semi_flen_buf(cs) + |
| 308 | offsetof(struct gdb_stat, gdb_st_size), |
| 309 | &size, 8, 0)) { |
| 310 | ret = -1, err = EFAULT; |
| 311 | } else { |
| 312 | size = be64_to_cpu(size); |
| 313 | if (ret != size) { |
| 314 | ret = -1, err = EOVERFLOW; |
| 315 | } |
| 316 | } |
Richard Henderson | 84ca0df | 2022-05-16 19:34:06 -0700 | [diff] [blame] | 317 | } |
| 318 | common_semi_cb(cs, ret, err); |
pbrook | 33d9cc8 | 2007-06-09 14:44:00 +0000 | [diff] [blame] | 319 | } |
| 320 | |
Richard Henderson | 1577eec | 2022-05-01 17:42:43 -0700 | [diff] [blame] | 321 | static void |
| 322 | common_semi_readc_cb(CPUState *cs, uint64_t ret, int err) |
| 323 | { |
| 324 | if (!err) { |
Richard Henderson | b77af26 | 2023-09-13 17:22:49 -0700 | [diff] [blame] | 325 | CPUArchState *env G_GNUC_UNUSED = cpu_env(cs); |
Richard Henderson | 1577eec | 2022-05-01 17:42:43 -0700 | [diff] [blame] | 326 | uint8_t ch; |
| 327 | |
| 328 | if (get_user_u8(ch, common_semi_stack_bottom(cs) - 1)) { |
| 329 | ret = -1, err = EFAULT; |
| 330 | } else { |
| 331 | ret = ch; |
| 332 | } |
| 333 | } |
| 334 | common_semi_cb(cs, ret, err); |
| 335 | } |
| 336 | |
Peter Maydell | c46a653 | 2019-09-16 15:15:42 +0100 | [diff] [blame] | 337 | #define SHFB_MAGIC_0 0x53 |
| 338 | #define SHFB_MAGIC_1 0x48 |
| 339 | #define SHFB_MAGIC_2 0x46 |
| 340 | #define SHFB_MAGIC_3 0x42 |
| 341 | |
Peter Maydell | 22a43bb | 2019-09-16 15:15:43 +0100 | [diff] [blame] | 342 | /* Feature bits reportable in feature byte 0 */ |
| 343 | #define SH_EXT_EXIT_EXTENDED (1 << 0) |
Peter Maydell | 6ee1864 | 2019-09-16 15:15:44 +0100 | [diff] [blame] | 344 | #define SH_EXT_STDOUT_STDERR (1 << 1) |
Peter Maydell | 22a43bb | 2019-09-16 15:15:43 +0100 | [diff] [blame] | 345 | |
Peter Maydell | c46a653 | 2019-09-16 15:15:42 +0100 | [diff] [blame] | 346 | static const uint8_t featurefile_data[] = { |
| 347 | SHFB_MAGIC_0, |
| 348 | SHFB_MAGIC_1, |
| 349 | SHFB_MAGIC_2, |
| 350 | SHFB_MAGIC_3, |
Peter Maydell | 6ee1864 | 2019-09-16 15:15:44 +0100 | [diff] [blame] | 351 | SH_EXT_EXIT_EXTENDED | SH_EXT_STDOUT_STDERR, /* Feature byte 0 */ |
Peter Maydell | c46a653 | 2019-09-16 15:15:42 +0100 | [diff] [blame] | 352 | }; |
| 353 | |
Alex Bennée | 3960ca5 | 2021-03-23 16:52:52 +0000 | [diff] [blame] | 354 | /* |
Alex Bennée | 4cb28db | 2019-05-14 12:08:39 +0100 | [diff] [blame] | 355 | * Do a semihosting call. |
| 356 | * |
| 357 | * The specification always says that the "return register" either |
| 358 | * returns a specific value or is corrupted, so we don't need to |
| 359 | * report to our caller whether we are returning a value or trying to |
Richard Henderson | 5d77289 | 2022-05-01 17:55:20 -0700 | [diff] [blame] | 360 | * leave the register unchanged. |
Alex Bennée | 4cb28db | 2019-05-14 12:08:39 +0100 | [diff] [blame] | 361 | */ |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 362 | void do_common_semihosting(CPUState *cs) |
bellard | a4f8197 | 2005-04-23 18:25:41 +0000 | [diff] [blame] | 363 | { |
Richard Henderson | b77af26 | 2023-09-13 17:22:49 -0700 | [diff] [blame] | 364 | CPUArchState *env = cpu_env(cs); |
pbrook | 53a5960 | 2006-03-25 19:31:22 +0000 | [diff] [blame] | 365 | target_ulong args; |
Peter Maydell | f296c0d | 2012-10-14 09:52:27 +0000 | [diff] [blame] | 366 | target_ulong arg0, arg1, arg2, arg3; |
Keith Packard | 27e3b10 | 2021-01-08 22:42:55 +0000 | [diff] [blame] | 367 | target_ulong ul_ret; |
bellard | a4f8197 | 2005-04-23 18:25:41 +0000 | [diff] [blame] | 368 | char * s; |
| 369 | int nr; |
Keith Packard | 4d83403 | 2021-01-08 22:42:54 +0000 | [diff] [blame] | 370 | int64_t elapsed; |
bellard | a4f8197 | 2005-04-23 18:25:41 +0000 | [diff] [blame] | 371 | |
Keith Packard | 3c37cfe | 2021-01-08 22:42:50 +0000 | [diff] [blame] | 372 | nr = common_semi_arg(cs, 0) & 0xffffffffU; |
| 373 | args = common_semi_arg(cs, 1); |
Peter Maydell | faacc04 | 2015-09-07 10:39:28 +0100 | [diff] [blame] | 374 | |
bellard | a4f8197 | 2005-04-23 18:25:41 +0000 | [diff] [blame] | 375 | switch (nr) { |
Stefan Weil | 3881725 | 2012-04-28 05:07:47 +0000 | [diff] [blame] | 376 | case TARGET_SYS_OPEN: |
Peter Maydell | 35e9a0a | 2019-09-16 15:15:33 +0100 | [diff] [blame] | 377 | { |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 378 | int ret, err = 0; |
| 379 | int hostfd; |
Peter Maydell | 35e9a0a | 2019-09-16 15:15:33 +0100 | [diff] [blame] | 380 | |
Peter Maydell | f296c0d | 2012-10-14 09:52:27 +0000 | [diff] [blame] | 381 | GET_ARG(0); |
| 382 | GET_ARG(1); |
| 383 | GET_ARG(2); |
| 384 | s = lock_user_string(arg0); |
| 385 | if (!s) { |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 386 | goto do_fault; |
Peter Maydell | f296c0d | 2012-10-14 09:52:27 +0000 | [diff] [blame] | 387 | } |
| 388 | if (arg1 >= 12) { |
| 389 | unlock_user(s, arg0, 0); |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 390 | common_semi_cb(cs, -1, EINVAL); |
| 391 | break; |
Peter Maydell | 35e9a0a | 2019-09-16 15:15:33 +0100 | [diff] [blame] | 392 | } |
| 393 | |
bellard | a4f8197 | 2005-04-23 18:25:41 +0000 | [diff] [blame] | 394 | if (strcmp(s, ":tt") == 0) { |
Peter Maydell | 6ee1864 | 2019-09-16 15:15:44 +0100 | [diff] [blame] | 395 | /* |
| 396 | * We implement SH_EXT_STDOUT_STDERR, so: |
| 397 | * open for read == stdin |
| 398 | * open for write == stdout |
| 399 | * open for append == stderr |
| 400 | */ |
| 401 | if (arg1 < 4) { |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 402 | hostfd = STDIN_FILENO; |
Peter Maydell | 6ee1864 | 2019-09-16 15:15:44 +0100 | [diff] [blame] | 403 | } else if (arg1 < 8) { |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 404 | hostfd = STDOUT_FILENO; |
Peter Maydell | 6ee1864 | 2019-09-16 15:15:44 +0100 | [diff] [blame] | 405 | } else { |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 406 | hostfd = STDERR_FILENO; |
Peter Maydell | 6ee1864 | 2019-09-16 15:15:44 +0100 | [diff] [blame] | 407 | } |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 408 | ret = alloc_guestfd(); |
| 409 | associate_guestfd(ret, hostfd); |
| 410 | } else if (strcmp(s, ":semihosting-features") == 0) { |
Peter Maydell | c46a653 | 2019-09-16 15:15:42 +0100 | [diff] [blame] | 411 | /* We must fail opens for modes other than 0 ('r') or 1 ('rb') */ |
| 412 | if (arg1 != 0 && arg1 != 1) { |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 413 | ret = -1; |
| 414 | err = EACCES; |
Peter Maydell | 35e9a0a | 2019-09-16 15:15:33 +0100 | [diff] [blame] | 415 | } else { |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 416 | ret = alloc_guestfd(); |
| 417 | staticfile_guestfd(ret, featurefile_data, |
| 418 | sizeof(featurefile_data)); |
| 419 | } |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 420 | } else { |
Richard Henderson | 5b3f39c | 2022-04-28 01:44:28 -0700 | [diff] [blame] | 421 | unlock_user(s, arg0, 0); |
| 422 | semihost_sys_open(cs, common_semi_cb, arg0, arg2 + 1, |
| 423 | gdb_open_modeflags[arg1], 0644); |
| 424 | break; |
pbrook | a2d1eba | 2007-01-28 03:10:55 +0000 | [diff] [blame] | 425 | } |
Peter Maydell | f296c0d | 2012-10-14 09:52:27 +0000 | [diff] [blame] | 426 | unlock_user(s, arg0, 0); |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 427 | common_semi_cb(cs, ret, err); |
| 428 | break; |
Peter Maydell | 35e9a0a | 2019-09-16 15:15:33 +0100 | [diff] [blame] | 429 | } |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 430 | |
Stefan Weil | 3881725 | 2012-04-28 05:07:47 +0000 | [diff] [blame] | 431 | case TARGET_SYS_CLOSE: |
Peter Maydell | f296c0d | 2012-10-14 09:52:27 +0000 | [diff] [blame] | 432 | GET_ARG(0); |
Richard Henderson | 5eadbbf | 2022-04-28 09:22:18 -0700 | [diff] [blame] | 433 | semihost_sys_close(cs, common_semi_cb, arg0); |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 434 | break; |
| 435 | |
Stefan Weil | 3881725 | 2012-04-28 05:07:47 +0000 | [diff] [blame] | 436 | case TARGET_SYS_WRITEC: |
Richard Henderson | 5d77289 | 2022-05-01 17:55:20 -0700 | [diff] [blame] | 437 | /* |
| 438 | * FIXME: the byte to be written is in a target_ulong slot, |
| 439 | * which means this is wrong for a big-endian guest. |
| 440 | */ |
| 441 | semihost_sys_write_gf(cs, common_semi_dead_cb, |
| 442 | &console_out_gf, args, 1); |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 443 | break; |
| 444 | |
Stefan Weil | 3881725 | 2012-04-28 05:07:47 +0000 | [diff] [blame] | 445 | case TARGET_SYS_WRITE0: |
Richard Henderson | 7281550 | 2022-05-01 18:02:53 -0700 | [diff] [blame] | 446 | { |
| 447 | ssize_t len = target_strlen(args); |
| 448 | if (len < 0) { |
| 449 | common_semi_dead_cb(cs, -1, EFAULT); |
| 450 | } else { |
| 451 | semihost_sys_write_gf(cs, common_semi_dead_cb, |
| 452 | &console_out_gf, args, len); |
| 453 | } |
| 454 | } |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 455 | break; |
| 456 | |
Stefan Weil | 3881725 | 2012-04-28 05:07:47 +0000 | [diff] [blame] | 457 | case TARGET_SYS_WRITE: |
Peter Maydell | f296c0d | 2012-10-14 09:52:27 +0000 | [diff] [blame] | 458 | GET_ARG(0); |
| 459 | GET_ARG(1); |
| 460 | GET_ARG(2); |
Richard Henderson | aa915bd | 2022-04-28 11:49:47 -0700 | [diff] [blame] | 461 | semihost_sys_write(cs, common_semi_rw_cb, arg0, arg1, arg2); |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 462 | break; |
Peter Maydell | 35e9a0a | 2019-09-16 15:15:33 +0100 | [diff] [blame] | 463 | |
Stefan Weil | 3881725 | 2012-04-28 05:07:47 +0000 | [diff] [blame] | 464 | case TARGET_SYS_READ: |
Peter Maydell | f296c0d | 2012-10-14 09:52:27 +0000 | [diff] [blame] | 465 | GET_ARG(0); |
| 466 | GET_ARG(1); |
| 467 | GET_ARG(2); |
Richard Henderson | af0484b | 2022-04-28 11:40:41 -0700 | [diff] [blame] | 468 | semihost_sys_read(cs, common_semi_rw_cb, arg0, arg1, arg2); |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 469 | break; |
Peter Maydell | 35e9a0a | 2019-09-16 15:15:33 +0100 | [diff] [blame] | 470 | |
Stefan Weil | 3881725 | 2012-04-28 05:07:47 +0000 | [diff] [blame] | 471 | case TARGET_SYS_READC: |
Richard Henderson | 1577eec | 2022-05-01 17:42:43 -0700 | [diff] [blame] | 472 | semihost_sys_read_gf(cs, common_semi_readc_cb, &console_in_gf, |
| 473 | common_semi_stack_bottom(cs) - 1, 1); |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 474 | break; |
| 475 | |
Keith Packard | 767ba04 | 2021-01-08 22:42:56 +0000 | [diff] [blame] | 476 | case TARGET_SYS_ISERROR: |
| 477 | GET_ARG(0); |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 478 | common_semi_set_ret(cs, (target_long)arg0 < 0); |
| 479 | break; |
| 480 | |
Stefan Weil | 3881725 | 2012-04-28 05:07:47 +0000 | [diff] [blame] | 481 | case TARGET_SYS_ISTTY: |
Peter Maydell | f296c0d | 2012-10-14 09:52:27 +0000 | [diff] [blame] | 482 | GET_ARG(0); |
Richard Henderson | a221247 | 2022-04-28 12:31:25 -0700 | [diff] [blame] | 483 | semihost_sys_isatty(cs, common_semi_istty_cb, arg0); |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 484 | break; |
Peter Maydell | 35e9a0a | 2019-09-16 15:15:33 +0100 | [diff] [blame] | 485 | |
Stefan Weil | 3881725 | 2012-04-28 05:07:47 +0000 | [diff] [blame] | 486 | case TARGET_SYS_SEEK: |
Peter Maydell | f296c0d | 2012-10-14 09:52:27 +0000 | [diff] [blame] | 487 | GET_ARG(0); |
| 488 | GET_ARG(1); |
Richard Henderson | 9a89470 | 2022-04-28 12:04:44 -0700 | [diff] [blame] | 489 | semihost_sys_lseek(cs, common_semi_seek_cb, arg0, arg1, GDB_SEEK_SET); |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 490 | break; |
Peter Maydell | 35e9a0a | 2019-09-16 15:15:33 +0100 | [diff] [blame] | 491 | |
Stefan Weil | 3881725 | 2012-04-28 05:07:47 +0000 | [diff] [blame] | 492 | case TARGET_SYS_FLEN: |
Peter Maydell | f296c0d | 2012-10-14 09:52:27 +0000 | [diff] [blame] | 493 | GET_ARG(0); |
Richard Henderson | a6300ed | 2022-04-29 09:05:36 -0700 | [diff] [blame] | 494 | semihost_sys_flen(cs, common_semi_flen_fstat_cb, common_semi_cb, |
| 495 | arg0, common_semi_flen_buf(cs)); |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 496 | break; |
Peter Maydell | 35e9a0a | 2019-09-16 15:15:33 +0100 | [diff] [blame] | 497 | |
Stefan Weil | 3881725 | 2012-04-28 05:07:47 +0000 | [diff] [blame] | 498 | case TARGET_SYS_TMPNAM: |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 499 | { |
| 500 | int len; |
| 501 | char *p; |
| 502 | |
Keith Packard | 27e3b10 | 2021-01-08 22:42:55 +0000 | [diff] [blame] | 503 | GET_ARG(0); |
| 504 | GET_ARG(1); |
| 505 | GET_ARG(2); |
Bin Meng | 3878d0c | 2022-10-27 19:36:16 +0100 | [diff] [blame] | 506 | len = asprintf(&s, "%s/qemu-%x%02x", g_get_tmp_dir(), |
| 507 | getpid(), (int)arg1 & 0xff); |
Peter Maydell | 9b1268f | 2022-07-25 15:05:16 +0100 | [diff] [blame] | 508 | if (len < 0) { |
| 509 | common_semi_set_ret(cs, -1); |
| 510 | break; |
| 511 | } |
| 512 | |
| 513 | /* Allow for trailing NUL */ |
| 514 | len++; |
Keith Packard | 27e3b10 | 2021-01-08 22:42:55 +0000 | [diff] [blame] | 515 | /* Make sure there's enough space in the buffer */ |
Peter Maydell | 9b1268f | 2022-07-25 15:05:16 +0100 | [diff] [blame] | 516 | if (len > arg2) { |
| 517 | free(s); |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 518 | common_semi_set_ret(cs, -1); |
| 519 | break; |
Keith Packard | 27e3b10 | 2021-01-08 22:42:55 +0000 | [diff] [blame] | 520 | } |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 521 | p = lock_user(VERIFY_WRITE, arg0, len, 0); |
| 522 | if (!p) { |
Peter Maydell | 9b1268f | 2022-07-25 15:05:16 +0100 | [diff] [blame] | 523 | free(s); |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 524 | goto do_fault; |
| 525 | } |
Peter Maydell | 9b1268f | 2022-07-25 15:05:16 +0100 | [diff] [blame] | 526 | memcpy(p, s, len); |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 527 | unlock_user(p, arg0, len); |
Keith Packard | 27e3b10 | 2021-01-08 22:42:55 +0000 | [diff] [blame] | 528 | free(s); |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 529 | common_semi_set_ret(cs, 0); |
| 530 | break; |
| 531 | } |
| 532 | |
Stefan Weil | 3881725 | 2012-04-28 05:07:47 +0000 | [diff] [blame] | 533 | case TARGET_SYS_REMOVE: |
Peter Maydell | f296c0d | 2012-10-14 09:52:27 +0000 | [diff] [blame] | 534 | GET_ARG(0); |
| 535 | GET_ARG(1); |
Richard Henderson | d49e79b | 2022-04-29 09:29:27 -0700 | [diff] [blame] | 536 | semihost_sys_remove(cs, common_semi_cb, arg0, arg1 + 1); |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 537 | break; |
| 538 | |
Stefan Weil | 3881725 | 2012-04-28 05:07:47 +0000 | [diff] [blame] | 539 | case TARGET_SYS_RENAME: |
Peter Maydell | f296c0d | 2012-10-14 09:52:27 +0000 | [diff] [blame] | 540 | GET_ARG(0); |
| 541 | GET_ARG(1); |
| 542 | GET_ARG(2); |
| 543 | GET_ARG(3); |
Richard Henderson | 25a95da | 2022-04-29 10:11:31 -0700 | [diff] [blame] | 544 | semihost_sys_rename(cs, common_semi_cb, arg0, arg1 + 1, arg2, arg3 + 1); |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 545 | break; |
| 546 | |
Stefan Weil | 3881725 | 2012-04-28 05:07:47 +0000 | [diff] [blame] | 547 | case TARGET_SYS_CLOCK: |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 548 | common_semi_set_ret(cs, clock() / (CLOCKS_PER_SEC / 100)); |
| 549 | break; |
| 550 | |
Stefan Weil | 3881725 | 2012-04-28 05:07:47 +0000 | [diff] [blame] | 551 | case TARGET_SYS_TIME: |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 552 | ul_ret = time(NULL); |
| 553 | common_semi_cb(cs, ul_ret, ul_ret == -1 ? errno : 0); |
| 554 | break; |
| 555 | |
Stefan Weil | 3881725 | 2012-04-28 05:07:47 +0000 | [diff] [blame] | 556 | case TARGET_SYS_SYSTEM: |
Peter Maydell | f296c0d | 2012-10-14 09:52:27 +0000 | [diff] [blame] | 557 | GET_ARG(0); |
| 558 | GET_ARG(1); |
Richard Henderson | 90d8e0b | 2022-04-29 13:57:19 -0700 | [diff] [blame] | 559 | semihost_sys_system(cs, common_semi_cb, arg0, arg1 + 1); |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 560 | break; |
| 561 | |
Stefan Weil | 3881725 | 2012-04-28 05:07:47 +0000 | [diff] [blame] | 562 | case TARGET_SYS_ERRNO: |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 563 | common_semi_set_ret(cs, get_swi_errno(cs)); |
| 564 | break; |
| 565 | |
Stefan Weil | 3881725 | 2012-04-28 05:07:47 +0000 | [diff] [blame] | 566 | case TARGET_SYS_GET_CMDLINE: |
pbrook | 38d0662 | 2006-11-19 20:29:35 +0000 | [diff] [blame] | 567 | { |
Cédric VINCENT | 1c1b40c | 2011-06-29 12:49:41 +0200 | [diff] [blame] | 568 | /* Build a command-line from the original argv. |
| 569 | * |
| 570 | * The inputs are: |
Peter Maydell | f296c0d | 2012-10-14 09:52:27 +0000 | [diff] [blame] | 571 | * * arg0, pointer to a buffer of at least the size |
| 572 | * specified in arg1. |
| 573 | * * arg1, size of the buffer pointed to by arg0 in |
Cédric VINCENT | 1c1b40c | 2011-06-29 12:49:41 +0200 | [diff] [blame] | 574 | * bytes. |
| 575 | * |
| 576 | * The outputs are: |
Peter Maydell | f296c0d | 2012-10-14 09:52:27 +0000 | [diff] [blame] | 577 | * * arg0, pointer to null-terminated string of the |
Cédric VINCENT | 1c1b40c | 2011-06-29 12:49:41 +0200 | [diff] [blame] | 578 | * command line. |
Peter Maydell | f296c0d | 2012-10-14 09:52:27 +0000 | [diff] [blame] | 579 | * * arg1, length of the string pointed to by arg0. |
Cédric VINCENT | 1c1b40c | 2011-06-29 12:49:41 +0200 | [diff] [blame] | 580 | */ |
bellard | 579a97f | 2007-11-11 14:26:47 +0000 | [diff] [blame] | 581 | |
Cédric VINCENT | 1c1b40c | 2011-06-29 12:49:41 +0200 | [diff] [blame] | 582 | char *output_buffer; |
Peter Maydell | f296c0d | 2012-10-14 09:52:27 +0000 | [diff] [blame] | 583 | size_t input_size; |
Cédric VINCENT | 1c1b40c | 2011-06-29 12:49:41 +0200 | [diff] [blame] | 584 | size_t output_size; |
| 585 | int status = 0; |
Liviu Ionescu | f3c2bda | 2015-06-26 14:22:36 +0100 | [diff] [blame] | 586 | #if !defined(CONFIG_USER_ONLY) |
| 587 | const char *cmdline; |
Peter Maydell | 6ed6845 | 2019-09-16 15:15:34 +0100 | [diff] [blame] | 588 | #else |
Ilya Leoshkevich | e4e5cb4 | 2024-03-05 12:09:39 +0000 | [diff] [blame] | 589 | TaskState *ts = get_task_state(cs); |
Liviu Ionescu | f3c2bda | 2015-06-26 14:22:36 +0100 | [diff] [blame] | 590 | #endif |
Peter Maydell | f296c0d | 2012-10-14 09:52:27 +0000 | [diff] [blame] | 591 | GET_ARG(0); |
| 592 | GET_ARG(1); |
| 593 | input_size = arg1; |
Cédric VINCENT | 1c1b40c | 2011-06-29 12:49:41 +0200 | [diff] [blame] | 594 | /* Compute the size of the output string. */ |
| 595 | #if !defined(CONFIG_USER_ONLY) |
Liviu Ionescu | f3c2bda | 2015-06-26 14:22:36 +0100 | [diff] [blame] | 596 | cmdline = semihosting_get_cmdline(); |
| 597 | if (cmdline == NULL) { |
| 598 | cmdline = ""; /* Default to an empty line. */ |
| 599 | } |
| 600 | output_size = strlen(cmdline) + 1; /* Count terminating 0. */ |
Cédric VINCENT | 1c1b40c | 2011-06-29 12:49:41 +0200 | [diff] [blame] | 601 | #else |
Wolfgang Schildbach | 2e8785a | 2010-12-06 15:06:05 +0000 | [diff] [blame] | 602 | unsigned int i; |
pbrook | 38d0662 | 2006-11-19 20:29:35 +0000 | [diff] [blame] | 603 | |
Richard Henderson | 60f1c80 | 2022-04-26 19:51:29 -0700 | [diff] [blame] | 604 | output_size = ts->info->env_strings - ts->info->arg_strings; |
Cédric VINCENT | 1c1b40c | 2011-06-29 12:49:41 +0200 | [diff] [blame] | 605 | if (!output_size) { |
Alex Bennée | 4cb28db | 2019-05-14 12:08:39 +0100 | [diff] [blame] | 606 | /* |
| 607 | * We special-case the "empty command line" case (argc==0). |
| 608 | * Just provide the terminating 0. |
| 609 | */ |
Cédric VINCENT | 1c1b40c | 2011-06-29 12:49:41 +0200 | [diff] [blame] | 610 | output_size = 1; |
Wolfgang Schildbach | 2e8785a | 2010-12-06 15:06:05 +0000 | [diff] [blame] | 611 | } |
pbrook | 8e71621 | 2007-01-20 17:12:09 +0000 | [diff] [blame] | 612 | #endif |
Cédric VINCENT | 1c1b40c | 2011-06-29 12:49:41 +0200 | [diff] [blame] | 613 | |
| 614 | if (output_size > input_size) { |
Alex Bennée | 4cb28db | 2019-05-14 12:08:39 +0100 | [diff] [blame] | 615 | /* Not enough space to store command-line arguments. */ |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 616 | common_semi_cb(cs, -1, E2BIG); |
| 617 | break; |
Cédric VINCENT | 1c1b40c | 2011-06-29 12:49:41 +0200 | [diff] [blame] | 618 | } |
| 619 | |
| 620 | /* Adjust the command-line length. */ |
Peter Maydell | f296c0d | 2012-10-14 09:52:27 +0000 | [diff] [blame] | 621 | if (SET_ARG(1, output_size - 1)) { |
| 622 | /* Couldn't write back to argument block */ |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 623 | goto do_fault; |
Peter Maydell | f296c0d | 2012-10-14 09:52:27 +0000 | [diff] [blame] | 624 | } |
Cédric VINCENT | 1c1b40c | 2011-06-29 12:49:41 +0200 | [diff] [blame] | 625 | |
| 626 | /* Lock the buffer on the ARM side. */ |
Peter Maydell | f296c0d | 2012-10-14 09:52:27 +0000 | [diff] [blame] | 627 | output_buffer = lock_user(VERIFY_WRITE, arg0, output_size, 0); |
Cédric VINCENT | 1c1b40c | 2011-06-29 12:49:41 +0200 | [diff] [blame] | 628 | if (!output_buffer) { |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 629 | goto do_fault; |
Cédric VINCENT | 1c1b40c | 2011-06-29 12:49:41 +0200 | [diff] [blame] | 630 | } |
| 631 | |
| 632 | /* Copy the command-line arguments. */ |
| 633 | #if !defined(CONFIG_USER_ONLY) |
Liviu Ionescu | f3c2bda | 2015-06-26 14:22:36 +0100 | [diff] [blame] | 634 | pstrcpy(output_buffer, output_size, cmdline); |
Cédric VINCENT | 1c1b40c | 2011-06-29 12:49:41 +0200 | [diff] [blame] | 635 | #else |
| 636 | if (output_size == 1) { |
| 637 | /* Empty command-line. */ |
| 638 | output_buffer[0] = '\0'; |
| 639 | goto out; |
| 640 | } |
| 641 | |
Richard Henderson | 60f1c80 | 2022-04-26 19:51:29 -0700 | [diff] [blame] | 642 | if (copy_from_user(output_buffer, ts->info->arg_strings, |
Cédric VINCENT | 1c1b40c | 2011-06-29 12:49:41 +0200 | [diff] [blame] | 643 | output_size)) { |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 644 | unlock_user(output_buffer, arg0, 0); |
| 645 | goto do_fault; |
Cédric VINCENT | 1c1b40c | 2011-06-29 12:49:41 +0200 | [diff] [blame] | 646 | } |
| 647 | |
| 648 | /* Separate arguments by white spaces. */ |
| 649 | for (i = 0; i < output_size - 1; i++) { |
| 650 | if (output_buffer[i] == 0) { |
| 651 | output_buffer[i] = ' '; |
| 652 | } |
| 653 | } |
| 654 | out: |
| 655 | #endif |
| 656 | /* Unlock the buffer on the ARM side. */ |
Peter Maydell | f296c0d | 2012-10-14 09:52:27 +0000 | [diff] [blame] | 657 | unlock_user(output_buffer, arg0, output_size); |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 658 | common_semi_cb(cs, status, 0); |
Cédric VINCENT | 1c1b40c | 2011-06-29 12:49:41 +0200 | [diff] [blame] | 659 | } |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 660 | break; |
| 661 | |
Stefan Weil | 3881725 | 2012-04-28 05:07:47 +0000 | [diff] [blame] | 662 | case TARGET_SYS_HEAPINFO: |
bellard | a4f8197 | 2005-04-23 18:25:41 +0000 | [diff] [blame] | 663 | { |
Peter Maydell | f566641 | 2016-07-04 13:06:35 +0100 | [diff] [blame] | 664 | target_ulong retvals[4]; |
Peter Maydell | f566641 | 2016-07-04 13:06:35 +0100 | [diff] [blame] | 665 | int i; |
Peter Maydell | 6ed6845 | 2019-09-16 15:15:34 +0100 | [diff] [blame] | 666 | #ifdef CONFIG_USER_ONLY |
Ilya Leoshkevich | e4e5cb4 | 2024-03-05 12:09:39 +0000 | [diff] [blame] | 667 | TaskState *ts = get_task_state(cs); |
Alex Bennée | 5fc983a | 2022-02-25 17:20:20 +0000 | [diff] [blame] | 668 | target_ulong limit; |
Peter Maydell | 6951595 | 2020-11-19 09:23:46 +0000 | [diff] [blame] | 669 | #else |
Alex Bennée | 5fc983a | 2022-02-25 17:20:20 +0000 | [diff] [blame] | 670 | LayoutInfo info = common_semi_find_bases(cs); |
Peter Maydell | 6ed6845 | 2019-09-16 15:15:34 +0100 | [diff] [blame] | 671 | #endif |
Peter Maydell | f566641 | 2016-07-04 13:06:35 +0100 | [diff] [blame] | 672 | |
Peter Maydell | f296c0d | 2012-10-14 09:52:27 +0000 | [diff] [blame] | 673 | GET_ARG(0); |
bellard | a4f8197 | 2005-04-23 18:25:41 +0000 | [diff] [blame] | 674 | |
pbrook | 8e71621 | 2007-01-20 17:12:09 +0000 | [diff] [blame] | 675 | #ifdef CONFIG_USER_ONLY |
Alex Bennée | 4cb28db | 2019-05-14 12:08:39 +0100 | [diff] [blame] | 676 | /* |
| 677 | * Some C libraries assume the heap immediately follows .bss, so |
| 678 | * allocate it using sbrk. |
| 679 | */ |
bellard | a4f8197 | 2005-04-23 18:25:41 +0000 | [diff] [blame] | 680 | if (!ts->heap_limit) { |
Peter Maydell | 206ae74 | 2011-04-18 16:34:25 +0100 | [diff] [blame] | 681 | abi_ulong ret; |
bellard | a4f8197 | 2005-04-23 18:25:41 +0000 | [diff] [blame] | 682 | |
pbrook | 53a5960 | 2006-03-25 19:31:22 +0000 | [diff] [blame] | 683 | ts->heap_base = do_brk(0); |
Keith Packard | 3c37cfe | 2021-01-08 22:42:50 +0000 | [diff] [blame] | 684 | limit = ts->heap_base + COMMON_SEMI_HEAP_SIZE; |
bellard | a4f8197 | 2005-04-23 18:25:41 +0000 | [diff] [blame] | 685 | /* Try a big heap, and reduce the size if that fails. */ |
| 686 | for (;;) { |
pbrook | 53a5960 | 2006-03-25 19:31:22 +0000 | [diff] [blame] | 687 | ret = do_brk(limit); |
Peter Maydell | 206ae74 | 2011-04-18 16:34:25 +0100 | [diff] [blame] | 688 | if (ret >= limit) { |
bellard | a4f8197 | 2005-04-23 18:25:41 +0000 | [diff] [blame] | 689 | break; |
Peter Maydell | 206ae74 | 2011-04-18 16:34:25 +0100 | [diff] [blame] | 690 | } |
bellard | a4f8197 | 2005-04-23 18:25:41 +0000 | [diff] [blame] | 691 | limit = (ts->heap_base >> 1) + (limit >> 1); |
| 692 | } |
| 693 | ts->heap_limit = limit; |
| 694 | } |
ths | 3b46e62 | 2007-09-17 08:09:54 +0000 | [diff] [blame] | 695 | |
Peter Maydell | f566641 | 2016-07-04 13:06:35 +0100 | [diff] [blame] | 696 | retvals[0] = ts->heap_base; |
| 697 | retvals[1] = ts->heap_limit; |
| 698 | retvals[2] = ts->stack_base; |
| 699 | retvals[3] = 0; /* Stack limit. */ |
pbrook | 8e71621 | 2007-01-20 17:12:09 +0000 | [diff] [blame] | 700 | #else |
Alex Bennée | 5fc983a | 2022-02-25 17:20:20 +0000 | [diff] [blame] | 701 | retvals[0] = info.heapbase; /* Heap Base */ |
| 702 | retvals[1] = info.heaplimit; /* Heap Limit */ |
| 703 | retvals[2] = info.heaplimit; /* Stack base */ |
| 704 | retvals[3] = info.heapbase; /* Stack limit. */ |
pbrook | 8e71621 | 2007-01-20 17:12:09 +0000 | [diff] [blame] | 705 | #endif |
Peter Maydell | f566641 | 2016-07-04 13:06:35 +0100 | [diff] [blame] | 706 | |
| 707 | for (i = 0; i < ARRAY_SIZE(retvals); i++) { |
| 708 | bool fail; |
| 709 | |
Alex Bennée | 35e3f02 | 2021-03-23 16:52:53 +0000 | [diff] [blame] | 710 | if (is_64bit_semihosting(env)) { |
| 711 | fail = put_user_u64(retvals[i], arg0 + i * 8); |
| 712 | } else { |
| 713 | fail = put_user_u32(retvals[i], arg0 + i * 4); |
| 714 | } |
Peter Maydell | f566641 | 2016-07-04 13:06:35 +0100 | [diff] [blame] | 715 | |
| 716 | if (fail) { |
| 717 | /* Couldn't write back to argument block */ |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 718 | goto do_fault; |
Peter Maydell | f566641 | 2016-07-04 13:06:35 +0100 | [diff] [blame] | 719 | } |
| 720 | } |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 721 | common_semi_set_ret(cs, 0); |
bellard | a4f8197 | 2005-04-23 18:25:41 +0000 | [diff] [blame] | 722 | } |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 723 | break; |
| 724 | |
Stefan Weil | 3881725 | 2012-04-28 05:07:47 +0000 | [diff] [blame] | 725 | case TARGET_SYS_EXIT: |
Peter Maydell | 22a43bb | 2019-09-16 15:15:43 +0100 | [diff] [blame] | 726 | case TARGET_SYS_EXIT_EXTENDED: |
Philippe Mathieu-Daudé | a60e573 | 2023-10-04 14:00:16 +0200 | [diff] [blame] | 727 | { |
| 728 | uint32_t ret; |
| 729 | |
Keith Packard | 3c37cfe | 2021-01-08 22:42:50 +0000 | [diff] [blame] | 730 | if (common_semi_sys_exit_extended(cs, nr)) { |
Alex Bennée | 4cb28db | 2019-05-14 12:08:39 +0100 | [diff] [blame] | 731 | /* |
Peter Maydell | 22a43bb | 2019-09-16 15:15:43 +0100 | [diff] [blame] | 732 | * The A64 version of SYS_EXIT takes a parameter block, |
Peter Maydell | 7446d35 | 2015-09-07 10:39:28 +0100 | [diff] [blame] | 733 | * so the application-exit type can return a subcode which |
| 734 | * is the exit status code from the application. |
Peter Maydell | 22a43bb | 2019-09-16 15:15:43 +0100 | [diff] [blame] | 735 | * SYS_EXIT_EXTENDED is an a new-in-v2.0 optional function |
| 736 | * which allows A32/T32 guests to also provide a status code. |
Peter Maydell | 7446d35 | 2015-09-07 10:39:28 +0100 | [diff] [blame] | 737 | */ |
| 738 | GET_ARG(0); |
| 739 | GET_ARG(1); |
| 740 | |
| 741 | if (arg0 == ADP_Stopped_ApplicationExit) { |
| 742 | ret = arg1; |
| 743 | } else { |
| 744 | ret = 1; |
| 745 | } |
| 746 | } else { |
Alex Bennée | 4cb28db | 2019-05-14 12:08:39 +0100 | [diff] [blame] | 747 | /* |
Peter Maydell | 22a43bb | 2019-09-16 15:15:43 +0100 | [diff] [blame] | 748 | * The A32/T32 version of SYS_EXIT specifies only |
| 749 | * Stopped_ApplicationExit as normal exit, but does not |
| 750 | * allow the guest to specify the exit status code. |
| 751 | * Everything else is considered an error. |
Alex Bennée | 4cb28db | 2019-05-14 12:08:39 +0100 | [diff] [blame] | 752 | */ |
Peter Maydell | 7446d35 | 2015-09-07 10:39:28 +0100 | [diff] [blame] | 753 | ret = (args == ADP_Stopped_ApplicationExit) ? 0 : 1; |
| 754 | } |
Alex Bennée | ad9dcb2 | 2021-01-08 22:42:43 +0000 | [diff] [blame] | 755 | gdb_exit(ret); |
Liviu Ionescu | 1ecc3a2 | 2014-12-11 12:07:48 +0000 | [diff] [blame] | 756 | exit(ret); |
Philippe Mathieu-Daudé | a60e573 | 2023-10-04 14:00:16 +0200 | [diff] [blame] | 757 | } |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 758 | |
Keith Packard | 4d83403 | 2021-01-08 22:42:54 +0000 | [diff] [blame] | 759 | case TARGET_SYS_ELAPSED: |
| 760 | elapsed = get_clock() - clock_start; |
| 761 | if (sizeof(target_ulong) == 8) { |
Peter Maydell | fed49cd | 2022-07-25 15:05:15 +0100 | [diff] [blame] | 762 | if (SET_ARG(0, elapsed)) { |
| 763 | goto do_fault; |
| 764 | } |
Keith Packard | 4d83403 | 2021-01-08 22:42:54 +0000 | [diff] [blame] | 765 | } else { |
Peter Maydell | fed49cd | 2022-07-25 15:05:15 +0100 | [diff] [blame] | 766 | if (SET_ARG(0, (uint32_t) elapsed) || |
| 767 | SET_ARG(1, (uint32_t) (elapsed >> 32))) { |
| 768 | goto do_fault; |
| 769 | } |
Keith Packard | 4d83403 | 2021-01-08 22:42:54 +0000 | [diff] [blame] | 770 | } |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 771 | common_semi_set_ret(cs, 0); |
| 772 | break; |
| 773 | |
Keith Packard | 4d83403 | 2021-01-08 22:42:54 +0000 | [diff] [blame] | 774 | case TARGET_SYS_TICKFREQ: |
| 775 | /* qemu always uses nsec */ |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 776 | common_semi_set_ret(cs, 1000000000); |
| 777 | break; |
| 778 | |
Peter Maydell | e9ebfbf | 2015-09-07 10:39:28 +0100 | [diff] [blame] | 779 | case TARGET_SYS_SYNCCACHE: |
Alex Bennée | 4cb28db | 2019-05-14 12:08:39 +0100 | [diff] [blame] | 780 | /* |
| 781 | * Clean the D-cache and invalidate the I-cache for the specified |
Peter Maydell | e9ebfbf | 2015-09-07 10:39:28 +0100 | [diff] [blame] | 782 | * virtual address range. This is a nop for us since we don't |
| 783 | * implement caches. This is only present on A64. |
| 784 | */ |
Richard Henderson | a1df4ba | 2022-04-29 14:16:01 -0700 | [diff] [blame] | 785 | if (common_semi_has_synccache(env)) { |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 786 | common_semi_set_ret(cs, 0); |
| 787 | break; |
Peter Maydell | e9ebfbf | 2015-09-07 10:39:28 +0100 | [diff] [blame] | 788 | } |
Richard Henderson | a1df4ba | 2022-04-29 14:16:01 -0700 | [diff] [blame] | 789 | /* fall through */ |
bellard | a4f8197 | 2005-04-23 18:25:41 +0000 | [diff] [blame] | 790 | default: |
| 791 | fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr); |
Markus Armbruster | 90c84c5 | 2019-04-17 21:18:02 +0200 | [diff] [blame] | 792 | cpu_dump_state(cs, stderr, 0); |
bellard | a4f8197 | 2005-04-23 18:25:41 +0000 | [diff] [blame] | 793 | abort(); |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 794 | |
Richard Henderson | ed3a06b | 2022-04-28 01:10:55 -0700 | [diff] [blame] | 795 | do_fault: |
| 796 | common_semi_cb(cs, -1, EFAULT); |
| 797 | break; |
bellard | a4f8197 | 2005-04-23 18:25:41 +0000 | [diff] [blame] | 798 | } |
| 799 | } |