summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Universal/Disk/PartitionDxe
diff options
context:
space:
mode:
authorkx <kx@radix.pro>2024-06-04 06:43:08 +0300
committerkx <kx@radix.pro>2024-06-04 06:43:08 +0300
commit7e2ccccace24636f29ddc210b94606abd4c7e42b (patch)
tree545d43ea12671048956cafeb12303e84d601e571 /MdeModulePkg/Universal/Disk/PartitionDxe
parent27b044605cd5f6b33a3d231576003850b3fe305b (diff)
downloadedk2-trunk.tar.xz
Renormalized end-of-lines from master@27b044605cd5f6b33a3d231576003850b3fe305btrunk
Diffstat (limited to 'MdeModulePkg/Universal/Disk/PartitionDxe')
-rw-r--r--MdeModulePkg/Universal/Disk/PartitionDxe/ComponentName.c358
-rw-r--r--MdeModulePkg/Universal/Disk/PartitionDxe/ElTorito.c560
-rw-r--r--MdeModulePkg/Universal/Disk/PartitionDxe/Gpt.c1766
-rw-r--r--MdeModulePkg/Universal/Disk/PartitionDxe/Mbr.c738
-rw-r--r--MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c2762
-rw-r--r--MdeModulePkg/Universal/Disk/PartitionDxe/Partition.h966
-rw-r--r--MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf170
-rw-r--r--MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.uni48
-rw-r--r--MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxeExtra.uni28
-rw-r--r--MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c1654
10 files changed, 4525 insertions, 4525 deletions
diff --git a/MdeModulePkg/Universal/Disk/PartitionDxe/ComponentName.c b/MdeModulePkg/Universal/Disk/PartitionDxe/ComponentName.c
index fd27a84b81..26dbf22479 100644
--- a/MdeModulePkg/Universal/Disk/PartitionDxe/ComponentName.c
+++ b/MdeModulePkg/Universal/Disk/PartitionDxe/ComponentName.c
@@ -1,179 +1,179 @@
-/** @file
- UEFI Component Name protocol for Partition driver.
-
-Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "Partition.h"
-
-//
-// EFI Component Name Protocol
-//
-GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gPartitionComponentName = {
- PartitionComponentNameGetDriverName,
- PartitionComponentNameGetControllerName,
- "eng"
-};
-
-//
-// EFI Component Name 2 Protocol
-//
-GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gPartitionComponentName2 = {
- (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)PartitionComponentNameGetDriverName,
- (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)PartitionComponentNameGetControllerName,
- "en"
-};
-
-//
-// Driver name table for Partition module.
-// It is shared by the implementation of ComponentName & ComponentName2 Protocol.
-//
-GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mPartitionDriverNameTable[] = {
- {
- "eng;en",
- L"Partition Driver(MBR/GPT/El Torito)"
- },
- {
- NULL,
- NULL
- }
-};
-
-/**
- Retrieves a Unicode string that is the user readable name of the driver.
-
- This function retrieves the user readable name of a driver in the form of a
- Unicode string. If the driver specified by This has a user readable name in
- the language specified by Language, then a pointer to the driver name is
- returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
- by This does not support the language specified by Language,
- then EFI_UNSUPPORTED is returned.
-
- @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
- EFI_COMPONENT_NAME_PROTOCOL instance.
-
- @param Language[in] A pointer to a Null-terminated ASCII string
- array indicating the language. This is the
- language of the driver name that the caller is
- requesting, and it must match one of the
- languages specified in SupportedLanguages. The
- number of languages supported by a driver is up
- to the driver writer. Language is specified
- in RFC 4646 or ISO 639-2 language code format.
-
- @param DriverName[out] A pointer to the Unicode string to return.
- This Unicode string is the name of the
- driver specified by This in the language
- specified by Language.
-
- @retval EFI_SUCCESS The Unicode string for the Driver specified by
- This and the language specified by Language was
- returned in DriverName.
-
- @retval EFI_INVALID_PARAMETER Language is NULL.
-
- @retval EFI_INVALID_PARAMETER DriverName is NULL.
-
- @retval EFI_UNSUPPORTED The driver specified by This does not support
- the language specified by Language.
-
-**/
-EFI_STATUS
-EFIAPI
-PartitionComponentNameGetDriverName (
- IN EFI_COMPONENT_NAME_PROTOCOL *This,
- IN CHAR8 *Language,
- OUT CHAR16 **DriverName
- )
-{
- return LookupUnicodeString2 (
- Language,
- This->SupportedLanguages,
- mPartitionDriverNameTable,
- DriverName,
- (BOOLEAN)(This == &gPartitionComponentName)
- );
-}
-
-/**
- Retrieves a Unicode string that is the user readable name of the controller
- that is being managed by a driver.
-
- This function retrieves the user readable name of the controller specified by
- ControllerHandle and ChildHandle in the form of a Unicode string. If the
- driver specified by This has a user readable name in the language specified by
- Language, then a pointer to the controller name is returned in ControllerName,
- and EFI_SUCCESS is returned. If the driver specified by This is not currently
- managing the controller specified by ControllerHandle and ChildHandle,
- then EFI_UNSUPPORTED is returned. If the driver specified by This does not
- support the language specified by Language, then EFI_UNSUPPORTED is returned.
-
- @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
- EFI_COMPONENT_NAME_PROTOCOL instance.
-
- @param ControllerHandle[in] The handle of a controller that the driver
- specified by This is managing. This handle
- specifies the controller whose name is to be
- returned.
-
- @param ChildHandle[in] The handle of the child controller to retrieve
- the name of. This is an optional parameter that
- may be NULL. It will be NULL for device
- drivers. It will also be NULL for a bus drivers
- that wish to retrieve the name of the bus
- controller. It will not be NULL for a bus
- driver that wishes to retrieve the name of a
- child controller.
-
- @param Language[in] A pointer to a Null-terminated ASCII string
- array indicating the language. This is the
- language of the driver name that the caller is
- requesting, and it must match one of the
- languages specified in SupportedLanguages. The
- number of languages supported by a driver is up
- to the driver writer. Language is specified in
- RFC 4646 or ISO 639-2 language code format.
-
- @param ControllerName[out] A pointer to the Unicode string to return.
- This Unicode string is the name of the
- controller specified by ControllerHandle and
- ChildHandle in the language specified by
- Language from the point of view of the driver
- specified by This.
-
- @retval EFI_SUCCESS The Unicode string for the user readable name in
- the language specified by Language for the
- driver specified by This was returned in
- DriverName.
-
- @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
-
- @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
- EFI_HANDLE.
-
- @retval EFI_INVALID_PARAMETER Language is NULL.
-
- @retval EFI_INVALID_PARAMETER ControllerName is NULL.
-
- @retval EFI_UNSUPPORTED The driver specified by This is not currently
- managing the controller specified by
- ControllerHandle and ChildHandle.
-
- @retval EFI_UNSUPPORTED The driver specified by This does not support
- the language specified by Language.
-
-**/
-EFI_STATUS
-EFIAPI
-PartitionComponentNameGetControllerName (
- IN EFI_COMPONENT_NAME_PROTOCOL *This,
- IN EFI_HANDLE ControllerHandle,
- IN EFI_HANDLE ChildHandle OPTIONAL,
- IN CHAR8 *Language,
- OUT CHAR16 **ControllerName
- )
-{
- return EFI_UNSUPPORTED;
-}
+/** @file
+ UEFI Component Name protocol for Partition driver.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Partition.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gPartitionComponentName = {
+ PartitionComponentNameGetDriverName,
+ PartitionComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gPartitionComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)PartitionComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)PartitionComponentNameGetControllerName,
+ "en"
+};
+
+//
+// Driver name table for Partition module.
+// It is shared by the implementation of ComponentName & ComponentName2 Protocol.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mPartitionDriverNameTable[] = {
+ {
+ "eng;en",
+ L"Partition Driver(MBR/GPT/El Torito)"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mPartitionDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gPartitionComponentName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/MdeModulePkg/Universal/Disk/PartitionDxe/ElTorito.c b/MdeModulePkg/Universal/Disk/PartitionDxe/ElTorito.c
index 977ded851e..4ea6d1cb6a 100644
--- a/MdeModulePkg/Universal/Disk/PartitionDxe/ElTorito.c
+++ b/MdeModulePkg/Universal/Disk/PartitionDxe/ElTorito.c
@@ -1,280 +1,280 @@
-/** @file
- Decode an El Torito formatted CD-ROM
-
-Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
-Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "Partition.h"
-
-/**
- Install child handles if the Handle supports El Torito format.
-
- @param[in] This Calling context.
- @param[in] Handle Parent Handle.
- @param[in] DiskIo Parent DiskIo interface.
- @param[in] DiskIo2 Parent DiskIo2 interface.
- @param[in] BlockIo Parent BlockIo interface.
- @param[in] BlockIo2 Parent BlockIo2 interface.
- @param[in] DevicePath Parent Device Path
-
-
- @retval EFI_SUCCESS Child handle(s) was added.
- @retval EFI_MEDIA_CHANGED Media changed Detected.
- @retval other no child handle was added.
-
-**/
-EFI_STATUS
-PartitionInstallElToritoChildHandles (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE Handle,
- IN EFI_DISK_IO_PROTOCOL *DiskIo,
- IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
- IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
- IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
- IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
- )
-{
- EFI_STATUS Status;
- UINT64 VolDescriptorOffset;
- UINT32 Lba2KB;
- EFI_BLOCK_IO_MEDIA *Media;
- CDROM_VOLUME_DESCRIPTOR *VolDescriptor;
- ELTORITO_CATALOG *Catalog;
- UINTN Check;
- UINTN Index;
- UINTN BootEntry;
- UINTN MaxIndex;
- UINT16 *CheckBuffer;
- CDROM_DEVICE_PATH CdDev;
- UINT32 SubBlockSize;
- UINT32 SectorCount;
- EFI_STATUS Found;
- UINT32 VolSpaceSize;
- EFI_PARTITION_INFO_PROTOCOL PartitionInfo;
-
- Found = EFI_NOT_FOUND;
- Media = BlockIo->Media;
-
- VolSpaceSize = 0;
-
- //
- // CD_ROM has the fixed block size as 2048 bytes (SIZE_2KB)
- //
-
- // If the ISO image has been copied onto a different storage media
- // then the block size might be different (eg: USB).
- // Ensure 2048 (SIZE_2KB) is a multiple of block size
- if (((SIZE_2KB % Media->BlockSize) != 0) || (Media->BlockSize > SIZE_2KB)) {
- return EFI_NOT_FOUND;
- }
-
- VolDescriptor = AllocatePool ((UINTN)SIZE_2KB);
-
- if (VolDescriptor == NULL) {
- return EFI_NOT_FOUND;
- }
-
- Catalog = (ELTORITO_CATALOG *)VolDescriptor;
-
- //
- // Loop: handle one volume descriptor per time
- // The ISO-9660 volume descriptor starts at 32k on the media
- //
- for (VolDescriptorOffset = SIZE_32KB;
- VolDescriptorOffset <= MultU64x32 (Media->LastBlock, Media->BlockSize);
- VolDescriptorOffset += SIZE_2KB)
- {
- Status = DiskIo->ReadDisk (
- DiskIo,
- Media->MediaId,
- VolDescriptorOffset,
- SIZE_2KB,
- VolDescriptor
- );
- if (EFI_ERROR (Status)) {
- Found = Status;
- break;
- }
-
- //
- // Check for valid volume descriptor signature
- //
- if ((VolDescriptor->Unknown.Type == CDVOL_TYPE_END) ||
- (CompareMem (VolDescriptor->Unknown.Id, CDVOL_ID, sizeof (VolDescriptor->Unknown.Id)) != 0)
- )
- {
- //
- // end of Volume descriptor list
- //
- break;
- }
-
- //
- // Read the Volume Space Size from Primary Volume Descriptor 81-88 byte,
- // the 32-bit numerical values is stored in Both-byte orders
- //
- if (VolDescriptor->PrimaryVolume.Type == CDVOL_TYPE_CODED) {
- VolSpaceSize = VolDescriptor->PrimaryVolume.VolSpaceSize[0];
- }
-
- //
- // Is it an El Torito volume descriptor?
- //
- if (CompareMem (VolDescriptor->BootRecordVolume.SystemId, CDVOL_ELTORITO_ID, sizeof (CDVOL_ELTORITO_ID) - 1) != 0) {
- continue;
- }
-
- //
- // Read in the boot El Torito boot catalog
- // The LBA unit used by El Torito boot catalog is 2KB unit
- //
- Lba2KB = UNPACK_INT32 (VolDescriptor->BootRecordVolume.EltCatalog);
- // Ensure the LBA (in 2KB unit) fits into our media
- if (Lba2KB * (SIZE_2KB / Media->BlockSize) > Media->LastBlock) {
- continue;
- }
-
- Status = DiskIo->ReadDisk (
- DiskIo,
- Media->MediaId,
- MultU64x32 (Lba2KB, SIZE_2KB),
- SIZE_2KB,
- Catalog
- );
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "EltCheckDevice: error reading catalog %r\n", Status));
- continue;
- }
-
- //
- // We don't care too much about the Catalog header's contents, but we do want
- // to make sure it looks like a Catalog header
- //
- if ((Catalog->Catalog.Indicator != ELTORITO_ID_CATALOG) || (Catalog->Catalog.Id55AA != 0xAA55)) {
- DEBUG ((DEBUG_ERROR, "EltCheckBootCatalog: El Torito boot catalog header IDs not correct\n"));
- continue;
- }
-
- Check = 0;
- CheckBuffer = (UINT16 *)Catalog;
- for (Index = 0; Index < sizeof (ELTORITO_CATALOG) / sizeof (UINT16); Index += 1) {
- Check += CheckBuffer[Index];
- }
-
- if ((Check & 0xFFFF) != 0) {
- DEBUG ((DEBUG_ERROR, "EltCheckBootCatalog: El Torito boot catalog header checksum failed\n"));
- continue;
- }
-
- MaxIndex = Media->BlockSize / sizeof (ELTORITO_CATALOG);
- for (Index = 1, BootEntry = 1; Index < MaxIndex; Index += 1) {
- //
- // Next entry
- //
- Catalog += 1;
-
- //
- // Check this entry
- //
- if ((Catalog->Boot.Indicator != ELTORITO_ID_SECTION_BOOTABLE) || (Catalog->Boot.Lba == 0)) {
- continue;
- }
-
- SubBlockSize = 512;
- SectorCount = Catalog->Boot.SectorCount;
-
- switch (Catalog->Boot.MediaType) {
- case ELTORITO_NO_EMULATION:
- SubBlockSize = Media->BlockSize;
- break;
-
- case ELTORITO_HARD_DISK:
- break;
-
- case ELTORITO_12_DISKETTE:
- SectorCount = 0x50 * 0x02 * 0x0F;
- break;
-
- case ELTORITO_14_DISKETTE:
- SectorCount = 0x50 * 0x02 * 0x12;
- break;
-
- case ELTORITO_28_DISKETTE:
- SectorCount = 0x50 * 0x02 * 0x24;
- break;
-
- default:
- DEBUG ((DEBUG_INIT, "EltCheckDevice: unsupported El Torito boot media type %x\n", Catalog->Boot.MediaType));
- SectorCount = 0;
- SubBlockSize = Media->BlockSize;
- break;
- }
-
- //
- // Create child device handle
- //
- CdDev.Header.Type = MEDIA_DEVICE_PATH;
- CdDev.Header.SubType = MEDIA_CDROM_DP;
- SetDevicePathNodeLength (&CdDev.Header, sizeof (CdDev));
-
- if (Index == 1) {
- //
- // This is the initial/default entry
- //
- BootEntry = 0;
- }
-
- CdDev.BootEntry = (UINT32)BootEntry;
- BootEntry++;
- CdDev.PartitionStart = Catalog->Boot.Lba * (SIZE_2KB / Media->BlockSize);
- if (SectorCount < 2) {
- //
- // When the SectorCount < 2, set the Partition as the whole CD.
- //
- if (VolSpaceSize * (SIZE_2KB / Media->BlockSize) > (Media->LastBlock + 1)) {
- CdDev.PartitionSize = (UINT32)(Media->LastBlock - Catalog->Boot.Lba * (SIZE_2KB / Media->BlockSize) + 1);
- } else {
- CdDev.PartitionSize = (UINT32)(VolSpaceSize - Catalog->Boot.Lba) * (SIZE_2KB / Media->BlockSize);
- }
- } else {
- CdDev.PartitionSize = DivU64x32 (
- MultU64x32 (
- SectorCount * (SIZE_2KB / Media->BlockSize),
- SubBlockSize
- ) + Media->BlockSize - 1,
- Media->BlockSize
- );
- }
-
- ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
- PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
- PartitionInfo.Type = PARTITION_TYPE_OTHER;
-
- Status = PartitionInstallChildHandle (
- This,
- Handle,
- DiskIo,
- DiskIo2,
- BlockIo,
- BlockIo2,
- DevicePath,
- (EFI_DEVICE_PATH_PROTOCOL *)&CdDev,
- &PartitionInfo,
- Catalog->Boot.Lba * (SIZE_2KB / Media->BlockSize),
- Catalog->Boot.Lba * (SIZE_2KB / Media->BlockSize) + CdDev.PartitionSize - 1,
- SubBlockSize,
- NULL
- );
- if (!EFI_ERROR (Status)) {
- Found = EFI_SUCCESS;
- }
- }
- }
-
- FreePool (VolDescriptor);
-
- return Found;
-}
+/** @file
+ Decode an El Torito formatted CD-ROM
+
+Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Partition.h"
+
+/**
+ Install child handles if the Handle supports El Torito format.
+
+ @param[in] This Calling context.
+ @param[in] Handle Parent Handle.
+ @param[in] DiskIo Parent DiskIo interface.
+ @param[in] DiskIo2 Parent DiskIo2 interface.
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] BlockIo2 Parent BlockIo2 interface.
+ @param[in] DevicePath Parent Device Path
+
+
+ @retval EFI_SUCCESS Child handle(s) was added.
+ @retval EFI_MEDIA_CHANGED Media changed Detected.
+ @retval other no child handle was added.
+
+**/
+EFI_STATUS
+PartitionInstallElToritoChildHandles (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_STATUS Status;
+ UINT64 VolDescriptorOffset;
+ UINT32 Lba2KB;
+ EFI_BLOCK_IO_MEDIA *Media;
+ CDROM_VOLUME_DESCRIPTOR *VolDescriptor;
+ ELTORITO_CATALOG *Catalog;
+ UINTN Check;
+ UINTN Index;
+ UINTN BootEntry;
+ UINTN MaxIndex;
+ UINT16 *CheckBuffer;
+ CDROM_DEVICE_PATH CdDev;
+ UINT32 SubBlockSize;
+ UINT32 SectorCount;
+ EFI_STATUS Found;
+ UINT32 VolSpaceSize;
+ EFI_PARTITION_INFO_PROTOCOL PartitionInfo;
+
+ Found = EFI_NOT_FOUND;
+ Media = BlockIo->Media;
+
+ VolSpaceSize = 0;
+
+ //
+ // CD_ROM has the fixed block size as 2048 bytes (SIZE_2KB)
+ //
+
+ // If the ISO image has been copied onto a different storage media
+ // then the block size might be different (eg: USB).
+ // Ensure 2048 (SIZE_2KB) is a multiple of block size
+ if (((SIZE_2KB % Media->BlockSize) != 0) || (Media->BlockSize > SIZE_2KB)) {
+ return EFI_NOT_FOUND;
+ }
+
+ VolDescriptor = AllocatePool ((UINTN)SIZE_2KB);
+
+ if (VolDescriptor == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ Catalog = (ELTORITO_CATALOG *)VolDescriptor;
+
+ //
+ // Loop: handle one volume descriptor per time
+ // The ISO-9660 volume descriptor starts at 32k on the media
+ //
+ for (VolDescriptorOffset = SIZE_32KB;
+ VolDescriptorOffset <= MultU64x32 (Media->LastBlock, Media->BlockSize);
+ VolDescriptorOffset += SIZE_2KB)
+ {
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ Media->MediaId,
+ VolDescriptorOffset,
+ SIZE_2KB,
+ VolDescriptor
+ );
+ if (EFI_ERROR (Status)) {
+ Found = Status;
+ break;
+ }
+
+ //
+ // Check for valid volume descriptor signature
+ //
+ if ((VolDescriptor->Unknown.Type == CDVOL_TYPE_END) ||
+ (CompareMem (VolDescriptor->Unknown.Id, CDVOL_ID, sizeof (VolDescriptor->Unknown.Id)) != 0)
+ )
+ {
+ //
+ // end of Volume descriptor list
+ //
+ break;
+ }
+
+ //
+ // Read the Volume Space Size from Primary Volume Descriptor 81-88 byte,
+ // the 32-bit numerical values is stored in Both-byte orders
+ //
+ if (VolDescriptor->PrimaryVolume.Type == CDVOL_TYPE_CODED) {
+ VolSpaceSize = VolDescriptor->PrimaryVolume.VolSpaceSize[0];
+ }
+
+ //
+ // Is it an El Torito volume descriptor?
+ //
+ if (CompareMem (VolDescriptor->BootRecordVolume.SystemId, CDVOL_ELTORITO_ID, sizeof (CDVOL_ELTORITO_ID) - 1) != 0) {
+ continue;
+ }
+
+ //
+ // Read in the boot El Torito boot catalog
+ // The LBA unit used by El Torito boot catalog is 2KB unit
+ //
+ Lba2KB = UNPACK_INT32 (VolDescriptor->BootRecordVolume.EltCatalog);
+ // Ensure the LBA (in 2KB unit) fits into our media
+ if (Lba2KB * (SIZE_2KB / Media->BlockSize) > Media->LastBlock) {
+ continue;
+ }
+
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ Media->MediaId,
+ MultU64x32 (Lba2KB, SIZE_2KB),
+ SIZE_2KB,
+ Catalog
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EltCheckDevice: error reading catalog %r\n", Status));
+ continue;
+ }
+
+ //
+ // We don't care too much about the Catalog header's contents, but we do want
+ // to make sure it looks like a Catalog header
+ //
+ if ((Catalog->Catalog.Indicator != ELTORITO_ID_CATALOG) || (Catalog->Catalog.Id55AA != 0xAA55)) {
+ DEBUG ((DEBUG_ERROR, "EltCheckBootCatalog: El Torito boot catalog header IDs not correct\n"));
+ continue;
+ }
+
+ Check = 0;
+ CheckBuffer = (UINT16 *)Catalog;
+ for (Index = 0; Index < sizeof (ELTORITO_CATALOG) / sizeof (UINT16); Index += 1) {
+ Check += CheckBuffer[Index];
+ }
+
+ if ((Check & 0xFFFF) != 0) {
+ DEBUG ((DEBUG_ERROR, "EltCheckBootCatalog: El Torito boot catalog header checksum failed\n"));
+ continue;
+ }
+
+ MaxIndex = Media->BlockSize / sizeof (ELTORITO_CATALOG);
+ for (Index = 1, BootEntry = 1; Index < MaxIndex; Index += 1) {
+ //
+ // Next entry
+ //
+ Catalog += 1;
+
+ //
+ // Check this entry
+ //
+ if ((Catalog->Boot.Indicator != ELTORITO_ID_SECTION_BOOTABLE) || (Catalog->Boot.Lba == 0)) {
+ continue;
+ }
+
+ SubBlockSize = 512;
+ SectorCount = Catalog->Boot.SectorCount;
+
+ switch (Catalog->Boot.MediaType) {
+ case ELTORITO_NO_EMULATION:
+ SubBlockSize = Media->BlockSize;
+ break;
+
+ case ELTORITO_HARD_DISK:
+ break;
+
+ case ELTORITO_12_DISKETTE:
+ SectorCount = 0x50 * 0x02 * 0x0F;
+ break;
+
+ case ELTORITO_14_DISKETTE:
+ SectorCount = 0x50 * 0x02 * 0x12;
+ break;
+
+ case ELTORITO_28_DISKETTE:
+ SectorCount = 0x50 * 0x02 * 0x24;
+ break;
+
+ default:
+ DEBUG ((DEBUG_INIT, "EltCheckDevice: unsupported El Torito boot media type %x\n", Catalog->Boot.MediaType));
+ SectorCount = 0;
+ SubBlockSize = Media->BlockSize;
+ break;
+ }
+
+ //
+ // Create child device handle
+ //
+ CdDev.Header.Type = MEDIA_DEVICE_PATH;
+ CdDev.Header.SubType = MEDIA_CDROM_DP;
+ SetDevicePathNodeLength (&CdDev.Header, sizeof (CdDev));
+
+ if (Index == 1) {
+ //
+ // This is the initial/default entry
+ //
+ BootEntry = 0;
+ }
+
+ CdDev.BootEntry = (UINT32)BootEntry;
+ BootEntry++;
+ CdDev.PartitionStart = Catalog->Boot.Lba * (SIZE_2KB / Media->BlockSize);
+ if (SectorCount < 2) {
+ //
+ // When the SectorCount < 2, set the Partition as the whole CD.
+ //
+ if (VolSpaceSize * (SIZE_2KB / Media->BlockSize) > (Media->LastBlock + 1)) {
+ CdDev.PartitionSize = (UINT32)(Media->LastBlock - Catalog->Boot.Lba * (SIZE_2KB / Media->BlockSize) + 1);
+ } else {
+ CdDev.PartitionSize = (UINT32)(VolSpaceSize - Catalog->Boot.Lba) * (SIZE_2KB / Media->BlockSize);
+ }
+ } else {
+ CdDev.PartitionSize = DivU64x32 (
+ MultU64x32 (
+ SectorCount * (SIZE_2KB / Media->BlockSize),
+ SubBlockSize
+ ) + Media->BlockSize - 1,
+ Media->BlockSize
+ );
+ }
+
+ ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
+ PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
+ PartitionInfo.Type = PARTITION_TYPE_OTHER;
+
+ Status = PartitionInstallChildHandle (
+ This,
+ Handle,
+ DiskIo,
+ DiskIo2,
+ BlockIo,
+ BlockIo2,
+ DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *)&CdDev,
+ &PartitionInfo,
+ Catalog->Boot.Lba * (SIZE_2KB / Media->BlockSize),
+ Catalog->Boot.Lba * (SIZE_2KB / Media->BlockSize) + CdDev.PartitionSize - 1,
+ SubBlockSize,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ Found = EFI_SUCCESS;
+ }
+ }
+ }
+
+ FreePool (VolDescriptor);
+
+ return Found;
+}
diff --git a/MdeModulePkg/Universal/Disk/PartitionDxe/Gpt.c b/MdeModulePkg/Universal/Disk/PartitionDxe/Gpt.c
index 5bcf94d587..c8089dae99 100644
--- a/MdeModulePkg/Universal/Disk/PartitionDxe/Gpt.c
+++ b/MdeModulePkg/Universal/Disk/PartitionDxe/Gpt.c
@@ -1,883 +1,883 @@
-/** @file
- Decode a hard disk partitioned with the GPT scheme in the UEFI 2.0
- specification.
-
- Caution: This file requires additional review when modified.
- This driver will have external input - disk partition.
- This external input must be validated carefully to avoid security issue like
- buffer overflow, integer overflow.
-
- PartitionInstallGptChildHandles() routine will read disk partition content and
- do basic validation before PartitionInstallChildHandle().
-
- PartitionValidGptTable(), PartitionCheckGptEntry() routine will accept disk
- partition content and validate the GPT table and GPT entry.
-
-Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
-Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "Partition.h"
-
-/**
- Install child handles if the Handle supports GPT partition structure.
-
- Caution: This function may receive untrusted input.
- The GPT partition table header is external input, so this routine
- will do basic validation for GPT partition table header before return.
-
- @param[in] BlockIo Parent BlockIo interface.
- @param[in] DiskIo Disk Io protocol.
- @param[in] Lba The starting Lba of the Partition Table
- @param[out] PartHeader Stores the partition table that is read
-
- @retval TRUE The partition table is valid
- @retval FALSE The partition table is not valid
-
-**/
-BOOLEAN
-PartitionValidGptTable (
- IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
- IN EFI_DISK_IO_PROTOCOL *DiskIo,
- IN EFI_LBA Lba,
- OUT EFI_PARTITION_TABLE_HEADER *PartHeader
- );
-
-/**
- Check if the CRC field in the Partition table header is valid
- for Partition entry array.
-
- @param[in] BlockIo Parent BlockIo interface
- @param[in] DiskIo Disk Io Protocol.
- @param[in] PartHeader Partition table header structure
-
- @retval TRUE the CRC is valid
- @retval FALSE the CRC is invalid
-
-**/
-BOOLEAN
-PartitionCheckGptEntryArrayCRC (
- IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
- IN EFI_DISK_IO_PROTOCOL *DiskIo,
- IN EFI_PARTITION_TABLE_HEADER *PartHeader
- );
-
-/**
- Restore Partition Table to its alternate place
- (Primary -> Backup or Backup -> Primary).
-
- @param[in] BlockIo Parent BlockIo interface.
- @param[in] DiskIo Disk Io Protocol.
- @param[in] PartHeader Partition table header structure.
-
- @retval TRUE Restoring succeeds
- @retval FALSE Restoring failed
-
-**/
-BOOLEAN
-PartitionRestoreGptTable (
- IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
- IN EFI_DISK_IO_PROTOCOL *DiskIo,
- IN EFI_PARTITION_TABLE_HEADER *PartHeader
- );
-
-/**
- This routine will check GPT partition entry and return entry status.
-
- Caution: This function may receive untrusted input.
- The GPT partition entry is external input, so this routine
- will do basic validation for GPT partition entry and report status.
-
- @param[in] PartHeader Partition table header structure
- @param[in] PartEntry The partition entry array
- @param[out] PEntryStatus the partition entry status array
- recording the status of each partition
-
-**/
-VOID
-PartitionCheckGptEntry (
- IN EFI_PARTITION_TABLE_HEADER *PartHeader,
- IN EFI_PARTITION_ENTRY *PartEntry,
- OUT EFI_PARTITION_ENTRY_STATUS *PEntryStatus
- );
-
-/**
- Checks the CRC32 value in the table header.
-
- @param MaxSize Max Size limit
- @param Size The size of the table
- @param Hdr Table to check
-
- @return TRUE CRC Valid
- @return FALSE CRC Invalid
-
-**/
-BOOLEAN
-PartitionCheckCrcAltSize (
- IN UINTN MaxSize,
- IN UINTN Size,
- IN OUT EFI_TABLE_HEADER *Hdr
- );
-
-/**
- Checks the CRC32 value in the table header.
-
- @param MaxSize Max Size limit
- @param Hdr Table to check
-
- @return TRUE CRC Valid
- @return FALSE CRC Invalid
-
-**/
-BOOLEAN
-PartitionCheckCrc (
- IN UINTN MaxSize,
- IN OUT EFI_TABLE_HEADER *Hdr
- );
-
-/**
- Updates the CRC32 value in the table header.
-
- @param Size The size of the table
- @param Hdr Table to update
-
-**/
-VOID
-PartitionSetCrcAltSize (
- IN UINTN Size,
- IN OUT EFI_TABLE_HEADER *Hdr
- );
-
-/**
- Updates the CRC32 value in the table header.
-
- @param Hdr Table to update
-
-**/
-VOID
-PartitionSetCrc (
- IN OUT EFI_TABLE_HEADER *Hdr
- );
-
-/**
- Install child handles if the Handle supports GPT partition structure.
-
- Caution: This function may receive untrusted input.
- The GPT partition table is external input, so this routine
- will do basic validation for GPT partition table before install
- child handle for each GPT partition.
-
- @param[in] This Calling context.
- @param[in] Handle Parent Handle.
- @param[in] DiskIo Parent DiskIo interface.
- @param[in] DiskIo2 Parent DiskIo2 interface.
- @param[in] BlockIo Parent BlockIo interface.
- @param[in] BlockIo2 Parent BlockIo2 interface.
- @param[in] DevicePath Parent Device Path.
-
- @retval EFI_SUCCESS Valid GPT disk.
- @retval EFI_MEDIA_CHANGED Media changed Detected.
- @retval other Not a valid GPT disk.
-
-**/
-EFI_STATUS
-PartitionInstallGptChildHandles (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE Handle,
- IN EFI_DISK_IO_PROTOCOL *DiskIo,
- IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
- IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
- IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
- IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
- )
-{
- EFI_STATUS Status;
- UINT32 BlockSize;
- EFI_LBA LastBlock;
- MASTER_BOOT_RECORD *ProtectiveMbr;
- EFI_PARTITION_TABLE_HEADER *PrimaryHeader;
- EFI_PARTITION_TABLE_HEADER *BackupHeader;
- EFI_PARTITION_ENTRY *PartEntry;
- EFI_PARTITION_ENTRY *Entry;
- EFI_PARTITION_ENTRY_STATUS *PEntryStatus;
- UINTN Index;
- EFI_STATUS GptValidStatus;
- HARDDRIVE_DEVICE_PATH HdDev;
- UINT32 MediaId;
- EFI_PARTITION_INFO_PROTOCOL PartitionInfo;
-
- ProtectiveMbr = NULL;
- PrimaryHeader = NULL;
- BackupHeader = NULL;
- PartEntry = NULL;
- PEntryStatus = NULL;
-
- BlockSize = BlockIo->Media->BlockSize;
- LastBlock = BlockIo->Media->LastBlock;
- MediaId = BlockIo->Media->MediaId;
-
- DEBUG ((DEBUG_INFO, " BlockSize : %d \n", BlockSize));
- DEBUG ((DEBUG_INFO, " LastBlock : %lx \n", LastBlock));
-
- GptValidStatus = EFI_NOT_FOUND;
-
- //
- // Ensure the block size can hold the MBR
- //
- if (BlockSize < sizeof (MASTER_BOOT_RECORD)) {
- return EFI_NOT_FOUND;
- }
-
- //
- // Allocate a buffer for the Protective MBR
- //
- ProtectiveMbr = AllocatePool (BlockSize);
- if (ProtectiveMbr == NULL) {
- return EFI_NOT_FOUND;
- }
-
- //
- // Read the Protective MBR from LBA #0
- //
- Status = DiskIo->ReadDisk (
- DiskIo,
- MediaId,
- 0,
- BlockSize,
- ProtectiveMbr
- );
- if (EFI_ERROR (Status)) {
- GptValidStatus = Status;
- goto Done;
- }
-
- //
- // Verify that the Protective MBR is valid
- //
- for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
- if ((ProtectiveMbr->Partition[Index].OSIndicator == PMBR_GPT_PARTITION) &&
- (UNPACK_UINT32 (ProtectiveMbr->Partition[Index].StartingLBA) == 1)
- )
- {
- break;
- }
- }
-
- if (Index == MAX_MBR_PARTITIONS) {
- goto Done;
- }
-
- //
- // Allocate the GPT structures
- //
- PrimaryHeader = AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER));
- if (PrimaryHeader == NULL) {
- goto Done;
- }
-
- BackupHeader = AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER));
- if (BackupHeader == NULL) {
- goto Done;
- }
-
- //
- // Check primary and backup partition tables
- //
- if (!PartitionValidGptTable (BlockIo, DiskIo, PRIMARY_PART_HEADER_LBA, PrimaryHeader)) {
- DEBUG ((DEBUG_INFO, " Not Valid primary partition table\n"));
-
- if (!PartitionValidGptTable (BlockIo, DiskIo, LastBlock, BackupHeader)) {
- DEBUG ((DEBUG_INFO, " Not Valid backup partition table\n"));
- goto Done;
- } else {
- DEBUG ((DEBUG_INFO, " Valid backup partition table\n"));
- DEBUG ((DEBUG_INFO, " Restore primary partition table by the backup\n"));
- if (!PartitionRestoreGptTable (BlockIo, DiskIo, BackupHeader)) {
- DEBUG ((DEBUG_INFO, " Restore primary partition table error\n"));
- }
-
- if (PartitionValidGptTable (BlockIo, DiskIo, BackupHeader->AlternateLBA, PrimaryHeader)) {
- DEBUG ((DEBUG_INFO, " Restore backup partition table success\n"));
- }
- }
- } else if (!PartitionValidGptTable (BlockIo, DiskIo, PrimaryHeader->AlternateLBA, BackupHeader)) {
- DEBUG ((DEBUG_INFO, " Valid primary and !Valid backup partition table\n"));
- DEBUG ((DEBUG_INFO, " Restore backup partition table by the primary\n"));
- if (!PartitionRestoreGptTable (BlockIo, DiskIo, PrimaryHeader)) {
- DEBUG ((DEBUG_INFO, " Restore backup partition table error\n"));
- }
-
- if (PartitionValidGptTable (BlockIo, DiskIo, PrimaryHeader->AlternateLBA, BackupHeader)) {
- DEBUG ((DEBUG_INFO, " Restore backup partition table success\n"));
- }
- }
-
- DEBUG ((DEBUG_INFO, " Valid primary and Valid backup partition table\n"));
-
- //
- // Read the EFI Partition Entries
- //
- PartEntry = AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry);
- if (PartEntry == NULL) {
- DEBUG ((DEBUG_ERROR, "Allocate pool error\n"));
- goto Done;
- }
-
- Status = DiskIo->ReadDisk (
- DiskIo,
- MediaId,
- MultU64x32 (PrimaryHeader->PartitionEntryLBA, BlockSize),
- PrimaryHeader->NumberOfPartitionEntries * (PrimaryHeader->SizeOfPartitionEntry),
- PartEntry
- );
- if (EFI_ERROR (Status)) {
- GptValidStatus = Status;
- DEBUG ((DEBUG_ERROR, " Partition Entry ReadDisk error\n"));
- goto Done;
- }
-
- DEBUG ((DEBUG_INFO, " Partition entries read block success\n"));
-
- DEBUG ((DEBUG_INFO, " Number of partition entries: %d\n", PrimaryHeader->NumberOfPartitionEntries));
-
- PEntryStatus = AllocateZeroPool (PrimaryHeader->NumberOfPartitionEntries * sizeof (EFI_PARTITION_ENTRY_STATUS));
- if (PEntryStatus == NULL) {
- DEBUG ((DEBUG_ERROR, "Allocate pool error\n"));
- goto Done;
- }
-
- //
- // Check the integrity of partition entries
- //
- PartitionCheckGptEntry (PrimaryHeader, PartEntry, PEntryStatus);
-
- //
- // If we got this far the GPT layout of the disk is valid and we should return true
- //
- GptValidStatus = EFI_SUCCESS;
-
- //
- // Create child device handles
- //
- for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {
- Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index * PrimaryHeader->SizeOfPartitionEntry);
- if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid) ||
- PEntryStatus[Index].OutOfRange ||
- PEntryStatus[Index].Overlap ||
- PEntryStatus[Index].OsSpecific
- )
- {
- //
- // Don't use null EFI Partition Entries, Invalid Partition Entries or OS specific
- // partition Entries
- //
- continue;
- }
-
- ZeroMem (&HdDev, sizeof (HdDev));
- HdDev.Header.Type = MEDIA_DEVICE_PATH;
- HdDev.Header.SubType = MEDIA_HARDDRIVE_DP;
- SetDevicePathNodeLength (&HdDev.Header, sizeof (HdDev));
-
- HdDev.PartitionNumber = (UINT32)Index + 1;
- HdDev.MBRType = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;
- HdDev.SignatureType = SIGNATURE_TYPE_GUID;
- HdDev.PartitionStart = Entry->StartingLBA;
- HdDev.PartitionSize = Entry->EndingLBA - Entry->StartingLBA + 1;
- CopyMem (HdDev.Signature, &Entry->UniquePartitionGUID, sizeof (EFI_GUID));
-
- ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
- PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
- PartitionInfo.Type = PARTITION_TYPE_GPT;
- if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeSystemPartGuid)) {
- PartitionInfo.System = 1;
- }
-
- CopyMem (&PartitionInfo.Info.Gpt, Entry, sizeof (EFI_PARTITION_ENTRY));
-
- DEBUG ((DEBUG_INFO, " Index : %d\n", (UINT32)Index));
- DEBUG ((DEBUG_INFO, " Start LBA : %lx\n", (UINT64)HdDev.PartitionStart));
- DEBUG ((DEBUG_INFO, " End LBA : %lx\n", (UINT64)Entry->EndingLBA));
- DEBUG ((DEBUG_INFO, " Partition size: %lx\n", (UINT64)HdDev.PartitionSize));
- DEBUG ((DEBUG_INFO, " Start : %lx", MultU64x32 (Entry->StartingLBA, BlockSize)));
- DEBUG ((DEBUG_INFO, " End : %lx\n", MultU64x32 (Entry->EndingLBA, BlockSize)));
-
- Status = PartitionInstallChildHandle (
- This,
- Handle,
- DiskIo,
- DiskIo2,
- BlockIo,
- BlockIo2,
- DevicePath,
- (EFI_DEVICE_PATH_PROTOCOL *)&HdDev,
- &PartitionInfo,
- Entry->StartingLBA,
- Entry->EndingLBA,
- BlockSize,
- &Entry->PartitionTypeGUID
- );
- }
-
- DEBUG ((DEBUG_INFO, "Prepare to Free Pool\n"));
-
-Done:
- if (ProtectiveMbr != NULL) {
- FreePool (ProtectiveMbr);
- }
-
- if (PrimaryHeader != NULL) {
- FreePool (PrimaryHeader);
- }
-
- if (BackupHeader != NULL) {
- FreePool (BackupHeader);
- }
-
- if (PartEntry != NULL) {
- FreePool (PartEntry);
- }
-
- if (PEntryStatus != NULL) {
- FreePool (PEntryStatus);
- }
-
- return GptValidStatus;
-}
-
-/**
- This routine will read GPT partition table header and return it.
-
- Caution: This function may receive untrusted input.
- The GPT partition table header is external input, so this routine
- will do basic validation for GPT partition table header before return.
-
- @param[in] BlockIo Parent BlockIo interface.
- @param[in] DiskIo Disk Io protocol.
- @param[in] Lba The starting Lba of the Partition Table
- @param[out] PartHeader Stores the partition table that is read
-
- @retval TRUE The partition table is valid
- @retval FALSE The partition table is not valid
-
-**/
-BOOLEAN
-PartitionValidGptTable (
- IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
- IN EFI_DISK_IO_PROTOCOL *DiskIo,
- IN EFI_LBA Lba,
- OUT EFI_PARTITION_TABLE_HEADER *PartHeader
- )
-{
- EFI_STATUS Status;
- UINT32 BlockSize;
- EFI_PARTITION_TABLE_HEADER *PartHdr;
- UINT32 MediaId;
-
- BlockSize = BlockIo->Media->BlockSize;
- MediaId = BlockIo->Media->MediaId;
- PartHdr = AllocateZeroPool (BlockSize);
-
- if (PartHdr == NULL) {
- DEBUG ((DEBUG_ERROR, "Allocate pool error\n"));
- return FALSE;
- }
-
- //
- // Read the EFI Partition Table Header
- //
- Status = DiskIo->ReadDisk (
- DiskIo,
- MediaId,
- MultU64x32 (Lba, BlockSize),
- BlockSize,
- PartHdr
- );
- if (EFI_ERROR (Status)) {
- FreePool (PartHdr);
- return FALSE;
- }
-
- if ((PartHdr->Header.Signature != EFI_PTAB_HEADER_ID) ||
- !PartitionCheckCrc (BlockSize, &PartHdr->Header) ||
- (PartHdr->MyLBA != Lba) ||
- (PartHdr->SizeOfPartitionEntry < sizeof (EFI_PARTITION_ENTRY))
- )
- {
- DEBUG ((DEBUG_INFO, "Invalid efi partition table header\n"));
- FreePool (PartHdr);
- return FALSE;
- }
-
- //
- // Ensure the NumberOfPartitionEntries * SizeOfPartitionEntry doesn't overflow.
- //
- if (PartHdr->NumberOfPartitionEntries > DivU64x32 (MAX_UINTN, PartHdr->SizeOfPartitionEntry)) {
- FreePool (PartHdr);
- return FALSE;
- }
-
- CopyMem (PartHeader, PartHdr, sizeof (EFI_PARTITION_TABLE_HEADER));
- if (!PartitionCheckGptEntryArrayCRC (BlockIo, DiskIo, PartHeader)) {
- FreePool (PartHdr);
- return FALSE;
- }
-
- DEBUG ((DEBUG_INFO, " Valid efi partition table header\n"));
- FreePool (PartHdr);
- return TRUE;
-}
-
-/**
- Check if the CRC field in the Partition table header is valid
- for Partition entry array.
-
- @param[in] BlockIo Parent BlockIo interface
- @param[in] DiskIo Disk Io Protocol.
- @param[in] PartHeader Partition table header structure
-
- @retval TRUE the CRC is valid
- @retval FALSE the CRC is invalid
-
-**/
-BOOLEAN
-PartitionCheckGptEntryArrayCRC (
- IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
- IN EFI_DISK_IO_PROTOCOL *DiskIo,
- IN EFI_PARTITION_TABLE_HEADER *PartHeader
- )
-{
- EFI_STATUS Status;
- UINT8 *Ptr;
- UINT32 Crc;
- UINTN Size;
-
- //
- // Read the EFI Partition Entries
- //
- Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry);
- if (Ptr == NULL) {
- DEBUG ((DEBUG_ERROR, " Allocate pool error\n"));
- return FALSE;
- }
-
- Status = DiskIo->ReadDisk (
- DiskIo,
- BlockIo->Media->MediaId,
- MultU64x32 (PartHeader->PartitionEntryLBA, BlockIo->Media->BlockSize),
- PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,
- Ptr
- );
- if (EFI_ERROR (Status)) {
- FreePool (Ptr);
- return FALSE;
- }
-
- Size = PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry;
-
- Status = gBS->CalculateCrc32 (Ptr, Size, &Crc);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "CheckPEntryArrayCRC: Crc calculation failed\n"));
- FreePool (Ptr);
- return FALSE;
- }
-
- FreePool (Ptr);
-
- return (BOOLEAN)(PartHeader->PartitionEntryArrayCRC32 == Crc);
-}
-
-/**
- Restore Partition Table to its alternate place
- (Primary -> Backup or Backup -> Primary).
-
- @param[in] BlockIo Parent BlockIo interface.
- @param[in] DiskIo Disk Io Protocol.
- @param[in] PartHeader Partition table header structure.
-
- @retval TRUE Restoring succeeds
- @retval FALSE Restoring failed
-
-**/
-BOOLEAN
-PartitionRestoreGptTable (
- IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
- IN EFI_DISK_IO_PROTOCOL *DiskIo,
- IN EFI_PARTITION_TABLE_HEADER *PartHeader
- )
-{
- EFI_STATUS Status;
- UINTN BlockSize;
- EFI_PARTITION_TABLE_HEADER *PartHdr;
- EFI_LBA PEntryLBA;
- UINT8 *Ptr;
- UINT32 MediaId;
-
- PartHdr = NULL;
- Ptr = NULL;
-
- BlockSize = BlockIo->Media->BlockSize;
- MediaId = BlockIo->Media->MediaId;
-
- PartHdr = AllocateZeroPool (BlockSize);
-
- if (PartHdr == NULL) {
- DEBUG ((DEBUG_ERROR, "Allocate pool error\n"));
- return FALSE;
- }
-
- PEntryLBA = (PartHeader->MyLBA == PRIMARY_PART_HEADER_LBA) ? \
- (PartHeader->LastUsableLBA + 1) : \
- (PRIMARY_PART_HEADER_LBA + 1);
-
- CopyMem (PartHdr, PartHeader, sizeof (EFI_PARTITION_TABLE_HEADER));
-
- PartHdr->MyLBA = PartHeader->AlternateLBA;
- PartHdr->AlternateLBA = PartHeader->MyLBA;
- PartHdr->PartitionEntryLBA = PEntryLBA;
- PartitionSetCrc ((EFI_TABLE_HEADER *)PartHdr);
-
- Status = DiskIo->WriteDisk (
- DiskIo,
- MediaId,
- MultU64x32 (PartHdr->MyLBA, (UINT32)BlockSize),
- BlockSize,
- PartHdr
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry);
- if (Ptr == NULL) {
- DEBUG ((DEBUG_ERROR, " Allocate pool error\n"));
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
-
- Status = DiskIo->ReadDisk (
- DiskIo,
- MediaId,
- MultU64x32 (PartHeader->PartitionEntryLBA, (UINT32)BlockSize),
- PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,
- Ptr
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- Status = DiskIo->WriteDisk (
- DiskIo,
- MediaId,
- MultU64x32 (PEntryLBA, (UINT32)BlockSize),
- PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,
- Ptr
- );
-
-Done:
- FreePool (PartHdr);
-
- if (Ptr != NULL) {
- FreePool (Ptr);
- }
-
- if (EFI_ERROR (Status)) {
- return FALSE;
- }
-
- return TRUE;
-}
-
-/**
- This routine will check GPT partition entry and return entry status.
-
- Caution: This function may receive untrusted input.
- The GPT partition entry is external input, so this routine
- will do basic validation for GPT partition entry and report status.
-
- @param[in] PartHeader Partition table header structure
- @param[in] PartEntry The partition entry array
- @param[out] PEntryStatus the partition entry status array
- recording the status of each partition
-
-**/
-VOID
-PartitionCheckGptEntry (
- IN EFI_PARTITION_TABLE_HEADER *PartHeader,
- IN EFI_PARTITION_ENTRY *PartEntry,
- OUT EFI_PARTITION_ENTRY_STATUS *PEntryStatus
- )
-{
- EFI_LBA StartingLBA;
- EFI_LBA EndingLBA;
- EFI_PARTITION_ENTRY *Entry;
- UINTN Index1;
- UINTN Index2;
-
- DEBUG ((DEBUG_INFO, " start check partition entries\n"));
- for (Index1 = 0; Index1 < PartHeader->NumberOfPartitionEntries; Index1++) {
- Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index1 * PartHeader->SizeOfPartitionEntry);
- if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {
- continue;
- }
-
- StartingLBA = Entry->StartingLBA;
- EndingLBA = Entry->EndingLBA;
- if ((StartingLBA > EndingLBA) ||
- (StartingLBA < PartHeader->FirstUsableLBA) ||
- (StartingLBA > PartHeader->LastUsableLBA) ||
- (EndingLBA < PartHeader->FirstUsableLBA) ||
- (EndingLBA > PartHeader->LastUsableLBA)
- )
- {
- PEntryStatus[Index1].OutOfRange = TRUE;
- continue;
- }
-
- if ((Entry->Attributes & BIT1) != 0) {
- //
- // If Bit 1 is set, this indicate that this is an OS specific GUID partition.
- //
- PEntryStatus[Index1].OsSpecific = TRUE;
- }
-
- for (Index2 = Index1 + 1; Index2 < PartHeader->NumberOfPartitionEntries; Index2++) {
- Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index2 * PartHeader->SizeOfPartitionEntry);
- if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {
- continue;
- }
-
- if ((Entry->EndingLBA >= StartingLBA) && (Entry->StartingLBA <= EndingLBA)) {
- //
- // This region overlaps with the Index1'th region
- //
- PEntryStatus[Index1].Overlap = TRUE;
- PEntryStatus[Index2].Overlap = TRUE;
- continue;
- }
- }
- }
-
- DEBUG ((DEBUG_INFO, " End check partition entries\n"));
-}
-
-/**
- Updates the CRC32 value in the table header.
-
- @param Hdr Table to update
-
-**/
-VOID
-PartitionSetCrc (
- IN OUT EFI_TABLE_HEADER *Hdr
- )
-{
- PartitionSetCrcAltSize (Hdr->HeaderSize, Hdr);
-}
-
-/**
- Updates the CRC32 value in the table header.
-
- @param Size The size of the table
- @param Hdr Table to update
-
-**/
-VOID
-PartitionSetCrcAltSize (
- IN UINTN Size,
- IN OUT EFI_TABLE_HEADER *Hdr
- )
-{
- UINT32 Crc;
-
- Hdr->CRC32 = 0;
- gBS->CalculateCrc32 ((UINT8 *)Hdr, Size, &Crc);
- Hdr->CRC32 = Crc;
-}
-
-/**
- Checks the CRC32 value in the table header.
-
- @param MaxSize Max Size limit
- @param Hdr Table to check
-
- @return TRUE CRC Valid
- @return FALSE CRC Invalid
-
-**/
-BOOLEAN
-PartitionCheckCrc (
- IN UINTN MaxSize,
- IN OUT EFI_TABLE_HEADER *Hdr
- )
-{
- return PartitionCheckCrcAltSize (MaxSize, Hdr->HeaderSize, Hdr);
-}
-
-/**
- Checks the CRC32 value in the table header.
-
- @param MaxSize Max Size limit
- @param Size The size of the table
- @param Hdr Table to check
-
- @return TRUE CRC Valid
- @return FALSE CRC Invalid
-
-**/
-BOOLEAN
-PartitionCheckCrcAltSize (
- IN UINTN MaxSize,
- IN UINTN Size,
- IN OUT EFI_TABLE_HEADER *Hdr
- )
-{
- UINT32 Crc;
- UINT32 OrgCrc;
- EFI_STATUS Status;
-
- Crc = 0;
-
- if (Size == 0) {
- //
- // If header size is 0 CRC will pass so return FALSE here
- //
- return FALSE;
- }
-
- if ((MaxSize != 0) && (Size > MaxSize)) {
- DEBUG ((DEBUG_ERROR, "CheckCrc32: Size > MaxSize\n"));
- return FALSE;
- }
-
- //
- // clear old crc from header
- //
- OrgCrc = Hdr->CRC32;
- Hdr->CRC32 = 0;
-
- Status = gBS->CalculateCrc32 ((UINT8 *)Hdr, Size, &Crc);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "CheckCrc32: Crc calculation failed\n"));
- return FALSE;
- }
-
- //
- // set results
- //
- Hdr->CRC32 = Crc;
-
- //
- // return status
- //
- DEBUG_CODE_BEGIN ();
- if (OrgCrc != Crc) {
- DEBUG ((DEBUG_ERROR, "CheckCrc32: Crc check failed\n"));
- }
-
- DEBUG_CODE_END ();
-
- return (BOOLEAN)(OrgCrc == Crc);
-}
+/** @file
+ Decode a hard disk partitioned with the GPT scheme in the UEFI 2.0
+ specification.
+
+ Caution: This file requires additional review when modified.
+ This driver will have external input - disk partition.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+ PartitionInstallGptChildHandles() routine will read disk partition content and
+ do basic validation before PartitionInstallChildHandle().
+
+ PartitionValidGptTable(), PartitionCheckGptEntry() routine will accept disk
+ partition content and validate the GPT table and GPT entry.
+
+Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Partition.h"
+
+/**
+ Install child handles if the Handle supports GPT partition structure.
+
+ Caution: This function may receive untrusted input.
+ The GPT partition table header is external input, so this routine
+ will do basic validation for GPT partition table header before return.
+
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] DiskIo Disk Io protocol.
+ @param[in] Lba The starting Lba of the Partition Table
+ @param[out] PartHeader Stores the partition table that is read
+
+ @retval TRUE The partition table is valid
+ @retval FALSE The partition table is not valid
+
+**/
+BOOLEAN
+PartitionValidGptTable (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_LBA Lba,
+ OUT EFI_PARTITION_TABLE_HEADER *PartHeader
+ );
+
+/**
+ Check if the CRC field in the Partition table header is valid
+ for Partition entry array.
+
+ @param[in] BlockIo Parent BlockIo interface
+ @param[in] DiskIo Disk Io Protocol.
+ @param[in] PartHeader Partition table header structure
+
+ @retval TRUE the CRC is valid
+ @retval FALSE the CRC is invalid
+
+**/
+BOOLEAN
+PartitionCheckGptEntryArrayCRC (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_PARTITION_TABLE_HEADER *PartHeader
+ );
+
+/**
+ Restore Partition Table to its alternate place
+ (Primary -> Backup or Backup -> Primary).
+
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] DiskIo Disk Io Protocol.
+ @param[in] PartHeader Partition table header structure.
+
+ @retval TRUE Restoring succeeds
+ @retval FALSE Restoring failed
+
+**/
+BOOLEAN
+PartitionRestoreGptTable (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_PARTITION_TABLE_HEADER *PartHeader
+ );
+
+/**
+ This routine will check GPT partition entry and return entry status.
+
+ Caution: This function may receive untrusted input.
+ The GPT partition entry is external input, so this routine
+ will do basic validation for GPT partition entry and report status.
+
+ @param[in] PartHeader Partition table header structure
+ @param[in] PartEntry The partition entry array
+ @param[out] PEntryStatus the partition entry status array
+ recording the status of each partition
+
+**/
+VOID
+PartitionCheckGptEntry (
+ IN EFI_PARTITION_TABLE_HEADER *PartHeader,
+ IN EFI_PARTITION_ENTRY *PartEntry,
+ OUT EFI_PARTITION_ENTRY_STATUS *PEntryStatus
+ );
+
+/**
+ Checks the CRC32 value in the table header.
+
+ @param MaxSize Max Size limit
+ @param Size The size of the table
+ @param Hdr Table to check
+
+ @return TRUE CRC Valid
+ @return FALSE CRC Invalid
+
+**/
+BOOLEAN
+PartitionCheckCrcAltSize (
+ IN UINTN MaxSize,
+ IN UINTN Size,
+ IN OUT EFI_TABLE_HEADER *Hdr
+ );
+
+/**
+ Checks the CRC32 value in the table header.
+
+ @param MaxSize Max Size limit
+ @param Hdr Table to check
+
+ @return TRUE CRC Valid
+ @return FALSE CRC Invalid
+
+**/
+BOOLEAN
+PartitionCheckCrc (
+ IN UINTN MaxSize,
+ IN OUT EFI_TABLE_HEADER *Hdr
+ );
+
+/**
+ Updates the CRC32 value in the table header.
+
+ @param Size The size of the table
+ @param Hdr Table to update
+
+**/
+VOID
+PartitionSetCrcAltSize (
+ IN UINTN Size,
+ IN OUT EFI_TABLE_HEADER *Hdr
+ );
+
+/**
+ Updates the CRC32 value in the table header.
+
+ @param Hdr Table to update
+
+**/
+VOID
+PartitionSetCrc (
+ IN OUT EFI_TABLE_HEADER *Hdr
+ );
+
+/**
+ Install child handles if the Handle supports GPT partition structure.
+
+ Caution: This function may receive untrusted input.
+ The GPT partition table is external input, so this routine
+ will do basic validation for GPT partition table before install
+ child handle for each GPT partition.
+
+ @param[in] This Calling context.
+ @param[in] Handle Parent Handle.
+ @param[in] DiskIo Parent DiskIo interface.
+ @param[in] DiskIo2 Parent DiskIo2 interface.
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] BlockIo2 Parent BlockIo2 interface.
+ @param[in] DevicePath Parent Device Path.
+
+ @retval EFI_SUCCESS Valid GPT disk.
+ @retval EFI_MEDIA_CHANGED Media changed Detected.
+ @retval other Not a valid GPT disk.
+
+**/
+EFI_STATUS
+PartitionInstallGptChildHandles (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_STATUS Status;
+ UINT32 BlockSize;
+ EFI_LBA LastBlock;
+ MASTER_BOOT_RECORD *ProtectiveMbr;
+ EFI_PARTITION_TABLE_HEADER *PrimaryHeader;
+ EFI_PARTITION_TABLE_HEADER *BackupHeader;
+ EFI_PARTITION_ENTRY *PartEntry;
+ EFI_PARTITION_ENTRY *Entry;
+ EFI_PARTITION_ENTRY_STATUS *PEntryStatus;
+ UINTN Index;
+ EFI_STATUS GptValidStatus;
+ HARDDRIVE_DEVICE_PATH HdDev;
+ UINT32 MediaId;
+ EFI_PARTITION_INFO_PROTOCOL PartitionInfo;
+
+ ProtectiveMbr = NULL;
+ PrimaryHeader = NULL;
+ BackupHeader = NULL;
+ PartEntry = NULL;
+ PEntryStatus = NULL;
+
+ BlockSize = BlockIo->Media->BlockSize;
+ LastBlock = BlockIo->Media->LastBlock;
+ MediaId = BlockIo->Media->MediaId;
+
+ DEBUG ((DEBUG_INFO, " BlockSize : %d \n", BlockSize));
+ DEBUG ((DEBUG_INFO, " LastBlock : %lx \n", LastBlock));
+
+ GptValidStatus = EFI_NOT_FOUND;
+
+ //
+ // Ensure the block size can hold the MBR
+ //
+ if (BlockSize < sizeof (MASTER_BOOT_RECORD)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Allocate a buffer for the Protective MBR
+ //
+ ProtectiveMbr = AllocatePool (BlockSize);
+ if (ProtectiveMbr == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Read the Protective MBR from LBA #0
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ MediaId,
+ 0,
+ BlockSize,
+ ProtectiveMbr
+ );
+ if (EFI_ERROR (Status)) {
+ GptValidStatus = Status;
+ goto Done;
+ }
+
+ //
+ // Verify that the Protective MBR is valid
+ //
+ for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
+ if ((ProtectiveMbr->Partition[Index].OSIndicator == PMBR_GPT_PARTITION) &&
+ (UNPACK_UINT32 (ProtectiveMbr->Partition[Index].StartingLBA) == 1)
+ )
+ {
+ break;
+ }
+ }
+
+ if (Index == MAX_MBR_PARTITIONS) {
+ goto Done;
+ }
+
+ //
+ // Allocate the GPT structures
+ //
+ PrimaryHeader = AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER));
+ if (PrimaryHeader == NULL) {
+ goto Done;
+ }
+
+ BackupHeader = AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER));
+ if (BackupHeader == NULL) {
+ goto Done;
+ }
+
+ //
+ // Check primary and backup partition tables
+ //
+ if (!PartitionValidGptTable (BlockIo, DiskIo, PRIMARY_PART_HEADER_LBA, PrimaryHeader)) {
+ DEBUG ((DEBUG_INFO, " Not Valid primary partition table\n"));
+
+ if (!PartitionValidGptTable (BlockIo, DiskIo, LastBlock, BackupHeader)) {
+ DEBUG ((DEBUG_INFO, " Not Valid backup partition table\n"));
+ goto Done;
+ } else {
+ DEBUG ((DEBUG_INFO, " Valid backup partition table\n"));
+ DEBUG ((DEBUG_INFO, " Restore primary partition table by the backup\n"));
+ if (!PartitionRestoreGptTable (BlockIo, DiskIo, BackupHeader)) {
+ DEBUG ((DEBUG_INFO, " Restore primary partition table error\n"));
+ }
+
+ if (PartitionValidGptTable (BlockIo, DiskIo, BackupHeader->AlternateLBA, PrimaryHeader)) {
+ DEBUG ((DEBUG_INFO, " Restore backup partition table success\n"));
+ }
+ }
+ } else if (!PartitionValidGptTable (BlockIo, DiskIo, PrimaryHeader->AlternateLBA, BackupHeader)) {
+ DEBUG ((DEBUG_INFO, " Valid primary and !Valid backup partition table\n"));
+ DEBUG ((DEBUG_INFO, " Restore backup partition table by the primary\n"));
+ if (!PartitionRestoreGptTable (BlockIo, DiskIo, PrimaryHeader)) {
+ DEBUG ((DEBUG_INFO, " Restore backup partition table error\n"));
+ }
+
+ if (PartitionValidGptTable (BlockIo, DiskIo, PrimaryHeader->AlternateLBA, BackupHeader)) {
+ DEBUG ((DEBUG_INFO, " Restore backup partition table success\n"));
+ }
+ }
+
+ DEBUG ((DEBUG_INFO, " Valid primary and Valid backup partition table\n"));
+
+ //
+ // Read the EFI Partition Entries
+ //
+ PartEntry = AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry);
+ if (PartEntry == NULL) {
+ DEBUG ((DEBUG_ERROR, "Allocate pool error\n"));
+ goto Done;
+ }
+
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ MediaId,
+ MultU64x32 (PrimaryHeader->PartitionEntryLBA, BlockSize),
+ PrimaryHeader->NumberOfPartitionEntries * (PrimaryHeader->SizeOfPartitionEntry),
+ PartEntry
+ );
+ if (EFI_ERROR (Status)) {
+ GptValidStatus = Status;
+ DEBUG ((DEBUG_ERROR, " Partition Entry ReadDisk error\n"));
+ goto Done;
+ }
+
+ DEBUG ((DEBUG_INFO, " Partition entries read block success\n"));
+
+ DEBUG ((DEBUG_INFO, " Number of partition entries: %d\n", PrimaryHeader->NumberOfPartitionEntries));
+
+ PEntryStatus = AllocateZeroPool (PrimaryHeader->NumberOfPartitionEntries * sizeof (EFI_PARTITION_ENTRY_STATUS));
+ if (PEntryStatus == NULL) {
+ DEBUG ((DEBUG_ERROR, "Allocate pool error\n"));
+ goto Done;
+ }
+
+ //
+ // Check the integrity of partition entries
+ //
+ PartitionCheckGptEntry (PrimaryHeader, PartEntry, PEntryStatus);
+
+ //
+ // If we got this far the GPT layout of the disk is valid and we should return true
+ //
+ GptValidStatus = EFI_SUCCESS;
+
+ //
+ // Create child device handles
+ //
+ for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {
+ Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index * PrimaryHeader->SizeOfPartitionEntry);
+ if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid) ||
+ PEntryStatus[Index].OutOfRange ||
+ PEntryStatus[Index].Overlap ||
+ PEntryStatus[Index].OsSpecific
+ )
+ {
+ //
+ // Don't use null EFI Partition Entries, Invalid Partition Entries or OS specific
+ // partition Entries
+ //
+ continue;
+ }
+
+ ZeroMem (&HdDev, sizeof (HdDev));
+ HdDev.Header.Type = MEDIA_DEVICE_PATH;
+ HdDev.Header.SubType = MEDIA_HARDDRIVE_DP;
+ SetDevicePathNodeLength (&HdDev.Header, sizeof (HdDev));
+
+ HdDev.PartitionNumber = (UINT32)Index + 1;
+ HdDev.MBRType = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;
+ HdDev.SignatureType = SIGNATURE_TYPE_GUID;
+ HdDev.PartitionStart = Entry->StartingLBA;
+ HdDev.PartitionSize = Entry->EndingLBA - Entry->StartingLBA + 1;
+ CopyMem (HdDev.Signature, &Entry->UniquePartitionGUID, sizeof (EFI_GUID));
+
+ ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
+ PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
+ PartitionInfo.Type = PARTITION_TYPE_GPT;
+ if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeSystemPartGuid)) {
+ PartitionInfo.System = 1;
+ }
+
+ CopyMem (&PartitionInfo.Info.Gpt, Entry, sizeof (EFI_PARTITION_ENTRY));
+
+ DEBUG ((DEBUG_INFO, " Index : %d\n", (UINT32)Index));
+ DEBUG ((DEBUG_INFO, " Start LBA : %lx\n", (UINT64)HdDev.PartitionStart));
+ DEBUG ((DEBUG_INFO, " End LBA : %lx\n", (UINT64)Entry->EndingLBA));
+ DEBUG ((DEBUG_INFO, " Partition size: %lx\n", (UINT64)HdDev.PartitionSize));
+ DEBUG ((DEBUG_INFO, " Start : %lx", MultU64x32 (Entry->StartingLBA, BlockSize)));
+ DEBUG ((DEBUG_INFO, " End : %lx\n", MultU64x32 (Entry->EndingLBA, BlockSize)));
+
+ Status = PartitionInstallChildHandle (
+ This,
+ Handle,
+ DiskIo,
+ DiskIo2,
+ BlockIo,
+ BlockIo2,
+ DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *)&HdDev,
+ &PartitionInfo,
+ Entry->StartingLBA,
+ Entry->EndingLBA,
+ BlockSize,
+ &Entry->PartitionTypeGUID
+ );
+ }
+
+ DEBUG ((DEBUG_INFO, "Prepare to Free Pool\n"));
+
+Done:
+ if (ProtectiveMbr != NULL) {
+ FreePool (ProtectiveMbr);
+ }
+
+ if (PrimaryHeader != NULL) {
+ FreePool (PrimaryHeader);
+ }
+
+ if (BackupHeader != NULL) {
+ FreePool (BackupHeader);
+ }
+
+ if (PartEntry != NULL) {
+ FreePool (PartEntry);
+ }
+
+ if (PEntryStatus != NULL) {
+ FreePool (PEntryStatus);
+ }
+
+ return GptValidStatus;
+}
+
+/**
+ This routine will read GPT partition table header and return it.
+
+ Caution: This function may receive untrusted input.
+ The GPT partition table header is external input, so this routine
+ will do basic validation for GPT partition table header before return.
+
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] DiskIo Disk Io protocol.
+ @param[in] Lba The starting Lba of the Partition Table
+ @param[out] PartHeader Stores the partition table that is read
+
+ @retval TRUE The partition table is valid
+ @retval FALSE The partition table is not valid
+
+**/
+BOOLEAN
+PartitionValidGptTable (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_LBA Lba,
+ OUT EFI_PARTITION_TABLE_HEADER *PartHeader
+ )
+{
+ EFI_STATUS Status;
+ UINT32 BlockSize;
+ EFI_PARTITION_TABLE_HEADER *PartHdr;
+ UINT32 MediaId;
+
+ BlockSize = BlockIo->Media->BlockSize;
+ MediaId = BlockIo->Media->MediaId;
+ PartHdr = AllocateZeroPool (BlockSize);
+
+ if (PartHdr == NULL) {
+ DEBUG ((DEBUG_ERROR, "Allocate pool error\n"));
+ return FALSE;
+ }
+
+ //
+ // Read the EFI Partition Table Header
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ MediaId,
+ MultU64x32 (Lba, BlockSize),
+ BlockSize,
+ PartHdr
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (PartHdr);
+ return FALSE;
+ }
+
+ if ((PartHdr->Header.Signature != EFI_PTAB_HEADER_ID) ||
+ !PartitionCheckCrc (BlockSize, &PartHdr->Header) ||
+ (PartHdr->MyLBA != Lba) ||
+ (PartHdr->SizeOfPartitionEntry < sizeof (EFI_PARTITION_ENTRY))
+ )
+ {
+ DEBUG ((DEBUG_INFO, "Invalid efi partition table header\n"));
+ FreePool (PartHdr);
+ return FALSE;
+ }
+
+ //
+ // Ensure the NumberOfPartitionEntries * SizeOfPartitionEntry doesn't overflow.
+ //
+ if (PartHdr->NumberOfPartitionEntries > DivU64x32 (MAX_UINTN, PartHdr->SizeOfPartitionEntry)) {
+ FreePool (PartHdr);
+ return FALSE;
+ }
+
+ CopyMem (PartHeader, PartHdr, sizeof (EFI_PARTITION_TABLE_HEADER));
+ if (!PartitionCheckGptEntryArrayCRC (BlockIo, DiskIo, PartHeader)) {
+ FreePool (PartHdr);
+ return FALSE;
+ }
+
+ DEBUG ((DEBUG_INFO, " Valid efi partition table header\n"));
+ FreePool (PartHdr);
+ return TRUE;
+}
+
+/**
+ Check if the CRC field in the Partition table header is valid
+ for Partition entry array.
+
+ @param[in] BlockIo Parent BlockIo interface
+ @param[in] DiskIo Disk Io Protocol.
+ @param[in] PartHeader Partition table header structure
+
+ @retval TRUE the CRC is valid
+ @retval FALSE the CRC is invalid
+
+**/
+BOOLEAN
+PartitionCheckGptEntryArrayCRC (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_PARTITION_TABLE_HEADER *PartHeader
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *Ptr;
+ UINT32 Crc;
+ UINTN Size;
+
+ //
+ // Read the EFI Partition Entries
+ //
+ Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry);
+ if (Ptr == NULL) {
+ DEBUG ((DEBUG_ERROR, " Allocate pool error\n"));
+ return FALSE;
+ }
+
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32 (PartHeader->PartitionEntryLBA, BlockIo->Media->BlockSize),
+ PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,
+ Ptr
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (Ptr);
+ return FALSE;
+ }
+
+ Size = PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry;
+
+ Status = gBS->CalculateCrc32 (Ptr, Size, &Crc);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "CheckPEntryArrayCRC: Crc calculation failed\n"));
+ FreePool (Ptr);
+ return FALSE;
+ }
+
+ FreePool (Ptr);
+
+ return (BOOLEAN)(PartHeader->PartitionEntryArrayCRC32 == Crc);
+}
+
+/**
+ Restore Partition Table to its alternate place
+ (Primary -> Backup or Backup -> Primary).
+
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] DiskIo Disk Io Protocol.
+ @param[in] PartHeader Partition table header structure.
+
+ @retval TRUE Restoring succeeds
+ @retval FALSE Restoring failed
+
+**/
+BOOLEAN
+PartitionRestoreGptTable (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_PARTITION_TABLE_HEADER *PartHeader
+ )
+{
+ EFI_STATUS Status;
+ UINTN BlockSize;
+ EFI_PARTITION_TABLE_HEADER *PartHdr;
+ EFI_LBA PEntryLBA;
+ UINT8 *Ptr;
+ UINT32 MediaId;
+
+ PartHdr = NULL;
+ Ptr = NULL;
+
+ BlockSize = BlockIo->Media->BlockSize;
+ MediaId = BlockIo->Media->MediaId;
+
+ PartHdr = AllocateZeroPool (BlockSize);
+
+ if (PartHdr == NULL) {
+ DEBUG ((DEBUG_ERROR, "Allocate pool error\n"));
+ return FALSE;
+ }
+
+ PEntryLBA = (PartHeader->MyLBA == PRIMARY_PART_HEADER_LBA) ? \
+ (PartHeader->LastUsableLBA + 1) : \
+ (PRIMARY_PART_HEADER_LBA + 1);
+
+ CopyMem (PartHdr, PartHeader, sizeof (EFI_PARTITION_TABLE_HEADER));
+
+ PartHdr->MyLBA = PartHeader->AlternateLBA;
+ PartHdr->AlternateLBA = PartHeader->MyLBA;
+ PartHdr->PartitionEntryLBA = PEntryLBA;
+ PartitionSetCrc ((EFI_TABLE_HEADER *)PartHdr);
+
+ Status = DiskIo->WriteDisk (
+ DiskIo,
+ MediaId,
+ MultU64x32 (PartHdr->MyLBA, (UINT32)BlockSize),
+ BlockSize,
+ PartHdr
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry);
+ if (Ptr == NULL) {
+ DEBUG ((DEBUG_ERROR, " Allocate pool error\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ MediaId,
+ MultU64x32 (PartHeader->PartitionEntryLBA, (UINT32)BlockSize),
+ PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,
+ Ptr
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = DiskIo->WriteDisk (
+ DiskIo,
+ MediaId,
+ MultU64x32 (PEntryLBA, (UINT32)BlockSize),
+ PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,
+ Ptr
+ );
+
+Done:
+ FreePool (PartHdr);
+
+ if (Ptr != NULL) {
+ FreePool (Ptr);
+ }
+
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ This routine will check GPT partition entry and return entry status.
+
+ Caution: This function may receive untrusted input.
+ The GPT partition entry is external input, so this routine
+ will do basic validation for GPT partition entry and report status.
+
+ @param[in] PartHeader Partition table header structure
+ @param[in] PartEntry The partition entry array
+ @param[out] PEntryStatus the partition entry status array
+ recording the status of each partition
+
+**/
+VOID
+PartitionCheckGptEntry (
+ IN EFI_PARTITION_TABLE_HEADER *PartHeader,
+ IN EFI_PARTITION_ENTRY *PartEntry,
+ OUT EFI_PARTITION_ENTRY_STATUS *PEntryStatus
+ )
+{
+ EFI_LBA StartingLBA;
+ EFI_LBA EndingLBA;
+ EFI_PARTITION_ENTRY *Entry;
+ UINTN Index1;
+ UINTN Index2;
+
+ DEBUG ((DEBUG_INFO, " start check partition entries\n"));
+ for (Index1 = 0; Index1 < PartHeader->NumberOfPartitionEntries; Index1++) {
+ Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index1 * PartHeader->SizeOfPartitionEntry);
+ if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {
+ continue;
+ }
+
+ StartingLBA = Entry->StartingLBA;
+ EndingLBA = Entry->EndingLBA;
+ if ((StartingLBA > EndingLBA) ||
+ (StartingLBA < PartHeader->FirstUsableLBA) ||
+ (StartingLBA > PartHeader->LastUsableLBA) ||
+ (EndingLBA < PartHeader->FirstUsableLBA) ||
+ (EndingLBA > PartHeader->LastUsableLBA)
+ )
+ {
+ PEntryStatus[Index1].OutOfRange = TRUE;
+ continue;
+ }
+
+ if ((Entry->Attributes & BIT1) != 0) {
+ //
+ // If Bit 1 is set, this indicate that this is an OS specific GUID partition.
+ //
+ PEntryStatus[Index1].OsSpecific = TRUE;
+ }
+
+ for (Index2 = Index1 + 1; Index2 < PartHeader->NumberOfPartitionEntries; Index2++) {
+ Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index2 * PartHeader->SizeOfPartitionEntry);
+ if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {
+ continue;
+ }
+
+ if ((Entry->EndingLBA >= StartingLBA) && (Entry->StartingLBA <= EndingLBA)) {
+ //
+ // This region overlaps with the Index1'th region
+ //
+ PEntryStatus[Index1].Overlap = TRUE;
+ PEntryStatus[Index2].Overlap = TRUE;
+ continue;
+ }
+ }
+ }
+
+ DEBUG ((DEBUG_INFO, " End check partition entries\n"));
+}
+
+/**
+ Updates the CRC32 value in the table header.
+
+ @param Hdr Table to update
+
+**/
+VOID
+PartitionSetCrc (
+ IN OUT EFI_TABLE_HEADER *Hdr
+ )
+{
+ PartitionSetCrcAltSize (Hdr->HeaderSize, Hdr);
+}
+
+/**
+ Updates the CRC32 value in the table header.
+
+ @param Size The size of the table
+ @param Hdr Table to update
+
+**/
+VOID
+PartitionSetCrcAltSize (
+ IN UINTN Size,
+ IN OUT EFI_TABLE_HEADER *Hdr
+ )
+{
+ UINT32 Crc;
+
+ Hdr->CRC32 = 0;
+ gBS->CalculateCrc32 ((UINT8 *)Hdr, Size, &Crc);
+ Hdr->CRC32 = Crc;
+}
+
+/**
+ Checks the CRC32 value in the table header.
+
+ @param MaxSize Max Size limit
+ @param Hdr Table to check
+
+ @return TRUE CRC Valid
+ @return FALSE CRC Invalid
+
+**/
+BOOLEAN
+PartitionCheckCrc (
+ IN UINTN MaxSize,
+ IN OUT EFI_TABLE_HEADER *Hdr
+ )
+{
+ return PartitionCheckCrcAltSize (MaxSize, Hdr->HeaderSize, Hdr);
+}
+
+/**
+ Checks the CRC32 value in the table header.
+
+ @param MaxSize Max Size limit
+ @param Size The size of the table
+ @param Hdr Table to check
+
+ @return TRUE CRC Valid
+ @return FALSE CRC Invalid
+
+**/
+BOOLEAN
+PartitionCheckCrcAltSize (
+ IN UINTN MaxSize,
+ IN UINTN Size,
+ IN OUT EFI_TABLE_HEADER *Hdr
+ )
+{
+ UINT32 Crc;
+ UINT32 OrgCrc;
+ EFI_STATUS Status;
+
+ Crc = 0;
+
+ if (Size == 0) {
+ //
+ // If header size is 0 CRC will pass so return FALSE here
+ //
+ return FALSE;
+ }
+
+ if ((MaxSize != 0) && (Size > MaxSize)) {
+ DEBUG ((DEBUG_ERROR, "CheckCrc32: Size > MaxSize\n"));
+ return FALSE;
+ }
+
+ //
+ // clear old crc from header
+ //
+ OrgCrc = Hdr->CRC32;
+ Hdr->CRC32 = 0;
+
+ Status = gBS->CalculateCrc32 ((UINT8 *)Hdr, Size, &Crc);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "CheckCrc32: Crc calculation failed\n"));
+ return FALSE;
+ }
+
+ //
+ // set results
+ //
+ Hdr->CRC32 = Crc;
+
+ //
+ // return status
+ //
+ DEBUG_CODE_BEGIN ();
+ if (OrgCrc != Crc) {
+ DEBUG ((DEBUG_ERROR, "CheckCrc32: Crc check failed\n"));
+ }
+
+ DEBUG_CODE_END ();
+
+ return (BOOLEAN)(OrgCrc == Crc);
+}
diff --git a/MdeModulePkg/Universal/Disk/PartitionDxe/Mbr.c b/MdeModulePkg/Universal/Disk/PartitionDxe/Mbr.c
index 531b3b45ea..005d5991b4 100644
--- a/MdeModulePkg/Universal/Disk/PartitionDxe/Mbr.c
+++ b/MdeModulePkg/Universal/Disk/PartitionDxe/Mbr.c
@@ -1,369 +1,369 @@
-/** @file
- Decode a hard disk partitioned with the legacy MBR found on most PC's
-
- MBR - Master Boot Record is in the first sector of a partitioned hard disk.
- The MBR supports four partitions per disk. The MBR also contains legacy
- code that is not run on an EFI system. The legacy code reads the
- first sector of the active partition into memory and
-
- BPB - BIOS Parameter Block is in the first sector of a FAT file system.
- The BPB contains information about the FAT file system. The BPB is
- always on the first sector of a media. The first sector also contains
- the legacy boot strap code.
-
-Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
-Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>
-Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "Partition.h"
-
-/**
- Test to see if the Mbr buffer is a valid MBR.
-
- @param Mbr Parent Handle.
- @param LastLba Last Lba address on the device.
-
- @retval TRUE Mbr is a Valid MBR.
- @retval FALSE Mbr is not a Valid MBR.
-
-**/
-BOOLEAN
-PartitionValidMbr (
- IN MASTER_BOOT_RECORD *Mbr,
- IN EFI_LBA LastLba
- )
-{
- UINT32 StartingLBA;
- UINT32 EndingLBA;
- UINT32 NewEndingLBA;
- INTN Index1;
- INTN Index2;
- BOOLEAN MbrValid;
-
- if (Mbr->Signature != MBR_SIGNATURE) {
- return FALSE;
- }
-
- //
- // The BPB also has this signature, so it can not be used alone.
- //
- MbrValid = FALSE;
- for (Index1 = 0; Index1 < MAX_MBR_PARTITIONS; Index1++) {
- if ((Mbr->Partition[Index1].OSIndicator == 0x00) || (UNPACK_UINT32 (Mbr->Partition[Index1].SizeInLBA) == 0)) {
- continue;
- }
-
- MbrValid = TRUE;
- StartingLBA = UNPACK_UINT32 (Mbr->Partition[Index1].StartingLBA);
- EndingLBA = StartingLBA + UNPACK_UINT32 (Mbr->Partition[Index1].SizeInLBA) - 1;
- if (EndingLBA > LastLba) {
- //
- // Compatibility Errata:
- // Some systems try to hide drive space with their INT 13h driver
- // This does not hide space from the OS driver. This means the MBR
- // that gets created from DOS is smaller than the MBR created from
- // a real OS (NT & Win98). This leads to BlockIo->LastBlock being
- // wrong on some systems FDISKed by the OS.
- //
- // return FALSE since no block devices on a system are implemented
- // with INT 13h
- //
-
- DEBUG ((DEBUG_INFO, "PartitionValidMbr: Bad MBR partition size EndingLBA(%1x) > LastLBA(%1x)\n", EndingLBA, LastLba));
-
- return FALSE;
- }
-
- for (Index2 = Index1 + 1; Index2 < MAX_MBR_PARTITIONS; Index2++) {
- if ((Mbr->Partition[Index2].OSIndicator == 0x00) || (UNPACK_UINT32 (Mbr->Partition[Index2].SizeInLBA) == 0)) {
- continue;
- }
-
- NewEndingLBA = UNPACK_UINT32 (Mbr->Partition[Index2].StartingLBA) + UNPACK_UINT32 (Mbr->Partition[Index2].SizeInLBA) - 1;
- if ((NewEndingLBA >= StartingLBA) && (UNPACK_UINT32 (Mbr->Partition[Index2].StartingLBA) <= EndingLBA)) {
- //
- // This region overlaps with the Index1'th region
- //
- return FALSE;
- }
- }
- }
-
- //
- // None of the regions overlapped so MBR is O.K.
- //
- return MbrValid;
-}
-
-/**
- Install child handles if the Handle supports MBR format.
-
- @param[in] This Calling context.
- @param[in] Handle Parent Handle.
- @param[in] DiskIo Parent DiskIo interface.
- @param[in] DiskIo2 Parent DiskIo2 interface.
- @param[in] BlockIo Parent BlockIo interface.
- @param[in] BlockIo2 Parent BlockIo2 interface.
- @param[in] DevicePath Parent Device Path.
-
- @retval EFI_SUCCESS A child handle was added.
- @retval EFI_MEDIA_CHANGED Media change was detected.
- @retval Others MBR partition was not found.
-
-**/
-EFI_STATUS
-PartitionInstallMbrChildHandles (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE Handle,
- IN EFI_DISK_IO_PROTOCOL *DiskIo,
- IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
- IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
- IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
- IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
- )
-{
- EFI_STATUS Status;
- MASTER_BOOT_RECORD *Mbr;
- UINT32 ExtMbrStartingLba;
- UINT32 Index;
- HARDDRIVE_DEVICE_PATH HdDev;
- HARDDRIVE_DEVICE_PATH ParentHdDev;
- EFI_STATUS Found;
- EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
- EFI_DEVICE_PATH_PROTOCOL *LastDevicePathNode;
- UINT32 BlockSize;
- UINT32 MediaId;
- EFI_LBA LastSector;
- EFI_PARTITION_INFO_PROTOCOL PartitionInfo;
-
- Found = EFI_NOT_FOUND;
-
- BlockSize = BlockIo->Media->BlockSize;
- MediaId = BlockIo->Media->MediaId;
- LastSector = DivU64x32 (
- MultU64x32 (BlockIo->Media->LastBlock + 1, BlockSize),
- MBR_SIZE
- ) - 1;
-
- //
- // Ensure the block size can hold the MBR
- //
- if (BlockSize < sizeof (MASTER_BOOT_RECORD)) {
- return EFI_NOT_FOUND;
- }
-
- Mbr = AllocatePool (BlockSize);
- if (Mbr == NULL) {
- return Found;
- }
-
- Status = DiskIo->ReadDisk (
- DiskIo,
- MediaId,
- 0,
- BlockSize,
- Mbr
- );
- if (EFI_ERROR (Status)) {
- Found = Status;
- goto Done;
- }
-
- if (!PartitionValidMbr (Mbr, LastSector)) {
- goto Done;
- }
-
- //
- // We have a valid mbr - add each partition
- //
- //
- // Get starting and ending LBA of the parent block device.
- //
- LastDevicePathNode = NULL;
- ZeroMem (&ParentHdDev, sizeof (ParentHdDev));
- DevicePathNode = DevicePath;
- while (!IsDevicePathEnd (DevicePathNode)) {
- LastDevicePathNode = DevicePathNode;
- DevicePathNode = NextDevicePathNode (DevicePathNode);
- }
-
- if (LastDevicePathNode != NULL) {
- if ((DevicePathType (LastDevicePathNode) == MEDIA_DEVICE_PATH) &&
- (DevicePathSubType (LastDevicePathNode) == MEDIA_HARDDRIVE_DP)
- )
- {
- CopyMem (&ParentHdDev, LastDevicePathNode, sizeof (ParentHdDev));
- } else {
- LastDevicePathNode = NULL;
- }
- }
-
- ZeroMem (&HdDev, sizeof (HdDev));
- HdDev.Header.Type = MEDIA_DEVICE_PATH;
- HdDev.Header.SubType = MEDIA_HARDDRIVE_DP;
- SetDevicePathNodeLength (&HdDev.Header, sizeof (HdDev));
- HdDev.MBRType = MBR_TYPE_PCAT;
- HdDev.SignatureType = SIGNATURE_TYPE_MBR;
-
- if (LastDevicePathNode == NULL) {
- //
- // This is a MBR, add each partition
- //
- for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
- if ((Mbr->Partition[Index].OSIndicator == 0x00) || (UNPACK_UINT32 (Mbr->Partition[Index].SizeInLBA) == 0)) {
- //
- // Don't use null MBR entries
- //
- continue;
- }
-
- if (Mbr->Partition[Index].OSIndicator == PMBR_GPT_PARTITION) {
- //
- // This is the guard MBR for the GPT. If you ever see a GPT disk with zero partitions you can get here.
- // We can not produce an MBR BlockIo for this device as the MBR spans the GPT headers. So formating
- // this BlockIo would corrupt the GPT structures and require a recovery that would corrupt the format
- // that corrupted the GPT partition.
- //
- continue;
- }
-
- HdDev.PartitionNumber = Index + 1;
- HdDev.PartitionStart = UNPACK_UINT32 (Mbr->Partition[Index].StartingLBA);
- HdDev.PartitionSize = UNPACK_UINT32 (Mbr->Partition[Index].SizeInLBA);
- CopyMem (HdDev.Signature, &(Mbr->UniqueMbrSignature[0]), sizeof (Mbr->UniqueMbrSignature));
-
- ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
- PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
- PartitionInfo.Type = PARTITION_TYPE_MBR;
- if (Mbr->Partition[Index].OSIndicator == EFI_PARTITION) {
- PartitionInfo.System = 1;
- }
-
- CopyMem (&PartitionInfo.Info.Mbr, &Mbr->Partition[Index], sizeof (MBR_PARTITION_RECORD));
-
- Status = PartitionInstallChildHandle (
- This,
- Handle,
- DiskIo,
- DiskIo2,
- BlockIo,
- BlockIo2,
- DevicePath,
- (EFI_DEVICE_PATH_PROTOCOL *)&HdDev,
- &PartitionInfo,
- HdDev.PartitionStart,
- HdDev.PartitionStart + HdDev.PartitionSize - 1,
- MBR_SIZE,
- ((Mbr->Partition[Index].OSIndicator == EFI_PARTITION) ? &gEfiPartTypeSystemPartGuid : NULL)
- );
-
- if (!EFI_ERROR (Status)) {
- Found = EFI_SUCCESS;
- }
- }
- } else {
- //
- // It's an extended partition. Follow the extended partition
- // chain to get all the logical drives
- //
- Index = 0;
- ExtMbrStartingLba = 0;
-
- do {
- Status = DiskIo->ReadDisk (
- DiskIo,
- MediaId,
- MultU64x32 (ExtMbrStartingLba, BlockSize),
- BlockSize,
- Mbr
- );
- if (EFI_ERROR (Status)) {
- Found = Status;
- goto Done;
- }
-
- if (UNPACK_UINT32 (Mbr->Partition[0].SizeInLBA) == 0) {
- break;
- }
-
- if ((Mbr->Partition[0].OSIndicator == EXTENDED_DOS_PARTITION) ||
- (Mbr->Partition[0].OSIndicator == EXTENDED_WINDOWS_PARTITION))
- {
- ExtMbrStartingLba = UNPACK_UINT32 (Mbr->Partition[0].StartingLBA);
- //
- // A value of 0 is invalid for StartingLBA
- //
- if (ExtMbrStartingLba == 0) {
- break;
- }
-
- continue;
- }
-
- HdDev.PartitionNumber = ++Index;
- HdDev.PartitionStart = UNPACK_UINT32 (Mbr->Partition[0].StartingLBA) + ExtMbrStartingLba + ParentHdDev.PartitionStart;
- HdDev.PartitionSize = UNPACK_UINT32 (Mbr->Partition[0].SizeInLBA);
- if ((HdDev.PartitionStart + HdDev.PartitionSize - 1 >= ParentHdDev.PartitionStart + ParentHdDev.PartitionSize) ||
- (HdDev.PartitionStart <= ParentHdDev.PartitionStart))
- {
- break;
- }
-
- //
- // The signature in EBR(Extended Boot Record) should always be 0.
- //
- *((UINT32 *)&HdDev.Signature[0]) = 0;
-
- ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
- PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
- PartitionInfo.Type = PARTITION_TYPE_MBR;
- if (Mbr->Partition[0].OSIndicator == EFI_PARTITION) {
- PartitionInfo.System = 1;
- }
-
- CopyMem (&PartitionInfo.Info.Mbr, &Mbr->Partition[0], sizeof (MBR_PARTITION_RECORD));
-
- Status = PartitionInstallChildHandle (
- This,
- Handle,
- DiskIo,
- DiskIo2,
- BlockIo,
- BlockIo2,
- DevicePath,
- (EFI_DEVICE_PATH_PROTOCOL *)&HdDev,
- &PartitionInfo,
- HdDev.PartitionStart - ParentHdDev.PartitionStart,
- HdDev.PartitionStart - ParentHdDev.PartitionStart + HdDev.PartitionSize - 1,
- MBR_SIZE,
- ((Mbr->Partition[0].OSIndicator == EFI_PARTITION) ? &gEfiPartTypeSystemPartGuid : NULL)
- );
- if (!EFI_ERROR (Status)) {
- Found = EFI_SUCCESS;
- }
-
- if ((Mbr->Partition[1].OSIndicator != EXTENDED_DOS_PARTITION) &&
- (Mbr->Partition[1].OSIndicator != EXTENDED_WINDOWS_PARTITION)
- )
- {
- break;
- }
-
- ExtMbrStartingLba = UNPACK_UINT32 (Mbr->Partition[1].StartingLBA);
- //
- // Don't allow partition to be self referencing
- //
- if (ExtMbrStartingLba == 0) {
- break;
- }
- } while (ExtMbrStartingLba < ParentHdDev.PartitionSize);
- }
-
-Done:
- FreePool (Mbr);
-
- return Found;
-}
+/** @file
+ Decode a hard disk partitioned with the legacy MBR found on most PC's
+
+ MBR - Master Boot Record is in the first sector of a partitioned hard disk.
+ The MBR supports four partitions per disk. The MBR also contains legacy
+ code that is not run on an EFI system. The legacy code reads the
+ first sector of the active partition into memory and
+
+ BPB - BIOS Parameter Block is in the first sector of a FAT file system.
+ The BPB contains information about the FAT file system. The BPB is
+ always on the first sector of a media. The first sector also contains
+ the legacy boot strap code.
+
+Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
+Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Partition.h"
+
+/**
+ Test to see if the Mbr buffer is a valid MBR.
+
+ @param Mbr Parent Handle.
+ @param LastLba Last Lba address on the device.
+
+ @retval TRUE Mbr is a Valid MBR.
+ @retval FALSE Mbr is not a Valid MBR.
+
+**/
+BOOLEAN
+PartitionValidMbr (
+ IN MASTER_BOOT_RECORD *Mbr,
+ IN EFI_LBA LastLba
+ )
+{
+ UINT32 StartingLBA;
+ UINT32 EndingLBA;
+ UINT32 NewEndingLBA;
+ INTN Index1;
+ INTN Index2;
+ BOOLEAN MbrValid;
+
+ if (Mbr->Signature != MBR_SIGNATURE) {
+ return FALSE;
+ }
+
+ //
+ // The BPB also has this signature, so it can not be used alone.
+ //
+ MbrValid = FALSE;
+ for (Index1 = 0; Index1 < MAX_MBR_PARTITIONS; Index1++) {
+ if ((Mbr->Partition[Index1].OSIndicator == 0x00) || (UNPACK_UINT32 (Mbr->Partition[Index1].SizeInLBA) == 0)) {
+ continue;
+ }
+
+ MbrValid = TRUE;
+ StartingLBA = UNPACK_UINT32 (Mbr->Partition[Index1].StartingLBA);
+ EndingLBA = StartingLBA + UNPACK_UINT32 (Mbr->Partition[Index1].SizeInLBA) - 1;
+ if (EndingLBA > LastLba) {
+ //
+ // Compatibility Errata:
+ // Some systems try to hide drive space with their INT 13h driver
+ // This does not hide space from the OS driver. This means the MBR
+ // that gets created from DOS is smaller than the MBR created from
+ // a real OS (NT & Win98). This leads to BlockIo->LastBlock being
+ // wrong on some systems FDISKed by the OS.
+ //
+ // return FALSE since no block devices on a system are implemented
+ // with INT 13h
+ //
+
+ DEBUG ((DEBUG_INFO, "PartitionValidMbr: Bad MBR partition size EndingLBA(%1x) > LastLBA(%1x)\n", EndingLBA, LastLba));
+
+ return FALSE;
+ }
+
+ for (Index2 = Index1 + 1; Index2 < MAX_MBR_PARTITIONS; Index2++) {
+ if ((Mbr->Partition[Index2].OSIndicator == 0x00) || (UNPACK_UINT32 (Mbr->Partition[Index2].SizeInLBA) == 0)) {
+ continue;
+ }
+
+ NewEndingLBA = UNPACK_UINT32 (Mbr->Partition[Index2].StartingLBA) + UNPACK_UINT32 (Mbr->Partition[Index2].SizeInLBA) - 1;
+ if ((NewEndingLBA >= StartingLBA) && (UNPACK_UINT32 (Mbr->Partition[Index2].StartingLBA) <= EndingLBA)) {
+ //
+ // This region overlaps with the Index1'th region
+ //
+ return FALSE;
+ }
+ }
+ }
+
+ //
+ // None of the regions overlapped so MBR is O.K.
+ //
+ return MbrValid;
+}
+
+/**
+ Install child handles if the Handle supports MBR format.
+
+ @param[in] This Calling context.
+ @param[in] Handle Parent Handle.
+ @param[in] DiskIo Parent DiskIo interface.
+ @param[in] DiskIo2 Parent DiskIo2 interface.
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] BlockIo2 Parent BlockIo2 interface.
+ @param[in] DevicePath Parent Device Path.
+
+ @retval EFI_SUCCESS A child handle was added.
+ @retval EFI_MEDIA_CHANGED Media change was detected.
+ @retval Others MBR partition was not found.
+
+**/
+EFI_STATUS
+PartitionInstallMbrChildHandles (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_STATUS Status;
+ MASTER_BOOT_RECORD *Mbr;
+ UINT32 ExtMbrStartingLba;
+ UINT32 Index;
+ HARDDRIVE_DEVICE_PATH HdDev;
+ HARDDRIVE_DEVICE_PATH ParentHdDev;
+ EFI_STATUS Found;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
+ EFI_DEVICE_PATH_PROTOCOL *LastDevicePathNode;
+ UINT32 BlockSize;
+ UINT32 MediaId;
+ EFI_LBA LastSector;
+ EFI_PARTITION_INFO_PROTOCOL PartitionInfo;
+
+ Found = EFI_NOT_FOUND;
+
+ BlockSize = BlockIo->Media->BlockSize;
+ MediaId = BlockIo->Media->MediaId;
+ LastSector = DivU64x32 (
+ MultU64x32 (BlockIo->Media->LastBlock + 1, BlockSize),
+ MBR_SIZE
+ ) - 1;
+
+ //
+ // Ensure the block size can hold the MBR
+ //
+ if (BlockSize < sizeof (MASTER_BOOT_RECORD)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Mbr = AllocatePool (BlockSize);
+ if (Mbr == NULL) {
+ return Found;
+ }
+
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ MediaId,
+ 0,
+ BlockSize,
+ Mbr
+ );
+ if (EFI_ERROR (Status)) {
+ Found = Status;
+ goto Done;
+ }
+
+ if (!PartitionValidMbr (Mbr, LastSector)) {
+ goto Done;
+ }
+
+ //
+ // We have a valid mbr - add each partition
+ //
+ //
+ // Get starting and ending LBA of the parent block device.
+ //
+ LastDevicePathNode = NULL;
+ ZeroMem (&ParentHdDev, sizeof (ParentHdDev));
+ DevicePathNode = DevicePath;
+ while (!IsDevicePathEnd (DevicePathNode)) {
+ LastDevicePathNode = DevicePathNode;
+ DevicePathNode = NextDevicePathNode (DevicePathNode);
+ }
+
+ if (LastDevicePathNode != NULL) {
+ if ((DevicePathType (LastDevicePathNode) == MEDIA_DEVICE_PATH) &&
+ (DevicePathSubType (LastDevicePathNode) == MEDIA_HARDDRIVE_DP)
+ )
+ {
+ CopyMem (&ParentHdDev, LastDevicePathNode, sizeof (ParentHdDev));
+ } else {
+ LastDevicePathNode = NULL;
+ }
+ }
+
+ ZeroMem (&HdDev, sizeof (HdDev));
+ HdDev.Header.Type = MEDIA_DEVICE_PATH;
+ HdDev.Header.SubType = MEDIA_HARDDRIVE_DP;
+ SetDevicePathNodeLength (&HdDev.Header, sizeof (HdDev));
+ HdDev.MBRType = MBR_TYPE_PCAT;
+ HdDev.SignatureType = SIGNATURE_TYPE_MBR;
+
+ if (LastDevicePathNode == NULL) {
+ //
+ // This is a MBR, add each partition
+ //
+ for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
+ if ((Mbr->Partition[Index].OSIndicator == 0x00) || (UNPACK_UINT32 (Mbr->Partition[Index].SizeInLBA) == 0)) {
+ //
+ // Don't use null MBR entries
+ //
+ continue;
+ }
+
+ if (Mbr->Partition[Index].OSIndicator == PMBR_GPT_PARTITION) {
+ //
+ // This is the guard MBR for the GPT. If you ever see a GPT disk with zero partitions you can get here.
+ // We can not produce an MBR BlockIo for this device as the MBR spans the GPT headers. So formating
+ // this BlockIo would corrupt the GPT structures and require a recovery that would corrupt the format
+ // that corrupted the GPT partition.
+ //
+ continue;
+ }
+
+ HdDev.PartitionNumber = Index + 1;
+ HdDev.PartitionStart = UNPACK_UINT32 (Mbr->Partition[Index].StartingLBA);
+ HdDev.PartitionSize = UNPACK_UINT32 (Mbr->Partition[Index].SizeInLBA);
+ CopyMem (HdDev.Signature, &(Mbr->UniqueMbrSignature[0]), sizeof (Mbr->UniqueMbrSignature));
+
+ ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
+ PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
+ PartitionInfo.Type = PARTITION_TYPE_MBR;
+ if (Mbr->Partition[Index].OSIndicator == EFI_PARTITION) {
+ PartitionInfo.System = 1;
+ }
+
+ CopyMem (&PartitionInfo.Info.Mbr, &Mbr->Partition[Index], sizeof (MBR_PARTITION_RECORD));
+
+ Status = PartitionInstallChildHandle (
+ This,
+ Handle,
+ DiskIo,
+ DiskIo2,
+ BlockIo,
+ BlockIo2,
+ DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *)&HdDev,
+ &PartitionInfo,
+ HdDev.PartitionStart,
+ HdDev.PartitionStart + HdDev.PartitionSize - 1,
+ MBR_SIZE,
+ ((Mbr->Partition[Index].OSIndicator == EFI_PARTITION) ? &gEfiPartTypeSystemPartGuid : NULL)
+ );
+
+ if (!EFI_ERROR (Status)) {
+ Found = EFI_SUCCESS;
+ }
+ }
+ } else {
+ //
+ // It's an extended partition. Follow the extended partition
+ // chain to get all the logical drives
+ //
+ Index = 0;
+ ExtMbrStartingLba = 0;
+
+ do {
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ MediaId,
+ MultU64x32 (ExtMbrStartingLba, BlockSize),
+ BlockSize,
+ Mbr
+ );
+ if (EFI_ERROR (Status)) {
+ Found = Status;
+ goto Done;
+ }
+
+ if (UNPACK_UINT32 (Mbr->Partition[0].SizeInLBA) == 0) {
+ break;
+ }
+
+ if ((Mbr->Partition[0].OSIndicator == EXTENDED_DOS_PARTITION) ||
+ (Mbr->Partition[0].OSIndicator == EXTENDED_WINDOWS_PARTITION))
+ {
+ ExtMbrStartingLba = UNPACK_UINT32 (Mbr->Partition[0].StartingLBA);
+ //
+ // A value of 0 is invalid for StartingLBA
+ //
+ if (ExtMbrStartingLba == 0) {
+ break;
+ }
+
+ continue;
+ }
+
+ HdDev.PartitionNumber = ++Index;
+ HdDev.PartitionStart = UNPACK_UINT32 (Mbr->Partition[0].StartingLBA) + ExtMbrStartingLba + ParentHdDev.PartitionStart;
+ HdDev.PartitionSize = UNPACK_UINT32 (Mbr->Partition[0].SizeInLBA);
+ if ((HdDev.PartitionStart + HdDev.PartitionSize - 1 >= ParentHdDev.PartitionStart + ParentHdDev.PartitionSize) ||
+ (HdDev.PartitionStart <= ParentHdDev.PartitionStart))
+ {
+ break;
+ }
+
+ //
+ // The signature in EBR(Extended Boot Record) should always be 0.
+ //
+ *((UINT32 *)&HdDev.Signature[0]) = 0;
+
+ ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
+ PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
+ PartitionInfo.Type = PARTITION_TYPE_MBR;
+ if (Mbr->Partition[0].OSIndicator == EFI_PARTITION) {
+ PartitionInfo.System = 1;
+ }
+
+ CopyMem (&PartitionInfo.Info.Mbr, &Mbr->Partition[0], sizeof (MBR_PARTITION_RECORD));
+
+ Status = PartitionInstallChildHandle (
+ This,
+ Handle,
+ DiskIo,
+ DiskIo2,
+ BlockIo,
+ BlockIo2,
+ DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *)&HdDev,
+ &PartitionInfo,
+ HdDev.PartitionStart - ParentHdDev.PartitionStart,
+ HdDev.PartitionStart - ParentHdDev.PartitionStart + HdDev.PartitionSize - 1,
+ MBR_SIZE,
+ ((Mbr->Partition[0].OSIndicator == EFI_PARTITION) ? &gEfiPartTypeSystemPartGuid : NULL)
+ );
+ if (!EFI_ERROR (Status)) {
+ Found = EFI_SUCCESS;
+ }
+
+ if ((Mbr->Partition[1].OSIndicator != EXTENDED_DOS_PARTITION) &&
+ (Mbr->Partition[1].OSIndicator != EXTENDED_WINDOWS_PARTITION)
+ )
+ {
+ break;
+ }
+
+ ExtMbrStartingLba = UNPACK_UINT32 (Mbr->Partition[1].StartingLBA);
+ //
+ // Don't allow partition to be self referencing
+ //
+ if (ExtMbrStartingLba == 0) {
+ break;
+ }
+ } while (ExtMbrStartingLba < ParentHdDev.PartitionSize);
+ }
+
+Done:
+ FreePool (Mbr);
+
+ return Found;
+}
diff --git a/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c b/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c
index bc89559727..7e81c9ccbe 100644
--- a/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c
+++ b/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c
@@ -1,1381 +1,1381 @@
-/** @file
- Partition driver that produces logical BlockIo devices from a physical
- BlockIo device. The logical BlockIo devices are based on the format
- of the raw block devices media. Currently "El Torito CD-ROM", UDF, Legacy
- MBR, and GPT partition schemes are supported.
-
-Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "Partition.h"
-
-//
-// Partition Driver Global Variables.
-//
-EFI_DRIVER_BINDING_PROTOCOL gPartitionDriverBinding = {
- PartitionDriverBindingSupported,
- PartitionDriverBindingStart,
- PartitionDriverBindingStop,
- //
- // Grub4Dos copies the BPB of the first partition to the MBR. If the
- // DriverBindingStart() of the Fat driver gets run before that of Partition
- // driver only the first partition can be recognized.
- // Let the driver binding version of Partition driver be higher than that of
- // Fat driver to make sure the DriverBindingStart() of the Partition driver
- // gets run before that of Fat driver so that all the partitions can be recognized.
- //
- 0xb,
- NULL,
- NULL
-};
-
-//
-// Prioritized function list to detect partition table.
-// Refer to UEFI Spec 13.3.2 Partition Discovery, the block device
-// should be scanned in below order:
-// 1. GPT
-// 2. ISO 9660 (El Torito) (or UDF)
-// 3. MBR
-// 4. no partiton found
-// Note: UDF is using a same method as booting from CD-ROM, so put it along
-// with CD-ROM check.
-//
-PARTITION_DETECT_ROUTINE mPartitionDetectRoutineTable[] = {
- PartitionInstallGptChildHandles,
- PartitionInstallUdfChildHandles,
- PartitionInstallMbrChildHandles,
- NULL
-};
-
-/**
- Test to see if this driver supports ControllerHandle. Any ControllerHandle
- than contains a BlockIo and DiskIo protocol or a BlockIo2 protocol can be
- supported.
-
- @param[in] This Protocol instance pointer.
- @param[in] ControllerHandle Handle of device to test.
- @param[in] RemainingDevicePath Optional parameter use to pick a specific child
- device to start.
-
- @retval EFI_SUCCESS This driver supports this device
- @retval EFI_ALREADY_STARTED This driver is already running on this device
- @retval other This driver does not support this device
-
-**/
-EFI_STATUS
-EFIAPI
-PartitionDriverBindingSupported (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE ControllerHandle,
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
- )
-{
- EFI_STATUS Status;
- EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
- EFI_DISK_IO_PROTOCOL *DiskIo;
- EFI_DEV_PATH *Node;
-
- //
- // Check RemainingDevicePath validation
- //
- if (RemainingDevicePath != NULL) {
- //
- // Check if RemainingDevicePath is the End of Device Path Node,
- // if yes, go on checking other conditions
- //
- if (!IsDevicePathEnd (RemainingDevicePath)) {
- //
- // If RemainingDevicePath isn't the End of Device Path Node,
- // check its validation
- //
- Node = (EFI_DEV_PATH *)RemainingDevicePath;
- if ((Node->DevPath.Type != MEDIA_DEVICE_PATH) ||
- (Node->DevPath.SubType != MEDIA_HARDDRIVE_DP) ||
- (DevicePathNodeLength (&Node->DevPath) != sizeof (HARDDRIVE_DEVICE_PATH)))
- {
- return EFI_UNSUPPORTED;
- }
- }
- }
-
- //
- // Open the IO Abstraction(s) needed to perform the supported test
- //
- Status = gBS->OpenProtocol (
- ControllerHandle,
- &gEfiDiskIoProtocolGuid,
- (VOID **)&DiskIo,
- This->DriverBindingHandle,
- ControllerHandle,
- EFI_OPEN_PROTOCOL_BY_DRIVER
- );
- if (Status == EFI_ALREADY_STARTED) {
- return EFI_SUCCESS;
- }
-
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Close the I/O Abstraction(s) used to perform the supported test
- //
- gBS->CloseProtocol (
- ControllerHandle,
- &gEfiDiskIoProtocolGuid,
- This->DriverBindingHandle,
- ControllerHandle
- );
-
- //
- // Open the EFI Device Path protocol needed to perform the supported test
- //
- Status = gBS->OpenProtocol (
- ControllerHandle,
- &gEfiDevicePathProtocolGuid,
- (VOID **)&ParentDevicePath,
- This->DriverBindingHandle,
- ControllerHandle,
- EFI_OPEN_PROTOCOL_BY_DRIVER
- );
- if (Status == EFI_ALREADY_STARTED) {
- return EFI_SUCCESS;
- }
-
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Close protocol, don't use device path protocol in the Support() function
- //
- gBS->CloseProtocol (
- ControllerHandle,
- &gEfiDevicePathProtocolGuid,
- This->DriverBindingHandle,
- ControllerHandle
- );
-
- //
- // Open the IO Abstraction(s) needed to perform the supported test
- //
- Status = gBS->OpenProtocol (
- ControllerHandle,
- &gEfiBlockIoProtocolGuid,
- NULL,
- This->DriverBindingHandle,
- ControllerHandle,
- EFI_OPEN_PROTOCOL_TEST_PROTOCOL
- );
-
- return Status;
-}
-
-/**
- Start this driver on ControllerHandle by opening a Block IO or a Block IO2
- or both, and Disk IO protocol, reading Device Path, and creating a child
- handle with a Disk IO and device path protocol.
-
- @param[in] This Protocol instance pointer.
- @param[in] ControllerHandle Handle of device to bind driver to
- @param[in] RemainingDevicePath Optional parameter use to pick a specific child
- device to start.
-
- @retval EFI_SUCCESS This driver is added to ControllerHandle
- @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
- @retval other This driver does not support this device
-
-**/
-EFI_STATUS
-EFIAPI
-PartitionDriverBindingStart (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE ControllerHandle,
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
- )
-{
- EFI_STATUS Status;
- EFI_STATUS OpenStatus;
- EFI_BLOCK_IO_PROTOCOL *BlockIo;
- EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
- EFI_DISK_IO_PROTOCOL *DiskIo;
- EFI_DISK_IO2_PROTOCOL *DiskIo2;
- EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
- PARTITION_DETECT_ROUTINE *Routine;
- BOOLEAN MediaPresent;
- EFI_TPL OldTpl;
-
- BlockIo2 = NULL;
- OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
- //
- // Check RemainingDevicePath validation
- //
- if (RemainingDevicePath != NULL) {
- //
- // Check if RemainingDevicePath is the End of Device Path Node,
- // if yes, return EFI_SUCCESS
- //
- if (IsDevicePathEnd (RemainingDevicePath)) {
- Status = EFI_SUCCESS;
- goto Exit;
- }
- }
-
- //
- // Try to open BlockIO and BlockIO2. If BlockIO would be opened, continue,
- // otherwise, return error.
- //
- Status = gBS->OpenProtocol (
- ControllerHandle,
- &gEfiBlockIoProtocolGuid,
- (VOID **)&BlockIo,
- This->DriverBindingHandle,
- ControllerHandle,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
- if (EFI_ERROR (Status)) {
- goto Exit;
- }
-
- Status = gBS->OpenProtocol (
- ControllerHandle,
- &gEfiBlockIo2ProtocolGuid,
- (VOID **)&BlockIo2,
- This->DriverBindingHandle,
- ControllerHandle,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
- if (EFI_ERROR (Status)) {
- BlockIo2 = NULL;
- }
-
- //
- // Get the Device Path Protocol on ControllerHandle's handle.
- //
- Status = gBS->OpenProtocol (
- ControllerHandle,
- &gEfiDevicePathProtocolGuid,
- (VOID **)&ParentDevicePath,
- This->DriverBindingHandle,
- ControllerHandle,
- EFI_OPEN_PROTOCOL_BY_DRIVER
- );
- if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
- goto Exit;
- }
-
- //
- // Get the DiskIo and DiskIo2.
- //
- Status = gBS->OpenProtocol (
- ControllerHandle,
- &gEfiDiskIoProtocolGuid,
- (VOID **)&DiskIo,
- This->DriverBindingHandle,
- ControllerHandle,
- EFI_OPEN_PROTOCOL_BY_DRIVER
- );
- if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
- gBS->CloseProtocol (
- ControllerHandle,
- &gEfiDevicePathProtocolGuid,
- This->DriverBindingHandle,
- ControllerHandle
- );
- goto Exit;
- }
-
- OpenStatus = Status;
-
- Status = gBS->OpenProtocol (
- ControllerHandle,
- &gEfiDiskIo2ProtocolGuid,
- (VOID **)&DiskIo2,
- This->DriverBindingHandle,
- ControllerHandle,
- EFI_OPEN_PROTOCOL_BY_DRIVER
- );
- if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
- DiskIo2 = NULL;
- }
-
- //
- // Try to read blocks when there's media or it is removable physical partition.
- //
- Status = EFI_UNSUPPORTED;
- MediaPresent = BlockIo->Media->MediaPresent;
- if (BlockIo->Media->MediaPresent ||
- (BlockIo->Media->RemovableMedia && !BlockIo->Media->LogicalPartition))
- {
- //
- // Try for GPT, then legacy MBR partition types, and then UDF and El Torito.
- // If the media supports a given partition type install child handles to
- // represent the partitions described by the media.
- //
- Routine = &mPartitionDetectRoutineTable[0];
- while (*Routine != NULL) {
- Status = (*Routine)(
- This,
- ControllerHandle,
- DiskIo,
- DiskIo2,
- BlockIo,
- BlockIo2,
- ParentDevicePath
- );
- if (!EFI_ERROR (Status) || (Status == EFI_MEDIA_CHANGED) || (Status == EFI_NO_MEDIA)) {
- break;
- }
-
- Routine++;
- }
- }
-
- //
- // In the case that the driver is already started (OpenStatus == EFI_ALREADY_STARTED),
- // the DevicePathProtocol and the DiskIoProtocol are not actually opened by the
- // driver. So don't try to close them. Otherwise, we will break the dependency
- // between the controller and the driver set up before.
- //
- // In the case that when the media changes on a device it will Reinstall the
- // BlockIo interaface. This will cause a call to our Stop(), and a subsequent
- // reentrant call to our Start() successfully. We should leave the device open
- // when this happen. The "media change" case includes either the status is
- // EFI_MEDIA_CHANGED or it is a "media" to "no media" change.
- //
- if (EFI_ERROR (Status) &&
- !EFI_ERROR (OpenStatus) &&
- (Status != EFI_MEDIA_CHANGED) &&
- !(MediaPresent && (Status == EFI_NO_MEDIA)))
- {
- gBS->CloseProtocol (
- ControllerHandle,
- &gEfiDiskIoProtocolGuid,
- This->DriverBindingHandle,
- ControllerHandle
- );
- //
- // Close Parent DiskIo2 if has.
- //
- gBS->CloseProtocol (
- ControllerHandle,
- &gEfiDiskIo2ProtocolGuid,
- This->DriverBindingHandle,
- ControllerHandle
- );
-
- gBS->CloseProtocol (
- ControllerHandle,
- &gEfiDevicePathProtocolGuid,
- This->DriverBindingHandle,
- ControllerHandle
- );
- }
-
-Exit:
- gBS->RestoreTPL (OldTpl);
- return Status;
-}
-
-/**
- Stop this driver on ControllerHandle. Support stopping any child handles
- created by this driver.
-
- @param This Protocol instance pointer.
- @param ControllerHandle Handle of device to stop driver on
- @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
- children is zero stop the entire bus driver.
- @param ChildHandleBuffer List of Child Handles to Stop.
-
- @retval EFI_SUCCESS This driver is removed ControllerHandle
- @retval other This driver was not removed from this device
-
-**/
-EFI_STATUS
-EFIAPI
-PartitionDriverBindingStop (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE ControllerHandle,
- IN UINTN NumberOfChildren,
- IN EFI_HANDLE *ChildHandleBuffer
- )
-{
- EFI_STATUS Status;
- UINTN Index;
- EFI_BLOCK_IO_PROTOCOL *BlockIo;
- EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
- BOOLEAN AllChildrenStopped;
- PARTITION_PRIVATE_DATA *Private;
- EFI_DISK_IO_PROTOCOL *DiskIo;
- EFI_GUID *TypeGuid;
-
- BlockIo = NULL;
- BlockIo2 = NULL;
- Private = NULL;
-
- if (NumberOfChildren == 0) {
- //
- // In the case of re-entry of the PartitionDriverBindingStop, the
- // NumberOfChildren may not reflect the actual number of children on the
- // bus driver. Hence, additional check is needed here.
- //
- if (HasChildren (ControllerHandle)) {
- DEBUG ((DEBUG_ERROR, "PartitionDriverBindingStop: Still has child.\n"));
- return EFI_DEVICE_ERROR;
- }
-
- //
- // Close the bus driver
- //
- gBS->CloseProtocol (
- ControllerHandle,
- &gEfiDiskIoProtocolGuid,
- This->DriverBindingHandle,
- ControllerHandle
- );
- //
- // Close Parent BlockIO2 if has.
- //
- gBS->CloseProtocol (
- ControllerHandle,
- &gEfiDiskIo2ProtocolGuid,
- This->DriverBindingHandle,
- ControllerHandle
- );
-
- gBS->CloseProtocol (
- ControllerHandle,
- &gEfiDevicePathProtocolGuid,
- This->DriverBindingHandle,
- ControllerHandle
- );
- return EFI_SUCCESS;
- }
-
- AllChildrenStopped = TRUE;
- for (Index = 0; Index < NumberOfChildren; Index++) {
- gBS->OpenProtocol (
- ChildHandleBuffer[Index],
- &gEfiBlockIoProtocolGuid,
- (VOID **)&BlockIo,
- This->DriverBindingHandle,
- ControllerHandle,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
- //
- // Try to locate BlockIo2.
- //
- gBS->OpenProtocol (
- ChildHandleBuffer[Index],
- &gEfiBlockIo2ProtocolGuid,
- (VOID **)&BlockIo2,
- This->DriverBindingHandle,
- ControllerHandle,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
-
- Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo);
- if (Private->InStop) {
- //
- // If the child handle is going to be stopped again during the re-entry
- // of DriverBindingStop, just do nothing.
- //
- break;
- }
-
- Private->InStop = TRUE;
-
- BlockIo->FlushBlocks (BlockIo);
-
- if (BlockIo2 != NULL) {
- Status = BlockIo2->FlushBlocksEx (BlockIo2, NULL);
- DEBUG ((DEBUG_ERROR, "PartitionDriverBindingStop: FlushBlocksEx returned with %r\n", Status));
- } else {
- Status = EFI_SUCCESS;
- }
-
- gBS->CloseProtocol (
- ControllerHandle,
- &gEfiDiskIoProtocolGuid,
- This->DriverBindingHandle,
- ChildHandleBuffer[Index]
- );
-
- if (IsZeroGuid (&Private->TypeGuid)) {
- TypeGuid = NULL;
- } else {
- TypeGuid = &Private->TypeGuid;
- }
-
- //
- // All Software protocols have be freed from the handle so remove it.
- // Remove the BlockIo Protocol if has.
- // Remove the BlockIo2 Protocol if has.
- //
- if (BlockIo2 != NULL) {
- //
- // Some device drivers might re-install the BlockIO(2) protocols for a
- // media change condition. Therefore, if the FlushBlocksEx returned with
- // EFI_MEDIA_CHANGED, just let the BindingStop fail to avoid potential
- // reference of already stopped child handle.
- //
- if (Status != EFI_MEDIA_CHANGED) {
- Status = gBS->UninstallMultipleProtocolInterfaces (
- ChildHandleBuffer[Index],
- &gEfiDevicePathProtocolGuid,
- Private->DevicePath,
- &gEfiBlockIoProtocolGuid,
- &Private->BlockIo,
- &gEfiBlockIo2ProtocolGuid,
- &Private->BlockIo2,
- &gEfiPartitionInfoProtocolGuid,
- &Private->PartitionInfo,
- TypeGuid,
- NULL,
- NULL
- );
- }
- } else {
- Status = gBS->UninstallMultipleProtocolInterfaces (
- ChildHandleBuffer[Index],
- &gEfiDevicePathProtocolGuid,
- Private->DevicePath,
- &gEfiBlockIoProtocolGuid,
- &Private->BlockIo,
- &gEfiPartitionInfoProtocolGuid,
- &Private->PartitionInfo,
- TypeGuid,
- NULL,
- NULL
- );
- }
-
- if (EFI_ERROR (Status)) {
- Private->InStop = FALSE;
- gBS->OpenProtocol (
- ControllerHandle,
- &gEfiDiskIoProtocolGuid,
- (VOID **)&DiskIo,
- This->DriverBindingHandle,
- ChildHandleBuffer[Index],
- EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
- );
- } else {
- FreePool (Private->DevicePath);
- FreePool (Private);
- }
-
- if (EFI_ERROR (Status)) {
- AllChildrenStopped = FALSE;
- if (Status == EFI_MEDIA_CHANGED) {
- break;
- }
- }
- }
-
- if (!AllChildrenStopped) {
- return EFI_DEVICE_ERROR;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Reset the Block Device.
-
- @param This Protocol instance pointer.
- @param ExtendedVerification Driver may perform diagnostics on reset.
-
- @retval EFI_SUCCESS The device was reset.
- @retval EFI_DEVICE_ERROR The device is not functioning properly and could
- not be reset.
-
-**/
-EFI_STATUS
-EFIAPI
-PartitionReset (
- IN EFI_BLOCK_IO_PROTOCOL *This,
- IN BOOLEAN ExtendedVerification
- )
-{
- PARTITION_PRIVATE_DATA *Private;
-
- Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
-
- return Private->ParentBlockIo->Reset (
- Private->ParentBlockIo,
- ExtendedVerification
- );
-}
-
-/**
- Probe the media status and return EFI_NO_MEDIA or EFI_MEDIA_CHANGED
- for no media or media change case. Otherwise DefaultStatus is returned.
-
- @param DiskIo Pointer to the DiskIo instance.
- @param MediaId Id of the media, changes every time the media is replaced.
- @param DefaultStatus The default status to return when it's not the no media
- or media change case.
-
- @retval EFI_NO_MEDIA There is no media.
- @retval EFI_MEDIA_CHANGED The media was changed.
- @retval others The default status to return.
-**/
-EFI_STATUS
-ProbeMediaStatus (
- IN EFI_DISK_IO_PROTOCOL *DiskIo,
- IN UINT32 MediaId,
- IN EFI_STATUS DefaultStatus
- )
-{
- EFI_STATUS Status;
- UINT8 Buffer[1];
-
- //
- // Read 1 byte from offset 0 to check if the MediaId is still valid.
- // The reading operation is synchronious thus it is not worth it to
- // allocate a buffer from the pool. The destination buffer for the
- // data is in the stack.
- //
- Status = DiskIo->ReadDisk (DiskIo, MediaId, 0, 1, (VOID *)Buffer);
- if ((Status == EFI_NO_MEDIA) || (Status == EFI_MEDIA_CHANGED)) {
- return Status;
- }
-
- return DefaultStatus;
-}
-
-/**
- Read by using the Disk IO protocol on the parent device. Lba addresses
- must be converted to byte offsets.
-
- @param This Protocol instance pointer.
- @param MediaId Id of the media, changes every time the media is replaced.
- @param Lba The starting Logical Block Address to read from
- @param BufferSize Size of Buffer, must be a multiple of device block size.
- @param Buffer Buffer containing read data
-
- @retval EFI_SUCCESS The data was read correctly from the device.
- @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
- @retval EFI_NO_MEDIA There is no media in the device.
- @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
- @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
- @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
- valid for the device.
-
-**/
-EFI_STATUS
-EFIAPI
-PartitionReadBlocks (
- IN EFI_BLOCK_IO_PROTOCOL *This,
- IN UINT32 MediaId,
- IN EFI_LBA Lba,
- IN UINTN BufferSize,
- OUT VOID *Buffer
- )
-{
- PARTITION_PRIVATE_DATA *Private;
- UINT64 Offset;
-
- Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
-
- if (BufferSize % Private->BlockSize != 0) {
- return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_BAD_BUFFER_SIZE);
- }
-
- Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
- if (Offset + BufferSize > Private->End) {
- return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_INVALID_PARAMETER);
- }
-
- //
- // Because some kinds of partition have different block size from their parent
- // device, we call the Disk IO protocol on the parent device, not the Block IO
- // protocol
- //
- return Private->DiskIo->ReadDisk (Private->DiskIo, MediaId, Offset, BufferSize, Buffer);
-}
-
-/**
- Write by using the Disk IO protocol on the parent device. Lba addresses
- must be converted to byte offsets.
-
- @param[in] This Protocol instance pointer.
- @param[in] MediaId Id of the media, changes every time the media is replaced.
- @param[in] Lba The starting Logical Block Address to read from
- @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
- @param[in] Buffer Buffer containing data to be written to device.
-
- @retval EFI_SUCCESS The data was written correctly to the device.
- @retval EFI_WRITE_PROTECTED The device can not be written to.
- @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
- @retval EFI_NO_MEDIA There is no media in the device.
- @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
- @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
- @retval EFI_INVALID_PARAMETER The write request contains a LBA that is not
- valid for the device.
-
-**/
-EFI_STATUS
-EFIAPI
-PartitionWriteBlocks (
- IN EFI_BLOCK_IO_PROTOCOL *This,
- IN UINT32 MediaId,
- IN EFI_LBA Lba,
- IN UINTN BufferSize,
- IN VOID *Buffer
- )
-{
- PARTITION_PRIVATE_DATA *Private;
- UINT64 Offset;
-
- Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
-
- if (BufferSize % Private->BlockSize != 0) {
- return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_BAD_BUFFER_SIZE);
- }
-
- Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
- if (Offset + BufferSize > Private->End) {
- return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_INVALID_PARAMETER);
- }
-
- //
- // Because some kinds of partition have different block size from their parent
- // device, we call the Disk IO protocol on the parent device, not the Block IO
- // protocol
- //
- return Private->DiskIo->WriteDisk (Private->DiskIo, MediaId, Offset, BufferSize, Buffer);
-}
-
-/**
- Flush the parent Block Device.
-
- @param This Protocol instance pointer.
-
- @retval EFI_SUCCESS All outstanding data was written to the device
- @retval EFI_DEVICE_ERROR The device reported an error while writting back the data
- @retval EFI_NO_MEDIA There is no media in the device.
-
-**/
-EFI_STATUS
-EFIAPI
-PartitionFlushBlocks (
- IN EFI_BLOCK_IO_PROTOCOL *This
- )
-{
- PARTITION_PRIVATE_DATA *Private;
-
- Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
-
- return Private->ParentBlockIo->FlushBlocks (Private->ParentBlockIo);
-}
-
-/**
- Probe the media status and return EFI_NO_MEDIA or EFI_MEDIA_CHANGED
- for no media or media change case. Otherwise DefaultStatus is returned.
-
- @param DiskIo2 Pointer to the DiskIo2 instance.
- @param MediaId Id of the media, changes every time the media is replaced.
- @param DefaultStatus The default status to return when it's not the no media
- or media change case.
-
- @retval EFI_NO_MEDIA There is no media.
- @retval EFI_MEDIA_CHANGED The media was changed.
- @retval others The default status to return.
-**/
-EFI_STATUS
-ProbeMediaStatusEx (
- IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
- IN UINT32 MediaId,
- IN EFI_STATUS DefaultStatus
- )
-{
- EFI_STATUS Status;
- UINT8 Buffer[1];
-
- //
- // Read 1 byte from offset 0 to check if the MediaId is still valid.
- // The reading operation is synchronious thus it is not worth it to
- // allocate a buffer from the pool. The destination buffer for the
- // data is in the stack.
- //
- Status = DiskIo2->ReadDiskEx (DiskIo2, MediaId, 0, NULL, 1, (VOID *)Buffer);
- if ((Status == EFI_NO_MEDIA) || (Status == EFI_MEDIA_CHANGED)) {
- return Status;
- }
-
- return DefaultStatus;
-}
-
-/**
- Reset the Block Device throught Block I/O2 protocol.
-
- @param This Protocol instance pointer.
- @param ExtendedVerification Driver may perform diagnostics on reset.
-
- @retval EFI_SUCCESS The device was reset.
- @retval EFI_DEVICE_ERROR The device is not functioning properly and could
- not be reset.
-
-**/
-EFI_STATUS
-EFIAPI
-PartitionResetEx (
- IN EFI_BLOCK_IO2_PROTOCOL *This,
- IN BOOLEAN ExtendedVerification
- )
-{
- PARTITION_PRIVATE_DATA *Private;
-
- Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
-
- return Private->ParentBlockIo2->Reset (
- Private->ParentBlockIo2,
- ExtendedVerification
- );
-}
-
-/**
- The general callback for the DiskIo2 interfaces.
- @param Event Event whose notification function is being invoked.
- @param Context The pointer to the notification function's context,
- which points to the PARTITION_ACCESS_TASK instance.
-**/
-VOID
-EFIAPI
-PartitionOnAccessComplete (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- PARTITION_ACCESS_TASK *Task;
-
- Task = (PARTITION_ACCESS_TASK *)Context;
-
- gBS->CloseEvent (Event);
-
- Task->BlockIo2Token->TransactionStatus = Task->DiskIo2Token.TransactionStatus;
- gBS->SignalEvent (Task->BlockIo2Token->Event);
-
- FreePool (Task);
-}
-
-/**
- Create a new PARTITION_ACCESS_TASK instance.
-
- @param Token Pointer to the EFI_BLOCK_IO2_TOKEN.
-
- @return Pointer to the created PARTITION_ACCESS_TASK instance or NULL upon failure.
-**/
-PARTITION_ACCESS_TASK *
-PartitionCreateAccessTask (
- IN EFI_BLOCK_IO2_TOKEN *Token
- )
-{
- EFI_STATUS Status;
- PARTITION_ACCESS_TASK *Task;
-
- Task = AllocatePool (sizeof (*Task));
- if (Task == NULL) {
- return NULL;
- }
-
- Status = gBS->CreateEvent (
- EVT_NOTIFY_SIGNAL,
- TPL_NOTIFY,
- PartitionOnAccessComplete,
- Task,
- &Task->DiskIo2Token.Event
- );
- if (EFI_ERROR (Status)) {
- FreePool (Task);
- return NULL;
- }
-
- Task->BlockIo2Token = Token;
-
- return Task;
-}
-
-/**
- Read BufferSize bytes from Lba into Buffer.
-
- This function reads the requested number of blocks from the device. All the
- blocks are read, or an error is returned.
- If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and
- non-blocking I/O is being used, the Event associated with this request will
- not be signaled.
-
- @param[in] This Indicates a pointer to the calling context.
- @param[in] MediaId Id of the media, changes every time the media is
- replaced.
- @param[in] Lba The starting Logical Block Address to read from.
- @param[in, out] Token A pointer to the token associated with the transaction.
- @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
- @param[out] Buffer A pointer to the destination buffer for the data. The
- caller is responsible for either having implicit or
- explicit ownership of the buffer.
-
- @retval EFI_SUCCESS The read request was queued if Token->Event is
- not NULL.The data was read correctly from the
- device if the Token->Event is NULL.
- @retval EFI_DEVICE_ERROR The device reported an error while performing
- the read.
- @retval EFI_NO_MEDIA There is no media in the device.
- @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
- @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
- intrinsic block size of the device.
- @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
- or the buffer is not on proper alignment.
- @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
- of resources.
-**/
-EFI_STATUS
-EFIAPI
-PartitionReadBlocksEx (
- IN EFI_BLOCK_IO2_PROTOCOL *This,
- IN UINT32 MediaId,
- IN EFI_LBA Lba,
- IN OUT EFI_BLOCK_IO2_TOKEN *Token,
- IN UINTN BufferSize,
- OUT VOID *Buffer
- )
-{
- EFI_STATUS Status;
- PARTITION_PRIVATE_DATA *Private;
- UINT64 Offset;
- PARTITION_ACCESS_TASK *Task;
-
- Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
-
- if (BufferSize % Private->BlockSize != 0) {
- return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_BAD_BUFFER_SIZE);
- }
-
- Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
- if (Offset + BufferSize > Private->End) {
- return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_INVALID_PARAMETER);
- }
-
- if ((Token != NULL) && (Token->Event != NULL)) {
- Task = PartitionCreateAccessTask (Token);
- if (Task == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- Status = Private->DiskIo2->ReadDiskEx (Private->DiskIo2, MediaId, Offset, &Task->DiskIo2Token, BufferSize, Buffer);
- if (EFI_ERROR (Status)) {
- gBS->CloseEvent (Task->DiskIo2Token.Event);
- FreePool (Task);
- }
- } else {
- Status = Private->DiskIo2->ReadDiskEx (Private->DiskIo2, MediaId, Offset, NULL, BufferSize, Buffer);
- }
-
- return Status;
-}
-
-/**
- Write BufferSize bytes from Lba into Buffer.
-
- This function writes the requested number of blocks to the device. All blocks
- are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,
- EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is
- being used, the Event associated with this request will not be signaled.
-
- @param[in] This Indicates a pointer to the calling context.
- @param[in] MediaId The media ID that the write request is for.
- @param[in] Lba The starting logical block address to be written. The
- caller is responsible for writing to only legitimate
- locations.
- @param[in, out] Token A pointer to the token associated with the transaction.
- @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
- @param[in] Buffer A pointer to the source buffer for the data.
-
- @retval EFI_SUCCESS The write request was queued if Event is not NULL.
- The data was written correctly to the device if
- the Event is NULL.
- @retval EFI_WRITE_PROTECTED The device can not be written to.
- @retval EFI_NO_MEDIA There is no media in the device.
- @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
- @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
- @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
- @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
- or the buffer is not on proper alignment.
- @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
- of resources.
-
-**/
-EFI_STATUS
-EFIAPI
-PartitionWriteBlocksEx (
- IN EFI_BLOCK_IO2_PROTOCOL *This,
- IN UINT32 MediaId,
- IN EFI_LBA Lba,
- IN OUT EFI_BLOCK_IO2_TOKEN *Token,
- IN UINTN BufferSize,
- IN VOID *Buffer
- )
-{
- EFI_STATUS Status;
- PARTITION_PRIVATE_DATA *Private;
- UINT64 Offset;
- PARTITION_ACCESS_TASK *Task;
-
- Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
-
- if (BufferSize % Private->BlockSize != 0) {
- return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_BAD_BUFFER_SIZE);
- }
-
- Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
- if (Offset + BufferSize > Private->End) {
- return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_INVALID_PARAMETER);
- }
-
- if ((Token != NULL) && (Token->Event != NULL)) {
- Task = PartitionCreateAccessTask (Token);
- if (Task == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- Status = Private->DiskIo2->WriteDiskEx (Private->DiskIo2, MediaId, Offset, &Task->DiskIo2Token, BufferSize, Buffer);
- if (EFI_ERROR (Status)) {
- gBS->CloseEvent (Task->DiskIo2Token.Event);
- FreePool (Task);
- }
- } else {
- Status = Private->DiskIo2->WriteDiskEx (Private->DiskIo2, MediaId, Offset, NULL, BufferSize, Buffer);
- }
-
- return Status;
-}
-
-/**
- Flush the Block Device.
-
- If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED
- is returned and non-blocking I/O is being used, the Event associated with
- this request will not be signaled.
-
- @param[in] This Indicates a pointer to the calling context.
- @param[in, out] Token A pointer to the token associated with the transaction
-
- @retval EFI_SUCCESS The flush request was queued if Event is not NULL.
- All outstanding data was written correctly to the
- device if the Event is NULL.
- @retval EFI_DEVICE_ERROR The device reported an error while writting back
- the data.
- @retval EFI_WRITE_PROTECTED The device cannot be written to.
- @retval EFI_NO_MEDIA There is no media in the device.
- @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
- @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
- of resources.
-
-**/
-EFI_STATUS
-EFIAPI
-PartitionFlushBlocksEx (
- IN EFI_BLOCK_IO2_PROTOCOL *This,
- IN OUT EFI_BLOCK_IO2_TOKEN *Token
- )
-{
- EFI_STATUS Status;
- PARTITION_PRIVATE_DATA *Private;
- PARTITION_ACCESS_TASK *Task;
-
- Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
-
- if ((Token != NULL) && (Token->Event != NULL)) {
- Task = PartitionCreateAccessTask (Token);
- if (Task == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- Status = Private->DiskIo2->FlushDiskEx (Private->DiskIo2, &Task->DiskIo2Token);
- if (EFI_ERROR (Status)) {
- gBS->CloseEvent (Task->DiskIo2Token.Event);
- FreePool (Task);
- }
- } else {
- Status = Private->DiskIo2->FlushDiskEx (Private->DiskIo2, NULL);
- }
-
- return Status;
-}
-
-/**
- Create a child handle for a logical block device that represents the
- bytes Start to End of the Parent Block IO device.
-
- @param[in] This Protocol instance pointer.
- @param[in] ParentHandle Parent Handle for new child.
- @param[in] ParentDiskIo Parent DiskIo interface.
- @param[in] ParentDiskIo2 Parent DiskIo2 interface.
- @param[in] ParentBlockIo Parent BlockIo interface.
- @param[in] ParentBlockIo2 Parent BlockIo2 interface.
- @param[in] ParentDevicePath Parent Device Path.
- @param[in] DevicePathNode Child Device Path node.
- @param[in] PartitionInfo Child Partition Information interface.
- @param[in] Start Start Block.
- @param[in] End End Block.
- @param[in] BlockSize Child block size.
- @param[in] TypeGuid Partition GUID Type.
-
- @retval EFI_SUCCESS A child handle was added.
- @retval other A child handle was not added.
-
-**/
-EFI_STATUS
-PartitionInstallChildHandle (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE ParentHandle,
- IN EFI_DISK_IO_PROTOCOL *ParentDiskIo,
- IN EFI_DISK_IO2_PROTOCOL *ParentDiskIo2,
- IN EFI_BLOCK_IO_PROTOCOL *ParentBlockIo,
- IN EFI_BLOCK_IO2_PROTOCOL *ParentBlockIo2,
- IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
- IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode,
- IN EFI_PARTITION_INFO_PROTOCOL *PartitionInfo,
- IN EFI_LBA Start,
- IN EFI_LBA End,
- IN UINT32 BlockSize,
- IN EFI_GUID *TypeGuid
- )
-{
- EFI_STATUS Status;
- PARTITION_PRIVATE_DATA *Private;
-
- Status = EFI_SUCCESS;
- Private = AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA));
- if (Private == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- Private->Signature = PARTITION_PRIVATE_DATA_SIGNATURE;
-
- Private->Start = MultU64x32 (Start, ParentBlockIo->Media->BlockSize);
- Private->End = MultU64x32 (End + 1, ParentBlockIo->Media->BlockSize);
-
- Private->BlockSize = BlockSize;
- Private->ParentBlockIo = ParentBlockIo;
- Private->ParentBlockIo2 = ParentBlockIo2;
- Private->DiskIo = ParentDiskIo;
- Private->DiskIo2 = ParentDiskIo2;
-
- //
- // Set the BlockIO into Private Data.
- //
- Private->BlockIo.Revision = ParentBlockIo->Revision;
-
- Private->BlockIo.Media = &Private->Media;
- CopyMem (Private->BlockIo.Media, ParentBlockIo->Media, sizeof (EFI_BLOCK_IO_MEDIA));
-
- Private->BlockIo.Reset = PartitionReset;
- Private->BlockIo.ReadBlocks = PartitionReadBlocks;
- Private->BlockIo.WriteBlocks = PartitionWriteBlocks;
- Private->BlockIo.FlushBlocks = PartitionFlushBlocks;
-
- //
- // Set the BlockIO2 into Private Data.
- //
- if (Private->DiskIo2 != NULL) {
- ASSERT (Private->ParentBlockIo2 != NULL);
- Private->BlockIo2.Media = &Private->Media2;
- CopyMem (Private->BlockIo2.Media, ParentBlockIo2->Media, sizeof (EFI_BLOCK_IO_MEDIA));
-
- Private->BlockIo2.Reset = PartitionResetEx;
- Private->BlockIo2.ReadBlocksEx = PartitionReadBlocksEx;
- Private->BlockIo2.WriteBlocksEx = PartitionWriteBlocksEx;
- Private->BlockIo2.FlushBlocksEx = PartitionFlushBlocksEx;
- }
-
- Private->Media.IoAlign = 0;
- Private->Media.LogicalPartition = TRUE;
- Private->Media.LastBlock = DivU64x32 (
- MultU64x32 (
- End - Start + 1,
- ParentBlockIo->Media->BlockSize
- ),
- BlockSize
- ) - 1;
-
- Private->Media.BlockSize = (UINT32)BlockSize;
-
- Private->Media2.IoAlign = 0;
- Private->Media2.LogicalPartition = TRUE;
- Private->Media2.LastBlock = Private->Media.LastBlock;
- Private->Media2.BlockSize = (UINT32)BlockSize;
-
- //
- // Per UEFI Spec, LowestAlignedLba, LogicalBlocksPerPhysicalBlock and OptimalTransferLengthGranularity must be 0
- // for logical partitions.
- //
- if (Private->BlockIo.Revision >= EFI_BLOCK_IO_PROTOCOL_REVISION2) {
- Private->Media.LowestAlignedLba = 0;
- Private->Media.LogicalBlocksPerPhysicalBlock = 0;
- Private->Media2.LowestAlignedLba = 0;
- Private->Media2.LogicalBlocksPerPhysicalBlock = 0;
- if (Private->BlockIo.Revision >= EFI_BLOCK_IO_PROTOCOL_REVISION3) {
- Private->Media.OptimalTransferLengthGranularity = 0;
- Private->Media2.OptimalTransferLengthGranularity = 0;
- }
- }
-
- Private->DevicePath = AppendDevicePathNode (ParentDevicePath, DevicePathNode);
-
- if (Private->DevicePath == NULL) {
- FreePool (Private);
- return EFI_OUT_OF_RESOURCES;
- }
-
- //
- // Set the PartitionInfo into Private Data.
- //
- CopyMem (&Private->PartitionInfo, PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
-
- if (TypeGuid != NULL) {
- CopyGuid (&(Private->TypeGuid), TypeGuid);
- } else {
- ZeroMem ((VOID *)&(Private->TypeGuid), sizeof (EFI_GUID));
- }
-
- //
- // Create the new handle.
- //
- Private->Handle = NULL;
- if (Private->DiskIo2 != NULL) {
- Status = gBS->InstallMultipleProtocolInterfaces (
- &Private->Handle,
- &gEfiDevicePathProtocolGuid,
- Private->DevicePath,
- &gEfiBlockIoProtocolGuid,
- &Private->BlockIo,
- &gEfiBlockIo2ProtocolGuid,
- &Private->BlockIo2,
- &gEfiPartitionInfoProtocolGuid,
- &Private->PartitionInfo,
- TypeGuid,
- NULL,
- NULL
- );
- } else {
- Status = gBS->InstallMultipleProtocolInterfaces (
- &Private->Handle,
- &gEfiDevicePathProtocolGuid,
- Private->DevicePath,
- &gEfiBlockIoProtocolGuid,
- &Private->BlockIo,
- &gEfiPartitionInfoProtocolGuid,
- &Private->PartitionInfo,
- TypeGuid,
- NULL,
- NULL
- );
- }
-
- if (!EFI_ERROR (Status)) {
- //
- // Open the Parent Handle for the child
- //
- Status = gBS->OpenProtocol (
- ParentHandle,
- &gEfiDiskIoProtocolGuid,
- (VOID **)&ParentDiskIo,
- This->DriverBindingHandle,
- Private->Handle,
- EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
- );
- } else {
- FreePool (Private->DevicePath);
- FreePool (Private);
-
- //
- // if the Status == EFI_ALREADY_STARTED, it means the child handles
- // are already installed. So return EFI_SUCCESS to avoid do the next
- // partition type check.
- //
- if (Status == EFI_ALREADY_STARTED) {
- Status = EFI_SUCCESS;
- }
- }
-
- return Status;
-}
-
-/**
- The user Entry Point for module Partition. The user code starts with this function.
-
- @param[in] ImageHandle The firmware allocated handle for the EFI image.
- @param[in] SystemTable A pointer to the EFI System Table.
-
- @retval EFI_SUCCESS The entry point is executed successfully.
- @retval other Some error occurs when executing this entry point.
-
-**/
-EFI_STATUS
-EFIAPI
-InitializePartition (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- EFI_STATUS Status;
-
- //
- // Install driver model protocol(s).
- //
- Status = EfiLibInstallDriverBindingComponentName2 (
- ImageHandle,
- SystemTable,
- &gPartitionDriverBinding,
- ImageHandle,
- &gPartitionComponentName,
- &gPartitionComponentName2
- );
- ASSERT_EFI_ERROR (Status);
-
- return Status;
-}
-
-/**
- Test to see if there is any child on ControllerHandle.
-
- @param[in] ControllerHandle Handle of device to test.
-
- @retval TRUE There are children on the ControllerHandle.
- @retval FALSE No child is on the ControllerHandle.
-
-**/
-BOOLEAN
-HasChildren (
- IN EFI_HANDLE ControllerHandle
- )
-{
- EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
- UINTN EntryCount;
- EFI_STATUS Status;
- UINTN Index;
-
- Status = gBS->OpenProtocolInformation (
- ControllerHandle,
- &gEfiDiskIoProtocolGuid,
- &OpenInfoBuffer,
- &EntryCount
- );
- ASSERT_EFI_ERROR (Status);
-
- for (Index = 0; Index < EntryCount; Index++) {
- if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
- break;
- }
- }
-
- FreePool (OpenInfoBuffer);
-
- return (BOOLEAN)(Index < EntryCount);
-}
+/** @file
+ Partition driver that produces logical BlockIo devices from a physical
+ BlockIo device. The logical BlockIo devices are based on the format
+ of the raw block devices media. Currently "El Torito CD-ROM", UDF, Legacy
+ MBR, and GPT partition schemes are supported.
+
+Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Partition.h"
+
+//
+// Partition Driver Global Variables.
+//
+EFI_DRIVER_BINDING_PROTOCOL gPartitionDriverBinding = {
+ PartitionDriverBindingSupported,
+ PartitionDriverBindingStart,
+ PartitionDriverBindingStop,
+ //
+ // Grub4Dos copies the BPB of the first partition to the MBR. If the
+ // DriverBindingStart() of the Fat driver gets run before that of Partition
+ // driver only the first partition can be recognized.
+ // Let the driver binding version of Partition driver be higher than that of
+ // Fat driver to make sure the DriverBindingStart() of the Partition driver
+ // gets run before that of Fat driver so that all the partitions can be recognized.
+ //
+ 0xb,
+ NULL,
+ NULL
+};
+
+//
+// Prioritized function list to detect partition table.
+// Refer to UEFI Spec 13.3.2 Partition Discovery, the block device
+// should be scanned in below order:
+// 1. GPT
+// 2. ISO 9660 (El Torito) (or UDF)
+// 3. MBR
+// 4. no partiton found
+// Note: UDF is using a same method as booting from CD-ROM, so put it along
+// with CD-ROM check.
+//
+PARTITION_DETECT_ROUTINE mPartitionDetectRoutineTable[] = {
+ PartitionInstallGptChildHandles,
+ PartitionInstallUdfChildHandles,
+ PartitionInstallMbrChildHandles,
+ NULL
+};
+
+/**
+ Test to see if this driver supports ControllerHandle. Any ControllerHandle
+ than contains a BlockIo and DiskIo protocol or a BlockIo2 protocol can be
+ supported.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of device to test.
+ @param[in] RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver supports this device
+ @retval EFI_ALREADY_STARTED This driver is already running on this device
+ @retval other This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+ EFI_DEV_PATH *Node;
+
+ //
+ // Check RemainingDevicePath validation
+ //
+ if (RemainingDevicePath != NULL) {
+ //
+ // Check if RemainingDevicePath is the End of Device Path Node,
+ // if yes, go on checking other conditions
+ //
+ if (!IsDevicePathEnd (RemainingDevicePath)) {
+ //
+ // If RemainingDevicePath isn't the End of Device Path Node,
+ // check its validation
+ //
+ Node = (EFI_DEV_PATH *)RemainingDevicePath;
+ if ((Node->DevPath.Type != MEDIA_DEVICE_PATH) ||
+ (Node->DevPath.SubType != MEDIA_HARDDRIVE_DP) ||
+ (DevicePathNodeLength (&Node->DevPath) != sizeof (HARDDRIVE_DEVICE_PATH)))
+ {
+ return EFI_UNSUPPORTED;
+ }
+ }
+ }
+
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ (VOID **)&DiskIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Close the I/O Abstraction(s) used to perform the supported test
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ //
+ // Open the EFI Device Path protocol needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **)&ParentDevicePath,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Close protocol, don't use device path protocol in the Support() function
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiBlockIoProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+
+ return Status;
+}
+
+/**
+ Start this driver on ControllerHandle by opening a Block IO or a Block IO2
+ or both, and Disk IO protocol, reading Device Path, and creating a child
+ handle with a Disk IO and device path protocol.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of device to bind driver to
+ @param[in] RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver is added to ControllerHandle
+ @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
+ @retval other This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS OpenStatus;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+ EFI_DISK_IO2_PROTOCOL *DiskIo2;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ PARTITION_DETECT_ROUTINE *Routine;
+ BOOLEAN MediaPresent;
+ EFI_TPL OldTpl;
+
+ BlockIo2 = NULL;
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ //
+ // Check RemainingDevicePath validation
+ //
+ if (RemainingDevicePath != NULL) {
+ //
+ // Check if RemainingDevicePath is the End of Device Path Node,
+ // if yes, return EFI_SUCCESS
+ //
+ if (IsDevicePathEnd (RemainingDevicePath)) {
+ Status = EFI_SUCCESS;
+ goto Exit;
+ }
+ }
+
+ //
+ // Try to open BlockIO and BlockIO2. If BlockIO would be opened, continue,
+ // otherwise, return error.
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **)&BlockIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiBlockIo2ProtocolGuid,
+ (VOID **)&BlockIo2,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ BlockIo2 = NULL;
+ }
+
+ //
+ // Get the Device Path Protocol on ControllerHandle's handle.
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **)&ParentDevicePath,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
+ goto Exit;
+ }
+
+ //
+ // Get the DiskIo and DiskIo2.
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ (VOID **)&DiskIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ goto Exit;
+ }
+
+ OpenStatus = Status;
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDiskIo2ProtocolGuid,
+ (VOID **)&DiskIo2,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
+ DiskIo2 = NULL;
+ }
+
+ //
+ // Try to read blocks when there's media or it is removable physical partition.
+ //
+ Status = EFI_UNSUPPORTED;
+ MediaPresent = BlockIo->Media->MediaPresent;
+ if (BlockIo->Media->MediaPresent ||
+ (BlockIo->Media->RemovableMedia && !BlockIo->Media->LogicalPartition))
+ {
+ //
+ // Try for GPT, then legacy MBR partition types, and then UDF and El Torito.
+ // If the media supports a given partition type install child handles to
+ // represent the partitions described by the media.
+ //
+ Routine = &mPartitionDetectRoutineTable[0];
+ while (*Routine != NULL) {
+ Status = (*Routine)(
+ This,
+ ControllerHandle,
+ DiskIo,
+ DiskIo2,
+ BlockIo,
+ BlockIo2,
+ ParentDevicePath
+ );
+ if (!EFI_ERROR (Status) || (Status == EFI_MEDIA_CHANGED) || (Status == EFI_NO_MEDIA)) {
+ break;
+ }
+
+ Routine++;
+ }
+ }
+
+ //
+ // In the case that the driver is already started (OpenStatus == EFI_ALREADY_STARTED),
+ // the DevicePathProtocol and the DiskIoProtocol are not actually opened by the
+ // driver. So don't try to close them. Otherwise, we will break the dependency
+ // between the controller and the driver set up before.
+ //
+ // In the case that when the media changes on a device it will Reinstall the
+ // BlockIo interaface. This will cause a call to our Stop(), and a subsequent
+ // reentrant call to our Start() successfully. We should leave the device open
+ // when this happen. The "media change" case includes either the status is
+ // EFI_MEDIA_CHANGED or it is a "media" to "no media" change.
+ //
+ if (EFI_ERROR (Status) &&
+ !EFI_ERROR (OpenStatus) &&
+ (Status != EFI_MEDIA_CHANGED) &&
+ !(MediaPresent && (Status == EFI_NO_MEDIA)))
+ {
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ //
+ // Close Parent DiskIo2 if has.
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDiskIo2ProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ }
+
+Exit:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+/**
+ Stop this driver on ControllerHandle. Support stopping any child handles
+ created by this driver.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to stop driver on
+ @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
+ children is zero stop the entire bus driver.
+ @param ChildHandleBuffer List of Child Handles to Stop.
+
+ @retval EFI_SUCCESS This driver is removed ControllerHandle
+ @retval other This driver was not removed from this device
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
+ BOOLEAN AllChildrenStopped;
+ PARTITION_PRIVATE_DATA *Private;
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+ EFI_GUID *TypeGuid;
+
+ BlockIo = NULL;
+ BlockIo2 = NULL;
+ Private = NULL;
+
+ if (NumberOfChildren == 0) {
+ //
+ // In the case of re-entry of the PartitionDriverBindingStop, the
+ // NumberOfChildren may not reflect the actual number of children on the
+ // bus driver. Hence, additional check is needed here.
+ //
+ if (HasChildren (ControllerHandle)) {
+ DEBUG ((DEBUG_ERROR, "PartitionDriverBindingStop: Still has child.\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Close the bus driver
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ //
+ // Close Parent BlockIO2 if has.
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDiskIo2ProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ return EFI_SUCCESS;
+ }
+
+ AllChildrenStopped = TRUE;
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+ gBS->OpenProtocol (
+ ChildHandleBuffer[Index],
+ &gEfiBlockIoProtocolGuid,
+ (VOID **)&BlockIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ //
+ // Try to locate BlockIo2.
+ //
+ gBS->OpenProtocol (
+ ChildHandleBuffer[Index],
+ &gEfiBlockIo2ProtocolGuid,
+ (VOID **)&BlockIo2,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo);
+ if (Private->InStop) {
+ //
+ // If the child handle is going to be stopped again during the re-entry
+ // of DriverBindingStop, just do nothing.
+ //
+ break;
+ }
+
+ Private->InStop = TRUE;
+
+ BlockIo->FlushBlocks (BlockIo);
+
+ if (BlockIo2 != NULL) {
+ Status = BlockIo2->FlushBlocksEx (BlockIo2, NULL);
+ DEBUG ((DEBUG_ERROR, "PartitionDriverBindingStop: FlushBlocksEx returned with %r\n", Status));
+ } else {
+ Status = EFI_SUCCESS;
+ }
+
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index]
+ );
+
+ if (IsZeroGuid (&Private->TypeGuid)) {
+ TypeGuid = NULL;
+ } else {
+ TypeGuid = &Private->TypeGuid;
+ }
+
+ //
+ // All Software protocols have be freed from the handle so remove it.
+ // Remove the BlockIo Protocol if has.
+ // Remove the BlockIo2 Protocol if has.
+ //
+ if (BlockIo2 != NULL) {
+ //
+ // Some device drivers might re-install the BlockIO(2) protocols for a
+ // media change condition. Therefore, if the FlushBlocksEx returned with
+ // EFI_MEDIA_CHANGED, just let the BindingStop fail to avoid potential
+ // reference of already stopped child handle.
+ //
+ if (Status != EFI_MEDIA_CHANGED) {
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ChildHandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid,
+ Private->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &Private->BlockIo,
+ &gEfiBlockIo2ProtocolGuid,
+ &Private->BlockIo2,
+ &gEfiPartitionInfoProtocolGuid,
+ &Private->PartitionInfo,
+ TypeGuid,
+ NULL,
+ NULL
+ );
+ }
+ } else {
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ChildHandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid,
+ Private->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &Private->BlockIo,
+ &gEfiPartitionInfoProtocolGuid,
+ &Private->PartitionInfo,
+ TypeGuid,
+ NULL,
+ NULL
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ Private->InStop = FALSE;
+ gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ (VOID **)&DiskIo,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index],
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ } else {
+ FreePool (Private->DevicePath);
+ FreePool (Private);
+ }
+
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ if (Status == EFI_MEDIA_CHANGED) {
+ break;
+ }
+ }
+ }
+
+ if (!AllChildrenStopped) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Reset the Block Device.
+
+ @param This Protocol instance pointer.
+ @param ExtendedVerification Driver may perform diagnostics on reset.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could
+ not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ PARTITION_PRIVATE_DATA *Private;
+
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
+
+ return Private->ParentBlockIo->Reset (
+ Private->ParentBlockIo,
+ ExtendedVerification
+ );
+}
+
+/**
+ Probe the media status and return EFI_NO_MEDIA or EFI_MEDIA_CHANGED
+ for no media or media change case. Otherwise DefaultStatus is returned.
+
+ @param DiskIo Pointer to the DiskIo instance.
+ @param MediaId Id of the media, changes every time the media is replaced.
+ @param DefaultStatus The default status to return when it's not the no media
+ or media change case.
+
+ @retval EFI_NO_MEDIA There is no media.
+ @retval EFI_MEDIA_CHANGED The media was changed.
+ @retval others The default status to return.
+**/
+EFI_STATUS
+ProbeMediaStatus (
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UINT32 MediaId,
+ IN EFI_STATUS DefaultStatus
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Buffer[1];
+
+ //
+ // Read 1 byte from offset 0 to check if the MediaId is still valid.
+ // The reading operation is synchronious thus it is not worth it to
+ // allocate a buffer from the pool. The destination buffer for the
+ // data is in the stack.
+ //
+ Status = DiskIo->ReadDisk (DiskIo, MediaId, 0, 1, (VOID *)Buffer);
+ if ((Status == EFI_NO_MEDIA) || (Status == EFI_MEDIA_CHANGED)) {
+ return Status;
+ }
+
+ return DefaultStatus;
+}
+
+/**
+ Read by using the Disk IO protocol on the parent device. Lba addresses
+ must be converted to byte offsets.
+
+ @param This Protocol instance pointer.
+ @param MediaId Id of the media, changes every time the media is replaced.
+ @param Lba The starting Logical Block Address to read from
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer Buffer containing read data
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
+ valid for the device.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ PARTITION_PRIVATE_DATA *Private;
+ UINT64 Offset;
+
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
+
+ if (BufferSize % Private->BlockSize != 0) {
+ return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_BAD_BUFFER_SIZE);
+ }
+
+ Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
+ if (Offset + BufferSize > Private->End) {
+ return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_INVALID_PARAMETER);
+ }
+
+ //
+ // Because some kinds of partition have different block size from their parent
+ // device, we call the Disk IO protocol on the parent device, not the Block IO
+ // protocol
+ //
+ return Private->DiskIo->ReadDisk (Private->DiskIo, MediaId, Offset, BufferSize, Buffer);
+}
+
+/**
+ Write by using the Disk IO protocol on the parent device. Lba addresses
+ must be converted to byte offsets.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] MediaId Id of the media, changes every time the media is replaced.
+ @param[in] Lba The starting Logical Block Address to read from
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[in] Buffer Buffer containing data to be written to device.
+
+ @retval EFI_SUCCESS The data was written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device can not be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains a LBA that is not
+ valid for the device.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ PARTITION_PRIVATE_DATA *Private;
+ UINT64 Offset;
+
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
+
+ if (BufferSize % Private->BlockSize != 0) {
+ return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_BAD_BUFFER_SIZE);
+ }
+
+ Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
+ if (Offset + BufferSize > Private->End) {
+ return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_INVALID_PARAMETER);
+ }
+
+ //
+ // Because some kinds of partition have different block size from their parent
+ // device, we call the Disk IO protocol on the parent device, not the Block IO
+ // protocol
+ //
+ return Private->DiskIo->WriteDisk (Private->DiskIo, MediaId, Offset, BufferSize, Buffer);
+}
+
+/**
+ Flush the parent Block Device.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS All outstanding data was written to the device
+ @retval EFI_DEVICE_ERROR The device reported an error while writting back the data
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ )
+{
+ PARTITION_PRIVATE_DATA *Private;
+
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
+
+ return Private->ParentBlockIo->FlushBlocks (Private->ParentBlockIo);
+}
+
+/**
+ Probe the media status and return EFI_NO_MEDIA or EFI_MEDIA_CHANGED
+ for no media or media change case. Otherwise DefaultStatus is returned.
+
+ @param DiskIo2 Pointer to the DiskIo2 instance.
+ @param MediaId Id of the media, changes every time the media is replaced.
+ @param DefaultStatus The default status to return when it's not the no media
+ or media change case.
+
+ @retval EFI_NO_MEDIA There is no media.
+ @retval EFI_MEDIA_CHANGED The media was changed.
+ @retval others The default status to return.
+**/
+EFI_STATUS
+ProbeMediaStatusEx (
+ IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
+ IN UINT32 MediaId,
+ IN EFI_STATUS DefaultStatus
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Buffer[1];
+
+ //
+ // Read 1 byte from offset 0 to check if the MediaId is still valid.
+ // The reading operation is synchronious thus it is not worth it to
+ // allocate a buffer from the pool. The destination buffer for the
+ // data is in the stack.
+ //
+ Status = DiskIo2->ReadDiskEx (DiskIo2, MediaId, 0, NULL, 1, (VOID *)Buffer);
+ if ((Status == EFI_NO_MEDIA) || (Status == EFI_MEDIA_CHANGED)) {
+ return Status;
+ }
+
+ return DefaultStatus;
+}
+
+/**
+ Reset the Block Device throught Block I/O2 protocol.
+
+ @param This Protocol instance pointer.
+ @param ExtendedVerification Driver may perform diagnostics on reset.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could
+ not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionResetEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ PARTITION_PRIVATE_DATA *Private;
+
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
+
+ return Private->ParentBlockIo2->Reset (
+ Private->ParentBlockIo2,
+ ExtendedVerification
+ );
+}
+
+/**
+ The general callback for the DiskIo2 interfaces.
+ @param Event Event whose notification function is being invoked.
+ @param Context The pointer to the notification function's context,
+ which points to the PARTITION_ACCESS_TASK instance.
+**/
+VOID
+EFIAPI
+PartitionOnAccessComplete (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ PARTITION_ACCESS_TASK *Task;
+
+ Task = (PARTITION_ACCESS_TASK *)Context;
+
+ gBS->CloseEvent (Event);
+
+ Task->BlockIo2Token->TransactionStatus = Task->DiskIo2Token.TransactionStatus;
+ gBS->SignalEvent (Task->BlockIo2Token->Event);
+
+ FreePool (Task);
+}
+
+/**
+ Create a new PARTITION_ACCESS_TASK instance.
+
+ @param Token Pointer to the EFI_BLOCK_IO2_TOKEN.
+
+ @return Pointer to the created PARTITION_ACCESS_TASK instance or NULL upon failure.
+**/
+PARTITION_ACCESS_TASK *
+PartitionCreateAccessTask (
+ IN EFI_BLOCK_IO2_TOKEN *Token
+ )
+{
+ EFI_STATUS Status;
+ PARTITION_ACCESS_TASK *Task;
+
+ Task = AllocatePool (sizeof (*Task));
+ if (Task == NULL) {
+ return NULL;
+ }
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ PartitionOnAccessComplete,
+ Task,
+ &Task->DiskIo2Token.Event
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (Task);
+ return NULL;
+ }
+
+ Task->BlockIo2Token = Token;
+
+ return Task;
+}
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ This function reads the requested number of blocks from the device. All the
+ blocks are read, or an error is returned.
+ If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and
+ non-blocking I/O is being used, the Event associated with this request will
+ not be signaled.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId Id of the media, changes every time the media is
+ replaced.
+ @param[in] Lba The starting Logical Block Address to read from.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[out] Buffer A pointer to the destination buffer for the data. The
+ caller is responsible for either having implicit or
+ explicit ownership of the buffer.
+
+ @retval EFI_SUCCESS The read request was queued if Token->Event is
+ not NULL.The data was read correctly from the
+ device if the Token->Event is NULL.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing
+ the read.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
+ intrinsic block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
+ of resources.
+**/
+EFI_STATUS
+EFIAPI
+PartitionReadBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ PARTITION_PRIVATE_DATA *Private;
+ UINT64 Offset;
+ PARTITION_ACCESS_TASK *Task;
+
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
+
+ if (BufferSize % Private->BlockSize != 0) {
+ return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_BAD_BUFFER_SIZE);
+ }
+
+ Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
+ if (Offset + BufferSize > Private->End) {
+ return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_INVALID_PARAMETER);
+ }
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Task = PartitionCreateAccessTask (Token);
+ if (Task == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = Private->DiskIo2->ReadDiskEx (Private->DiskIo2, MediaId, Offset, &Task->DiskIo2Token, BufferSize, Buffer);
+ if (EFI_ERROR (Status)) {
+ gBS->CloseEvent (Task->DiskIo2Token.Event);
+ FreePool (Task);
+ }
+ } else {
+ Status = Private->DiskIo2->ReadDiskEx (Private->DiskIo2, MediaId, Offset, NULL, BufferSize, Buffer);
+ }
+
+ return Status;
+}
+
+/**
+ Write BufferSize bytes from Lba into Buffer.
+
+ This function writes the requested number of blocks to the device. All blocks
+ are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,
+ EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is
+ being used, the Event associated with this request will not be signaled.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the write request is for.
+ @param[in] Lba The starting logical block address to be written. The
+ caller is responsible for writing to only legitimate
+ locations.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[in] Buffer A pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The write request was queued if Event is not NULL.
+ The data was written correctly to the device if
+ the Event is NULL.
+ @retval EFI_WRITE_PROTECTED The device can not be written to.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
+ of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionWriteBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ PARTITION_PRIVATE_DATA *Private;
+ UINT64 Offset;
+ PARTITION_ACCESS_TASK *Task;
+
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
+
+ if (BufferSize % Private->BlockSize != 0) {
+ return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_BAD_BUFFER_SIZE);
+ }
+
+ Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
+ if (Offset + BufferSize > Private->End) {
+ return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_INVALID_PARAMETER);
+ }
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Task = PartitionCreateAccessTask (Token);
+ if (Task == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = Private->DiskIo2->WriteDiskEx (Private->DiskIo2, MediaId, Offset, &Task->DiskIo2Token, BufferSize, Buffer);
+ if (EFI_ERROR (Status)) {
+ gBS->CloseEvent (Task->DiskIo2Token.Event);
+ FreePool (Task);
+ }
+ } else {
+ Status = Private->DiskIo2->WriteDiskEx (Private->DiskIo2, MediaId, Offset, NULL, BufferSize, Buffer);
+ }
+
+ return Status;
+}
+
+/**
+ Flush the Block Device.
+
+ If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED
+ is returned and non-blocking I/O is being used, the Event associated with
+ this request will not be signaled.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in, out] Token A pointer to the token associated with the transaction
+
+ @retval EFI_SUCCESS The flush request was queued if Event is not NULL.
+ All outstanding data was written correctly to the
+ device if the Event is NULL.
+ @retval EFI_DEVICE_ERROR The device reported an error while writting back
+ the data.
+ @retval EFI_WRITE_PROTECTED The device cannot be written to.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
+ of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionFlushBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token
+ )
+{
+ EFI_STATUS Status;
+ PARTITION_PRIVATE_DATA *Private;
+ PARTITION_ACCESS_TASK *Task;
+
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Task = PartitionCreateAccessTask (Token);
+ if (Task == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = Private->DiskIo2->FlushDiskEx (Private->DiskIo2, &Task->DiskIo2Token);
+ if (EFI_ERROR (Status)) {
+ gBS->CloseEvent (Task->DiskIo2Token.Event);
+ FreePool (Task);
+ }
+ } else {
+ Status = Private->DiskIo2->FlushDiskEx (Private->DiskIo2, NULL);
+ }
+
+ return Status;
+}
+
+/**
+ Create a child handle for a logical block device that represents the
+ bytes Start to End of the Parent Block IO device.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ParentHandle Parent Handle for new child.
+ @param[in] ParentDiskIo Parent DiskIo interface.
+ @param[in] ParentDiskIo2 Parent DiskIo2 interface.
+ @param[in] ParentBlockIo Parent BlockIo interface.
+ @param[in] ParentBlockIo2 Parent BlockIo2 interface.
+ @param[in] ParentDevicePath Parent Device Path.
+ @param[in] DevicePathNode Child Device Path node.
+ @param[in] PartitionInfo Child Partition Information interface.
+ @param[in] Start Start Block.
+ @param[in] End End Block.
+ @param[in] BlockSize Child block size.
+ @param[in] TypeGuid Partition GUID Type.
+
+ @retval EFI_SUCCESS A child handle was added.
+ @retval other A child handle was not added.
+
+**/
+EFI_STATUS
+PartitionInstallChildHandle (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ParentHandle,
+ IN EFI_DISK_IO_PROTOCOL *ParentDiskIo,
+ IN EFI_DISK_IO2_PROTOCOL *ParentDiskIo2,
+ IN EFI_BLOCK_IO_PROTOCOL *ParentBlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *ParentBlockIo2,
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode,
+ IN EFI_PARTITION_INFO_PROTOCOL *PartitionInfo,
+ IN EFI_LBA Start,
+ IN EFI_LBA End,
+ IN UINT32 BlockSize,
+ IN EFI_GUID *TypeGuid
+ )
+{
+ EFI_STATUS Status;
+ PARTITION_PRIVATE_DATA *Private;
+
+ Status = EFI_SUCCESS;
+ Private = AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA));
+ if (Private == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Private->Signature = PARTITION_PRIVATE_DATA_SIGNATURE;
+
+ Private->Start = MultU64x32 (Start, ParentBlockIo->Media->BlockSize);
+ Private->End = MultU64x32 (End + 1, ParentBlockIo->Media->BlockSize);
+
+ Private->BlockSize = BlockSize;
+ Private->ParentBlockIo = ParentBlockIo;
+ Private->ParentBlockIo2 = ParentBlockIo2;
+ Private->DiskIo = ParentDiskIo;
+ Private->DiskIo2 = ParentDiskIo2;
+
+ //
+ // Set the BlockIO into Private Data.
+ //
+ Private->BlockIo.Revision = ParentBlockIo->Revision;
+
+ Private->BlockIo.Media = &Private->Media;
+ CopyMem (Private->BlockIo.Media, ParentBlockIo->Media, sizeof (EFI_BLOCK_IO_MEDIA));
+
+ Private->BlockIo.Reset = PartitionReset;
+ Private->BlockIo.ReadBlocks = PartitionReadBlocks;
+ Private->BlockIo.WriteBlocks = PartitionWriteBlocks;
+ Private->BlockIo.FlushBlocks = PartitionFlushBlocks;
+
+ //
+ // Set the BlockIO2 into Private Data.
+ //
+ if (Private->DiskIo2 != NULL) {
+ ASSERT (Private->ParentBlockIo2 != NULL);
+ Private->BlockIo2.Media = &Private->Media2;
+ CopyMem (Private->BlockIo2.Media, ParentBlockIo2->Media, sizeof (EFI_BLOCK_IO_MEDIA));
+
+ Private->BlockIo2.Reset = PartitionResetEx;
+ Private->BlockIo2.ReadBlocksEx = PartitionReadBlocksEx;
+ Private->BlockIo2.WriteBlocksEx = PartitionWriteBlocksEx;
+ Private->BlockIo2.FlushBlocksEx = PartitionFlushBlocksEx;
+ }
+
+ Private->Media.IoAlign = 0;
+ Private->Media.LogicalPartition = TRUE;
+ Private->Media.LastBlock = DivU64x32 (
+ MultU64x32 (
+ End - Start + 1,
+ ParentBlockIo->Media->BlockSize
+ ),
+ BlockSize
+ ) - 1;
+
+ Private->Media.BlockSize = (UINT32)BlockSize;
+
+ Private->Media2.IoAlign = 0;
+ Private->Media2.LogicalPartition = TRUE;
+ Private->Media2.LastBlock = Private->Media.LastBlock;
+ Private->Media2.BlockSize = (UINT32)BlockSize;
+
+ //
+ // Per UEFI Spec, LowestAlignedLba, LogicalBlocksPerPhysicalBlock and OptimalTransferLengthGranularity must be 0
+ // for logical partitions.
+ //
+ if (Private->BlockIo.Revision >= EFI_BLOCK_IO_PROTOCOL_REVISION2) {
+ Private->Media.LowestAlignedLba = 0;
+ Private->Media.LogicalBlocksPerPhysicalBlock = 0;
+ Private->Media2.LowestAlignedLba = 0;
+ Private->Media2.LogicalBlocksPerPhysicalBlock = 0;
+ if (Private->BlockIo.Revision >= EFI_BLOCK_IO_PROTOCOL_REVISION3) {
+ Private->Media.OptimalTransferLengthGranularity = 0;
+ Private->Media2.OptimalTransferLengthGranularity = 0;
+ }
+ }
+
+ Private->DevicePath = AppendDevicePathNode (ParentDevicePath, DevicePathNode);
+
+ if (Private->DevicePath == NULL) {
+ FreePool (Private);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Set the PartitionInfo into Private Data.
+ //
+ CopyMem (&Private->PartitionInfo, PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
+
+ if (TypeGuid != NULL) {
+ CopyGuid (&(Private->TypeGuid), TypeGuid);
+ } else {
+ ZeroMem ((VOID *)&(Private->TypeGuid), sizeof (EFI_GUID));
+ }
+
+ //
+ // Create the new handle.
+ //
+ Private->Handle = NULL;
+ if (Private->DiskIo2 != NULL) {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Private->Handle,
+ &gEfiDevicePathProtocolGuid,
+ Private->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &Private->BlockIo,
+ &gEfiBlockIo2ProtocolGuid,
+ &Private->BlockIo2,
+ &gEfiPartitionInfoProtocolGuid,
+ &Private->PartitionInfo,
+ TypeGuid,
+ NULL,
+ NULL
+ );
+ } else {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Private->Handle,
+ &gEfiDevicePathProtocolGuid,
+ Private->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &Private->BlockIo,
+ &gEfiPartitionInfoProtocolGuid,
+ &Private->PartitionInfo,
+ TypeGuid,
+ NULL,
+ NULL
+ );
+ }
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Open the Parent Handle for the child
+ //
+ Status = gBS->OpenProtocol (
+ ParentHandle,
+ &gEfiDiskIoProtocolGuid,
+ (VOID **)&ParentDiskIo,
+ This->DriverBindingHandle,
+ Private->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ } else {
+ FreePool (Private->DevicePath);
+ FreePool (Private);
+
+ //
+ // if the Status == EFI_ALREADY_STARTED, it means the child handles
+ // are already installed. So return EFI_SUCCESS to avoid do the next
+ // partition type check.
+ //
+ if (Status == EFI_ALREADY_STARTED) {
+ Status = EFI_SUCCESS;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ The user Entry Point for module Partition. The user code starts with this function.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializePartition (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gPartitionDriverBinding,
+ ImageHandle,
+ &gPartitionComponentName,
+ &gPartitionComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ Test to see if there is any child on ControllerHandle.
+
+ @param[in] ControllerHandle Handle of device to test.
+
+ @retval TRUE There are children on the ControllerHandle.
+ @retval FALSE No child is on the ControllerHandle.
+
+**/
+BOOLEAN
+HasChildren (
+ IN EFI_HANDLE ControllerHandle
+ )
+{
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
+ UINTN EntryCount;
+ EFI_STATUS Status;
+ UINTN Index;
+
+ Status = gBS->OpenProtocolInformation (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ &OpenInfoBuffer,
+ &EntryCount
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ for (Index = 0; Index < EntryCount; Index++) {
+ if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
+ break;
+ }
+ }
+
+ FreePool (OpenInfoBuffer);
+
+ return (BOOLEAN)(Index < EntryCount);
+}
diff --git a/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.h b/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.h
index 100aa4c310..d61053dd0b 100644
--- a/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.h
+++ b/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.h
@@ -1,483 +1,483 @@
-/** @file
- Partition driver that produces logical BlockIo devices from a physical
- BlockIo device. The logical BlockIo devices are based on the format
- of the raw block devices media. Currently "El Torito CD-ROM", UDF, Legacy
- MBR, and GPT partition schemes are supported.
-
-Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _PARTITION_H_
-#define _PARTITION_H_
-
-#include <Uefi.h>
-#include <Protocol/BlockIo.h>
-#include <Protocol/BlockIo2.h>
-#include <Guid/Gpt.h>
-#include <Protocol/ComponentName.h>
-#include <Protocol/DevicePath.h>
-#include <Protocol/DriverBinding.h>
-#include <Protocol/DiskIo.h>
-#include <Protocol/DiskIo2.h>
-#include <Protocol/PartitionInfo.h>
-#include <Library/DebugLib.h>
-#include <Library/UefiDriverEntryPoint.h>
-#include <Library/BaseLib.h>
-#include <Library/UefiLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Library/UefiBootServicesTableLib.h>
-#include <Library/DevicePathLib.h>
-
-#include <IndustryStandard/Mbr.h>
-#include <IndustryStandard/ElTorito.h>
-#include <IndustryStandard/Udf.h>
-
-//
-// Partition private data
-//
-#define PARTITION_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('P', 'a', 'r', 't')
-typedef struct {
- UINT64 Signature;
-
- EFI_HANDLE Handle;
- EFI_DEVICE_PATH_PROTOCOL *DevicePath;
- EFI_BLOCK_IO_PROTOCOL BlockIo;
- EFI_BLOCK_IO2_PROTOCOL BlockIo2;
- EFI_BLOCK_IO_MEDIA Media;
- EFI_BLOCK_IO_MEDIA Media2;// For BlockIO2
- EFI_PARTITION_INFO_PROTOCOL PartitionInfo;
-
- EFI_DISK_IO_PROTOCOL *DiskIo;
- EFI_DISK_IO2_PROTOCOL *DiskIo2;
- EFI_BLOCK_IO_PROTOCOL *ParentBlockIo;
- EFI_BLOCK_IO2_PROTOCOL *ParentBlockIo2;
- UINT64 Start;
- UINT64 End;
- UINT32 BlockSize;
- BOOLEAN InStop;
-
- EFI_GUID TypeGuid;
-} PARTITION_PRIVATE_DATA;
-
-typedef struct {
- EFI_DISK_IO2_TOKEN DiskIo2Token;
- EFI_BLOCK_IO2_TOKEN *BlockIo2Token;
-} PARTITION_ACCESS_TASK;
-
-#define PARTITION_DEVICE_FROM_BLOCK_IO_THIS(a) CR (a, PARTITION_PRIVATE_DATA, BlockIo, PARTITION_PRIVATE_DATA_SIGNATURE)
-#define PARTITION_DEVICE_FROM_BLOCK_IO2_THIS(a) CR (a, PARTITION_PRIVATE_DATA, BlockIo2, PARTITION_PRIVATE_DATA_SIGNATURE)
-
-//
-// Global Variables
-//
-extern EFI_DRIVER_BINDING_PROTOCOL gPartitionDriverBinding;
-extern EFI_COMPONENT_NAME_PROTOCOL gPartitionComponentName;
-extern EFI_COMPONENT_NAME2_PROTOCOL gPartitionComponentName2;
-
-//
-// Extract INT32 from char array
-//
-#define UNPACK_INT32(a) (INT32)( (((UINT8 *) a)[0] << 0) | \
- (((UINT8 *) a)[1] << 8) | \
- (((UINT8 *) a)[2] << 16) | \
- (((UINT8 *) a)[3] << 24) )
-
-//
-// Extract UINT32 from char array
-//
-#define UNPACK_UINT32(a) (UINT32)( (((UINT8 *) a)[0] << 0) | \
- (((UINT8 *) a)[1] << 8) | \
- (((UINT8 *) a)[2] << 16) | \
- (((UINT8 *) a)[3] << 24) )
-
-//
-// GPT Partition Entry Status
-//
-typedef struct {
- BOOLEAN OutOfRange;
- BOOLEAN Overlap;
- BOOLEAN OsSpecific;
-} EFI_PARTITION_ENTRY_STATUS;
-
-//
-// Function Prototypes
-//
-
-/**
- Test to see if this driver supports ControllerHandle. Any ControllerHandle
- than contains a BlockIo and DiskIo protocol can be supported.
-
- @param This Protocol instance pointer.
- @param ControllerHandle Handle of device to test
- @param RemainingDevicePath Optional parameter use to pick a specific child
- device to start.
-
- @retval EFI_SUCCESS This driver supports this device
- @retval EFI_ALREADY_STARTED This driver is already running on this device
- @retval other This driver does not support this device
-
-**/
-EFI_STATUS
-EFIAPI
-PartitionDriverBindingSupported (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE ControllerHandle,
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
- );
-
-/**
- Start this driver on ControllerHandle by opening a Block IO and Disk IO
- protocol, reading Device Path, and creating a child handle with a
- Disk IO and device path protocol.
-
- @param This Protocol instance pointer.
- @param ControllerHandle Handle of device to bind driver to
- @param RemainingDevicePath Optional parameter use to pick a specific child
- device to start.
-
- @retval EFI_SUCCESS This driver is added to ControllerHandle
- @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
- @retval other This driver does not support this device
-
-**/
-EFI_STATUS
-EFIAPI
-PartitionDriverBindingStart (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE ControllerHandle,
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
- );
-
-/**
- Stop this driver on ControllerHandle. Support stopping any child handles
- created by this driver.
-
- @param This Protocol instance pointer.
- @param ControllerHandle Handle of device to stop driver on
- @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
- children is zero stop the entire bus driver.
- @param ChildHandleBuffer List of Child Handles to Stop.
-
- @retval EFI_SUCCESS This driver is removed ControllerHandle
- @retval other This driver was not removed from this device
-
-**/
-EFI_STATUS
-EFIAPI
-PartitionDriverBindingStop (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE ControllerHandle,
- IN UINTN NumberOfChildren,
- IN EFI_HANDLE *ChildHandleBuffer
- );
-
-//
-// EFI Component Name Functions
-//
-
-/**
- Retrieves a Unicode string that is the user readable name of the driver.
-
- This function retrieves the user readable name of a driver in the form of a
- Unicode string. If the driver specified by This has a user readable name in
- the language specified by Language, then a pointer to the driver name is
- returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
- by This does not support the language specified by Language,
- then EFI_UNSUPPORTED is returned.
-
- @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
- EFI_COMPONENT_NAME_PROTOCOL instance.
-
- @param Language[in] A pointer to a Null-terminated ASCII string
- array indicating the language. This is the
- language of the driver name that the caller is
- requesting, and it must match one of the
- languages specified in SupportedLanguages. The
- number of languages supported by a driver is up
- to the driver writer. Language is specified
- in RFC 4646 or ISO 639-2 language code format.
-
- @param DriverName[out] A pointer to the Unicode string to return.
- This Unicode string is the name of the
- driver specified by This in the language
- specified by Language.
-
- @retval EFI_SUCCESS The Unicode string for the Driver specified by
- This and the language specified by Language was
- returned in DriverName.
-
- @retval EFI_INVALID_PARAMETER Language is NULL.
-
- @retval EFI_INVALID_PARAMETER DriverName is NULL.
-
- @retval EFI_UNSUPPORTED The driver specified by This does not support
- the language specified by Language.
-
-**/
-EFI_STATUS
-EFIAPI
-PartitionComponentNameGetDriverName (
- IN EFI_COMPONENT_NAME_PROTOCOL *This,
- IN CHAR8 *Language,
- OUT CHAR16 **DriverName
- );
-
-/**
- Retrieves a Unicode string that is the user readable name of the controller
- that is being managed by a driver.
-
- This function retrieves the user readable name of the controller specified by
- ControllerHandle and ChildHandle in the form of a Unicode string. If the
- driver specified by This has a user readable name in the language specified by
- Language, then a pointer to the controller name is returned in ControllerName,
- and EFI_SUCCESS is returned. If the driver specified by This is not currently
- managing the controller specified by ControllerHandle and ChildHandle,
- then EFI_UNSUPPORTED is returned. If the driver specified by This does not
- support the language specified by Language, then EFI_UNSUPPORTED is returned.
-
- @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
- EFI_COMPONENT_NAME_PROTOCOL instance.
-
- @param ControllerHandle[in] The handle of a controller that the driver
- specified by This is managing. This handle
- specifies the controller whose name is to be
- returned.
-
- @param ChildHandle[in] The handle of the child controller to retrieve
- the name of. This is an optional parameter that
- may be NULL. It will be NULL for device
- drivers. It will also be NULL for a bus drivers
- that wish to retrieve the name of the bus
- controller. It will not be NULL for a bus
- driver that wishes to retrieve the name of a
- child controller.
-
- @param Language[in] A pointer to a Null-terminated ASCII string
- array indicating the language. This is the
- language of the driver name that the caller is
- requesting, and it must match one of the
- languages specified in SupportedLanguages. The
- number of languages supported by a driver is up
- to the driver writer. Language is specified in
- RFC 4646 or ISO 639-2 language code format.
-
- @param ControllerName[out] A pointer to the Unicode string to return.
- This Unicode string is the name of the
- controller specified by ControllerHandle and
- ChildHandle in the language specified by
- Language from the point of view of the driver
- specified by This.
-
- @retval EFI_SUCCESS The Unicode string for the user readable name in
- the language specified by Language for the
- driver specified by This was returned in
- DriverName.
-
- @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
-
- @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
- EFI_HANDLE.
-
- @retval EFI_INVALID_PARAMETER Language is NULL.
-
- @retval EFI_INVALID_PARAMETER ControllerName is NULL.
-
- @retval EFI_UNSUPPORTED The driver specified by This is not currently
- managing the controller specified by
- ControllerHandle and ChildHandle.
-
- @retval EFI_UNSUPPORTED The driver specified by This does not support
- the language specified by Language.
-
-**/
-EFI_STATUS
-EFIAPI
-PartitionComponentNameGetControllerName (
- IN EFI_COMPONENT_NAME_PROTOCOL *This,
- IN EFI_HANDLE ControllerHandle,
- IN EFI_HANDLE ChildHandle OPTIONAL,
- IN CHAR8 *Language,
- OUT CHAR16 **ControllerName
- );
-
-/**
- Create a child handle for a logical block device that represents the
- bytes Start to End of the Parent Block IO device.
-
- @param[in] This Protocol instance pointer.
- @param[in] ParentHandle Parent Handle for new child.
- @param[in] ParentDiskIo Parent DiskIo interface.
- @param[in] ParentDiskIo2 Parent DiskIo2 interface.
- @param[in] ParentBlockIo Parent BlockIo interface.
- @param[in] ParentBlockIo2 Parent BlockIo2 interface.
- @param[in] ParentDevicePath Parent Device Path.
- @param[in] DevicePathNode Child Device Path node.
- @param[in] PartitionInfo Child Partition Information interface.
- @param[in] Start Start Block.
- @param[in] End End Block.
- @param[in] BlockSize Child block size.
- @param[in] TypeGuid Parition Type Guid.
-
- @retval EFI_SUCCESS A child handle was added.
- @retval other A child handle was not added.
-
-**/
-EFI_STATUS
-PartitionInstallChildHandle (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE ParentHandle,
- IN EFI_DISK_IO_PROTOCOL *ParentDiskIo,
- IN EFI_DISK_IO2_PROTOCOL *ParentDiskIo2,
- IN EFI_BLOCK_IO_PROTOCOL *ParentBlockIo,
- IN EFI_BLOCK_IO2_PROTOCOL *ParentBlockIo2,
- IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
- IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode,
- IN EFI_PARTITION_INFO_PROTOCOL *PartitionInfo,
- IN EFI_LBA Start,
- IN EFI_LBA End,
- IN UINT32 BlockSize,
- IN EFI_GUID *TypeGuid
- );
-
-/**
- Test to see if there is any child on ControllerHandle.
-
- @param[in] ControllerHandle Handle of device to test.
-
- @retval TRUE There are children on the ControllerHandle.
- @retval FALSE No child is on the ControllerHandle.
-
-**/
-BOOLEAN
-HasChildren (
- IN EFI_HANDLE ControllerHandle
- );
-
-/**
- Install child handles if the Handle supports GPT partition structure.
-
- @param[in] This Calling context.
- @param[in] Handle Parent Handle.
- @param[in] DiskIo Parent DiskIo interface.
- @param[in] DiskIo2 Parent DiskIo2 interface.
- @param[in] BlockIo Parent BlockIo interface.
- @param[in] BlockIo2 Parent BlockIo2 interface.
- @param[in] DevicePath Parent Device Path.
-
- @retval EFI_SUCCESS Valid GPT disk.
- @retval EFI_MEDIA_CHANGED Media changed Detected.
- @retval EFI_INVALID_PARAMETER If both BlockIo and BlockIo2 are NULL;
- @retval other Not a valid GPT disk.
-
-**/
-EFI_STATUS
-PartitionInstallGptChildHandles (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE Handle,
- IN EFI_DISK_IO_PROTOCOL *DiskIo,
- IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
- IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
- IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
- IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
- );
-
-/**
- Install child handles if the Handle supports El Torito format.
-
- @param[in] This Calling context.
- @param[in] Handle Parent Handle.
- @param[in] DiskIo Parent DiskIo interface.
- @param[in] DiskIo2 Parent DiskIo2 interface.
- @param[in] BlockIo Parent BlockIo interface.
- @param[in] BlockIo2 Parent BlockIo2 interface.
- @param[in] DevicePath Parent Device Path
-
-
- @retval EFI_SUCCESS Child handle(s) was added.
- @retval EFI_MEDIA_CHANGED Media changed Detected.
- @retval other no child handle was added.
-
-**/
-EFI_STATUS
-PartitionInstallElToritoChildHandles (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE Handle,
- IN EFI_DISK_IO_PROTOCOL *DiskIo,
- IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
- IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
- IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
- IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
- );
-
-/**
- Install child handles if the Handle supports MBR format.
-
- @param[in] This Calling context.
- @param[in] Handle Parent Handle.
- @param[in] DiskIo Parent DiskIo interface.
- @param[in] DiskIo2 Parent DiskIo2 interface.
- @param[in] BlockIo Parent BlockIo interface.
- @param[in] BlockIo2 Parent BlockIo2 interface.
- @param[in] DevicePath Parent Device Path.
-
- @retval EFI_SUCCESS A child handle was added.
- @retval EFI_MEDIA_CHANGED Media change was detected.
- @retval Others MBR partition was not found.
-
-**/
-EFI_STATUS
-PartitionInstallMbrChildHandles (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE Handle,
- IN EFI_DISK_IO_PROTOCOL *DiskIo,
- IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
- IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
- IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
- IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
- );
-
-/**
- Install child handles if the Handle supports UDF/ECMA-167 volume format.
-
- @param[in] This Calling context.
- @param[in] Handle Parent Handle.
- @param[in] DiskIo Parent DiskIo interface.
- @param[in] DiskIo2 Parent DiskIo2 interface.
- @param[in] BlockIo Parent BlockIo interface.
- @param[in] BlockIo2 Parent BlockIo2 interface.
- @param[in] DevicePath Parent Device Path
-
-
- @retval EFI_SUCCESS Child handle(s) was added.
- @retval EFI_MEDIA_CHANGED Media changed Detected.
- @retval other no child handle was added.
-
-**/
-EFI_STATUS
-PartitionInstallUdfChildHandles (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE Handle,
- IN EFI_DISK_IO_PROTOCOL *DiskIo,
- IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
- IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
- IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
- IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
- );
-
-typedef
-EFI_STATUS
-(*PARTITION_DETECT_ROUTINE) (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE Handle,
- IN EFI_DISK_IO_PROTOCOL *DiskIo,
- IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
- IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
- IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
- IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
- );
-
-#endif
+/** @file
+ Partition driver that produces logical BlockIo devices from a physical
+ BlockIo device. The logical BlockIo devices are based on the format
+ of the raw block devices media. Currently "El Torito CD-ROM", UDF, Legacy
+ MBR, and GPT partition schemes are supported.
+
+Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PARTITION_H_
+#define _PARTITION_H_
+
+#include <Uefi.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/BlockIo2.h>
+#include <Guid/Gpt.h>
+#include <Protocol/ComponentName.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/DiskIo.h>
+#include <Protocol/DiskIo2.h>
+#include <Protocol/PartitionInfo.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+
+#include <IndustryStandard/Mbr.h>
+#include <IndustryStandard/ElTorito.h>
+#include <IndustryStandard/Udf.h>
+
+//
+// Partition private data
+//
+#define PARTITION_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('P', 'a', 'r', 't')
+typedef struct {
+ UINT64 Signature;
+
+ EFI_HANDLE Handle;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_BLOCK_IO_PROTOCOL BlockIo;
+ EFI_BLOCK_IO2_PROTOCOL BlockIo2;
+ EFI_BLOCK_IO_MEDIA Media;
+ EFI_BLOCK_IO_MEDIA Media2;// For BlockIO2
+ EFI_PARTITION_INFO_PROTOCOL PartitionInfo;
+
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+ EFI_DISK_IO2_PROTOCOL *DiskIo2;
+ EFI_BLOCK_IO_PROTOCOL *ParentBlockIo;
+ EFI_BLOCK_IO2_PROTOCOL *ParentBlockIo2;
+ UINT64 Start;
+ UINT64 End;
+ UINT32 BlockSize;
+ BOOLEAN InStop;
+
+ EFI_GUID TypeGuid;
+} PARTITION_PRIVATE_DATA;
+
+typedef struct {
+ EFI_DISK_IO2_TOKEN DiskIo2Token;
+ EFI_BLOCK_IO2_TOKEN *BlockIo2Token;
+} PARTITION_ACCESS_TASK;
+
+#define PARTITION_DEVICE_FROM_BLOCK_IO_THIS(a) CR (a, PARTITION_PRIVATE_DATA, BlockIo, PARTITION_PRIVATE_DATA_SIGNATURE)
+#define PARTITION_DEVICE_FROM_BLOCK_IO2_THIS(a) CR (a, PARTITION_PRIVATE_DATA, BlockIo2, PARTITION_PRIVATE_DATA_SIGNATURE)
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gPartitionDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gPartitionComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gPartitionComponentName2;
+
+//
+// Extract INT32 from char array
+//
+#define UNPACK_INT32(a) (INT32)( (((UINT8 *) a)[0] << 0) | \
+ (((UINT8 *) a)[1] << 8) | \
+ (((UINT8 *) a)[2] << 16) | \
+ (((UINT8 *) a)[3] << 24) )
+
+//
+// Extract UINT32 from char array
+//
+#define UNPACK_UINT32(a) (UINT32)( (((UINT8 *) a)[0] << 0) | \
+ (((UINT8 *) a)[1] << 8) | \
+ (((UINT8 *) a)[2] << 16) | \
+ (((UINT8 *) a)[3] << 24) )
+
+//
+// GPT Partition Entry Status
+//
+typedef struct {
+ BOOLEAN OutOfRange;
+ BOOLEAN Overlap;
+ BOOLEAN OsSpecific;
+} EFI_PARTITION_ENTRY_STATUS;
+
+//
+// Function Prototypes
+//
+
+/**
+ Test to see if this driver supports ControllerHandle. Any ControllerHandle
+ than contains a BlockIo and DiskIo protocol can be supported.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to test
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver supports this device
+ @retval EFI_ALREADY_STARTED This driver is already running on this device
+ @retval other This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Start this driver on ControllerHandle by opening a Block IO and Disk IO
+ protocol, reading Device Path, and creating a child handle with a
+ Disk IO and device path protocol.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to bind driver to
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver is added to ControllerHandle
+ @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
+ @retval other This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop this driver on ControllerHandle. Support stopping any child handles
+ created by this driver.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to stop driver on
+ @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
+ children is zero stop the entire bus driver.
+ @param ChildHandleBuffer List of Child Handles to Stop.
+
+ @retval EFI_SUCCESS This driver is removed ControllerHandle
+ @retval other This driver was not removed from this device
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+//
+// EFI Component Name Functions
+//
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+/**
+ Create a child handle for a logical block device that represents the
+ bytes Start to End of the Parent Block IO device.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ParentHandle Parent Handle for new child.
+ @param[in] ParentDiskIo Parent DiskIo interface.
+ @param[in] ParentDiskIo2 Parent DiskIo2 interface.
+ @param[in] ParentBlockIo Parent BlockIo interface.
+ @param[in] ParentBlockIo2 Parent BlockIo2 interface.
+ @param[in] ParentDevicePath Parent Device Path.
+ @param[in] DevicePathNode Child Device Path node.
+ @param[in] PartitionInfo Child Partition Information interface.
+ @param[in] Start Start Block.
+ @param[in] End End Block.
+ @param[in] BlockSize Child block size.
+ @param[in] TypeGuid Parition Type Guid.
+
+ @retval EFI_SUCCESS A child handle was added.
+ @retval other A child handle was not added.
+
+**/
+EFI_STATUS
+PartitionInstallChildHandle (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ParentHandle,
+ IN EFI_DISK_IO_PROTOCOL *ParentDiskIo,
+ IN EFI_DISK_IO2_PROTOCOL *ParentDiskIo2,
+ IN EFI_BLOCK_IO_PROTOCOL *ParentBlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *ParentBlockIo2,
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode,
+ IN EFI_PARTITION_INFO_PROTOCOL *PartitionInfo,
+ IN EFI_LBA Start,
+ IN EFI_LBA End,
+ IN UINT32 BlockSize,
+ IN EFI_GUID *TypeGuid
+ );
+
+/**
+ Test to see if there is any child on ControllerHandle.
+
+ @param[in] ControllerHandle Handle of device to test.
+
+ @retval TRUE There are children on the ControllerHandle.
+ @retval FALSE No child is on the ControllerHandle.
+
+**/
+BOOLEAN
+HasChildren (
+ IN EFI_HANDLE ControllerHandle
+ );
+
+/**
+ Install child handles if the Handle supports GPT partition structure.
+
+ @param[in] This Calling context.
+ @param[in] Handle Parent Handle.
+ @param[in] DiskIo Parent DiskIo interface.
+ @param[in] DiskIo2 Parent DiskIo2 interface.
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] BlockIo2 Parent BlockIo2 interface.
+ @param[in] DevicePath Parent Device Path.
+
+ @retval EFI_SUCCESS Valid GPT disk.
+ @retval EFI_MEDIA_CHANGED Media changed Detected.
+ @retval EFI_INVALID_PARAMETER If both BlockIo and BlockIo2 are NULL;
+ @retval other Not a valid GPT disk.
+
+**/
+EFI_STATUS
+PartitionInstallGptChildHandles (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+/**
+ Install child handles if the Handle supports El Torito format.
+
+ @param[in] This Calling context.
+ @param[in] Handle Parent Handle.
+ @param[in] DiskIo Parent DiskIo interface.
+ @param[in] DiskIo2 Parent DiskIo2 interface.
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] BlockIo2 Parent BlockIo2 interface.
+ @param[in] DevicePath Parent Device Path
+
+
+ @retval EFI_SUCCESS Child handle(s) was added.
+ @retval EFI_MEDIA_CHANGED Media changed Detected.
+ @retval other no child handle was added.
+
+**/
+EFI_STATUS
+PartitionInstallElToritoChildHandles (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+/**
+ Install child handles if the Handle supports MBR format.
+
+ @param[in] This Calling context.
+ @param[in] Handle Parent Handle.
+ @param[in] DiskIo Parent DiskIo interface.
+ @param[in] DiskIo2 Parent DiskIo2 interface.
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] BlockIo2 Parent BlockIo2 interface.
+ @param[in] DevicePath Parent Device Path.
+
+ @retval EFI_SUCCESS A child handle was added.
+ @retval EFI_MEDIA_CHANGED Media change was detected.
+ @retval Others MBR partition was not found.
+
+**/
+EFI_STATUS
+PartitionInstallMbrChildHandles (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+/**
+ Install child handles if the Handle supports UDF/ECMA-167 volume format.
+
+ @param[in] This Calling context.
+ @param[in] Handle Parent Handle.
+ @param[in] DiskIo Parent DiskIo interface.
+ @param[in] DiskIo2 Parent DiskIo2 interface.
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] BlockIo2 Parent BlockIo2 interface.
+ @param[in] DevicePath Parent Device Path
+
+
+ @retval EFI_SUCCESS Child handle(s) was added.
+ @retval EFI_MEDIA_CHANGED Media changed Detected.
+ @retval other no child handle was added.
+
+**/
+EFI_STATUS
+PartitionInstallUdfChildHandles (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+typedef
+EFI_STATUS
+(*PARTITION_DETECT_ROUTINE) (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+#endif
diff --git a/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf b/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf
index 14ab6ae198..0619ba9779 100644
--- a/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf
+++ b/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf
@@ -1,85 +1,85 @@
-## @file
-# Modules that produces the logic Block I/O protocol for every partition via the physical Block I/O.
-#
-# This module produces the logical Block I/O device that represents
-# the bytes from Start to End of the Parent Block I/O device.
-# The partition of physical BlockIo device supported is one of legacy MBR, GPT,
-# UDF and "El Torito" partitions.
-#
-# Caution: This module requires additional review when modified.
-# This driver will have external input - disk partition.
-# This external input must be validated carefully to avoid security issue like
-# buffer overflow, integer overflow.
-#
-# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-##
-
-[Defines]
- INF_VERSION = 0x00010005
- BASE_NAME = PartitionDxe
- MODULE_UNI_FILE = PartitionDxe.uni
- FILE_GUID = 1FA1F39E-FEFF-4aae-BD7B-38A070A3B609
- MODULE_TYPE = UEFI_DRIVER
- VERSION_STRING = 1.0
- ENTRY_POINT = InitializePartition
-
-#
-# The following information is for reference only and not required by the build tools.
-#
-# VALID_ARCHITECTURES = IA32 X64 EBC
-#
-# DRIVER_BINDING = gPartitionDriverBinding
-# COMPONENT_NAME = gPartitionComponentName
-# COMPONENT_NAME2 = gPartitionComponentName2
-#
-
-[Sources]
- ComponentName.c
- Mbr.c
- Gpt.c
- ElTorito.c
- Udf.c
- Partition.c
- Partition.h
-
-
-[Packages]
- MdePkg/MdePkg.dec
-
-
-[LibraryClasses]
- DevicePathLib
- UefiBootServicesTableLib
- MemoryAllocationLib
- BaseMemoryLib
- UefiLib
- BaseLib
- UefiDriverEntryPoint
- DebugLib
-
-
-[Guids]
- gEfiPartTypeUnusedGuid ## SOMETIMES_CONSUMES ## GUID
- ## SOMETIMES_CONSUMES ## GUID
- ## SOMETIMES_CONSUMES ## GUID # Install protocol
- gEfiPartTypeSystemPartGuid
-
-
-[Protocols]
- ## BY_START
- ## TO_START
- gEfiBlockIoProtocolGuid
- ## BY_START
- ## TO_START
- gEfiBlockIo2ProtocolGuid
- ## BY_START
- ## TO_START
- gEfiDevicePathProtocolGuid
- gEfiPartitionInfoProtocolGuid ## BY_START
- gEfiDiskIoProtocolGuid ## TO_START
- gEfiDiskIo2ProtocolGuid ## TO_START
-
-[UserExtensions.TianoCore."ExtraFiles"]
- PartitionDxeExtra.uni
+## @file
+# Modules that produces the logic Block I/O protocol for every partition via the physical Block I/O.
+#
+# This module produces the logical Block I/O device that represents
+# the bytes from Start to End of the Parent Block I/O device.
+# The partition of physical BlockIo device supported is one of legacy MBR, GPT,
+# UDF and "El Torito" partitions.
+#
+# Caution: This module requires additional review when modified.
+# This driver will have external input - disk partition.
+# This external input must be validated carefully to avoid security issue like
+# buffer overflow, integer overflow.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PartitionDxe
+ MODULE_UNI_FILE = PartitionDxe.uni
+ FILE_GUID = 1FA1F39E-FEFF-4aae-BD7B-38A070A3B609
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializePartition
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+# DRIVER_BINDING = gPartitionDriverBinding
+# COMPONENT_NAME = gPartitionComponentName
+# COMPONENT_NAME2 = gPartitionComponentName2
+#
+
+[Sources]
+ ComponentName.c
+ Mbr.c
+ Gpt.c
+ ElTorito.c
+ Udf.c
+ Partition.c
+ Partition.h
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+
+[LibraryClasses]
+ DevicePathLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ UefiLib
+ BaseLib
+ UefiDriverEntryPoint
+ DebugLib
+
+
+[Guids]
+ gEfiPartTypeUnusedGuid ## SOMETIMES_CONSUMES ## GUID
+ ## SOMETIMES_CONSUMES ## GUID
+ ## SOMETIMES_CONSUMES ## GUID # Install protocol
+ gEfiPartTypeSystemPartGuid
+
+
+[Protocols]
+ ## BY_START
+ ## TO_START
+ gEfiBlockIoProtocolGuid
+ ## BY_START
+ ## TO_START
+ gEfiBlockIo2ProtocolGuid
+ ## BY_START
+ ## TO_START
+ gEfiDevicePathProtocolGuid
+ gEfiPartitionInfoProtocolGuid ## BY_START
+ gEfiDiskIoProtocolGuid ## TO_START
+ gEfiDiskIo2ProtocolGuid ## TO_START
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ PartitionDxeExtra.uni
diff --git a/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.uni b/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.uni
index e22c47bbc3..5b26a807bb 100644
--- a/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.uni
+++ b/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.uni
@@ -1,24 +1,24 @@
-// /** @file
-// Modules that produces the logic Block I/O protocol for every partition via the physical Block I/O.
-//
-// This module produces the logical Block I/O device that represents
-// the bytes from Start to End of the Parent Block I/O device.
-// The partition of physical BlockIo device supported is one of legacy MBR, GPT,
-// and "El Torito" partitions.
-//
-// Caution: This module requires additional review when modified.
-// This driver will have external input - disk partition.
-// This external input must be validated carefully to avoid security issue like
-// buffer overflow, integer overflow.
-//
-// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
-//
-// SPDX-License-Identifier: BSD-2-Clause-Patent
-//
-// **/
-
-
-#string STR_MODULE_ABSTRACT #language en-US "Produces the logic Block I/O protocol for every partition via the physical Block I/O."
-
-#string STR_MODULE_DESCRIPTION #language en-US "This module produces the logical Block I/O device that represents the bytes from Start to End of the Parent Block I/O device. The partition of physical BlockIO device supported is one of legacy MBR, GPT, and \"El Torito\" partitions.<BR><BR>"
-
+// /** @file
+// Modules that produces the logic Block I/O protocol for every partition via the physical Block I/O.
+//
+// This module produces the logical Block I/O device that represents
+// the bytes from Start to End of the Parent Block I/O device.
+// The partition of physical BlockIo device supported is one of legacy MBR, GPT,
+// and "El Torito" partitions.
+//
+// Caution: This module requires additional review when modified.
+// This driver will have external input - disk partition.
+// This external input must be validated carefully to avoid security issue like
+// buffer overflow, integer overflow.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Produces the logic Block I/O protocol for every partition via the physical Block I/O."
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module produces the logical Block I/O device that represents the bytes from Start to End of the Parent Block I/O device. The partition of physical BlockIO device supported is one of legacy MBR, GPT, and \"El Torito\" partitions.<BR><BR>"
+
diff --git a/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxeExtra.uni b/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxeExtra.uni
index f92d2e53c3..bd18518112 100644
--- a/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxeExtra.uni
+++ b/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxeExtra.uni
@@ -1,14 +1,14 @@
-// /** @file
-// PartitionDxe Localized Strings and Content
-//
-// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
-//
-// SPDX-License-Identifier: BSD-2-Clause-Patent
-//
-// **/
-
-#string STR_PROPERTIES_MODULE_NAME
-#language en-US
-"Partition DXE Driver"
-
-
+// /** @file
+// PartitionDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Partition DXE Driver"
+
+
diff --git a/MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c b/MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c
index 6e10defe59..dbd292f34a 100644
--- a/MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c
+++ b/MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c
@@ -1,827 +1,827 @@
-/** @file
- Scan for an UDF file system on a formatted media.
-
- Caution: This file requires additional review when modified.
- This driver will have external input - CD/DVD media.
- This external input must be validated carefully to avoid security issue like
- buffer overflow, integer overflow.
-
- FindUdfFileSystem() routine will consume the media properties and do basic
- validation.
-
- Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
- Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
- Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
-
- SPDX-License-Identifier: BSD-2-Clause-Patent
-**/
-
-#include "Partition.h"
-
-#define MAX_CORRECTION_BLOCKS_NUM 512u
-
-//
-// C5BD4D42-1A76-4996-8956-73CDA326CD0A
-//
-#define EFI_UDF_DEVICE_PATH_GUID \
- { 0xC5BD4D42, 0x1A76, 0x4996, \
- { 0x89, 0x56, 0x73, 0xCD, 0xA3, 0x26, 0xCD, 0x0A } \
- }
-
-typedef struct {
- VENDOR_DEVICE_PATH DevicePath;
- EFI_DEVICE_PATH_PROTOCOL End;
-} UDF_DEVICE_PATH;
-
-//
-// Vendor-Defined Device Path GUID for UDF file system
-//
-EFI_GUID gUdfDevPathGuid = EFI_UDF_DEVICE_PATH_GUID;
-
-//
-// Vendor-Defined Media Device Path for UDF file system
-//
-UDF_DEVICE_PATH gUdfDevicePath = {
- {
- { MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP,
- { sizeof (VENDOR_DEVICE_PATH), 0 }
- },
- EFI_UDF_DEVICE_PATH_GUID
- },
- { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
- { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
- }
-};
-
-/**
- Find the anchor volume descriptor pointer.
-
- @param[in] BlockIo BlockIo interface.
- @param[in] DiskIo DiskIo interface.
- @param[out] AnchorPoint Anchor volume descriptor pointer.
- @param[out] LastRecordedBlock Last recorded block.
-
- @retval EFI_SUCCESS Anchor volume descriptor pointer found.
- @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
- @retval other Anchor volume descriptor pointer not found.
-
-**/
-EFI_STATUS
-FindAnchorVolumeDescriptorPointer (
- IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
- IN EFI_DISK_IO_PROTOCOL *DiskIo,
- OUT UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPoint,
- OUT EFI_LBA *LastRecordedBlock
- )
-{
- EFI_STATUS Status;
- UINT32 BlockSize;
- EFI_LBA EndLBA;
- UDF_DESCRIPTOR_TAG *DescriptorTag;
- UINTN AvdpsCount;
- UINTN Size;
- UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPoints;
- INTN Index;
- UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPointPtr;
- EFI_LBA LastAvdpBlockNum;
-
- //
- // UDF 2.60, 2.2.3 Anchor Volume Descriptor Pointer
- //
- // An Anchor Volume Descriptor Pointer structure shall be recorded in at
- // least 2 of the following 3 locations on the media: Logical Sector 256,
- // N - 256 or N, where N is the last *addressable* sector of a volume.
- //
- // To figure out what logical sector N is, the SCSI commands READ CAPACITY and
- // READ TRACK INFORMATION are used, however many drives or medias report their
- // "last recorded block" wrongly. Although, READ CAPACITY returns the last
- // readable data block but there might be unwritten blocks, which are located
- // outside any track and therefore AVDP will not be found at block N.
- //
- // That said, we define a magic number of 512 blocks to be used as correction
- // when attempting to find AVDP and define last block number.
- //
- BlockSize = BlockIo->Media->BlockSize;
- EndLBA = BlockIo->Media->LastBlock;
- *LastRecordedBlock = EndLBA;
- AvdpsCount = 0;
-
- //
- // Check if the block size of the underlying media can hold the data of an
- // Anchor Volume Descriptor Pointer
- //
- if (BlockSize < sizeof (UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER)) {
- DEBUG ((
- DEBUG_ERROR,
- "%a: Media block size 0x%x unable to hold an AVDP.\n",
- __func__,
- BlockSize
- ));
- return EFI_UNSUPPORTED;
- }
-
- //
- // Find AVDP at block 256
- //
- Status = DiskIo->ReadDisk (
- DiskIo,
- BlockIo->Media->MediaId,
- MultU64x32 (256, BlockSize),
- sizeof (*AnchorPoint),
- AnchorPoint
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- DescriptorTag = &AnchorPoint->DescriptorTag;
-
- //
- // Check if read block is a valid AVDP descriptor
- //
- if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer) {
- DEBUG ((DEBUG_INFO, "%a: found AVDP at block %d\n", __func__, 256));
- AvdpsCount++;
- }
-
- //
- // Find AVDP at block N - 256
- //
- Status = DiskIo->ReadDisk (
- DiskIo,
- BlockIo->Media->MediaId,
- MultU64x32 ((UINT64)EndLBA - 256, BlockSize),
- sizeof (*AnchorPoint),
- AnchorPoint
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Check if read block is a valid AVDP descriptor
- //
- if ((DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer) &&
- (++AvdpsCount == 2))
- {
- DEBUG ((
- DEBUG_INFO,
- "%a: found AVDP at block %Ld\n",
- __func__,
- EndLBA - 256
- ));
- return EFI_SUCCESS;
- }
-
- //
- // Check if at least one AVDP was found in previous locations
- //
- if (AvdpsCount == 0) {
- return EFI_VOLUME_CORRUPTED;
- }
-
- //
- // Find AVDP at block N
- //
- Status = DiskIo->ReadDisk (
- DiskIo,
- BlockIo->Media->MediaId,
- MultU64x32 ((UINT64)EndLBA, BlockSize),
- sizeof (*AnchorPoint),
- AnchorPoint
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Check if read block is a valid AVDP descriptor
- //
- if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer) {
- return EFI_SUCCESS;
- }
-
- //
- // No AVDP found at block N. Possibly drive/media returned bad last recorded
- // block, or it is part of unwritten data blocks and outside any track.
- //
- // Search backwards for an AVDP from block N-1 through
- // N-MAX_CORRECTION_BLOCKS_NUM. If any AVDP is found, then correct last block
- // number for the new UDF partition child handle.
- //
- Size = MAX_CORRECTION_BLOCKS_NUM * BlockSize;
-
- AnchorPoints = AllocateZeroPool (Size);
- if (AnchorPoints == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- //
- // Read consecutive MAX_CORRECTION_BLOCKS_NUM disk blocks
- //
- Status = DiskIo->ReadDisk (
- DiskIo,
- BlockIo->Media->MediaId,
- MultU64x32 ((UINT64)EndLBA - MAX_CORRECTION_BLOCKS_NUM, BlockSize),
- Size,
- AnchorPoints
- );
- if (EFI_ERROR (Status)) {
- goto Out_Free;
- }
-
- Status = EFI_VOLUME_CORRUPTED;
-
- //
- // Search for AVDP from blocks N-1 through N-MAX_CORRECTION_BLOCKS_NUM
- //
- for (Index = MAX_CORRECTION_BLOCKS_NUM - 2; Index >= 0; Index--) {
- AnchorPointPtr = (VOID *)((UINTN)AnchorPoints + Index * BlockSize);
-
- DescriptorTag = &AnchorPointPtr->DescriptorTag;
-
- //
- // Check if read block is a valid AVDP descriptor
- //
- if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer) {
- //
- // Calculate last recorded block number
- //
- LastAvdpBlockNum = EndLBA - (MAX_CORRECTION_BLOCKS_NUM - Index);
- DEBUG ((
- DEBUG_WARN,
- "%a: found AVDP at block %Ld\n",
- __func__,
- LastAvdpBlockNum
- ));
- DEBUG ((
- DEBUG_WARN,
- "%a: correcting last block from %Ld to %Ld\n",
- __func__,
- EndLBA,
- LastAvdpBlockNum
- ));
- //
- // Save read AVDP from last block
- //
- CopyMem (AnchorPoint, AnchorPointPtr, sizeof (*AnchorPointPtr));
- //
- // Set last recorded block number
- //
- *LastRecordedBlock = LastAvdpBlockNum;
- Status = EFI_SUCCESS;
- break;
- }
- }
-
-Out_Free:
- FreePool (AnchorPoints);
- return Status;
-}
-
-/**
- Find UDF volume identifiers in a Volume Recognition Sequence.
-
- @param[in] BlockIo BlockIo interface.
- @param[in] DiskIo DiskIo interface.
-
- @retval EFI_SUCCESS UDF volume identifiers were found.
- @retval EFI_NOT_FOUND UDF volume identifiers were not found.
- @retval other Failed to perform disk I/O.
-
-**/
-EFI_STATUS
-FindUdfVolumeIdentifiers (
- IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
- IN EFI_DISK_IO_PROTOCOL *DiskIo
- )
-{
- EFI_STATUS Status;
- UINT64 Offset;
- UINT64 EndDiskOffset;
- CDROM_VOLUME_DESCRIPTOR VolDescriptor;
- CDROM_VOLUME_DESCRIPTOR TerminatingVolDescriptor;
-
- ZeroMem ((VOID *)&TerminatingVolDescriptor, sizeof (CDROM_VOLUME_DESCRIPTOR));
-
- //
- // Start Volume Recognition Sequence
- //
- EndDiskOffset = MultU64x32 (
- BlockIo->Media->LastBlock,
- BlockIo->Media->BlockSize
- );
-
- for (Offset = UDF_VRS_START_OFFSET; Offset < EndDiskOffset;
- Offset += UDF_LOGICAL_SECTOR_SIZE)
- {
- //
- // Check if block device has a Volume Structure Descriptor and an Extended
- // Area.
- //
- Status = DiskIo->ReadDisk (
- DiskIo,
- BlockIo->Media->MediaId,
- Offset,
- sizeof (CDROM_VOLUME_DESCRIPTOR),
- (VOID *)&VolDescriptor
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (CompareMem (
- (VOID *)VolDescriptor.Unknown.Id,
- (VOID *)UDF_BEA_IDENTIFIER,
- sizeof (VolDescriptor.Unknown.Id)
- ) == 0)
- {
- break;
- }
-
- if ((CompareMem (
- (VOID *)VolDescriptor.Unknown.Id,
- (VOID *)CDVOL_ID,
- sizeof (VolDescriptor.Unknown.Id)
- ) != 0) ||
- (CompareMem (
- (VOID *)&VolDescriptor,
- (VOID *)&TerminatingVolDescriptor,
- sizeof (CDROM_VOLUME_DESCRIPTOR)
- ) == 0))
- {
- return EFI_NOT_FOUND;
- }
- }
-
- //
- // Look for "NSR0{2,3}" identifiers in the Extended Area.
- //
- Offset += UDF_LOGICAL_SECTOR_SIZE;
- if (Offset >= EndDiskOffset) {
- return EFI_NOT_FOUND;
- }
-
- Status = DiskIo->ReadDisk (
- DiskIo,
- BlockIo->Media->MediaId,
- Offset,
- sizeof (CDROM_VOLUME_DESCRIPTOR),
- (VOID *)&VolDescriptor
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if ((CompareMem (
- (VOID *)VolDescriptor.Unknown.Id,
- (VOID *)UDF_NSR2_IDENTIFIER,
- sizeof (VolDescriptor.Unknown.Id)
- ) != 0) &&
- (CompareMem (
- (VOID *)VolDescriptor.Unknown.Id,
- (VOID *)UDF_NSR3_IDENTIFIER,
- sizeof (VolDescriptor.Unknown.Id)
- ) != 0))
- {
- return EFI_NOT_FOUND;
- }
-
- //
- // Look for "TEA01" identifier in the Extended Area
- //
- Offset += UDF_LOGICAL_SECTOR_SIZE;
- if (Offset >= EndDiskOffset) {
- return EFI_NOT_FOUND;
- }
-
- Status = DiskIo->ReadDisk (
- DiskIo,
- BlockIo->Media->MediaId,
- Offset,
- sizeof (CDROM_VOLUME_DESCRIPTOR),
- (VOID *)&VolDescriptor
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (CompareMem (
- (VOID *)VolDescriptor.Unknown.Id,
- (VOID *)UDF_TEA_IDENTIFIER,
- sizeof (VolDescriptor.Unknown.Id)
- ) != 0)
- {
- return EFI_NOT_FOUND;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Check if Logical Volume Descriptor is supported by current EDK2 UDF file
- system implementation.
-
- @param[in] LogicalVolDesc Logical Volume Descriptor pointer.
-
- @retval TRUE Logical Volume Descriptor is supported.
- @retval FALSE Logical Volume Descriptor is not supported.
-
-**/
-BOOLEAN
-IsLogicalVolumeDescriptorSupported (
- UDF_LOGICAL_VOLUME_DESCRIPTOR *LogicalVolDesc
- )
-{
- //
- // Check for a valid UDF revision range
- //
- switch (LogicalVolDesc->DomainIdentifier.Suffix.Domain.UdfRevision) {
- case 0x0102:
- case 0x0150:
- case 0x0200:
- case 0x0201:
- case 0x0250:
- case 0x0260:
- break;
- default:
- return FALSE;
- }
-
- //
- // Check for a single Partition Map
- //
- if (LogicalVolDesc->NumberOfPartitionMaps > 1) {
- return FALSE;
- }
-
- //
- // UDF 1.02 revision supports only Type 1 (Physical) partitions, but
- // let's check it any way.
- //
- // PartitionMap[0] -> type
- // PartitionMap[1] -> length (in bytes)
- //
- if ((LogicalVolDesc->PartitionMaps[0] != 1) ||
- (LogicalVolDesc->PartitionMaps[1] != 6))
- {
- return FALSE;
- }
-
- return TRUE;
-}
-
-/**
- Find UDF logical volume location and whether it is supported by current EDK2
- UDF file system implementation.
-
- @param[in] BlockIo BlockIo interface.
- @param[in] DiskIo DiskIo interface.
- @param[in] AnchorPoint Anchor volume descriptor pointer.
- @param[in] LastRecordedBlock Last recorded block in media.
- @param[out] MainVdsStartBlock Main VDS starting block number.
- @param[out] MainVdsEndBlock Main VDS ending block number.
-
- @retval EFI_SUCCESS UDF logical volume was found.
- @retval EFI_VOLUME_CORRUPTED UDF file system structures are corrupted.
- @retval EFI_UNSUPPORTED UDF logical volume is not supported.
- @retval other Failed to perform disk I/O.
-
-**/
-EFI_STATUS
-FindLogicalVolumeLocation (
- IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
- IN EFI_DISK_IO_PROTOCOL *DiskIo,
- IN UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPoint,
- IN EFI_LBA LastRecordedBlock,
- OUT UINT64 *MainVdsStartBlock,
- OUT UINT64 *MainVdsEndBlock
- )
-{
- EFI_STATUS Status;
- UINT32 BlockSize;
- UDF_EXTENT_AD *ExtentAd;
- UINT64 SeqBlocksNum;
- UINT64 SeqStartBlock;
- UINT64 GuardMainVdsStartBlock;
- VOID *Buffer;
- UINT64 SeqEndBlock;
- BOOLEAN StopSequence;
- UINTN LvdsCount;
- UDF_LOGICAL_VOLUME_DESCRIPTOR *LogicalVolDesc;
- UDF_DESCRIPTOR_TAG *DescriptorTag;
-
- BlockSize = BlockIo->Media->BlockSize;
- ExtentAd = &AnchorPoint->MainVolumeDescriptorSequenceExtent;
-
- //
- // UDF 2.60, 2.2.3.1 struct MainVolumeDescriptorSequenceExtent
- //
- // The Main Volume Descriptor Sequence Extent shall have a minimum length of
- // 16 logical sectors.
- //
- // Also make sure it does not exceed maximum number of blocks in the disk.
- //
- SeqBlocksNum = DivU64x32 ((UINT64)ExtentAd->ExtentLength, BlockSize);
- if ((SeqBlocksNum < 16) || ((EFI_LBA)SeqBlocksNum > LastRecordedBlock + 1)) {
- return EFI_VOLUME_CORRUPTED;
- }
-
- //
- // Check for valid Volume Descriptor Sequence starting block number
- //
- SeqStartBlock = (UINT64)ExtentAd->ExtentLocation;
- if ((SeqStartBlock > LastRecordedBlock) ||
- (SeqStartBlock + SeqBlocksNum - 1 > LastRecordedBlock))
- {
- return EFI_VOLUME_CORRUPTED;
- }
-
- GuardMainVdsStartBlock = SeqStartBlock;
-
- //
- // Allocate buffer for reading disk blocks
- //
- Buffer = AllocateZeroPool ((UINTN)BlockSize);
- if (Buffer == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- SeqEndBlock = SeqStartBlock + SeqBlocksNum;
- StopSequence = FALSE;
- LvdsCount = 0;
- Status = EFI_VOLUME_CORRUPTED;
- //
- // Start Main Volume Descriptor Sequence
- //
- for ( ; SeqStartBlock < SeqEndBlock && !StopSequence; SeqStartBlock++) {
- //
- // Read disk block
- //
- Status = BlockIo->ReadBlocks (
- BlockIo,
- BlockIo->Media->MediaId,
- SeqStartBlock,
- BlockSize,
- Buffer
- );
- if (EFI_ERROR (Status)) {
- goto Out_Free;
- }
-
- DescriptorTag = Buffer;
-
- //
- // ECMA 167, 8.4.1 Contents of a Volume Descriptor Sequence
- //
- // - A Volume Descriptor Sequence shall contain one or more Primary Volume
- // Descriptors.
- // - A Volume Descriptor Sequence shall contain zero or more Implementation
- // Use Volume Descriptors.
- // - A Volume Descriptor Sequence shall contain zero or more Partition
- // Descriptors.
- // - A Volume Descriptor Sequence shall contain zero or more Logical Volume
- // Descriptors.
- // - A Volume Descriptor Sequence shall contain zero or more Unallocated
- // Space Descriptors.
- //
- switch (DescriptorTag->TagIdentifier) {
- case UdfPrimaryVolumeDescriptor:
- case UdfImplemenationUseVolumeDescriptor:
- case UdfPartitionDescriptor:
- case UdfUnallocatedSpaceDescriptor:
- break;
-
- case UdfLogicalVolumeDescriptor:
- LogicalVolDesc = Buffer;
-
- //
- // Check for existence of a single LVD and whether it is supported by
- // current EDK2 UDF file system implementation.
- //
- if ((++LvdsCount > 1) ||
- !IsLogicalVolumeDescriptorSupported (LogicalVolDesc))
- {
- Status = EFI_UNSUPPORTED;
- StopSequence = TRUE;
- }
-
- break;
-
- case UdfTerminatingDescriptor:
- //
- // Stop the sequence when we find a Terminating Descriptor
- // (aka Unallocated Sector), se we don't have to walk all the unallocated
- // area unnecessarily.
- //
- StopSequence = TRUE;
- break;
-
- default:
- //
- // An invalid Volume Descriptor has been found in the sequece. Volume is
- // corrupted.
- //
- Status = EFI_VOLUME_CORRUPTED;
- goto Out_Free;
- }
- }
-
- //
- // Check if LVD was found
- //
- if (!EFI_ERROR (Status) && (LvdsCount == 1)) {
- *MainVdsStartBlock = GuardMainVdsStartBlock;
- //
- // We do not need to read either LVD or PD descriptors to know the last
- // valid block in the found UDF file system. It's already
- // LastRecordedBlock.
- //
- *MainVdsEndBlock = LastRecordedBlock;
-
- Status = EFI_SUCCESS;
- }
-
-Out_Free:
- //
- // Free block read buffer
- //
- FreePool (Buffer);
-
- return Status;
-}
-
-/**
- Find a supported UDF file system in block device.
-
- @attention This is boundary function that may receive untrusted input.
- @attention The input is from Partition.
-
- The CD/DVD media is the external input, so this routine will do basic
- validation for the media.
-
- @param[in] BlockIo BlockIo interface.
- @param[in] DiskIo DiskIo interface.
- @param[out] StartingLBA UDF file system starting LBA.
- @param[out] EndingLBA UDF file system starting LBA.
-
- @retval EFI_SUCCESS UDF file system was found.
- @retval other UDF file system was not found.
-
-**/
-EFI_STATUS
-FindUdfFileSystem (
- IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
- IN EFI_DISK_IO_PROTOCOL *DiskIo,
- OUT EFI_LBA *StartingLBA,
- OUT EFI_LBA *EndingLBA
- )
-{
- EFI_STATUS Status;
- UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER AnchorPoint;
- EFI_LBA LastRecordedBlock;
-
- //
- // Find UDF volume identifiers
- //
- Status = FindUdfVolumeIdentifiers (BlockIo, DiskIo);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Find Anchor Volume Descriptor Pointer
- //
- Status = FindAnchorVolumeDescriptorPointer (
- BlockIo,
- DiskIo,
- &AnchorPoint,
- &LastRecordedBlock
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Find Logical Volume location
- //
- Status = FindLogicalVolumeLocation (
- BlockIo,
- DiskIo,
- &AnchorPoint,
- LastRecordedBlock,
- (UINT64 *)StartingLBA,
- (UINT64 *)EndingLBA
- );
-
- return Status;
-}
-
-/**
- Install child handles if the Handle supports UDF/ECMA-167 volume format.
-
- @param[in] This Calling context.
- @param[in] Handle Parent Handle.
- @param[in] DiskIo Parent DiskIo interface.
- @param[in] DiskIo2 Parent DiskIo2 interface.
- @param[in] BlockIo Parent BlockIo interface.
- @param[in] BlockIo2 Parent BlockIo2 interface.
- @param[in] DevicePath Parent Device Path
-
-
- @retval EFI_SUCCESS Child handle(s) was added.
- @retval EFI_MEDIA_CHANGED Media changed Detected.
- @retval other no child handle was added.
-
-**/
-EFI_STATUS
-PartitionInstallUdfChildHandles (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE Handle,
- IN EFI_DISK_IO_PROTOCOL *DiskIo,
- IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
- IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
- IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
- IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
- )
-{
- UINT32 RemainderByMediaBlockSize;
- EFI_STATUS Status;
- EFI_BLOCK_IO_MEDIA *Media;
- EFI_PARTITION_INFO_PROTOCOL PartitionInfo;
- EFI_LBA StartingLBA;
- EFI_LBA EndingLBA;
- BOOLEAN ChildCreated;
-
- Media = BlockIo->Media;
- ChildCreated = FALSE;
-
- //
- // Check if UDF logical block size is multiple of underlying device block size
- //
- DivU64x32Remainder (
- UDF_LOGICAL_SECTOR_SIZE, // Dividend
- Media->BlockSize, // Divisor
- &RemainderByMediaBlockSize // Remainder
- );
- if (RemainderByMediaBlockSize != 0) {
- return EFI_NOT_FOUND;
- }
-
- //
- // Detect El Torito feature first.
- // And always continue to search for UDF.
- //
- Status = PartitionInstallElToritoChildHandles (
- This,
- Handle,
- DiskIo,
- DiskIo2,
- BlockIo,
- BlockIo2,
- DevicePath
- );
- if (!EFI_ERROR (Status)) {
- DEBUG ((DEBUG_INFO, "PartitionDxe: El Torito standard found on handle 0x%p.\n", Handle));
- ChildCreated = TRUE;
- }
-
- //
- // Search for an UDF file system on block device
- //
- Status = FindUdfFileSystem (BlockIo, DiskIo, &StartingLBA, &EndingLBA);
- if (EFI_ERROR (Status)) {
- return (ChildCreated ? EFI_SUCCESS : EFI_NOT_FOUND);
- }
-
- //
- // Create Partition Info protocol for UDF file system
- //
- ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
- PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
- PartitionInfo.Type = PARTITION_TYPE_OTHER;
-
- //
- // Install partition child handle for UDF file system
- //
- Status = PartitionInstallChildHandle (
- This,
- Handle,
- DiskIo,
- DiskIo2,
- BlockIo,
- BlockIo2,
- DevicePath,
- (EFI_DEVICE_PATH_PROTOCOL *)&gUdfDevicePath,
- &PartitionInfo,
- StartingLBA,
- EndingLBA,
- Media->BlockSize,
- NULL
- );
- if (EFI_ERROR (Status)) {
- return (ChildCreated ? EFI_SUCCESS : Status);
- }
-
- return EFI_SUCCESS;
-}
+/** @file
+ Scan for an UDF file system on a formatted media.
+
+ Caution: This file requires additional review when modified.
+ This driver will have external input - CD/DVD media.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+ FindUdfFileSystem() routine will consume the media properties and do basic
+ validation.
+
+ Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
+ Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
+ Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "Partition.h"
+
+#define MAX_CORRECTION_BLOCKS_NUM 512u
+
+//
+// C5BD4D42-1A76-4996-8956-73CDA326CD0A
+//
+#define EFI_UDF_DEVICE_PATH_GUID \
+ { 0xC5BD4D42, 0x1A76, 0x4996, \
+ { 0x89, 0x56, 0x73, 0xCD, 0xA3, 0x26, 0xCD, 0x0A } \
+ }
+
+typedef struct {
+ VENDOR_DEVICE_PATH DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} UDF_DEVICE_PATH;
+
+//
+// Vendor-Defined Device Path GUID for UDF file system
+//
+EFI_GUID gUdfDevPathGuid = EFI_UDF_DEVICE_PATH_GUID;
+
+//
+// Vendor-Defined Media Device Path for UDF file system
+//
+UDF_DEVICE_PATH gUdfDevicePath = {
+ {
+ { MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP,
+ { sizeof (VENDOR_DEVICE_PATH), 0 }
+ },
+ EFI_UDF_DEVICE_PATH_GUID
+ },
+ { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
+ }
+};
+
+/**
+ Find the anchor volume descriptor pointer.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[out] AnchorPoint Anchor volume descriptor pointer.
+ @param[out] LastRecordedBlock Last recorded block.
+
+ @retval EFI_SUCCESS Anchor volume descriptor pointer found.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval other Anchor volume descriptor pointer not found.
+
+**/
+EFI_STATUS
+FindAnchorVolumeDescriptorPointer (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ OUT UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPoint,
+ OUT EFI_LBA *LastRecordedBlock
+ )
+{
+ EFI_STATUS Status;
+ UINT32 BlockSize;
+ EFI_LBA EndLBA;
+ UDF_DESCRIPTOR_TAG *DescriptorTag;
+ UINTN AvdpsCount;
+ UINTN Size;
+ UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPoints;
+ INTN Index;
+ UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPointPtr;
+ EFI_LBA LastAvdpBlockNum;
+
+ //
+ // UDF 2.60, 2.2.3 Anchor Volume Descriptor Pointer
+ //
+ // An Anchor Volume Descriptor Pointer structure shall be recorded in at
+ // least 2 of the following 3 locations on the media: Logical Sector 256,
+ // N - 256 or N, where N is the last *addressable* sector of a volume.
+ //
+ // To figure out what logical sector N is, the SCSI commands READ CAPACITY and
+ // READ TRACK INFORMATION are used, however many drives or medias report their
+ // "last recorded block" wrongly. Although, READ CAPACITY returns the last
+ // readable data block but there might be unwritten blocks, which are located
+ // outside any track and therefore AVDP will not be found at block N.
+ //
+ // That said, we define a magic number of 512 blocks to be used as correction
+ // when attempting to find AVDP and define last block number.
+ //
+ BlockSize = BlockIo->Media->BlockSize;
+ EndLBA = BlockIo->Media->LastBlock;
+ *LastRecordedBlock = EndLBA;
+ AvdpsCount = 0;
+
+ //
+ // Check if the block size of the underlying media can hold the data of an
+ // Anchor Volume Descriptor Pointer
+ //
+ if (BlockSize < sizeof (UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Media block size 0x%x unable to hold an AVDP.\n",
+ __func__,
+ BlockSize
+ ));
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Find AVDP at block 256
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32 (256, BlockSize),
+ sizeof (*AnchorPoint),
+ AnchorPoint
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DescriptorTag = &AnchorPoint->DescriptorTag;
+
+ //
+ // Check if read block is a valid AVDP descriptor
+ //
+ if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer) {
+ DEBUG ((DEBUG_INFO, "%a: found AVDP at block %d\n", __func__, 256));
+ AvdpsCount++;
+ }
+
+ //
+ // Find AVDP at block N - 256
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32 ((UINT64)EndLBA - 256, BlockSize),
+ sizeof (*AnchorPoint),
+ AnchorPoint
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Check if read block is a valid AVDP descriptor
+ //
+ if ((DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer) &&
+ (++AvdpsCount == 2))
+ {
+ DEBUG ((
+ DEBUG_INFO,
+ "%a: found AVDP at block %Ld\n",
+ __func__,
+ EndLBA - 256
+ ));
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Check if at least one AVDP was found in previous locations
+ //
+ if (AvdpsCount == 0) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ //
+ // Find AVDP at block N
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32 ((UINT64)EndLBA, BlockSize),
+ sizeof (*AnchorPoint),
+ AnchorPoint
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Check if read block is a valid AVDP descriptor
+ //
+ if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // No AVDP found at block N. Possibly drive/media returned bad last recorded
+ // block, or it is part of unwritten data blocks and outside any track.
+ //
+ // Search backwards for an AVDP from block N-1 through
+ // N-MAX_CORRECTION_BLOCKS_NUM. If any AVDP is found, then correct last block
+ // number for the new UDF partition child handle.
+ //
+ Size = MAX_CORRECTION_BLOCKS_NUM * BlockSize;
+
+ AnchorPoints = AllocateZeroPool (Size);
+ if (AnchorPoints == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Read consecutive MAX_CORRECTION_BLOCKS_NUM disk blocks
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32 ((UINT64)EndLBA - MAX_CORRECTION_BLOCKS_NUM, BlockSize),
+ Size,
+ AnchorPoints
+ );
+ if (EFI_ERROR (Status)) {
+ goto Out_Free;
+ }
+
+ Status = EFI_VOLUME_CORRUPTED;
+
+ //
+ // Search for AVDP from blocks N-1 through N-MAX_CORRECTION_BLOCKS_NUM
+ //
+ for (Index = MAX_CORRECTION_BLOCKS_NUM - 2; Index >= 0; Index--) {
+ AnchorPointPtr = (VOID *)((UINTN)AnchorPoints + Index * BlockSize);
+
+ DescriptorTag = &AnchorPointPtr->DescriptorTag;
+
+ //
+ // Check if read block is a valid AVDP descriptor
+ //
+ if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer) {
+ //
+ // Calculate last recorded block number
+ //
+ LastAvdpBlockNum = EndLBA - (MAX_CORRECTION_BLOCKS_NUM - Index);
+ DEBUG ((
+ DEBUG_WARN,
+ "%a: found AVDP at block %Ld\n",
+ __func__,
+ LastAvdpBlockNum
+ ));
+ DEBUG ((
+ DEBUG_WARN,
+ "%a: correcting last block from %Ld to %Ld\n",
+ __func__,
+ EndLBA,
+ LastAvdpBlockNum
+ ));
+ //
+ // Save read AVDP from last block
+ //
+ CopyMem (AnchorPoint, AnchorPointPtr, sizeof (*AnchorPointPtr));
+ //
+ // Set last recorded block number
+ //
+ *LastRecordedBlock = LastAvdpBlockNum;
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
+
+Out_Free:
+ FreePool (AnchorPoints);
+ return Status;
+}
+
+/**
+ Find UDF volume identifiers in a Volume Recognition Sequence.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+
+ @retval EFI_SUCCESS UDF volume identifiers were found.
+ @retval EFI_NOT_FOUND UDF volume identifiers were not found.
+ @retval other Failed to perform disk I/O.
+
+**/
+EFI_STATUS
+FindUdfVolumeIdentifiers (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Offset;
+ UINT64 EndDiskOffset;
+ CDROM_VOLUME_DESCRIPTOR VolDescriptor;
+ CDROM_VOLUME_DESCRIPTOR TerminatingVolDescriptor;
+
+ ZeroMem ((VOID *)&TerminatingVolDescriptor, sizeof (CDROM_VOLUME_DESCRIPTOR));
+
+ //
+ // Start Volume Recognition Sequence
+ //
+ EndDiskOffset = MultU64x32 (
+ BlockIo->Media->LastBlock,
+ BlockIo->Media->BlockSize
+ );
+
+ for (Offset = UDF_VRS_START_OFFSET; Offset < EndDiskOffset;
+ Offset += UDF_LOGICAL_SECTOR_SIZE)
+ {
+ //
+ // Check if block device has a Volume Structure Descriptor and an Extended
+ // Area.
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ Offset,
+ sizeof (CDROM_VOLUME_DESCRIPTOR),
+ (VOID *)&VolDescriptor
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (CompareMem (
+ (VOID *)VolDescriptor.Unknown.Id,
+ (VOID *)UDF_BEA_IDENTIFIER,
+ sizeof (VolDescriptor.Unknown.Id)
+ ) == 0)
+ {
+ break;
+ }
+
+ if ((CompareMem (
+ (VOID *)VolDescriptor.Unknown.Id,
+ (VOID *)CDVOL_ID,
+ sizeof (VolDescriptor.Unknown.Id)
+ ) != 0) ||
+ (CompareMem (
+ (VOID *)&VolDescriptor,
+ (VOID *)&TerminatingVolDescriptor,
+ sizeof (CDROM_VOLUME_DESCRIPTOR)
+ ) == 0))
+ {
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ //
+ // Look for "NSR0{2,3}" identifiers in the Extended Area.
+ //
+ Offset += UDF_LOGICAL_SECTOR_SIZE;
+ if (Offset >= EndDiskOffset) {
+ return EFI_NOT_FOUND;
+ }
+
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ Offset,
+ sizeof (CDROM_VOLUME_DESCRIPTOR),
+ (VOID *)&VolDescriptor
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((CompareMem (
+ (VOID *)VolDescriptor.Unknown.Id,
+ (VOID *)UDF_NSR2_IDENTIFIER,
+ sizeof (VolDescriptor.Unknown.Id)
+ ) != 0) &&
+ (CompareMem (
+ (VOID *)VolDescriptor.Unknown.Id,
+ (VOID *)UDF_NSR3_IDENTIFIER,
+ sizeof (VolDescriptor.Unknown.Id)
+ ) != 0))
+ {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Look for "TEA01" identifier in the Extended Area
+ //
+ Offset += UDF_LOGICAL_SECTOR_SIZE;
+ if (Offset >= EndDiskOffset) {
+ return EFI_NOT_FOUND;
+ }
+
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ Offset,
+ sizeof (CDROM_VOLUME_DESCRIPTOR),
+ (VOID *)&VolDescriptor
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (CompareMem (
+ (VOID *)VolDescriptor.Unknown.Id,
+ (VOID *)UDF_TEA_IDENTIFIER,
+ sizeof (VolDescriptor.Unknown.Id)
+ ) != 0)
+ {
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check if Logical Volume Descriptor is supported by current EDK2 UDF file
+ system implementation.
+
+ @param[in] LogicalVolDesc Logical Volume Descriptor pointer.
+
+ @retval TRUE Logical Volume Descriptor is supported.
+ @retval FALSE Logical Volume Descriptor is not supported.
+
+**/
+BOOLEAN
+IsLogicalVolumeDescriptorSupported (
+ UDF_LOGICAL_VOLUME_DESCRIPTOR *LogicalVolDesc
+ )
+{
+ //
+ // Check for a valid UDF revision range
+ //
+ switch (LogicalVolDesc->DomainIdentifier.Suffix.Domain.UdfRevision) {
+ case 0x0102:
+ case 0x0150:
+ case 0x0200:
+ case 0x0201:
+ case 0x0250:
+ case 0x0260:
+ break;
+ default:
+ return FALSE;
+ }
+
+ //
+ // Check for a single Partition Map
+ //
+ if (LogicalVolDesc->NumberOfPartitionMaps > 1) {
+ return FALSE;
+ }
+
+ //
+ // UDF 1.02 revision supports only Type 1 (Physical) partitions, but
+ // let's check it any way.
+ //
+ // PartitionMap[0] -> type
+ // PartitionMap[1] -> length (in bytes)
+ //
+ if ((LogicalVolDesc->PartitionMaps[0] != 1) ||
+ (LogicalVolDesc->PartitionMaps[1] != 6))
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Find UDF logical volume location and whether it is supported by current EDK2
+ UDF file system implementation.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] AnchorPoint Anchor volume descriptor pointer.
+ @param[in] LastRecordedBlock Last recorded block in media.
+ @param[out] MainVdsStartBlock Main VDS starting block number.
+ @param[out] MainVdsEndBlock Main VDS ending block number.
+
+ @retval EFI_SUCCESS UDF logical volume was found.
+ @retval EFI_VOLUME_CORRUPTED UDF file system structures are corrupted.
+ @retval EFI_UNSUPPORTED UDF logical volume is not supported.
+ @retval other Failed to perform disk I/O.
+
+**/
+EFI_STATUS
+FindLogicalVolumeLocation (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPoint,
+ IN EFI_LBA LastRecordedBlock,
+ OUT UINT64 *MainVdsStartBlock,
+ OUT UINT64 *MainVdsEndBlock
+ )
+{
+ EFI_STATUS Status;
+ UINT32 BlockSize;
+ UDF_EXTENT_AD *ExtentAd;
+ UINT64 SeqBlocksNum;
+ UINT64 SeqStartBlock;
+ UINT64 GuardMainVdsStartBlock;
+ VOID *Buffer;
+ UINT64 SeqEndBlock;
+ BOOLEAN StopSequence;
+ UINTN LvdsCount;
+ UDF_LOGICAL_VOLUME_DESCRIPTOR *LogicalVolDesc;
+ UDF_DESCRIPTOR_TAG *DescriptorTag;
+
+ BlockSize = BlockIo->Media->BlockSize;
+ ExtentAd = &AnchorPoint->MainVolumeDescriptorSequenceExtent;
+
+ //
+ // UDF 2.60, 2.2.3.1 struct MainVolumeDescriptorSequenceExtent
+ //
+ // The Main Volume Descriptor Sequence Extent shall have a minimum length of
+ // 16 logical sectors.
+ //
+ // Also make sure it does not exceed maximum number of blocks in the disk.
+ //
+ SeqBlocksNum = DivU64x32 ((UINT64)ExtentAd->ExtentLength, BlockSize);
+ if ((SeqBlocksNum < 16) || ((EFI_LBA)SeqBlocksNum > LastRecordedBlock + 1)) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ //
+ // Check for valid Volume Descriptor Sequence starting block number
+ //
+ SeqStartBlock = (UINT64)ExtentAd->ExtentLocation;
+ if ((SeqStartBlock > LastRecordedBlock) ||
+ (SeqStartBlock + SeqBlocksNum - 1 > LastRecordedBlock))
+ {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ GuardMainVdsStartBlock = SeqStartBlock;
+
+ //
+ // Allocate buffer for reading disk blocks
+ //
+ Buffer = AllocateZeroPool ((UINTN)BlockSize);
+ if (Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ SeqEndBlock = SeqStartBlock + SeqBlocksNum;
+ StopSequence = FALSE;
+ LvdsCount = 0;
+ Status = EFI_VOLUME_CORRUPTED;
+ //
+ // Start Main Volume Descriptor Sequence
+ //
+ for ( ; SeqStartBlock < SeqEndBlock && !StopSequence; SeqStartBlock++) {
+ //
+ // Read disk block
+ //
+ Status = BlockIo->ReadBlocks (
+ BlockIo,
+ BlockIo->Media->MediaId,
+ SeqStartBlock,
+ BlockSize,
+ Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ goto Out_Free;
+ }
+
+ DescriptorTag = Buffer;
+
+ //
+ // ECMA 167, 8.4.1 Contents of a Volume Descriptor Sequence
+ //
+ // - A Volume Descriptor Sequence shall contain one or more Primary Volume
+ // Descriptors.
+ // - A Volume Descriptor Sequence shall contain zero or more Implementation
+ // Use Volume Descriptors.
+ // - A Volume Descriptor Sequence shall contain zero or more Partition
+ // Descriptors.
+ // - A Volume Descriptor Sequence shall contain zero or more Logical Volume
+ // Descriptors.
+ // - A Volume Descriptor Sequence shall contain zero or more Unallocated
+ // Space Descriptors.
+ //
+ switch (DescriptorTag->TagIdentifier) {
+ case UdfPrimaryVolumeDescriptor:
+ case UdfImplemenationUseVolumeDescriptor:
+ case UdfPartitionDescriptor:
+ case UdfUnallocatedSpaceDescriptor:
+ break;
+
+ case UdfLogicalVolumeDescriptor:
+ LogicalVolDesc = Buffer;
+
+ //
+ // Check for existence of a single LVD and whether it is supported by
+ // current EDK2 UDF file system implementation.
+ //
+ if ((++LvdsCount > 1) ||
+ !IsLogicalVolumeDescriptorSupported (LogicalVolDesc))
+ {
+ Status = EFI_UNSUPPORTED;
+ StopSequence = TRUE;
+ }
+
+ break;
+
+ case UdfTerminatingDescriptor:
+ //
+ // Stop the sequence when we find a Terminating Descriptor
+ // (aka Unallocated Sector), se we don't have to walk all the unallocated
+ // area unnecessarily.
+ //
+ StopSequence = TRUE;
+ break;
+
+ default:
+ //
+ // An invalid Volume Descriptor has been found in the sequece. Volume is
+ // corrupted.
+ //
+ Status = EFI_VOLUME_CORRUPTED;
+ goto Out_Free;
+ }
+ }
+
+ //
+ // Check if LVD was found
+ //
+ if (!EFI_ERROR (Status) && (LvdsCount == 1)) {
+ *MainVdsStartBlock = GuardMainVdsStartBlock;
+ //
+ // We do not need to read either LVD or PD descriptors to know the last
+ // valid block in the found UDF file system. It's already
+ // LastRecordedBlock.
+ //
+ *MainVdsEndBlock = LastRecordedBlock;
+
+ Status = EFI_SUCCESS;
+ }
+
+Out_Free:
+ //
+ // Free block read buffer
+ //
+ FreePool (Buffer);
+
+ return Status;
+}
+
+/**
+ Find a supported UDF file system in block device.
+
+ @attention This is boundary function that may receive untrusted input.
+ @attention The input is from Partition.
+
+ The CD/DVD media is the external input, so this routine will do basic
+ validation for the media.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[out] StartingLBA UDF file system starting LBA.
+ @param[out] EndingLBA UDF file system starting LBA.
+
+ @retval EFI_SUCCESS UDF file system was found.
+ @retval other UDF file system was not found.
+
+**/
+EFI_STATUS
+FindUdfFileSystem (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ OUT EFI_LBA *StartingLBA,
+ OUT EFI_LBA *EndingLBA
+ )
+{
+ EFI_STATUS Status;
+ UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER AnchorPoint;
+ EFI_LBA LastRecordedBlock;
+
+ //
+ // Find UDF volume identifiers
+ //
+ Status = FindUdfVolumeIdentifiers (BlockIo, DiskIo);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Find Anchor Volume Descriptor Pointer
+ //
+ Status = FindAnchorVolumeDescriptorPointer (
+ BlockIo,
+ DiskIo,
+ &AnchorPoint,
+ &LastRecordedBlock
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Find Logical Volume location
+ //
+ Status = FindLogicalVolumeLocation (
+ BlockIo,
+ DiskIo,
+ &AnchorPoint,
+ LastRecordedBlock,
+ (UINT64 *)StartingLBA,
+ (UINT64 *)EndingLBA
+ );
+
+ return Status;
+}
+
+/**
+ Install child handles if the Handle supports UDF/ECMA-167 volume format.
+
+ @param[in] This Calling context.
+ @param[in] Handle Parent Handle.
+ @param[in] DiskIo Parent DiskIo interface.
+ @param[in] DiskIo2 Parent DiskIo2 interface.
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] BlockIo2 Parent BlockIo2 interface.
+ @param[in] DevicePath Parent Device Path
+
+
+ @retval EFI_SUCCESS Child handle(s) was added.
+ @retval EFI_MEDIA_CHANGED Media changed Detected.
+ @retval other no child handle was added.
+
+**/
+EFI_STATUS
+PartitionInstallUdfChildHandles (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ UINT32 RemainderByMediaBlockSize;
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_MEDIA *Media;
+ EFI_PARTITION_INFO_PROTOCOL PartitionInfo;
+ EFI_LBA StartingLBA;
+ EFI_LBA EndingLBA;
+ BOOLEAN ChildCreated;
+
+ Media = BlockIo->Media;
+ ChildCreated = FALSE;
+
+ //
+ // Check if UDF logical block size is multiple of underlying device block size
+ //
+ DivU64x32Remainder (
+ UDF_LOGICAL_SECTOR_SIZE, // Dividend
+ Media->BlockSize, // Divisor
+ &RemainderByMediaBlockSize // Remainder
+ );
+ if (RemainderByMediaBlockSize != 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Detect El Torito feature first.
+ // And always continue to search for UDF.
+ //
+ Status = PartitionInstallElToritoChildHandles (
+ This,
+ Handle,
+ DiskIo,
+ DiskIo2,
+ BlockIo,
+ BlockIo2,
+ DevicePath
+ );
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "PartitionDxe: El Torito standard found on handle 0x%p.\n", Handle));
+ ChildCreated = TRUE;
+ }
+
+ //
+ // Search for an UDF file system on block device
+ //
+ Status = FindUdfFileSystem (BlockIo, DiskIo, &StartingLBA, &EndingLBA);
+ if (EFI_ERROR (Status)) {
+ return (ChildCreated ? EFI_SUCCESS : EFI_NOT_FOUND);
+ }
+
+ //
+ // Create Partition Info protocol for UDF file system
+ //
+ ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
+ PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
+ PartitionInfo.Type = PARTITION_TYPE_OTHER;
+
+ //
+ // Install partition child handle for UDF file system
+ //
+ Status = PartitionInstallChildHandle (
+ This,
+ Handle,
+ DiskIo,
+ DiskIo2,
+ BlockIo,
+ BlockIo2,
+ DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *)&gUdfDevicePath,
+ &PartitionInfo,
+ StartingLBA,
+ EndingLBA,
+ Media->BlockSize,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return (ChildCreated ? EFI_SUCCESS : Status);
+ }
+
+ return EFI_SUCCESS;
+}