嵌入式Linux——分析kernel运行过程(1):kernel第一阶段

[kernel 启动流程] (第七章)第一阶段之——跳转到start_kernel 零、说明本文是《[kernel 启动流程] (第一章)概述》的延伸, 阅读本文前建议先阅读《[kernel 启动流程] (第一章)概述》1、kernel启动流程第一阶段简单说明arch/arm/kernel/head.S kernel入口地址对应stext ENTRY(stext) 第一阶段要做的事情,也就是stext的实现内容设置为SVC模式,关闭所有中断 获取CPU ID,提取相应的proc 阅读详情

简介:

        本章主要介绍在2.6.22.6内核中,代码的运行过程。而这里主要介绍kernel第一阶段的汇编代码部分。在这部分我们将讲解内核如何对单板控制器信息和机器ID的进行检测。同时也会讲解内核如何创建页表和使能mmu。

声明:

        本文主要是看了韦东山老师的视频后所写,希望对你有所帮助。

u-boot版本 : u-boot-1.1.6

开发板 : JZ2440

Linux内核 : Linux-2.6.22.6

起始汇编代码:

        我们知道不管是在u-boot中还是在kernel中,起始的代码都是汇编代码。这是因为在编译器中汇编代码较C语言代码转化的效率更高,因此在硬件中汇编代码的运行效率更高。同时我们也应该清楚汇编语言较C语言更低级,而对于硬件来说越低级的代码运行情况越好。所以在代码开始的时候使用汇编代码更利于底层程序的运行。

        而在讲内核程序之前,我们应该先回顾一下u-boot所做的工作。u-boot的工作是加载并启动内核,而在u-boot启动内核之前,他会为内核传递三个参数:0,单板的机器ID,以及TAG参数的首地址。而这三个参数被分别存放在内核寄存器r0,r1,r2中。

        下面我们看内核代码了。内核要做的第一件事为:通过控制当前程序状态寄存器将cpu设置为管理模式,并关闭中断和快速中断。他的代码在arch\arm\kernel\head.S :

	msr	cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ ensure svc mode
						@ and irqs disabled

        与u-boot相同,内核要做的第一件事也是将CPU设置为管理模式来让内核运行在特权模式下。从而可以使内核代码在运行时不受任何其他权限的限制。

        接下来内核要通过操作协处理寄存器来获得单板的处理器信息,并将获得的单板处理器信息与内核中所保存的处理器信息进行比较来确定内核中是否存在所要移植的单板。他的代码在arch\arm\kernel\head-common.S:

	mrc	p15, 0, r9, c0, c0		@ get processor id
	bl	__lookup_processor_type		@ r5=procinfo r9=cpuid

        现在我们进入__lookup_processor_type来看在这个函数中做了什么:

ENTRY(lookup_processor_type)
	stmfd	sp!, {r4 - r7, r9, lr}
	mov	r9, r0
	bl	__lookup_processor_type
	mov	r0, r5
	ldmfd	sp!, {r4 - r7, r9, pc}

/*
 * Read processor ID register (CP#15, CR0), and look up in the linker-built
 * supported processor list.  Note that we can't use the absolute addresses
 * for the __proc_info lists since we aren't running with the MMU on
 * (and therefore, we are not in the correct address space).  We have to
 * calculate the offset.
 *
 *	r9 = cpuid
 * Returns:
 *	r3, r4, r6 corrupted
 *	r5 = proc_info pointer in physical address space
 *	r9 = cpuid (preserved)
 */
	.type	__lookup_processor_type, %function
__lookup_processor_type:
	adr	r3, 3f
	ldmda	r3, {r5 - r7}
	sub	r3, r3, r7			@ get offset between virt&phys
	add	r5, r5, r3			@ convert virt addresses to
	add	r6, r6, r3			@ physical address space
1:	ldmia	r5, {r3, r4}			@ value, mask
	and	r4, r4, r9			@ mask wanted bits
	teq	r3, r4
	beq	2f
	add	r5, r5, #PROC_INFO_SZ		@ sizeof(proc_info_list)
	cmp	r5, r6
	blo	1b
	mov	r5, #0				@ unknown processor
