xref: /openbmc/linux/tools/testing/selftests/kvm/lib/guest_modes.c (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
1e42ac777SAndrew Jones // SPDX-License-Identifier: GPL-2.0
2e42ac777SAndrew Jones /*
3e42ac777SAndrew Jones  * Copyright (C) 2020, Red Hat, Inc.
4e42ac777SAndrew Jones  */
5e42ac777SAndrew Jones #include "guest_modes.h"
6e42ac777SAndrew Jones 
7357c628eSMarc Zyngier #ifdef __aarch64__
80303ffdbSMarc Zyngier #include "processor.h"
9357c628eSMarc Zyngier enum vm_guest_mode vm_mode_default;
10357c628eSMarc Zyngier #endif
11357c628eSMarc Zyngier 
12e42ac777SAndrew Jones struct guest_mode guest_modes[NUM_VM_MODES];
13e42ac777SAndrew Jones 
guest_modes_append_default(void)14e42ac777SAndrew Jones void guest_modes_append_default(void)
15e42ac777SAndrew Jones {
16357c628eSMarc Zyngier #ifndef __aarch64__
17e42ac777SAndrew Jones 	guest_mode_append(VM_MODE_DEFAULT, true, true);
18357c628eSMarc Zyngier #else
19e42ac777SAndrew Jones 	{
20e42ac777SAndrew Jones 		unsigned int limit = kvm_check_cap(KVM_CAP_ARM_VM_IPA_SIZE);
210303ffdbSMarc Zyngier 		bool ps4k, ps16k, ps64k;
22357c628eSMarc Zyngier 		int i;
23357c628eSMarc Zyngier 
240303ffdbSMarc Zyngier 		aarch64_get_supported_page_sizes(limit, &ps4k, &ps16k, &ps64k);
250303ffdbSMarc Zyngier 
26357c628eSMarc Zyngier 		vm_mode_default = NUM_VM_MODES;
27357c628eSMarc Zyngier 
28e42ac777SAndrew Jones 		if (limit >= 52)
290303ffdbSMarc Zyngier 			guest_mode_append(VM_MODE_P52V48_64K, ps64k, ps64k);
30e42ac777SAndrew Jones 		if (limit >= 48) {
310303ffdbSMarc Zyngier 			guest_mode_append(VM_MODE_P48V48_4K, ps4k, ps4k);
32aa674de1SMarc Zyngier 			guest_mode_append(VM_MODE_P48V48_16K, ps16k, ps16k);
330303ffdbSMarc Zyngier 			guest_mode_append(VM_MODE_P48V48_64K, ps64k, ps64k);
34e42ac777SAndrew Jones 		}
35357c628eSMarc Zyngier 		if (limit >= 40) {
360303ffdbSMarc Zyngier 			guest_mode_append(VM_MODE_P40V48_4K, ps4k, ps4k);
37aa674de1SMarc Zyngier 			guest_mode_append(VM_MODE_P40V48_16K, ps16k, ps16k);
380303ffdbSMarc Zyngier 			guest_mode_append(VM_MODE_P40V48_64K, ps64k, ps64k);
390303ffdbSMarc Zyngier 			if (ps4k)
40357c628eSMarc Zyngier 				vm_mode_default = VM_MODE_P40V48_4K;
41357c628eSMarc Zyngier 		}
42e7f58a6bSMarc Zyngier 		if (limit >= 36) {
43e7f58a6bSMarc Zyngier 			guest_mode_append(VM_MODE_P36V48_4K, ps4k, ps4k);
44aa674de1SMarc Zyngier 			guest_mode_append(VM_MODE_P36V48_16K, ps16k, ps16k);
45e7f58a6bSMarc Zyngier 			guest_mode_append(VM_MODE_P36V48_64K, ps64k, ps64k);
46aa674de1SMarc Zyngier 			guest_mode_append(VM_MODE_P36V47_16K, ps16k, ps16k);
47e7f58a6bSMarc Zyngier 		}
48357c628eSMarc Zyngier 
49357c628eSMarc Zyngier 		/*
50357c628eSMarc Zyngier 		 * Pick the first supported IPA size if the default
51357c628eSMarc Zyngier 		 * isn't available.
52357c628eSMarc Zyngier 		 */
53357c628eSMarc Zyngier 		for (i = 0; vm_mode_default == NUM_VM_MODES && i < NUM_VM_MODES; i++) {
54357c628eSMarc Zyngier 			if (guest_modes[i].supported && guest_modes[i].enabled)
55357c628eSMarc Zyngier 				vm_mode_default = i;
56357c628eSMarc Zyngier 		}
57357c628eSMarc Zyngier 
58357c628eSMarc Zyngier 		TEST_ASSERT(vm_mode_default != NUM_VM_MODES,
59357c628eSMarc Zyngier 			    "No supported mode!");
60e42ac777SAndrew Jones 	}
61e42ac777SAndrew Jones #endif
62fb5dad40SChristian Borntraeger #ifdef __s390x__
63fb5dad40SChristian Borntraeger 	{
64fb5dad40SChristian Borntraeger 		int kvm_fd, vm_fd;
65fb5dad40SChristian Borntraeger 		struct kvm_s390_vm_cpu_processor info;
66fb5dad40SChristian Borntraeger 
67fb5dad40SChristian Borntraeger 		kvm_fd = open_kvm_dev_path_or_exit();
68fcba483eSSean Christopherson 		vm_fd = __kvm_ioctl(kvm_fd, KVM_CREATE_VM, NULL);
6940918184SSean Christopherson 		kvm_device_attr_get(vm_fd, KVM_S390_VM_CPU_MODEL,
7040918184SSean Christopherson 				    KVM_S390_VM_CPU_PROCESSOR, &info);
71fb5dad40SChristian Borntraeger 		close(vm_fd);
72fb5dad40SChristian Borntraeger 		close(kvm_fd);
73fb5dad40SChristian Borntraeger 		/* Starting with z13 we have 47bits of physical address */
74fb5dad40SChristian Borntraeger 		if (info.ibc >= 0x30)
75fb5dad40SChristian Borntraeger 			guest_mode_append(VM_MODE_P47V64_4K, true, true);
76fb5dad40SChristian Borntraeger 	}
77fb5dad40SChristian Borntraeger #endif
783e06cdf1SAnup Patel #ifdef __riscv
793e06cdf1SAnup Patel 	{
803e06cdf1SAnup Patel 		unsigned int sz = kvm_check_cap(KVM_CAP_VM_GPA_BITS);
813e06cdf1SAnup Patel 
823e06cdf1SAnup Patel 		if (sz >= 52)
833e06cdf1SAnup Patel 			guest_mode_append(VM_MODE_P52V48_4K, true, true);
843e06cdf1SAnup Patel 		if (sz >= 48)
853e06cdf1SAnup Patel 			guest_mode_append(VM_MODE_P48V48_4K, true, true);
863e06cdf1SAnup Patel 	}
873e06cdf1SAnup Patel #endif
88e42ac777SAndrew Jones }
89e42ac777SAndrew Jones 
for_each_guest_mode(void (* func)(enum vm_guest_mode,void *),void * arg)90e42ac777SAndrew Jones void for_each_guest_mode(void (*func)(enum vm_guest_mode, void *), void *arg)
91e42ac777SAndrew Jones {
92e42ac777SAndrew Jones 	int i;
93e42ac777SAndrew Jones 
94e42ac777SAndrew Jones 	for (i = 0; i < NUM_VM_MODES; ++i) {
95e42ac777SAndrew Jones 		if (!guest_modes[i].enabled)
96e42ac777SAndrew Jones 			continue;
97e42ac777SAndrew Jones 		TEST_ASSERT(guest_modes[i].supported,
98e42ac777SAndrew Jones 			    "Guest mode ID %d (%s) not supported.",
99e42ac777SAndrew Jones 			    i, vm_guest_mode_string(i));
100e42ac777SAndrew Jones 		func(i, arg);
101e42ac777SAndrew Jones 	}
102e42ac777SAndrew Jones }
103e42ac777SAndrew Jones 
guest_modes_help(void)104e42ac777SAndrew Jones void guest_modes_help(void)
105e42ac777SAndrew Jones {
106e42ac777SAndrew Jones 	int i;
107e42ac777SAndrew Jones 
108e42ac777SAndrew Jones 	printf(" -m: specify the guest mode ID to test\n"
109e42ac777SAndrew Jones 	       "     (default: test all supported modes)\n"
110e42ac777SAndrew Jones 	       "     This option may be used multiple times.\n"
111e42ac777SAndrew Jones 	       "     Guest mode IDs:\n");
112e42ac777SAndrew Jones 	for (i = 0; i < NUM_VM_MODES; ++i) {
113e42ac777SAndrew Jones 		printf("         %d:    %s%s\n", i, vm_guest_mode_string(i),
114e42ac777SAndrew Jones 		       guest_modes[i].supported ? " (supported)" : "");
115e42ac777SAndrew Jones 	}
116e42ac777SAndrew Jones }
117e42ac777SAndrew Jones 
guest_modes_cmdline(const char * arg)118e42ac777SAndrew Jones void guest_modes_cmdline(const char *arg)
119e42ac777SAndrew Jones {
120e42ac777SAndrew Jones 	static bool mode_selected;
121e42ac777SAndrew Jones 	unsigned int mode;
122e42ac777SAndrew Jones 	int i;
123e42ac777SAndrew Jones 
124e42ac777SAndrew Jones 	if (!mode_selected) {
125e42ac777SAndrew Jones 		for (i = 0; i < NUM_VM_MODES; ++i)
126e42ac777SAndrew Jones 			guest_modes[i].enabled = false;
127e42ac777SAndrew Jones 		mode_selected = true;
128e42ac777SAndrew Jones 	}
129e42ac777SAndrew Jones 
130*7ae69d70SShaoqin Huang 	mode = atoi_non_negative("Guest mode ID", arg);
131e42ac777SAndrew Jones 	TEST_ASSERT(mode < NUM_VM_MODES, "Guest mode ID %d too big", mode);
132e42ac777SAndrew Jones 	guest_modes[mode].enabled = true;
133e42ac777SAndrew Jones }
134