1 /** @file
2 
3   Virtual Memory Management Services to set or clear the memory encryption bit
4 
5   Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
6   Copyright (c) 2017 - 2020, AMD Incorporated. All rights reserved.<BR>
7 
8   SPDX-License-Identifier: BSD-2-Clause-Patent
9 
10   Code is derived from MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
11 
12 **/
13 
14 #include <Library/CpuLib.h>
15 #include <Library/MemEncryptSevLib.h>
16 #include <Register/Amd/Cpuid.h>
17 #include <Register/Cpuid.h>
18 
19 #include "VirtualMemory.h"
20 
21 STATIC BOOLEAN mAddressEncMaskChecked = FALSE;
22 STATIC UINT64  mAddressEncMask;
23 STATIC PAGE_TABLE_POOL   *mPageTablePool = NULL;
24 
25 typedef enum {
26    SetCBit,
27    ClearCBit
28 } MAP_RANGE_MODE;
29 
30 /**
31   Return the pagetable memory encryption mask.
32 
33   @return  The pagetable memory encryption mask.
34 
35 **/
36 UINT64
37 EFIAPI
InternalGetMemEncryptionAddressMask(VOID)38 InternalGetMemEncryptionAddressMask (
39   VOID
40   )
41 {
42   UINT64                            EncryptionMask;
43 
44   if (mAddressEncMaskChecked) {
45     return mAddressEncMask;
46   }
47 
48   EncryptionMask = MemEncryptSevGetEncryptionMask ();
49 
50   mAddressEncMask = EncryptionMask & PAGING_1G_ADDRESS_MASK_64;
51   mAddressEncMaskChecked = TRUE;
52 
53   return mAddressEncMask;
54 }
55 
56 /**
57   Initialize a buffer pool for page table use only.
58 
59   To reduce the potential split operation on page table, the pages reserved for
60   page table should be allocated in the times of PAGE_TABLE_POOL_UNIT_PAGES and
61   at the boundary of PAGE_TABLE_POOL_ALIGNMENT. So the page pool is always
62   initialized with number of pages greater than or equal to the given
63   PoolPages.
64 
65   Once the pages in the pool are used up, this method should be called again to
66   reserve at least another PAGE_TABLE_POOL_UNIT_PAGES. Usually this won't
67   happen often in practice.
68 
69   @param[in] PoolPages      The least page number of the pool to be created.
70 
71   @retval TRUE    The pool is initialized successfully.
72   @retval FALSE   The memory is out of resource.
73 **/
74 STATIC
75 BOOLEAN
InitializePageTablePool(IN UINTN PoolPages)76 InitializePageTablePool (
77   IN  UINTN                           PoolPages
78   )
79 {
80   VOID                      *Buffer;
81 
82   //
83   // Always reserve at least PAGE_TABLE_POOL_UNIT_PAGES, including one page for
84   // header.
85   //
86   PoolPages += 1;   // Add one page for header.
87   PoolPages = ((PoolPages - 1) / PAGE_TABLE_POOL_UNIT_PAGES + 1) *
88               PAGE_TABLE_POOL_UNIT_PAGES;
89   Buffer = AllocateAlignedPages (PoolPages, PAGE_TABLE_POOL_ALIGNMENT);
90   if (Buffer == NULL) {
91     DEBUG ((DEBUG_ERROR, "ERROR: Out of aligned pages\r\n"));
92     return FALSE;
93   }
94 
95   //
96   // Link all pools into a list for easier track later.
97   //
98   if (mPageTablePool == NULL) {
99     mPageTablePool = Buffer;
100     mPageTablePool->NextPool = mPageTablePool;
101   } else {
102     ((PAGE_TABLE_POOL *)Buffer)->NextPool = mPageTablePool->NextPool;
103     mPageTablePool->NextPool = Buffer;
104     mPageTablePool = Buffer;
105   }
106 
107   //
108   // Reserve one page for pool header.
109   //
110   mPageTablePool->FreePages  = PoolPages - 1;
111   mPageTablePool->Offset = EFI_PAGES_TO_SIZE (1);
112 
113   return TRUE;
114 }
115 
116 /**
117   This API provides a way to allocate memory for page table.
118 
119   This API can be called more than once to allocate memory for page tables.
120 
121   Allocates the number of 4KB pages and returns a pointer to the allocated
122   buffer. The buffer returned is aligned on a 4KB boundary.
123 
124   If Pages is 0, then NULL is returned.
125   If there is not enough memory remaining to satisfy the request, then NULL is
126   returned.
127 
128   @param  Pages                 The number of 4 KB pages to allocate.
129 
130   @return A pointer to the allocated buffer or NULL if allocation fails.
131 
132 **/
133 STATIC
134 VOID *
135 EFIAPI
AllocatePageTableMemory(IN UINTN Pages)136 AllocatePageTableMemory (
137   IN UINTN           Pages
138   )
139 {
140   VOID                            *Buffer;
141 
142   if (Pages == 0) {
143     return NULL;
144   }
145 
146   //
147   // Renew the pool if necessary.
148   //
149   if (mPageTablePool == NULL ||
150       Pages > mPageTablePool->FreePages) {
151     if (!InitializePageTablePool (Pages)) {
152       return NULL;
153     }
154   }
155 
156   Buffer = (UINT8 *)mPageTablePool + mPageTablePool->Offset;
157 
158   mPageTablePool->Offset     += EFI_PAGES_TO_SIZE (Pages);
159   mPageTablePool->FreePages  -= Pages;
160 
161   DEBUG ((
162     DEBUG_VERBOSE,
163     "%a:%a: Buffer=0x%Lx Pages=%ld\n",
164     gEfiCallerBaseName,
165     __FUNCTION__,
166     Buffer,
167     Pages
168     ));
169 
170   return Buffer;
171 }
172 
173 
174 /**
175   Split 2M page to 4K.
176 
177   @param[in]      PhysicalAddress       Start physical address the 2M page
178                                         covered.
179   @param[in, out] PageEntry2M           Pointer to 2M page entry.
180   @param[in]      StackBase             Stack base address.
181   @param[in]      StackSize             Stack size.
182 
183 **/
184 STATIC
185 VOID
Split2MPageTo4K(IN PHYSICAL_ADDRESS PhysicalAddress,IN OUT UINT64 * PageEntry2M,IN PHYSICAL_ADDRESS StackBase,IN UINTN StackSize)186 Split2MPageTo4K (
187   IN        PHYSICAL_ADDRESS               PhysicalAddress,
188   IN  OUT   UINT64                        *PageEntry2M,
189   IN        PHYSICAL_ADDRESS               StackBase,
190   IN        UINTN                          StackSize
191   )
192 {
193   PHYSICAL_ADDRESS                  PhysicalAddress4K;
194   UINTN                             IndexOfPageTableEntries;
195   PAGE_TABLE_4K_ENTRY               *PageTableEntry;
196   PAGE_TABLE_4K_ENTRY               *PageTableEntry1;
197   UINT64                            AddressEncMask;
198 
199   PageTableEntry = AllocatePageTableMemory(1);
200 
201   PageTableEntry1 = PageTableEntry;
202 
203   AddressEncMask = InternalGetMemEncryptionAddressMask ();
204 
205   ASSERT (PageTableEntry != NULL);
206   ASSERT (*PageEntry2M & AddressEncMask);
207 
208   PhysicalAddress4K = PhysicalAddress;
209   for (IndexOfPageTableEntries = 0;
210        IndexOfPageTableEntries < 512;
211        (IndexOfPageTableEntries++,
212         PageTableEntry++,
213         PhysicalAddress4K += SIZE_4KB)) {
214     //
215     // Fill in the Page Table entries
216     //
217     PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K | AddressEncMask;
218     PageTableEntry->Bits.ReadWrite = 1;
219     PageTableEntry->Bits.Present = 1;
220     if ((PhysicalAddress4K >= StackBase) &&
221         (PhysicalAddress4K < StackBase + StackSize)) {
222       //
223       // Set Nx bit for stack.
224       //
225       PageTableEntry->Bits.Nx = 1;
226     }
227   }
228 
229   //
230   // Fill in 2M page entry.
231   //
232   *PageEntry2M = ((UINT64)(UINTN)PageTableEntry1 |
233                   IA32_PG_P | IA32_PG_RW | AddressEncMask);
234 }
235 
236 /**
237   Set one page of page table pool memory to be read-only.
238 
239   @param[in] PageTableBase    Base address of page table (CR3).
240   @param[in] Address          Start address of a page to be set as read-only.
241   @param[in] Level4Paging     Level 4 paging flag.
242 
243 **/
244 STATIC
245 VOID
SetPageTablePoolReadOnly(IN UINTN PageTableBase,IN EFI_PHYSICAL_ADDRESS Address,IN BOOLEAN Level4Paging)246 SetPageTablePoolReadOnly (
247   IN  UINTN                             PageTableBase,
248   IN  EFI_PHYSICAL_ADDRESS              Address,
249   IN  BOOLEAN                           Level4Paging
250   )
251 {
252   UINTN                 Index;
253   UINTN                 EntryIndex;
254   UINT64                AddressEncMask;
255   EFI_PHYSICAL_ADDRESS  PhysicalAddress;
256   UINT64                *PageTable;
257   UINT64                *NewPageTable;
258   UINT64                PageAttr;
259   UINT64                LevelSize[5];
260   UINT64                LevelMask[5];
261   UINTN                 LevelShift[5];
262   UINTN                 Level;
263   UINT64                PoolUnitSize;
264 
265   ASSERT (PageTableBase != 0);
266 
267   //
268   // Since the page table is always from page table pool, which is always
269   // located at the boundary of PcdPageTablePoolAlignment, we just need to
270   // set the whole pool unit to be read-only.
271   //
272   Address = Address & PAGE_TABLE_POOL_ALIGN_MASK;
273 
274   LevelShift[1] = PAGING_L1_ADDRESS_SHIFT;
275   LevelShift[2] = PAGING_L2_ADDRESS_SHIFT;
276   LevelShift[3] = PAGING_L3_ADDRESS_SHIFT;
277   LevelShift[4] = PAGING_L4_ADDRESS_SHIFT;
278 
279   LevelMask[1] = PAGING_4K_ADDRESS_MASK_64;
280   LevelMask[2] = PAGING_2M_ADDRESS_MASK_64;
281   LevelMask[3] = PAGING_1G_ADDRESS_MASK_64;
282   LevelMask[4] = PAGING_1G_ADDRESS_MASK_64;
283 
284   LevelSize[1] = SIZE_4KB;
285   LevelSize[2] = SIZE_2MB;
286   LevelSize[3] = SIZE_1GB;
287   LevelSize[4] = SIZE_512GB;
288 
289   AddressEncMask  = InternalGetMemEncryptionAddressMask();
290   PageTable       = (UINT64 *)(UINTN)PageTableBase;
291   PoolUnitSize    = PAGE_TABLE_POOL_UNIT_SIZE;
292 
293   for (Level = (Level4Paging) ? 4 : 3; Level > 0; --Level) {
294     Index = ((UINTN)RShiftU64 (Address, LevelShift[Level]));
295     Index &= PAGING_PAE_INDEX_MASK;
296 
297     PageAttr = PageTable[Index];
298     if ((PageAttr & IA32_PG_PS) == 0) {
299       //
300       // Go to next level of table.
301       //
302       PageTable = (UINT64 *)(UINTN)(PageAttr & ~AddressEncMask &
303                                     PAGING_4K_ADDRESS_MASK_64);
304       continue;
305     }
306 
307     if (PoolUnitSize >= LevelSize[Level]) {
308       //
309       // Clear R/W bit if current page granularity is not larger than pool unit
310       // size.
311       //
312       if ((PageAttr & IA32_PG_RW) != 0) {
313         while (PoolUnitSize > 0) {
314           //
315           // PAGE_TABLE_POOL_UNIT_SIZE and PAGE_TABLE_POOL_ALIGNMENT are fit in
316           // one page (2MB). Then we don't need to update attributes for pages
317           // crossing page directory. ASSERT below is for that purpose.
318           //
319           ASSERT (Index < EFI_PAGE_SIZE/sizeof (UINT64));
320 
321           PageTable[Index] &= ~(UINT64)IA32_PG_RW;
322           PoolUnitSize    -= LevelSize[Level];
323 
324           ++Index;
325         }
326       }
327 
328       break;
329 
330     } else {
331       //
332       // The smaller granularity of page must be needed.
333       //
334       ASSERT (Level > 1);
335 
336       NewPageTable = AllocatePageTableMemory (1);
337       ASSERT (NewPageTable != NULL);
338 
339       PhysicalAddress = PageAttr & LevelMask[Level];
340       for (EntryIndex = 0;
341             EntryIndex < EFI_PAGE_SIZE/sizeof (UINT64);
342             ++EntryIndex) {
343         NewPageTable[EntryIndex] = PhysicalAddress  | AddressEncMask |
344                                    IA32_PG_P | IA32_PG_RW;
345         if (Level > 2) {
346           NewPageTable[EntryIndex] |= IA32_PG_PS;
347         }
348         PhysicalAddress += LevelSize[Level - 1];
349       }
350 
351       PageTable[Index] = (UINT64)(UINTN)NewPageTable | AddressEncMask |
352                                         IA32_PG_P | IA32_PG_RW;
353       PageTable = NewPageTable;
354     }
355   }
356 }
357 
358 /**
359   Prevent the memory pages used for page table from been overwritten.
360 
361   @param[in] PageTableBase    Base address of page table (CR3).
362   @param[in] Level4Paging     Level 4 paging flag.
363 
364 **/
365 STATIC
366 VOID
EnablePageTableProtection(IN UINTN PageTableBase,IN BOOLEAN Level4Paging)367 EnablePageTableProtection (
368   IN  UINTN     PageTableBase,
369   IN  BOOLEAN   Level4Paging
370   )
371 {
372   PAGE_TABLE_POOL         *HeadPool;
373   PAGE_TABLE_POOL         *Pool;
374   UINT64                  PoolSize;
375   EFI_PHYSICAL_ADDRESS    Address;
376 
377   if (mPageTablePool == NULL) {
378     return;
379   }
380 
381   //
382   // SetPageTablePoolReadOnly might update mPageTablePool. It's safer to
383   // remember original one in advance.
384   //
385   HeadPool = mPageTablePool;
386   Pool = HeadPool;
387   do {
388     Address  = (EFI_PHYSICAL_ADDRESS)(UINTN)Pool;
389     PoolSize = Pool->Offset + EFI_PAGES_TO_SIZE (Pool->FreePages);
390 
391     //
392     // The size of one pool must be multiple of PAGE_TABLE_POOL_UNIT_SIZE,
393     // which is one of page size of the processor (2MB by default). Let's apply
394     // the protection to them one by one.
395     //
396     while (PoolSize > 0) {
397       SetPageTablePoolReadOnly(PageTableBase, Address, Level4Paging);
398       Address   += PAGE_TABLE_POOL_UNIT_SIZE;
399       PoolSize  -= PAGE_TABLE_POOL_UNIT_SIZE;
400     }
401 
402     Pool = Pool->NextPool;
403   } while (Pool != HeadPool);
404 
405 }
406 
407 
408 /**
409   Split 1G page to 2M.
410 
411   @param[in]      PhysicalAddress       Start physical address the 1G page
412                                         covered.
413   @param[in, out] PageEntry1G           Pointer to 1G page entry.
414   @param[in]      StackBase             Stack base address.
415   @param[in]      StackSize             Stack size.
416 
417 **/
418 STATIC
419 VOID
Split1GPageTo2M(IN PHYSICAL_ADDRESS PhysicalAddress,IN OUT UINT64 * PageEntry1G,IN PHYSICAL_ADDRESS StackBase,IN UINTN StackSize)420 Split1GPageTo2M (
421   IN          PHYSICAL_ADDRESS               PhysicalAddress,
422   IN  OUT     UINT64                         *PageEntry1G,
423   IN          PHYSICAL_ADDRESS               StackBase,
424   IN          UINTN                          StackSize
425   )
426 {
427   PHYSICAL_ADDRESS                  PhysicalAddress2M;
428   UINTN                             IndexOfPageDirectoryEntries;
429   PAGE_TABLE_ENTRY                  *PageDirectoryEntry;
430   UINT64                            AddressEncMask;
431 
432   PageDirectoryEntry = AllocatePageTableMemory(1);
433 
434   AddressEncMask = InternalGetMemEncryptionAddressMask ();
435   ASSERT (PageDirectoryEntry != NULL);
436   ASSERT (*PageEntry1G & AddressEncMask);
437   //
438   // Fill in 1G page entry.
439   //
440   *PageEntry1G = ((UINT64)(UINTN)PageDirectoryEntry |
441                   IA32_PG_P | IA32_PG_RW | AddressEncMask);
442 
443   PhysicalAddress2M = PhysicalAddress;
444   for (IndexOfPageDirectoryEntries = 0;
445        IndexOfPageDirectoryEntries < 512;
446        (IndexOfPageDirectoryEntries++,
447         PageDirectoryEntry++,
448         PhysicalAddress2M += SIZE_2MB)) {
449     if ((PhysicalAddress2M < StackBase + StackSize) &&
450         ((PhysicalAddress2M + SIZE_2MB) > StackBase)) {
451       //
452       // Need to split this 2M page that covers stack range.
453       //
454       Split2MPageTo4K (
455         PhysicalAddress2M,
456         (UINT64 *)PageDirectoryEntry,
457         StackBase,
458         StackSize
459         );
460     } else {
461       //
462       // Fill in the Page Directory entries
463       //
464       PageDirectoryEntry->Uint64 = (UINT64) PhysicalAddress2M | AddressEncMask;
465       PageDirectoryEntry->Bits.ReadWrite = 1;
466       PageDirectoryEntry->Bits.Present = 1;
467       PageDirectoryEntry->Bits.MustBe1 = 1;
468     }
469   }
470 }
471 
472 
473 /**
474   Set or Clear the memory encryption bit
475 
476   @param[in, out] PageTablePointer      Page table entry pointer (PTE).
477   @param[in]      Mode                  Set or Clear encryption bit
478 
479 **/
480 STATIC VOID
SetOrClearCBit(IN OUT UINT64 * PageTablePointer,IN MAP_RANGE_MODE Mode)481 SetOrClearCBit(
482   IN   OUT     UINT64*            PageTablePointer,
483   IN           MAP_RANGE_MODE     Mode
484   )
485 {
486   UINT64      AddressEncMask;
487 
488   AddressEncMask = InternalGetMemEncryptionAddressMask ();
489 
490   if (Mode == SetCBit) {
491     *PageTablePointer |= AddressEncMask;
492   } else {
493     *PageTablePointer &= ~AddressEncMask;
494   }
495 
496 }
497 
498 /**
499  Check the WP status in CR0 register. This bit is used to lock or unlock write
500  access to pages marked as read-only.
501 
502   @retval TRUE    Write protection is enabled.
503   @retval FALSE   Write protection is disabled.
504 **/
505 STATIC
506 BOOLEAN
IsReadOnlyPageWriteProtected(VOID)507 IsReadOnlyPageWriteProtected (
508   VOID
509   )
510 {
511   return ((AsmReadCr0 () & BIT16) != 0);
512 }
513 
514 
515 /**
516  Disable Write Protect on pages marked as read-only.
517 **/
518 STATIC
519 VOID
DisableReadOnlyPageWriteProtect(VOID)520 DisableReadOnlyPageWriteProtect (
521   VOID
522   )
523 {
524   AsmWriteCr0 (AsmReadCr0() & ~BIT16);
525 }
526 
527 /**
528  Enable Write Protect on pages marked as read-only.
529 **/
530 STATIC
531 VOID
EnableReadOnlyPageWriteProtect(VOID)532 EnableReadOnlyPageWriteProtect (
533   VOID
534   )
535 {
536   AsmWriteCr0 (AsmReadCr0() | BIT16);
537 }
538 
539 
540 /**
541   This function either sets or clears memory encryption bit for the memory
542   region specified by PhysicalAddress and Length from the current page table
543   context.
544 
545   The function iterates through the PhysicalAddress one page at a time, and set
546   or clears the memory encryption mask in the page table. If it encounters
547   that a given physical address range is part of large page then it attempts to
548   change the attribute at one go (based on size), otherwise it splits the
549   large pages into smaller (e.g 2M page into 4K pages) and then try to set or
550   clear the encryption bit on the smallest page size.
551 
552   @param[in]  Cr3BaseAddress          Cr3 Base Address (if zero then use
553                                       current CR3)
554   @param[in]  PhysicalAddress         The physical address that is the start
555                                       address of a memory region.
556   @param[in]  Length                  The length of memory region
557   @param[in]  Mode                    Set or Clear mode
558   @param[in]  CacheFlush              Flush the caches before applying the
559                                       encryption mask
560 
561   @retval RETURN_SUCCESS              The attributes were cleared for the
562                                       memory region.
563   @retval RETURN_INVALID_PARAMETER    Number of pages is zero.
564   @retval RETURN_UNSUPPORTED          Setting the memory encyrption attribute
565                                       is not supported
566 **/
567 STATIC
568 RETURN_STATUS
569 EFIAPI
SetMemoryEncDec(IN PHYSICAL_ADDRESS Cr3BaseAddress,IN PHYSICAL_ADDRESS PhysicalAddress,IN UINTN Length,IN MAP_RANGE_MODE Mode,IN BOOLEAN CacheFlush)570 SetMemoryEncDec (
571   IN    PHYSICAL_ADDRESS         Cr3BaseAddress,
572   IN    PHYSICAL_ADDRESS         PhysicalAddress,
573   IN    UINTN                    Length,
574   IN    MAP_RANGE_MODE           Mode,
575   IN    BOOLEAN                  CacheFlush
576   )
577 {
578   PAGE_MAP_AND_DIRECTORY_POINTER *PageMapLevel4Entry;
579   PAGE_MAP_AND_DIRECTORY_POINTER *PageUpperDirectoryPointerEntry;
580   PAGE_MAP_AND_DIRECTORY_POINTER *PageDirectoryPointerEntry;
581   PAGE_TABLE_1G_ENTRY            *PageDirectory1GEntry;
582   PAGE_TABLE_ENTRY               *PageDirectory2MEntry;
583   PAGE_TABLE_4K_ENTRY            *PageTableEntry;
584   UINT64                         PgTableMask;
585   UINT64                         AddressEncMask;
586   BOOLEAN                        IsWpEnabled;
587   RETURN_STATUS                  Status;
588 
589   //
590   // Set PageMapLevel4Entry to suppress incorrect compiler/analyzer warnings.
591   //
592   PageMapLevel4Entry = NULL;
593 
594   DEBUG ((
595     DEBUG_VERBOSE,
596     "%a:%a: Cr3Base=0x%Lx Physical=0x%Lx Length=0x%Lx Mode=%a CacheFlush=%u\n",
597     gEfiCallerBaseName,
598     __FUNCTION__,
599     Cr3BaseAddress,
600     PhysicalAddress,
601     (UINT64)Length,
602     (Mode == SetCBit) ? "Encrypt" : "Decrypt",
603     (UINT32)CacheFlush
604     ));
605 
606   //
607   // Check if we have a valid memory encryption mask
608   //
609   AddressEncMask = InternalGetMemEncryptionAddressMask ();
610   if (!AddressEncMask) {
611     return RETURN_ACCESS_DENIED;
612   }
613 
614   PgTableMask = AddressEncMask | EFI_PAGE_MASK;
615 
616   if (Length == 0) {
617     return RETURN_INVALID_PARAMETER;
618   }
619 
620   //
621   // We are going to change the memory encryption attribute from C=0 -> C=1 or
622   // vice versa Flush the caches to ensure that data is written into memory
623   // with correct C-bit
624   //
625   if (CacheFlush) {
626     WriteBackInvalidateDataCacheRange((VOID*) (UINTN)PhysicalAddress, Length);
627   }
628 
629   //
630   // Make sure that the page table is changeable.
631   //
632   IsWpEnabled = IsReadOnlyPageWriteProtected ();
633   if (IsWpEnabled) {
634     DisableReadOnlyPageWriteProtect ();
635   }
636 
637   Status = EFI_SUCCESS;
638 
639   while (Length != 0)
640   {
641     //
642     // If Cr3BaseAddress is not specified then read the current CR3
643     //
644     if (Cr3BaseAddress == 0) {
645       Cr3BaseAddress = AsmReadCr3();
646     }
647 
648     PageMapLevel4Entry = (VOID*) (Cr3BaseAddress & ~PgTableMask);
649     PageMapLevel4Entry += PML4_OFFSET(PhysicalAddress);
650     if (!PageMapLevel4Entry->Bits.Present) {
651       DEBUG ((
652         DEBUG_ERROR,
653         "%a:%a: bad PML4 for Physical=0x%Lx\n",
654         gEfiCallerBaseName,
655         __FUNCTION__,
656         PhysicalAddress
657         ));
658       Status = RETURN_NO_MAPPING;
659       goto Done;
660     }
661 
662     PageDirectory1GEntry = (VOID *)(
663                              (PageMapLevel4Entry->Bits.PageTableBaseAddress <<
664                               12) & ~PgTableMask
665                              );
666     PageDirectory1GEntry += PDP_OFFSET(PhysicalAddress);
667     if (!PageDirectory1GEntry->Bits.Present) {
668       DEBUG ((
669         DEBUG_ERROR,
670         "%a:%a: bad PDPE for Physical=0x%Lx\n",
671         gEfiCallerBaseName,
672         __FUNCTION__,
673         PhysicalAddress
674         ));
675       Status = RETURN_NO_MAPPING;
676       goto Done;
677     }
678 
679     //
680     // If the MustBe1 bit is not 1, it's not actually a 1GB entry
681     //
682     if (PageDirectory1GEntry->Bits.MustBe1) {
683       //
684       // Valid 1GB page
685       // If we have at least 1GB to go, we can just update this entry
686       //
687       if ((PhysicalAddress & (BIT30 - 1)) == 0 && Length >= BIT30) {
688         SetOrClearCBit(&PageDirectory1GEntry->Uint64, Mode);
689         DEBUG ((
690           DEBUG_VERBOSE,
691           "%a:%a: updated 1GB entry for Physical=0x%Lx\n",
692           gEfiCallerBaseName,
693           __FUNCTION__,
694           PhysicalAddress
695           ));
696         PhysicalAddress += BIT30;
697         Length -= BIT30;
698       } else {
699         //
700         // We must split the page
701         //
702         DEBUG ((
703           DEBUG_VERBOSE,
704           "%a:%a: splitting 1GB page for Physical=0x%Lx\n",
705           gEfiCallerBaseName,
706           __FUNCTION__,
707           PhysicalAddress
708           ));
709         Split1GPageTo2M (
710           (UINT64)PageDirectory1GEntry->Bits.PageTableBaseAddress << 30,
711           (UINT64 *)PageDirectory1GEntry,
712           0,
713           0
714           );
715         continue;
716       }
717     } else {
718       //
719       // Actually a PDP
720       //
721       PageUpperDirectoryPointerEntry =
722         (PAGE_MAP_AND_DIRECTORY_POINTER *)PageDirectory1GEntry;
723       PageDirectory2MEntry =
724         (VOID *)(
725           (PageUpperDirectoryPointerEntry->Bits.PageTableBaseAddress <<
726            12) & ~PgTableMask
727           );
728       PageDirectory2MEntry += PDE_OFFSET(PhysicalAddress);
729       if (!PageDirectory2MEntry->Bits.Present) {
730         DEBUG ((
731           DEBUG_ERROR,
732           "%a:%a: bad PDE for Physical=0x%Lx\n",
733           gEfiCallerBaseName,
734           __FUNCTION__,
735           PhysicalAddress
736           ));
737         Status = RETURN_NO_MAPPING;
738         goto Done;
739       }
740       //
741       // If the MustBe1 bit is not a 1, it's not a 2MB entry
742       //
743       if (PageDirectory2MEntry->Bits.MustBe1) {
744         //
745         // Valid 2MB page
746         // If we have at least 2MB left to go, we can just update this entry
747         //
748         if ((PhysicalAddress & (BIT21-1)) == 0 && Length >= BIT21) {
749           SetOrClearCBit (&PageDirectory2MEntry->Uint64, Mode);
750           PhysicalAddress += BIT21;
751           Length -= BIT21;
752         } else {
753           //
754           // We must split up this page into 4K pages
755           //
756           DEBUG ((
757             DEBUG_VERBOSE,
758             "%a:%a: splitting 2MB page for Physical=0x%Lx\n",
759             gEfiCallerBaseName,
760             __FUNCTION__,
761             PhysicalAddress
762             ));
763           Split2MPageTo4K (
764             (UINT64)PageDirectory2MEntry->Bits.PageTableBaseAddress << 21,
765             (UINT64 *)PageDirectory2MEntry,
766             0,
767             0
768             );
769           continue;
770         }
771       } else {
772         PageDirectoryPointerEntry =
773           (PAGE_MAP_AND_DIRECTORY_POINTER *)PageDirectory2MEntry;
774         PageTableEntry =
775           (VOID *)(
776             (PageDirectoryPointerEntry->Bits.PageTableBaseAddress <<
777              12) & ~PgTableMask
778             );
779         PageTableEntry += PTE_OFFSET(PhysicalAddress);
780         if (!PageTableEntry->Bits.Present) {
781           DEBUG ((
782             DEBUG_ERROR,
783             "%a:%a: bad PTE for Physical=0x%Lx\n",
784             gEfiCallerBaseName,
785             __FUNCTION__,
786             PhysicalAddress
787             ));
788           Status = RETURN_NO_MAPPING;
789           goto Done;
790         }
791         SetOrClearCBit (&PageTableEntry->Uint64, Mode);
792         PhysicalAddress += EFI_PAGE_SIZE;
793         Length -= EFI_PAGE_SIZE;
794       }
795     }
796   }
797 
798   //
799   // Protect the page table by marking the memory used for page table to be
800   // read-only.
801   //
802   if (IsWpEnabled) {
803     EnablePageTableProtection ((UINTN)PageMapLevel4Entry, TRUE);
804   }
805 
806   //
807   // Flush TLB
808   //
809   CpuFlushTlb();
810 
811 Done:
812   //
813   // Restore page table write protection, if any.
814   //
815   if (IsWpEnabled) {
816     EnableReadOnlyPageWriteProtect ();
817   }
818 
819   return Status;
820 }
821 
822 /**
823   This function clears memory encryption bit for the memory region specified by
824   PhysicalAddress and Length from the current page table context.
825 
826   @param[in]  Cr3BaseAddress          Cr3 Base Address (if zero then use
827                                       current CR3)
828   @param[in]  PhysicalAddress         The physical address that is the start
829                                       address of a memory region.
830   @param[in]  Length                  The length of memory region
831   @param[in]  Flush                   Flush the caches before applying the
832                                       encryption mask
833 
834   @retval RETURN_SUCCESS              The attributes were cleared for the
835                                       memory region.
836   @retval RETURN_INVALID_PARAMETER    Number of pages is zero.
837   @retval RETURN_UNSUPPORTED          Clearing the memory encyrption attribute
838                                       is not supported
839 **/
840 RETURN_STATUS
841 EFIAPI
InternalMemEncryptSevSetMemoryDecrypted(IN PHYSICAL_ADDRESS Cr3BaseAddress,IN PHYSICAL_ADDRESS PhysicalAddress,IN UINTN Length,IN BOOLEAN Flush)842 InternalMemEncryptSevSetMemoryDecrypted (
843   IN  PHYSICAL_ADDRESS        Cr3BaseAddress,
844   IN  PHYSICAL_ADDRESS        PhysicalAddress,
845   IN  UINTN                   Length,
846   IN  BOOLEAN                 Flush
847   )
848 {
849 
850   return SetMemoryEncDec (
851            Cr3BaseAddress,
852            PhysicalAddress,
853            Length,
854            ClearCBit,
855            Flush
856            );
857 }
858 
859 /**
860   This function sets memory encryption bit for the memory region specified by
861   PhysicalAddress and Length from the current page table context.
862 
863   @param[in]  Cr3BaseAddress          Cr3 Base Address (if zero then use
864                                       current CR3)
865   @param[in]  PhysicalAddress         The physical address that is the start
866                                       address of a memory region.
867   @param[in]  Length                  The length of memory region
868   @param[in]  Flush                   Flush the caches before applying the
869                                       encryption mask
870 
871   @retval RETURN_SUCCESS              The attributes were set for the memory
872                                       region.
873   @retval RETURN_INVALID_PARAMETER    Number of pages is zero.
874   @retval RETURN_UNSUPPORTED          Setting the memory encyrption attribute
875                                       is not supported
876 **/
877 RETURN_STATUS
878 EFIAPI
InternalMemEncryptSevSetMemoryEncrypted(IN PHYSICAL_ADDRESS Cr3BaseAddress,IN PHYSICAL_ADDRESS PhysicalAddress,IN UINTN Length,IN BOOLEAN Flush)879 InternalMemEncryptSevSetMemoryEncrypted (
880   IN  PHYSICAL_ADDRESS        Cr3BaseAddress,
881   IN  PHYSICAL_ADDRESS        PhysicalAddress,
882   IN  UINTN                   Length,
883   IN  BOOLEAN                 Flush
884   )
885 {
886   return SetMemoryEncDec (
887            Cr3BaseAddress,
888            PhysicalAddress,
889            Length,
890            SetCBit,
891            Flush
892            );
893 }
894