2:	mov	pc, lr

/*
 * 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_end
3:	.long	.
	.long	__arch_info_begin
	.long	__arch_info_end

        从上面的代码中可以看出,程序首先要做的就是保护现场。我们知道在汇编代码中很多的事情要自己写代码,而在其他的高级语言中这些工作编译器已经做好了。例如,在C语言中如果想要调用某个函数直接调用就好,并且也不用在意调用完之后去恢复现场。这是由于C语言相对于汇编来说是高级语言,而其实在C语言转化为汇编的时候也是会有上面保存现场和恢复现场的过程。而上面汇编代码所做的就是调用之前的保存现场和调用完之后的恢复现场。

        而真正__lookup_processor_type函数所做的事为:从地址空间为__proc_info_begin的地方取出处理器信息与程序通过协处理器得到的信息进行比较,看是否匹配,当匹配时获取内核中所存放的关于处理器的信息。当比较到 __proc_info_end 依然没有找到从协处理器获得的处理器信息时,程序将获得空值返回。

        讲到这里我想大家要问了:这里的区间__proc_info_begin和 __proc_info_end在哪里啊?我们根据以往的经验可以知道这些对特定参数定义的区间一般要到链接文件中去寻找,所以我们打开链接文件可以看到:

		__proc_info_begin = .;
			*(.proc.info.init)
		__proc_info_end = .;

        而从上面代码中我们可以知道,所有用 .proc.info.init 修饰的参数都会放到上面定义的这个特殊区域中。而对于我们单板所对应的CPU的定义在arch\arm\mm\proc-arm920.S:


/*
 * Purpose : Function pointers used to access above functions - all calls
 *	     come through these
 */
	.type	arm920_processor_functions, #object
arm920_processor_functions:
	.word	v4t_early_abort
	.word	cpu_arm920_proc_init
	.word	cpu_arm920_proc_fin
	.word	cpu_arm920_reset
	.word   cpu_arm920_do_idle
	.word	cpu_arm920_dcache_clean_area
	.word	cpu_arm920_switch_mm
	.word	cpu_arm920_set_pte_ext
	.size	arm920_processor_functions, . - arm920_processor_functions

	.section ".rodata"

	.type	cpu_arch_name, #object
cpu_arch_name:
	.asciz	"armv4t"
	.size	cpu_arch_name, . - cpu_arch_name

	.type	cpu_elf_name, #object
cpu_elf_name:
	.asciz	"v4"
	.size	cpu_elf_name, . - cpu_elf_name

	.type	cpu_arm920_name, #object
cpu_arm920_name:
	.asciz	"ARM920T"
	.size	cpu_arm920_name, . - cpu_arm920_name

	.align

	.section ".proc.info.init", #alloc, #execinstr

	.type	__arm920_proc_info,#object
__arm920_proc_info:
	.long	0x41009200
	.long	0xff00fff0
	.long   PMD_TYPE_SECT | \
		PMD_SECT_BUFFERABLE | \
		PMD_SECT_CACHEABLE | \
		PMD_BIT4 | \
		PMD_SECT_AP_WRITE | \
		PMD_SECT_AP_READ
	.long   PMD_TYPE_SECT | \
		PMD_BIT4 | \
		PMD_SECT_AP_WRITE | \
		PMD_SECT_AP_READ
	b	__arm920_setup
	.long	cpu_arch_name
	.long	cpu_elf_name
	.long	HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB
	.long	cpu_arm920_name
	.long	arm920_processor_functions
	.long	v4wbi_tlb_fns
	.long	v4wb_user_fns
#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
	.long	arm920_cache_fns
#else
	.long	v4wt_cache_fns
#endif
	.size	__arm920_proc_info, . - __arm920_proc_info

        而在上面的定义中就为我们详细的定义了对用arm920处理器所有的特性。

        在比较完处理器信息后,程序还会比较从u-boot传入的机器ID是否为内核所支持的机器ID,并通过不同的机器ID来找到内核中定义的不同类型的单板,并获得这些信息来为后面的调用做准备。而在arch\arm\kernel\head.S中代码为:

	bl	__lookup_machine_type		@ r5=machinfo

        而在arch\arm\kernel\head-common.S中__lookup_machine_type函数为:

