ubuntu 在 R40e 上 還有 Debian 在 Sempron 2600 上

2012年4月10日 星期二

u-boot boot code -- alter path of boot

boot code trace
cpu/arm_cortexa8/cpu.S 就像是以前 ads 的 startup.S

一開始就是 arm 的 interrupt vector。
後面就是 code.

從 reset 開始。
然後call cpu_init_crit (low level init ?)。
之後就是 relocate。
-- 因為 iMX51 的 bootrom 已經把DDR config 好,並且把 uboot load 到 DDR,所以不用作 reloacate 了。

設定 stack:
sp = _TEXT_BASE - #CONFIG_SYS_MALLOC_LEN - #CONFIG_SYS_GBL_DATA_SIZE - 12

clear bbs: __bss_start -- __bss_end 的區域都填 0

run board_mmu_init.
這段code 要參考 Reference Manual Chapter 2 : Memory Map. 對照 Physical Address 的內容 (其實註解已經寫得很清楚)
/* Actual Virtual Size Attributes Function */ /* Base Base MB cached? buffered? access permissions */ /* xxx00000 xxx00000 */ X_ARM_MMU_SECTION(0x000, 0x200, 0x1, ARM_UNCACHEABLE, ARM_UNBUFFERABLE, ARM_ACCESS_PERM_RW_RW); /* ROM */ X_ARM_MMU_SECTION(0x1FF, 0x1FF, 0x001, ARM_UNCACHEABLE, ARM_UNBUFFERABLE, ARM_ACCESS_PERM_RW_RW); /* IRAM */ X_ARM_MMU_SECTION(0x300, 0x300, 0x100, ARM_UNCACHEABLE, ARM_UNBUFFERABLE, ARM_ACCESS_PERM_RW_RW); /* GPU */ X_ARM_MMU_SECTION(0x400, 0x400, 0x200, ARM_UNCACHEABLE, ARM_UNBUFFERABLE, ARM_ACCESS_PERM_RW_RW); /* IPUv3D */ X_ARM_MMU_SECTION(0x600, 0x600, 0x300, ARM_UNCACHEABLE, ARM_UNBUFFERABLE, ARM_ACCESS_PERM_RW_RW); /* periperals */ X_ARM_MMU_SECTION(0x900, 0x000, 0x1FF, ARM_CACHEABLE, ARM_BUFFERABLE, ARM_ACCESS_PERM_RW_RW); /* SDRAM */ X_ARM_MMU_SECTION(0x900, 0x900, 0x200, ARM_CACHEABLE, ARM_BUFFERABLE, ARM_ACCESS_PERM_RW_RW); /* SDRAM */ X_ARM_MMU_SECTION(0x900, 0xE00, 0x200, ARM_UNCACHEABLE, ARM_UNBUFFERABLE, ARM_ACCESS_PERM_RW_RW); /* SDRAM 0:128M*/ X_ARM_MMU_SECTION(0xB80, 0xB80, 0x10, ARM_UNCACHEABLE, ARM_UNBUFFERABLE, ARM_ACCESS_PERM_RW_RW); /* CS1 EIM control*/ X_ARM_MMU_SECTION(0xCC0, 0xCC0, 0x040, ARM_UNCACHEABLE, ARM_UNBUFFERABLE, ARM_ACCESS_PERM_RW_RW); /* CS4/5/NAND Flash buffer */
其中 X_ARM_MMU_SECTION 的內容,跟 MMU 的spec 一樣,一個 entry 是 1M ,所以: #define X_ARM_MMU_SECTION(abase, vbase, size, cache, buff, access) \ { \ int i; int j = abase; int k = vbase; \ for (i = size; i > 0 ; i--, j++, k++) \ ARM_MMU_SECTION(ttb_base, j, k, cache, buff, access); \ }
根據 size 以 1M 為單位,把所有的 table entry 都設完。
-- 因為 MMU 的 translation 是把bit20~31 拿去作 translate。所以單位是 1M (0~19 bit).

  1. 關於 mmu section translation 可以google 一下:https://www.google.com.tw/search?q=arm%20mmu%20section%20translation&um=1&ie=UTF-8&hl=zh-TW&tbm=isch&source=og&sa=N&tab=wi&ei=3NSDT_-eJaz0mAWizJW4Bw&biw=1366&bih=630&sei=-dSDT8-LEMycmQXnquSyBw

這 code 跟 spec 的圖結合在一起: union ARM_MMU_FIRST_LEVEL_DESCRIPTOR { unsigned long word; struct ARM_MMU_FIRST_LEVEL_FAULT fault; struct ARM_MMU_FIRST_LEVEL_PAGE_TABLE page_table; struct ARM_MMU_FIRST_LEVEL_SECTION section; struct ARM_MMU_FIRST_LEVEL_RESERVED reserved; }; 是 UNION.
ref : ARM processor MMU -- level one descriptor 的圖。

之後就可以啟動 MMU。

然後執行 start_armboot()。



start_armboot()準備 gd_t (globale_data) 的空間,然後用類似 linux init 的方式 call init function (這裡是手動): for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { if ((*init_fnc_ptr)() != 0) { hang (); } } init_fnc_t *init_sequence[] = { #if defined(CONFIG_ARCH_CPU_INIT) arch_cpu_init, /* basic arch cpu dependent setup */ #endif board_init, /* basic board dependent setup */ #if defined(CONFIG_USE_IRQ) interrupt_init, /* set up exceptions */ #endif timer_init, /* initialize timer */ env_init, /* initialize environment */ init_baudrate, /* initialze baudrate settings */ serial_init, /* serial communications setup */ console_init_f, /* stage 1 init of console */ display_banner, /* say that we are here */ #if defined(CONFIG_DISPLAY_CPUINFO) print_cpuinfo, /* display cpu info (and speed) */ #endif #if defined(CONFIG_DISPLAY_BOARDINFO) checkboard, /* display board info */ #endif #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C) init_func_i2c, #endif dram_init, /* configure available RAM banks */ #if defined(CONFIG_CMD_PCI) || defined (CONFIG_PCI) arm_pci_init, #endif display_dram_config, NULL, }; 之後就是一個一個個別 hardware function 的 init... (?為什摩不在 init_sequence[] 裡作?)

然後 call check_recovery_mode()
最後是 main_loop().



check_recovery_mode( ) 就是偵測 hardware pin,然後call setup_recovery_env( )。
單純操作 env: void setup_recovery_env(void) { char *env, *boot_args, *boot_cmd; int bootdev = get_boot_device(); boot_cmd = supported_reco_envs[bootdev].cmd; boot_args = supported_reco_envs[bootdev].args; if (boot_cmd == NULL) { printf("Unsupported bootup device for recovery\n"); return; } printf("setup env for recovery..\n"); env = getenv("bootargs_android_recovery"); /* Set env to recovery mode */ /* Only set recovery env when these env not exist, give user a * chance to change their recovery env */ if (!env) setenv("bootargs_android_recovery", boot_args); env = getenv("bootcmd_android_recovery"); if (!env) setenv("bootcmd_android_recovery", boot_cmd); setenv("bootcmd", "run bootcmd_android_recovery"); }
就是改 bootcmd 為 "run bootcmd_android_recoery"。
這樣之後的 boot process,去 run bootcmd ,就會 run bootcmd_android_recovery.

沒有留言:

標籤

網誌存檔