Exynos4412 内核移植(三)—— 内核启动过程分析

内核启动所用函数如下:



        与移植U-Boot 的过程相似,在移植Linux 之前,先了解它的启动过程。Linux 的过程可以分为两部分:架构/开发板相关的引导过程、后续的通用启动过程。对于uImage、zImage ,它们首先进行自解压得到vmlinux ,然后执行 vmlinux 开始“正常的”启动流程。

       引导阶段通常使用汇编语言编写,它首先检查内核是否支持当前架构的处理器,然后检查是否支持当前开发板。通过检查后,就为调用下一阶段的start_kernel函数作准备了。这主要分如下两个步骤:

1)-- 连接内核时使用的虚拟地址,所以要设置页表、使能MMU;

2)调用C 函数 start_kernel 之前的常规工作,包括复制数据段、清除BSS段、调用start_kernel 函数。


        第二阶段的关键代码主要使用C语言编写。它进行内核初始化的全部工作,最后调用 rest_init 函数启动init 过程,创建系统第一个进程:init 进程。在第二阶段,仍有部分架构/开发板相关的代码,比如重新设置页表、设置系统时钟、初始化串口等。


下面是详细解析:

一、第一阶段

        与Uboot 一样,我们在连接文件中查看函数入口点,内核编译完成后会在arch/arm/kernel/下生成 vmlinux.lds 文件,打开:


        stext 在 linux/arch/arm/kernel/head.S 中被定义,做为函数入口点,linux/arch/arm/kernel/head.S是linux内核映像解压后执行的第一个文件



代码只是部分,但可以看到这一阶段究竟做了些什么:

a -- 设定为SVC模式,关闭IRQ、FIQ;

b -- 确定CPU的ID号,判定其是否有效;

c -- 确定machine的ID号,检查合法性;

d -- 检查bootloader传入的参数列表atags的合法性

e -- 创建初始页表


下面对上面遇到的程序段展开分析:

a -- 确保处于SVC模式


这没什么好讲的,就是设置CPSR 模式位,并屏蔽中断;


b -- 检查CPU ID 是否匹配



获取ID并放到 r9 寄存器中,调用_lookup_processor_type 函数, 函数主要用来判定内核是否和当前的CPU匹配,如果不匹配,r5寄存器的值应为0,此时会调用 _error_p函数,它用来打印错误信息,即内核和当前的CPU不匹配,此时内核时不能启动的;如果两者匹配,会返回一个描述处理器结构的地址(在r5寄存器中),然后调用下面的函数。

      下面看_lookup_processor_type 函数,在arch/arm/kernel/head-common.S 中定义:


        上面的代码其实就是一个地址转换过程,因为在判定CPU架构时未开启系统的MMU功能,所以均使用物理地址,而内核代码在连接时是以虚拟地址来实现的,因此要想用proc_info_list 结构体,就要先找到proc_info_list 结构的物理地址,这样必须使用上面的转换代码。

        proc_info_list 结构体很重要。在Linux 内核映像中定义了很多个proc_info_list 结构,该结构表示的是内核所支持的CPU架构,这部分下面会讲到,先分析上面的代码:

153 行:r3 存储的是_lookup_processor_type_data 的物理地址 ;

155 行:得到虚拟地址和物理地址之间的offset;

156 - 157 行:利用offset,将 r5 和 r6 中保存的虚拟地址转变为物理地址,主要是获得_proc_info_begin 及_proc_info_end 的物理地址,分别放到r5 和 r6 中

159 行:r9 中存放的是先前读出的 processor ID,此处屏蔽不需要的位;

160 行:查看代码和CPU硬件是否匹配,如果匹配就返回,此时 r5 存放的是该CPU类型对应的结构体_proc_info_list 的基地址 ;不成功,则查看下一个 proc_info_list 结构体;

163行:如果直到 _proc_info_end ,都没有匹配,则定为未知CPU,向 r5 赋 0,然后返回 ;


      下面来看看 proc_info_list 结构体 ,这个结构体在 arch/arm/include/asm/procinfo.h 中定义:



