30
30
#include <asm/smp.h>
31
31
#include <asm/cacheflush.h>
32
32
#include <asm/e820/types.h>
33
+ #include <asm/sev.h>
33
34
34
35
#include "psp-dev.h"
35
36
#include "sev-dev.h"
@@ -73,9 +74,14 @@ static int psp_timeout;
73
74
* The TMR is a 1MB area that must be 1MB aligned. Use the page allocator
74
75
* to allocate the memory, which will return aligned memory for the specified
75
76
* allocation order.
77
+ *
78
+ * When SEV-SNP is enabled the TMR needs to be 2MB aligned and 2MB sized.
76
79
*/
77
- #define SEV_ES_TMR_SIZE (1024 * 1024)
80
+ #define SEV_TMR_SIZE (1024 * 1024)
81
+ #define SNP_TMR_SIZE (2 * 1024 * 1024)
82
+
78
83
static void * sev_es_tmr ;
84
+ static size_t sev_es_tmr_size = SEV_TMR_SIZE ;
79
85
80
86
/* INIT_EX NV Storage:
81
87
* The NV Storage is a 32Kb area and must be 4Kb page aligned. Use the page
@@ -192,17 +198,6 @@ static int sev_cmd_buffer_len(int cmd)
192
198
return 0 ;
193
199
}
194
200
195
- static void * sev_fw_alloc (unsigned long len )
196
- {
197
- struct page * page ;
198
-
199
- page = alloc_pages (GFP_KERNEL , get_order (len ));
200
- if (!page )
201
- return NULL ;
202
-
203
- return page_address (page );
204
- }
205
-
206
201
static struct file * open_file_as_root (const char * filename , int flags , umode_t mode )
207
202
{
208
203
struct file * fp ;
@@ -333,6 +328,142 @@ static int sev_write_init_ex_file_if_required(int cmd_id)
333
328
return sev_write_init_ex_file ();
334
329
}
335
330
331
+ /*
332
+ * snp_reclaim_pages() needs __sev_do_cmd_locked(), and __sev_do_cmd_locked()
333
+ * needs snp_reclaim_pages(), so a forward declaration is needed.
334
+ */
335
+ static int __sev_do_cmd_locked (int cmd , void * data , int * psp_ret );
336
+
337
+ static int snp_reclaim_pages (unsigned long paddr , unsigned int npages , bool locked )
338
+ {
339
+ int ret , err , i ;
340
+
341
+ paddr = __sme_clr (ALIGN_DOWN (paddr , PAGE_SIZE ));
342
+
343
+ for (i = 0 ; i < npages ; i ++ , paddr += PAGE_SIZE ) {
344
+ struct sev_data_snp_page_reclaim data = {0 };
345
+
346
+ data .paddr = paddr ;
347
+
348
+ if (locked )
349
+ ret = __sev_do_cmd_locked (SEV_CMD_SNP_PAGE_RECLAIM , & data , & err );
350
+ else
351
+ ret = sev_do_cmd (SEV_CMD_SNP_PAGE_RECLAIM , & data , & err );
352
+
353
+ if (ret )
354
+ goto cleanup ;
355
+
356
+ ret = rmp_make_shared (__phys_to_pfn (paddr ), PG_LEVEL_4K );
357
+ if (ret )
358
+ goto cleanup ;
359
+ }
360
+
361
+ return 0 ;
362
+
363
+ cleanup :
364
+ /*
365
+ * If there was a failure reclaiming the page then it is no longer safe
366
+ * to release it back to the system; leak it instead.
367
+ */
368
+ snp_leak_pages (__phys_to_pfn (paddr ), npages - i );
369
+ return ret ;
370
+ }
371
+
372
+ static int rmp_mark_pages_firmware (unsigned long paddr , unsigned int npages , bool locked )
373
+ {
374
+ unsigned long pfn = __sme_clr (paddr ) >> PAGE_SHIFT ;
375
+ int rc , i ;
376
+
377
+ for (i = 0 ; i < npages ; i ++ , pfn ++ ) {
378
+ rc = rmp_make_private (pfn , 0 , PG_LEVEL_4K , 0 , true);
379
+ if (rc )
380
+ goto cleanup ;
381
+ }
382
+
383
+ return 0 ;
384
+
385
+ cleanup :
386
+ /*
387
+ * Try unrolling the firmware state changes by
388
+ * reclaiming the pages which were already changed to the
389
+ * firmware state.
390
+ */
391
+ snp_reclaim_pages (paddr , i , locked );
392
+
393
+ return rc ;
394
+ }
395
+
396
+ static struct page * __snp_alloc_firmware_pages (gfp_t gfp_mask , int order )
397
+ {
398
+ unsigned long npages = 1ul << order , paddr ;
399
+ struct sev_device * sev ;
400
+ struct page * page ;
401
+
402
+ if (!psp_master || !psp_master -> sev_data )
403
+ return NULL ;
404
+
405
+ page = alloc_pages (gfp_mask , order );
406
+ if (!page )
407
+ return NULL ;
408
+
409
+ /* If SEV-SNP is initialized then add the page in RMP table. */
410
+ sev = psp_master -> sev_data ;
411
+ if (!sev -> snp_initialized )
412
+ return page ;
413
+
414
+ paddr = __pa ((unsigned long )page_address (page ));
415
+ if (rmp_mark_pages_firmware (paddr , npages , false))
416
+ return NULL ;
417
+
418
+ return page ;
419
+ }
420
+
421
+ void * snp_alloc_firmware_page (gfp_t gfp_mask )
422
+ {
423
+ struct page * page ;
424
+
425
+ page = __snp_alloc_firmware_pages (gfp_mask , 0 );
426
+
427
+ return page ? page_address (page ) : NULL ;
428
+ }
429
+ EXPORT_SYMBOL_GPL (snp_alloc_firmware_page );
430
+
431
+ static void __snp_free_firmware_pages (struct page * page , int order , bool locked )
432
+ {
433
+ struct sev_device * sev = psp_master -> sev_data ;
434
+ unsigned long paddr , npages = 1ul << order ;
435
+
436
+ if (!page )
437
+ return ;
438
+
439
+ paddr = __pa ((unsigned long )page_address (page ));
440
+ if (sev -> snp_initialized &&
441
+ snp_reclaim_pages (paddr , npages , locked ))
442
+ return ;
443
+
444
+ __free_pages (page , order );
445
+ }
446
+
447
+ void snp_free_firmware_page (void * addr )
448
+ {
449
+ if (!addr )
450
+ return ;
451
+
452
+ __snp_free_firmware_pages (virt_to_page (addr ), 0 , false);
453
+ }
454
+ EXPORT_SYMBOL_GPL (snp_free_firmware_page );
455
+
456
+ static void * sev_fw_alloc (unsigned long len )
457
+ {
458
+ struct page * page ;
459
+
460
+ page = __snp_alloc_firmware_pages (GFP_KERNEL , get_order (len ));
461
+ if (!page )
462
+ return NULL ;
463
+
464
+ return page_address (page );
465
+ }
466
+
336
467
static int __sev_do_cmd_locked (int cmd , void * data , int * psp_ret )
337
468
{
338
469
struct psp_device * psp = psp_master ;
@@ -456,7 +587,7 @@ static int __sev_init_locked(int *error)
456
587
data .tmr_address = __pa (sev_es_tmr );
457
588
458
589
data .flags |= SEV_INIT_FLAGS_SEV_ES ;
459
- data .tmr_len = SEV_ES_TMR_SIZE ;
590
+ data .tmr_len = sev_es_tmr_size ;
460
591
}
461
592
462
593
return __sev_do_cmd_locked (SEV_CMD_INIT , & data , error );
@@ -479,7 +610,7 @@ static int __sev_init_ex_locked(int *error)
479
610
data .tmr_address = __pa (sev_es_tmr );
480
611
481
612
data .flags |= SEV_INIT_FLAGS_SEV_ES ;
482
- data .tmr_len = SEV_ES_TMR_SIZE ;
613
+ data .tmr_len = sev_es_tmr_size ;
483
614
}
484
615
485
616
return __sev_do_cmd_locked (SEV_CMD_INIT_EX , & data , error );
@@ -623,9 +754,27 @@ static int __sev_snp_init_locked(int *error)
623
754
sev -> snp_initialized = true;
624
755
dev_dbg (sev -> dev , "SEV-SNP firmware initialized\n" );
625
756
757
+ sev_es_tmr_size = SNP_TMR_SIZE ;
758
+
626
759
return rc ;
627
760
}
628
761
762
+ static void __sev_platform_init_handle_tmr (struct sev_device * sev )
763
+ {
764
+ if (sev_es_tmr )
765
+ return ;
766
+
767
+ /* Obtain the TMR memory area for SEV-ES use */
768
+ sev_es_tmr = sev_fw_alloc (sev_es_tmr_size );
769
+ if (sev_es_tmr ) {
770
+ /* Must flush the cache before giving it to the firmware */
771
+ if (!sev -> snp_initialized )
772
+ clflush_cache_range (sev_es_tmr , sev_es_tmr_size );
773
+ } else {
774
+ dev_warn (sev -> dev , "SEV: TMR allocation failed, SEV-ES support unavailable\n" );
775
+ }
776
+ }
777
+
629
778
static int __sev_platform_init_locked (int * error )
630
779
{
631
780
int rc , psp_ret = SEV_RET_NO_FW_CALL ;
@@ -639,16 +788,7 @@ static int __sev_platform_init_locked(int *error)
639
788
if (sev -> state == SEV_STATE_INIT )
640
789
return 0 ;
641
790
642
- if (!sev_es_tmr ) {
643
- /* Obtain the TMR memory area for SEV-ES use */
644
- sev_es_tmr = sev_fw_alloc (SEV_ES_TMR_SIZE );
645
- if (sev_es_tmr )
646
- /* Must flush the cache before giving it to the firmware */
647
- clflush_cache_range (sev_es_tmr , SEV_ES_TMR_SIZE );
648
- else
649
- dev_warn (sev -> dev ,
650
- "SEV: TMR allocation failed, SEV-ES support unavailable\n" );
651
- }
791
+ __sev_platform_init_handle_tmr (sev );
652
792
653
793
if (sev_init_ex_buffer ) {
654
794
rc = sev_read_init_ex_file ();
@@ -1546,8 +1686,9 @@ static void sev_firmware_shutdown(struct sev_device *sev)
1546
1686
/* The TMR area was encrypted, flush it from the cache */
1547
1687
wbinvd_on_all_cpus ();
1548
1688
1549
- free_pages ((unsigned long )sev_es_tmr ,
1550
- get_order (SEV_ES_TMR_SIZE ));
1689
+ __snp_free_firmware_pages (virt_to_page (sev_es_tmr ),
1690
+ get_order (sev_es_tmr_size ),
1691
+ false);
1551
1692
sev_es_tmr = NULL ;
1552
1693
}
1553
1694
0 commit comments