]> git.proxmox.com Git - mirror_qemu.git/blame - target-mips/mips-semi.c
qcow2: Inform block layer about discard boundaries
[mirror_qemu.git] / target-mips / mips-semi.c
CommitLineData
3b3c1694
LA
1/*
2 * Unified Hosting Interface syscalls.
3 *
4 * Copyright (c) 2015 Imagination Technologies
5 *
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.
10 *
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.
15 *
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/>.
18 */
19
c684822a 20#include "qemu/osdep.h"
3b3c1694 21#include "cpu.h"
63c91552 22#include "qemu/log.h"
3b3c1694
LA
23#include "exec/helper-proto.h"
24#include "exec/softmmu-semi.h"
25#include "exec/semihost.h"
26
27typedef enum UHIOp {
28 UHI_exit = 1,
29 UHI_open = 2,
30 UHI_close = 3,
31 UHI_read = 4,
32 UHI_write = 5,
33 UHI_lseek = 6,
34 UHI_unlink = 7,
35 UHI_fstat = 8,
36 UHI_argc = 9,
37 UHI_argnlen = 10,
38 UHI_argn = 11,
39 UHI_plog = 13,
40 UHI_assert = 14,
41 UHI_pread = 19,
42 UHI_pwrite = 20,
43 UHI_link = 22
44} UHIOp;
45
46typedef struct UHIStat {
47 int16_t uhi_st_dev;
48 uint16_t uhi_st_ino;
49 uint32_t uhi_st_mode;
50 uint16_t uhi_st_nlink;
51 uint16_t uhi_st_uid;
52 uint16_t uhi_st_gid;
53 int16_t uhi_st_rdev;
54 uint64_t uhi_st_size;
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];
64} UHIStat;
65
66enum UHIOpenFlags {
67 UHIOpen_RDONLY = 0x0,
68 UHIOpen_WRONLY = 0x1,
69 UHIOpen_RDWR = 0x2,
70 UHIOpen_APPEND = 0x8,
71 UHIOpen_CREAT = 0x200,
72 UHIOpen_TRUNC = 0x400,
73 UHIOpen_EXCL = 0x800
74};
75
2c44b19c
LA
76/* Errno values taken from asm-mips/errno.h */
77static uint16_t host_to_mips_errno[] = {
78 [ENAMETOOLONG] = 78,
79#ifdef EOVERFLOW
80 [EOVERFLOW] = 79,
81#endif
82#ifdef ELOOP
83 [ELOOP] = 90,
84#endif
85};
86
87static int errno_mips(int err)
88{
89 if (err < 0 || err >= ARRAY_SIZE(host_to_mips_errno)) {
90 return EINVAL;
91 } else if (host_to_mips_errno[err]) {
92 return host_to_mips_errno[err];
93 } else {
94 return err;
95 }
96}
97
3b3c1694
LA
98static int copy_stat_to_target(CPUMIPSState *env, const struct stat *src,
99 target_ulong vaddr)
100{
101 hwaddr len = sizeof(struct UHIStat);
102 UHIStat *dst = lock_user(VERIFY_WRITE, vaddr, len, 0);
103 if (!dst) {
104 errno = EFAULT;
105 return -1;
106 }
107
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);
119#ifdef _WIN32
120 dst->uhi_st_blksize = 0;
121 dst->uhi_st_blocks = 0;
122#else
123 dst->uhi_st_blksize = tswap64(src->st_blksize);
124 dst->uhi_st_blocks = tswap64(src->st_blocks);
125#endif
126 unlock_user(dst, vaddr, len);
127 return 0;
128}
129
130static int get_open_flags(target_ulong target_flags)
131{
132 int open_flags = 0;
133
134 if (target_flags & UHIOpen_RDWR) {
135 open_flags |= O_RDWR;
136 } else if (target_flags & UHIOpen_WRONLY) {
137 open_flags |= O_WRONLY;
138 } else {
139 open_flags |= O_RDONLY;
140 }
141
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;
146
147 return open_flags;
148}
149
150static int write_to_file(CPUMIPSState *env, target_ulong fd, target_ulong vaddr,
151 target_ulong len, target_ulong offset)
152{
153 int num_of_bytes;
154 void *dst = lock_user(VERIFY_READ, vaddr, len, 1);
155 if (!dst) {
156 errno = EFAULT;
157 return -1;
158 }
159
160 if (offset) {
161#ifdef _WIN32
162 num_of_bytes = 0;
163#else
164 num_of_bytes = pwrite(fd, dst, len, offset);
165#endif
166 } else {
167 num_of_bytes = write(fd, dst, len);
168 }
169
170 unlock_user(dst, vaddr, 0);
171 return num_of_bytes;
172}
173
174static int read_from_file(CPUMIPSState *env, target_ulong fd,
175 target_ulong vaddr, target_ulong len,
176 target_ulong offset)
177{
178 int num_of_bytes;
179 void *dst = lock_user(VERIFY_WRITE, vaddr, len, 0);
180 if (!dst) {
181 errno = EFAULT;
182 return -1;
183 }
184
185 if (offset) {
186#ifdef _WIN32
187 num_of_bytes = 0;
188#else
189 num_of_bytes = pread(fd, dst, len, offset);
190#endif
191 } else {
192 num_of_bytes = read(fd, dst, len);
193 }
194
195 unlock_user(dst, vaddr, len);
196 return num_of_bytes;
197}
198
199static int copy_argn_to_target(CPUMIPSState *env, int arg_num,
200 target_ulong vaddr)
201{
202 int strsize = strlen(semihosting_get_arg(arg_num)) + 1;
203 char *dst = lock_user(VERIFY_WRITE, vaddr, strsize, 0);
204 if (!dst) {
205 return -1;
206 }
207
208 strcpy(dst, semihosting_get_arg(arg_num));
209
210 unlock_user(dst, vaddr, strsize);
211 return 0;
212}
213
214#define GET_TARGET_STRING(p, addr) \
215 do { \
216 p = lock_user_string(addr); \
217 if (!p) { \
218 gpr[2] = -1; \
219 gpr[3] = EFAULT; \
220 goto uhi_done; \
221 } \
222 } while (0)
223
26e7e982
LA
224#define GET_TARGET_STRINGS_2(p, addr, p2, addr2) \
225 do { \
226 p = lock_user_string(addr); \
227 if (!p) { \
228 gpr[2] = -1; \
229 gpr[3] = EFAULT; \
230 goto uhi_done; \
231 } \
232 p2 = lock_user_string(addr2); \
233 if (!p2) { \
234 unlock_user(p, addr, 0); \
235 gpr[2] = -1; \
236 gpr[3] = EFAULT; \
237 goto uhi_done; \
238 } \
239 } while (0)
240
3b3c1694
LA
241#define FREE_TARGET_STRING(p, gpr) \
242 do { \
243 unlock_user(p, gpr, 0); \
244 } while (0)
245
246void helper_do_semihosting(CPUMIPSState *env)
247{
248 target_ulong *gpr = env->active_tc.gpr;
249 const UHIOp op = gpr[25];
250 char *p, *p2;
251
252 switch (op) {
253 case UHI_exit:
254 qemu_log("UHI(%d): exit(%d)\n", op, (int)gpr[4]);
255 exit(gpr[4]);
256 case UHI_open:
257 GET_TARGET_STRING(p, gpr[4]);
258 if (!strcmp("/dev/stdin", p)) {
259 gpr[2] = 0;
260 } else if (!strcmp("/dev/stdout", p)) {
261 gpr[2] = 1;
262 } else if (!strcmp("/dev/stderr", p)) {
263 gpr[2] = 2;
264 } else {
265 gpr[2] = open(p, get_open_flags(gpr[5]), gpr[6]);
2c44b19c 266 gpr[3] = errno_mips(errno);
3b3c1694
LA
267 }
268 FREE_TARGET_STRING(p, gpr[4]);
269 break;
270 case UHI_close:
271 if (gpr[4] < 3) {
272 /* ignore closing stdin/stdout/stderr */
273 gpr[2] = 0;
274 goto uhi_done;
275 }
276 gpr[2] = close(gpr[4]);
2c44b19c 277 gpr[3] = errno_mips(errno);
3b3c1694
LA
278 break;
279 case UHI_read:
280 gpr[2] = read_from_file(env, gpr[4], gpr[5], gpr[6], 0);
2c44b19c 281 gpr[3] = errno_mips(errno);
3b3c1694
LA
282 break;
283 case UHI_write:
284 gpr[2] = write_to_file(env, gpr[4], gpr[5], gpr[6], 0);
2c44b19c 285 gpr[3] = errno_mips(errno);
3b3c1694
LA
286 break;
287 case UHI_lseek:
288 gpr[2] = lseek(gpr[4], gpr[5], gpr[6]);
2c44b19c 289 gpr[3] = errno_mips(errno);
3b3c1694
LA
290 break;
291 case UHI_unlink:
292 GET_TARGET_STRING(p, gpr[4]);
293 gpr[2] = remove(p);
2c44b19c 294 gpr[3] = errno_mips(errno);
3b3c1694
LA
295 FREE_TARGET_STRING(p, gpr[4]);
296 break;
297 case UHI_fstat:
298 {
299 struct stat sbuf;
300 memset(&sbuf, 0, sizeof(sbuf));
301 gpr[2] = fstat(gpr[4], &sbuf);
2c44b19c 302 gpr[3] = errno_mips(errno);
3b3c1694
LA
303 if (gpr[2]) {
304 goto uhi_done;
305 }
306 gpr[2] = copy_stat_to_target(env, &sbuf, gpr[5]);
2c44b19c 307 gpr[3] = errno_mips(errno);
3b3c1694
LA
308 }
309 break;
310 case UHI_argc:
311 gpr[2] = semihosting_get_argc();
312 break;
313 case UHI_argnlen:
314 if (gpr[4] >= semihosting_get_argc()) {
315 gpr[2] = -1;
316 goto uhi_done;
317 }
318 gpr[2] = strlen(semihosting_get_arg(gpr[4]));
319 break;
320 case UHI_argn:
321 if (gpr[4] >= semihosting_get_argc()) {
322 gpr[2] = -1;
323 goto uhi_done;
324 }
325 gpr[2] = copy_argn_to_target(env, gpr[4], gpr[5]);
326 break;
327 case UHI_plog:
328 GET_TARGET_STRING(p, gpr[4]);
329 p2 = strstr(p, "%d");
330 if (p2) {
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);
336 g_free(buf);
337 } else {
338 gpr[2] = printf("%s", p);
339 }
340 FREE_TARGET_STRING(p, gpr[4]);
341 break;
342 case UHI_assert:
26e7e982 343 GET_TARGET_STRINGS_2(p, gpr[4], p2, gpr[5]);
3b3c1694
LA
344 printf("assertion '");
345 printf("\"%s\"", p);
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]);
349 abort();
350 break;
351 case UHI_pread:
352 gpr[2] = read_from_file(env, gpr[4], gpr[5], gpr[6], gpr[7]);
2c44b19c 353 gpr[3] = errno_mips(errno);
3b3c1694
LA
354 break;
355 case UHI_pwrite:
356 gpr[2] = write_to_file(env, gpr[4], gpr[5], gpr[6], gpr[7]);
2c44b19c 357 gpr[3] = errno_mips(errno);
3b3c1694
LA
358 break;
359#ifndef _WIN32
360 case UHI_link:
26e7e982 361 GET_TARGET_STRINGS_2(p, gpr[4], p2, gpr[5]);
3b3c1694 362 gpr[2] = link(p, p2);
2c44b19c 363 gpr[3] = errno_mips(errno);
3b3c1694
LA
364 FREE_TARGET_STRING(p2, gpr[5]);
365 FREE_TARGET_STRING(p, gpr[4]);
366 break;
367#endif
368 default:
369 fprintf(stderr, "Unknown UHI operation %d\n", op);
370 abort();
371 }
372uhi_done:
373 return;
374}