RTL8382M Linux源码阅读思路 - head.s(2)

#kernel分析
PTR_LA		$28, init_thread_union
PTR_LI		sp, _THREAD_SIZE - 32
PTR_ADDU	sp, $28
set_saved_sp	sp, t0, t1
PTR_SUBU	sp, 4 * SZREG		# init stack pointer
j		start_kernel

第1行:将init_thread_union结构地址赋值给$28$28 = $gp在mips中表示全局数据区指针寄存器

init_thread_union结构体实例定义在:

/*
 * Initial thread structure.
 *
 * We need to make sure that this is 8192-byte aligned due to the
 * way process stacks are handled. This is done by making sure
 * the linker maps this in the .text segment right after head.S,
 * and making head.S ensure the proper alignment.
 *
 * The things we do for performance..
 */
union thread_union init_thread_union
	__attribute__((__section__(".data.init_task"),
				   __aligned__(THREAD_SIZE))) =
		{ INIT_THREAD_INFO(init_task) };
/*
 * Initial task structure.
 *
 * All other task structs will be allocated on slabs in fork.c
 */
struct task_struct init_task = INIT_TASK(init_task);

以上代码翻译成人话意思是:定义一个thread_union类型的共用体init_thread_union并赋值,具体解释如下:

首先看此共用体类型的声明:

union thread_union {
	struct thread_info thread_info;
	unsigned long stack[THREAD_SIZE/sizeof(long)];
};

继续thread_info结构体声明:

/*
 * low level task data that entry.S needs immediate access to
 * - this struct should fit entirely inside of one cache line
 * - this struct shares the supervisor stack pages
 * - if the contents of this structure are changed, the assembly constants
 *   must also be changed
 */
struct thread_info {
	struct task_struct	*task;		/* main task structure */
	struct exec_domain	*exec_domain;	/* execution domain */
	unsigned long		flags;		/* low level flags */
	unsigned long		tp_value;	/* thread pointer */
	__u32			cpu;		/* current CPU */
	int			preempt_count;	/* 0 => preemptable, <0 => BUG */
	mm_segment_t		addr_limit;	/* thread address space:
						   0-0xBFFFFFFF for user-thead
						   0-0xFFFFFFFF for kernel-thread
						*/
	struct restart_block	restart_block;
	struct pt_regs		*regs;
};

具体每个字段什么意思我也不知道@@

继续……

thread_union共用体变量类型实际上是一个共用的内存结构,根据除thread_info的另一个数组stack可以猜出来,此共用结构可以同时作为thread_info和栈数组使用(好像是废话……)

上面解释完了thread_union共用体类型的字段,因此init_thread_union就是一个thread_union的实例化

__attribute__((__section__(".data.init_task"),表示此共用体结构必须被编译在内核空间的.data.init_task段,具体在哪里有vmlinux.lds定义

__aligned__(THREAD_SIZE))) =表示此结构对齐到THREAD_SIZE,就是0x20008k byte 因此,thread_info和栈数组共用8k

{ INIT_THREAD_INFO(init_task) };是此实例在.data.init_task的赋值,在被定义的时候赋值,赋值的地址是.data.init_task 查看system.map得知801d2000 D init_thread_union

struct task_struct init_task = INIT_TASK(init_task);表示在init_thread_union后面8k开外定义一个init_task结构实例并初始化赋值

翻译过来就是说,前一个定义在内核数据段的开头定义了个一个线程结构与内核堆栈的共用体共8k,这8k后面紧接着定义个一个进程(任务)结构

因此,第1行的意思就是将内核数据段开头的内核堆栈区的底部(也就是开头)指针赋值给了$28全局(数据段)指针

第2行:将内核数据段开头8k刚好是一个init_thread_union结构的,也可以说是内核堆栈区-32byte的大小,赋值给$sp,也就是mips保留的(内核)堆栈区大小

第3行:将$sp堆栈指针(之前保存堆栈区大小)加上$gp内核数据段开头地址,因此,$sp刚好指向init_thread_union结构尾巴,也就是内核堆栈区顶部

第4行:保存这两个指针

第5行:PTR_SUBU sp, 4 * SZREG # init stack pointer

$sp内核堆栈区减4*4个byte,原因不清楚,猜测可能是为了保存start_kernel的参数

第7行:j start_kernel

j指令将跳转到start_kernel地址