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.

508 lines
12 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. #include <efiboot.h>
  22. ARC_STATUS
  23. BlpGetPartitionFromDevicePath (
  24. IN EFI_DEVICE_PATH UNALIGNED *DevicePath,
  25. IN PUCHAR MaximumValidAddress,
  26. OUT PULONG DiskNumber,
  27. OUT PULONG PartitionNumber,
  28. OUT HARDDRIVE_DEVICE_PATH UNALIGNED **HarddriveDevicePath,
  29. OUT FILEPATH_DEVICE_PATH UNALIGNED **FilepathDevicePath
  30. );
  31. //
  32. // Externals
  33. //
  34. extern VOID FlipToVirtual();
  35. extern VOID FlipToPhysical();
  36. extern ULONGLONG CompareGuid();
  37. extern BOOT_CONTEXT BootContext;
  38. extern EFI_HANDLE EfiImageHandle;
  39. extern EFI_SYSTEM_TABLE *EfiST;
  40. extern EFI_BOOT_SERVICES *EfiBS;
  41. extern EFI_RUNTIME_SERVICES *EfiRS;
  42. extern EFI_GUID EfiDevicePathProtocol;
  43. extern EFI_GUID EfiBlockIoProtocol;
  44. EFI_STATUS
  45. EfiGetVariable (
  46. IN CHAR16 *VariableName,
  47. IN EFI_GUID *VendorGuid,
  48. OUT UINT32 *Attributes OPTIONAL,
  49. IN OUT UINTN *DataSize,
  50. OUT VOID *Data
  51. )
  52. {
  53. EFI_STATUS status;
  54. FlipToPhysical();
  55. status = EfiST->RuntimeServices->GetVariable(
  56. VariableName,
  57. VendorGuid,
  58. Attributes,
  59. DataSize,
  60. Data
  61. );
  62. FlipToVirtual();
  63. return status;
  64. } // EfiGetVariable
  65. EFI_STATUS
  66. EfiSetVariable (
  67. IN CHAR16 *VariableName,
  68. IN EFI_GUID *VendorGuid,
  69. IN UINT32 Attributes,
  70. IN UINTN DataSize,
  71. IN VOID *Data
  72. )
  73. {
  74. EFI_STATUS status;
  75. FlipToPhysical();
  76. status = EfiST->RuntimeServices->SetVariable(
  77. VariableName,
  78. VendorGuid,
  79. Attributes,
  80. DataSize,
  81. Data
  82. );
  83. FlipToVirtual();
  84. return status;
  85. } // EfiSetVariable
  86. EFI_STATUS
  87. EfiGetNextVariableName (
  88. IN OUT UINTN *VariableNameSize,
  89. IN OUT CHAR16 *VariableName,
  90. IN OUT EFI_GUID *VendorGuid
  91. )
  92. {
  93. EFI_STATUS status;
  94. FlipToPhysical();
  95. status = EfiST->RuntimeServices->GetNextVariableName(
  96. VariableNameSize,
  97. VariableName,
  98. VendorGuid
  99. );
  100. FlipToVirtual();
  101. return status;
  102. } // EfiGetNextVariableName
  103. LONG
  104. SafeStrlen (
  105. PUCHAR String,
  106. PUCHAR Max
  107. )
  108. {
  109. PUCHAR p = String;
  110. while ( (p < Max) && (*p != 0) ) {
  111. p++;
  112. }
  113. if ( p < Max ) {
  114. return (LONG)(p - String);
  115. }
  116. return -1;
  117. } // SafeStrlen
  118. LONG
  119. SafeWcslen (
  120. PWCHAR String,
  121. PWCHAR Max
  122. )
  123. {
  124. PWCHAR p = String;
  125. while ( (p < Max) && (*p != 0) ) {
  126. p++;
  127. }
  128. if ( p < Max ) {
  129. return (LONG)(p - String);
  130. }
  131. return -1;
  132. } // SafeWclen
  133. ARC_STATUS
  134. BlGetEfiBootOptions (
  135. OUT PUCHAR Argv0String OPTIONAL,
  136. OUT PUCHAR SystemPartition OPTIONAL,
  137. OUT PUCHAR OsLoaderFilename OPTIONAL,
  138. OUT PUCHAR OsLoadPartition OPTIONAL,
  139. OUT PUCHAR OsLoadFilename OPTIONAL,
  140. OUT PUCHAR FullKernelPath OPTIONAL,
  141. OUT PUCHAR OsLoadOptions OPTIONAL
  142. )
  143. {
  144. EFI_STATUS status;
  145. ARC_STATUS arcStatus;
  146. EFI_GUID EfiGlobalVariable = EFI_GLOBAL_VARIABLE;
  147. UCHAR variable[512];
  148. UCHAR syspart[100];
  149. UCHAR loader[100];
  150. UCHAR loadpart[100];
  151. UCHAR loadname[100];
  152. PEFI_LOAD_OPTION efiLoadOption;
  153. EFI_DEVICE_PATH UNALIGNED *devicePath;
  154. HARDDRIVE_DEVICE_PATH UNALIGNED *harddriveDp;
  155. FILEPATH_DEVICE_PATH UNALIGNED *filepathDp;
  156. WINDOWS_OS_OPTIONS UNALIGNED *osOptions;
  157. UINT16 bootCurrent;
  158. UINTN length;
  159. PUCHAR max;
  160. PUCHAR osloadpart;
  161. PUCHAR osloadname;
  162. PUCHAR osloadoptions;
  163. LONG l;
  164. BOOLEAN end;
  165. WCHAR UNALIGNED *fp;
  166. ULONG bootDisk;
  167. ULONG bootPartition;
  168. ULONG loadDisk;
  169. ULONG loadPartition;
  170. LONG i;
  171. PFILE_PATH loadFilePath;
  172. PWCHAR wideosloadoptions;
  173. WCHAR currentBootEntryName[9];
  174. //
  175. // Get the ordinal of the entry that was used to boot the system.
  176. //
  177. length = sizeof(bootCurrent);
  178. status = EfiGetVariable( L"BootCurrent", &EfiGlobalVariable, NULL, &length, &bootCurrent );
  179. if ( status != EFI_SUCCESS ) {
  180. return ENOENT;
  181. }
  182. //
  183. // Read the boot entry.
  184. //
  185. swprintf( currentBootEntryName, L"Boot%04x", bootCurrent );
  186. length = 512;
  187. status = EfiGetVariable( currentBootEntryName, &EfiGlobalVariable, NULL, &length, variable );
  188. if ( status != EFI_SUCCESS ) {
  189. return ENOENT;
  190. }
  191. //
  192. // Verify the boot entry.
  193. //
  194. max = variable + length;
  195. //
  196. // Is it long enough even to contain the base part of the EFI load option?
  197. //
  198. if ( length < sizeof(EFI_LOAD_OPTION) ) {
  199. return ENOENT;
  200. }
  201. //
  202. // Is the description properly terminated?
  203. //
  204. efiLoadOption = (PEFI_LOAD_OPTION)variable;
  205. l = SafeWcslen( efiLoadOption->Description, (PWCHAR)max );
  206. if ( l < 0 ) {
  207. return ENOENT;
  208. }
  209. devicePath = (EFI_DEVICE_PATH *)((PUCHAR)efiLoadOption +
  210. FIELD_OFFSET(EFI_LOAD_OPTION,Description) +
  211. ((l + 1) * sizeof(CHAR16)));
  212. osOptions = (WINDOWS_OS_OPTIONS UNALIGNED *)((PUCHAR)devicePath + efiLoadOption->FilePathLength);
  213. length -= (UINTN)((PUCHAR)osOptions - variable);
  214. //
  215. // Does the OsOptions structure look like a WINDOWS_OS_OPTIONS structure?
  216. //
  217. if ( (length < FIELD_OFFSET(WINDOWS_OS_OPTIONS, OsLoadOptions)) ||
  218. (length != osOptions->Length) ||
  219. (WINDOWS_OS_OPTIONS_VERSION != osOptions->Version) ||
  220. (strcmp(osOptions->Signature, WINDOWS_OS_OPTIONS_SIGNATURE) != 0) ) {
  221. return ENOENT;
  222. }
  223. //
  224. // Is the OsLoadOptions string properly terminated?
  225. //
  226. wideosloadoptions = (PWCHAR)osOptions->OsLoadOptions;
  227. l = SafeWcslen( wideosloadoptions, (PWCHAR)max );
  228. if ( l < 0 ) {
  229. return ENOENT;
  230. }
  231. //
  232. // Convert the OsLoadOptions string to ANSI.
  233. //
  234. osloadoptions = (PUCHAR)wideosloadoptions;
  235. for ( i = 1; i <= l; i++ ) {
  236. osloadoptions[i] = (UCHAR)wideosloadoptions[i];
  237. }
  238. //
  239. // Parse the device path to determine the OS load partition and directory.
  240. // Convert the directory name to ANSI.
  241. //
  242. loadFilePath = ADD_OFFSET( osOptions, OsLoadPathOffset );
  243. #if 0
  244. //
  245. // turn this on to see the device path to the loader executable and device
  246. // path to the operating system
  247. //
  248. BlPrint(TEXT("Device Path = %s\r\n"), DevicePathToStr( devicePath ));
  249. BlPrint(TEXT("Embedded Device Path to OS = %s\r\n"), DevicePathToStr( (EFI_DEVICE_PATH UNALIGNED *)loadFilePath->FilePath ));
  250. DBG_EFI_PAUSE();
  251. #endif
  252. arcStatus = BlpGetPartitionFromDevicePath(
  253. (EFI_DEVICE_PATH UNALIGNED *)loadFilePath->FilePath,
  254. max,
  255. &loadDisk,
  256. &loadPartition,
  257. &harddriveDp,
  258. &filepathDp
  259. );
  260. if (arcStatus != ESUCCESS) {
  261. return arcStatus;
  262. }
  263. sprintf( loadpart,
  264. "multi(0)disk(0)rdisk(%d)partition(%d)",
  265. loadDisk,
  266. loadPartition );
  267. fp = filepathDp->PathName;
  268. l = 0;
  269. while ( (l < (99 - 9 - strlen(loadpart))) &&
  270. ((PUCHAR)fp < max) &&
  271. (*fp != 0) ) {
  272. loadname[l++] = (UCHAR)*fp++;
  273. }
  274. loadname[l] = 0;
  275. //
  276. // Translate loader device path to partition/path.
  277. //
  278. arcStatus = BlpGetPartitionFromDevicePath(
  279. devicePath,
  280. max,
  281. &bootDisk,
  282. &bootPartition,
  283. &harddriveDp,
  284. &filepathDp
  285. );
  286. if (arcStatus != ESUCCESS) {
  287. return arcStatus;
  288. }
  289. //
  290. // Form the ARC name for the partition.
  291. //
  292. sprintf( syspart,
  293. "multi(0)disk(0)rdisk(%d)partition(%d)",
  294. bootDisk,
  295. bootPartition );
  296. //
  297. // Extract the path to the loader.
  298. //
  299. fp = filepathDp->PathName;
  300. l = 0;
  301. while ( (l < (99 - 9 - strlen(syspart))) &&
  302. ((PUCHAR)fp < max) &&
  303. (*fp != 0) ) {
  304. loader[l++] = (UCHAR)*fp++;
  305. }
  306. loader[l] = 0;
  307. //
  308. // Create the strings that the loader needs.
  309. //
  310. if ( Argv0String != NULL ) {
  311. sprintf( Argv0String, "%s%s", syspart, loader );
  312. }
  313. if ( OsLoaderFilename != NULL ) {
  314. sprintf( OsLoaderFilename, "OSLOADER=%s%s", syspart, loader );
  315. }
  316. if ( SystemPartition != NULL ) {
  317. sprintf( SystemPartition, "SYSTEMPARTITION=%s", syspart );
  318. }
  319. if ( OsLoadOptions != NULL ) {
  320. sprintf( OsLoadOptions, "OSLOADOPTIONS=%s", osloadoptions );
  321. }
  322. if ( OsLoadFilename != NULL ) {
  323. sprintf( OsLoadFilename, "OSLOADFILENAME=%s", loadname );
  324. }
  325. if ( FullKernelPath != NULL ) {
  326. sprintf( FullKernelPath, "%s%s", loadpart, loadname );
  327. }
  328. if ( OsLoadPartition != NULL ) {
  329. sprintf( OsLoadPartition, "OSLOADPARTITION=%s", loadpart );
  330. }
  331. return ESUCCESS;
  332. } // BlGetEfiBootOptions
  333. ARC_STATUS
  334. BlpGetPartitionFromDevicePath (
  335. IN EFI_DEVICE_PATH UNALIGNED *DevicePath,
  336. IN PUCHAR MaximumValidAddress,
  337. OUT PULONG DiskNumber,
  338. OUT PULONG PartitionNumber,
  339. OUT HARDDRIVE_DEVICE_PATH UNALIGNED **HarddriveDevicePath,
  340. OUT FILEPATH_DEVICE_PATH UNALIGNED **FilepathDevicePath
  341. )
  342. {
  343. ARC_STATUS status;
  344. EFI_DEVICE_PATH UNALIGNED *devicePath;
  345. HARDDRIVE_DEVICE_PATH UNALIGNED *harddriveDp;
  346. FILEPATH_DEVICE_PATH UNALIGNED *filepathDp;
  347. LOGICAL end;
  348. ULONG disk;
  349. ULONG partition;
  350. //
  351. // Find the MEDIA/HARDDRIVE and MEDIA/FILEPATH elements in the device path.
  352. //
  353. devicePath = DevicePath;
  354. harddriveDp = NULL;
  355. filepathDp = NULL;
  356. end = FALSE;
  357. while ( ((PUCHAR)devicePath < MaximumValidAddress) &&
  358. !end &&
  359. ((harddriveDp == NULL) || (filepathDp == NULL)) ) {
  360. switch( devicePath->Type ) {
  361. case END_DEVICE_PATH_TYPE:
  362. end = TRUE;
  363. break;
  364. case MEDIA_DEVICE_PATH:
  365. switch ( devicePath->SubType ) {
  366. case MEDIA_HARDDRIVE_DP:
  367. harddriveDp = (HARDDRIVE_DEVICE_PATH UNALIGNED *)devicePath;
  368. break;
  369. case MEDIA_FILEPATH_DP:
  370. filepathDp = (FILEPATH_DEVICE_PATH UNALIGNED *)devicePath;
  371. break;
  372. default:
  373. break;
  374. }
  375. default:
  376. break;
  377. }
  378. devicePath = (EFI_DEVICE_PATH UNALIGNED *)NextDevicePathNode( devicePath );
  379. }
  380. //
  381. // If the two necessary elements weren't found, we can't continue.
  382. //
  383. if ( (harddriveDp == NULL) || (filepathDp == NULL) ) {
  384. return ENOENT;
  385. }
  386. //
  387. // Determine the disk number of the disk by opening the given partition
  388. // number on each disk and checking the partition signature.
  389. //
  390. partition = harddriveDp->PartitionNumber;
  391. disk = 0;
  392. while ( TRUE ) {
  393. EFI_PARTITION_ENTRY UNALIGNED *partEntry;
  394. status = BlGetGPTDiskPartitionEntry( disk, (UCHAR)partition, &partEntry );
  395. if ( status == EINVAL ) {
  396. return ENOENT;
  397. }
  398. if ( status == ESUCCESS ) {
  399. if ( memcmp(partEntry->Id, harddriveDp->Signature, 16) == 0 ) {
  400. break;
  401. }
  402. }
  403. disk++;
  404. }
  405. //
  406. // Return information about this disk, and about the device path.
  407. //
  408. *DiskNumber = disk;
  409. *PartitionNumber = partition;
  410. *HarddriveDevicePath = harddriveDp;
  411. *FilepathDevicePath = filepathDp;
  412. return ESUCCESS;
  413. } // BlpGetPartitionFromDevicePath