+ //\r
+ // Obtain the size of the memory map\r
+ //\r
+ MemMapSize = 0;\r
+ MemMap = NULL;\r
+ Status = gBS->GetMemoryMap (&MemMapSize, MemMap, &MapKey, &DescriptorSize,\r
+ &DescriptorVersion);\r
+ ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
+\r
+ //\r
+ // Add some slack to the allocation to cater for changes in the memory\r
+ // map if ExitBootServices () fails the first time around.\r
+ //\r
+ MemMapSize += SIZE_4KB;\r
+ Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData,\r
+ EFI_SIZE_TO_PAGES (MemMapSize), &Alloc);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ MemMap = (EFI_MEMORY_DESCRIPTOR *)(UINTN)Alloc;\r
+\r
+ Status = gBS->GetMemoryMap (&MemMapSize, MemMap, &MapKey, &DescriptorSize,\r
+ &DescriptorVersion);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ Status = gBS->ExitBootServices (gImageHandle, MapKey);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // ExitBootServices () may fail the first time around if an event fired\r
+ // right after the call to GetMemoryMap() which allocated or freed memory.\r
+ // Since that first call to ExitBootServices () will disarm the timer,\r
+ // this is guaranteed not to happen again, so one additional attempt\r
+ // should suffice.\r
+ //\r
+ Status = gBS->GetMemoryMap (&MemMapSize, MemMap, &MapKey, &DescriptorSize,\r
+ &DescriptorVersion);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ Status = gBS->ExitBootServices (gImageHandle, MapKey);\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+\r
+ DisableMmuAndReenterPei ();\r