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