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 "exec/helper-proto.h"
24 #include "exec/softmmu-semi.h"
25 #include "hw/semihosting/semihost.h"
26 #include "hw/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,
77 /* Errno values taken from asm-mips/errno.h */
78 static uint16_t host_to_mips_errno
[] = {
88 static int errno_mips(int err
)
90 if (err
< 0 || err
>= ARRAY_SIZE(host_to_mips_errno
)) {
92 } else if (host_to_mips_errno
[err
]) {
93 return host_to_mips_errno
[err
];
99 static int copy_stat_to_target(CPUMIPSState
*env
, const struct stat
*src
,
102 hwaddr len
= sizeof(struct UHIStat
);
103 UHIStat
*dst
= lock_user(VERIFY_WRITE
, vaddr
, len
, 0);
109 dst
->uhi_st_dev
= tswap16(src
->st_dev
);
110 dst
->uhi_st_ino
= tswap16(src
->st_ino
);
111 dst
->uhi_st_mode
= tswap32(src
->st_mode
);
112 dst
->uhi_st_nlink
= tswap16(src
->st_nlink
);
113 dst
->uhi_st_uid
= tswap16(src
->st_uid
);
114 dst
->uhi_st_gid
= tswap16(src
->st_gid
);
115 dst
->uhi_st_rdev
= tswap16(src
->st_rdev
);
116 dst
->uhi_st_size
= tswap64(src
->st_size
);
117 dst
->uhi_st_atime
= tswap64(src
->st_atime
);
118 dst
->uhi_st_mtime
= tswap64(src
->st_mtime
);
119 dst
->uhi_st_ctime
= tswap64(src
->st_ctime
);
121 dst
->uhi_st_blksize
= 0;
122 dst
->uhi_st_blocks
= 0;
124 dst
->uhi_st_blksize
= tswap64(src
->st_blksize
);
125 dst
->uhi_st_blocks
= tswap64(src
->st_blocks
);
127 unlock_user(dst
, vaddr
, len
);
131 static int get_open_flags(target_ulong target_flags
)
135 if (target_flags
& UHIOpen_RDWR
) {
136 open_flags
|= O_RDWR
;
137 } else if (target_flags
& UHIOpen_WRONLY
) {
138 open_flags
|= O_WRONLY
;
140 open_flags
|= O_RDONLY
;
143 open_flags
|= (target_flags
& UHIOpen_APPEND
) ? O_APPEND
: 0;
144 open_flags
|= (target_flags
& UHIOpen_CREAT
) ? O_CREAT
: 0;
145 open_flags
|= (target_flags
& UHIOpen_TRUNC
) ? O_TRUNC
: 0;
146 open_flags
|= (target_flags
& UHIOpen_EXCL
) ? O_EXCL
: 0;
151 static int write_to_file(CPUMIPSState
*env
, target_ulong fd
, target_ulong vaddr
,
152 target_ulong len
, target_ulong offset
)
155 void *dst
= lock_user(VERIFY_READ
, vaddr
, len
, 1);
165 num_of_bytes
= pwrite(fd
, dst
, len
, offset
);
168 num_of_bytes
= write(fd
, dst
, len
);
171 unlock_user(dst
, vaddr
, 0);
175 static int read_from_file(CPUMIPSState
*env
, target_ulong fd
,
176 target_ulong vaddr
, target_ulong len
,
180 void *dst
= lock_user(VERIFY_WRITE
, vaddr
, len
, 0);
190 num_of_bytes
= pread(fd
, dst
, len
, offset
);
193 num_of_bytes
= read(fd
, dst
, len
);
196 unlock_user(dst
, vaddr
, len
);
200 static int copy_argn_to_target(CPUMIPSState
*env
, int arg_num
,
203 int strsize
= strlen(semihosting_get_arg(arg_num
)) + 1;
204 char *dst
= lock_user(VERIFY_WRITE
, vaddr
, strsize
, 0);
209 strcpy(dst
, semihosting_get_arg(arg_num
));
211 unlock_user(dst
, vaddr
, strsize
);
215 #define GET_TARGET_STRING(p, addr) \
217 p = lock_user_string(addr); \
225 #define GET_TARGET_STRINGS_2(p, addr, p2, addr2) \
227 p = lock_user_string(addr); \
233 p2 = lock_user_string(addr2); \
235 unlock_user(p, addr, 0); \
242 #define FREE_TARGET_STRING(p, gpr) \
244 unlock_user(p, gpr, 0); \
247 void helper_do_semihosting(CPUMIPSState
*env
)
249 target_ulong
*gpr
= env
->active_tc
.gpr
;
250 const UHIOp op
= gpr
[25];
255 qemu_log("UHI(%d): exit(%d)\n", op
, (int)gpr
[4]);
258 GET_TARGET_STRING(p
, gpr
[4]);
259 if (!strcmp("/dev/stdin", p
)) {
261 } else if (!strcmp("/dev/stdout", p
)) {
263 } else if (!strcmp("/dev/stderr", p
)) {
266 gpr
[2] = open(p
, get_open_flags(gpr
[5]), gpr
[6]);
267 gpr
[3] = errno_mips(errno
);
269 FREE_TARGET_STRING(p
, gpr
[4]);
273 /* ignore closing stdin/stdout/stderr */
277 gpr
[2] = close(gpr
[4]);
278 gpr
[3] = errno_mips(errno
);
281 gpr
[2] = read_from_file(env
, gpr
[4], gpr
[5], gpr
[6], 0);
282 gpr
[3] = errno_mips(errno
);
285 gpr
[2] = write_to_file(env
, gpr
[4], gpr
[5], gpr
[6], 0);
286 gpr
[3] = errno_mips(errno
);
289 gpr
[2] = lseek(gpr
[4], gpr
[5], gpr
[6]);
290 gpr
[3] = errno_mips(errno
);
293 GET_TARGET_STRING(p
, gpr
[4]);
295 gpr
[3] = errno_mips(errno
);
296 FREE_TARGET_STRING(p
, gpr
[4]);
301 memset(&sbuf
, 0, sizeof(sbuf
));
302 gpr
[2] = fstat(gpr
[4], &sbuf
);
303 gpr
[3] = errno_mips(errno
);
307 gpr
[2] = copy_stat_to_target(env
, &sbuf
, gpr
[5]);
308 gpr
[3] = errno_mips(errno
);
312 gpr
[2] = semihosting_get_argc();
315 if (gpr
[4] >= semihosting_get_argc()) {
319 gpr
[2] = strlen(semihosting_get_arg(gpr
[4]));
322 if (gpr
[4] >= semihosting_get_argc()) {
326 gpr
[2] = copy_argn_to_target(env
, gpr
[4], gpr
[5]);
329 GET_TARGET_STRING(p
, gpr
[4]);
330 p2
= strstr(p
, "%d");
332 int char_num
= p2
- p
;
333 GString
*s
= g_string_new_len(p
, char_num
);
334 g_string_append_printf(s
, "%d%s", (int)gpr
[5], p2
+ 2);
335 gpr
[2] = qemu_semihosting_log_out(s
->str
, s
->len
);
336 g_string_free(s
, true);
338 gpr
[2] = qemu_semihosting_log_out(p
, strlen(p
));
340 FREE_TARGET_STRING(p
, gpr
[4]);
343 GET_TARGET_STRINGS_2(p
, gpr
[4], p2
, gpr
[5]);
344 printf("assertion '");
346 printf("': file \"%s\", line %d\n", p2
, (int)gpr
[6]);
347 FREE_TARGET_STRING(p2
, gpr
[5]);
348 FREE_TARGET_STRING(p
, gpr
[4]);
352 gpr
[2] = read_from_file(env
, gpr
[4], gpr
[5], gpr
[6], gpr
[7]);
353 gpr
[3] = errno_mips(errno
);
356 gpr
[2] = write_to_file(env
, gpr
[4], gpr
[5], gpr
[6], gpr
[7]);
357 gpr
[3] = errno_mips(errno
);
361 GET_TARGET_STRINGS_2(p
, gpr
[4], p2
, gpr
[5]);
362 gpr
[2] = link(p
, p2
);
363 gpr
[3] = errno_mips(errno
);
364 FREE_TARGET_STRING(p2
, gpr
[5]);
365 FREE_TARGET_STRING(p
, gpr
[4]);
369 fprintf(stderr
, "Unknown UHI operation %d\n", op
);