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.

2950 lines
78 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. arc.c
  5. Abstract:
  6. ARC/NV-RAM manipulation routines for 32-bit winnt setup.
  7. Author:
  8. Ted Miller (tedm) 19-December-1993
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #include "initguid.h"
  14. #include "diskguid.h"
  15. #ifdef UNICODE // Always true for ARC, never true for Win9x upgrade
  16. #if defined(_X86_)
  17. LOGICAL IsArcChecked = FALSE;
  18. LOGICAL IsArcMachine;
  19. #endif
  20. #if defined(EFI_NVRAM_ENABLED)
  21. #include <ntosp.h> // for ALIGN_UP
  22. LOGICAL IsEfiChecked = FALSE;
  23. LOGICAL IsEfiMachine;
  24. DWORD
  25. InitializeEfiStuff(
  26. IN HWND Parent
  27. );
  28. NTSTATUS
  29. (*AddBootEntry) (
  30. IN PBOOT_ENTRY BootEntry,
  31. OUT PULONG Id OPTIONAL
  32. );
  33. NTSTATUS
  34. (*DeleteBootEntry) (
  35. IN ULONG Id
  36. );
  37. NTSTATUS
  38. (*EnumerateBootEntries) (
  39. OUT PVOID Buffer,
  40. IN OUT PULONG BufferLength
  41. );
  42. NTSTATUS
  43. (*QueryBootEntryOrder) (
  44. OUT PULONG Ids,
  45. IN OUT PULONG Count
  46. );
  47. NTSTATUS
  48. (*SetBootEntryOrder) (
  49. IN PULONG Ids,
  50. IN ULONG Count
  51. );
  52. NTSTATUS
  53. (*QueryBootOptions) (
  54. OUT PBOOT_OPTIONS BootOptions,
  55. IN OUT PULONG BootOptionsLength
  56. );
  57. NTSTATUS
  58. (*SetBootOptions) (
  59. IN PBOOT_OPTIONS BootOptions,
  60. IN ULONG FieldsToChange
  61. );
  62. PBOOT_OPTIONS BootOptions = NULL;
  63. PBOOT_OPTIONS OriginalBootOptions = NULL;
  64. PULONG OriginalBootEntryOrder = NULL;
  65. ULONG OriginalBootEntryOrderCount;
  66. PBOOT_ENTRY_LIST BootEntries = NULL;
  67. //
  68. // MY_BOOT_ENTRY is the internal representation of an EFI NVRAM boot item.
  69. // The NtBootEntry item is the structure passed to/from the NT boot entry APIs.
  70. //
  71. typedef struct _MY_BOOT_ENTRY {
  72. struct _MY_BOOT_ENTRY *Next;
  73. PUCHAR AllocationEnd;
  74. ULONG Status;
  75. PWSTR FriendlyName;
  76. ULONG FriendlyNameLength;
  77. PWSTR OsLoadOptions;
  78. ULONG OsLoadOptionsLength;
  79. PFILE_PATH BootFilePath;
  80. PFILE_PATH OsFilePath;
  81. BOOT_ENTRY NtBootEntry;
  82. } MY_BOOT_ENTRY, *PMY_BOOT_ENTRY;
  83. #define MBE_STATUS_ORDERED 0x00000001
  84. #define MBE_STATUS_NEW 0x00000002
  85. #define MBE_STATUS_DELETED 0x00000004
  86. #define MBE_STATUS_COMMITTED 0x00000008
  87. #define IS_BOOT_ENTRY_ACTIVE(_be) \
  88. (((_be)->NtBootEntry.Attributes & BOOT_ENTRY_ATTRIBUTE_ACTIVE) != 0)
  89. #define IS_BOOT_ENTRY_WINDOWS(_be) \
  90. (((_be)->NtBootEntry.Attributes & BOOT_ENTRY_ATTRIBUTE_WINDOWS) != 0)
  91. #define IS_BOOT_ENTRY_REMOVABLE_MEDIA(_be) \
  92. (((_be)->NtBootEntry.Attributes & BOOT_ENTRY_ATTRIBUTE_REMOVABLE_MEDIA) != 0)
  93. #define IS_BOOT_ENTRY_ORDERED(_be) \
  94. (((_be)->Status & MBE_STATUS_ORDERED) != 0)
  95. #define IS_BOOT_ENTRY_NEW(_be) \
  96. (((_be)->Status & MBE_STATUS_NEW) != 0)
  97. #define IS_BOOT_ENTRY_DELETED(_be) \
  98. (((_be)->Status & MBE_STATUS_DELETED) != 0)
  99. #define IS_BOOT_ENTRY_COMMITTED(_be) \
  100. (((_be)->Status & MBE_STATUS_COMMITTED) != 0)
  101. PMY_BOOT_ENTRY MyBootEntries = NULL;
  102. NTSTATUS
  103. ConvertBootEntries(
  104. VOID
  105. );
  106. BOOL
  107. CreateBootEntry(
  108. PWSTR BootFileDevice,
  109. PWSTR BootFilePath,
  110. PWSTR OsLoadDevice,
  111. PWSTR OsLoadPath,
  112. PWSTR OsLoadOptions,
  113. PWSTR FriendlyName
  114. );
  115. #define ADD_OFFSET(_p,_o) (PVOID)((PUCHAR)(_p) + (_p)->_o)
  116. #endif // defined(EFI_NVRAM_ENABLED)
  117. UINT SystemPartitionCount;
  118. PWSTR* SystemPartitionNtNames;
  119. PWSTR SystemPartitionNtName;
  120. PWSTR SystemPartitionVolumeGuid;
  121. typedef enum {
  122. BootVarSystemPartition,
  123. BootVarOsLoader,
  124. BootVarOsLoadPartition,
  125. BootVarOsLoadFilename,
  126. BootVarLoadIdentifier,
  127. BootVarOsLoadOptions,
  128. BootVarMax
  129. } BootVars;
  130. LPCWSTR BootVarNames[BootVarMax] = { L"SYSTEMPARTITION",
  131. L"OSLOADER",
  132. L"OSLOADPARTITION",
  133. L"OSLOADFILENAME",
  134. L"LOADIDENTIFIER",
  135. L"OSLOADOPTIONS"
  136. };
  137. LPCWSTR szAUTOLOAD = L"AUTOLOAD";
  138. LPCWSTR szCOUNTDOWN = L"COUNTDOWN";
  139. LPWSTR BootVarValues[BootVarMax];
  140. LPCWSTR OriginalBootVarValues[BootVarMax];
  141. LPCWSTR OriginalCountdown;
  142. LPCWSTR OriginalAutoload;
  143. DWORD BootVarComponentCount[BootVarMax];
  144. LPWSTR *BootVarComponents[BootVarMax];
  145. DWORD LargestComponentCount;
  146. LPWSTR DosDeviceTargets[26];
  147. //
  148. // Flag indicating whether we messed with NV-RAM and thus need to
  149. // try to restore it in case the user cancels.
  150. //
  151. BOOL CleanUpNvRam;
  152. //
  153. // Leave as array because some code uses sizeof(ArcNameDirectory)
  154. //
  155. WCHAR ArcNameDirectory[] = L"\\ArcName";
  156. #define GLOBAL_ROOT L"\\\\?\\GLOBALROOT"
  157. #define MAX_COMPONENTS 20
  158. WCHAR ForcedSystemPartition;
  159. //
  160. // Helper macro to make object attribute initialization a little cleaner.
  161. //
  162. #define INIT_OBJA(Obja,UnicodeString,UnicodeText) \
  163. \
  164. RtlInitUnicodeString((UnicodeString),(UnicodeText)); \
  165. \
  166. InitializeObjectAttributes( \
  167. (Obja), \
  168. (UnicodeString), \
  169. OBJ_CASE_INSENSITIVE, \
  170. NULL, \
  171. NULL \
  172. )
  173. UINT
  174. NormalizeArcPath(
  175. IN PCWSTR Path,
  176. OUT LPWSTR *NormalizedPath
  177. )
  178. /*++
  179. Routine Description:
  180. Transform an ARC path into one with no sets of empty parenthesis
  181. (ie, transforom all instances of () to (0).).
  182. Arguments:
  183. Path - ARC path to be normalized.
  184. NormalizedPath - if successful, receives a pointer to the
  185. normalized arc path. The caller must free with FREE().
  186. Return Value:
  187. Win32 error code indicating outcome.
  188. --*/
  189. {
  190. LPWSTR r;
  191. LPCWSTR p,q;
  192. LPWSTR normalizedPath;
  193. if(normalizedPath = MALLOC((lstrlen(Path)+100)*sizeof(WCHAR))) {
  194. ZeroMemory(normalizedPath,(lstrlen(Path)+100)*sizeof(WCHAR));
  195. } else {
  196. return(ERROR_NOT_ENOUGH_MEMORY);
  197. }
  198. for(p=Path; q=wcsstr(p,L"()"); p=q+2) {
  199. r = normalizedPath + lstrlen(normalizedPath);
  200. lstrcpyn(r,p,(int)(q-p)+1);
  201. lstrcat(normalizedPath,L"(0)");
  202. }
  203. lstrcat(normalizedPath,p);
  204. if(r = REALLOC(normalizedPath,(lstrlen(normalizedPath)+1)*sizeof(WCHAR))) {
  205. *NormalizedPath = r;
  206. return(NO_ERROR);
  207. } else {
  208. FREE(normalizedPath);
  209. return(ERROR_NOT_ENOUGH_MEMORY);
  210. }
  211. }
  212. DWORD
  213. GetVarComponents(
  214. IN PCWSTR VarValue,
  215. OUT LPWSTR **Components,
  216. OUT PDWORD ComponentCount
  217. )
  218. /*++
  219. Routine Description:
  220. Split a semi-colon delineated list of arc paths up into
  221. a set of individual strings. For each component
  222. leading and trailing spaces are stripped out.
  223. Arguments:
  224. VarValue - supplies string with list of arc paths to be split apart.
  225. Components - receives array of pointers to individual components
  226. on the variable specified in VarValue.
  227. ComponentCount - receives number of separate arc paths in the
  228. Components array.
  229. Return Value:
  230. Win32 error indicating outcome. If NO_ERROR then the caller
  231. must free the Components array and the strings pointed to by its elements.
  232. --*/
  233. {
  234. LPWSTR *components;
  235. LPWSTR *temp;
  236. DWORD componentCount;
  237. LPCWSTR p;
  238. LPCWSTR Var;
  239. LPWSTR comp;
  240. DWORD len;
  241. UINT ec;
  242. components = MALLOC(MAX_COMPONENTS * sizeof(LPWSTR));
  243. if(!components) {
  244. return(ERROR_NOT_ENOUGH_MEMORY);
  245. }
  246. ZeroMemory(components,MAX_COMPONENTS * sizeof(LPWSTR));
  247. ec = NO_ERROR;
  248. for(Var=VarValue,componentCount=0; *Var; ) {
  249. //
  250. // Skip leading spaces.
  251. //
  252. while((*Var == L' ') || (*Var == L'\t')) {
  253. Var++;
  254. }
  255. if(*Var == 0) {
  256. break;
  257. }
  258. p = Var;
  259. while(*p && (*p != L';')) {
  260. p++;
  261. }
  262. len = (DWORD)((PUCHAR)p - (PUCHAR)Var);
  263. comp = MALLOC(len + sizeof(WCHAR));
  264. if(!comp) {
  265. ec = ERROR_NOT_ENOUGH_MEMORY;
  266. break;
  267. }
  268. len /= sizeof(WCHAR);
  269. lstrcpynW(comp,Var,len+1);
  270. ec = NormalizeArcPath(comp,&components[componentCount]);
  271. FREE(comp);
  272. if(ec != NO_ERROR) {
  273. break;
  274. }
  275. componentCount++;
  276. if(componentCount == MAX_COMPONENTS) {
  277. break;
  278. }
  279. Var = p;
  280. if(*Var) {
  281. Var++; // skip ;
  282. }
  283. }
  284. if(ec == NO_ERROR) {
  285. if(componentCount) {
  286. temp = REALLOC(components,componentCount*sizeof(LPWSTR));
  287. if(!temp) {
  288. ec = ERROR_NOT_ENOUGH_MEMORY;
  289. }
  290. } else {
  291. temp = NULL;
  292. }
  293. }
  294. if(ec == NO_ERROR) {
  295. *Components = temp;
  296. *ComponentCount = componentCount;
  297. } else {
  298. for(len=0; components[len] && (len<MAX_COMPONENTS); len++) {
  299. FREE(components[len]);
  300. }
  301. FREE(components);
  302. }
  303. return(ec);
  304. }
  305. NTSTATUS
  306. QueryCanonicalName(
  307. IN PWSTR Name,
  308. IN ULONG MaxDepth,
  309. OUT PWSTR CanonicalName,
  310. IN ULONG SizeOfBufferInBytes
  311. )
  312. /*++
  313. Routine Description:
  314. Resolves the symbolic name to the specified depth. To resolve
  315. a symbolic name completely specify the MaxDepth as -1
  316. Arguments:
  317. Name - Symbolic name to be resolved
  318. MaxDepth - The depth till which the resolution needs to
  319. be carried out
  320. CanonicalName - The fully resolved name
  321. SizeOfBufferInBytes - The size of the CanonicalName buffer in
  322. bytes
  323. Return Value:
  324. Appropriate NT status code
  325. --*/
  326. {
  327. UNICODE_STRING name, canonName;
  328. OBJECT_ATTRIBUTES oa;
  329. NTSTATUS status;
  330. HANDLE handle;
  331. ULONG CurrentDepth;
  332. RtlInitUnicodeString(&name, Name);
  333. canonName.MaximumLength = (USHORT) (SizeOfBufferInBytes - sizeof(WCHAR));
  334. canonName.Length = 0;
  335. canonName.Buffer = CanonicalName;
  336. if (name.Length >= canonName.MaximumLength) {
  337. return STATUS_BUFFER_TOO_SMALL;
  338. }
  339. RtlCopyMemory(canonName.Buffer, name.Buffer, name.Length);
  340. canonName.Length = name.Length;
  341. canonName.Buffer[canonName.Length/sizeof(WCHAR)] = 0;
  342. for (CurrentDepth = 0; CurrentDepth < MaxDepth; CurrentDepth++) {
  343. InitializeObjectAttributes(&oa, &canonName, OBJ_CASE_INSENSITIVE, 0, 0);
  344. status = NtOpenSymbolicLinkObject(&handle,
  345. READ_CONTROL | SYMBOLIC_LINK_QUERY,
  346. &oa);
  347. if (!NT_SUCCESS(status)) {
  348. break;
  349. }
  350. status = NtQuerySymbolicLinkObject(handle, &canonName, NULL);
  351. NtClose(handle);
  352. if (!NT_SUCCESS(status)) {
  353. return status;
  354. }
  355. canonName.Buffer[canonName.Length/sizeof(WCHAR)] = 0;
  356. }
  357. return STATUS_SUCCESS;
  358. }
  359. //
  360. // Structure to map from old NT partition names like
  361. // \device\harddisk0\partition1 to new NT partition names
  362. // like \device\harddiskvolume1
  363. //
  364. typedef struct _NAME_TRANSLATIONS {
  365. WCHAR OldNtName[MAX_PATH];
  366. WCHAR NewNtName[MAX_PATH];
  367. } NT_NAME_TRANSLATION, * PNT_NAME_TRANSLATION;
  368. //
  369. // Map of old style NT partition names to new style NT
  370. // partition names
  371. //
  372. NT_NAME_TRANSLATION OldNewNtNames[256] = {0};
  373. PWSTR
  374. OldNtNameToNewNtName(
  375. IN PCWSTR OldNtName
  376. )
  377. /*++
  378. Routine Description:
  379. Given a old format NT name tries to lookup at new format
  380. NT name in the global map
  381. Arguments:
  382. OldNtName - The partition name specified in the old
  383. format
  384. Return Value:
  385. The new NT name if there exists one, otherwise NULL.
  386. --*/
  387. {
  388. ULONG Index = 0;
  389. ULONG MaxEntries = sizeof(OldNewNtNames)/sizeof(NT_NAME_TRANSLATION);
  390. PWSTR NewNtName = NULL;
  391. for (Index = 0; (Index < MaxEntries); Index++) {
  392. if (OldNewNtNames[Index].OldNtName[0] &&
  393. !_wcsicmp(OldNewNtNames[Index].OldNtName, OldNtName)) {
  394. NewNtName = OldNewNtNames[Index].NewNtName;
  395. }
  396. }
  397. return NewNtName;
  398. }
  399. PWSTR
  400. NewNtNameToOldNtName(
  401. IN PCWSTR NewNtName
  402. )
  403. /*++
  404. Routine Description:
  405. Given a new format NT name tries to lookup at old format
  406. NT name in the global map
  407. Arguments:
  408. NewNtName - The partition name specified in the new
  409. format
  410. Return Value:
  411. The old NT name if there exists one, otherwise NULL.
  412. --*/
  413. {
  414. ULONG Index = 0;
  415. ULONG MaxEntries = sizeof(OldNewNtNames)/sizeof(NT_NAME_TRANSLATION);
  416. PWSTR OldNtName = NULL;
  417. for (Index=0; (Index < MaxEntries); Index++) {
  418. if (OldNewNtNames[Index].NewNtName[0] &&
  419. !_wcsicmp(OldNewNtNames[Index].NewNtName, NewNtName)) {
  420. OldNtName = OldNewNtNames[Index].OldNtName;
  421. }
  422. }
  423. return OldNtName;
  424. }
  425. DWORD
  426. InitOldToNewNtNameTranslations(
  427. VOID
  428. )
  429. /*++
  430. Routine Description:
  431. Initializes the global old NT partition names to
  432. new NT partition names mapping.
  433. Arguments:
  434. None.
  435. Return Value:
  436. The number of valid entries in the map
  437. --*/
  438. {
  439. DWORD MappingCount = 0;
  440. SYSTEM_DEVICE_INFORMATION SysDevInfo = {0};
  441. NTSTATUS Status;
  442. OBJECT_ATTRIBUTES ObjAttrs;
  443. UNICODE_STRING ObjName;
  444. Status = NtQuerySystemInformation(SystemDeviceInformation,
  445. &SysDevInfo,
  446. sizeof(SYSTEM_DEVICE_INFORMATION),
  447. NULL);
  448. if (NT_SUCCESS(Status)) {
  449. ULONG Index;
  450. WCHAR OldNtPath[MAX_PATH];
  451. DWORD ErrorCode = 0;
  452. ULONG SlotIndex = 0;
  453. ULONG MaxSlots = sizeof(OldNewNtNames)/sizeof(NT_NAME_TRANSLATION);
  454. for (Index=0;
  455. (!ErrorCode) && (Index < SysDevInfo.NumberOfDisks) &&
  456. (SlotIndex < MaxSlots);
  457. Index++) {
  458. HANDLE DirectoryHandle;
  459. swprintf(OldNtPath,
  460. L"\\device\\Harddisk%d",
  461. Index);
  462. //
  463. // Open the disk directory.
  464. //
  465. INIT_OBJA(&ObjAttrs, &ObjName, OldNtPath);
  466. Status = NtOpenDirectoryObject(&DirectoryHandle,
  467. DIRECTORY_QUERY,
  468. &ObjAttrs);
  469. if(NT_SUCCESS(Status)) {
  470. BOOLEAN RestartScan = TRUE;
  471. ULONG Context = 0;
  472. BOOLEAN MoreEntries = TRUE;
  473. WCHAR Buffer[MAX_PATH * 2] = {0};
  474. POBJECT_DIRECTORY_INFORMATION DirInfo = (POBJECT_DIRECTORY_INFORMATION)Buffer;
  475. do {
  476. Status = NtQueryDirectoryObject(
  477. DirectoryHandle,
  478. Buffer,
  479. sizeof(Buffer),
  480. TRUE, // return single entry
  481. RestartScan,
  482. &Context,
  483. NULL // return length
  484. );
  485. if(NT_SUCCESS(Status)) {
  486. //
  487. // Make sure this name is a symbolic link.
  488. //
  489. if(DirInfo->Name.Length &&
  490. (DirInfo->TypeName.Length >= 24) &&
  491. CharUpperBuff((LPWSTR)DirInfo->TypeName.Buffer,12) &&
  492. !memcmp(DirInfo->TypeName.Buffer,L"SYMBOLICLINK",24)) {
  493. WCHAR EntryName[MAX_PATH];
  494. lstrcpy(EntryName, OldNtPath);
  495. ConcatenatePaths(EntryName,
  496. DirInfo->Name.Buffer,
  497. (DWORD)(-1));
  498. Status = QueryCanonicalName(EntryName, -1, Buffer, sizeof(Buffer));
  499. if (NT_SUCCESS(Status)) {
  500. wcscpy(OldNewNtNames[SlotIndex].OldNtName, EntryName);
  501. wcscpy(OldNewNtNames[SlotIndex].NewNtName, Buffer);
  502. SlotIndex++;
  503. }
  504. }
  505. } else {
  506. MoreEntries = FALSE;
  507. if(Status == STATUS_NO_MORE_ENTRIES) {
  508. Status = STATUS_SUCCESS;
  509. }
  510. ErrorCode = RtlNtStatusToDosError(Status);
  511. }
  512. RestartScan = FALSE;
  513. } while(MoreEntries && (SlotIndex < MaxSlots));
  514. NtClose(DirectoryHandle);
  515. } else {
  516. ErrorCode = RtlNtStatusToDosError(Status);
  517. }
  518. }
  519. if (!ErrorCode && NT_SUCCESS(Status)) {
  520. MappingCount = SlotIndex;
  521. }
  522. }
  523. return MappingCount;
  524. }
  525. DWORD
  526. NtNameToArcPath (
  527. IN PCWSTR NtName,
  528. OUT LPWSTR *ArcPath
  529. )
  530. /*++
  531. Routine Description:
  532. Convert an NT volume name to an ARC path.
  533. Arguments:
  534. NtName - supplies name of drive to be converted.
  535. ArcPath - receives pointer to buffer containing arc path
  536. if the routine is successful. Caller must free with FREE().
  537. Return Value:
  538. Win32 error code indicating outcome.
  539. --*/
  540. {
  541. UNICODE_STRING UnicodeString;
  542. HANDLE DirectoryHandle;
  543. OBJECT_ATTRIBUTES Obja;
  544. NTSTATUS Status;
  545. BOOLEAN RestartScan;
  546. DWORD Context;
  547. BOOL MoreEntries;
  548. LPWSTR ArcName = NULL;
  549. WCHAR Buffer[512];
  550. WCHAR ArcDiskName[MAX_PATH] = {0};
  551. WCHAR NtDiskName[MAX_PATH] = {0};
  552. WCHAR ArcPartitionName[MAX_PATH] = {0};
  553. PWSTR PartitionName = NULL;
  554. PWSTR PartitionNumStr = NULL;
  555. POBJECT_DIRECTORY_INFORMATION DirInfo = (POBJECT_DIRECTORY_INFORMATION)Buffer;
  556. DWORD ErrorCode;
  557. ErrorCode = NO_ERROR;
  558. *ArcPath = NULL;
  559. //
  560. // Get hold of the NT disk name
  561. //
  562. PartitionName = NewNtNameToOldNtName(NtName);
  563. if (PartitionName) {
  564. PWSTR PartitionNameStart = PartitionName;
  565. PartitionName = wcsrchr(PartitionName, L'\\');
  566. if (PartitionName && wcsstr(PartitionName, L"Partition")) {
  567. wcsncpy(NtDiskName, PartitionNameStart, PartitionName - PartitionNameStart);
  568. wcscat(NtDiskName, L"\\Partition0");
  569. PartitionNumStr = PartitionName + wcslen(L"\\Partition");
  570. }
  571. }
  572. //
  573. // Open the \ArcName directory.
  574. //
  575. INIT_OBJA(&Obja,&UnicodeString,ArcNameDirectory);
  576. Status = NtOpenDirectoryObject(&DirectoryHandle,DIRECTORY_QUERY,&Obja);
  577. if(NT_SUCCESS(Status)) {
  578. RestartScan = TRUE;
  579. Context = 0;
  580. MoreEntries = TRUE;
  581. do {
  582. Status = NtQueryDirectoryObject(
  583. DirectoryHandle,
  584. Buffer,
  585. sizeof(Buffer),
  586. TRUE, // return single entry
  587. RestartScan,
  588. &Context,
  589. NULL // return length
  590. );
  591. if(NT_SUCCESS(Status)) {
  592. CharLower(DirInfo->Name.Buffer);
  593. //
  594. // Make sure this name is a symbolic link.
  595. //
  596. if(DirInfo->Name.Length
  597. && (DirInfo->TypeName.Length >= 24)
  598. && CharUpperBuff((LPWSTR)DirInfo->TypeName.Buffer,12)
  599. && !memcmp(DirInfo->TypeName.Buffer,L"SYMBOLICLINK",24))
  600. {
  601. WCHAR OldNtName[MAX_PATH] = {0};
  602. ArcName = MALLOC(DirInfo->Name.Length + sizeof(ArcNameDirectory) + sizeof(WCHAR));
  603. if(!ArcName) {
  604. ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
  605. break;
  606. }
  607. lstrcpy(ArcName,ArcNameDirectory);
  608. ConcatenatePaths(ArcName,DirInfo->Name.Buffer,(DWORD)(-1));
  609. //
  610. // We have the entire arc name in ArcName. Now open the first
  611. // level symbolic link.
  612. //
  613. Status = QueryCanonicalName(ArcName, 1, Buffer, sizeof(Buffer));
  614. if (NT_SUCCESS(Status)) {
  615. wcscpy(OldNtName, Buffer);
  616. //
  617. // Now resolve the complete symbolic link
  618. //
  619. Status = QueryCanonicalName(ArcName, -1, Buffer, sizeof(Buffer));
  620. if (NT_SUCCESS(Status)) {
  621. if(!lstrcmpi(Buffer, NtName)) {
  622. *ArcPath = ArcName + (sizeof(ArcNameDirectory)/sizeof(WCHAR));
  623. } else {
  624. if (!lstrcmpi(OldNtName, NtDiskName)) {
  625. wcscpy(ArcDiskName,
  626. ArcName + (sizeof(ArcNameDirectory)/sizeof(WCHAR)));
  627. }
  628. }
  629. } else {
  630. if(!lstrcmpi(OldNtName, NtName)) {
  631. *ArcPath = ArcName + (sizeof(ArcNameDirectory)/sizeof(WCHAR));
  632. }
  633. }
  634. }
  635. if(!(*ArcPath)) {
  636. FREE(ArcName);
  637. ArcName = NULL;
  638. }
  639. }
  640. } else {
  641. MoreEntries = FALSE;
  642. if(Status == STATUS_NO_MORE_ENTRIES) {
  643. Status = STATUS_SUCCESS;
  644. }
  645. ErrorCode = RtlNtStatusToDosError(Status);
  646. }
  647. RestartScan = FALSE;
  648. } while(MoreEntries && !(*ArcPath));
  649. NtClose(DirectoryHandle);
  650. } else {
  651. ErrorCode = RtlNtStatusToDosError(Status);
  652. }
  653. //
  654. // If we found a match for the disk but not for the actual
  655. // partition specified then guess thepartition number
  656. // (based on the current nt partition number )
  657. //
  658. if ((!*ArcPath) && ArcDiskName[0] && PartitionName && PartitionNumStr) {
  659. PWSTR EndPtr = NULL;
  660. ULONG PartitionNumber = wcstoul(PartitionNumStr, &EndPtr, 10);
  661. if (PartitionNumber) {
  662. swprintf(ArcPartitionName,
  663. L"%wspartition(%d)",
  664. ArcDiskName,
  665. PartitionNumber);
  666. *ArcPath = DupString(ArcPartitionName);
  667. ErrorCode = NO_ERROR;
  668. DebugLog( Winnt32LogInformation,
  669. TEXT("\nCould not find arcname mapping for %1 partition.\r\n")
  670. TEXT("Guessing the arcname to be %2"),
  671. 0,
  672. NtName,
  673. ArcPartitionName);
  674. }
  675. }
  676. if (ErrorCode == NO_ERROR) {
  677. if(*ArcPath) {
  678. //
  679. // ArcPath points into the middle of a buffer.
  680. // The caller needs to be able to free it, so place it in its
  681. // own buffer here.
  682. //
  683. *ArcPath = DupString(*ArcPath);
  684. if (ArcName) {
  685. FREE(ArcName);
  686. }
  687. if(*ArcPath == NULL) {
  688. ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
  689. }
  690. } else {
  691. //
  692. // No matching drive.
  693. //
  694. ErrorCode = ERROR_INVALID_DRIVE;
  695. }
  696. }
  697. return ErrorCode;
  698. }
  699. DWORD
  700. DriveLetterToArcPath(
  701. IN WCHAR DriveLetter,
  702. OUT LPWSTR *ArcPath
  703. )
  704. /*++
  705. Routine Description:
  706. Convert a drive letter to an ARC path.
  707. This routine relies on the DosDeviceTargets array being set up
  708. beforehand.
  709. Arguments:
  710. DriveLetter - supplies letter of drive to be converted.
  711. ArcPath - receives pointer to buffer containing arc path
  712. if the routine is successful. Caller must free with FREE().
  713. Return Value:
  714. Win32 error code indicating outcome.
  715. --*/
  716. {
  717. LPWSTR NtPath;
  718. NtPath = DosDeviceTargets[(WCHAR)CharUpper((PWCHAR)DriveLetter)-L'A'];
  719. if(!NtPath) {
  720. return(ERROR_INVALID_DRIVE);
  721. }
  722. return NtNameToArcPath (NtPath, ArcPath);
  723. }
  724. DWORD
  725. ArcPathToDriveLetterAndNtName (
  726. IN PCWSTR ArcPath,
  727. OUT PWCHAR DriveLetter,
  728. OUT PWSTR NtName,
  729. IN DWORD BufferSizeInBytes
  730. )
  731. /*++
  732. Routine Description:
  733. Convert an arc path to a drive letter.
  734. This routine relies on the DosDeviceTargets array being set up
  735. beforehand.
  736. Arguments:
  737. ArcPath - specifies arc path to be converted.
  738. DriveLetter - if successful, receives letter of drive.
  739. Return Value:
  740. Win32 error code indicating outcome.
  741. --*/
  742. {
  743. NTSTATUS Status;
  744. WCHAR drive;
  745. LPWSTR arcPath;
  746. DWORD ec;
  747. //
  748. // Assume failure
  749. //
  750. *DriveLetter = 0;
  751. arcPath = MALLOC(((lstrlen(ArcPath)+1)*sizeof(WCHAR)) + sizeof(ArcNameDirectory));
  752. if(!arcPath) {
  753. return(ERROR_NOT_ENOUGH_MEMORY);
  754. }
  755. lstrcpy(arcPath,ArcNameDirectory);
  756. lstrcat(arcPath,L"\\");
  757. lstrcat(arcPath,ArcPath);
  758. Status = QueryCanonicalName(arcPath, -1, NtName, BufferSizeInBytes);
  759. if (NT_SUCCESS(Status)) {
  760. ec = ERROR_INVALID_DRIVE;
  761. for(drive=L'A'; drive<=L'Z'; drive++) {
  762. if(DosDeviceTargets[drive-L'A']
  763. && !lstrcmpi(NtName,DosDeviceTargets[drive-L'A']))
  764. {
  765. *DriveLetter = drive;
  766. ec = NO_ERROR;
  767. break;
  768. }
  769. }
  770. } else {
  771. ec = RtlNtStatusToDosError(Status);
  772. }
  773. FREE(arcPath);
  774. return(ec);
  775. }
  776. DWORD
  777. InitDriveNameTranslations(
  778. VOID
  779. )
  780. {
  781. WCHAR DriveName[15];
  782. WCHAR Drive;
  783. WCHAR Buffer[512];
  784. NTSTATUS status;
  785. swprintf(DriveName, L"\\DosDevices\\c:");
  786. //
  787. // Calculate NT names for all local hard disks C-Z.
  788. //
  789. for(Drive=L'A'; Drive<=L'Z'; Drive++) {
  790. DosDeviceTargets[Drive-L'A'] = NULL;
  791. if(MyGetDriveType(Drive) == DRIVE_FIXED) {
  792. DriveName[12] = Drive;
  793. status = QueryCanonicalName(DriveName, -1, Buffer, sizeof(Buffer));
  794. if (NT_SUCCESS(status)) {
  795. DosDeviceTargets[Drive-L'A'] = DupString(Buffer);
  796. if(!DosDeviceTargets[Drive-L'A']) {
  797. return(ERROR_NOT_ENOUGH_MEMORY);
  798. }
  799. }
  800. }
  801. }
  802. //
  803. // Initialize old Nt Parition names to new partition name
  804. // mapping
  805. //
  806. InitOldToNewNtNameTranslations();
  807. return(NO_ERROR);
  808. }
  809. DWORD
  810. DetermineSystemPartitions(
  811. VOID
  812. )
  813. {
  814. LPWSTR *SyspartComponents;
  815. DWORD NumSyspartComponents;
  816. DWORD d;
  817. DWORD rc;
  818. UINT u;
  819. WCHAR drive;
  820. WCHAR DeviceNtName[512];
  821. SyspartComponents = BootVarComponents[BootVarSystemPartition];
  822. NumSyspartComponents = BootVarComponentCount[BootVarSystemPartition];
  823. SystemPartitionNtNames = MALLOC ((NumSyspartComponents + 1) * sizeof (PWSTR));
  824. if (!SystemPartitionNtNames) {
  825. return ERROR_NOT_ENOUGH_MEMORY;
  826. }
  827. ZeroMemory(SystemPartitionNtNames, (NumSyspartComponents + 1) * sizeof (PWSTR));
  828. ZeroMemory(SystemPartitionDriveLetters,27*sizeof(WCHAR));
  829. //
  830. // Convert each system partition to a drive letter.
  831. //
  832. for(d=0; d<NumSyspartComponents; d++) {
  833. //
  834. // check for duplicates
  835. //
  836. if (SystemPartitionCount > 0) {
  837. for (u = 0; u < SystemPartitionCount; u++) {
  838. if (lstrcmpi (SyspartComponents[d], SystemPartitionNtNames[u]) == 0) {
  839. break;
  840. }
  841. }
  842. if (u < SystemPartitionCount) {
  843. continue;
  844. }
  845. }
  846. rc = ArcPathToDriveLetterAndNtName (
  847. SyspartComponents[d],
  848. &drive,
  849. DeviceNtName,
  850. (DWORD) sizeof (DeviceNtName)
  851. );
  852. if(rc == ERROR_NOT_ENOUGH_MEMORY) {
  853. return(ERROR_NOT_ENOUGH_MEMORY);
  854. }
  855. if (rc == ERROR_SUCCESS) {
  856. SystemPartitionDriveLetters[SystemPartitionCount] = drive;
  857. }
  858. SystemPartitionNtNames[SystemPartitionCount++] = DupString (DeviceNtName);
  859. }
  860. return(NO_ERROR);
  861. }
  862. DWORD
  863. DoInitializeArcStuff(
  864. VOID
  865. )
  866. {
  867. DWORD ec;
  868. DWORD var;
  869. UNICODE_STRING UnicodeString;
  870. NTSTATUS Status;
  871. WCHAR Buffer[4096];
  872. ec = InitDriveNameTranslations();
  873. if(ec != NO_ERROR) {
  874. goto c0;
  875. }
  876. //
  877. // Get relevent boot vars.
  878. //
  879. // Enable privilege -- since we check this privilege up front
  880. // in main() this should not fail.
  881. //
  882. if(!EnablePrivilege(SE_SYSTEM_ENVIRONMENT_NAME,TRUE)) {
  883. ec = ERROR_ACCESS_DENIED;
  884. goto c0;
  885. }
  886. for(var=0; var<BootVarMax; var++) {
  887. RtlInitUnicodeString(&UnicodeString,BootVarNames[var]);
  888. Status = NtQuerySystemEnvironmentValue(
  889. &UnicodeString,
  890. Buffer,
  891. sizeof(Buffer) / sizeof(WCHAR),
  892. NULL
  893. );
  894. if(NT_SUCCESS(Status)) {
  895. BootVarValues[var] = DupString(Buffer);
  896. OriginalBootVarValues[var] = DupString(Buffer);
  897. } else {
  898. //
  899. // We may get back failure if the variable is empty.
  900. //
  901. BootVarValues[var] = DupString(L"");
  902. OriginalBootVarValues[var] = DupString(L"");
  903. }
  904. if(!BootVarValues[var] || !OriginalBootVarValues[var]) {
  905. ec = ERROR_NOT_ENOUGH_MEMORY;
  906. goto c2;
  907. }
  908. ec = GetVarComponents(
  909. BootVarValues[var],
  910. &BootVarComponents[var],
  911. &BootVarComponentCount[var]
  912. );
  913. if(ec != NO_ERROR) {
  914. goto c2;
  915. }
  916. //
  917. // Track the variable with the most number of components.
  918. //
  919. if(BootVarComponentCount[var] > LargestComponentCount) {
  920. LargestComponentCount = BootVarComponentCount[var];
  921. }
  922. }
  923. //
  924. // Get original countdown and autoload values.
  925. // If not successful, oh well, we won't be able to restore them
  926. // if the user cancels.
  927. //
  928. RtlInitUnicodeString(&UnicodeString,szCOUNTDOWN);
  929. Status = NtQuerySystemEnvironmentValue(
  930. &UnicodeString,
  931. Buffer,
  932. sizeof(Buffer) / sizeof(WCHAR),
  933. NULL
  934. );
  935. if(NT_SUCCESS(Status)) {
  936. OriginalCountdown = DupString(Buffer);
  937. } else {
  938. OriginalCountdown = DupString(L"");
  939. }
  940. RtlInitUnicodeString(&UnicodeString,szAUTOLOAD);
  941. Status = NtQuerySystemEnvironmentValue(
  942. &UnicodeString,
  943. Buffer,
  944. sizeof(Buffer) / sizeof(WCHAR),
  945. NULL
  946. );
  947. if(NT_SUCCESS(Status)) {
  948. OriginalAutoload = DupString(Buffer);
  949. } else {
  950. OriginalAutoload = DupString(L"NO");
  951. }
  952. ec = DetermineSystemPartitions();
  953. if(ec != NO_ERROR) {
  954. goto c2;
  955. }
  956. return(NO_ERROR);
  957. c2:
  958. c0:
  959. return(ec);
  960. }
  961. BOOL
  962. ArcInitializeArcStuff(
  963. IN HWND Parent
  964. )
  965. {
  966. DWORD ec;
  967. BOOL b;
  968. HKEY key;
  969. DWORD type;
  970. DWORD size;
  971. PBYTE buffer = NULL;
  972. DWORD i;
  973. #if defined(EFI_NVRAM_ENABLED)
  974. //
  975. // Try to initialize as an EFI machine. If we're on an EFI machine,
  976. // this will succeed. Otherwise it will fail, in which case we try
  977. // to initialize as an ARC machine.
  978. //
  979. ec = InitializeEfiStuff(Parent);
  980. if (!IsEfi())
  981. #endif
  982. {
  983. //
  984. // Try to initialize as an ARC machine. This is expect to
  985. // always succeed.
  986. //
  987. ec = DoInitializeArcStuff();
  988. }
  989. switch(ec) {
  990. case NO_ERROR:
  991. #if defined(EFI_NVRAM_ENABLED)
  992. //
  993. // On an EFI machine, the rest of this code (determining system
  994. // partitions) is not necessary.
  995. //
  996. if (IsEfi()) {
  997. b = TRUE;
  998. } else
  999. #endif
  1000. {
  1001. //
  1002. // Make sure there is at least one valid system partition.
  1003. //
  1004. if(!SystemPartitionCount) {
  1005. MessageBoxFromMessage(
  1006. Parent,
  1007. MSG_SYSTEM_PARTITION_INVALID,
  1008. FALSE,
  1009. AppTitleStringId,
  1010. MB_OK | MB_ICONERROR | MB_TASKMODAL
  1011. );
  1012. b = FALSE;
  1013. } else {
  1014. i = 0;
  1015. //
  1016. // On ARC machines we set up a local boot directory that is
  1017. // placed in the root of the system partition.
  1018. //
  1019. //
  1020. // read the SystemPartition value from registry
  1021. //
  1022. ec = RegOpenKey (HKEY_LOCAL_MACHINE, TEXT("System\\Setup"), &key);
  1023. if (ec == ERROR_SUCCESS) {
  1024. ec = RegQueryValueEx (key, TEXT("SystemPartition"), NULL, &type, NULL, &size);
  1025. if (ec == ERROR_SUCCESS && type == REG_SZ) {
  1026. buffer = MALLOC (size);
  1027. if (buffer) {
  1028. ec = RegQueryValueEx (key, TEXT("SystemPartition"), NULL, &type, buffer, &size);
  1029. if (ec != ERROR_SUCCESS) {
  1030. FREE (buffer);
  1031. buffer = NULL;
  1032. }
  1033. }
  1034. }
  1035. RegCloseKey (key);
  1036. }
  1037. #if defined(EFI_NVRAM_ENABLED)
  1038. //
  1039. // we just trust the value that comes from the regkey -- EFI
  1040. // systems only have one system partition, so it doesn't make
  1041. // sense to try to match this up against a list of potential
  1042. // system partitions.
  1043. //
  1044. SystemPartitionNtName = (PWSTR) buffer;
  1045. #else
  1046. //
  1047. // look for this system partition to make sure things are OK
  1048. //
  1049. if (buffer) {
  1050. while (i < SystemPartitionCount) {
  1051. if (lstrcmpi (SystemPartitionNtNames[i], (PCTSTR)buffer) == 0) {
  1052. SystemPartitionNtName = SystemPartitionNtNames[i];
  1053. break;
  1054. }
  1055. i++;
  1056. }
  1057. FREE (buffer);
  1058. }
  1059. #endif
  1060. if(!SystemPartitionNtName) {
  1061. MessageBoxFromMessage(
  1062. Parent,
  1063. MSG_SYSTEM_PARTITION_INVALID,
  1064. FALSE,
  1065. AppTitleStringId,
  1066. MB_OK | MB_ICONERROR | MB_TASKMODAL
  1067. );
  1068. b = FALSE;
  1069. break;
  1070. }
  1071. #if !defined(EFI_NVRAM_ENABLED)
  1072. if (SystemPartitionDriveLetters[i]) {
  1073. SystemPartitionDriveLetter = ForcedSystemPartition
  1074. ? ForcedSystemPartition
  1075. : SystemPartitionDriveLetters[i];
  1076. LocalBootDirectory[0] = SystemPartitionDriveLetter;
  1077. LocalBootDirectory[1] = TEXT(':');
  1078. LocalBootDirectory[2] = TEXT('\\');
  1079. LocalBootDirectory[3] = 0;
  1080. } else
  1081. #endif
  1082. {
  1083. // SystemPartitionNtNtname is valid at this point thanks to
  1084. // the check above.
  1085. size = sizeof(GLOBAL_ROOT) +
  1086. lstrlen(SystemPartitionNtName)*sizeof(WCHAR) +
  1087. sizeof(WCHAR) + sizeof(WCHAR);
  1088. SystemPartitionVolumeGuid = MALLOC (size);
  1089. if(!SystemPartitionVolumeGuid) {
  1090. goto MemoryError;
  1091. }
  1092. lstrcpy (SystemPartitionVolumeGuid, GLOBAL_ROOT);
  1093. lstrcat (SystemPartitionVolumeGuid, SystemPartitionNtName);
  1094. lstrcat (SystemPartitionVolumeGuid, L"\\");
  1095. lstrcpy (LocalBootDirectory, SystemPartitionVolumeGuid);
  1096. }
  1097. b = TRUE;
  1098. }
  1099. }
  1100. break;
  1101. case ERROR_NOT_ENOUGH_MEMORY:
  1102. MemoryError:
  1103. MessageBoxFromMessage(
  1104. Parent,
  1105. MSG_OUT_OF_MEMORY,
  1106. FALSE,
  1107. AppTitleStringId,
  1108. MB_OK | MB_ICONERROR | MB_TASKMODAL
  1109. );
  1110. b = FALSE;
  1111. break;
  1112. default:
  1113. //
  1114. // Some other unknown error.
  1115. //
  1116. MessageBoxFromMessage(
  1117. Parent,
  1118. MSG_COULDNT_READ_NVRAM,
  1119. FALSE,
  1120. AppTitleStringId,
  1121. MB_OK | MB_ICONERROR | MB_TASKMODAL
  1122. );
  1123. b = FALSE;
  1124. break;
  1125. }
  1126. #if defined(EFI_NVRAM_ENABLED)
  1127. //
  1128. // make sure the system partition is on a GPT disk.
  1129. //
  1130. if (b) {
  1131. HANDLE hDisk;
  1132. PARTITION_INFORMATION_EX partitionEx;
  1133. DWORD sizePartitionEx = 0;
  1134. UNICODE_STRING uString;
  1135. OBJECT_ATTRIBUTES ObjectAttributes;
  1136. IO_STATUS_BLOCK IoStatus;
  1137. NTSTATUS Status;
  1138. PWSTR p,q;
  1139. b = FALSE;
  1140. MYASSERT( SystemPartitionVolumeGuid != NULL );
  1141. //
  1142. // SystemPartitionVolumeGuid may have a '\' at the end of it.
  1143. // delete this character or we won't open the partition properly
  1144. //
  1145. p = DupString( SystemPartitionVolumeGuid + wcslen(GLOBAL_ROOT) );
  1146. if (p) {
  1147. if (*(p+wcslen(p)-1) == L'\\') {
  1148. *(p+wcslen(p)-1) = L'\0';
  1149. }
  1150. INIT_OBJA( &ObjectAttributes, &uString, p );
  1151. Status = NtCreateFile(&hDisk,
  1152. (ACCESS_MASK)FILE_GENERIC_READ,
  1153. &ObjectAttributes,
  1154. &IoStatus,
  1155. NULL,
  1156. FILE_ATTRIBUTE_NORMAL,
  1157. FILE_SHARE_READ|FILE_SHARE_WRITE,
  1158. FILE_OPEN,
  1159. FILE_SYNCHRONOUS_IO_NONALERT,
  1160. NULL,
  1161. 0
  1162. );
  1163. if (NT_SUCCESS(Status)) {
  1164. Status = NtDeviceIoControlFile(
  1165. hDisk,
  1166. NULL,
  1167. NULL,
  1168. NULL,
  1169. &IoStatus,
  1170. IOCTL_DISK_GET_PARTITION_INFO_EX,
  1171. NULL,
  1172. 0,
  1173. &partitionEx,
  1174. sizeof(PARTITION_INFORMATION_EX) );
  1175. if (NT_SUCCESS(Status)) {
  1176. if (partitionEx.PartitionStyle == PARTITION_STYLE_GPT) {
  1177. b = TRUE;
  1178. }
  1179. } else if (Status == STATUS_INVALID_DEVICE_REQUEST) {
  1180. //
  1181. // we must be running on an older build where the IOCTL
  1182. // code is different
  1183. //
  1184. Status = NtDeviceIoControlFile(
  1185. hDisk,
  1186. NULL,
  1187. NULL,
  1188. NULL,
  1189. &IoStatus,
  1190. CTL_CODE(IOCTL_DISK_BASE, 0x0012, METHOD_BUFFERED, FILE_READ_ACCESS),
  1191. NULL,
  1192. 0,
  1193. &partitionEx,
  1194. sizeof(PARTITION_INFORMATION_EX) );
  1195. if (NT_SUCCESS(Status)) {
  1196. if (partitionEx.PartitionStyle == PARTITION_STYLE_GPT) {
  1197. b = TRUE;
  1198. }
  1199. }
  1200. }
  1201. NtClose(hDisk);
  1202. }
  1203. FREE( p );
  1204. }
  1205. if (!b) {
  1206. MessageBoxFromMessage(
  1207. Parent,
  1208. MSG_SYSTEM_PARTITIONTYPE_INVALID,
  1209. FALSE,
  1210. AppTitleStringId,
  1211. MB_OK | MB_ICONERROR | MB_TASKMODAL
  1212. );
  1213. }
  1214. }
  1215. #endif
  1216. return(b);
  1217. }
  1218. #if defined(EFI_NVRAM_ENABLED)
  1219. DWORD
  1220. LocateEfiSystemPartition(
  1221. OUT PWSTR SystemPartitionName
  1222. )
  1223. /*++
  1224. Routine Description:
  1225. Locates the EFI system partition on a GPT disk
  1226. by scanning all the available hard disks.
  1227. Arguments:
  1228. SystemPartitionName : Buffer to receive system partition
  1229. name, if one is present
  1230. Return Value:
  1231. Win32 error code indicating outcome.
  1232. --*/
  1233. {
  1234. DWORD ErrorCode = ERROR_BAD_ARGUMENTS;
  1235. if (SystemPartitionName) {
  1236. SYSTEM_DEVICE_INFORMATION SysDevInfo;
  1237. NTSTATUS Status;
  1238. *SystemPartitionName = UNICODE_NULL;
  1239. //
  1240. // Get hold of number of hard disks on the system
  1241. //
  1242. ZeroMemory(&SysDevInfo, sizeof(SYSTEM_DEVICE_INFORMATION));
  1243. Status = NtQuerySystemInformation(SystemDeviceInformation,
  1244. &SysDevInfo,
  1245. sizeof(SYSTEM_DEVICE_INFORMATION),
  1246. NULL);
  1247. if (NT_SUCCESS(Status)) {
  1248. ULONG HardDiskCount = SysDevInfo.NumberOfDisks;
  1249. ULONG CurrentDisk;
  1250. ULONG BufferSize = sizeof(DRIVE_LAYOUT_INFORMATION_EX) +
  1251. (sizeof(PARTITION_INFORMATION_EX) * 128);
  1252. PCHAR Buffer = MALLOC(BufferSize);
  1253. BOOL Found = FALSE;
  1254. if (Buffer) {
  1255. //
  1256. // Go through each disk and find out its partition
  1257. // layout
  1258. //
  1259. for (CurrentDisk = 0;
  1260. (!Found && (CurrentDisk < HardDiskCount));
  1261. CurrentDisk++) {
  1262. WCHAR DiskName[MAX_PATH];
  1263. HANDLE DiskHandle;
  1264. swprintf(DiskName,
  1265. L"\\\\.\\PHYSICALDRIVE%d",
  1266. CurrentDisk);
  1267. DiskHandle = CreateFile(DiskName,
  1268. GENERIC_READ | GENERIC_WRITE,
  1269. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1270. NULL,
  1271. OPEN_EXISTING,
  1272. FILE_ATTRIBUTE_NORMAL,
  1273. NULL);
  1274. if ((DiskHandle) &&
  1275. (DiskHandle != INVALID_HANDLE_VALUE)) {
  1276. DWORD ReturnSize = 0;
  1277. ZeroMemory(Buffer, BufferSize);
  1278. if (DeviceIoControl(DiskHandle,
  1279. IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
  1280. NULL,
  1281. 0,
  1282. Buffer,
  1283. BufferSize,
  1284. &ReturnSize,
  1285. NULL)) {
  1286. //
  1287. // Only search in GPT disks on IA64
  1288. //
  1289. PDRIVE_LAYOUT_INFORMATION_EX DriveLayout;
  1290. DriveLayout = (PDRIVE_LAYOUT_INFORMATION_EX)Buffer;
  1291. if (DriveLayout->PartitionStyle == PARTITION_STYLE_GPT) {
  1292. ULONG PartitionIndex;
  1293. for (PartitionIndex = 0;
  1294. (PartitionIndex < DriveLayout->PartitionCount);
  1295. PartitionIndex++) {
  1296. PPARTITION_INFORMATION_EX Partition;
  1297. GUID *PartitionType;
  1298. Partition = DriveLayout->PartitionEntry + PartitionIndex;
  1299. PartitionType = &(Partition->Gpt.PartitionType);
  1300. if (IsEqualGUID(PartitionType, &PARTITION_SYSTEM_GUID)) {
  1301. swprintf(SystemPartitionName,
  1302. L"\\Device\\Harddisk%d\\Partition%d",
  1303. CurrentDisk,
  1304. Partition->PartitionNumber
  1305. );
  1306. Found = TRUE;
  1307. break;
  1308. }
  1309. }
  1310. }
  1311. }
  1312. CloseHandle(DiskHandle);
  1313. }
  1314. }
  1315. FREE(Buffer);
  1316. } else {
  1317. ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
  1318. }
  1319. if (!Found) {
  1320. ErrorCode = ERROR_FILE_NOT_FOUND;
  1321. } else {
  1322. ErrorCode = ERROR_SUCCESS;
  1323. }
  1324. }
  1325. }
  1326. return ErrorCode;
  1327. }
  1328. DWORD
  1329. InitializeEfiStuff(
  1330. IN HWND Parent
  1331. )
  1332. {
  1333. DWORD ec;
  1334. NTSTATUS status;
  1335. HMODULE h;
  1336. WCHAR dllName[MAX_PATH];
  1337. ULONG length;
  1338. HKEY key;
  1339. DWORD type;
  1340. LONG i;
  1341. PMY_BOOT_ENTRY bootEntry;
  1342. PMY_BOOT_ENTRY previousBootEntry;
  1343. MYASSERT(!IsEfiChecked);
  1344. //
  1345. // IsEfi() uses IsEfiMachine to determine its return value. Assume that
  1346. // we're not on an EFI machine.
  1347. //
  1348. IsEfiChecked = TRUE;
  1349. IsEfiMachine = FALSE;
  1350. //
  1351. // Enable the privilege that is necessary to query/set NVRAM.
  1352. //
  1353. if(!EnablePrivilege(SE_SYSTEM_ENVIRONMENT_NAME,TRUE)) {
  1354. ec = GetLastError();
  1355. return ec;
  1356. }
  1357. //
  1358. // Load ntdll.dll from the system directory.
  1359. //
  1360. GetSystemDirectory(dllName, MAX_PATH);
  1361. ConcatenatePaths(dllName, TEXT("ntdll.dll"), MAX_PATH);
  1362. h = LoadLibrary(dllName);
  1363. if (h == NULL) {
  1364. ec = GetLastError();
  1365. return ec;
  1366. }
  1367. //
  1368. // Get the addresses of the NVRAM APIs that we need to use. If any of
  1369. // these APIs are not available, this must be a pre-EFI NVRAM build.
  1370. //
  1371. (FARPROC)AddBootEntry = GetProcAddress(h, "NtAddBootEntry");
  1372. (FARPROC)DeleteBootEntry = GetProcAddress(h, "NtDeleteBootEntry");
  1373. (FARPROC)EnumerateBootEntries = GetProcAddress(h, "NtEnumerateBootEntries");
  1374. (FARPROC)QueryBootEntryOrder = GetProcAddress(h, "NtQueryBootEntryOrder");
  1375. (FARPROC)SetBootEntryOrder = GetProcAddress(h, "NtSetBootEntryOrder");
  1376. (FARPROC)QueryBootOptions = GetProcAddress(h, "NtQueryBootOptions");
  1377. (FARPROC)SetBootOptions = GetProcAddress(h, "NtSetBootOptions");
  1378. if ((AddBootEntry == NULL) ||
  1379. (DeleteBootEntry == NULL) ||
  1380. (EnumerateBootEntries == NULL) ||
  1381. (QueryBootEntryOrder == NULL) ||
  1382. (SetBootEntryOrder == NULL) ||
  1383. (QueryBootOptions == NULL) ||
  1384. (SetBootOptions == NULL)) {
  1385. return ERROR_OLD_WIN_VERSION;
  1386. }
  1387. //
  1388. // Get the global system boot options. If the call fails with
  1389. // STATUS_NOT_IMPLEMENTED, this is not an EFI machine.
  1390. //
  1391. length = 0;
  1392. status = QueryBootOptions(NULL, &length);
  1393. if (status != STATUS_NOT_IMPLEMENTED) {
  1394. IsEfiMachine = TRUE;
  1395. }
  1396. if (status != STATUS_BUFFER_TOO_SMALL) {
  1397. if (status == STATUS_SUCCESS) {
  1398. status = STATUS_UNSUCCESSFUL;
  1399. }
  1400. return RtlNtStatusToDosError(status);
  1401. }
  1402. BootOptions = MALLOC(length);
  1403. OriginalBootOptions = MALLOC(length);
  1404. if ((BootOptions == NULL) || (OriginalBootOptions == NULL)) {
  1405. return RtlNtStatusToDosError(ERROR_NOT_ENOUGH_MEMORY);
  1406. }
  1407. status = QueryBootOptions(BootOptions, &length);
  1408. if (status != STATUS_SUCCESS) {
  1409. FREE(BootOptions);
  1410. FREE(OriginalBootOptions);
  1411. BootOptions = NULL;
  1412. OriginalBootOptions = NULL;
  1413. return RtlNtStatusToDosError(status);
  1414. }
  1415. memcpy(OriginalBootOptions, BootOptions, length);
  1416. //
  1417. // Get the system boot order list.
  1418. //
  1419. length = 0;
  1420. status = QueryBootEntryOrder(NULL, &length);
  1421. if (status != STATUS_BUFFER_TOO_SMALL) {
  1422. if (status == STATUS_SUCCESS) {
  1423. status = STATUS_UNSUCCESSFUL;
  1424. }
  1425. return RtlNtStatusToDosError(status);
  1426. }
  1427. OriginalBootEntryOrder = MALLOC(length * sizeof(ULONG));
  1428. if (OriginalBootEntryOrder == NULL) {
  1429. return ERROR_NOT_ENOUGH_MEMORY;
  1430. }
  1431. status = QueryBootEntryOrder(OriginalBootEntryOrder, &length);
  1432. if (status != STATUS_SUCCESS) {
  1433. FREE(OriginalBootEntryOrder);
  1434. OriginalBootEntryOrder = NULL;
  1435. return RtlNtStatusToDosError(status);
  1436. }
  1437. OriginalBootEntryOrderCount = length;
  1438. //
  1439. // Get all existing boot entries.
  1440. //
  1441. length = 0;
  1442. status = EnumerateBootEntries(NULL, &length);
  1443. if (status != STATUS_BUFFER_TOO_SMALL) {
  1444. if (status == STATUS_SUCCESS) {
  1445. status = STATUS_UNSUCCESSFUL;
  1446. }
  1447. return RtlNtStatusToDosError(status);
  1448. }
  1449. BootEntries = MALLOC(length);
  1450. if (BootEntries == NULL) {
  1451. return ERROR_NOT_ENOUGH_MEMORY;
  1452. }
  1453. status = EnumerateBootEntries(BootEntries, &length);
  1454. if (status != STATUS_SUCCESS) {
  1455. FREE(BootEntries);
  1456. BootEntries = NULL;
  1457. return RtlNtStatusToDosError(status);
  1458. }
  1459. //
  1460. // Initialize drive name translations, which are needed for converting
  1461. // the boot entries into their internal representations.
  1462. //
  1463. ec = InitDriveNameTranslations();
  1464. if(ec != NO_ERROR) {
  1465. return ec;
  1466. }
  1467. //
  1468. // Convert the boot entries into an internal representation.
  1469. //
  1470. status = ConvertBootEntries();
  1471. if (!NT_SUCCESS(status)) {
  1472. return RtlNtStatusToDosError(status);
  1473. }
  1474. //
  1475. // Free the enumeration buffer.
  1476. //
  1477. FREE(BootEntries);
  1478. BootEntries = NULL;
  1479. //
  1480. // Boot entries are returned in an unspecified order. They are currently
  1481. // in the MyBootEntries list in the order in which they were returned.
  1482. // Sort the boot entry list based on the boot order. Do this by walking
  1483. // the boot order array backwards, reinserting the entry corresponding to
  1484. // each element of the array at the head of the list.
  1485. //
  1486. for (i = (LONG)OriginalBootEntryOrderCount - 1; i >= 0; i--) {
  1487. for (previousBootEntry = NULL, bootEntry = MyBootEntries;
  1488. bootEntry != NULL;
  1489. previousBootEntry = bootEntry, bootEntry = bootEntry->Next) {
  1490. if (bootEntry->NtBootEntry.Id == OriginalBootEntryOrder[i] ) {
  1491. //
  1492. // We found the boot entry with this ID. If it's not already
  1493. // at the front of the list, move it there.
  1494. //
  1495. bootEntry->Status |= MBE_STATUS_ORDERED;
  1496. if (previousBootEntry != NULL) {
  1497. previousBootEntry->Next = bootEntry->Next;
  1498. bootEntry->Next = MyBootEntries;
  1499. MyBootEntries = bootEntry;
  1500. } else {
  1501. ASSERT(MyBootEntries == bootEntry);
  1502. }
  1503. break;
  1504. }
  1505. }
  1506. }
  1507. //
  1508. // Get the NT name of the system partition from the registry.
  1509. //
  1510. ec = RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("System\\Setup"), &key);
  1511. if (ec == ERROR_SUCCESS) {
  1512. ec = RegQueryValueEx(key, TEXT("SystemPartition"), NULL, &type, NULL, &length);
  1513. if (ec == ERROR_SUCCESS) {
  1514. if (type == REG_SZ) {
  1515. SystemPartitionNtName = MALLOC(length);
  1516. if (SystemPartitionNtName != NULL) {
  1517. ec = RegQueryValueEx(
  1518. key,
  1519. TEXT("SystemPartition"),
  1520. NULL,
  1521. &type,
  1522. (PBYTE)SystemPartitionNtName,
  1523. &length);
  1524. if (ec != ERROR_SUCCESS) {
  1525. FREE(SystemPartitionNtName);
  1526. }
  1527. } else {
  1528. return ERROR_NOT_ENOUGH_MEMORY;
  1529. }
  1530. } else {
  1531. return ERROR_INVALID_PARAMETER;
  1532. }
  1533. }
  1534. RegCloseKey (key);
  1535. }
  1536. if (ec != NO_ERROR) {
  1537. if (IsWinPEMode()) {
  1538. WCHAR OldSysPartName[MAX_PATH] = {0};
  1539. WCHAR NewSysPartName[MAX_PATH] = {0};
  1540. ec = LocateEfiSystemPartition(OldSysPartName);
  1541. if ((ec == NO_ERROR) && OldSysPartName[0]) {
  1542. NTSTATUS Status = QueryCanonicalName(OldSysPartName,
  1543. -1,
  1544. NewSysPartName,
  1545. sizeof(NewSysPartName));
  1546. if (NT_SUCCESS(Status) && NewSysPartName[0]) {
  1547. SystemPartitionNtName = DupString(NewSysPartName);
  1548. } else {
  1549. ec = ERROR_FILE_NOT_FOUND;
  1550. }
  1551. }
  1552. if ((ec == NO_ERROR) && (NewSysPartName[0] == UNICODE_NULL)) {
  1553. ec = ERROR_FILE_NOT_FOUND;
  1554. }
  1555. }
  1556. if (ec != NO_ERROR) {
  1557. return ec;
  1558. }
  1559. }
  1560. //
  1561. // Get the volume name for the NT name.
  1562. //
  1563. length = sizeof(GLOBAL_ROOT) +
  1564. lstrlen(SystemPartitionNtName)*sizeof(WCHAR) +
  1565. sizeof(WCHAR) + sizeof(WCHAR);
  1566. SystemPartitionVolumeGuid = MALLOC (length);
  1567. if(!SystemPartitionVolumeGuid) {
  1568. return ERROR_NOT_ENOUGH_MEMORY;
  1569. }
  1570. lstrcpy (SystemPartitionVolumeGuid, GLOBAL_ROOT);
  1571. lstrcat (SystemPartitionVolumeGuid, SystemPartitionNtName);
  1572. lstrcat (SystemPartitionVolumeGuid, L"\\");
  1573. lstrcpy (LocalBootDirectory, SystemPartitionVolumeGuid);
  1574. return NO_ERROR;
  1575. } // InitializeEfiStuff
  1576. #endif // defined(EFI_NVRAM_ENABLED)
  1577. /////////////////////////////////////////////////////////////////////
  1578. //
  1579. // Everything above this line is concerned with reading NV-RAM.
  1580. // Everything below this line is concerned with setting NV-RAM.
  1581. //
  1582. /////////////////////////////////////////////////////////////////////
  1583. BOOL
  1584. DoSetNvRamVar(
  1585. IN LPCWSTR VarName,
  1586. IN LPCWSTR VarValue
  1587. )
  1588. {
  1589. UNICODE_STRING U1,U2;
  1590. RtlInitUnicodeString(&U1,VarName);
  1591. RtlInitUnicodeString(&U2,VarValue);
  1592. return(NT_SUCCESS(NtSetSystemEnvironmentValue(&U1,&U2)));
  1593. }
  1594. BOOL
  1595. WriteNewBootSetVar(
  1596. IN DWORD var,
  1597. IN PTSTR NewPart
  1598. )
  1599. {
  1600. WCHAR Buffer[2048];
  1601. DWORD i;
  1602. //
  1603. // Write the new part first.
  1604. //
  1605. lstrcpy(Buffer,NewPart);
  1606. //
  1607. // Append all components that were not deleted.
  1608. //
  1609. for(i=0; i<BootVarComponentCount[var]; i++) {
  1610. if(BootVarComponents[var][i]) {
  1611. lstrcat(Buffer,L";");
  1612. lstrcat(Buffer,BootVarComponents[var][i]);
  1613. }
  1614. }
  1615. //
  1616. // Remember new value for this var.
  1617. //
  1618. if(BootVarValues[var]) {
  1619. FREE(BootVarValues[var]);
  1620. }
  1621. BootVarValues[var] = DupString(Buffer);
  1622. //
  1623. // Write the var into nvram and return.
  1624. //
  1625. return(DoSetNvRamVar(BootVarNames[var],BootVarValues[var]));
  1626. }
  1627. BOOL
  1628. WriteBootSet(
  1629. VOID
  1630. )
  1631. {
  1632. DWORD set;
  1633. DWORD var;
  1634. LPWSTR SystemPartition;
  1635. WCHAR Buffer[2048];
  1636. LPWSTR LocalSourceArc;
  1637. LPWSTR OsLoader;
  1638. WCHAR LoadId[128];
  1639. BOOL b;
  1640. CleanUpNvRam = TRUE;
  1641. //
  1642. // Find and remove any remnants of previously attempted
  1643. // winnt32 runs. Such runs are identified by 'winnt32'
  1644. // in their osloadoptions.
  1645. //
  1646. #if defined(EFI_NVRAM_ENABLED)
  1647. if (IsEfi()) {
  1648. NTSTATUS status;
  1649. PMY_BOOT_ENTRY bootEntry;
  1650. PWSTR NtPath;
  1651. //
  1652. // EFI machine. Walk the boot entry list.
  1653. //
  1654. for (bootEntry = MyBootEntries; bootEntry != NULL; bootEntry = bootEntry->Next) {
  1655. if (IS_BOOT_ENTRY_WINDOWS(bootEntry)) {
  1656. if (!lstrcmpi(bootEntry->OsLoadOptions, L"WINNT32")) {
  1657. //
  1658. // Delete this boot entry. Note that we don't update the
  1659. // boot entry order list at this point. CreateBootEntry()
  1660. // will do that.
  1661. //
  1662. status = DeleteBootEntry(bootEntry->NtBootEntry.Id);
  1663. bootEntry->Status |= MBE_STATUS_DELETED;
  1664. }
  1665. }
  1666. }
  1667. //
  1668. // Now create a new boot entry for textmode setup.
  1669. //
  1670. MYASSERT(LocalSourceDrive);
  1671. NtPath = DosDeviceTargets[(WCHAR)CharUpper((PWCHAR)LocalSourceDrive)-L'A'];
  1672. LoadString(hInst,IDS_RISCBootString,LoadId,sizeof(LoadId)/sizeof(TCHAR));
  1673. b = CreateBootEntry(
  1674. SystemPartitionNtName,
  1675. L"\\" SETUPLDR_FILENAME,
  1676. NtPath,
  1677. LocalSourceWithPlatform + 2,
  1678. L"WINNT32",
  1679. LoadId
  1680. );
  1681. if (b) {
  1682. //
  1683. // Set up for automatic startup, 10 second countdown. We don't
  1684. // care if this fails.
  1685. //
  1686. // Set the boot entry we added to be booted automatically on
  1687. // the next boot, without waiting for a timeout at the boot menu.
  1688. //
  1689. // NB: CreateBootEntry() sets BootOptions->NextBootEntryId.
  1690. //
  1691. BootOptions->Timeout = 10;
  1692. status = SetBootOptions(
  1693. BootOptions,
  1694. BOOT_OPTIONS_FIELD_TIMEOUT | BOOT_OPTIONS_FIELD_NEXT_BOOT_ENTRY_ID
  1695. );
  1696. }
  1697. return b;
  1698. }
  1699. #endif // defined(EFI_NVRAM_ENABLED)
  1700. //
  1701. // We get here if we're NOT on an EFI machine.
  1702. //
  1703. // Find and remove any remnants of previously attempted
  1704. // winnt32 runs. Such runs are identified by 'winnt32'
  1705. // in their osloadoptions.
  1706. //
  1707. for(set=0; set<min(LargestComponentCount,BootVarComponentCount[BootVarOsLoadOptions]); set++) {
  1708. //
  1709. // See if the os load options indicate that this is a winnt32 set.
  1710. //
  1711. if(!lstrcmpi(BootVarComponents[BootVarOsLoadOptions][set],L"WINNT32")) {
  1712. //
  1713. // Delete this boot set.
  1714. //
  1715. for(var=0; var<BootVarMax; var++) {
  1716. if(set < BootVarComponentCount[var]) {
  1717. FREE(BootVarComponents[var][set]);
  1718. BootVarComponents[var][set] = NULL;
  1719. }
  1720. }
  1721. }
  1722. }
  1723. //
  1724. // Now we want to write out each variable with the appropriate
  1725. // part of the new boot set added to the front.
  1726. //
  1727. if (SystemPartitionDriveLetter) {
  1728. if(DriveLetterToArcPath(SystemPartitionDriveLetter,&SystemPartition) != NO_ERROR) {
  1729. return(FALSE);
  1730. }
  1731. } else {
  1732. if(NtNameToArcPath (SystemPartitionNtName, &SystemPartition) != NO_ERROR) {
  1733. return(FALSE);
  1734. }
  1735. }
  1736. MYASSERT (LocalSourceDrive);
  1737. if(DriveLetterToArcPath(LocalSourceDrive,&LocalSourceArc) != NO_ERROR) {
  1738. FREE(SystemPartition);
  1739. return(FALSE);
  1740. }
  1741. LoadString(hInst,IDS_RISCBootString,LoadId,sizeof(LoadId)/sizeof(TCHAR));
  1742. lstrcpy(Buffer,SystemPartition);
  1743. lstrcat(Buffer,L"\\" SETUPLDR_FILENAME);
  1744. OsLoader = DupString(Buffer);
  1745. //
  1746. // System partition: use the selected system partition as the
  1747. // new system partition component.
  1748. //
  1749. if(WriteNewBootSetVar(BootVarSystemPartition,SystemPartition)
  1750. //
  1751. // Os Loader: use the system partition + setupldr as the
  1752. // new os loader component.
  1753. //
  1754. && WriteNewBootSetVar(BootVarOsLoader,OsLoader)
  1755. //
  1756. // Os Load Partition: use the local source drive as the
  1757. // new os load partition component.
  1758. //
  1759. && WriteNewBootSetVar(BootVarOsLoadPartition,LocalSourceArc)
  1760. //
  1761. // Os Load Filename: use the platform-specific local source directory
  1762. // as the new os load filename component (do not include the drive letter).
  1763. //
  1764. && WriteNewBootSetVar(BootVarOsLoadFilename,LocalSourceWithPlatform+2)
  1765. //
  1766. // Os Load Options: use WINNT32 as the new os load options component.
  1767. //
  1768. && WriteNewBootSetVar(BootVarOsLoadOptions,L"WINNT32")
  1769. //
  1770. // Load Identifier: use a string we get from the resources as the
  1771. // new load identifier component.
  1772. //
  1773. && WriteNewBootSetVar(BootVarLoadIdentifier,LoadId))
  1774. {
  1775. //
  1776. // Set up for automatic startup, 10 second countdown.
  1777. // Note the order so that if setting countdown fails we don't
  1778. // set of for autoload. Also note that we don't really care
  1779. // if this fails.
  1780. //
  1781. if(DoSetNvRamVar(szCOUNTDOWN,L"10")) {
  1782. DoSetNvRamVar(szAUTOLOAD,L"YES");
  1783. }
  1784. b = TRUE;
  1785. } else {
  1786. //
  1787. // Setting nv-ram failed. Code in cleanup.c will come along and
  1788. // restore to original state later.
  1789. //
  1790. b = FALSE;
  1791. }
  1792. FREE(SystemPartition);
  1793. FREE(LocalSourceArc);
  1794. FREE(OsLoader);
  1795. return(b);
  1796. }
  1797. BOOL
  1798. SetUpNvRam(
  1799. IN HWND ParentWindow
  1800. )
  1801. {
  1802. if(!WriteBootSet()) {
  1803. MessageBoxFromMessage(
  1804. ParentWindow,
  1805. MSG_COULDNT_WRITE_NVRAM,
  1806. FALSE,
  1807. AppTitleStringId,
  1808. MB_OK | MB_ICONERROR | MB_TASKMODAL
  1809. );
  1810. return(FALSE);
  1811. }
  1812. return(TRUE);
  1813. }
  1814. BOOL
  1815. RestoreNvRam(
  1816. VOID
  1817. )
  1818. {
  1819. UINT var;
  1820. BOOL b;
  1821. b = TRUE;
  1822. if(CleanUpNvRam) {
  1823. #if defined(EFI_NVRAM_ENABLED)
  1824. if (IsEfi()) {
  1825. NTSTATUS status;
  1826. PMY_BOOT_ENTRY bootEntry;
  1827. //
  1828. // EFI machine. Walk the boot entry list. For any boot entry that
  1829. // was added, delete it.
  1830. //
  1831. for (bootEntry = MyBootEntries; bootEntry != NULL; bootEntry = bootEntry->Next) {
  1832. if (IS_BOOT_ENTRY_COMMITTED(bootEntry)) {
  1833. MYASSERT(IS_BOOT_ENTRY_NEW(bootEntry));
  1834. status = DeleteBootEntry(bootEntry->NtBootEntry.Id);
  1835. if (!NT_SUCCESS(status)) {
  1836. b = FALSE;
  1837. }
  1838. }
  1839. }
  1840. //
  1841. // Restore the original boot order list and the original timeout.
  1842. //
  1843. status = SetBootEntryOrder(OriginalBootEntryOrder, OriginalBootEntryOrderCount);
  1844. if (!NT_SUCCESS(status)) {
  1845. b = FALSE;
  1846. }
  1847. status = SetBootOptions(OriginalBootOptions, BOOT_OPTIONS_FIELD_TIMEOUT);
  1848. if (!NT_SUCCESS(status)) {
  1849. b = FALSE;
  1850. }
  1851. }
  1852. } else {
  1853. #endif // defined(EFI_NVRAM_ENABLED)
  1854. for(var=0; var<BootVarMax; var++) {
  1855. if(!DoSetNvRamVar(BootVarNames[var],OriginalBootVarValues[var])) {
  1856. b = FALSE;
  1857. }
  1858. }
  1859. if(OriginalAutoload) {
  1860. if(!DoSetNvRamVar(szAUTOLOAD,OriginalAutoload)) {
  1861. b = FALSE;
  1862. }
  1863. }
  1864. if(OriginalCountdown) {
  1865. if(!DoSetNvRamVar(szCOUNTDOWN,OriginalCountdown)) {
  1866. b = FALSE;
  1867. }
  1868. }
  1869. }
  1870. return(b);
  1871. }
  1872. VOID
  1873. MigrateBootVarData(
  1874. VOID
  1875. )
  1876. /*++
  1877. Routine Description:
  1878. This routine retreives any boot data we want to migrate into a global
  1879. variable so that it can be written into winnt.sif.
  1880. Currently we only retreive the countdown
  1881. Arguments:
  1882. None
  1883. Return Value:
  1884. None. updates the Timeout global variable
  1885. --*/
  1886. {
  1887. UNICODE_STRING UnicodeString;
  1888. NTSTATUS Status;
  1889. WCHAR Buffer[4096];
  1890. MYASSERT(IsArc());
  1891. //
  1892. // If this is an EFI machine, use the cached BootOptions to get the timeout.
  1893. // (See IsEfi().) Otherwise, use the old version of the system service to
  1894. // query the "COUNTDOWN" variable.
  1895. //
  1896. #if defined(EFI_NVRAM_ENABLED)
  1897. if (IsEfi()) {
  1898. MYASSERT(BootOptions != NULL);
  1899. swprintf( Timeout, L"%d", BootOptions->Timeout );
  1900. } else
  1901. #endif // defined(EFI_NVRAM_ENABLED)
  1902. {
  1903. RtlInitUnicodeString(&UnicodeString,szCOUNTDOWN);
  1904. Status = NtQuerySystemEnvironmentValue(
  1905. &UnicodeString,
  1906. Buffer,
  1907. sizeof(Buffer) / sizeof(WCHAR),
  1908. NULL
  1909. );
  1910. if(NT_SUCCESS(Status)) {
  1911. lstrcpy(Timeout,Buffer);
  1912. }
  1913. }
  1914. }
  1915. #if defined(_X86_)
  1916. BOOL
  1917. IsArc(
  1918. VOID
  1919. )
  1920. /*++
  1921. Routine Description:
  1922. Run time check to determine if this is an Arc system. We attempt to read an
  1923. Arc variable using the Hal. This will fail for Bios based systems.
  1924. Arguments:
  1925. None
  1926. Return Value:
  1927. True = This is an Arc system.
  1928. --*/
  1929. {
  1930. UNICODE_STRING UnicodeString;
  1931. NTSTATUS Status;
  1932. WCHAR Buffer[4096];
  1933. //
  1934. // If we've already done the check once, don't bother doing it again.
  1935. //
  1936. if (IsArcChecked) {
  1937. return IsArcMachine;
  1938. }
  1939. IsArcChecked = TRUE;
  1940. IsArcMachine = FALSE;
  1941. if(!EnablePrivilege(SE_SYSTEM_ENVIRONMENT_NAME,TRUE)) {
  1942. return FALSE; // need better error handling?
  1943. }
  1944. //
  1945. // Get the env var into the temp buffer.
  1946. //
  1947. RtlInitUnicodeString(&UnicodeString,BootVarNames[BootVarOsLoader]);
  1948. Status = NtQuerySystemEnvironmentValue(
  1949. &UnicodeString,
  1950. Buffer,
  1951. sizeof(Buffer)/sizeof(WCHAR),
  1952. NULL
  1953. );
  1954. if (NT_SUCCESS(Status)) {
  1955. IsArcMachine = TRUE;
  1956. }
  1957. return IsArcMachine;
  1958. }
  1959. #endif // defined(_X86_)
  1960. #if defined(EFI_NVRAM_ENABLED)
  1961. BOOL
  1962. IsEfi(
  1963. VOID
  1964. )
  1965. /*++
  1966. Routine Description:
  1967. Run time check to determine if this is an EFI system.
  1968. Arguments:
  1969. None
  1970. Return Value:
  1971. True = This is an EFI system.
  1972. --*/
  1973. {
  1974. //
  1975. // InitializeEfiStuff() must be called first to do the actual check.
  1976. //
  1977. MYASSERT(IsEfiChecked);
  1978. return IsEfiMachine;
  1979. } // IsEfi
  1980. NTSTATUS
  1981. ConvertBootEntries(
  1982. VOID
  1983. )
  1984. /*++
  1985. Routine Description:
  1986. Convert boot entries read from EFI NVRAM into our internal format.
  1987. Arguments:
  1988. None.
  1989. Return Value:
  1990. NTSTATUS - Not STATUS_SUCCESS if an unexpected error occurred.
  1991. --*/
  1992. {
  1993. PBOOT_ENTRY_LIST bootEntryList;
  1994. PBOOT_ENTRY bootEntry;
  1995. PBOOT_ENTRY bootEntryCopy;
  1996. PMY_BOOT_ENTRY myBootEntry;
  1997. PMY_BOOT_ENTRY previousEntry;
  1998. PWINDOWS_OS_OPTIONS osOptions;
  1999. ULONG length;
  2000. bootEntryList = BootEntries;
  2001. previousEntry = NULL;
  2002. while (TRUE) {
  2003. bootEntry = &bootEntryList->BootEntry;
  2004. //
  2005. // Calculate the length of our internal structure. This includes
  2006. // the base part of MY_BOOT_ENTRY plus the NT BOOT_ENTRY.
  2007. //
  2008. length = FIELD_OFFSET(MY_BOOT_ENTRY, NtBootEntry) + bootEntry->Length;
  2009. myBootEntry = MALLOC(length);
  2010. if (myBootEntry == NULL) {
  2011. return STATUS_INSUFFICIENT_RESOURCES;
  2012. }
  2013. RtlZeroMemory(myBootEntry, length);
  2014. //
  2015. // Link the new entry into the list.
  2016. //
  2017. if (previousEntry != NULL) {
  2018. previousEntry->Next = myBootEntry;
  2019. } else {
  2020. MyBootEntries = myBootEntry;
  2021. }
  2022. previousEntry = myBootEntry;
  2023. //
  2024. // Copy the NT BOOT_ENTRY into the allocated buffer.
  2025. //
  2026. bootEntryCopy = &myBootEntry->NtBootEntry;
  2027. //
  2028. // work around till bootentry has the correct length specified
  2029. //
  2030. __try {
  2031. memcpy(bootEntryCopy, bootEntry, bootEntry->Length);
  2032. }
  2033. __except(EXCEPTION_EXECUTE_HANDLER) {
  2034. if (bootEntry->Length > sizeof(ULONG)) {
  2035. bootEntry->Length -= sizeof(ULONG);
  2036. memcpy(bootEntryCopy, bootEntry, bootEntry->Length);
  2037. } else {
  2038. //
  2039. // Lets atleast AV rather than having invalid
  2040. // in memory data structures
  2041. //
  2042. memcpy(bootEntryCopy, bootEntry, bootEntry->Length);
  2043. }
  2044. }
  2045. //
  2046. // Fill in the base part of the structure.
  2047. //
  2048. myBootEntry->Next = NULL;
  2049. myBootEntry->AllocationEnd = (PUCHAR)myBootEntry + length - 1;
  2050. myBootEntry->FriendlyName = ADD_OFFSET(bootEntryCopy, FriendlyNameOffset);
  2051. myBootEntry->FriendlyNameLength = (wcslen(myBootEntry->FriendlyName) + 1) * sizeof(WCHAR);
  2052. myBootEntry->BootFilePath = ADD_OFFSET(bootEntryCopy, BootFilePathOffset);
  2053. //
  2054. // If this is an NT boot entry, capture the NT-specific information in
  2055. // the OsOptions.
  2056. //
  2057. osOptions = (PWINDOWS_OS_OPTIONS)bootEntryCopy->OsOptions;
  2058. if (!IS_BOOT_ENTRY_WINDOWS(myBootEntry)) {
  2059. //
  2060. // The original implementation of NtEnumerateBootEntries() didn't
  2061. // set BOOT_ENTRY_ATTRIBUTE_WINDOWS, so we need to check for that
  2062. // here.
  2063. //
  2064. if ((bootEntryCopy->OsOptionsLength >= FIELD_OFFSET(WINDOWS_OS_OPTIONS, OsLoadOptions)) &&
  2065. (strcmp(osOptions->Signature, WINDOWS_OS_OPTIONS_SIGNATURE) == 0)) {
  2066. myBootEntry->NtBootEntry.Attributes |= BOOT_ENTRY_ATTRIBUTE_WINDOWS;
  2067. }
  2068. }
  2069. if (IS_BOOT_ENTRY_WINDOWS(myBootEntry)) {
  2070. myBootEntry->OsLoadOptions = osOptions->OsLoadOptions;
  2071. myBootEntry->OsLoadOptionsLength = (wcslen(myBootEntry->OsLoadOptions) + 1) * sizeof(WCHAR);
  2072. myBootEntry->OsFilePath = ADD_OFFSET(osOptions, OsLoadPathOffset);
  2073. } else {
  2074. //
  2075. // It's not an NT entry. Check to see if it represents a removable
  2076. // media device. We want to know this so that we don't put our
  2077. // boot entry ahead of the floppy or the CD, if they're already
  2078. // at the front of the list. A boot entry represents a
  2079. }
  2080. //
  2081. // Move to the next entry in the enumeration list, if any.
  2082. //
  2083. if (bootEntryList->NextEntryOffset == 0) {
  2084. break;
  2085. }
  2086. bootEntryList = ADD_OFFSET(bootEntryList, NextEntryOffset);
  2087. }
  2088. return STATUS_SUCCESS;
  2089. } // ConvertBootEntries
  2090. BOOL
  2091. CreateBootEntry(
  2092. PWSTR BootFileDevice,
  2093. PWSTR BootFilePath,
  2094. PWSTR OsLoadDevice,
  2095. PWSTR OsLoadPath,
  2096. PWSTR OsLoadOptions,
  2097. PWSTR FriendlyName
  2098. )
  2099. /*++
  2100. Routine Description:
  2101. Create an internal-format boot entry.
  2102. Arguments:
  2103. BootFileDevice - The NT name of the device on which the OS loader resides.
  2104. BootFilePath - The volume-relative path to the OS loader. Must start with
  2105. a backslash.
  2106. OsLoadDevice - The NT name ofthe device on which the OS resides.
  2107. OsLoadPath - The volume-relative path to the OS root directory (\WINDOWS).
  2108. Must start with a backslash.
  2109. OsLoadOptions - Boot options for the OS. Can be an empty string.
  2110. FriendlyName - The user-visible name for the boot entry. (This is ARC's
  2111. LOADIDENTIFIER.)
  2112. Return Value:
  2113. BOOLEAN - FALSE if an unexpected error occurred.
  2114. --*/
  2115. {
  2116. NTSTATUS status;
  2117. ULONG requiredLength;
  2118. ULONG osOptionsOffset;
  2119. ULONG osLoadOptionsLength;
  2120. ULONG osLoadPathOffset;
  2121. ULONG osLoadPathLength;
  2122. ULONG osOptionsLength;
  2123. ULONG friendlyNameOffset;
  2124. ULONG friendlyNameLength;
  2125. ULONG bootPathOffset;
  2126. ULONG bootPathLength;
  2127. PMY_BOOT_ENTRY myBootEntry;
  2128. PMY_BOOT_ENTRY previousBootEntry;
  2129. PMY_BOOT_ENTRY nextBootEntry;
  2130. PBOOT_ENTRY ntBootEntry;
  2131. PWINDOWS_OS_OPTIONS osOptions;
  2132. PFILE_PATH osLoadPath;
  2133. PWSTR friendlyName;
  2134. PFILE_PATH bootPath;
  2135. PWSTR p;
  2136. PULONG order;
  2137. ULONG count;
  2138. ULONG savedAttributes;
  2139. //
  2140. // Calculate how long the internal boot entry needs to be. This includes
  2141. // our internal structure, plus the BOOT_ENTRY structure that the NT APIs
  2142. // use.
  2143. //
  2144. // Our structure:
  2145. //
  2146. requiredLength = FIELD_OFFSET(MY_BOOT_ENTRY, NtBootEntry);
  2147. //
  2148. // Base part of NT structure:
  2149. //
  2150. requiredLength += FIELD_OFFSET(BOOT_ENTRY, OsOptions);
  2151. //
  2152. // Save offset to BOOT_ENTRY.OsOptions. Add in base part of
  2153. // WINDOWS_OS_OPTIONS. Calculate length in bytes of OsLoadOptions
  2154. // and add that in.
  2155. //
  2156. osOptionsOffset = requiredLength;
  2157. requiredLength += FIELD_OFFSET(WINDOWS_OS_OPTIONS, OsLoadOptions);
  2158. osLoadOptionsLength = (wcslen(OsLoadOptions) + 1) * sizeof(WCHAR);
  2159. requiredLength += osLoadOptionsLength;
  2160. //
  2161. // Round up to a ULONG boundary for the OS FILE_PATH in the
  2162. // WINDOWS_OS_OPTIONS. Save offset to OS FILE_PATH. Add in base part
  2163. // of FILE_PATH. Add in length in bytes of OS device NT name and OS
  2164. // directory. Calculate total length of OS FILE_PATH and of
  2165. // WINDOWS_OS_OPTIONS.
  2166. //
  2167. requiredLength = ALIGN_UP(requiredLength, ULONG);
  2168. osLoadPathOffset = requiredLength;
  2169. requiredLength += FIELD_OFFSET(FILE_PATH, FilePath);
  2170. requiredLength += (wcslen(OsLoadDevice) + 1 + wcslen(OsLoadPath) + 1) * sizeof(WCHAR);
  2171. osLoadPathLength = requiredLength - osLoadPathOffset;
  2172. osOptionsLength = requiredLength - osOptionsOffset;
  2173. //
  2174. // Round up to a ULONG boundary for the friendly name in the BOOT_ENTRY.
  2175. // Save offset to friendly name. Calculate length in bytes of friendly name
  2176. // and add that in.
  2177. //
  2178. requiredLength = ALIGN_UP(requiredLength, ULONG);
  2179. friendlyNameOffset = requiredLength;
  2180. friendlyNameLength = (wcslen(FriendlyName) + 1) * sizeof(WCHAR);
  2181. requiredLength += friendlyNameLength;
  2182. //
  2183. // Round up to a ULONG boundary for the boot FILE_PATH in the BOOT_ENTRY.
  2184. // Save offset to boot FILE_PATH. Add in base part of FILE_PATH. Add in
  2185. // length in bytes of boot device NT name and boot file. Calculate total
  2186. // length of boot FILE_PATH.
  2187. //
  2188. requiredLength = ALIGN_UP(requiredLength, ULONG);
  2189. bootPathOffset = requiredLength;
  2190. requiredLength += FIELD_OFFSET(FILE_PATH, FilePath);
  2191. requiredLength += (wcslen(BootFileDevice) + 1 + wcslen(BootFilePath) + 1) * sizeof(WCHAR);
  2192. bootPathLength = requiredLength - bootPathOffset;
  2193. //
  2194. // Allocate memory for the boot entry.
  2195. //
  2196. myBootEntry = MALLOC(requiredLength);
  2197. if (myBootEntry == NULL) {
  2198. return FALSE;
  2199. }
  2200. RtlZeroMemory(myBootEntry, requiredLength);
  2201. //
  2202. // Calculate addresses of various substructures using the saved offsets.
  2203. //
  2204. ntBootEntry = &myBootEntry->NtBootEntry;
  2205. osOptions = (PWINDOWS_OS_OPTIONS)ntBootEntry->OsOptions;
  2206. osLoadPath = (PFILE_PATH)((PUCHAR)myBootEntry + osLoadPathOffset);
  2207. friendlyName = (PWSTR)((PUCHAR)myBootEntry + friendlyNameOffset);
  2208. bootPath = (PFILE_PATH)((PUCHAR)myBootEntry + bootPathOffset);
  2209. //
  2210. // Fill in the internal-format structure.
  2211. //
  2212. myBootEntry->AllocationEnd = (PUCHAR)myBootEntry + requiredLength;
  2213. myBootEntry->Status = MBE_STATUS_NEW | MBE_STATUS_ORDERED;
  2214. myBootEntry->FriendlyName = friendlyName;
  2215. myBootEntry->FriendlyNameLength = friendlyNameLength;
  2216. myBootEntry->OsLoadOptions = osOptions->OsLoadOptions;
  2217. myBootEntry->OsLoadOptionsLength = osLoadOptionsLength;
  2218. myBootEntry->BootFilePath = bootPath;
  2219. myBootEntry->OsFilePath = osLoadPath;
  2220. //
  2221. // Fill in the base part of the NT boot entry.
  2222. //
  2223. ntBootEntry->Version = BOOT_ENTRY_VERSION;
  2224. ntBootEntry->Length = requiredLength - FIELD_OFFSET(MY_BOOT_ENTRY, NtBootEntry);
  2225. ntBootEntry->Attributes = BOOT_ENTRY_ATTRIBUTE_ACTIVE | BOOT_ENTRY_ATTRIBUTE_WINDOWS;
  2226. ntBootEntry->FriendlyNameOffset = (ULONG)((PUCHAR)friendlyName - (PUCHAR)ntBootEntry);
  2227. ntBootEntry->BootFilePathOffset = (ULONG)((PUCHAR)bootPath - (PUCHAR)ntBootEntry);
  2228. ntBootEntry->OsOptionsLength = osOptionsLength;
  2229. //
  2230. // Fill in the base part of the WINDOWS_OS_OPTIONS, including the
  2231. // OsLoadOptions.
  2232. //
  2233. strcpy(osOptions->Signature, WINDOWS_OS_OPTIONS_SIGNATURE);
  2234. osOptions->Version = WINDOWS_OS_OPTIONS_VERSION;
  2235. osOptions->Length = osOptionsLength;
  2236. osOptions->OsLoadPathOffset = (ULONG)((PUCHAR)osLoadPath - (PUCHAR)osOptions);
  2237. wcscpy(osOptions->OsLoadOptions, OsLoadOptions);
  2238. //
  2239. // Fill in the OS FILE_PATH.
  2240. //
  2241. osLoadPath->Version = FILE_PATH_VERSION;
  2242. osLoadPath->Length = osLoadPathLength;
  2243. osLoadPath->Type = FILE_PATH_TYPE_NT;
  2244. p = (PWSTR)osLoadPath->FilePath;
  2245. wcscpy(p, OsLoadDevice);
  2246. p += wcslen(p) + 1;
  2247. wcscpy(p, OsLoadPath);
  2248. //
  2249. // Copy the friendly name.
  2250. //
  2251. wcscpy(friendlyName, FriendlyName);
  2252. //
  2253. // Fill in the boot FILE_PATH.
  2254. //
  2255. bootPath->Version = FILE_PATH_VERSION;
  2256. bootPath->Length = bootPathLength;
  2257. bootPath->Type = FILE_PATH_TYPE_NT;
  2258. p = (PWSTR)bootPath->FilePath;
  2259. wcscpy(p, BootFileDevice);
  2260. p += wcslen(p) + 1;
  2261. wcscpy(p, BootFilePath);
  2262. //
  2263. // Add the new boot entry.
  2264. //
  2265. // NB: The original implementation of NtAddBootEntry didn't like it
  2266. // when attribute bits other than _ACTIVE and _DEFAULT were set, so
  2267. // we need to mask the other bits off here.
  2268. //
  2269. savedAttributes = ntBootEntry->Attributes;
  2270. ntBootEntry->Attributes &= (BOOT_ENTRY_ATTRIBUTE_DEFAULT | BOOT_ENTRY_ATTRIBUTE_ACTIVE);
  2271. status = AddBootEntry(ntBootEntry, &ntBootEntry->Id);
  2272. ntBootEntry->Attributes = savedAttributes;
  2273. if (!NT_SUCCESS(status)) {
  2274. FREE(myBootEntry);
  2275. return FALSE;
  2276. }
  2277. myBootEntry->Status |= MBE_STATUS_COMMITTED;
  2278. //
  2279. // Remember the ID of the new boot entry as the entry to be booted
  2280. // immediately on the next boot.
  2281. //
  2282. BootOptions->NextBootEntryId = ntBootEntry->Id;
  2283. //
  2284. // Link the new boot entry into the list, after any removable media
  2285. // entries that are at the front of the list.
  2286. //
  2287. previousBootEntry = NULL;
  2288. nextBootEntry = MyBootEntries;
  2289. while ((nextBootEntry != NULL) &&
  2290. IS_BOOT_ENTRY_REMOVABLE_MEDIA(nextBootEntry)) {
  2291. previousBootEntry = nextBootEntry;
  2292. nextBootEntry = nextBootEntry->Next;
  2293. }
  2294. myBootEntry->Next = nextBootEntry;
  2295. if (previousBootEntry == NULL) {
  2296. MyBootEntries = myBootEntry;
  2297. } else {
  2298. previousBootEntry->Next = myBootEntry;
  2299. }
  2300. //
  2301. // Build the new boot order list. Insert all boot entries with
  2302. // MBE_STATUS_ORDERED into the list. (Don't insert deleted entries.)
  2303. //
  2304. count = 0;
  2305. nextBootEntry = MyBootEntries;
  2306. while (nextBootEntry != NULL) {
  2307. if (IS_BOOT_ENTRY_ORDERED(nextBootEntry) && !IS_BOOT_ENTRY_DELETED(nextBootEntry)) {
  2308. count++;
  2309. }
  2310. nextBootEntry = nextBootEntry->Next;
  2311. }
  2312. order = MALLOC(count * sizeof(ULONG));
  2313. if (order == NULL) {
  2314. return FALSE;
  2315. }
  2316. count = 0;
  2317. nextBootEntry = MyBootEntries;
  2318. while (nextBootEntry != NULL) {
  2319. if (IS_BOOT_ENTRY_ORDERED(nextBootEntry) && !IS_BOOT_ENTRY_DELETED(nextBootEntry)) {
  2320. order[count++] = nextBootEntry->NtBootEntry.Id;
  2321. }
  2322. nextBootEntry = nextBootEntry->Next;
  2323. }
  2324. //
  2325. // Write the new boot entry order list.
  2326. //
  2327. status = SetBootEntryOrder(order, count);
  2328. FREE(order);
  2329. if (!NT_SUCCESS(status)) {
  2330. return FALSE;
  2331. }
  2332. return TRUE;
  2333. } // CreateBootEntry
  2334. #endif // defined(EFI_NVRAM_ENABLED)
  2335. #endif // UNICODE