512M内存, 地址范围 [0x80000000, 0xA0000000)

 UBOOT原先位置 0x87800000, 移动后的位置0x9FF47000,   也就是最后 700多k,  前面的位置留给内核

https://www.cnblogs.com/kehuadong/p/14054220.html  中说到main调用了board_init_f, 参数0

common/board_f.c 中的 board_init_f

void board_init_f(ulong boot_flags)
{
#ifdef CONFIG_SYS_GENERIC_GLOBAL_DATA
  /*
  * For some archtectures, global data is initialized and used before
  * calling this function. The data should be preserved. For others,
  * CONFIG_SYS_GENERIC_GLOBAL_DATA should be defined and use the stack
  * here to host global data until relocation.
  */
  gd_t data;

  gd = &data;

  /*
  * Clear global data before it is accessed at debug print
  * in initcall_run_list. Otherwise the debug print probably
  * get the wrong vaule of gd->have_console.
  */
  zero_global_data();
#endif

  gd->flags = boot_flags;
  gd->have_console = 0;

  if (initcall_run_list(init_sequence_f))
    hang();

#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) && \
!defined(CONFIG_EFI_APP)
  /* NOTREACHED - jump_to_copy() does not return */
  hang();
#endif

  /* Light up LED1 */
  imx6_light_up_led1();
}

 

static init_fnc_t init_sequence_f[] = {
#ifdef CONFIG_SANDBOX
  setup_ram_buf,
#endif
  setup_mon_len,
#ifdef CONFIG_OF_CONTROL
  fdtdec_setup,
#endif
#ifdef CONFIG_TRACE
  trace_early_init,
#endif
  initf_malloc,
  initf_console_record,
#if defined(CONFIG_MPC85xx) || defined(CONFIG_MPC86xx)
  /* TODO: can this go into arch_cpu_init()? */
  probecpu,
#endif
#if defined(CONFIG_X86) && defined(CONFIG_HAVE_FSP)
  x86_fsp_init,
#endif
  arch_cpu_init, /* basic arch cpu dependent setup */
  initf_dm,
  arch_cpu_init_dm,
  mark_bootstage, /* need timer, go after init dm */
#if defined(CONFIG_BOARD_EARLY_INIT_F)
  board_early_init_f,
#endif
/* TODO: can any of this go into arch_cpu_init()? */
#if defined(CONFIG_PPC) && !defined(CONFIG_8xx_CPUCLK_DEFAULT)
  get_clocks, /* get CPU and bus clocks (etc.) */
  #if defined(CONFIG_TQM8xxL) && !defined(CONFIG_TQM866M) \
    && !defined(CONFIG_TQM885D)
    adjust_sdram_tbs_8xx,
  #endif
  /* TODO: can we rename this to timer_init()? */
  init_timebase,
#endif
#if defined(CONFIG_ARM) || defined(CONFIG_MIPS) || \
defined(CONFIG_BLACKFIN) || defined(CONFIG_NDS32) || \
defined(CONFIG_SPARC)
  timer_init, /* initialize timer */
#endif
#ifdef CONFIG_SYS_ALLOC_DPRAM
  #if !defined(CONFIG_CPM2)
    dpram_init,
  #endif
#endif
#if defined(CONFIG_BOARD_POSTCLK_INIT)
  board_postclk_init,
#endif
#if defined(CONFIG_SYS_FSL_CLK) || defined(CONFIG_M68K)
  get_clocks,
#endif
  env_init, /* initialize environment */
#if defined(CONFIG_8xx_CPUCLK_DEFAULT)
  /* get CPU and bus clocks according to the environment variable */
  get_clocks_866,
  /* adjust sdram refresh rate according to the new clock */
  sdram_adjust_866,
  init_timebase,
#endif
  init_baud_rate, /* initialze baudrate settings */
  serial_init, /* serial communications setup */
  console_init_f, /* stage 1 init of console */
#ifdef CONFIG_SANDBOX
  sandbox_early_getopt_check,
#endif
#ifdef CONFIG_OF_CONTROL
  fdtdec_prepare_fdt,
#endif
  display_options, /* say that we are here */
  display_text_info, /* show debugging info if required */
#if defined(CONFIG_MPC8260)
  prt_8260_rsr,
  prt_8260_clks,
#endif /* CONFIG_MPC8260 */
#if defined(CONFIG_MPC83xx)
  prt_83xx_rsr,
#endif
#if defined(CONFIG_PPC) || defined(CONFIG_M68K)
  checkcpu,
#endif
  print_cpuinfo, /* display cpu info (and speed) */
#if defined(CONFIG_MPC5xxx)
  prt_mpc5xxx_clks,
#endif /* CONFIG_MPC5xxx */
#if defined(CONFIG_DISPLAY_BOARDINFO)
  show_board_info,
#endif
INIT_FUNC_WATCHDOG_INIT
#if defined(CONFIG_MISC_INIT_F)
  misc_init_f,
#endif
  INIT_FUNC_WATCHDOG_RESET
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SYS_I2C)
  init_func_i2c,
#endif
#if defined(CONFIG_HARD_SPI)
  init_func_spi,
#endif
  announce_dram_init,
/* TODO: unify all these dram functions? */
#if defined(CONFIG_ARM) || defined(CONFIG_X86) || defined(CONFIG_NDS32) || \
defined(CONFIG_MICROBLAZE) || defined(CONFIG_AVR32)
  dram_init, /* configure available RAM banks */
#endif
#if defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_M68K)
  init_func_ram,
#endif
#ifdef CONFIG_POST
  post_init_f,
#endif
  INIT_FUNC_WATCHDOG_RESET
#if defined(CONFIG_SYS_DRAM_TEST)
  testdram,
