qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

xtensa-semi.c (14549B)


      1 /*
      2  * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
      3  * All rights reserved.
      4  *
      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.
     15  *
     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.
     26  */
     27 
     28 #include "qemu/osdep.h"
     29 #include "cpu.h"
     30 #include "chardev/char-fe.h"
     31 #include "exec/helper-proto.h"
     32 #include "semihosting/semihost.h"
     33 #include "qapi/error.h"
     34 #include "qemu/log.h"
     35 
     36 enum {
     37     TARGET_SYS_exit = 1,
     38     TARGET_SYS_read = 3,
     39     TARGET_SYS_write = 4,
     40     TARGET_SYS_open = 5,
     41     TARGET_SYS_close = 6,
     42     TARGET_SYS_lseek = 19,
     43     TARGET_SYS_select_one = 29,
     44 
     45     TARGET_SYS_argc = 1000,
     46     TARGET_SYS_argv_sz = 1001,
     47     TARGET_SYS_argv = 1002,
     48     TARGET_SYS_memset = 1004,
     49 };
     50 
     51 enum {
     52     SELECT_ONE_READ   = 1,
     53     SELECT_ONE_WRITE  = 2,
     54     SELECT_ONE_EXCEPT = 3,
     55 };
     56 
     57 enum {
     58     TARGET_EPERM        =  1,
     59     TARGET_ENOENT       =  2,
     60     TARGET_ESRCH        =  3,
     61     TARGET_EINTR        =  4,
     62     TARGET_EIO          =  5,
     63     TARGET_ENXIO        =  6,
     64     TARGET_E2BIG        =  7,
     65     TARGET_ENOEXEC      =  8,
     66     TARGET_EBADF        =  9,
     67     TARGET_ECHILD       = 10,
     68     TARGET_EAGAIN       = 11,
     69     TARGET_ENOMEM       = 12,
     70     TARGET_EACCES       = 13,
     71     TARGET_EFAULT       = 14,
     72     TARGET_ENOTBLK      = 15,
     73     TARGET_EBUSY        = 16,
     74     TARGET_EEXIST       = 17,
     75     TARGET_EXDEV        = 18,
     76     TARGET_ENODEV       = 19,
     77     TARGET_ENOTDIR      = 20,
     78     TARGET_EISDIR       = 21,
     79     TARGET_EINVAL       = 22,
     80     TARGET_ENFILE       = 23,
     81     TARGET_EMFILE       = 24,
     82     TARGET_ENOTTY       = 25,
     83     TARGET_ETXTBSY      = 26,
     84     TARGET_EFBIG        = 27,
     85     TARGET_ENOSPC       = 28,
     86     TARGET_ESPIPE       = 29,
     87     TARGET_EROFS        = 30,
     88     TARGET_EMLINK       = 31,
     89     TARGET_EPIPE        = 32,
     90     TARGET_EDOM         = 33,
     91     TARGET_ERANGE       = 34,
     92     TARGET_ENOSYS       = 88,
     93     TARGET_ELOOP        = 92,
     94 };
     95 
     96 static uint32_t errno_h2g(int host_errno)
     97 {
     98     switch (host_errno) {
     99     case 0:         return 0;
    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;
    114 #ifdef ENOTBLK
    115     case ENOTBLK:   return TARGET_ENOTBLK;
    116 #endif
    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;
    127 #ifdef ETXTBSY
    128     case ETXTBSY:   return TARGET_ETXTBSY;
    129 #endif
    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;
    139 #ifdef ELOOP
    140     case ELOOP:     return TARGET_ELOOP;
    141 #endif
    142     };
    143 
    144     return TARGET_EINVAL;
    145 }
    146 
    147 typedef struct XtensaSimConsole {
    148     CharBackend be;
    149     struct {
    150         char buffer[16];
    151         size_t offset;
    152     } input;
    153 } XtensaSimConsole;
    154 
    155 static XtensaSimConsole *sim_console;
    156 
    157 static IOCanReadHandler sim_console_can_read;
    158 static int sim_console_can_read(void *opaque)
    159 {
    160     XtensaSimConsole *p = opaque;
    161 
    162     return sizeof(p->input.buffer) - p->input.offset;
    163 }
    164 
    165 static IOReadHandler sim_console_read;
    166 static void sim_console_read(void *opaque, const uint8_t *buf, int size)
    167 {
    168     XtensaSimConsole *p = opaque;
    169     size_t copy = sizeof(p->input.buffer) - p->input.offset;
    170 
    171     if (size < copy) {
    172         copy = size;
    173     }
    174     memcpy(p->input.buffer + p->input.offset, buf, copy);
    175     p->input.offset += copy;
    176 }
    177 
    178 void xtensa_sim_open_console(Chardev *chr)
    179 {
    180     static XtensaSimConsole console;
    181 
    182     qemu_chr_fe_init(&console.be, chr, &error_abort);
    183     qemu_chr_fe_set_handlers(&console.be,
    184                              sim_console_can_read,
    185                              sim_console_read,
    186                              NULL, NULL, &console,
    187                              NULL, true);
    188     sim_console = &console;
    189 }
    190 
    191 void HELPER(simcall)(CPUXtensaState *env)
    192 {
    193     CPUState *cs = env_cpu(env);
    194     uint32_t *regs = env->regs;
    195 
    196     switch (regs[2]) {
    197     case TARGET_SYS_exit:
    198         exit(regs[3]);
    199         break;
    200 
    201     case TARGET_SYS_read:
    202     case TARGET_SYS_write:
    203         {
    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;
    209 
    210             while (len > 0) {
    211                 hwaddr paddr = cpu_get_phys_page_debug(cs, vaddr);
    212                 uint32_t page_left =
    213                     TARGET_PAGE_SIZE - (vaddr & (TARGET_PAGE_SIZE - 1));
    214                 uint32_t io_sz = page_left < len ? page_left : len;
    215                 hwaddr sz = io_sz;
    216                 void *buf = cpu_physical_memory_map(paddr, &sz, !is_write);
    217                 uint32_t io_done;
    218                 bool error = false;
    219 
    220                 if (buf) {
    221                     vaddr += io_sz;
    222                     len -= io_sz;
    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,
    226                                                             buf, io_sz);
    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) {
    232                                     io_done = io_sz;
    233                                 }
    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);
    240                             } else {
    241                                 io_done = -1;
    242                                 regs[3] = TARGET_EAGAIN;
    243                             }
    244                         } else {
    245                             qemu_log_mask(LOG_GUEST_ERROR,
    246                                           "%s fd %d is not supported with chardev console\n",
    247                                           is_write ?
    248                                           "writing to" : "reading from", fd);
    249                             io_done = -1;
    250                             regs[3] = TARGET_EBADF;
    251                         }
    252                     } else {
    253                         io_done = is_write ?
    254                             write(fd, buf, io_sz) :
    255                             read(fd, buf, io_sz);
    256                         regs[3] = errno_h2g(errno);
    257                     }
    258                     if (io_done == -1) {
    259                         error = true;
    260                         io_done = 0;
    261                     }
    262                     cpu_physical_memory_unmap(buf, sz, !is_write, io_done);
    263                 } else {
    264                     error = true;
    265                     regs[3] = TARGET_EINVAL;
    266                     break;
    267                 }
    268                 if (error) {
    269                     if (!len_done) {
    270                         len_done = -1;
    271                     }
    272                     break;
    273                 }
    274                 len_done += io_done;
    275                 if (io_done < io_sz) {
    276                     break;
    277                 }
    278             }
    279             regs[2] = len_done;
    280         }
    281         break;
    282 
    283     case TARGET_SYS_open:
    284         {
    285             char name[1024];
    286             int rc;
    287             int i;
    288 
    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) {
    293                     break;
    294                 }
    295             }
    296 
    297             if (rc == 0 && i < ARRAY_SIZE(name)) {
    298                 regs[2] = open(name, regs[4], regs[5]);
    299                 regs[3] = errno_h2g(errno);
    300             } else {
    301                 regs[2] = -1;
    302                 regs[3] = TARGET_EINVAL;
    303             }
    304         }
    305         break;
    306 
    307     case TARGET_SYS_close:
    308         if (regs[3] < 3) {
    309             regs[2] = regs[3] = 0;
    310         } else {
    311             regs[2] = close(regs[3]);
    312             regs[3] = errno_h2g(errno);
    313         }
    314         break;
    315 
    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);
    319         break;
    320 
    321     case TARGET_SYS_select_one:
    322         {
    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];
    327 
    328             struct timeval tv = {0};
    329 
    330             if (target_tv) {
    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]);
    335             }
    336             if (fd < 3 && sim_console) {
    337                 if ((fd == 1 || fd == 2) && rq == SELECT_ONE_WRITE) {
    338                     regs[2] = 1;
    339                 } else if (fd == 0 && rq == SELECT_ONE_READ) {
    340                     regs[2] = sim_console->input.offset > 0;
    341                 } else {
    342                     regs[2] = 0;
    343                 }
    344                 regs[3] = 0;
    345             } else {
    346                 fd_set fdset;
    347 
    348                 FD_ZERO(&fdset);
    349                 FD_SET(fd, &fdset);
    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);
    356             }
    357         }
    358         break;
    359 
    360     case TARGET_SYS_argc:
    361         regs[2] = semihosting_get_argc();
    362         regs[3] = 0;
    363         break;
    364 
    365     case TARGET_SYS_argv_sz:
    366         {
    367             int argc = semihosting_get_argc();
    368             int sz = (argc + 1) * sizeof(uint32_t);
    369             int i;
    370 
    371             for (i = 0; i < argc; ++i) {
    372                 sz += 1 + strlen(semihosting_get_arg(i));
    373             }
    374             regs[2] = sz;
    375             regs[3] = 0;
    376         }
    377         break;
    378 
    379     case TARGET_SYS_argv:
    380         {
    381             int argc = semihosting_get_argc();
    382             int str_offset = (argc + 1) * sizeof(uint32_t);
    383             int i;
    384             uint32_t argptr;
    385 
    386             for (i = 0; i < argc; ++i) {
    387                 const char *str = semihosting_get_arg(i);
    388                 int str_size = strlen(str) + 1;
    389 
    390                 argptr = tswap32(regs[3] + str_offset);
    391 
    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;
    399             }
    400             argptr = 0;
    401             cpu_memory_rw_debug(cs,
    402                                 regs[3] + i * sizeof(uint32_t),
    403                                 (uint8_t *)&argptr, sizeof(argptr), 1);
    404             regs[3] = 0;
    405         }
    406         break;
    407 
    408     case TARGET_SYS_memset:
    409         {
    410             uint32_t base = regs[3];
    411             uint32_t sz = regs[5];
    412 
    413             while (sz) {
    414                 hwaddr len = sz;
    415                 void *buf = cpu_physical_memory_map(base, &len, 1);
    416 
    417                 if (buf && len) {
    418                     memset(buf, regs[4], len);
    419                     cpu_physical_memory_unmap(buf, len, 1, len);
    420                 } else {
    421                     len = 1;
    422                 }
    423                 base += len;
    424                 sz -= len;
    425             }
    426             regs[2] = regs[3];
    427             regs[3] = 0;
    428         }
    429         break;
    430 
    431     default:
    432         qemu_log_mask(LOG_GUEST_ERROR, "%s(%d): not implemented\n", __func__, regs[2]);
    433         regs[2] = -1;
    434         regs[3] = TARGET_ENOSYS;
    435         break;
    436     }
    437 }