Skip to content

Commit 226494e

Browse files
romank-msftliuw
authored andcommitted
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>
1 parent 163224c commit 226494e

2 files changed

Lines changed: 112 additions & 90 deletions

File tree

drivers/hv/hv.c

Lines changed: 94 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,70 @@ int hv_post_message(union hv_connection_id connection_id,
9696
return hv_result(status);
9797
}
9898

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+
99158
int hv_synic_alloc(void)
100159
{
101160
int cpu, ret = -ENOMEM;
102161
struct hv_per_cpu_context *hv_cpu;
162+
const bool decrypt = !vmbus_is_confidential();
103163

104164
/*
105165
* First, zero all per-cpu memory areas so hv_synic_free() can
@@ -125,73 +185,37 @@ int hv_synic_alloc(void)
125185
vmbus_on_msg_dpc, (unsigned long)hv_cpu);
126186

127187
if (ms_hyperv.paravisor_present && hv_isolation_type_tdx()) {
128-
hv_cpu->post_msg_page = (void *)get_zeroed_page(GFP_ATOMIC);
129-
if (!hv_cpu->post_msg_page) {
130-
pr_err("Unable to allocate post msg page\n");
188+
ret = hv_alloc_page(&hv_cpu->post_msg_page,
189+
decrypt, "post msg");
190+
if (ret)
131191
goto err;
132-
}
133-
134-
ret = set_memory_decrypted((unsigned long)hv_cpu->post_msg_page, 1);
135-
if (ret) {
136-
pr_err("Failed to decrypt post msg page: %d\n", ret);
137-
/* Just leak the page, as it's unsafe to free the page. */
138-
hv_cpu->post_msg_page = NULL;
139-
goto err;
140-
}
141-
142-
memset(hv_cpu->post_msg_page, 0, PAGE_SIZE);
143192
}
144193

145194
/*
146-
* Synic message and event pages are allocated by paravisor.
147-
* Skip these pages allocation here.
195+
* If these SynIC pages are not allocated, SIEF and SIM pages
196+
* are configured using what the root partition or the paravisor
197+
* provides upon reading the SIEFP and SIMP registers.
148198
*/
149199
if (!ms_hyperv.paravisor_present && !hv_root_partition()) {
150-
hv_cpu->hyp_synic_message_page =
151-
(void *)get_zeroed_page(GFP_ATOMIC);
152-
if (!hv_cpu->hyp_synic_message_page) {
153-
pr_err("Unable to allocate SYNIC message page\n");
200+
ret = hv_alloc_page(&hv_cpu->hyp_synic_message_page,
201+
decrypt, "hypervisor SynIC msg");
202+
if (ret)
154203
goto err;
155-
}
156-
157-
hv_cpu->hyp_synic_event_page =
158-
(void *)get_zeroed_page(GFP_ATOMIC);
159-
if (!hv_cpu->hyp_synic_event_page) {
160-
pr_err("Unable to allocate SYNIC event page\n");
161-
162-
free_page((unsigned long)hv_cpu->hyp_synic_message_page);
163-
hv_cpu->hyp_synic_message_page = NULL;
204+
ret = hv_alloc_page(&hv_cpu->hyp_synic_event_page,
205+
decrypt, "hypervisor SynIC event");
206+
if (ret)
164207
goto err;
165-
}
166208
}
167209

168-
if (!ms_hyperv.paravisor_present &&
169-
(hv_isolation_type_snp() || hv_isolation_type_tdx())) {
170-
ret = set_memory_decrypted((unsigned long)
171-
hv_cpu->hyp_synic_message_page, 1);
172-
if (ret) {
173-
pr_err("Failed to decrypt SYNIC msg page: %d\n", ret);
174-
hv_cpu->hyp_synic_message_page = NULL;
175-
176-
/*
177-
* Free the event page here so that hv_synic_free()
178-
* won't later try to re-encrypt it.
179-
*/
180-
free_page((unsigned long)hv_cpu->hyp_synic_event_page);
181-
hv_cpu->hyp_synic_event_page = NULL;
210+
if (vmbus_is_confidential()) {
211+
ret = hv_alloc_page(&hv_cpu->para_synic_message_page,
212+
false, "paravisor SynIC msg");
213+
if (ret)
182214
goto err;
183-
}
184-
185-
ret = set_memory_decrypted((unsigned long)
186-
hv_cpu->hyp_synic_event_page, 1);
187-
if (ret) {
188-
pr_err("Failed to decrypt SYNIC event page: %d\n", ret);
189-
hv_cpu->hyp_synic_event_page = NULL;
215+
ret = hv_alloc_page(&hv_cpu->para_synic_event_page,
216+
false, "paravisor SynIC event");
217+
if (ret)
190218
goto err;
191-
}
192-
193-
memset(hv_cpu->hyp_synic_message_page, 0, PAGE_SIZE);
194-
memset(hv_cpu->hyp_synic_event_page, 0, PAGE_SIZE);
195219
}
196220
}
197221

