partmbr.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. /*++
  2. Copyright (c) 2014 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. partmbr.c
  9. Abstract:
  10. This module implements support for parsing MBR-style partitioned disks.
  11. Author:
  12. Evan Green 20-Mar-2014
  13. Environment:
  14. Firmware
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #include "ueficore.h"
  20. #include "part.h"
  21. //
  22. // --------------------------------------------------------------------- Macros
  23. //
  24. //
  25. // ---------------------------------------------------------------- Definitions
  26. //
  27. //
  28. // ------------------------------------------------------ Data Type Definitions
  29. //
  30. //
  31. // ----------------------------------------------- Internal Function Prototypes
  32. //
  33. BOOLEAN
  34. EfipPartitionIsValidMbr (
  35. EFI_MASTER_BOOT_RECORD *Mbr,
  36. EFI_LBA LastLba
  37. );
  38. //
  39. // -------------------------------------------------------------------- Globals
  40. //
  41. //
  42. // ------------------------------------------------------------------ Functions
  43. //
  44. EFI_STATUS
  45. EfiPartitionDetectMbr (
  46. EFI_DRIVER_BINDING_PROTOCOL *This,
  47. EFI_HANDLE Handle,
  48. EFI_DISK_IO_PROTOCOL *DiskIo,
  49. EFI_BLOCK_IO_PROTOCOL *BlockIo,
  50. EFI_DEVICE_PATH_PROTOCOL *DevicePath
  51. )
  52. /*++
  53. Routine Description:
  54. This routine attempts to detect an El Torito partitioned disk, and exposes
  55. child block devices for each partition it finds.
  56. Arguments:
  57. This - Supplies the driver binding protocol instance.
  58. Handle - Supplies the new controller handle.
  59. DiskIo - Supplies a pointer to the disk I/O protocol.
  60. BlockIo - Supplies a pointer to the block I/O protocol.
  61. DevicePath - Supplies a pointer to the device path.
  62. Return Value:
  63. EFI status code.
  64. --*/
  65. {
  66. UINT32 BlockSize;
  67. UINT64 ChildSize;
  68. EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
  69. HARDDRIVE_DEVICE_PATH DrivePath;
  70. UINT32 ExtMbrStartingLba;
  71. EFI_STATUS Found;
  72. UINTN Index;
  73. EFI_LBA LastBlock;
  74. EFI_DEVICE_PATH_PROTOCOL *LastDevicePathNode;
  75. EFI_MASTER_BOOT_RECORD *Mbr;
  76. UINT32 MediaId;
  77. HARDDRIVE_DEVICE_PATH ParentPath;
  78. UINT32 PartitionNumber;
  79. EFI_STATUS Status;
  80. BOOLEAN SystemPartition;
  81. Found = EFI_NOT_FOUND;
  82. BlockSize = BlockIo->Media->BlockSize;
  83. MediaId = BlockIo->Media->MediaId;
  84. LastBlock = BlockIo->Media->LastBlock;
  85. Mbr = EfiCoreAllocateBootPool(BlockSize);
  86. if (Mbr == NULL) {
  87. return Found;
  88. }
  89. Status = DiskIo->ReadDisk(DiskIo, MediaId, 0, BlockSize, Mbr);
  90. if (EFI_ERROR(Status)) {
  91. Found = Status;
  92. goto PartitionDetectMbrEnd;
  93. }
  94. if (EfipPartitionIsValidMbr(Mbr, LastBlock) == FALSE) {
  95. goto PartitionDetectMbrEnd;
  96. }
  97. //
  98. // This is a valid MBR. Add each partition. Start by getting the starting
  99. // and ending LBA of the parent block device.
  100. //
  101. LastDevicePathNode = NULL;
  102. EfiSetMem(&ParentPath, sizeof(ParentPath), 0);
  103. DevicePathNode = DevicePath;
  104. while (EfiCoreIsDevicePathEnd(DevicePathNode) == FALSE) {
  105. LastDevicePathNode = DevicePathNode;
  106. DevicePathNode = EfiCoreGetNextDevicePathNode(DevicePathNode);
  107. }
  108. if (LastDevicePathNode != NULL) {
  109. if ((EfiCoreGetDevicePathType(LastDevicePathNode) ==
  110. MEDIA_DEVICE_PATH) &&
  111. (EfiCoreGetDevicePathSubType(LastDevicePathNode) ==
  112. MEDIA_HARDDRIVE_DP)) {
  113. EfiCopyMem(&ParentPath, LastDevicePathNode, sizeof(ParentPath));
  114. } else {
  115. LastDevicePathNode = NULL;
  116. }
  117. }
  118. PartitionNumber = 0;
  119. EfiSetMem(&DrivePath, sizeof(DrivePath), 0);
  120. DrivePath.Header.Type = MEDIA_DEVICE_PATH;
  121. DrivePath.Header.SubType = MEDIA_HARDDRIVE_DP;
  122. EfiCoreSetDevicePathNodeLength(&(DrivePath.Header), sizeof(DrivePath));
  123. DrivePath.MBRType = MBR_TYPE_PCAT;
  124. DrivePath.SignatureType = SIGNATURE_TYPE_MBR;
  125. //
  126. // If this is an MBR, add each partition.
  127. //
  128. if (LastDevicePathNode == NULL) {
  129. for (Index = 0; Index < EFI_MAX_MBR_PARTITIONS; Index += 1) {
  130. //
  131. // Skip null/free entries.
  132. //
  133. if ((Mbr->Partition[Index].OsIndicator == 0) ||
  134. (EFI_UNPACK_UINT32(Mbr->Partition[Index].SizeInLba) == 0)) {
  135. continue;
  136. }
  137. //
  138. // Skip GPT guards. Code can get here if there's a GPT disk with
  139. // zero partitions.
  140. //
  141. if (Mbr->Partition[Index].OsIndicator ==
  142. EFI_PROTECTIVE_MBR_PARTITION) {
  143. continue;
  144. }
  145. PartitionNumber += 1;
  146. DrivePath.PartitionNumber = PartitionNumber;
  147. DrivePath.PartitionStart =
  148. EFI_UNPACK_UINT32(Mbr->Partition[Index].StartingLba);
  149. DrivePath.PartitionSize =
  150. EFI_UNPACK_UINT32(Mbr->Partition[Index].SizeInLba);
  151. EfiCopyMem(DrivePath.Signature,
  152. &(Mbr->UniqueMbrSignature[0]),
  153. sizeof(Mbr->UniqueMbrSignature));
  154. SystemPartition = FALSE;
  155. if (Mbr->Partition[Index].OsIndicator == EFI_PARTITION) {
  156. SystemPartition = TRUE;
  157. }
  158. Status = EfiPartitionInstallChildHandle(
  159. This,
  160. Handle,
  161. DiskIo,
  162. BlockIo,
  163. DevicePath,
  164. (EFI_DEVICE_PATH_PROTOCOL *)&DrivePath,
  165. DrivePath.PartitionStart,
  166. DrivePath.PartitionStart + DrivePath.PartitionSize - 1,
  167. EFI_MBR_SIZE,
  168. SystemPartition);
  169. if (!EFI_ERROR(Status)) {
  170. Found = EFI_SUCCESS;
  171. }
  172. }
  173. //
  174. // This is an extended partition. Follow the extended partition chain to
  175. // get all logical drives.
  176. //
  177. } else {
  178. ExtMbrStartingLba = 0;
  179. do {
  180. Status = DiskIo->ReadDisk(DiskIo,
  181. MediaId,
  182. ExtMbrStartingLba * BlockSize,
  183. BlockSize,
  184. Mbr);
  185. if (EFI_ERROR(Status)) {
  186. Found = Status;
  187. goto PartitionDetectMbrEnd;
  188. }
  189. if (EFI_UNPACK_UINT32(Mbr->Partition[0].SizeInLba) == 0) {
  190. break;
  191. }
  192. if ((Mbr->Partition[0].OsIndicator ==
  193. EFI_EXTENDED_DOS_PARTITION) ||
  194. (Mbr->Partition[0].OsIndicator ==
  195. EFI_EXTENDED_WINDOWS_PARTITION)) {
  196. ExtMbrStartingLba =
  197. EFI_UNPACK_UINT32(Mbr->Partition[0].StartingLba);
  198. continue;
  199. }
  200. PartitionNumber += 1;
  201. DrivePath.PartitionNumber = PartitionNumber;
  202. DrivePath.PartitionStart =
  203. EFI_UNPACK_UINT32(Mbr->Partition[0].StartingLba) +
  204. ExtMbrStartingLba;
  205. DrivePath.PartitionSize =
  206. EFI_UNPACK_UINT32(Mbr->Partition[0].SizeInLba);
  207. if ((DrivePath.PartitionStart + DrivePath.PartitionSize - 1 >=
  208. ParentPath.PartitionStart + ParentPath.PartitionSize) ||
  209. (DrivePath.PartitionStart <= ParentPath.PartitionStart)) {
  210. break;
  211. }
  212. EfiSetMem(DrivePath.Signature, sizeof(DrivePath.Signature), 0);
  213. SystemPartition = FALSE;
  214. if (Mbr->Partition[0].OsIndicator == EFI_PARTITION) {
  215. SystemPartition = TRUE;
  216. }
  217. ChildSize = DrivePath.PartitionStart - ParentPath.PartitionStart +
  218. DrivePath.PartitionSize - 1;
  219. Status = EfiPartitionInstallChildHandle(
  220. This,
  221. Handle,
  222. DiskIo,
  223. BlockIo,
  224. DevicePath,
  225. (EFI_DEVICE_PATH_PROTOCOL *)&DrivePath,
  226. DrivePath.PartitionStart - ParentPath.PartitionStart,
  227. ChildSize,
  228. EFI_MBR_SIZE,
  229. SystemPartition);
  230. if (!EFI_ERROR(Status)) {
  231. Found = EFI_SUCCESS;
  232. }
  233. if ((Mbr->Partition[1].OsIndicator !=
  234. EFI_EXTENDED_DOS_PARTITION) &&
  235. (Mbr->Partition[1].OsIndicator !=
  236. EFI_EXTENDED_WINDOWS_PARTITION)) {
  237. break;
  238. }
  239. ExtMbrStartingLba =
  240. EFI_UNPACK_UINT32(Mbr->Partition[1].StartingLba);
  241. if (ExtMbrStartingLba == 0) {
  242. break;
  243. }
  244. } while (ExtMbrStartingLba < ParentPath.PartitionSize);
  245. }
  246. PartitionDetectMbrEnd:
  247. EfiFreePool(Mbr);
  248. return Found;
  249. }
  250. //
  251. // --------------------------------------------------------- Internal Functions
  252. //
  253. BOOLEAN
  254. EfipPartitionIsValidMbr (
  255. EFI_MASTER_BOOT_RECORD *Mbr,
  256. EFI_LBA LastLba
  257. )
  258. /*++
  259. Routine Description:
  260. This routine validates the given MBR.
  261. Arguments:
  262. Mbr - Supplies a pointer to the MBR to validate.
  263. LastLba - Supplies the last valid block address on the disk.
  264. Return Value:
  265. TRUE if the MBR is valid.
  266. FALSE if the MBR is garbage.
  267. --*/
  268. {
  269. UINT32 EndingLba;
  270. UINT32 NewEndingLba;
  271. UINT32 OtherStart;
  272. UINTN PartitionIndex;
  273. UINTN SearchIndex;
  274. UINT32 Size;
  275. UINT32 StartingLba;
  276. BOOLEAN Valid;
  277. if (Mbr->Signature != EFI_MBR_SIGNATURE) {
  278. return FALSE;
  279. }
  280. Valid = FALSE;
  281. for (PartitionIndex = 0;
  282. PartitionIndex < EFI_MAX_MBR_PARTITIONS;
  283. PartitionIndex += 1) {
  284. Size = EFI_UNPACK_UINT32(Mbr->Partition[PartitionIndex].SizeInLba);
  285. if ((Mbr->Partition[PartitionIndex].OsIndicator == 0x00) ||
  286. (Size == 0)) {
  287. continue;
  288. }
  289. Valid = TRUE;
  290. StartingLba =
  291. EFI_UNPACK_UINT32(Mbr->Partition[PartitionIndex].StartingLba);
  292. EndingLba = StartingLba + Size - 1;
  293. if (EndingLba > LastLba) {
  294. return FALSE;
  295. }
  296. //
  297. // Search the other entries for overlap.
  298. //
  299. for (SearchIndex = PartitionIndex + 1;
  300. SearchIndex < EFI_MAX_MBR_PARTITIONS;
  301. SearchIndex += 1) {
  302. Size = EFI_UNPACK_UINT32(Mbr->Partition[SearchIndex].SizeInLba);
  303. if ((Mbr->Partition[SearchIndex].OsIndicator == 0x00) ||
  304. (Size == 0)) {
  305. continue;
  306. }
  307. OtherStart =
  308. EFI_UNPACK_UINT32(Mbr->Partition[SearchIndex].StartingLba);
  309. NewEndingLba = OtherStart + Size - 1;
  310. if ((NewEndingLba >= StartingLba) && (OtherStart <= EndingLba)) {
  311. return FALSE;
  312. }
  313. }
  314. }
  315. return Valid;
  316. }