#endif /* CONFIG_SYS_DRAM_TEST */
  INIT_FUNC_WATCHDOG_RESET

#ifdef CONFIG_POST
  init_post,
#endif
  INIT_FUNC_WATCHDOG_RESET
  /*
  * Now that we have DRAM mapped and working, we can
  * relocate the code and continue running from DRAM.
  *
  * Reserve memory at end of RAM for (top down in that order):
  * - area that won't get touched by U-Boot and Linux (optional)
  * - kernel log buffer
  * - protected RAM
  * - LCD framebuffer
  * - monitor code
  * - board info struct
  */
  setup_dest_addr,
#if defined(CONFIG_BLACKFIN)
  /* Blackfin u-boot monitor should be on top of the ram */
  reserve_uboot,
#endif
#if defined(CONFIG_SPARC)
  reserve_prom,
#endif
#if defined(CONFIG_LOGBUFFER) && !defined(CONFIG_ALT_LB_ADDR)
  reserve_logbuffer,
#endif
#ifdef CONFIG_PRAM
  reserve_pram,
#endif
  reserve_round_4k,
#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF)) && \
defined(CONFIG_ARM)
  reserve_mmu,
#endif
#ifdef CONFIG_DM_VIDEO
  reserve_video,
#else
  # ifdef CONFIG_LCD
    reserve_lcd,
  # endif
  /* TODO: Why the dependency on CONFIG_8xx? */
  # if defined(CONFIG_VIDEO) && (!defined(CONFIG_PPC) || defined(CONFIG_8xx)) && \
    !defined(CONFIG_ARM) && !defined(CONFIG_X86) && \
    !defined(CONFIG_BLACKFIN) && !defined(CONFIG_M68K)
    reserve_legacy_video,
  # endif
#endif /* CONFIG_DM_VIDEO */
  reserve_trace,
#if !defined(CONFIG_BLACKFIN)
  reserve_uboot,
#endif
#ifndef CONFIG_SPL_BUILD
  reserve_malloc,
  reserve_board,
#endif
  setup_machine,
  reserve_global_data,
  reserve_fdt,
  reserve_arch,
  reserve_stacks,
  setup_dram_config,
  show_dram_config,
#if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_MIPS)
  setup_board_part1,
#endif
#if defined(CONFIG_PPC) || defined(CONFIG_M68K)
  INIT_FUNC_WATCHDOG_RESET
  setup_board_part2,
#endif
  display_new_sp,
#ifdef CONFIG_SYS_EXTBDINFO
  setup_board_extra,
#endif
  INIT_FUNC_WATCHDOG_RESET
  reloc_fdt,
  setup_reloc,
#if defined(CONFIG_X86) || defined(CONFIG_ARC)
  copy_uboot_to_ram,
  clear_bss,
  do_elf_reloc_fixups,
#endif
#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX)
  jump_to_copy,
#endif
  NULL,
};

 

设置 gd 的 mon_len 成员变量,此处为__bss_end -_start,也就是整个代码的长度。0X878A8E74-0x87800000=0XA8E74=691,828

common/board_f.c

static int setup_mon_len(void)
{
#if defined(__ARM__) || defined(__MICROBLAZE__)
  gd->mon_len = (ulong)&__bss_end - (ulong)_start;
#elif defined(CONFIG_SANDBOX) || defined(CONFIG_EFI_APP)
  gd->mon_len = (ulong)&_end - (ulong)_init;
#elif defined(CONFIG_BLACKFIN) || defined(CONFIG_NIOS2)
  gd->mon_len = CONFIG_SYS_MONITOR_LEN;
#elif defined(CONFIG_NDS32)
  gd->mon_len = (ulong)(&__bss_end) - (ulong)(&_start);
#else
  /* TODO: use (ulong)&__bss_end - (ulong)&__text_start; ? */
  gd->mon_len = (ulong)&__bss_end - CONFIG_SYS_MONITOR_BASE;
#endif
  return 0;
}

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
. = 0x00000000;
. = ALIGN(4);
.text :
{
*(.__image_copy_start)
*(.vectors)  _start在这里
arch/arm/cpu/armv7/start.o (.text*)
*(.text*)
}
. = ALIGN(4);
.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : {
*(.data*)
}
. = ALIGN(4);
. = .;
. = ALIGN(4);
.u_boot_list : {
KEEP(*(SORT(.u_boot_list*)));
}
. = ALIGN(4);
.image_copy_end :
{
*(.__image_copy_end)
}
.rel_dyn_start :
{
*(.__rel_dyn_start)
}
.rel.dyn : {
*(.rel*)
}
.rel_dyn_end :
{
*(.__rel_dyn_end)
}
.end :
{
*(.__end)
}
_image_binary_end = .;
. = ALIGN(4096);
.mmutable : {
*(.mmutable)
}
.bss_start __rel_dyn_start (OVERLAY) : {
KEEP(*(.__bss_start));
__bss_base = .;
}
.bss __bss_base (OVERLAY) : {
*(.bss*)
. = ALIGN(4);
__bss_limit = .;
}
.bss_end __bss_limit (OVERLAY) : {
KEEP(*(.__bss_end));    _bss_end在这里
}

initf_malloc 函数初始化 gd 中跟 malloc 有关的成员变量,比如 malloc_limit,此函数会设置 g
d->malloc_limit = CONFIG_SYS_MALLOC_F_LEN=0X400。malloc_limit 表示 malloc内存池大小

common/dlmalloc.c

int initf_malloc(void)
{
#ifdef CONFIG_SYS_MALLOC_F_LEN
  assert(gd->malloc_base); /* Set up by crt0.S */
  gd->malloc_limit = CONFIG_SYS_MALLOC_F_LEN;  // board_init_f_init_reserve中所预留的动态分配空间, 4*0x100=1k
  gd->malloc_ptr = 0;
#endif

  return 0;
}

