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

char-win-stdio.c (8007B)


      1/*
      2 * QEMU System Emulator
      3 *
      4 * Copyright (c) 2003-2008 Fabrice Bellard
      5 *
      6 * Permission is hereby granted, free of charge, to any person obtaining a copy
      7 * of this software and associated documentation files (the "Software"), to deal
      8 * in the Software without restriction, including without limitation the rights
      9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     10 * copies of the Software, and to permit persons to whom the Software is
     11 * furnished to do so, subject to the following conditions:
     12 *
     13 * The above copyright notice and this permission notice shall be included in
     14 * all copies or substantial portions of the Software.
     15 *
     16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     22 * THE SOFTWARE.
     23 */
     24
     25#include "qemu/osdep.h"
     26#include "qapi/error.h"
     27#include "qemu/main-loop.h"
     28#include "qemu/module.h"
     29#include "chardev/char-win.h"
     30#include "chardev/char-win-stdio.h"
     31#include "qom/object.h"
     32
     33struct WinStdioChardev {
     34    Chardev parent;
     35    HANDLE  hStdIn;
     36    HANDLE  hInputReadyEvent;
     37    HANDLE  hInputDoneEvent;
     38    HANDLE  hInputThread;
     39    uint8_t win_stdio_buf;
     40};
     41typedef struct WinStdioChardev WinStdioChardev;
     42
     43DECLARE_INSTANCE_CHECKER(WinStdioChardev, WIN_STDIO_CHARDEV,
     44                         TYPE_CHARDEV_WIN_STDIO)
     45
     46static void win_stdio_wait_func(void *opaque)
     47{
     48    Chardev *chr = CHARDEV(opaque);
     49    WinStdioChardev *stdio = WIN_STDIO_CHARDEV(opaque);
     50    INPUT_RECORD       buf[4];
     51    int                ret;
     52    DWORD              dwSize;
     53    int                i;
     54
     55    ret = ReadConsoleInput(stdio->hStdIn, buf, ARRAY_SIZE(buf), &dwSize);
     56
     57    if (!ret) {
     58        /* Avoid error storm */
     59        qemu_del_wait_object(stdio->hStdIn, NULL, NULL);
     60        return;
     61    }
     62
     63    for (i = 0; i < dwSize; i++) {
     64        KEY_EVENT_RECORD *kev = &buf[i].Event.KeyEvent;
     65
     66        if (buf[i].EventType == KEY_EVENT && kev->bKeyDown) {
     67            int j;
     68            if (kev->uChar.AsciiChar != 0) {
     69                for (j = 0; j < kev->wRepeatCount; j++) {
     70                    if (qemu_chr_be_can_write(chr)) {
     71                        uint8_t c = kev->uChar.AsciiChar;
     72                        qemu_chr_be_write(chr, &c, 1);
     73                    }
     74                }
     75            }
     76        }
     77    }
     78}
     79
     80static DWORD WINAPI win_stdio_thread(LPVOID param)
     81{
     82    WinStdioChardev *stdio = WIN_STDIO_CHARDEV(param);
     83    int                ret;
     84    DWORD              dwSize;
     85
     86    while (1) {
     87
     88        /* Wait for one byte */
     89        ret = ReadFile(stdio->hStdIn, &stdio->win_stdio_buf, 1, &dwSize, NULL);
     90
     91        /* Exit in case of error, continue if nothing read */
     92        if (!ret) {
     93            break;
     94        }
     95        if (!dwSize) {
     96            continue;
     97        }
     98
     99        /* Some terminal emulator returns \r\n for Enter, just pass \n */
    100        if (stdio->win_stdio_buf == '\r') {
    101            continue;
    102        }
    103
    104        /* Signal the main thread and wait until the byte was eaten */
    105        if (!SetEvent(stdio->hInputReadyEvent)) {
    106            break;
    107        }
    108        if (WaitForSingleObject(stdio->hInputDoneEvent, INFINITE)
    109            != WAIT_OBJECT_0) {
    110            break;
    111        }
    112    }
    113
    114    qemu_del_wait_object(stdio->hInputReadyEvent, NULL, NULL);
    115    return 0;
    116}
    117
    118static void win_stdio_thread_wait_func(void *opaque)
    119{
    120    Chardev *chr = CHARDEV(opaque);
    121    WinStdioChardev *stdio = WIN_STDIO_CHARDEV(opaque);
    122
    123    if (qemu_chr_be_can_write(chr)) {
    124        qemu_chr_be_write(chr, &stdio->win_stdio_buf, 1);
    125    }
    126
    127    SetEvent(stdio->hInputDoneEvent);
    128}
    129
    130static void qemu_chr_set_echo_win_stdio(Chardev *chr, bool echo)
    131{
    132    WinStdioChardev *stdio = WIN_STDIO_CHARDEV(chr);
    133    DWORD              dwMode = 0;
    134
    135    GetConsoleMode(stdio->hStdIn, &dwMode);
    136
    137    if (echo) {
    138        SetConsoleMode(stdio->hStdIn, dwMode | ENABLE_ECHO_INPUT);
    139    } else {
    140        SetConsoleMode(stdio->hStdIn, dwMode & ~ENABLE_ECHO_INPUT);
    141    }
    142}
    143
    144static void qemu_chr_open_stdio(Chardev *chr,
    145                                ChardevBackend *backend,
    146                                bool *be_opened,
    147                                Error **errp)
    148{
    149    WinStdioChardev *stdio = WIN_STDIO_CHARDEV(chr);
    150    DWORD              dwMode;
    151    int                is_console = 0;
    152
    153    stdio->hStdIn = GetStdHandle(STD_INPUT_HANDLE);
    154    if (stdio->hStdIn == INVALID_HANDLE_VALUE) {
    155        error_setg(errp, "cannot open stdio: invalid handle");
    156        return;
    157    }
    158
    159    is_console = GetConsoleMode(stdio->hStdIn, &dwMode) != 0;
    160
    161    if (is_console) {
    162        if (qemu_add_wait_object(stdio->hStdIn,
    163                                 win_stdio_wait_func, chr)) {
    164            error_setg(errp, "qemu_add_wait_object: failed");
    165            goto err1;
    166        }
    167    } else {
    168        DWORD   dwId;
    169
    170        stdio->hInputReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    171        stdio->hInputDoneEvent  = CreateEvent(NULL, FALSE, FALSE, NULL);
    172        if (stdio->hInputReadyEvent == INVALID_HANDLE_VALUE
    173            || stdio->hInputDoneEvent == INVALID_HANDLE_VALUE) {
    174            error_setg(errp, "cannot create event");
    175            goto err2;
    176        }
    177        if (qemu_add_wait_object(stdio->hInputReadyEvent,
    178                                 win_stdio_thread_wait_func, chr)) {
    179            error_setg(errp, "qemu_add_wait_object: failed");
    180            goto err2;
    181        }
    182        stdio->hInputThread     = CreateThread(NULL, 0, win_stdio_thread,
    183                                               chr, 0, &dwId);
    184
    185        if (stdio->hInputThread == INVALID_HANDLE_VALUE) {
    186            error_setg(errp, "cannot create stdio thread");
    187            goto err3;
    188        }
    189    }
    190
    191    dwMode |= ENABLE_LINE_INPUT;
    192
    193    if (is_console) {
    194        /* set the terminal in raw mode */
    195        /* ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS */
    196        dwMode |= ENABLE_PROCESSED_INPUT;
    197    }
    198
    199    SetConsoleMode(stdio->hStdIn, dwMode);
    200
    201    qemu_chr_set_echo_win_stdio(chr, false);
    202
    203    return;
    204
    205err3:
    206    qemu_del_wait_object(stdio->hInputReadyEvent, NULL, NULL);
    207err2:
    208    CloseHandle(stdio->hInputReadyEvent);
    209    CloseHandle(stdio->hInputDoneEvent);
    210err1:
    211    qemu_del_wait_object(stdio->hStdIn, NULL, NULL);
    212}
    213
    214static void char_win_stdio_finalize(Object *obj)
    215{
    216    WinStdioChardev *stdio = WIN_STDIO_CHARDEV(obj);
    217
    218    if (stdio->hInputReadyEvent != INVALID_HANDLE_VALUE) {
    219        CloseHandle(stdio->hInputReadyEvent);
    220    }
    221    if (stdio->hInputDoneEvent != INVALID_HANDLE_VALUE) {
    222        CloseHandle(stdio->hInputDoneEvent);
    223    }
    224    if (stdio->hInputThread != INVALID_HANDLE_VALUE) {
    225        TerminateThread(stdio->hInputThread, 0);
    226    }
    227}
    228
    229static int win_stdio_write(Chardev *chr, const uint8_t *buf, int len)
    230{
    231    HANDLE  hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
    232    DWORD   dwSize;
    233    int     len1;
    234
    235    len1 = len;
    236
    237    while (len1 > 0) {
    238        if (!WriteFile(hStdOut, buf, len1, &dwSize, NULL)) {
    239            break;
    240        }
    241        buf  += dwSize;
    242        len1 -= dwSize;
    243    }
    244
    245    return len - len1;
    246}
    247
    248static void char_win_stdio_class_init(ObjectClass *oc, void *data)
    249{
    250    ChardevClass *cc = CHARDEV_CLASS(oc);
    251
    252    cc->open = qemu_chr_open_stdio;
    253    cc->chr_write = win_stdio_write;
    254    cc->chr_set_echo = qemu_chr_set_echo_win_stdio;
    255}
    256
    257static const TypeInfo char_win_stdio_type_info = {
    258    .name = TYPE_CHARDEV_WIN_STDIO,
    259    .parent = TYPE_CHARDEV,
    260    .instance_size = sizeof(WinStdioChardev),
    261    .instance_finalize = char_win_stdio_finalize,
    262    .class_init = char_win_stdio_class_init,
    263    .abstract = true,
    264};
    265
    266static void register_types(void)
    267{
    268    type_register_static(&char_win_stdio_type_info);
    269}
    270
    271type_init(register_types);