Beispiel #1
0
/* grub_fatal() on error */
static grub_err_t
grub_cmd_readpcr( grub_command_t cmd __attribute__ ((unused)), int argc, char **args) {

	if ( argc == 0 ) {
		grub_fatal( "grub_cmd_readpcr: index expected" );
	}

	if ( argc > 1 ) {
		grub_fatal( "grub_cmd_readpcr: Too many arguments" );
	}

	unsigned long index = grub_strtoul( args[0], NULL, 10 );

	/* if index is invalid */
	if( grub_errno != GRUB_ERR_NONE ) {
        grub_fatal( "grub_cmd_readpcr: invalid format for index" );
	}

	grub_uint8_t result[SHA1_DIGEST_SIZE] = { 0 };
    grub_TPM_readpcr( index, &result[0] );

	grub_printf( "PCR[%lu]=", index );
	print_sha1( result );
	grub_printf("\n");

	return GRUB_ERR_NONE;
}
Beispiel #2
0
/* grub_fatal() on error */
static void
grub_TPM_readpcr( const unsigned long index, grub_uint8_t* result ) {

    CHECK_FOR_NULL_ARGUMENT( result )

	PassThroughToTPM_InputParamBlock *passThroughInput = NULL;
	PCRReadIncoming* pcrReadIncoming = NULL;
    grub_uint16_t inputlen = sizeof( *passThroughInput ) - sizeof( passThroughInput->TPMOperandIn ) + sizeof( *pcrReadIncoming );

	PassThroughToTPM_OutputParamBlock *passThroughOutput = NULL;
	PCRReadOutgoing* pcrReadOutgoing = NULL;
    grub_uint16_t outputlen = sizeof( *passThroughOutput ) - sizeof( passThroughOutput->TPMOperandOut ) + sizeof( *pcrReadOutgoing );

	passThroughInput = grub_zalloc( inputlen );
	if( ! passThroughInput ) {
        grub_fatal( "readpcr: memory allocation failed" );
	}

	passThroughInput->IPBLength = inputlen;
	passThroughInput->OPBLength = outputlen;

	pcrReadIncoming = (void *)passThroughInput->TPMOperandIn;
	pcrReadIncoming->tag = grub_swap_bytes16_compile_time( TPM_TAG_RQU_COMMAND );
	pcrReadIncoming->paramSize = grub_swap_bytes32( sizeof( *pcrReadIncoming ) );
	pcrReadIncoming->ordinal = grub_swap_bytes32_compile_time( TPM_ORD_PcrRead );
	pcrReadIncoming->pcrIndex = grub_swap_bytes32( (grub_uint32_t) index);

	passThroughOutput = grub_zalloc( outputlen );
	if( ! passThroughOutput ) {
		grub_free( passThroughInput );
        grub_fatal( "readpcr: memory allocation failed" );
	}

	grub_TPM_int1A_passThroughToTPM( passThroughInput, passThroughOutput );
	grub_free( passThroughInput );

	pcrReadOutgoing = (void *)passThroughOutput->TPMOperandOut;
	grub_uint32_t tpm_PCRreadReturnCode = grub_swap_bytes32( pcrReadOutgoing->returnCode );

	if( tpm_PCRreadReturnCode != TPM_SUCCESS ) {
		grub_free( passThroughOutput );

		if( tpm_PCRreadReturnCode == TPM_BADINDEX ) {
            grub_fatal( "readpcr: bad pcr index" );
		}

        grub_fatal( "readpcr: tpm_PCRreadReturnCode: %u", tpm_PCRreadReturnCode );
	}

	grub_memcpy( result, pcrReadOutgoing->pcr_value, SHA1_DIGEST_SIZE );
	grub_free( passThroughOutput );
}
Beispiel #3
0
volatile void *
grub_pci_device_map_range (grub_pci_device_t dev __attribute__ ((unused)),
			   grub_addr_t base, grub_size_t size)
{
  int i;
  grub_addr_t newbase;

  /* First try already used registers. */
  for (i = 0; i < GRUB_MACHINE_PCI_NUM_WIN; i++)
    if (usage_win[i] && base_win[i] <= base 
	&& base_win[i] + sizes_win[i] > base + size)
      {
	usage_win[i]++;
	return (void *) 
	  (addr_win[i] | (base & GRUB_MACHINE_PCI_WIN_OFFSET_MASK));
      }
  /* Map new register.  */
  newbase = base & ~GRUB_MACHINE_PCI_WIN_OFFSET_MASK;
  for (i = 0; i < GRUB_MACHINE_PCI_NUM_WIN; i++)
    if (!usage_win[i] && newbase <= base 
	&& newbase + sizes_win[i] > base + size)
      {
	usage_win[i]++;
	base_win[i] = newbase;
	write_bases ();
	return (void *) 
	  (addr_win[i] | (base & GRUB_MACHINE_PCI_WIN_OFFSET_MASK));
      }
  grub_fatal ("Out of PCI windows.");
}
Beispiel #4
0
void
grub_tsc_init (void)
{
  if (!grub_cpu_is_tsc_supported ())
    {
#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_IEEE1275)
      grub_install_get_time_ms (grub_rtc_get_time_ms);
#else
      grub_fatal ("no TSC found");
#endif
      return;
    }

  tsc_boot_time = grub_get_tsc ();

#ifdef GRUB_MACHINE_XEN
  (void) (grub_tsc_calibrate_from_xen () || calibrate_tsc_hardcode());
#elif defined (GRUB_MACHINE_EFI)
  (void) (grub_tsc_calibrate_from_pit () || grub_tsc_calibrate_from_pmtimer () || grub_tsc_calibrate_from_efi() || calibrate_tsc_hardcode());
#elif defined (GRUB_MACHINE_COREBOOT)
  (void) (grub_tsc_calibrate_from_pmtimer () || grub_tsc_calibrate_from_pit () || calibrate_tsc_hardcode());
#else
  (void) (grub_tsc_calibrate_from_pit () || calibrate_tsc_hardcode());
#endif
  grub_install_get_time_ms (grub_tsc_get_time_ms);
}
Beispiel #5
0
/* grub_fatal() on error */
static grub_err_t
grub_cmd_measure( grub_command_t cmd __attribute__ ((unused)), int argc, char **args) {

	if ( argc != 2 ) {
		grub_fatal( "Wrong number of arguments" );
	}

	unsigned long index = grub_strtoul( args[1], NULL, 10 );

    /* if index is invalid */
    if( grub_errno != GRUB_ERR_NONE ) {
        grub_fatal( "invalid format for index" );
    }

	grub_TPM_measure_file( args[0], index );

	return GRUB_ERR_NONE;
}
Beispiel #6
0
static int panic (lua_State *L) {
  (void)L;  /* to avoid warnings */
#if 0
  fprintf(stderr, "PANIC: unprotected error in call to Lua API (%s)\n",
                   lua_tostring(L, -1));
#else
  grub_fatal ("PANIC: unprotected error in call to Lua API (%s)\n",
	      lua_tostring(L, -1));
#endif
  return 0;
}
Beispiel #7
0
/* grub_fatal() on error */
static grub_err_t
grub_cmd_tcglog( grub_command_t cmd __attribute__ ((unused)), int argc, char **args) {

	if ( argc == 0 ) {
		grub_fatal( "grub_cmd_tcglog: index expected" );
	}

	if ( argc > 1 ) {
		grub_fatal( "grub_cmd_tcglog: Too many arguments" );
	}

	unsigned long index = grub_strtoul( args[0], NULL, 10 );

    /* if index is invalid */
    if( grub_errno != GRUB_ERR_NONE ) {
        grub_fatal( "grub_cmd_tcglog: invalid format for index" );
    }

	grub_TPM_read_tcglog( index ) ;

	return GRUB_ERR_NONE;
}
Beispiel #8
0
grub_err_t
grub_linuxbios_table_iterate (int (*hook) (grub_linuxbios_table_item_t,
					   void *),
			      void *hook_data)
{
  grub_linuxbios_table_header_t table_header;
  grub_linuxbios_table_item_t table_item;

  /* Assuming table_header is aligned to its size (8 bytes).  */

  for (table_header = (grub_linuxbios_table_header_t) 0x500;
       table_header < (grub_linuxbios_table_header_t) 0x1000; table_header++)
    if (check_signature (table_header))
      goto signature_found;

  for (table_header = (grub_linuxbios_table_header_t) 0xf0000;
       table_header < (grub_linuxbios_table_header_t) 0x100000; table_header++)
    if (check_signature (table_header))
      goto signature_found;

  grub_fatal ("Could not find coreboot table\n");

signature_found:

  table_item =
    (grub_linuxbios_table_item_t) ((char *) table_header +
				   table_header->header_size);
  for (; table_item < (grub_linuxbios_table_item_t) ((char *) table_header
						     + table_header->header_size
						     + table_header->table_size);
       table_item = (grub_linuxbios_table_item_t) ((char *) table_item + table_item->size))
    {
      if (table_item->tag == GRUB_LINUXBIOS_MEMBER_LINK
         && check_signature ((grub_linuxbios_table_header_t) (grub_addr_t)
                             *(grub_uint64_t *) (table_item + 1)))
       {
         table_header = (grub_linuxbios_table_header_t) (grub_addr_t)
           *(grub_uint64_t *) (table_item + 1);
         goto signature_found;   
       }
      if (hook (table_item, hook_data))
       return 1;
    }

  return 0;
}
Beispiel #9
0
void
grub_arch_sync_caches (void *address, grub_size_t len)
{
  grub_size_t start, end, max_align;

  if (dlinesz == 0)
    probe_caches();
  if (dlinesz == 0)
    grub_fatal ("Unknown cache line size!");

  max_align = dlinesz > ilinesz ? dlinesz : ilinesz;

  start = ALIGN_DOWN ((grub_size_t) address, max_align);
  end = ALIGN_UP ((grub_size_t) address + len, max_align);

  grub_arch_clean_dcache_range (start, end, dlinesz);
  grub_arch_invalidate_icache_range (start, end, ilinesz);
}
Beispiel #10
0
/* Load all modules in core.  */
static void
grub_load_modules (void)
{
  auto int hook (struct grub_module_header *);
  int hook (struct grub_module_header *header)
    {
      /* Not an ELF module, skip.  */
      if (header->type != OBJ_TYPE_ELF)
        return 0;

      if (! grub_dl_load_core ((char *) header + sizeof (struct grub_module_header),
			       (header->size - sizeof (struct grub_module_header))))
	grub_fatal ("%s", grub_errmsg);

      if (grub_errno)
	grub_print_error ();

      return 0;
    }

  grub_module_iterate (hook);
}
Beispiel #11
0
/* Find the optimal number of pages for the memory map. Is it better to
   move this code to efi/mm.c?  */