initf_console_record , 如 果 定 义 了 宏 CONFIG_CONSOLE_RECORD 和 宏CONFIG_SYS_MALLOC_F_LEN 的话此函数就会调用函数 console_record_init,
但是 IMX6ULL的 uboot 没有定义宏 CONFIG_CONSOLE_RECORD,所以此函数直接返回 0。

common/board_f.c

static int initf_console_record(void)
{
#if defined(CONFIG_CONSOLE_RECORD) && defined(CONFIG_SYS_MALLOC_F_LEN)
  return console_record_init();  // 不到这里,因为IMX6ULL没定义CONFIG_CONSOLE_RECORD
#else
  return 0;
#endif
}

  
第 5 行,arch_cpu_init 函数。
arch/arm/cpu/armv7/mx6/soc.c

int arch_cpu_init(void)
{
  if (!is_cpu_type(MXC_CPU_MX6SL) && !is_cpu_type(MXC_CPU_MX6SX)
    && !is_cpu_type(MXC_CPU_MX6UL) && !is_cpu_type(MXC_CPU_MX6ULL)
    && !is_cpu_type(MXC_CPU_MX6SLL)) {
    /*
    * imx6sl doesn't have pcie at all.
    * this bit is not used by imx6sx anymore
    */
    u32 val;

    /*
    * There are about 0.02% percentage, random pcie link down
    * when warm-reset is used.
    * clear the ref_ssp_en bit16 of gpr1 to workaround it.
    * then warm-reset imx6q/dl/solo again.
    */
    val = readl(IOMUXC_BASE_ADDR + 0x4);
    if (val & (0x1 << 16)) {
      val &= ~(0x1 << 16);
      writel(val, IOMUXC_BASE_ADDR + 0x4);
      reset_cpu(0);
    }
  }

  init_aips();

  /* Need to clear MMDC_CHx_MASK to make warm reset work. */
  clear_mmdc_ch_mask();

  /*
  * Disable self-bias circuit in the analog bandap.
  * The self-bias circuit is used by the bandgap during startup.
  * This bit should be set after the bandgap has initialized.
  */
  init_bandgap();

  if (!is_cpu_type(MXC_CPU_MX6UL) && !is_cpu_type(MXC_CPU_MX6ULL)) {
    /*
    * When low freq boot is enabled, ROM will not set AHB
    * freq, so we need to ensure AHB freq is 132MHz in such
    * scenario.
    */
    if (mxc_get_clock(MXC_ARM_CLK) == 396000000)
      set_ahb_rate(132000000);
  }

  if (is_cpu_type(MXC_CPU_MX6UL)) {
    if (is_soc_rev(CHIP_REV_1_0)) {
      /*
      * According to the design team's requirement on i.MX6UL,
      * the PMIC_STBY_REQ PAD should be configured as open
      * drain 100K (0x0000b8a0).
      */
      writel(0x0000b8a0, IOMUXC_BASE_ADDR + 0x29c);
    } else {
      /*
      * From TO1.1, SNVS adds internal pull up control for POR_B,
      * the register filed is GPBIT[1:0], after system boot up,
      * it can be set to 2b'01 to disable internal pull up.
      * It can save about 30uA power in SNVS mode.
      */
      writel((readl(MX6UL_SNVS_LP_BASE_ADDR + 0x10) & (~0x1400)) | 0x400,
      MX6UL_SNVS_LP_BASE_ADDR + 0x10);
    }
  }

  if (is_cpu_type(MXC_CPU_MX6ULL)) {
    /*
    * GPBIT[1:0] is suggested to set to 2'b11:
    * 2'b00 : always PUP100K
    * 2'b01 : PUP100K when PMIC_ON_REQ or SOC_NOT_FAIL
    * 2'b10 : always disable PUP100K
    * 2'b11 : PDN100K when SOC_FAIL, PUP100K when SOC_NOT_FAIL
    * register offset is different from i.MX6UL, since
    * i.MX6UL is fixed by ECO.
    */
    writel(readl(MX6UL_SNVS_LP_BASE_ADDR) |0x3, MX6UL_SNVS_LP_BASE_ADDR);
  }

  /* Set perclk to source from OSC 24MHz */
#if defined(CONFIG_MX6SL)
  set_preclk_from_osc();
#endif

  if (is_cpu_type(MXC_CPU_MX6SX))
    set_uart_from_osc();

  imx_set_wdog_powerdown(false); /* Disable PDE bit of WMCR register */

  if (!is_cpu_type(MXC_CPU_MX6SL) && !is_cpu_type(MXC_CPU_MX6UL) &&
    !is_cpu_type(MXC_CPU_MX6ULL) && !is_cpu_type(MXC_CPU_MX6SLL))
    imx_set_pcie_phy_power_down();

  if (!is_mx6dqp() && !is_cpu_type(MXC_CPU_MX6UL) &&
    !is_cpu_type(MXC_CPU_MX6ULL) && !is_cpu_type(MXC_CPU_MX6SLL))
    imx_set_vddpu_power_down();

#ifdef CONFIG_APBH_DMA
  /* Start APBH DMA */
  mxs_dma_init();
#endif

  init_src();

  if (is_mx6dqp())
    writel(0x80000201, 0xbb0608);

  return 0;
}

 
initf_dm 函数,驱动模型的一些初始化。

common/board_f.c

static int initf_dm(void)
{
#if defined(CONFIG_DM) && defined(CONFIG_SYS_MALLOC_F_LEN)
  int ret;

  ret = dm_init_and_scan(true);
  if (ret)
    return ret;
#endif
#ifdef CONFIG_TIMER_EARLY
  ret = dm_timer_init();
  if (ret)
    return ret;
#endif

  return 0;
}

 
arch_cpu_init_dm 函数未实现。

