Path: blob/master/tools/testing/selftests/kvm/s390/tprot.c
38245 views
// SPDX-License-Identifier: GPL-2.0-or-later1/*2* Test TEST PROTECTION emulation.3*4* Copyright IBM Corp. 20215*/6#include <sys/mman.h>7#include "test_util.h"8#include "kvm_util.h"9#include "kselftest.h"10#include "ucall_common.h"11#include "processor.h"1213#define CR0_FETCH_PROTECTION_OVERRIDE (1UL << (63 - 38))14#define CR0_STORAGE_PROTECTION_OVERRIDE (1UL << (63 - 39))1516static __aligned(PAGE_SIZE) uint8_t pages[2][PAGE_SIZE];17static uint8_t *const page_store_prot = pages[0];18static uint8_t *const page_fetch_prot = pages[1];1920/* Nonzero return value indicates that address not mapped */21static int set_storage_key(void *addr, uint8_t key)22{23int not_mapped = 0;2425asm volatile (26"lra %[addr], 0(0,%[addr])\n"27" jz 0f\n"28" llill %[not_mapped],1\n"29" j 1f\n"30"0: sske %[key], %[addr]\n"31"1:"32: [addr] "+&a" (addr), [not_mapped] "+r" (not_mapped)33: [key] "r" (key)34: "cc"35);36return -not_mapped;37}3839enum permission {40READ_WRITE = 0,41READ = 1,42RW_PROTECTED = 2,43TRANSL_UNAVAIL = 3,44};4546static enum permission test_protection(void *addr, uint8_t key)47{48uint64_t mask;4950asm volatile (51"tprot %[addr], 0(%[key])\n"52" ipm %[mask]\n"53: [mask] "=r" (mask)54: [addr] "Q" (*(char *)addr),55[key] "a" (key)56: "cc"57);5859return (enum permission)(mask >> 28);60}6162enum stage {63STAGE_INIT_SIMPLE,64TEST_SIMPLE,65STAGE_INIT_FETCH_PROT_OVERRIDE,66TEST_FETCH_PROT_OVERRIDE,67TEST_STORAGE_PROT_OVERRIDE,68STAGE_END /* must be the last entry (it's the amount of tests) */69};7071struct test {72enum stage stage;73void *addr;74uint8_t key;75enum permission expected;76} tests[] = {77/*78* We perform each test in the array by executing TEST PROTECTION on79* the specified addr with the specified key and checking if the returned80* permissions match the expected value.81* Both guest and host cooperate to set up the required test conditions.82* A central condition is that the page targeted by addr has to be DAT83* protected in the host mappings, in order for KVM to emulate the84* TEST PROTECTION instruction.85* Since the page tables are shared, the host uses mprotect to achieve86* this.87*88* Test resulting in RW_PROTECTED/TRANSL_UNAVAIL will be interpreted89* by SIE, not KVM, but there is no harm in testing them also.90* See Enhanced Suppression-on-Protection Facilities in the91* Interpretive-Execution Mode92*/93/*94* guest: set storage key of page_store_prot to 195* storage key of page_fetch_prot to 9 and enable96* protection for it97* STAGE_INIT_SIMPLE98* host: write protect both via mprotect99*/100/* access key 0 matches any storage key -> RW */101{ TEST_SIMPLE, page_store_prot, 0x00, READ_WRITE },102/* access key matches storage key -> RW */103{ TEST_SIMPLE, page_store_prot, 0x10, READ_WRITE },104/* mismatched keys, but no fetch protection -> RO */105{ TEST_SIMPLE, page_store_prot, 0x20, READ },106/* access key 0 matches any storage key -> RW */107{ TEST_SIMPLE, page_fetch_prot, 0x00, READ_WRITE },108/* access key matches storage key -> RW */109{ TEST_SIMPLE, page_fetch_prot, 0x90, READ_WRITE },110/* mismatched keys, fetch protection -> inaccessible */111{ TEST_SIMPLE, page_fetch_prot, 0x10, RW_PROTECTED },112/* page 0 not mapped yet -> translation not available */113{ TEST_SIMPLE, (void *)0x00, 0x10, TRANSL_UNAVAIL },114/*115* host: try to map page 0116* guest: set storage key of page 0 to 9 and enable fetch protection117* STAGE_INIT_FETCH_PROT_OVERRIDE118* host: write protect page 0119* enable fetch protection override120*/121/* mismatched keys, fetch protection, but override applies -> RO */122{ TEST_FETCH_PROT_OVERRIDE, (void *)0x00, 0x10, READ },123/* mismatched keys, fetch protection, override applies to 0-2048 only -> inaccessible */124{ TEST_FETCH_PROT_OVERRIDE, (void *)2049, 0x10, RW_PROTECTED },125/*126* host: enable storage protection override127*/128/* mismatched keys, but override applies (storage key 9) -> RW */129{ TEST_STORAGE_PROT_OVERRIDE, page_fetch_prot, 0x10, READ_WRITE },130/* mismatched keys, no fetch protection, override doesn't apply -> RO */131{ TEST_STORAGE_PROT_OVERRIDE, page_store_prot, 0x20, READ },132/* mismatched keys, but override applies (storage key 9) -> RW */133{ TEST_STORAGE_PROT_OVERRIDE, (void *)2049, 0x10, READ_WRITE },134/* end marker */135{ STAGE_END, 0, 0, 0 },136};137138static enum stage perform_next_stage(int *i, bool mapped_0)139{140enum stage stage = tests[*i].stage;141enum permission result;142bool skip;143144for (; tests[*i].stage == stage; (*i)++) {145/*146* Some fetch protection override tests require that page 0147* be mapped, however, when the hosts tries to map that page via148* vm_vaddr_alloc, it may happen that some other page gets mapped149* instead.150* In order to skip these tests we detect this inside the guest151*/152skip = tests[*i].addr < (void *)PAGE_SIZE &&153tests[*i].expected != TRANSL_UNAVAIL &&154!mapped_0;155if (!skip) {156result = test_protection(tests[*i].addr, tests[*i].key);157__GUEST_ASSERT(result == tests[*i].expected,158"Wanted %u, got %u, for i = %u",159tests[*i].expected, result, *i);160}161}162return stage;163}164165static void guest_code(void)166{167bool mapped_0;168int i = 0;169170GUEST_ASSERT_EQ(set_storage_key(page_store_prot, 0x10), 0);171GUEST_ASSERT_EQ(set_storage_key(page_fetch_prot, 0x98), 0);172GUEST_SYNC(STAGE_INIT_SIMPLE);173GUEST_SYNC(perform_next_stage(&i, false));174175/* Fetch-protection override */176mapped_0 = !set_storage_key((void *)0, 0x98);177GUEST_SYNC(STAGE_INIT_FETCH_PROT_OVERRIDE);178GUEST_SYNC(perform_next_stage(&i, mapped_0));179180/* Storage-protection override */181GUEST_SYNC(perform_next_stage(&i, mapped_0));182}183184#define HOST_SYNC_NO_TAP(vcpup, stage) \185({ \186struct kvm_vcpu *__vcpu = (vcpup); \187struct ucall uc; \188int __stage = (stage); \189\190vcpu_run(__vcpu); \191get_ucall(__vcpu, &uc); \192if (uc.cmd == UCALL_ABORT) \193REPORT_GUEST_ASSERT(uc); \194TEST_ASSERT_EQ(uc.cmd, UCALL_SYNC); \195TEST_ASSERT_EQ(uc.args[1], __stage); \196})197198#define HOST_SYNC(vcpu, stage) \199({ \200HOST_SYNC_NO_TAP(vcpu, stage); \201ksft_test_result_pass("" #stage "\n"); \202})203204int main(int argc, char *argv[])205{206struct kvm_vcpu *vcpu;207struct kvm_vm *vm;208struct kvm_run *run;209vm_vaddr_t guest_0_page;210211ksft_print_header();212ksft_set_plan(STAGE_END);213214vm = vm_create_with_one_vcpu(&vcpu, guest_code);215run = vcpu->run;216217HOST_SYNC(vcpu, STAGE_INIT_SIMPLE);218mprotect(addr_gva2hva(vm, (vm_vaddr_t)pages), PAGE_SIZE * 2, PROT_READ);219HOST_SYNC(vcpu, TEST_SIMPLE);220221guest_0_page = vm_vaddr_alloc(vm, PAGE_SIZE, 0);222if (guest_0_page != 0) {223/* Use NO_TAP so we don't get a PASS print */224HOST_SYNC_NO_TAP(vcpu, STAGE_INIT_FETCH_PROT_OVERRIDE);225ksft_test_result_skip("STAGE_INIT_FETCH_PROT_OVERRIDE - "226"Did not allocate page at 0\n");227} else {228HOST_SYNC(vcpu, STAGE_INIT_FETCH_PROT_OVERRIDE);229}230if (guest_0_page == 0)231mprotect(addr_gva2hva(vm, (vm_vaddr_t)0), PAGE_SIZE, PROT_READ);232run->s.regs.crs[0] |= CR0_FETCH_PROTECTION_OVERRIDE;233run->kvm_dirty_regs = KVM_SYNC_CRS;234HOST_SYNC(vcpu, TEST_FETCH_PROT_OVERRIDE);235236run->s.regs.crs[0] |= CR0_STORAGE_PROTECTION_OVERRIDE;237run->kvm_dirty_regs = KVM_SYNC_CRS;238HOST_SYNC(vcpu, TEST_STORAGE_PROT_OVERRIDE);239240kvm_vm_free(vm);241242ksft_finished(); /* Print results and exit() accordingly */243}244245246