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_64K, ps64k, ps64k); 33 } 34 if (limit >= 40) { 35 guest_mode_append(VM_MODE_P40V48_4K, ps4k, ps4k); 36 guest_mode_append(VM_MODE_P40V48_64K, ps64k, ps64k); 37 if (ps4k) 38 vm_mode_default = VM_MODE_P40V48_4K; 39 } 40 if (limit >= 36) { 41 guest_mode_append(VM_MODE_P36V48_4K, ps4k, ps4k); 42 guest_mode_append(VM_MODE_P36V48_64K, ps64k, ps64k); 43 } 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 = ioctl(kvm_fd, KVM_CREATE_VM, 0); 65 kvm_device_access(vm_fd, KVM_S390_VM_CPU_MODEL, 66 KVM_S390_VM_CPU_PROCESSOR, &info, false); 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, true); 72 } 73 #endif 74 } 75 76 void for_each_guest_mode(void (*func)(enum vm_guest_mode, void *), void *arg) 77 { 78 int i; 79 80 for (i = 0; i < NUM_VM_MODES; ++i) { 81 if (!guest_modes[i].enabled) 82 continue; 83 TEST_ASSERT(guest_modes[i].supported, 84 "Guest mode ID %d (%s) not supported.", 85 i, vm_guest_mode_string(i)); 86 func(i, arg); 87 } 88 } 89 90 void guest_modes_help(void) 91 { 92 int i; 93 94 printf(" -m: specify the guest mode ID to test\n" 95 " (default: test all supported modes)\n" 96 " This option may be used multiple times.\n" 97 " Guest mode IDs:\n"); 98 for (i = 0; i < NUM_VM_MODES; ++i) { 99 printf(" %d: %s%s\n", i, vm_guest_mode_string(i), 100 guest_modes[i].supported ? " (supported)" : ""); 101 } 102 } 103 104 void guest_modes_cmdline(const char *arg) 105 { 106 static bool mode_selected; 107 unsigned int mode; 108 int i; 109 110 if (!mode_selected) { 111 for (i = 0; i < NUM_VM_MODES; ++i) 112 guest_modes[i].enabled = false; 113 mode_selected = true; 114 } 115 116 mode = strtoul(optarg, NULL, 10); 117 TEST_ASSERT(mode < NUM_VM_MODES, "Guest mode ID %d too big", mode); 118 guest_modes[mode].enabled = true; 119 } 120