个人可以做几个网站,连云港公司网站制作,wordpress 搬家 mysql,北京快速网站建设head.S是linux启动后的第一个文件#xff0c;主要完成以下功能#xff1a;1、检查处理器信息#xff0c;并保存#xff1b;2、检查平台号#xff0c;并保存#xff1b;3、创建页表#xff0c;并开启MMU功能#xff1b;4、对内核data section、bbs section作调整和初始化…head.S是linux启动后的第一个文件主要完成以下功能1、检查处理器信息并保存2、检查平台号并保存3、创建页表并开启MMU功能4、对内核data section、bbs section作调整和初始化保存必要的变量设置栈指针跳到start_kernel;实现过程//定义进程0的页表基地址位于内核代码前16k,注意这是一个虚拟地址。.globl swapper_pg_dir.equ swapper_pg_dir, TEXTADDR - 0x4000//这个宏用于计算内核页表的基地址是物理地址。.macro pgtbl, rd, physadr \rd, stextsub \rd, \rd, #0x4000.endm//定义所属为init段__INIT//定义个函数地址.type stext, %functionENTRY(stext)//设置处理器SVC模式禁止IRQ中断、FIQ中断。msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | MODE_SVC//查找处理器类型并判断是否有效。bl __lookup_processor_type r5procinfo r9cpuidmovs r10, r5 invalid processor (r50)?beq __error_p yes, error p//查找平台类型并判断是否有效。bl __lookup_machine_type r5machinfomovs r8, r5 invalid machine (r50)?beq __error_a yes, error a//创建页表。bl __create_page_tables//把__switch_data地址处的内容放到r13,也就是r13_mmap_swithced,在__enable_mmu之后会返回到这里执行。要注意这个r13放的可以虚拟地址在打开MMU之后跳到这。ldr r13, __switch_data//在PROCINFO_INITFUNC被调用之后执行_enable_mmuadr lr, __enable_mmu return (PIC) address//调用处理器相关的初始化函数(arch/arm/mm/proc-arm920.S -arm920_setup)。add pc, r10, #PROCINFO_INITFUNC//.type __switch_data, %object__switch_data:.long __mmap_switched.long __data_loc r4.long __data_start r5.long __bss_start r6.long _end r7.long processor_id r4.long __machine_arch_type r5.long cr_alignment r6.long init_thread_union THREAD_START_SP sp/** The following fragment of code is executed with the MMU on, and uses* absolute addresses; this is not position independent.** r0 cp#15 control register* r1 machine ID* r9 processor ID*/.type __mmap_switched, %function__mmap_switched://r4_data_loc,r5_data_start,r6_bss_start,r7_endadr r3, __switch_data 4ldmia r3!, {r4, r5, r6, r7}//_data_loc_data_start不用移动。cmp r4, r5 Copy data segment if needed1: cmpne r5, r6ldrne fp, [r4], #4strne fp, [r5], #4bne 1b//清除BSS段。mov fp, #0 Clear BSS (and zero fp)1: cmp r6, r7strcc fp, [r6],#4bcc 1bldmia r3, {r4, r5, r6, sp}str r9, [r4] Save processor IDstr r1, [r5] Save machine typebic r4, r0, #CR_A Clear A bitstmia r6, {r0, r4} Save control register valuesb start_kernel从下面开始说上面的子调用1、CPU信息和平台信息的检查/** Read processor ID register (CP#15, CR0), and look up in the linker-built* supported processor list. Note that we cant use the absolute addresses* for the __proc_info lists since we arent running with the MMU on* (and therefore, we are not in the correct address space). We have to* calculate the offset.** Returns:* r3, r4, r6 corrupted* r5 proc_info pointer in physical address space* r9 cpuid*/.type __lookup_processor_type, %function__lookup_processor_type://把下面红色的3位置处的地址放到r3,是物理地址。adr r3, 3f//把红3放到r9,r5__proc_info_begin,r6__proc_info_endldmda r3, {r5, r6, r9}//计算物理地址与虚拟地址的偏移放到r3.sub r3, r3, r9 get offset between virtphys//把r5 r6转化为物理地址。add r5, r5, r3 convert virt addresses toadd r6, r6, r3 physical address space//从协处理器读出cpu的ID放到r9.mrc p15, 0, r9, c0, c0 get processor id//把proc_info_list里的cpu_val和cpu_mask读到r3和r4.处理器信息存放在(arch/arm/mm/arm/proc-arm920.S cpu_val0x41009200,cpu_mask0xff00fff0).判断是否cpu_valcpu_maskr9)如果失败r50。1: ldmia r5, {r3, r4} value, maskand r4, r4, r9 mask wanted bitsteq r3, r4beq 2fadd r5, r5, #PROC_INFO_SZ sizeof(proc_info_list)cmp r5, r6blo 1bmov r5, #0 unknown processor2: mov pc, lr/** This provides a C-API version of the above function.*///这个是C函数调用的API如此学一下如何写被C调用的汇编函数。ENTRY(lookup_processor_type)stmfd sp!, {r4 - r6, r9, lr}bl __lookup_processor_typemov r0, r5ldmfd sp!, {r4 - r6, r9, pc}/** Look in include/asm-arm/procinfo.h and arch/arm/kernel/arch.[ch] for* more information about the __proc_info and __arch_info structures.*/.long __proc_info_begin.long __proc_info_end3: .long ..long __arch_info_begin.long __arch_info_end/** Lookup machine architecture in the linker-build list of architectures.* Note that we cant use the absolute addresses for the __arch_info* lists since we arent running with the MMU on (and therefore, we are* not in the correct address space). We have to calculate the offset.** r1 machine architecture number* Returns:* r3, r4, r6 corrupted* r5 mach_info pointer in physical address space*///这个和上面那个__lookup_processor_type语法格式是完全一样的把loader传过来的机器号和从内核里定义的相比较看是否相等如果相等会把这个mach_info存放到r5里mach_info在文件arch/arm/mach-s3c2410/mach-smdk2410.c里而机器号在include/asm/mach-type.h里。.type __lookup_machine_type, %function__lookup_machine_type:adr r3, 3bldmia r3, {r4, r5, r6}sub r3, r3, r4 get offset between virtphysadd r5, r5, r3 convert virt addresses toadd r6, r6, r3 physical address space1: ldr r3, [r5, MACHINFO_TYPE] get machine typeteq r3, r1 matches loader number?beq 2f foundadd r5, r5, #SIZEOF_MACHINE_DESC next machine_desccmp r5, r6blo 1bmov r5, #0 unknown machine2: mov pc, lr/** This provides a C-API version of the above function.*/ENTRY(lookup_machine_type)stmfd sp!, {r4 - r6, lr}mov r1, r0bl __lookup_machine_typemov r0, r5ldmfd sp!, {r4 - r6, pc}2、创建面表/** Setup the initial page tables. We only setup the barest* amount which are required to get the kernel running, which* generally means mapping in the kernel code.** r8 machinfo* r9 cpuid* r10 procinfo** Returns:* r0, r3, r5, r6, r7 corrupted* r4 physical page table address*/.type __create_page_tables, %function__create_page_tables://把SDRAM的物理地址放到r5.ldr r5, [r8, #MACHINFO_PHYSRAM] physram//用pgtbl宏计算出面表的物理地址在内核代码前16kpgtbl r4, r5 page table address/** Clear the 16K level 1 swapper page table*///把16K页表内容清0.mov r0, r4mov r3, #0add r6, r0, #0x40001: str r3, [r0], #4str r3, [r0], #4str r3, [r0], #4str r3, [r0], #4teq r0, r6bne 1b//从处理器信息结构读出MMU参数。ldr r7, [r10, #PROCINFO_MMUFLAGS] mmuflags/** Create identity mapping for first MB of kernel to* cater for the MMU enable. This identity mapping* will be removed by paging_init(). We use our current program* counter to determine corresponding section base address.*///为了打开MMU功能时不出问题把当前物理地址的1Mb范围内与虚拟地址做相等映射。mov r6, pc, lsr #20 start of kernel sectionorr r3, r7, r6, lsl #20 flags kernel base//[r4, r6, lsl #2]代表页表的项所在的地址这个#2是因为每个页表项占用4个字节r3代表向相应的页表项地址所填写的内容也就是要映射的虚拟地址。str r3, [r4, r6, lsl #2] identity mapping/** Now setup the pagetables for our kernel direct* mapped region. We round TEXTADDR down to the* nearest megabyte boundary. It is assumed that* the kernel fits within 4 contigous 1MB sections.*///把内核的前4MB虚拟地址映射到相应的物理地址。add r0, r4, #(TEXTADDR 0xff000000) 18str r3, [r0, #(TEXTADDR 0x00f00000) 18]!add r3, r3, #1 20str r3, [r0, #4]! KERNEL 1MBadd r3, r3, #1 20str r3, [r0, #4]! KERNEL 2MBadd r3, r3, #1 20str r3, [r0, #4] KERNEL 3MB/** Then map first 1MB of ram in case it contains our boot params.*///把内核开始地址映射到物理ram的开始处。add r0, r4, #VIRT_OFFSET 18//页表项的偏移。orr r6, r5, r7//物理ram的开如地址。str r6, [r0]mov pc, lr3、调用处理器相关的初始化函数__arm920_setup:mov r0, #0mcr p15, 0, r0, c7, c7 invalidate I,D caches on v4mcr p15, 0, r0, c7, c10, 4 drain write buffer on v4mcr p15, 0, r0, c8, c7 invalidate I,D TLBs on v4//读出cp15的c1寄存器到r0,清除并设置最终目录如下使能MMU禁止内存地址对齐检查功能使能cache,禁止写入缓存控制中断向量表的地址为高端。mrc p15, 0, r0, c1, c0 get control register v4ldr r5, arm920_cr1_clearbic r0, r0, r5ldr r5, arm920_cr1_setorr r0, r0, r5mov pc, lr//这里的arm920_cr1_clear0x3f3f, arm920_cr1_set0x31354、打开MMU/** Setup common bits before finally enabling the MMU. Essentially* this is just loading the page table pointer and domain access* registers.*/.type __enable_mmu, %function__enable_mmu:#ifdef CONFIG_ALIGNMENT_TRAP//设置地址对齐检查功能。orr r0, r0, CR_A#elsebic r0, r0, #CR_A#endif#ifdef CONFIG_CPU_DCACHE_DISABLEbic r0, r0, #CR_C#endif#ifdef CONFIG_CPU_BPREDICT_DISABLEbic r0, r0, #CR_Z#endif#ifdef CONFIG_CPU_ICACHE_DISABLEbic r0, r0, #CR_I#endif//设置MMU中的域mov r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \domain_val(DOMAIN_IO, DOMAIN_CLIENT))mcr p15, 0, r5, c3, c0, 0 load domain access register//把页表基址设置MMU到MMU的C2。mcr p15, 0, r4, c2, c0, 0 load page table pointerb __turn_mmu_on/** Enable the MMU. This completely changes the structure of the visible* memory space. You will not be able to trace execution through this.* If you have an enquiry about this, *please* check the linux-arm-kernel* mailing list archives BEFORE sending another post to the list.** r0 cp#15 control register* r13 *virtual* address to jump to upon completion** other registers depend on the function called upon completion*/.align 5.type __turn_mmu_on, %function__turn_mmu_on:mov r0, r0//打开MMUmcr p15, 0, r0, c1, c0, 0 write control regmrc p15, 0, r3, c0, c0, 0 read id regmov r3, r3mov r3, r3mov pc, r13asmlinkage void __init start_kernel(void){char * command_line;extern struct kernel_param __start___param[], __stop___param[];/** Interrupts are still disabled. Do necessary setups, then* enable them*/lock_kernel();page_address_init();printk(KERN_NOTICE);printk(linux_banner);//平台相关初始化SDRAM、CPU。setup_arch(command_line);//smpsetup_per_cpu_areas();smp_prepare_boot_cpu();//进程调度队列初始化。sched_init();preempt_disable();//设置每个节点的zonelist。build_all_zonelists();//smppage_alloc_init();printk(KERN_NOTICE Kernel command line: %s\n, saved_command_line);parse_early_param();parse_args(Booting kernel, command_line, __start___param,__stop___param - __start___param,unknown_bootoption);sort_main_extable();//copy 中断向量表。trap_init();rcu_init();//初始化中断向量表调用平台中断初始化函数。init_IRQ();//进程PID哈希表。pidhash_init();//定时器软中断。init_timers();//软中断tasklet.softirq_init();//初始化时钟中断。time_init();//控制台初始化开始打印。console_init();if (panic_later)panic(panic_later, panic_param);profile_init();//打开CPU的中断。local_irq_enable();#ifdef CONFIG_BLK_DEV_INITRDif (initrd_start !initrd_below_start_ok initrd_start min_low_pfn PAGE_SHIFT) {printk(KERN_CRIT initrd overwritten (0x%08lx 0x%08lx) - disabling it.\n,initrd_start,min_low_pfn PAGE_SHIFT);initrd_start 0;}#endif//虚拟文件系统数据结构分配。vfs_caches_init_early();//把bootmem不用的内存回收到页框分配器。mem_init();//slab分配器初化。kmem_cache_init();//NUMAsetup_per_cpu_pageset();numa_policy_init();if (late_time_init)late_time_init();calibrate_delay();//PID位图初始化。pidmap_init();//空pgtable_cache_init();prio_tree_init();anon_vma_init();#ifdef CONFIG_X86if (efi_enabled)efi_enter_virtual_mode();#endif//进程创建数据结构初始化。fork_init(num_physpages);//多种SLAB分配器的分配。proc_caches_init();buffer_init();unnamed_dev_init();//空。key_init();security_init();//文件系统相关数据初始化。vfs_caches_init(num_physpages);//radix_tree_init();//信号。signals_init();/* rootfs populating might need page-writeback */page_writeback_init();//PROC文件系统。#ifdef CONFIG_PROC_FSproc_root_init();#endifcpuset_init();check_bugs();acpi_early_init();//启动INIT进程作剩余部分初始化。rest_init();}