Linux内核分析 SMP启动
- 格式:ppt
- 大小:271.50 KB
- 文档页数:30
Linux 内核启动分析1. 内核启动地址1.1. 名词解释ZTEXTADDR解压代码运行的开始地址。
没有物理地址和虚拟地址之分,因为此时MMU处于关闭状态。
这个地址不一定时RAM的地址,可以是支持读写寻址的flash等存储中介。
Start address of decompressor. here's no point in talking about virtual or physical addresses here, since the MMU will be off at the time when you call the decompressor code. Y ou normally call the kernel at this address to start it booting. This doesn't have to be located in RAM, it can be in flash or other read-only or read-write addressable medium.ZRELADDR内核启动在RAM中的地址。
压缩的内核映像被解压到这个地址,然后执行。
This is the address where the decompressed kernel will be written, and eventually executed. The following constraint must be valid:__virt_to_phys(TEXTADDR) == ZRELADDRThe initial part of the kernel is carefully coded to be position independent.TEXTADDR内核启动的虚拟地址,与ZRELADDR相对应。
一般内核启动的虚拟地址为RAM的第一个bank地址加上0x8000。
【内核】linux内核启动流程详细分析Linux内核启动流程 arch/arm/kernel/head-armv.S 该⽂件是内核最先执⾏的⼀个⽂件,包括内核⼊⼝ENTRY(stext)到start_kernel间的初始化代码, 主要作⽤是检查CPU ID, Architecture Type,初始化BSS等操作,并跳到start_kernel函数。
在执⾏前,处理器应满⾜以下状态:r0 - should be 0r1 - unique architecture numberMMU - offI-cache - on or offD-cache – off1/* 部分源代码分析 */2/* 内核⼊⼝点 */3 ENTRY(stext)4/* 程序状态,禁⽌FIQ、IRQ,设定SVC模式 */5 mov r0, #F_BIT | I_BIT | MODE_SVC@ make sure svc mode6/* 置当前程序状态寄存器 */7 msr cpsr_c, r0 @ and all irqs disabled8/* 判断CPU类型,查找运⾏的CPU ID值与Linux编译⽀持的ID值是否⽀持 */9 bl __lookup_processor_type10/* 跳到__error */11 teq r10, #0 @ invalid processor?12 moveq r0, #'p' @ yes, error 'p'13 beq __error14/* 判断体系类型,查看R1寄存器的Architecture Type值是否⽀持 */15 bl __lookup_architecture_type16/* 不⽀持,跳到出错 */17 teq r7, #0 @ invalid architecture?18 moveq r0, #'a' @ yes, error 'a'19 beq __error20/* 创建核⼼页表 */21 bl __create_page_tables22 adr lr, __ret @ return address23 add pc, r10, #12 @ initialise processor24/* 跳转到start_kernel函数 */25 b start_kernel1. start_kernel()函数分析 下⾯对start_kernel()函数及其相关函数进⾏分析。
在Linux内核启动时,可以通过解析参数来配置内核的行为。
这些参数通常由引导加载程序(如GRUB)或内核命令行传递。
以下是一些常见的内核启动解析参数:
1. `root=`:指定根文件系统的设备或UUID。
例如,`root=/dev/sda1`或
`root=UUID=12345678-1234-5678-1234-56789abcdef`。
2. `init=`:指定作为第一个进程启动的程序的路径。
通常是init进程(如`/sbin/init`)。
3. `ro`或`rw`:指定根文件系统以只读(read-only)或读写(read-write)模式挂载。
4. `quiet`或`silent`:禁止内核在启动期间输出冗长的消息。
5. `loglevel=`:设置内核的日志级别。
较低的值会产生更多的调试信息,较高的值则会减少输出。
例如,`loglevel=7`。
6. `nomodeset`:禁用图形模式设置,可能有助于解决某些图形问题。
7. `acpi=off`:禁用ACPI(高级配置与电源接口)功能。
8. `irqpoll`:在中断处理期间轮询(poll)IRQ线,用于解决某些硬件兼容性问题。
9. `debug`:启用内核调试模式,产生更详细的调试信息。
这只是一小部分常见的内核启动解析参数,实际上还有许多其他可用的参数。
你可以根据需要选择和配置这些参数来满足特定的需求。
【IT专家】Linux在多核处理器-SMP中的3个进程(每个进程在不同的核心中运行)之间共享内存本文由我司收集整编,推荐下载,如有疑问,请与我司联系Linux 在多核处理器/ SMP中的3个进程(每个进程在不同的核心中运行)之间共享内存Linux在多核处理器/ SMP中的3个进程(每个进程在不同的核心中运行)之间共享内存[英]Linux Shared memory between 3 processes (each process running in different core) in Multicore Processor/SMP目的:I want to synchronize three different processes, so I thought of using shared memory between the processes. So I have forked two child’s from one process and create d a shared memory segment before creating the child’s. My intention is to run the child processes and parent process in different cores to make it parallel execution. So I have used the affinity control to assign the according CPU. Both the child’s will wa it in indefinite while loop (consuming on the same CPU which is assigned) until it gets the trigger from the parent via shared memory. So when the parent writes some specific character/string, the child should come out loop and start executing the rest of the code.我想同步三个不同的进程,因此我想在进程之间使用共享内存。
【整理】Linux中对于SMP系统的实现
Linux从2.0开始增加对SMP系统的⽀持。
在2.2前的内核中,SMP实现在⽤户级,Linux内核本⾝并不能因为有多个处理器⽽得到加速;在2.4内核后,SMP实现在核⼼级,使⽤多处理器可以加快内核的处理速度。
1、SMP中的系统引导
在同⼀时间,⼀个“上下⽂”只能由⼀个CPU处理。
在系统引导和初始化阶段,只有⼀个“上下⽂”,只能由⼀个处理器来处理。
BP完成系统的引导和初始化,并创建起多进程,从⽽可以由多个处理器同时参与处理时,才启动所有的AP,让它们在完成⾃⾝的初始化后投⼊运⾏。
在Linux中,SMP系统的引导是⼀个分阶段的过程,这中间需要主CPU和次CPU在⼏个地⽅进⾏同步,已取得相同的同步和协调,最终基本在同⼀时间进⼊SMP的进程调度。
Linux中SMP系统在Intel的Pentium上的引导过程如下:
2、SMP中的进程调度
在SMP结构的系统中同时有多个进程在运⾏,需要Linux在进程的task_struct数据结构中加上两个字段,⼀个是has_cpu,表进程是否在CPU上运⾏,另⼀个是processor,表进程在哪个CPU上运⾏。
Linux操作系统内核对SMP(对称多处理器)的支持
高珍;吴永明;周卫华
【期刊名称】《计算机应用研究》
【年(卷),期】2002(019)009
【摘要】详细介绍了Linux操作系统内核是怎样支持SMP(对称多处理器)系统工作的,并具体分析了其内核源代码的实现过程.
【总页数】3页(P62-63,67)
【作者】高珍;吴永明;周卫华
【作者单位】同济大学,计算机科学与工程系,上海,200092;同济大学,计算机科学与工程系,上海,200092;同济大学,计算机科学与工程系,上海,200092
【正文语种】中文
【中图分类】TP393
【相关文献】
1.Linux
2.6内核对SMP系统支持的研究 [J], 李兰英;温现杰
2.片多处理器和对称多核处理器的研究进展 [J], 王永明;;
3.支持对称多处理器结构的操作系统设计 [J], 任晓瑞;时磊
4.基于多核对称最小二乘支持向量机的永磁同步电机混沌建模 [J], 陈强;任雪梅
5.MIPS科技宣布其对称多处理(SMP)支持MIPS-Based^(TM) SoC上的Android^(TM)平台 [J],
因版权原因,仅展示原文概要,查看原文内容请购买。
linuxSMP启动过程学习笔记(转载)linux SMP 启动过程学习笔记1. SMP 硬件体系结构:对于 SMP 最简单可以理解为系统存在多个完全相同的 CPU ,所有 CPU 共享总线,拥有自己的寄存器。
对于内存和外部设备访问,由于共享总线,所以是共享的。
Linux 操作系统多个 CPU 共享在系统空间上映射相同,是完全对等的。
由于系统中存在多个 CPU ,这是就引入一个问题,当外部设备产生中断的时候,具体有哪一个 CPU 进行处理?为此, intel 公司提出了 IO APCI 和 LOCAL APCI 的体系结构。
IO APIC 连接各个外部设备,并可以设置分发类型,根据设定的分发类型,中断信号发送的对应 CPU 的 LOCAL APIC 上。
LOCAL APIC 负责本地 CPU 的中断处理, LOCAL APIC 不仅可以接受IO APIC 的中断,也需要处理本地CPU 产生的异常。
同时LOCAL APIC 还提供了一个定时器。
如何确定那个 CPU 是引导 CPU ?根据 intel 公司中的资料,系统上电后,会根据 MP Initialization Protocol 随机选择一个 CPU 作为 BSP ,只有 BSP 会运行 BIOS 程序,其他 AP 都进入等待状态, BSP 发送 IPI 中断触发后才可以运行。
具体的 MP Initialization Protocol 细节,可以参考 Intel? 64 and IA-32 Architectures Software Developer’s Ma nual Volume 3A: System Programming Guide, Part 1 第 8 章。
引导 CPU 如何控制其他 CPU 开始运行?BSP 可以通过 IPI 消息控制 AP 从指定的起始地址运行。
CPU 中集成的 LOCAL APIC 提供了这个功能。
S h e n z h e n F a. lizhiguo0532@ 2010-6-041Linux 2.6lizhiguo0532@ 2010-6-04----------------------------------------------------------------------------------------------------------------------/sz_farsight---------------------------------------------------------------------------------------------------------------------- ^_^SDMakefile uImageMakefile uImage *.o1. arm-linux-gnu-ld arch/arm/kernel/vmlinux.ldsarch/arm/kernel/head.o arch/arm/kernel/init_task.oS h e nz h e n F a r silizhiguo0532@ 2010-6-042 vmlinux.lds2. 3. 4. piggy.gz5.S h e ns i gh t In c . lizhiguo0532@ 2010-6-043piggy.gz piggy.o ld6. arm-linux-gnu-ld arch/arm/boot/compressed/piggy.o27 *(.piggydata) piggydata piggydata Image piggy.gzvmlinux.ldsS h e n zc . lizhiguo0532@ 2010-6-0447.8.uboot arch/arm/boot/compressed/piggy.gz- arch/arm/boot/compressed/piggy.o 0xc0008000 (arch/arm/boot/compressed/vmlinux- arch/arm/boot/zImage) 0x0 0x00000000 0x0 0x30008000 Image vmlinux 0xc0008000S h e n z h e nF a r s i g h t In c . lizhiguo0532@ 2010-6-0450x0 arch/arm/boot/compressed/head.s misc.c 1. uboot thekernelr0—>r8,r1- r7.2. LC00x0 0x300080003. 0x00x30008000 CONFIG_ZBOOT_ROM r2, r3 r5, r6, ip, sp r6 ip got4. clear bss5. cache 4K.align.section ".stack", "w"user_stack: .space 4096S h eh tI nc.lizhiguo0532@ 2010-6-0466.Zreladdr vmlinuxarch/arm/mach-s3c2410/Makefile.bootarch/arm/boot/MakefileS h e nz h e n F a r si gh t I n c .lizhiguo0532@ 2010-6-047 arch/arm/boot/compressed/Makefile ZRELADDR vmlinux ImageuImage load zImage load uImage zImage uboot zImage load entryuImage zImage mkimage uImage -a data load -e entry arch/arm/boot/Makefile0x30008000S h e n z h e n F a r s i g h t In c . lizhiguo0532@ 2010-6-048 r4 Image 0x30008000 r5 zImage r2 zImager4>=r2, r4=0x30800000 Image r2=0x30008000+(zImage+bss size)+stack size 4K + malloc size 64K zImage Image 0x30800000r4+4M<r5, r5=0x30800000 r4=30008000 zImage r4r4+4M>r5, r4=r5=0x30008000 0x30008000@ r0 = malloc end or decompress space,@ r1 = sp end or malloc begin,@ r2 = malloc end ,@ r3 = architecture IDdecompress_kernelmalloc 0x300080007. decompress_kernel in arch/arm/boot/compressed/misc.cS h e nn F a r s i gh t I n c .lizhiguo0532@ 2010-6-049Gunzip() lib/inflate.c gunzip 8. 128add r0, r0, #127bic r0, r0, #127 @ align the kernel length9 head.S 0x30008000R1 128 r2 reloc_start r3 reloc_end head.Scache_clean_flush cache cache reloc_startzImage gdb9. reloc_startS h e n z h enF a r s i g h t I n c . lizhiguo0532@ 2010-6-0410* r0 = decompressed kernel length * r1-r3 = unused* r4 = kernel execution address* r5 = decompressed kernel start* r6 = processor ID* r7 = architecture ID* r8-r14 = unused0x30008000 cache r0 r1 pc 0x30008000 /node/3VMLINUX arch/arm/kernel/head.S init/Main.c 0x0 0xC0008000Mmu I Cache D Cache r0=0 r1=architecture ID arch/arm/kernel/vmlinux.lds stext1. SVC FIR IRQ2. __lookup_processor_type cp15 cpuid .init proc_info_list cpu3. __lookup_machine_type uboot machinearchitecture number .init machine number machine_descS h e n z h n F a r si g h t I n c .lizhiguo0532@ 2010-6-0411 ……………………arch-arm-kernel-head.Sarch-arm-kernel-head/node/4start_kernel in init/Main.c1. printk(linux_banner)2. a. setup_processor()proc_info_list list cpu_name cpuname idproc_arch system_utsname= list->arch_name armv4telf_platform= list->elf_name v4 elf_hwcap = list->elf_hwcap;/* 1|2|4 */ cpu_proc_init()Cpu-single.h#define cpu_proc_init __cpu_fn(CPU_NAME,_proc_init)#define __cpu_fn(name,x) __catify_fn(name,x)#define __catify_fn(name,x) name##xCPU_NAME = cpu_arm920cpu_proc_init(); cpu_arm920_proc_init()proc_arm920.S b. mdesc = setup_machine(machine_arch_type).init machine_desclist list-namec. machine_name = mdesc->name machine_named. tags = phys_to_virt(mdesc->boot_params)uboot 0x300001000xc0000100e.if (tags->hdr.tag == ATAG_CORE) {if (meminfo.nr_banks != 0) /* meminfo defined in setup.c */squash_mem_tags(tags);parse_tags(tags);}static struct meminfo meminfo __initdata = { 0, };in steup.cparse_tags(tags) in steup.cS h e n z h e n F a r s i g h t In clizhiguo0532@ 2010-6-0412Steup_arch()- parse_tags()- parse_tag(), all function in steup.c __tagtable_begin, __tagtable_end arch/arm/kernel/vmlinux.ldsparse_tag()parseIgnoring unrecognised tag 0x%08x\n ubootf. struct mm_struct init_mm = INIT_MM(init_mm);init_mm.start_code = (unsigned long) &_text;init_mm.end_code = (unsigned long) &_etext;init_mm.end_data = (unsigned long) &_edata;init_mm.brk = (unsigned long) &_end;_text, _etext, _edata, _end arch/arm/kernel/vmlinux.ldsg. parse_cmdline(cmdline_p, from) uboot commond_linefrom command_linecommand_linestart_kernerl mem initrdstart_kernel()->parse_option() mem initrdcommand_line *cmdline_pstart_kernelmem initrdh. paging_init(&meminfo, mdesc);/**/ in arch/arm/mm/init.cmemtable_init(mi)/bbstcon,board,Embedded,reid,1165977462.html0xffff0000mdesc->map_io() smdk2410arch/arm/mach-s3c2410/mach-smdk2410.c Linux , smdk2410_map_io() 1 iotable_init(s3c_iodesc, GPIO,IRQ,MEMCTRL,UARTS h e nz h e n F a r s i gh t In c . lizhiguo0532@ 2010-6-0413 2 (cpu->map_io)(mach_desc, size) LCD, map.h S3C2410_ADDR(x) ((void __iomem *)0xF0000000 + (x)) IO 0xF0000000 1M 1. GPIO IRQ UART MEMCRTL WATCHDOG USB 2. kmalloc 0x30008000 phys_to_virt virt_to_ phys 3. mmu TTB 0x30004000 16K mmu arch/arm/kernel/head.S 4M mmu sector Uarth.request_standard_resources(&meminfo, mdesc) memory kernel_text kernel_data video_ram new new resource NULLi. cpu_init() in arch/arm/kernel/setup.ccpu cpu id cache IRQ ABT UND stack 12 svci. __mach_desc_SMDK2410_typeinit_arch_irq init_machine system_timer3. sched_init()init_idle (current, smp_processor_id()) idle4. preempt_disable()5. (zone) build_all_zonelists()6. printk(KERN_NOTICE "Kernel command line: %s\n", saved_command_line); uboot command_line setup_arch7. parse_early_param()S h e n z h e n F a r s i g h t In c . lizhiguo0532@ 2010-6-0414 __setup setup_arch &command_line command_linesaved_command_line8. parse_args("Booting kernel", command_line, __start___param,__stop___param - __start___param,&unknown_bootoption);parse_early_param(); setup paramcommand_line setup_arch__start___param param System.map__stop___param - __start___paramunknown_bootoption paramparse_one()parse_one() param __setupLinux bootargs9. sort_main_extable()__start___ex_table __stop___ex_table *(__ex_table) struct exception_table_entry insn10. setup_arch- paging_init- memtable_initinit_maps, alloc_bootmem_low_pages ARM 0xFFFF0000 0xFFFF0000trap_init .Lcvectors 0xffff0000 __stubs_start __stubs_end 0xffff0200 0xffff0500 0xffff0000 cache DOMAIN_USER DOMAIN_MANAGER DOMAIN_CLIENT11.rcu_init() cpu struct rcu_dataper_cpu_rcu_data per_cpu_rcu_bh_data.12.init_IRQstruct irqdesc irq_desc[NR_IRQS], irq_desc[n] bad_irq_desc pendS h e nz h e n F a r s i gh t I n c . lizhiguo0532@ 2010-6-0415 init_arch_irq setup_arch smdk2410_init_irq in mach-smdk2410.cs3c24xx_init_irq do_level_IRQ do_edge_IRQ __do_irquart ADC13.pidhash_init()pid_hash hash pidhash_shift pidhash_shift min 12 hash hash pid_hash[n](n=1~3), hash hash struct hlist_head first NULL14.init_timers()struct tvec_t_base_s per_cpu_tvec_bases, per_cpu_tvec_bases lock15.softirq_initS h e n z h e n F a r s i gh t I n c .lizhiguo0532@ 2010-6-041616.time_init() timersetup_archtime_init if s3c2410_timer_init timer417.console_initprintk log_bufa. tty_register_ldisc TTYtty ttyttytty ttyS h e n z h e n F ar s i g h t I n c . lizhiguo0532@ 2010-6-0417 ppp tty tty b. s3c24xx_serial_initconsole /*vmlinux.lds.S__con_initcall_start = .;*(.con_initcall.init)__con_initcall_end = .;con_initcall.initfn .con_initcall.init :#define console_initcall(fn) \static initcall_t __initcall_##fn \__attribute_used____attribute__((__section__(".con_initcall.init")))=fn*///:console_initcall(s3c24xx_serial_initconsole);//:start_kernel->console_init->s3c24xx_serial_initconsolecall = __con_initcall_start; /* console_initcall */while (call < __con_initcall_end) {(*call)();call++;}18.profile_init()/* *///profile// bootargs profile/*profile menuconfig profiling support1. profileprofile profile=1 profile=schedule 12. /proc/profile readprofilereadprofile -m /proc/kallsyms | sort -nr > ~/cur_profile.log,readprofile -r -m /proc/kallsyms |sort -nr,readprofile -r && sleep 1 && readprofile -m /proc/kallsymsS h e n z h e n F a r s i g h t In c . lizhiguo0532@ 2010-6-0418|sort -nr >~/cur_profile.log 3. /proc/profile profile profile=?profile=schedule ? schedule schedule*/19.local_irq_enable()IRQ20.mem_init()alloc_bootmem(),alloc_bootmem_low(),alloc_bootmem_pages()21.kmem_cache_init()slab22. numa_policy_init();if (late_time_init)late_time_init();calibrate_delay();// BogMIPS23. pidmap_init();pgtable_cache_init();prio_tree_init();/*index_bits_to_maxindex[BITS_PER_LONG]index_bits_to_maxindex[n] -1index_bits_to_maxindex[BITS_PER_LONG-1] ~0UL*/24 anon_vma_init();/*kmem_cache_creat() struct anon_vmakmem_cache_t anon_vma ,void anon_vma_ctor NULLkmem_cache_t anon_vma_chachepS h e n z h e n F a r s i g h tlizhiguo0532@ 2010-6-0419 */ 25. fork_init(num_physpages);/* */ 26. proc_caches_init();buffer_init();/*kmem_cache_create("buffer_head",sizeof(struct buffer_head), 0,SLAB_RECLAIM_ACCOUNT|SLAB_PANIC, init_buffer_head, NULL) struct buffer_head kmem_cache_t */27. security_init();/* */28. vfs_caches_init(num_physpages);radix_tree_init();signals_init();kmem_cache_create("sigqueue",sizeof(struct sigqueue),__alignof__(struct sigqueue),SLAB_PANIC, NULL, NULL) struct sigqueue kmem_cache_t sigqueue cache line kmem_cache_t sihqueue_cachep.29. page_writeback_init()buffer_pages.30. proc_root_init();/* proc CONFIG_PROC_FS */31. check_bugs();/* arm */32 rest_init()initlinux :0 rest_init()a. in arch/arm/kernel/process.cinitb. schedule() idle schedulec. cpu_idle()0S h e n z h e n F a r s i g h t In c . lizhiguo0532@ 2010-6-0420 init in main.c a. lock_kernel() lock b. smpc. populate_rootfs() initcallsd. do_basic_setup()#define module_init(x) __initcall(x);#define __initcall(fn) device_initcall(fn)#define core_initcall(fn) __define_initcall("1",fn)#define postcore_initcall(fn) __define_initcall("2",fn) #define arch_initcall(fn) __define_initcall("3",fn) #define subsys_initcall(fn) __define_initcall("4",fn) #define fs_initcall(fn) __define_initcall("5",fn) #define device_initcall(fn) __define_initcall("6",fn) #define late_initcall(fn) __define_initcall("7",fn)#define __define_initcall(level,fn) \static initcall_t __initcall_##fn __attribute_used__ \__attribute__((__section__(".initcall" level ".init"))) = fn include/linux/init.harch_initcall initcall module_init init 1 do_basic_setup do_initcalls()S h e n z h e n F a r s i gh t I n c . lizhiguo0532@ 2010-6-0421 Start_kernel * -- rest_init()* -- kernel_thread()* init 1 -- Init* -- populate_rootfs() -- do_basic_setup()* initcall modlue_init -- init_workqueues() -- usermodehelper_init() khelper-- driver_init()-- sysctl_init()-- sock_init() socket-- do_initcalls()*-- (*call)()* initcall-- prepare_namespace()-- name_to_dev_t()root bootargs root=/dev/** root=31:03 /dev/mtdblock3 root /dev/ 31-- mount_root();/* */-- free_initmem() init:Freeing init memory: 116K-- sys_open() and sys_dup(0) 0 1 2-- run_init_process(execute_command) init=/initrd command_line-- cpu_idle() 0init 1 …… run_init_process("/sbin/init");run_init_process("/etc/init");run_init_process("/bin/init");run_init_process("/bin/sh");……S h n n F a r s i g h t In c . lizhiguo0532@ 2010-6-0422 ARM Linux -- -PXA255--- Linux bootargs/u3/99423/article.html/bbstcon,board,Embedded,reid,1165977462.html/node/4。
Linux内核分析:Linux内核启动流程分析(注:本⽂参考资料:朱有鹏嵌⼊式课程、。
本⽂为个⼈学习记录,如有错误,欢迎指正。
内核版本:九⿍公司移植的2.6.35.7)1. Linux内核⾃解压过程uboot完成系统引导以后,执⾏环境变量bootm中的命令;即,将Linux内核调⼊内存中并调⽤do_bootm函数启动内核,跳转⾄kernel的起始位置。
如果内核没有被压缩,则直接启动;如果内核被压缩过,则需要进⾏解压,被压缩过的kernel头部有解压程序。
压缩过的kernel⼊⼝第⼀个⽂件源码位置在/kernel/arch/arm/boot/compressed/head.S。
它将调⽤decompress_kernel()函数进⾏解压,解压完成后,打印出信息“Uncompressing Linux...done,booting the kernel”。
解压缩完成后,调⽤gunzip()函数(或unlz4()、或bunzip2()、或unlz())将内核放于指定位置,开始启动内核。
P.S.:。
2. Linux内核启动准备阶段由内核链接脚本/kernel/arch/arm/kernel/vmlinux.lds可知,内核⼊⼝函数为stext(/kernel/arch/arm/kernel/head.S)。
内核解压完成后,解压缩代码调⽤stext函数启动内核。
P.S.:内核链接脚本vmlinux.lds在内核配置过程中产⽣,由/kernel/arch/arm/kernel/vmlinux.lds.S⽂件⽣成。
原因是,内核链接脚本为适应不同平台,有条件编译的需求,故由⼀个汇编⽂件来完成链接脚本的制作。
ENTRY(stext)setmodePSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode@ and irqs disabledmrcp15, 0, r9, c0, c0 @ 获得处理器ID,并存储在r9寄存器中bl__lookup_processor_type @ 结果返回:描述处理器结构体的地址 r5=procinfo ,处理器ID号 r9=cpuidmovsr10, r5 @ invalid processor (r5=0)?判断内核是否⽀持该处理器beq__error_p @ yes, error 'p'bl__lookup_machine_type @结果返回:描述机器(开发板)的结构体地址 r5=machinfomovsr8, r5 @ invalid machine (r5=0)?判断内核是否⽀持该机器(开发板)beq__error_a @ yes, error 'a'bl__vet_atags @检查uboot给内核的传参ATAGS格式是否正确bl__create_page_tables @建⽴虚拟地址映射页表ldrr13, __switch_data @ address to jump to after(1)关闭IRQ、FIQ中断,进⼊SVC模式。
内核启动过程分析在学习过程中“行走的流云”的博文给了我很大的帮助,我也复制了很多他的总结,在这里感谢他!本文件的代码主要是讲内核开始工作前的准备工作,其工作主要有一下几点:1.进入管理模式,判断处理器ID是否匹配,判断机器ID是否匹配,判断atags指针是否合法。
2.建立页表,实现虚拟地址和物理地址的映射。
3.关闭Icache、Dcache、清空write buffer、使TLB无效4.使能MMU、使能cache跳转到start kernel开始真正的内核运行。
对于经过压缩的内核(zIm age),先运行解压缩decom press_kernel,然后还需要重定位,然后调用内核,就象跳到未压缩的内核中的开始处,内核的s tartup在arch/arm/kernel/head.S中,进行页表初始化和处理器缓存初始化等工作,然后跳到C代码init/main.c中的s tart_kernel,接下来的事情就是大众化工作了,在这里,我们继续分析解压缩后的工作,即是arch/arm/kernel/head.S的工作内容。
首先先说下内核的启动条件:1. CPU必须处于SVC(s upervis or)模式,并且IRQ和FIQ中断都是禁止的;2. MMU(内存管理单元)必须是关闭的, 此时虚拟地址对物理地址;3. 数据cache(Data cache)必须是关闭的4. 指令cache(Ins truction cache)可以是打开的,也可以是关闭的,这个没有强制要求;5. CPU 通用寄存器0 (r0)必须是0;6. CPU 通用寄存器1 (r1)必须是ARM Linux m achine type7. CPU 通用寄存器2 (r2) 必须是kernel param eter lis t 的物理地址/** linux/arch/arm/kernel/head.S** Copyright (C) 1994-2002 Russell King* Copyright (c) 2003 ARM Limited* All Rights Reserved** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License version 2 as* published by the Free Software Foundation.** Kernel startup code for all 32-bit CPUs*/#include <linux/linkage.h>#include <linux/init.h>#include <asm/assembler.h>#include <asm/domain.h>#include <asm/ptrace.h>#include <asm/asm-offsets.h>#include <asm/memory.h>#include <asm/thread_info.h>#include <asm/system.h>#if (PHYS_OFFSET & 0x001fffff)#error "PHYS_OFFSET must be at an even 2MiB boundary!"//boundary(分界线)#endif#define KERNEL_RAM_V ADDR (PAGE_OFFSET + TEXT_OFFSET)#define KERNEL_RAM_PADDR (PHYS_OFFSET + TEXT_OFFSET)/** swapper_pg_dir is the virtual address of the initial page* We place the page tables 16K below KERNEL_RAM_V ADDR. Therefore, we must* make sure that KERNEL_RAM_V ADDR is correctly set. Currently, we expect* the least significant 16 bits to be 0x8000, but we could probably* relax this restriction to KERNEL_RAM_V ADDR >= PAGE_OFFSET + 0x4000.*/swapper_pg_dir 是初始页表的虚拟地址.我们将页表放在KERNEL_RAM_VADDR以下16K的空间中.因此我们必须保证KERNEL_RAM_VADDR已经被正常设置.当前,我们期望的是这个地址的最后16 bits为0x8000,但我们或许可以放宽这项限制到KERNEL_RAM_VADDR >=PAGE_OFFSET + 0x4000.#if (KERNEL_RAM_V ADDR & 0xffff) != 0x8000#error KERNEL_RAM_V ADDR must start at 0xXXXX8000 //内核的起始地址必须是32k对齐#endif.globl swapper_pg_dir //定义一个全局变量.equ swapper_pg_dir, KERNEL_RAM_V ADDR - 0x4000/*页表的起始地址,大小为16kb*/.macro pgtbl, rd /*定义一个宏,在建页表时用到*/ldr \rd, =(KERNEL_RAM_PADDR - 0x4000).endm#ifdef CONFIG_XIP_KERNEL#define KERNEL_ST ART XIP_VIRT_ADDR(CONFIG_XIP_PHYS_ADDR)#define KERNEL_END _edata_loc#else#define KERNEL_ST ART KERNEL_RAM_V ADDR#define KERNEL_END _end /*内核镜像的结束地址(虚拟地址,在vmlinux.lds.S 中定义)*/#endif/** Kernel startup entry point.* ---------------------------*这些参数同通常是由解压代码传进来的* This is normally called from the decompressor code. The requirements* are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0,* r1 = machine nr, r2 = atags pointer.** This code is mostly position independent, so if you link the kernel at* 0xc0008000, you call this at __pa(0xc0008000).** See linux/arch/arm/tools/mach-types for the complete list of machine* numbers for r1. r1中放的是机器ID** We're trying to keep crap to a minimum; DO NOT add any machine specific* crap here - that's what the boot loader (or in extreme极度的, well justified合理的* circumstances事件,详细事件,zImage) is for.不要随意的添加机器ID,要和bootloard 提供的相匹配。
linux-mips启动分析(1)系统加电起动后,MIPS 处理器默认的程序入口是0xBFC00000,此地址在无缓存的KSEG1的地址区域内,对应的物理地址是0x1FC00000,即CPU从0x1FC00000开始取第一条指令,这个地址在硬件上已经确定为FLASH的位置,Bootloader将Linux 内核映像拷贝到RAM 中某个空闲地址处,然后一般有个内存移动操作,目的地址在arch/mips/Makefile 内指定:load-$(CONFIG_MIPS_PB1550) += 0xFFFFFFFF80100000,则最终bootloader定会将内核移到物理地址0x00100000 处。
上面Makefile 里指定的的load 地址,最后会被编译系统写入到arch/mips/kernel/vmlinux.lds 中:OUTPUT_ARCH(mips)ENTRY(kernel_entry)jiffies = jiffies_64;SECTIONS{. = 0xFFFFFFFF80100000;/* read-only */_text = .; /* Text and read-only data */.text : {*(.text)...这个文件最终会以参数-Xlinker --script -Xlinker vmlinux.lds 的形式传给gcc,并最终传给链接器ld 来控制其行为。
ld 会将 .text 节的地址链接到0xFFFFFFFF80100000 处。
关于内核ELF 文件的入口地址(Entry point),即bootloader 移动完内核后,直接跳转到的地址,由ld 写入ELF的头中,其会依次用下面的方法尝试设置入口点,当遇到成功时则停止:a. 命令行选项-e entryb. 脚本中的ENTRY(symbol)c. 如果有定义start 符号,则使用start符号(symbol)d. 如果存在 .text 节,则使用第一个字节的地址。
Linux内核启动参数详解1.环境:Ubuntu 16.04Linux linuxidc 4.4.0-89-generic #112-Ubuntu SMP Mon Jul 31 19:38:41 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux2.查看当前linux内核的启动参数:cat /proc/cmdline笔者的输出内容如下:BOOT_IMAGE=/boot/vmlinuz-4.4.0-89-generic root=UUID=bef418fa-4202-4513-b39b-cde6a5d9753f ro quiet splash vt.handoff=73.开始解析root=UUID=bef418fa-4202-4513-b39b-cde6a5d9753f :这⼀串可以⽤root=/dev/sda1(假如根⽂件系统在第⼀个分区)来代替,但是不能⽤root=(hd0,msdos1)来代替ro : 启动时以只读⽅式挂载根⽂件系统quiet: 不进⾏打印信息的输出,所以去掉此项将会迎来很多打印信息splash: 显⽰开机动画vt.handoff=7 : 图形界⾯会去使⽤tty7,此项⽤来禁⽌splash占⽤tty7,因此如果将splash参数去掉,此项就⽆效了4.添加新的启动参数vi /boot/grub/grub.cfg此⽂件中会有第2步输出的内容,在其后追加参数即可,例如:笔者的grub.cfg⽂件中就有如下⾏:(是不是与第2步输出的信息有些类似)linux /boot/vmlinuz-4.4.0-89-generic root=UUID=bef418fa-4202-4513-b39b-cde6a5d9753f ro quiet splash $vt_handoff假设笔者要加⼊参数dwc_otg.speed=1,那么修改后如下:linux /boot/vmlinuz-4.4.0-89-generic root=UUID=bef418fa-4202-4513-b39b-cde6a5d9753f ro quiet splash $vt_handoff dwc_otg.speed=1⾄此保存此⽂件重启即可使此参数⽣效5.为何没有使⽤update-grub来更新grub.cfg⽂件呢?update-grub命令⽆法满⾜更细致的内核参数修改需求。
基于SMP的Linux内核自旋锁分析
彭正文;徐新爱
【期刊名称】《江西教育学院学报》
【年(卷),期】2005(26)3
【摘要】现代操作系统中多支持SMP系统,而在SMP系统中一个必须解决的问题就是多个CPU之间的并发执行问题,Linux也不例外.在Linux内核中,实现并执行的方法有许多,其中包括信号量、自旋锁、原语操作和等待队列等,但对SMP的并发实现则主要采用自旋锁机制.本文通过对Linux 2.4.20内核源码分析,使用实例简要说明读写自旋锁在SMP的并发机制及实现.
【总页数】4页(P23-25,28)
【作者】彭正文;徐新爱
【作者单位】江西教育学院数计系,江西南昌,330029;江西教育学院数计系,江西南昌,330029
【正文语种】中文
【中图分类】TP316.9
【相关文献】
1.基于SMP结构的linux内核进程调度的研究 [J], 李锋涛;郑晓曦
2.基于SMP结构的linux内核进程调度的研究 [J], 李锋涛;郑晓曦
3.一种Linux内核自旋锁死锁检测机制的设计与实现 [J], 张文盛;侯整风
4.基于SMPSO-SVM的土石坝运行期渗流\r监测模型的建立与运用 [J], 安海
5.基于SMPSO的多初始故障场景下的电网安全分析 [J], 罗杰;李晨晨
因版权原因,仅展示原文概要,查看原文内容请购买。