static grub_efi_uintn_t
find_efi_mmap_size (void)
{
  static grub_efi_uintn_t mmap_size = 0;

  if (mmap_size != 0)
    return mmap_size;

  mmap_size = (1 << 12);
  while (1)
    {
      int ret;
      grub_efi_memory_descriptor_t *mmap;
      grub_efi_uintn_t desc_size;

      mmap = grub_malloc (mmap_size);
      if (! mmap)
	return 0;

      ret = grub_efi_get_memory_map (&mmap_size, mmap, 0, &desc_size, 0);
      grub_free (mmap);

      if (ret < 0)
	grub_fatal ("cannot get memory map");
      else if (ret > 0)
	break;

      mmap_size += (1 << 12);
    }

  /* Increase the size a bit for safety, because GRUB allocates more on
     later, and EFI itself may allocate more.  */
  mmap_size += (1 << 12);

  mmap_size = page_align (mmap_size);
  return mmap_size;
}
Beispiel #12
0
Datei: compat.c Projekt: xk/bits
__attribute__((noreturn)) void exit(int status)
{
    grub_fatal("Internal error: Python tried to exit with status %d\n", status);
}
Beispiel #13
0
Datei: compat.c Projekt: xk/bits
void _assert(const char *filename, unsigned line, int condition, const char *condition_str)
{
    if (!condition)
        grub_fatal("%s:%u: Python assertion failure: assert(%s)\n", filename, line, condition_str);
}
Beispiel #14
0
grub_uint32_t
grub_get_rtc (void)
{
  grub_fatal ("grub_get_rtc() is not implemented.\n");
}
Beispiel #15
0
/****************
 * RES = BASE ^ EXPO mod MOD
 */
