[U-Boot] RNG implementation fails

André Schaller an.schall at googlemail.com
Tue Jul 30 14:14:31 CEST 2013


HI,

I wanted to include a RNG implementation of the Mersenne-Twister into
the SPL part of u-boot. However, although the (standalone) code compiles
and runs fine on my linux box, u-boot stops to boot and I am not sure
why. I am sure I am missing a rather basic design principle of the
u-boot code but I can't figure which.

SPL stops booting at the twisted feedback line in function genrand_int32().

Here is the code of the hwinit-common.h in arch/arm/cpu/armv7/omap-common/:


#include <common.h>
#include <asm/io.h>
#include <asm/arch/sys_proto.h>
#include <asm/sizes.h>
#include <asm/emif.h>
#include <asm/omap_common.h>

/* Period parameters */
#define N 624
#define M 397
#define MATRIX_A 0x9908b0dfUL   /* constant vector a */
#define UPPER_MASK 0x80000000UL /* most significant w-r bits */
#define LOWER_MASK 0x7fffffffUL /* least significant r bits */

static unsigned long x[N];      /* the array for the state vector  */
static unsigned long *p0, *p1, *pm;


DECLARE_GLOBAL_DATA_PTR;

/*
   initialize MT with a seed
*/
void init_genrand(unsigned long s)
{
  int i;

  x[0] = s & 0xffffffffUL;
  for (i = 1; i < N; ++i) {
    x[i] = (1812433253UL * (x[i - 1] ^ (x[i - 1] >> 30)) + i)
      & 0xffffffffUL;           /* for >32 bit machines */
  }
  p0 = x;
  p1 = x + 1;
  pm = x + M;
}

/*
   initialize by an array with array-length
   init_key is the array for initializing keys
   key_length is its length
*/
void init_by_array(unsigned long init_key[], int key_length)
{
  int i, j, k;

  init_genrand(19650218UL);
  i = 1;
  j = 0;
  for (k = (N > key_length ? N : key_length); k; --k) {
    /* non linear */
    x[i] = ((x[i] ^ ((x[i - 1] ^ (x[i - 1] >> 30)) * 1664525UL))
            + init_key[j] + j) & 0xffffffffUL;  /* for WORDSIZE > 32
machines */
    if (++i >= N) {
      x[0] = x[N - 1];
      i = 1;
    }
    if (++j >= key_length) {
      j = 0;
    }
  }
  for (k = N - 1; k; --k) {
    /* non linear */
    x[i] = ((x[i] ^ ((x[i - 1] ^ (x[i - 1] >> 30)) * 1566083941UL)) - i)
      & 0xffffffffUL;           /* for WORDSIZE > 32 machines */
    if (++i >= N) {
      x[0] = x[N - 1];
      i = 1;
    }
  }
  x[0] = 0x80000000UL;          /* MSB is 1; assuring non-zero initial
array */
}

/* generates a random number on the interval [0,0xffffffff] */
unsigned long genrand_int32(void)
{
  unsigned long y;


  if (!p0) {
    /* Default seed */
    init_genrand(5489UL);
  }

  /* Twisted feedback -- HERE WE GET STUCK*/
  y = *p0 = *pm++ ^ (((*p0 & UPPER_MASK) | (*p1 & LOWER_MASK)) >> 1)
    ^ (-(*p1 & 1) & MATRIX_A);
  p0 = p1++;

  if (pm == x + N) {
    pm = x;
  }

  if (p1 == x + N) {
    p1 = x;
  }
  /* Temper */

  y ^= y >> 11;
  y ^= y << 7 & 0x9d2c5680UL;
  y ^= y << 15 & 0xefc60000UL;
  y ^= y >> 18;
  return y;
}

void do_set_mux(u32 base, struct pad_conf_entry const *array, int size)
{
    int i;
    struct pad_conf_entry *pad = (struct pad_conf_entry *) array;

    for (i = 0; i < size; i++, pad++)
        writew(pad->val, base + pad->offset);
}

static void set_mux_conf_regs(void)
{
    switch (omap_hw_init_context()) {
    case OMAP_INIT_CONTEXT_SPL:
        set_muxconf_regs_essential();
        break;
    case OMAP_INIT_CONTEXT_UBOOT_AFTER_SPL:
#ifdef CONFIG_SYS_ENABLE_PADS_ALL
        set_muxconf_regs_non_essential();
#endif
        break;
    case OMAP_INIT_CONTEXT_UBOOT_FROM_NOR:
    case OMAP_INIT_CONTEXT_UBOOT_AFTER_CH:
        set_muxconf_regs_essential();
#ifdef CONFIG_SYS_ENABLE_PADS_ALL
        set_muxconf_regs_non_essential();
#endif
        break;
    }
}

u32 cortex_rev(void)
{

    unsigned int rev;

    /* Read Main ID Register (MIDR) */
    asm ("mrc p15, 0, %0, c0, c0, 0" : "=r" (rev));

    return rev;
}

void omap_rev_string(void)
{
    u32 omap_rev = omap_revision();
    u32 omap_variant = (omap_rev & 0xFFFF0000) >> 16;
    u32 major_rev = (omap_rev & 0x00000F00) >> 8;
    u32 minor_rev = (omap_rev & 0x000000F0) >> 4;

    printf("OMAP%x ES%x.%x\n", omap_variant, major_rev,
        minor_rev);
}

#ifdef CONFIG_SPL_BUILD
static void init_boot_params(void)
{
    boot_params_ptr = (u32 *) &boot_params;
}
#endif

