OK6410A 开发板 (八) 6 linux-5.11 OK6410A 详细解析 从 u-boot 的 theKernel 到 linux的 start_kernel

之前写过 linux-3.0.1 ok6410a 的启动流程, 从 arch/arm/boot/compressed/head.S 到 mm_init 完成
回忆 linux-3.0.1 ok6410a 的启动流程

这里讲述了 内存镜像的生成过程以及压缩/无压缩镜像启动的不同打印
压缩内核 会打印 Uncompressing Linux… done, booting the kernel ,再打印 Booting Linux on physical CPU
非压缩内核直接打印 Booting Linux on physical CPU

这里讲述了 压缩内核的入口(arch/arm/boot/compressed/head.S 中的start )及出口(到非压缩内核)(mov pc, r4 @ call kernel) 和 非压缩内核的入口(arch/arm/kernel/head.S 中的 stext)及出口(start_kernel) (b start_kernel)

这里简述了 arm压缩内核的 启动流程
这里简述了 arm非压缩内核的启动流程
这里 简述了 arm64 和 risc-v 架构的架构相关启动流程

这里 简述了各种地址(物理地址 虚拟地址 链接地址 运行地址)概念

这里 讲述了 uImage的头部

这里 从目录角度讲述了 目录在启动过程中扮演的角色


这里 讲述了 从 start 到 start_kernel 的过程中的内存分布
这里 讲述了 过程中的一些与内存相关的符号
这里 讲述了 过程中的一些与内存相关的内核配置

简述 linux-5.11 OK6410A 启动流程
1 从u-boot 到 arch/arm/boot/compressed/head.S 中的start
  • 打印信息
bootm 0x50008000

## Booting kernel from Legacy Image at 50008000 ...
   Image Name:   Linux-5.11.0-00006-g1829225a7fa
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    2913264 Bytes = 2.8 MiB
   Load Address: 50008000
   Entry Point:  50008000
   Verifying Checksum ... OK
   Loading Kernel Image

Starting kernel ...

Booting Linux on physical CPU 0x0

  • 流程
u-boot 
	1. 将 zImage 放置到  50008000
	2. 设置 r0 为 0
	3. 设置 r1 为 1626 // 这个是 smdk6410的board id
	4. 设置 r2 为 atags的 地址 0x50000100 , 此前 设置 了 setup_start_tag setup_commandline_tag setup_memory_tags setup_end_tag , 这个有 152 字节
	
	5. 并 将pc 置为 0x50008000

linux
	0x50008000 为 arch/arm/boot/compressed/head.S 中的start  // 需要去分析 arch/arm/boot/compressed/vmlinux.lds

2 从 arch/arm/boot/compressed/head.S 中的start 到 arch/arm/kernel/head.S 中的 stext
  • 运行前的状态

内存 : 
Image : 0x50008000 - 0x502D12C7 2.8MB
atags : 0x50000100 - 0x50000197 152字节
cpu寄存器 : 
r0 : 0
r1 : 1626 
r2 : 0x50000100
pc : 0x50008000 

协处理器寄存器 :
mmu off
dcache off
icache off
没有关注CONFIG_ARM_VIRT_EXT,TODO
  • 流程
简述 : 大概就是 利用 解压代码A 将 arch/arm/boot/compressed/piggy_data 解压 为 Image
过程中涉及到了 很多事情
	1. 解压后的 Image 起始位置的确定
	2. 解压后的 Image 是否与 当前kernel运行空间 重叠
		如果重叠
			要搬运当前kernel
			要处理搬运后的符号链接问题(解压代码A的符号链接)
	3. 解压核心代码 decompress_kernel


可直接 加载 运行 Image,从而忽略这个过程, 与加载 uImage并运行 产生的效果是一样的
	效果 : arch/arm/kernel/head.S 中的 stext 运行时的状态

arch/arm/boot/compressed/head.S

