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.

430 lines
12 KiB

  1. /*++
  2. Copyright (c) 2000 Intel Corporation
  3. Module Name:
  4. guidgen.c
  5. Abstract:
  6. Add the GUID generator logic for the EFI 1.0 Disk Utilities.
  7. Revision History
  8. ** Intel 2000 Update for EFI 1.0
  9. ** Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
  10. ** Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. &
  11. ** Digital Equipment Corporation, Maynard, Mass.
  12. ** To anyone who acknowledges that this file is provided AS IS
  13. ** without any express or implied warranty: permission to use, copy,
  14. ** modify, and distribute this file for any purpose is hereby
  15. ** granted without fee, provided that the above copyright notices and
  16. ** this notice appears in all source code copies, and that none of
  17. ** the names of Open Software Foundation, Inc., Hewlett-Packard
  18. ** Company, or Digital Equipment Corporation be used in advertising
  19. ** or publicity pertaining to distribution of the software without
  20. ** specific, written prior permission. Neither Open Software
  21. ** Foundation, Inc., Hewlett-Packard Company, nor Digital Equipment
  22. ** Corporation makes any representations about the suitability of
  23. ** this software for any purpose.
  24. */
  25. #include "efi.h"
  26. #include "efilib.h"
  27. #include "md5.h"
  28. //#define NONVOLATILE_CLOCK
  29. extern EFI_HANDLE SavedImageHandle;
  30. extern EFI_HANDLE *DiskHandleList;
  31. extern INTN DiskHandleCount;
  32. #define CLOCK_SEQ_LAST 0x3FFF
  33. #define RAND_MASK CLOCK_SEQ_LAST
  34. typedef struct _uuid_t {
  35. UINT32 time_low;
  36. UINT16 time_mid;
  37. UINT16 time_hi_and_version;
  38. UINT8 clock_seq_hi_and_reserved;
  39. UINT8 clock_seq_low;
  40. UINT8 node[6];
  41. } uuid_t;
  42. typedef struct {
  43. UINT32 lo;
  44. UINT32 hi;
  45. } unsigned64_t;
  46. /*
  47. ** Add two unsigned 64-bit long integers.
  48. */
  49. #define ADD_64b_2_64b(A, B, sum) \
  50. { \
  51. if (!(((A)->lo & 0x80000000UL) ^ ((B)->lo & 0x80000000UL))) { \
  52. if (((A)->lo&0x80000000UL)) { \
  53. (sum)->lo = (A)->lo + (B)->lo; \
  54. (sum)->hi = (A)->hi + (B)->hi + 1; \
  55. } \
  56. else { \
  57. (sum)->lo = (A)->lo + (B)->lo; \
  58. (sum)->hi = (A)->hi + (B)->hi; \
  59. } \
  60. } \
  61. else { \
  62. (sum)->lo = (A)->lo + (B)->lo; \
  63. (sum)->hi = (A)->hi + (B)->hi; \
  64. if (!((sum)->lo&0x80000000UL)) (sum)->hi++; \
  65. } \
  66. }
  67. /*
  68. ** Add a 16-bit unsigned integer to a 64-bit unsigned integer.
  69. */
  70. #define ADD_16b_2_64b(A, B, sum) \
  71. { \
  72. (sum)->hi = (B)->hi; \
  73. if ((B)->lo & 0x80000000UL) { \
  74. (sum)->lo = (*A) + (B)->lo; \
  75. if (!((sum)->lo & 0x80000000UL)) (sum)->hi++; \
  76. } \
  77. else \
  78. (sum)->lo = (*A) + (B)->lo; \
  79. }
  80. /*
  81. ** Global variables.
  82. */
  83. static unsigned64_t time_last;
  84. static UINT16 clock_seq;
  85. VOID
  86. GetIeeeNodeIdentifier(
  87. UINT8 MacAddress[]
  88. )
  89. // Use the Device Path for the NIC to provide a MAC address
  90. {
  91. UINTN NoHandles, Index;
  92. EFI_HANDLE *Handles;
  93. EFI_HANDLE Handle;
  94. EFI_DEVICE_PATH *DevPathNode, *DevicePath;
  95. MAC_ADDR_DEVICE_PATH *SourceMacAddress;
  96. UINT8 *Anchor;
  97. EFI_MEMORY_DESCRIPTOR *Desc, *MemMap;
  98. UINTN DescriptorSize;
  99. UINT32 DescriptorVersion;
  100. UINTN NoDesc, MapKey;
  101. UINT8 *pDataBuf;
  102. UINT32 cData;
  103. EFI_TIME Time;
  104. EFI_STATUS Status;
  105. Status = EFI_SUCCESS;
  106. //
  107. // Find all Device Paths
  108. //
  109. LibLocateHandle (ByProtocol, &DevicePathProtocol, NULL, &NoHandles, &Handles);
  110. for (Index=0; Index < NoHandles; Index++) {
  111. Handle = Handles[Index];
  112. DevicePath = DevicePathFromHandle (Handle);
  113. //
  114. // Process each device path node
  115. //
  116. DevPathNode = DevicePath;
  117. while (!IsDevicePathEnd(DevPathNode)) {
  118. //
  119. // Find the handler to dump this device path node
  120. //
  121. if (DevicePathType(DevPathNode) == MESSAGING_DEVICE_PATH &&
  122. DevicePathSubType(DevPathNode) == MSG_MAC_ADDR_DP) {
  123. SourceMacAddress = (MAC_ADDR_DEVICE_PATH *) DevPathNode;
  124. if (SourceMacAddress->IfType == 0x01 || SourceMacAddress->IfType == 0x00) {
  125. CopyMem(&MacAddress[0], &SourceMacAddress->MacAddress, sizeof(UINT8) * 6);
  126. return;
  127. }
  128. }
  129. DevPathNode = NextDevicePathNode(DevPathNode);
  130. }
  131. }
  132. //
  133. // Arriving here means that there is not an SNP-compliant
  134. // device in the system. Use the MD5 1-way hash function to
  135. // generate the node address
  136. //
  137. MemMap = LibMemoryMap (&NoDesc, &MapKey, &DescriptorSize, &DescriptorVersion);
  138. if (!MemMap) {
  139. Print (L"Memory map was not returned\n");
  140. } else {
  141. pDataBuf = AllocatePool (NoDesc * DescriptorSize +
  142. DiskHandleCount * sizeof(EFI_HANDLE) + sizeof(EFI_TIME));
  143. ASSERT (pDataBuf != NULL);
  144. Anchor = pDataBuf;
  145. Desc = MemMap;
  146. cData = 0;
  147. if (NoDesc != 0) {
  148. while (NoDesc --) {
  149. CopyMem(pDataBuf, Desc, DescriptorSize);
  150. Desc ++;
  151. pDataBuf += DescriptorSize;
  152. cData += (UINT32)DescriptorSize;
  153. }
  154. }
  155. //
  156. // Also copy in the handles of the Disks
  157. //
  158. if (DiskHandleCount != 0) {
  159. Index = DiskHandleCount;
  160. while (Index --) {
  161. CopyMem(pDataBuf, &DiskHandleList [Index], sizeof (EFI_HANDLE));
  162. pDataBuf += sizeof(EFI_HANDLE);
  163. cData += sizeof(EFI_HANDLE);
  164. }
  165. }
  166. Status = RT->GetTime(&Time,NULL);
  167. if (!EFI_ERROR(Status)) {
  168. CopyMem(pDataBuf, &Time, sizeof(EFI_TIME));
  169. pDataBuf += sizeof(EFI_TIME);
  170. cData += sizeof (EFI_TIME);
  171. }
  172. GenNodeID(Anchor, cData, &MacAddress[0]);
  173. FreePool(Anchor);
  174. FreePool(MemMap);
  175. return;
  176. }
  177. // Just case fall through
  178. ZeroMem(MacAddress, 6 * sizeof (UINT8));
  179. return;
  180. }
  181. static VOID
  182. mult32(UINT32 u, UINT32 v, unsigned64_t *result)
  183. {
  184. /* Following the notation in Knuth, Vol. 2. */
  185. UINT32 uuid1, uuid2, v1, v2, temp;
  186. uuid1 = u >> 16;
  187. uuid2 = u & 0xFFFF;
  188. v1 = v >> 16;
  189. v2 = v & 0xFFFF;
  190. temp = uuid2 * v2;
  191. result->lo = temp & 0xFFFF;
  192. temp = uuid1 * v2 + (temp >> 16);
  193. result->hi = temp >> 16;
  194. temp = uuid2 * v1 + (temp & 0xFFFF);
  195. result->lo += (temp & 0xFFFF) << 16;
  196. result->hi += uuid1 * v1 + (temp >> 16);
  197. }
  198. static VOID
  199. GetSystemTime(unsigned64_t *uuid_time)
  200. {
  201. // struct timeval tp;
  202. EFI_TIME Time;
  203. EFI_STATUS Status;
  204. unsigned64_t utc, usecs, os_basetime_diff;
  205. EFI_TIME_CAPABILITIES TimeCapabilities;
  206. UINTN DeadCount;
  207. UINT8 Second;
  208. DeadCount = 0;
  209. // gettimeofday(&tp, (struct timezone *)0);
  210. Status = RT->GetTime(&Time,&TimeCapabilities);
  211. Second = Time.Second;
  212. //
  213. // If the time resolution is 1Hz, then spin until a
  214. // second transition. This will at least make the
  215. // "0 nanoseconds" value appear correct inasmuch as
  216. // multiple reads within 1 second are prohibited and
  217. // the exit on roll-over really implies that the
  218. // nanoseconds field "would have" rolled to zero in
  219. // a more robust time keeper.
  220. //
  221. //
  222. if (TimeCapabilities.Resolution == 1) {
  223. while (Time.Second == Second) {
  224. Second = Time.Second;
  225. Status = RT->GetTime(&Time, NULL);
  226. if (DeadCount++ == 0x1000000) {
  227. break;
  228. }
  229. }
  230. }
  231. mult32(Time.Second, 10000000, &utc);
  232. mult32(Time.Nanosecond, 10, &usecs);
  233. ADD_64b_2_64b(&usecs, &utc, &utc);
  234. /* Offset between UUID formatted times and Unix formatted times.
  235. * UUID UTC base time is October 15, 1582.
  236. * Unix base time is January 1, 1970. */
  237. os_basetime_diff.lo = 0x13814000;
  238. os_basetime_diff.hi = 0x01B21DD2;
  239. ADD_64b_2_64b(&utc, &os_basetime_diff, uuid_time);
  240. }
  241. UINT32
  242. getpid() {
  243. UINT64 FakePidValue;
  244. BS->GetNextMonotonicCount(&FakePidValue);
  245. //FakePidValue = 0; //(UINT32) ((UINT32)FakePidValue + (UINT32) SavedImageHandle);
  246. FakePidValue = (UINT32) ((UINT32)FakePidValue + (UINT32) (UINT64) SavedImageHandle);
  247. return ((UINT32)FakePidValue);
  248. }
  249. /*
  250. ** See The Multiple Prime Random Number Generator by Alexander
  251. ** Hass pp. 368-381, ACM Transactions on Mathematical Software,
  252. ** 12/87.
  253. */
  254. static UINT32 rand_m;
  255. static UINT32 rand_ia;
  256. static UINT32 rand_ib;
  257. static UINT32 rand_irand;
  258. static VOID
  259. TrueRandomInit(VOID)
  260. {
  261. unsigned64_t t;
  262. EFI_TIME Time;
  263. EFI_STATUS Status;
  264. UINT16 seed;
  265. /* Generating our 'seed' value Start with the current time, but,
  266. * since the resolution of clocks is system hardware dependent
  267. and
  268. * most likely coarser than our resolution (10 usec) we 'mixup'
  269. the
  270. * bits by xor'ing all the bits together. This will have the
  271. effect
  272. * of involving all of the bits in the determination of the seed
  273. * value while remaining system independent. Then for good
  274. measure
  275. * to ensure a unique seed when there are multiple processes
  276. * creating UUIDs on a system, we add in the PID.
  277. */
  278. rand_m = 971;
  279. rand_ia = 11113;
  280. rand_ib = 104322;
  281. rand_irand = 4181;
  282. // GetSystemTime(&t);
  283. Status = RT->GetTime(&Time,NULL);
  284. t.lo = Time.Nanosecond;
  285. t.hi = (Time.Hour << 16) | Time.Second;
  286. seed = (UINT16) (t.lo & 0xFFFF);
  287. seed ^= (t.lo >> 16) & 0xFFFF;
  288. seed ^= t.hi & 0xFFFF;
  289. seed ^= (t.hi >> 16) & 0xFFFF;
  290. rand_irand += seed + getpid();
  291. }
  292. static UINT16
  293. true_random(VOID)
  294. {
  295. if ((rand_m += 7) >= 9973)
  296. rand_m -= 9871;
  297. if ((rand_ia += 1907) >= 99991)
  298. rand_ia -= 89989;
  299. if ((rand_ib += 73939) >= 224729)
  300. rand_ib -= 96233;
  301. rand_irand = (rand_irand * rand_m) + rand_ia + rand_ib;
  302. return (UINT16) ((rand_irand >> 16) ^ (rand_irand & RAND_MASK));
  303. }
  304. /*
  305. ** Startup initialization routine for the UUID module.
  306. */
  307. VOID
  308. InitGuid(VOID)
  309. {
  310. TrueRandomInit();
  311. GetSystemTime(&time_last);
  312. #ifdef NONVOLATILE_CLOCK
  313. clock_seq = read_clock();
  314. #else
  315. clock_seq = true_random();
  316. #endif
  317. }
  318. static INTN
  319. time_cmp(unsigned64_t *time1, unsigned64_t *time2)
  320. {
  321. if (time1->hi < time2->hi) return -1;
  322. if (time1->hi > time2->hi) return 1;
  323. if (time1->lo < time2->lo) return -1;
  324. if (time1->lo > time2->lo) return 1;
  325. return 0;
  326. }
  327. static VOID new_clock_seq(VOID)
  328. {
  329. clock_seq = (clock_seq + 1) % (CLOCK_SEQ_LAST + 1);
  330. if (clock_seq == 0) clock_seq = 1;
  331. #ifdef NONVOLATILE_CLOCK
  332. write_clock(clock_seq);
  333. #endif
  334. }
  335. VOID CreateGuid(uuid_t *guid)
  336. {
  337. static unsigned64_t time_now;
  338. static UINT16 time_adjust;
  339. UINT8 eaddr[6];
  340. INTN got_no_time = 0;
  341. GetIeeeNodeIdentifier(&eaddr[0]); /* TO BE PROVIDED by EFI device path */
  342. do {
  343. GetSystemTime(&time_now);
  344. switch (time_cmp(&time_now, &time_last)) {
  345. case -1:
  346. /* Time went backwards. */
  347. new_clock_seq();
  348. time_adjust = 0;
  349. break;
  350. case 1:
  351. time_adjust = 0;
  352. break;
  353. default:
  354. if (time_adjust == 0x7FFF)
  355. /* We're going too fast for our clock; spin. */
  356. got_no_time = 1;
  357. else
  358. time_adjust++;
  359. break;
  360. }
  361. } while (got_no_time);
  362. time_last.lo = time_now.lo;
  363. time_last.hi = time_now.hi;
  364. if (time_adjust != 0) {
  365. ADD_16b_2_64b(&time_adjust, &time_now, &time_now);
  366. }
  367. /* Construct a guid with the information we've gathered
  368. * plus a few constants. */
  369. guid->time_low = time_now.lo;
  370. guid->time_mid = (UINT16) (time_now.hi & 0x0000FFFF);
  371. guid->time_hi_and_version = (UINT16) (time_now.hi & 0x0FFF0000) >> 16;
  372. guid->time_hi_and_version |= (1 << 12);
  373. guid->clock_seq_low = clock_seq & 0xFF;
  374. guid->clock_seq_hi_and_reserved = (clock_seq & 0x3F00) >> 8;
  375. guid->clock_seq_hi_and_reserved |= 0x80;
  376. CopyMem (guid->node, &eaddr, sizeof guid->node);
  377. }