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"
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);