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 FREE_TARGET_STRING(p, gpr) \
225 unlock_user(p, gpr, 0); \
228 void helper_do_semihosting(CPUMIPSState
*env
)
230 target_ulong
*gpr
= env
->active_tc
.gpr
;
231 const UHIOp op
= gpr
[25];
236 qemu_log("UHI(%d): exit(%d)\n", op
, (int)gpr
[4]);
239 GET_TARGET_STRING(p
, gpr
[4]);
240 if (!strcmp("/dev/stdin", p
)) {
242 } else if (!strcmp("/dev/stdout", p
)) {
244 } else if (!strcmp("/dev/stderr", p
)) {
247 gpr
[2] = open(p
, get_open_flags(gpr
[5]), gpr
[6]);
248 gpr
[3] = errno_mips(errno
);
250 FREE_TARGET_STRING(p
, gpr
[4]);
254 /* ignore closing stdin/stdout/stderr */
258 gpr
[2] = close(gpr
[4]);
259 gpr
[3] = errno_mips(errno
);
262 gpr
[2] = read_from_file(env
, gpr
[4], gpr
[5], gpr
[6], 0);
263 gpr
[3] = errno_mips(errno
);
266 gpr
[2] = write_to_file(env
, gpr
[4], gpr
[5], gpr
[6], 0);
267 gpr
[3] = errno_mips(errno
);
270 gpr
[2] = lseek(gpr
[4], gpr
[5], gpr
[6]);
271 gpr
[3] = errno_mips(errno
);
274 GET_TARGET_STRING(p
, gpr
[4]);
276 gpr
[3] = errno_mips(errno
);
277 FREE_TARGET_STRING(p
, gpr
[4]);
282 memset(&sbuf
, 0, sizeof(sbuf
));
283 gpr
[2] = fstat(gpr
[4], &sbuf
);
284 gpr
[3] = errno_mips(errno
);
288 gpr
[2] = copy_stat_to_target(env
, &sbuf
, gpr
[5]);
289 gpr
[3] = errno_mips(errno
);
293 gpr
[2] = semihosting_get_argc();
296 if (gpr
[4] >= semihosting_get_argc()) {
300 gpr
[2] = strlen(semihosting_get_arg(gpr
[4]));
303 if (gpr
[4] >= semihosting_get_argc()) {
307 gpr
[2] = copy_argn_to_target(env
, gpr
[4], gpr
[5]);
310 GET_TARGET_STRING(p
, gpr
[4]);
311 p2
= strstr(p
, "%d");
313 int char_num
= p2
- p
;
314 char *buf
= g_malloc(char_num
+ 1);
315 strncpy(buf
, p
, char_num
);
316 buf
[char_num
] = '\0';
317 gpr
[2] = printf("%s%d%s", buf
, (int)gpr
[5], p2
+ 2);
320 gpr
[2] = printf("%s", p
);
322 FREE_TARGET_STRING(p
, gpr
[4]);
325 GET_TARGET_STRING(p
, gpr
[4]);
326 GET_TARGET_STRING(p2
, gpr
[5]);
327 printf("assertion '");
329 printf("': file \"%s\", line %d\n", p2
, (int)gpr
[6]);
330 FREE_TARGET_STRING(p2
, gpr
[5]);
331 FREE_TARGET_STRING(p
, gpr
[4]);
335 gpr
[2] = read_from_file(env
, gpr
[4], gpr
[5], gpr
[6], gpr
[7]);
336 gpr
[3] = errno_mips(errno
);
339 gpr
[2] = write_to_file(env
, gpr
[4], gpr
[5], gpr
[6], gpr
[7]);
340 gpr
[3] = errno_mips(errno
);
344 GET_TARGET_STRING(p
, gpr
[4]);
345 GET_TARGET_STRING(p2
, gpr
[5]);
346 gpr
[2] = link(p
, p2
);
347 gpr
[3] = errno_mips(errno
);
348 FREE_TARGET_STRING(p2
, gpr
[5]);
349 FREE_TARGET_STRING(p
, gpr
[4]);
353 fprintf(stderr
, "Unknown UHI operation %d\n", op
);