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 = 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 } 79 80 void for_each_guest_mode(void (*func)(enum vm_guest_mode, void *), void *arg) 81 { 82 int i; 83 84 for (i = 0; i < NUM_VM_MODES; ++i) { 85 if (!guest_modes[i].enabled) 86 continue; 87 TEST_ASSERT(guest_modes[i].supported, 88 "Guest mode ID %d (%s) not supported.", 89 i, vm_guest_mode_string(i)); 90 func(i, arg); 91 } 92 } 93 94 void guest_modes_help(void) 95 { 96 int i; 97 98 printf(" -m: specify the guest mode ID to test\n" 99 " (default: test all supported modes)\n" 100 " This option may be used multiple times.\n" 101 " Guest mode IDs:\n"); 102 for (i = 0; i < NUM_VM_MODES; ++i) { 103 printf(" %d: %s%s\n", i, vm_guest_mode_string(i), 104 guest_modes[i].supported ? " (supported)" : ""); 105 } 106 } 107 108 void guest_modes_cmdline(const char *arg) 109 { 110 static bool mode_selected; 111 unsigned int mode; 112 int i; 113 114 if (!mode_selected) { 115 for (i = 0; i < NUM_VM_MODES; ++i) 116 guest_modes[i].enabled = false; 117 mode_selected = true; 118 } 119 120 mode = strtoul(optarg, NULL, 10); 121 TEST_ASSERT(mode < NUM_VM_MODES, "Guest mode ID %d too big", mode); 122 guest_modes[mode].enabled = true; 123 } 124