Source code of Windows XP (NT5)
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.

1972 lines
47 KiB

  1. /*
  2. Module Name:
  3. DiskPart - GUID Partition Table scheme disk partitioning program.
  4. (The GPT version of FDISK, if you will)
  5. Abstract:
  6. Revision History
  7. */
  8. #include "DiskPart.h"
  9. #include "symbols.h"
  10. #include "helpmsg.h"
  11. //
  12. // Globals
  13. //
  14. UINTN DebugLevel = DEBUG_NONE;
  15. //UINTN DebugLevel = DEBUG_OPPROMPT;
  16. EFI_STATUS status;
  17. EFI_HANDLE *DiskHandleList = NULL;
  18. INTN DiskHandleCount = 0;
  19. INTN SelectedDisk = -1;
  20. EFI_HANDLE SavedImageHandle;
  21. EFI_STATUS ParseAndExecuteCommands();
  22. BOOLEAN ExecuteSingleCommand(CHAR16 *Token[]);
  23. VOID DumpGPT(
  24. EFI_HANDLE DiskHandle,
  25. PGPT_HEADER Header,
  26. PGPT_TABLE Table,
  27. BOOLEAN Raw,
  28. BOOLEAN Verbose
  29. );
  30. VOID
  31. PrintGptEntry(
  32. GPT_ENTRY *Entry,
  33. UINTN Index
  34. );
  35. EFI_GUID
  36. GetGUID(
  37. );
  38. #define CLEAN_RANGE (1024*1024)
  39. CHAR16 *TokenChar =
  40. L"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789`~!@#$%^&*()-_+[]{}':;/?.>,<\\|";
  41. VOID CmdInspectMBR(CHAR16 **Token);
  42. VOID CmdCreateMBR(CHAR16 **Token);
  43. VOID CmdNewMBR(CHAR16 **Token);
  44. VOID CmdDeleteMBR(CHAR16 **Token);
  45. //
  46. // Worker function type
  47. //
  48. typedef
  49. BOOLEAN
  50. (*PCMD_FUNCTION)(
  51. CHAR16 **Token
  52. );
  53. EFI_STATUS
  54. ReinstallFSDStack(
  55. );
  56. //
  57. // The parse table structure
  58. //
  59. typedef struct {
  60. CHAR16 *Name;
  61. PCMD_FUNCTION Function;
  62. CHAR16 *HelpSummary;
  63. } CMD_ENTRY;
  64. //
  65. // The parse/command table
  66. //
  67. CMD_ENTRY CmdTable[] = {
  68. { STR_LIST, CmdList, MSG_LIST },
  69. { STR_SELECT, CmdSelect, MSG_SELECT },
  70. { STR_INSPECT, CmdInspect, MSG_INSPECT },
  71. { STR_CLEAN, CmdClean, MSG_CLEAN },
  72. { STR_NEW, CmdNew, MSG_NEW },
  73. { STR_FIX, CmdFix, MSG_FIX },
  74. { STR_CREATE, CmdCreate, MSG_CREATE },
  75. { STR_DELETE, CmdDelete, MSG_DELETE },
  76. { STR_HELP, CmdHelp, MSG_HELP },
  77. { STR_HELP2, CmdHelp, MSG_ABBR_HELP },
  78. { STR_HELP3, CmdHelp, MSG_ABBR_HELP },
  79. { STR_EXIT, CmdExit, MSG_EXIT },
  80. { STR_SYMBOLS, CmdSymbols, MSG_SYMBOLS },
  81. { STR_REMARK, CmdRemark, MSG_REMARK },
  82. { STR_MAKE, CmdMake, MSG_MAKE },
  83. { STR_DEBUG, CmdDebug, NULL },
  84. { STR_ABOUT, CmdAbout, MSG_ABOUT },
  85. { NULL, NULL, NULL }
  86. };
  87. EFI_STATUS
  88. EfiMain(
  89. IN EFI_HANDLE ImageHandle,
  90. IN EFI_SYSTEM_TABLE *SystemTable
  91. )
  92. {
  93. //
  94. // Initialize the Library.
  95. //
  96. SavedImageHandle = ImageHandle;
  97. InitializeLib (ImageHandle, SystemTable);
  98. Print(L"DiskPart Version 0.2\n");
  99. Print(L"Based on EFI core release ");
  100. Print(MSG_ABOUT02,
  101. EFI_SPECIFICATION_MAJOR_REVISION,
  102. EFI_SPECIFICATION_MINOR_REVISION,
  103. EFI_FIRMWARE_MAJOR_REVISION,
  104. EFI_FIRMWARE_MINOR_REVISION
  105. );
  106. //
  107. // See if there are any disks that look like candidates to be partitioned
  108. //
  109. status = FindPartitionableDevices(&DiskHandleList, &DiskHandleCount);
  110. if (EFI_ERROR(status)) {
  111. Print(L"%s\n", MSG_NO_DISKS);
  112. return EFI_NOT_FOUND;
  113. }
  114. //
  115. // Start Parse Loop
  116. //
  117. ParseAndExecuteCommands();
  118. ReinstallFSDStack();
  119. DoFree(DiskHandleList);
  120. return status;
  121. }
  122. EFI_STATUS
  123. ReinstallFSDStack(
  124. )
  125. /*++
  126. Make sure that the partition driver is alerted to the changes in the
  127. the file system structures. One way to effect this end is to
  128. reinstall all of the blkio interfaces such that the partition driver
  129. will receive a notification and probe the partition tables to reconstruct
  130. the file system stack.
  131. --*/
  132. {
  133. INTN Index;
  134. EFI_STATUS Status;
  135. EFI_BLOCK_IO *IBlkIo;
  136. Status = EFI_SUCCESS;
  137. for (Index = 0; Index < DiskHandleCount; Index++) {
  138. Status = BS->HandleProtocol(
  139. DiskHandleList[Index],
  140. &BlockIoProtocol,
  141. &IBlkIo
  142. );
  143. if (!EFI_ERROR(Status)) {
  144. Status = BS->ReinstallProtocolInterface (
  145. DiskHandleList[Index],
  146. &BlockIoProtocol,
  147. IBlkIo,
  148. IBlkIo
  149. );
  150. }
  151. }
  152. return Status;
  153. }
  154. EFI_STATUS
  155. ParseAndExecuteCommands()
  156. /*
  157. ParseAndExecuteCommands reads 1 line at a time from stdin.
  158. Lines are parsed for commands and arguments.
  159. The symbol ";" (semicolon) is used to mark the end of a command
  160. and start a new one.
  161. \ is the escape, \\ => '\'
  162. All commands are upper cased before parsing to give us
  163. case insensitive operations. This does not apply to literal
  164. strings.
  165. Any white space is treated a token separator.
  166. Commandline is set quite long.
  167. */
  168. {
  169. CHAR16 *Prompt = MSG_PROMPT;
  170. CHAR16 CommandLine[COMMAND_LINE_MAX];
  171. CHAR16 *Token[TOKEN_COUNT_MAX];
  172. UINTN i;
  173. NewLine:
  174. while (TRUE) {
  175. for (i = 0; i < COMMAND_LINE_MAX; i++ ) {
  176. CommandLine[i] = NUL;
  177. }
  178. Input(Prompt, CommandLine, COMMAND_LINE_MAX);
  179. Print(L"\n");
  180. if (CommandLine[0] == NUL) {
  181. continue;
  182. }
  183. StrUpr(CommandLine);
  184. Tokenize(CommandLine, Token);
  185. if (Token[0] == (CHAR16 *)-1) {
  186. //
  187. // syntax error
  188. //
  189. Print(L"???\n");
  190. goto NewLine;
  191. }
  192. if (ExecuteSingleCommand(Token) == TRUE) {
  193. return TRUE;
  194. }
  195. if (DebugLevel >= DEBUG_ERRPRINT) {
  196. if (EFI_ERROR(status)) {
  197. Print(L"status = %x %r\n", status, status);
  198. }
  199. }
  200. }
  201. return EFI_SUCCESS;
  202. }
  203. VOID
  204. Tokenize(
  205. CHAR16 *CommandLine,
  206. CHAR16 *Token[]
  207. )
  208. /*
  209. Tokenize -
  210. find the tokens, where a token is any string of letter & numbers.
  211. tokens to contain blanks, etc, must begin end with "
  212. return
  213. Token[] set. if Token[0] = NULL, nothing in THIS command
  214. */
  215. {
  216. CHAR16 *ch;
  217. UINTN tx;
  218. //
  219. // init the token array
  220. //
  221. for (tx = 0; tx < TOKEN_COUNT_MAX; tx++) {
  222. Token[tx] = NULL;
  223. }
  224. tx = 0;
  225. //
  226. // sweep for tokens
  227. //
  228. ch = CommandLine;
  229. while (TRUE) {
  230. //
  231. // if we see a quote, advance to the closing quote
  232. // and call the result a token.
  233. //
  234. if (*ch == '"') {
  235. ch++;
  236. Token[tx] = ch;
  237. while ((*ch != '"') && (*ch != NUL)) {
  238. ch++;
  239. }
  240. if (*ch == '"') {
  241. //
  242. // we have the closing ", we have a token
  243. //
  244. *ch = NUL; // mark end of token
  245. ch++;
  246. tx++;
  247. } else {
  248. Token[0] = (CHAR16 *)-1; // report error
  249. return;
  250. }
  251. } else {
  252. //
  253. // not a quoted string, so pick off a normal token
  254. //
  255. // Start by finding start of token
  256. //
  257. for ( ; *ch != NUL; ch++) {
  258. if (IsIn(*ch, TokenChar)) {
  259. Token[tx] = ch;
  260. tx++;
  261. break;
  262. }
  263. }
  264. while (IsIn(*ch, TokenChar)) {
  265. ch++;
  266. }
  267. //
  268. // if we're at the end of the command line, we're done
  269. // else, trim off token and go on
  270. //
  271. if (*ch == NUL) {
  272. //
  273. // we hit the end
  274. //
  275. Token[tx] = NULL;
  276. return;
  277. } else {
  278. *ch = NUL;
  279. ch++;
  280. }
  281. } // else
  282. } // while
  283. }
  284. BOOLEAN
  285. ExecuteSingleCommand(
  286. CHAR16 *Token[]
  287. )
  288. /*
  289. Returns TRUE to tell program to exit, else FALSE
  290. */
  291. {
  292. UINTN i;
  293. for (i = 0; CmdTable[i].Name != NULL; i++) {
  294. if (StrCmp(CmdTable[i].Name, Token[0]) == 0) {
  295. return CmdTable[i].Function(Token);
  296. }
  297. }
  298. //
  299. // If we're here, we didn't understand the command
  300. //
  301. Print(L"%s\n%s\n", MSG_BAD_CMD, MSG_GET_HELP);
  302. return FALSE;
  303. }
  304. BOOLEAN
  305. CmdAbout(
  306. CHAR16 **Token
  307. )
  308. {
  309. Print(MSG_ABOUT02,
  310. EFI_FIRMWARE_MAJOR_REVISION,
  311. EFI_FIRMWARE_MINOR_REVISION,
  312. EFI_FIRMWARE_MAJOR_REVISION,
  313. EFI_FIRMWARE_MINOR_REVISION
  314. );
  315. return FALSE;
  316. }
  317. BOOLEAN
  318. CmdList(
  319. CHAR16 **Token
  320. )
  321. /*
  322. CmdList - print the list of Partionable Disks
  323. Globals: DiskHandleList, DiskHandleCount
  324. Cmd Args: None.
  325. */
  326. {
  327. INTN i;
  328. EFI_BLOCK_IO *BlkIo;
  329. CHAR16 c;
  330. Print(MSG_LIST01);
  331. Print(MSG_LIST01B);
  332. for (i = 0; i < DiskHandleCount; i++) {
  333. status = BS->HandleProtocol(DiskHandleList[i], &BlockIoProtocol, &BlkIo);
  334. if (i == SelectedDisk) {
  335. c = '*';
  336. } else {
  337. c = ' ';
  338. }
  339. if (EFI_ERROR(status)) {
  340. Print(MSG_LIST03, i);
  341. } else {
  342. Print(
  343. MSG_LIST02,
  344. c,
  345. i,
  346. BlkIo->Media->BlockSize,
  347. BlkIo->Media->LastBlock+1
  348. );
  349. }
  350. }
  351. return FALSE;
  352. }
  353. BOOLEAN
  354. CmdSelect(
  355. CHAR16 **Token
  356. )
  357. /*
  358. CmdSelect - Select the disk that most commands operate on.
  359. Globals: SelectedDisk, DiskHandleCount
  360. Options: None.
  361. Cmd Args: none for display, number to select
  362. */
  363. {
  364. INTN NewSelect;
  365. if (Token[1] == NULL) {
  366. if (SelectedDisk == -1) {
  367. Print(MSG_SELECT01);
  368. } else {
  369. Print(MSG_SELECT02, SelectedDisk);
  370. }
  371. } else {
  372. NewSelect = Atoi(Token[1]);
  373. if ((NewSelect >= 0) &&
  374. (NewSelect < DiskHandleCount) &&
  375. (IsIn(*Token[1], L"0123456789")) )
  376. {
  377. SelectedDisk = NewSelect;
  378. Print(MSG_SELECT02, SelectedDisk);
  379. } else {
  380. Print(MSG_SELECT03);
  381. }
  382. }
  383. return FALSE;
  384. }
  385. BOOLEAN
  386. CmdInspect(
  387. CHAR16 **Token
  388. )
  389. /*
  390. CmdInspect - report data on the currently selected disk
  391. Globals: SelectedDisk, DiskHandleList
  392. Cmd Args: [RAW] [VER]
  393. */
  394. {
  395. EFI_HANDLE DiskHandle;
  396. UINTN DiskType = 0;
  397. PGPT_HEADER Header = NULL;
  398. PGPT_TABLE Table = NULL;
  399. PLBA_BLOCK LbaBlock = NULL;
  400. BOOLEAN Raw;
  401. BOOLEAN Verbose;
  402. UINTN i;
  403. if (SelectedDisk == -1) {
  404. Print(MSG_INSPECT01);
  405. return FALSE;
  406. }
  407. Print(MSG_SELECT02, SelectedDisk);
  408. DiskHandle = DiskHandleList[SelectedDisk];
  409. status = ReadGPT(DiskHandle, &Header, &Table, &LbaBlock, &DiskType);
  410. if (EFI_ERROR(status)) {
  411. return FALSE;
  412. }
  413. if (DiskType == DISK_RAW) {
  414. Print(MSG_INSPECT04);
  415. goto Exit;
  416. } else if (DiskType == DISK_MBR) {
  417. CmdInspectMBR(Token);
  418. goto Exit;
  419. } else if (DiskType == DISK_GPT_BAD) {
  420. Print(MSG_INSPECT06);
  421. goto Exit;
  422. } else if ( (DiskType != DISK_GPT_UPD) &&
  423. (DiskType != DISK_GPT))
  424. {
  425. TerribleError(L"Bad Disk Type returnted to Inspect!");
  426. goto Exit;
  427. }
  428. if (DiskType == DISK_GPT_UPD) {
  429. Print(MSG_INSPECT03);
  430. }
  431. if ( (Token[1]) &&
  432. (StrCmp(Token[1], STR_HELP) == 0) )
  433. {
  434. PrintHelp(InspectHelpText);
  435. goto Exit;
  436. }
  437. Raw = FALSE;
  438. Verbose = FALSE;
  439. for (i = 1; Token[i]; i++) {
  440. if (StrCmp(Token[i], STR_RAW) == 0) {
  441. Raw = TRUE;
  442. } else if (StrCmp(Token[i], STR_VER) == 0) {
  443. Verbose = TRUE;
  444. } else {
  445. PrintHelp(InspectHelpText);
  446. goto Exit;
  447. }
  448. }
  449. DumpGPT(DiskHandle, Header, Table, Raw, Verbose);
  450. Exit:
  451. DoFree(Header);
  452. DoFree(Table);
  453. DoFree(LbaBlock);
  454. return FALSE;
  455. }
  456. typedef struct {
  457. UINTN Slot;
  458. EFI_LBA StartingLBA;
  459. } SORT_SLOT_ENTRY;
  460. VOID
  461. DumpGPT(
  462. EFI_HANDLE DiskHandle,
  463. PGPT_HEADER Header,
  464. PGPT_TABLE Table,
  465. BOOLEAN Raw,
  466. BOOLEAN Verbose
  467. )
  468. /*
  469. DumpGPT - print out the GPT passed in via Header and Table
  470. if (Raw) print slot order, all slots, table order.
  471. else print only allocated slots, StartingLBA order.
  472. if (Verbose) print out the Header data.
  473. */
  474. {
  475. EFI_BLOCK_IO *BlkIo;
  476. UINTN i;
  477. UINTN AllocatedSlots;
  478. CHAR16 Buffer[PART_NAME_LEN+1];
  479. BOOLEAN changed;
  480. SORT_SLOT_ENTRY *SortSlot;
  481. GPT_ENTRY Entry;
  482. UINTN tslot;
  483. EFI_LBA tlba;
  484. SortSlot = DoAllocate(Header->EntriesAllocated * sizeof(SORT_SLOT_ENTRY));
  485. if (SortSlot == NULL) {
  486. status = EFI_OUT_OF_RESOURCES;
  487. Print(MSG_INSPECT02);
  488. return;
  489. }
  490. //
  491. // Dump the handle data just as List would
  492. //
  493. BS->HandleProtocol(DiskHandle, &BlockIoProtocol, &BlkIo);
  494. Print(MSG_LIST01);
  495. Print(MSG_LIST01B);
  496. Print(MSG_LIST02, '*', SelectedDisk, BlkIo->Media->BlockSize, BlkIo->Media->LastBlock+1);
  497. if (Verbose) {
  498. //
  499. // Dump the header
  500. //
  501. Print(L"\nHeader Structure\n");
  502. Print(L" Signature= %16lx Revision=%8X\n",
  503. Header->Signature, Header->Revision);
  504. Print(L" HeaderSize=%8x HeaderCRC32=%8x\n",
  505. Header->HeaderSize, Header->HeaderCRC32);
  506. Print(L" MyLBA=%16lx AlternateLBA=%16lx\n",
  507. Header->MyLBA, Header->AlternateLBA);
  508. Print(L" FirstUsableLBA=%16lx LastUsableLBA=%16lx\n",
  509. Header->FirstUsableLBA, Header->LastUsableLBA);
  510. Print(L" TableLBA=%16lx\n", Header->TableLBA);
  511. Print(L" EntrySize=%8x EntriesAllowed=%8x TableCRC=%8x\n\n",
  512. Header->SizeOfGPT_ENTRY, Header->EntriesAllocated, Header->TableCRC32);
  513. }
  514. //
  515. // Print the Table of GPT entries
  516. //
  517. if (!Raw) {
  518. //
  519. // !Raw == Cooked -> Print the Allocated entries in StartingLBA
  520. // SORTED order...
  521. //
  522. // Find ALL of the allocated entries
  523. //
  524. AllocatedSlots = 0;
  525. for (i = 0; i < Header->EntriesAllocated; i++) {
  526. CopyMem(&Entry, &Table->Entry[i], sizeof(GPT_ENTRY));
  527. if (CompareMem(&(Entry.PartitionType), &GuidNull, sizeof(EFI_GUID)) != 0) {
  528. SortSlot[AllocatedSlots].Slot = i;
  529. SortSlot[AllocatedSlots].StartingLBA = Entry.StartingLBA;
  530. AllocatedSlots++;
  531. }
  532. }
  533. // j has the count of allocated entries
  534. //
  535. // Sort them - yes this is a bubble sort, but the list is probably
  536. // in order and probably small, so for the vastly typical case
  537. // this is actually optimal
  538. //
  539. if (AllocatedSlots > 0) {
  540. do {
  541. changed = FALSE;
  542. for (i = 0; i < AllocatedSlots-1; i++) {
  543. if (SortSlot[i].StartingLBA > SortSlot[i+1].StartingLBA) {
  544. tslot = SortSlot[i+1].Slot;
  545. tlba = SortSlot[i+1].StartingLBA;
  546. changed = TRUE;
  547. SortSlot[i+1].Slot = SortSlot[i].Slot;
  548. SortSlot[i+1].StartingLBA = SortSlot[i].StartingLBA;
  549. SortSlot[i].Slot = tslot;
  550. SortSlot[i].StartingLBA = tlba;
  551. }
  552. }
  553. } while (changed);
  554. //
  555. // Print them, but print the SLOT number, not the row number.
  556. // This is to make Delete be reliable.
  557. //
  558. for (i = 0; i < AllocatedSlots; i++) {
  559. PrintGptEntry(&Table->Entry[SortSlot[i].Slot], SortSlot[i].Slot);
  560. if (((i+1) % 4) == 0) {
  561. Input(MSG_MORE, Buffer, PART_NAME_LEN);
  562. }
  563. }
  564. }
  565. } else {
  566. //
  567. // Raw -> Print ALL of the entries in Table order
  568. // (mostly for test, debug, looking at cratered disks
  569. //
  570. Print(L"RAW RAW RAW\n");
  571. for (i = 0; i < Header->EntriesAllocated; i++) {
  572. PrintGptEntry(&Table->Entry[i], i);
  573. if (((i+1) % 4) == 0) {
  574. Input(MSG_MORE, Buffer, PART_NAME_LEN);
  575. }
  576. }
  577. Print(L"RAW RAW RAW\n");
  578. }
  579. DoFree(SortSlot);
  580. return;
  581. }
  582. VOID
  583. PrintGptEntry(
  584. GPT_ENTRY *Entry,
  585. UINTN Index
  586. )
  587. {
  588. CHAR16 Buffer[PART_NAME_LEN+1];
  589. UINTN j;
  590. Print(L"\n%3d: ", Index);
  591. ZeroMem(Buffer, (PART_NAME_LEN+1)*sizeof(CHAR16));
  592. CopyMem(Buffer, &(Entry->PartitionName), PART_NAME_LEN*sizeof(CHAR16));
  593. Print(L"%s\n ", Buffer);
  594. PrintGuidString(&(Entry->PartitionType));
  595. for (j = 0; SymbolList[j].SymName; j++) {
  596. if (CompareMem(&(Entry->PartitionType), SymbolList[j].Value, sizeof(EFI_GUID)) == 0) {
  597. Print(L" = %s", SymbolList[j].SymName);
  598. }
  599. }
  600. if (CompareMem(&(Entry->PartitionType), &GuidNull, sizeof(EFI_GUID)) == 0) {
  601. Print(L" = UNALLOCATED SLOT");
  602. }
  603. Print(L"\n ");
  604. PrintGuidString(&(Entry->PartitionID));
  605. Print(L" @%16x\n", Entry->Attributes);
  606. Print(L" %16lx - %16lx\n",
  607. Entry->StartingLBA,
  608. Entry->EndingLBA
  609. );
  610. }
  611. BOOLEAN
  612. CmdClean(
  613. CHAR16 **Token
  614. )
  615. /*
  616. CmdClean - Clean off the disk
  617. Globals: SelectedDisk, DiskHandleList
  618. Cmd Args: ALL to clean whole disk, rather than just 1st and last megabyte
  619. We write out 1 block at a time. While this is slow, it avoids wondering
  620. about the Block protocol write size limit, and about how big a buffer
  621. we can allocate.
  622. */
  623. {
  624. EFI_HANDLE DiskHandle;
  625. CHAR16 Answer[COMMAND_LINE_MAX];
  626. BOOLEAN CleanAll;
  627. UINT32 BlockSize;
  628. UINT64 DiskSize;
  629. UINT64 DiskBytes;
  630. UINT64 RangeBlocks;
  631. UINT64 EndRange;
  632. UINT64 i;
  633. CHAR8 *zbuf;
  634. if (SelectedDisk == -1) {
  635. Print(MSG_INSPECT01);
  636. return FALSE;
  637. }
  638. DiskHandle = DiskHandleList[SelectedDisk];
  639. BlockSize = GetBlockSize(DiskHandle);
  640. DiskSize = GetDiskSize(DiskHandle);
  641. DiskBytes = MultU64x32(DiskSize, BlockSize);
  642. zbuf = DoAllocate(CLEAN_RANGE);
  643. if (zbuf == NULL) return FALSE;
  644. ZeroMem(zbuf, CLEAN_RANGE);
  645. //
  646. // Are you sure?
  647. //
  648. Print(MSG_CLEAN01, SelectedDisk);
  649. Input(STR_CLEAN_PROMPT, Answer, COMMAND_LINE_MAX);
  650. StrUpr(Answer);
  651. Print(L"\n");
  652. if (StrCmp(Answer, L"Y") != 0) {
  653. DoFree(zbuf);
  654. return FALSE;
  655. }
  656. //
  657. // Are you REALLY Sure?
  658. //
  659. Print(MSG_CLEAN02);
  660. Input(STR_CLEAN_PROMPT, Answer, COMMAND_LINE_MAX);
  661. Print(L"\n");
  662. if (StrCmp(Answer, STR_CLEAN_ANS) != 0) {
  663. DoFree(zbuf);
  664. return FALSE;
  665. }
  666. //
  667. // OK, the user really wants to do this
  668. //
  669. //
  670. // All? or just start and end?
  671. //
  672. CleanAll = FALSE;
  673. if (Token[1]) {
  674. if (StrCmp(Token[1], STR_CLEAN03) == 0) {
  675. CleanAll = TRUE;
  676. }
  677. }
  678. if (DiskBytes > (2 * CLEAN_RANGE)) {
  679. RangeBlocks = CLEAN_RANGE / BlockSize;
  680. WriteBlock(DiskHandle, zbuf, 0, CLEAN_RANGE);
  681. EndRange = DiskSize - RangeBlocks;
  682. if (CleanAll) {
  683. for (i=RangeBlocks; i < DiskSize; i += RangeBlocks) {
  684. WriteBlock(DiskHandle, zbuf, i, CLEAN_RANGE);
  685. }
  686. }
  687. WriteBlock(DiskHandle, zbuf, EndRange, CLEAN_RANGE);
  688. } else {
  689. //
  690. // Kind of a small disk, clean it all always
  691. //
  692. for (i = 0; i < DiskSize; i++) {
  693. WriteBlock(DiskHandle, zbuf, i, BlockSize);
  694. }
  695. }
  696. FlushBlock(DiskHandle);
  697. DoFree(zbuf);
  698. return FALSE;
  699. }
  700. BOOLEAN
  701. CmdNew(
  702. CHAR16 **Token
  703. )
  704. /*
  705. CmdNew [mbr | [gpt=numentry]
  706. Changes a RAW disk into either an MBR (well, somebody) or GPT disk
  707. "new mbr" - you want an mbr disk (not implemented)
  708. "new gpt" - you want a gpt disk, you get a default table
  709. "new gpt=xyz" - you want a gpt disk, with at least xyz entries
  710. (you will get less than xyz if exceeds sanity threshold)
  711. anything else - try again with right syntax
  712. */
  713. {
  714. EFI_HANDLE DiskHandle;
  715. PGPT_HEADER Header;
  716. PGPT_TABLE Table;
  717. PLBA_BLOCK LbaBlock;
  718. UINTN DiskType;
  719. UINTN GptOptSize;
  720. if (SelectedDisk == -1) {
  721. Print(MSG_INSPECT01);
  722. return FALSE;
  723. }
  724. DiskHandle = DiskHandleList[SelectedDisk];
  725. status = ReadGPT(DiskHandle, &Header, &Table, &LbaBlock, &DiskType);
  726. if (EFI_ERROR(status)) {
  727. return FALSE;
  728. }
  729. if (DiskType != DISK_RAW) {
  730. Print(MSG_NEW01, SelectedDisk);
  731. Print(MSG_NEW02);
  732. return FALSE;
  733. }
  734. //
  735. // OK, it's a raw disk...
  736. //
  737. GptOptSize = 0;
  738. if (Token[1]) {
  739. if (StrCmp(Token[1], STR_GPT) == 0) {
  740. if (Token[2]) {
  741. GptOptSize = Atoi(Token[2]);
  742. }
  743. CreateGPT(DiskHandle, GptOptSize);
  744. } else if (StrCmp(Token[1], STR_MBR) == 0) {
  745. CmdNewMBR(Token);
  746. }
  747. } else {
  748. Print(MSG_NEW03);
  749. }
  750. return FALSE;
  751. }
  752. BOOLEAN
  753. CmdFix(
  754. CHAR16 **Token
  755. )
  756. /*
  757. CmdFix - very basic tool to try to fix up GPT disks.
  758. Basic strategy is to read the GPT, if it seems to be a
  759. GPT disk (not MBR, RAW, or totally dead) then call
  760. WriteGPT, which will write both GPTs (and thus sync them)
  761. and rebuild the shadow MBR, all as a matter of course.
  762. */
  763. {
  764. EFI_HANDLE DiskHandle;
  765. PGPT_HEADER Header = NULL;
  766. PGPT_TABLE Table = NULL;
  767. PLBA_BLOCK LbaBlock = NULL;
  768. UINTN DiskType;
  769. //
  770. // Setup parameters and error handling
  771. //
  772. if (SelectedDisk == -1) {
  773. Print(MSG_INSPECT01);
  774. return FALSE;
  775. }
  776. if ( (Token[1]) &&
  777. (StrCmp(Token[1], STR_HELP) == 0) )
  778. {
  779. PrintHelp(FixHelpText);
  780. return FALSE;
  781. }
  782. DiskHandle = DiskHandleList[SelectedDisk];
  783. status = ReadGPT(DiskHandle, &Header, &Table, &LbaBlock, &DiskType);
  784. if (EFI_ERROR(status)) {
  785. Print(MSG_FIX05);
  786. return FALSE;
  787. }
  788. //
  789. // From this point on, must exit this Procedure with a goto Exit
  790. // to free up allocated stuff, otherwise we leak pool...
  791. //
  792. if (DiskType == DISK_RAW) {
  793. Print(MSG_FIX01);
  794. goto Exit;
  795. }
  796. if (DiskType == DISK_MBR) {
  797. Print(MSG_FIX02);
  798. goto Exit;
  799. }
  800. if ((DiskType != DISK_GPT) &&
  801. (DiskType != DISK_GPT_UPD)) {
  802. if (DebugLevel >= DEBUG_ERRPRINT) {
  803. Print(L"DiskType = %d\n", DiskType);
  804. }
  805. Print(MSG_FIX03);
  806. goto Exit;
  807. }
  808. status = WriteGPT(DiskHandle, Header, Table, LbaBlock);
  809. if (EFI_ERROR(status)) {
  810. Print(MSG_FIX04);
  811. }
  812. Exit:
  813. DoFree(Header);
  814. DoFree(Table);
  815. DoFree(LbaBlock);
  816. return FALSE;
  817. }
  818. //
  819. // ----- Create and sub procs thereof
  820. //
  821. BOOLEAN
  822. CmdCreate(
  823. CHAR16 **Token
  824. )
  825. /*
  826. CmdCreate - Create a new partition
  827. (Actually, this routine is a GPT only partition creator)
  828. create name="name string" size=sss type=name typeguid=<guid> attributes=hex
  829. name is label string
  830. offset is in megabytes, or start at the end of the last partition if absent
  831. size is in megabytes, or "fill the disk" if 0 or absent or > free space
  832. type is any named symbol type (symbols gives list)
  833. typeguid is an arbitrary type guid
  834. attributes is hex 32bit flag
  835. if "help" is first arg, print better help data
  836. name, type or typeguid, required
  837. if all that parses out OK, read the gpt, edit it, write it back,
  838. and voila, we have a new partition.
  839. */
  840. {
  841. EFI_HANDLE DiskHandle;
  842. PGPT_HEADER Header = NULL;
  843. PGPT_TABLE Table = NULL;
  844. PLBA_BLOCK LbaBlock = NULL;
  845. UINTN DiskType;
  846. UINT64 SizeInMegaBytes = 0;
  847. UINT64 OffsetInBlocks = 0;
  848. UINT64 StartBlock;
  849. UINT64 EndBlock;
  850. UINT64 SizeInBytes = 0;
  851. UINT64 Attributes = 0;
  852. UINTN i;
  853. UINTN j;
  854. EFI_GUID *TypeGuid = NULL;
  855. EFI_GUID GuidBody;
  856. EFI_GUID PartitionIdGuid;
  857. CHAR16 *TypeName = NULL;
  858. CHAR16 PartName[PART_NAME_LEN+1]; // 36 allowed by spec plus NUL we need
  859. CHAR16 Buffer[10];
  860. BOOLEAN Verbose = FALSE;
  861. UINT32 BlockSize;
  862. UINT64 DiskSizeBlocks;
  863. UINT8 *p;
  864. BOOLEAN OffsetSpecified = FALSE;
  865. BOOLEAN AllZeros;
  866. INTN AllZeroEntry;
  867. INTN OldFreeEntry;
  868. UINT64 AvailBlocks;
  869. UINT64 BlocksToAllocate;
  870. UINT64 HighSeen;
  871. UINTN Slot;
  872. //
  873. // Setup parameters and error handling
  874. //
  875. if (SelectedDisk == -1) {
  876. Print(MSG_INSPECT01);
  877. return FALSE;
  878. }
  879. if (Token[1] == NULL) {
  880. PrintHelp(CreateHelpText);
  881. return FALSE;
  882. }
  883. if ( (Token[1]) &&
  884. (StrCmp(Token[1], STR_HELP) == 0) )
  885. {
  886. PrintHelp(CreateHelpText);
  887. return FALSE;
  888. }
  889. DiskHandle = DiskHandleList[SelectedDisk];
  890. status = ReadGPT(DiskHandle, &Header, &Table, &LbaBlock, &DiskType);
  891. if (EFI_ERROR(status)) {
  892. return FALSE;
  893. }
  894. BlockSize = GetBlockSize(DiskHandle);
  895. DiskSizeBlocks = GetDiskSize(DiskHandle);
  896. //
  897. // From this point on, must exit this Procedure with a goto Exit
  898. // to free up allocated stuff, otherwise we leak pool...
  899. //
  900. if (DiskType == DISK_RAW) {
  901. Print(MSG_CREATE01, SelectedDisk);
  902. goto Exit;
  903. }
  904. if (DiskType == DISK_MBR) {
  905. CmdCreateMBR(Token);
  906. goto Exit;
  907. }
  908. if (DiskType != DISK_GPT) {
  909. if (DebugLevel >= DEBUG_ERRPRINT) {
  910. Print(L"DiskType = %d\n", DiskType);
  911. }
  912. Print(MSG_CREATE02);
  913. goto Exit;
  914. }
  915. //
  916. // Parse arguments...
  917. //
  918. for (i = 1; Token[i]; i++) {
  919. if (StrCmp(Token[i], STR_NAME) == 0) {
  920. ZeroMem(PartName, (PART_NAME_LEN+1)*sizeof(CHAR16));
  921. StrCpy(PartName, Token[i+1]);
  922. i++;
  923. } else if (StrCmp(Token[i], STR_TYPE) == 0) {
  924. if (Token[i+1] == NULL) {
  925. PrintHelp(CreateHelpText);
  926. goto Exit;
  927. }
  928. for (j = 0; SymbolList[j].SymName != NULL; j++) {
  929. if (StrCmp(SymbolList[j].SymName, Token[i+1]) == 0) {
  930. TypeGuid = SymbolList[j].Value;
  931. TypeName = SymbolList[j].SymName;
  932. break;
  933. }
  934. }
  935. if (TypeGuid == NULL) {
  936. Print(MSG_CREATE03);
  937. goto Exit;
  938. }
  939. i++;
  940. } else if (StrCmp(Token[i], STR_TYPEGUID) == 0) {
  941. if (Token[i+1] == NULL) {
  942. PrintHelp(CreateHelpText);
  943. goto Exit;
  944. }
  945. status = GetGuidFromString(Token[i+1], &GuidBody);
  946. if (EFI_ERROR(status)) {
  947. PrintHelp(CreateHelpText);
  948. goto Exit;
  949. }
  950. TypeGuid = &GuidBody;
  951. i++;
  952. } else if (StrCmp(Token[i], STR_OFFSET) == 0) {
  953. if (Token[i+1] == NULL) {
  954. PrintHelp(CreateHelpText);
  955. goto Exit;
  956. }
  957. OffsetInBlocks = Xtoi64(Token[i+1]);
  958. OffsetSpecified = TRUE;
  959. i++;
  960. } else if (StrCmp(Token[i], STR_SIZE) == 0) {
  961. if (Token[i+1] == NULL) {
  962. PrintHelp(CreateHelpText);
  963. goto Exit;
  964. }
  965. SizeInMegaBytes = Atoi64(Token[i+1]);
  966. i++;
  967. } else if (StrCmp(Token[i], STR_ATTR) == 0) {
  968. if (Token[i+1] == NULL) {
  969. PrintHelp(CreateHelpText);
  970. goto Exit;
  971. }
  972. Attributes = Xtoi64(Token[i+1]);
  973. i++;
  974. } else if (StrCmp(Token[i], STR_VER) == 0) {
  975. Verbose = TRUE;
  976. // do NOT increment i, we only consumed 1 Token
  977. } else {
  978. Print(L"\n??? % ???\n", Token[i]);
  979. PrintHelp(CreateHelpText);
  980. goto Exit;
  981. }
  982. }
  983. if ( (PartName == NULL) ||
  984. (TypeGuid == NULL) )
  985. {
  986. PrintHelp(CreateHelpText);
  987. goto Exit;
  988. }
  989. if ( (DebugLevel >= DEBUG_ARGPRINT) ||
  990. (Verbose) )
  991. {
  992. Print(L"CmdCreate arguments:\n");
  993. Print(L"SelectedDisk = %d\n", SelectedDisk);
  994. Print(L"Name=%s\n", PartName);
  995. Print(L"TypeGuid = ");
  996. PrintGuidString(TypeGuid);
  997. Print(L"\n");
  998. if (TypeName) {
  999. Print(L"TypeName = %s\n", TypeName);
  1000. }
  1001. Print(L"Requested OffsetInBlocks = %lx\n", OffsetInBlocks);
  1002. Print(L"Requested SizeInMegaBytes = %ld\n", SizeInMegaBytes);
  1003. Print(L"Attributes = %lx\n", Attributes);
  1004. }
  1005. if (DebugLevel >= DEBUG_OPPROMPT) {
  1006. Input(L"\nCreate = Enter to Continue\n", Buffer, 10);
  1007. }
  1008. //
  1009. // If Requested size is 0, or greater than size remaining,
  1010. // we want to fill the disk.
  1011. // Otherwise, use enough blocks to provide at *least* the
  1012. // required storage. (Not likely to be a problem...)
  1013. //
  1014. //
  1015. // First, scan the Table and decide where the first unallocated
  1016. // space is. Note that for this procedure's primitive space allocation,
  1017. // holes between the beginning of the first allocated partition and
  1018. // the last allocated partition are ignored.
  1019. //
  1020. AllZeroEntry = -1;
  1021. OldFreeEntry = -1;
  1022. HighSeen = Header->FirstUsableLBA - 1;
  1023. if (OffsetSpecified) {
  1024. //
  1025. // if offset is specified, compute the start and end blocks
  1026. //
  1027. StartBlock = OffsetInBlocks;
  1028. if (StartBlock < Header->FirstUsableLBA ||
  1029. StartBlock > Header->LastUsableLBA) {
  1030. //
  1031. // Offset specified is too large
  1032. //
  1033. status = EFI_INVALID_PARAMETER;
  1034. Print(MSG_CREATE08);
  1035. goto Exit;
  1036. }
  1037. SizeInBytes = MultU64x32(SizeInMegaBytes, (1024*1024));
  1038. if (SizeInBytes < SizeInMegaBytes || SizeInBytes == 0) {
  1039. //
  1040. // If size is not specified or too large,
  1041. // try to make the partition as big as it can be
  1042. //
  1043. BlocksToAllocate = EndBlock = SizeInBytes = 0xffffffffffffffff;
  1044. } else {
  1045. BlocksToAllocate = DivU64x32(SizeInBytes, BlockSize, NULL);
  1046. EndBlock = StartBlock + BlocksToAllocate - 1;
  1047. if (EndBlock > Header->LastUsableLBA) {
  1048. EndBlock = Header->LastUsableLBA;
  1049. BlocksToAllocate = EndBlock - StartBlock + 1;
  1050. }
  1051. }
  1052. }
  1053. for (i = 0; i < Header->EntriesAllocated; i++) {
  1054. if (CompareMem(
  1055. &(Table->Entry[i].PartitionType),
  1056. &GuidNull,
  1057. sizeof(EFI_GUID)
  1058. ) != 0)
  1059. {
  1060. //
  1061. // Type not null, so it's allocated
  1062. //
  1063. if (Table->Entry[i].EndingLBA > HighSeen) {
  1064. HighSeen = Table->Entry[i].EndingLBA;
  1065. }
  1066. if (OffsetSpecified) {
  1067. //
  1068. // make sure new partition does not overlap with existing partitions
  1069. //
  1070. if (Table->Entry[i].StartingLBA <= StartBlock &&
  1071. StartBlock <= Table->Entry[i].EndingLBA) {
  1072. //
  1073. // starting block is inside an existing partition
  1074. //
  1075. status = EFI_INVALID_PARAMETER;
  1076. Print(MSG_CREATE08);
  1077. goto Exit;
  1078. }
  1079. if ((Table->Entry[i].StartingLBA <= EndBlock &&
  1080. EndBlock <= Table->Entry[i].EndingLBA) ||
  1081. (StartBlock <= Table->Entry[i].StartingLBA &&
  1082. Table->Entry[i].StartingLBA <= EndBlock) ||
  1083. (StartBlock <= Table->Entry[i].EndingLBA &&
  1084. Table->Entry[i].EndingLBA <= EndBlock)) {
  1085. //
  1086. // new partition overlaps with an existing partition
  1087. // readjust new partition size to avoid overlapping
  1088. //
  1089. EndBlock = Table->Entry[i].StartingLBA-1;
  1090. if (EndBlock < StartBlock) {
  1091. status = EFI_INVALID_PARAMETER;
  1092. Print(MSG_CREATE08);
  1093. goto Exit;
  1094. } else {
  1095. BlocksToAllocate = EndBlock - StartBlock + 1;
  1096. }
  1097. }
  1098. }
  1099. } else {
  1100. p = (UINT8 *)(&(Table->Entry[i]));
  1101. AllZeros = TRUE;
  1102. for (j = 0; j < sizeof(GPT_ENTRY); j++) {
  1103. if (p[j] != 0) {
  1104. AllZeros = FALSE;
  1105. }
  1106. }
  1107. if (AllZeros) {
  1108. if (AllZeroEntry == -1) {
  1109. AllZeroEntry = i;
  1110. }
  1111. } else if (OldFreeEntry == -1) {
  1112. OldFreeEntry = i;
  1113. }
  1114. }
  1115. }
  1116. //
  1117. // AllZeroEntry - if not -1, is pointer to a never before used entry (free)
  1118. // OldFreeEntry - if not -1, is pointer to some pre-used free entry
  1119. //
  1120. if ( (AllZeroEntry == -1) && (OldFreeEntry == -1) ) {
  1121. //
  1122. // TABLE IS FULL!!
  1123. //
  1124. status = EFI_OUT_OF_RESOURCES;
  1125. Print(MSG_CREATE04);
  1126. goto Exit;
  1127. }
  1128. if (OffsetSpecified) {
  1129. //
  1130. // the user haven't specified the new partition size and we haven't
  1131. // run into any partition that will limit the size of this new partition.
  1132. // So, use the max it can
  1133. //
  1134. if (BlocksToAllocate == -1) {
  1135. EndBlock = Header->LastUsableLBA;
  1136. BlocksToAllocate = EndBlock - StartBlock + 1;
  1137. }
  1138. } else {
  1139. //
  1140. // [HighSeen+1 ... LastUsableLBA] is available...
  1141. // avail = (LastUsableLBA - (HighSeen+1)) + 1 => LastUsabbleLBA - HighSeen
  1142. //
  1143. AvailBlocks = Header->LastUsableLBA - HighSeen;
  1144. if (AvailBlocks == 0) {
  1145. status = EFI_OUT_OF_RESOURCES;
  1146. Print(MSG_CREATE07);
  1147. goto Exit;
  1148. }
  1149. SizeInBytes = MultU64x32(SizeInMegaBytes, (1024*1024));
  1150. if (SizeInBytes < SizeInMegaBytes) {
  1151. //
  1152. // overflow, force a very big answer
  1153. //
  1154. SizeInBytes = 0xffffffffffffffff;
  1155. }
  1156. if ((SizeInBytes == 0) ||
  1157. (SizeInBytes > (MultU64x32(AvailBlocks, BlockSize)) ) )
  1158. {
  1159. //
  1160. // User asked for zero, or for more than we've got,
  1161. // so give them all that is left
  1162. //
  1163. BlocksToAllocate = AvailBlocks;
  1164. } else {
  1165. //
  1166. // We would have to have a BlockSize > 1mb for Remainder to
  1167. // not be 0. Since we cannot actually test this case, we
  1168. // ingore it...
  1169. //
  1170. BlocksToAllocate = DivU64x32(SizeInBytes, BlockSize, NULL);
  1171. }
  1172. }
  1173. //
  1174. // We have a name
  1175. // We have a type guid
  1176. // We have a size in blocks
  1177. // We have an attribute mask
  1178. //
  1179. if (BlocksToAllocate < ((1024*1024)/BlockSize)) {
  1180. status = EFI_OUT_OF_RESOURCES;
  1181. Print(MSG_CREATE09);
  1182. goto Exit;
  1183. }
  1184. if ( (Verbose) ||
  1185. (DebugLevel > DEBUG_ARGPRINT) )
  1186. {
  1187. Print(L"Requested SizeInMegaBytes = %ld\n", SizeInMegaBytes);
  1188. Print(L"Resulting size in Blocks = %ld\n", BlocksToAllocate);
  1189. Print(L"Results size in Bytes = %ld\n", MultU64x32(BlocksToAllocate, BlockSize));
  1190. }
  1191. if (AllZeroEntry != -1) {
  1192. Slot = AllZeroEntry;
  1193. } else {
  1194. Slot = OldFreeEntry;
  1195. }
  1196. PartitionIdGuid = GetGUID();
  1197. CopyMem(&(Table->Entry[Slot].PartitionType), TypeGuid, sizeof(EFI_GUID));
  1198. CopyMem(&(Table->Entry[Slot].PartitionID), &PartitionIdGuid, sizeof(EFI_GUID));
  1199. if (OffsetSpecified) {
  1200. Table->Entry[Slot].StartingLBA = StartBlock;
  1201. Table->Entry[Slot].EndingLBA = EndBlock;
  1202. } else {
  1203. Table->Entry[Slot].StartingLBA = HighSeen + 1;
  1204. Table->Entry[Slot].EndingLBA = HighSeen + BlocksToAllocate;
  1205. }
  1206. if (! ( ((Table->Entry[Slot].EndingLBA - Table->Entry[Slot].StartingLBA) + 1) == BlocksToAllocate) ) {
  1207. TerribleError(L"Wrong Size for new partiton in CmdCreate\n");
  1208. }
  1209. if ( (Table->Entry[Slot].StartingLBA < Header->FirstUsableLBA) ||
  1210. (Table->Entry[Slot].EndingLBA > Header->LastUsableLBA) )
  1211. {
  1212. TerribleError(L"New Partition out of bounds in CmdCreate\n");
  1213. }
  1214. Table->Entry[Slot].Attributes = Attributes;
  1215. CopyMem(&(Table->Entry[Slot].PartitionName[0]), PartName, PART_NAME_LEN*sizeof(CHAR16));
  1216. status = WriteGPT(DiskHandle, Header, Table, LbaBlock);
  1217. if (EFI_ERROR(status)) {
  1218. Print(MSG_CREATE05);
  1219. }
  1220. Exit:
  1221. DoFree(Header);
  1222. DoFree(Table);
  1223. DoFree(LbaBlock);
  1224. return FALSE;
  1225. }
  1226. //
  1227. // -----
  1228. //
  1229. BOOLEAN
  1230. CmdDelete(
  1231. CHAR16 **Token
  1232. )
  1233. /*
  1234. CmdDelete - deletes a partition from the currently selected disk
  1235. */
  1236. {
  1237. EFI_HANDLE DiskHandle;
  1238. UINTN DiskType = 0;
  1239. PGPT_HEADER Header = NULL;
  1240. PGPT_TABLE Table = NULL;
  1241. PLBA_BLOCK LbaBlock = NULL;
  1242. INTN Victim;
  1243. CHAR16 Answer[COMMAND_LINE_MAX];
  1244. GPT_ENTRY Entry;
  1245. if (SelectedDisk == -1) {
  1246. Print(MSG_INSPECT01);
  1247. return FALSE;
  1248. }
  1249. if (Token[1] == NULL) {
  1250. PrintHelp(DeleteHelpText);
  1251. return FALSE;
  1252. }
  1253. if ( (Token[1]) &&
  1254. (StrCmp(Token[1], STR_HELP) == 0) )
  1255. {
  1256. PrintHelp(DeleteHelpText);
  1257. return FALSE;
  1258. }
  1259. Print(MSG_SELECT02, SelectedDisk);
  1260. DiskHandle = DiskHandleList[SelectedDisk];
  1261. status = ReadGPT(DiskHandle, &Header, &Table, &LbaBlock, &DiskType);
  1262. if (EFI_ERROR(status)) {
  1263. return FALSE;
  1264. }
  1265. if (DiskType == DISK_RAW) {
  1266. Print(MSG_DELETE02);
  1267. goto Exit;
  1268. } else if (DiskType == DISK_MBR) {
  1269. CmdInspectMBR(Token);
  1270. goto Exit;
  1271. } else if (DiskType == DISK_GPT_UPD) {
  1272. Print(MSG_DELETE03);
  1273. goto Exit;
  1274. } else if (DiskType == DISK_GPT_BAD) {
  1275. Print(MSG_DELETE04);
  1276. goto Exit;
  1277. } else if (DiskType != DISK_GPT) {
  1278. TerribleError(L"Bad Disk Type returned to Delete!");
  1279. goto Exit;
  1280. }
  1281. //
  1282. // OK, it's a Good GPT disk, so do the Delete thing for GPT...
  1283. //
  1284. if ( (Token[1] == NULL) ||
  1285. (Token[2] != NULL) )
  1286. {
  1287. PrintHelp(InspectHelpText);
  1288. goto Exit;
  1289. }
  1290. Victim = Atoi(Token[1]);
  1291. if ( (Victim < 0) ||
  1292. ((UINT32)Victim > Header->EntriesAllocated) )
  1293. {
  1294. Print(MSG_DELETE05);
  1295. goto Exit;
  1296. }
  1297. CopyMem(&Entry, &Table->Entry[Victim], sizeof(GPT_ENTRY));
  1298. if (CompareMem(&(Entry.PartitionType), &GuidNull, sizeof(EFI_GUID)) == 0) {
  1299. Print(MSG_DELETE06);
  1300. goto Exit;
  1301. }
  1302. //
  1303. // What you are going to delete, are you sure, are you really sure...
  1304. //
  1305. Print(MSG_DELETE07, Victim);
  1306. PrintGptEntry(&Entry, Victim);
  1307. Print(L"\n\n");
  1308. Print(MSG_DELETE09);
  1309. Print(MSG_DELETE10);
  1310. Input(STR_DELETE_PROMPT, Answer, COMMAND_LINE_MAX);
  1311. Print(L"\n");
  1312. StrUpr(Answer);
  1313. if (StrCmp(Answer, L"Y") != 0) {
  1314. goto Exit;
  1315. }
  1316. Print(MSG_DELETE11);
  1317. Input(STR_DELETE_PROMPT, Answer, COMMAND_LINE_MAX);
  1318. Print(L"\n");
  1319. StrUpr(Answer);
  1320. if (StrCmp(Answer, STR_DELETE_ANS) != 0) {
  1321. goto Exit;
  1322. }
  1323. //
  1324. // If we get here, then...
  1325. // Victim is the number of legal GPT slot
  1326. // Victim refers to a slot which is allocated
  1327. // The user has seen confirmation of which slot that is
  1328. // The user says they realy truly want to delete it
  1329. //
  1330. CopyMem(&(Table->Entry[Victim].PartitionType), &GuidNull, sizeof(EFI_GUID));
  1331. status = WriteGPT(DiskHandle, Header, Table, LbaBlock);
  1332. if (EFI_ERROR(status)) {
  1333. Print(MSG_DELETE08);
  1334. }
  1335. Exit:
  1336. DoFree(Header);
  1337. DoFree(Table);
  1338. DoFree(LbaBlock);
  1339. return FALSE;
  1340. }
  1341. BOOLEAN
  1342. CmdHelp(
  1343. CHAR16 **Token
  1344. )
  1345. {
  1346. UINTN i;
  1347. for (i = 0; CmdTable[i].Name != NULL; i++) {
  1348. Print(L"%s %s\n", CmdTable[i].Name, CmdTable[i].HelpSummary);
  1349. }
  1350. return FALSE;
  1351. }
  1352. BOOLEAN
  1353. CmdExit(
  1354. CHAR16 **Token
  1355. )
  1356. {
  1357. Print(L"%s\n", MSG_EXITING);
  1358. return TRUE;
  1359. }
  1360. BOOLEAN
  1361. CmdSymbols(
  1362. CHAR16 **Token
  1363. )
  1364. /*
  1365. CmdSymbols - print out the GUID symbols compiled into the program
  1366. For predefined symbol (see ...) we print it's friendly name,
  1367. it's text definition, and it's actual value.
  1368. */
  1369. {
  1370. UINTN i;
  1371. EFI_GUID *Guid;
  1372. BOOLEAN Verbose = FALSE;
  1373. if ( (Token[1]) &&
  1374. (StrCmp(Token[1], STR_VER) == 0) )
  1375. {
  1376. Verbose = TRUE;
  1377. }
  1378. for (i = 0; SymbolList[i].SymName != NULL; i++) {
  1379. Guid = SymbolList[i].Value;
  1380. Print(L"%s = %s\n", SymbolList[i].SymName, SymbolList[i].Comment);
  1381. if (Verbose) {
  1382. PrintGuidString(Guid);
  1383. Print(L"\n\n");
  1384. }
  1385. }
  1386. return FALSE;
  1387. }
  1388. BOOLEAN
  1389. CmdRemark(
  1390. CHAR16 **Token
  1391. )
  1392. {
  1393. //
  1394. // The remark command does nothing...
  1395. return FALSE;
  1396. }
  1397. BOOLEAN
  1398. CmdMake(
  1399. CHAR16 **Token
  1400. )
  1401. {
  1402. UINTN i;
  1403. Token++;
  1404. if (Token[0] != NULL) {
  1405. for (i = 0; ScriptTable[i].Name != NULL; i++) {
  1406. if (StrCmp(ScriptTable[i].Name, Token[0]) == 0) {
  1407. return ScriptTable[i].Function(Token);
  1408. }
  1409. }
  1410. }
  1411. //
  1412. // Nothing we know about, so run list
  1413. //
  1414. return ScriptList(Token);
  1415. }
  1416. BOOLEAN
  1417. CmdDebug(
  1418. CHAR16 **Token
  1419. )
  1420. /*
  1421. Debug -
  1422. Without args, shows last status value, and AllocCount
  1423. If an arg, it sets the debug/checkout support level
  1424. 0 = do nothing extra
  1425. 1 = print full computed arguments before starting an operation
  1426. 2 = print full computed arguments and hold for prompt before
  1427. doing a major operation.
  1428. */
  1429. {
  1430. if (Token[1]) {
  1431. DebugLevel = Atoi(Token[1]);
  1432. }
  1433. Print(L"status = %x %r\n", status, status);
  1434. Print(L"AllocCount = %d\n", AllocCount);
  1435. Print(L"DebugLevel = %d\n", DebugLevel);
  1436. return FALSE;
  1437. }
  1438. //
  1439. // ----- SubUnits to do MBR operations -----
  1440. //
  1441. VOID
  1442. CmdInspectMBR(
  1443. CHAR16 **Token
  1444. )
  1445. /*
  1446. CmdInspectMBR - dumps the partition data for an MBR disk
  1447. */
  1448. {
  1449. Print(MSG_INSPECT05);
  1450. return;
  1451. }
  1452. VOID
  1453. CmdCreateMBR(
  1454. CHAR16 **Token
  1455. )
  1456. /*
  1457. CmdCreateMBR - creates an MBR parititon
  1458. */
  1459. {
  1460. Print(MSG_CREATE06);
  1461. return;
  1462. }
  1463. VOID
  1464. CmdNewMBR(
  1465. CHAR16 **Token
  1466. )
  1467. /*
  1468. CmdCreateMBR - creates an MBR parititon
  1469. */
  1470. {
  1471. Print(MSG_NEW04);
  1472. return;
  1473. }
  1474. VOID
  1475. CmdDeleteMBR(
  1476. CHAR16 **Token
  1477. )
  1478. /*
  1479. CmdDeleteMBR - deletes an MBR parititon
  1480. */
  1481. {
  1482. Print(MSG_DELETE01);
  1483. return;
  1484. }
  1485. //
  1486. // ----- Various Support Routines -----
  1487. //
  1488. VOID
  1489. PrintGuidString(
  1490. EFI_GUID *Guid
  1491. )
  1492. {
  1493. CHAR16 Buffer[40];
  1494. SPrint(Buffer, 40, L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
  1495. Guid->Data1,
  1496. Guid->Data2,
  1497. Guid->Data3,
  1498. Guid->Data4[0],
  1499. Guid->Data4[1],
  1500. Guid->Data4[2],
  1501. Guid->Data4[3],
  1502. Guid->Data4[4],
  1503. Guid->Data4[5],
  1504. Guid->Data4[6],
  1505. Guid->Data4[7]
  1506. );
  1507. Print(L"%s", Buffer);
  1508. return;
  1509. }
  1510. EFI_STATUS
  1511. GetGuidFromString(
  1512. CHAR16 *String,
  1513. EFI_GUID *Guid
  1514. )
  1515. /*
  1516. GetGuidFromString
  1517. This routine scans the string looking for 32 hex digits. Each
  1518. such digits is shifted into the Guid. Non hex digits are skipped.
  1519. This means the guid MUST begin with the first digit, not with a filler
  1520. 0 or 0x or the like. However, because non hex digits are skipped,
  1521. any set of dashes, dots, etc. may be used as punctuation.
  1522. So:
  1523. 01234567-abcd-ef01-12-34-56-78-9a-bc-de-f0
  1524. &
  1525. 01.23.45.67-ab.cd.ef.01-12.34.56.78-9a.bc.de.f0
  1526. Will create the same Guid value.
  1527. */
  1528. {
  1529. EFI_GUID TempGuid;
  1530. INTN x;
  1531. UINTN i;
  1532. UINTN j;
  1533. //
  1534. // scan until we have the right number of hex digits for each part
  1535. // of the guid structure, skipping over non hex digits
  1536. //
  1537. ZeroMem((CHAR16 *)&TempGuid, sizeof(EFI_GUID));
  1538. //
  1539. // 1st uint32
  1540. //
  1541. for (i = 0; i < 8; String++) {
  1542. if (*String == NUL) {
  1543. status = EFI_INVALID_PARAMETER;
  1544. return status;
  1545. }
  1546. x = HexChar(*String);
  1547. if (x != -1) {
  1548. TempGuid.Data1 = (UINT32)((TempGuid.Data1 * 16) + x);
  1549. i++;
  1550. }
  1551. }
  1552. //
  1553. // 2nd unit - uint16
  1554. //
  1555. for (i = 0; i < 4; String++) {
  1556. if (*String == NUL) {
  1557. status = EFI_INVALID_PARAMETER;
  1558. return status;
  1559. }
  1560. x = HexChar(*String);
  1561. if (x != -1) {
  1562. TempGuid.Data2 = (TempGuid.Data2 * 16) + (UINT16)x;
  1563. i++;
  1564. }
  1565. }
  1566. //
  1567. // 3nd unit - uint16
  1568. //
  1569. for (i = 0; i < 4; String++) {
  1570. if (*String == NUL) {
  1571. status = EFI_INVALID_PARAMETER;
  1572. return status;
  1573. }
  1574. x = HexChar(*String);
  1575. if (x != -1) {
  1576. TempGuid.Data3 = (TempGuid.Data3 * 16) + (UINT16)x;
  1577. i++;
  1578. }
  1579. }
  1580. //
  1581. // 4th unit - 8 uint8s
  1582. //
  1583. for (j = 0; j < 8; j++) {
  1584. for (i = 0; i < 2; String++) {
  1585. if (*String == NUL) {
  1586. status = EFI_INVALID_PARAMETER;
  1587. return status;
  1588. }
  1589. x = HexChar(*String);
  1590. if (x != -1) {
  1591. TempGuid.Data4[j] = (TempGuid.Data4[j] * 16) + (UINT8)x;
  1592. i++;
  1593. }
  1594. }
  1595. }
  1596. CopyMem(Guid, &TempGuid, sizeof(EFI_GUID));
  1597. return status = EFI_SUCCESS;
  1598. }
  1599. INTN
  1600. HexChar(
  1601. CHAR16 Ch
  1602. )
  1603. /*
  1604. HexChar just finds the offset of Ch in the string "0123456789ABCDEF",
  1605. which in effect converts a hex digit to a number.
  1606. (a one char at a time xtoi)
  1607. If Ch isn't a hex digit, -1 is returned.
  1608. */
  1609. {
  1610. UINTN i;
  1611. CHAR16 *String = L"0123456789ABCDEF";
  1612. for (i = 0; String[i] != NUL; i++) {
  1613. if (Ch == String[i]) {
  1614. return i;
  1615. }
  1616. }
  1617. return -1;
  1618. }
  1619. UINT64
  1620. Xtoi64(
  1621. CHAR16 *String
  1622. )
  1623. /*
  1624. Xtoi64 is NOT fully xtoi compatible, it requires that the hex
  1625. number start at the first character and stops at first non hex char
  1626. Always returns a 64bit value
  1627. */
  1628. {
  1629. UINT64 BigHex;
  1630. INT32 x;
  1631. BigHex = 0;
  1632. x = (INT32)HexChar(*String);
  1633. while (x != -1) {
  1634. BigHex = MultU64x32(BigHex, 16) + x;
  1635. String++;
  1636. x = (INT32)HexChar(*String);
  1637. }
  1638. return BigHex;
  1639. }
  1640. UINT64
  1641. Atoi64(
  1642. CHAR16 *String
  1643. )
  1644. /*
  1645. Atoi64 is NOT fully atoi compatible, it requires that the number
  1646. start at the first character and stops at first non number char
  1647. Always returns a 64bit value
  1648. */
  1649. {
  1650. UINT64 BigNum;
  1651. INT32 x;
  1652. BigNum = 0;
  1653. x = (INT32)HexChar(*String);
  1654. while ( (x >= 0) && (x <= 9) ) {
  1655. BigNum = MultU64x32(BigNum, 10);
  1656. BigNum = BigNum + x;
  1657. String++;
  1658. x = (INT32)HexChar(*String);
  1659. }
  1660. return BigNum;
  1661. }
  1662. BOOLEAN
  1663. IsIn(
  1664. CHAR16 What,
  1665. CHAR16 *InWhat
  1666. )
  1667. /*
  1668. IsIn - return TRUE if What is found in InWhat, else FALSE;
  1669. */
  1670. {
  1671. UINTN i;
  1672. for (i = 0; InWhat[i] != NUL; i++) {
  1673. if (InWhat[i] == What) {
  1674. return TRUE;
  1675. }
  1676. }
  1677. return FALSE;
  1678. }
  1679. VOID
  1680. PrintHelp(
  1681. CHAR16 *HelpText[]
  1682. )
  1683. {
  1684. UINTN i;
  1685. for (i = 0; HelpText[i] != NULL; i++) {
  1686. Print(HelpText[i]);
  1687. }
  1688. return;
  1689. }
  1690. VOID
  1691. TerribleError(
  1692. CHAR16 *String
  1693. )
  1694. {
  1695. CHAR16 *Buffer;
  1696. Buffer = AllocatePool(512);
  1697. SPrint(Buffer, 512, L"Terrible Error = %s status=%x %r\nProgram terminated.\n", String, status, status);
  1698. Print(Buffer);
  1699. BS->Exit(SavedImageHandle, EFI_VOLUME_CORRUPTED, StrLen(Buffer), Buffer);
  1700. }