partelto.c 8.0 KB

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