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

sgx.c (4498B)


      1/*
      2 * SGX common code
      3 *
      4 * Copyright (C) 2021 Intel Corporation
      5 *
      6 * Authors:
      7 *   Yang Zhong<yang.zhong@intel.com>
      8 *   Sean Christopherson <sean.j.christopherson@intel.com>
      9 *
     10 * This work is licensed under the terms of the GNU GPL, version 2 or later.
     11 * See the COPYING file in the top-level directory.
     12 */
     13#include "qemu/osdep.h"
     14#include "hw/i386/pc.h"
     15#include "hw/i386/sgx-epc.h"
     16#include "hw/mem/memory-device.h"
     17#include "monitor/qdev.h"
     18#include "qapi/error.h"
     19#include "exec/address-spaces.h"
     20#include "hw/i386/sgx.h"
     21#include "sysemu/hw_accel.h"
     22
     23#define SGX_MAX_EPC_SECTIONS            8
     24#define SGX_CPUID_EPC_INVALID           0x0
     25
     26/* A valid EPC section. */
     27#define SGX_CPUID_EPC_SECTION           0x1
     28#define SGX_CPUID_EPC_MASK              0xF
     29
     30static uint64_t sgx_calc_section_metric(uint64_t low, uint64_t high)
     31{
     32    return (low & MAKE_64BIT_MASK(12, 20)) +
     33           ((high & MAKE_64BIT_MASK(0, 20)) << 32);
     34}
     35
     36static uint64_t sgx_calc_host_epc_section_size(void)
     37{
     38    uint32_t i, type;
     39    uint32_t eax, ebx, ecx, edx;
     40    uint64_t size = 0;
     41
     42    for (i = 0; i < SGX_MAX_EPC_SECTIONS; i++) {
     43        host_cpuid(0x12, i + 2, &eax, &ebx, &ecx, &edx);
     44
     45        type = eax & SGX_CPUID_EPC_MASK;
     46        if (type == SGX_CPUID_EPC_INVALID) {
     47            break;
     48        }
     49
     50        if (type != SGX_CPUID_EPC_SECTION) {
     51            break;
     52        }
     53
     54        size += sgx_calc_section_metric(ecx, edx);
     55    }
     56
     57    return size;
     58}
     59
     60SGXInfo *sgx_get_capabilities(Error **errp)
     61{
     62    SGXInfo *info = NULL;
     63    uint32_t eax, ebx, ecx, edx;
     64
     65    int fd = qemu_open_old("/dev/sgx_vepc", O_RDWR);
     66    if (fd < 0) {
     67        error_setg(errp, "SGX is not enabled in KVM");
     68        return NULL;
     69    }
     70
     71    info = g_new0(SGXInfo, 1);
     72    host_cpuid(0x7, 0, &eax, &ebx, &ecx, &edx);
     73
     74    info->sgx = ebx & (1U << 2) ? true : false;
     75    info->flc = ecx & (1U << 30) ? true : false;
     76
     77    host_cpuid(0x12, 0, &eax, &ebx, &ecx, &edx);
     78    info->sgx1 = eax & (1U << 0) ? true : false;
     79    info->sgx2 = eax & (1U << 1) ? true : false;
     80
     81    info->section_size = sgx_calc_host_epc_section_size();
     82
     83    close(fd);
     84
     85    return info;
     86}
     87
     88SGXInfo *sgx_get_info(Error **errp)
     89{
     90    SGXInfo *info = NULL;
     91    X86MachineState *x86ms;
     92    PCMachineState *pcms =
     93        (PCMachineState *)object_dynamic_cast(qdev_get_machine(),
     94                                              TYPE_PC_MACHINE);
     95    if (!pcms) {
     96        error_setg(errp, "SGX is only supported on PC machines");
     97        return NULL;
     98    }
     99
    100    x86ms = X86_MACHINE(pcms);
    101    if (!x86ms->sgx_epc_list) {
    102        error_setg(errp, "No EPC regions defined, SGX not available");
    103        return NULL;
    104    }
    105
    106    SGXEPCState *sgx_epc = &pcms->sgx_epc;
    107    info = g_new0(SGXInfo, 1);
    108
    109    info->sgx = true;
    110    info->sgx1 = true;
    111    info->sgx2 = true;
    112    info->flc = true;
    113    info->section_size = sgx_epc->size;
    114
    115    return info;
    116}
    117
    118int sgx_epc_get_section(int section_nr, uint64_t *addr, uint64_t *size)
    119{
    120    PCMachineState *pcms = PC_MACHINE(qdev_get_machine());
    121    SGXEPCDevice *epc;
    122
    123    if (pcms->sgx_epc.size == 0 || pcms->sgx_epc.nr_sections <= section_nr) {
    124        return 1;
    125    }
    126
    127    epc = pcms->sgx_epc.sections[section_nr];
    128
    129    *addr = epc->addr;
    130    *size = memory_device_get_region_size(MEMORY_DEVICE(epc), &error_fatal);
    131
    132    return 0;
    133}
    134
    135void pc_machine_init_sgx_epc(PCMachineState *pcms)
    136{
    137    SGXEPCState *sgx_epc = &pcms->sgx_epc;
    138    X86MachineState *x86ms = X86_MACHINE(pcms);
    139    SgxEPCList *list = NULL;
    140    Object *obj;
    141
    142    memset(sgx_epc, 0, sizeof(SGXEPCState));
    143    if (!x86ms->sgx_epc_list) {
    144        return;
    145    }
    146
    147    sgx_epc->base = 0x100000000ULL + x86ms->above_4g_mem_size;
    148
    149    memory_region_init(&sgx_epc->mr, OBJECT(pcms), "sgx-epc", UINT64_MAX);
    150    memory_region_add_subregion(get_system_memory(), sgx_epc->base,
    151                                &sgx_epc->mr);
    152
    153    for (list = x86ms->sgx_epc_list; list; list = list->next) {
    154        obj = object_new("sgx-epc");
    155
    156        /* set the memdev link with memory backend */
    157        object_property_parse(obj, SGX_EPC_MEMDEV_PROP, list->value->memdev,
    158                              &error_fatal);
    159        object_property_set_bool(obj, "realized", true, &error_fatal);
    160        object_unref(obj);
    161    }
    162
    163    if ((sgx_epc->base + sgx_epc->size) < sgx_epc->base) {
    164        error_report("Size of all 'sgx-epc' =0x%"PRIu64" causes EPC to wrap",
    165                     sgx_epc->size);
    166        exit(EXIT_FAILURE);
    167    }
    168
    169    memory_region_set_size(&sgx_epc->mr, sgx_epc->size);
    170}