xref: /openbmc/qemu/target/xtensa/xtensa-semi.c (revision 86108e23d798bcd3fce35ad271b198f8a8611746)
1fcf5ef2aSThomas Huth /*
2fcf5ef2aSThomas Huth  * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
3fcf5ef2aSThomas Huth  * All rights reserved.
4fcf5ef2aSThomas Huth  *
5fcf5ef2aSThomas Huth  * Redistribution and use in source and binary forms, with or without
6fcf5ef2aSThomas Huth  * modification, are permitted provided that the following conditions are met:
7fcf5ef2aSThomas Huth  *     * Redistributions of source code must retain the above copyright
8fcf5ef2aSThomas Huth  *       notice, this list of conditions and the following disclaimer.
9fcf5ef2aSThomas Huth  *     * Redistributions in binary form must reproduce the above copyright
10fcf5ef2aSThomas Huth  *       notice, this list of conditions and the following disclaimer in the
11fcf5ef2aSThomas Huth  *       documentation and/or other materials provided with the distribution.
12fcf5ef2aSThomas Huth  *     * Neither the name of the Open Source and Linux Lab nor the
13fcf5ef2aSThomas Huth  *       names of its contributors may be used to endorse or promote products
14fcf5ef2aSThomas Huth  *       derived from this software without specific prior written permission.
15fcf5ef2aSThomas Huth  *
16fcf5ef2aSThomas Huth  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17fcf5ef2aSThomas Huth  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18fcf5ef2aSThomas Huth  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19fcf5ef2aSThomas Huth  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20fcf5ef2aSThomas Huth  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21fcf5ef2aSThomas Huth  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22fcf5ef2aSThomas Huth  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23fcf5ef2aSThomas Huth  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24fcf5ef2aSThomas Huth  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25fcf5ef2aSThomas Huth  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26fcf5ef2aSThomas Huth  */
27fcf5ef2aSThomas Huth 
28fcf5ef2aSThomas Huth #include "qemu/osdep.h"
29fcf5ef2aSThomas Huth #include "cpu.h"
308128b3e0SMax Filippov #include "chardev/char-fe.h"
31fcf5ef2aSThomas Huth #include "exec/helper-proto.h"
326b5fe137SPhilippe Mathieu-Daudé #include "semihosting/semihost.h"
338128b3e0SMax Filippov #include "qapi/error.h"
34fcf5ef2aSThomas Huth #include "qemu/log.h"
358128b3e0SMax Filippov 
36fcf5ef2aSThomas Huth enum {
37fcf5ef2aSThomas Huth     TARGET_SYS_exit = 1,
38fcf5ef2aSThomas Huth     TARGET_SYS_read = 3,
39fcf5ef2aSThomas Huth     TARGET_SYS_write = 4,
40fcf5ef2aSThomas Huth     TARGET_SYS_open = 5,
41fcf5ef2aSThomas Huth     TARGET_SYS_close = 6,
42fcf5ef2aSThomas Huth     TARGET_SYS_lseek = 19,
43fcf5ef2aSThomas Huth     TARGET_SYS_select_one = 29,
44fcf5ef2aSThomas Huth 
45fcf5ef2aSThomas Huth     TARGET_SYS_argc = 1000,
46fcf5ef2aSThomas Huth     TARGET_SYS_argv_sz = 1001,
47fcf5ef2aSThomas Huth     TARGET_SYS_argv = 1002,
48fcf5ef2aSThomas Huth     TARGET_SYS_memset = 1004,
49fcf5ef2aSThomas Huth };
50fcf5ef2aSThomas Huth 
51fcf5ef2aSThomas Huth enum {
52fcf5ef2aSThomas Huth     SELECT_ONE_READ   = 1,
53fcf5ef2aSThomas Huth     SELECT_ONE_WRITE  = 2,
54fcf5ef2aSThomas Huth     SELECT_ONE_EXCEPT = 3,
55fcf5ef2aSThomas Huth };
56fcf5ef2aSThomas Huth 
57fcf5ef2aSThomas Huth enum {
58fcf5ef2aSThomas Huth     TARGET_EPERM        =  1,
59fcf5ef2aSThomas Huth     TARGET_ENOENT       =  2,
60fcf5ef2aSThomas Huth     TARGET_ESRCH        =  3,
61fcf5ef2aSThomas Huth     TARGET_EINTR        =  4,
62fcf5ef2aSThomas Huth     TARGET_EIO          =  5,
63fcf5ef2aSThomas Huth     TARGET_ENXIO        =  6,
64fcf5ef2aSThomas Huth     TARGET_E2BIG        =  7,
65fcf5ef2aSThomas Huth     TARGET_ENOEXEC      =  8,
66fcf5ef2aSThomas Huth     TARGET_EBADF        =  9,
67fcf5ef2aSThomas Huth     TARGET_ECHILD       = 10,
68fcf5ef2aSThomas Huth     TARGET_EAGAIN       = 11,
69fcf5ef2aSThomas Huth     TARGET_ENOMEM       = 12,
70fcf5ef2aSThomas Huth     TARGET_EACCES       = 13,
71fcf5ef2aSThomas Huth     TARGET_EFAULT       = 14,
72fcf5ef2aSThomas Huth     TARGET_ENOTBLK      = 15,
73fcf5ef2aSThomas Huth     TARGET_EBUSY        = 16,
74fcf5ef2aSThomas Huth     TARGET_EEXIST       = 17,
75fcf5ef2aSThomas Huth     TARGET_EXDEV        = 18,
76fcf5ef2aSThomas Huth     TARGET_ENODEV       = 19,
77fcf5ef2aSThomas Huth     TARGET_ENOTDIR      = 20,
78fcf5ef2aSThomas Huth     TARGET_EISDIR       = 21,
79fcf5ef2aSThomas Huth     TARGET_EINVAL       = 22,
80fcf5ef2aSThomas Huth     TARGET_ENFILE       = 23,
81fcf5ef2aSThomas Huth     TARGET_EMFILE       = 24,
82fcf5ef2aSThomas Huth     TARGET_ENOTTY       = 25,
83fcf5ef2aSThomas Huth     TARGET_ETXTBSY      = 26,
84fcf5ef2aSThomas Huth     TARGET_EFBIG        = 27,
85fcf5ef2aSThomas Huth     TARGET_ENOSPC       = 28,
86fcf5ef2aSThomas Huth     TARGET_ESPIPE       = 29,
87fcf5ef2aSThomas Huth     TARGET_EROFS        = 30,
88fcf5ef2aSThomas Huth     TARGET_EMLINK       = 31,
89fcf5ef2aSThomas Huth     TARGET_EPIPE        = 32,
90fcf5ef2aSThomas Huth     TARGET_EDOM         = 33,
91fcf5ef2aSThomas Huth     TARGET_ERANGE       = 34,
92fcf5ef2aSThomas Huth     TARGET_ENOSYS       = 88,
93fcf5ef2aSThomas Huth     TARGET_ELOOP        = 92,
94fcf5ef2aSThomas Huth };
95fcf5ef2aSThomas Huth 
errno_h2g(int host_errno)96fcf5ef2aSThomas Huth static uint32_t errno_h2g(int host_errno)
97fcf5ef2aSThomas Huth {
98*3b51b506SThomas Huth     switch (host_errno) {
99*3b51b506SThomas Huth     case 0:         return 0;
100*3b51b506SThomas Huth     case EPERM:     return TARGET_EPERM;
101*3b51b506SThomas Huth     case ENOENT:    return TARGET_ENOENT;
102*3b51b506SThomas Huth     case ESRCH:     return TARGET_ESRCH;
103*3b51b506SThomas Huth     case EINTR:     return TARGET_EINTR;
104*3b51b506SThomas Huth     case EIO:       return TARGET_EIO;
105*3b51b506SThomas Huth     case ENXIO:     return TARGET_ENXIO;
106*3b51b506SThomas Huth     case E2BIG:     return TARGET_E2BIG;
107*3b51b506SThomas Huth     case ENOEXEC:   return TARGET_ENOEXEC;
108*3b51b506SThomas Huth     case EBADF:     return TARGET_EBADF;
109*3b51b506SThomas Huth     case ECHILD:    return TARGET_ECHILD;
110*3b51b506SThomas Huth     case EAGAIN:    return TARGET_EAGAIN;
111*3b51b506SThomas Huth     case ENOMEM:    return TARGET_ENOMEM;
112*3b51b506SThomas Huth     case EACCES:    return TARGET_EACCES;
113*3b51b506SThomas Huth     case EFAULT:    return TARGET_EFAULT;
114fcf5ef2aSThomas Huth #ifdef ENOTBLK
115*3b51b506SThomas Huth     case ENOTBLK:   return TARGET_ENOTBLK;
116fcf5ef2aSThomas Huth #endif
117*3b51b506SThomas Huth     case EBUSY:     return TARGET_EBUSY;
118*3b51b506SThomas Huth     case EEXIST:    return TARGET_EEXIST;
119*3b51b506SThomas Huth     case EXDEV:     return TARGET_EXDEV;
120*3b51b506SThomas Huth     case ENODEV:    return TARGET_ENODEV;
121*3b51b506SThomas Huth     case ENOTDIR:   return TARGET_ENOTDIR;
122*3b51b506SThomas Huth     case EISDIR:    return TARGET_EISDIR;
123*3b51b506SThomas Huth     case EINVAL:    return TARGET_EINVAL;
124*3b51b506SThomas Huth     case ENFILE:    return TARGET_ENFILE;
125*3b51b506SThomas Huth     case EMFILE:    return TARGET_EMFILE;
126*3b51b506SThomas Huth     case ENOTTY:    return TARGET_ENOTTY;
127fcf5ef2aSThomas Huth #ifdef ETXTBSY
128*3b51b506SThomas Huth     case ETXTBSY:   return TARGET_ETXTBSY;
129fcf5ef2aSThomas Huth #endif
130*3b51b506SThomas Huth     case EFBIG:     return TARGET_EFBIG;
131*3b51b506SThomas Huth     case ENOSPC:    return TARGET_ENOSPC;
132*3b51b506SThomas Huth     case ESPIPE:    return TARGET_ESPIPE;
133*3b51b506SThomas Huth     case EROFS:     return TARGET_EROFS;
134*3b51b506SThomas Huth     case EMLINK:    return TARGET_EMLINK;
135*3b51b506SThomas Huth     case EPIPE:     return TARGET_EPIPE;
136*3b51b506SThomas Huth     case EDOM:      return TARGET_EDOM;
137*3b51b506SThomas Huth     case ERANGE:    return TARGET_ERANGE;
138*3b51b506SThomas Huth     case ENOSYS:    return TARGET_ENOSYS;
139fcf5ef2aSThomas Huth #ifdef ELOOP
140*3b51b506SThomas Huth     case ELOOP:     return TARGET_ELOOP;
141fcf5ef2aSThomas Huth #endif
142fcf5ef2aSThomas Huth     };
143fcf5ef2aSThomas Huth 
144fcf5ef2aSThomas Huth     return TARGET_EINVAL;
145fcf5ef2aSThomas Huth }
146fcf5ef2aSThomas Huth 
1475aa37f48SMax Filippov typedef struct XtensaSimConsole {
1485aa37f48SMax Filippov     CharBackend be;
1495aa37f48SMax Filippov     struct {
1505aa37f48SMax Filippov         char buffer[16];
1515aa37f48SMax Filippov         size_t offset;
1525aa37f48SMax Filippov     } input;
1535aa37f48SMax Filippov } XtensaSimConsole;
1545aa37f48SMax Filippov 
1555aa37f48SMax Filippov static XtensaSimConsole *sim_console;
1565aa37f48SMax Filippov 
1575aa37f48SMax Filippov static IOCanReadHandler sim_console_can_read;
sim_console_can_read(void * opaque)1585aa37f48SMax Filippov static int sim_console_can_read(void *opaque)
1595aa37f48SMax Filippov {
1605aa37f48SMax Filippov     XtensaSimConsole *p = opaque;
1615aa37f48SMax Filippov 
1625aa37f48SMax Filippov     return sizeof(p->input.buffer) - p->input.offset;
1635aa37f48SMax Filippov }
1645aa37f48SMax Filippov 
1655aa37f48SMax Filippov static IOReadHandler sim_console_read;
sim_console_read(void * opaque,const uint8_t * buf,int size)1665aa37f48SMax Filippov static void sim_console_read(void *opaque, const uint8_t *buf, int size)
1675aa37f48SMax Filippov {
1685aa37f48SMax Filippov     XtensaSimConsole *p = opaque;
1695aa37f48SMax Filippov     size_t copy = sizeof(p->input.buffer) - p->input.offset;
1705aa37f48SMax Filippov 
1715aa37f48SMax Filippov     if (size < copy) {
1725aa37f48SMax Filippov         copy = size;
1735aa37f48SMax Filippov     }
1745aa37f48SMax Filippov     memcpy(p->input.buffer + p->input.offset, buf, copy);
1755aa37f48SMax Filippov     p->input.offset += copy;
1765aa37f48SMax Filippov }
1775aa37f48SMax Filippov 
xtensa_sim_open_console(Chardev * chr)1788128b3e0SMax Filippov void xtensa_sim_open_console(Chardev *chr)
1798128b3e0SMax Filippov {
1805aa37f48SMax Filippov     static XtensaSimConsole console;
1818128b3e0SMax Filippov 
1825aa37f48SMax Filippov     qemu_chr_fe_init(&console.be, chr, &error_abort);
1835aa37f48SMax Filippov     qemu_chr_fe_set_handlers(&console.be,
1845aa37f48SMax Filippov                              sim_console_can_read,
1855aa37f48SMax Filippov                              sim_console_read,
1865aa37f48SMax Filippov                              NULL, NULL, &console,
1875aa37f48SMax Filippov                              NULL, true);
1885aa37f48SMax Filippov     sim_console = &console;
1898128b3e0SMax Filippov }
1908128b3e0SMax Filippov 
HELPER(simcall)191fcf5ef2aSThomas Huth void HELPER(simcall)(CPUXtensaState *env)
192fcf5ef2aSThomas Huth {
19392fddfbdSRichard Henderson     CPUState *cs = env_cpu(env);
194fcf5ef2aSThomas Huth     uint32_t *regs = env->regs;
195fcf5ef2aSThomas Huth 
196fcf5ef2aSThomas Huth     switch (regs[2]) {
197fcf5ef2aSThomas Huth     case TARGET_SYS_exit:
198fcf5ef2aSThomas Huth         exit(regs[3]);
199fcf5ef2aSThomas Huth         break;
200fcf5ef2aSThomas Huth 
201fcf5ef2aSThomas Huth     case TARGET_SYS_read:
202fcf5ef2aSThomas Huth     case TARGET_SYS_write:
203fcf5ef2aSThomas Huth         {
204fcf5ef2aSThomas Huth             bool is_write = regs[2] == TARGET_SYS_write;
205fcf5ef2aSThomas Huth             uint32_t fd = regs[3];
206fcf5ef2aSThomas Huth             uint32_t vaddr = regs[4];
207fcf5ef2aSThomas Huth             uint32_t len = regs[5];
208347ec030SMax Filippov             uint32_t len_done = 0;
209fcf5ef2aSThomas Huth 
210fcf5ef2aSThomas Huth             while (len > 0) {
211fcf5ef2aSThomas Huth                 hwaddr paddr = cpu_get_phys_page_debug(cs, vaddr);
212fcf5ef2aSThomas Huth                 uint32_t page_left =
213fcf5ef2aSThomas Huth                     TARGET_PAGE_SIZE - (vaddr & (TARGET_PAGE_SIZE - 1));
214fcf5ef2aSThomas Huth                 uint32_t io_sz = page_left < len ? page_left : len;
215fcf5ef2aSThomas Huth                 hwaddr sz = io_sz;
21630c2afd1SMax Filippov                 void *buf = cpu_physical_memory_map(paddr, &sz, !is_write);
217347ec030SMax Filippov                 uint32_t io_done;
218347ec030SMax Filippov                 bool error = false;
219fcf5ef2aSThomas Huth 
220fcf5ef2aSThomas Huth                 if (buf) {
221fcf5ef2aSThomas Huth                     vaddr += io_sz;
222fcf5ef2aSThomas Huth                     len -= io_sz;
2235aa37f48SMax Filippov                     if (fd < 3 && sim_console) {
2248128b3e0SMax Filippov                         if (is_write && (fd == 1 || fd == 2)) {
2255aa37f48SMax Filippov                             io_done = qemu_chr_fe_write_all(&sim_console->be,
2268128b3e0SMax Filippov                                                             buf, io_sz);
2278128b3e0SMax Filippov                             regs[3] = errno_h2g(errno);
2285aa37f48SMax Filippov                         } else if (!is_write && fd == 0) {
2295aa37f48SMax Filippov                             if (sim_console->input.offset) {
2305aa37f48SMax Filippov                                 io_done = sim_console->input.offset;
2315aa37f48SMax Filippov                                 if (io_sz < io_done) {
2325aa37f48SMax Filippov                                     io_done = io_sz;
2335aa37f48SMax Filippov                                 }
2345aa37f48SMax Filippov                                 memcpy(buf, sim_console->input.buffer, io_done);
2355aa37f48SMax Filippov                                 memmove(sim_console->input.buffer,
2365aa37f48SMax Filippov                                         sim_console->input.buffer + io_done,
2375aa37f48SMax Filippov                                         sim_console->input.offset - io_done);
2385aa37f48SMax Filippov                                 sim_console->input.offset -= io_done;
2395aa37f48SMax Filippov                                 qemu_chr_fe_accept_input(&sim_console->be);
2405aa37f48SMax Filippov                             } else {
2415aa37f48SMax Filippov                                 io_done = -1;
2425aa37f48SMax Filippov                                 regs[3] = TARGET_EAGAIN;
2435aa37f48SMax Filippov                             }
2448128b3e0SMax Filippov                         } else {
2458128b3e0SMax Filippov                             qemu_log_mask(LOG_GUEST_ERROR,
2468128b3e0SMax Filippov                                           "%s fd %d is not supported with chardev console\n",
2478128b3e0SMax Filippov                                           is_write ?
2488128b3e0SMax Filippov                                           "writing to" : "reading from", fd);
2498128b3e0SMax Filippov                             io_done = -1;
2508128b3e0SMax Filippov                             regs[3] = TARGET_EBADF;
2518128b3e0SMax Filippov                         }
2528128b3e0SMax Filippov                     } else {
253347ec030SMax Filippov                         io_done = is_write ?
254fcf5ef2aSThomas Huth                             write(fd, buf, io_sz) :
255fcf5ef2aSThomas Huth                             read(fd, buf, io_sz);
256fcf5ef2aSThomas Huth                         regs[3] = errno_h2g(errno);
2578128b3e0SMax Filippov                     }
258347ec030SMax Filippov                     if (io_done == -1) {
259347ec030SMax Filippov                         error = true;
260347ec030SMax Filippov                         io_done = 0;
261fcf5ef2aSThomas Huth                     }
262347ec030SMax Filippov                     cpu_physical_memory_unmap(buf, sz, !is_write, io_done);
263fcf5ef2aSThomas Huth                 } else {
264347ec030SMax Filippov                     error = true;
265fcf5ef2aSThomas Huth                     regs[3] = TARGET_EINVAL;
266fcf5ef2aSThomas Huth                     break;
267fcf5ef2aSThomas Huth                 }
268347ec030SMax Filippov                 if (error) {
269347ec030SMax Filippov                     if (!len_done) {
270347ec030SMax Filippov                         len_done = -1;
271fcf5ef2aSThomas Huth                     }
272347ec030SMax Filippov                     break;
273347ec030SMax Filippov                 }
274347ec030SMax Filippov                 len_done += io_done;
275347ec030SMax Filippov                 if (io_done < io_sz) {
276347ec030SMax Filippov                     break;
277347ec030SMax Filippov                 }
278347ec030SMax Filippov             }
279347ec030SMax Filippov             regs[2] = len_done;
280fcf5ef2aSThomas Huth         }
281fcf5ef2aSThomas Huth         break;
282fcf5ef2aSThomas Huth 
283fcf5ef2aSThomas Huth     case TARGET_SYS_open:
284fcf5ef2aSThomas Huth         {
285fcf5ef2aSThomas Huth             char name[1024];
286fcf5ef2aSThomas Huth             int rc;
287fcf5ef2aSThomas Huth             int i;
288fcf5ef2aSThomas Huth 
289fcf5ef2aSThomas Huth             for (i = 0; i < ARRAY_SIZE(name); ++i) {
290fcf5ef2aSThomas Huth                 rc = cpu_memory_rw_debug(cs, regs[3] + i,
291fcf5ef2aSThomas Huth                                          (uint8_t *)name + i, 1, 0);
292fcf5ef2aSThomas Huth                 if (rc != 0 || name[i] == 0) {
293fcf5ef2aSThomas Huth                     break;
294fcf5ef2aSThomas Huth                 }
295fcf5ef2aSThomas Huth             }
296fcf5ef2aSThomas Huth 
297fcf5ef2aSThomas Huth             if (rc == 0 && i < ARRAY_SIZE(name)) {
298fcf5ef2aSThomas Huth                 regs[2] = open(name, regs[4], regs[5]);
299fcf5ef2aSThomas Huth                 regs[3] = errno_h2g(errno);
300fcf5ef2aSThomas Huth             } else {
301fcf5ef2aSThomas Huth                 regs[2] = -1;
302fcf5ef2aSThomas Huth                 regs[3] = TARGET_EINVAL;
303fcf5ef2aSThomas Huth             }
304fcf5ef2aSThomas Huth         }
305fcf5ef2aSThomas Huth         break;
306fcf5ef2aSThomas Huth 
307fcf5ef2aSThomas Huth     case TARGET_SYS_close:
308fcf5ef2aSThomas Huth         if (regs[3] < 3) {
309fcf5ef2aSThomas Huth             regs[2] = regs[3] = 0;
310fcf5ef2aSThomas Huth         } else {
311fcf5ef2aSThomas Huth             regs[2] = close(regs[3]);
312fcf5ef2aSThomas Huth             regs[3] = errno_h2g(errno);
313fcf5ef2aSThomas Huth         }
314fcf5ef2aSThomas Huth         break;
315fcf5ef2aSThomas Huth 
316fcf5ef2aSThomas Huth     case TARGET_SYS_lseek:
317fcf5ef2aSThomas Huth         regs[2] = lseek(regs[3], (off_t)(int32_t)regs[4], regs[5]);
318fcf5ef2aSThomas Huth         regs[3] = errno_h2g(errno);
319fcf5ef2aSThomas Huth         break;
320fcf5ef2aSThomas Huth 
321fcf5ef2aSThomas Huth     case TARGET_SYS_select_one:
322fcf5ef2aSThomas Huth         {
323fcf5ef2aSThomas Huth             uint32_t fd = regs[3];
324fcf5ef2aSThomas Huth             uint32_t rq = regs[4];
325fcf5ef2aSThomas Huth             uint32_t target_tv = regs[5];
326fcf5ef2aSThomas Huth             uint32_t target_tvv[2];
327fcf5ef2aSThomas Huth 
328fcf5ef2aSThomas Huth             struct timeval tv = {0};
329fcf5ef2aSThomas Huth 
330fcf5ef2aSThomas Huth             if (target_tv) {
331fcf5ef2aSThomas Huth                 cpu_memory_rw_debug(cs, target_tv,
332fcf5ef2aSThomas Huth                         (uint8_t *)target_tvv, sizeof(target_tvv), 0);
333fcf5ef2aSThomas Huth                 tv.tv_sec = (int32_t)tswap32(target_tvv[0]);
334fcf5ef2aSThomas Huth                 tv.tv_usec = (int32_t)tswap32(target_tvv[1]);
335fcf5ef2aSThomas Huth             }
3365aa37f48SMax Filippov             if (fd < 3 && sim_console) {
3378128b3e0SMax Filippov                 if ((fd == 1 || fd == 2) && rq == SELECT_ONE_WRITE) {
3388128b3e0SMax Filippov                     regs[2] = 1;
3395aa37f48SMax Filippov                 } else if (fd == 0 && rq == SELECT_ONE_READ) {
3405aa37f48SMax Filippov                     regs[2] = sim_console->input.offset > 0;
3418128b3e0SMax Filippov                 } else {
3428128b3e0SMax Filippov                     regs[2] = 0;
3438128b3e0SMax Filippov                 }
3448128b3e0SMax Filippov                 regs[3] = 0;
3458128b3e0SMax Filippov             } else {
3468128b3e0SMax Filippov                 fd_set fdset;
3478128b3e0SMax Filippov 
3488128b3e0SMax Filippov                 FD_ZERO(&fdset);
3498128b3e0SMax Filippov                 FD_SET(fd, &fdset);
350fcf5ef2aSThomas Huth                 regs[2] = select(fd + 1,
351fcf5ef2aSThomas Huth                                  rq == SELECT_ONE_READ   ? &fdset : NULL,
352fcf5ef2aSThomas Huth                                  rq == SELECT_ONE_WRITE  ? &fdset : NULL,
353fcf5ef2aSThomas Huth                                  rq == SELECT_ONE_EXCEPT ? &fdset : NULL,
354fcf5ef2aSThomas Huth                                  target_tv ? &tv : NULL);
355fcf5ef2aSThomas Huth                 regs[3] = errno_h2g(errno);
356fcf5ef2aSThomas Huth             }
3578128b3e0SMax Filippov         }
358fcf5ef2aSThomas Huth         break;
359fcf5ef2aSThomas Huth 
360fcf5ef2aSThomas Huth     case TARGET_SYS_argc:
361f289bb09SMax Filippov         regs[2] = semihosting_get_argc();
362fcf5ef2aSThomas Huth         regs[3] = 0;
363fcf5ef2aSThomas Huth         break;
364fcf5ef2aSThomas Huth 
365fcf5ef2aSThomas Huth     case TARGET_SYS_argv_sz:
366f289bb09SMax Filippov         {
367f289bb09SMax Filippov             int argc = semihosting_get_argc();
368f289bb09SMax Filippov             int sz = (argc + 1) * sizeof(uint32_t);
369f289bb09SMax Filippov             int i;
370f289bb09SMax Filippov 
371f289bb09SMax Filippov             for (i = 0; i < argc; ++i) {
372f289bb09SMax Filippov                 sz += 1 + strlen(semihosting_get_arg(i));
373f289bb09SMax Filippov             }
374f289bb09SMax Filippov             regs[2] = sz;
375fcf5ef2aSThomas Huth             regs[3] = 0;
376f289bb09SMax Filippov         }
377fcf5ef2aSThomas Huth         break;
378fcf5ef2aSThomas Huth 
379fcf5ef2aSThomas Huth     case TARGET_SYS_argv:
380fcf5ef2aSThomas Huth         {
381f289bb09SMax Filippov             int argc = semihosting_get_argc();
382f289bb09SMax Filippov             int str_offset = (argc + 1) * sizeof(uint32_t);
383f289bb09SMax Filippov             int i;
384f289bb09SMax Filippov             uint32_t argptr;
385fcf5ef2aSThomas Huth 
386f289bb09SMax Filippov             for (i = 0; i < argc; ++i) {
387f289bb09SMax Filippov                 const char *str = semihosting_get_arg(i);
388f289bb09SMax Filippov                 int str_size = strlen(str) + 1;
389f289bb09SMax Filippov 
390f289bb09SMax Filippov                 argptr = tswap32(regs[3] + str_offset);
391f289bb09SMax Filippov 
392fcf5ef2aSThomas Huth                 cpu_memory_rw_debug(cs,
393f289bb09SMax Filippov                                     regs[3] + i * sizeof(uint32_t),
394f289bb09SMax Filippov                                     (uint8_t *)&argptr, sizeof(argptr), 1);
395f289bb09SMax Filippov                 cpu_memory_rw_debug(cs,
396f289bb09SMax Filippov                                     regs[3] + str_offset,
397f289bb09SMax Filippov                                     (uint8_t *)str, str_size, 1);
398f289bb09SMax Filippov                 str_offset += str_size;
399f289bb09SMax Filippov             }
400f289bb09SMax Filippov             argptr = 0;
401f289bb09SMax Filippov             cpu_memory_rw_debug(cs,
402f289bb09SMax Filippov                                 regs[3] + i * sizeof(uint32_t),
403f289bb09SMax Filippov                                 (uint8_t *)&argptr, sizeof(argptr), 1);
404f289bb09SMax Filippov             regs[3] = 0;
405fcf5ef2aSThomas Huth         }
406fcf5ef2aSThomas Huth         break;
407fcf5ef2aSThomas Huth 
408fcf5ef2aSThomas Huth     case TARGET_SYS_memset:
409fcf5ef2aSThomas Huth         {
410fcf5ef2aSThomas Huth             uint32_t base = regs[3];
411fcf5ef2aSThomas Huth             uint32_t sz = regs[5];
412fcf5ef2aSThomas Huth 
413fcf5ef2aSThomas Huth             while (sz) {
414fcf5ef2aSThomas Huth                 hwaddr len = sz;
415fcf5ef2aSThomas Huth                 void *buf = cpu_physical_memory_map(base, &len, 1);
416fcf5ef2aSThomas Huth 
417fcf5ef2aSThomas Huth                 if (buf && len) {
418fcf5ef2aSThomas Huth                     memset(buf, regs[4], len);
419fcf5ef2aSThomas Huth                     cpu_physical_memory_unmap(buf, len, 1, len);
420fcf5ef2aSThomas Huth                 } else {
421fcf5ef2aSThomas Huth                     len = 1;
422fcf5ef2aSThomas Huth                 }
423fcf5ef2aSThomas Huth                 base += len;
424fcf5ef2aSThomas Huth                 sz -= len;
425fcf5ef2aSThomas Huth             }
426fcf5ef2aSThomas Huth             regs[2] = regs[3];
427fcf5ef2aSThomas Huth             regs[3] = 0;
428fcf5ef2aSThomas Huth         }
429fcf5ef2aSThomas Huth         break;
430fcf5ef2aSThomas Huth 
431fcf5ef2aSThomas Huth     default:
432fcf5ef2aSThomas Huth         qemu_log_mask(LOG_GUEST_ERROR, "%s(%d): not implemented\n", __func__, regs[2]);
433fcf5ef2aSThomas Huth         regs[2] = -1;
434fcf5ef2aSThomas Huth         regs[3] = TARGET_ENOSYS;
435fcf5ef2aSThomas Huth         break;
436fcf5ef2aSThomas Huth     }
437fcf5ef2aSThomas Huth }
438