184         .section ".start", "ax"
...
235         mov r7, r1          @ save architecture ID
236         mov r8, r2          @ save atags pointer
...
250 not_angel: // 解决 Booting from Angel 的问题
251         safe_svcmode_maskall r0 	// 关闭IRQ与FIQ
252         msr spsr_cxsf, r9       @ Save the CPU boot mode in SPSR
...
288         add r4, r4, #TEXT_OFFSET // r4 中的值 0x50008000 , 为 解压后 Image的 起始位置
...
305         blcs    cache_on 	// 开cache
...
307 restart:    adr r0, LC1 		// 如果 会 overwrite,则进行relocate之后,会跳到这里,然后继续往下再次判断是否需要 overwrite
...
313         get_inflated_image_size r9, r10, lr // 得到 Image 的大小
...
435         add r10, r10, #16384 // 计算当前zImage是否与解压后的Image有重叠.
436         cmp r4, r10			 // 如果有重叠,则 重定位 zImage
437         bhs wont_overwrite
---------------------------------------------------------- relocate自身 的开始
...
481         sub r9, r6, r5      @ size to copy
...
491 #ifdef DEBUG
...
503         dbgkc   r5, r6, r10, r9	 // 打印了 C:0x500080C0-0x502D1240->0x5088F000-0x50B58180
...
506 #endif
...
513         badr    r0, restart
514         add r0, r0, r6
515         mov pc, r0
---------------------------------------------------------- relocate自身 的结束,会跳转到 restart 标号,而不是往下走

517 wont_overwrite: 		// 重定位第一步(代码搬运)完成,或者是没有重定位,直接跳转到这里 , 本例是 重定位完成

...
535         orrs    r1, r0, r5
536         beq not_relocated 
...
551          * Relocate all entries in the GOT table. // 重定位第二步,解决符号地址问题
...
563         /* bump our bss pointers too */ 	// 重定位第三步,清空bss段
...
582 not_relocated:  mov r0, #0
583 1:      str r0, [r2], #4        @ clear bss
...
610         bl  decompress_kernel		// 解压zImage 为 Image
...
616         bl  cache_clean_flush
617         bl  cache_off
...
623         bne __enter_kernel      @ boot kernel directly

1410 __enter_kernel:
...
1414  ARM(       mov pc, r4      )   @ call kernel	// 调用 Image的 arch/arm/kernel/head.S 中的 stext

  • 打印相关
C:0x500080C0-0x502D1240->0x5088F000-0x50B58180
Uncompressing Linux... done, booting the kernel. 
上述打印需要 内核配置支持
CONFIG_DEBUG_KERNEL=y
CONFIG_DEBUG_LL=y
CONFIG_DEBUG_UNCOMPRESS=y
  • 地址相关
zImage 在解压缩前 进行了一次搬移 从 0x500080C0-0x502D12000x5088F000-0x50B58140

zImage 被 解压缩 为 Image,Image在哪里?0x5088F000 前面,具体地址为
0x50008000 - 0x50008000 + 8938824(Image的大小) -10x50008000 - 0x5088E547

-rwxrwxr-x 1 suws suws 8938824 Apr 21 14:53 arch/arm/boot/Image
3 从 arch/arm/kernel/head.S 中的 stext 到 init/main.c 中的 start_kernel
  • 运行前的状态

内存 : 
Image : 0x50008000 - 0x5088E547 8.6M
atags : 0x50000100 - 0x50000197 152字节
cpu寄存器 : 
r0 : 0
r1 : 1626 
r2 : 0x50000100
pc : 0x50008000

协处理器寄存器 :
mmu off
dcache off
icache off
  • 流程