/*
 * Routine: s_init
 * Description: Does early system init of watchdog, muxing,  andclocks
 * Watchdog disable is done always. For the rest what gets done
 * depends on the boot mode in which this function is executed
 *   1. s_init of SPL running from SRAM
 *   2. s_init of U-Boot running from FLASH
 *   3. s_init of U-Boot loaded to SDRAM by SPL
 *   4. s_init of U-Boot loaded to SDRAM by ROM code using the
 *    Configuration Header feature
 * Please have a look at the respective functions to see what gets
 * done in each of these cases
 * This function is called with SRAM stack.
 */
void s_init(void)
{
    init_omap_revision();
    watchdog_init();
    set_mux_conf_regs();
#ifdef CONFIG_SPL_BUILD
    setup_clocks_for_console();
    preloader_console_init();

 
    unsigned char current_rn_char;
    unsigned long current_rn;
    int i = 0;
    unsigned long init[4] = { 0x123, 0x234, 0x345, 0x456 }, length = 4;

    // Start PRNG
    init_by_array(init, length);

    for (i=0; i<22; i++){
        current_rn = genrand_real1();
        current_rn_char = (char)current_rn;
        secret[i] = current_rn_char;
    }

    secret[22] = 0x00;
    printf("\nmeh2\n");
    printf("\n[I] - These are our secret bytes (%d
bytes):\n\t==================================\n\t", sizeof(secret));
    i = 0;   
    while(secret[i]!=0x0){
        printf("0x%02x ", secret[i]);
        i++;
    }
    printf("\n\t==================================\n");
   
    do_io_settings();
#endif
    prcm_init();
#ifdef CONFIG_SPL_BUILD
    timer_init();

    /* For regular u-boot sdram_init() is called from dram_init() */
    sdram_init();
    init_boot_params();
#endif
}

/*
 * Routine: wait_for_command_complete
 * Description: Wait for posting to finish on watchdog
 */
void wait_for_command_complete(struct watchdog *wd_base)
{
    int pending = 1;
    do {
        pending = readl(&wd_base->wwps);
    } while (pending);
}

/*
 * Routine: watchdog_init
 * Description: Shut down watch dogs
 */
void watchdog_init(void)
{
    struct watchdog *wd2_base = (struct watchdog *)WDT2_BASE;

    writel(WD_UNLOCK1, &wd2_base->wspr);
    wait_for_command_complete(wd2_base);
    writel(WD_UNLOCK2, &wd2_base->wspr);
}


/*
 * This function finds the SDRAM size available in the system
 * based on DMM section configurations
 * This is needed because the size of memory installed may be
 * different on different versions of the board
 */
u32 omap_sdram_size(void)
{
    u32 section, i, total_size = 0, size, addr;

    for (i = 0; i < 4; i++) {
        section    = __raw_readl(DMM_BASE + i*4);
        addr = section & EMIF_SYS_ADDR_MASK;
        /* See if the address is valid */
        if ((addr >= DRAM_ADDR_SPACE_START) &&
            (addr < DRAM_ADDR_SPACE_END)) {
            size = ((section & EMIF_SYS_SIZE_MASK) >>
                   EMIF_SYS_SIZE_SHIFT);
            size = 1 << size;
            size *= SZ_16M;
            total_size += size;
        }
    }

    return total_size;
}


/*
 * Routine: dram_init
 * Description: sets uboots idea of sdram size
 */
int dram_init(void)
{
    sdram_init();
    gd->ram_size = omap_sdram_size();
    return 0;
}

/*
 * Print board information
 */
int checkboard(void)
{
    puts(sysinfo.board_string);
    return 0;
}

/*
* This function is called by start_armboot. You can reliably use static
* data. Any boot-time function that require static data should be
* called from here
*/
int arch_cpu_init(void)
{
    return 0;
}

/*
 *  get_device_type(): tell if GP/HS/EMU/TST
 */
u32 get_device_type(void)
{
    return 0;
}

/*
 * Print CPU information
 */
int print_cpuinfo(void)
{
    puts("CPU  : ");
    omap_rev_string();

    return 0;
}

/*
 * this uses the unique per-cpu info from the cpu fuses set at factory to
 * generate a 6-byte MAC address.  Two bits in the generated code are used
 * to elaborate the generated address into four, so it can be used on
multiple
 * network interfaces.
 */
void omap4_die_id_to_ethernet_mac(u8 *mac, int subtype)
{
    struct ctrl_id *id_base = (struct ctrl_id *)(CTRL_BASE + 0x200);
    u32 idcode;
    u32 id[4];

    idcode = readl(&id_base->idcode);
    id[0] = readl(&id_base->die_id_0);
    id[1] = readl(&id_base->die_id_1);
    id[2] = readl(&id_base->die_id_2);
    id[3] = readl(&id_base->die_id_3);

    mac[0] = id[2];
    mac[1] = id[2] >> 8;
    mac[2] = id[1];
    mac[3] = id[1] >> 8;
    mac[4] = id[1] >> 16;
    mac[5] = id[1] >> 24;
    /* XOR other chip-specific data with ID */
    idcode ^= id[3];

    mac[0] ^= idcode;
    mac[1] ^= idcode >> 8;
    mac[2] ^= idcode >> 16;
    mac[3] ^= idcode >> 24;

    /* allow four MACs from this same basic data */
    mac[1] = (mac[1] & ~0xc0) | ((subtype & 3) << 6);

    /* mark it as not multicast and outside official 80211 MAC namespace */
    mac[0] = (mac[0] & ~1) | 2;
}

#ifndef CONFIG_SYS_DCACHE_OFF
void enable_caches(void)
{
    /* Enable D-cache. I-cache is already enabled in start.S */
    dcache_enable();
}
#endif


More information about the U-Boot mailing list