mini2440的linux各文件夹含义,基于mini2440的Linux内存布局分析

基于mini2440的Linux内存布局分析

在学习linux内存寻址的过程中,注意到在x86架构上,分段与分页机制共存。而在RSIC体系结构下一般只支持分页。《深入理解linux内核》是在x86架构上介绍的linux物理内存布局。在x86架构上,linux被安装在ram从物理地址的0x00100000也就是第二个1M的地方。内核态的线性地址:0xc0000000~0xffffffff,在内核态可以寻址0x00000000~0xbfffffff的地址,用户态的线性地址范围为:0x00000000~0xbfffffff,用户态的程序不能访问内核态的线性地址。这几个是线性地址只是CPU寻址的时候用,最终都是要映射到实际的物理地址。在内核镜像包括代码段,数据段。在数据段的后面保存了全局页表描述了线性地址怎样转化成物理地址的。在内核态的线性地址空间里,内核要映射全部的物理RAM,前8M的RAM有两个映射分别对应于线性地址0x00000000~0x0x007fffff与0xc0000000~0xc07fffff,这个是为了在内核初始化的时候,MMU开启前后的操作方便,这是临时映射。最终的内核态映射是线性地址与物理地址线性映射,就是每个线性地址都是物理地址加上一个偏移量,在x86上这个偏移量就是0xc0000000。以上就是x86架构上linux的物理内存布局。而mini2440的物理内存布局会有很大的不同,以64M的SDRAM来说,RAM的物理地址是从0x30000000开始的,结束与0x34000000。要了解linux在mini2440上的内存布局首先要看System.map文件,这个链接器生成的文件。描述了linux镜像在内存中的布局,地址全部是线性地址。

c0004000 A swapper_pg_dir

c0008000 T __init_begin

c0008000 T _sinittext

c0008000 T _stext

c0008000 T stext

c0008034 t __enable_mmu

......

......

c04b08d8 B proc_net_rpc

c04b08dc b sunrpc_table_header

c04b08e0 B rpc_debug

c04b08e4 B nfs_debug

c04b08e8 B nfsd_debug

c04b08ec B nlm_debug

c04b08f0 b nullstats.25712

c04b0910 B __bss_stop

c04b0910 B _end         可以看出,内核镜像起始地址为0xc0004000,终止地址为0xc04b0910,但是起始地址处到0xc0008000之间32K的地址似乎没有内容,内核镜像大小大约4M。那么这个内核镜像在物理内存是如何布局的呢。在/arch/arm/kernel/head.S中有描述:

#define KERNEL_RAM_VADDR(PAGE_OFFSET + TEXT_OFFSET)

//这个是内核线性地址的开始,PAGE_OFFSET = 0xc0000000 而TEXT_OFFSET = 0x00008000,所以KERNEL_RAM_VADDR = 0xc0008000

#define KERNEL_RAM_PADDR(PHYS_OFFSET + TEXT_OFFSET)

//这个是内核物理地址的开始处,PHYS_OFFSET = 0x30000000 而TEXT_OFFSET = 0x00008000,所以KERNEL_RAM_PADDR = 0x30008000,所以bootloader将内核装载到这个地址处,装载到其他地址是不行的

#if (KERNEL_RAM_VADDR & 0xffff) != 0x8000

#error KERNEL_RAM_VADDR must start at 0xXXXX8000

#endif

//检查定义的是否合法,内核开始物理地址必须是0xXXXX8000

.globlswapper_pg_dir

.equswapper_pg_dir, KERNEL_RAM_VADDR - 0x4000

//swapper_pg_dir这个变量是内核全局页表的起始地址 可以看出这里是0xc0004000,与内核链接符号表相同

.macropgtbl, rd

ldr\rd, =(KERNEL_RAM_PADDR - 0x4000)

.endm

//声明一个宏,作用就是将0x30004000赋值给rd

#ifdef CONFIG_XIP_KERNEL ///没定义

