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//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, 将引发异常的程序终止.

你可能感兴趣的:(MTK平台)