2 * Unified Hosting Interface syscalls.
4 * Copyright (c) 2015 Imagination Technologies
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 #include "qemu/osdep.h"
23 #include "semihosting/softmmu-uaccess.h"
24 #include "semihosting/semihost.h"
25 #include "semihosting/console.h"
47 typedef struct UHIStat
{
51 uint16_t uhi_st_nlink
;
56 uint64_t uhi_st_atime
;
57 uint64_t uhi_st_spare1
;
58 uint64_t uhi_st_mtime
;
59 uint64_t uhi_st_spare2
;
60 uint64_t uhi_st_ctime
;
61 uint64_t uhi_st_spare3
;
62 uint64_t uhi_st_blksize
;
63 uint64_t uhi_st_blocks
;
64 uint64_t uhi_st_spare4
[2];
72 UHIOpen_CREAT
= 0x200,
73 UHIOpen_TRUNC
= 0x400,
93 UHI_ENAMETOOLONG
= 91,
95 UHI_ENETUNREACH
= 114,
113 UHI_EWOULDBLOCK
= 11,
117 static int errno_mips(int host_errno
)
119 /* Errno values taken from asm-mips/errno.h */
120 switch (host_errno
) {
122 case ENAMETOOLONG
: return 78;
124 case EOVERFLOW
: return 79;
127 case ELOOP
: return 90;
129 default: return EINVAL
;
133 static int copy_stat_to_target(CPUMIPSState
*env
, const struct stat
*src
,
136 hwaddr len
= sizeof(struct UHIStat
);
137 UHIStat
*dst
= lock_user(VERIFY_WRITE
, vaddr
, len
, 0);
143 dst
->uhi_st_dev
= tswap16(src
->st_dev
);
144 dst
->uhi_st_ino
= tswap16(src
->st_ino
);
145 dst
->uhi_st_mode
= tswap32(src
->st_mode
);
146 dst
->uhi_st_nlink
= tswap16(src
->st_nlink
);
147 dst
->uhi_st_uid
= tswap16(src
->st_uid
);
148 dst
->uhi_st_gid
= tswap16(src
->st_gid
);
149 dst
->uhi_st_rdev
= tswap16(src
->st_rdev
);
150 dst
->uhi_st_size
= tswap64(src
->st_size
);
151 dst
->uhi_st_atime
= tswap64(src
->st_atime
);
152 dst
->uhi_st_mtime
= tswap64(src
->st_mtime
);
153 dst
->uhi_st_ctime
= tswap64(src
->st_ctime
);
155 dst
->uhi_st_blksize
= 0;
156 dst
->uhi_st_blocks
= 0;
158 dst
->uhi_st_blksize
= tswap64(src
->st_blksize
);
159 dst
->uhi_st_blocks
= tswap64(src
->st_blocks
);
161 unlock_user(dst
, vaddr
, len
);
165 static int get_open_flags(target_ulong target_flags
)
169 if (target_flags
& UHIOpen_RDWR
) {
170 open_flags
|= O_RDWR
;
171 } else if (target_flags
& UHIOpen_WRONLY
) {
172 open_flags
|= O_WRONLY
;
174 open_flags
|= O_RDONLY
;
177 open_flags
|= (target_flags
& UHIOpen_APPEND
) ? O_APPEND
: 0;
178 open_flags
|= (target_flags
& UHIOpen_CREAT
) ? O_CREAT
: 0;
179 open_flags
|= (target_flags
& UHIOpen_TRUNC
) ? O_TRUNC
: 0;
180 open_flags
|= (target_flags
& UHIOpen_EXCL
) ? O_EXCL
: 0;
185 static int write_to_file(CPUMIPSState
*env
, target_ulong fd
, target_ulong vaddr
,
186 target_ulong len
, target_ulong offset
)
189 void *dst
= lock_user(VERIFY_READ
, vaddr
, len
, 1);
199 num_of_bytes
= pwrite(fd
, dst
, len
, offset
);
202 num_of_bytes
= write(fd
, dst
, len
);
205 unlock_user(dst
, vaddr
, 0);
209 static int read_from_file(CPUMIPSState
*env
, target_ulong fd
,
210 target_ulong vaddr
, target_ulong len
,
214 void *dst
= lock_user(VERIFY_WRITE
, vaddr
, len
, 0);
224 num_of_bytes
= pread(fd
, dst
, len
, offset
);
227 num_of_bytes
= read(fd
, dst
, len
);
230 unlock_user(dst
, vaddr
, len
);
234 static int copy_argn_to_target(CPUMIPSState
*env
, int arg_num
,
237 int strsize
= strlen(semihosting_get_arg(arg_num
)) + 1;
238 char *dst
= lock_user(VERIFY_WRITE
, vaddr
, strsize
, 0);
243 strcpy(dst
, semihosting_get_arg(arg_num
));
245 unlock_user(dst
, vaddr
, strsize
);
249 #define GET_TARGET_STRING(p, addr) \
251 p = lock_user_string(addr); \
259 #define GET_TARGET_STRINGS_2(p, addr, p2, addr2) \
261 p = lock_user_string(addr); \
267 p2 = lock_user_string(addr2); \
269 unlock_user(p, addr, 0); \
276 #define FREE_TARGET_STRING(p, gpr) \
278 unlock_user(p, gpr, 0); \
281 void mips_semihosting(CPUMIPSState
*env
)
283 target_ulong
*gpr
= env
->active_tc
.gpr
;
284 const UHIOp op
= gpr
[25];
289 qemu_log("UHI(%d): exit(%d)\n", op
, (int)gpr
[4]);
292 GET_TARGET_STRING(p
, gpr
[4]);
293 if (!strcmp("/dev/stdin", p
)) {
295 } else if (!strcmp("/dev/stdout", p
)) {
297 } else if (!strcmp("/dev/stderr", p
)) {
300 gpr
[2] = open(p
, get_open_flags(gpr
[5]), gpr
[6]);
301 gpr
[3] = errno_mips(errno
);
303 FREE_TARGET_STRING(p
, gpr
[4]);
307 /* ignore closing stdin/stdout/stderr */
311 gpr
[2] = close(gpr
[4]);
312 gpr
[3] = errno_mips(errno
);
315 gpr
[2] = read_from_file(env
, gpr
[4], gpr
[5], gpr
[6], 0);
316 gpr
[3] = errno_mips(errno
);
319 gpr
[2] = write_to_file(env
, gpr
[4], gpr
[5], gpr
[6], 0);
320 gpr
[3] = errno_mips(errno
);
323 gpr
[2] = lseek(gpr
[4], gpr
[5], gpr
[6]);
324 gpr
[3] = errno_mips(errno
);
327 GET_TARGET_STRING(p
, gpr
[4]);
329 gpr
[3] = errno_mips(errno
);
330 FREE_TARGET_STRING(p
, gpr
[4]);
335 memset(&sbuf
, 0, sizeof(sbuf
));
336 gpr
[2] = fstat(gpr
[4], &sbuf
);
337 gpr
[3] = errno_mips(errno
);
341 gpr
[2] = copy_stat_to_target(env
, &sbuf
, gpr
[5]);
342 gpr
[3] = errno_mips(errno
);
346 gpr
[2] = semihosting_get_argc();
349 if (gpr
[4] >= semihosting_get_argc()) {
353 gpr
[2] = strlen(semihosting_get_arg(gpr
[4]));
356 if (gpr
[4] >= semihosting_get_argc()) {
360 gpr
[2] = copy_argn_to_target(env
, gpr
[4], gpr
[5]);
363 GET_TARGET_STRING(p
, gpr
[4]);
364 p2
= strstr(p
, "%d");
366 int char_num
= p2
- p
;
367 GString
*s
= g_string_new_len(p
, char_num
);
368 g_string_append_printf(s
, "%d%s", (int)gpr
[5], p2
+ 2);
369 gpr
[2] = qemu_semihosting_log_out(s
->str
, s
->len
);
370 g_string_free(s
, true);
372 gpr
[2] = qemu_semihosting_log_out(p
, strlen(p
));
374 FREE_TARGET_STRING(p
, gpr
[4]);
377 GET_TARGET_STRINGS_2(p
, gpr
[4], p2
, gpr
[5]);
378 printf("assertion '");
380 printf("': file \"%s\", line %d\n", p2
, (int)gpr
[6]);
381 FREE_TARGET_STRING(p2
, gpr
[5]);
382 FREE_TARGET_STRING(p
, gpr
[4]);
386 gpr
[2] = read_from_file(env
, gpr
[4], gpr
[5], gpr
[6], gpr
[7]);
387 gpr
[3] = errno_mips(errno
);
390 gpr
[2] = write_to_file(env
, gpr
[4], gpr
[5], gpr
[6], gpr
[7]);
391 gpr
[3] = errno_mips(errno
);
395 GET_TARGET_STRINGS_2(p
, gpr
[4], p2
, gpr
[5]);
396 gpr
[2] = link(p
, p2
);
397 gpr
[3] = errno_mips(errno
);
398 FREE_TARGET_STRING(p2
, gpr
[5]);
399 FREE_TARGET_STRING(p
, gpr
[4]);
403 fprintf(stderr
, "Unknown UHI operation %d\n", op
);