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

604 lines
16 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. envvar.c
  5. Abstract:
  6. Provides routines to access EFI environment variables.
  7. Author:
  8. Chuck Lenzmeier (chuckl) 10-Dec-2000
  9. Revision History:
  10. --*/
  11. #include "arccodes.h"
  12. #include "stdlib.h"
  13. #include "stdio.h"
  14. #include "string.h"
  15. #if defined(_IA64_)
  16. #include "bootia64.h"
  17. #endif
  18. #include "efi.h"
  19. #include "efip.h"
  20. #define ADD_OFFSET(_p,_o) (PVOID)((PUCHAR)(_p) + (_p)->_o)
  21. GUID RamdiskVendorGuid = {0};
  22. #include <efiboot.h>
  23. ARC_STATUS
  24. BlpGetPartitionFromDevicePath (
  25. IN EFI_DEVICE_PATH UNALIGNED *DevicePath,
  26. IN PUCHAR MaximumValidAddress,
  27. OUT PULONG DiskNumber,
  28. OUT PULONG PartitionNumber,
  29. OUT HARDDRIVE_DEVICE_PATH UNALIGNED **HarddriveDevicePath,
  30. OUT FILEPATH_DEVICE_PATH UNALIGNED **FilepathDevicePath
  31. );
  32. //
  33. // Externals
  34. //
  35. extern VOID FlipToVirtual();
  36. extern VOID FlipToPhysical();
  37. extern ULONGLONG CompareGuid();
  38. extern BOOT_CONTEXT BootContext;
  39. extern EFI_HANDLE EfiImageHandle;
  40. extern EFI_SYSTEM_TABLE *EfiST;
  41. extern EFI_BOOT_SERVICES *EfiBS;
  42. extern EFI_RUNTIME_SERVICES *EfiRS;
  43. extern EFI_GUID EfiDevicePathProtocol;
  44. extern EFI_GUID EfiBlockIoProtocol;
  45. EFI_STATUS
  46. EfiGetVariable (
  47. IN CHAR16 *VariableName,
  48. IN EFI_GUID *VendorGuid,
  49. OUT UINT32 *Attributes OPTIONAL,
  50. IN OUT UINTN *DataSize,
  51. OUT VOID *Data
  52. )
  53. {
  54. EFI_STATUS status;
  55. FlipToPhysical();
  56. status = EfiST->RuntimeServices->GetVariable(
  57. VariableName,
  58. VendorGuid,
  59. Attributes,
  60. DataSize,
  61. Data
  62. );
  63. FlipToVirtual();
  64. return status;
  65. } // EfiGetVariable
  66. EFI_STATUS
  67. EfiSetVariable (
  68. IN CHAR16 *VariableName,
  69. IN EFI_GUID *VendorGuid,
  70. IN UINT32 Attributes,
  71. IN UINTN DataSize,
  72. IN VOID *Data
  73. )
  74. {
  75. EFI_STATUS status;
  76. FlipToPhysical();
  77. status = EfiST->RuntimeServices->SetVariable(
  78. VariableName,
  79. VendorGuid,
  80. Attributes,
  81. DataSize,
  82. Data
  83. );
  84. FlipToVirtual();
  85. return status;
  86. } // EfiSetVariable
  87. EFI_STATUS
  88. EfiGetNextVariableName (
  89. IN OUT UINTN *VariableNameSize,
  90. IN OUT CHAR16 *VariableName,
  91. IN OUT EFI_GUID *VendorGuid
  92. )
  93. {
  94. EFI_STATUS status;
  95. FlipToPhysical();
  96. status = EfiST->RuntimeServices->GetNextVariableName(
  97. VariableNameSize,
  98. VariableName,
  99. VendorGuid
  100. );
  101. FlipToVirtual();
  102. return status;
  103. } // EfiGetNextVariableName
  104. LONG
  105. SafeStrlen (
  106. PUCHAR String,
  107. PUCHAR Max
  108. )
  109. {
  110. PUCHAR p = String;
  111. while ( (p < Max) && (*p != 0) ) {
  112. p++;
  113. }
  114. if ( p < Max ) {
  115. return (LONG)(p - String);
  116. }
  117. return -1;
  118. } // SafeStrlen
  119. LONG
  120. SafeWcslen (
  121. PWCHAR String,
  122. PWCHAR Max
  123. )
  124. {
  125. PWCHAR p = String;
  126. while ( (p < Max) && (*p != 0) ) {
  127. p++;
  128. }
  129. if ( p < Max ) {
  130. return (LONG)(p - String);
  131. }
  132. return -1;
  133. } // SafeWclen
  134. ARC_STATUS
  135. BlGetEfiBootOptions (
  136. OUT PUCHAR Argv0String OPTIONAL,
  137. OUT PUCHAR SystemPartition OPTIONAL,
  138. OUT PUCHAR OsLoaderFilename OPTIONAL,
  139. OUT PUCHAR OsLoadPartition OPTIONAL,
  140. OUT PUCHAR OsLoadFilename OPTIONAL,
  141. OUT PUCHAR FullKernelPath OPTIONAL,
  142. OUT PUCHAR OsLoadOptions OPTIONAL
  143. )
  144. {
  145. EFI_STATUS status;
  146. ARC_STATUS arcStatus;
  147. EFI_GUID EfiGlobalVariable = EFI_GLOBAL_VARIABLE;
  148. UCHAR variable[512];
  149. CHAR syspart[100];
  150. UCHAR loader[100];
  151. CHAR loadpart[100];
  152. UCHAR loadname[100];
  153. PEFI_LOAD_OPTION efiLoadOption;
  154. EFI_DEVICE_PATH UNALIGNED *devicePath;
  155. HARDDRIVE_DEVICE_PATH UNALIGNED *harddriveDp;
  156. FILEPATH_DEVICE_PATH UNALIGNED *filepathDp;
  157. WINDOWS_OS_OPTIONS UNALIGNED *osOptions;
  158. UINT16 bootCurrent;
  159. UINTN length;
  160. PUCHAR max;
  161. PUCHAR osloadoptions;
  162. LONG l;
  163. WCHAR UNALIGNED *fp;
  164. ULONG bootDisk;
  165. ULONG bootPartition;
  166. ULONG loadDisk;
  167. ULONG loadPartition;
  168. LONG i;
  169. FILE_PATH UNALIGNED *loadFilePath;
  170. PWCHAR wideosloadoptions;
  171. WCHAR currentBootEntryName[9];
  172. //
  173. // Get the ordinal of the entry that was used to boot the system.
  174. //
  175. length = sizeof(bootCurrent);
  176. status = EfiGetVariable( L"BootCurrent", &EfiGlobalVariable, NULL, &length, &bootCurrent );
  177. if ( status != EFI_SUCCESS ) {
  178. return ENOENT;
  179. }
  180. //
  181. // Read the boot entry.
  182. //
  183. swprintf( currentBootEntryName, L"Boot%04x", bootCurrent );
  184. length = 512;
  185. status = EfiGetVariable( currentBootEntryName, &EfiGlobalVariable, NULL, &length, variable );
  186. if ( status != EFI_SUCCESS ) {
  187. return ENOENT;
  188. }
  189. //
  190. // Verify the boot entry.
  191. //
  192. max = variable + length;
  193. //
  194. // Is it long enough even to contain the base part of the EFI load option?
  195. //
  196. if ( length < sizeof(EFI_LOAD_OPTION) ) {
  197. return ENOENT;
  198. }
  199. //
  200. // Is the description properly terminated?
  201. //
  202. efiLoadOption = (PEFI_LOAD_OPTION)variable;
  203. l = SafeWcslen( efiLoadOption->Description, (PWCHAR)max );
  204. if ( l < 0 ) {
  205. return ENOENT;
  206. }
  207. devicePath = (EFI_DEVICE_PATH *)((PUCHAR)efiLoadOption +
  208. FIELD_OFFSET(EFI_LOAD_OPTION,Description) +
  209. ((l + 1) * sizeof(CHAR16)));
  210. osOptions = (WINDOWS_OS_OPTIONS UNALIGNED *)((PUCHAR)devicePath + efiLoadOption->FilePathLength);
  211. length -= (UINTN)((PUCHAR)osOptions - variable);
  212. //
  213. // Does the OsOptions structure look like a WINDOWS_OS_OPTIONS structure?
  214. //
  215. if ( (length < FIELD_OFFSET(WINDOWS_OS_OPTIONS, OsLoadOptions)) ||
  216. (length != osOptions->Length) ||
  217. (WINDOWS_OS_OPTIONS_VERSION != osOptions->Version) ||
  218. (strcmp((PCHAR)osOptions->Signature, WINDOWS_OS_OPTIONS_SIGNATURE) != 0) ) {
  219. return ENOENT;
  220. }
  221. //
  222. // Is the OsLoadOptions string properly terminated?
  223. //
  224. wideosloadoptions = (PWCHAR)osOptions->OsLoadOptions;
  225. l = SafeWcslen( wideosloadoptions, (PWCHAR)max );
  226. if ( l < 0 ) {
  227. return ENOENT;
  228. }
  229. //
  230. // Convert the OsLoadOptions string to ANSI.
  231. //
  232. osloadoptions = (PUCHAR)wideosloadoptions;
  233. for ( i = 1; i <= l; i++ ) {
  234. osloadoptions[i] = (UCHAR)wideosloadoptions[i];
  235. }
  236. //
  237. // Parse the device path to determine the OS load partition and directory.
  238. // Convert the directory name to ANSI.
  239. //
  240. loadFilePath = ADD_OFFSET( osOptions, OsLoadPathOffset );
  241. if ( loadFilePath->Type == FILE_PATH_TYPE_EFI ) {
  242. EFI_DEVICE_PATH UNALIGNED *loadDp = (EFI_DEVICE_PATH UNALIGNED *)loadFilePath->FilePath;
  243. VENDOR_DEVICE_PATH UNALIGNED *vendorDp = (VENDOR_DEVICE_PATH UNALIGNED *)loadDp;
  244. PCHAR ramdiskArcPath = (PCHAR)(vendorDp + 1);
  245. #if 0
  246. //
  247. // turn this on to see the device path to the loader executable and device
  248. // path to the operating system
  249. //
  250. BlPrint(TEXT("Device Path = %s\r\n"), DevicePathToStr( devicePath ));
  251. BlPrint(TEXT("Embedded Device Path to OS = %s\r\n"), DevicePathToStr( loadDp ));
  252. DBG_EFI_PAUSE();
  253. #endif
  254. if ( (DevicePathType(loadDp) != HARDWARE_DEVICE_PATH) ||
  255. (DevicePathSubType(loadDp) != HW_VENDOR_DP) ||
  256. (DevicePathNodeLength(loadDp) < sizeof(VENDOR_DEVICE_PATH)) ||
  257. (memcmp(&vendorDp->Guid, &RamdiskVendorGuid, 16) != 0) ) {
  258. arcStatus = BlpGetPartitionFromDevicePath(
  259. loadDp,
  260. max,
  261. &loadDisk,
  262. &loadPartition,
  263. &harddriveDp,
  264. &filepathDp
  265. );
  266. if (arcStatus != ESUCCESS) {
  267. return arcStatus;
  268. }
  269. sprintf( loadpart,
  270. "multi(0)disk(0)rdisk(%d)partition(%d)",
  271. loadDisk,
  272. loadPartition );
  273. fp = filepathDp->PathName;
  274. l = 0;
  275. while ( (l < (99 - 9 - strlen(loadpart))) &&
  276. ((PUCHAR)fp < max) &&
  277. (*fp != 0) ) {
  278. loadname[l++] = (UCHAR)*fp++;
  279. }
  280. loadname[l] = 0;
  281. } else {
  282. //
  283. // Looks like a RAM disk path. Verify.
  284. //
  285. if ( DevicePathNodeLength(loadDp) < (sizeof(VENDOR_DEVICE_PATH) + sizeof("ramdisk(0)\\x")) ) {
  286. return ENOENT;
  287. }
  288. if ( _strnicmp(ramdiskArcPath, "ramdisk(", 8) != 0 ) {
  289. return ENOENT;
  290. }
  291. l = 0;
  292. while ( (l <= 99) && (*ramdiskArcPath != 0) && (*ramdiskArcPath != '\\') ) {
  293. loadpart[l++] = *ramdiskArcPath++;
  294. }
  295. if ( (l == 100) || (*ramdiskArcPath == 0) ) {
  296. return ENOENT;
  297. }
  298. loadpart[l] = 0;
  299. l = 0;
  300. while ( (l <= 99) && (*ramdiskArcPath != 0) ) {
  301. loadname[l++] = *ramdiskArcPath++;
  302. }
  303. if ( (l == 100) || (l < 2) ) {
  304. return ENOENT;
  305. }
  306. loadname[l] = 0;
  307. }
  308. } else {
  309. return ENOENT;
  310. }
  311. //
  312. // Translate loader device path to partition/path.
  313. //
  314. arcStatus = BlpGetPartitionFromDevicePath(
  315. devicePath,
  316. max,
  317. &bootDisk,
  318. &bootPartition,
  319. &harddriveDp,
  320. &filepathDp
  321. );
  322. if (arcStatus != ESUCCESS) {
  323. return arcStatus;
  324. }
  325. //
  326. // Form the ARC name for the partition.
  327. //
  328. sprintf( syspart,
  329. "multi(0)disk(0)rdisk(%d)partition(%d)",
  330. bootDisk,
  331. bootPartition );
  332. //
  333. // Extract the path to the loader.
  334. //
  335. fp = filepathDp->PathName;
  336. l = 0;
  337. while ( (l < (99 - 9 - strlen(syspart))) &&
  338. ((PUCHAR)fp < max) &&
  339. (*fp != 0) ) {
  340. loader[l++] = (UCHAR)*fp++;
  341. }
  342. loader[l] = 0;
  343. //
  344. // Create the strings that the loader needs.
  345. //
  346. if ( Argv0String != NULL ) {
  347. sprintf( (PCHAR)Argv0String, "%s%s", syspart, loader );
  348. }
  349. if ( OsLoaderFilename != NULL ) {
  350. sprintf( (PCHAR)OsLoaderFilename, "OSLOADER=%s%s", syspart, loader );
  351. }
  352. if ( SystemPartition != NULL ) {
  353. sprintf( (PCHAR)SystemPartition, "SYSTEMPARTITION=%s", syspart );
  354. }
  355. if ( OsLoadOptions != NULL ) {
  356. sprintf( (PCHAR)OsLoadOptions, "OSLOADOPTIONS=%s", osloadoptions );
  357. }
  358. if ( OsLoadFilename != NULL ) {
  359. sprintf( (PCHAR)OsLoadFilename, "OSLOADFILENAME=%s", loadname );
  360. }
  361. if ( FullKernelPath != NULL ) {
  362. sprintf( (PCHAR)FullKernelPath, "%s%s", loadpart, loadname );
  363. }
  364. if ( OsLoadPartition != NULL ) {
  365. sprintf( (PCHAR)OsLoadPartition, "OSLOADPARTITION=%s", loadpart );
  366. }
  367. return ESUCCESS;
  368. } // BlGetEfiBootOptions
  369. ARC_STATUS
  370. BlpGetPartitionFromDevicePath (
  371. IN EFI_DEVICE_PATH UNALIGNED *DevicePath,
  372. IN PUCHAR MaximumValidAddress,
  373. OUT PULONG DiskNumber,
  374. OUT PULONG PartitionNumber,
  375. OUT HARDDRIVE_DEVICE_PATH UNALIGNED **HarddriveDevicePath,
  376. OUT FILEPATH_DEVICE_PATH UNALIGNED **FilepathDevicePath
  377. )
  378. {
  379. ARC_STATUS status = ESUCCESS;
  380. EFI_DEVICE_PATH UNALIGNED *devicePath;
  381. HARDDRIVE_DEVICE_PATH UNALIGNED *harddriveDp;
  382. FILEPATH_DEVICE_PATH UNALIGNED *filepathDp;
  383. LOGICAL end;
  384. ULONG disk;
  385. ULONG partition;
  386. BOOLEAN DiskFound;
  387. //
  388. // Find the MEDIA/HARDDRIVE and MEDIA/FILEPATH elements in the device path.
  389. //
  390. devicePath = DevicePath;
  391. harddriveDp = NULL;
  392. filepathDp = NULL;
  393. end = FALSE;
  394. while ( ((PUCHAR)devicePath < MaximumValidAddress) &&
  395. !end &&
  396. ((harddriveDp == NULL) || (filepathDp == NULL)) ) {
  397. switch( devicePath->Type ) {
  398. case END_DEVICE_PATH_TYPE:
  399. end = TRUE;
  400. break;
  401. case MEDIA_DEVICE_PATH:
  402. switch ( devicePath->SubType ) {
  403. case MEDIA_HARDDRIVE_DP:
  404. harddriveDp = (HARDDRIVE_DEVICE_PATH UNALIGNED *)devicePath;
  405. break;
  406. case MEDIA_FILEPATH_DP:
  407. filepathDp = (FILEPATH_DEVICE_PATH UNALIGNED *)devicePath;
  408. break;
  409. default:
  410. break;
  411. }
  412. default:
  413. break;
  414. }
  415. devicePath = (EFI_DEVICE_PATH UNALIGNED *)NextDevicePathNode( devicePath );
  416. }
  417. //
  418. // If the two necessary elements weren't found, we can't continue.
  419. //
  420. if ( (harddriveDp == NULL) || (filepathDp == NULL) ) {
  421. return ENOENT;
  422. }
  423. //
  424. // Determine the disk number of the disk by opening the given partition
  425. // number on each disk and checking the partition signature.
  426. //
  427. partition = harddriveDp->PartitionNumber;
  428. //
  429. // find the disk this devicepath refers to
  430. //
  431. disk = 0;
  432. DiskFound = FALSE;
  433. while ( !DiskFound ) {
  434. switch (harddriveDp->SignatureType) {
  435. case SIGNATURE_TYPE_GUID: {
  436. EFI_PARTITION_ENTRY UNALIGNED *partEntry;
  437. status = BlGetGPTDiskPartitionEntry( disk, (UCHAR)partition, &partEntry );
  438. if ( status == ESUCCESS ) {
  439. //
  440. // we successfully got a GPT partition entry.
  441. // check to see if the partitions signature matches
  442. // the device path signature
  443. //
  444. if ( memcmp(partEntry->Id, harddriveDp->Signature, 16) == 0 ) {
  445. DiskFound = TRUE;
  446. }
  447. }
  448. break;
  449. }
  450. case SIGNATURE_TYPE_MBR: {
  451. ULONG MbrSignature;
  452. status = BlGetMbrDiskSignature(disk, &MbrSignature);
  453. if (status == ESUCCESS) {
  454. //
  455. // check to see if the MBR disk signature is
  456. // the signature we are looking for.
  457. //
  458. if ( MbrSignature == *(ULONG UNALIGNED *)&harddriveDp->Signature ) {
  459. DiskFound = TRUE;
  460. }
  461. }
  462. break;
  463. }
  464. default:
  465. //
  466. // invalid type, just continue
  467. //
  468. break;
  469. }
  470. if ( status == EINVAL ) {
  471. //
  472. // we will receive EINVAL when there
  473. // are no more disks to cycle through.
  474. // if we get this before we have found
  475. // our disk, we have a problem. return
  476. // the error.
  477. //
  478. return ENOENT;
  479. }
  480. disk++;
  481. }
  482. //
  483. // Return information about this disk, and about the device path.
  484. //
  485. *DiskNumber = disk - 1;
  486. *PartitionNumber = partition;
  487. *HarddriveDevicePath = harddriveDp;
  488. *FilepathDevicePath = filepathDp;
  489. return ESUCCESS;
  490. } // BlpGetPartitionFromDevicePath