common/board_f.c

__weak int arch_cpu_init_dm(void)
{
  return 0;
}

 

 
mark_bootstage 函数应该是和啥标记有关的

common/board_f.c

static int mark_bootstage(void)
{
  bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_F, "board_init_f");

  return 0;
}

 
board_early_init_f 函数,板子相关的早期的一些初始化设置,I.MX6ULL 用来初始化串口的 IO 配置
board/freescale/mx6ullevk/mx6ullevk.c

int board_early_init_f(void)
{
  setup_iomux_uart();

  return 0;
}

 
timer_init,初始化定时器,Cortex-A7 内核有一个定时器,这里初始化的就是 Cortex-A 内核的那个定时器

arch/arm/imx-common/tiemr.c

int timer_init(void)
{
  int i;

  /* setup GP Timer 1 */
  __raw_writel(GPTCR_SWR, &cur_gpt->control);

  /* We have no udelay by now */
  for (i = 0; i < 100; i++)
    __raw_writel(0, &cur_gpt->control);

  i = __raw_readl(&cur_gpt->control);
  i &= ~GPTCR_CLKSOURCE_MASK;

#ifdef CONFIG_MXC_GPT_HCLK
  if (gpt_has_clk_source_osc()) {
    i |= GPTCR_CLKSOURCE_OSC | GPTCR_TEN;

    /* For DL/S, SX, UL, ULL set 24Mhz OSC Enable bit and prescaler */
    if (is_cpu_type(MXC_CPU_MX6DL) ||
      is_cpu_type(MXC_CPU_MX6SOLO) ||
      is_cpu_type(MXC_CPU_MX6SX) ||
      is_cpu_type(MXC_CPU_MX7D) ||
      is_cpu_type(MXC_CPU_MX6UL) ||
      is_cpu_type(MXC_CPU_MX6ULL) ||
      is_cpu_type(MXC_CPU_MX6SLL)) {
      i |= GPTCR_24MEN;

      /* Produce 3Mhz clock */
      __raw_writel((7 << GPTPR_PRESCALER24M_SHIFT),
        &cur_gpt->prescaler);
    }
  } else {
    i |= GPTCR_CLKSOURCE_PRE | GPTCR_TEN;
  }
#else
  __raw_writel(0, &cur_gpt->prescaler); /* 32Khz */
  i |= GPTCR_CLKSOURCE_32 | GPTCR_TEN;
#endif
  __raw_writel(i, &cur_gpt->control);

  gd->arch.tbl = __raw_readl(&cur_gpt->counter);
  gd->arch.tbu = 0;

  return 0;
}

 

board_postclk_init,对于 I.MX6ULL 来说是设置 VDDSOC 电压。
arch/arm/cpu/armv7/mx6/soc.c
int board_postclk_init(void)

{
  /* NO LDO SOC on i.MX6SLL */
  if (is_cpu_type(MXC_CPU_MX6SLL))
  return 0;

  set_ldo_voltage(LDO_SOC, 1175); /* Set VDDSOC to 1.175V */

  return 0;
}

 
 
get_clocks 函数用于获取一些时钟值,I.MX6ULL 获取的是 sdhc_clk 时钟,也就是 SD 卡外设的时钟。

arch/arm/imx-common/speed.c

int get_clocks(void)

{
#ifdef CONFIG_FSL_ESDHC
  #ifdef CONFIG_FSL_USDHC
    #if CONFIG_SYS_FSL_ESDHC_ADDR == USDHC2_BASE_ADDR
      gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK);
    #elif CONFIG_SYS_FSL_ESDHC_ADDR == USDHC3_BASE_ADDR
      gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC3_CLK);
    #elif CONFIG_SYS_FSL_ESDHC_ADDR == USDHC4_BASE_ADDR
      gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC4_CLK);
    #else
      gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC_CLK);
    #endif
  #else
    #if CONFIG_SYS_FSL_ESDHC_ADDR == MMC_SDHC2_BASE_ADDR
      gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK);
    #elif CONFIG_SYS_FSL_ESDHC_ADDR == MMC_SDHC3_BASE_ADDR
      gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC3_CLK);
    #elif CONFIG_SYS_FSL_ESDHC_ADDR == MMC_SDHC4_BASE_ADDR
      gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC4_CLK);
    #else
      gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC_CLK);
    #endif
  #endif
#endif
  return 0;
}

  
env_init 函数是和环境变量有关的,设置 gd 的成员变量 env_addr,也就是环境变
量的保存地址。

common/env_mmc.c

int env_init(void)
{
  /* use default */
  gd->env_addr = (ulong)&default_environment[0];
  gd->env_valid = 1;

  return 0;
}

 

 
init_baud_rate 函数用于初始化波特率,根据环境变量 baudrate 来初始化 gd->baudrate。
common/board_f.c

static int init_baud_rate(void)
{
  gd->baudrate = getenv_ulong("baudrate", 10, CONFIG_BAUDRATE);
  return 0;
}

 
第 15 行,serial_init,初始化串口。
driver/serial/serial.c

int serial_init(void)
{
  gd->flags |= GD_FLG_SERIAL_READY;
  return get_current()->start();
}

 
console_init_f,设置 gd->have_console 为 1,表示有个控制台,此函数也将前面暂存在缓冲区中的数据通过控制台打印出来。
common/console.c

int console_init_f(void)
{
  gd->have_console = 1;

#ifdef CONFIG_SILENT_CONSOLE
  if (getenv("silent") != NULL)
    gd->flags |= GD_FLG_SILENT;
#endif

  print_pre_console_buffer(PRE_CONSOLE_FLUSHPOINT1_SERIAL);

  return 0;
}

 
display_options,通过串口输出一些信息

