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/>.
20 #include "qemu/osdep.h"
23 #include "exec/helper-proto.h"
24 #include "exec/softmmu-semi.h"
25 #include "exec/semihost.h"
46 typedef struct UHIStat
{
50 uint16_t uhi_st_nlink
;
55 uint64_t uhi_st_atime
;
56 uint64_t uhi_st_spare1
;
57 uint64_t uhi_st_mtime
;
58 uint64_t uhi_st_spare2
;
59 uint64_t uhi_st_ctime
;
60 uint64_t uhi_st_spare3
;
61 uint64_t uhi_st_blksize
;
62 uint64_t uhi_st_blocks
;
63 uint64_t uhi_st_spare4
[2];
71 UHIOpen_CREAT
= 0x200,
72 UHIOpen_TRUNC
= 0x400,
76 /* Errno values taken from asm-mips/errno.h */
77 static uint16_t host_to_mips_errno
[] = {
87 static int errno_mips(int err
)
89 if (err
< 0 || err
>= ARRAY_SIZE(host_to_mips_errno
)) {
91 } else if (host_to_mips_errno
[err
]) {
92 return host_to_mips_errno
[err
];
98 static int copy_stat_to_target(CPUMIPSState
*env
, const struct stat
*src
,
101 hwaddr len
= sizeof(struct UHIStat
);
102 UHIStat
*dst
= lock_user(VERIFY_WRITE
, vaddr
, len
, 0);
108 dst
->uhi_st_dev
= tswap16(src
->st_dev
);
109 dst
->uhi_st_ino
= tswap16(src
->st_ino
);
110 dst
->uhi_st_mode
= tswap32(src
->st_mode
);
111 dst
->uhi_st_nlink
= tswap16(src
->st_nlink
);
112 dst
->uhi_st_uid
= tswap16(src
->st_uid
);
113 dst
->uhi_st_gid
= tswap16(src
->st_gid
);
114 dst
->uhi_st_rdev
= tswap16(src
->st_rdev
);
115 dst
->uhi_st_size
= tswap64(src
->st_size
);
116 dst
->uhi_st_atime
= tswap64(src
->st_atime
);
117 dst
->uhi_st_mtime
= tswap64(src
->st_mtime
);
118 dst
->uhi_st_ctime
= tswap64(src
->st_ctime
);
120 dst
->uhi_st_blksize
= 0;
121 dst
->uhi_st_blocks
= 0;
123 dst
->uhi_st_blksize
= tswap64(src
->st_blksize
);
124 dst
->uhi_st_blocks
= tswap64(src
->st_blocks
);
126 unlock_user(dst
, vaddr
, len
);
130 static int get_open_flags(target_ulong target_flags
)
134 if (target_flags
& UHIOpen_RDWR
) {
135 open_flags
|= O_RDWR
;
136 } else if (target_flags
& UHIOpen_WRONLY
) {
137 open_flags
|= O_WRONLY
;
139 open_flags
|= O_RDONLY
;
142 open_flags
|= (target_flags
& UHIOpen_APPEND
) ? O_APPEND
: 0;
143 open_flags
|= (target_flags
& UHIOpen_CREAT
) ? O_CREAT
: 0;
144 open_flags
|= (target_flags
& UHIOpen_TRUNC
) ? O_TRUNC
: 0;
145 open_flags
|= (target_flags
& UHIOpen_EXCL
) ? O_EXCL
: 0;
150 static int write_to_file(CPUMIPSState
*env
, target_ulong fd
, target_ulong vaddr
,
151 target_ulong len
, target_ulong offset
)
154 void *dst
= lock_user(VERIFY_READ
, vaddr
, len
, 1);
164 num_of_bytes
= pwrite(fd
, dst
, len
, offset
);
167 num_of_bytes
= write(fd
, dst
, len
);
170 unlock_user(dst
, vaddr
, 0);
174 static int read_from_file(CPUMIPSState
*env
, target_ulong fd
,
175 target_ulong vaddr
, target_ulong len
,
179 void *dst
= lock_user(VERIFY_WRITE
, vaddr
, len
, 0);
189 num_of_bytes
= pread(fd
, dst
, len
, offset
);
192 num_of_bytes
= read(fd
, dst
, len
);
195 unlock_user(dst
, vaddr
, len
);
199 static int copy_argn_to_target(CPUMIPSState
*env
, int arg_num
,
202 int strsize
= strlen(semihosting_get_arg(arg_num
)) + 1;
203 char *dst
= lock_user(VERIFY_WRITE
, vaddr
, strsize
, 0);
208 strcpy(dst
, semihosting_get_arg(arg_num
));
210 unlock_user(dst
, vaddr
, strsize
);
214 #define GET_TARGET_STRING(p, addr) \
216 p = lock_user_string(addr); \
224 #define GET_TARGET_STRINGS_2(p, addr, p2, addr2) \
226 p = lock_user_string(addr); \
232 p2 = lock_user_string(addr2); \
234 unlock_user(p, addr, 0); \
241 #define FREE_TARGET_STRING(p, gpr) \
243 unlock_user(p, gpr, 0); \
246 void helper_do_semihosting(CPUMIPSState
*env
)
248 target_ulong
*gpr
= env
->active_tc
.gpr
;
249 const UHIOp op
= gpr
[25];
254 qemu_log("UHI(%d): exit(%d)\n", op
, (int)gpr
[4]);
257 GET_TARGET_STRING(p
, gpr
[4]);
258 if (!strcmp("/dev/stdin", p
)) {
260 } else if (!strcmp("/dev/stdout", p
)) {
262 } else if (!strcmp("/dev/stderr", p
)) {
265 gpr
[2] = open(p
, get_open_flags(gpr
[5]), gpr
[6]);
266 gpr
[3] = errno_mips(errno
);
268 FREE_TARGET_STRING(p
, gpr
[4]);
272 /* ignore closing stdin/stdout/stderr */
276 gpr
[2] = close(gpr
[4]);
277 gpr
[3] = errno_mips(errno
);
280 gpr
[2] = read_from_file(env
, gpr
[4], gpr
[5], gpr
[6], 0);
281 gpr
[3] = errno_mips(errno
);
284 gpr
[2] = write_to_file(env
, gpr
[4], gpr
[5], gpr
[6], 0);
285 gpr
[3] = errno_mips(errno
);
288 gpr
[2] = lseek(gpr
[4], gpr
[5], gpr
[6]);
289 gpr
[3] = errno_mips(errno
);
292 GET_TARGET_STRING(p
, gpr
[4]);
294 gpr
[3] = errno_mips(errno
);
295 FREE_TARGET_STRING(p
, gpr
[4]);
300 memset(&sbuf
, 0, sizeof(sbuf
));
301 gpr
[2] = fstat(gpr
[4], &sbuf
);
302 gpr
[3] = errno_mips(errno
);
306 gpr
[2] = copy_stat_to_target(env
, &sbuf
, gpr
[5]);
307 gpr
[3] = errno_mips(errno
);
311 gpr
[2] = semihosting_get_argc();
314 if (gpr
[4] >= semihosting_get_argc()) {
318 gpr
[2] = strlen(semihosting_get_arg(gpr
[4]));
321 if (gpr
[4] >= semihosting_get_argc()) {
325 gpr
[2] = copy_argn_to_target(env
, gpr
[4], gpr
[5]);
328 GET_TARGET_STRING(p
, gpr
[4]);
329 p2
= strstr(p
, "%d");
331 int char_num
= p2
- p
;
332 char *buf
= g_malloc(char_num
+ 1);
333 strncpy(buf
, p
, char_num
);
334 buf
[char_num
] = '\0';
335 gpr
[2] = printf("%s%d%s", buf
, (int)gpr
[5], p2
+ 2);
338 gpr
[2] = printf("%s", 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
);