Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

823 lines
20 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. arcdisk.c
  5. Abstract:
  6. Provides the routines for collecting the disk information for all the ARC
  7. disks visible in the ARC environment.
  8. Author:
  9. John Vert (jvert) 3-Nov-1993
  10. Revision History:
  11. Vijay Jayaseelan (vijayj) 2-April-2000
  12. - Added EFI partition table support
  13. --*/
  14. #include "bootlib.h"
  15. #ifdef i386
  16. #include "bldrx86.h"
  17. #endif
  18. #if defined(_IA64_)
  19. #include "bldria64.h"
  20. #endif
  21. #ifdef EFI_PARTITION_SUPPORT
  22. //
  23. // EFI partition entries
  24. //
  25. UNALIGNED EFI_PARTITION_ENTRY EfiPartitionBuffer[128] = {0};
  26. #endif
  27. BOOLEAN
  28. BlpEnumerateDisks(
  29. IN PCONFIGURATION_COMPONENT_DATA ConfigData
  30. );
  31. #if defined(_X86_) && !defined(ARCI386)
  32. static
  33. VOID
  34. BlpEnumerateXInt13(
  35. VOID
  36. )
  37. /*++
  38. Routine Description:
  39. This routine will go through all the enumerated disks and record
  40. their ability to support xInt13.
  41. Arguments:
  42. None.
  43. Return Value:
  44. None.
  45. --*/
  46. {
  47. CHAR Partition[100];
  48. ULONG DiskId;
  49. ARC_STATUS Status;
  50. PARC_DISK_SIGNATURE DiskSignature;
  51. PARC_DISK_INFORMATION DiskInfo;
  52. PLIST_ENTRY Entry;
  53. DiskInfo = BlLoaderBlock->ArcDiskInformation;
  54. Entry = DiskInfo->DiskSignatures.Flink;
  55. while (Entry != &DiskInfo->DiskSignatures) {
  56. DiskSignature = CONTAINING_RECORD(Entry,ARC_DISK_SIGNATURE,ListEntry);
  57. //
  58. // Open partition0 on the disk and get it's device ID.
  59. //
  60. strcpy(Partition, DiskSignature->ArcName);
  61. strcat(Partition, "partition(0)");
  62. Status = ArcOpen(Partition, ArcOpenReadOnly, &DiskId);
  63. if( Status == ESUCCESS ) {
  64. //
  65. // Now we've got the DiskId. Fortunately, someone
  66. // has been keeping track of all the DiskIds on the
  67. // machine and whether or not they've got xint13 support.
  68. // All we need to do now is go lookup our diskid in
  69. // that database and get the xint13 BOOLEAN.
  70. //
  71. DiskSignature->xInt13 = BlFileTable[DiskId].u.DriveContext.xInt13;
  72. //
  73. // We don't need you anymore.
  74. //
  75. ArcClose(DiskId);
  76. } else {
  77. DiskSignature->xInt13 = FALSE;
  78. }
  79. Entry = Entry->Flink;
  80. }
  81. }
  82. #endif // for defined(_X86_) && !defined(ARCI386)
  83. ARC_STATUS
  84. BlGetArcDiskInformation(
  85. BOOLEAN XInt13Support
  86. )
  87. /*++
  88. Routine Description:
  89. Enumerates the ARC disks present in the system and collects the identifying disk
  90. information from each one.
  91. Arguments:
  92. XInt13Support : Indicates whether to find XInt13 support or not
  93. Return Value:
  94. None.
  95. --*/
  96. {
  97. PARC_DISK_INFORMATION DiskInfo;
  98. #if !(defined(_X86_) && !defined(ARCI386))
  99. UNREFERENCED_PARAMETER(XInt13Support);
  100. #endif
  101. DiskInfo = BlAllocateHeap(sizeof(ARC_DISK_INFORMATION));
  102. if (DiskInfo==NULL) {
  103. return(ENOMEM);
  104. }
  105. InitializeListHead(&DiskInfo->DiskSignatures);
  106. BlLoaderBlock->ArcDiskInformation = DiskInfo;
  107. BlSearchConfigTree(BlLoaderBlock->ConfigurationRoot,
  108. PeripheralClass,
  109. DiskPeripheral,
  110. (ULONG)-1,
  111. BlpEnumerateDisks);
  112. #if defined(_X86_) && !defined(ARCI386)
  113. //
  114. // Enumerate XInt13 support on X86 only if asked for
  115. //
  116. if (XInt13Support) {
  117. BlpEnumerateXInt13();
  118. }
  119. #endif
  120. return(ESUCCESS);
  121. }
  122. BOOLEAN
  123. BlpEnumerateDisks(
  124. IN PCONFIGURATION_COMPONENT_DATA ConfigData
  125. )
  126. /*++
  127. Routine Description:
  128. Callback routine for enumerating the disks in the ARC firmware tree. It
  129. reads all the necessary information from the disk to uniquely identify
  130. it.
  131. Arguments:
  132. ConfigData - Supplies a pointer to the disk's ARC component data.
  133. Return Value:
  134. TRUE - continue searching
  135. FALSE - stop searching tree.
  136. --*/
  137. {
  138. CHAR DiskName[100];
  139. BlGetPathnameFromComponent(ConfigData, DiskName);
  140. return(BlReadSignature(DiskName,FALSE));
  141. }
  142. BOOLEAN
  143. BlReadSignature(
  144. IN PCHAR DiskName,
  145. IN BOOLEAN IsCdRom
  146. )
  147. /*++
  148. Routine Description:
  149. Given an ARC disk name, reads the MBR and adds its signature to the list of
  150. disks.
  151. Arguments:
  152. Diskname - Supplies the name of the disk.
  153. IsCdRom - Indicates whether the disk is a CD-ROM.
  154. Return Value:
  155. TRUE - Success
  156. FALSE - Failure
  157. --*/
  158. {
  159. PARC_DISK_SIGNATURE Signature;
  160. BOOLEAN Status = FALSE;
  161. Signature = BlAllocateHeap(sizeof(ARC_DISK_SIGNATURE));
  162. if (Signature==NULL) {
  163. return(FALSE);
  164. }
  165. Signature->ArcName = BlAllocateHeap((ULONG)strlen(DiskName)+2);
  166. if (Signature->ArcName==NULL) {
  167. return(FALSE);
  168. }
  169. #if defined(i386)
  170. Status = BlFindDiskSignature(DiskName, Signature);
  171. #endif
  172. if(!Status) {
  173. Status = BlGetDiskSignature(DiskName, IsCdRom, Signature);
  174. }
  175. if (Status) {
  176. InsertHeadList(&BlLoaderBlock->ArcDiskInformation->DiskSignatures,
  177. &Signature->ListEntry);
  178. }
  179. return(TRUE);
  180. }
  181. BOOLEAN
  182. ArcDiskGPTDiskReadCallback(
  183. ULONGLONG StartingLBA,
  184. ULONG BytesToRead,
  185. PVOID pContext,
  186. UNALIGNED PVOID OutputBuffer
  187. )
  188. /*++
  189. Routine Description:
  190. This routine is a callback for reading data for a routine that
  191. validates the GPT partition table.
  192. NOTE: This routine changes the seek position on disk, and you must seek
  193. back to your original seek position if you plan on reading from the
  194. disk after making this call.
  195. Arguments:
  196. StartingLBA - starting logical block address to read from.
  197. BytesToRead - Indicates how many bytes are to be read.
  198. pContext - context pointer for hte function (in this case, a pointer to the disk id.)
  199. OutputBuffer - a buffer that receives the data. It's assumed that it is at least
  200. BytesToRead big enough.
  201. Return Value:
  202. TRUE - success, data has been read
  203. FALSE - failed, data has not been read.
  204. --*/
  205. {
  206. ARC_STATUS Status;
  207. LARGE_INTEGER SeekPosition;
  208. PUSHORT DataPointer;
  209. ULONG DiskId;
  210. ULONG ReadCount = 0;
  211. DiskId = *((PULONG)pContext);
  212. //
  213. // read the second LBA on the disk
  214. //
  215. SeekPosition.QuadPart = StartingLBA * SECTOR_SIZE;
  216. Status = ArcSeek(DiskId,
  217. &SeekPosition,
  218. SeekAbsolute );
  219. if (Status != ESUCCESS) {
  220. return FALSE;
  221. }
  222. DataPointer = OutputBuffer;
  223. Status = ArcRead(
  224. DiskId,
  225. DataPointer,
  226. BytesToRead,
  227. &ReadCount);
  228. if ((Status == ESUCCESS) && (ReadCount == BytesToRead)) {
  229. return(TRUE);
  230. }
  231. return(FALSE);
  232. }
  233. BOOLEAN
  234. BlGetDiskSignature(
  235. IN PCHAR DiskName,
  236. IN BOOLEAN IsCdRom,
  237. PARC_DISK_SIGNATURE Signature
  238. )
  239. /*++
  240. Routine Description:
  241. This routine gets the NTFT disk signature for a specified partition or
  242. path.
  243. Arguments:
  244. DiskName - Supplies the arcname of the partition or drive.
  245. IsCdRom - Indicates whether the disk is a CD-ROM.
  246. Signature - Returns a full ARC_DISK_SIGNATURE.
  247. Return Value:
  248. TRUE - success, Signature will be filled in.
  249. FALSE - failed, Signature will not be filled in.
  250. --*/
  251. {
  252. UCHAR SectorBuffer[2048+256] = {0};
  253. CHAR Partition[100];
  254. ULONG DiskId;
  255. ULONG Status;
  256. LARGE_INTEGER SeekValue;
  257. PUCHAR Sector;
  258. ULONG i;
  259. ULONG Sum;
  260. ULONG Count;
  261. ULONG SectorSize;
  262. EFI_PARTITION_TABLE *EfiHdr;
  263. if (IsCdRom) {
  264. SectorSize = 2048;
  265. } else {
  266. SectorSize = 512;
  267. }
  268. #if defined(_i386_)
  269. //
  270. // NTDETECT creates an "eisa(0)..." arcname for detected
  271. // BIOS disks on an EISA machine. Change this to "multi(0)..."
  272. // in order to be consistent with the rest of the system
  273. // (particularly the arcname in boot.ini)
  274. //
  275. if (_strnicmp(DiskName,"eisa",4)==0) {
  276. strcpy(Signature->ArcName,"multi");
  277. strcpy(Partition,"multi");
  278. strcat(Signature->ArcName,DiskName+4);
  279. strcat(Partition,DiskName+4);
  280. } else {
  281. strcpy(Signature->ArcName, DiskName);
  282. strcpy(Partition, DiskName);
  283. }
  284. #else
  285. strcpy(Signature->ArcName, DiskName);
  286. strcpy(Partition, DiskName);
  287. #endif
  288. strcat(Partition, "partition(0)");
  289. Status = ArcOpen(Partition, ArcOpenReadOnly, &DiskId);
  290. if (Status != ESUCCESS) {
  291. return(FALSE);
  292. }
  293. //
  294. // Read in the first sector
  295. //
  296. Sector = ALIGN_BUFFER(SectorBuffer);
  297. if (IsCdRom) {
  298. //
  299. // For a CD-ROM, the interesting data starts at 0x8000.
  300. //
  301. SeekValue.QuadPart = 0x8000;
  302. } else {
  303. SeekValue.QuadPart = 0;
  304. }
  305. Status = ArcSeek(DiskId, &SeekValue, SeekAbsolute);
  306. if (Status == ESUCCESS) {
  307. Status = ArcRead(DiskId,
  308. Sector,
  309. SectorSize,
  310. &Count);
  311. }
  312. if (Status != ESUCCESS) {
  313. ArcClose(DiskId);
  314. return(FALSE);
  315. }
  316. //
  317. // Check to see whether this disk has a valid partition table signature or not.
  318. //
  319. if (((PUSHORT)Sector)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE) {
  320. Signature->ValidPartitionTable = FALSE;
  321. } else {
  322. Signature->ValidPartitionTable = TRUE;
  323. }
  324. Signature->Signature = ((PULONG)Sector)[PARTITION_TABLE_OFFSET/2-1];
  325. //
  326. // compute the checksum
  327. //
  328. Sum = 0;
  329. for (i=0; i<(SectorSize/4); i++) {
  330. Sum += ((PULONG)Sector)[i];
  331. }
  332. Signature->CheckSum = ~Sum + 1;
  333. //
  334. // Check for GPT disk.
  335. //
  336. Signature->IsGpt = FALSE;
  337. if (!IsCdRom) {
  338. SeekValue.QuadPart = 1 * SectorSize;
  339. Status = ArcSeek(DiskId, &SeekValue, SeekAbsolute);
  340. if (Status == ESUCCESS) {
  341. Status = ArcRead(DiskId,
  342. Sector,
  343. SectorSize,
  344. &Count);
  345. if (Status == ESUCCESS) {
  346. ULONG tmpDiskId = DiskId;
  347. //
  348. // verify EFI partition table
  349. //
  350. EfiHdr = (EFI_PARTITION_TABLE *)Sector;
  351. if (BlIsValidGUIDPartitionTable(
  352. EfiHdr,
  353. 1,
  354. &tmpDiskId,
  355. ArcDiskGPTDiskReadCallback)) {
  356. Signature->IsGpt = TRUE;
  357. memcpy(
  358. Signature->GptSignature,
  359. EfiHdr->DiskGuid,
  360. sizeof(EfiHdr->DiskGuid) );
  361. }
  362. }
  363. }
  364. }
  365. ArcClose(DiskId);
  366. return(TRUE);
  367. }
  368. #ifdef EFI_PARTITION_SUPPORT
  369. /*
  370. void DbgOut(PWSTR Str);
  371. //#define DBG_PRINT(x) DbgOut(x);
  372. ULONG BlGetKey();
  373. #if defined(_IA64_)
  374. #define STR_PREFIX L
  375. #define DBG_PRINT(x) DbgOut(x)
  376. #else
  377. #define STR_PREFIX
  378. #define DBG_PRINT(x) \
  379. {\
  380. BlPrint(x); \
  381. while (!BlGetKey()); \
  382. }
  383. #endif // _IA64_
  384. */
  385. #define DBG_PRINT(x)
  386. #define STR_PREFIX
  387. UNALIGNED EFI_PARTITION_ENTRY *
  388. BlLocateGPTPartition(
  389. IN UCHAR PartitionNumber,
  390. IN UCHAR MaxPartitions,
  391. IN PUCHAR ValidPartCount
  392. )
  393. {
  394. UNALIGNED EFI_PARTITION_ENTRY *PartEntry = NULL;
  395. UCHAR NullGuid[16] = {0};
  396. UCHAR PartIdx = 0;
  397. UCHAR PartCount = 0;
  398. #if 0
  399. BlPrint("BlLocateGPTPartition(%d,%d,%d)\r\n",
  400. PartitionNumber,
  401. MaxPartitions,
  402. ValidPartCount ? *ValidPartCount : 0);
  403. while (!BlGetKey());
  404. #endif
  405. if (ARGUMENT_PRESENT(ValidPartCount)) {
  406. PartCount = *ValidPartCount;
  407. }
  408. PartitionNumber++; // convert to one based index
  409. //
  410. // Locate the requested valid partition
  411. //
  412. while ((PartIdx < MaxPartitions) && (PartCount < PartitionNumber)) {
  413. DBG_PRINT(STR_PREFIX"Verifying GPT Partition Entry\r\n");
  414. PartEntry = (UNALIGNED EFI_PARTITION_ENTRY *)(EfiPartitionBuffer + PartIdx);
  415. if ((memcmp(PartEntry->Type, NullGuid, 16)) &&
  416. (memcmp(PartEntry->Id, NullGuid, 16)) &&
  417. (PartEntry->StartingLBA != 0) && (PartEntry->EndingLBA != 0)) {
  418. DBG_PRINT(STR_PREFIX"Found Valid GPT Partition Entry\r\n");
  419. PartCount++;
  420. if (ARGUMENT_PRESENT(ValidPartCount)) {
  421. (*ValidPartCount)++;
  422. }
  423. //
  424. // Get hold of the partition entry
  425. //
  426. if (PartCount == PartitionNumber) {
  427. break;
  428. } else {
  429. PartEntry = NULL;
  430. }
  431. } else {
  432. PartEntry = NULL;
  433. }
  434. PartIdx++;
  435. }
  436. return PartEntry;
  437. }
  438. BOOLEAN
  439. BlDiskOpenGPTDiskReadCallback(
  440. ULONGLONG StartingLBA,
  441. ULONG BytesToRead,
  442. PVOID pContext,
  443. UNALIGNED PVOID OutputBuffer
  444. )
  445. /*++
  446. Routine Description:
  447. This routine is a callback for reading data for a routine that
  448. validates the GPT partition table.
  449. Arguments:
  450. StartingLBA - starting logical block address to read from.
  451. BytesToRead - Indicates how many bytes are to be read.
  452. pContext - context pointer for hte function (in this case, a pointer to the disk id.)
  453. OutputBuffer - a buffer that receives the data. It's assumed that it is at least
  454. BytesToRead big enough.
  455. Return Value:
  456. TRUE - success, data has been read
  457. FALSE - failed, data has not been read.
  458. --*/
  459. {
  460. ARC_STATUS Status;
  461. LARGE_INTEGER SeekPosition;
  462. PUSHORT DataPointer;
  463. ULONG DiskId;
  464. ULONG ReadCount = 0;
  465. DiskId = *((PULONG)pContext);
  466. //
  467. // read the second LBA on the disk
  468. //
  469. SeekPosition.QuadPart = StartingLBA * SECTOR_SIZE;
  470. Status = (BlFileTable[DiskId].DeviceEntryTable->Seek)(DiskId,
  471. &SeekPosition,
  472. SeekAbsolute );
  473. if (Status != ESUCCESS) {
  474. return FALSE;
  475. }
  476. DataPointer = OutputBuffer;
  477. Status = (BlFileTable[DiskId].DeviceEntryTable->Read)(DiskId,
  478. DataPointer,
  479. BytesToRead,
  480. &ReadCount);
  481. if ((Status == ESUCCESS) && (ReadCount == BytesToRead)) {
  482. return(TRUE);
  483. }
  484. return(FALSE);
  485. }
  486. ARC_STATUS
  487. BlOpenGPTDiskPartition(
  488. IN ULONG FileId,
  489. IN ULONG DiskId,
  490. IN UCHAR PartitionNumber
  491. )
  492. {
  493. ARC_STATUS Status;
  494. LARGE_INTEGER SeekPosition;
  495. UCHAR DataBuffer[SECTOR_SIZE * 2] = {0};
  496. ULONG ReadCount = 0;
  497. UCHAR NullGuid[16] = {0};
  498. UNALIGNED EFI_PARTITION_TABLE *EfiHdr;
  499. UNALIGNED EFI_PARTITION_ENTRY *PartEntry;
  500. ULONG tmpDiskId = DiskId;
  501. if (PartitionNumber >= 128)
  502. return EINVAL;
  503. DBG_PRINT(STR_PREFIX"Seeking GPT PT\r\n");
  504. //
  505. // read the second LBA on the disk
  506. //
  507. SeekPosition.QuadPart = 1 * SECTOR_SIZE;
  508. Status = (BlFileTable[DiskId].DeviceEntryTable->Seek)(DiskId,
  509. &SeekPosition,
  510. SeekAbsolute );
  511. if (Status != ESUCCESS)
  512. return Status;
  513. DBG_PRINT(STR_PREFIX"Reading GPT PT\r\n");
  514. Status = (BlFileTable[DiskId].DeviceEntryTable->Read)(DiskId,
  515. DataBuffer,
  516. SECTOR_SIZE,
  517. &ReadCount);
  518. if (Status != ESUCCESS)
  519. return Status;
  520. if (ReadCount != SECTOR_SIZE) {
  521. Status = EIO;
  522. return Status;
  523. }
  524. EfiHdr = (UNALIGNED EFI_PARTITION_TABLE *)DataBuffer;
  525. DBG_PRINT(STR_PREFIX"Verifying GPT PT\r\n");
  526. //
  527. // verify EFI partition table
  528. //
  529. if (!BlIsValidGUIDPartitionTable(
  530. EfiHdr,
  531. 1,
  532. &tmpDiskId,
  533. BlDiskOpenGPTDiskReadCallback)) {
  534. Status = EBADF;
  535. return Status;
  536. }
  537. //
  538. // Locate and read the partition entry
  539. // which is requested
  540. //
  541. SeekPosition.QuadPart = EfiHdr->PartitionEntryLBA * SECTOR_SIZE;
  542. DBG_PRINT(STR_PREFIX"Seeking GPT Partition Entries\r\n");
  543. Status = (BlFileTable[DiskId].DeviceEntryTable->Seek)(DiskId,
  544. &SeekPosition,
  545. SeekAbsolute );
  546. if (Status != ESUCCESS)
  547. return Status;
  548. RtlZeroMemory(EfiPartitionBuffer, sizeof(EfiPartitionBuffer));
  549. DBG_PRINT(STR_PREFIX"Reading GPT Partition Entries\r\n");
  550. Status = (BlFileTable[DiskId].DeviceEntryTable->Read)(DiskId,
  551. EfiPartitionBuffer,
  552. sizeof(EfiPartitionBuffer),
  553. &ReadCount);
  554. if (Status != ESUCCESS)
  555. return Status;
  556. if (ReadCount != sizeof(EfiPartitionBuffer)) {
  557. Status = EIO;
  558. return Status;
  559. }
  560. DBG_PRINT(STR_PREFIX"Locating the correct GPT partition entry\r\n");
  561. PartEntry = (UNALIGNED EFI_PARTITION_ENTRY *)BlLocateGPTPartition(PartitionNumber, 128, NULL);
  562. if (PartEntry) {
  563. DBG_PRINT(STR_PREFIX"Verifying GPT Partition Entry\r\n");
  564. if ((memcmp(PartEntry->Type, NullGuid, 16)) &&
  565. (memcmp(PartEntry->Id, NullGuid, 16)) &&
  566. (PartEntry->StartingLBA != 0) && (PartEntry->EndingLBA != 0)) {
  567. PPARTITION_CONTEXT PartContext = &(BlFileTable[FileId].u.PartitionContext);
  568. ULONG SectorCount = (ULONG)(PartEntry->EndingLBA - PartEntry->StartingLBA);
  569. DBG_PRINT(STR_PREFIX"Initializing GPT Partition Entry Context\r\n");
  570. //
  571. // Fill the partition context structure
  572. //
  573. PartContext->PartitionLength.QuadPart = SectorCount * SECTOR_SIZE;
  574. PartContext->StartingSector = (ULONG)(PartEntry->StartingLBA);
  575. PartContext->EndingSector = (ULONG)(PartEntry->EndingLBA);
  576. PartContext->DiskId = (UCHAR)DiskId;
  577. BlFileTable[FileId].Position.QuadPart = 0;
  578. #if 0
  579. BlPrint("GPT Partition opened:L:%ld,%ld:%ld,SS:%ld,ES:%ld\n",
  580. PartitionNumber,
  581. (ULONG)PartContext->PartitionLength.QuadPart,
  582. (ULONG)PartContext->StartingSector,
  583. (ULONG)PartContext->EndingSector);
  584. while (!GET_KEY());
  585. #endif
  586. Status = ESUCCESS;
  587. } else {
  588. Status = EBADF;
  589. }
  590. } else {
  591. Status = EBADF;
  592. }
  593. DBG_PRINT(STR_PREFIX"Returning from BlOpenGPTDiskPartition(...)\r\n");
  594. return Status;
  595. }
  596. #endif // for EFI_PARTITION_SUPPORT