common/board_f.c

int display_options (void)
{
#if defined(BUILD_TAG)
  printf ("\n\n%s, Build: %s\n\n", version_string, BUILD_TAG);
#else
  printf ("\n\n%s\n\n", version_string);
#endif
  return 0;
}

 
display_text_info,打印一些文本信息,如果开启 UBOOT 的 DEBUG 功能的话就
会输出 text_base、bss_start、bss_end,形式如下:
debug("U-Boot code: %08lX -> %08lX BSS: -> %08lX\n",text_base, bss_start, bss_end);
common/board_f.c

static int display_text_info(void)
{
#if !defined(CONFIG_SANDBOX) && !defined(CONFIG_EFI_APP)
  ulong bss_start, bss_end, text_base;

  bss_start = (ulong)&__bss_start;
  bss_end = (ulong)&__bss_end;

#ifdef CONFIG_SYS_TEXT_BASE
  text_base = CONFIG_SYS_TEXT_BASE;
#else
  text_base = CONFIG_SYS_MONITOR_BASE;
#endif

  debug("U-Boot code: %08lX -> %08lX BSS: -> %08lX\n",
    text_base, bss_start, bss_end);
#endif

#ifdef CONFIG_USE_IRQ
  debug("IRQ Stack: %08lx\n", IRQ_STACK_START);
  debug("FIQ Stack: %08lx\n", FIQ_STACK_START);
#endif

  return 0;
}

注意到setup_mon_len的_bss_end是878A8E74, 而这里的打印是878B1EF8, 因此需要实测去验证

 

print_cpuinfo 函数用于打印 CPU 信息
arch/arm/imx-common/cpu.c

int print_cpuinfo(void)
{
  u32 cpurev;
  __maybe_unused u32 max_freq;
#if defined(CONFIG_DBG_MONITOR)
  struct dbg_monitor_regs *dbg =
    (struct dbg_monitor_regs *)DEBUG_MONITOR_BASE_ADDR;
#endif

  cpurev = get_cpu_rev();

#if defined(CONFIG_IMX_THERMAL)
  struct udevice *thermal_dev;
  int cpu_tmp, minc, maxc, ret;

  printf("CPU: Freescale i.MX%s rev%d.%d",
    get_imx_type((cpurev & 0xFF000) >> 12),
    (cpurev & 0x000F0) >> 4,
    (cpurev & 0x0000F) >> 0);
  max_freq = get_cpu_speed_grade_hz();
  if (!max_freq || max_freq == mxc_get_clock(MXC_ARM_CLK)) {
    printf(" at %dMHz\n", mxc_get_clock(MXC_ARM_CLK) / 1000000);
  } else {
    printf(" %d MHz (running at %d MHz)\n", max_freq / 1000000,
      mxc_get_clock(MXC_ARM_CLK) / 1000000);
  }
#else
  printf("CPU: Freescale i.MX%s rev%d.%d at %d MHz\n",
    get_imx_type((cpurev & 0xFF000) >> 12),
    (cpurev & 0x000F0) >> 4,
    (cpurev & 0x0000F) >> 0,
    mxc_get_clock(MXC_ARM_CLK) / 1000000);
#endif

#if defined(CONFIG_IMX_THERMAL)
  puts("CPU: ");
  switch (get_cpu_temp_grade(&minc, &maxc)) {
  case TEMP_AUTOMOTIVE:
    puts("Automotive temperature grade ");
    break;
  case TEMP_INDUSTRIAL:
    puts("Industrial temperature grade ");
    break;
  case TEMP_EXTCOMMERCIAL:
    puts("Extended Commercial temperature grade ");
    break;
  default:
    puts("Commercial temperature grade ");
    break;
  }
  printf("(%dC to %dC)", minc, maxc);
  ret = uclass_get_device(UCLASS_THERMAL, 0, &thermal_dev);
  if (!ret) {
    ret = thermal_get_temp(thermal_dev, &cpu_tmp);

    if (!ret)
      printf(" at %dC\n", cpu_tmp);
    else
      debug(" - invalid sensor data\n");
  } else {
    debug(" - invalid sensor device\n");
  }
#endif

#if defined(CONFIG_DBG_MONITOR)
  if (readl(&dbg->snvs_addr))
    printf("DBG snvs regs addr 0x%x, data 0x%x, info 0x%x\n",
      readl(&dbg->snvs_addr),
      readl(&dbg->snvs_data),
      readl(&dbg->snvs_info));
#endif

  printf("Reset cause: %s\n", get_reset_cause());
  return 0;
}

 
show_board_info 函数用于打印板子信息,会调用 checkboard 函数

common/board_info.c

int show_board_info(void)
{
#if defined(CONFIG_OF_CONTROL) && !defined(CONFIG_CUSTOM_BOARDINFO)
  DECLARE_GLOBAL_DATA_PTR;
  const char *model;

  model = fdt_getprop(gd->fdt_blob, 0, "model", NULL);

  if (model)
    printf("Model: %s\n", model);
#endif

  return checkboard();
}

 

INIT_FUNC_WATCHDOG_INIT,初始化看门狗,对于 I.MX6ULL 来说是空函数
 
INIT_FUNC_WATCHDOG_RESET,复位看门狗,对于 I.MX6ULL 来说是空函数 
 
init_func_i2c 函数用于初始化 I2C,

common/board_f.c

static int init_func_i2c(void)
{
  puts("I2C: ");
#ifdef CONFIG_SYS_I2C
  i2c_init_all();
#else
  i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
#endif
  puts("ready\n");
  return 0;
}

  