#define KERNEL_STARTXIP_VIRT_ADDR(CONFIG_XIP_PHYS_ADDR)

#define KERNEL_END_edata_loc

#else

#define KERNEL_STARTKERNEL_RAM_VADDR

#define KERNEL_END_end //_end是内核链接符号表中的变量,代表内核结束线性地址

#endif

ENTRY(stext)

setmodePSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode

@ and irqs disabled

mrcp15, 0, r9, c0, c0@ get processor id

bl__lookup_processor_type@ r5=procinfo r9=cpuid

movsr10, r5@ invalid processor (r5=0)?

beq__error_p@ yes, error 'p'

bl__lookup_machine_type@ r5=machinfo

movsr8, r5@ invalid machine (r5=0)?

beq__error_a@ yes, error 'a'

bl__vet_atags

bl__create_page_tables

/*

* The following calls CPU specific code in a position independent

* manner. See arch/arm/mm/proc-*.S for details. r10 = base of

* xxx_proc_info structure selected by __lookup_machine_type

* above. On return, the CPU will be ready for the MMU to be

* turned on, and r0 will hold the CPU control register value.

*/

ldrr13, __switch_data@ address to jump to after

@ mmu has been enabled

adrlr, BSYM(__enable_mmu)@ return (PIC) address

ARM(addpc, r10, #PROCINFO_INITFUNC)

THUMB(addr12, r10, #PROCINFO_INITFUNC)

THUMB(movpc, r12)

ENDPROC(stext)        由内核链接符号表可以看出,这段代码是内核最早运行的代码,其地址在0xc0008000。这段代码是bootloader将内核解压后执行的代码,执行的环境是:没有开启MMU,r0 = 0, r1 = machine nr, r2 = atags pointer atags pointer是标记列表的指针,这个是UBOOT或者其他bootloader传递给内核的参数。前面的汇编代码主要是检查机器吗,与提取内核参数。最后调用 __create_page_tables来创建内核临时页表。

__create_page_tables:

pgtblr4@ page table address

//r4中保存了内核临时页表的地址0x30004000

/*

* Clear the 16K level 1 swapper page table

*/

movr0, r4

movr3, #0

addr6, r0, #0x4000

1:strr3, [r0], #4

strr3, [r0], #4

strr3, [r0], #4

strr3, [r0], #4

teqr0, r6

bne1b

//将从0x30004000~0x30008000的内存清零

ldrr7, [r10, #PROCINFO_MM_MMUFLAGS] @ mm_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.

*/

movr6, pc

movr6, r6, lsr #20@ start of kernel section

orrr3, r7, r6, lsl #20@ flags + kernel base

strr3, [r4, r6, lsl #2]@ identity mapping

//一级页表使用段,每个段描述符都能映射1M的物理地址,这里只是映射前1M的物理地址

//内核物理地址从0xc0008000开始,所以一级页表表述符要存放在页表首地址的偏移0x0000c000这个位置上

//这里就是将一级页表表述符存放到此处,可以看出段基地址为0x30000000

/*

* Now setup the pagetables for our kernel direct

* mapped region.

*/

addr0, r4, #(KERNEL_START & 0xff000000) >> 18

strr3, [r0, #(KERNEL_START & 0x00f00000) >> 18]!

//这段代码将虚拟地址0x30008000开始的1M内存也映射到了0x30008000处了

ldrr6, =(KERNEL_END - 1)

addr0, r0, #4

addr6, r4, r6, lsr #18

1:cmpr0, r6

addr3, r3, #1 << 20

strlsr3, [r0], #4

bls1b

//将内核镜像全部映射到物理地址

//经过以上代码,我们访问从0xc0000000的前1M的地址起始就是访问物理地址从0x30000000开始的1M,我们访问从0x30000000到内核大小的线性地址,就是访问的真实的物理地址(前提是后面开启MMU)

/*

* Then map first 1MB of ram in case it contains our boot params.

*/

addr0, r4, #PAGE_OFFSET >> 18 //0x00003000

orrr6, r7, #(PHYS_OFFSET & 0xff000000)

.if(PHYS_OFFSET & 0x00f00000) //不成立

orrr6, r6, #(PHYS_OFFSET & 0x00f00000)

.endif

strr6, [r0]

//这段代码和上边做的事一样,就是将一级页表描述符写到正确的位置

movpc, lr

ENDPROC(__create_page_tables)        经过页表的初级初始化,0xc0000000~0xc0100000的线性地址被映射到了0x30000000~0x30100000的物理地址 0x30000000~0x30000000+KERNELSIZE的线性地址被映射到了0x30000000~0x30000000+KERNELSIZE物理地址。之所以这样的初始化,《深入理解linux内核》上是这样说的:分页第一阶段的目标就是允许在实模式下与保护模式下很容易对前8M的空间进行寻址,在arm上是1M。这个页表只是初级的初始化,后面会有更具体的页表初始化的,内核要映射全部的物理内存。在初始化完页表后,内核开启MMU,从而从实模式进入虚拟地址模式。

表情包
插入表情
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符
相关推荐
<p> 需要学习Windows系统YOLOv4的同学请前往《Windows版YOLOv4目标检测实战:原理与源码解析》, </p> <p> 课程链接 https://edu.csdn.net/course/detail/29865 </p> <h3> <span style="color:#3598db;">【为什么要学习这门课】</span> </h3> <p> <span>Linux</span>创始人<span>Linus Torvalds</span>有一句名言:<span>Talk is cheap. Show me the code. </span><strong><span style="color:#ba372a;">冗谈不够,放码过来!</span></strong> </p> <p> <span> </span>代码阅读是从基础到提高的必由之路。尤其对深度学习,许多框架隐藏了神经网络底层的实现,只能在上层调包使用,对其内部原理很难认识清晰,不利于进一步优化和创新。 </p> <p> YOLOv4是最近推出的基于深度学习的端到端实时目标检测方法。 </p> <p> YOLOv4的实现darknet是使用C语言开发的轻型开源深度学习框架,依赖少,可移植性好,可以作为很好的代码阅读案例,让我们深入探究其实现原理。 </p> <h3> <span style="color:#3598db;">【课程内容与收获】</span> </h3> <p> 本课程将解析YOLOv4的实现原理和源码,具体内容包括: </p> <p> - YOLOv4目标检测原理<br /> - 神经网络及darknet的C语言实现,尤其是反向传播的梯度求解和误差计算<br /> - 代码阅读工具及方法<br /> - 深度学习计算的利器:BLAS和GEMM<br /> - GPU的CUDA编程方法及在darknet的应用<br /> - YOLOv4的程序流程 </p> <p> - YOLOv4各层及关键技术的源码解析 </p> <p> 本课程将提供注释后的darknet的源码程序文件。 </p> <h3> <strong><span style="color:#3598db;">【相关课程】</span></strong> </h3> <p> 除本课程《YOLOv4目标检测:原理与源码解析》外,本人推出了有关YOLOv4目标检测的系列课程,包括: </p> <p> 《YOLOv4目标检测实战:训练自己的数据集》 </p> <p> 《YOLOv4-tiny目标检测实战:训练自己的数据集》 </p> <p> 《YOLOv4目标检测实战:人脸口罩佩戴检测》<br /> 《YOLOv4目标检测实战:中国交通标志识别》 </p> <p> 建议先学习一门YOLOv4实战课程,对YOLOv4的使用方法了解以后再学习本课程。 </p> <h3> <span style="color:#3598db;">【YOLOv4网络模型架构图】</span> </h3> <p> 下图由白勇老师绘制 </p> <p> <img alt="" src="https://img-bss.csdnimg.cn/202006291526195469.jpg" /> </p> <p>   </p> <p> <img alt="" src="https://img-bss.csdnimg.cn/202007011518185782.jpg" /> </p>
©️2020 CSDN 皮肤主题: 游动-白 设计师:白松林 返回首页