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 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/>.
22 #include "exec/helper-proto.h"
23 #include "exec/softmmu-semi.h"
24 #include "exec/semihost.h"
45 typedef struct UHIStat
{
49 uint16_t uhi_st_nlink
;
54 uint64_t uhi_st_atime
;
55 uint64_t uhi_st_spare1
;
56 uint64_t uhi_st_mtime
;
57 uint64_t uhi_st_spare2
;
58 uint64_t uhi_st_ctime
;
59 uint64_t uhi_st_spare3
;
60 uint64_t uhi_st_blksize
;
61 uint64_t uhi_st_blocks
;
62 uint64_t uhi_st_spare4
[2];
70 UHIOpen_CREAT
= 0x200,
71 UHIOpen_TRUNC
= 0x400,
75 /* Errno values taken from asm-mips/errno.h */
76 static uint16_t host_to_mips_errno
[] = {
86 static int errno_mips(int err
)
88 if (err
< 0 || err
>= ARRAY_SIZE(host_to_mips_errno
)) {
90 } else if (host_to_mips_errno
[err
]) {
91 return host_to_mips_errno
[err
];
97 static int copy_stat_to_target(CPUMIPSState
*env
, const struct stat
*src
,
100 hwaddr len
= sizeof(struct UHIStat
);
101 UHIStat
*dst
= lock_user(VERIFY_WRITE
, vaddr
, len
, 0);
107 dst
->uhi_st_dev
= tswap16(src
->st_dev
);
108 dst
->uhi_st_ino
= tswap16(src
->st_ino
);
109 dst
->uhi_st_mode
= tswap32(src
->st_mode
);
110 dst
->uhi_st_nlink
= tswap16(src
->st_nlink
);
111 dst
->uhi_st_uid
= tswap16(src
->st_uid
);
112 dst
->uhi_st_gid
= tswap16(src
->st_gid
);
113 dst
->uhi_st_rdev
= tswap16(src
->st_rdev
);
114 dst
->uhi_st_size
= tswap64(src
->st_size
);
115 dst
->uhi_st_atime
= tswap64(src
->st_atime
);
116 dst
->uhi_st_mtime
= tswap64(src
->st_mtime
);
117 dst
->uhi_st_ctime
= tswap64(src
->st_ctime
);
119 dst
->uhi_st_blksize
= 0;
120 dst
->uhi_st_blocks
= 0;
122 dst
->uhi_st_blksize
= tswap64(src
->st_blksize
);
123 dst
->uhi_st_blocks
= tswap64(src
->st_blocks
);
125 unlock_user(dst
, vaddr
, len
);
129 static int get_open_flags(target_ulong target_flags
)
133 if (target_flags
& UHIOpen_RDWR
) {
134 open_flags
|= O_RDWR
;
135 } else if (target_flags
& UHIOpen_WRONLY
) {
136 open_flags
|= O_WRONLY
;
138 open_flags
|= O_RDONLY
;
141 open_flags
|= (target_flags
& UHIOpen_APPEND
) ? O_APPEND
: 0;
142 open_flags
|= (target_flags
& UHIOpen_CREAT
) ? O_CREAT
: 0;
143 open_flags
|= (target_flags
& UHIOpen_TRUNC
) ? O_TRUNC
: 0;
144 open_flags
|= (target_flags
& UHIOpen_EXCL
) ? O_EXCL
: 0;
149 static int write_to_file(CPUMIPSState
*env
, target_ulong fd
, target_ulong vaddr
,
150 target_ulong len
, target_ulong offset
)
153 void *dst
= lock_user(VERIFY_READ
, vaddr
, len
, 1);
163 num_of_bytes
= pwrite(fd
, dst
, len
, offset
);
166 num_of_bytes
= write(fd
, dst
, len
);
169 unlock_user(dst
, vaddr
, 0);
173 static int read_from_file(CPUMIPSState
*env
, target_ulong fd
,
174 target_ulong vaddr
, target_ulong len
,
178 void *dst
= lock_user(VERIFY_WRITE
, vaddr
, len
, 0);
188 num_of_bytes
= pread(fd
, dst
, len
, offset
);
191 num_of_bytes
= read(fd
, dst
, len
);
194 unlock_user(dst
, vaddr
, len
);
198 static int copy_argn_to_target(CPUMIPSState
*env
, int arg_num
,
201 int strsize
= strlen(semihosting_get_arg(arg_num
)) + 1;
202 char *dst
= lock_user(VERIFY_WRITE
, vaddr
, strsize
, 0);
207 strcpy(dst
, semihosting_get_arg(arg_num
));
209 unlock_user(dst
, vaddr
, strsize
);
213 #define GET_TARGET_STRING(p, addr) \
215 p = lock_user_string(addr); \
223 #define GET_TARGET_STRINGS_2(p, addr, p2, addr2) \
225 p = lock_user_string(addr); \
231 p2 = lock_user_string(addr2); \
233 unlock_user(p, addr, 0); \
240 #define FREE_TARGET_STRING(p, gpr) \
242 unlock_user(p, gpr, 0); \
245 void helper_do_semihosting(CPUMIPSState
*env
)
247 target_ulong
*gpr
= env
->active_tc
.gpr
;
248 const UHIOp op
= gpr
[25];
253 qemu_log("UHI(%d): exit(%d)\n", op
, (int)gpr
[4]);
256 GET_TARGET_STRING(p
, gpr
[4]);
257 if (!strcmp("/dev/stdin", p
)) {
259 } else if (!strcmp("/dev/stdout", p
)) {
261 } else if (!strcmp("/dev/stderr", p
)) {
264 gpr
[2] = open(p
, get_open_flags(gpr
[5]), gpr
[6]);
265 gpr
[3] = errno_mips(errno
);
267 FREE_TARGET_STRING(p
, gpr
[4]);
271 /* ignore closing stdin/stdout/stderr */
275 gpr
[2] = close(gpr
[4]);
276 gpr
[3] = errno_mips(errno
);
279 gpr
[2] = read_from_file(env
, gpr
[4], gpr
[5], gpr
[6], 0);
280 gpr
[3] = errno_mips(errno
);
283 gpr
[2] = write_to_file(env
, gpr
[4], gpr
[5], gpr
[6], 0);
284 gpr
[3] = errno_mips(errno
);
287 gpr
[2] = lseek(gpr
[4], gpr
[5], gpr
[6]);
288 gpr
[3] = errno_mips(errno
);
291 GET_TARGET_STRING(p
, gpr
[4]);
293 gpr
[3] = errno_mips(errno
);
294 FREE_TARGET_STRING(p
, gpr
[4]);
299 memset(&sbuf
, 0, sizeof(sbuf
));
300 gpr
[2] = fstat(gpr
[4], &sbuf
);
301 gpr
[3] = errno_mips(errno
);
305 gpr
[2] = copy_stat_to_target(env
, &sbuf
, gpr
[5]);
306 gpr
[3] = errno_mips(errno
);
310 gpr
[2] = semihosting_get_argc();
313 if (gpr
[4] >= semihosting_get_argc()) {
317 gpr
[2] = strlen(semihosting_get_arg(gpr
[4]));
320 if (gpr
[4] >= semihosting_get_argc()) {
324 gpr
[2] = copy_argn_to_target(env
, gpr
[4], gpr
[5]);
327 GET_TARGET_STRING(p
, gpr
[4]);
328 p2
= strstr(p
, "%d");
330 int char_num
= p2
- p
;
331 char *buf
= g_malloc(char_num
+ 1);
332 strncpy(buf
, p
, char_num
);
333 buf
[char_num
] = '\0';
334 gpr
[2] = printf("%s%d%s", buf
, (int)gpr
[5], p2
+ 2);
337 gpr
[2] = printf("%s", p
);
339 FREE_TARGET_STRING(p
, gpr
[4]);
342 GET_TARGET_STRINGS_2(p
, gpr
[4], p2
, gpr
[5]);
343 printf("assertion '");
345 printf("': file \"%s\", line %d\n", p2
, (int)gpr
[6]);
346 FREE_TARGET_STRING(p2
, gpr
[5]);
347 FREE_TARGET_STRING(p
, gpr
[4]);
351 gpr
[2] = read_from_file(env
, gpr
[4], gpr
[5], gpr
[6], gpr
[7]);
352 gpr
[3] = errno_mips(errno
);
355 gpr
[2] = write_to_file(env
, gpr
[4], gpr
[5], gpr
[6], gpr
[7]);
356 gpr
[3] = errno_mips(errno
);
360 GET_TARGET_STRINGS_2(p
, gpr
[4], p2
, gpr
[5]);
361 gpr
[2] = link(p
, p2
);
362 gpr
[3] = errno_mips(errno
);
363 FREE_TARGET_STRING(p2
, gpr
[5]);
364 FREE_TARGET_STRING(p
, gpr
[4]);
368 fprintf(stderr
, "Unknown UHI operation %d\n", op
);