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.

837 lines
18 KiB

  1. /*++
  2. Copyright (c) 1998 Intel Corporation
  3. Module Name:
  4. bcfg.c
  5. Abstract:
  6. Shell app "bcfg"
  7. Boot time driver config
  8. Revision History
  9. --*/
  10. #include "shell.h"
  11. #define MAX_ENV_SIZE 1024
  12. #define BCFG_NONE 0
  13. #define BCFG_DUMP 1
  14. #define BCFG_MOVE 2
  15. #define BCFG_REMOVE 3
  16. #define BCFG_ADD 4
  17. #define BCFG_USAGE 5
  18. typedef struct {
  19. UINT32 Attributes;
  20. CHAR16 *Description;
  21. EFI_DEVICE_PATH *FilePath;
  22. VOID *LoadOptions;
  23. UINTN LoadOptionsSize;
  24. CHAR16 *FilePathStr;
  25. } BCFG_LOAD_OPTION;
  26. /*
  27. *
  28. */
  29. EFI_STATUS
  30. InitializeBCfg (
  31. IN EFI_HANDLE ImageHandle,
  32. IN EFI_SYSTEM_TABLE *SystemTable
  33. );
  34. VOID
  35. DumpFileInfo (
  36. IN SHELL_FILE_ARG *Arg
  37. );
  38. VOID
  39. BCfgDumpBootList (
  40. IN CHAR16 *BootOrder,
  41. IN CHAR16 *BootOption
  42. );
  43. BCFG_LOAD_OPTION *
  44. BCfgParseLoadOption (
  45. UINT8 *Data,
  46. UINTN DataSize
  47. );
  48. VOID
  49. BCfgFreeLoadOption (
  50. BCFG_LOAD_OPTION *Option
  51. );
  52. VOID
  53. BCfgSetOperation (
  54. UINTN *OldOper,
  55. UINTN NewOper
  56. );
  57. VOID
  58. BCfgUsage (
  59. VOID
  60. );
  61. VOID
  62. BCfgRemove (
  63. IN UINTN Position
  64. );
  65. VOID
  66. BCfgMove (
  67. IN UINTN Src,
  68. IN UINTN Dest
  69. );
  70. VOID
  71. BCfgAdd (
  72. IN UINTN Position,
  73. IN CHAR16 *File,
  74. IN CHAR16 *Desc
  75. );
  76. /*
  77. *
  78. */
  79. BOOLEAN BCfgVerbose = FALSE;
  80. /*
  81. * Selected list
  82. */
  83. CHAR16 *BCfgSelOrder;
  84. CHAR16 *BCfgSelOption;
  85. CHAR16 *BCfgSelName;
  86. UINT32 BCfgAttributes;
  87. /*
  88. * Scratch memory
  89. */
  90. UINTN BCfgOrderCount;
  91. UINT16 *BCfgOrder;
  92. UINT8 *BCfgData;
  93. /*
  94. *
  95. */
  96. EFI_DRIVER_ENTRY_POINT(InitializeBCfg)
  97. EFI_STATUS
  98. InitializeBCfg (
  99. IN EFI_HANDLE ImageHandle,
  100. IN EFI_SYSTEM_TABLE *SystemTable
  101. )
  102. {
  103. CHAR16 **Argv;
  104. UINTN Argc;
  105. EFI_STATUS Status;
  106. UINTN Index, BufferSize;
  107. UINTN No1, No2;
  108. CHAR16 *p, *File, *Desc;
  109. UINTN Oper;
  110. /*
  111. * Check to see if the app is to install as a "internal command"
  112. * to the shell
  113. */
  114. InstallInternalShellCommand (
  115. ImageHandle, SystemTable, InitializeBCfg,
  116. L"bcfg", /* command */
  117. L"bcfg -?", /* command syntax */
  118. L"Configures boot driver & load options", /* 1 line descriptor */
  119. NULL /* command help page */
  120. );
  121. /*
  122. * We are not being installed as an internal command driver, initialize
  123. * as an nshell app and run
  124. */
  125. InitializeShellApplication (ImageHandle, SystemTable);
  126. Argv = SI->Argv;
  127. Argc = SI->Argc;
  128. BCfgVerbose = FALSE;
  129. BCfgSelName = NULL;
  130. BCfgSelOrder = NULL;
  131. BCfgOrderCount = 0;
  132. No1 = 0;
  133. No2 = 0;
  134. File = NULL;
  135. Desc = NULL;
  136. BCfgOrder = AllocatePool(MAX_ENV_SIZE + 32);
  137. BCfgData = AllocatePool(MAX_ENV_SIZE + 32);
  138. /*
  139. * Scan args for flags
  140. */
  141. Oper = BCFG_NONE;
  142. for (Index = 1; Index < Argc; Index += 1) {
  143. p = Argv[Index];
  144. if (StrCmp(p, L"?") == 0) {
  145. BCfgSetOperation (&Oper, BCFG_USAGE);
  146. } else if (StrCmp(p, L"driver") == 0) {
  147. BCfgSelOrder = VarDriverOrder;
  148. BCfgSelOption = VarDriverOption;
  149. BCfgSelName = L"boot driver";
  150. } else if (StrCmp(p, L"boot") == 0) {
  151. BCfgSelOrder = VarBootOrder;
  152. BCfgSelOption = VarBootOption;
  153. BCfgSelName = L"boot option";
  154. } else if (StrCmp(p, L"dump") == 0) {
  155. BCfgSetOperation (&Oper, BCFG_DUMP);
  156. } else if (StrCmp(p, L"v") == 0) {
  157. BCfgVerbose = TRUE;
  158. } else if (StrCmp(p, L"rm") == 0) {
  159. Index += 1;
  160. if (Index < Argc) {
  161. No1 = Atoi(Argv[Index]);
  162. }
  163. BCfgSetOperation (&Oper, BCFG_REMOVE);
  164. } else if (StrCmp(p, L"mv") == 0) {
  165. Index += 1;
  166. if (Index < Argc) {
  167. No1 = Atoi(Argv[Index]);
  168. }
  169. Index += 1;
  170. if (Index < Argc) {
  171. No2 = Atoi(Argv[Index]);
  172. }
  173. BCfgSetOperation (&Oper, BCFG_MOVE);
  174. } else if (StrCmp(p, L"add") == 0) {
  175. Index += 1;
  176. if (Index < Argc) {
  177. No1 = Atoi(Argv[Index]);
  178. }
  179. Index += 1;
  180. if (Index < Argc) {
  181. File = Argv[Index];
  182. }
  183. Index += 1;
  184. if (Index < Argc) {
  185. Desc = Argv[Index];
  186. }
  187. BCfgSetOperation (&Oper, BCFG_ADD);
  188. } else {
  189. Print (L"bfg: unknown flag '%h'\n", p);
  190. Oper = BCFG_USAGE;
  191. break;
  192. }
  193. }
  194. if (BCfgSelOrder) {
  195. /*
  196. * Read the boot order var
  197. */
  198. BufferSize = MAX_ENV_SIZE;
  199. Status = RT->GetVariable (
  200. BCfgSelOrder,
  201. &EfiGlobalVariable,
  202. &BCfgAttributes,
  203. &BufferSize,
  204. BCfgOrder
  205. );
  206. if (EFI_ERROR(Status)) {
  207. BufferSize = 0;
  208. BCfgAttributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS;
  209. if (BCfgSelOrder == VarBootOrder) {
  210. BCfgAttributes = BCfgAttributes | EFI_VARIABLE_RUNTIME_ACCESS;
  211. }
  212. }
  213. BCfgOrderCount = BufferSize / sizeof(UINT16);
  214. }
  215. if (Oper == BCFG_NONE) {
  216. Oper = BCFG_USAGE;
  217. }
  218. if (Oper != BCFG_USAGE && !BCfgSelName) {
  219. Print (L"bcfg: must supply 'driver' or 'boot'\n");
  220. Oper = BCFG_NONE;
  221. }
  222. switch (Oper) {
  223. case BCFG_NONE:
  224. break;
  225. case BCFG_USAGE:
  226. BCfgUsage();
  227. break;
  228. case BCFG_DUMP:
  229. Print (L"The %s list is:\n", BCfgSelName);
  230. BCfgDumpBootList (BCfgSelOrder, BCfgSelOption);
  231. break;
  232. case BCFG_ADD:
  233. BCfgAdd (No1, File, Desc);
  234. break;
  235. case BCFG_MOVE:
  236. BCfgMove (No1, No2);
  237. break;
  238. case BCFG_REMOVE:
  239. BCfgRemove (No1);
  240. break;
  241. }
  242. /*
  243. * Done
  244. */
  245. if (BCfgOrder) {
  246. FreePool (BCfgOrder);
  247. }
  248. if (BCfgData) {
  249. FreePool (BCfgData);
  250. }
  251. return EFI_SUCCESS;
  252. }
  253. VOID
  254. BCfgSetOperation (
  255. UINTN *OldOper,
  256. UINTN NewOper
  257. )
  258. {
  259. if (*OldOper != BCFG_NONE && *OldOper != BCFG_USAGE) {
  260. Print (L"bcfg: only one operation may be specified at a time\n");
  261. *OldOper = BCFG_USAGE;
  262. }
  263. *OldOper = NewOper;
  264. }
  265. VOID
  266. BCfgUsage (
  267. VOID
  268. )
  269. {
  270. Print (L"bcfg driver|boot [dump [-v]] [add # file \"desc\"] [rm #] [mv # #]\n");
  271. Print (L" driver selects boot driver list\n");
  272. Print (L" boot selects boot option list\n");
  273. Print (L" dump dumps selected list\n");
  274. Print (L" v dumps verbose (includes load options)\n");
  275. Print (L" add add 'file' with 'desc' at position #\n");
  276. Print (L" rm remove #\n");
  277. Print (L" mv move # to #\n");
  278. }
  279. VOID
  280. BCfgAdd (
  281. IN UINTN Position,
  282. IN CHAR16 *File,
  283. IN CHAR16 *Desc
  284. )
  285. {
  286. EFI_STATUS Status;
  287. EFI_DEVICE_PATH *DevicePath, *FilePath, *FileNode;
  288. CHAR16 *Str, *p;
  289. UINT8 *p8;
  290. SHELL_FILE_ARG *Arg;
  291. LIST_ENTRY FileList;
  292. CHAR16 OptionStr[40];
  293. UINTN DescSize, FilePathSize;
  294. BOOLEAN Found;
  295. UINTN Target, Index;
  296. Str = NULL;
  297. FilePath = NULL;
  298. FileNode = NULL;
  299. InitializeListHead (&FileList);
  300. if (Position < 1) {
  301. Position = 1;
  302. }
  303. Position = Position - 1;
  304. if (Position > BCfgOrderCount) {
  305. Position = BCfgOrderCount;
  306. }
  307. if (!File || !Desc) {
  308. Print (L"bcfg: missing parameter for 'add' operation\n");
  309. Print (L"cfg: driver|boot add # file \"desc\"\n");
  310. goto Done;
  311. }
  312. /*
  313. * Get file info
  314. */
  315. ShellFileMetaArg (File, &FileList);
  316. /*
  317. * If filename expadned to multiple names, fail
  318. */
  319. if (FileList.Flink->Flink != &FileList) {
  320. Print (L"bcfg: too many source files\n");
  321. goto Done;
  322. }
  323. Arg = CR(FileList.Flink, SHELL_FILE_ARG, Link, SHELL_FILE_ARG_SIGNATURE);
  324. Status = Arg->Status;
  325. if (EFI_ERROR(Status)) {
  326. Print (L"bcfg: file %hs - %r\n", Arg->FileName, Status);
  327. goto Done;
  328. }
  329. /*
  330. * Build FilePath to the filename
  331. */
  332. /* split full name at device string */
  333. for(p=Arg->FullName; *p && *p != ':'; p++) ;
  334. if (!*p) {
  335. Print (L"bcfg: unsupported file name '%hs'\n", Arg->FullName);
  336. Status = EFI_UNSUPPORTED;
  337. goto Done;
  338. }
  339. /* get the device path */
  340. *p = 0;
  341. DevicePath = (EFI_DEVICE_PATH *) ShellGetMap(Arg->FullName);
  342. if (!DevicePath) {
  343. Print (L"bcfg: no device path for %s\n", Arg->FullName);
  344. Status = EFI_UNSUPPORTED;
  345. goto Done;
  346. }
  347. /* append the file */
  348. FileNode = FileDevicePath(NULL, p+1);
  349. FilePath = AppendDevicePath(DevicePath, FileNode);
  350. /*
  351. * Find a free target # (bugbug: brute force implementation)
  352. */
  353. Found = FALSE;
  354. for (Target=1; Target < 0xFFFF; Target += 1) {
  355. Found = TRUE;
  356. for (Index=0; Index < BCfgOrderCount; Index += 1) {
  357. if (BCfgOrder[Index] == Target) {
  358. Found = FALSE;
  359. break;
  360. }
  361. }
  362. if (Found) {
  363. break;
  364. }
  365. }
  366. if (Target == 0xFFFF) {
  367. Print (L"bcfg: Failed to find available variable name\n");
  368. goto Done;
  369. }
  370. Print (L"Target = %d\n", Target);
  371. /*
  372. * Add the option
  373. */
  374. DescSize = StrSize(Desc);
  375. FilePathSize = DevicePathSize(FilePath);
  376. p8 = BCfgData;
  377. *((UINT32 *) p8) = 0; /* Attributes */
  378. p8 += sizeof (UINT32);
  379. CopyMem (p8, Desc, DescSize);
  380. p8 += DescSize;
  381. CopyMem (p8, FilePath, FilePathSize);
  382. SPrint (OptionStr, sizeof(OptionStr), BCfgSelOption, Target);
  383. Status = RT->SetVariable (
  384. OptionStr,
  385. &EfiGlobalVariable,
  386. BCfgAttributes,
  387. sizeof(UINT32) + DescSize + FilePathSize,
  388. BCfgData
  389. );
  390. if (EFI_ERROR(Status)) {
  391. Print (L"bcfg: failed to add %hs - %hr\n", OptionStr, Status);
  392. goto Done;
  393. }
  394. /*
  395. * Insert target into order list
  396. */
  397. BCfgOrderCount += 1;
  398. for (Index=BCfgOrderCount-1; Index > Position; Index -= 1) {
  399. BCfgOrder[Index] = BCfgOrder[Index-1];
  400. }
  401. BCfgOrder[Position] = (UINT16) Target;
  402. Status = RT->SetVariable (
  403. BCfgSelOrder,
  404. &EfiGlobalVariable,
  405. BCfgAttributes,
  406. BCfgOrderCount * sizeof(UINT16),
  407. BCfgOrder
  408. );
  409. if (EFI_ERROR(Status)) {
  410. Print (L"bcfg: failed to update %hs - %hr\n", BCfgSelOrder, Status);
  411. goto Done;
  412. }
  413. /*
  414. * Done
  415. */
  416. Print (L"bcfg: %s added as %d\n", BCfgSelName, Position+1);
  417. Done:
  418. if (FileNode) {
  419. FreePool (FileNode);
  420. }
  421. if (FilePath) {
  422. FreePool (FilePath);
  423. }
  424. if (Str) {
  425. FreePool(Str);
  426. }
  427. ShellFreeFileList (&FileList);
  428. }
  429. VOID
  430. BCfgRemove (
  431. IN UINTN Position
  432. )
  433. {
  434. CHAR16 OptionStr[40];
  435. EFI_STATUS Status;
  436. UINTN Index;
  437. UINT16 Target;
  438. if (Position < 1 || Position > BCfgOrderCount) {
  439. Print (L"bcfg: %hd not removed. Value is out of range\n", Position);
  440. return ;
  441. }
  442. Target = BCfgOrder[Position-1];
  443. /*
  444. * remove from order list
  445. */
  446. BCfgOrderCount = BCfgOrderCount - 1;
  447. for (Index=Position-1; Index < BCfgOrderCount; Index += 1) {
  448. BCfgOrder[Index] = BCfgOrder[Index+1];
  449. }
  450. Status = RT->SetVariable (
  451. BCfgSelOrder,
  452. &EfiGlobalVariable,
  453. BCfgAttributes,
  454. BCfgOrderCount * sizeof(UINT16),
  455. BCfgOrder
  456. );
  457. /*
  458. * Remove the option
  459. */
  460. SPrint (OptionStr, sizeof(OptionStr), BCfgSelOption, Target);
  461. RT->SetVariable (OptionStr, &EfiGlobalVariable, BCfgAttributes, 0, NULL);
  462. /*
  463. * Done
  464. */
  465. if (EFI_ERROR(Status)) {
  466. Print (L"bcfg: failed to remove - %hr\n", Status);
  467. } else {
  468. Print (L"bcfg: %s %d removed\n", BCfgSelName, Position);
  469. }
  470. }
  471. VOID
  472. BCfgMove (
  473. IN UINTN Src,
  474. IN UINTN Dest
  475. )
  476. {
  477. UINT16 Target;
  478. UINTN Index;
  479. EFI_STATUS Status;
  480. if (Src < 1 || Src > BCfgOrderCount) {
  481. Print (L"bcfg: %hd not moved. Value is out of range\n", Src);
  482. return ;
  483. }
  484. if (Dest < 1) {
  485. Dest = 1;
  486. }
  487. if (Dest > BCfgOrderCount) {
  488. Dest = BCfgOrderCount;
  489. }
  490. /*
  491. *
  492. */
  493. Src = Src - 1;
  494. Dest = Dest - 1;
  495. Target = BCfgOrder[Src];
  496. /*
  497. * Remove the item
  498. */
  499. for (Index=Src; Index < BCfgOrderCount-1; Index += 1) {
  500. BCfgOrder[Index] = BCfgOrder[Index+1];
  501. }
  502. /*
  503. * Insert it
  504. */
  505. for (Index=BCfgOrderCount-1; Index > Dest; Index -= 1) {
  506. BCfgOrder[Index] = BCfgOrder[Index-1];
  507. }
  508. BCfgOrder[Dest] = Target;
  509. /*
  510. * Update the order
  511. */
  512. Status = RT->SetVariable (
  513. BCfgSelOrder,
  514. &EfiGlobalVariable,
  515. BCfgAttributes,
  516. BCfgOrderCount * sizeof(UINT16),
  517. BCfgOrder
  518. );
  519. /*
  520. * Done
  521. */
  522. if (EFI_ERROR(Status)) {
  523. Print (L"bcfg: failed to move option - %hr\n", Status);
  524. } else {
  525. Print (L"bcfg: %s %d moved to %d\n", BCfgSelName, Src+1, Dest+1);
  526. }
  527. }
  528. VOID
  529. BCfgDumpBootList (
  530. IN CHAR16 *BootOrder,
  531. IN CHAR16 *BootOption
  532. )
  533. {
  534. EFI_STATUS Status;
  535. UINTN DataSize;
  536. UINT32 Attributes;
  537. CHAR16 OptionStr[40];
  538. BCFG_LOAD_OPTION *Option;
  539. UINTN Index;
  540. for (Index=0; Index < BCfgOrderCount; Index++) {
  541. SPrint (OptionStr, sizeof(OptionStr), BootOption, BCfgOrder[Index]);
  542. DataSize = MAX_ENV_SIZE;
  543. Status = RT->GetVariable (
  544. OptionStr,
  545. &EfiGlobalVariable,
  546. &Attributes,
  547. &DataSize,
  548. BCfgData
  549. );
  550. Print (L"%02x. ", Index+1);
  551. if (!EFI_ERROR(Status)) {
  552. Option = BCfgParseLoadOption ((UINT8 *) BCfgData, DataSize);
  553. if (!Option) {
  554. Print (L"%Hcould not parse option%N\n");
  555. continue;
  556. }
  557. Print (L"%s %H\"%ns\"%s%N\n",
  558. Option->FilePathStr,
  559. Option->Description,
  560. Option->LoadOptionsSize ? L" OPT" : L""
  561. );
  562. BCfgFreeLoadOption (Option);
  563. } else {
  564. Print (L"%hr\n", Status);
  565. }
  566. }
  567. }
  568. BCFG_LOAD_OPTION *
  569. BCfgParseLoadOption (
  570. UINT8 *Data,
  571. UINTN DataSize
  572. )
  573. {
  574. BCFG_LOAD_OPTION *Option;
  575. BOOLEAN Valid;
  576. UINT8 *End;
  577. EFI_DEVICE_PATH *DevicePathNode;
  578. Valid = FALSE;
  579. Option = AllocateZeroPool(sizeof(BCFG_LOAD_OPTION));
  580. /*
  581. * Parse the load option into the Option structure
  582. */
  583. if (DataSize < 10) {
  584. goto Done;
  585. }
  586. /*
  587. * First 32 bits are the load option attributes
  588. */
  589. CopyMem (&Option->Attributes, Data, sizeof(UINT32));
  590. Data += sizeof(UINT32);
  591. DataSize -= sizeof(UINT32);
  592. /*
  593. * Next is a null terminated string
  594. */
  595. Option->Description = AllocatePool(DataSize);
  596. CopyMem (Option->Description, Data, DataSize);
  597. /* find the string terminator */
  598. Data = (UINT8 *) Option->Description;
  599. End = Data + DataSize;
  600. while (*((CHAR16 *) Data)) {
  601. if (Data > End - sizeof(CHAR16) - 1) {
  602. goto Done;
  603. }
  604. Data += sizeof(UINT16);
  605. }
  606. Data += sizeof(UINT16);
  607. DataSize = End - Data;
  608. /*
  609. * Next is the file path
  610. */
  611. Option->FilePath = AllocatePool (DataSize);
  612. CopyMem (Option->FilePath, Data, DataSize);
  613. /* find the end of path terminator */
  614. DevicePathNode = (EFI_DEVICE_PATH *) Data;
  615. while (!IsDevicePathEnd (DevicePathNode)) {
  616. DevicePathNode = NextDevicePathNode (DevicePathNode);
  617. if ((UINT8 *) DevicePathNode > End - sizeof(EFI_DEVICE_PATH)) {
  618. goto Done;
  619. }
  620. }
  621. Data = ((UINT8 *) DevicePathNode) + sizeof(EFI_DEVICE_PATH);
  622. DataSize = End - Data;
  623. /*
  624. * Next is the load options
  625. */
  626. if (DataSize) {
  627. Option->LoadOptions = Data;
  628. Option->LoadOptionsSize = DataSize;
  629. }
  630. /*
  631. * Expand the FilePath to a string
  632. */
  633. Option->FilePathStr = DevicePathToStr(Option->FilePath);
  634. Valid = TRUE;
  635. Done:
  636. if (!Valid && Option) {
  637. BCfgFreeLoadOption (Option);
  638. Option = NULL;
  639. }
  640. return Option;
  641. }
  642. VOID
  643. BCfgFreeLoadOption (
  644. BCFG_LOAD_OPTION *Option
  645. )
  646. {
  647. if (Option->Description) {
  648. FreePool (Option->Description);
  649. }
  650. if (Option->FilePath) {
  651. FreePool (Option->FilePath);
  652. }
  653. if (Option->FilePathStr) {
  654. FreePool (Option->FilePathStr);
  655. }
  656. FreePool (Option);
  657. }