fatboot.c 27 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109
  1. /*++
  2. Copyright (c) 2013 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. fatboot.c
  5. Abstract:
  6. This module implements support for the FAT boot code. It's a small
  7. section of code that is loaded directly by the first stage loader, and
  8. knows only how to load and execute the firmware.
  9. Author:
  10. Evan Green 14-Oct-2013
  11. Environment:
  12. Boot
  13. --*/
  14. //
  15. // ------------------------------------------------------------------- Includes
  16. //
  17. #include <minoca/lib/fat/fatlib.h>
  18. #include <uefifw.h>
  19. #include <dev/tirom.h>
  20. #include "util.h"
  21. //
  22. // ---------------------------------------------------------------- Definitions
  23. //
  24. #define FAT_DIRECTORY_ENTRIES_PER_BLOCK \
  25. (SECTOR_SIZE / sizeof(FAT_DIRECTORY_ENTRY))
  26. //
  27. // Define the address of a scratch buffer to hold a sector.
  28. //
  29. #define FAT_BOOT_SCRATCH (PVOID)0x81FFE000
  30. #define FAT_BOOT_FAT12_REGION (PVOID)0x81FFC000
  31. #define SECTOR_SIZE 512
  32. //
  33. // Define the number of clusters (which are 32 bits in FAT32) that can fit on
  34. // a sector in the FAT. Note this is not the number of actual clusters that
  35. // can fit in a block, just the count of cluster numbers that can fit on a
  36. // block.
  37. //
  38. #define FAT16_CLUSTERS_PER_BLOCK (SECTOR_SIZE / FAT16_CLUSTER_WIDTH)
  39. #define FAT32_CLUSTERS_PER_BLOCK (SECTOR_SIZE / FAT32_CLUSTER_WIDTH)
  40. //
  41. // Define some MBR values.
  42. //
  43. #define MBR_SIGNATURE_OFFSET 0x1FE
  44. #define MBR_SIGNATURE 0xAA55
  45. #define MBR_PARTITION_ENTRY_OFFSET 0x1BE
  46. #define MBR_PARTITION_ENTRY_COUNT 4
  47. //
  48. // ------------------------------------------------------ Data Type Definitions
  49. //
  50. /*++
  51. Structure Description:
  52. This structure defines the standard partition table entry format for MBR
  53. formatted disks.
  54. Members:
  55. BootIndicator - Stores either 0 (not the boot partition) or 0x80 (the
  56. active/boot partition).
  57. StartingHead - Stores the head number of the first sector of the partition
  58. in legacy CHS geometry.
  59. StartingSector - Stores the sector number of the first sector of the
  60. partition in legacy CHS geometry. Actually bits 0-5 stores the
  61. sector number, bits 6 and 7 are the high bits of the starting cylinder
  62. number.
  63. StartingCylinder - Stores the cylinder number of the first sector of the
  64. partition in legacy CHS geometry. Actually this really stores the low
  65. 8 bits, the high 2 bits are in the upper bits of the starting sector.
  66. SystemId - Stores the wild west system ID byte. No standard ever came for
  67. this byte.
  68. EndingHead - Stores the head number of the last sector of the partition
  69. (inclusive) in legacy CHS geometry.
  70. EndingSector - Stores the sector number of the last sector of the partition
  71. (inclusive) in legacy CHS geometry. Bits 0-5 store the sector, bits
  72. 6 and 7 stores the lowest 2 bits of the ending cylinder.
  73. EndingCylinder - Stores the cylinder number of the last cylinder of the
  74. partition (inclusive) in legacy CHS geometry. This is actually the
  75. low 8 bits of the value, the highest two bits are in the upper bits of
  76. the ending sector.
  77. StartingLba - Stores the Logical Block Address of the first sector of the
  78. disk. This is the value everybody uses, and it's also the one that
  79. limits MBR disks to 2TB. This value is relative, but what it's relative
  80. to depends on which table and entry it is.
  81. SectorCount - Stores the number of sectors in the partition. This is the
  82. value everybody uses, but again is limited to 2TB.
  83. --*/
  84. typedef struct _PARTITION_TABLE_ENTRY {
  85. UCHAR BootIndicator;
  86. UCHAR StartingHead;
  87. UCHAR StartingSector;
  88. UCHAR StartingCylinder;
  89. UCHAR SystemId;
  90. UCHAR EndingHead;
  91. UCHAR EndingSector;
  92. UCHAR EndingCylinder;
  93. ULONG StartingLba;
  94. ULONG SectorCount;
  95. } PACKED PARTITION_TABLE_ENTRY, *PPARTITION_TABLE_ENTRY;
  96. //
  97. // ----------------------------------------------- Internal Function Prototypes
  98. //
  99. KSTATUS
  100. EfipTiGetActivePartition (
  101. PVOID Mbr,
  102. PULONG PartitionOffset
  103. );
  104. BOOL
  105. EfipFatMatchDirectoryEntry (
  106. PFAT_DIRECTORY_ENTRY Entry,
  107. PSTR Name,
  108. PLONG State
  109. );
  110. KSTATUS
  111. EfipFatGetNextCluster (
  112. PTI_ROM_MEM_HANDLE Handle,
  113. FAT_FORMAT Format,
  114. PVOID ScratchBuffer,
  115. PULONG Cluster
  116. );
  117. UCHAR
  118. EfipFatChecksumDirectoryEntry (
  119. PFAT_DIRECTORY_ENTRY Entry
  120. );
  121. KSTATUS
  122. EfipReadSectors (
  123. PTI_ROM_MEM_HANDLE Handle,
  124. PVOID Buffer,
  125. ULONG AbsoluteSector,
  126. ULONG SectorCount
  127. );
  128. PVOID
  129. EfipInitCopyMemory (
  130. PVOID Destination,
  131. PVOID Source,
  132. ULONG ByteCount
  133. );
  134. //
  135. // -------------------------------------------------------------------- Globals
  136. //
  137. //
  138. // Store the boot disk information and geometry.
  139. //
  140. ULONG EfiBootPartitionStart;
  141. //
  142. // Store the basic FAT file system information.
  143. //
  144. ULONG EfiFatSectorsPerCluster;
  145. ULONG EfiFatFatBlockOffset;
  146. ULONG EfiFatClustersBlockOffset;
  147. ULONG EfiFatSectorsPerFat;
  148. //
  149. // Store a volatile variable for debugging indicating how far the code got
  150. // before dying.
  151. //
  152. UCHAR EfiFatStepNumber;
  153. //
  154. // Store some more debugging variables.
  155. //
  156. ULONG EfiDirectoryEntriesExamined;
  157. ULONG EfiLoaderCluster;
  158. //
  159. // Store the pointer where the entire FAT12 FAT is read in, to avoid trying to
  160. // read a cluster that spans a sector.
  161. //
  162. PVOID EfiFat12FatRegion;
  163. //
  164. // ------------------------------------------------------------------ Functions
  165. //
  166. INTN
  167. EfipTiLoadFirmwareFromFat (
  168. PTI_ROM_MEM_HANDLE Handle,
  169. CHAR8 *FileName,
  170. VOID *LoadAddress,
  171. UINT32 *Length
  172. )
  173. /*++
  174. Routine Description:
  175. This routine loads the firmware from a FAT file system.
  176. Arguments:
  177. Handle - Supplies a pointer to the connection to the block device.
  178. FileName - Supplies a pointer to the null terminated name of the file.
  179. LoadAddress - Supplies the address where the image should be loaded.
  180. Length - Supplies a pointer where the length will be returned on success.
  181. Return Value:
  182. 0 on success.
  183. Non-zero on failure.
  184. --*/
  185. {
  186. ULONG BlockIndex;
  187. PFAT_BOOT_SECTOR BootSector;
  188. USHORT BytesPerSector;
  189. ULONG ClusterBlock;
  190. ULONG ClusterCount;
  191. ULONG ClusterShift;
  192. ULONG DataSectorCount;
  193. PFAT_DIRECTORY_ENTRY DirectoryEntry;
  194. ULONG DirectoryEntryIndex;
  195. ULONG FileSize;
  196. FAT_FORMAT Format;
  197. ULONGLONG Identifier;
  198. ULONG LoadedSize;
  199. PVOID Loader;
  200. ULONG LoaderCluster;
  201. INT Match;
  202. LONG MatchState;
  203. INTN Result;
  204. ULONG RootBlocks;
  205. ULONG RootDirectoryCluster;
  206. ULONG RootDirectoryCount;
  207. PVOID Scratch;
  208. KSTATUS Status;
  209. ULONG TotalSectors;
  210. EfiBootPartitionStart = 0;
  211. EfiDirectoryEntriesExamined = 0;
  212. EfiFatStepNumber = 1;
  213. EfiFat12FatRegion = NULL;
  214. //
  215. // Read the MBR to figure out where the active partition is.
  216. //
  217. Scratch = FAT_BOOT_SCRATCH;
  218. Status = EfipReadSectors(Handle, Scratch, 0, 1);
  219. if (!KSUCCESS(Status)) {
  220. goto TiLoadFirmwareFromFatEnd;
  221. }
  222. EfiFatStepNumber += 1;
  223. Status = EfipTiGetActivePartition(Scratch, &EfiBootPartitionStart);
  224. if (!KSUCCESS(Status)) {
  225. goto TiLoadFirmwareFromFatEnd;
  226. }
  227. //
  228. // Read the first sector of the partition to validate that this is a FAT
  229. // drive and find out where basic structures lie.
  230. //
  231. Scratch = FAT_BOOT_SCRATCH;
  232. Status = EfipReadSectors(Handle, Scratch, 0, 1);
  233. if (!KSUCCESS(Status)) {
  234. goto TiLoadFirmwareFromFatEnd;
  235. }
  236. EfiFatStepNumber += 1;
  237. BootSector = Scratch;
  238. if (BootSector->FatParameters.Signature != FAT_BOOT_SIGNATURE) {
  239. Status = STATUS_UNRECOGNIZED_FILE_SYSTEM;
  240. goto TiLoadFirmwareFromFatEnd;
  241. }
  242. if ((BootSector->Fat32Parameters.ExtendedBootSignature ==
  243. FAT_EXTENDED_BOOT_SIGNATURE) ||
  244. (BootSector->Fat32Parameters.ExtendedBootSignature ==
  245. FAT_EXTENDED_BOOT_SIGNATURE2)) {
  246. EfiFatSectorsPerFat =
  247. BootSector->Fat32Parameters.SectorsPerAllocationTable;
  248. RootDirectoryCluster = BootSector->Fat32Parameters.RootDirectoryCluster;
  249. RootDirectoryCount = 0;
  250. EfipInitCopyMemory(&Identifier,
  251. BootSector->Fat32Parameters.FatType,
  252. sizeof(ULONGLONG));
  253. } else {
  254. EfiFatSectorsPerFat = BootSector->SectorsPerFileAllocationTable;
  255. RootDirectoryCluster = 0;
  256. RootDirectoryCount =
  257. READ_UNALIGNED16(&(BootSector->RootDirectoryCount));
  258. EfipInitCopyMemory(&Identifier,
  259. BootSector->FatParameters.FatType,
  260. sizeof(ULONGLONG));
  261. }
  262. if ((Identifier != FAT32_IDENTIFIER) &&
  263. (Identifier != FAT16_IDENTIFIER) &&
  264. (Identifier != FAT12_IDENTIFIER) &&
  265. (Identifier != FAT_IDENTIFIER)) {
  266. Status = STATUS_UNRECOGNIZED_FILE_SYSTEM;
  267. goto TiLoadFirmwareFromFatEnd;
  268. }
  269. EfiFatStepNumber += 1;
  270. //
  271. // This code assumes that FAT's concept of the sector size is the same as
  272. // the old school BIOS 512 byte sectors.
  273. //
  274. BytesPerSector = READ_UNALIGNED16(&(BootSector->BytesPerSector));
  275. if (BytesPerSector != SECTOR_SIZE) {
  276. Status = STATUS_DATA_LENGTH_MISMATCH;
  277. goto TiLoadFirmwareFromFatEnd;
  278. }
  279. TotalSectors = READ_UNALIGNED16(&(BootSector->SmallTotalSectors));
  280. if (TotalSectors == 0) {
  281. TotalSectors = BootSector->BigTotalSectors;
  282. }
  283. EfiFatStepNumber += 1;
  284. EfiFatSectorsPerCluster = BootSector->SectorsPerCluster;
  285. EfiFatFatBlockOffset = READ_UNALIGNED16(&(BootSector->ReservedSectorCount));
  286. RootBlocks = RootDirectoryCount * sizeof(FAT_DIRECTORY_ENTRY);
  287. RootBlocks = ALIGN_RANGE_UP(RootBlocks, BytesPerSector) / BytesPerSector;
  288. EfiFatClustersBlockOffset = EfiFatFatBlockOffset +
  289. (EfiFatSectorsPerFat *
  290. BootSector->AllocationTableCount) +
  291. RootBlocks;
  292. FileSize = 0;
  293. LoaderCluster = 0;
  294. LoadedSize = 0;
  295. EfiFatStepNumber += 1;
  296. //
  297. // Figure out the total number of clusters, and therefore the FAT format.
  298. //
  299. DataSectorCount = TotalSectors - EfiFatClustersBlockOffset;
  300. ClusterShift = 0;
  301. while (BootSector->SectorsPerCluster != 0) {
  302. ClusterShift += 1;
  303. BootSector->SectorsPerCluster >>= 1;
  304. }
  305. ClusterShift -= 1;
  306. ClusterCount = (DataSectorCount >> ClusterShift) + FAT_CLUSTER_BEGIN;
  307. if (ClusterCount < FAT12_CLUSTER_CUTOFF) {
  308. Format = Fat12Format;
  309. } else if (ClusterCount < FAT16_CLUSTER_CUTOFF) {
  310. Format = Fat16Format;
  311. } else {
  312. Format = Fat32Format;
  313. }
  314. EfiFatStepNumber += 1;
  315. //
  316. // If the format is FAT12, read the entire FAT in.
  317. //
  318. if (Format == Fat12Format) {
  319. EfiFat12FatRegion = FAT_BOOT_FAT12_REGION;
  320. Status = EfipReadSectors(Handle,
  321. EfiFat12FatRegion,
  322. EfiFatFatBlockOffset,
  323. EfiFatSectorsPerFat);
  324. if (!KSUCCESS(Status)) {
  325. goto TiLoadFirmwareFromFatEnd;
  326. }
  327. }
  328. EfiFatStepNumber += 1;
  329. //
  330. // Loop across all clusters or blocks in the root directory.
  331. //
  332. if (RootDirectoryCluster != 0) {
  333. ClusterBlock = EfiFatClustersBlockOffset +
  334. ((RootDirectoryCluster - FAT_CLUSTER_BEGIN) *
  335. EfiFatSectorsPerCluster);
  336. } else {
  337. ClusterBlock = EfiFatClustersBlockOffset - RootBlocks;
  338. }
  339. Match = FALSE;
  340. MatchState = 0;
  341. DirectoryEntry = NULL;
  342. while (TRUE) {
  343. //
  344. // Loop over every block in the cluster.
  345. //
  346. for (BlockIndex = 0;
  347. BlockIndex < EfiFatSectorsPerCluster;
  348. BlockIndex += 1) {
  349. Status = EfipReadSectors(Handle,
  350. Scratch,
  351. ClusterBlock + BlockIndex,
  352. 1);
  353. if (!KSUCCESS(Status)) {
  354. goto TiLoadFirmwareFromFatEnd;
  355. }
  356. //
  357. // Loop over every directory entry in the block.
  358. //
  359. DirectoryEntry = Scratch;
  360. for (DirectoryEntryIndex = 0;
  361. DirectoryEntryIndex < FAT_DIRECTORY_ENTRIES_PER_BLOCK;
  362. DirectoryEntryIndex += 1) {
  363. EfiDirectoryEntriesExamined += 1;
  364. //
  365. // If the directory ended, fail sadly.
  366. //
  367. if (DirectoryEntry->DosName[0] == FAT_DIRECTORY_ENTRY_END) {
  368. Status = STATUS_PATH_NOT_FOUND;
  369. goto TiLoadFirmwareFromFatEnd;
  370. }
  371. Match = EfipFatMatchDirectoryEntry(DirectoryEntry,
  372. FileName,
  373. &MatchState);
  374. if (Match != FALSE) {
  375. LoaderCluster = (DirectoryEntry->ClusterHigh << 16) |
  376. DirectoryEntry->ClusterLow;
  377. break;
  378. }
  379. DirectoryEntry += 1;
  380. }
  381. if (Match != FALSE) {
  382. break;
  383. }
  384. }
  385. if (Match != FALSE) {
  386. break;
  387. }
  388. //
  389. // Get the next cluster of the directory entry. If this is the root
  390. // directory of FAT12/16, just advance to the next block.
  391. //
  392. if (RootBlocks != 0) {
  393. if (RootBlocks <= BlockIndex) {
  394. break;
  395. }
  396. RootBlocks -= BlockIndex;
  397. ClusterBlock += BlockIndex;
  398. //
  399. // For directories in the main data area, fetch the next cluster of the
  400. // directory.
  401. //
  402. } else {
  403. Status = EfipFatGetNextCluster(Handle,
  404. Format,
  405. Scratch,
  406. &RootDirectoryCluster);
  407. if (!KSUCCESS(Status)) {
  408. goto TiLoadFirmwareFromFatEnd;
  409. }
  410. ClusterBlock = EfiFatClustersBlockOffset +
  411. ((RootDirectoryCluster - FAT_CLUSTER_BEGIN) *
  412. EfiFatSectorsPerCluster);
  413. }
  414. }
  415. EfiFatStepNumber += 1;
  416. FileSize = DirectoryEntry->FileSizeInBytes;
  417. if (FileSize == 0) {
  418. Status = STATUS_INVALID_ADDRESS;
  419. goto TiLoadFirmwareFromFatEnd;
  420. }
  421. EfiFatStepNumber += 1;
  422. EfiLoaderCluster = LoaderCluster;
  423. //
  424. // Loop through every cluster in the loader.
  425. //
  426. Loader = LoadAddress;
  427. while (TRUE) {
  428. ClusterBlock = EfiFatClustersBlockOffset +
  429. ((LoaderCluster - FAT_CLUSTER_BEGIN) *
  430. EfiFatSectorsPerCluster);
  431. Status = EfipReadSectors(Handle,
  432. Loader,
  433. ClusterBlock,
  434. EfiFatSectorsPerCluster);
  435. if (!KSUCCESS(Status)) {
  436. goto TiLoadFirmwareFromFatEnd;
  437. }
  438. Loader += EfiFatSectorsPerCluster * SECTOR_SIZE;
  439. LoadedSize += EfiFatSectorsPerCluster * SECTOR_SIZE;
  440. if (LoadedSize >= FileSize) {
  441. break;
  442. }
  443. Status = EfipFatGetNextCluster(Handle, Format, Scratch, &LoaderCluster);
  444. if (!KSUCCESS(Status)) {
  445. goto TiLoadFirmwareFromFatEnd;
  446. }
  447. }
  448. EfiFatStepNumber += 1;
  449. Status = STATUS_SUCCESS;
  450. //
  451. // Jump into the loader. This is not expected to return.
  452. //
  453. *Length = FileSize;
  454. Status = STATUS_SUCCESS;
  455. TiLoadFirmwareFromFatEnd:
  456. Result = 0;
  457. if (!KSUCCESS(Status)) {
  458. EfipSerialPrintString("Failed to find UEFI firmware. Status ");
  459. EfipSerialPrintHexInteger(Status);
  460. EfipSerialPrintString(" Step ");
  461. EfipSerialPrintHexInteger(EfiFatStepNumber);
  462. EfipSerialPrintString(".\n");
  463. Result = 1;
  464. }
  465. return Result;
  466. }
  467. //
  468. // --------------------------------------------------------- Internal Functions
  469. //
  470. KSTATUS
  471. EfipTiGetActivePartition (
  472. PVOID Mbr,
  473. PULONG PartitionOffset
  474. )
  475. /*++
  476. Routine Description:
  477. This routine determines the partition offset of the active partition.
  478. Arguments:
  479. Mbr - Supplies a pointer to the MBR.
  480. PartitionOffset - Supplies a pointer where the offset in sectors to the
  481. active partition will be returned.
  482. Return Value:
  483. STATUS_SUCCESS on success.
  484. STATUS_DUPLICATE_ENTRY if there is more than one active partition.
  485. STATUS_NOT_FOUND if the MBR is not valid, the partition information is
  486. not valid, or there is not one active partition.
  487. --*/
  488. {
  489. PPARTITION_TABLE_ENTRY Entries;
  490. UINTN Index;
  491. UINT32 SectorCount;
  492. UINT16 Signature;
  493. UINT32 StartingLba;
  494. Signature = READ_UNALIGNED16(Mbr + MBR_SIGNATURE_OFFSET);
  495. if (Signature != MBR_SIGNATURE) {
  496. return STATUS_NOT_FOUND;
  497. }
  498. *PartitionOffset = 0;
  499. Entries = Mbr + MBR_PARTITION_ENTRY_OFFSET;
  500. for (Index = 0; Index < MBR_PARTITION_ENTRY_COUNT; Index += 1) {
  501. if (Entries[Index].BootIndicator == 0) {
  502. continue;
  503. }
  504. if (Entries[Index].BootIndicator != 0x80) {
  505. return STATUS_NOT_FOUND;
  506. }
  507. StartingLba = READ_UNALIGNED32(&(Entries[Index].StartingLba));
  508. SectorCount = READ_UNALIGNED32(&(Entries[Index].SectorCount));
  509. if ((StartingLba == 0) || (SectorCount == 0)) {
  510. continue;
  511. }
  512. if (*PartitionOffset != 0) {
  513. return STATUS_DUPLICATE_ENTRY;
  514. }
  515. *PartitionOffset = StartingLba;
  516. }
  517. return STATUS_SUCCESS;
  518. }
  519. BOOL
  520. EfipFatMatchDirectoryEntry (
  521. PFAT_DIRECTORY_ENTRY Entry,
  522. PSTR Name,
  523. PLONG State
  524. )
  525. /*++
  526. Routine Description:
  527. This routine compares the given directory entry against the desired
  528. loader directory entry.
  529. Arguments:
  530. Entry - Supplies a pointer to the directory entry.
  531. Name - Supplies a pointer to the eleven byte short format name (containing
  532. no period and space for padding on the right). This name must be all
  533. lower-case, the directory entry name will be converted to lower case.
  534. State - Supplies a pointer to the match state used by this routine.
  535. Initialize this to zero for the first directory entry.
  536. Return Value:
  537. TRUE if directory entry matches the desired name.
  538. FALSE if the directory entry does not match.
  539. --*/
  540. {
  541. CHAR Character;
  542. ULONG CharacterIndex;
  543. UCHAR ComputedChecksum;
  544. PSTR EntryName;
  545. PFAT_LONG_DIRECTORY_ENTRY LongEntry;
  546. UCHAR LongEntryChecksum;
  547. ULONG NameIndex;
  548. PUSHORT Region;
  549. ULONG RegionIndex;
  550. ULONG RegionSize;
  551. UCHAR Sequence;
  552. if (Entry->FileAttributes == FAT_LONG_FILE_NAME_ATTRIBUTES) {
  553. *State = 0;
  554. LongEntry = (PFAT_LONG_DIRECTORY_ENTRY)Entry;
  555. if (LongEntry->SequenceNumber == FAT_DIRECTORY_ENTRY_ERASED) {
  556. return FALSE;
  557. }
  558. //
  559. // The terminating entry comes first, so there should be more long file
  560. // name entries on the way.
  561. //
  562. if ((LongEntry->SequenceNumber & FAT_LONG_DIRECTORY_ENTRY_END) != 0) {
  563. Sequence = LongEntry->SequenceNumber &
  564. FAT_LONG_DIRECTORY_ENTRY_SEQUENCE_MASK;
  565. //
  566. // This routine currently only supports matching a single long
  567. // entry.
  568. //
  569. if (Sequence != 1) {
  570. return FALSE;
  571. }
  572. NameIndex = *State;
  573. for (RegionIndex = 0; RegionIndex < 3; RegionIndex += 1) {
  574. if (RegionIndex == 0) {
  575. Region = LongEntry->Name1;
  576. RegionSize = FAT_LONG_DIRECTORY_ENTRY_NAME1_SIZE;
  577. } else if (RegionIndex == 1) {
  578. Region = LongEntry->Name2;
  579. RegionSize = FAT_LONG_DIRECTORY_ENTRY_NAME2_SIZE;
  580. } else {
  581. Region = LongEntry->Name3;
  582. RegionSize = FAT_LONG_DIRECTORY_ENTRY_NAME3_SIZE;
  583. }
  584. for (CharacterIndex = 0;
  585. CharacterIndex < RegionSize;
  586. CharacterIndex += 1) {
  587. if (Name[NameIndex] == '\0') {
  588. break;
  589. }
  590. if (READ_UNALIGNED16(&(Region[CharacterIndex])) !=
  591. Name[NameIndex]) {
  592. return FALSE;
  593. }
  594. NameIndex += 1;
  595. }
  596. }
  597. //
  598. // This long entry matches. The next short entry is the one.
  599. //
  600. *State = NameIndex |
  601. (LongEntry->ShortFileNameChecksum << BITS_PER_BYTE);
  602. return FALSE;
  603. }
  604. } else if ((Entry->FileAttributes & FAT_VOLUME_LABEL) != 0) {
  605. *State = 0;
  606. return FALSE;
  607. }
  608. //
  609. // If the previous long entry matched the entire name, then compare the
  610. // checksums and return this short entry if they match.
  611. //
  612. NameIndex = *State & 0xFF;
  613. if (Name[NameIndex] == '\0') {
  614. LongEntryChecksum = (*State >> BITS_PER_BYTE) & 0xFF;
  615. ComputedChecksum = EfipFatChecksumDirectoryEntry(Entry);
  616. if (ComputedChecksum == LongEntryChecksum) {
  617. return TRUE;
  618. }
  619. }
  620. //
  621. // Compare the short entry directly against the file name.
  622. //
  623. *State = 0;
  624. EntryName = (PSTR)(Entry->DosName);
  625. NameIndex = 0;
  626. for (CharacterIndex = 0;
  627. CharacterIndex < FAT_NAME_SIZE;
  628. CharacterIndex += 1) {
  629. //
  630. // Index through the name knowing that the extension comes right after
  631. // it. This is code no one is ever supposed to see.
  632. //
  633. Character = EntryName[CharacterIndex];
  634. //
  635. // If the name ended, it better be spaces all the way to the end.
  636. //
  637. if (Name[NameIndex] == '\0') {
  638. if (Character != ' ') {
  639. return FALSE;
  640. }
  641. continue;
  642. //
  643. // If it's a dot and the current character is still in the DOS name
  644. // portion, it had better be a blanking space. If it's at the extension
  645. // boundary, advance past the dot to compare the extension.
  646. //
  647. } else if (Name[NameIndex] == '.') {
  648. if (CharacterIndex < FAT_FILE_LENGTH) {
  649. if (Character != ' ') {
  650. return FALSE;
  651. }
  652. continue;
  653. } else if (CharacterIndex == FAT_FILE_LENGTH) {
  654. NameIndex += 1;
  655. }
  656. }
  657. //
  658. // Lowercase the character.
  659. //
  660. if ((Character >= 'A') && (Character <= 'Z')) {
  661. Character = Character - 'A' + 'a';
  662. }
  663. if (Character != Name[NameIndex]) {
  664. return FALSE;
  665. }
  666. NameIndex += 1;
  667. }
  668. return TRUE;
  669. }
  670. KSTATUS
  671. EfipFatGetNextCluster (
  672. PTI_ROM_MEM_HANDLE Handle,
  673. FAT_FORMAT Format,
  674. PVOID ScratchBuffer,
  675. PULONG Cluster
  676. )
  677. /*++
  678. Routine Description:
  679. This routine finds the next cluster given a current cluster.
  680. Arguments:
  681. Handle - Supplies the handle to the device.
  682. Format - Supplies the FAT formatting (the cluster number size).
  683. ScratchBuffer - Supplies a pointer to a sector sized buffer this routine
  684. can use for scratch.
  685. Cluster - Supplies a pointer to a pointer that on input contains the
  686. current cluster. On successful output, contains the next cluster.
  687. Return Value:
  688. STATUS_SUCCESS on success.
  689. STATUS_END_OF_FILE if there is no next cluster.
  690. STATUS_VOLUME_CORRUPT if the current cluster is greater than the size of
  691. the FAT.
  692. --*/
  693. {
  694. PVOID Fat;
  695. ULONG FatOffset;
  696. ULONG NextCluster;
  697. KSTATUS Status;
  698. if (Format == Fat12Format) {
  699. *Cluster = FAT12_READ_CLUSTER(EfiFat12FatRegion, *Cluster);
  700. return STATUS_SUCCESS;
  701. }
  702. if (Format == Fat16Format) {
  703. FatOffset = *Cluster / FAT16_CLUSTERS_PER_BLOCK;
  704. } else {
  705. FatOffset = *Cluster / FAT32_CLUSTERS_PER_BLOCK;
  706. }
  707. if (FatOffset >= EfiFatSectorsPerFat) {
  708. return STATUS_VOLUME_CORRUPT;
  709. }
  710. Status = EfipReadSectors(Handle,
  711. ScratchBuffer,
  712. EfiFatFatBlockOffset + FatOffset,
  713. 1);
  714. if (!KSUCCESS(Status)) {
  715. return Status;
  716. }
  717. Fat = ScratchBuffer;
  718. if (Format == Fat16Format) {
  719. NextCluster = ((PUSHORT)Fat)[*Cluster % FAT16_CLUSTERS_PER_BLOCK];
  720. if (NextCluster >= FAT16_CLUSTER_BAD) {
  721. return STATUS_END_OF_FILE;
  722. }
  723. } else {
  724. NextCluster = ((PULONG)Fat)[*Cluster % FAT32_CLUSTERS_PER_BLOCK];
  725. if (NextCluster >= FAT32_CLUSTER_BAD) {
  726. return STATUS_END_OF_FILE;
  727. }
  728. }
  729. if (NextCluster < FAT_CLUSTER_BEGIN) {
  730. return STATUS_VOLUME_CORRUPT;
  731. }
  732. *Cluster = NextCluster;
  733. return STATUS_SUCCESS;
  734. }
  735. UCHAR
  736. EfipFatChecksumDirectoryEntry (
  737. PFAT_DIRECTORY_ENTRY Entry
  738. )
  739. /*++
  740. Routine Description:
  741. This routine returns the checksum of the given fat short directory entry
  742. based on the file name.
  743. Arguments:
  744. Entry - Supplies a pointer to the directory entry.
  745. Return Value:
  746. Returns the checksum of the directory entry.
  747. --*/
  748. {
  749. ULONG Index;
  750. UCHAR Sum;
  751. Sum = 0;
  752. for (Index = 0; Index < FAT_FILE_LENGTH; Index += 1) {
  753. Sum = ((Sum & 0x1) << 0x7) + (Sum >> 1) + Entry->DosName[Index];
  754. }
  755. for (Index = 0; Index < FAT_FILE_EXTENSION_LENGTH; Index += 1) {
  756. Sum = ((Sum & 0x1) << 0x7) + (Sum >> 1) + Entry->DosExtension[Index];
  757. }
  758. return Sum;
  759. }
  760. KSTATUS
  761. EfipReadSectors (
  762. PTI_ROM_MEM_HANDLE Handle,
  763. PVOID Buffer,
  764. ULONG AbsoluteSector,
  765. ULONG SectorCount
  766. )
  767. /*++
  768. Routine Description:
  769. This routine reads sectors from the SD card using the ROM.
  770. Arguments:
  771. Handle - Supplies a pointer to the ROM handle.
  772. Buffer - Supplies the buffer where the read data will be returned.
  773. AbsoluteSector - Supplies the zero-based sector number to read from.
  774. SectorCount - Supplies the number of sectors to read. The supplied buffer
  775. must be at least this large.
  776. Return Value:
  777. STATUS_SUCCESS if the operation completed successfully.
  778. STATUS_DEVICE_IO_ERROR if the ROM code failed the operation.
  779. --*/
  780. {
  781. INT Result;
  782. Result = EfipTiMemRead(Handle,
  783. AbsoluteSector + EfiBootPartitionStart,
  784. SectorCount,
  785. Buffer);
  786. if (Result != 0) {
  787. EfipSerialPrintString("Failed to read from SD: ");
  788. EfipSerialPrintHexInteger(Result);
  789. EfipSerialPrintString(".\n");
  790. return STATUS_DEVICE_IO_ERROR;
  791. }
  792. return STATUS_SUCCESS;
  793. }
  794. PVOID
  795. EfipInitCopyMemory (
  796. PVOID Destination,
  797. PVOID Source,
  798. ULONG ByteCount
  799. )
  800. /*++
  801. Routine Description:
  802. This routine copies a section of memory.
  803. Arguments:
  804. Destination - Supplies a pointer to the buffer where the memory will be
  805. copied to.
  806. Source - Supplies a pointer to the buffer to be copied.
  807. ByteCount - Supplies the number of bytes to copy.
  808. Return Value:
  809. Returns the destination pointer.
  810. --*/
  811. {
  812. PUCHAR From;
  813. PUCHAR To;
  814. From = (PUCHAR)Source;
  815. To = (PUCHAR)Destination;
  816. while (ByteCount > 0) {
  817. *To = *From;
  818. To += 1;
  819. From += 1;
  820. ByteCount -= 1;
  821. }
  822. return Destination;
  823. }