cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

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
     36enum {
     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
     51enum {
     52    SELECT_ONE_READ   = 1,
     53    SELECT_ONE_WRITE  = 2,
     54    SELECT_ONE_EXCEPT = 3,
     55};
     56
     57enum {
     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
     96static 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
    147typedef struct XtensaSimConsole {
    148    CharBackend be;
    149    struct {
    150        char buffer[16];
    151        size_t offset;
    152    } input;
    153} XtensaSimConsole;
    154
    155static XtensaSimConsole *sim_console;
    156
    157static IOCanReadHandler sim_console_can_read;
    158static int sim_console_can_read(void *opaque)
    159{
    160    XtensaSimConsole *p = opaque;
    161
    162    return sizeof(p->input.buffer) - p->input.offset;
    163}
    164
    165static IOReadHandler sim_console_read;
    166static 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
    178void 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
    191void 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}