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

mips-semi.c (10725B)


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