partelto.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  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. partelto.c
  9. Abstract:
  10. This module implements support for parsing El Torito partitions.
  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. // ---------------------------------------------------------------- Definitions
  23. //
  24. //
  25. // ------------------------------------------------------ Data Type Definitions
  26. //
  27. //
  28. // ----------------------------------------------- Internal Function Prototypes
  29. //
  30. //
  31. // -------------------------------------------------------------------- Globals
  32. //
  33. //
  34. // ------------------------------------------------------------------ Functions
  35. //
  36. EFI_STATUS
  37. EfiPartitionDetectElTorito (
  38. EFI_DRIVER_BINDING_PROTOCOL *This,
  39. EFI_HANDLE Handle,
  40. EFI_DISK_IO_PROTOCOL *DiskIo,
  41. EFI_BLOCK_IO_PROTOCOL *BlockIo,
  42. EFI_DEVICE_PATH_PROTOCOL *DevicePath
  43. )
  44. /*++
  45. Routine Description:
  46. This routine attempts to detect an El Torito partitioned disk, and exposes
  47. child block devices for each partition it finds.
  48. Arguments:
  49. This - Supplies the driver binding protocol instance.
  50. Handle - Supplies the new controller handle.
  51. DiskIo - Supplies a pointer to the disk I/O protocol.
  52. BlockIo - Supplies a pointer to the block I/O protocol.
  53. DevicePath - Supplies a pointer to the device path.
  54. Return Value:
  55. EFI status code.
  56. --*/
  57. {
  58. UINTN BootEntry;
  59. EFI_ELTORITO_CATALOG *Catalog;
  60. CDROM_DEVICE_PATH CdPath;
  61. UINTN Check;
  62. UINT16 *CheckBuffer;
  63. INTN CompareResult;
  64. EFI_STATUS Found;
  65. UINTN Index;
  66. UINT32 Lba;
  67. UINTN MaxIndex;
  68. EFI_BLOCK_IO_MEDIA *Media;
  69. UINT32 SectorCount;
  70. EFI_STATUS Status;
  71. UINT32 SubBlockSize;
  72. EFI_CDROM_VOLUME_DESCRIPTOR *VolumeDescriptor;
  73. UINT32 VolumeDescriptorLba;
  74. UINT32 VolumeSpaceSize;
  75. Found = EFI_NOT_FOUND;
  76. Media = BlockIo->Media;
  77. VolumeSpaceSize = 0;
  78. //
  79. // CD-ROMs have a fixed block size.
  80. //
  81. if (Media->BlockSize != EFI_CD_BLOCK_SIZE) {
  82. return EFI_NOT_FOUND;
  83. }
  84. VolumeDescriptor = EfiCoreAllocateBootPool((UINTN)(Media->BlockSize));
  85. if (VolumeDescriptor == NULL) {
  86. return EFI_NOT_FOUND;
  87. }
  88. Catalog = (EFI_ELTORITO_CATALOG *)VolumeDescriptor;
  89. //
  90. // The ISO-9660 volume descriptor starts at 32k on the media (and the
  91. // block size is fixed to 2048 remember).
  92. //
  93. VolumeDescriptorLba = EFI_CD_VOLUME_RECORD_LBA - 1;
  94. //
  95. // Loop over all the volumes.
  96. //
  97. while (TRUE) {
  98. VolumeDescriptorLba += 1;
  99. if (VolumeDescriptorLba > Media->LastBlock) {
  100. break;
  101. }
  102. Status = DiskIo->ReadDisk(DiskIo,
  103. Media->MediaId,
  104. VolumeDescriptorLba * Media->BlockSize,
  105. Media->BlockSize,
  106. VolumeDescriptor);
  107. if (EFI_ERROR(Status)) {
  108. RtlDebugPrint("ElTorito: Failed to read volume descriptor.\n");
  109. Found = Status;
  110. break;
  111. }
  112. //
  113. // Check for a valid volume descriptor signature.
  114. //
  115. if (VolumeDescriptor->BootRecordVolume.Type == EFI_CD_VOLUME_TYPE_END) {
  116. break;
  117. }
  118. CompareResult = EfiCoreCompareMemory(
  119. VolumeDescriptor->BootRecordVolume.SystemId,
  120. EFI_CD_VOLUME_ELTORITO_ID,
  121. sizeof(EFI_CD_VOLUME_ELTORITO_ID) - 1);
  122. if (CompareResult != 0) {
  123. continue;
  124. }
  125. //
  126. // Read in the boot catalog.
  127. //
  128. Lba = EFI_UNPACK_UINT32(VolumeDescriptor->BootRecordVolume.Catalog);
  129. if (Lba > Media->LastBlock) {
  130. continue;
  131. }
  132. Status = DiskIo->ReadDisk(DiskIo,
  133. Media->MediaId,
  134. Lba * Media->BlockSize,
  135. Media->BlockSize,
  136. Catalog);
  137. if (EFI_ERROR(Status)) {
  138. RtlDebugPrint("ElTorito: Error reading catalog at lba 0x%I64x.\n",
  139. Lba);
  140. continue;
  141. }
  142. //
  143. // Make sure it looks like a catalog.
  144. //
  145. if ((Catalog->Catalog.Indicator != EFI_ELTORITO_ID_CATALOG) ||
  146. (Catalog->Catalog.Id55AA != 0xAA55)) {
  147. RtlDebugPrint("ElTorito: Bad catalog.\n");
  148. continue;
  149. }
  150. Check = 0;
  151. CheckBuffer = (UINT16 *)Catalog;
  152. for (Index = 0;
  153. Index < sizeof(EFI_ELTORITO_CATALOG) / sizeof(UINT16);
  154. Index += 1) {
  155. Check += CheckBuffer[Index];
  156. }
  157. if ((Check & 0xFFFF) != 0) {
  158. RtlDebugPrint("ElTorito: Catalog checksum failure.\n");
  159. }
  160. MaxIndex = Media->BlockSize / sizeof(EFI_ELTORITO_CATALOG);
  161. BootEntry = 1;
  162. for (Index = 1; Index < MaxIndex; Index += 1) {
  163. Catalog += 1;
  164. if ((Catalog->Boot.Indicator != EFI_ELTORITO_ID_SECTION_BOOTABLE) ||
  165. (Catalog->Boot.Lba == 0)) {
  166. continue;
  167. }
  168. SubBlockSize = 512;
  169. SectorCount = Catalog->Boot.SectorCount;
  170. switch (Catalog->Boot.MediaType) {
  171. case EFI_ELTORITO_NO_EMULATION:
  172. SubBlockSize = Media->BlockSize;
  173. break;
  174. case EFI_ELTORITO_HARD_DISK:
  175. break;
  176. case EFI_ELTORITO_12_DISKETTE:
  177. SectorCount = 0x50 * 0x02 * 0x0F;
  178. break;
  179. case EFI_ELTORITO_14_DISKETTE:
  180. SectorCount = 0x50 * 0x02 * 0x12;
  181. break;
  182. case EFI_ELTORITO_28_DISKETTE:
  183. SectorCount = 0x50 * 0x02 * 0x24;
  184. break;
  185. default:
  186. RtlDebugPrint("ElTorito: Unsupported boot media type 0x%x.\n",
  187. Catalog->Boot.MediaType);
  188. break;
  189. }
  190. VolumeSpaceSize += SectorCount * SubBlockSize;
  191. //
  192. // Create a child device handle.
  193. //
  194. CdPath.Header.Type = MEDIA_DEVICE_PATH;
  195. CdPath.Header.SubType = MEDIA_CDROM_DP;
  196. EfiCoreSetDevicePathNodeLength(&(CdPath.Header), sizeof(CdPath));
  197. if (Index == 1) {
  198. BootEntry = 0;
  199. }
  200. CdPath.BootEntry = (UINT32)BootEntry;
  201. BootEntry += 1;
  202. CdPath.PartitionStart = Catalog->Boot.Lba;
  203. //
  204. // If the sector count is less than two, set the partition as the
  205. // whole CD.
  206. //
  207. if (SectorCount < 2) {
  208. if (VolumeSpaceSize > Media->LastBlock + 1) {
  209. CdPath.PartitionSize = (UINT32)(Media->LastBlock -
  210. Catalog->Boot.Lba + 1);
  211. } else {
  212. CdPath.PartitionSize = (UINT32)(VolumeSpaceSize -
  213. Catalog->Boot.Lba);
  214. }
  215. } else {
  216. CdPath.PartitionSize = ALIGN_VALUE(SectorCount * SubBlockSize,
  217. Media->BlockSize);
  218. }
  219. Status = EfiPartitionInstallChildHandle(
  220. This,
  221. Handle,
  222. DiskIo,
  223. BlockIo,
  224. DevicePath,
  225. (EFI_DEVICE_PATH_PROTOCOL *)&CdPath,
  226. Catalog->Boot.Lba,
  227. Catalog->Boot.Lba + CdPath.PartitionSize - 1,
  228. SubBlockSize,
  229. FALSE);
  230. if (!EFI_ERROR(Status)) {
  231. Found = EFI_SUCCESS;
  232. }
  233. }
  234. }
  235. EfiFreePool(VolumeDescriptor);
  236. return Found;
  237. }
  238. //
  239. // --------------------------------------------------------- Internal Functions
  240. //