ENTRY(lookup_machine_type)
	stmfd	sp!, {r4 - r6, lr}
	mov	r1, r0
	bl	__lookup_machine_type
	mov	r0, r5
	ldmfd	sp!, {r4 - r6, pc}


/*
 * Lookup machine architecture in the linker-build list of architectures.
 * Note that we can't use the absolute addresses for the __arch_info
 * lists since we aren't 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
 */
	.type	__lookup_machine_type, %function
__lookup_machine_type:
	adr	r3, 3b
	ldmia	r3, {r4, r5, r6}
	sub	r3, r3, r4			@ get offset between virt&phys
	add	r5, r5, r3			@ convert virt addresses to
	add	r6, r6, r3			@ physical address space
1:	ldr	r3, [r5, #MACHINFO_TYPE]	@ get machine type
	teq	r3, r1				@ matches loader number?
	beq	2f				@ found
	add	r5, r5, #SIZEOF_MACHINE_DESC	@ next machine_desc
	cmp	r5, r6
	blo	1b
	mov	r5, #0				@ unknown machine
2:	mov	pc, lr


3:	.long	.
	.long	__arch_info_begin
	.long	__arch_info_end

        查询机器ID要做的第一件事同样是保存现场。然后再调用__lookup_machine_type函数,当完成这个函数操作后,程序再用上面保存现场的变量来恢复现场。而我们继续看上面的代码会发现在其实__lookup_machine_type函数要做的是:从区间__arch_info_begin到__arch_info_end中寻找是否存在与u-boot中传入的相同的机器ID,如果有则获取其相关的参数。如果没有则返回0,表示寻找失败。同查找CPU信息一样,上面的__arch_info_begin和 __arch_info_end这两个区间边界在链接文件中定义:

		__arch_info_begin = .;
			*(.arch.info.init)
		__arch_info_end = .;

        通过上面链接文件中的信息我们知道与机器ID相关的信息要加段属性:.arch.info.init。而我们在代码中找到与这个段信息相关的宏定义在 include\asm-arm\mach\arch.h : 

/*
 * Set of macros to define architecture features.  This is built into
 * a table by the linker.
 */
#define MACHINE_START(_type,_name)			\
static const struct machine_desc __mach_desc_##_type	\
 __used							\
 __attribute__((__section__(".arch.info.init"))) = {	\
	.nr		= MACH_TYPE_##_type,		\
	.name		= _name,

#define MACHINE_END				\
};

        而同时我们要查找在什么地方调用了这个宏定义,查找与我们单板相关的信息在arch\arm\mach-s3c2410\mach-smdk2410.c : 

MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch
				    * to SMDK2410 */
	/* Maintainer: Jonas Dietsche */
	.phys_io	= S3C2410_PA_UART,
	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
	.boot_params	= S3C2410_SDRAM_PA + 0x100,
	.map_io		= smdk2410_map_io,
	.init_irq	= s3c24xx_init_irq,
	.init_machine	= smdk2410_init,
	.timer		= &s3c24xx_timer,
MACHINE_END

        我们将宏定义的内容带回到宏中,从而得到与2410单板相关的各种信息的定义,而我们观察这个带回的信息会发现,其实这就是对结构体machine_desc的填充。在machine_desc结构体中定义了与机器相关的信息,其中包括:机器ID,物理IO的开始地址,机器名,以及一些重要的函数。而machine_desc结构体的信息为:

struct machine_desc {
	/*
	 * Note! The first four elements are used
	 * by assembler code in head-armv.S
	 */
	unsigned int		nr;		/* architecture number	*/
	unsigned int		phys_io;	/* start of physical io	*/
	unsigned int		io_pg_offst;	/* byte offset for io 
						 * page tabe entry	*/

	const char		*name;		/* architecture name	*/
	unsigned long		boot_params;	/* tagged list		*/

	unsigned int		video_start;	/* start of video RAM	*/
	unsigned int		video_end;	/* end of video RAM	*/

	unsigned int		reserve_lp0 :1;	/* never has lp0	*/
	unsigned int		reserve_lp1 :1;	/* never has lp1	*/
	unsigned int		reserve_lp2 :1;	/* never has lp2	*/
	unsigned int		soft_reboot :1;	/* soft reboot		*/
	void			(*fixup)(struct machine_desc *,
					 struct tag *, char **,
					 struct meminfo *);
	void			(*map_io)(void);/* IO mapping function	*/
	void			(*init_irq)(void);
	struct sys_timer	*timer;		/* system tick timer	*/
	void			(*init_machine)(void);
};

        完成上面两项工作之后说明在内核中有对应的单板的信息,并且程序已经了解了这些信息。在内核中下一步要做的就是创建页表了。我们知道在内核中使用的是虚拟地址而并不是物理地址。所以在这里就要创建页表来支持虚拟地址。而这里关于虚拟地址和页表的关系为: 虚拟内存的基本思想是,每个进程有用独立的逻辑地址空间,内存被分为大小相等的多个块,称为页(Page).每个页都是一段连续的地址。对于进程来看,逻辑上貌似有很多内存空间,其中一部分对应物理内存上的一块(称为页框,通常页和页框大小相等),还有一些没加载在内存中的对应在硬盘上,如图所示。

而关于虚拟内存的详细介绍,大家可以看:虚拟内存(虚拟地址, 页表,换页...)

而关于更加详细的页表创建内容,大家可以看:arm linux 页表创建

        在上面说了要在内核中运行就要使用虚拟内存,而虚拟内存的使用是建立在页表和内存管理的基础上了。页表为我们使用虚拟内存提供表格支持,而内存管理却是单板是否可以使用虚拟内存的关键。所以在上面创建好页表后,这里就要使能单板的内存管理(MMU)了。在使能mmu后,内核就可以使用虚拟地址了。而在使能mmu之前我们要先设置一下跳转地址,即当使能好mmu后就可以跳转到__switch_data里的去执行了。而使能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
#else
	bic	r0, r0, #CR_A
#endif
#ifdef CONFIG_CPU_DCACHE_DISABLE
	bic	r0, r0, #CR_C
#endif
#ifdef CONFIG_CPU_BPREDICT_DISABLE
	bic	r0, r0, #CR_Z
#endif
#ifdef CONFIG_CPU_ICACHE_DISABLE
	bic	r0, r0, #CR_I
#endif
	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
	mcr	p15, 0, r4, c2, c0, 0		@ load page table pointer
	b	__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
	mcr	p15, 0, r0, c1, c0, 0		@ write control reg
	mrc	p15, 0, r3, c0, c0, 0		@ read id reg
	mov	r3, r3
	mov	r3, r3
	mov	pc, r13

        而通过上面的代码我们可以看出其实使能mmu更多的是对写寄存器的读写操作。

        而在进入__switch_data后程序就要准备进入C语言中了,使用c语言可以实现更加复杂的功能。而我们会在第二阶段讲解start_kernel的内容。

十七.linux开发之Kernel移植——内核的启动过程分析 有道云笔记地址: 详情看这里链接,记录太多,就不一一排版了。 http://note.youdao.com/noteshare?id=e68caf68c259bc3491dd7f8c4ac4bb99&sub=435C54F4A4C444B995888BCC71CDB607 2.6.35.7版本kernel。 参考:http://blog.chinaunix.net/uid-26... 阅读详情

相关推荐

Linux kernel 分析之二:main函数执行启动过程

内核是从哪里开始执行的呢?几乎任何一本Linux内核源代码分析的书都会给出详细的答案。不过,我试图从一个不同的角度(一个初学者的角度)来叙述,而不是一上来就给出答案。从熟悉的事物入手,慢慢接近陌生的事物,这是比较常见的思路。既然都是二进制代码,那么不妨从最简单的用户态C程序,hello world开始。说不定能找到共同点。恰好我是一个喜欢寻根究底的人。也许,理解了hello world程序的启动过

vanileo的专栏 3806

详解linux设备树全集

本课程属于嵌入式linux核心课程2期,是核心课程2期的技术专题之一,主要讲解设备树技术。秉持我们一贯课程风格和原则,从原理出发,从源码分析,边讲解边实验验证。本课程适合学习完核心课程1期,有一定linux基础,希望进一步学习高版本kernel的设备树技术的同学继续学习。

嵌入式kernel 移植全方位解析

Kernel的配置和裁剪,说白了就是个因地制宜的过程。每个嵌入式项目的需求都不一样,硬件平台千差万别,应用场景也各有侧重。有的设备追求极致性能,有的则更看重功耗和体积。所以,配置时别照搬别人的方案,得结合硬件手册、项目目标和实际测试,摸索出一套最适合自己的路子。这一路走下来,从工具的使用到选项的分析,再到裁剪的平衡,相信你对Kernel配置已经有了更深的理解。接下来的步骤,就是把配置好的Kernel编译出来,烧录到板子上跑一跑,看看实际效果如何。

大模型大数据攻城狮的专栏 1488

sizeof是如何实现的,和内核里面宏如出一辙

0x00    很多东西用多了就缺乏了,洞察力,觉得就该如此。这也许就是中国那句老话:当局者迷。今天看到c群里面的一个学生问求一个数组的大小如何写,当然不由自主的敲了sizeof    0x04 sizeof是一个运算符不是函数,但是我突然觉得,他是如何实现的那?如果是一个字符串还可以判断末尾的 '\0' 那对一块内存如何去判断他的结束那?    0x08 注意sizeof

张飞online博客 1万+

PX4实战指南:通过遥控器通道映射实现多舵机PWM精准控制

本文详细介绍了通过PX4飞控的AUX PWM接口实现遥控器通道映射控制多舵机的实战指南。内容包括硬件选型与连接、软件参数配置、通道映射方法以及常见问题排查,帮助开发者精准实现无人机舵机PWM控制,适用于云台、机械臂等扩展功能开发。

ee345的博客 304

Linux与Windows双系统,安装完linux后无法通过grub进入Windows的解决方法

先装Windows 10,Windows可正常启动,再装Kali,Kali提示装grub后照装。然而装完后重启发现无Windows选项。

sakurashockwave的博客 6453

[转贴] 你会用sizeof吗?(vc篇) kernelhao(原作)

[转贴] 你会用sizeof吗?(vc篇) kernelhao(原作) 发表:2004-4-9 11:55:52 出处:你的博客网(yourblog.org) 本文主要包括二个部分,第一部分重点介绍在VC中,怎么样采用sizeof来求结构的大小,以及容易出现的问题,并给出解决问题的方法,第二部分总结出VC中sizeof的主要用法。 1、 sizeof应用在结构上的情况 请看下面的结构: s

我的仓库 My Storehouse 1080

【算法设计与分析】期末复习题(超详细)

刚刚整理了一下电脑的文件,发现了这份上学期的算法设计与分析期末复习题,有需要的文后自取。

a1234567822的博客 6610

Linux kernel中常见的宏整理

0x00 宏的基本知识// object-like #define宏名 替换列表 换行符 //function-like #define宏名 ([标识符列表]) 替换列表 换行符 替...

嵌入式Linux 1961

4D 毫米波雷达:智驾普及的新路径(一)

总体而言,4D 毫米波雷达具有更佳的探测能力,更高的分辨率和精度,在人工智能技术的加持下,能够实现更加智能化的感知和跟踪,从而为自动驾驶、智能交通等领域提供更加可靠的数据支持。博世的第五代引入了俯仰维度,但其角度分辨率较差,且最大探测距离为。车载毫米波雷达的尺寸受限,我们认为通过算法的优化、天线内置等方式可以在保障性能的前提下,压缩尺寸,便于车企进行灵活的设计安装。在物理设计、天线性能设计、电连接、封装工艺和材料、散热处理、可靠性与自动化测试等方面进行持续优化,推出可大规模量产的高性能毫米波雷达解决方案。

奔袭的算法工程师 3954

RT-DETR改进策略【注意力机制篇】| 2024 PPA 并行补丁感知注意模块,提高小目标关注度

本文记录的是利用改进检测精度,详细说明了优化原因,注意事项等。原论文在红外小目标检测任务中,小目标在多次下采样操作中容易丢失关键信息。通过替代编码器和解码器基本组件中的传统卷积操作,更好地保留小目标的重要信息。HCF-Net: Hierarchical Context Fusion Network for Infrared Small Object Detection采用多分支特征提取策略,通过不同分支提取不同尺度和层次的特征。利用局部、全局和串行卷积分支,对输入特征张量进行处理。通过控制 patch si

Limiiiing的博客 1646

linux kernel变长数组使用示例

在一个结构体中,定义了长度为0的数组,而我们有希望这个变成数组和结构体是物理连续的,如图所示: 可以参考linux kernel的代码,如下所示: struct skcipher_sg_list { struct list_head list; int cur; struct scatterlist sg[0]; }; #define MAX_SGL_ENTS ((4096 - sizeof(struct skcipher_sg_list)) / \ sizeof(struct sc

baron-周贺贺-代码改变世界ctw 2686

ZYNQ 使用AXI_BRAM实现PS与PL 数据交互数据交互

有时CPU需要与PL进行小批量的数据交换,可以通过Block RAM实现。通过Zynq 的GP Master 接口读写PL端的 BRAM,实现PS与PL的交互。加入自定义的 FPGA 程序,并利用 AXI4 总线进行配置,通知何时读写 BRAM。CPU通过 AXI BRAM Controller 读取 BRAM 数据,CPU 仅配置自定义的 PL BRAM Controller 的寄存器,不通过它读写数将BRAM与socket进行联合使用,将电脑的数据发到PS端,PS端放在PL端,PL端再发给PS端,P据。

wangjie36的博客 1万+

Linux内核(Kernel)启动过程分析

Linux内核(Kernel)启动过程

Android应用开发工程师 2270

Android 14安装的APK默认允许运行时权限

本文介绍了在Android系统中实现安装应用后自动授予运行时权限的方法。通过在安装完成广播中检测应用安装状态,调用新增的DefaultPermissionGrantPolicy.grantAppRuntimePermissions()函数来授予常规权限,并使用allowSpecialPermission()处理特殊权限(如安装未知应用和悬浮窗权限)。文章详细说明了如何修改DefaultPermissionGrantPolicy类,添加grantAppRuntimePermissions和grantRunti

热衷于Android Framework和系统APP的修改经验分享 683

使用 MATLAB/Simulink + Simscape Electrical + SimPowerSystems + Stateflow,构建一个多能互补微电网系统的动态响应仿真模型

本文详细介绍了使用MATLAB/Simulink构建多能互补微电网动态响应仿真模型的方法。文章从系统架构设计入手,包含光伏、风电、柴油发电机、锂电池储能等多种组件,重点讲解了建模过程、控制策略(下垂控制、PLL、SOC管理)和模式切换逻辑(Stateflow)。通过四种典型场景(负荷突增、光伏出力骤降、并网/孤岛切换、电动机启动)的仿真分析,验证了微电网在动态响应中的关键性能指标,并提出了高可靠性设计建议。该模型为微电网的稳定性分析和优化设计提供了有效工具,特别强调了储能系统在快速功率支撑中的重要作用。

amy_mhd的博客 159

Linux Kernel Panic 分析机制全解:一篇读懂从原理到实战

本文全面解析Linux Kernel Panic机制,从原理到实践提供系统化解决方案。首先阐释Kernel Panic本质是内核遇到致命错误时主动终止运行的保护机制,列举空指针引用、内存非法访问等典型触发场景。文章详细说明内核panic处理流程,并给出5步调试方法论:获取崩溃信息、复现步骤、使用crash工具分析、配置早期打印、启用kdump机制。针对嵌入式开发,特别介绍Yocto环境下如何配置调试支持。最后整理典型问题解答,强调搭建调试环境、掌握crash工具和熟悉常见panic场景的重要性。本文为Lin

Interview_TC的博客 3128

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

Linux内核Kernel启动过程

减少存储空间: 压缩内核映像可以显著减少其在存储设备上的占用空间。这对嵌入式系统、存储资源有限的设备以及需要快速分发和更新内核的环境尤其重要加快加载速度: 压缩文件占用的空间更小,这意味着启动加载程序从磁盘读取文件到内存中的时间会更短。虽然解压缩内核映像需要一些时间,但现代处理器的解压缩速度非常快,通常解压缩的时间比从存储设备读取更多数据的时间要少。这会整体上加快启动过程。提高传输效率: 在网络上传输内核映像时,压缩文件可以显著减少带宽使用量。这对于需要远程更新内核的系统(OTA)非常有利。

weixin_60669486的博客 3545

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

嵌入式linux 运行期间升级u-boot,kernel和文件系统

本文主要就是介绍,在嵌入式Linux 系统下,已经实现了nand 驱动后, 如何利用mtd 工具,进行在线升级u-boot,Linux和文件系统。 主要使用到的工具是mtd-utils-1.3.1,如果你需要源码,可以到官网下载http://www.linux-mtd.infradead.org/source.html。也可以等我有空上传到资源里面去下载。   在利用 mtd 工具升级系统

qing_ping的专栏 4868

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

linux kernel的cmdline参数解析原理分析

依据我的思路(时间顺序,如何开始,如何结束),首先看kernel下2种参数的注册。 第一种是kernel通用参数,如console=ttyS0,115200 root=/rdinit/init等。这里以console为例。 第二种是kernel下各个driver中需要的参数,在写driver中,如果需要一些启动时可变参数。 可以在driver最后加入module_param()来注册一个参数,kernel启动时由cmdline指定该参数的值。 这里以drivers/usb/gadget/serial.c中

做一个有技术追求的人 5万+

关于嵌入式Linux系统的启动(很好的嵌入式linux启动过程分析)

lw:虽然zImage的开头是head_armv.S的8个空循环,但是实际是先执行compressed/head.S进行解压操作。=================================#1  关于嵌入式系统的启动(SHARE FOR ALL)嵌入式Linux启动分为两个部分,系统引导与Linux启动。系统引导将完成Linux装入内存前,初始化CPU和相关IO设备,并将Linux调入内存

小伟 1万+

Linux kernel 启动流程分析4

Linux kernel 启动流程分析4---第一阶段proc info的获取

ListQ的博客 884

Linux kernel 启动流程分析8

Linux kernel 启动流程分析8---第一阶段跳转至start_kernel

ListQ的博客 871

内核窥秘之一:start_kernel()运行过程记录

本文系itspy原创,复制/转载请尽量标明原出处http://blog.csdn.net/yyplc/article/details/7030983,谢谢! 解开linux内核的神秘面纱,它是怎么运行起来的呢?它是怎么做到的?做了什么,怎么做,流程如何等等,均需要一个清晰的过程(因为要给我们一个说法~!),如何更好的亲密、深入的了解,接触它,找到一个很好的突破点是很关键的---那就是‘从头开始’

自由枫~ 4437

在Linux运行期间升级Linux系统(Uboot+kernel+Rootfs)

版本:v1.2 摘要 本文主要介绍了如何在嵌入式Linux系统运行的时候,进行升级整个Linux系统,包括uboot,kernel和rootfs。以及简介Linux中的已有的通用的Nor Flash驱动m25p80,和简介mtd util以及相关工具mtdinfo,flash_erase,flash_eraseall,nanddump,nandwrite等的基

3930

在Linux运行期间升级Linux系统(Uboot+kernel+Rootfs)v1.0:轻松掌握在线升级技巧

在Linux运行期间升级Linux系统(Uboot+kernel+Rootfs)v1.0:轻松掌握在线升级技巧 【下载地址】在Linux运行期间升级Linux系统UbootkernelRootfsv1.0使用说明 该项目专注于在Linux系统运行时实现无缝在线升级,覆盖Uboot、Kernel和Rootfs三大核心组件。...

gitblog_06792的博客 1017
上一篇: 嵌入式Linux——分析u-boot运行过程(4):u-boot第四阶段代码
下一篇: 嵌入式Linux——分析kernel运行过程(2):kernel第二阶段
moxue10
博客等级 码龄19年 388粉丝 85原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值