announce_dram_init,此函数很简单,就是输出字符串“DRAM:”

common/board_f.c

static int announce_dram_init(void)
{
  puts("DRAM: ");
  return 0;
}

 
dram_init,并非真正的初始化 DDR,只是设置 gd->ram_size 的值,对于正点原子 I.MX6ULL 开发板 EMMC 版本核心板来说就是 512MB。
 board/freescale/mx6ullevk/mx6ullevk.c

int dram_init(void)
{
  gd->ram_size = imx_ddr_size();

  return 0;
}

arch/arm/imx-common/cpu.c

unsigned imx_ddr_size(void)
{
  struct esd_mmdc_regs *mem = (struct esd_mmdc_regs *)MEMCTL_BASE;
  unsigned ctl = readl(&mem->ctl);
  unsigned misc = readl(&mem->misc);
  int bits = 11 + 0 + 0 + 1; /* row + col + bank + width */

  bits += ESD_MMDC_CTL_GET_ROW(ctl);
  bits += col_lookup[ESD_MMDC_CTL_GET_COLUMN(ctl)];
  bits += bank_lookup[ESD_MMDC_MISC_GET_BANK(misc)];
  bits += ESD_MMDC_CTL_GET_WIDTH(ctl);
  bits += ESD_MMDC_CTL_GET_CS1(ctl);

  /* The MX6 can do only 3840 MiB of DRAM */
  if (bits == 32)
    return 0xf0000000;

  return 1 << bits;
}

 
 
post_init_f,此函数用来完成一些测试,初始化 gd->post_init_f_time

post/post.c

int post_init_f(void)
{
  int res = 0;
  unsigned int i;

  for (i = 0; i < post_list_size; i++) {
    struct post_test *test = post_list + i;

    if (test->init_f && test->init_f())
      res = -1;
  }

  gd->post_init_f_time = post_time_ms(0);
  if (!gd->post_init_f_time)
    printf("%s: post_time_ms not implemented\n", __FILE__);

  return res;
}

 
testdram,测试 DRAM,空函数。
 
 
setup_dest_addr函数,设置目的地址,设置gd->ram_size,gd->ram_top,gd->relocaddr
这三个的值。接下来我们会遇到很多跟数值有关的设置,如果直接看代码分析的话就太费时间
了,我可以修改 uboot 代码,直接将这些值通过串口打印出来,比如这里我们修改文件
common/board_f.c,因为 setup_dest_addr函数定义在文件 common/board_f.c 中
common/board_f.c

static int setup_dest_addr(void)
{
  debug("Monitor len: %08lX\n", gd->mon_len);
  /*
  * Ram is setup, size stored in gd !!
  */
  debug("Ram size: %08lX\n", (ulong)gd->ram_size);  // dram_init中初始化了ram_size
#ifdef CONFIG_SYS_MEM_RESERVE_SECURE
  /* Reserve memory for secure MMU tables, and/or security monitor */
  gd->ram_size -= CONFIG_SYS_MEM_RESERVE_SECURE;
  /*
  * Record secure memory location. Need recalcuate if memory splits
  * into banks, or the ram base is not zero.
  */
  gd->secure_ram = gd->ram_size;
#endif
  /*
  * Subtract specified amount of memory to hide so that it won't
  * get "touched" at all by U-Boot. By fixing up gd->ram_size
  * the Linux kernel should now get passed the now "corrected"
  * memory size and won't touch it either. This has been used
  * by arch/powerpc exclusively. Now ARMv8 takes advantage of
  * thie mechanism. If memory is split into banks, addresses
  * need to be calculated.
  */
  gd->ram_size = board_reserve_ram_top(gd->ram_size);

#ifdef CONFIG_SYS_SDRAM_BASE
  gd->ram_top = CONFIG_SYS_SDRAM_BASE;
#endif
  gd->ram_top += get_effective_memsize();
  gd->ram_top = board_get_usable_ram_top(gd->mon_len);
  gd->relocaddr = gd->ram_top;
  debug("Ram top: %08lX\n", (ulong)gd->ram_top);
#if defined(CONFIG_MP) && (defined(CONFIG_MPC86xx) || defined(CONFIG_E500))
  /*
  * We need to make sure the location we intend to put secondary core
  * boot code is reserved and not used by any part of u-boot
  */
  if (gd->relocaddr > determine_mp_bootpg(NULL)) {
    gd->relocaddr = determine_mp_bootpg(NULL);
    debug("Reserving MP boot page to %08lx\n", gd->relocaddr);
  }
#endif
  return 0;
}

 

 
reserve_round_4k 函数用于对 gd->relocaddr 做 4KB 对 齐 , 因 为
gd->relocaddr=0XA0000000,已经是 4K 对齐了,所以调整后不变。

common/board_f.c

static int reserve_round_4k(void)
{
  gd->relocaddr &= ~(4096 - 1);
  return 0;
}

 

 
reserve_mmu,留出 MMU 的 TLB 表的位置,分配 MMU 的 TLB 表内存以后会对 gd->relocaddr 做 64K 字节对齐。
完成以后 gd->arch.tlb_size、gd->arch.tlb_addr 和 gd->relocaddr

common/board_f.c

static int reserve_mmu(void)
{
  /* reserve TLB table */
  gd->arch.tlb_size = PGTABLE_SIZE;
  gd->relocaddr -= gd->arch.tlb_size;

  /* round down to next 64 kB limit */
  gd->relocaddr &= ~(0x10000 - 1);

  gd->arch.tlb_addr = gd->relocaddr;
  debug("TLB table from %08lx to %08lx\n", gd->arch.tlb_addr,
  gd->arch.tlb_addr + gd->arch.tlb_size);
  return 0;
}

 
 

 
reserve_trace 函数,留出跟踪调试的内存,I.MX6ULL 没有用到!

