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
8282 static bool psp_dead;
8383 static int psp_timeout;
8484
85+enum snp_hv_fixed_pages_state {
86+ ALLOCATED,
87+ HV_FIXED,
88+};
89+
90+struct 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+
98+static LIST_HEAD(snp_hv_fixed_pages);
99+
85100 /* Trusted Memory Region (TMR):
86101 * The TMR is a 1MB area that must be 1MB aligned. Use the page allocator
87102 * 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
10731088 wrmsrq(MSR_VM_HSAVE_PA, 0);
10741089 }
10751090
1091+/* Hypervisor Fixed pages API interface */
1092+static 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+ */
1111+struct 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+
1167+void 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+
1202+static 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+
1234+static 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+
10761250 static int snp_filter_reserved_mem_regions(struct resource *rs, void *arg)
10771251 {
10781252 struct sev_data_range_list *range_list = arg;
@@ -1163,6 +1337,12 @@ static int __sev_snp_init_locked(int *error) · 84 unmodified lines
11631337 return rc;
11641338 }
11651339
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+
11661346 memset(&data, 0, sizeof(data));
11671347 data.init_rmp = 1;
11681348 data.list_paddr_en = 1;
@@ -1202,6 +1382,7 @@ static int __sev_snp_init_locked(int *error) · 33 unmodified lines
12021382 return rc;
12031383 }
12041384
1385+ snp_hv_fixed_pages_state_update(sev, HV_FIXED);
12051386 sev->snp_initialized = true;
12061387 dev_dbg(sev->dev, "SEV-SNP firmware initialized\n");
12071388
@@ -1784,6 +1965,7 @@ static int __sev_snp_shutdown_locked(int *error, bool panic) · 576 unmodified lines
17841965 return ret;
17851966 }
17861967
1968+ snp_leak_hv_fixed_pages();
17871969 sev->snp_initialized = false;
17881970 dev_dbg(sev->dev, "SEV-SNP firmware shutdown\n");
17891971
drivers/crypto/ccp/sev-dev.h+3−0
@@ -65,4 +65,7 @@ void sev_dev_destroy(struct psp_device *psp); · 64 unmodified lines
6565 void sev_pci_init(void);
6666 void sev_pci_exit(void);
6767
68+struct page *snp_alloc_hv_fixed_pages(unsigned int num_2mb_pages);
69+void snp_free_hv_fixed_pages(struct page *page);
70+
6871 #endif /* __SEV_DEV_H */