History

crypto: ccp - Add new HV-Fixed page allocation/free API

When SEV-SNP is active, the TEE extended command header page and all output buffers for TEE extended commands (such as used by Seamless Firmware servicing support) must be in hypervisor-fixed state, assigned to the hypervisor and marked immutable in the RMP entrie(s). Add a new generic SEV API interface to allocate/free hypervisor fixed pages which abstracts hypervisor fixed page allocation/free for PSP sub devices. The API internally uses SNP_INIT_EX to transition pages to HV-Fixed page state. If SNP is not enabled then the allocator is simply a wrapper over alloc_pages() and __free_pages(). When the sub device free the pages, they are put on a free list and future allocation requests will try to re-use the freed pages from this list. But this list is not preserved across PSP driver load/unload hence this free/reuse support is only supported while PSP driver is loaded. As HV_FIXED page state is only changed at reboot, these pages are leaked as they cannot be returned back to the page allocator and then potentially allocated to guests, which will cause SEV-SNP guests to fail to start or terminate when accessing the HV_FIXED page.

Ashish Kalra committed 1 year ago

Commit e09701d1 parent e4c00c42 files · +185 −0Browse files

Unified · Split

2 files
  1. drivers/crypto/ccp/sev-dev.c +182 −0
  2. drivers/crypto/ccp/sev-dev.h +3 −0
