1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2020, Red Hat, Inc. 4 */ 5 #include "guest_modes.h" 6 7 #if defined(__aarch64__) || defined(__riscv) 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 #if !defined(__aarch64__) && !defined(__riscv) 17 guest_mode_append(VM_MODE_DEFAULT, true); 18 #endif 19 20 #ifdef __aarch64__ 21 { 22 unsigned int limit = kvm_check_cap(KVM_CAP_ARM_VM_IPA_SIZE); 23 uint32_t ipa4k, ipa16k, ipa64k; 24 int i; 25 26 aarch64_get_supported_page_sizes(limit, &ipa4k, &ipa16k, &ipa64k); 27 28 guest_mode_append(VM_MODE_P52V48_4K, ipa4k >= 52); 29 guest_mode_append(VM_MODE_P52V48_16K, ipa16k >= 52); 30 guest_mode_append(VM_MODE_P52V48_64K, ipa64k >= 52); 31 32 guest_mode_append(VM_MODE_P48V48_4K, ipa4k >= 48); 33 guest_mode_append(VM_MODE_P48V48_16K, ipa16k >= 48); 34 guest_mode_append(VM_MODE_P48V48_64K, ipa64k >= 48); 35 36 guest_mode_append(VM_MODE_P40V48_4K, ipa4k >= 40); 37 guest_mode_append(VM_MODE_P40V48_16K, ipa16k >= 40); 38 guest_mode_append(VM_MODE_P40V48_64K, ipa64k >= 40); 39 40 guest_mode_append(VM_MODE_P36V48_4K, ipa4k >= 36); 41 guest_mode_append(VM_MODE_P36V48_16K, ipa16k >= 36); 42 guest_mode_append(VM_MODE_P36V48_64K, ipa64k >= 36); 43 guest_mode_append(VM_MODE_P36V47_16K, ipa16k >= 36); 44 45 vm_mode_default = ipa4k >= 40 ? VM_MODE_P40V48_4K : NUM_VM_MODES; 46 47 /* 48 * Pick the first supported IPA size if the default 49 * isn't available. 50 */ 51 for (i = 0; vm_mode_default == NUM_VM_MODES && i < NUM_VM_MODES; i++) { 52 if (guest_modes[i].supported && guest_modes[i].enabled) 53 vm_mode_default = i; 54 } 55 56 TEST_ASSERT(vm_mode_default != NUM_VM_MODES, 57 "No supported mode!"); 58 } 59 #endif 60 #ifdef __s390x__ 61 { 62 int kvm_fd, vm_fd; 63 struct kvm_s390_vm_cpu_processor info; 64 65 kvm_fd = open_kvm_dev_path_or_exit(); 66 vm_fd = __kvm_ioctl(kvm_fd, KVM_CREATE_VM, NULL); 67 kvm_device_attr_get(vm_fd, KVM_S390_VM_CPU_MODEL, 68 KVM_S390_VM_CPU_PROCESSOR, &info); 69 close(vm_fd); 70 close(kvm_fd); 71 /* Starting with z13 we have 47bits of physical address */ 72 if (info.ibc >= 0x30) 73 guest_mode_append(VM_MODE_P47V64_4K, true); 74 } 75 #endif 76 #ifdef __riscv 77 { 78 unsigned int sz = kvm_check_cap(KVM_CAP_VM_GPA_BITS); 79 unsigned long satp_mode = riscv64_get_satp_mode() << SATP_MODE_SHIFT; 80 int i; 81 82 switch (sz) { 83 case 59: 84 guest_mode_append(VM_MODE_P56V57_4K, satp_mode >= SATP_MODE_57); 85 guest_mode_append(VM_MODE_P56V48_4K, satp_mode >= SATP_MODE_48); 86 guest_mode_append(VM_MODE_P56V39_4K, satp_mode >= SATP_MODE_39); 87 break; 88 case 50: 89 guest_mode_append(VM_MODE_P50V57_4K, satp_mode >= SATP_MODE_57); 90 guest_mode_append(VM_MODE_P50V48_4K, satp_mode >= SATP_MODE_48); 91 guest_mode_append(VM_MODE_P50V39_4K, satp_mode >= SATP_MODE_39); 92 break; 93 case 41: 94 guest_mode_append(VM_MODE_P41V57_4K, satp_mode >= SATP_MODE_57); 95 guest_mode_append(VM_MODE_P41V48_4K, satp_mode >= SATP_MODE_48); 96 guest_mode_append(VM_MODE_P41V39_4K, satp_mode >= SATP_MODE_39); 97 break; 98 default: 99 break; 100 } 101 102 /* set the first supported mode as default */ 103 vm_mode_default = NUM_VM_MODES; 104 for (i = 0; vm_mode_default == NUM_VM_MODES && i < NUM_VM_MODES; i++) { 105 if (guest_modes[i].supported && guest_modes[i].enabled) 106 vm_mode_default = i; 107 } 108 TEST_ASSERT(vm_mode_default != NUM_VM_MODES, "No supported mode!"); 109 } 110 #endif 111 } 112 113 void for_each_guest_mode(void (*func)(enum vm_guest_mode, void *), void *arg) 114 { 115 int i; 116 117 for (i = 0; i < NUM_VM_MODES; ++i) { 118 if (!guest_modes[i].enabled) 119 continue; 120 TEST_ASSERT(guest_modes[i].supported, 121 "Guest mode ID %d (%s) not supported.", 122 i, vm_guest_mode_string(i)); 123 func(i, arg); 124 } 125 } 126 127 void guest_modes_help(void) 128 { 129 int i; 130 131 printf(" -m: specify the guest mode ID to test\n" 132 " (default: test all supported modes)\n" 133 " This option may be used multiple times.\n" 134 " Guest mode IDs:\n"); 135 for (i = 0; i < NUM_VM_MODES; ++i) { 136 printf(" %d: %s%s\n", i, vm_guest_mode_string(i), 137 guest_modes[i].supported ? " (supported)" : ""); 138 } 139 } 140 141 void guest_modes_cmdline(const char *arg) 142 { 143 static bool mode_selected; 144 unsigned int mode; 145 int i; 146 147 if (!mode_selected) { 148 for (i = 0; i < NUM_VM_MODES; ++i) 149 guest_modes[i].enabled = false; 150 mode_selected = true; 151 } 152 153 mode = atoi_non_negative("Guest mode ID", arg); 154 TEST_ASSERT(mode < NUM_VM_MODES, "Guest mode ID %d too big", mode); 155 guest_modes[mode].enabled = true; 156 } 157