|
3 | 3 | #include <asm/cpufeature.h>
|
4 | 4 | #include <asm/tdx.h>
|
5 | 5 | #include "capabilities.h"
|
| 6 | +#include "mmu.h" |
6 | 7 | #include "x86_ops.h"
|
7 | 8 | #include "lapic.h"
|
8 | 9 | #include "tdx.h"
|
@@ -849,6 +850,103 @@ static int __tdx_td_init(struct kvm *kvm, struct td_params *td_params,
|
849 | 850 | return ret;
|
850 | 851 | }
|
851 | 852 |
|
| 853 | +static u64 tdx_td_metadata_field_read(struct kvm_tdx *tdx, u64 field_id, |
| 854 | + u64 *data) |
| 855 | +{ |
| 856 | + u64 err; |
| 857 | + |
| 858 | + err = tdh_mng_rd(&tdx->td, field_id, data); |
| 859 | + |
| 860 | + return err; |
| 861 | +} |
| 862 | + |
| 863 | +#define TDX_MD_UNREADABLE_LEAF_MASK GENMASK(30, 7) |
| 864 | +#define TDX_MD_UNREADABLE_SUBLEAF_MASK GENMASK(31, 7) |
| 865 | + |
| 866 | +static int tdx_read_cpuid(struct kvm_vcpu *vcpu, u32 leaf, u32 sub_leaf, |
| 867 | + bool sub_leaf_set, int *entry_index, |
| 868 | + struct kvm_cpuid_entry2 *out) |
| 869 | +{ |
| 870 | + struct kvm_tdx *kvm_tdx = to_kvm_tdx(vcpu->kvm); |
| 871 | + u64 field_id = TD_MD_FIELD_ID_CPUID_VALUES; |
| 872 | + u64 ebx_eax, edx_ecx; |
| 873 | + u64 err = 0; |
| 874 | + |
| 875 | + if (sub_leaf > 0b1111111) |
| 876 | + return -EINVAL; |
| 877 | + |
| 878 | + if (*entry_index >= KVM_MAX_CPUID_ENTRIES) |
| 879 | + return -EINVAL; |
| 880 | + |
| 881 | + if (leaf & TDX_MD_UNREADABLE_LEAF_MASK || |
| 882 | + sub_leaf & TDX_MD_UNREADABLE_SUBLEAF_MASK) |
| 883 | + return -EINVAL; |
| 884 | + |
| 885 | + /* |
| 886 | + * bit 23:17, REVSERVED: reserved, must be 0; |
| 887 | + * bit 16, LEAF_31: leaf number bit 31; |
| 888 | + * bit 15:9, LEAF_6_0: leaf number bits 6:0, leaf bits 30:7 are |
| 889 | + * implicitly 0; |
| 890 | + * bit 8, SUBLEAF_NA: sub-leaf not applicable flag; |
| 891 | + * bit 7:1, SUBLEAF_6_0: sub-leaf number bits 6:0. If SUBLEAF_NA is 1, |
| 892 | + * the SUBLEAF_6_0 is all-1. |
| 893 | + * sub-leaf bits 31:7 are implicitly 0; |
| 894 | + * bit 0, ELEMENT_I: Element index within field; |
| 895 | + */ |
| 896 | + field_id |= ((leaf & 0x80000000) ? 1 : 0) << 16; |
| 897 | + field_id |= (leaf & 0x7f) << 9; |
| 898 | + if (sub_leaf_set) |
| 899 | + field_id |= (sub_leaf & 0x7f) << 1; |
| 900 | + else |
| 901 | + field_id |= 0x1fe; |
| 902 | + |
| 903 | + err = tdx_td_metadata_field_read(kvm_tdx, field_id, &ebx_eax); |
| 904 | + if (err) //TODO check for specific errors |
| 905 | + goto err_out; |
| 906 | + |
| 907 | + out->eax = (u32) ebx_eax; |
| 908 | + out->ebx = (u32) (ebx_eax >> 32); |
| 909 | + |
| 910 | + field_id++; |
| 911 | + err = tdx_td_metadata_field_read(kvm_tdx, field_id, &edx_ecx); |
| 912 | + /* |
| 913 | + * It's weird that reading edx_ecx fails while reading ebx_eax |
| 914 | + * succeeded. |
| 915 | + */ |
| 916 | + if (WARN_ON_ONCE(err)) |
| 917 | + goto err_out; |
| 918 | + |
| 919 | + out->ecx = (u32) edx_ecx; |
| 920 | + out->edx = (u32) (edx_ecx >> 32); |
| 921 | + |
| 922 | + out->function = leaf; |
| 923 | + out->index = sub_leaf; |
| 924 | + out->flags |= sub_leaf_set ? KVM_CPUID_FLAG_SIGNIFCANT_INDEX : 0; |
| 925 | + |
| 926 | + /* |
| 927 | + * Work around missing support on old TDX modules, fetch |
| 928 | + * guest maxpa from gfn_direct_bits. |
| 929 | + */ |
| 930 | + if (leaf == 0x80000008) { |
| 931 | + gpa_t gpa_bits = gfn_to_gpa(kvm_gfn_direct_bits(vcpu->kvm)); |
| 932 | + unsigned int g_maxpa = __ffs(gpa_bits) + 1; |
| 933 | + |
| 934 | + out->eax = tdx_set_guest_phys_addr_bits(out->eax, g_maxpa); |
| 935 | + } |
| 936 | + |
| 937 | + (*entry_index)++; |
| 938 | + |
| 939 | + return 0; |
| 940 | + |
| 941 | +err_out: |
| 942 | + out->eax = 0; |
| 943 | + out->ebx = 0; |
| 944 | + out->ecx = 0; |
| 945 | + out->edx = 0; |
| 946 | + |
| 947 | + return -EIO; |
| 948 | +} |
| 949 | + |
852 | 950 | static int tdx_td_init(struct kvm *kvm, struct kvm_tdx_cmd *cmd)
|
853 | 951 | {
|
854 | 952 | struct kvm_tdx *kvm_tdx = to_kvm_tdx(kvm);
|
@@ -1043,6 +1141,96 @@ static int tdx_td_vcpu_init(struct kvm_vcpu *vcpu, u64 vcpu_rcx)
|
1043 | 1141 | return ret;
|
1044 | 1142 | }
|
1045 | 1143 |
|
| 1144 | +/* Sometimes reads multipple subleafs. Return how many enties were written. */ |
| 1145 | +static int tdx_vcpu_get_cpuid_leaf(struct kvm_vcpu *vcpu, u32 leaf, int *entry_index, |
| 1146 | + struct kvm_cpuid_entry2 *output_e) |
| 1147 | +{ |
| 1148 | + int sub_leaf = 0; |
| 1149 | + int ret; |
| 1150 | + |
| 1151 | + /* First try without a subleaf */ |
| 1152 | + ret = tdx_read_cpuid(vcpu, leaf, 0, false, entry_index, output_e); |
| 1153 | + |
| 1154 | + /* If success, or invalid leaf, just give up */ |
| 1155 | + if (ret != -EIO) |
| 1156 | + return ret; |
| 1157 | + |
| 1158 | + /* |
| 1159 | + * If the try without a subleaf failed, try reading subleafs until |
| 1160 | + * failure. The TDX module only supports 6 bits of subleaf index. |
| 1161 | + */ |
| 1162 | + while (1) { |
| 1163 | + /* Keep reading subleafs until there is a failure. */ |
| 1164 | + if (tdx_read_cpuid(vcpu, leaf, sub_leaf, true, entry_index, output_e)) |
| 1165 | + return !sub_leaf; |
| 1166 | + |
| 1167 | + sub_leaf++; |
| 1168 | + output_e++; |
| 1169 | + } |
| 1170 | + |
| 1171 | + return 0; |
| 1172 | +} |
| 1173 | + |
| 1174 | +static int tdx_vcpu_get_cpuid(struct kvm_vcpu *vcpu, struct kvm_tdx_cmd *cmd) |
| 1175 | +{ |
| 1176 | + struct kvm_cpuid2 __user *output, *td_cpuid; |
| 1177 | + int r = 0, i = 0, leaf; |
| 1178 | + u32 level; |
| 1179 | + |
| 1180 | + output = u64_to_user_ptr(cmd->data); |
| 1181 | + td_cpuid = kzalloc(sizeof(*td_cpuid) + |
| 1182 | + sizeof(output->entries[0]) * KVM_MAX_CPUID_ENTRIES, |
| 1183 | + GFP_KERNEL); |
| 1184 | + if (!td_cpuid) |
| 1185 | + return -ENOMEM; |
| 1186 | + |
| 1187 | + if (copy_from_user(td_cpuid, output, sizeof(*output))) { |
| 1188 | + r = -EFAULT; |
| 1189 | + goto out; |
| 1190 | + } |
| 1191 | + |
| 1192 | + /* Read max CPUID for normal range */ |
| 1193 | + if (tdx_vcpu_get_cpuid_leaf(vcpu, 0, &i, &td_cpuid->entries[i])) { |
| 1194 | + r = -EIO; |
| 1195 | + goto out; |
| 1196 | + } |
| 1197 | + level = td_cpuid->entries[0].eax; |
| 1198 | + |
| 1199 | + for (leaf = 1; leaf <= level; leaf++) |
| 1200 | + tdx_vcpu_get_cpuid_leaf(vcpu, leaf, &i, &td_cpuid->entries[i]); |
| 1201 | + |
| 1202 | + /* Read max CPUID for extended range */ |
| 1203 | + if (tdx_vcpu_get_cpuid_leaf(vcpu, 0x80000000, &i, &td_cpuid->entries[i])) { |
| 1204 | + r = -EIO; |
| 1205 | + goto out; |
| 1206 | + } |
| 1207 | + level = td_cpuid->entries[i - 1].eax; |
| 1208 | + |
| 1209 | + for (leaf = 0x80000001; leaf <= level; leaf++) |
| 1210 | + tdx_vcpu_get_cpuid_leaf(vcpu, leaf, &i, &td_cpuid->entries[i]); |
| 1211 | + |
| 1212 | + if (td_cpuid->nent < i) |
| 1213 | + r = -E2BIG; |
| 1214 | + td_cpuid->nent = i; |
| 1215 | + |
| 1216 | + if (copy_to_user(output, td_cpuid, sizeof(*output))) { |
| 1217 | + r = -EFAULT; |
| 1218 | + goto out; |
| 1219 | + } |
| 1220 | + |
| 1221 | + if (r == -E2BIG) |
| 1222 | + goto out; |
| 1223 | + |
| 1224 | + if (copy_to_user(output->entries, td_cpuid->entries, |
| 1225 | + td_cpuid->nent * sizeof(struct kvm_cpuid_entry2))) |
| 1226 | + r = -EFAULT; |
| 1227 | + |
| 1228 | +out: |
| 1229 | + kfree(td_cpuid); |
| 1230 | + |
| 1231 | + return r; |
| 1232 | +} |
| 1233 | + |
1046 | 1234 | static int tdx_vcpu_init(struct kvm_vcpu *vcpu, struct kvm_tdx_cmd *cmd)
|
1047 | 1235 | {
|
1048 | 1236 | u64 apic_base;
|
@@ -1092,6 +1280,9 @@ int tdx_vcpu_ioctl(struct kvm_vcpu *vcpu, void __user *argp)
|
1092 | 1280 | case KVM_TDX_INIT_VCPU:
|
1093 | 1281 | ret = tdx_vcpu_init(vcpu, &cmd);
|
1094 | 1282 | break;
|
| 1283 | + case KVM_TDX_GET_CPUID: |
| 1284 | + ret = tdx_vcpu_get_cpuid(vcpu, &cmd); |
| 1285 | + break; |
1095 | 1286 | default:
|
1096 | 1287 | ret = -EINVAL;
|
1097 | 1288 | break;
|
|
0 commit comments