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); 18 #else 19 { 20 unsigned int limit = kvm_check_cap(KVM_CAP_ARM_VM_IPA_SIZE); 21 uint32_t ipa4k, ipa16k, ipa64k; 22 int i; 23 24 aarch64_get_supported_page_sizes(limit, &ipa4k, &ipa16k, &ipa64k); 25 26 guest_mode_append(VM_MODE_P52V48_4K, ipa4k >= 52); 27 guest_mode_append(VM_MODE_P52V48_16K, ipa16k >= 52); 28 guest_mode_append(VM_MODE_P52V48_64K, ipa64k >= 52); 29 30 guest_mode_append(VM_MODE_P48V48_4K, ipa4k >= 48); 31 guest_mode_append(VM_MODE_P48V48_16K, ipa16k >= 48); 32 guest_mode_append(VM_MODE_P48V48_64K, ipa64k >= 48); 33 34 guest_mode_append(VM_MODE_P40V48_4K, ipa4k >= 40); 35 guest_mode_append(VM_MODE_P40V48_16K, ipa16k >= 40); 36 guest_mode_append(VM_MODE_P40V48_64K, ipa64k >= 40); 37 38 guest_mode_append(VM_MODE_P36V48_4K, ipa4k >= 36); 39 guest_mode_append(VM_MODE_P36V48_16K, ipa16k >= 36); 40 guest_mode_append(VM_MODE_P36V48_64K, ipa64k >= 36); 41 guest_mode_append(VM_MODE_P36V47_16K, ipa16k >= 36); 42 43 vm_mode_default = ipa4k >= 40 ? VM_MODE_P40V48_4K : NUM_VM_MODES; 44 45 /* 46 * Pick the first supported IPA size if the default 47 * isn't available. 48 */ 49 for (i = 0; vm_mode_default == NUM_VM_MODES && i < NUM_VM_MODES; i++) { 50 if (guest_modes[i].supported && guest_modes[i].enabled) 51 vm_mode_default = i; 52 } 53 54 TEST_ASSERT(vm_mode_default != NUM_VM_MODES, 55 "No supported mode!"); 56 } 57 #endif 58 #ifdef __s390x__ 59 { 60 int kvm_fd, vm_fd; 61 struct kvm_s390_vm_cpu_processor info; 62 63 kvm_fd = open_kvm_dev_path_or_exit(); 64 vm_fd = __kvm_ioctl(kvm_fd, KVM_CREATE_VM, NULL); 65 kvm_device_attr_get(vm_fd, KVM_S390_VM_CPU_MODEL, 66 KVM_S390_VM_CPU_PROCESSOR, &info); 67 close(vm_fd); 68 close(kvm_fd); 69 /* Starting with z13 we have 47bits of physical address */ 70 if (info.ibc >= 0x30) 71 guest_mode_append(VM_MODE_P47V64_4K, true); 72 } 73 #endif 74 #ifdef __riscv 75 { 76 unsigned int sz = kvm_check_cap(KVM_CAP_VM_GPA_BITS); 77 78 if (sz >= 52) 79 guest_mode_append(VM_MODE_P52V48_4K, true); 80 if (sz >= 48) 81 guest_mode_append(VM_MODE_P48V48_4K, true); 82 } 83 #endif 84 } 85 86 void for_each_guest_mode(void (*func)(enum vm_guest_mode, void *), void *arg) 87 { 88 int i; 89 90 for (i = 0; i < NUM_VM_MODES; ++i) { 91 if (!guest_modes[i].enabled) 92 continue; 93 TEST_ASSERT(guest_modes[i].supported, 94 "Guest mode ID %d (%s) not supported.", 95 i, vm_guest_mode_string(i)); 96 func(i, arg); 97 } 98 } 99 100 void guest_modes_help(void) 101 { 102 int i; 103 104 printf(" -m: specify the guest mode ID to test\n" 105 " (default: test all supported modes)\n" 106 " This option may be used multiple times.\n" 107 " Guest mode IDs:\n"); 108 for (i = 0; i < NUM_VM_MODES; ++i) { 109 printf(" %d: %s%s\n", i, vm_guest_mode_string(i), 110 guest_modes[i].supported ? " (supported)" : ""); 111 } 112 } 113 114 void guest_modes_cmdline(const char *arg) 115 { 116 static bool mode_selected; 117 unsigned int mode; 118 int i; 119 120 if (!mode_selected) { 121 for (i = 0; i < NUM_VM_MODES; ++i) 122 guest_modes[i].enabled = false; 123 mode_selected = true; 124 } 125 126 mode = atoi_non_negative("Guest mode ID", arg); 127 TEST_ASSERT(mode < NUM_VM_MODES, "Guest mode ID %d too big", mode); 128 guest_modes[mode].enabled = true; 129 } 130
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.