arch/arm/kernel/head.S
77 ENTRY(stext)
...
89     safe_svcmode_maskall r9
...
92     bl  __lookup_processor_type     @ r5=procinfo r9=cpuid
...
106     adr_l   r8, _text           @ __pa(_text) 
107     sub r8, r8, #TEXT_OFFSET        @ PHYS_OFFSET
...
116     bl  __vet_atags
...
123     bl  __create_page_tables
...
144     ldr r13, =__mmap_switched       @ address to jump to after
...
151     mov r8, r4              @ set TTBR1 to swapper_pg_dir	// r8 中值 为 50004000 , r4 中的值 也为 50004000 
...
153     ldr r12, [r10, #PROCINFO_INITFUNC]
154     add r12, r12, r10
155     ret r12						// 跳转到 arch/arm/mm/proc-v6.S 中的 __v6_setup ,并返回

156 1:  b   __enable_mmu			// 跳转到 __enable_mmu
...
157 ENDPROC(stext)
arch/arm/kernel/head.S

420 __enable_mmu:
...
439     mcr p15, 0, r5, c3, c0, 0       @ load domain access register
440     mcr p15, 0, r4, c2, c0, 0       @ load page table pointer // 将 页表基址(50004000) 告知 mmu 
...
442     b   __turn_mmu_on		// 跳转到 __turn_mmu_on		
443 ENDPROC(__enable_mmu)

461 ENTRY(__turn_mmu_on)
...
468     mov r3, r13
469     ret r3					//	 跳转到 __mmap_switched       
470 __turn_mmu_on_end:
471 ENDPROC(__turn_mmu_on)

arch/arm/kernel/head-common.S

77 __mmap_switched:
...
106     bl  __memset            @ clear .bss
...
108     ldmia   r4, {r0, r1, r2, r3} 
109     str r9, [r0]            @ Save processor ID
110     str r7, [r1]            @ Save machine type
111     str r8, [r2]            @ Save atags pointer
...
118     b   start_kernel		// 跳转到 start_kernel		

  • 重点函数解析 __create_page_tables
__create_page_tables
	Clear the swapper page table // 16KB 空间 即 4K个页表(1个页表4Byte) 清0,1个页表map 1MB虚拟地址 , 正好 Map 4GB虚拟地址
	addr 		value
	50004000	0
	50004004	0
	50004008 	0
	5000400c	0	
	50004010 	0
	...
	50007ffc	0
	
	Create identity mapping to cater for __enable_mmu // __turn_mmu_on
	addr 		value
	50005400	50100c0e
	
	Map our RAM from the start to the end of the kernel .bss section.	// 9MB, 因为 我们的 Image 为 8.6M ,不足 9个MB
	addr 		value
	50007000	50000c0e
	50007004	50100c0e
	50007008	50200c0e
	5000700c	50300c0e
	50007010	50400c0e
	50007014	50500c0e
	50007018	50600c0e
	5000701c	50700c0e
	50007020	50800c0e

	Then map boot params address in r2 if specified
	addr 		value
	50007fe0 	50000c0e
	50007fe4 	50100c0e

// 一旦开启 mmu , 多了虚拟地址 ,对应的虚拟地址为 
500x xxxx	__enable_mmu
C00x xxxx  	kernel
ff8x xxxx 	atags
  10 00001MB	

页表的含义:50000c0e
Section base address : 500 00000
Section
B:1
C:1
XN:0
Domain:0000		// 表明 属于 domain0 , D0 
IMP:0
AP:11
TEX:000
APX:0
S:0
nG:0

  • 重点过程解析 虚拟地址和连接地址一致问题
__turn_mmu_on

在 非压缩内核启动流程中
	重定位前, 访问 全局符号 时,因为全局符号是链接地址,所以要将链接地址转换为运行地址(运行的物理地址)
	重定位技术: MMU
	重定位后, 访问全局符号 时,因为全局符号时虚拟地址,MMU自动将虚拟地址转换为运行地址,直接给出(指令或数据)
	

而 MMU 开启前, 创建了 三组页表,

其中对 整个 Image 所在内存的映射,
做出来的 start_kernel 虚拟地址 和 start_kernel 的链接地址 是一样的
不是因为巧合,是必须这么做.

下面看一下 链接地址的生成过程A(决定了链接地址) 和 页表的创建过程B(决定了虚拟地址)
A:
	arch/arm/kernel/vmlinux.lds
	10  . = ((0xC0000000)) + 0x00008000;                                                
	11  .head.text : {                                                                  
	12   _text = .; 
	 
	arch/arm/kernel/vmlinux.lds.S
	50     . = PAGE_OFFSET + TEXT_OFFSET;                                               
	51     .head.text : {                                                               
	52         _text = .;

	arch/arm/include/asm/memory.h
	24 #define PAGE_OFFSET     UL(CONFIG_PAGE_OFFSET)
	
	include/generated/autoconf.
	377 #define CONFIG_PAGE_OFFSET 0xC0000000
	
	arch/arm/Makefile
	141 textofs-y := 0x00008000
	238 TEXT_OFFSET := $(textofs-y)


B:
	arch/arm/kernel/head.S
	232     /*                                                                           
	233      * Map our RAM from the start to the end of the kernel .bss section.         
	234      */                                                                          
	235     add r0, r4, #PAGE_OFFSET >> (SECTION_SHIFT - PMD_ORDER)   // r4 = 50004000 , r0 = 50007000
			//  C0008000 的虚拟地址和  50004000的页表基址决定了 必须在 50007000 写页表           
	236                                                                                  
	237     ldr r6, =(_end - 1)   // _end : c08c413c                                                       
	238     orr r3, r8, r7        // 计算写入的值(页表描述符)   ,值为 50000c0e
			// 这个值决定了 该表为 section表
			// 索引该页表时,物理地址为  0x50000000 - 0x50100000                     
	239     add r6, r4, r6, lsr #(SECTION_SHIFT - PMD_ORDER)    // 计算 末位地址     
			// 此时已经准备好                     
	240 1:  str r3, [r0], #1 << PMD_ORDER         // 写入                                        
	241     add r3, r3, #1 << SECTION_SHIFT       // 重新计算写入的值(页表描述符)                                 
	242     cmp r0, r6                            // 比较写入的地址                    
	243     bls 1b								  // 地址不同,执行循环

	arch/arm/include/asm/pgtable-2level.h
	95 #define SECTION_SHIFT          20
	
	arch/arm/kernel/head.S
	44 #define PG_DIR_SIZE 0x4000
	45 #define PMD_ORDER   2


  • 重点函数解析 __mmap_switched
__mmap_switched
	
arch/arm/kernel/head-common.S
68  * The following fragment of code is executed with the MMU on in MMU mode,
69  * and uses absolute addresses; this is not position independent.
...
71  *  r0  = cp#15 control register (exc_ret for M-class) 				// 用来 mcr p15, 0, r0, c1, c0, 0       @ write control reg (arch/arm/kernel/head.S L476)
72  *  r1  = machine ID
73  *  r2  = atags/dtb pointer
74  *  r9  = processor ID
...
76     __INIT
77 __mmap_switched:
78
79     mov r7, r1														// 将 machine id 放入 r7 , 值为1626
80     mov r8, r2														// 将 atags pointer 放入 r8 , 值为 0xC0000100 (虚拟地址)
81     mov r10, r0														// 将 ??? 放入 r10
83     adr r4, __mmap_switched_data										// 将 __mmap_switched_data 的地址放入 r4
84     mov fp, #0 														// 将 0 放入 r11
101    ARM( ldmia   r4!, {r0, r1, sp} )									// 将内存中的数据加载到 寄存器中
																		// 将 __bss_start 放入 r0 , 该符号为连接符号,在 System.map 查到地址
																		// 将 __bss_stop  放入 r1
																		// 将 init_thread_union + THREAD_START_SP 放入 sp
...
104     sub r2, r1, r0													// r2 = r1 - r0, 计算 .bss段 的长度 , 0x00035BF4
105     mov r1, #0														// 将 0 放入 r1 中
106     bl  __memset            @ clear .bss							// 此时r0为__bss_start,r1为0,r2为长度,调用 __memset 来 clear bss
107
108     ldmia   r4, {r0, r1, r2, r3} 									// 将内存中的数据加载到 寄存器中
																		// 将 processor_id 放入 r0
																		// 将 __machine_arch_type 放入 r0
																		// 将 __atags_pointer 放入 r2
																		// 将 cr_alignment 放入 r3
109     str r9, [r0]            @ Save processor ID 					// 将r9中的值 放入 以r0中的值为地址的 地址中 ,赋值 unsigned int processor_id
110     str r7, [r1]            @ Save machine type						// 将r7中的值 放入 以r1中的值为地址的 地址中 ,赋值 unsigned int __machine_arch_type
111     str r8, [r2]            @ Save atags pointer 					// 将r8中的值 放入 以r2中的值为地址的 地址中 ,赋值 unsigned int __atags_pointer __initdata
112     cmp r3, #0														// 比较 r3中的值 与 0  , r3 中存放的值 的值 就是 cr_alignment 变量初始化的值 为 0 
113     strne   r10, [r3]           @ Save control register values 		// 不相等,则 将r10中的值 放入 以r3中的值为地址的 地址中 ,赋值 cr_alignment
...
117     mov lr, #0 														// 将 0 放入 lr 中
118     b   start_kernel 												// 跳转到 start_kernel , 不修改 lr



...
122     .type   __mmap_switched_data, %object                                         
123 __mmap_switched_data:
...
133     .long   __bss_start         @ r0                                             
134     .long   __bss_stop          @ r1                                             
135     .long   init_thread_union + THREAD_START_SP @ sp                             
136                                                                                  
137     .long   processor_id            @ r0                                         
138     .long   __machine_arch_type     @ r1                                         
139     .long   __atags_pointer         @ r2                                         
...
141     .long   cr_alignment            @ r3                                         
...
146     .size   __mmap_switched_data, . - __mmap_switched_data                       


  • b start_kernel 运行前的状态
b start_kernel 运行前的状态

cpu寄存器
	r0 		: 
	r1 		: 
	r2 		: 
	r3 		:
	r4 		: 
	r5 		: 
	r6 		:
	r7 		: 
	r8 		:
	r9 		:
	r10 	:
	r11 	: 
	r12 	: 
	r13 	: init_thread_union + THREAD_START_SP // init_thread_union + (((1 << 12) << 1) - 8) // 0xc0800000 + (十进制)8184 =  0xC0801FF8
	r14 	: 0
	pc 		: start_kernel 的虚拟地址 0xc07009f0
	spsr 	: 0x600001d3
	cpsr 	: 0x200001d3
		Supervisor Mode
		ARM Instruction Set
		IRQ disabled
		FIQ disabled
		Disables imprecise data aborts
		little endian
		
		运行非cpsr相关指令时会修改的位
			dsp指令
				GE[3:0] bit[19:16]
					在ARMv6中,SIMD指令使用位[19:16] 作为结果的单个字节或半字的大于或等于(GE)标志。您可以使用这些标志来控制以后的SEL指令
				Q 		bit[27] 
					在ARMv5及更高版本的E变体中,CPSR的位[27]的Q标志称为Q标志,用于指示在某些面向DSP的指令中是否发生了溢出和/或饱和。
			arm指令
				N	bit[31] 负
				Z 	bit[30] 零
				C 	bit[29] 进位
				V  	bit[28] 溢出
		

协处理器cp15寄存器
	cp15 Register 1: Control register 		: 0x00c5387d
		mmu 					: 	enabled
		Alignment fault checking: 	disabled
		Dcache					: 	enabled
		write buffer			: 	enabled
		The use of the S and R bits is deprecated in VMSAv6
		Icache 					: 	enabled
		
		Normal replacement strategy
		subpages 				: 	disabled	
	cp15 Register 2: Translation table base : 0x50004000 
		页表基址寄存器,存放的是物理地址
	cp15 Register 3: Domain access control 	: 0x00000051
		D0	: 01	: Client Accesses are checked against the access permission bits in the TLB entry
		D1 	: 00	: No access Any access generates a domain fault
		D2	: 01	: Client Accesses are checked against the access permission bits in the TLB entry
		D3 	: 01 	: Client Accesses are checked against the access permission bits in the TLB entry
		D4 	: 00	: No access Any access generates a domain fault
		...
	cp15 Register 7: cache management functions
		instr_sync : mcr p15, 0, r0, c7, c5, 4
			// Flush prefetch buffer (PrefetchFlush)
			// Instruction barrier

内存
	物理内存
		页表	  : 物理地址: 0x50005400 - 0x50005403 	__turn_mmu_on
		页表	  : 物理地址: 0x50007000 - 0x50007023 	Image
		页表	  : 物理地址: 0x50007fe0 - 0x50007fe7 	atags
		
		Image : 物理地址: 0x50008000 - 0x5088E547 8.6MB
		atags : 物理地址: 0x50000100 - 0x50000197 152字节
	虚拟内存
		针对页表	  : 用 下面(Image) 的映射关系
		针对Image : 虚拟地址:0xC000 0000 - 0xC08F FFFF 9MB  		<->		物理地址 0x5000 0000 - 0x508F FFFF 9MB
		针对atags : 虚拟地址:0xFF80 0000 - 0xFF9F FFFF 2MB 		<->		物理地址 0x5000 0000 - 0x501F FFFF 2MB
	
	页表内容:
		三组页表都是段表(bit[1:0]10)
		bit[31:20] 为 Section base address , 这个值在不同页表中不同
			// 例如 500 表示 Section base address : 500 00000
		其他bit都是相同的, bit[19:0]0x00c0e
			bit[1:0]:10	// 表示该First-level descriptor是一个 Section descriptor
			
			Memory region attributes
				TEX:000 
				B:1
				C:1
				S:0	
				
				表示 Outer and inner write back, no write allocate 
					// 对于 s3c6410 来说 , 无 Outer , inner 为 16KB的 dcache
					// 也就是说 dcache 支持 write back, 支持 no write allocate 
					// write allocate/write through/write back 是 缓存策略的范畴, 全局搜索 缓存策略
				Memory type : Normal
					// 属于内存属性的范畴 , 还没理清楚
				Page shareable : S设置则shareable,否则not shareable //该例为 not shareable
					// 属于内存属性的范畴 , 还没理清楚

			Memory access control
				Domains permissions
					Domain:0000	
						// 表明 属于 domain0 , D0 
						// 参与 Domains permissions
						// D0 为01,表示  Accesses are checked against the access permission bits in the TLB entry
						// 即 Domain permissions 是 OK的,但还要检查 access permission bits
				Access permissions
					APX:0
					AP:11	
						// 参与 Access permissions
						// 表示 Full access	
			XN:0	
				// 表示包含可执行代码	
			IMP:0	
				//微架构实现定义 , 需查询 ARM1176 的 TRM 手册
			nG:0	
				//页表翻译条目 在TLB中应标记为全局
		
	Image 虚拟内存分段
		Image 虚拟地址 : 0xC0008000 - 0xC088E547 8.6MB
			
			// include/asm-generic/sections.h
			
						_stext			_etext
		.code		: 	c0100000 	- 	c0600000
		
						__start_rodata	__end_rodata
		.rodata		: 	c0600000 	- 	c06b6000
		
						_sdata			_edata
		.data			c0800000 	- 	c088e548
		
						__bss_start 	__bss_stop
		.bss		: 	c088e548 	- 	c08c413c	
		
										init_thread_union + THREAD_START_SP
		.stack		: 				- 	C0801FF8
		
		.heap		: 	null
		
	Image 全局变量
		arch/arm/kernel/setup.c 中的 unsigned int processor_id					: 0x410fb766
		arch/arm/boot/compressed/misc.c 中的 unsigned int __machine_arch_type 	: 0x0000065a // 1626
		arch/arm/kernel/setup.c 中的 unsigned int __atags_pointer				: 0x50000100
			// SUDEBUG : arch/arm/kernel/setup.c,setup_arch,line = 1090,atags_vaddr:0xff800100
		arch/arm/kernel/entry-armv.S 中的 cr_alignment							: 0x00c5387d 	// cp15 Register 1: Control register 的值

其他
  • 过程 2 从 arch/arm/boot/compressed/head.S 中的start 到 arch/arm/kernel/head.S 中的 stext 的等价过程
参考 https://blog.csdn.net/u011011827/article/details/115766762 中的 镜像Image的执行 

bash ./scripts/mkuboot.sh -A arm -O linux -C none  -T kernel -a 0x50008000 -e 0x50008000 -n 'Linux-5.11.0-00004-g2b88cbadf5c-dirty' -d arch/arm/boot/Image arch/arm/boot/uImage2
=> tftp 0x50008000 uImage2
=> bootm 0x50008000

  • 缓存策略
一、CPU读数据

  1. Read through
    即直接从内存中读取数据;

  2. Read allocate
    先把数据读取到Cache中,再从Cache中读数据。

二、CPU写数据

  1. 若hit命中,有两种处理方式:

    Write-through:
    write through: 
      write is done synchronously both to the cache and to the backing store。
      (直写模式)在数据更新时,把数据同时写入Cache和后端存储。此模式的优点是操作简单;缺点是因为数据修改需要同时写入存储,数据写入速度较慢。

    Write-back (also called write-behind) write back
      initially, writing is done only to the cache. The write to the backing store is postponed until the cache blocks containing the data are about to be modified/replaced by new content。
      (回写模式)在数据更新时只写入缓存Cache。只在数据被替换出缓存时,被修改的缓存数据才会被写到后端存储(即先把数据写到Cache中,再通过flush方式写入到内存中)。
      此模式的优点是数据写入速度快,因为不需要写存储;缺点是一旦更新后的数据未被写入存储时出现系统掉电的情况,数据将无法找回。         

  2. 若miss,有两种处理方式:

    Write allocate (also called fetch on write)
      data at the missed-write location is loaded to cache, followed by a write-hit operation. In this approach, write misses are similar to read misses.
      先把要写的数据载入到Cache中,写Cache,然后再通过flush方式写入到内存中;  写缺失操作与读缺失操作类似。      

    No-write allocate (also called write-no-allocate or write around)
      data at the missed-write location is not loaded to cache, and is written directly to the backing store. In this approach, only the reads are being cached。
      并不将写入位置读入缓存,直接把要写的数据写入到内存中。这种方式下,只有读操作会被缓存。
  • swapper_pg_dir
arch/arm/kernel/head.S L28
swapper_pg_dir is the virtual address of the initial page table.


.globl swapper_pg_dir // 页表基址 对应的 虚拟地址
.equ swapper_pg_dir, (((0xC0000000)) + 0x00008000) - 0x4000
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值