cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

hyperv_features.c (14681B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2021, Red Hat, Inc.
      4 *
      5 * Tests for Hyper-V features enablement
      6 */
      7#include <asm/kvm_para.h>
      8#include <linux/kvm_para.h>
      9#include <stdint.h>
     10
     11#include "test_util.h"
     12#include "kvm_util.h"
     13#include "processor.h"
     14#include "hyperv.h"
     15
     16#define VCPU_ID 0
     17#define LINUX_OS_ID ((u64)0x8100 << 48)
     18
     19extern unsigned char rdmsr_start;
     20extern unsigned char rdmsr_end;
     21
     22static u64 do_rdmsr(u32 idx)
     23{
     24	u32 lo, hi;
     25
     26	asm volatile("rdmsr_start: rdmsr;"
     27		     "rdmsr_end:"
     28		     : "=a"(lo), "=c"(hi)
     29		     : "c"(idx));
     30
     31	return (((u64) hi) << 32) | lo;
     32}
     33
     34extern unsigned char wrmsr_start;
     35extern unsigned char wrmsr_end;
     36
     37static void do_wrmsr(u32 idx, u64 val)
     38{
     39	u32 lo, hi;
     40
     41	lo = val;
     42	hi = val >> 32;
     43
     44	asm volatile("wrmsr_start: wrmsr;"
     45		     "wrmsr_end:"
     46		     : : "a"(lo), "c"(idx), "d"(hi));
     47}
     48
     49static int nr_gp;
     50static int nr_ud;
     51
     52static inline u64 hypercall(u64 control, vm_vaddr_t input_address,
     53			    vm_vaddr_t output_address)
     54{
     55	u64 hv_status;
     56
     57	asm volatile("mov %3, %%r8\n"
     58		     "vmcall"
     59		     : "=a" (hv_status),
     60		       "+c" (control), "+d" (input_address)
     61		     :  "r" (output_address)
     62		     : "cc", "memory", "r8", "r9", "r10", "r11");
     63
     64	return hv_status;
     65}
     66
     67static void guest_gp_handler(struct ex_regs *regs)
     68{
     69	unsigned char *rip = (unsigned char *)regs->rip;
     70	bool r, w;
     71
     72	r = rip == &rdmsr_start;
     73	w = rip == &wrmsr_start;
     74	GUEST_ASSERT(r || w);
     75
     76	nr_gp++;
     77
     78	if (r)
     79		regs->rip = (uint64_t)&rdmsr_end;
     80	else
     81		regs->rip = (uint64_t)&wrmsr_end;
     82}
     83
     84static void guest_ud_handler(struct ex_regs *regs)
     85{
     86	nr_ud++;
     87	regs->rip += 3;
     88}
     89
     90struct msr_data {
     91	uint32_t idx;
     92	bool available;
     93	bool write;
     94	u64 write_val;
     95};
     96
     97struct hcall_data {
     98	uint64_t control;
     99	uint64_t expect;
    100	bool ud_expected;
    101};
    102
    103static void guest_msr(struct msr_data *msr)
    104{
    105	int i = 0;
    106
    107	while (msr->idx) {
    108		WRITE_ONCE(nr_gp, 0);
    109		if (!msr->write)
    110			do_rdmsr(msr->idx);
    111		else
    112			do_wrmsr(msr->idx, msr->write_val);
    113
    114		if (msr->available)
    115			GUEST_ASSERT(READ_ONCE(nr_gp) == 0);
    116		else
    117			GUEST_ASSERT(READ_ONCE(nr_gp) == 1);
    118
    119		GUEST_SYNC(i++);
    120	}
    121
    122	GUEST_DONE();
    123}
    124
    125static void guest_hcall(vm_vaddr_t pgs_gpa, struct hcall_data *hcall)
    126{
    127	int i = 0;
    128	u64 res, input, output;
    129
    130	wrmsr(HV_X64_MSR_GUEST_OS_ID, LINUX_OS_ID);
    131	wrmsr(HV_X64_MSR_HYPERCALL, pgs_gpa);
    132
    133	while (hcall->control) {
    134		nr_ud = 0;
    135		if (!(hcall->control & HV_HYPERCALL_FAST_BIT)) {
    136			input = pgs_gpa;
    137			output = pgs_gpa + 4096;
    138		} else {
    139			input = output = 0;
    140		}
    141
    142		res = hypercall(hcall->control, input, output);
    143		if (hcall->ud_expected)
    144			GUEST_ASSERT(nr_ud == 1);
    145		else
    146			GUEST_ASSERT(res == hcall->expect);
    147
    148		GUEST_SYNC(i++);
    149	}
    150
    151	GUEST_DONE();
    152}
    153
    154static void hv_set_cpuid(struct kvm_vm *vm, struct kvm_cpuid2 *cpuid,
    155			 struct kvm_cpuid_entry2 *feat,
    156			 struct kvm_cpuid_entry2 *recomm,
    157			 struct kvm_cpuid_entry2 *dbg)
    158{
    159	TEST_ASSERT(set_cpuid(cpuid, feat),
    160		    "failed to set KVM_CPUID_FEATURES leaf");
    161	TEST_ASSERT(set_cpuid(cpuid, recomm),
    162		    "failed to set HYPERV_CPUID_ENLIGHTMENT_INFO leaf");
    163	TEST_ASSERT(set_cpuid(cpuid, dbg),
    164		    "failed to set HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES leaf");
    165	vcpu_set_cpuid(vm, VCPU_ID, cpuid);
    166}
    167
    168static void guest_test_msrs_access(void)
    169{
    170	struct kvm_run *run;
    171	struct kvm_vm *vm;
    172	struct ucall uc;
    173	int stage = 0, r;
    174	struct kvm_cpuid_entry2 feat = {
    175		.function = HYPERV_CPUID_FEATURES
    176	};
    177	struct kvm_cpuid_entry2 recomm = {
    178		.function = HYPERV_CPUID_ENLIGHTMENT_INFO
    179	};
    180	struct kvm_cpuid_entry2 dbg = {
    181		.function = HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES
    182	};
    183	struct kvm_cpuid2 *best;
    184	vm_vaddr_t msr_gva;
    185	struct kvm_enable_cap cap = {
    186		.cap = KVM_CAP_HYPERV_ENFORCE_CPUID,
    187		.args = {1}
    188	};
    189	struct msr_data *msr;
    190
    191	while (true) {
    192		vm = vm_create_default(VCPU_ID, 0, guest_msr);
    193
    194		msr_gva = vm_vaddr_alloc_page(vm);
    195		memset(addr_gva2hva(vm, msr_gva), 0x0, getpagesize());
    196		msr = addr_gva2hva(vm, msr_gva);
    197
    198		vcpu_args_set(vm, VCPU_ID, 1, msr_gva);
    199		vcpu_enable_cap(vm, VCPU_ID, &cap);
    200
    201		vcpu_set_hv_cpuid(vm, VCPU_ID);
    202
    203		best = kvm_get_supported_hv_cpuid();
    204
    205		vm_init_descriptor_tables(vm);
    206		vcpu_init_descriptor_tables(vm, VCPU_ID);
    207		vm_install_exception_handler(vm, GP_VECTOR, guest_gp_handler);
    208
    209		run = vcpu_state(vm, VCPU_ID);
    210
    211		switch (stage) {
    212		case 0:
    213			/*
    214			 * Only available when Hyper-V identification is set
    215			 */
    216			msr->idx = HV_X64_MSR_GUEST_OS_ID;
    217			msr->write = 0;
    218			msr->available = 0;
    219			break;
    220		case 1:
    221			msr->idx = HV_X64_MSR_HYPERCALL;
    222			msr->write = 0;
    223			msr->available = 0;
    224			break;
    225		case 2:
    226			feat.eax |= HV_MSR_HYPERCALL_AVAILABLE;
    227			/*
    228			 * HV_X64_MSR_GUEST_OS_ID has to be written first to make
    229			 * HV_X64_MSR_HYPERCALL available.
    230			 */
    231			msr->idx = HV_X64_MSR_GUEST_OS_ID;
    232			msr->write = 1;
    233			msr->write_val = LINUX_OS_ID;
    234			msr->available = 1;
    235			break;
    236		case 3:
    237			msr->idx = HV_X64_MSR_GUEST_OS_ID;
    238			msr->write = 0;
    239			msr->available = 1;
    240			break;
    241		case 4:
    242			msr->idx = HV_X64_MSR_HYPERCALL;
    243			msr->write = 0;
    244			msr->available = 1;
    245			break;
    246
    247		case 5:
    248			msr->idx = HV_X64_MSR_VP_RUNTIME;
    249			msr->write = 0;
    250			msr->available = 0;
    251			break;
    252		case 6:
    253			feat.eax |= HV_MSR_VP_RUNTIME_AVAILABLE;
    254			msr->write = 0;
    255			msr->available = 1;
    256			break;
    257		case 7:
    258			/* Read only */
    259			msr->write = 1;
    260			msr->write_val = 1;
    261			msr->available = 0;
    262			break;
    263
    264		case 8:
    265			msr->idx = HV_X64_MSR_TIME_REF_COUNT;
    266			msr->write = 0;
    267			msr->available = 0;
    268			break;
    269		case 9:
    270			feat.eax |= HV_MSR_TIME_REF_COUNT_AVAILABLE;
    271			msr->write = 0;
    272			msr->available = 1;
    273			break;
    274		case 10:
    275			/* Read only */
    276			msr->write = 1;
    277			msr->write_val = 1;
    278			msr->available = 0;
    279			break;
    280
    281		case 11:
    282			msr->idx = HV_X64_MSR_VP_INDEX;
    283			msr->write = 0;
    284			msr->available = 0;
    285			break;
    286		case 12:
    287			feat.eax |= HV_MSR_VP_INDEX_AVAILABLE;
    288			msr->write = 0;
    289			msr->available = 1;
    290			break;
    291		case 13:
    292			/* Read only */
    293			msr->write = 1;
    294			msr->write_val = 1;
    295			msr->available = 0;
    296			break;
    297
    298		case 14:
    299			msr->idx = HV_X64_MSR_RESET;
    300			msr->write = 0;
    301			msr->available = 0;
    302			break;
    303		case 15:
    304			feat.eax |= HV_MSR_RESET_AVAILABLE;
    305			msr->write = 0;
    306			msr->available = 1;
    307			break;
    308		case 16:
    309			msr->write = 1;
    310			msr->write_val = 0;
    311			msr->available = 1;
    312			break;
    313
    314		case 17:
    315			msr->idx = HV_X64_MSR_REFERENCE_TSC;
    316			msr->write = 0;
    317			msr->available = 0;
    318			break;
    319		case 18:
    320			feat.eax |= HV_MSR_REFERENCE_TSC_AVAILABLE;
    321			msr->write = 0;
    322			msr->available = 1;
    323			break;
    324		case 19:
    325			msr->write = 1;
    326			msr->write_val = 0;
    327			msr->available = 1;
    328			break;
    329
    330		case 20:
    331			msr->idx = HV_X64_MSR_EOM;
    332			msr->write = 0;
    333			msr->available = 0;
    334			break;
    335		case 21:
    336			/*
    337			 * Remains unavailable even with KVM_CAP_HYPERV_SYNIC2
    338			 * capability enabled and guest visible CPUID bit unset.
    339			 */
    340			cap.cap = KVM_CAP_HYPERV_SYNIC2;
    341			cap.args[0] = 0;
    342			vcpu_enable_cap(vm, VCPU_ID, &cap);
    343			break;
    344		case 22:
    345			feat.eax |= HV_MSR_SYNIC_AVAILABLE;
    346			msr->write = 0;
    347			msr->available = 1;
    348			break;
    349		case 23:
    350			msr->write = 1;
    351			msr->write_val = 0;
    352			msr->available = 1;
    353			break;
    354
    355		case 24:
    356			msr->idx = HV_X64_MSR_STIMER0_CONFIG;
    357			msr->write = 0;
    358			msr->available = 0;
    359			break;
    360		case 25:
    361			feat.eax |= HV_MSR_SYNTIMER_AVAILABLE;
    362			msr->write = 0;
    363			msr->available = 1;
    364			break;
    365		case 26:
    366			msr->write = 1;
    367			msr->write_val = 0;
    368			msr->available = 1;
    369			break;
    370		case 27:
    371			/* Direct mode test */
    372			msr->write = 1;
    373			msr->write_val = 1 << 12;
    374			msr->available = 0;
    375			break;
    376		case 28:
    377			feat.edx |= HV_STIMER_DIRECT_MODE_AVAILABLE;
    378			msr->available = 1;
    379			break;
    380
    381		case 29:
    382			msr->idx = HV_X64_MSR_EOI;
    383			msr->write = 0;
    384			msr->available = 0;
    385			break;
    386		case 30:
    387			feat.eax |= HV_MSR_APIC_ACCESS_AVAILABLE;
    388			msr->write = 1;
    389			msr->write_val = 1;
    390			msr->available = 1;
    391			break;
    392
    393		case 31:
    394			msr->idx = HV_X64_MSR_TSC_FREQUENCY;
    395			msr->write = 0;
    396			msr->available = 0;
    397			break;
    398		case 32:
    399			feat.eax |= HV_ACCESS_FREQUENCY_MSRS;
    400			msr->write = 0;
    401			msr->available = 1;
    402			break;
    403		case 33:
    404			/* Read only */
    405			msr->write = 1;
    406			msr->write_val = 1;
    407			msr->available = 0;
    408			break;
    409
    410		case 34:
    411			msr->idx = HV_X64_MSR_REENLIGHTENMENT_CONTROL;
    412			msr->write = 0;
    413			msr->available = 0;
    414			break;
    415		case 35:
    416			feat.eax |= HV_ACCESS_REENLIGHTENMENT;
    417			msr->write = 0;
    418			msr->available = 1;
    419			break;
    420		case 36:
    421			msr->write = 1;
    422			msr->write_val = 1;
    423			msr->available = 1;
    424			break;
    425		case 37:
    426			/* Can only write '0' */
    427			msr->idx = HV_X64_MSR_TSC_EMULATION_STATUS;
    428			msr->write = 1;
    429			msr->write_val = 1;
    430			msr->available = 0;
    431			break;
    432
    433		case 38:
    434			msr->idx = HV_X64_MSR_CRASH_P0;
    435			msr->write = 0;
    436			msr->available = 0;
    437			break;
    438		case 39:
    439			feat.edx |= HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE;
    440			msr->write = 0;
    441			msr->available = 1;
    442			break;
    443		case 40:
    444			msr->write = 1;
    445			msr->write_val = 1;
    446			msr->available = 1;
    447			break;
    448
    449		case 41:
    450			msr->idx = HV_X64_MSR_SYNDBG_STATUS;
    451			msr->write = 0;
    452			msr->available = 0;
    453			break;
    454		case 42:
    455			feat.edx |= HV_FEATURE_DEBUG_MSRS_AVAILABLE;
    456			dbg.eax |= HV_X64_SYNDBG_CAP_ALLOW_KERNEL_DEBUGGING;
    457			msr->write = 0;
    458			msr->available = 1;
    459			break;
    460		case 43:
    461			msr->write = 1;
    462			msr->write_val = 0;
    463			msr->available = 1;
    464			break;
    465
    466		case 44:
    467			/* END */
    468			msr->idx = 0;
    469			break;
    470		}
    471
    472		hv_set_cpuid(vm, best, &feat, &recomm, &dbg);
    473
    474		if (msr->idx)
    475			pr_debug("Stage %d: testing msr: 0x%x for %s\n", stage,
    476				 msr->idx, msr->write ? "write" : "read");
    477		else
    478			pr_debug("Stage %d: finish\n", stage);
    479
    480		r = _vcpu_run(vm, VCPU_ID);
    481		TEST_ASSERT(!r, "vcpu_run failed: %d\n", r);
    482		TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
    483			    "unexpected exit reason: %u (%s)",
    484			    run->exit_reason, exit_reason_str(run->exit_reason));
    485
    486		switch (get_ucall(vm, VCPU_ID, &uc)) {
    487		case UCALL_SYNC:
    488			TEST_ASSERT(uc.args[1] == 0,
    489				    "Unexpected stage: %ld (0 expected)\n",
    490				    uc.args[1]);
    491			break;
    492		case UCALL_ABORT:
    493			TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0],
    494				  __FILE__, uc.args[1]);
    495			return;
    496		case UCALL_DONE:
    497			return;
    498		}
    499
    500		stage++;
    501		kvm_vm_free(vm);
    502	}
    503}
    504
    505static void guest_test_hcalls_access(void)
    506{
    507	struct kvm_run *run;
    508	struct kvm_vm *vm;
    509	struct ucall uc;
    510	int stage = 0, r;
    511	struct kvm_cpuid_entry2 feat = {
    512		.function = HYPERV_CPUID_FEATURES,
    513		.eax = HV_MSR_HYPERCALL_AVAILABLE
    514	};
    515	struct kvm_cpuid_entry2 recomm = {
    516		.function = HYPERV_CPUID_ENLIGHTMENT_INFO
    517	};
    518	struct kvm_cpuid_entry2 dbg = {
    519		.function = HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES
    520	};
    521	struct kvm_enable_cap cap = {
    522		.cap = KVM_CAP_HYPERV_ENFORCE_CPUID,
    523		.args = {1}
    524	};
    525	vm_vaddr_t hcall_page, hcall_params;
    526	struct hcall_data *hcall;
    527	struct kvm_cpuid2 *best;
    528
    529	while (true) {
    530		vm = vm_create_default(VCPU_ID, 0, guest_hcall);
    531
    532		vm_init_descriptor_tables(vm);
    533		vcpu_init_descriptor_tables(vm, VCPU_ID);
    534		vm_install_exception_handler(vm, UD_VECTOR, guest_ud_handler);
    535
    536		/* Hypercall input/output */
    537		hcall_page = vm_vaddr_alloc_pages(vm, 2);
    538		hcall = addr_gva2hva(vm, hcall_page);
    539		memset(addr_gva2hva(vm, hcall_page), 0x0, 2 * getpagesize());
    540
    541		hcall_params = vm_vaddr_alloc_page(vm);
    542		memset(addr_gva2hva(vm, hcall_params), 0x0, getpagesize());
    543
    544		vcpu_args_set(vm, VCPU_ID, 2, addr_gva2gpa(vm, hcall_page), hcall_params);
    545		vcpu_enable_cap(vm, VCPU_ID, &cap);
    546
    547		vcpu_set_hv_cpuid(vm, VCPU_ID);
    548
    549		best = kvm_get_supported_hv_cpuid();
    550
    551		run = vcpu_state(vm, VCPU_ID);
    552
    553		switch (stage) {
    554		case 0:
    555			hcall->control = 0xdeadbeef;
    556			hcall->expect = HV_STATUS_INVALID_HYPERCALL_CODE;
    557			break;
    558
    559		case 1:
    560			hcall->control = HVCALL_POST_MESSAGE;
    561			hcall->expect = HV_STATUS_ACCESS_DENIED;
    562			break;
    563		case 2:
    564			feat.ebx |= HV_POST_MESSAGES;
    565			hcall->expect = HV_STATUS_INVALID_HYPERCALL_INPUT;
    566			break;
    567
    568		case 3:
    569			hcall->control = HVCALL_SIGNAL_EVENT;
    570			hcall->expect = HV_STATUS_ACCESS_DENIED;
    571			break;
    572		case 4:
    573			feat.ebx |= HV_SIGNAL_EVENTS;
    574			hcall->expect = HV_STATUS_INVALID_HYPERCALL_INPUT;
    575			break;
    576
    577		case 5:
    578			hcall->control = HVCALL_RESET_DEBUG_SESSION;
    579			hcall->expect = HV_STATUS_INVALID_HYPERCALL_CODE;
    580			break;
    581		case 6:
    582			dbg.eax |= HV_X64_SYNDBG_CAP_ALLOW_KERNEL_DEBUGGING;
    583			hcall->expect = HV_STATUS_ACCESS_DENIED;
    584			break;
    585		case 7:
    586			feat.ebx |= HV_DEBUGGING;
    587			hcall->expect = HV_STATUS_OPERATION_DENIED;
    588			break;
    589
    590		case 8:
    591			hcall->control = HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE;
    592			hcall->expect = HV_STATUS_ACCESS_DENIED;
    593			break;
    594		case 9:
    595			recomm.eax |= HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED;
    596			hcall->expect = HV_STATUS_SUCCESS;
    597			break;
    598		case 10:
    599			hcall->control = HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX;
    600			hcall->expect = HV_STATUS_ACCESS_DENIED;
    601			break;
    602		case 11:
    603			recomm.eax |= HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED;
    604			hcall->expect = HV_STATUS_SUCCESS;
    605			break;
    606
    607		case 12:
    608			hcall->control = HVCALL_SEND_IPI;
    609			hcall->expect = HV_STATUS_ACCESS_DENIED;
    610			break;
    611		case 13:
    612			recomm.eax |= HV_X64_CLUSTER_IPI_RECOMMENDED;
    613			hcall->expect = HV_STATUS_INVALID_HYPERCALL_INPUT;
    614			break;
    615		case 14:
    616			/* Nothing in 'sparse banks' -> success */
    617			hcall->control = HVCALL_SEND_IPI_EX;
    618			hcall->expect = HV_STATUS_SUCCESS;
    619			break;
    620
    621		case 15:
    622			hcall->control = HVCALL_NOTIFY_LONG_SPIN_WAIT;
    623			hcall->expect = HV_STATUS_ACCESS_DENIED;
    624			break;
    625		case 16:
    626			recomm.ebx = 0xfff;
    627			hcall->expect = HV_STATUS_SUCCESS;
    628			break;
    629		case 17:
    630			/* XMM fast hypercall */
    631			hcall->control = HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE | HV_HYPERCALL_FAST_BIT;
    632			hcall->ud_expected = true;
    633			break;
    634		case 18:
    635			feat.edx |= HV_X64_HYPERCALL_XMM_INPUT_AVAILABLE;
    636			hcall->ud_expected = false;
    637			hcall->expect = HV_STATUS_SUCCESS;
    638			break;
    639
    640		case 19:
    641			/* END */
    642			hcall->control = 0;
    643			break;
    644		}
    645
    646		hv_set_cpuid(vm, best, &feat, &recomm, &dbg);
    647
    648		if (hcall->control)
    649			pr_debug("Stage %d: testing hcall: 0x%lx\n", stage,
    650				 hcall->control);
    651		else
    652			pr_debug("Stage %d: finish\n", stage);
    653
    654		r = _vcpu_run(vm, VCPU_ID);
    655		TEST_ASSERT(!r, "vcpu_run failed: %d\n", r);
    656		TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
    657			    "unexpected exit reason: %u (%s)",
    658			    run->exit_reason, exit_reason_str(run->exit_reason));
    659
    660		switch (get_ucall(vm, VCPU_ID, &uc)) {
    661		case UCALL_SYNC:
    662			TEST_ASSERT(uc.args[1] == 0,
    663				    "Unexpected stage: %ld (0 expected)\n",
    664				    uc.args[1]);
    665			break;
    666		case UCALL_ABORT:
    667			TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0],
    668				  __FILE__, uc.args[1]);
    669			return;
    670		case UCALL_DONE:
    671			return;
    672		}
    673
    674		stage++;
    675		kvm_vm_free(vm);
    676	}
    677}
    678
    679int main(void)
    680{
    681	pr_info("Testing access to Hyper-V specific MSRs\n");
    682	guest_test_msrs_access();
    683
    684	pr_info("Testing access to Hyper-V hypercalls\n");
    685	guest_test_hcalls_access();
    686}