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-g1829225a7faImage Type: ARM Linux Kernel Image (uncompressed)Data Size: 2913264 Bytes = 2.8 MiBLoad Address: 50008000Entry Point: 50008000Verifying Checksum ... OKLoading Kernel ImageStarting kernel ...Booting Linux on physical CPU 0x0
- 流程
u-boot 1. 将 zImage 放置到 500080002. 设置 r0 为 03. 设置 r1 为 1626 // 这个是 smdk6410的board id4. 设置 r2 为 atags的 地址 0x50000100 , 此前 设置 了 setup_start_tag setup_commandline_tag setup_memory_tags setup_end_tag , 这个有 152 字节5. 并 将pc 置为 0x50008000linux0x50008000 为 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.S184 .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 directly1410 __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-0x502D1200 到 0x5088F000-0x50B58140zImage 被 解压缩 为 Image,Image在哪里?
在 0x5088F000 前面,具体地址为
0x50008000 - 0x50008000 + 8938824(Image的大小) -1
即
0x50008000 - 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.S420 __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.S77 __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_tablesClear the swapper page table // 16KB 空间 即 4K个页表(1个页表4Byte) 清0,1个页表map 1MB虚拟地址 , 正好 Map 4GB虚拟地址addr value50004000 050004004 050004008 05000400c 0 50004010 0...50007ffc 0Create identity mapping to cater for __enable_mmu // __turn_mmu_onaddr value50005400 50100c0eMap our RAM from the start to the end of the kernel .bss section. // 9MB, 因为 我们的 Image 为 8.6M ,不足 9个MBaddr value50007000 50000c0e50007004 50100c0e50007008 50200c0e5000700c 50300c0e50007010 50400c0e50007014 50500c0e50007018 50600c0e5000701c 50700c0e50007020 50800c0eThen map boot params address in r2 if specifiedaddr value50007fe0 50000c0e50007fe4 50100c0e// 一旦开启 mmu , 多了虚拟地址 ,对应的虚拟地址为
500x xxxx __enable_mmu
C00x xxxx kernel
ff8x xxxx atags10 0000 是 1MB 页表的含义: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.lds10 . = ((0xC0000000)) + 0x00008000; 11 .head.text : { 12 _text = .; arch/arm/kernel/vmlinux.lds.S50 . = PAGE_OFFSET + TEXT_OFFSET; 51 .head.text : { 52 _text = .;arch/arm/include/asm/memory.h24 #define PAGE_OFFSET UL(CONFIG_PAGE_OFFSET)include/generated/autoconf.377 #define CONFIG_PAGE_OFFSET 0xC0000000arch/arm/Makefile141 textofs-y := 0x00008000238 TEXT_OFFSET := $(textofs-y)B:arch/arm/kernel/head.S232 /* 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.h95 #define SECTION_SHIFT 20arch/arm/kernel/head.S44 #define PG_DIR_SIZE 0x400045 #define PMD_ORDER 2
- 重点函数解析 __mmap_switched
__mmap_switchedarch/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 = 0xC0801FF8r14 : 0pc : start_kernel 的虚拟地址 0xc07009f0spsr : 0x600001d3cpsr : 0x200001d3Supervisor ModeARM Instruction SetIRQ disabledFIQ disabledDisables imprecise data abortslittle 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 : 0x00c5387dmmu : enabledAlignment fault checking: disabledDcache : enabledwrite buffer : enabledThe use of the S and R bits is deprecated in VMSAv6Icache : enabledNormal replacement strategysubpages : disabled cp15 Register 2: Translation table base : 0x50004000 页表基址寄存器,存放的是物理地址cp15 Register 3: Domain access control : 0x00000051D0 : 01 : Client Accesses are checked against the access permission bits in the TLB entryD1 : 00 : No access Any access generates a domain faultD2 : 01 : Client Accesses are checked against the access permission bits in the TLB entryD3 : 01 : Client Accesses are checked against the access permission bits in the TLB entryD4 : 00 : No access Any access generates a domain fault...cp15 Register 7: cache management functionsinstr_sync : mcr p15, 0, r0, c7, c5, 4// Flush prefetch buffer (PrefetchFlush)// Instruction barrier内存物理内存页表 : 物理地址: 0x50005400 - 0x50005403 __turn_mmu_on页表 : 物理地址: 0x50007000 - 0x50007023 Image页表 : 物理地址: 0x50007fe0 - 0x50007fe7 atagsImage : 物理地址: 0x50008000 - 0x5088E547 8.6MBatags : 物理地址: 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] 为 0x00c0ebit[1:0]:10 // 表示该First-level descriptor是一个 Section descriptorMemory region attributesTEX:000 B:1C:1S: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 controlDomains permissionsDomain:0000 // 表明 属于 domain0 , D0 // 参与 Domains permissions// D0 为01,表示 Accesses are checked against the access permission bits in the TLB entry// 即 Domain permissions 是 OK的,但还要检查 access permission bitsAccess permissionsAPX:0AP: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 : nullImage 全局变量arch/arm/kernel/setup.c 中的 unsigned int processor_id : 0x410fb766arch/arm/boot/compressed/misc.c 中的 unsigned int __machine_arch_type : 0x0000065a // 1626arch/arm/kernel/setup.c 中的 unsigned int __atags_pointer : 0x50000100// SUDEBUG : arch/arm/kernel/setup.c,setup_arch,line = 1090,atags_vaddr:0xff800100arch/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 backinitially, 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
OK6410A 开发板 (八) 6 linux-5.11 OK6410A 详细解析 从 u-boot 的 theKernel 到 linux的 start_kernel相关推荐
- OK6410A 开发板 (八) 63 linux-5.11 OK6410A linux内核空间常见的异常情景及分析 kernel exception
异常情景的level1 异常情景的level1 是最底层 show 当前状况的 api 其他具体的异常情景会根据 自身情景 调用 这些api oops打印Unable to ... 到 ---[ en ...
- 【Android 系统开发】 编译 Android文件系统 u-boot 内核 并烧写到 OK-6410A 开发板上
博客地址 : http://blog.csdn.net/shulianghan/article/details/40299813 本篇文章中用到的工具源码下载 : -- ok-6410A 附带的 A ...
- Linux操作系统PS命令详细 解析
http://blog.chinaunix.net/space.php?uid=20564848&do=blog&id=74654 Linux操作系统PS命令详细 解析 要对系统中进程 ...
- Linux操作系统Ifconfig命令详细解析
无论是Linux 自动安装还是我们手工安装,Linux 都会向你询问有关网络的问题并配置相关的软件.这个用于配置网卡的基本命令就是ifconfig. 在执行ifconfig 命令后,系统将在内核表中设 ...
- OK6410A 开发板 (三) 4 u-boot-2021.01 boot 解析 SPL 编译链接部分
1. include/generated/asm-offsets.h 和 include/generated/asm-offsets.h的生成 CC spl/./lib/asm-offsets.s U ...
- 移植QT5.6到韦东山JZ2240嵌入式开发板(史上最最最最最详细的QT移植教程)
首先感谢http://blog.csdn.net/lizuobin2/article/details/52673494的博主,应该是韦东山团队的老师,说实话,拿到JZ2440的板子很长时间了,每次都有 ...
- [Linux] Ubuntu13.04 搭建OK6410-A开发板的开发环境
# 下载dnw与驱动文件 cd ~ mkdir -p tmp 2>/dev/null cd tmp/ git clone git://github.com/Qunero/dnw4linux.gi ...
- OK6410A 开发板 (三) 3 u-boot-2021.01 boot 解析概览
// 需要分析的一套过程 1.配置文件分析 2.配置过程分析 3.编译过程分析 4.链接过程分析 5.生成文件分析 6.镜像加载分析 7.镜像运行分析 u-boot-2021.01 配置出来了 两个镜 ...
- Linux操作系统PS命令详细解析
要对系统中进程进行监测控制,用 ps 命令满足你. /bin/ps ps 是显示瞬间行程的状态,并不动态连续:如果想对进程运行时间监控,应该用 top 工具. kill 用于杀死进程. ======= ...
最新文章
- 'Push segues can only be used when the source controller is managed by an instance of UINavigationC
- html手机pc不同页面,PC端和手机端如何同时生成静态页
- GDCM:DICOM转储到DshibaDTI的测试程序
- PyTorch-训练
- python贪心算法求删数问题_贪心算法删数问题
- java 自动类型_java类型自动转换
- jqgrid为什么表头和数据之间有间隙_面试官:你看过Redis数据结构底层实现吗?...
- 952开头的电话一天响两三次,不是诈骗就是推销,请问该怎么屏蔽呢?
- 计算机的视觉应用研究,计算机视觉技术应用研究.doc
- springboot网上订餐管理系统设计与实现.rar(项目源码)
- 淘宝网卖家必须缴纳消保保证金才能发布宝贝的商品类目
- 小程序微信支付errcode:40163问题
- 输入一个数,打印一个三角形
- KVM磁盘格式转换,raw转qcow2
- 漫画:如何用脚本抢月饼?
- mysqlfulljoin
- [Python 爬虫] 使用 Scrapy 爬取新浪微博用户信息(三) —— 数据的持久化——使用MongoDB存储爬取的数据
- div布局根据内容自适应宽度
- 基于turn.js库电子书在线阅读器源码
- Windows+Ubuntu20.04双系统安装详细教程