init函數詳解

1.主要功能,紅色部分是android特有的一些功能,如fastboot,recovery模式等:
* Variety of nand devices for bootup
* USB driver to enable upgrading images over usb during development
* Keypad driver to enable developers enter ‘fastboot’ mode for image upgrades
* Display driver for debugging and splash screen
* Enable Android recovery image and image upgrades

2.配置dram內存大小,供linux kernel使用
The memory tags can be customized inlk/target/<target_name>/atags.c

3.fastboot模式,可以自行打開或者關閉
如,在boot中關閉按鍵或者usb 驅動,都可以達到此目的
相關文件
lk/app/aboot/fastboot.c
lk/app/aboot/aboot.c


4.MTD block setting
可以配置各個mtd image 分區在如下 文件中
lk\target\tcc8900_evm\init.c
static struct ptentry board_part_list[]

5.打開或者關閉splash screen in the bootloader
DISPLAY_SPLASH_SCREEN功能可以來打開關閉
開機時候,boot會從’splash’ MTD分區中讀取原始的文件到framebuffer中顯示,所以也需要加載display 的驅動
入口函數在 kernel/main.c 中的 kmain(), 以下就來讀讀這一段 code.

void kmain(void)
{
// get us into some sort of thread context
thread_init_early();
// early arch stuff
arch_early_init();
// do any super early platform initialization
platform_early_init();
// do any super early target initialization
target_early_init();
dprintf(INFO, "welcome to lk/n/n");

// deal with any static constructors
dprintf(SPEW, "calling constructors/n");
call_constructors();
// bring up the kernel heap
dprintf(SPEW, "initializing heap/n");
heap_init();
// initialize the threading system
dprintf(SPEW, "initializing threads/n");
thread_init();
// initialize the dpc system
dprintf(SPEW, "initializing dpc/n");
dpc_init();
// initialize kernel timers
dprintf(SPEW, "initializing timers/n");
timer_init();
#if (!ENABLE_NANDWRITE)
// create a thread to complete system initialization
dprintf(SPEW, "creating bootstrap completion thread/n");
thread_resume(thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
// enable interrupts
exit_critical_section();
// become the idle thread
thread_become_idle();
#else
bootstrap_nandwrite();
#endif
}

In include/debug.h: 我們可以看到 dprintf ()的第一個參數是代表 debug level.

/* debug levels */
#define CRITICAL 0
#define ALWAYS 0
#define INFO 1
#define SPEW 2
In include/debug.h:

view plainprint?
#define dprintf(level, x...) do { if ((level) <= DEBUGLEVEL) { _dprintf(x); } } while (0)

所以 dprintf 會依 DEBUGLEVEL 來判斷是否輸出信息.

來看第一個 call 的函數: thread_init_early, define in thread.c

view plainprint?
void thread_init_early(void)
{
int i;
/* initialize the run queues */
for (i=0; i < NUM_PRIORITIES; i++)
list_initialize(&run_queue[i]);
/* initialize the thread list */
list_initialize(&thread_list);
/* create a thread to cover the current running state */
thread_t *t = &bootstrap_thread;
init_thread_struct(t, "bootstrap");
/* half construct this thread, since we're already running */
t->priority = HIGHEST_PRIORITY;
t->state = THREAD_RUNNING;
t->saved_critical_section_count = 1;
list_add_head(&thread_list, &t->thread_list_node);
current_thread = t;
}

#define NUM_PRIORITIES 32 in include/kernel/thread.h

list_initialize() defined in include/list.h: initialized a list

view plainprint?
static inline void list_initialize(struct list_node *list)
{
list->prev = list->next = list;
}

run_queue 是 static struct list_node run_queue[NUM_PRIORITIES]

thread_list 是 static struct list_node thread_list

再來要 call 的函數是: arch_early_init() defined in arch/arm/arch.c

view plainprint?
void arch_early_init(void)
{
/* turn off the cache */
arch_disable_cache(UCACHE);
/* set the vector base to our exception vectors so we dont need to double map at 0 */
#if ARM_CPU_CORTEX_A8
set_vector_base(MEMBASE);
#endif
#if ARM_WITH_MMU
arm_mmu_init();
platform_init_mmu_mappings();
#endif
/* turn the cache back on */
arch_enable_cache(UCACHE);
#if ARM_WITH_NEON
/* enable cp10 and cp11 */
uint32_t val;
__asm__ volatile("mrc p15, 0, %0, c1, c0, 2" : "=r" (val));
val |= (3<<22)|(3<<20);
__asm__ volatile("mcr p15, 0, %0, c1, c0, 2" :: "r" (val));
/* set enable bit in fpexc */
val = (1<<30);
__asm__ volatile("mcr p10, 7, %0, c8, c0, 0" :: "r" (val));
#endif
}

現代操作系統普遍採用虛擬內存管理(Virtual Memory Management)機制,這需要處理器中的MMU(Memory Management Unit,
內存管理單元)提供支持。
CPU執行單元發出的內存地址將被MMU截獲,從CPU到MMU的地址稱爲虛擬地址(Virtual Address,以下簡稱VA),而MMU將這個地
址翻譯成另一個地址發到CPU芯片的外部地址引腳上,也就是將VA映射成PA
MMU將VA映射到PA是以頁(Page)爲單位的,32位處理器的頁尺寸通常是4KB。例如,MMU可以通過一個映射項將VA的一頁
0xb7001000~0xb7001fff映射到PA的一頁0x2000~0x2fff,如果CPU執行單元要訪問虛擬地址0xb7001008,則實際訪問到的物理地
址是0x2008。物理內存中的頁稱爲物理頁面或者頁幀(Page Frame)。虛擬內存的哪個頁面映射到物理內存的哪個頁幀是通過頁
表(Page Table)來描述的,頁表保存在物理內存中,MMU會查找頁表來確定一個VA應該映射到什麼PA。

操作系統和MMU是這樣配合的:

1. 操作系統在初始化或分配、釋放內存時會執行一些指令在物理內存中填寫頁表,然後用指令設置MMU,告訴MMU頁表在物理內存中
的什麼位置。
2. 設置好之後,CPU每次執行訪問內存的指令都會自動引發MMU做查表和地址轉換操作,地址轉換操作由硬件自動完成,不需要用指令
控制MMU去做。

MMU除了做地址轉換之外,還提供內存保護機制。各種體系結構都有用戶模式(User Mode)和特權模式(Privileged Mode)之分,
操作系統可以在頁表中設置每個內存頁面的訪問權限,有些頁面不允許訪問,有些頁面只有在CPU處於特權模式時才允許訪問,有些頁面
在用戶模式和特權模式都可以訪問,訪問權限又分爲可讀、可寫和可執行三種。這樣設定好之後,當CPU要訪問一個VA時,MMU會檢查
CPU當前處於用戶模式還是特權模式,訪問內存的目的是讀數據、寫數據還是取指令,如果和操作系統設定的頁面權限相符,就允許訪
問,把它轉換成PA,否則不允許訪問,產生一個異常(Exception)

常見的 segmentation fault 產生的原因:
用戶程序要訪問一段 VA, 經 MMU 檢查後無權訪問, MMU 會產生異常, CPU 從用戶模式切換到特權模式, 跳轉到內核代碼中執行異常服務程序.
內核就會把這個異常解釋爲 segmentation fault, 將引發異常的程序終止.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章