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
13 KiB
430 lines
13 KiB
/*++
|
|
|
|
Copyright (c) 2000 Intel Corporation
|
|
|
|
Module Name:
|
|
|
|
guidgen.c
|
|
|
|
Abstract:
|
|
|
|
Add the GUID generator logic for the EFI 1.0 Disk Utilities.
|
|
|
|
Revision History
|
|
|
|
** Intel 2000 Update for EFI 1.0
|
|
** Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
|
|
** Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. &
|
|
** Digital Equipment Corporation, Maynard, Mass.
|
|
** To anyone who acknowledges that this file is provided “AS IS”
|
|
** without any express or implied warranty: permission to use, copy,
|
|
** modify, and distribute this file for any purpose is hereby
|
|
** granted without fee, provided that the above copyright notices and
|
|
** this notice appears in all source code copies, and that none of
|
|
** the names of Open Software Foundation, Inc., Hewlett-Packard
|
|
** Company, or Digital Equipment Corporation be used in advertising
|
|
** or publicity pertaining to distribution of the software without
|
|
** specific, written prior permission. Neither Open Software
|
|
** Foundation, Inc., Hewlett-Packard Company, nor Digital Equipment
|
|
** Corporation makes any representations about the suitability of
|
|
** this software for any purpose.
|
|
*/
|
|
|
|
#include "efi.h"
|
|
#include "efilib.h"
|
|
#include "md5.h"
|
|
|
|
//#define NONVOLATILE_CLOCK
|
|
|
|
extern EFI_HANDLE SavedImageHandle;
|
|
extern EFI_HANDLE *DiskHandleList;
|
|
extern INTN DiskHandleCount;
|
|
|
|
#define CLOCK_SEQ_LAST 0x3FFF
|
|
#define RAND_MASK CLOCK_SEQ_LAST
|
|
|
|
typedef struct _uuid_t {
|
|
UINT32 time_low;
|
|
UINT16 time_mid;
|
|
UINT16 time_hi_and_version;
|
|
UINT8 clock_seq_hi_and_reserved;
|
|
UINT8 clock_seq_low;
|
|
UINT8 node[6];
|
|
} uuid_t;
|
|
|
|
typedef struct {
|
|
UINT32 lo;
|
|
UINT32 hi;
|
|
} unsigned64_t;
|
|
|
|
|
|
/*
|
|
** Add two unsigned 64-bit long integers.
|
|
*/
|
|
#define ADD_64b_2_64b(A, B, sum) \
|
|
{ \
|
|
if (!(((A)->lo & 0x80000000UL) ^ ((B)->lo & 0x80000000UL))) { \
|
|
if (((A)->lo&0x80000000UL)) { \
|
|
(sum)->lo = (A)->lo + (B)->lo; \
|
|
(sum)->hi = (A)->hi + (B)->hi + 1; \
|
|
} \
|
|
else { \
|
|
(sum)->lo = (A)->lo + (B)->lo; \
|
|
(sum)->hi = (A)->hi + (B)->hi; \
|
|
} \
|
|
} \
|
|
else { \
|
|
(sum)->lo = (A)->lo + (B)->lo; \
|
|
(sum)->hi = (A)->hi + (B)->hi; \
|
|
if (!((sum)->lo&0x80000000UL)) (sum)->hi++; \
|
|
} \
|
|
}
|
|
|
|
/*
|
|
** Add a 16-bit unsigned integer to a 64-bit unsigned integer.
|
|
*/
|
|
#define ADD_16b_2_64b(A, B, sum) \
|
|
{ \
|
|
(sum)->hi = (B)->hi; \
|
|
if ((B)->lo & 0x80000000UL) { \
|
|
(sum)->lo = (*A) + (B)->lo; \
|
|
if (!((sum)->lo & 0x80000000UL)) (sum)->hi++; \
|
|
} \
|
|
else \
|
|
(sum)->lo = (*A) + (B)->lo; \
|
|
}
|
|
|
|
/*
|
|
** Global variables.
|
|
*/
|
|
static unsigned64_t time_last;
|
|
static UINT16 clock_seq;
|
|
|
|
VOID
|
|
GetIeeeNodeIdentifier(
|
|
UINT8 MacAddress[]
|
|
)
|
|
// Use the Device Path for the NIC to provide a MAC address
|
|
{
|
|
UINTN NoHandles, Index;
|
|
EFI_HANDLE *Handles;
|
|
EFI_HANDLE Handle;
|
|
EFI_DEVICE_PATH *DevPathNode, *DevicePath;
|
|
MAC_ADDR_DEVICE_PATH *SourceMacAddress;
|
|
UINT8 *Anchor;
|
|
EFI_MEMORY_DESCRIPTOR *Desc, *MemMap;
|
|
UINTN DescriptorSize;
|
|
UINT32 DescriptorVersion;
|
|
UINTN NoDesc, MapKey;
|
|
UINT8 *pDataBuf;
|
|
UINT32 cData;
|
|
EFI_TIME Time;
|
|
EFI_STATUS Status;
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
//
|
|
// Find all Device Paths
|
|
//
|
|
|
|
LibLocateHandle (ByProtocol, &DevicePathProtocol, NULL, &NoHandles, &Handles);
|
|
|
|
for (Index=0; Index < NoHandles; Index++) {
|
|
Handle = Handles[Index];
|
|
DevicePath = DevicePathFromHandle (Handle);
|
|
|
|
//
|
|
// Process each device path node
|
|
//
|
|
DevPathNode = DevicePath;
|
|
while (!IsDevicePathEnd(DevPathNode)) {
|
|
//
|
|
// Find the handler to dump this device path node
|
|
//
|
|
if (DevicePathType(DevPathNode) == MESSAGING_DEVICE_PATH &&
|
|
DevicePathSubType(DevPathNode) == MSG_MAC_ADDR_DP) {
|
|
SourceMacAddress = (MAC_ADDR_DEVICE_PATH *) DevPathNode;
|
|
if (SourceMacAddress->IfType == 0x01 || SourceMacAddress->IfType == 0x00) {
|
|
CopyMem(&MacAddress[0], &SourceMacAddress->MacAddress, sizeof(UINT8) * 6);
|
|
return;
|
|
}
|
|
}
|
|
DevPathNode = NextDevicePathNode(DevPathNode);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Arriving here means that there is not an SNP-compliant
|
|
// device in the system. Use the MD5 1-way hash function to
|
|
// generate the node address
|
|
//
|
|
MemMap = LibMemoryMap (&NoDesc, &MapKey, &DescriptorSize, &DescriptorVersion);
|
|
|
|
if (!MemMap) {
|
|
Print (L"Memory map was not returned\n");
|
|
} else {
|
|
pDataBuf = AllocatePool (NoDesc * DescriptorSize +
|
|
DiskHandleCount * sizeof(EFI_HANDLE) + sizeof(EFI_TIME));
|
|
ASSERT (pDataBuf != NULL);
|
|
Anchor = pDataBuf;
|
|
Desc = MemMap;
|
|
cData = 0;
|
|
if (NoDesc != 0) {
|
|
while (NoDesc --) {
|
|
CopyMem(pDataBuf, Desc, DescriptorSize);
|
|
Desc ++;
|
|
pDataBuf += DescriptorSize;
|
|
cData += (UINT32)DescriptorSize;
|
|
}
|
|
}
|
|
//
|
|
// Also copy in the handles of the Disks
|
|
//
|
|
if (DiskHandleCount != 0) {
|
|
Index = DiskHandleCount;
|
|
while (Index --) {
|
|
CopyMem(pDataBuf, &DiskHandleList [Index], sizeof (EFI_HANDLE));
|
|
pDataBuf += sizeof(EFI_HANDLE);
|
|
cData += sizeof(EFI_HANDLE);
|
|
}
|
|
}
|
|
Status = RT->GetTime(&Time,NULL);
|
|
if (!EFI_ERROR(Status)) {
|
|
CopyMem(pDataBuf, &Time, sizeof(EFI_TIME));
|
|
pDataBuf += sizeof(EFI_TIME);
|
|
cData += sizeof (EFI_TIME);
|
|
}
|
|
|
|
GenNodeID(Anchor, cData, &MacAddress[0]);
|
|
|
|
FreePool(Anchor);
|
|
FreePool(MemMap);
|
|
return;
|
|
}
|
|
// Just case fall through
|
|
ZeroMem(MacAddress, 6 * sizeof (UINT8));
|
|
return;
|
|
}
|
|
|
|
|
|
static VOID
|
|
mult32(UINT32 u, UINT32 v, unsigned64_t *result)
|
|
{
|
|
/* Following the notation in Knuth, Vol. 2. */
|
|
UINT32 uuid1, uuid2, v1, v2, temp;
|
|
uuid1 = u >> 16;
|
|
uuid2 = u & 0xFFFF;
|
|
v1 = v >> 16;
|
|
v2 = v & 0xFFFF;
|
|
temp = uuid2 * v2;
|
|
result->lo = temp & 0xFFFF;
|
|
temp = uuid1 * v2 + (temp >> 16);
|
|
result->hi = temp >> 16;
|
|
temp = uuid2 * v1 + (temp & 0xFFFF);
|
|
result->lo += (temp & 0xFFFF) << 16;
|
|
result->hi += uuid1 * v1 + (temp >> 16);
|
|
}
|
|
|
|
static VOID
|
|
GetSystemTime(unsigned64_t *uuid_time)
|
|
{
|
|
// struct timeval tp;
|
|
EFI_TIME Time;
|
|
EFI_STATUS Status;
|
|
unsigned64_t utc, usecs, os_basetime_diff;
|
|
EFI_TIME_CAPABILITIES TimeCapabilities;
|
|
UINTN DeadCount;
|
|
UINT8 Second;
|
|
|
|
DeadCount = 0;
|
|
|
|
// gettimeofday(&tp, (struct timezone *)0);
|
|
Status = RT->GetTime(&Time,&TimeCapabilities);
|
|
|
|
Second = Time.Second;
|
|
|
|
//
|
|
// If the time resolution is 1Hz, then spin until a
|
|
// second transition. This will at least make the
|
|
// "0 nanoseconds" value appear correct inasmuch as
|
|
// multiple reads within 1 second are prohibited and
|
|
// the exit on roll-over really implies that the
|
|
// nanoseconds field "would have" rolled to zero in
|
|
// a more robust time keeper.
|
|
//
|
|
//
|
|
if (TimeCapabilities.Resolution == 1) {
|
|
while (Time.Second == Second) {
|
|
Second = Time.Second;
|
|
Status = RT->GetTime(&Time, NULL);
|
|
if (DeadCount++ == 0x1000000) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
mult32(Time.Second, 10000000, &utc);
|
|
mult32(Time.Nanosecond, 10, &usecs);
|
|
ADD_64b_2_64b(&usecs, &utc, &utc);
|
|
|
|
/* Offset between UUID formatted times and Unix formatted times.
|
|
* UUID UTC base time is October 15, 1582.
|
|
* Unix base time is January 1, 1970. */
|
|
|
|
os_basetime_diff.lo = 0x13814000;
|
|
os_basetime_diff.hi = 0x01B21DD2;
|
|
ADD_64b_2_64b(&utc, &os_basetime_diff, uuid_time);
|
|
}
|
|
|
|
UINT32
|
|
getpid() {
|
|
UINT64 FakePidValue;
|
|
|
|
BS->GetNextMonotonicCount(&FakePidValue);
|
|
//FakePidValue = 0; //(UINT32) ((UINT32)FakePidValue + (UINT32) SavedImageHandle);
|
|
FakePidValue = (UINT32) ((UINT32)FakePidValue + (UINT32) (UINT64) SavedImageHandle);
|
|
return ((UINT32)FakePidValue);
|
|
}
|
|
|
|
/*
|
|
** See “The Multiple Prime Random Number Generator” by Alexander
|
|
** Hass pp. 368-381, ACM Transactions on Mathematical Software,
|
|
** 12/87.
|
|
*/
|
|
static UINT32 rand_m;
|
|
static UINT32 rand_ia;
|
|
static UINT32 rand_ib;
|
|
static UINT32 rand_irand;
|
|
|
|
static VOID
|
|
TrueRandomInit(VOID)
|
|
{
|
|
unsigned64_t t;
|
|
EFI_TIME Time;
|
|
EFI_STATUS Status;
|
|
|
|
UINT16 seed;
|
|
/* Generating our 'seed' value Start with the current time, but,
|
|
* since the resolution of clocks is system hardware dependent
|
|
and
|
|
* most likely coarser than our resolution (10 usec) we 'mixup'
|
|
the
|
|
* bits by xor'ing all the bits together. This will have the
|
|
effect
|
|
* of involving all of the bits in the determination of the seed
|
|
* value while remaining system independent. Then for good
|
|
measure
|
|
* to ensure a unique seed when there are multiple processes
|
|
* creating UUIDs on a system, we add in the PID.
|
|
*/
|
|
rand_m = 971;
|
|
rand_ia = 11113;
|
|
rand_ib = 104322;
|
|
rand_irand = 4181;
|
|
// GetSystemTime(&t);
|
|
Status = RT->GetTime(&Time,NULL);
|
|
|
|
t.lo = Time.Nanosecond;
|
|
t.hi = (Time.Hour << 16) | Time.Second;
|
|
|
|
seed = (UINT16) (t.lo & 0xFFFF);
|
|
seed ^= (t.lo >> 16) & 0xFFFF;
|
|
seed ^= t.hi & 0xFFFF;
|
|
seed ^= (t.hi >> 16) & 0xFFFF;
|
|
rand_irand += seed + getpid();
|
|
}
|
|
|
|
static UINT16
|
|
true_random(VOID)
|
|
{
|
|
if ((rand_m += 7) >= 9973)
|
|
rand_m -= 9871;
|
|
if ((rand_ia += 1907) >= 99991)
|
|
rand_ia -= 89989;
|
|
if ((rand_ib += 73939) >= 224729)
|
|
rand_ib -= 96233;
|
|
rand_irand = (rand_irand * rand_m) + rand_ia + rand_ib;
|
|
return (UINT16) ((rand_irand >> 16) ^ (rand_irand & RAND_MASK));
|
|
}
|
|
|
|
/*
|
|
** Startup initialization routine for the UUID module.
|
|
*/
|
|
VOID
|
|
InitGuid(VOID)
|
|
{
|
|
TrueRandomInit();
|
|
GetSystemTime(&time_last);
|
|
#ifdef NONVOLATILE_CLOCK
|
|
clock_seq = read_clock();
|
|
#else
|
|
clock_seq = true_random();
|
|
#endif
|
|
}
|
|
|
|
static INTN
|
|
time_cmp(unsigned64_t *time1, unsigned64_t *time2)
|
|
{
|
|
if (time1->hi < time2->hi) return -1;
|
|
if (time1->hi > time2->hi) return 1;
|
|
if (time1->lo < time2->lo) return -1;
|
|
if (time1->lo > time2->lo) return 1;
|
|
return 0;
|
|
}
|
|
|
|
static VOID new_clock_seq(VOID)
|
|
{
|
|
clock_seq = (clock_seq + 1) % (CLOCK_SEQ_LAST + 1);
|
|
if (clock_seq == 0) clock_seq = 1;
|
|
#ifdef NONVOLATILE_CLOCK
|
|
write_clock(clock_seq);
|
|
#endif
|
|
}
|
|
|
|
VOID CreateGuid(uuid_t *guid)
|
|
{
|
|
static unsigned64_t time_now;
|
|
static UINT16 time_adjust;
|
|
UINT8 eaddr[6];
|
|
INTN got_no_time = 0;
|
|
|
|
GetIeeeNodeIdentifier(&eaddr[0]); /* TO BE PROVIDED by EFI device path */
|
|
|
|
do {
|
|
GetSystemTime(&time_now);
|
|
switch (time_cmp(&time_now, &time_last)) {
|
|
case -1:
|
|
/* Time went backwards. */
|
|
new_clock_seq();
|
|
time_adjust = 0;
|
|
break;
|
|
case 1:
|
|
time_adjust = 0;
|
|
break;
|
|
default:
|
|
if (time_adjust == 0x7FFF)
|
|
/* We're going too fast for our clock; spin. */
|
|
got_no_time = 1;
|
|
else
|
|
time_adjust++;
|
|
break;
|
|
}
|
|
} while (got_no_time);
|
|
|
|
time_last.lo = time_now.lo;
|
|
time_last.hi = time_now.hi;
|
|
if (time_adjust != 0) {
|
|
ADD_16b_2_64b(&time_adjust, &time_now, &time_now);
|
|
}
|
|
/* Construct a guid with the information we've gathered
|
|
* plus a few constants. */
|
|
guid->time_low = time_now.lo;
|
|
guid->time_mid = (UINT16) (time_now.hi & 0x0000FFFF);
|
|
guid->time_hi_and_version = (UINT16) (time_now.hi & 0x0FFF0000) >> 16;
|
|
guid->time_hi_and_version |= (1 << 12);
|
|
guid->clock_seq_low = clock_seq & 0xFF;
|
|
guid->clock_seq_hi_and_reserved = (clock_seq & 0x3F00) >> 8;
|
|
guid->clock_seq_hi_and_reserved |= 0x80;
|
|
CopyMem (guid->node, &eaddr, sizeof guid->node);
|
|
}
|
|
|