1 /* 2 * Syscall implementations for semihosting. 3 * 4 * Copyright (c) 2022 Linaro 5 * 6 * SPDX-License-Identifier: GPL-2.0-or-later 7 */ 8 9 #include "qemu/osdep.h" 10 #include "exec/gdbstub.h" 11 #include "semihosting/guestfd.h" 12 #include "semihosting/syscalls.h" 13 #ifdef CONFIG_USER_ONLY 14 #include "qemu.h" 15 #else 16 #include "semihosting/softmmu-uaccess.h" 17 #endif 18 19 20 /* 21 * Validate or compute the length of the string (including terminator). 22 */ 23 static int validate_strlen(CPUState *cs, target_ulong str, target_ulong tlen) 24 { 25 CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; 26 char c; 27 28 if (tlen == 0) { 29 ssize_t slen = target_strlen(str); 30 31 if (slen < 0) { 32 return -EFAULT; 33 } 34 if (slen >= INT32_MAX) { 35 return -ENAMETOOLONG; 36 } 37 return slen + 1; 38 } 39 if (tlen > INT32_MAX) { 40 return -ENAMETOOLONG; 41 } 42 if (get_user_u8(c, str + tlen - 1)) { 43 return -EFAULT; 44 } 45 if (c != 0) { 46 return -EINVAL; 47 } 48 return tlen; 49 } 50 51 static int validate_lock_user_string(char **pstr, CPUState *cs, 52 target_ulong tstr, target_ulong tlen) 53 { 54 int ret = validate_strlen(cs, tstr, tlen); 55 CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; 56 char *str = NULL; 57 58 if (ret > 0) { 59 str = lock_user(VERIFY_READ, tstr, ret, true); 60 ret = str ? 0 : -EFAULT; 61 } 62 *pstr = str; 63 return ret; 64 } 65 66 /* 67 * GDB semihosting syscall implementations. 68 */ 69 70 static gdb_syscall_complete_cb gdb_open_complete; 71 72 static void gdb_open_cb(CPUState *cs, target_ulong ret, target_ulong err) 73 { 74 if (!err) { 75 int guestfd = alloc_guestfd(); 76 associate_guestfd(guestfd, ret); 77 ret = guestfd; 78 } 79 gdb_open_complete(cs, ret, err); 80 } 81 82 static void gdb_open(CPUState *cs, gdb_syscall_complete_cb complete, 83 target_ulong fname, target_ulong fname_len, 84 int gdb_flags, int mode) 85 { 86 int len = validate_strlen(cs, fname, fname_len); 87 if (len < 0) { 88 complete(cs, -1, -len); 89 return; 90 } 91 92 gdb_open_complete = complete; 93 gdb_do_syscall(gdb_open_cb, "open,%s,%x,%x", 94 fname, len, (target_ulong)gdb_flags, (target_ulong)mode); 95 } 96 97 static void gdb_close(CPUState *cs, gdb_syscall_complete_cb complete, 98 GuestFD *gf) 99 { 100 gdb_do_syscall(complete, "close,%x", (target_ulong)gf->hostfd); 101 } 102 103 static void gdb_read(CPUState *cs, gdb_syscall_complete_cb complete, 104 GuestFD *gf, target_ulong buf, target_ulong len) 105 { 106 gdb_do_syscall(complete, "read,%x,%x,%x", 107 (target_ulong)gf->hostfd, buf, len); 108 } 109 110 static void gdb_write(CPUState *cs, gdb_syscall_complete_cb complete, 111 GuestFD *gf, target_ulong buf, target_ulong len) 112 { 113 gdb_do_syscall(complete, "write,%x,%x,%x", 114 (target_ulong)gf->hostfd, buf, len); 115 } 116 117 static void gdb_lseek(CPUState *cs, gdb_syscall_complete_cb complete, 118 GuestFD *gf, int64_t off, int gdb_whence) 119 { 120 gdb_do_syscall(complete, "lseek,%x,%lx,%x", 121 (target_ulong)gf->hostfd, off, (target_ulong)gdb_whence); 122 } 123 124 static void gdb_isatty(CPUState *cs, gdb_syscall_complete_cb complete, 125 GuestFD *gf) 126 { 127 gdb_do_syscall(complete, "isatty,%x", (target_ulong)gf->hostfd); 128 } 129 130 /* 131 * Host semihosting syscall implementations. 132 */ 133 134 static void host_open(CPUState *cs, gdb_syscall_complete_cb complete, 135 target_ulong fname, target_ulong fname_len, 136 int gdb_flags, int mode) 137 { 138 CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; 139 char *p; 140 int ret, host_flags; 141 142 ret = validate_lock_user_string(&p, cs, fname, fname_len); 143 if (ret < 0) { 144 complete(cs, -1, -ret); 145 return; 146 } 147 148 if (gdb_flags & GDB_O_WRONLY) { 149 host_flags = O_WRONLY; 150 } else if (gdb_flags & GDB_O_RDWR) { 151 host_flags = O_RDWR; 152 } else { 153 host_flags = O_RDONLY; 154 } 155 if (gdb_flags & GDB_O_CREAT) { 156 host_flags |= O_CREAT; 157 } 158 if (gdb_flags & GDB_O_TRUNC) { 159 host_flags |= O_TRUNC; 160 } 161 if (gdb_flags & GDB_O_EXCL) { 162 host_flags |= O_EXCL; 163 } 164 165 ret = open(p, host_flags, mode); 166 if (ret < 0) { 167 complete(cs, -1, errno); 168 } else { 169 int guestfd = alloc_guestfd(); 170 associate_guestfd(guestfd, ret); 171 complete(cs, guestfd, 0); 172 } 173 unlock_user(p, fname, 0); 174 } 175 176 static void host_close(CPUState *cs, gdb_syscall_complete_cb complete, 177 GuestFD *gf) 178 { 179 /* 180 * Only close the underlying host fd if it's one we opened on behalf 181 * of the guest in SYS_OPEN. 182 */ 183 if (gf->hostfd != STDIN_FILENO && 184 gf->hostfd != STDOUT_FILENO && 185 gf->hostfd != STDERR_FILENO && 186 close(gf->hostfd) < 0) { 187 complete(cs, -1, errno); 188 } else { 189 complete(cs, 0, 0); 190 } 191 } 192 193 static void host_read(CPUState *cs, gdb_syscall_complete_cb complete, 194 GuestFD *gf, target_ulong buf, target_ulong len) 195 { 196 CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; 197 void *ptr = lock_user(VERIFY_WRITE, buf, len, 0); 198 ssize_t ret; 199 200 if (!ptr) { 201 complete(cs, -1, EFAULT); 202 return; 203 } 204 do { 205 ret = read(gf->hostfd, ptr, len); 206 } while (ret == -1 && errno == EINTR); 207 if (ret == -1) { 208 complete(cs, -1, errno); 209 unlock_user(ptr, buf, 0); 210 } else { 211 complete(cs, ret, 0); 212 unlock_user(ptr, buf, ret); 213 } 214 } 215 216 static void host_write(CPUState *cs, gdb_syscall_complete_cb complete, 217 GuestFD *gf, target_ulong buf, target_ulong len) 218 { 219 CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; 220 void *ptr = lock_user(VERIFY_READ, buf, len, 1); 221 ssize_t ret; 222 223 if (!ptr) { 224 complete(cs, -1, EFAULT); 225 return; 226 } 227 ret = write(gf->hostfd, ptr, len); 228 complete(cs, ret, ret == -1 ? errno : 0); 229 unlock_user(ptr, buf, 0); 230 } 231 232 static void host_lseek(CPUState *cs, gdb_syscall_complete_cb complete, 233 GuestFD *gf, int64_t off, int whence) 234 { 235 /* So far, all hosts use the same values. */ 236 QEMU_BUILD_BUG_ON(GDB_SEEK_SET != SEEK_SET); 237 QEMU_BUILD_BUG_ON(GDB_SEEK_CUR != SEEK_CUR); 238 QEMU_BUILD_BUG_ON(GDB_SEEK_END != SEEK_END); 239 240 off_t ret = off; 241 int err = 0; 242 243 if (ret == off) { 244 ret = lseek(gf->hostfd, ret, whence); 245 if (ret == -1) { 246 err = errno; 247 } 248 } else { 249 ret = -1; 250 err = EINVAL; 251 } 252 complete(cs, ret, err); 253 } 254 255 static void host_isatty(CPUState *cs, gdb_syscall_complete_cb complete, 256 GuestFD *gf) 257 { 258 int ret = isatty(gf->hostfd); 259 complete(cs, ret, ret ? 0 : errno); 260 } 261 262 /* 263 * Static file semihosting syscall implementations. 264 */ 265 266 static void staticfile_read(CPUState *cs, gdb_syscall_complete_cb complete, 267 GuestFD *gf, target_ulong buf, target_ulong len) 268 { 269 CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; 270 target_ulong rest = gf->staticfile.len - gf->staticfile.off; 271 void *ptr; 272 273 if (len > rest) { 274 len = rest; 275 } 276 ptr = lock_user(VERIFY_WRITE, buf, len, 0); 277 if (!ptr) { 278 complete(cs, -1, EFAULT); 279 return; 280 } 281 memcpy(ptr, gf->staticfile.data + gf->staticfile.off, len); 282 gf->staticfile.off += len; 283 complete(cs, len, 0); 284 unlock_user(ptr, buf, len); 285 } 286 287 static void staticfile_lseek(CPUState *cs, gdb_syscall_complete_cb complete, 288 GuestFD *gf, int64_t off, int gdb_whence) 289 { 290 int64_t ret; 291 292 switch (gdb_whence) { 293 case GDB_SEEK_SET: 294 ret = off; 295 break; 296 case GDB_SEEK_CUR: 297 ret = gf->staticfile.off + off; 298 break; 299 case GDB_SEEK_END: 300 ret = gf->staticfile.len + off; 301 break; 302 default: 303 ret = -1; 304 break; 305 } 306 if (ret >= 0 && ret <= gf->staticfile.len) { 307 gf->staticfile.off = ret; 308 complete(cs, ret, 0); 309 } else { 310 complete(cs, -1, EINVAL); 311 } 312 } 313 314 /* 315 * Syscall entry points. 316 */ 317 318 void semihost_sys_open(CPUState *cs, gdb_syscall_complete_cb complete, 319 target_ulong fname, target_ulong fname_len, 320 int gdb_flags, int mode) 321 { 322 if (use_gdb_syscalls()) { 323 gdb_open(cs, complete, fname, fname_len, gdb_flags, mode); 324 } else { 325 host_open(cs, complete, fname, fname_len, gdb_flags, mode); 326 } 327 } 328 329 void semihost_sys_close(CPUState *cs, gdb_syscall_complete_cb complete, int fd) 330 { 331 GuestFD *gf = get_guestfd(fd); 332 333 if (!gf) { 334 complete(cs, -1, EBADF); 335 return; 336 } 337 switch (gf->type) { 338 case GuestFDGDB: 339 gdb_close(cs, complete, gf); 340 break; 341 case GuestFDHost: 342 host_close(cs, complete, gf); 343 break; 344 case GuestFDStatic: 345 complete(cs, 0, 0); 346 break; 347 default: 348 g_assert_not_reached(); 349 } 350 dealloc_guestfd(fd); 351 } 352 353 void semihost_sys_read_gf(CPUState *cs, gdb_syscall_complete_cb complete, 354 GuestFD *gf, target_ulong buf, target_ulong len) 355 { 356 /* 357 * Bound length for 64-bit guests on 32-bit hosts, not overlowing ssize_t. 358 * Note the Linux kernel does this with MAX_RW_COUNT, so it's not a bad 359 * idea to do this unconditionally. 360 */ 361 if (len > INT32_MAX) { 362 len = INT32_MAX; 363 } 364 switch (gf->type) { 365 case GuestFDGDB: 366 gdb_read(cs, complete, gf, buf, len); 367 break; 368 case GuestFDHost: 369 host_read(cs, complete, gf, buf, len); 370 break; 371 case GuestFDStatic: 372 staticfile_read(cs, complete, gf, buf, len); 373 break; 374 default: 375 g_assert_not_reached(); 376 } 377 } 378 379 void semihost_sys_read(CPUState *cs, gdb_syscall_complete_cb complete, 380 int fd, target_ulong buf, target_ulong len) 381 { 382 GuestFD *gf = get_guestfd(fd); 383 384 if (gf) { 385 semihost_sys_read_gf(cs, complete, gf, buf, len); 386 } else { 387 complete(cs, -1, EBADF); 388 } 389 } 390 391 void semihost_sys_write_gf(CPUState *cs, gdb_syscall_complete_cb complete, 392 GuestFD *gf, target_ulong buf, target_ulong len) 393 { 394 /* 395 * Bound length for 64-bit guests on 32-bit hosts, not overlowing ssize_t. 396 * Note the Linux kernel does this with MAX_RW_COUNT, so it's not a bad 397 * idea to do this unconditionally. 398 */ 399 if (len > INT32_MAX) { 400 len = INT32_MAX; 401 } 402 switch (gf->type) { 403 case GuestFDGDB: 404 gdb_write(cs, complete, gf, buf, len); 405 break; 406 case GuestFDHost: 407 host_write(cs, complete, gf, buf, len); 408 break; 409 case GuestFDStatic: 410 /* Static files are never open for writing: EBADF. */ 411 complete(cs, -1, EBADF); 412 break; 413 default: 414 g_assert_not_reached(); 415 } 416 } 417 418 void semihost_sys_write(CPUState *cs, gdb_syscall_complete_cb complete, 419 int fd, target_ulong buf, target_ulong len) 420 { 421 GuestFD *gf = get_guestfd(fd); 422 423 if (gf) { 424 semihost_sys_write_gf(cs, complete, gf, buf, len); 425 } else { 426 complete(cs, -1, EBADF); 427 } 428 } 429 430 void semihost_sys_lseek(CPUState *cs, gdb_syscall_complete_cb complete, 431 int fd, int64_t off, int gdb_whence) 432 { 433 GuestFD *gf = get_guestfd(fd); 434 435 if (!gf) { 436 complete(cs, -1, EBADF); 437 return; 438 } 439 switch (gf->type) { 440 case GuestFDGDB: 441 gdb_lseek(cs, complete, gf, off, gdb_whence); 442 return; 443 case GuestFDHost: 444 host_lseek(cs, complete, gf, off, gdb_whence); 445 break; 446 case GuestFDStatic: 447 staticfile_lseek(cs, complete, gf, off, gdb_whence); 448 break; 449 default: 450 g_assert_not_reached(); 451 } 452 } 453 454 void semihost_sys_isatty(CPUState *cs, gdb_syscall_complete_cb complete, int fd) 455 { 456 GuestFD *gf = get_guestfd(fd); 457 458 if (!gf) { 459 complete(cs, 0, EBADF); 460 return; 461 } 462 switch (gf->type) { 463 case GuestFDGDB: 464 gdb_isatty(cs, complete, gf); 465 break; 466 case GuestFDHost: 467 host_isatty(cs, complete, gf); 468 break; 469 case GuestFDStatic: 470 complete(cs, 0, ENOTTY); 471 break; 472 default: 473 g_assert_not_reached(); 474 } 475 } 476