void
gcry_mpi_powm (gcry_mpi_t res,
               gcry_mpi_t base, gcry_mpi_t expo, gcry_mpi_t mod)
{
  /* Pointer to the limbs of the arguments, their size and signs. */
  mpi_ptr_t  rp, ep, mp, bp;
  mpi_size_t esize, msize, bsize, rsize;
  int               msign, bsign, rsign;
  /* Flags telling the secure allocation status of the arguments.  */
  int        esec,  msec,  bsec;
  /* Size of the result including space for temporary values.  */
  mpi_size_t size;
  /* Helper.  */
  int mod_shift_cnt;
  int negative_result;
  mpi_ptr_t mp_marker = NULL;
  mpi_ptr_t bp_marker = NULL;
  mpi_ptr_t ep_marker = NULL;
  mpi_ptr_t xp_marker = NULL;
  unsigned int mp_nlimbs = 0;
  unsigned int bp_nlimbs = 0;
  unsigned int ep_nlimbs = 0;
  unsigned int xp_nlimbs = 0;
  mpi_ptr_t tspace = NULL;
  mpi_size_t tsize = 0;


  esize = expo->nlimbs;
  msize = mod->nlimbs;
  size = 2 * msize;
  msign = mod->sign;

  esec = mpi_is_secure(expo);
  msec = mpi_is_secure(mod);
  bsec = mpi_is_secure(base);

  rp = res->d;
  ep = expo->d;

  if (!msize)
    grub_fatal ("mpi division by zero");

  if (!esize)
    {
      /* Exponent is zero, result is 1 mod MOD, i.e., 1 or 0 depending
         on if MOD equals 1.  */
      res->nlimbs = (msize == 1 && mod->d[0] == 1) ? 0 : 1;
      if (res->nlimbs)
        {
          RESIZE_IF_NEEDED (res, 1);
          rp = res->d;
          rp[0] = 1;
        }
      res->sign = 0;
      goto leave;
    }

  /* Normalize MOD (i.e. make its most significant bit set) as
     required by mpn_divrem.  This will make the intermediate values
     in the calculation slightly larger, but the correct result is
     obtained after a final reduction using the original MOD value. */
  mp_nlimbs = msec? msize:0;
  mp = mp_marker = mpi_alloc_limb_space(msize, msec);
  count_leading_zeros (mod_shift_cnt, mod->d[msize-1]);
  if (mod_shift_cnt)
    _gcry_mpih_lshift (mp, mod->d, msize, mod_shift_cnt);
  else
    MPN_COPY( mp, mod->d, msize );

  bsize = base->nlimbs;
  bsign = base->sign;
  if (bsize > msize)
    {
      /* The base is larger than the module.  Reduce it.

         Allocate (BSIZE + 1) with space for remainder and quotient.
         (The quotient is (bsize - msize + 1) limbs.)  */
      bp_nlimbs = bsec ? (bsize + 1):0;
      bp = bp_marker = mpi_alloc_limb_space( bsize + 1, bsec );
      MPN_COPY ( bp, base->d, bsize );
      /* We don't care about the quotient, store it above the
       * remainder, at BP + MSIZE.  */
      _gcry_mpih_divrem( bp + msize, 0, bp, bsize, mp, msize );
      bsize = msize;
      /* Canonicalize the base, since we are going to multiply with it
	 quite a few times.  */
      MPN_NORMALIZE( bp, bsize );
    }
  else
    bp = base->d;

  if (!bsize)
    {
      res->nlimbs = 0;
      res->sign = 0;
      goto leave;
    }


  /* Make BASE, EXPO and MOD not overlap with RES.  */
  if ( rp == bp )
    {
      /* RES and BASE are identical.  Allocate temp. space for BASE.  */
      gcry_assert (!bp_marker);
      bp_nlimbs = bsec? bsize:0;
      bp = bp_marker = mpi_alloc_limb_space( bsize, bsec );
      MPN_COPY(bp, rp, bsize);
    }
  if ( rp == ep )
    {
      /* RES and EXPO are identical.  Allocate temp. space for EXPO.  */
      ep_nlimbs = esec? esize:0;
      ep = ep_marker = mpi_alloc_limb_space( esize, esec );
      MPN_COPY(ep, rp, esize);
    }
  if ( rp == mp )
    {
      /* RES and MOD are identical.  Allocate temporary space for MOD.*/
      gcry_assert (!mp_marker);
      mp_nlimbs = msec?msize:0;
      mp = mp_marker = mpi_alloc_limb_space( msize, msec );
      MPN_COPY(mp, rp, msize);
    }

  /* Copy base to the result.  */
  if (res->alloced < size)
    {
      mpi_resize (res, size);
      rp = res->d;
    }
  MPN_COPY ( rp, bp, bsize );
  rsize = bsize;
  rsign = bsign;

  /* Main processing.  */
  {
    mpi_size_t i;
    mpi_ptr_t xp;
    int c;
    mpi_limb_t e;
    mpi_limb_t carry_limb;
    struct karatsuba_ctx karactx;

    xp_nlimbs = msec? (2 * (msize + 1)):0;
    xp = xp_marker = mpi_alloc_limb_space( 2 * (msize + 1), msec );

    memset( &karactx, 0, sizeof karactx );
    negative_result = (ep[0] & 1) && base->sign;

    i = esize - 1;
    e = ep[i];
    count_leading_zeros (c, e);
    e = (e << c) << 1;     /* Shift the expo bits to the left, lose msb.  */
    c = BITS_PER_MPI_LIMB - 1 - c;

    /* Main loop.

       Make the result be pointed to alternately by XP and RP.  This
       helps us avoid block copying, which would otherwise be
       necessary with the overlap restrictions of
       _gcry_mpih_divmod. With 50% probability the result after this
       loop will be in the area originally pointed by RP (==RES->d),
       and with 50% probability in the area originally pointed to by XP. */
    for (;;)
      {
        while (c)
          {
            mpi_ptr_t tp;
            mpi_size_t xsize;

            /*mpih_mul_n(xp, rp, rp, rsize);*/
            if ( rsize < KARATSUBA_THRESHOLD )
              _gcry_mpih_sqr_n_basecase( xp, rp, rsize );
            else
              {
                if ( !tspace )
                  {
                    tsize = 2 * rsize;
                    tspace = mpi_alloc_limb_space( tsize, 0 );
                  }
                else if ( tsize < (2*rsize) )
                  {
                    _gcry_mpi_free_limb_space (tspace, 0);
                    tsize = 2 * rsize;
                    tspace = mpi_alloc_limb_space (tsize, 0 );
                  }
                _gcry_mpih_sqr_n (xp, rp, rsize, tspace);
              }

            xsize = 2 * rsize;
            if ( xsize > msize )
              {
                _gcry_mpih_divrem(xp + msize, 0, xp, xsize, mp, msize);
                xsize = msize;
              }

            tp = rp; rp = xp; xp = tp;
            rsize = xsize;

            /* To mitigate the Yarom/Falkner flush+reload cache
             * side-channel attack on the RSA secret exponent, we do
             * the multiplication regardless of the value of the
             * high-bit of E.  But to avoid this performance penalty
             * we do it only if the exponent has been stored in secure
             * memory and we can thus assume it is a secret exponent.  */
            if (esec || (mpi_limb_signed_t)e < 0)
              {
                /*mpih_mul( xp, rp, rsize, bp, bsize );*/
                if( bsize < KARATSUBA_THRESHOLD )
                  _gcry_mpih_mul ( xp, rp, rsize, bp, bsize );
                else
                  _gcry_mpih_mul_karatsuba_case (xp, rp, rsize, bp, bsize,
                                                 &karactx);

                xsize = rsize + bsize;
                if ( xsize > msize )
                  {
                    _gcry_mpih_divrem(xp + msize, 0, xp, xsize, mp, msize);
                    xsize = msize;
                  }
              }
            if ( (mpi_limb_signed_t)e < 0 )
              {
                tp = rp; rp = xp; xp = tp;
                rsize = xsize;
              }
            e <<= 1;
            c--;
          }

        i--;
        if ( i < 0 )
          break;
        e = ep[i];
        c = BITS_PER_MPI_LIMB;
      }

    /* We shifted MOD, the modulo reduction argument, left
       MOD_SHIFT_CNT steps.  Adjust the result by reducing it with the
       original MOD.

       Also make sure the result is put in RES->d (where it already
       might be, see above).  */
    if ( mod_shift_cnt )
      {
        carry_limb = _gcry_mpih_lshift( res->d, rp, rsize, mod_shift_cnt);
        rp = res->d;
        if ( carry_limb )
          {
            rp[rsize] = carry_limb;
            rsize++;
          }
      }
    else if (res->d != rp)
      {
        MPN_COPY (res->d, rp, rsize);
        rp = res->d;
      }

    if ( rsize >= msize )
      {
        _gcry_mpih_divrem(rp + msize, 0, rp, rsize, mp, msize);
        rsize = msize;
      }

    /* Remove any leading zero words from the result.  */
    if ( mod_shift_cnt )
      _gcry_mpih_rshift( rp, rp, rsize, mod_shift_cnt);
    MPN_NORMALIZE (rp, rsize);

    _gcry_mpih_release_karatsuba_ctx (&karactx );
  }

  /* Fixup for negative results.  */
  if ( negative_result && rsize )
    {
      if ( mod_shift_cnt )
        _gcry_mpih_rshift( mp, mp, msize, mod_shift_cnt);
      _gcry_mpih_sub( rp, mp, msize, rp, rsize);
      rsize = msize;
      rsign = msign;
      MPN_NORMALIZE(rp, rsize);
    }
  gcry_assert (res->d == rp);
  res->nlimbs = rsize;
  res->sign = rsign;

 leave:
  if (mp_marker)
    _gcry_mpi_free_limb_space( mp_marker, mp_nlimbs );
  if (bp_marker)
    _gcry_mpi_free_limb_space( bp_marker, bp_nlimbs );
  if (ep_marker)
    _gcry_mpi_free_limb_space( ep_marker, ep_nlimbs );
  if (xp_marker)
    _gcry_mpi_free_limb_space( xp_marker, xp_nlimbs );
  if (tspace)
    _gcry_mpi_free_limb_space( tspace, 0 );
}
Beispiel #16
0
void
grub_machine_init (void)
{
  int i;
  int grub_lower_mem;

  /* Initialize the console as early as possible.  */
  grub_console_init ();

  grub_lower_mem = grub_get_conv_memsize () << 10;

  /* Sanity check.  */
  if (grub_lower_mem < GRUB_MEMORY_MACHINE_RESERVED_END)
    grub_fatal ("too small memory");

/* FIXME: This prevents loader/i386/linux.c from using low memory.  When our
   heap implements support for requesting a chunk in low memory, this should
   no longer be a problem.  */
#if 0
  /* Add the lower memory into free memory.  */
  if (grub_lower_mem >= GRUB_MEMORY_MACHINE_RESERVED_END)
    add_mem_region (GRUB_MEMORY_MACHINE_RESERVED_END,
		    grub_lower_mem - GRUB_MEMORY_MACHINE_RESERVED_END);
#endif

  auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t,
				  grub_memory_type_t);
  int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size,
			     grub_memory_type_t type)
    {
      /* Avoid the lower memory.  */
      if (addr < 0x100000)
	{
	  if (size <= 0x100000 - addr)
	    return 0;

	  size -= 0x100000 - addr;
	  addr = 0x100000;
	}

      /* Ignore >4GB.  */
      if (addr <= 0xFFFFFFFF && type == GRUB_MEMORY_AVAILABLE)
	{
	  grub_size_t len;

	  len = (grub_size_t) ((addr + size > 0xFFFFFFFF)
		 ? 0xFFFFFFFF - addr
		 : size);
	  add_mem_region (addr, len);
	}

      return 0;
    }

  grub_machine_mmap_iterate (hook);

  compact_mem_regions ();

  for (i = 0; i < num_regions; i++)
      grub_mm_init_region ((void *) mem_regions[i].addr, mem_regions[i].size);

  grub_tsc_init ();
}
Beispiel #17
0
Datei: compat.c Projekt: xk/bits
__attribute__((noreturn)) void abort(void)
{
    grub_fatal("Internal error: Python called abort()\n");
}
Beispiel #18
0
/* grub_fatal() on error */
static void
grub_TPM_read_tcglog( const unsigned long index ) {

	grub_uint32_t returnCode, featureFlags, eventLog = 0, logAddr = 0, edi = 0;
	grub_uint8_t major, minor;

	/* get event log pointer */
	grub_TPM_int1A_statusCheck( &returnCode, &major, &minor, &featureFlags, &eventLog, &edi );

	/* edi = 0 means event log is empty */
	if( edi == 0 ) {
        grub_fatal( "Event log is empty" );
	}

	logAddr = eventLog;
	TCG_PCClientPCREvent *event = NULL;
	/* index = 0: print all entries */
	if ( index == 0 ) {

		/* eventLog = absolute pointer to the beginning of the event log. */
		event = (TCG_PCClientPCREvent *) logAddr;

		/* If there is exactly one entry */
		if( edi == eventLog ) {
			grub_printf( "pcrIndex: %u \n", event->pcrIndex );
			grub_printf( "eventType: %u \n", event->eventType );
			grub_printf( "digest: " );
			print_sha1( event->digest );
			grub_printf( "\n\n" );
		} else {	/* If there is more than one entry */
			do {
				grub_printf( "pcrIndex: %u \n", event->pcrIndex );
				grub_printf( "eventType: %u \n", event->eventType );
				grub_printf( "digest: " );
				print_sha1( event->digest );
				grub_printf( "\n\n" );

				logAddr += TCG_PCR_EVENT_SIZE + event->eventDataSize;
				event = (TCG_PCClientPCREvent *)logAddr;
			} while( logAddr != edi );

			/* print the last one */
			grub_printf( "pcrIndex: %u \n", event->pcrIndex );
			grub_printf( "eventType: %u \n", event->eventType );
			grub_printf( "digest: " );
			print_sha1( event->digest );
			grub_printf( "\n\n" );
		}
	} else { /* print specific entry */
		logAddr = eventLog;

		unsigned long i;
		for( i = 1; i < index; i++ ) {
			event = (TCG_PCClientPCREvent *)logAddr;
			logAddr += TCG_PCR_EVENT_SIZE + event->eventDataSize;

			if( logAddr > edi ) { /* index not valid.  */
                grub_fatal( "No entry at specified index" );
			}
		}

		event = (TCG_PCClientPCREvent *)logAddr;
		grub_printf( "pcrIndex: %u \n", event->pcrIndex );
		grub_printf( "eventType: %u \n", event->eventType );
		grub_printf( "digest: " );
		print_sha1( event->digest );
		grub_printf( "\n\n" );
	}
}