@@ -207,48 +231,28 @@ int hv_synic_alloc(void)
207231

208232
void hv_synic_free(void)
209233
{
210-
int cpu, ret;
234+
int cpu;
235+
const bool encrypt = !vmbus_is_confidential();
211236

212237
for_each_present_cpu(cpu) {
213238
struct hv_per_cpu_context *hv_cpu =
214239
per_cpu_ptr(hv_context.cpu_context, cpu);
215240

216-
/* It's better to leak the page if the encryption fails. */
217-
if (ms_hyperv.paravisor_present && hv_isolation_type_tdx()) {
218-
if (hv_cpu->post_msg_page) {
219-
ret = set_memory_encrypted((unsigned long)
220-
hv_cpu->post_msg_page, 1);
221-
if (ret) {
222-
pr_err("Failed to encrypt post msg page: %d\n", ret);
223-
hv_cpu->post_msg_page = NULL;
224-
}
225-
}
241+
if (ms_hyperv.paravisor_present && hv_isolation_type_tdx())
242+
hv_free_page(&hv_cpu->post_msg_page,
243+
encrypt, "post msg");
244+
if (!ms_hyperv.paravisor_present && !hv_root_partition()) {
245+
hv_free_page(&hv_cpu->hyp_synic_event_page,
246+
encrypt, "hypervisor SynIC event");
247+
hv_free_page(&hv_cpu->hyp_synic_message_page,
248+
encrypt, "hypervisor SynIC msg");
226249
}
227-
228-
if (!ms_hyperv.paravisor_present &&
229-
(hv_isolation_type_snp() || hv_isolation_type_tdx())) {
230-
if (hv_cpu->hyp_synic_message_page) {
231-
ret = set_memory_encrypted((unsigned long)
232-
hv_cpu->hyp_synic_message_page, 1);
233-
if (ret) {
234-
pr_err("Failed to encrypt SYNIC msg page: %d\n", ret);
235-
hv_cpu->hyp_synic_message_page = NULL;
236-
}
237-
}
238-
239-
if (hv_cpu->hyp_synic_event_page) {
240-
ret = set_memory_encrypted((unsigned long)
241-
hv_cpu->hyp_synic_event_page, 1);
242-
if (ret) {
243-
pr_err("Failed to encrypt SYNIC event page: %d\n", ret);
244-
hv_cpu->hyp_synic_event_page = NULL;
245-
}
246-
}
250+
if (vmbus_is_confidential()) {
251+
hv_free_page(&hv_cpu->para_synic_event_page,
252+
false, "paravisor SynIC event");
253+
hv_free_page(&hv_cpu->para_synic_message_page,
254+
false, "paravisor SynIC msg");
247255
}
248-
249-
free_page((unsigned long)hv_cpu->post_msg_page);
250-
free_page((unsigned long)hv_cpu->hyp_synic_event_page);
251-
free_page((unsigned long)hv_cpu->hyp_synic_message_page);
252256
}
253257

254258
kfree(hv_context.hv_numa_map);

drivers/hv/hyperv_vmbus.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,26 @@ enum {
121121
* Per cpu state for channel handling
122122
*/
123123
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+
*/
124132
void *hyp_synic_message_page;
125133
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;
126144

127145
/*
128146
* The page is only used in hv_post_message() for a TDX VM (with the

0 commit comments

Comments
 (0)