2 * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the Open Source and Linux Lab nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include "qemu/osdep.h"
30 #include "chardev/char-fe.h"
31 #include "exec/helper-proto.h"
32 #include "semihosting/semihost.h"
33 #include "qapi/error.h"
42 TARGET_SYS_lseek
= 19,
43 TARGET_SYS_select_one
= 29,
45 TARGET_SYS_argc
= 1000,
46 TARGET_SYS_argv_sz
= 1001,
47 TARGET_SYS_argv
= 1002,
48 TARGET_SYS_memset
= 1004,
54 SELECT_ONE_EXCEPT
= 3,
96 static uint32_t errno_h2g(int host_errno
)
100 case EPERM
: return TARGET_EPERM
;
101 case ENOENT
: return TARGET_ENOENT
;
102 case ESRCH
: return TARGET_ESRCH
;
103 case EINTR
: return TARGET_EINTR
;
104 case EIO
: return TARGET_EIO
;
105 case ENXIO
: return TARGET_ENXIO
;
106 case E2BIG
: return TARGET_E2BIG
;
107 case ENOEXEC
: return TARGET_ENOEXEC
;
108 case EBADF
: return TARGET_EBADF
;
109 case ECHILD
: return TARGET_ECHILD
;
110 case EAGAIN
: return TARGET_EAGAIN
;
111 case ENOMEM
: return TARGET_ENOMEM
;
112 case EACCES
: return TARGET_EACCES
;
113 case EFAULT
: return TARGET_EFAULT
;
115 case ENOTBLK
: return TARGET_ENOTBLK
;
117 case EBUSY
: return TARGET_EBUSY
;
118 case EEXIST
: return TARGET_EEXIST
;
119 case EXDEV
: return TARGET_EXDEV
;
120 case ENODEV
: return TARGET_ENODEV
;
121 case ENOTDIR
: return TARGET_ENOTDIR
;
122 case EISDIR
: return TARGET_EISDIR
;
123 case EINVAL
: return TARGET_EINVAL
;
124 case ENFILE
: return TARGET_ENFILE
;
125 case EMFILE
: return TARGET_EMFILE
;
126 case ENOTTY
: return TARGET_ENOTTY
;
128 case ETXTBSY
: return TARGET_ETXTBSY
;
130 case EFBIG
: return TARGET_EFBIG
;
131 case ENOSPC
: return TARGET_ENOSPC
;
132 case ESPIPE
: return TARGET_ESPIPE
;
133 case EROFS
: return TARGET_EROFS
;
134 case EMLINK
: return TARGET_EMLINK
;
135 case EPIPE
: return TARGET_EPIPE
;
136 case EDOM
: return TARGET_EDOM
;
137 case ERANGE
: return TARGET_ERANGE
;
138 case ENOSYS
: return TARGET_ENOSYS
;
140 case ELOOP
: return TARGET_ELOOP
;
144 return TARGET_EINVAL
;
147 typedef struct XtensaSimConsole
{
155 static XtensaSimConsole
*sim_console
;
157 static IOCanReadHandler sim_console_can_read
;
158 static int sim_console_can_read(void *opaque
)
160 XtensaSimConsole
*p
= opaque
;
162 return sizeof(p
->input
.buffer
) - p
->input
.offset
;
165 static IOReadHandler sim_console_read
;
166 static void sim_console_read(void *opaque
, const uint8_t *buf
, int size
)
168 XtensaSimConsole
*p
= opaque
;
169 size_t copy
= sizeof(p
->input
.buffer
) - p
->input
.offset
;
174 memcpy(p
->input
.buffer
+ p
->input
.offset
, buf
, copy
);
175 p
->input
.offset
+= copy
;
178 void xtensa_sim_open_console(Chardev
*chr
)
180 static XtensaSimConsole console
;
182 qemu_chr_fe_init(&console
.be
, chr
, &error_abort
);
183 qemu_chr_fe_set_handlers(&console
.be
,
184 sim_console_can_read
,
186 NULL
, NULL
, &console
,
188 sim_console
= &console
;
191 void HELPER(simcall
)(CPUXtensaState
*env
)
193 CPUState
*cs
= env_cpu(env
);
194 uint32_t *regs
= env
->regs
;
197 case TARGET_SYS_exit
:
201 case TARGET_SYS_read
:
202 case TARGET_SYS_write
:
204 bool is_write
= regs
[2] == TARGET_SYS_write
;
205 uint32_t fd
= regs
[3];
206 uint32_t vaddr
= regs
[4];
207 uint32_t len
= regs
[5];
208 uint32_t len_done
= 0;
211 hwaddr paddr
= cpu_get_phys_page_debug(cs
, vaddr
);
213 TARGET_PAGE_SIZE
- (vaddr
& (TARGET_PAGE_SIZE
- 1));
214 uint32_t io_sz
= page_left
< len
? page_left
: len
;
216 void *buf
= cpu_physical_memory_map(paddr
, &sz
, !is_write
);
223 if (fd
< 3 && sim_console
) {
224 if (is_write
&& (fd
== 1 || fd
== 2)) {
225 io_done
= qemu_chr_fe_write_all(&sim_console
->be
,
227 regs
[3] = errno_h2g(errno
);
228 } else if (!is_write
&& fd
== 0) {
229 if (sim_console
->input
.offset
) {
230 io_done
= sim_console
->input
.offset
;
231 if (io_sz
< io_done
) {
234 memcpy(buf
, sim_console
->input
.buffer
, io_done
);
235 memmove(sim_console
->input
.buffer
,
236 sim_console
->input
.buffer
+ io_done
,
237 sim_console
->input
.offset
- io_done
);
238 sim_console
->input
.offset
-= io_done
;
239 qemu_chr_fe_accept_input(&sim_console
->be
);
242 regs
[3] = TARGET_EAGAIN
;
245 qemu_log_mask(LOG_GUEST_ERROR
,
246 "%s fd %d is not supported with chardev console\n",
248 "writing to" : "reading from", fd
);
250 regs
[3] = TARGET_EBADF
;
254 write(fd
, buf
, io_sz
) :
255 read(fd
, buf
, io_sz
);
256 regs
[3] = errno_h2g(errno
);
262 cpu_physical_memory_unmap(buf
, sz
, !is_write
, io_done
);
265 regs
[3] = TARGET_EINVAL
;
275 if (io_done
< io_sz
) {
283 case TARGET_SYS_open
:
289 for (i
= 0; i
< ARRAY_SIZE(name
); ++i
) {
290 rc
= cpu_memory_rw_debug(cs
, regs
[3] + i
,
291 (uint8_t *)name
+ i
, 1, 0);
292 if (rc
!= 0 || name
[i
] == 0) {
297 if (rc
== 0 && i
< ARRAY_SIZE(name
)) {
298 regs
[2] = open(name
, regs
[4], regs
[5]);
299 regs
[3] = errno_h2g(errno
);
302 regs
[3] = TARGET_EINVAL
;
307 case TARGET_SYS_close
:
309 regs
[2] = regs
[3] = 0;
311 regs
[2] = close(regs
[3]);
312 regs
[3] = errno_h2g(errno
);
316 case TARGET_SYS_lseek
:
317 regs
[2] = lseek(regs
[3], (off_t
)(int32_t)regs
[4], regs
[5]);
318 regs
[3] = errno_h2g(errno
);
321 case TARGET_SYS_select_one
:
323 uint32_t fd
= regs
[3];
324 uint32_t rq
= regs
[4];
325 uint32_t target_tv
= regs
[5];
326 uint32_t target_tvv
[2];
328 struct timeval tv
= {0};
331 cpu_memory_rw_debug(cs
, target_tv
,
332 (uint8_t *)target_tvv
, sizeof(target_tvv
), 0);
333 tv
.tv_sec
= (int32_t)tswap32(target_tvv
[0]);
334 tv
.tv_usec
= (int32_t)tswap32(target_tvv
[1]);
336 if (fd
< 3 && sim_console
) {
337 if ((fd
== 1 || fd
== 2) && rq
== SELECT_ONE_WRITE
) {
339 } else if (fd
== 0 && rq
== SELECT_ONE_READ
) {
340 regs
[2] = sim_console
->input
.offset
> 0;
350 regs
[2] = select(fd
+ 1,
351 rq
== SELECT_ONE_READ
? &fdset
: NULL
,
352 rq
== SELECT_ONE_WRITE
? &fdset
: NULL
,
353 rq
== SELECT_ONE_EXCEPT
? &fdset
: NULL
,
354 target_tv
? &tv
: NULL
);
355 regs
[3] = errno_h2g(errno
);
360 case TARGET_SYS_argc
:
361 regs
[2] = semihosting_get_argc();
365 case TARGET_SYS_argv_sz
:
367 int argc
= semihosting_get_argc();
368 int sz
= (argc
+ 1) * sizeof(uint32_t);
371 for (i
= 0; i
< argc
; ++i
) {
372 sz
+= 1 + strlen(semihosting_get_arg(i
));
379 case TARGET_SYS_argv
:
381 int argc
= semihosting_get_argc();
382 int str_offset
= (argc
+ 1) * sizeof(uint32_t);
386 for (i
= 0; i
< argc
; ++i
) {
387 const char *str
= semihosting_get_arg(i
);
388 int str_size
= strlen(str
) + 1;
390 argptr
= tswap32(regs
[3] + str_offset
);
392 cpu_memory_rw_debug(cs
,
393 regs
[3] + i
* sizeof(uint32_t),
394 (uint8_t *)&argptr
, sizeof(argptr
), 1);
395 cpu_memory_rw_debug(cs
,
396 regs
[3] + str_offset
,
397 (uint8_t *)str
, str_size
, 1);
398 str_offset
+= str_size
;
401 cpu_memory_rw_debug(cs
,
402 regs
[3] + i
* sizeof(uint32_t),
403 (uint8_t *)&argptr
, sizeof(argptr
), 1);
408 case TARGET_SYS_memset
:
410 uint32_t base
= regs
[3];
411 uint32_t sz
= regs
[5];
415 void *buf
= cpu_physical_memory_map(base
, &len
, 1);
418 memset(buf
, regs
[4], len
);
419 cpu_physical_memory_unmap(buf
, len
, 1, len
);
432 qemu_log_mask(LOG_GUEST_ERROR
, "%s(%d): not implemented\n", __func__
, regs
[2]);
434 regs
[3] = TARGET_ENOSYS
;