common/board_f.c

static int reserve_trace(void)
{
#ifdef CONFIG_TRACE
  gd->relocaddr -= CONFIG_TRACE_BUFFER_SIZE;
  gd->trace_buff = map_sysmem(gd->relocaddr, CONFIG_TRACE_BUFFER_SIZE);
  debug("Reserving %dk for trace data at: %08lx\n",
  CONFIG_TRACE_BUFFER_SIZE >> 10, gd->relocaddr);
#endif

  return 0;
}

 

 
 
reserve_uboot, 留出重定位后的 uboot 所占用的内存区域,uboot 所占用大小由gd->mon_len 所指定,
留出 uboot 的空间以后还要对 gd->relocaddr 做 4K 字节对齐,并且重新设置 gd->start_addr_sp
 common/board_f.c

static int reserve_uboot(void)
{
  /*
  * reserve memory for U-Boot code, data & bss
  * round down to next 4 kB limit
  */
  gd->relocaddr -= gd->mon_len;
  gd->relocaddr &= ~(4096 - 1);    // 4k对齐
#ifdef CONFIG_E500
  /* round down to next 64 kB limit so that IVPR stays aligned */
  gd->relocaddr &= ~(65536 - 1);
#endif

  debug("Reserving %ldk for U-Boot at: %08lx\n", gd->mon_len >> 10,
    gd->relocaddr);

  gd->start_addr_sp = gd->relocaddr;

  return 0;
}

reserve_malloc,留出 malloc 区域,调整 gd->start_addr_sp 位置,malloc 区域由宏TOTAL_MALLOC_LEN 定义

common/boad_f.c

static int reserve_malloc(void)
{
  gd->start_addr_sp = gd->start_addr_sp - TOTAL_MALLOC_LEN;
    debug("Reserving %dk for malloc() at: %08lx\n",
    TOTAL_MALLOC_LEN >> 10, gd->start_addr_sp);
  return 0;
}

 
 

reserve_board 函数,留出板子 bd 所占的内存区,bd 是结构体 bd_t,bd_t 大小为80 字节

common/board_f.c

static int reserve_board(void)
{
  if (!gd->bd) {
    gd->start_addr_sp -= sizeof(bd_t);
    gd->bd = (bd_t *)map_sysmem(gd->start_addr_sp, sizeof(bd_t));
    memset(gd->bd, '\0', sizeof(bd_t));
    debug("Reserving %zu Bytes for Board Info at: %08lx\n",
      sizeof(bd_t), gd->start_addr_sp);
  }
  return 0;
}

 

setup_machine,设置机器 ID,linux 启动的时候会和这个机器 ID 匹配,如果匹
配的话 linux 就会启动正常。但是!!I.MX6ULL 不用这种方式了,这是以前老版本的 uboot 和
linux 使用的,新版本使用设备树了,因此此函数无效

common/board_f.c

static int setup_machine(void)
{
  #ifdef CONFIG_MACH_TYPE
    gd->bd->bi_arch_number = CONFIG_MACH_TYPE; /* board id for Linux */
  #endif
  return 0;
}


 
reserve_global_data 函数,保留出 gd_t 的内存区域,gd_t 结构体大小为 248B

common/board_f.c

static int reserve_global_data(void)
{
  gd->start_addr_sp -= sizeof(gd_t);
  gd->new_gd = (gd_t *)map_sysmem(gd->start_addr_sp, sizeof(gd_t));
  debug("Reserving %zu Bytes for Global Data at: %08lx\n",
  sizeof(gd_t), gd->start_addr_sp);
  return 0;
}

 
 

reserve_fdt,留出设备树相关的内存区域,I.MX6ULL 的 uboot 没有用到,因此此函数无效。

common/board_f.c

static int reserve_fdt(void)
{
#ifndef CONFIG_OF_EMBED
  /*
  * If the device tree is sitting immediately above our image then we
  * must relocate it. If it is embedded in the data section, then it
  * will be relocated with other data.
  */
  if (gd->fdt_blob) {
    gd->fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob) + 0x1000, 32);

    gd->start_addr_sp -= gd->fdt_size;
    gd->new_fdt = map_sysmem(gd->start_addr_sp, gd->fdt_size);
    debug("Reserving %lu Bytes for FDT at: %08lx\n",
      gd->fdt_size, gd->start_addr_sp);
  }
#endif

  return 0;
}

 
reserve_arch 是个空函数。
 
reserve_stacks,留出栈空间,先对 gd->start_addr_sp 减去 16,然后做 16 字节对齐

common/board_f.c

static int reserve_stacks(void)
{
  /* make stack pointer 16-byte aligned */
  gd->start_addr_sp -= 16;
  gd->start_addr_sp &= ~0xf;

  /*
  * let the architecture-specific code tailor gd->start_addr_sp and
  * gd->irq_sp
  */
  return arch_reserve_stacks();
}

int arch_reserve_stacks(void)
{
#ifdef CONFIG_SPL_BUILD
  gd->start_addr_sp -= 128; /* leave 32 words for abort-stack */
  gd->irq_sp = gd->start_addr_sp;
#else
  /* setup stack pointer for exceptions */
  gd->irq_sp = gd->start_addr_sp;

# if !defined(CONFIG_ARM64)
# ifdef CONFIG_USE_IRQ
  gd->start_addr_sp -= (CONFIG_STACKSIZE_IRQ + CONFIG_STACKSIZE_FIQ);
  debug("Reserving %zu Bytes for IRQ stack at: %08lx\n",
    CONFIG_STACKSIZE_IRQ + CONFIG_STACKSIZE_FIQ, gd->start_addr_sp);

  /* 8-byte alignment for ARM ABI compliance */
  gd->start_addr_sp &= ~0x07;
# endif
  /* leave 3 words for abort-stack, plus 1 for alignment */
  gd->start_addr_sp -= 16;
# endif
#endif

  return 0;
}

 
 
