(三)DIM-SUM系统之系统初始化

一、Makefile分析

从 src/ 目录下的Makefile可以看出,工程的结构基本与Linux系统保持一致:

_all
all
vmlinux
vmlinux-lds
vmlinux-init
head-y
init-y:= init/
vmlinux-main
vmlinux.o
kallsyms.o

在 init/ 目录中的Makefile主要内容如下:

obj-y := main.o version.o init_task.o test.o

在 arch/arm64/kernel/Makefile中可以找到:

head-y := head.o

从Makefile的分析可以看出,系统的初始化是在head.S和main.c这两个文件完成的,接下来我们来看看这两个文件。

二、head.S

head.S是一个汇编文件,内部的执行流程如下:

fake_start
real_start
__prepare_jump_to_master
start_master

知道了具体步骤之后,我们再来看看每一步做了什么。

1、fake_start

这一步直接跳转到了real_start,具体意义不明。

ENTRY(fake_start)
	b real_start
ENDPROC(fake_start)

2、real_start

在real_start中,首先将bootloader传递给内核的启动参数保存到了boot_params数组(该数组定义在main.c里)中;然后启动了MMU单元,最后跳转到了__prepare_jump_to_master。

ENTRY(real_start)
	/**
	 * 将x0~x3保存到boot_params中
	 * 这三个参数是boot传递给内核的值
	 */
	adr_l	x9, boot_params
	stp	x0, x1, [x9]
	stp	x2, x3, [x9, #16]

	/**
	 * 对boot_params中32个字节(x0~x3)执行inval操作
	 */
	adr_l x0, boot_params
	add	x1, x0, #0x20			// 4 x 8 bytes
	/**
	 * 在MMU未打开时,需要先调用此句
	 * 才能执行inval操作
	 */
	dmb	sy
	bl	__inval_cache_range

	adrp	x11, VA_OFFSET
	bl	__create_temporary_page_tables		/* x12=TTBR0, x13=TTBR1 */
	
	/**
	 * 前面已经准备好页表。
	 * 准备调用CPU设置代码,打开MMU.
	 */
	bl	__prepare_cpu_mmu
	/**
	 * 打开MMU以后,直接跳转到这里
	 */
	ldr	x14, =__prepare_jump_to_master
	b	__turn_on_cpu_mmu
ENDPROC(real_start)

3、__prepare_jump_to_master

这一步主要是为运行C语言程序准备环境,初始化堆栈之后直接跳转到了main.c中的start_master函数运行。

__prepare_jump_to_master:
	adr_l	x6, __bss_start
	adr_l	x7, __bss_stop

/**
 * 清空BSS段的内容
 */
1:	cmp	x6, x7
	b.hs	2f
	str	xzr, [x6], #8
	b	1b
/**
 * 准备启动线程的堆栈
 * 并跳转到C函数入口处
 */
2:
	adr_l	sp, initial_sp, x4
	str_l	x9, device_tree_phys, x5
	str_l	x11, phys_addr_origin, x6
	mov	x29, #0

/**
 * 是不是有点小激动??
 */
	b	start_master
ENDPROC(__prepare_jump_to_master)

三、main.c

程序运行到main.c文件,就是由大家熟悉的C语言进行编写了,我们先来看看程序流程:

进程
start_master
init_in_process
init_in_process

从流程图来看main.c文件的内容好像非常少,但其实这个文件完成了主要的系统初始化工作。

1、start_master

在函数前端看到了熟悉的标记 __init,猜测这个标记的作用可能与Linux系统中的作用类似。

在函数中我们可以看到各种系统初始化的函数(init_xxx),这里就不展开讨论了,在后面具体模块的代码分析中我们再来讨论。我们可以看到 boot_state 全局变量表示当前系统的初始化状态,在状态变化为 KERN_PREPARE_RUN 之后,就进入到了 kick_rest 函数中。cpu_idle 函数作用类似于一个死循环,防止系统直接运行结束。

/**
 * 主核初始化
 */
asmlinkage void __init start_master(void)
{
	boot_state = BOOTING;

	disable_irq();

	/* 为主核设置其活动掩码 */
	smp_mark_master();

	/* 体系结构特定的初始化过程 */
	start_arch();

	init_memory_early();
	init_vfs_early();
	init_sched_early();

	init_linear_mapping();

	/**
	 * 初始化内存子系统
	 * 自此以后,可以调用内存分配API了^_^
	 */
	init_memory();

	boot_state = KERN_MALLOC_READY;

	init_pagecache();
	init_virt_space();
	init_radix_tree();
	init_IRQ();
	init_time();
	init_timer();
	init_sched();
	init_console();

	enable_irq();

	boot_state = KERN_PREPARE_RUN;

	kick_rest();

	cpu_idle();
	//不可能运行到这里来
	BUG();
}

2、init_in_process

这个函数顾名思义,创建了一个新的进程继续系统初始化的操作。

static void kick_rest(void)
{
	create_process(init_in_process,
			NULL,
			"init_in_process",
			5
		);
}

3、init_in_process

从调用的函数名可以看出这一步主要是为运行用户的应用程序做准备,同时打开了命令行终端设备,最后将系统的控制权交给用户。

/**
 * 在进程上下文进行初始化工作。
 * 在开中断的情况下运行,此时可以睡眠。
 */
static __maybe_unused int init_in_process(void *unused)
{
	/**
	 * 初始化工作队列
	 * 可睡眠的延迟任务
	 */
	init_sleep_works();

	init_vfs();
	init_file_systems();

	init_bus();
	probe_devices();
	init_tty();

	mount_file_systems();
	/**
	 * 初始化lwip协议栈
	 */
	init_lwip();

	/**
	 * 启动所有从核
	 */
	launch_slave();

	/**
	 * 打开console设备
	 * 将其作为默认的输出设备
	 */
	if (sys_open("/dev/console", O_RDWR, 0) < 0)
		printk("Warning: unable to open an initial console.\n");

	/**
	 * 用于printf
	 */
	(void) sys_dup(0);
	(void) sys_dup(0);
	
	boot_state = KERN_RUNNING;

	__init_klibc();
	dim_sum_test();

	/**
	 * 将控制权交给用户线程
	 */
	usrAppInit();
	
	return 0;
}

DIM-SUM系统的学习就从这里开始了,后续我会持续更新各个子系统的分析文章。

(目前DIM-SUM系统版本为HOTPOT,本文内容为鄙人愚见,有不足之处请大家指正,如果有意转载请标明来源:https://blog.csdn.net/wdy8841693/article/details/107937706。在这里感谢谢宝友前辈的付出,另外向大家推荐《自研操作系统:DIM-SUM设计与实现》这本书)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值