drivers/crypto/ccp/sev-dev.c+182−0
@@ -82,6 +82,21 @@ MODULE_FIRMWARE("amd/amd_sev_fam19h_model1xh.sbin"); /* 4th gen EPYC */ · 81 unmodified lines
82static bool psp_dead;82static bool psp_dead;
83static int psp_timeout;83static int psp_timeout;
84 84
85enum snp_hv_fixed_pages_state {
86 ALLOCATED,
87 HV_FIXED,
88};
89
90struct snp_hv_fixed_pages_entry {
91 struct list_head list;
92 struct page *page;
93 unsigned int order;
94 bool free;
95 enum snp_hv_fixed_pages_state page_state;
96};
97
98static LIST_HEAD(snp_hv_fixed_pages);
99
85/* Trusted Memory Region (TMR):100/* Trusted Memory Region (TMR):
86 * The TMR is a 1MB area that must be 1MB aligned. Use the page allocator101 * The TMR is a 1MB area that must be 1MB aligned. Use the page allocator
87 * to allocate the memory, which will return aligned memory for the specified102 * to allocate the memory, which will return aligned memory for the specified
@@ -1073,6 +1088,165 @@ static void snp_set_hsave_pa(void *arg) · 985 unmodified lines
1073 wrmsrq(MSR_VM_HSAVE_PA, 0);1088 wrmsrq(MSR_VM_HSAVE_PA, 0);
1074}1089}
1075 1090
1091/* Hypervisor Fixed pages API interface */
1092static void snp_hv_fixed_pages_state_update(struct sev_device *sev,
1093 enum snp_hv_fixed_pages_state page_state)
1094{
1095 struct snp_hv_fixed_pages_entry *entry;
1096
1097 /* List is protected by sev_cmd_mutex */
1098 lockdep_assert_held(&sev_cmd_mutex);
1099
1100 if (list_empty(&snp_hv_fixed_pages))
1101 return;
1102
1103 list_for_each_entry(entry, &snp_hv_fixed_pages, list)
1104 entry->page_state = page_state;
1105}
1106
1107/*
1108 * Allocate HV_FIXED pages in 2MB aligned sizes to ensure the whole
1109 * 2MB pages are marked as HV_FIXED.
1110 */
1111struct page *snp_alloc_hv_fixed_pages(unsigned int num_2mb_pages)
1112{
1113 struct psp_device *psp_master = psp_get_master_device();
1114 struct snp_hv_fixed_pages_entry *entry;
1115 struct sev_device *sev;
1116 unsigned int order;
1117 struct page *page;
1118
1119 if (!psp_master || !psp_master->sev_data)
1120 return NULL;
1121
1122 sev = psp_master->sev_data;
1123
1124 order = get_order(PMD_SIZE * num_2mb_pages);
1125
1126 /*
1127 * SNP_INIT_EX is protected by sev_cmd_mutex, therefore this list
1128 * also needs to be protected using the same mutex.
1129 */
1130 guard(mutex)(&sev_cmd_mutex);
1131
1132 /*
1133 * This API uses SNP_INIT_EX to transition allocated pages to HV_Fixed
1134 * page state, fail if SNP is already initialized.
1135 */
1136 if (sev->snp_initialized)
1137 return NULL;
1138
1139 /* Re-use freed pages that match the request */
1140 list_for_each_entry(entry, &snp_hv_fixed_pages, list) {
1141 /* Hypervisor fixed page allocator implements exact fit policy */
1142 if (entry->order == order && entry->free) {
1143 entry->free = false;
1144 memset(page_address(entry->page), 0,
1145 (1 << entry->order) * PAGE_SIZE);
1146 return entry->page;
1147 }
1148 }
1149
1150 page = alloc_pages(GFP_KERNEL | __GFP_ZERO, order);
1151 if (!page)
1152 return NULL;
1153
1154 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
1155 if (!entry) {
1156 __free_pages(page, order);
1157 return NULL;
1158 }
1159
1160 entry->page = page;
1161 entry->order = order;
1162 list_add_tail(&entry->list, &snp_hv_fixed_pages);
1163
1164 return page;
1165}
1166
1167void snp_free_hv_fixed_pages(struct page *page)
1168{
1169 struct psp_device *psp_master = psp_get_master_device();
1170 struct snp_hv_fixed_pages_entry *entry, *nentry;
1171
1172 if (!psp_master || !psp_master->sev_data)
1173 return;
1174
1175 /*
1176 * SNP_INIT_EX is protected by sev_cmd_mutex, therefore this list
1177 * also needs to be protected using the same mutex.
1178 */
1179 guard(mutex)(&sev_cmd_mutex);
1180
1181 list_for_each_entry_safe(entry, nentry, &snp_hv_fixed_pages, list) {
1182 if (entry->page != page)
1183 continue;
1184
1185 /*
1186 * HV_FIXED page state cannot be changed until reboot
1187 * and they cannot be used by an SNP guest, so they cannot
1188 * be returned back to the page allocator.
1189 * Mark the pages as free internally to allow possible re-use.
1190 */
1191 if (entry->page_state == HV_FIXED) {
1192 entry->free = true;
1193 } else {
1194 __free_pages(page, entry->order);
1195 list_del(&entry->list);
1196 kfree(entry);
1197 }
1198 return;
1199 }
1200}
1201
1202static void snp_add_hv_fixed_pages(struct sev_device *sev, struct sev_data_range_list *range_list)
1203{
1204 struct snp_hv_fixed_pages_entry *entry;
1205 struct sev_data_range *range;
1206 int num_elements;
1207
1208 lockdep_assert_held(&sev_cmd_mutex);
1209
1210 if (list_empty(&snp_hv_fixed_pages))
1211 return;
1212
1213 num_elements = list_count_nodes(&snp_hv_fixed_pages) +
1214 range_list->num_elements;
1215
1216 /*
1217 * Ensure the list of HV_FIXED pages that will be passed to firmware
1218 * do not exceed the page-sized argument buffer.
1219 */
1220 if (num_elements * sizeof(*range) + sizeof(*range_list) > PAGE_SIZE) {
1221 dev_warn(sev->dev, "Additional HV_Fixed pages cannot be accommodated, omitting\n");
1222 return;
1223 }
1224
1225 range = &range_list->ranges[range_list->num_elements];
1226 list_for_each_entry(entry, &snp_hv_fixed_pages, list) {
1227 range->base = page_to_pfn(entry->page) << PAGE_SHIFT;
1228 range->page_count = 1 << entry->order;
1229 range++;
1230 }
1231 range_list->num_elements = num_elements;
1232}
1233
1234static void snp_leak_hv_fixed_pages(void)
1235{
1236 struct snp_hv_fixed_pages_entry *entry;
1237
1238 /* List is protected by sev_cmd_mutex */
1239 lockdep_assert_held(&sev_cmd_mutex);
1240
1241 if (list_empty(&snp_hv_fixed_pages))
1242 return;
1243
1244 list_for_each_entry(entry, &snp_hv_fixed_pages, list)
1245 if (entry->page_state == HV_FIXED)
1246 __snp_leak_pages(page_to_pfn(entry->page),
1247 1 << entry->order, false);
1248}
1249
1076static int snp_filter_reserved_mem_regions(struct resource *rs, void *arg)1250static int snp_filter_reserved_mem_regions(struct resource *rs, void *arg)
1077{1251{
1078 struct sev_data_range_list *range_list = arg;1252 struct sev_data_range_list *range_list = arg;
@@ -1163,6 +1337,12 @@ static int __sev_snp_init_locked(int *error) · 84 unmodified lines
1163 return rc;1337 return rc;
1164 }1338 }
1165 1339
1340 /*
1341 * Add HV_Fixed pages from other PSP sub-devices, such as SFS to the
1342 * HV_Fixed page list.
1343 */
1344 snp_add_hv_fixed_pages(sev, snp_range_list);
1345
1166 memset(&data, 0, sizeof(data));1346 memset(&data, 0, sizeof(data));
1167 data.init_rmp = 1;1347 data.init_rmp = 1;
1168 data.list_paddr_en = 1;1348 data.list_paddr_en = 1;
@@ -1202,6 +1382,7 @@ static int __sev_snp_init_locked(int *error) · 33 unmodified lines
1202 return rc;1382 return rc;
1203 }1383 }
1204 1384
1385 snp_hv_fixed_pages_state_update(sev, HV_FIXED);
1205 sev->snp_initialized = true;1386 sev->snp_initialized = true;
1206 dev_dbg(sev->dev, "SEV-SNP firmware initialized\n");1387 dev_dbg(sev->dev, "SEV-SNP firmware initialized\n");
1207 1388
@@ -1784,6 +1965,7 @@ static int __sev_snp_shutdown_locked(int *error, bool panic) · 576 unmodified lines
1784 return ret;1965 return ret;
1785 }1966 }
1786 1967
1968 snp_leak_hv_fixed_pages();
1787 sev->snp_initialized = false;1969 sev->snp_initialized = false;
1788 dev_dbg(sev->dev, "SEV-SNP firmware shutdown\n");1970 dev_dbg(sev->dev, "SEV-SNP firmware shutdown\n");
1789 1971
drivers/crypto/ccp/sev-dev.h+3−0
@@ -65,4 +65,7 @@ void sev_dev_destroy(struct psp_device *psp); · 64 unmodified lines
65void sev_pci_init(void);65void sev_pci_init(void);
66void sev_pci_exit(void);66void sev_pci_exit(void);
67 67
68struct page *snp_alloc_hv_fixed_pages(unsigned int num_2mb_pages);
69void snp_free_hv_fixed_pages(struct page *page);
70
68#endif /* __SEV_DEV_H */71#endif /* __SEV_DEV_H */