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

proxy-memory-listener.c (7638B)


      1/*
      2 * Copyright © 2018, 2021 Oracle and/or its affiliates.
      3 *
      4 * This work is licensed under the terms of the GNU GPL, version 2 or later.
      5 * See the COPYING file in the top-level directory.
      6 *
      7 */
      8
      9#include "qemu/osdep.h"
     10#include "qemu-common.h"
     11
     12#include "qemu/compiler.h"
     13#include "qemu/int128.h"
     14#include "qemu/range.h"
     15#include "exec/memory.h"
     16#include "exec/cpu-common.h"
     17#include "exec/ram_addr.h"
     18#include "qapi/error.h"
     19#include "hw/remote/mpqemu-link.h"
     20#include "hw/remote/proxy-memory-listener.h"
     21
     22/*
     23 * TODO: get_fd_from_hostaddr(), proxy_mrs_can_merge() and
     24 * proxy_memory_listener_commit() defined below perform tasks similar to the
     25 * functions defined in vhost-user.c. These functions are good candidates
     26 * for refactoring.
     27 *
     28 */
     29
     30static void proxy_memory_listener_reset(MemoryListener *listener)
     31{
     32    ProxyMemoryListener *proxy_listener = container_of(listener,
     33                                                       ProxyMemoryListener,
     34                                                       listener);
     35    int mrs;
     36
     37    for (mrs = 0; mrs < proxy_listener->n_mr_sections; mrs++) {
     38        memory_region_unref(proxy_listener->mr_sections[mrs].mr);
     39    }
     40
     41    g_free(proxy_listener->mr_sections);
     42    proxy_listener->mr_sections = NULL;
     43    proxy_listener->n_mr_sections = 0;
     44}
     45
     46static int get_fd_from_hostaddr(uint64_t host, ram_addr_t *offset)
     47{
     48    MemoryRegion *mr;
     49    ram_addr_t off;
     50
     51    /**
     52     * Assumes that the host address is a valid address as it's
     53     * coming from the MemoryListener system. In the case host
     54     * address is not valid, the following call would return
     55     * the default subregion of "system_memory" region, and
     56     * not NULL. So it's not possible to check for NULL here.
     57     */
     58    mr = memory_region_from_host((void *)(uintptr_t)host, &off);
     59
     60    if (offset) {
     61        *offset = off;
     62    }
     63
     64    return memory_region_get_fd(mr);
     65}
     66
     67static bool proxy_mrs_can_merge(uint64_t host, uint64_t prev_host, size_t size)
     68{
     69    if (((prev_host + size) != host)) {
     70        return false;
     71    }
     72
     73    if (get_fd_from_hostaddr(host, NULL) !=
     74            get_fd_from_hostaddr(prev_host, NULL)) {
     75        return false;
     76    }
     77
     78    return true;
     79}
     80
     81static bool try_merge(ProxyMemoryListener *proxy_listener,
     82                      MemoryRegionSection *section)
     83{
     84    uint64_t mrs_size, mrs_gpa, mrs_page;
     85    MemoryRegionSection *prev_sec;
     86    bool merged = false;
     87    uintptr_t mrs_host;
     88    RAMBlock *mrs_rb;
     89
     90    if (!proxy_listener->n_mr_sections) {
     91        return false;
     92    }
     93
     94    mrs_rb = section->mr->ram_block;
     95    mrs_page = (uint64_t)qemu_ram_pagesize(mrs_rb);
     96    mrs_size = int128_get64(section->size);
     97    mrs_gpa = section->offset_within_address_space;
     98    mrs_host = (uintptr_t)memory_region_get_ram_ptr(section->mr) +
     99               section->offset_within_region;
    100
    101    if (get_fd_from_hostaddr(mrs_host, NULL) < 0) {
    102        return true;
    103    }
    104
    105    mrs_host = mrs_host & ~(mrs_page - 1);
    106    mrs_gpa = mrs_gpa & ~(mrs_page - 1);
    107    mrs_size = ROUND_UP(mrs_size, mrs_page);
    108
    109    prev_sec = proxy_listener->mr_sections +
    110               (proxy_listener->n_mr_sections - 1);
    111    uint64_t prev_gpa_start = prev_sec->offset_within_address_space;
    112    uint64_t prev_size = int128_get64(prev_sec->size);
    113    uint64_t prev_gpa_end   = range_get_last(prev_gpa_start, prev_size);
    114    uint64_t prev_host_start =
    115        (uintptr_t)memory_region_get_ram_ptr(prev_sec->mr) +
    116        prev_sec->offset_within_region;
    117    uint64_t prev_host_end = range_get_last(prev_host_start, prev_size);
    118
    119    if (mrs_gpa <= (prev_gpa_end + 1)) {
    120        g_assert(mrs_gpa > prev_gpa_start);
    121
    122        if ((section->mr == prev_sec->mr) &&
    123            proxy_mrs_can_merge(mrs_host, prev_host_start,
    124                                (mrs_gpa - prev_gpa_start))) {
    125            uint64_t max_end = MAX(prev_host_end, mrs_host + mrs_size);
    126            merged = true;
    127            prev_sec->offset_within_address_space =
    128                MIN(prev_gpa_start, mrs_gpa);
    129            prev_sec->offset_within_region =
    130                MIN(prev_host_start, mrs_host) -
    131                (uintptr_t)memory_region_get_ram_ptr(prev_sec->mr);
    132            prev_sec->size = int128_make64(max_end - MIN(prev_host_start,
    133                                                         mrs_host));
    134        }
    135    }
    136
    137    return merged;
    138}
    139
    140static void proxy_memory_listener_region_addnop(MemoryListener *listener,
    141                                                MemoryRegionSection *section)
    142{
    143    ProxyMemoryListener *proxy_listener = container_of(listener,
    144                                                       ProxyMemoryListener,
    145                                                       listener);
    146
    147    if (!memory_region_is_ram(section->mr) ||
    148            memory_region_is_rom(section->mr)) {
    149        return;
    150    }
    151
    152    if (try_merge(proxy_listener, section)) {
    153        return;
    154    }
    155
    156    ++proxy_listener->n_mr_sections;
    157    proxy_listener->mr_sections = g_renew(MemoryRegionSection,
    158                                          proxy_listener->mr_sections,
    159                                          proxy_listener->n_mr_sections);
    160    proxy_listener->mr_sections[proxy_listener->n_mr_sections - 1] = *section;
    161    proxy_listener->mr_sections[proxy_listener->n_mr_sections - 1].fv = NULL;
    162    memory_region_ref(section->mr);
    163}
    164
    165static void proxy_memory_listener_commit(MemoryListener *listener)
    166{
    167    ProxyMemoryListener *proxy_listener = container_of(listener,
    168                                                       ProxyMemoryListener,
    169                                                       listener);
    170    MPQemuMsg msg;
    171    MemoryRegionSection *section;
    172    ram_addr_t offset;
    173    uintptr_t host_addr;
    174    int region;
    175    Error *local_err = NULL;
    176
    177    memset(&msg, 0, sizeof(MPQemuMsg));
    178
    179    msg.cmd = MPQEMU_CMD_SYNC_SYSMEM;
    180    msg.num_fds = proxy_listener->n_mr_sections;
    181    msg.size = sizeof(SyncSysmemMsg);
    182    if (msg.num_fds > REMOTE_MAX_FDS) {
    183        error_report("Number of fds is more than %d", REMOTE_MAX_FDS);
    184        return;
    185    }
    186
    187    for (region = 0; region < proxy_listener->n_mr_sections; region++) {
    188        section = &proxy_listener->mr_sections[region];
    189        msg.data.sync_sysmem.gpas[region] =
    190            section->offset_within_address_space;
    191        msg.data.sync_sysmem.sizes[region] = int128_get64(section->size);
    192        host_addr = (uintptr_t)memory_region_get_ram_ptr(section->mr) +
    193                    section->offset_within_region;
    194        msg.fds[region] = get_fd_from_hostaddr(host_addr, &offset);
    195        msg.data.sync_sysmem.offsets[region] = offset;
    196    }
    197    if (!mpqemu_msg_send(&msg, proxy_listener->ioc, &local_err)) {
    198        error_report_err(local_err);
    199    }
    200}
    201
    202void proxy_memory_listener_deconfigure(ProxyMemoryListener *proxy_listener)
    203{
    204    memory_listener_unregister(&proxy_listener->listener);
    205
    206    proxy_memory_listener_reset(&proxy_listener->listener);
    207}
    208
    209void proxy_memory_listener_configure(ProxyMemoryListener *proxy_listener,
    210                                     QIOChannel *ioc)
    211{
    212    proxy_listener->n_mr_sections = 0;
    213    proxy_listener->mr_sections = NULL;
    214
    215    proxy_listener->ioc = ioc;
    216
    217    proxy_listener->listener.begin = proxy_memory_listener_reset;
    218    proxy_listener->listener.commit = proxy_memory_listener_commit;
    219    proxy_listener->listener.region_add = proxy_memory_listener_region_addnop;
    220    proxy_listener->listener.region_nop = proxy_memory_listener_region_addnop;
    221    proxy_listener->listener.priority = 10;
    222    proxy_listener->listener.name = "proxy";
    223
    224    memory_listener_register(&proxy_listener->listener,
    225                             &address_space_memory);
    226}