对于 Cortex-A9 来说,其结构体在文件 arch/arm/mm/proc-v7.S 中初始化



       .section ".proc.info.init"表明了该结构在编译后存放的位置。在链接文件arch/arm/kernel/vmlinux.lds中:

__proc_info_begin .;

*(.proc.info.init)

__proc_info_end .;


      上面两个变量 _proc_info_begin  与 _proc_info_end 用于计算 proc_info_list 结构的物理地址。

      如果CPU ID匹配,在编译内核文件时,会编译 proc-v7.S 这个文件,可以在arch/arm/mm/Makefile 中看到这个文件



c -- 检测 机器ID是否匹配

      主要用到_lookup_machine_type 函数,其与_lookup_processor_type 函数实现代码很相似,这里不予阐述;


d -- 检查bootloader传入的参数列表atags的合法性



        _vet_atags 函数用于检测参数列表atags的合法性

        内核参数链表的格式和说明可以从内核源代码目录树中的 中找到,参数链表必须以ATAG_CORE 开始,以ATAG_NONE结束。这里的 ATAG_CORE,ATAG_NONE是各个参数的标记,本身是一个32位值,例如:ATAG_CORE=0x54410001。其它的参数标记还包括: ATAG_MEM32 , ATAG_INITRD , ATAG_RAMDISK ,ATAG_COMDLINE 等。每个参数标记就代表一个参数结构体,由各个参数结构体构成了参数链表。参数结构体的定义如下:

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. struct tag {  
  2.       struct  tag_header  hdr;  
  3.       union {  
  4.              struct tag_core  core;  
  5.        struct tag_mem32   mem;  
  6.           struct tag_videotext videotext;  
  7. struct tag_ramdisk  ramdisk;  
  8. struct tag_initrd     initrd;  
  9.           struct tag_serialnr     serialnr;  
  10. struct tag_revision  revision;  
  11.           struct tag_videolfb  videolfb;  
  12.           struct tag_cmdline  cmdline;  
  13.  struct tag_acorn       acorn;  
  14. struct tag_memclk    memclk;  
  15.         } u;  
  16. };  

参数结构体包括两个部分,一个是 tag_header结构体,一个是u联合体。

tag_header结构体的定义如下: 
   struct tag_header { 
                 u32 size;   
                 u32 tag; 
}; 

