Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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.

Suggested-by: Thomas Lendacky <Thomas.Lendacky@amd.com>
Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Reviewed-by: Tom Lendacky <thomas.lendacky@amd.com>
Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
Link: https://lore.kernel.org/cover.1758057691.git.ashish.kalra@amd.com

authored by

Ashish Kalra and committed by
Borislav Petkov (AMD)
e09701dc e4c00c4c

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