/* * Lenovo Confidential * Microcode Source Materials * COPYRIGHT LENOVO 2005, 2012 All RIGHTS RESERVED */ #include #include #include #include #include #include "UUID.h" #include "GETNODE.h" static UINT32 rand_m; static UINT32 rand_ia; static UINT32 rand_ib; static UINT32 rand_irand; static UINT16 clock_seq; static unsigned64_t time_last; // ******************************************************************* // // FUNCTION NAME. // mult32 // // FUNCTIONAL DESCRIPTION. // // // ENTRY PARAMETERS. // // EXIT PARAMETERS. // // WARNINGS. // // ******************************************************************* 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); } // mult32 // ******************************************************************* // // FUNCTION NAME. // new_clock_seq // // FUNCTIONAL DESCRIPTION. // // // ENTRY PARAMETERS. // // EXIT PARAMETERS. // // WARNINGS. // // ******************************************************************* 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 } // new_clock_seq // ******************************************************************* // // FUNCTION NAME. // time_cmp // // FUNCTIONAL DESCRIPTION. // // // ENTRY PARAMETERS. // // EXIT PARAMETERS. // // WARNINGS. // // ******************************************************************* static int 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; } // time_cmp // ******************************************************************* // // FUNCTION NAME. // true_random // // FUNCTIONAL DESCRIPTION. // // // ENTRY PARAMETERS. // // EXIT PARAMETERS. // // WARNINGS. // // ******************************************************************* 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) ); } // true_random // ******************************************************************* // // FUNCTION NAME. // get_system_time // // FUNCTIONAL DESCRIPTION. // // ENTRY PARAMETERS. // // EXIT PARAMETERS. // // WARNINGS. // // ******************************************************************* static EFI_STATUS get_system_time(unsigned64_t *uuid_time) { EFI_STATUS Status; EFI_TIME Time; #ifdef HOZU // struct timeval tp; #endif unsigned64_t utc = {0UL, 0UL}; unsigned64_t usecs = {0UL, 0UL}; unsigned64_t os_basetime_diff = {0UL, 0UL}; #ifdef HOZU // gettimeofday(&tp, (struct timezone *)0); // // mult32((long)tp.tv_sec, 10000000, &utc); // timeval.tv_sec : second // mult32((long)tp.tv_usec, 10, &usecs); // timeval.tv_usec : microsecond #else { unsigned short theDays; unsigned char h, m, s; unsigned long theSec; unsigned long theUSec; // original is u_char theDays = 0; h = m = s = 0; theSec = 0; theUSec = 0; ZeroMem (&Time, sizeof (EFI_TIME)); // Get System Time Status = gRT->GetTime (&Time, NULL); if (EFI_ERROR (Status)) { DEBUG((EFI_D_ERROR, "ERROR : Get Time, Status=[%r]\n", Status)); return Status; } theSec = ( unsigned long )Time.Day * 86400L + ( unsigned long )Time.Hour * 3600L + ( unsigned long )Time.Minute * 60L + ( unsigned long )Time.Second; if(Time.Nanosecond != 0){ theUSec = Time.Nanosecond; }else{ theUSec = true_random(); // substitute for Nanosecond } //-------------------------------------------------------------------- // __asm // { // mov ah, 4 // int 0x1a // mov theDays, cx // mov ah,2 // int 0x1a // mov h, ch // mov m, cl // mov s, dh // } // // theSec = ( unsigned long )theDays * 86400L + // ( unsigned long )h * 3600L + // ( unsigned long )m * 60L + // ( unsigned long )s; // // __asm // { // mov ah, 0 // int 0x1a // mov theUSec, al // theUSec : unsigned char // } //-------------------------------------------------------------------- mult32((long)theSec, 10000000, &utc); mult32((long)theUSec, 10, &usecs); } #endif 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); return EFI_SUCCESS; } // get_system_time // ******************************************************************* // // FUNCTION NAME. // true_random_init // // FUNCTIONAL DESCRIPTION. // // ENTRY PARAMETERS. // // EXIT PARAMETERS. // // WARNINGS. // // ******************************************************************* static EFI_STATUS true_random_init(VOID) { EFI_STATUS Status; unsigned64_t t; UINT16 seed; Status = EFI_SUCCESS; seed = 0; ZeroMem (&t, sizeof(t)); /* 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; Status = get_system_time(&t); if (EFI_ERROR (Status)) { return Status; } seed = (UINT16)t.lo & 0xFFFF; seed = (UINT16)(t.lo >> 16) & 0xFFFF; seed = (UINT16) t.hi & 0xFFFF; seed = (UINT16)(t.hi >> 16) & 0xFFFF; #ifdef HOZU // rand_irand += seed + getpid(); #else rand_irand += seed; #endif return EFI_SUCCESS; } // true_random_init // ******************************************************************* // // FUNCTION NAME. // uuid_init // // FUNCTIONAL DESCRIPTION. // // ENTRY PARAMETERS. // // EXIT PARAMETERS. // // WARNINGS. // // ******************************************************************* EFI_STATUS uuid_init( VOID) { EFI_STATUS Status; // Initialize Status = EFI_SUCCESS; // Make seed from system time Status = true_random_init(); if (EFI_ERROR (Status)) { DEBUG((EFI_D_ERROR, "ERROR : true random init, Status=[%r]\n", Status)); return Status; } // Get system time after calculation Status = get_system_time(&time_last); if (EFI_ERROR (Status)) { DEBUG((EFI_D_ERROR, "ERROR : get system time, Status=[%r]\n", Status)); return Status; } #ifdef NONVOLATILE_CLOCK // clock_seq = read_clock(); #else // Make "clock_seq" clock_seq = true_random(); #endif return EFI_SUCCESS; } // uuid_init // ******************************************************************* // // FUNCTION NAME. // uuid_create // // FUNCTIONAL DESCRIPTION. // // // ENTRY PARAMETERS. // // EXIT PARAMETERS. // // WARNINGS. // // ******************************************************************* EFI_STATUS uuid_create(uuid_t *uuid) { EFI_STATUS Status; static unsigned64_t time_now; static UINT16 time_adjust; UINT8 eaddr[6]; UINTN got_no_time = 0; UINTN i; UINTN tempSize; unsigned char theBuff[8 + sizeof(UINT16)]; // Initialize Status = EFI_SUCCESS; ZeroMem (eaddr, sizeof(eaddr)); ZeroMem (theBuff, sizeof(theBuff)); // // UUID create // #ifdef HOZU // get_ieee_node_identifier(&eaddr); /* TO BE PROVIDED */ #else { //#if defined(_M_AMD64) *(UINT64*)(theBuff) = AsmReadTsc(); //#else // // ----------------------------------------------------------- // // Get total CPU clock count from the started (8byte) // // eax : low byte (4byte), edx : high byte (4byte) // // ----------------------------------------------------------- // __asm // { // rdtsc // mov dword ptr theBuff[0], eax // mov dword ptr theBuff[4], edx // } // // ----------------------------------------------------------- //#endif *( UINT16 * )&theBuff[8] = true_random(); GenNodeID( ( unsigned char * )theBuff, sizeof( theBuff ), eaddr ); } #endif do { Status = get_system_time(&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 uuid with the information we've gathered * plus a few constants. */ uuid->time_low = time_now.lo; uuid->time_mid = (UINT16)( time_now.hi & 0x0000FFFF ); uuid->time_hi_and_version = (UINT16)((time_now.hi & 0x0FFF0000) >> 16); uuid->time_hi_and_version |= (1 << 12); uuid->clock_seq_low = (UINT8)( clock_seq & 0xFF ); uuid->clock_seq_hi_and_reserved = (UINT8)((clock_seq & 0x3F00) >> 8); uuid->clock_seq_hi_and_reserved |= 0x80; //memcpy(uuid->node, &eaddr, sizeof uuid->node); tempSize = sizeof(uuid->node); for(i=0 ; inode[i] = eaddr[i]; } return EFI_SUCCESS; } // uuid_create