3030#include <asm/smp.h>
3131#include <asm/cacheflush.h>
3232#include <asm/e820/types.h>
33+ #include <asm/sev.h>
3334
3435#include "psp-dev.h"
3536#include "sev-dev.h"
@@ -73,9 +74,14 @@ static int psp_timeout;
7374 * The TMR is a 1MB area that must be 1MB aligned. Use the page allocator
7475 * to allocate the memory, which will return aligned memory for the specified
7576 * allocation order.
77+ *
78+ * When SEV-SNP is enabled the TMR needs to be 2MB aligned and 2MB sized.
7679 */
77- #define SEV_ES_TMR_SIZE (1024 * 1024)
80+ #define SEV_TMR_SIZE (1024 * 1024)
81+ #define SNP_TMR_SIZE (2 * 1024 * 1024)
82+
7883static void * sev_es_tmr ;
84+ static size_t sev_es_tmr_size = SEV_TMR_SIZE ;
7985
8086/* INIT_EX NV Storage:
8187 * 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)
192198 return 0 ;
193199}
194200
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-
206201static struct file * open_file_as_root (const char * filename , int flags , umode_t mode )
207202{
208203 struct file * fp ;
@@ -333,6 +328,142 @@ static int sev_write_init_ex_file_if_required(int cmd_id)
333328 return sev_write_init_ex_file ();
334329}
335330
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+
336467static int __sev_do_cmd_locked (int cmd , void * data , int * psp_ret )
337468{
338469 struct psp_device * psp = psp_master ;
@@ -456,7 +587,7 @@ static int __sev_init_locked(int *error)
456587 data .tmr_address = __pa (sev_es_tmr );
457588
458589 data .flags |= SEV_INIT_FLAGS_SEV_ES ;
459- data .tmr_len = SEV_ES_TMR_SIZE ;
590+ data .tmr_len = sev_es_tmr_size ;
460591 }
461592
462593 return __sev_do_cmd_locked (SEV_CMD_INIT , & data , error );
@@ -479,7 +610,7 @@ static int __sev_init_ex_locked(int *error)
479610 data .tmr_address = __pa (sev_es_tmr );
480611
481612 data .flags |= SEV_INIT_FLAGS_SEV_ES ;
482- data .tmr_len = SEV_ES_TMR_SIZE ;
613+ data .tmr_len = sev_es_tmr_size ;
483614 }
484615
485616 return __sev_do_cmd_locked (SEV_CMD_INIT_EX , & data , error );
@@ -623,9 +754,27 @@ static int __sev_snp_init_locked(int *error)
623754 sev -> snp_initialized = true;
624755 dev_dbg (sev -> dev , "SEV-SNP firmware initialized\n" );
625756
757+ sev_es_tmr_size = SNP_TMR_SIZE ;
758+
626759 return rc ;
627760}
628761
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+
629778static int __sev_platform_init_locked (int * error )
630779{
631780 int rc , psp_ret = SEV_RET_NO_FW_CALL ;
@@ -639,16 +788,7 @@ static int __sev_platform_init_locked(int *error)
639788 if (sev -> state == SEV_STATE_INIT )
640789 return 0 ;
641790
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 );
652792
653793 if (sev_init_ex_buffer ) {
654794 rc = sev_read_init_ex_file ();
@@ -1546,8 +1686,9 @@ static void sev_firmware_shutdown(struct sev_device *sev)
15461686 /* The TMR area was encrypted, flush it from the cache */
15471687 wbinvd_on_all_cpus ();
15481688
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);
15511692 sev_es_tmr = NULL ;
15521693 }
15531694
0 commit comments