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.

4589 lines
122 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. spboot.c
  5. Abstract:
  6. accessing and configuring boot variables.
  7. Author:
  8. Sunil Pai (sunilp) 26-October-1993
  9. Revision History:
  10. --*/
  11. #include "spprecmp.h"
  12. #pragma hdrstop
  13. #include <hdlsblk.h>
  14. #include <hdlsterm.h>
  15. #if defined(EFI_NVRAM_ENABLED)
  16. #include <efi.h>
  17. #include <efiapi.h>
  18. #endif
  19. #include "bootvar.h"
  20. //
  21. // Globals to this module
  22. //
  23. static ULONG Timeout;
  24. static PWSTR Default;
  25. ULONG DefaultSignature;
  26. static PWSTR *BootVars[MAXBOOTVARS];
  27. static BOOLEAN CleanSysPartOrphan = FALSE;
  28. PWSTR *CurrentNtDirectoryList = NULL;
  29. // do NOT change the order of the elements in this array.
  30. PCHAR NvramVarNames[MAXBOOTVARS] = {
  31. LOADIDENTIFIERVAR,
  32. OSLOADERVAR,
  33. OSLOADPARTITIONVAR,
  34. OSLOADFILENAMEVAR,
  35. OSLOADOPTIONSVAR,
  36. SYSTEMPARTITIONVAR
  37. };
  38. PCHAR OldBootVars[MAXBOOTVARS];
  39. PWSTR NewBootVars[MAXBOOTVARS];
  40. #if defined(_X86_)
  41. BOOLEAN IsArcChecked = FALSE;
  42. BOOLEAN IsArcMachine;
  43. #endif
  44. PSP_BOOT_ENTRY SpBootEntries = NULL;
  45. PBOOT_OPTIONS SpBootOptions = NULL;
  46. RedirectSwitchesModeEnum RedirectSwitchesMode = UseDefaultSwitches;
  47. REDIRECT_SWITCHES RedirectSwitches;
  48. #ifdef _X86_
  49. extern BOOLEAN g_Win9xBackup;
  50. #endif
  51. //
  52. // Local functions.
  53. //
  54. PWSTR
  55. SpArcPathFromBootSet(
  56. IN BOOTVAR BootVariable,
  57. IN ULONG Component
  58. );
  59. BOOLEAN
  60. SpConvertArcBootEntries (
  61. IN ULONG MaxComponents
  62. );
  63. VOID
  64. SpCreateBootEntry(
  65. IN ULONG_PTR Status,
  66. IN PDISK_REGION BootFileRegion,
  67. IN PWSTR BootFilePath,
  68. IN PDISK_REGION OsLoadRegion,
  69. IN PWSTR OsLoadPath,
  70. IN PWSTR OsLoadOptions,
  71. IN PWSTR FriendlyName
  72. );
  73. PCHAR
  74. SppGetArcEnvVar(
  75. IN BOOTVAR Variable
  76. );
  77. VOID
  78. SpFreeBootEntries (
  79. VOID
  80. );
  81. BOOLEAN
  82. SppSetArcEnvVar(
  83. IN BOOTVAR Variable,
  84. IN PWSTR *VarComponents,
  85. IN BOOLEAN bWriteVar
  86. );
  87. #if defined(EFI_NVRAM_ENABLED)
  88. typedef struct _HARDDISK_NAME_TRANSLATION {
  89. struct _HARDDISK_NAME_TRANSLATION *Next;
  90. PWSTR VolumeName;
  91. PWSTR PartitionName;
  92. } HARDDISK_NAME_TRANSLATION, *PHARDDISK_NAME_TRANSLATION;
  93. PHARDDISK_NAME_TRANSLATION SpHarddiskNameTranslations = NULL;
  94. BOOLEAN
  95. SpBuildHarddiskNameTranslations (
  96. VOID
  97. );
  98. BOOLEAN
  99. SpFlushEfiBootEntries (
  100. VOID
  101. );
  102. BOOLEAN
  103. SpReadAndConvertEfiBootEntries (
  104. VOID
  105. );
  106. ULONG
  107. SpSafeWcslen (
  108. IN PWSTR String,
  109. IN PWSTR Max
  110. );
  111. VOID
  112. SpTranslateFilePathToRegion (
  113. IN PFILE_PATH FilePath,
  114. OUT PDISK_REGION *DiskRegion,
  115. OUT PWSTR *PartitionNtName,
  116. OUT PWSTR *PartitionRelativePath
  117. );
  118. #define ADD_OFFSET(_p,_o) (PVOID)((PUCHAR)(_p) + (_p)->_o)
  119. #endif
  120. //
  121. // Function implementation
  122. //
  123. BOOLEAN
  124. SpInitBootVars(
  125. )
  126. /*++
  127. Routine Description:
  128. Captures the state of the NVRAM Boot Variables.
  129. Arguments:
  130. None.
  131. Return Value:
  132. --*/
  133. {
  134. BOOLEAN Status = TRUE;
  135. BOOTVAR i;
  136. ULONG Component, MaxComponents, SysPartComponents;
  137. PCHAR puArcString; // SGI
  138. CLEAR_CLIENT_SCREEN();
  139. SpDisplayStatusText(SP_STAT_EXAMINING_FLEXBOOT,DEFAULT_STATUS_ATTRIBUTE);
  140. //
  141. // Initialize the boot variables from the corresponding NVRAM variables
  142. //
  143. #if defined(EFI_NVRAM_ENABLED)
  144. if (SpIsEfi()) {
  145. //
  146. // Build a list of all of the \Device\HarddiskN\PartitionM symbolic
  147. // links, along with their translations to \Device\HarddiskVolumeN
  148. // device names. This list is used to translate the
  149. // \Device\HarddiskVolumeN names returned by NtTranslateFilePath into
  150. // names that setupdd can translate to ARC names.
  151. //
  152. SpBuildHarddiskNameTranslations();
  153. //
  154. // Read the boot entries from NVRAM and convert them into our
  155. // internal format.
  156. //
  157. Status = SpReadAndConvertEfiBootEntries();
  158. } else
  159. #endif
  160. {
  161. if (SpIsArc()) {
  162. ULONG NumComponents;
  163. for(i = FIRSTBOOTVAR; i <= LASTBOOTVAR; i++) {
  164. OldBootVars[i] = SppGetArcEnvVar( i );
  165. SpGetEnvVarWComponents( OldBootVars[i], BootVars + i, &NumComponents );
  166. }
  167. Timeout = DEFAULT_TIMEOUT;
  168. Default = NULL;
  169. #if defined _X86_
  170. } else {
  171. Spx86InitBootVars( BootVars, &Default, &Timeout );
  172. #endif
  173. }
  174. //
  175. // We now go back and replace all NULL OsLoadOptions with "", because we
  176. // validate a boot set by making sure that all components are non-NULL.
  177. //
  178. // First, find the maximum number of components in any of the other
  179. // boot variables, so that we can make OsLoadOptions have this many.
  180. // (We also disregard SYSTEMPARTITION since some machines have this component
  181. // sitting all by itself on a new machine.)
  182. //
  183. MaxComponents = 0;
  184. for(i = FIRSTBOOTVAR; i <= LASTBOOTVAR; i++) {
  185. if(i != OSLOADOPTIONS) {
  186. for(Component = 0; BootVars[i][Component]; Component++);
  187. if (i == SYSTEMPARTITION) {
  188. SysPartComponents = Component;
  189. } else if(Component > MaxComponents) {
  190. MaxComponents = Component;
  191. }
  192. }
  193. }
  194. if(SysPartComponents > MaxComponents) {
  195. CleanSysPartOrphan = TRUE;
  196. }
  197. for(Component = 0; BootVars[OSLOADOPTIONS][Component]; Component++);
  198. if(Component < MaxComponents) {
  199. //
  200. // Then we need to add empty strings to fill it out.
  201. //
  202. BootVars[OSLOADOPTIONS] = SpMemRealloc(BootVars[OSLOADOPTIONS],
  203. (MaxComponents + 1) * sizeof(PWSTR *));
  204. ASSERT(BootVars[OSLOADOPTIONS]);
  205. BootVars[OSLOADOPTIONS][MaxComponents] = NULL;
  206. for(; Component < MaxComponents; Component++) {
  207. BootVars[OSLOADOPTIONS][Component] = SpDupStringW(L"");
  208. }
  209. }
  210. //
  211. // Now convert the ARC boot sets into our internal format.
  212. //
  213. Status = SpConvertArcBootEntries(MaxComponents);
  214. }
  215. CLEAR_CLIENT_SCREEN();
  216. return ( Status );
  217. }
  218. BOOLEAN
  219. SpFlushBootVars(
  220. )
  221. /*++
  222. Routine Description:
  223. Updates the NVRAM variables / boot.ini
  224. from the current state of the boot variables.
  225. Arguments:
  226. Return Value:
  227. --*/
  228. {
  229. BOOLEAN Status, OldStatus;
  230. BOOTVAR i, iFailPoint;
  231. CHAR TimeoutValue[24];
  232. #if defined(EFI_NVRAM_ENABLED)
  233. if (SpIsEfi()) {
  234. //
  235. // This is an EFI machine. Write changed boot entries back to NVRAM.
  236. //
  237. Status = SpFlushEfiBootEntries();
  238. } else
  239. #endif
  240. {
  241. Status = FALSE;
  242. if (SpIsArc()) {
  243. //
  244. // Run through all the boot variables and set the corresponding
  245. // NVRAM variables
  246. for(OldStatus = TRUE, i = FIRSTBOOTVAR; i <= LASTBOOTVAR; i++) {
  247. Status = SppSetArcEnvVar( i, BootVars[i], OldStatus );
  248. if(Status != OldStatus) {
  249. iFailPoint = i;
  250. OldStatus = Status;
  251. }
  252. }
  253. // if we failed in writing any of the variables, then restore everything we
  254. // modified back to its original state.
  255. if(!Status) {
  256. for(i = FIRSTBOOTVAR; i < iFailPoint; i++) {
  257. HalSetEnvironmentVariable(NvramVarNames[i], OldBootVars[i]);
  258. }
  259. }
  260. // Free all of the old boot variable strings
  261. for(i = FIRSTBOOTVAR; i <= LASTBOOTVAR; i++) {
  262. SpMemFree(OldBootVars[i]);
  263. OldBootVars[i] = NULL;
  264. }
  265. //
  266. // Now set the timeout.
  267. //
  268. if(Status) {
  269. Status = FALSE;
  270. sprintf(TimeoutValue,"%u",Timeout);
  271. if((HalSetEnvironmentVariable("COUNTDOWN",TimeoutValue) == ESUCCESS)
  272. && (HalSetEnvironmentVariable("AUTOLOAD" ,"YES" ) == ESUCCESS))
  273. {
  274. Status = TRUE;
  275. }
  276. }
  277. #if defined(_X86_)
  278. } else {
  279. Status = Spx86FlushBootVars( BootVars, Timeout, Default );
  280. #endif
  281. }
  282. }
  283. return( Status );
  284. }
  285. VOID
  286. SpFreeBootVars(
  287. )
  288. /*++
  289. Routine Description:
  290. To free any memory allocated and do other cleanup
  291. Arguments:
  292. None
  293. Return Value:
  294. None
  295. --*/
  296. {
  297. BOOTVAR i;
  298. //
  299. // Free internal-format boot entries.
  300. //
  301. SpFreeBootEntries();
  302. #if defined(EFI_NVRAM_ENABLED)
  303. if (!SpIsEfi())
  304. #endif
  305. {
  306. //
  307. // Go through the globals and free them
  308. //
  309. for(i = FIRSTBOOTVAR; i <= LASTBOOTVAR; i++) {
  310. if( BootVars[i] ) {
  311. SpFreeEnvVarComponents( BootVars[i] );
  312. BootVars[i] = NULL;
  313. }
  314. }
  315. if ( Default ) {
  316. SpMemFree( Default );
  317. Default = NULL;
  318. }
  319. }
  320. return;
  321. }
  322. VOID
  323. SpAddBootSet(
  324. IN PWSTR *BootSet,
  325. IN BOOLEAN DefaultOS,
  326. IN ULONG Signature
  327. )
  328. /*++
  329. Routine Description:
  330. To add a new system to the installed system list. The system is added
  331. as the first bootset. If is found in the currently installed boot sets
  332. the boot set is extracted and shifted to position 0.
  333. Arguments:
  334. BootSet - A list of the boot variables to use.
  335. Default - Whether this system is to be the default system to boot.
  336. Return Value:
  337. Component list of the value of the boot variable.
  338. --*/
  339. {
  340. BOOTVAR i;
  341. ULONG MatchComponent, j;
  342. LONG k;
  343. BOOLEAN ValidBootSet, ComponentMatched;
  344. PWSTR Temp;
  345. ASSERT( !SpIsEfi() );
  346. //
  347. // Validate the BootSet passed in
  348. //
  349. for(i = FIRSTBOOTVAR; i <= LASTBOOTVAR; i++) {
  350. ASSERT( BootSet[i] );
  351. }
  352. //
  353. // Examine all the boot sets and make sure we don't have a boot set
  354. // already matching. Note that we will compare all variables in
  355. // tandem. We are not interested in matches which are generated by
  356. // the variables not being in tandem because they are difficult to
  357. // shift around.
  358. //
  359. ValidBootSet = TRUE;
  360. ComponentMatched = FALSE;
  361. for( MatchComponent = 0;
  362. BootVars[OSLOADPARTITION][MatchComponent];
  363. MatchComponent++
  364. ) {
  365. //
  366. // Validate the boot set at the current component
  367. //
  368. for(i = FIRSTBOOTVAR; i <= LASTBOOTVAR; i++) {
  369. ValidBootSet = ValidBootSet && BootVars[i][MatchComponent];
  370. }
  371. if( !ValidBootSet ) {
  372. break;
  373. }
  374. //
  375. // Valid Boot Set, compare the components against what we have in the
  376. // current BootSet
  377. //
  378. ComponentMatched = TRUE;
  379. for(i = FIRSTBOOTVAR; ComponentMatched && i <= LASTBOOTVAR; i++) {
  380. ComponentMatched = !_wcsicmp( BootSet[i], BootVars[i][MatchComponent] );
  381. }
  382. if( ComponentMatched ) {
  383. break;
  384. }
  385. }
  386. //
  387. // If component didn't match then prepend the BootSet to the boot sets
  388. // that currently exist. It is important to prepend the BootSet, because
  389. // appending the BootSet doesn't guarantee a matched BootSet in the
  390. // environment variables. If a match was found then we
  391. // have a cleanly matched set which can be exchanged with the first
  392. // one in the set.
  393. //
  394. if( ComponentMatched ) {
  395. // If the currently selected OS is to be the default:
  396. // Shift down all variables from position 0 to MatchComponent - 1
  397. // and store whatever was there at MatchComponent at position 0
  398. //
  399. if ( DefaultOS && MatchComponent != 0 ) {
  400. for(i = FIRSTBOOTVAR; i <= LASTBOOTVAR; i++) {
  401. Temp = BootVars[i][MatchComponent];
  402. for( k = MatchComponent - 1; k >= 0; k-- ) {
  403. BootVars[i][k + 1] = BootVars[i][k];
  404. }
  405. BootVars[i][0] = Temp;
  406. }
  407. }
  408. }
  409. else {
  410. for(i = FIRSTBOOTVAR; i <= LASTBOOTVAR; i++) {
  411. //
  412. // Find out the size of the current value
  413. //
  414. for(j = 0; BootVars[i][j]; j++) {
  415. }
  416. //
  417. // Realloc the current buffer to hold one more
  418. //
  419. BootVars[i] = SpMemRealloc( BootVars[i], (j + 1 + 1)*sizeof(PWSTR) );
  420. //
  421. // Shift all the variables down one and store the current value
  422. // at index 0;
  423. //
  424. for( k = j; k >= 0 ; k-- ) {
  425. BootVars[i][k+1] = BootVars[i][k];
  426. }
  427. BootVars[i][0] = SpDupStringW( BootSet[i] );
  428. ASSERT( BootVars[i][0] );
  429. }
  430. }
  431. //
  432. // If this has been indicated as the default then set this to be the
  433. // default OS after freeing the current default variable
  434. //
  435. if( DefaultOS ) {
  436. if( Default ) {
  437. SpMemFree( Default );
  438. }
  439. Default = SpMemAlloc( MAX_PATH * sizeof(WCHAR) );
  440. ASSERT( Default );
  441. wcscpy( Default, BootSet[OSLOADPARTITION] );
  442. wcscat( Default, BootSet[OSLOADFILENAME] );
  443. DefaultSignature = Signature;
  444. }
  445. return;
  446. }
  447. VOID
  448. SpDeleteBootSet(
  449. IN PWSTR *BootSet,
  450. OUT PWSTR *OldOsLoadOptions OPTIONAL
  451. )
  452. /*++
  453. Routine Description:
  454. To delete all boot sets in the list matching the boot set provided.
  455. Note that the information to use in comparing the bootset is provided
  456. by selectively providing fields in the boot set. So in the boot set
  457. if the system partition is not provided it is not used in the comparison
  458. to see if the boot sets match. By providing all NULL members we can
  459. delete all the boot sets currently present.
  460. Arguments:
  461. BootSet - A list of the boot variables to use.
  462. Return Value:
  463. None.
  464. --*/
  465. {
  466. ULONG Component, j;
  467. BOOLEAN ValidBootSet, ComponentMatched;
  468. BOOTVAR i;
  469. PWSTR OsPartPath;
  470. ASSERT( !SpIsEfi() );
  471. Component = 0;
  472. while(TRUE) {
  473. //
  474. // See if we have any boot sets left, if none left we are done
  475. //
  476. ValidBootSet = TRUE;
  477. for(i = FIRSTBOOTVAR; i <= LASTBOOTVAR; i++) {
  478. ValidBootSet = ValidBootSet && BootVars[i][Component];
  479. }
  480. if( !ValidBootSet ) {
  481. break;
  482. }
  483. //
  484. // Valid Boot Set, compare the components against what we have in the
  485. // current BootSet. Use only members of the BootSet which are not NULL
  486. //
  487. ComponentMatched = TRUE;
  488. for(i = FIRSTBOOTVAR; ComponentMatched && i <= LASTBOOTVAR; i++) {
  489. if( BootSet[i] ) {
  490. if((i == OSLOADPARTITION) ||
  491. (i == SYSTEMPARTITION)) {
  492. //
  493. // Then we may have a boot set existing in tertiary ARC path form, so
  494. // we first translate this path to a primary or secondary ARC path.
  495. //
  496. OsPartPath = SpArcPathFromBootSet(i, Component);
  497. ComponentMatched = !_wcsicmp( BootSet[i], OsPartPath );
  498. SpMemFree(OsPartPath);
  499. } else {
  500. ComponentMatched = !_wcsicmp( BootSet[i], BootVars[i][Component] );
  501. }
  502. }
  503. }
  504. if( (ComponentMatched)
  505. #ifdef PRERELEASE
  506. //
  507. // If we're being asked to delete a boot entry, and this
  508. // isn't the *exact* entry (i.e. it's a duplicate) that
  509. // also has some private OSLOADOPTIONS, then keep it around.
  510. //
  511. && !( wcsstr(BootVars[OSLOADOPTIONS][Component], L"/kernel") ||
  512. wcsstr(BootVars[OSLOADOPTIONS][Component], L"/hal") ||
  513. wcsstr(BootVars[OSLOADOPTIONS][Component], L"/pae") ||
  514. wcsstr(BootVars[OSLOADOPTIONS][Component], L"/sos") )
  515. #endif
  516. ) {
  517. //
  518. // Delete all the values in the current component and advance
  519. // all the other components one index up
  520. //
  521. for(i = FIRSTBOOTVAR; i <= LASTBOOTVAR; i++) {
  522. if((i == OSLOADOPTIONS) && OldOsLoadOptions && !(*OldOsLoadOptions)) {
  523. //
  524. // If we've been passed a pointer to OldOsLoadOptions,
  525. // and haven't previously found a pertinent entry, then
  526. // save this one
  527. //
  528. *OldOsLoadOptions = BootVars[i][Component];
  529. } else {
  530. SpMemFree(BootVars[i][Component]);
  531. }
  532. j = Component;
  533. do {
  534. BootVars[i][j] = BootVars[i][j+1];
  535. j++;
  536. } while(BootVars[i][j] != NULL);
  537. }
  538. }
  539. else {
  540. Component++;
  541. }
  542. }
  543. return;
  544. }
  545. VOID
  546. SpCleanSysPartOrphan(
  547. VOID
  548. )
  549. {
  550. INT Component, Orphan;
  551. BOOLEAN DupFound;
  552. PWSTR NormalizedArcPath;
  553. if(!CleanSysPartOrphan) {
  554. return;
  555. }
  556. ASSERT( !SpIsEfi() );
  557. //
  558. // find the last SystemPartition entry
  559. //
  560. for(Orphan = 0; BootVars[SYSTEMPARTITION][Orphan]; Orphan++);
  561. //
  562. // it's position better be > 0, otherwise, just exit
  563. //
  564. if(Orphan < 2) {
  565. return;
  566. } else {
  567. NormalizedArcPath = SpNormalizeArcPath(BootVars[SYSTEMPARTITION][--Orphan]);
  568. }
  569. //
  570. // Make sure that this component is duplicated somewhere else in the
  571. // SystemPartition list.
  572. //
  573. for(Component = Orphan - 1, DupFound = FALSE;
  574. ((Component >= 0) && !DupFound);
  575. Component--)
  576. {
  577. DupFound = !_wcsicmp(NormalizedArcPath, BootVars[SYSTEMPARTITION][Component]);
  578. }
  579. if(DupFound) {
  580. SpMemFree(BootVars[SYSTEMPARTITION][Orphan]);
  581. BootVars[SYSTEMPARTITION][Orphan] = NULL;
  582. }
  583. SpMemFree(NormalizedArcPath);
  584. }
  585. PWSTR
  586. SpArcPathFromBootSet(
  587. IN BOOTVAR BootVariable,
  588. IN ULONG Component
  589. )
  590. /*++
  591. Routine Description:
  592. Given the index of a boot set, return the primary (multi) or
  593. secondary ("absolute" scsi) ARC path for the specified variable.
  594. This takes into account the NT 3.1 case where we had 'tertiary'
  595. ARC paths where a relative scsi ordinal was passed in via the
  596. /scsiordinal switch.
  597. Arguments:
  598. BootVariable - supplies the index of the variable we want to return.
  599. Component - supplies the index of the boot set to use.
  600. Return Value:
  601. String representing the primary or secondary ARC path. This string
  602. must be freed by the caller with SpMemFree.
  603. --*/
  604. {
  605. ASSERT( !SpIsEfi() );
  606. if(!SpIsArc()){
  607. PWSTR p = NULL, q = NULL, ReturnedPath = NULL, RestOfString;
  608. WCHAR ForceOrdinalSwitch[] = L"/scsiordinal:";
  609. WCHAR ScsiPrefix[] = L"scsi(";
  610. WCHAR OrdinalString[11];
  611. ULONG ScsiOrdinal, PrefixLength;
  612. //
  613. // Check to see if this boot set had the /scsiordinal option switch
  614. //
  615. if(BootVars[OSLOADOPTIONS][Component]) {
  616. wcscpy(TemporaryBuffer, BootVars[OSLOADOPTIONS][Component]);
  617. SpStringToLower(TemporaryBuffer);
  618. if(p = wcsstr(TemporaryBuffer, ForceOrdinalSwitch)) {
  619. p += sizeof(ForceOrdinalSwitch)/sizeof(WCHAR) - 1;
  620. if(!(*p)) {
  621. p = NULL;
  622. }
  623. }
  624. }
  625. if(p) {
  626. //
  627. // We have found a scsiordinal, so use it
  628. //
  629. ScsiOrdinal = SpStringToLong(p, &RestOfString, 10);
  630. wcscpy(TemporaryBuffer, BootVars[BootVariable][Component]);
  631. SpStringToLower(TemporaryBuffer);
  632. if(p = wcsstr(TemporaryBuffer, ScsiPrefix)) {
  633. p += sizeof(ScsiPrefix)/sizeof(WCHAR) - 1;
  634. if(*p) {
  635. q = wcschr(p, L')');
  636. } else {
  637. p = NULL;
  638. }
  639. }
  640. if(q) {
  641. //
  642. // build the new secondary ARC path
  643. //
  644. swprintf(OrdinalString, L"%u", ScsiOrdinal);
  645. PrefixLength = (ULONG)(p - TemporaryBuffer);
  646. ReturnedPath = SpMemAlloc((PrefixLength + wcslen(OrdinalString) + wcslen(q) + 1)
  647. * sizeof(WCHAR)
  648. );
  649. wcsncpy(ReturnedPath, TemporaryBuffer, PrefixLength);
  650. ReturnedPath[PrefixLength] = L'\0';
  651. wcscat(ReturnedPath, OrdinalString);
  652. wcscat(ReturnedPath, q);
  653. }
  654. }
  655. if(!ReturnedPath) {
  656. //
  657. // We didn't find a scsiordinal, this is a multi-style path, or
  658. // there was some problem, so just use the boot variable as-is.
  659. //
  660. ReturnedPath = SpDupStringW(BootVars[BootVariable][Component]);
  661. }
  662. return ReturnedPath;
  663. }else{ // not x86
  664. //
  665. // Nothing to do on ARC machines.
  666. //
  667. return SpDupStringW(BootVars[BootVariable][Component]);
  668. }
  669. }
  670. #if defined(REMOTE_BOOT)
  671. BOOLEAN
  672. SpFlushRemoteBootVars(
  673. IN PDISK_REGION TargetRegion
  674. )
  675. {
  676. #if defined(EFI_NVRAM_ENABLED)
  677. if (SpIsEfi()) {
  678. //
  679. // Insert EFI code here.
  680. //
  681. return FALSE;
  682. } else
  683. #endif
  684. {
  685. if (SpIsArc()) {
  686. //
  687. // Insert ARC code here.
  688. //
  689. return FALSE;
  690. #if defined(_X86_)
  691. } else {
  692. return Spx86FlushRemoteBootVars( TargetRegion, BootVars, Default );
  693. #endif
  694. }
  695. }
  696. }
  697. #endif // defined(REMOTE_BOOT)
  698. BOOLEAN
  699. SppSetArcEnvVar(
  700. IN BOOTVAR Variable,
  701. IN PWSTR *VarComponents,
  702. IN BOOLEAN bWriteVar
  703. )
  704. /*++
  705. Routine Description:
  706. Set the value of the arc environment variable
  707. Arguments:
  708. VarName - supplies the name of the arc environment variable
  709. whose value is to be set.
  710. VarComponents - Set of components of the variable value to be set
  711. bWriteVar - if TRUE, then write the variable to nvram, otherwise
  712. just return FALSE (having put the first component in NewBootVars).
  713. Return Value:
  714. TRUE if values were written to nvram / FALSE otherwise
  715. --*/
  716. {
  717. ULONG Length, NBVLen, i;
  718. PWSTR Temp;
  719. PUCHAR Value;
  720. ARC_STATUS ArcStatus;
  721. ASSERT( !SpIsEfi() );
  722. if( VarComponents == NULL ) {
  723. Temp = SpDupStringW( L"" );
  724. NewBootVars[Variable] = SpDupStringW( L"" );
  725. }
  726. else {
  727. for( i = 0, Length = 0; VarComponents[i]; i++ ) {
  728. Length = Length + (wcslen(VarComponents[i]) + 1) * sizeof(WCHAR);
  729. if(i == 0) {
  730. NBVLen = Length; // we just want to store the first component
  731. }
  732. }
  733. Temp = SpMemAlloc( Length );
  734. ASSERT( Temp );
  735. wcscpy( Temp, L"" );
  736. NewBootVars[Variable] = SpMemAlloc( NBVLen );
  737. ASSERT( NewBootVars[Variable] );
  738. wcscpy( NewBootVars[Variable], L"" );
  739. for( i = 0; VarComponents[i]; i++ ) {
  740. wcscat( Temp, VarComponents[i] );
  741. if( VarComponents[i + 1] ) {
  742. wcscat( Temp, L";" );
  743. }
  744. if(i == 0) {
  745. wcscat( NewBootVars[Variable], VarComponents[i]);
  746. }
  747. }
  748. }
  749. if(bWriteVar) {
  750. Value = SpToOem( Temp );
  751. ArcStatus = HalSetEnvironmentVariable( NvramVarNames[ Variable ], Value );
  752. SpMemFree( Value );
  753. } else {
  754. ArcStatus = ENOMEM;
  755. }
  756. SpMemFree( Temp );
  757. return ( ArcStatus == ESUCCESS );
  758. }
  759. #ifdef _X86_
  760. BOOLEAN
  761. SpIsArc(
  762. VOID
  763. )
  764. /*++
  765. Routine Description:
  766. Run time check to determine if this is an Arc system. We attempt to read an
  767. Arc variable using the Hal. This will fail for Bios based systems.
  768. Arguments:
  769. None
  770. Return Value:
  771. True = This is an Arc system.
  772. --*/
  773. {
  774. #define BUFFERLENGTH 512
  775. ARC_STATUS ArcStatus = EBADF;
  776. UCHAR *buf;
  777. if (IsArcChecked) {
  778. return IsArcMachine;
  779. }
  780. IsArcChecked = TRUE;
  781. IsArcMachine = FALSE;
  782. //
  783. // Get the env var into the temp buffer.
  784. //
  785. buf = SpMemAlloc( BUFFERLENGTH );
  786. if( buf ) {
  787. ArcStatus = HalGetEnvironmentVariable(
  788. NvramVarNames[ OSLOADER ],
  789. BUFFERLENGTH, //sizeof(TemporaryBuffer),
  790. buf //(PUCHAR)TemporaryBuffer
  791. );
  792. SpMemFree( buf );
  793. }
  794. if (ArcStatus == ESUCCESS) {
  795. IsArcMachine = TRUE;
  796. }
  797. return IsArcMachine;
  798. }
  799. #endif
  800. VOID
  801. SpFreeBootEntries (
  802. VOID
  803. )
  804. /*++
  805. Routine Description:
  806. Frees memory used to hold internal-format boot entries and options.
  807. Arguments:
  808. None.
  809. Return Value:
  810. None.
  811. --*/
  812. {
  813. PSP_BOOT_ENTRY bootEntry;
  814. //
  815. // Free boot options. These will only be allocated on EFI machines.
  816. //
  817. if (SpBootOptions != NULL) {
  818. ASSERT(SpIsEfi());
  819. SpMemFree(SpBootOptions);
  820. SpBootOptions = NULL;
  821. }
  822. //
  823. // Free internal-format boot entries. These will be allocated on all
  824. // machines.
  825. //
  826. while (SpBootEntries != NULL) {
  827. bootEntry = SpBootEntries;
  828. SpBootEntries = bootEntry->Next;
  829. //
  830. // Space for some fields is allocated with the base structure.
  831. // If a fields address indicates that it was allocated with the
  832. // base structure, don't try to free it.
  833. //
  834. #define IS_SEPARATE_ALLOCATION(_p) \
  835. ((bootEntry->_p != NULL) && \
  836. (((PUCHAR)bootEntry->_p < (PUCHAR)bootEntry) || \
  837. ((PUCHAR)bootEntry->_p > (PUCHAR)bootEntry->AllocationEnd)))
  838. #define FREE_IF_SEPARATE_ALLOCATION(_p) \
  839. if (IS_SEPARATE_ALLOCATION(_p)) { \
  840. SpMemFree(bootEntry->_p); \
  841. }
  842. FREE_IF_SEPARATE_ALLOCATION(FriendlyName);
  843. FREE_IF_SEPARATE_ALLOCATION(OsLoadOptions);
  844. FREE_IF_SEPARATE_ALLOCATION(LoaderPath);
  845. FREE_IF_SEPARATE_ALLOCATION(LoaderPartitionNtName);
  846. FREE_IF_SEPARATE_ALLOCATION(LoaderFile);
  847. FREE_IF_SEPARATE_ALLOCATION(OsPath);
  848. FREE_IF_SEPARATE_ALLOCATION(OsPartitionNtName);
  849. FREE_IF_SEPARATE_ALLOCATION(OsDirectory);
  850. FREE_IF_SEPARATE_ALLOCATION(Pid20Array);
  851. SpMemFree(bootEntry);
  852. }
  853. ASSERT(SpBootEntries == NULL);
  854. return;
  855. } // SpFreeBootEntries
  856. PCHAR
  857. SppGetArcEnvVar(
  858. IN BOOTVAR Variable
  859. )
  860. /*++
  861. Routine Description:
  862. Query the value of an ARC environment variable.
  863. A buffer will be returned in all cases -- if the variable does not exist,
  864. the buffer will be empty.
  865. Arguments:
  866. VarName - supplies the name of the arc environment variable
  867. whose value is desired.
  868. Return Value:
  869. Buffer containing value of the environemnt variable.
  870. The caller must free this buffer with SpMemFree.
  871. --*/
  872. {
  873. ARC_STATUS ArcStatus;
  874. ASSERT( !SpIsEfi() );
  875. //
  876. // Get the env var into the temp buffer.
  877. //
  878. ArcStatus = HalGetEnvironmentVariable(
  879. NvramVarNames[ Variable ],
  880. sizeof(TemporaryBuffer),
  881. (PCHAR) TemporaryBuffer
  882. );
  883. if(ArcStatus != ESUCCESS) {
  884. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: arc status %u getting env var %s\n",ArcStatus,NvramVarNames[Variable]));
  885. //
  886. // return empty buffer.
  887. //
  888. TemporaryBuffer[0] = 0;
  889. }
  890. return(SpDupString((PCHAR)TemporaryBuffer));
  891. }
  892. #ifdef _X86_
  893. //
  894. // NEC98
  895. //
  896. BOOLEAN
  897. SpReInitializeBootVars_Nec98(
  898. VOID
  899. )
  900. {
  901. return SppReInitializeBootVars_Nec98( BootVars, &Default, &Timeout );
  902. }
  903. #endif
  904. PWSTR
  905. SpGetDefaultBootEntry (
  906. OUT UINT *DefaultSignatureOut
  907. )
  908. {
  909. *DefaultSignatureOut = DefaultSignature;
  910. return Default;
  911. }
  912. VOID
  913. SpDetermineUniqueAndPresentBootEntries(
  914. VOID
  915. )
  916. /*++
  917. Routine Description:
  918. This routine goes through the list of NT boot entries and marks all
  919. such entries that are both unique and present.
  920. Arguments:
  921. None. This routine modifies entries in the SpBootEntries list as
  922. appropriate.
  923. Return Value:
  924. None.
  925. --*/
  926. {
  927. PSP_BOOT_ENTRY BootEntry;
  928. PSP_BOOT_ENTRY BootEntry2;
  929. //
  930. // Initialize
  931. //
  932. CLEAR_CLIENT_SCREEN();
  933. SpDisplayStatusText(SP_STAT_LOOKING_FOR_WINNT,DEFAULT_STATUS_ATTRIBUTE);
  934. //
  935. // Go through all the matched boot sets and find out which NTs are
  936. // upgradeable/repairable. The criteria here are:
  937. //
  938. // 1. The system partition should exist and be valid.
  939. // 2. The OS load partition should exist.
  940. // 3. An NT should exist in <OSLoadPartition><OsDirectory>.
  941. // 4. OsLoadPartition should be a non-FT partition, or it should be a
  942. // member 0 of a mirror.
  943. //
  944. for (BootEntry = SpBootEntries; BootEntry != NULL; BootEntry = BootEntry->Next) {
  945. //
  946. // Initialize to false.
  947. //
  948. BootEntry->Processable = FALSE;
  949. //
  950. // If this entry has been deleted or is not an NT boot entry, skip it.
  951. //
  952. if (!IS_BOOT_ENTRY_WINDOWS(BootEntry) || IS_BOOT_ENTRY_DELETED(BootEntry)) {
  953. continue;
  954. }
  955. //
  956. // Check if the system and OS partitions are present and valid.
  957. //
  958. if ((BootEntry->LoaderPartitionDiskRegion == NULL) ||
  959. (BootEntry->OsPartitionDiskRegion == NULL)) {
  960. continue;
  961. }
  962. if (!BootEntry->LoaderPartitionDiskRegion->PartitionedSpace) {
  963. continue;
  964. }
  965. //
  966. // Check whether this directory has been covered before in the
  967. // boot entry list. This happens when multiple boot entries point
  968. // at the same tree. The comparison is done based on the system
  969. // partition region, the OS partition region, and the OS directory.
  970. //
  971. for ( BootEntry2 = SpBootEntries; BootEntry2 != BootEntry; BootEntry2 = BootEntry2->Next ) {
  972. if ((BootEntry->LoaderPartitionDiskRegion == BootEntry2->LoaderPartitionDiskRegion) &&
  973. (BootEntry->OsPartitionDiskRegion == BootEntry2->OsPartitionDiskRegion) &&
  974. (_wcsicmp(BootEntry->OsDirectory, BootEntry2->OsDirectory) == 0)) {
  975. break;
  976. }
  977. }
  978. if (BootEntry != BootEntry2) {
  979. //
  980. // This entry duplicates a previous entry. Skip it.
  981. //
  982. continue;
  983. }
  984. //
  985. // This boot entry is the first one to point to this OS directory.
  986. // Check whether an NT installation is actually present there.
  987. //
  988. if (SpIsNtInDirectory(BootEntry->OsPartitionDiskRegion, BootEntry->OsDirectory)
  989. // && !BootEntry->OsPartitionDiskRegion->FtPartition
  990. ) {
  991. }
  992. BootEntry->Processable = TRUE;
  993. }
  994. CLEAR_CLIENT_SCREEN();
  995. return;
  996. }
  997. VOID
  998. SpRemoveInstallationFromBootList(
  999. IN PDISK_REGION SysPartitionRegion, OPTIONAL
  1000. IN PDISK_REGION NtPartitionRegion, OPTIONAL
  1001. IN PWSTR SysRoot, OPTIONAL
  1002. IN PWSTR SystemLoadIdentifier, OPTIONAL
  1003. IN PWSTR SystemLoadOptions, OPTIONAL
  1004. IN ENUMARCPATHTYPE ArcPathType,
  1005. #if defined(REMOTE_BOOT)
  1006. IN BOOLEAN RemoteBootPath,
  1007. #endif // defined(REMOTE_BOOT)
  1008. OUT PWSTR *OldOsLoadOptions OPTIONAL
  1009. )
  1010. {
  1011. PWSTR BootSet[MAXBOOTVARS];
  1012. PWSTR TempSysRoot = NULL;
  1013. PWSTR FirstBackslash;
  1014. BOOTVAR i;
  1015. WCHAR Drive[] = L"?:";
  1016. PWSTR tmp2;
  1017. PSP_BOOT_ENTRY bootEntry;
  1018. //
  1019. // Tell the user what we are doing.
  1020. //
  1021. CLEAR_CLIENT_SCREEN();
  1022. SpDisplayStatusText(SP_STAT_CLEANING_FLEXBOOT,DEFAULT_STATUS_ATTRIBUTE);
  1023. //
  1024. // Find all boot entries that match the input specifications, and mark
  1025. // them for deletion.
  1026. //
  1027. for (bootEntry = SpBootEntries; bootEntry != NULL; bootEntry = bootEntry->Next) {
  1028. ASSERT(bootEntry->FriendlyName != NULL);
  1029. if (IS_BOOT_ENTRY_WINDOWS(bootEntry)) {
  1030. ASSERT(bootEntry->OsLoadOptions != NULL);
  1031. }
  1032. if (IS_BOOT_ENTRY_WINDOWS(bootEntry) &&
  1033. !IS_BOOT_ENTRY_DELETED(bootEntry) &&
  1034. ((SysPartitionRegion == NULL) ||
  1035. (bootEntry->LoaderPartitionDiskRegion == SysPartitionRegion)) &&
  1036. ((NtPartitionRegion == NULL) ||
  1037. (bootEntry->OsPartitionDiskRegion == NtPartitionRegion)) &&
  1038. ((SysRoot == NULL) ||
  1039. ((bootEntry->OsDirectory != NULL) &&
  1040. (_wcsicmp(bootEntry->OsDirectory, SysRoot) == 0))) &&
  1041. ((SystemLoadIdentifier == NULL) ||
  1042. (_wcsicmp(bootEntry->FriendlyName, SystemLoadIdentifier) == 0)) &&
  1043. ((SystemLoadOptions == NULL) ||
  1044. (_wcsicmp(bootEntry->OsLoadOptions, SystemLoadOptions) == 0))) {
  1045. bootEntry->Status |= BE_STATUS_DELETED;
  1046. if ((OldOsLoadOptions != NULL) && (*OldOsLoadOptions == NULL)) {
  1047. *OldOsLoadOptions = SpDupStringW(bootEntry->OsLoadOptions);
  1048. }
  1049. }
  1050. }
  1051. //
  1052. // If not on an EFI machine, then also delete matching ARC boot sets.
  1053. //
  1054. if (!SpIsEfi()) {
  1055. //
  1056. // Set up the boot set
  1057. //
  1058. for(i = FIRSTBOOTVAR; i <= LASTBOOTVAR; i++) {
  1059. BootSet[i] = NULL;
  1060. }
  1061. tmp2 = TemporaryBuffer + (sizeof(TemporaryBuffer) / sizeof(WCHAR) / 2);
  1062. if( NtPartitionRegion ) {
  1063. SpArcNameFromRegion(NtPartitionRegion,tmp2,sizeof(TemporaryBuffer)/2,PartitionOrdinalOnDisk,ArcPathType);
  1064. BootSet[OSLOADPARTITION] = SpDupStringW(tmp2);
  1065. }
  1066. if( SysPartitionRegion ) {
  1067. SpArcNameFromRegion(SysPartitionRegion,tmp2,sizeof(TemporaryBuffer)/2,PartitionOrdinalOnDisk,ArcPathType);
  1068. BootSet[SYSTEMPARTITION] = SpDupStringW(tmp2);
  1069. }
  1070. BootSet[OSLOADFILENAME] = SysRoot;
  1071. BootSet[LOADIDENTIFIER] = SystemLoadIdentifier;
  1072. BootSet[OSLOADOPTIONS] = SystemLoadOptions;
  1073. #if defined(REMOTE_BOOT)
  1074. //
  1075. // If this is a remote boot path, then move anything in OSLOADPARTITION
  1076. // after (and including) the first backslash over to the OSLOADFILENAME --
  1077. // this is the way that boot.ini is parsed when it is read, so it will
  1078. // allow SpDeleteBootSet to match it properly.
  1079. //
  1080. if (RemoteBootPath && NtPartitionRegion &&
  1081. (FirstBackslash = wcschr(BootSet[OSLOADPARTITION], L'\\'))) {
  1082. wcscpy(tmp2, FirstBackslash);
  1083. wcscat(tmp2, SysRoot);
  1084. TempSysRoot = SpDupStringW(tmp2);
  1085. BootSet[OSLOADFILENAME] = TempSysRoot;
  1086. *FirstBackslash = L'\0'; // truncate BootSet[OSLOADPARTITION]
  1087. }
  1088. #endif // defined(REMOTE_BOOT)
  1089. //
  1090. // Delete the boot set
  1091. //
  1092. SpDeleteBootSet(BootSet, OldOsLoadOptions);
  1093. //
  1094. // To take care of the case where the OSLOADPARTITION is a DOS drive letter
  1095. // in the boot set, change the OSLOADPARTITION to a drive and retry
  1096. // deletion
  1097. //
  1098. if( BootSet[OSLOADPARTITION] != NULL ) {
  1099. SpMemFree(BootSet[OSLOADPARTITION]);
  1100. }
  1101. if( NtPartitionRegion && (ULONG)(Drive[0] = NtPartitionRegion->DriveLetter) != 0) {
  1102. BootSet[OSLOADPARTITION] = Drive;
  1103. SpDeleteBootSet(BootSet, OldOsLoadOptions);
  1104. }
  1105. #ifdef _X86_
  1106. //
  1107. // If OldOsLoadOptions contains "/scsiordinal:", then remove it
  1108. //
  1109. if( ( OldOsLoadOptions != NULL ) &&
  1110. ( *OldOsLoadOptions != NULL ) ) {
  1111. PWSTR p, q;
  1112. WCHAR SaveChar;
  1113. SpStringToLower(*OldOsLoadOptions);
  1114. p = wcsstr( *OldOsLoadOptions, L"/scsiordinal:" );
  1115. if( p != NULL ) {
  1116. SaveChar = *p;
  1117. *p = (WCHAR)'\0';
  1118. wcscpy(TemporaryBuffer, *OldOsLoadOptions);
  1119. *p = SaveChar;
  1120. q = wcschr( p, (WCHAR)' ' );
  1121. if( q != NULL ) {
  1122. wcscat( TemporaryBuffer, q );
  1123. }
  1124. SpMemFree( *OldOsLoadOptions );
  1125. *OldOsLoadOptions = SpDupStringW( ( PWSTR )TemporaryBuffer );
  1126. }
  1127. }
  1128. #endif
  1129. //
  1130. // Cleanup
  1131. //
  1132. if( BootSet[SYSTEMPARTITION] != NULL ) {
  1133. SpMemFree(BootSet[SYSTEMPARTITION]);
  1134. }
  1135. if (TempSysRoot != NULL) {
  1136. SpMemFree(TempSysRoot);
  1137. }
  1138. }
  1139. return;
  1140. }
  1141. VOID
  1142. SpAddInstallationToBootList(
  1143. IN PVOID SifHandle,
  1144. IN PDISK_REGION SystemPartitionRegion,
  1145. IN PWSTR SystemPartitionDirectory,
  1146. IN PDISK_REGION NtPartitionRegion,
  1147. IN PWSTR Sysroot,
  1148. IN BOOLEAN BaseVideoOption,
  1149. IN PWSTR OldOsLoadOptions OPTIONAL
  1150. )
  1151. /*++
  1152. Routine Description:
  1153. Construct a boot set for the given installation
  1154. parameters and add it to the current boot list.
  1155. Perform modifications to the os load options if
  1156. necessary.
  1157. Notes: if this code changes, please ensure that
  1158. SpAddUserDefinedInstallationToBootList()
  1159. stays in sync if appropriate.
  1160. --*/
  1161. {
  1162. PWSTR BootVars[MAXBOOTVARS];
  1163. PWSTR SystemPartitionArcName;
  1164. PWSTR TargetPartitionArcName;
  1165. PWSTR tmp;
  1166. PWSTR tmp2;
  1167. PWSTR SifKeyName;
  1168. ULONG Signature;
  1169. BOOLEAN AddBaseVideo = FALSE;
  1170. WCHAR BaseVideoString[] = L"/basevideo";
  1171. WCHAR BaseVideoSosString[] = L"/sos";
  1172. BOOLEAN AddSosToBaseVideoString;
  1173. HEADLESS_RSP_QUERY_INFO Response;
  1174. WCHAR HeadlessRedirectString[] = L"/redirect";
  1175. #ifdef _X86_
  1176. WCHAR BootFastString[] = L"/fastdetect";
  1177. BOOLEAN AddBootFastString = TRUE;
  1178. #endif
  1179. ENUMARCPATHTYPE ArcPathType = PrimaryArcPath;
  1180. WCHAR HalString[] = L"/hal=";
  1181. BOOLEAN OldOsLoadOptionsReplaced;
  1182. NTSTATUS Status;
  1183. SIZE_T Length;
  1184. PWSTR LoadOptions;
  1185. PWSTR LoadIdentifier;
  1186. //
  1187. // Tell the user what we are doing.
  1188. //
  1189. CLEAR_CLIENT_SCREEN();
  1190. SpDisplayStatusText(SP_STAT_INITING_FLEXBOOT,DEFAULT_STATUS_ATTRIBUTE);
  1191. OldOsLoadOptionsReplaced = FALSE;
  1192. if( OldOsLoadOptions ) {
  1193. PWSTR p;
  1194. tmp = SpDupStringW( OldOsLoadOptions );
  1195. if (tmp) {
  1196. SpStringToLower(tmp);
  1197. if( p = wcsstr(tmp, HalString) ) { // found /hal=
  1198. WCHAR SaveChar;
  1199. PWSTR q;
  1200. SaveChar = *p;
  1201. *p = L'\0';
  1202. wcscpy( TemporaryBuffer, OldOsLoadOptions );
  1203. q = TemporaryBuffer + wcslen( tmp );
  1204. *q = L'\0';
  1205. Length = wcslen( tmp );
  1206. *p = SaveChar;
  1207. for( ; *p && (*p != L' '); p++ ) {
  1208. Length++;
  1209. }
  1210. for( ; *p && (*p == L' '); p++ ) {
  1211. Length++;
  1212. }
  1213. if( *p ) {
  1214. wcscat( TemporaryBuffer, OldOsLoadOptions+Length );
  1215. }
  1216. OldOsLoadOptions = SpDupStringW( TemporaryBuffer );
  1217. OldOsLoadOptionsReplaced = TRUE;
  1218. }
  1219. SpMemFree( tmp );
  1220. }
  1221. }
  1222. tmp2 = TemporaryBuffer + (sizeof(TemporaryBuffer) / sizeof(WCHAR) / 2);
  1223. if (!SpIsEfi()) {
  1224. //
  1225. // Get an ARC name for the system partition.
  1226. //
  1227. if (SystemPartitionRegion != NULL) {
  1228. SpArcNameFromRegion(
  1229. SystemPartitionRegion,
  1230. tmp2,
  1231. sizeof(TemporaryBuffer)/2,
  1232. PartitionOrdinalOnDisk,
  1233. PrimaryArcPath
  1234. );
  1235. SystemPartitionArcName = SpDupStringW(tmp2);
  1236. } else {
  1237. SystemPartitionArcName = NULL;
  1238. }
  1239. //
  1240. // Get an ARC name for the target partition.
  1241. //
  1242. //
  1243. // If the partition is on a SCSI disk that has more than 1024 cylinders
  1244. // and the partition has sectors located on cylinders beyond cylinder
  1245. // 1024, the get the arc name in the secondary format. See also
  1246. // spcopy.c!SpCreateNtbootddSys().
  1247. //
  1248. if(
  1249. !SpIsArc() &&
  1250. #if defined(REMOTE_BOOT)
  1251. !RemoteBootSetup &&
  1252. #endif // defined(REMOTE_BOOT)
  1253. #ifdef _X86_
  1254. !SpUseBIOSToBoot(NtPartitionRegion, NULL, SifHandle) &&
  1255. #endif
  1256. (HardDisks[NtPartitionRegion->DiskNumber].ScsiMiniportShortname[0]) ) {
  1257. ArcPathType = SecondaryArcPath;
  1258. } else {
  1259. ArcPathType = PrimaryArcPath;
  1260. }
  1261. SpArcNameFromRegion(
  1262. NtPartitionRegion,
  1263. tmp2,
  1264. sizeof(TemporaryBuffer)/2,
  1265. PartitionOrdinalOnDisk,
  1266. ArcPathType
  1267. );
  1268. TargetPartitionArcName = SpDupStringW(tmp2);
  1269. }
  1270. //
  1271. // OSLOADOPTIONS is specified in the setup information file.
  1272. //
  1273. tmp = SpGetSectionKeyIndex(
  1274. WinntSifHandle,
  1275. SIF_SETUPDATA,
  1276. SIF_OSLOADOPTIONSVAR,
  1277. 0
  1278. );
  1279. if (tmp == NULL) {
  1280. tmp = SpGetSectionKeyIndex(
  1281. SifHandle,
  1282. SIF_SETUPDATA,
  1283. SIF_OSLOADOPTIONSVAR,
  1284. 0
  1285. );
  1286. }
  1287. //
  1288. // If OsLoadOptionsVar wasn't specified, then we'll preserve any flags
  1289. // the user had specified.
  1290. //
  1291. if(!tmp && OldOsLoadOptions) {
  1292. tmp = OldOsLoadOptions;
  1293. }
  1294. AddSosToBaseVideoString = BaseVideoOption;
  1295. AddBaseVideo = BaseVideoOption;
  1296. if(tmp) {
  1297. //
  1298. // make sure we don't already have a /basevideo option, so we
  1299. // won't add another
  1300. //
  1301. wcscpy(TemporaryBuffer, tmp);
  1302. SpStringToLower(TemporaryBuffer);
  1303. if(wcsstr(TemporaryBuffer, BaseVideoString)) { // already have /basevideo
  1304. BaseVideoOption = TRUE;
  1305. AddBaseVideo = FALSE;
  1306. }
  1307. if(wcsstr(TemporaryBuffer, BaseVideoSosString)) { // already have /sos
  1308. AddSosToBaseVideoString = FALSE;
  1309. }
  1310. #ifdef _X86_
  1311. if(wcsstr(TemporaryBuffer, BootFastString)) { // already have /bootfast
  1312. AddBootFastString = FALSE;
  1313. }
  1314. #endif
  1315. }
  1316. if(AddBaseVideo || AddSosToBaseVideoString
  1317. #ifdef _X86_
  1318. || AddBootFastString
  1319. #endif
  1320. ) {
  1321. Length = ((tmp ? wcslen(tmp) + 1 : 0) * sizeof(WCHAR));
  1322. if( AddBaseVideo ) {
  1323. Length += sizeof(BaseVideoString);
  1324. }
  1325. if( AddSosToBaseVideoString ) {
  1326. Length += sizeof( BaseVideoSosString );
  1327. }
  1328. #ifdef _X86_
  1329. if( AddBootFastString ) {
  1330. Length += sizeof( BootFastString );
  1331. }
  1332. #endif
  1333. tmp2 = SpMemAlloc(Length);
  1334. *tmp2 = ( WCHAR )'\0';
  1335. if( AddBaseVideo ) {
  1336. wcscat(tmp2, BaseVideoString);
  1337. }
  1338. if( AddSosToBaseVideoString ) {
  1339. if( *tmp2 != (WCHAR)'\0' ) {
  1340. wcscat(tmp2, L" ");
  1341. }
  1342. wcscat(tmp2, BaseVideoSosString);
  1343. }
  1344. #ifdef _X86_
  1345. if( AddBootFastString ) {
  1346. if( *tmp2 != (WCHAR)'\0' ) {
  1347. wcscat(tmp2, L" ");
  1348. }
  1349. wcscat(tmp2, BootFastString);
  1350. }
  1351. #endif
  1352. if(tmp) {
  1353. if( *tmp2 != (WCHAR)'\0' ) {
  1354. wcscat(tmp2, L" ");
  1355. }
  1356. wcscat(tmp2, tmp);
  1357. }
  1358. LoadOptions = SpDupStringW(tmp2);
  1359. SpMemFree(tmp2);
  1360. } else {
  1361. LoadOptions = SpDupStringW(tmp ? tmp : L"");
  1362. }
  1363. //
  1364. // Add on headless redirect parameter if we are redirecting right now.
  1365. //
  1366. Length = sizeof(HEADLESS_RSP_QUERY_INFO);
  1367. Status = HeadlessDispatch(HeadlessCmdQueryInformation,
  1368. NULL,
  1369. 0,
  1370. &Response,
  1371. &Length
  1372. );
  1373. if (NT_SUCCESS(Status) &&
  1374. (Response.PortType == HeadlessSerialPort) &&
  1375. Response.Serial.TerminalAttached) {
  1376. //
  1377. // Before we go adding a /redirect string, we need to make
  1378. // sure there's not already one.
  1379. //
  1380. if( !wcsstr(LoadOptions, HeadlessRedirectString) ) {
  1381. Length = (wcslen(LoadOptions) + 1) * sizeof(WCHAR);
  1382. Length += sizeof(HeadlessRedirectString);
  1383. tmp2 = SpMemAlloc(Length);
  1384. ASSERT(tmp2 != NULL);
  1385. *tmp2 = UNICODE_NULL;
  1386. wcscat(tmp2, LoadOptions);
  1387. if (*tmp2 != UNICODE_NULL) {
  1388. wcscat(tmp2, L" ");
  1389. }
  1390. wcscat(tmp2, HeadlessRedirectString);
  1391. SpMemFree(LoadOptions);
  1392. LoadOptions = tmp2;
  1393. }
  1394. }
  1395. //
  1396. // LOADIDENTIFIER is specified in the setup information file.
  1397. // We need to surround it in double quotes.
  1398. // Which value to use depends on the BaseVideo flag.
  1399. //
  1400. SifKeyName = BaseVideoOption ? SIF_BASEVIDEOLOADID : SIF_LOADIDENTIFIER;
  1401. tmp = SpGetSectionKeyIndex(SifHandle,SIF_SETUPDATA,SifKeyName,0);
  1402. if(!tmp) {
  1403. SpFatalSifError(SifHandle,SIF_SETUPDATA,SifKeyName,0,0);
  1404. }
  1405. if(!SpIsArc()) {
  1406. //
  1407. // Need quotation marks around the description on x86.
  1408. //
  1409. LoadIdentifier = SpMemAlloc((wcslen(tmp)+3)*sizeof(WCHAR));
  1410. LoadIdentifier[0] = L'\"';
  1411. wcscpy(LoadIdentifier+1,tmp);
  1412. wcscat(LoadIdentifier,L"\"");
  1413. } else {
  1414. LoadIdentifier = SpDupStringW(tmp);
  1415. }
  1416. //
  1417. // Create a new internal-format boot entry.
  1418. //
  1419. tmp = TemporaryBuffer;
  1420. wcscpy(tmp,SystemPartitionDirectory);
  1421. SpConcatenatePaths(
  1422. tmp,
  1423. #ifdef _X86_
  1424. SpIsArc() ? L"arcldr.exe" : L"ntldr"
  1425. #elif _IA64_
  1426. L"ia64ldr.efi"
  1427. #else
  1428. L"osloader.exe"
  1429. #endif
  1430. );
  1431. tmp = SpDupStringW(tmp);
  1432. SpCreateBootEntry(
  1433. BE_STATUS_NEW,
  1434. SystemPartitionRegion,
  1435. tmp,
  1436. NtPartitionRegion,
  1437. Sysroot,
  1438. LoadOptions,
  1439. LoadIdentifier
  1440. );
  1441. SpMemFree(tmp);
  1442. //
  1443. // If not on an EFI machine, add a new ARC-style boot set.
  1444. //
  1445. if (!SpIsEfi()) {
  1446. BootVars[OSLOADOPTIONS] = LoadOptions;
  1447. BootVars[LOADIDENTIFIER] = LoadIdentifier;
  1448. //
  1449. // OSLOADER is the system partition path + the system partition directory +
  1450. // osloader.exe. (ntldr on x86 machines).
  1451. //
  1452. if (SystemPartitionRegion != NULL) {
  1453. tmp = TemporaryBuffer;
  1454. wcscpy(tmp,SystemPartitionArcName);
  1455. SpConcatenatePaths(tmp,SystemPartitionDirectory);
  1456. SpConcatenatePaths(
  1457. tmp,
  1458. #ifdef _X86_
  1459. (SpIsArc() ? L"arcldr.exe" : L"ntldr")
  1460. #elif _IA64_
  1461. L"ia64ldr.efi"
  1462. #else
  1463. L"osloader.exe"
  1464. #endif
  1465. );
  1466. BootVars[OSLOADER] = SpDupStringW(tmp);
  1467. } else {
  1468. BootVars[OSLOADER] = SpDupStringW(L"");
  1469. }
  1470. //
  1471. // OSLOADPARTITION is the ARC name of the windows nt partition.
  1472. //
  1473. BootVars[OSLOADPARTITION] = TargetPartitionArcName;
  1474. //
  1475. // OSLOADFILENAME is sysroot.
  1476. //
  1477. BootVars[OSLOADFILENAME] = Sysroot;
  1478. //
  1479. // SYSTEMPARTITION is the ARC name of the system partition.
  1480. //
  1481. if (SystemPartitionRegion != NULL) {
  1482. BootVars[SYSTEMPARTITION] = SystemPartitionArcName;
  1483. } else {
  1484. BootVars[SYSTEMPARTITION] = L"";
  1485. }
  1486. //
  1487. // get the disk signature
  1488. //
  1489. if ((NtPartitionRegion->DiskNumber != 0xffffffff) && HardDisks[NtPartitionRegion->DiskNumber].Signature) {
  1490. Signature = HardDisks[NtPartitionRegion->DiskNumber].Signature;
  1491. } else {
  1492. Signature = 0;
  1493. }
  1494. //
  1495. // Add the boot set and make it the default.
  1496. //
  1497. SpAddBootSet(BootVars, TRUE, Signature);
  1498. SpMemFree(BootVars[OSLOADER]);
  1499. }
  1500. //
  1501. // Free memory allocated.
  1502. //
  1503. SpMemFree(LoadOptions);
  1504. SpMemFree(LoadIdentifier);
  1505. if (!SpIsEfi()) {
  1506. if (SystemPartitionArcName != NULL) {
  1507. SpMemFree(SystemPartitionArcName);
  1508. }
  1509. SpMemFree(TargetPartitionArcName);
  1510. }
  1511. if( OldOsLoadOptionsReplaced ) {
  1512. SpMemFree( OldOsLoadOptions );
  1513. }
  1514. }
  1515. VOID
  1516. SpCompleteBootListConfig(
  1517. WCHAR DriveLetter
  1518. )
  1519. {
  1520. if(!RepairWinnt) {
  1521. if (!SpIsArc()) {
  1522. Timeout = 1;
  1523. } else {
  1524. Timeout = 5;
  1525. //
  1526. // If this is a winnt setup, there will be a boot set to start
  1527. // text setup ("Install/Upgrade Windows NT"). Remove it here.
  1528. //
  1529. if(WinntSetup) {
  1530. PSP_BOOT_ENTRY bootEntry;
  1531. for (bootEntry = SpBootEntries; bootEntry != NULL; bootEntry = bootEntry->Next) {
  1532. if (IS_BOOT_ENTRY_WINDOWS(bootEntry) &&
  1533. !IS_BOOT_ENTRY_DELETED(bootEntry) &&
  1534. (_wcsicmp(bootEntry->OsLoadOptions, L"WINNT32") == 0)) {
  1535. bootEntry->Status |= BE_STATUS_DELETED;
  1536. }
  1537. }
  1538. if (!SpIsEfi()) {
  1539. PWSTR BootVars[MAXBOOTVARS];
  1540. RtlZeroMemory(BootVars,sizeof(BootVars));
  1541. BootVars[OSLOADOPTIONS] = L"WINNT32";
  1542. SpDeleteBootSet(BootVars, NULL);
  1543. }
  1544. }
  1545. }
  1546. }
  1547. #ifdef _X86_
  1548. if (g_Win9xBackup) {
  1549. SpRemoveExtraBootIniEntry();
  1550. }
  1551. #endif
  1552. //
  1553. // Flush boot vars.
  1554. // On some machines, NVRAM update takes a few seconds,
  1555. // so change the message to tell the user we are doing something different.
  1556. //
  1557. SpDisplayStatusText(SP_STAT_UPDATING_NVRAM,DEFAULT_STATUS_ATTRIBUTE);
  1558. if(!SpFlushBootVars()) {
  1559. if(SpIsEfi() || !SpIsArc()) {
  1560. //
  1561. // Fatal on x86 and EFI machines, nonfatal on arc machines.
  1562. //
  1563. if (SpIsEfi()) {
  1564. SpStartScreen(SP_SCRN_CANT_INIT_FLEXBOOT_EFI,
  1565. 3,
  1566. HEADER_HEIGHT+1,
  1567. FALSE,
  1568. FALSE,
  1569. DEFAULT_ATTRIBUTE
  1570. );
  1571. } else {
  1572. WCHAR DriveLetterString[2];
  1573. DriveLetterString[0] = DriveLetter;
  1574. DriveLetterString[1] = L'\0';
  1575. SpStringToUpper(DriveLetterString);
  1576. SpStartScreen(SP_SCRN_CANT_INIT_FLEXBOOT,
  1577. 3,
  1578. HEADER_HEIGHT+1,
  1579. FALSE,
  1580. FALSE,
  1581. DEFAULT_ATTRIBUTE,
  1582. DriveLetterString,
  1583. DriveLetterString
  1584. );
  1585. }
  1586. SpDisplayStatusText(SP_STAT_F3_EQUALS_EXIT,DEFAULT_STATUS_ATTRIBUTE);
  1587. SpInputDrain();
  1588. while(SpInputGetKeypress() != KEY_F3) ;
  1589. SpDone(0,FALSE,TRUE);
  1590. } else {
  1591. BOOL b;
  1592. b = TRUE;
  1593. while(b) {
  1594. ULONG ValidKeys[2] = { ASCI_CR, 0 };
  1595. SpStartScreen(
  1596. SP_SCRN_CANT_UPDATE_BOOTVARS,
  1597. 3,
  1598. HEADER_HEIGHT+1,
  1599. FALSE,
  1600. FALSE,
  1601. DEFAULT_ATTRIBUTE,
  1602. NewBootVars[LOADIDENTIFIER],
  1603. NewBootVars[OSLOADER],
  1604. NewBootVars[OSLOADPARTITION],
  1605. NewBootVars[OSLOADFILENAME],
  1606. NewBootVars[OSLOADOPTIONS],
  1607. NewBootVars[SYSTEMPARTITION]
  1608. );
  1609. SpDisplayStatusOptions(
  1610. DEFAULT_STATUS_ATTRIBUTE,
  1611. SP_STAT_ENTER_EQUALS_CONTINUE,
  1612. 0
  1613. );
  1614. switch(SpWaitValidKey(ValidKeys,NULL,NULL)) {
  1615. case ASCI_CR:
  1616. b = FALSE;
  1617. }
  1618. }
  1619. }
  1620. }
  1621. if(SpIsArc() && !SpIsEfi()) {
  1622. // Free all of the boot variable strings
  1623. BOOTVAR i;
  1624. for(i = FIRSTBOOTVAR; i <= LASTBOOTVAR; i++) {
  1625. SpMemFree(NewBootVars[i]);
  1626. NewBootVars[i] = NULL;
  1627. }
  1628. }
  1629. }
  1630. VOID
  1631. SpPtDeleteBootSetsForRegion(
  1632. PDISK_REGION Region
  1633. )
  1634. /*++
  1635. Routine Description:
  1636. This routine goes through all the valid boot entries and
  1637. deletes the ones which point to the specified region.
  1638. Arguments:
  1639. Region : The region whose references from boot entries need
  1640. to be removed
  1641. Return Value:
  1642. None.
  1643. --*/
  1644. {
  1645. PWSTR bootSet[MAXBOOTVARS];
  1646. ENUMARCPATHTYPE arcPathType;
  1647. ULONG i;
  1648. PSP_BOOT_ENTRY bootEntry;
  1649. if (Region->PartitionedSpace) {
  1650. BOOLEAN IsSystemPartition = SPPT_IS_REGION_SYSTEMPARTITION(Region);
  1651. //
  1652. // Find all boot entries that have the specified region as the
  1653. // OS load partition, and mark them for deletion.
  1654. //
  1655. for (bootEntry = SpBootEntries; bootEntry != NULL; bootEntry = bootEntry->Next) {
  1656. if (IS_BOOT_ENTRY_WINDOWS(bootEntry) &&
  1657. !IS_BOOT_ENTRY_DELETED(bootEntry) &&
  1658. (IsSystemPartition ? (bootEntry->LoaderPartitionDiskRegion == Region) :
  1659. (bootEntry->OsPartitionDiskRegion == Region))) {
  1660. bootEntry->Status |= BE_STATUS_DELETED;
  1661. //
  1662. // Make the regions also NULL since they might have actually
  1663. // been deleted
  1664. //
  1665. bootEntry->LoaderPartitionDiskRegion = NULL;
  1666. bootEntry->OsPartitionDiskRegion = NULL;
  1667. }
  1668. }
  1669. //
  1670. // If we're not on an EFI machine, we also have to munge the ARC
  1671. // boot variables.
  1672. //
  1673. if (!SpIsEfi()) {
  1674. //
  1675. // Set up the boot set
  1676. //
  1677. for (i = FIRSTBOOTVAR; i <= LASTBOOTVAR; i++) {
  1678. bootSet[i] = NULL;
  1679. }
  1680. //
  1681. // We go through this loop twice, once for primary ARC path
  1682. // and once for secondary. We delete any image which has
  1683. // the OS load partition on the region we are deleting.
  1684. //
  1685. for (i = 0; i < 2; i++) {
  1686. if (i == 0) {
  1687. arcPathType = PrimaryArcPath;
  1688. } else {
  1689. arcPathType = SecondaryArcPath;
  1690. }
  1691. SpArcNameFromRegion(
  1692. Region,
  1693. TemporaryBuffer,
  1694. sizeof(TemporaryBuffer),
  1695. PartitionOrdinalOnDisk,
  1696. arcPathType);
  1697. if ((TemporaryBuffer)[0] != L'\0') {
  1698. ULONG Index = IsSystemPartition ?
  1699. SYSTEMPARTITION : OSLOADPARTITION;
  1700. bootSet[Index] = SpDupStringW(TemporaryBuffer);
  1701. SpDeleteBootSet(bootSet, NULL);
  1702. SpMemFree(bootSet[Index]);
  1703. }
  1704. }
  1705. }
  1706. }
  1707. }
  1708. VOID
  1709. SpGetNtDirectoryList(
  1710. OUT PWSTR **DirectoryList,
  1711. OUT PULONG DirectoryCount
  1712. )
  1713. /*++
  1714. Routine Description:
  1715. Determine the list of directories into which NT may be installed.
  1716. This is independent of the partitions onto which it may be installed.
  1717. The determination of which directories nt might be in is based on
  1718. boot.ini in the x86 case, or on arc firmware (OSLOADFILENAME var)
  1719. in the arc case.
  1720. Arguments:
  1721. DirectoryList - receives a pointer to an array of strings,
  1722. each of which contains a possible windows nt tree.
  1723. DirectoryCount - receives the number of elements in DirectoryList.
  1724. This may be 0.
  1725. Return Value:
  1726. None. The caller must free the array in DirectoryList if
  1727. DirectoryCount is returned as non-0.
  1728. --*/
  1729. {
  1730. ULONG count;
  1731. PSP_BOOT_ENTRY BootEntry;
  1732. PSP_BOOT_ENTRY BootEntry2;
  1733. PWSTR *DirList;
  1734. //
  1735. // Free any previously allocated list.
  1736. //
  1737. if (CurrentNtDirectoryList != NULL) {
  1738. SpMemFree(CurrentNtDirectoryList);
  1739. }
  1740. //
  1741. // Walk the boot entry list to determine how many unique NT directory names
  1742. // exist.
  1743. //
  1744. count = 0;
  1745. for (BootEntry = SpBootEntries; BootEntry != NULL; BootEntry = BootEntry->Next) {
  1746. if (!IS_BOOT_ENTRY_WINDOWS(BootEntry) || (BootEntry->OsDirectory == NULL)) {
  1747. continue;
  1748. }
  1749. for (BootEntry2 = SpBootEntries; BootEntry2 != BootEntry; BootEntry2 = BootEntry2->Next) {
  1750. if (!IS_BOOT_ENTRY_WINDOWS(BootEntry2) || (BootEntry2->OsDirectory == NULL)) {
  1751. continue;
  1752. }
  1753. if (_wcsicmp(BootEntry2->OsDirectory, BootEntry->OsDirectory) == 0) {
  1754. break;
  1755. }
  1756. }
  1757. if (BootEntry2 == BootEntry) {
  1758. count++;
  1759. }
  1760. }
  1761. //
  1762. // Allocate space for the list.
  1763. //
  1764. DirList = SpMemAlloc(count * sizeof(PWSTR));
  1765. ASSERT(DirList != NULL);
  1766. //
  1767. // Populate the list.
  1768. //
  1769. count = 0;
  1770. for (BootEntry = SpBootEntries; BootEntry != NULL; BootEntry = BootEntry->Next) {
  1771. if (!IS_BOOT_ENTRY_WINDOWS(BootEntry) || (BootEntry->OsDirectory == NULL)) {
  1772. continue;
  1773. }
  1774. for (BootEntry2 = SpBootEntries; BootEntry2 != BootEntry; BootEntry2 = BootEntry2->Next) {
  1775. if (!IS_BOOT_ENTRY_WINDOWS(BootEntry2) || (BootEntry2->OsDirectory == NULL)) {
  1776. continue;
  1777. }
  1778. if (_wcsicmp(BootEntry2->OsDirectory, BootEntry->OsDirectory) == 0) {
  1779. break;
  1780. }
  1781. }
  1782. if (BootEntry2 == BootEntry) {
  1783. DirList[count++] = BootEntry->OsDirectory;
  1784. }
  1785. }
  1786. //
  1787. // Return a pointer to the list that we allocated.
  1788. //
  1789. CurrentNtDirectoryList = DirList;
  1790. *DirectoryList = DirList;
  1791. *DirectoryCount = count;
  1792. return;
  1793. }
  1794. BOOLEAN
  1795. SpConvertArcBootEntries (
  1796. IN ULONG MaxComponents
  1797. )
  1798. /*++
  1799. Routine Description:
  1800. Convert ARC boot entries (read from boot.ini or from ARC NVRAM) into
  1801. our internal format.
  1802. Arguments:
  1803. MaxComponents - maximum number of elements in any NVRAM variable.
  1804. Return Value:
  1805. BOOLEAN - FALSE if any unexpected errors occurred.
  1806. --*/
  1807. {
  1808. LONG i;
  1809. PDISK_REGION systemPartitionRegion;
  1810. PDISK_REGION ntPartitionRegion;
  1811. PWSTR loaderName;
  1812. for (i = (LONG)MaxComponents - 1; i >= 0; i--) {
  1813. //
  1814. // Skip this boot set if it is not complete.
  1815. //
  1816. if ((BootVars[SYSTEMPARTITION][i] != NULL) &&
  1817. (BootVars[OSLOADPARTITION][i] != NULL) &&
  1818. (BootVars[OSLOADER][i] != NULL) &&
  1819. (BootVars[OSLOADFILENAME][i] != NULL) &&
  1820. (BootVars[OSLOADOPTIONS][i] != NULL) &&
  1821. (BootVars[LOADIDENTIFIER][i] != NULL)) {
  1822. //
  1823. // Translate the SYSTEMPARTITION and OSLOADPARTITION ARC names
  1824. // into disk region pointers. Get the loader file name from
  1825. // OSLOADER, which contains an ARC name (same as OSLOADPARTITION)
  1826. // and a file name.
  1827. //
  1828. systemPartitionRegion = SpRegionFromArcName(
  1829. BootVars[SYSTEMPARTITION][i],
  1830. PartitionOrdinalCurrent,
  1831. NULL
  1832. );
  1833. ntPartitionRegion = SpRegionFromArcName(
  1834. BootVars[OSLOADPARTITION][i],
  1835. PartitionOrdinalCurrent,
  1836. NULL
  1837. );
  1838. //
  1839. // Take care of duplicate arc names for the same disk by searching
  1840. // and validating the NT directory is present on the partition
  1841. //
  1842. while (ntPartitionRegion &&
  1843. !SpIsNtInDirectory(ntPartitionRegion, BootVars[OSLOADFILENAME][i])) {
  1844. //
  1845. // Continue to look for same name region from the current
  1846. // searched region
  1847. //
  1848. ntPartitionRegion = SpRegionFromArcName(
  1849. BootVars[OSLOADPARTITION][i],
  1850. PartitionOrdinalCurrent,
  1851. ntPartitionRegion
  1852. );
  1853. }
  1854. loaderName = wcschr(BootVars[OSLOADER][i], L'\\');
  1855. //
  1856. // If all of the above worked, then add an internal-format boot
  1857. // entry for this ARC boot set.
  1858. //
  1859. if ((systemPartitionRegion != NULL) &&
  1860. (ntPartitionRegion != NULL) &&
  1861. (loaderName != NULL)) {
  1862. SpCreateBootEntry(
  1863. BE_STATUS_FROM_BOOT_INI,
  1864. systemPartitionRegion,
  1865. loaderName,
  1866. ntPartitionRegion,
  1867. BootVars[OSLOADFILENAME][i],
  1868. BootVars[OSLOADOPTIONS][i],
  1869. BootVars[LOADIDENTIFIER][i]
  1870. );
  1871. }
  1872. }
  1873. }
  1874. return TRUE;
  1875. }
  1876. VOID
  1877. SpUpdateRegionForBootEntries(
  1878. VOID
  1879. )
  1880. /*++
  1881. Routine Description:
  1882. Update the region pointers for all the given boot entries.
  1883. NOTE : The region pointers change with every commit so we
  1884. can't cache them across commits.
  1885. Arguments:
  1886. None.
  1887. Return Value:
  1888. None.
  1889. --*/
  1890. {
  1891. PSP_BOOT_ENTRY BootEntry;
  1892. //
  1893. // Walk through each boot entry and update its system partition region
  1894. // pointer and NT partition region pointer.
  1895. //
  1896. for (BootEntry = SpBootEntries; BootEntry != NULL; BootEntry = BootEntry->Next) {
  1897. if (!IS_BOOT_ENTRY_DELETED(BootEntry)) {
  1898. if (BootEntry->LoaderPartitionNtName != NULL) {
  1899. BootEntry->LoaderPartitionDiskRegion =
  1900. SpRegionFromNtName(BootEntry->LoaderPartitionNtName,
  1901. PartitionOrdinalCurrent);
  1902. } else {
  1903. BootEntry->LoaderPartitionDiskRegion = NULL;
  1904. }
  1905. if (BootEntry->OsPartitionNtName != NULL) {
  1906. BootEntry->OsPartitionDiskRegion =
  1907. SpRegionFromNtName(BootEntry->OsPartitionNtName,
  1908. PartitionOrdinalCurrent);
  1909. } else {
  1910. BootEntry->OsPartitionDiskRegion = NULL;
  1911. }
  1912. }
  1913. }
  1914. return;
  1915. } // SpUpdateRegionForBootEntries
  1916. VOID
  1917. SpCreateBootEntry (
  1918. IN ULONG_PTR Status,
  1919. IN PDISK_REGION BootFileRegion,
  1920. IN PWSTR BootFilePath,
  1921. IN PDISK_REGION OsLoadRegion,
  1922. IN PWSTR OsLoadPath,
  1923. IN PWSTR OsLoadOptions,
  1924. IN PWSTR FriendlyName
  1925. )
  1926. /*++
  1927. Routine Description:
  1928. Create an internal-format boot entry.
  1929. Arguments:
  1930. Status - The status to be assigned to the boot entry. This should be either
  1931. zero (for an entry already in NVRAM) or BE_STATUS_NEW for a new boot
  1932. entry. Entries marked BE_STATUS_NEW are written to NVRAM at the end
  1933. of textmode setup.
  1934. BootFileRegion - The disk region on which the OS loader resides.
  1935. BootFilePath - The volume-relative path to the OS loader. Must start with
  1936. a backslash.
  1937. OsLoadRegion - The disk region on which the OS resides.
  1938. OsLoadPath - The volume-relative path to the OS root directory (\WINDOWS).
  1939. Must start with a backslash.
  1940. OsLoadOptions - Boot options for the OS. Can be an empty string.
  1941. FriendlyName - The user-visible name for the boot entry. (This is ARC's
  1942. LOADIDENTIFIER.)
  1943. Return Value:
  1944. None. Only memory allocation failures are possible, and these are
  1945. handled out-of-band.
  1946. --*/
  1947. {
  1948. NTSTATUS status;
  1949. ULONG requiredLength;
  1950. ULONG osOptionsOffset;
  1951. ULONG osLoadOptionsLength;
  1952. ULONG osLoadPathOffset;
  1953. ULONG osLoadPathLength;
  1954. ULONG osOptionsLength;
  1955. ULONG friendlyNameOffset;
  1956. ULONG friendlyNameLength;
  1957. ULONG bootPathOffset;
  1958. ULONG bootPathLength;
  1959. PSP_BOOT_ENTRY myBootEntry;
  1960. PSP_BOOT_ENTRY previousBootEntry;
  1961. PSP_BOOT_ENTRY nextBootEntry;
  1962. PBOOT_ENTRY ntBootEntry;
  1963. PWINDOWS_OS_OPTIONS osOptions;
  1964. PFILE_PATH osLoadPath;
  1965. PWSTR friendlyName;
  1966. PFILE_PATH bootPath;
  1967. PWSTR p;
  1968. PWSTR bootFileDevice;
  1969. PWSTR osLoadDevice;
  1970. //
  1971. // Get NT names for the input disk regions.
  1972. //
  1973. bootFileDevice = SpMemAlloc(512);
  1974. SpNtNameFromRegion(BootFileRegion, bootFileDevice, 512, PartitionOrdinalCurrent);
  1975. osLoadDevice = SpMemAlloc(512);
  1976. SpNtNameFromRegion(OsLoadRegion, osLoadDevice, 512, PartitionOrdinalCurrent);
  1977. //
  1978. // Calculate how long the internal boot entry needs to be. This includes
  1979. // our internal structure, plus the BOOT_ENTRY structure that the NT APIs
  1980. // use.
  1981. //
  1982. // Our structure:
  1983. //
  1984. requiredLength = FIELD_OFFSET(SP_BOOT_ENTRY, NtBootEntry);
  1985. //
  1986. // Base part of NT structure:
  1987. //
  1988. requiredLength += FIELD_OFFSET(BOOT_ENTRY, OsOptions);
  1989. //
  1990. // Save offset to BOOT_ENTRY.OsOptions. Add in base part of
  1991. // WINDOWS_OS_OPTIONS. Calculate length in bytes of OsLoadOptions
  1992. // and add that in.
  1993. //
  1994. osOptionsOffset = requiredLength;
  1995. requiredLength += FIELD_OFFSET(WINDOWS_OS_OPTIONS, OsLoadOptions);
  1996. osLoadOptionsLength = (wcslen(OsLoadOptions) + 1) * sizeof(WCHAR);
  1997. requiredLength += osLoadOptionsLength;
  1998. //
  1999. // Round up to a ULONG boundary for the OS FILE_PATH in the
  2000. // WINDOWS_OS_OPTIONS. Save offset to OS FILE_PATH. Add in base part
  2001. // of FILE_PATH. Add in length in bytes of OS device NT name and OS
  2002. // directory. Calculate total length of OS FILE_PATH and of
  2003. // WINDOWS_OS_OPTIONS.
  2004. //
  2005. requiredLength = ALIGN_UP(requiredLength, ULONG);
  2006. osLoadPathOffset = requiredLength;
  2007. requiredLength += FIELD_OFFSET(FILE_PATH, FilePath);
  2008. requiredLength += (wcslen(osLoadDevice) + 1 + wcslen(OsLoadPath) + 1) * sizeof(WCHAR);
  2009. osLoadPathLength = requiredLength - osLoadPathOffset;
  2010. osOptionsLength = requiredLength - osOptionsOffset;
  2011. //
  2012. // Round up to a ULONG boundary for the friendly name in the BOOT_ENTRY.
  2013. // Save offset to friendly name. Calculate length in bytes of friendly name
  2014. // and add that in.
  2015. //
  2016. requiredLength = ALIGN_UP(requiredLength, ULONG);
  2017. friendlyNameOffset = requiredLength;
  2018. friendlyNameLength = (wcslen(FriendlyName) + 1) * sizeof(WCHAR);
  2019. requiredLength += friendlyNameLength;
  2020. //
  2021. // Round up to a ULONG boundary for the boot FILE_PATH in the BOOT_ENTRY.
  2022. // Save offset to boot FILE_PATH. Add in base part of FILE_PATH. Add in
  2023. // length in bytes of boot device NT name and boot file. Calculate total
  2024. // length of boot FILE_PATH.
  2025. //
  2026. requiredLength = ALIGN_UP(requiredLength, ULONG);
  2027. bootPathOffset = requiredLength;
  2028. requiredLength += FIELD_OFFSET(FILE_PATH, FilePath);
  2029. requiredLength += (wcslen(bootFileDevice) + 1 + wcslen(BootFilePath) + 1) * sizeof(WCHAR);
  2030. bootPathLength = requiredLength - bootPathOffset;
  2031. //
  2032. // Allocate memory for the boot entry.
  2033. //
  2034. myBootEntry = SpMemAlloc(requiredLength);
  2035. ASSERT(myBootEntry != NULL);
  2036. RtlZeroMemory(myBootEntry, requiredLength);
  2037. //
  2038. // Calculate addresses of various substructures using the saved offsets.
  2039. //
  2040. ntBootEntry = &myBootEntry->NtBootEntry;
  2041. osOptions = (PWINDOWS_OS_OPTIONS)ntBootEntry->OsOptions;
  2042. osLoadPath = (PFILE_PATH)((PUCHAR)myBootEntry + osLoadPathOffset);
  2043. friendlyName = (PWSTR)((PUCHAR)myBootEntry + friendlyNameOffset);
  2044. bootPath = (PFILE_PATH)((PUCHAR)myBootEntry + bootPathOffset);
  2045. //
  2046. // Fill in the internal-format structure.
  2047. //
  2048. myBootEntry->AllocationEnd = (PUCHAR)myBootEntry + requiredLength;
  2049. myBootEntry->Status = Status | BE_STATUS_ORDERED;
  2050. myBootEntry->FriendlyName = friendlyName;
  2051. myBootEntry->FriendlyNameLength = friendlyNameLength;
  2052. myBootEntry->OsLoadOptions = osOptions->OsLoadOptions;
  2053. myBootEntry->OsLoadOptionsLength = osLoadOptionsLength;
  2054. myBootEntry->LoaderPath = bootPath;
  2055. myBootEntry->OsPath = osLoadPath;
  2056. myBootEntry->LoaderPartitionDiskRegion = BootFileRegion;
  2057. myBootEntry->OsPartitionDiskRegion = OsLoadRegion;
  2058. //
  2059. // Fill in the base part of the NT boot entry.
  2060. //
  2061. ntBootEntry->Version = BOOT_ENTRY_VERSION;
  2062. ntBootEntry->Length = requiredLength - FIELD_OFFSET(SP_BOOT_ENTRY, NtBootEntry);
  2063. ntBootEntry->Attributes = BOOT_ENTRY_ATTRIBUTE_ACTIVE | BOOT_ENTRY_ATTRIBUTE_WINDOWS;
  2064. ntBootEntry->FriendlyNameOffset = (ULONG)((PUCHAR)friendlyName - (PUCHAR)ntBootEntry);
  2065. ntBootEntry->BootFilePathOffset = (ULONG)((PUCHAR)bootPath - (PUCHAR)ntBootEntry);
  2066. ntBootEntry->OsOptionsLength = osOptionsLength;
  2067. //
  2068. // Fill in the base part of the WINDOWS_OS_OPTIONS, including the
  2069. // OsLoadOptions.
  2070. //
  2071. strcpy(osOptions->Signature, WINDOWS_OS_OPTIONS_SIGNATURE);
  2072. osOptions->Version = WINDOWS_OS_OPTIONS_VERSION;
  2073. osOptions->Length = osOptionsLength;
  2074. osOptions->OsLoadPathOffset = (ULONG)((PUCHAR)osLoadPath - (PUCHAR)osOptions);
  2075. wcscpy(osOptions->OsLoadOptions, OsLoadOptions);
  2076. //
  2077. // Fill in the OS FILE_PATH.
  2078. //
  2079. osLoadPath->Version = FILE_PATH_VERSION;
  2080. osLoadPath->Length = osLoadPathLength;
  2081. osLoadPath->Type = FILE_PATH_TYPE_NT;
  2082. p = (PWSTR)osLoadPath->FilePath;
  2083. myBootEntry->OsPartitionNtName = p;
  2084. wcscpy(p, osLoadDevice);
  2085. p += wcslen(p) + 1;
  2086. myBootEntry->OsDirectory = p;
  2087. wcscpy(p, OsLoadPath);
  2088. //
  2089. // Copy the friendly name.
  2090. //
  2091. wcscpy(friendlyName, FriendlyName);
  2092. //
  2093. // Fill in the boot FILE_PATH.
  2094. //
  2095. bootPath->Version = FILE_PATH_VERSION;
  2096. bootPath->Length = bootPathLength;
  2097. bootPath->Type = FILE_PATH_TYPE_NT;
  2098. p = (PWSTR)bootPath->FilePath;
  2099. myBootEntry->LoaderPartitionNtName = p;
  2100. wcscpy(p, bootFileDevice);
  2101. p += wcslen(p) + 1;
  2102. myBootEntry->LoaderFile = p;
  2103. wcscpy(p, BootFilePath);
  2104. //
  2105. // Link the new boot entry into the list, after any removable media
  2106. // entries that are at the front of the list.
  2107. //
  2108. previousBootEntry = NULL;
  2109. nextBootEntry = SpBootEntries;
  2110. while ((nextBootEntry != NULL) &&
  2111. IS_BOOT_ENTRY_REMOVABLE_MEDIA(nextBootEntry)) {
  2112. previousBootEntry = nextBootEntry;
  2113. nextBootEntry = nextBootEntry->Next;
  2114. }
  2115. myBootEntry->Next = nextBootEntry;
  2116. if (previousBootEntry == NULL) {
  2117. SpBootEntries = myBootEntry;
  2118. } else {
  2119. previousBootEntry->Next = myBootEntry;
  2120. }
  2121. //
  2122. // Free local memory.
  2123. //
  2124. SpMemFree(bootFileDevice);
  2125. SpMemFree(osLoadDevice);
  2126. return;
  2127. } // SpCreateBootEntry
  2128. #if defined(EFI_NVRAM_ENABLED)
  2129. BOOLEAN
  2130. SpBuildHarddiskNameTranslations (
  2131. VOID
  2132. )
  2133. /*++
  2134. Routine Description:
  2135. Build a list of the translations of all \Device\HarddiskN\PartitionM
  2136. symbolic links to \Device\HarddiskVolumeN device names.
  2137. Arguments:
  2138. None.
  2139. Return Value:
  2140. BOOLEAN - FALSE if an unexpected error occurred.
  2141. --*/
  2142. {
  2143. NTSTATUS status;
  2144. OBJECT_ATTRIBUTES obja;
  2145. UNICODE_STRING unicodeString;
  2146. HANDLE deviceHandle;
  2147. HANDLE diskHandle;
  2148. HANDLE linkHandle;
  2149. PUCHAR buffer1;
  2150. PUCHAR buffer2;
  2151. BOOLEAN restartScan;
  2152. ULONG context1;
  2153. ULONG context2;
  2154. POBJECT_DIRECTORY_INFORMATION dirInfo1;
  2155. POBJECT_DIRECTORY_INFORMATION dirInfo2;
  2156. PWSTR linkName;
  2157. PWSTR p;
  2158. PHARDDISK_NAME_TRANSLATION translation;
  2159. //
  2160. // Allocate buffers for directory queries.
  2161. //
  2162. #define BUFFER_SIZE 2048
  2163. buffer1 = SpMemAlloc(BUFFER_SIZE);
  2164. buffer2 = SpMemAlloc(BUFFER_SIZE);
  2165. //
  2166. // Open the \Device directory.
  2167. //
  2168. INIT_OBJA(&obja, &unicodeString, L"\\device");
  2169. status = ZwOpenDirectoryObject(&deviceHandle, DIRECTORY_ALL_ACCESS, &obja);
  2170. if (!NT_SUCCESS(status)) {
  2171. ASSERT(FALSE);
  2172. goto cleanup;
  2173. }
  2174. restartScan = TRUE;
  2175. context1 = 0;
  2176. do {
  2177. //
  2178. // Search the \Device directory for HarddiskN subdirectories.
  2179. //
  2180. status = ZwQueryDirectoryObject(
  2181. deviceHandle,
  2182. buffer1,
  2183. BUFFER_SIZE,
  2184. TRUE,
  2185. restartScan,
  2186. &context1,
  2187. NULL
  2188. );
  2189. restartScan = FALSE;
  2190. if (!NT_SUCCESS(status)) {
  2191. if (status != STATUS_NO_MORE_ENTRIES) {
  2192. ASSERT(FALSE);
  2193. goto cleanup;
  2194. }
  2195. status = STATUS_SUCCESS;
  2196. break;
  2197. }
  2198. //
  2199. // We only care about directories with HarddiskN names.
  2200. //
  2201. dirInfo1 = (POBJECT_DIRECTORY_INFORMATION)buffer1;
  2202. if ((dirInfo1->Name.Length < sizeof(L"harddisk")) ||
  2203. (dirInfo1->TypeName.Length < (sizeof(L"Directory") - sizeof(WCHAR))) ||
  2204. (_wcsnicmp(dirInfo1->TypeName.Buffer,L"Directory",wcslen(L"Directory")) != 0)) {
  2205. continue;
  2206. }
  2207. SpStringToLower(dirInfo1->Name.Buffer);
  2208. if (wcsncmp(dirInfo1->Name.Buffer, L"harddisk", wcslen(L"harddisk")) != 0) {
  2209. continue;
  2210. }
  2211. p = dirInfo1->Name.Buffer + wcslen(L"Harddisk");
  2212. if (*p == 0) {
  2213. continue;
  2214. }
  2215. do {
  2216. if ((*p < L'0') || (*p > L'9')) {
  2217. break;
  2218. }
  2219. p++;
  2220. } while (*p != 0);
  2221. if (*p != 0) {
  2222. continue;
  2223. }
  2224. //
  2225. // We have the name of a \Device\HarddiskN directory. Open it and look
  2226. // for PartitionM names.
  2227. //
  2228. InitializeObjectAttributes(
  2229. &obja,
  2230. &dirInfo1->Name,
  2231. OBJ_CASE_INSENSITIVE,
  2232. deviceHandle,
  2233. NULL
  2234. );
  2235. status = ZwOpenDirectoryObject(&diskHandle, DIRECTORY_ALL_ACCESS, &obja);
  2236. if (!NT_SUCCESS(status)) {
  2237. goto cleanup;
  2238. }
  2239. restartScan = TRUE;
  2240. context2 = 0;
  2241. do {
  2242. //
  2243. // Search the \Device\HarddiskN directory for PartitionM symbolic
  2244. // links.
  2245. //
  2246. status = ZwQueryDirectoryObject(
  2247. diskHandle,
  2248. buffer2,
  2249. BUFFER_SIZE,
  2250. TRUE,
  2251. restartScan,
  2252. &context2,
  2253. NULL
  2254. );
  2255. restartScan = FALSE;
  2256. if (!NT_SUCCESS(status)) {
  2257. if (status != STATUS_NO_MORE_ENTRIES) {
  2258. ASSERT(FALSE);
  2259. goto cleanup;
  2260. }
  2261. status = STATUS_SUCCESS;
  2262. break;
  2263. }
  2264. //
  2265. // We only care about symbolic links with PartitionN names.
  2266. //
  2267. dirInfo2 = (POBJECT_DIRECTORY_INFORMATION)buffer2;
  2268. if ((dirInfo2->Name.Length < sizeof(L"partition")) ||
  2269. (dirInfo2->TypeName.Length < (sizeof(L"SymbolicLink") - sizeof(WCHAR))) ||
  2270. (_wcsnicmp(dirInfo2->TypeName.Buffer,L"SymbolicLink",wcslen(L"SymbolicLink")) != 0)) {
  2271. continue;
  2272. }
  2273. SpStringToLower(dirInfo2->Name.Buffer);
  2274. if (wcsncmp(dirInfo2->Name.Buffer, L"partition", wcslen(L"partition")) != 0) {
  2275. continue;
  2276. }
  2277. p = dirInfo2->Name.Buffer + wcslen(L"partition");
  2278. if ((*p == 0) || (*p == L'0')) { // skip partition0
  2279. continue;
  2280. }
  2281. do {
  2282. if ((*p < L'0') || (*p > L'9')) {
  2283. break;
  2284. }
  2285. p++;
  2286. } while (*p != 0);
  2287. if (*p != 0) {
  2288. continue;
  2289. }
  2290. //
  2291. // Open the \Device\HarddiskN\PartitionM symbolic link.
  2292. //
  2293. linkName = SpMemAlloc(sizeof(L"\\device") +
  2294. dirInfo1->Name.Length +
  2295. dirInfo2->Name.Length +
  2296. sizeof(WCHAR));
  2297. wcscpy(linkName, L"\\device");
  2298. SpConcatenatePaths(linkName, dirInfo1->Name.Buffer);
  2299. SpConcatenatePaths(linkName, dirInfo2->Name.Buffer);
  2300. INIT_OBJA(&obja, &unicodeString, linkName);
  2301. status = ZwOpenSymbolicLinkObject(
  2302. &linkHandle,
  2303. READ_CONTROL | SYMBOLIC_LINK_QUERY,
  2304. &obja
  2305. );
  2306. if (!NT_SUCCESS(status)) {
  2307. ASSERT(FALSE);
  2308. SpMemFree(linkName);
  2309. goto cleanup;
  2310. }
  2311. //
  2312. // Query the link to get the link target.
  2313. //
  2314. unicodeString.Buffer = TemporaryBuffer;
  2315. unicodeString.Length = 0;
  2316. unicodeString.MaximumLength = sizeof(TemporaryBuffer);
  2317. status = ZwQuerySymbolicLinkObject(
  2318. linkHandle,
  2319. &unicodeString,
  2320. NULL
  2321. );
  2322. ZwClose(linkHandle);
  2323. if (!NT_SUCCESS(status)) {
  2324. ASSERT(FALSE);
  2325. SpMemFree(linkName);
  2326. goto cleanup;
  2327. }
  2328. //
  2329. // Terminate the returned string.
  2330. //
  2331. TemporaryBuffer[unicodeString.Length/sizeof(WCHAR)] = 0;
  2332. //
  2333. // Create a translation entry.
  2334. //
  2335. translation = SpMemAlloc(sizeof(HARDDISK_NAME_TRANSLATION));
  2336. translation->Next = SpHarddiskNameTranslations;
  2337. SpHarddiskNameTranslations = translation;
  2338. translation->PartitionName = linkName;
  2339. translation->VolumeName = SpDupStringW(TemporaryBuffer);
  2340. } while (TRUE);
  2341. ZwClose(diskHandle);
  2342. } while (TRUE);
  2343. ASSERT(status == STATUS_SUCCESS);
  2344. cleanup:
  2345. SpMemFree(buffer1);
  2346. SpMemFree(buffer2);
  2347. return (NT_SUCCESS(status) ? TRUE : FALSE);
  2348. } // SpBuildHarddiskNameTranslations
  2349. NTSTATUS
  2350. SpGetBootEntryFilePath(
  2351. IN ULONG Id,
  2352. IN PWSTR LoaderPartitionNtName,
  2353. IN PWSTR LoaderFile,
  2354. OUT PWSTR* FilePath
  2355. )
  2356. /*++
  2357. Routine Description:
  2358. Construct a filepath including the loaderpartition name, the directory path to the
  2359. OS loader and a filename for the boot entry specified.
  2360. Arguments:
  2361. Id the boot entry id
  2362. LoaderPartitionNtName pointer to the string representing the disk partition
  2363. LoaderFile pointer to the string representing the path to the EFI OS loader
  2364. FilePath upon completion, this points to the completed filepath to the
  2365. boot entry file
  2366. Return Value:
  2367. NTSTATUS
  2368. --*/
  2369. {
  2370. NTSTATUS status;
  2371. WCHAR* p;
  2372. ULONG FilePathSize;
  2373. WCHAR idString[9];
  2374. //
  2375. // use the EFI variable name as the filename
  2376. //
  2377. swprintf( idString, L"Boot%04x", Id);
  2378. //
  2379. // determine the size of the final filepath
  2380. //
  2381. // Note: FilePathSize should be a little bigger than actually needed
  2382. // since we are including the full LoadFile string. Also, the '\'
  2383. // characters may be extra.
  2384. //
  2385. FilePathSize = (wcslen(LoaderPartitionNtName) * sizeof(WCHAR)) + // partition
  2386. sizeof(WCHAR) + // '\'
  2387. (wcslen(LoaderFile) * sizeof(WCHAR)) + // path
  2388. sizeof(WCHAR) + // '\'
  2389. (wcslen(idString) * sizeof(WCHAR)) + // new filename
  2390. sizeof(WCHAR); // null term.
  2391. ASSERT(FilePathSize > 0);
  2392. if (FilePathSize <= 0) {
  2393. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: invalid loader partition name and/or loader path\n"));
  2394. return STATUS_INVALID_PARAMETER;
  2395. }
  2396. *FilePath = SpMemAlloc(FilePathSize);
  2397. if (!*FilePath) {
  2398. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Failed to allocate memory for FilePath\n"));
  2399. return STATUS_NO_MEMORY;
  2400. }
  2401. wcscpy(*FilePath, LoaderPartitionNtName);
  2402. SpConcatenatePaths(*FilePath, LoaderFile);
  2403. // remove the os loader filename from the path
  2404. p = wcsrchr(*FilePath, L'\\');
  2405. if (p != NULL) {
  2406. p++;
  2407. } else {
  2408. // we could get here, but it would be wierd.
  2409. p = *FilePath;
  2410. wcscat(p, L"\\");
  2411. }
  2412. //
  2413. // insert the filename
  2414. //
  2415. wcscpy(p, idString);
  2416. ASSERT((wcslen(*FilePath) + 1) * sizeof(WCHAR) <= FilePathSize);
  2417. return STATUS_SUCCESS;
  2418. }
  2419. NTSTATUS
  2420. SpGetAndWriteBootEntry(
  2421. IN ULONG Id,
  2422. IN PWSTR BootEntryPath
  2423. )
  2424. /*++
  2425. Routine Description:
  2426. Get the boot entry from NVRAM for the given boot entry Id. Construct a filename
  2427. of the form BootXXXX, where XXXX = id. Put the file in the same directory as the
  2428. EFI OS loader. The directory is determined from the LoaderFile string.
  2429. Arguments:
  2430. bootEntry pointer to a SP_BOOT_ENTRY structure of the entry to write
  2431. BootEntryPath pinter to the ARC/NT style reference to the boot entry filename
  2432. Return Value:
  2433. NTSTATUS
  2434. --*/
  2435. {
  2436. NTSTATUS status;
  2437. WCHAR idString[9];
  2438. HANDLE hfile;
  2439. OBJECT_ATTRIBUTES oa;
  2440. IO_STATUS_BLOCK iostatus;
  2441. UCHAR* bootVar;
  2442. ULONG bootVarSize;
  2443. UNICODE_STRING uFilePath;
  2444. UINT64 BootNumber;
  2445. UINT64 BootSize;
  2446. GUID EfiBootVariablesGuid = EFI_GLOBAL_VARIABLE;
  2447. hfile = NULL;
  2448. //
  2449. // Retrieve the NVRAM entry for the Id specified
  2450. //
  2451. swprintf( idString, L"Boot%04x", Id);
  2452. bootVarSize = 0;
  2453. status = HalGetEnvironmentVariableEx(idString,
  2454. &EfiBootVariablesGuid,
  2455. NULL,
  2456. &bootVarSize,
  2457. NULL);
  2458. if (status != STATUS_BUFFER_TOO_SMALL) {
  2459. ASSERT(FALSE);
  2460. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Failed to get size for boot entry buffer.\n"));
  2461. goto Done;
  2462. } else {
  2463. bootVar = SpMemAlloc(bootVarSize);
  2464. if (!bootVar) {
  2465. status = STATUS_NO_MEMORY;
  2466. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Failed to allocate boot entry buffer.\n"));
  2467. goto Done;
  2468. }
  2469. status = HalGetEnvironmentVariableEx(idString,
  2470. &EfiBootVariablesGuid,
  2471. bootVar,
  2472. &bootVarSize,
  2473. NULL);
  2474. if (status != STATUS_SUCCESS) {
  2475. ASSERT(FALSE);
  2476. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Failed to get boot entry.\n"));
  2477. goto Done;
  2478. }
  2479. }
  2480. //
  2481. // open the file
  2482. //
  2483. INIT_OBJA(&oa, &uFilePath, BootEntryPath);
  2484. status = ZwCreateFile(&hfile,
  2485. GENERIC_WRITE,
  2486. &oa,
  2487. &iostatus,
  2488. NULL,
  2489. FILE_ATTRIBUTE_NORMAL,
  2490. 0,
  2491. FILE_OVERWRITE_IF,
  2492. FILE_SYNCHRONOUS_IO_NONALERT,
  2493. NULL,
  2494. 0
  2495. );
  2496. if ( ! NT_SUCCESS(status) ) {
  2497. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Failed to create boot entry recovery file.\n"));
  2498. goto Done;
  2499. }
  2500. //
  2501. // Write the bits to disk using the format required
  2502. // by base/efiutil/efinvram/savrstor.c
  2503. //
  2504. // [BootNumber][BootSize][BootEntry (of BootSize)]
  2505. //
  2506. //
  2507. // build the header info for the boot entry block
  2508. //
  2509. // [header] include the boot id
  2510. BootNumber = Id;
  2511. status = ZwWriteFile( hfile,
  2512. NULL,
  2513. NULL,
  2514. NULL,
  2515. &iostatus,
  2516. &BootNumber,
  2517. sizeof(BootNumber),
  2518. NULL,
  2519. NULL
  2520. );
  2521. if ( ! NT_SUCCESS(status) ) {
  2522. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Failed writing boot number to boot entry recovery file.\n"));
  2523. goto Done;
  2524. }
  2525. // [header] include the boot size
  2526. BootSize = bootVarSize;
  2527. status = ZwWriteFile( hfile,
  2528. NULL,
  2529. NULL,
  2530. NULL,
  2531. &iostatus,
  2532. &BootSize,
  2533. sizeof(BootSize),
  2534. NULL,
  2535. NULL
  2536. );
  2537. if ( ! NT_SUCCESS(status) ) {
  2538. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Failed writing boot entry size to boot entry recovery file.\n"));
  2539. goto Done;
  2540. }
  2541. // boot entry bits
  2542. status = ZwWriteFile( hfile,
  2543. NULL,
  2544. NULL,
  2545. NULL,
  2546. &iostatus,
  2547. bootVar,
  2548. bootVarSize,
  2549. NULL,
  2550. NULL
  2551. );
  2552. if ( ! NT_SUCCESS(status) ) {
  2553. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Failed writing boot entry to boot entry recovery file.\n"));
  2554. goto Done;
  2555. }
  2556. Done:
  2557. //
  2558. // We are done
  2559. //
  2560. if (bootVar) {
  2561. SpMemFree(bootVar);
  2562. }
  2563. if (hfile) {
  2564. ZwClose( hfile );
  2565. }
  2566. return status;
  2567. }
  2568. BOOLEAN
  2569. SpFlushEfiBootEntries (
  2570. VOID
  2571. )
  2572. /*++
  2573. Routine Description:
  2574. Write boot entry changes back to NVRAM.
  2575. Arguments:
  2576. None.
  2577. Return Value:
  2578. BOOLEAN - FALSE if an unexpected error occurred.
  2579. --*/
  2580. {
  2581. PSP_BOOT_ENTRY bootEntry;
  2582. ULONG count;
  2583. PULONG order;
  2584. ULONG i;
  2585. NTSTATUS status;
  2586. PWSTR BootEntryFilePath;
  2587. ASSERT(SpIsEfi());
  2588. //
  2589. // Walk the list of boot entries, looking for entries that have been
  2590. // deleted. Delete these entries from NVRAM. Do not delete entries that
  2591. // are both new AND deleted; these are entries that have never been
  2592. // written to NVRAM.
  2593. //
  2594. for (bootEntry = SpBootEntries; bootEntry != NULL; bootEntry = bootEntry->Next) {
  2595. if (IS_BOOT_ENTRY_DELETED(bootEntry) &&
  2596. !IS_BOOT_ENTRY_NEW(bootEntry)) {
  2597. ASSERT(IS_BOOT_ENTRY_WINDOWS(bootEntry));
  2598. //
  2599. // Delete this boot entry.
  2600. //
  2601. status = ZwDeleteBootEntry(bootEntry->NtBootEntry.Id);
  2602. if (!NT_SUCCESS(status)) {
  2603. return FALSE;
  2604. }
  2605. }
  2606. }
  2607. //
  2608. // Walk the list of boot entries, looking for entries that have are new.
  2609. // Add these entries to NVRAM. Do not write entries that are both new AND
  2610. // deleted.
  2611. //
  2612. for (bootEntry = SpBootEntries; bootEntry != NULL; bootEntry = bootEntry->Next) {
  2613. if (IS_BOOT_ENTRY_NEW(bootEntry) &&
  2614. !IS_BOOT_ENTRY_DELETED(bootEntry)) {
  2615. ASSERT(IS_BOOT_ENTRY_WINDOWS(bootEntry));
  2616. //
  2617. // Add this boot entry.
  2618. //
  2619. status = ZwAddBootEntry(&bootEntry->NtBootEntry, &bootEntry->NtBootEntry.Id);
  2620. if (!NT_SUCCESS(status)) {
  2621. return FALSE;
  2622. }
  2623. //
  2624. // get the location we are going to store a copy of the NVRAM boot entry
  2625. //
  2626. BootEntryFilePath = NULL;
  2627. status = SpGetBootEntryFilePath(bootEntry->NtBootEntry.Id,
  2628. bootEntry->LoaderPartitionNtName,
  2629. bootEntry->LoaderFile,
  2630. &BootEntryFilePath
  2631. );
  2632. if (!NT_SUCCESS(status)) {
  2633. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Failed getting boot entry filepath.\n"));
  2634. } else {
  2635. ASSERT(BootEntryFilePath);
  2636. //
  2637. // Fetch the bits from the newly created NVRAM entry and
  2638. // write them as a file in the the EFI load path
  2639. //
  2640. status = SpGetAndWriteBootEntry(bootEntry->NtBootEntry.Id,
  2641. BootEntryFilePath
  2642. );
  2643. if (!NT_SUCCESS(status)) {
  2644. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Failed boot entry recovery file.\n"));
  2645. }
  2646. //
  2647. // We are done with the boot entry filepath
  2648. //
  2649. SpMemFree(BootEntryFilePath);
  2650. }
  2651. //
  2652. // Remember the ID of the new boot entry as the entry to be booted
  2653. // immediately on the next boot.
  2654. //
  2655. SpBootOptions->NextBootEntryId = bootEntry->NtBootEntry.Id;
  2656. }
  2657. }
  2658. //
  2659. // Build the new boot order list. Insert all boot entries with
  2660. // BE_STATUS_ORDERED into the list. (Don't insert deleted entries.)
  2661. //
  2662. count = 0;
  2663. bootEntry = SpBootEntries;
  2664. while (bootEntry != NULL) {
  2665. if (IS_BOOT_ENTRY_ORDERED(bootEntry) && !IS_BOOT_ENTRY_DELETED(bootEntry)) {
  2666. count++;
  2667. }
  2668. bootEntry = bootEntry->Next;
  2669. }
  2670. order = SpMemAlloc(count * sizeof(ULONG));
  2671. count = 0;
  2672. bootEntry = SpBootEntries;
  2673. while (bootEntry != NULL) {
  2674. if (IS_BOOT_ENTRY_ORDERED(bootEntry) && !IS_BOOT_ENTRY_DELETED(bootEntry)) {
  2675. order[count++] = bootEntry->NtBootEntry.Id;
  2676. }
  2677. bootEntry = bootEntry->Next;
  2678. }
  2679. //
  2680. // Write the new boot entry order list to NVRAM.
  2681. //
  2682. status = ZwSetBootEntryOrder(order, count);
  2683. SpMemFree(order);
  2684. if (!NT_SUCCESS(status)) {
  2685. return FALSE;
  2686. }
  2687. //
  2688. // Write the new timeout value to NVRAM.
  2689. //
  2690. // Set the boot entry we added to be booted automatically on
  2691. // the next boot, without waiting for a timeout at the boot menu.
  2692. //
  2693. // NB: SpCreateBootEntry() sets SpBootOptions->NextBootEntryId.
  2694. //
  2695. SpBootOptions->Timeout = Timeout;
  2696. status = ZwSetBootOptions(
  2697. SpBootOptions,
  2698. BOOT_OPTIONS_FIELD_TIMEOUT | BOOT_OPTIONS_FIELD_NEXT_BOOT_ENTRY_ID
  2699. );
  2700. if (!NT_SUCCESS(status)) {
  2701. return FALSE;
  2702. }
  2703. return TRUE;
  2704. } // SpFlushEfiBootEntries
  2705. BOOLEAN
  2706. SpReadAndConvertEfiBootEntries (
  2707. VOID
  2708. )
  2709. /*++
  2710. Routine Description:
  2711. Read boot entries from EFI NVRAM and convert them into our internal format.
  2712. Arguments:
  2713. None.
  2714. Return Value:
  2715. BOOLEAN - FALSE if an unexpected error occurred.
  2716. --*/
  2717. {
  2718. NTSTATUS status;
  2719. ULONG length;
  2720. PBOOT_ENTRY_LIST bootEntries;
  2721. PBOOT_ENTRY_LIST bootEntryList;
  2722. PBOOT_ENTRY bootEntry;
  2723. PBOOT_ENTRY bootEntryCopy;
  2724. PSP_BOOT_ENTRY myBootEntry;
  2725. PSP_BOOT_ENTRY previousEntry;
  2726. PWINDOWS_OS_OPTIONS osOptions;
  2727. LONG i;
  2728. PULONG order;
  2729. ULONG count;
  2730. //
  2731. // SpStartSetup() does not expect our caller, SpInitBootVars(), to fail.
  2732. // So textmode is going to continue even if we have failures here.
  2733. // Therefore we need to leave here in a consistent state. That means
  2734. // that we MUST allocate a buffer for SpBootOptions, even if we can't
  2735. // get the real information from the kernel.
  2736. //
  2737. //
  2738. // Get the global system boot options.
  2739. //
  2740. length = 0;
  2741. status = ZwQueryBootOptions(NULL, &length);
  2742. if (status != STATUS_BUFFER_TOO_SMALL) {
  2743. ASSERT(FALSE);
  2744. if (status == STATUS_SUCCESS) {
  2745. status = STATUS_UNSUCCESSFUL;
  2746. }
  2747. } else {
  2748. SpBootOptions = SpMemAlloc(length);
  2749. status = ZwQueryBootOptions(SpBootOptions, &length);
  2750. if (status != STATUS_SUCCESS) {
  2751. ASSERT(FALSE);
  2752. }
  2753. }
  2754. if (status != STATUS_SUCCESS) {
  2755. //
  2756. // An unexpected error occurred reading the boot options. Create
  2757. // a fake boot options structure.
  2758. //
  2759. if (SpBootOptions != NULL) {
  2760. SpMemFree(SpBootOptions);
  2761. }
  2762. length = FIELD_OFFSET(BOOT_OPTIONS,HeadlessRedirection) + sizeof(WCHAR);
  2763. SpBootOptions = SpMemAlloc(length);
  2764. RtlZeroMemory(SpBootOptions, length);
  2765. SpBootOptions->Version = BOOT_OPTIONS_VERSION;
  2766. SpBootOptions->Length = length;
  2767. }
  2768. //
  2769. // Get the system boot order list.
  2770. //
  2771. count = 0;
  2772. status = ZwQueryBootEntryOrder(NULL, &count);
  2773. if (status != STATUS_BUFFER_TOO_SMALL) {
  2774. if (status == STATUS_SUCCESS) {
  2775. //
  2776. // There are no entries in the boot order list. Strange but
  2777. // possible.
  2778. //
  2779. count = 0;
  2780. } else {
  2781. //
  2782. // An unexpected error occurred. Just pretend that the boot
  2783. // entry order list is empty.
  2784. //
  2785. ASSERT(FALSE);
  2786. count = 0;
  2787. }
  2788. }
  2789. if (count != 0) {
  2790. order = SpMemAlloc(count * sizeof(ULONG));
  2791. status = ZwQueryBootEntryOrder(order, &count);
  2792. if (status != STATUS_SUCCESS) {
  2793. //
  2794. // An unexpected error occurred. Just pretend that the boot
  2795. // entry order list is empty.
  2796. //
  2797. ASSERT(FALSE);
  2798. count = 0;
  2799. }
  2800. }
  2801. //
  2802. // Get all existing boot entries.
  2803. //
  2804. length = 0;
  2805. status = ZwEnumerateBootEntries(NULL, &length);
  2806. if (status != STATUS_BUFFER_TOO_SMALL) {
  2807. if (status == STATUS_SUCCESS) {
  2808. //
  2809. // Somehow there are no boot entries in NVRAM. Handle this
  2810. // by just creating an empty list.
  2811. //
  2812. length = 0;
  2813. } else {
  2814. //
  2815. // An unexpected error occurred. Just pretend that no boot
  2816. // entries exist.
  2817. //
  2818. ASSERT(FALSE);
  2819. length = 0;
  2820. }
  2821. }
  2822. if (length == 0) {
  2823. ASSERT(SpBootEntries == NULL);
  2824. } else {
  2825. bootEntries = SpMemAlloc(length);
  2826. status = ZwEnumerateBootEntries(bootEntries, &length);
  2827. if (status != STATUS_SUCCESS) {
  2828. ASSERT(FALSE);
  2829. return FALSE;
  2830. }
  2831. //
  2832. // Convert the boot entries into our internal representation.
  2833. //
  2834. bootEntryList = bootEntries;
  2835. previousEntry = NULL;
  2836. while (TRUE) {
  2837. bootEntry = &bootEntryList->BootEntry;
  2838. //
  2839. // Calculate the length of our internal structure. This includes
  2840. // the base part of SP_BOOT_ENTRY plus the NT BOOT_ENTRY.
  2841. //
  2842. length = FIELD_OFFSET(SP_BOOT_ENTRY, NtBootEntry) + bootEntry->Length;
  2843. myBootEntry = SpMemAlloc(length);
  2844. ASSERT(myBootEntry != NULL);
  2845. RtlZeroMemory(myBootEntry, length);
  2846. //
  2847. // Copy the NT BOOT_ENTRY into the allocated buffer.
  2848. //
  2849. bootEntryCopy = &myBootEntry->NtBootEntry;
  2850. memcpy(bootEntryCopy, bootEntry, bootEntry->Length);
  2851. //
  2852. // Fill in the base part of the structure.
  2853. //
  2854. myBootEntry->Next = NULL;
  2855. myBootEntry->AllocationEnd = (PUCHAR)myBootEntry + length - 1;
  2856. myBootEntry->FriendlyName = ADD_OFFSET(bootEntryCopy, FriendlyNameOffset);
  2857. myBootEntry->FriendlyNameLength = (wcslen(myBootEntry->FriendlyName) + 1) * sizeof(WCHAR);
  2858. myBootEntry->LoaderPath = ADD_OFFSET(bootEntryCopy, BootFilePathOffset);
  2859. //
  2860. // If this is an NT boot entry, translate the file paths.
  2861. //
  2862. osOptions = (PWINDOWS_OS_OPTIONS)bootEntryCopy->OsOptions;
  2863. if (IS_BOOT_ENTRY_WINDOWS(myBootEntry)) {
  2864. PSP_BOOT_ENTRY bootEntry2;
  2865. myBootEntry->OsLoadOptions = osOptions->OsLoadOptions;
  2866. myBootEntry->OsLoadOptionsLength = (wcslen(myBootEntry->OsLoadOptions) + 1) * sizeof(WCHAR);
  2867. myBootEntry->OsPath = ADD_OFFSET(osOptions, OsLoadPathOffset);
  2868. //
  2869. // Translate the OS FILE_PATH and the boot FILE_PATH. Note that
  2870. // the translation can fail when the target device is not present.
  2871. //
  2872. SpTranslateFilePathToRegion(
  2873. myBootEntry->OsPath,
  2874. &myBootEntry->OsPartitionDiskRegion,
  2875. &myBootEntry->OsPartitionNtName,
  2876. &myBootEntry->OsDirectory
  2877. );
  2878. SpTranslateFilePathToRegion(
  2879. myBootEntry->LoaderPath,
  2880. &myBootEntry->LoaderPartitionDiskRegion,
  2881. &myBootEntry->LoaderPartitionNtName,
  2882. &myBootEntry->LoaderFile
  2883. );
  2884. }
  2885. //
  2886. // Link the new entry into the list.
  2887. //
  2888. if (previousEntry != NULL) {
  2889. previousEntry->Next = myBootEntry;
  2890. } else {
  2891. SpBootEntries = myBootEntry;
  2892. }
  2893. previousEntry = myBootEntry;
  2894. //
  2895. // Move to the next entry in the enumeration list, if any.
  2896. //
  2897. if (bootEntryList->NextEntryOffset == 0) {
  2898. break;
  2899. }
  2900. bootEntryList = ADD_OFFSET(bootEntryList, NextEntryOffset);
  2901. }
  2902. //
  2903. // Free the enumeration buffer.
  2904. //
  2905. SpMemFree(bootEntries);
  2906. }
  2907. //
  2908. // Boot entries are returned in an unspecified order. They are currently
  2909. // in the SpBootEntries list in the order in which they were returned.
  2910. // Sort the boot entry list based on the boot order. Do this by walking
  2911. // the boot order array backwards, reinserting the entry corresponding to
  2912. // each element of the array at the head of the list.
  2913. //
  2914. for (i = (LONG)count - 1; i >= 0; i--) {
  2915. for (previousEntry = NULL, myBootEntry = SpBootEntries;
  2916. myBootEntry != NULL;
  2917. previousEntry = myBootEntry, myBootEntry = myBootEntry->Next) {
  2918. if (myBootEntry->NtBootEntry.Id == order[i] ) {
  2919. //
  2920. // We found the boot entry with this ID. If it's not already
  2921. // at the front of the list, move it there.
  2922. //
  2923. myBootEntry->Status |= BE_STATUS_ORDERED;
  2924. if (previousEntry != NULL) {
  2925. previousEntry->Next = myBootEntry->Next;
  2926. myBootEntry->Next = SpBootEntries;
  2927. SpBootEntries = myBootEntry;
  2928. } else {
  2929. ASSERT(SpBootEntries == myBootEntry);
  2930. }
  2931. break;
  2932. }
  2933. }
  2934. }
  2935. if (count != 0) {
  2936. SpMemFree(order);
  2937. }
  2938. return TRUE;
  2939. } // SpReadAndConvertEfiBootEntries
  2940. ULONG
  2941. SpSafeWcslen (
  2942. IN PWSTR String,
  2943. IN PWSTR Max
  2944. )
  2945. /*++
  2946. Routine Description:
  2947. Calculate the length of a null-terminated string in a safe manner,
  2948. avoiding walking off the end of the buffer if the string is not
  2949. properly terminated.
  2950. Arguments:
  2951. String - Address of string.
  2952. Max - Address of first byte beyond the maximum legal address for the
  2953. string. In other words, the address of the first byte past the end
  2954. of the buffer in which the string is contained.
  2955. Return Value:
  2956. ULONG - Length of the string, in characters, not including the null
  2957. terminator. If the string is not terminated before the end of
  2958. the buffer, 0xffffffff is returned.
  2959. --*/
  2960. {
  2961. PWSTR p = String;
  2962. //
  2963. // Walk through the string, looking for either the end of the buffer
  2964. // or a null terminator.
  2965. //
  2966. while ((p < Max) && (*p != 0)) {
  2967. p++;
  2968. }
  2969. //
  2970. // If we didn't reach the end of the buffer, then we found a null
  2971. // terminator. Return the length of the string, in characters.
  2972. //
  2973. if (p < Max) {
  2974. return (ULONG)(p - String);
  2975. }
  2976. //
  2977. // The string is not properly terminated. Return an error indicator.
  2978. //
  2979. return 0xffffffff;
  2980. } // SpSafeWcslen
  2981. VOID
  2982. SpTranslateFilePathToRegion (
  2983. IN PFILE_PATH FilePath,
  2984. OUT PDISK_REGION *DiskRegion,
  2985. OUT PWSTR *PartitionNtName,
  2986. OUT PWSTR *PartitionRelativePath
  2987. )
  2988. /*++
  2989. Routine Description:
  2990. Translate a FILE_PATH to a pointer to a disk region and the path
  2991. relative to the region.
  2992. Arguments:
  2993. FilePath - Address of FILE_PATH.
  2994. DiskRegion - Returns the address of the disk region described by
  2995. FilePath. NULL is returned if the matching disk region cannot
  2996. be found.
  2997. PartitionNtName - Returns the NT name associated with the disk region.
  2998. NULL is returned if the file path cannot be translated into NT
  2999. format.
  3000. PartitionRelativePath - Returns the volume-relative path of the file
  3001. or directory described by the FilePath. NULL is returned if the
  3002. file path cannot be translated into NT format.
  3003. Return Value:
  3004. None.
  3005. --*/
  3006. {
  3007. NTSTATUS status;
  3008. ULONG length;
  3009. PFILE_PATH ntFilePath;
  3010. PWSTR p;
  3011. PWSTR q;
  3012. PHARDDISK_NAME_TRANSLATION translation;
  3013. //
  3014. // Translate the file path into NT format. (It is probably in EFI format.)
  3015. //
  3016. length = 0;
  3017. status = ZwTranslateFilePath(
  3018. FilePath,
  3019. FILE_PATH_TYPE_NT,
  3020. NULL,
  3021. &length
  3022. );
  3023. if (status != STATUS_BUFFER_TOO_SMALL) {
  3024. *PartitionNtName = NULL;
  3025. *DiskRegion = NULL;
  3026. *PartitionRelativePath = NULL;
  3027. return;
  3028. }
  3029. ntFilePath = SpMemAlloc(length);
  3030. status = ZwTranslateFilePath(
  3031. FilePath,
  3032. FILE_PATH_TYPE_NT,
  3033. ntFilePath,
  3034. &length
  3035. );
  3036. if (status != STATUS_SUCCESS) {
  3037. ASSERT(FALSE);
  3038. *PartitionNtName = NULL;
  3039. *DiskRegion = NULL;
  3040. *PartitionRelativePath = NULL;
  3041. SpMemFree(ntFilePath);
  3042. return;
  3043. }
  3044. //
  3045. // NtTranslateFilePath returns a name of the form \Device\HarddiskVolumeN.
  3046. // We need to have a name of the form \Device\HardiskN\PartitionM. (This is
  3047. // because all of the ARC<->NT translations use the latter form.) Use the
  3048. // translation list built by SpBuildHarddiskNameTranslations to do the
  3049. // translation.
  3050. //
  3051. // If the returned name doesn't include "HarddiskVolume", or if no
  3052. // translation is found, use the returned name and hope for the best.
  3053. //
  3054. p = (PWSTR)ntFilePath->FilePath;
  3055. q = p;
  3056. if (wcsstr(q, L"HarddiskVolume") != NULL) {
  3057. for ( translation = SpHarddiskNameTranslations;
  3058. translation != NULL;
  3059. translation = translation->Next ) {
  3060. if (_wcsicmp(translation->VolumeName, q) == 0) {
  3061. break;
  3062. }
  3063. }
  3064. if (translation != NULL) {
  3065. q = translation->PartitionName;
  3066. }
  3067. }
  3068. //
  3069. // We now have the file path in NT format. Get the disk region that
  3070. // corresponds to the NT device name. Return the obtained information.
  3071. //
  3072. *PartitionNtName = SpDupStringW(q);
  3073. *DiskRegion = SpRegionFromNtName(q, PartitionOrdinalCurrent);
  3074. p += wcslen(p) + 1;
  3075. *PartitionRelativePath = SpDupStringW(p);
  3076. //
  3077. // Free local memory.
  3078. //
  3079. SpMemFree(ntFilePath);
  3080. return;
  3081. }
  3082. #endif // defined(EFI_NVRAM_ENABLED)
  3083. NTSTATUS
  3084. SpAddNTInstallToBootList(
  3085. IN PVOID SifHandle,
  3086. IN PDISK_REGION SystemPartitionRegion,
  3087. IN PWSTR SystemPartitionDirectory,
  3088. IN PDISK_REGION NtPartitionRegion,
  3089. IN PWSTR Sysroot,
  3090. IN PWSTR OsLoadOptions, OPTIONAL
  3091. IN PWSTR LoadIdentifier OPTIONAL
  3092. )
  3093. /*++
  3094. Routine Description:
  3095. This routine takes the core components of a boot set and passes
  3096. them on to SpAddUserDefinedInstallationToBootList, which does
  3097. the real work of constructing a boot set. After the new boot
  3098. set is created, the boot vars are flushed - the exact implementation
  3099. of the flush depends on the architecture. On x86, we'll have a new
  3100. boot.ini after this routine is done.
  3101. Arguments:
  3102. SifHandle - pointer to the setup sif file
  3103. Return Value:
  3104. STATUS_SUCCESS if the NT install was successfully added to the
  3105. boot list
  3106. if there was an error, the status is returned
  3107. --*/
  3108. {
  3109. NTSTATUS status;
  3110. //
  3111. // create the new user defined boot set
  3112. //
  3113. status = SpAddUserDefinedInstallationToBootList(SifHandle,
  3114. SystemPartitionRegion,
  3115. SystemPartitionDirectory,
  3116. NtPartitionRegion,
  3117. Sysroot,
  3118. OsLoadOptions,
  3119. LoadIdentifier
  3120. );
  3121. if (! NT_SUCCESS(status)) {
  3122. KdPrintEx((DPFLTR_SETUP_ID,
  3123. DPFLTR_ERROR_LEVEL,
  3124. "SpExportBootEntries: failed while installing new boot set: Status = %lx\n",
  3125. status
  3126. ));
  3127. return status;
  3128. }
  3129. //
  3130. // write the new boot set out
  3131. //
  3132. if (SpFlushBootVars() == FALSE) {
  3133. KdPrintEx((DPFLTR_SETUP_ID,
  3134. DPFLTR_ERROR_LEVEL,
  3135. "SpAddDiscoveredNTInstallToBootList: failed flushing boot vars\n"
  3136. ));
  3137. status = STATUS_UNSUCCESSFUL;
  3138. } else {
  3139. status = STATUS_SUCCESS;
  3140. }
  3141. return status;
  3142. }
  3143. NTSTATUS
  3144. SpAddUserDefinedInstallationToBootList(
  3145. IN PVOID SifHandle,
  3146. IN PDISK_REGION SystemPartitionRegion,
  3147. IN PWSTR SystemPartitionDirectory,
  3148. IN PDISK_REGION NtPartitionRegion,
  3149. IN PWSTR Sysroot,
  3150. IN PWSTR OsLoadOptions, OPTIONAL
  3151. IN PWSTR LoadIdentifier OPTIONAL
  3152. )
  3153. /*++
  3154. Routine Description:
  3155. This routine is based on SpAddInstallationToBootList, with the major
  3156. differences being:
  3157. there is no processing of the load options
  3158. the user can specifiy the loadIdentifier
  3159. Return Value:
  3160. STATUS_SUCCESS if the NT install was successfully added to the
  3161. boot list
  3162. if there was an error, the status is returned
  3163. --*/
  3164. {
  3165. PWSTR BootVars[MAXBOOTVARS];
  3166. PWSTR SystemPartitionArcName;
  3167. PWSTR TargetPartitionArcName;
  3168. PWSTR tmp;
  3169. PWSTR tmp2;
  3170. PWSTR locOsLoadOptions;
  3171. PWSTR locLoadIdentifier;
  3172. ULONG Signature;
  3173. ENUMARCPATHTYPE ArcPathType;
  3174. NTSTATUS status;
  3175. status = STATUS_SUCCESS;
  3176. ArcPathType = PrimaryArcPath;
  3177. tmp2 = TemporaryBuffer + (sizeof(TemporaryBuffer) / sizeof(WCHAR) / 2);
  3178. if (!SpIsEfi()) {
  3179. //
  3180. // Get an ARC name for the system partition.
  3181. //
  3182. if (SystemPartitionRegion != NULL) {
  3183. SpArcNameFromRegion(
  3184. SystemPartitionRegion,
  3185. tmp2,
  3186. sizeof(TemporaryBuffer)/2,
  3187. PartitionOrdinalOnDisk,
  3188. PrimaryArcPath
  3189. );
  3190. SystemPartitionArcName = SpDupStringW(tmp2);
  3191. } else {
  3192. SystemPartitionArcName = NULL;
  3193. }
  3194. //
  3195. // Get an ARC name for the target partition.
  3196. //
  3197. //
  3198. // If the partition is on a SCSI disk that has more than 1024 cylinders
  3199. // and the partition has sectors located on cylinders beyond cylinder
  3200. // 1024, the get the arc name in the secondary format. See also
  3201. // spcopy.c!SpCreateNtbootddSys().
  3202. //
  3203. if(
  3204. !SpIsArc() &&
  3205. #if defined(REMOTE_BOOT)
  3206. !RemoteBootSetup &&
  3207. #endif // defined(REMOTE_BOOT)
  3208. #ifdef _X86_
  3209. !SpUseBIOSToBoot(NtPartitionRegion, NULL, SifHandle) &&
  3210. #endif
  3211. (HardDisks[NtPartitionRegion->DiskNumber].ScsiMiniportShortname[0]) ) {
  3212. ArcPathType = SecondaryArcPath;
  3213. } else {
  3214. ArcPathType = PrimaryArcPath;
  3215. }
  3216. SpArcNameFromRegion(
  3217. NtPartitionRegion,
  3218. tmp2,
  3219. sizeof(TemporaryBuffer)/2,
  3220. PartitionOrdinalOnDisk,
  3221. ArcPathType
  3222. );
  3223. TargetPartitionArcName = SpDupStringW(tmp2);
  3224. }
  3225. //
  3226. // Tweak the load identifier if necessary
  3227. //
  3228. if (LoadIdentifier) {
  3229. if(!SpIsArc()) {
  3230. //
  3231. // Need quotation marks around the description on x86.
  3232. //
  3233. locLoadIdentifier = SpMemAlloc((wcslen(LoadIdentifier)+3)*sizeof(WCHAR));
  3234. locLoadIdentifier[0] = L'\"';
  3235. wcscpy(locLoadIdentifier+1,LoadIdentifier);
  3236. wcscat(locLoadIdentifier,L"\"");
  3237. } else {
  3238. locLoadIdentifier = SpDupStringW(LoadIdentifier);
  3239. }
  3240. } else {
  3241. locLoadIdentifier = SpDupStringW(L"");
  3242. }
  3243. ASSERT(locLoadIdentifier);
  3244. //
  3245. // Tweak the load options if necessary
  3246. //
  3247. if (OsLoadOptions) {
  3248. locOsLoadOptions = SpDupStringW(OsLoadOptions);
  3249. } else {
  3250. locOsLoadOptions = SpDupStringW(L"");
  3251. }
  3252. ASSERT(locOsLoadOptions);
  3253. //
  3254. // Create a new internal-format boot entry.
  3255. //
  3256. tmp = TemporaryBuffer;
  3257. wcscpy(tmp,SystemPartitionDirectory);
  3258. SpConcatenatePaths(
  3259. tmp,
  3260. #ifdef _X86_
  3261. SpIsArc() ? L"arcldr.exe" : L"ntldr"
  3262. #elif _IA64_
  3263. L"ia64ldr.efi"
  3264. #else
  3265. L"osloader.exe"
  3266. #endif
  3267. );
  3268. tmp = SpDupStringW(tmp);
  3269. SpCreateBootEntry(
  3270. BE_STATUS_NEW,
  3271. SystemPartitionRegion,
  3272. tmp,
  3273. NtPartitionRegion,
  3274. Sysroot,
  3275. locOsLoadOptions,
  3276. locLoadIdentifier
  3277. );
  3278. SpMemFree(tmp);
  3279. //
  3280. // If not on an EFI machine, add a new ARC-style boot set.
  3281. //
  3282. if (!SpIsEfi()) {
  3283. BootVars[OSLOADOPTIONS] = locOsLoadOptions;
  3284. BootVars[LOADIDENTIFIER] = locLoadIdentifier;
  3285. //
  3286. // OSLOADER is the system partition path + the system partition directory +
  3287. // osloader.exe. (ntldr on x86 machines).
  3288. //
  3289. if (SystemPartitionRegion != NULL) {
  3290. tmp = TemporaryBuffer;
  3291. wcscpy(tmp,SystemPartitionArcName);
  3292. SpConcatenatePaths(tmp,SystemPartitionDirectory);
  3293. SpConcatenatePaths(
  3294. tmp,
  3295. #ifdef _X86_
  3296. (SpIsArc() ? L"arcldr.exe" : L"ntldr")
  3297. #elif _IA64_
  3298. L"ia64ldr.efi"
  3299. #else
  3300. L"osloader.exe"
  3301. #endif
  3302. );
  3303. BootVars[OSLOADER] = SpDupStringW(tmp);
  3304. } else {
  3305. BootVars[OSLOADER] = SpDupStringW(L"");
  3306. }
  3307. //
  3308. // OSLOADPARTITION is the ARC name of the windows nt partition.
  3309. //
  3310. BootVars[OSLOADPARTITION] = TargetPartitionArcName;
  3311. //
  3312. // OSLOADFILENAME is sysroot.
  3313. //
  3314. BootVars[OSLOADFILENAME] = Sysroot;
  3315. //
  3316. // SYSTEMPARTITION is the ARC name of the system partition.
  3317. //
  3318. if (SystemPartitionRegion != NULL) {
  3319. BootVars[SYSTEMPARTITION] = SystemPartitionArcName;
  3320. } else {
  3321. BootVars[SYSTEMPARTITION] = L"";
  3322. }
  3323. //
  3324. // get the disk signature
  3325. //
  3326. if ((NtPartitionRegion->DiskNumber != 0xffffffff) && HardDisks[NtPartitionRegion->DiskNumber].Signature) {
  3327. Signature = HardDisks[NtPartitionRegion->DiskNumber].Signature;
  3328. } else {
  3329. Signature = 0;
  3330. }
  3331. //
  3332. // Add the boot set and make it the default.
  3333. //
  3334. SpAddBootSet(BootVars, TRUE, Signature);
  3335. SpMemFree(BootVars[OSLOADER]);
  3336. }
  3337. //
  3338. // Free memory allocated.
  3339. //
  3340. if (locLoadIdentifier) {
  3341. SpMemFree(locLoadIdentifier);
  3342. }
  3343. if (!SpIsEfi()) {
  3344. if (SystemPartitionArcName) {
  3345. SpMemFree(SystemPartitionArcName);
  3346. }
  3347. if (TargetPartitionArcName) {
  3348. SpMemFree(TargetPartitionArcName);
  3349. }
  3350. }
  3351. return status;
  3352. }
  3353. NTSTATUS
  3354. SpExportBootEntries(
  3355. IN OUT PLIST_ENTRY BootEntries,
  3356. OUT PULONG BootEntryCnt
  3357. )
  3358. /*++
  3359. Routine Description:
  3360. This routine compiles a safely exportable string represenation
  3361. of the boot options.
  3362. Arguments:
  3363. BootEntries - returns pointing to the head of the linked list
  3364. containing the exported boot entries
  3365. BootEntriesCnt - returns with the # of boot entries exported
  3366. Return Value:
  3367. STATUS_SUCCESS if the boot entries were successfully exported
  3368. if there was an error, the status is returned
  3369. --*/
  3370. {
  3371. PSP_BOOT_ENTRY bootEntry;
  3372. PSP_EXPORTED_BOOT_ENTRY ebootEntry;
  3373. *BootEntryCnt = 0;
  3374. //
  3375. // make sure we were given the list head
  3376. //
  3377. ASSERT(BootEntries);
  3378. if (!BootEntries) {
  3379. KdPrintEx((DPFLTR_SETUP_ID,
  3380. DPFLTR_ERROR_LEVEL,
  3381. "SpExportBootEntries: pointer to boot entry list is NULL\n"
  3382. ));
  3383. return STATUS_INVALID_PARAMETER;
  3384. }
  3385. //
  3386. // make sure the list is empty
  3387. //
  3388. ASSERT(IsListEmpty(BootEntries));
  3389. if (! IsListEmpty(BootEntries)) {
  3390. KdPrintEx((DPFLTR_SETUP_ID,
  3391. DPFLTR_ERROR_LEVEL,
  3392. "SpExportBootEntries: incoming boot entry list should be empty\n"
  3393. ));
  3394. return STATUS_INVALID_PARAMETER;
  3395. }
  3396. //
  3397. // for each boot entry, collect a subset of information and compile
  3398. // it in an exportable (safe) string form
  3399. //
  3400. for (bootEntry = SpBootEntries; bootEntry != NULL; bootEntry = bootEntry->Next) {
  3401. //
  3402. // allocate the node...
  3403. //
  3404. ebootEntry = SpMemAlloc(sizeof(SP_EXPORTED_BOOT_ENTRY));
  3405. ASSERT(ebootEntry);
  3406. if (ebootEntry == NULL) {
  3407. KdPrintEx((DPFLTR_SETUP_ID,
  3408. DPFLTR_ERROR_LEVEL,
  3409. "SpExportBootEntries: failed allocationg new exported boot entry\n"
  3410. ));
  3411. return STATUS_NO_MEMORY;
  3412. }
  3413. RtlZeroMemory( ebootEntry, sizeof(SP_EXPORTED_BOOT_ENTRY) );
  3414. //
  3415. // map selected fields from SpBootEntries to our export
  3416. //
  3417. ebootEntry->LoadIdentifier = SpDupStringW(bootEntry->FriendlyName);
  3418. ebootEntry->OsLoadOptions = SpDupStringW(bootEntry->OsLoadOptions);
  3419. ebootEntry->DriverLetter = bootEntry->OsPartitionDiskRegion->DriveLetter;
  3420. ebootEntry->OsDirectory = SpDupStringW(bootEntry->OsDirectory);
  3421. InsertTailList( BootEntries, &ebootEntry->ListEntry );
  3422. ++*BootEntryCnt;
  3423. }
  3424. if (*BootEntryCnt == 0) {
  3425. ASSERT(IsListEmpty(BootEntries));
  3426. if(! IsListEmpty(BootEntries)) {
  3427. KdPrintEx((DPFLTR_SETUP_ID,
  3428. DPFLTR_ERROR_LEVEL,
  3429. "SpExportBootEntries: exported boot entry list should be empty\n"
  3430. ));
  3431. return STATUS_UNSUCCESSFUL;
  3432. }
  3433. } else {
  3434. ASSERT(! IsListEmpty(BootEntries));
  3435. if(IsListEmpty(BootEntries)) {
  3436. KdPrintEx((DPFLTR_SETUP_ID,
  3437. DPFLTR_ERROR_LEVEL,
  3438. "SpExportBootEntries: exported boot entry list should NOT be empty\n"
  3439. ));
  3440. return STATUS_UNSUCCESSFUL;
  3441. }
  3442. }
  3443. return STATUS_SUCCESS;
  3444. }
  3445. NTSTATUS
  3446. SpFreeExportedBootEntries(
  3447. IN PLIST_ENTRY BootEntries,
  3448. IN ULONG BootEntryCnt
  3449. )
  3450. /*++
  3451. Routine Description:
  3452. A convenience routine to free the exported boot entries
  3453. Arguments:
  3454. BootEntries - points to the head of the linked list
  3455. containing the exported boot entries
  3456. BootEntriesCnt - the # of boot entries exported
  3457. Return Value:
  3458. STATUS_SUCCESS if the exported boot entries were successfully freed
  3459. if there was an error, the status is returned
  3460. --*/
  3461. {
  3462. PSP_EXPORTED_BOOT_ENTRY bootEntry;
  3463. PLIST_ENTRY listEntry;
  3464. ULONG cnt;
  3465. NTSTATUS status;
  3466. cnt = 0;
  3467. while ( !IsListEmpty(BootEntries) ) {
  3468. listEntry = RemoveHeadList(BootEntries);
  3469. bootEntry = CONTAINING_RECORD(listEntry,
  3470. SP_EXPORTED_BOOT_ENTRY,
  3471. ListEntry
  3472. );
  3473. if (bootEntry->LoadIdentifier) {
  3474. SpMemFree(bootEntry->LoadIdentifier);
  3475. }
  3476. if (bootEntry->OsLoadOptions) {
  3477. SpMemFree(bootEntry->OsLoadOptions);
  3478. }
  3479. if (bootEntry->OsDirectory) {
  3480. SpMemFree(bootEntry->OsDirectory);
  3481. }
  3482. SpMemFree(bootEntry);
  3483. cnt++;
  3484. }
  3485. ASSERT(cnt == BootEntryCnt);
  3486. if (cnt == BootEntryCnt) {
  3487. status = STATUS_SUCCESS;
  3488. } else {
  3489. KdPrintEx((DPFLTR_SETUP_ID,
  3490. DPFLTR_ERROR_LEVEL,
  3491. "SpFreeExportedBootEntries: incorrect # of boot entries freed\n"
  3492. ));
  3493. status = STATUS_UNSUCCESSFUL;
  3494. }
  3495. return status;
  3496. }
  3497. NTSTATUS
  3498. SpSetRedirectSwitchMode(
  3499. IN RedirectSwitchesModeEnum mode,
  3500. IN PCHAR redirectSwitch,
  3501. IN PCHAR redirectBaudRateSwitch
  3502. )
  3503. /*++
  3504. Routine Description:
  3505. This routine is used to manage how the redirect switches
  3506. are set in the boot configuration (x86 ==> boot.ini)
  3507. Depending on the mode chosen, the user may specify
  3508. which parameters they want to set or if they just
  3509. want the default (legacy) behavior.
  3510. NOTE:
  3511. The user specified switches are copied into globals for
  3512. use by the Flush routines.
  3513. The global, RedirectSwitchesMode, is set and remains set
  3514. after this routine returns. All subsequent FlushBootVars
  3515. will use this mode.
  3516. Arguments:
  3517. mode - how we affect the redirect switches
  3518. redirectSwitch - the user defined redirect parameter
  3519. redirectBaudRateSwitch - the user defined baudrate paramtere
  3520. Return Value:
  3521. STATUS_SUCCESS if the redirect values were successfully set
  3522. if there was an error, the status is returned
  3523. --*/
  3524. {
  3525. NTSTATUS status;
  3526. //
  3527. // set the mode and user defined parameters
  3528. //
  3529. RedirectSwitchesMode = mode;
  3530. //
  3531. // null the redirect switches by default
  3532. //
  3533. RedirectSwitches.port[0] = '\0';
  3534. RedirectSwitches.baudrate[0] = '\0';
  3535. //
  3536. // get copies of the user defined switches if specified
  3537. //
  3538. if (redirectSwitch) {
  3539. strncpy(RedirectSwitches.port,
  3540. redirectSwitch,
  3541. MAXSIZE_REDIRECT_SWITCH);
  3542. }
  3543. if (redirectBaudRateSwitch) {
  3544. strncpy(RedirectSwitches.baudrate,
  3545. redirectBaudRateSwitch,
  3546. MAXSIZE_REDIRECT_SWITCH);
  3547. }
  3548. //
  3549. // update the boot options using the specified mode
  3550. //
  3551. if (SpFlushBootVars() == FALSE) {
  3552. KdPrintEx((DPFLTR_SETUP_ID,
  3553. DPFLTR_ERROR_LEVEL,
  3554. "SpAddDiscoveredNTInstallToBootList: failed flushing boot vars\n"
  3555. ));
  3556. status = STATUS_UNSUCCESSFUL;
  3557. } else {
  3558. status = STATUS_SUCCESS;
  3559. }
  3560. return status;
  3561. }
  3562. NTSTATUS
  3563. SpSetDefaultBootEntry(
  3564. ULONG BootEntryNumber
  3565. )
  3566. /*++
  3567. Routine Description:
  3568. Set the Default boot entry to the user specified boot entry.
  3569. Arguments:
  3570. BootEntryNumber - the position of the boot entry in the list
  3571. which is intended to become the default.
  3572. This number should be >= 1.
  3573. Return Value:
  3574. STATUS_SUCCESS if the default was successfully set
  3575. STATUS_NOT_FOUND if the specified boot entry was not found
  3576. or is missing
  3577. if there was an error, the status is returned
  3578. --*/
  3579. {
  3580. PSP_BOOT_ENTRY bootEntry;
  3581. NTSTATUS status;
  3582. ULONG BootEntryCount;
  3583. //
  3584. // Find the user specified boot entry
  3585. //
  3586. BootEntryCount = 1;
  3587. for (bootEntry = SpBootEntries;
  3588. (bootEntry != NULL) && (BootEntryCount != BootEntryNumber);
  3589. bootEntry = bootEntry->Next) {
  3590. ++BootEntryCount;
  3591. }
  3592. ASSERT(BootEntryCount == BootEntryNumber);
  3593. ASSERT(bootEntry);
  3594. //
  3595. // if we have found our match, then set the Default
  3596. //
  3597. if ((bootEntry != NULL) &&
  3598. (BootEntryCount == BootEntryNumber)) {
  3599. PDISK_REGION Region;
  3600. //
  3601. // point to the disk region with the sig info
  3602. //
  3603. Region = bootEntry->OsPartitionDiskRegion;
  3604. ASSERT(Region);
  3605. if (! Region) {
  3606. KdPrintEx((DPFLTR_SETUP_ID,
  3607. DPFLTR_ERROR_LEVEL,
  3608. "SpSetDefaultBootEntry: new default partition region is NULL\n"
  3609. ));
  3610. return STATUS_UNSUCCESSFUL;
  3611. }
  3612. //
  3613. // Free the previous Default
  3614. //
  3615. if( Default ) {
  3616. SpMemFree( Default );
  3617. }
  3618. Default = SpMemAlloc( MAX_PATH * sizeof(WCHAR) );
  3619. ASSERT( Default );
  3620. if (! Default) {
  3621. KdPrintEx((DPFLTR_SETUP_ID,
  3622. DPFLTR_ERROR_LEVEL,
  3623. "SpSetDefaultBootEntry: failed to allocate new Default\n"
  3624. ));
  3625. return STATUS_UNSUCCESSFUL;
  3626. }
  3627. //
  3628. // fetch the arc name for the region
  3629. //
  3630. SpArcNameFromRegion(
  3631. Region,
  3632. TemporaryBuffer,
  3633. sizeof(TemporaryBuffer)/2,
  3634. PartitionOrdinalOnDisk,
  3635. PrimaryArcPath
  3636. );
  3637. //
  3638. // store the new partition and directory info
  3639. //
  3640. wcscpy( Default, TemporaryBuffer);
  3641. SpConcatenatePaths(Default, bootEntry->OsDirectory);
  3642. //
  3643. // get the disk signature of the new default disk
  3644. //
  3645. if ((Region->DiskNumber != 0xffffffff) && HardDisks[Region->DiskNumber].Signature) {
  3646. DefaultSignature = HardDisks[Region->DiskNumber].Signature;
  3647. } else {
  3648. DefaultSignature = 0;
  3649. }
  3650. //
  3651. // update the boot options using the specified mode
  3652. //
  3653. if(SpFlushBootVars() == FALSE) {
  3654. KdPrintEx((DPFLTR_SETUP_ID,
  3655. DPFLTR_ERROR_LEVEL,
  3656. "SpSetDefaultBootEntry: failed flushing boot vars\n"
  3657. ));
  3658. status = STATUS_UNSUCCESSFUL;
  3659. } else {
  3660. status = STATUS_SUCCESS;
  3661. }
  3662. } else {
  3663. KdPrintEx((DPFLTR_SETUP_ID,
  3664. DPFLTR_ERROR_LEVEL,
  3665. "SpSetDefaultBootEntry: failed to find specified boot entry to use as default\n"
  3666. ));
  3667. status = STATUS_NOT_FOUND;
  3668. }
  3669. return status;
  3670. }