]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Disk/Partition/Dxe/Mbr.c
add modules DiskIo, Partition and SecurityStub.
[mirror_edk2.git] / MdeModulePkg / Universal / Disk / Partition / Dxe / Mbr.c
diff --git a/MdeModulePkg/Universal/Disk/Partition/Dxe/Mbr.c b/MdeModulePkg/Universal/Disk/Partition/Dxe/Mbr.c
new file mode 100644 (file)
index 0000000..bc08963
--- /dev/null
@@ -0,0 +1,333 @@
+/*++\r
+\r
+Copyright (c) 2006 - 2007, Intel Corporation                                                         \r
+All rights reserved. This program and the accompanying materials                          \r
+are licensed and made available under the terms and conditions of the BSD License         \r
+which accompanies this distribution.  The full text of the license may be found at        \r
+http://opensource.org/licenses/bsd-license.php                                            \r
+                                                                                          \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
+\r
+Module Name:\r
+\r
+  Mbr.c\r
+  \r
+Abstract:\r
+\r
+  Decode a hard disk partitioned with the legacy MBR found on most PC's\r
+\r
+  MBR - Master Boot Record is in the first sector of a partitioned hard disk.\r
+        The MBR supports four partitions per disk. The MBR also contains legacy\r
+        code that is not run on an EFI system. The legacy code reads the \r
+        first sector of the active partition into memory and \r
+\r
+  BPB - Boot(?) Parameter Block is in the first sector of a FAT file system. \r
+        The BPB contains information about the FAT file system. The BPB is \r
+        always on the first sector of a media. The first sector also contains\r
+        the legacy boot strap code.\r
+\r
+--*/\r
+\r
+//\r
+// Include common header file for this module.\r
+//\r
+#include "CommonHeader.h"\r
+\r
+#include "Partition.h"\r
+\r
+STATIC\r
+BOOLEAN\r
+PartitionValidMbr (\r
+  IN  MASTER_BOOT_RECORD      *Mbr,\r
+  IN  EFI_LBA                 LastLba\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Test to see if the Mbr buffer is a valid MBR\r
+\r
+Arguments:       \r
+  Mbr     - Parent Handle \r
+  LastLba - Last Lba address on the device.\r
+\r
+Returns:\r
+  TRUE  - Mbr is a Valid MBR\r
+  FALSE - Mbr is not a Valid MBR\r
+\r
+--*/\r
+{\r
+  UINT32  StartingLBA;\r
+  UINT32  EndingLBA;\r
+  UINT32  NewEndingLBA;\r
+  INTN    Index1;\r
+  INTN    Index2;\r
+  BOOLEAN MbrValid;\r
+\r
+  if (Mbr->Signature != MBR_SIGNATURE) {\r
+    return FALSE;\r
+  }\r
+  //\r
+  // The BPB also has this signature, so it can not be used alone.\r
+  //\r
+  MbrValid = FALSE;\r
+  for (Index1 = 0; Index1 < MAX_MBR_PARTITIONS; Index1++) {\r
+    if (Mbr->Partition[Index1].OSIndicator == 0x00 || UNPACK_UINT32 (Mbr->Partition[Index1].SizeInLBA) == 0) {\r
+      continue;\r
+    }\r
+\r
+    MbrValid    = TRUE;\r
+    StartingLBA = UNPACK_UINT32 (Mbr->Partition[Index1].StartingLBA);\r
+    EndingLBA   = StartingLBA + UNPACK_UINT32 (Mbr->Partition[Index1].SizeInLBA) - 1;\r
+    if (EndingLBA > LastLba) {\r
+      //\r
+      // Compatibility Errata:\r
+      //  Some systems try to hide drive space with their INT 13h driver\r
+      //  This does not hide space from the OS driver. This means the MBR\r
+      //  that gets created from DOS is smaller than the MBR created from\r
+      //  a real OS (NT & Win98). This leads to BlockIo->LastBlock being\r
+      //  wrong on some systems FDISKed by the OS.\r
+      //\r
+      // return FALSE since no block devices on a system are implemented\r
+      // with INT 13h\r
+      //\r
+      return FALSE;\r
+    }\r
+\r
+    for (Index2 = Index1 + 1; Index2 < MAX_MBR_PARTITIONS; Index2++) {\r
+      if (Mbr->Partition[Index2].OSIndicator == 0x00 || UNPACK_UINT32 (Mbr->Partition[Index2].SizeInLBA) == 0) {\r
+        continue;\r
+      }\r
+\r
+      NewEndingLBA = UNPACK_UINT32 (Mbr->Partition[Index2].StartingLBA) + UNPACK_UINT32 (Mbr->Partition[Index2].SizeInLBA) - 1;\r
+      if (NewEndingLBA >= StartingLBA && UNPACK_UINT32 (Mbr->Partition[Index2].StartingLBA) <= EndingLBA) {\r
+        //\r
+        // This region overlaps with the Index1'th region\r
+        //\r
+        return FALSE;\r
+      }\r
+    }\r
+  }\r
+  //\r
+  // Non of the regions overlapped so MBR is O.K.\r
+  //\r
+  return MbrValid;\r
+}\r
+\r
+EFI_STATUS\r
+PartitionInstallMbrChildHandles (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                   Handle,\r
+  IN  EFI_DISK_IO_PROTOCOL         *DiskIo,\r
+  IN  EFI_BLOCK_IO_PROTOCOL        *BlockIo,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL     *DevicePath\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Install child handles if the Handle supports MBR format.\r
+\r
+Arguments:       \r
+  This       - Calling context.\r
+  Handle     - Parent Handle \r
+  DiskIo     - Parent DiskIo interface\r
+  BlockIo    - Parent BlockIo interface\r
+  DevicePath - Parent Device Path\r
+\r
+Returns:\r
+  EFI_SUCCESS       - If a child handle was added\r
+  EFI_MEDIA_CHANGED - Media changed Detected\r
+       !EFI_SUCCESS      - Not found MBR partition.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                Status;\r
+  MASTER_BOOT_RECORD        *Mbr;\r
+  UINT32                    ExtMbrStartingLba;\r
+  UINTN                     Index;\r
+  HARDDRIVE_DEVICE_PATH     HdDev;\r
+  HARDDRIVE_DEVICE_PATH     ParentHdDev;\r
+  EFI_STATUS                Found;\r
+  UINT32                    PartitionNumber;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePathNode;\r
+  EFI_DEVICE_PATH_PROTOCOL  *LastDevicePathNode;\r
+\r
+  Mbr             = NULL;\r
+  Found           = EFI_NOT_FOUND;\r
+\r
+  Mbr             = AllocatePool (BlockIo->Media->BlockSize);\r
+  if (Mbr == NULL) {\r
+    goto Done;\r
+  }\r
+\r
+  Status = BlockIo->ReadBlocks (\r
+                      BlockIo,\r
+                      BlockIo->Media->MediaId,\r
+                      0,\r
+                      BlockIo->Media->BlockSize,\r
+                      Mbr\r
+                      );\r
+  if (EFI_ERROR (Status)) {\r
+    Found = Status;\r
+    goto Done;\r
+  }\r
+  if (!PartitionValidMbr (Mbr, BlockIo->Media->LastBlock)) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // We have a valid mbr - add each partition\r
+  //\r
+  //\r
+  // Get starting and ending LBA of the parent block device.\r
+  //\r
+  LastDevicePathNode = NULL;\r
+  ZeroMem (&ParentHdDev, sizeof (ParentHdDev));\r
+  DevicePathNode = DevicePath;\r
+  while (!EfiIsDevicePathEnd (DevicePathNode)) {\r
+    LastDevicePathNode  = DevicePathNode;\r
+    DevicePathNode      = EfiNextDevicePathNode (DevicePathNode);\r
+  }\r
+\r
+  if (LastDevicePathNode != NULL) {\r
+    if (DevicePathType (LastDevicePathNode) == MEDIA_DEVICE_PATH &&\r
+        DevicePathSubType (LastDevicePathNode) == MEDIA_HARDDRIVE_DP\r
+        ) {\r
+      CopyMem (&ParentHdDev, LastDevicePathNode, sizeof (ParentHdDev));\r
+    } else {\r
+      LastDevicePathNode = NULL;\r
+    }\r
+  }\r
+\r
+  PartitionNumber = 1;\r
+\r
+  ZeroMem (&HdDev, sizeof (HdDev));\r
+  HdDev.Header.Type     = MEDIA_DEVICE_PATH;\r
+  HdDev.Header.SubType  = MEDIA_HARDDRIVE_DP;\r
+  SetDevicePathNodeLength (&HdDev.Header, sizeof (HdDev));\r
+  HdDev.MBRType         = MBR_TYPE_PCAT;\r
+  HdDev.SignatureType   = SIGNATURE_TYPE_MBR;\r
+\r
+  if (LastDevicePathNode == NULL) {\r
+    //\r
+    // This is a MBR, add each partition\r
+    //\r
+    for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {\r
+      if (Mbr->Partition[Index].OSIndicator == 0x00 || UNPACK_UINT32 (Mbr->Partition[Index].SizeInLBA) == 0) {\r
+        //\r
+        // Don't use null MBR entries\r
+        //\r
+        continue;\r
+      }\r
+\r
+      if (Mbr->Partition[Index].OSIndicator == PMBR_GPT_PARTITION) {\r
+        //\r
+        // This is the guard MBR for the GPT. If you ever see a GPT disk with zero partitions you can get here.\r
+        //  We can not produce an MBR BlockIo for this device as the MBR spans the GPT headers. So formating \r
+        //  this BlockIo would corrupt the GPT structures and require a recovery that would corrupt the format\r
+        //  that corrupted the GPT partition. \r
+        //\r
+        continue;\r
+      }\r
+\r
+      HdDev.PartitionNumber = PartitionNumber ++;\r
+      HdDev.PartitionStart  = UNPACK_UINT32 (Mbr->Partition[Index].StartingLBA);\r
+      HdDev.PartitionSize   = UNPACK_UINT32 (Mbr->Partition[Index].SizeInLBA);\r
+      CopyMem (HdDev.Signature, &(Mbr->UniqueMbrSignature[0]), sizeof (UINT32));\r
+\r
+      Status = PartitionInstallChildHandle (\r
+                This,\r
+                Handle,\r
+                DiskIo,\r
+                BlockIo,\r
+                DevicePath,\r
+                (EFI_DEVICE_PATH_PROTOCOL *) &HdDev,\r
+                HdDev.PartitionStart,\r
+                HdDev.PartitionStart + HdDev.PartitionSize - 1,\r
+                MBR_SIZE,\r
+                (BOOLEAN) (Mbr->Partition[Index].OSIndicator == EFI_PARTITION)\r
+                );\r
+\r
+      if (!EFI_ERROR (Status)) {\r
+        Found = EFI_SUCCESS;\r
+      }\r
+    }\r
+  } else {\r
+    //\r
+    // It's an extended partition. Follow the extended partition\r
+    // chain to get all the logical drives\r
+    //\r
+    ExtMbrStartingLba = 0;\r
+\r
+    do {\r
+\r
+      Status = BlockIo->ReadBlocks (\r
+                          BlockIo,\r
+                          BlockIo->Media->MediaId,\r
+                          ExtMbrStartingLba,\r
+                          BlockIo->Media->BlockSize,\r
+                          Mbr\r
+                          );\r
+      if (EFI_ERROR (Status)) {\r
+        Found = Status;\r
+        goto Done;\r
+      }\r
+\r
+      if (Mbr->Partition[0].OSIndicator == 0) {\r
+        break;\r
+      }\r
+\r
+      if ((Mbr->Partition[0].OSIndicator == EXTENDED_DOS_PARTITION) ||\r
+          (Mbr->Partition[0].OSIndicator == EXTENDED_WINDOWS_PARTITION)) {\r
+        ExtMbrStartingLba = UNPACK_UINT32 (Mbr->Partition[0].StartingLBA);\r
+        continue;\r
+      }\r
+      HdDev.PartitionNumber = PartitionNumber ++;\r
+      HdDev.PartitionStart  = UNPACK_UINT32 (Mbr->Partition[0].StartingLBA) + ExtMbrStartingLba + ParentHdDev.PartitionStart;\r
+      HdDev.PartitionSize   = UNPACK_UINT32 (Mbr->Partition[0].SizeInLBA);\r
+      if ((HdDev.PartitionStart + HdDev.PartitionSize - 1 >= ParentHdDev.PartitionStart + ParentHdDev.PartitionSize) ||\r
+          (HdDev.PartitionStart <= ParentHdDev.PartitionStart)) {\r
+        break;\r
+      }\r
+\r
+      //\r
+      // The signature in EBR(Extended Boot Record) should always be 0.\r
+      //\r
+      *((UINT32 *) &HdDev.Signature[0]) = 0;\r
+\r
+      Status = PartitionInstallChildHandle (\r
+                This,\r
+                Handle,\r
+                DiskIo,\r
+                BlockIo,\r
+                DevicePath,\r
+                (EFI_DEVICE_PATH_PROTOCOL *) &HdDev,\r
+                HdDev.PartitionStart - ParentHdDev.PartitionStart,\r
+                HdDev.PartitionStart - ParentHdDev.PartitionStart + HdDev.PartitionSize - 1,\r
+                MBR_SIZE,\r
+                (BOOLEAN) (Mbr->Partition[0].OSIndicator == EFI_PARTITION)\r
+                );\r
+      if (!EFI_ERROR (Status)) {\r
+        Found = EFI_SUCCESS;\r
+      }\r
+\r
+      if ((Mbr->Partition[1].OSIndicator != EXTENDED_DOS_PARTITION) &&\r
+          (Mbr->Partition[1].OSIndicator != EXTENDED_WINDOWS_PARTITION)\r
+          ) {\r
+        break;\r
+      }\r
+\r
+      ExtMbrStartingLba = UNPACK_UINT32 (Mbr->Partition[1].StartingLBA);\r
+      //\r
+      // Don't allow partition to be self referencing\r
+      //\r
+      if (ExtMbrStartingLba == 0) {\r
+        break;\r
+      }\r
+    } while (ExtMbrStartingLba  < ParentHdDev.PartitionSize);\r
+  }\r
+\r
+Done:\r
+  FreePool (Mbr);\r
+\r
+  return Found;\r
+}\r