内核启动之启动内核——startup_32

本文详细分析了x86架构下内核启动过程中的startup_32阶段,包括初始化段寄存器、设置堆栈、处理boot_params结构体、建立页表并启用分页、初始化IDT、CPU参数检查、加载IDTR和GDTR,最后跳转到i386_start_kernel。通过对这段汇编代码的逐行解析,理解了保护模式下内核启动的关键步骤。
摘要由CSDN通过智能技术生成

        这段代码在arch/x86/boot/kernel/header_32.S中,它是在内核被解压缩到0x100000处之后跳转到这个地址开始执行的,前面的操作算是为这一步做铺垫吧,现在到了真正的内核,为了能够让自己把内核代码真的弄懂,不再采用前面那种比较比较笼统的方式了,而是按照内核源码分析的那种方式将这个代码复制下来,然后逐行的分析,这样就不至于再给自己偷懒的机会了,嗯,以后就这样做,争取能够把不懂的内容搞懂。 

        在这个时候,我们已经进入了保护模式(也就是寻址方式发生了改变),但是没有启用分页,所以得到的线性地址就是物理地址,之前的bootloader的内容已经对我们没有任何意义了,唯一剩余的就是它留下来一个关于一些参数结构体boot_params,这个结构体的地址保存在寄存器esi中,现在重新开始内核的执行。

代码如下:

.text

/* 省略头文件 */

/* Physical address */
#define pa(X) ((X) - __PAGE_OFFSET)      //逻辑地址转换成物理地址,因为这时候已经开启了保护模式,所以内核对应着高端的1G内存,并且和物理内存直接映射


/*
 * References to members of the new_cpu_data structure.
 */


#define X86 new_cpu_data+CPUINFO_x86
#define X86_VENDOR new_cpu_data+CPUINFO_x86_vendor
#define X86_MODEL new_cpu_data+CPUINFO_x86_model
#define X86_MASK new_cpu_data+CPUINFO_x86_mask
#define X86_HARD_MATH new_cpu_data+CPUINFO_hard_math
#define X86_CPUID new_cpu_data+CPUINFO_cpuid_level
#define X86_CAPABILITY new_cpu_data+CPUINFO_x86_capability
#define X86_VENDOR_ID new_cpu_data+CPUINFO_x86_vendor_id


/*
 * This is how much memory in addition to the memory covered up to
 * and including _end we need mapped initially.
 * We need:
 *     (KERNEL_IMAGE_SIZE/4096) / 1024 pages (worst case, non PAE)
 *     (KERNEL_IMAGE_SIZE/4096) / 512 + 4 pages (worst case for PAE)
 *
 * Modulo rounding, each megabyte assigned here requires a kilobyte of
 * memory, which is currently unreclaimed.
 *
 * This should be a multiple of a page.
 *
 * KERNEL_IMAGE_SIZE should be greater than pa(_end)
 * and small than max_low_pfn, otherwise will waste some page table entries
 */


#if PTRS_PER_PMD > 1
#define PAGE_TABLE_SIZE(pages) (((pages) / PTRS_PER_PMD) + PTRS_PER_PGD)
#else
#define PAGE_TABLE_SIZE(pages) ((pages) / PTRS_PER_PGD)    //pages页需要的页表项
#endif


/* Number of possible pages in the lowmem region */
LOWMEM_PAGES = (((1<<32) - __PAGE_OFFSET) >> PAGE_SHIFT)         //内核能够映射的物理内存的大小,低端内存

/* Enough space to fit pagetables for the low memory linear map */
MAPPING_BEYOND_END = PAGE_TABLE_SIZE(LOWMEM_PAGES) << PAGE_SHIFT     //低端内存所占用的页表项的大小


/*
 * Worst-case size of the kernel mapping we need to make:
 * a relocatable kernel can live anywhere in lowmem, so we need to be able
 * to map all of lowmem.
 */
KERNEL_PAGES = LOWMEM_PAGES                            //内核能够映射的内存大小


INIT_MAP_SIZE = PAGE_TABLE_SIZE(KERNEL_PAGES) * PAGE_SIZE           //同MAPPING_BEYOND_END
RESERVE_BRK(pagetables, INIT_MAP_SIZE)


/*
 * 32-bit kernel entrypoint; only used by the boot CPU.  On entry,
 * %esi points to the real-mode code as a 32-bit pointer.
 * CS and DS must be 4 GB flat segments, but we don't depend on
 * any particular GDT layout, because we load our own as soon as we
 * can.
 */
__HEAD
ENTRY(startup_32)                    //0x100000,从这里开始执行内核的代码
movl pa(stack_start),%ecx            //这里设置堆栈

/* test KEEP_SEGMENTS flag to see if the bootloader is asking
us to not reload segments */
testb $(1<<6), BP_loadflags(%esi)          //判断是否需要重新设置各个段寄存器
jnz 2f


/*
 * Set segments to known values.
 */
lgdt pa(boot_gdt_descr)                     //设置临时的全局页描述符表,后面还需要进一步初始化
movl $(__BOOT_DS),%eax                      //初始化各个段寄存器
movl %eax,%ds
movl %eax,%es
movl %eax,%fs
movl %eax,%gs
movl %eax,%ss
2:
leal -__PAGE_OFFSET(%ecx),%esp             //设置堆栈的栈顶指针,这个堆栈就是init_task的堆栈,这里相当于手工初始化了一个进程

/*
 * Clear BSS first so that there are no surprises...
 */                                                 //初始化bss段,清0
cld
xorl %eax,%eax
movl $pa(__bss_start),%edi                          //bss段的起始位置
movl $pa(__bss_stop),%ecx                           
subl %edi,%ecx                                      //计算bss段的大小
shrl $2,%ecx                                        //以4字节为单位对bss段进行清0
rep ; stosl
/*
 * Copy bootup parameters out of the way.
 * Note: %esi still has the pointer to the real-mode data.
 * With the kexec as boot loader, parameter segment might be loaded beyond
 * kernel image and might not even be addressable by early boot page tables.
 * (kexec on panic case). Hence copy out the parameters before initializing
 * page tables.
 */
movl $pa(boot_params),%edi            //拷贝boot_params的内容
movl $(PARAM_SIZE/4),%ecx
cld
rep
movsl
movl pa(boot_params) + NEW_CL_POINTER,%esi         //这里保存的是boot_params.hdr.cmd_line_ptr
andl %esi,%esi
jz 1f # No command line
movl $pa(boot_command_line),%edi
movl 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值