1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2020, Red Hat, Inc. 4 */ 5 #include "guest_modes.h" 6 7 #ifdef __aarch64__ 8 #include "processor.h" 9 enum vm_guest_mode vm_mode_default; 10 #endif 11 12 struct guest_mode guest_modes[NUM_VM_MODES]; 13 14 void guest_modes_append_default(void) 15 { 16 #ifndef __aarch64__ 17 guest_mode_append(VM_MODE_DEFAULT, true, true); 18 #else 19 { 20 unsigned int limit = kvm_check_cap(KVM_CAP_ARM_VM_IPA_SIZE); 21 bool ps4k, ps16k, ps64k; 22 int i; 23 24 aarch64_get_supported_page_sizes(limit, &ps4k, &ps16k, &ps64k); 25 26 vm_mode_default = NUM_VM_MODES; 27 28 if (limit >= 52) 29 guest_mode_append(VM_MODE_P52V48_64K, ps64k, ps64k); 30 if (limit >= 48) { 31 guest_mode_append(VM_MODE_P48V48_4K, ps4k, ps4k); 32 guest_mode_append(VM_MODE_P48V48_16K, ps16k, ps16k); 33 guest_mode_append(VM_MODE_P48V48_64K, ps64k, ps64k); 34 } 35 if (limit >= 40) { 36 guest_mode_append(VM_MODE_P40V48_4K, ps4k, ps4k); 37 guest_mode_append(VM_MODE_P40V48_16K, ps16k, ps16k); 38 guest_mode_append(VM_MODE_P40V48_64K, ps64k, ps64k); 39 if (ps4k) 40 vm_mode_default = VM_MODE_P40V48_4K; 41 } 42 if (limit >= 36) { 43 guest_mode_append(VM_MODE_P36V48_4K, ps4k, ps4k); 44 guest_mode_append(VM_MODE_P36V48_16K, ps16k, ps16k); 45 guest_mode_append(VM_MODE_P36V48_64K, ps64k, ps64k); 46 guest_mode_append(VM_MODE_P36V47_16K, ps16k, ps16k); 47 } 48 49 /* 50 * Pick the first supported IPA size if the default 51 * isn't available. 52 */ 53 for (i = 0; vm_mode_default == NUM_VM_MODES && i < NUM_VM_MODES; i++) { 54 if (guest_modes[i].supported && guest_modes[i].enabled) 55 vm_mode_default = i; 56 } 57 58 TEST_ASSERT(vm_mode_default != NUM_VM_MODES, 59 "No supported mode!"); 60 } 61 #endif 62 #ifdef __s390x__ 63 { 64 int kvm_fd, vm_fd; 65 struct kvm_s390_vm_cpu_processor info; 66 67 kvm_fd = open_kvm_dev_path_or_exit(); 68 vm_fd = __kvm_ioctl(kvm_fd, KVM_CREATE_VM, 0); 69 kvm_device_access(vm_fd, KVM_S390_VM_CPU_MODEL, 70 KVM_S390_VM_CPU_PROCESSOR, &info, false); 71 close(vm_fd); 72 close(kvm_fd); 73 /* Starting with z13 we have 47bits of physical address */ 74 if (info.ibc >= 0x30) 75 guest_mode_append(VM_MODE_P47V64_4K, true, true); 76 } 77 #endif 78 #ifdef __riscv 79 { 80 unsigned int sz = kvm_check_cap(KVM_CAP_VM_GPA_BITS); 81 82 if (sz >= 52) 83 guest_mode_append(VM_MODE_P52V48_4K, true, true); 84 if (sz >= 48) 85 guest_mode_append(VM_MODE_P48V48_4K, true, true); 86 } 87 #endif 88 } 89 90 void for_each_guest_mode(void (*func)(enum vm_guest_mode, void *), void *arg) 91 { 92 int i; 93 94 for (i = 0; i < NUM_VM_MODES; ++i) { 95 if (!guest_modes[i].enabled) 96 continue; 97 TEST_ASSERT(guest_modes[i].supported, 98 "Guest mode ID %d (%s) not supported.", 99 i, vm_guest_mode_string(i)); 100 func(i, arg); 101 } 102 } 103 104 void guest_modes_help(void) 105 { 106 int i; 107 108 printf(" -m: specify the guest mode ID to test\n" 109 " (default: test all supported modes)\n" 110 " This option may be used multiple times.\n" 111 " Guest mode IDs:\n"); 112 for (i = 0; i < NUM_VM_MODES; ++i) { 113 printf(" %d: %s%s\n", i, vm_guest_mode_string(i), 114 guest_modes[i].supported ? " (supported)" : ""); 115 } 116 } 117 118 void guest_modes_cmdline(const char *arg) 119 { 120 static bool mode_selected; 121 unsigned int mode; 122 int i; 123 124 if (!mode_selected) { 125 for (i = 0; i < NUM_VM_MODES; ++i) 126 guest_modes[i].enabled = false; 127 mode_selected = true; 128 } 129 130 mode = strtoul(optarg, NULL, 10); 131 TEST_ASSERT(mode < NUM_VM_MODES, "Guest mode ID %d too big", mode); 132 guest_modes[mode].enabled = true; 133 } 134