其中 size:表示整个 tag 结构体的大小(用字的个数来表示,而不是字节的个数),等于tag_header的大小加上 u联合体的大小,例如,参数结构体 ATAG_CORE 的 size=(sizeof(tag->tag_header)+sizeof(tag->u.core))>>2,一般通过函数 tag_size(struct * tag_xxx)来获得每个参数结构体的 size。其中 tag:表示整个 tag 结构体的标记,如:ATAG_CORE等。 

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. __vet_atags:  
  2. tst r2, #0x3 //r2指向该参数链表的起始位置,此处判断它是否字对齐  
  3. bne 1f  
  4.    
  5. ldr r5, [r2, #0] //获取第一个tag结构的size  
  6. //#define ATAG_CORE_SIZE ((2*4 + 3*4) >> 2) 判断该tag的长度是否合法  
  7. subs r5, r5, #ATAG_CORE_SIZE  
  8. bne 1f  
  9. ldr r5, [r2, #4]  //获取第一个tag结构体的标记,  
  10. ldr r6, =ATAG_CORE   
  11. cmp r5, r6 //判断第一个tag结构体的标记是不是ATAG_CORE  
  12. bne 1f    
  13.    
  14. mov pc, lr //正常退出  
  15.    
  16. 1: mov r2, #0  
  17. mov pc, lr  //参数连表不正确  
  18. ENDPROC(__vet_atags)  


e -- 创建初始页表


其在下面被执行:


下面是详细分析:

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. /* 
  2.  * Setup the initial page tables.  We only setup the barest 
  3.  * amount which are required to get the kernel running, which 
  4.  * generally means mapping in the kernel code. 
  5.  * 
  6.  * r8 = phys_offset, r9 = cpuid, r10 = procinfo 
  7.  * 
  8.  * Returns: 
  9.  *  r0, r3, r5-r7 corrupted 
  10.  *  r4 = page table (see ARCH_PGD_SHIFT in asm/memory.h) 
  11.  */  
  12. __create_page_tables:  
  13.     pgtbl   r4, r8              @ page table address  
  14.   
  15.     /* 
  16.      * Clear the swapper page table 
  17.      */  
  18.     mov r0, r4  
  19.     mov r3, #0  
  20.     add r6, r0, #PG_DIR_SIZE  
  21. 1:  str r3, [r0], #4  
  22.     str r3, [r0], #4  
  23.     str r3, [r0], #4  
  24.     str r3, [r0], #4  
  25.     teq r0, r6  
  26.     bne 1b  
  27.   
  28. #ifdef CONFIG_ARM_LPAE  
  29.     /* 
  30.      * Build the PGD table (first level) to point to the PMD table. A PGD 
  31.      * entry is 64-bit wide. 
  32.      */  
  33.     mov r0, r4  
  34.     add r3, r4, #0x1000         @ first PMD table address  
  35.     orr r3, r3, #3          @ PGD block type  
  36.     mov r6, #4              @ PTRS_PER_PGD  
  37.     mov r7, #1 << (55 - 32)       @ L_PGD_SWAPPER  
  38. 1:  
  39. #ifdef CONFIG_CPU_ENDIAN_BE8  
  40.     str r7, [r0], #4            @ set top PGD entry bits  
  41.     str r3, [r0], #4            @ set bottom PGD entry bits  
  42. #else  
  43.     str r3, [r0], #4            @ set bottom PGD entry bits  
  44.     str r7, [r0], #4            @ set top PGD entry bits  
  45. #endif  
  46.     add r3, r3, #0x1000         @ next PMD table  
  47.     subs    r6, r6, #1  
  48.     bne 1b  
  49.   
  50.     add r4, r4, #0x1000         @ point to the PMD tables  
  51. #ifdef CONFIG_CPU_ENDIAN_BE8  
  52.     add r4, r4, #4          @ we only write the bottom word  
  53. #endif  
  54. #endif  
  55.   
  56.     ldr r7, [r10, #PROCINFO_MM_MMUFLAGS] @ mm_mmuflags  
  57.   
  58.     /* 
  59.      * Create identity mapping to cater for __enable_mmu. 
  60.      * This identity mapping will be removed by paging_init(). 
  61.      */  
  62.     adr r0, __turn_mmu_on_loc  
  63.     ldmia   r0, {r3, r5, r6}  
  64.     sub r0, r0, r3          @ virt->phys offset  
  65.     add r5, r5, r0          @ phys __turn_mmu_on  
  66.     add r6, r6, r0          @ phys __turn_mmu_on_end  
  67.     mov r5, r5, lsr #SECTION_SHIFT  
  68.     mov r6, r6, lsr #SECTION_SHIFT  
  69.   
  70. 1:  orr r3, r7, r5, lsl #SECTION_SHIFT  @ flags + kernel base  
  71.     str r3, [r4, r5, lsl #PMD_ORDER]    @ identity mapping  
  72.     cmp r5, r6  
  73.     addlo   r5, r5, #1          @ next section  
  74.     blo 1b  
  75.   
  76.     /* 
  77.      * Map our RAM from the start to the end of the kernel .bss section. 
  78.      */  
  79.     add r0, r4, #PAGE_OFFSET >> (SECTION_SHIFT - PMD_ORDER)  
  80.     ldr r6, =(_end - 1)  
  81.     orr r3, r8, r7  
  82.     add r6, r4, r6, lsr #(SECTION_SHIFT - PMD_ORDER)  
  83. 1:  str r3, [r0], #1 << PMD_ORDER  
  84.     add r3, r3, #1 << SECTION_SHIFT  
  85.     cmp r0, r6  
  86.     bls 1b  
  87.   
  88. #ifdef CONFIG_XIP_KERNEL  
  89.     /* 
  90.      * Map the kernel image separately as it is not located in RAM. 
  91.      */  
  92. #define XIP_START XIP_VIRT_ADDR(CONFIG_XIP_PHYS_ADDR)  
  93.     mov r3, pc  
  94.     mov r3, r3, lsr #SECTION_SHIFT  
  95.     orr r3, r7, r3, lsl #SECTION_SHIFT  
  96.     add r0, r4,  #(XIP_START & 0xff000000) >> (SECTION_SHIFT - PMD_ORDER)  
  97.     str r3, [r0, #((XIP_START & 0x00f00000) >> SECTION_SHIFT) << PMD_ORDER]!  
  98.     ldr r6, =(_edata_loc - 1)  
  99.     add r0, r0, #1 << PMD_ORDER  
  100.     add r6, r4, r6, lsr #(SECTION_SHIFT - PMD_ORDER)  
  101. 1:  cmp r0, r6  
  102.     add r3, r3, #1 << SECTION_SHIFT  
  103.     strls   r3, [r0], #1 << PMD_ORDER  
  104.     bls 1b  
  105. #endif  
  106.   
  107.     /* 
  108.      * Then map boot params address in r2 if specified. 
  109.      * We map 2 sections in case the ATAGs/DTB crosses a section boundary. 
  110.      */  
  111.     mov r0, r2, lsr #SECTION_SHIFT  
  112.     movs    r0, r0, lsl #SECTION_SHIFT  
  113.     subne   r3, r0, r8  
  114.     addne   r3, r3, #PAGE_OFFSET  
  115.     addne   r3, r4, r3, lsr #(SECTION_SHIFT - PMD_ORDER)  
  116.     orrne   r6, r7, r0  
  117.     strne   r6, [r3], #1 << PMD_ORDER  
  118.     addne   r6, r6, #1 << SECTION_SHIFT  
  119.     strne   r6, [r3]  
  120.   
  121. #if defined(CONFIG_ARM_LPAE) && defined(CONFIG_CPU_ENDIAN_BE8)  
  122.     sub r4, r4, #4          @ Fixup page table pointer  
  123.                         @ for 64-bit descriptors  
  124. #endif  
  125.   
  126. #ifdef CONFIG_DEBUG_LL  
  127. #if !defined(CONFIG_DEBUG_ICEDCC) && !defined(CONFIG_DEBUG_SEMIHOSTING)  
  128.     /* 
  129.      * Map in IO space for serial debugging. 
  130.      * This allows debug messages to be output 
  131.      * via a serial console before paging_init. 
  132.      */  
  133.     addruart r7, r3, r0  
  134.   
  135.     mov r3, r3, lsr #SECTION_SHIFT  
  136.     mov r3, r3, lsl #PMD_ORDER  
  137.   
  138.     add r0, r4, r3  
  139.     mov r3, r7, lsr #SECTION_SHIFT  
  140.     ldr r7, [r10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags  
  141.     orr r3, r7, r3, lsl #SECTION_SHIFT  
  142. #ifdef CONFIG_ARM_LPAE  
  143.     mov r7, #1 << (54 - 32)       @ XN  
  144. #ifdef CONFIG_CPU_ENDIAN_BE8  
  145.     str r7, [r0], #4  
  146.     str r3, [r0], #4  
  147. #else  
  148.     str r3, [r0], #4  
  149.     str r7, [r0], #4  
  150. #endif  
  151. #else  
  152.     orr r3, r3, #PMD_SECT_XN  
  153.     str r3, [r0], #4  
  154. #endif  
  155.   
  156. #else /* CONFIG_DEBUG_ICEDCC || CONFIG_DEBUG_SEMIHOSTING */  
  157.     /* we don't need any serial debugging mappings */  
  158.     ldr r7, [r10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags  
  159. #endif  
  160.   
  161. #if defined(CONFIG_ARCH_NETWINDER) || defined(CONFIG_ARCH_CATS)  
  162.     /* 
  163.      * If we're using the NetWinder or CATS, we also need to map 
  164.      * in the 16550-type serial port for the debug messages 
  165.      */  
  166.     add r0, r4, #0xff000000 >> (SECTION_SHIFT - PMD_ORDER)  
  167.     orr r3, r7, #0x7c000000  
  168.     str r3, [r0]  
  169. #endif  
  170. #ifdef CONFIG_ARCH_RPC  
  171.     /* 
  172.      * Map in screen at 0x02000000 & SCREEN2_BASE 
  173.      * Similar reasons here - for debug.  This is 
  174.      * only for Acorn RiscPC architectures. 
  175.      */  
  176.     add r0, r4, #0x02000000 >> (SECTION_SHIFT - PMD_ORDER)  
  177.     orr r3, r7, #0x02000000  
  178.     str r3, [r0]  
  179.     add r0, r4, #0xd8000000 >> (SECTION_SHIFT - PMD_ORDER)  
  180.     str r3, [r0]  
  181. #endif  
  182. #endif  
  183. #ifdef CONFIG_ARM_LPAE  
  184.     sub r4, r4, #0x1000     @ point to the PGD table  
  185.     mov r4, r4, lsr #ARCH_PGD_SHIFT  
  186. #endif  
  187.     mov pc, lr  
  188. ENDPROC(__create_page_tables)  


f -- 使能MMU,跳转到start_kernel



文件linux/arch/arm/kernel/head.S



文件linux/arch/arm/kernel/head.S



在前面有过这样的指令操作ldr r13, __switch_data 

mov pc, r13 就是将跳转到__switch_data处。

在文件linux/arch/arm/kernel/head-common.S中:

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. .type __switch_data, %object  //定义一个对象  
  2. __switch_data:  
  3. .long __mmap_switched  //由此可知上面程序将跳转到该程序段处。  
  4. .long __data_loc @ r4  
  5. .long _data @ r5  
  6. .long __bss_start @ r6  
  7. .long _end @ r7  
  8. .long processor_id @ r4  
  9. .long __machine_arch_type @ r5  
  10. .long __atags_pointer @ r6  
  11. .long cr_alignment @ r7  
  12. .long init_thread_union + THREAD_START_SP @ sp  
  13.    
  14.    
  15.  . = PAGE_OFFSET + TEXT_OFFSET;  
  16.  #else  
  17.  . = ALIGN(THREAD_SIZE);  
  18.  __data_loc = .;  
  19.  #endif  
  20.    
  21.  .data : AT(__data_loc) {  //此处数据存储在上面__data_loc处。  
  22.  _data = .;  
  23.    
  24.  *(.data.init_task)  
  25. …………………………  
  26.    
  27. .bss : {  
  28. __bss_start = .;  
  29. *(.bss)  
  30. *(COMMON)  
  31. _end = .;  
  32. }  
  33. ………………………………  
  34. }  
  35. init_thread_union 是 init进程的基地址. 在 arch/arm/kernel/init_task.c 中:  
  36.    
  37. 00033: union thread_union init_thread_union  
  38. 00034:         __attribute__((__section__(".init.task"))) =  
  39. 00035:                 { INIT_THREAD_INFO(init_task) };          
  40.    
  41.     对照 vmlnux.lds.S 中,我们可以知道init task是存放在 .data 段的开始8k, 并且是THREAD_SIZE(8k)对齐的  
  42. */  
  43.    
  44. __mmap_switched:  
  45. adr r3, __switch_data + 4  
  46.    
  47. ldmia r3!, {r4, r5, r6, r7}    
  48. cmp r4, r5 @ Copy data segment if needed  
  49. 1: cmpne r5, r6  //将 __data_loc处数据搬移到_data处  
  50. ldrne fp, [r4], #4  
  51. strne fp, [r5], #4  
  52. bne 1b  
  53.    
  54. mov fp, #0 //清除BSS段内容  
  55. 1: cmp r6, r7      
  56. strcc fp, [r6],#4  
  57. bcc 1b  
  58.    
  59. ldmia r3, {r4, r5, r6, r7, sp}  
  60. str r9, [r4] @ Save processor ID  
  61. str r1, [r5] @ Save machine type  
  62. str r2, [r6] @ Save atags pointer  
  63. bic r4, r0, #CR_A @ Clear 'A' bit  
  64. stmia r7, {r0, r4} @ Save control register values  
  65. b start_kernel  //程序跳转到函数start_kernel进入C语言部分。  
  66. ENDPROC(__mmap_switched)  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/402091.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

开源自己用python封装的一个Windows GUI(UI Automation)自动化工具,支持MFC,Windows Forms,WPF,Metro,Qt...

首先&#xff0c;大家可以看下这个链接 Windows GUI自动化测试技术的比较和展望 。 这篇文章介绍了Windows中GUI自动化的三种技术&#xff1a;Windows API, MSAA - Microsoft Active Accessibility, UIAutomation 用脚本语言AutoIT实现自动化就是第一种技术Windows API, 查找窗…

Exynos4412 Uboot 移植(六)—— 相关知识补充

Uboot版本&#xff1a;u-boot-2013.01 一、gd结构体的定义与使用 gd_t 和 bd_t 是u-boot中两个重要的数据结构&#xff0c;在初始化操作很多都要靠这两个数据结构来保存或传递。 gd_t 定义在/u-boot-2013.01/arch/arm/include/asm/global_data.h bd_t 定义在 ./include/asm-ar…

Exynos4412 Uboot 移植(五)—— Uboot 移植过程

Uboot 版本&#xff1a;u-boot-2013.01 开发板&#xff1a;FS_4412 平台&#xff08;Exynos4412,可以根据自己的板子修改&#xff0c;只要是4412的过程都是一样的&#xff09; 一、建立自己的平台 1、下载源码 我们可以在下面这个网站上下载最新的和以前任一版本的uboot ftp://…

Nagios 安装及常见错误

一、实验环境监控服务器&#xff08;nagios服务器--192.168.1.100&#xff09;CentOS5.4 nagios-3.2.1 nagios-plugins-1.4.14 nrpe-2.12被监控客户端&#xff08;linux客户端--192.168.1.200&#xff09;CentOS5.4 nagios-plugins-1.4.14 nrpe-2.12二、nrpe插件1、nrpe插…

Exynos4412 Uboot 移植(四)—— Uboot引导内核过程分析

bootloader 要想启动内核&#xff0c;可以直接跳到内核的第一个指令处&#xff0c;即内核的起始地址&#xff0c;这样便可以完成内核的启动工作了。但是要想启动内核还需要满足一些条件&#xff0c;如下所示&#xff1a; 1、cpu 寄存器设置 * R0 0 * R1 机器类型 id …

Exynos4412 Uboot 移植(三)—— Uboot添加自定义命令

Uboot添加自定义命令&#xff1a;uboot中的命令使用U_BOOT_CMD这个宏声明来注册进系统&#xff0c;链接脚本会把所有的cmd_tbl_t结构体放在相邻的地方。 UBoot版本&#xff1a;u-boot-2013.01 一、U-Boot命令的格式 即使是内核的启动&#xff0c;也是通过U-Boot命令来实现的。…

Exynos4412 Uboot 移植(二)—— Uboot 启动流程分析

uboot启动流程分析如下&#xff1a; 第一阶段&#xff1a; a -- 设置cpu工作模式为SVC模式 b -- 关闭中断&#xff0c;mmu,cache v -- 关看门狗 d -- 初始化内存&#xff0c;串口 e -- 设置栈 f -- 代码自搬移 g -- 清bss h -- 跳c 第二阶段 a -- 初始化外设&#xff0c;进入超…

Linux内核学习四库全书

http://blog.csdn.net/21aspnet/article/details/6585602 关于内核学习我建议不要上来就读内核而是先了解内核的构成和特性&#xff0c;然后通过思考发现疑问这时再去读内核源码。即先了解概貌在读局部细节。而且内核分成好多部分&#xff0c;不要只是按照顺序去读&#xff0c;…

Exynos4412 Uboot 移植(一)—— Uboot 编译流程分析

Uboot 所用版本 u-boot-2013.01 u-boot-2013.01 中有上千文件&#xff0c;要想了解对于某款开发板&#xff0c;使用哪些文件、哪些文件首先执行、可执行文件占用内存的情况&#xff0c;最好的方法就是阅读它的Makefile。 根据顶层Readme文件的说明&#xff1a; 可以知道如果使…

Exynos4412 所用内存 —— DDR2

一、SDRAM 二、DDR 三、DDR2 四、DDR2的配置

Exynos4412启动过程分析

学习Exynos4412启动流程前&#xff0c;我们先看看三星4412芯片启动框图&#xff1a; 我们从图中可以看到4412内部有64K的ROM和256K SRAM&#xff0c;在ROM中已经固化好了一段代码&#xff0c;当硬件上电后首先运行的就是这段代码&#xff0c;这段代码三星起名为BLO&#xff08;…

Exynos4412 所用外存 —— eMMC

Exynos4412所用外存不是原来的Nand Flash 与 Nor Flash&#xff0c;而是eMMC。eMMC是什么呢&#xff1f;和Nand Flash有什么区别呢&#xff1f; 一、eMMC概述 eMMC&#xff08;Embeded MultiMedia Card&#xff09;&#xff1a;它并非是一种全新尺寸的存储卡&#xff0c;而…

mini-uboot 启动过程简单分析

单片机有最小系统&#xff0c;所谓最小系统&#xff0c;就是单片机能正常工作所需要的最少外设。对于Uboot来说&#xff0c;同样有个最小系统&#xff0c;因为Uboot最主要的功能就是引导内核。下面我们通过一个简单的Mini-Uboot来分析Uboot的启动加载过程。&#xff08;只是分析…

MySql中的varchar类型

2019独角兽企业重金招聘Python工程师标准>>> MySql中的varchar类型&#xff08;转&#xff09; 今天新开始的项目在做数据库设计&#xff0c;发现自己对MySql的varchar类型还不熟悉&#xff0c;故又上网收集资料整理如下。 1.varchar类型的变化 MySQL 数据库的va…

进入保护模式(三)内存的分页

2019独角兽企业重金招聘Python工程师标准>>> 一、分页 先入为主理解的分页和系统中内存内应的分页 1.弄过数据库数据查找展示&#xff0c;有个数据分页展示的概念&#xff0c;这个的目的是为了速度、和展示效果上的提升 2.内存的分页又是怎么回事哪&#xff1f; …

C#实现简单的 Ping 的功能,用于测试网络是否已经联通

1 /// <summary>2 /// 是否能 Ping 通指定的主机3 /// </summary>4 /// <param name"ip">ip 地址或主机名或域名</param>5 /// <returns>true 通&#xff0c;false 不通</returns>6 …

Binutils工具集 解析

对于嵌入式系统开发&#xff0c;掌握相应的工具至关重要&#xff0c;它能使我们解决问题的效率大大提高。目前&#xff0c;可以说嵌入式系统的开发工具是GNU的天下&#xff0c;因为来自GNU的GCC编译器支持大量的目标处理器。除了GCC&#xff0c;还有一个非常重要的、同样来自于…

ARM 软中断指令SWI

前面我们学习ARM工作模式中&#xff0c;处理器模式切换可以通过软件控制进行切换&#xff0c;即修改CPSR模式位&#xff0c;但这是在特权模式下&#xff0c;当我们处于用户模式下&#xff0c;是没有权限实现模式转换的。若想实现模式切换&#xff0c;只能由另一种方法来实现&am…

yum install 失败

https://blog.csdn.net/weixin_45621658/article/details/110734514 原因&#xff1a;centos6的默认源在2012年-12月左右被官方搞掉了 下列是错误详情 Bash [rootc8-20 ~]# yum makecache Loaded plugins: fastestmirror Loading mirror speeds from cached hostfile YumRepo …

sphinx

2019独角兽企业重金招聘Python工程师标准>>> ./configure --prefix/usr/local/sphinx --with-mysql/usr/local/mysql make && make install cd /usr/local/sphinx/etc cp sphinx.conf.dist sphinx.conf vim sphinx.conf mysql -u test < /usr/local/sphi…