setup_dram_config 函数设置 dram 信息,就是设置 gd->bd->bi_dram[0].start 和
gd->bd->bi_dram[0].size,后面会传递给 linux 内核,告诉 linux DRAM 的起始地址和大小

common/board_f.c

static int setup_dram_config(void)
{
  /* Ram is board specific, so move it to board code ... */
  dram_init_banksize();

  return 0;
}

__weak void dram_init_banksize(void)
{
#if defined(CONFIG_NR_DRAM_BANKS) && defined(CONFIG_SYS_SDRAM_BASE)
  gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
  gd->bd->bi_dram[0].size = get_effective_memsize();
#endif
}

 

 
show_dram_config 函数,用于显示 DRAM 的配置

common/board_f.c

static int show_dram_config(void)
{
  unsigned long long size;

#ifdef CONFIG_NR_DRAM_BANKS
  int i;

  debug("\nRAM Configuration:\n");
  for (i = size = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
    size += gd->bd->bi_dram[i].size;
    debug("Bank #%d: %llx ", i,
      (unsigned long long)(gd->bd->bi_dram[i].start));
#ifdef DEBUG
    print_size(gd->bd->bi_dram[i].size, "\n");
#endif
  }
  debug("\nDRAM: ");
#else
  size = gd->ram_size;
#endif

  print_size(size, "");
  board_add_ram_info(0);
  putc('\n');

  return 0;
}

 
 
第 58 行,display_new_sp 函数,显示新的 sp 位置,也就是 gd->start_addr_sp,不过要定义
宏 DEBUG

common/board_f.c

static int display_new_sp(void)
{
  debug("New Stack Pointer is: %08lx\n", gd->start_addr_sp);

  return 0;
}

 
第 60 行,reloc_fdt 函数用于重定位 fdt,没有用到。

common/board_f.c

static int reloc_fdt(void)
{
#ifndef CONFIG_OF_EMBED
  if (gd->flags & GD_FLG_SKIP_RELOC)
    return 0;
  if (gd->new_fdt) {
    memcpy(gd->new_fdt, gd->fdt_blob, gd->fdt_size);
    gd->fdt_blob = gd->new_fdt;
  }
#endif

  return 0;
}

 

 
第 61 行,setup_reloc,设置 gd 的其他一些成员变量,供后面重定位的时候使用,并且将以
前的 gd 拷贝到 gd->new_gd 处。需要使能 DEBUG 才能看到相应的信息输出
common/board_f.c

static int setup_reloc(void)
{
  if (gd->flags & GD_FLG_SKIP_RELOC) {
    debug("Skipping relocation due to flag\n");
    return 0;
}

#ifdef CONFIG_SYS_TEXT_BASE
  gd->reloc_off = gd->relocaddr - CONFIG_SYS_TEXT_BASE;
#ifdef CONFIG_M68K
  /*
  * On all ColdFire arch cpu, monitor code starts always
  * just after the default vector table location, so at 0x400
  */
  gd->reloc_off = gd->relocaddr - (CONFIG_SYS_TEXT_BASE + 0x400);
#endif
#endif
  memcpy(gd->new_gd, (char *)gd, sizeof(gd_t));

  debug("Relocation Offset is: %08lx\n", gd->reloc_off);
  debug("Relocating to %08lx, new gd at %08lx, sp at %08lx\n",
    gd->relocaddr, (ulong)map_to_sysmem(gd->new_gd),
    gd->start_addr_sp);

  return 0;
}

 

 可以看到最后几个函数所进行的动作都是为各个区块预留内存空间

他们分别是mmu, uboot, 动态内存区,board, gd, 最后减了2次16字节,再16字节对齐, 得到start_addr_sp

 

最新文章

  1. Linix登录报&quot;/etc/profile: line 11: syntax error near unexpected token `$'{\r''&quot;
  2. jQuery .attr(&quot;checked&quot;)得undefined 问题解决
  3. linux 脚本小试系列
  4. 由ASP.NET所谓前台调用后台、后台调用前台想到HTTP——理论篇
  5. 【Oozie】安装配置Oozie
  6. 在64位的linux上运行32位的程序
  7. VS2008 由于应用程序配置不正确,应用程序未能启动。重新安装应用程序可能会纠正这个问题。
  8. js常用设计模式
  9. Android Gson深入分析
  10. Easyui 让Window弹出居中
  11. jump堡垒机配置使用
  12. QQGame防专线中断系统介绍
  13. 8. Filters in ASP.NET MVC 5.0【ASP.NET MVC 5.0中的过滤器】
  14. Synchronized和lock的区别和用法
  15. java.sql.SQLException: ORA-28040: 没有匹配的验证协议(12c或者12c rac)
  16. Swagger使用小记
  17. Apache通过配置.htaccess文件禁止访问.git、.svn等目录
  18. go语言中的方法method
  19. java swing MenuItem乱码处理
  20. mysql服务器,大量tcp连接状态TIME_WAIT

热门文章

  1. 【云原生 · Kubernetes】部署博客系统
  2. 运用领域模型——DDD
  3. Django基础笔记10(前端展示)
  4. python爬虫爬取网易云音乐(超详细教程,附源码)
  5. python random模块几个常用方法
  6. RocketMQ Connect 构建流式数据处理平台
  7. dotTrace工具
  8. elementui中 分页在vue中的使用
  9. 数值分析——插值(一)、Runge现象
  10. [OpenCV实战]39 在OpenCV中使用ArUco标记的增强现实