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

Configure Feed

Select the types of activity you want to include in your feed.

Drivers: hv: Allocate the paravisor SynIC pages when required

Confidential VMBus requires interacting with two SynICs -- one
provided by the host hypervisor, and one provided by the paravisor.
Each SynIC requires its own message and event pages.

Refactor and extend the existing code to add allocating and freeing
the message and event pages for the paravisor SynIC when it is
present.

Signed-off-by: Roman Kisel <romank@linux.microsoft.com>
Reviewed-by: Tianyu Lan <tiala@microsoft.com>
Reviewed-by: Michael Kelley <mhklinux@outlook.com>
Signed-off-by: Wei Liu <wei.liu@kernel.org>

authored by

Roman Kisel and committed by
Wei Liu
226494e5 163224c1

+112 -90
+94 -90
drivers/hv/hv.c
··· 96 96 return hv_result(status); 97 97 } 98 98 99 + static int hv_alloc_page(void **page, bool decrypt, const char *note) 100 + { 101 + int ret = 0; 102 + 103 + /* 104 + * After the page changes its encryption status, its contents might 105 + * appear scrambled on some hardware. Thus `get_zeroed_page` would 106 + * zero the page out in vain, so do that explicitly exactly once. 107 + * 108 + * By default, the page is allocated encrypted in a CoCo VM. 109 + */ 110 + *page = (void *)__get_free_page(GFP_KERNEL); 111 + if (!*page) 112 + return -ENOMEM; 113 + 114 + if (decrypt) 115 + ret = set_memory_decrypted((unsigned long)*page, 1); 116 + if (ret) 117 + goto failed; 118 + 119 + memset(*page, 0, PAGE_SIZE); 120 + return 0; 121 + 122 + failed: 123 + /* 124 + * Report the failure but don't put the page back on the free list as 125 + * its encryption status is unknown. 126 + */ 127 + pr_err("allocation failed for %s page, error %d, decrypted %d\n", 128 + note, ret, decrypt); 129 + *page = NULL; 130 + return ret; 131 + } 132 + 133 + static int hv_free_page(void **page, bool encrypt, const char *note) 134 + { 135 + int ret = 0; 136 + 137 + if (!*page) 138 + return 0; 139 + 140 + if (encrypt) 141 + ret = set_memory_encrypted((unsigned long)*page, 1); 142 + 143 + /* 144 + * In the case of the failure, the page is leaked. Something is wrong, 145 + * prefer to lose the page with the unknown encryption status and stay afloat. 146 + */ 147 + if (ret) 148 + pr_err("deallocation failed for %s page, error %d, encrypt %d\n", 149 + note, ret, encrypt); 150 + else 151 + free_page((unsigned long)*page); 152 + 153 + *page = NULL; 154 + 155 + return ret; 156 + } 157 + 99 158 int hv_synic_alloc(void) 100 159 { 101 160 int cpu, ret = -ENOMEM; 102 161 struct hv_per_cpu_context *hv_cpu; 162 + const bool decrypt = !vmbus_is_confidential(); 103 163 104 164 /* 105 165 * First, zero all per-cpu memory areas so hv_synic_free() can ··· 185 125 vmbus_on_msg_dpc, (unsigned long)hv_cpu); 186 126 187 127 if (ms_hyperv.paravisor_present && hv_isolation_type_tdx()) { 188 - hv_cpu->post_msg_page = (void *)get_zeroed_page(GFP_ATOMIC); 189 - if (!hv_cpu->post_msg_page) { 190 - pr_err("Unable to allocate post msg page\n"); 128 + ret = hv_alloc_page(&hv_cpu->post_msg_page, 129 + decrypt, "post msg"); 130 + if (ret) 191 131 goto err; 192 - } 193 - 194 - ret = set_memory_decrypted((unsigned long)hv_cpu->post_msg_page, 1); 195 - if (ret) { 196 - pr_err("Failed to decrypt post msg page: %d\n", ret); 197 - /* Just leak the page, as it's unsafe to free the page. */ 198 - hv_cpu->post_msg_page = NULL; 199 - goto err; 200 - } 201 - 202 - memset(hv_cpu->post_msg_page, 0, PAGE_SIZE); 203 132 } 204 133 205 134 /* 206 - * Synic message and event pages are allocated by paravisor. 207 - * Skip these pages allocation here. 135 + * If these SynIC pages are not allocated, SIEF and SIM pages 136 + * are configured using what the root partition or the paravisor 137 + * provides upon reading the SIEFP and SIMP registers. 208 138 */ 209 139 if (!ms_hyperv.paravisor_present && !hv_root_partition()) { 210 - hv_cpu->hyp_synic_message_page = 211 - (void *)get_zeroed_page(GFP_ATOMIC); 212 - if (!hv_cpu->hyp_synic_message_page) { 213 - pr_err("Unable to allocate SYNIC message page\n"); 140 + ret = hv_alloc_page(&hv_cpu->hyp_synic_message_page, 141 + decrypt, "hypervisor SynIC msg"); 142 + if (ret) 214 143 goto err; 215 - } 216 - 217 - hv_cpu->hyp_synic_event_page = 218 - (void *)get_zeroed_page(GFP_ATOMIC); 219 - if (!hv_cpu->hyp_synic_event_page) { 220 - pr_err("Unable to allocate SYNIC event page\n"); 221 - 222 - free_page((unsigned long)hv_cpu->hyp_synic_message_page); 223 - hv_cpu->hyp_synic_message_page = NULL; 144 + ret = hv_alloc_page(&hv_cpu->hyp_synic_event_page, 145 + decrypt, "hypervisor SynIC event"); 146 + if (ret) 224 147 goto err; 225 - } 226 148 } 227 149 228 - if (!ms_hyperv.paravisor_present && 229 - (hv_isolation_type_snp() || hv_isolation_type_tdx())) { 230 - ret = set_memory_decrypted((unsigned long) 231 - hv_cpu->hyp_synic_message_page, 1); 232 - if (ret) { 233 - pr_err("Failed to decrypt SYNIC msg page: %d\n", ret); 234 - hv_cpu->hyp_synic_message_page = NULL; 235 - 236 - /* 237 - * Free the event page here so that hv_synic_free() 238 - * won't later try to re-encrypt it. 239 - */ 240 - free_page((unsigned long)hv_cpu->hyp_synic_event_page); 241 - hv_cpu->hyp_synic_event_page = NULL; 150 + if (vmbus_is_confidential()) { 151 + ret = hv_alloc_page(&hv_cpu->para_synic_message_page, 152 + false, "paravisor SynIC msg"); 153 + if (ret) 242 154 goto err; 243 - } 244 - 245 - ret = set_memory_decrypted((unsigned long) 246 - hv_cpu->hyp_synic_event_page, 1); 247 - if (ret) { 248 - pr_err("Failed to decrypt SYNIC event page: %d\n", ret); 249 - hv_cpu->hyp_synic_event_page = NULL; 155 + ret = hv_alloc_page(&hv_cpu->para_synic_event_page, 156 + false, "paravisor SynIC event"); 157 + if (ret) 250 158 goto err; 251 - } 252 - 253 - memset(hv_cpu->hyp_synic_message_page, 0, PAGE_SIZE); 254 - memset(hv_cpu->hyp_synic_event_page, 0, PAGE_SIZE); 255 159 } 256 160 } 257 161 ··· 231 207 232 208 void hv_synic_free(void) 233 209 { 234 - int cpu, ret; 210 + int cpu; 211 + const bool encrypt = !vmbus_is_confidential(); 235 212 236 213 for_each_present_cpu(cpu) { 237 214 struct hv_per_cpu_context *hv_cpu = 238 215 per_cpu_ptr(hv_context.cpu_context, cpu); 239 216 240 - /* It's better to leak the page if the encryption fails. */ 241 - if (ms_hyperv.paravisor_present && hv_isolation_type_tdx()) { 242 - if (hv_cpu->post_msg_page) { 243 - ret = set_memory_encrypted((unsigned long) 244 - hv_cpu->post_msg_page, 1); 245 - if (ret) { 246 - pr_err("Failed to encrypt post msg page: %d\n", ret); 247 - hv_cpu->post_msg_page = NULL; 248 - } 249 - } 217 + if (ms_hyperv.paravisor_present && hv_isolation_type_tdx()) 218 + hv_free_page(&hv_cpu->post_msg_page, 219 + encrypt, "post msg"); 220 + if (!ms_hyperv.paravisor_present && !hv_root_partition()) { 221 + hv_free_page(&hv_cpu->hyp_synic_event_page, 222 + encrypt, "hypervisor SynIC event"); 223 + hv_free_page(&hv_cpu->hyp_synic_message_page, 224 + encrypt, "hypervisor SynIC msg"); 250 225 } 251 - 252 - if (!ms_hyperv.paravisor_present && 253 - (hv_isolation_type_snp() || hv_isolation_type_tdx())) { 254 - if (hv_cpu->hyp_synic_message_page) { 255 - ret = set_memory_encrypted((unsigned long) 256 - hv_cpu->hyp_synic_message_page, 1); 257 - if (ret) { 258 - pr_err("Failed to encrypt SYNIC msg page: %d\n", ret); 259 - hv_cpu->hyp_synic_message_page = NULL; 260 - } 261 - } 262 - 263 - if (hv_cpu->hyp_synic_event_page) { 264 - ret = set_memory_encrypted((unsigned long) 265 - hv_cpu->hyp_synic_event_page, 1); 266 - if (ret) { 267 - pr_err("Failed to encrypt SYNIC event page: %d\n", ret); 268 - hv_cpu->hyp_synic_event_page = NULL; 269 - } 270 - } 226 + if (vmbus_is_confidential()) { 227 + hv_free_page(&hv_cpu->para_synic_event_page, 228 + false, "paravisor SynIC event"); 229 + hv_free_page(&hv_cpu->para_synic_message_page, 230 + false, "paravisor SynIC msg"); 271 231 } 272 - 273 - free_page((unsigned long)hv_cpu->post_msg_page); 274 - free_page((unsigned long)hv_cpu->hyp_synic_event_page); 275 - free_page((unsigned long)hv_cpu->hyp_synic_message_page); 276 232 } 277 233 278 234 kfree(hv_context.hv_numa_map);
+18
drivers/hv/hyperv_vmbus.h
··· 121 121 * Per cpu state for channel handling 122 122 */ 123 123 struct hv_per_cpu_context { 124 + /* 125 + * SynIC pages for communicating with the host. 126 + * 127 + * These pages are accessible to the host partition and the hypervisor. 128 + * They may be used for exchanging data with the host partition and the 129 + * hypervisor even when they aren't trusted yet the guest partition 130 + * must be prepared to handle the malicious behavior. 131 + */ 124 132 void *hyp_synic_message_page; 125 133 void *hyp_synic_event_page; 134 + /* 135 + * SynIC pages for communicating with the paravisor. 136 + * 137 + * These pages may be accessed from within the guest partition only in 138 + * CoCo VMs. Neither the host partition nor the hypervisor can access 139 + * these pages in that case; they are used for exchanging data with the 140 + * paravisor. 141 + */ 142 + void *para_synic_message_page; 143 + void *para_synic_event_page; 126 144 127 145 /* 128 146 * The page is only used in hv_post_message() for a TDX VM (with the