当前位置:首页 > 代码 > 正文

bootloader代码(bootloader代码解读)

admin 发布:2022-12-19 21:20 123


本篇文章给大家谈谈bootloader代码,以及bootloader代码解读对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。

本文目录一览:

嵌入式linux的bootloader的启动流程是怎样的?

嵌入式 Linux 系统从软件角度看可以分为四个部分:引导加载程序(Bootloader), Linux 内核,文件系统,应用程序。

当系统首次引导时,或系统被重置时,处理器会执行一个位于Flash/ROM中的已知位置处的代码,Bootloader就是这第一段代码。它主要用来初始化处理器及外设,然后调用 Linux 内核。Linux 内核在完成系统的初始化之后需要挂载某个文件系统作为根文件系统(Root Filesystem),然后加载必要的内核模块,启动应用程序。这就是嵌入式Linux系统启动过程 Linux 引导的整个过程。

Bootloader 的启动方式:

网络启动方式。这种方式的开发板不需要较大的存储介质,跟无盘工作站有点类似,但是使用这种启动方式之前,需要把Bootloader安装到板上的EPROM或者Flash中。Bootloader通过以太网接口远程下载Linux内核映像或者文件系统。Bootloader下载文件一般都使用TFTP网络协议,还可以通过DHCP的方式动态配置IP地址。

硬盘启动方式

传统的Linux系统运行在台式机或者服务器上,这些计算机一般都使用BIOS引导,并使用磁盘作为存储介质。Linux传统上是LILO (Linux Loader) 引导,后来又出现了GUN的软件 (Grand Unified Bootloader) 。 这两种Bootloader广泛应用在X86的Linux系统上。

Flash启动方式。大多数嵌入式系统上都使用Flash存储介质。Flash有很多类型,包括NOR Flash、NAND Flash和其它半导体盘。它们之间的不同在于: NOR Flash 支持芯片内执行(XIP, eXecute In Place),这样代码可以在Flash上直接执行而不必拷贝到RAM中去执行。而NAND Flash并不支持XIP,所以要想执行 NAND Flash 上的代码,必须先将其拷贝到 RAM中去,然后跳到 RAM 中去执行。NOR Flash 使用最为普遍。Bootloader一般放在Flash的底端或者顶端,这需要根据处理器的复位向量来进行设置。可以配置成MTD设备来访问Flash分区。

什么是Bootloader,为何要解锁Bootloader

Bootloader从字面上来看就是启动加载的意思。Bootloader是嵌入式系统在加电后执行的第一段代码。BootLoader是在操作系统内核运行之前运行。可以初始化硬件设备、建立内存空间映射图,从而将系统的软硬件环境带到一个合适状态,以便为最终调用操作系统内核准备好正确的环境。在嵌入式系统中,通常并没有像BIOS那样的固件程序,因此整个系统的加载启动任务就完全由BootLoader来完成。

因此可以看出,bootloader很重要,如果bootloader不能正常加载,手机就是砖头一个,无法正常启动和使用。这也就是为什么bootloader被锁的手机必须要破解才能刷第三方rom。

小米平板2刷机提示bootloader error code03怎么解决

bootloader error code 03

引导载入错误代码 03

1,先关机,然后按住开机+音量增加键(或按主屏幕键(即home键)+音量上键+电源键),进入Recovey模式,执行“Wipe data/factory reset”和“Wipe cache partiton”,将之前系统一些配置、缓存清除。

2,如果上述处理后,还是不能开机,建议到官网上下载ROM和刷机程序,尝试刷机。

3,如果上述方法无效或无法开机,建议联系官方售后去检测维修。

启动代码和BootLoader的区别和联系

启动代码和Bootloader有点类似于类和结构体的关系,也就是说结构体只是一种很特殊很特殊的类,但不能说类是一种结构体。

也就是说可以说启动代码是Bootloader,但是不能说Bootloader是启动代码。但是这也不是绝对的,只在某些情况下可以这么说。

通常,启动代码仅仅是指CPU复位后到main函数之前需要执行的汇编代码。需要这段代码是为了给C语言程序准备好堆栈空间,中断入口和外部数据等。而且这段汇编代码可以直接对硬件进行操作,效率很高。

Bootloader不是代码,而是程序,完整的程序,比如引导转载Linux和WinCE,以及BIOS程序。有些Bootloader将启动代 码也包含在内。也就是说启动代码相当于Bootloader的第一阶段,但是第一阶段的内容并不是绝对的,有些可以拿到第二阶段去实现,只不过牺牲了效 率。

什么是bootloader

Bootloader是嵌入式系统在加电后执行的第一段代码,在它完成CPU和相关硬件的初始化之后,再将操作系统映像或固化的嵌入式应用程序装在到内存中然后跳转到操作系统所在的空间,启动操作系统运行。[1]

对于嵌入式系统,Bootloader是基于特定硬件平台来实现的。因此,几乎不可能为所有的嵌入式系统建立一个通用的Bootloader,不同的处理器架构都有不同的Bootloader。Bootloader不但依赖于CPU的体系结构,而且依赖于嵌入式系统板级设备的配置。对于2块不同的嵌入式板而言,即使它们使用同一种处理器,要想让运行在一块板子上的Bootloader程序也能运行在另一块板子上,一般也都需要修改Bootloader的源程序。

反过来,大部分Bootloader仍然具有很多共性,某些Bootloader也能够支持多种体系结构的嵌入式系统。例如,U-Boot就同时支持PowerPC、ARM、MIPS和X86等体系结构,支持的板子有上百种。通常,它们都能够自动从存储介质上启动,都能够引导操作系统启动,并且大部分都可以支持串口和以太网接口。

在专用的嵌入式板子运行GNU/Linux系统已经变得越来越流行。一个嵌入式Linux系统从软件的角度看通常可以分为四个层次:

1、 引导加载程序。包括固化在固件(firmware)中的boot代码(可选),和BootLoader两大部分。

2、Linux内核。特定于嵌入式板子的定制内核以及内核的启动参数。

3、 文件系统。包括根文件系统和建立于Flash内存设备之上文件系统。通常用ramdisk来作为rootfs。

4、 用户应用程序。特定于用户的应用程序。有时在用户应用程序和内核层之间可能还会包括一个嵌入式图形用户界面。常用的嵌入式GUI有:MicroWindows和MiniGUI等。

通常,BootLoader是严重地依赖于硬件而实现的,特别是在嵌入式世界。因此,在嵌入式世界里建立一个通用的BootLoader几乎是不可能的。尽管如此,我们仍然可以对bootloader归纳出一些通用的概念来,以指导用户特定的BootLoader设计与实现。

关于Bootloader,是否有完整的应用笔记和参考代码

bootloader的最终目的是启动内核,而在启动内核前要进行一系列的初始化:

关闭看门狗、改变系统时钟、初始化存储控制器、重定位代码(将更多的代码复制到内存中去)等,

然后将内核从nand flash读到SDRAM中,为内核传递启动参数,跳到相应的地址启动内核。

1. 关闭看门狗

向WTCON寄存器WTCON中写入零

汇编代码:

ldr r0, =0x53000000

mov r1, #0

str r1, [r0]

C代码:(调用C代码之前必须先设置栈,即sp指针,指令mov sp, #4096)

#define WTCON (*(volatile unsigned long *)0x53000000)

void disable_watch_dog(void)

{

WTCON = 0; // 关闭WATCHDOG很简单,往这个寄存器写0即可

}

2. 设置系统时钟

汇编代码:

#define S3C2440_MPLL_400MHZ ((0x5c12)|(0x014)|(0x01))

ldr r0, =0x4c000014

// mov r1, #0x03; // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1

mov r1, #0x05; // FCLK:HCLK:PCLK=1:4:8

str r1, [r0]

/* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */

mrc p15, 0, r1, c1, c0, 0 /* 读出控制寄存器 */

orr r1, r1, #0xc0000000 /* 设置为“asynchronous bus mode” */

mcr p15, 0, r1, c1, c0, 0 /* 写入控制寄存器 */

/* MPLLCON = S3C2440_MPLL_200MHZ */

ldr r0, =0x4c000004

ldr r1, =S3C2440_MPLL_400MHZ

str r1, [r0]

C代码:

void clock_init(void)

{

// LOCKTIME = 0x00ffffff; // 使用默认值即可

CLKDIVN = 0x03; // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1

// 潜入汇编的写法,语法上的要求。

/* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */

__asm__(

"mrc p15, 0, r1, c1, c0, 0\n" /* 读出控制寄存器 */

"orr r1, r1, #0xc0000000\n" /* 设置为“asynchronous bus mode” */

"mcr p15, 0, r1, c1, c0, 0\n" /* 写入控制寄存器 */

);

MPLLCON = S3C2440_MPLL_200MHZ; /* 现在,FCLK=200MHz,HCLK=100MHz,PCLK=50MHz */

}

3. 初始化SDRAM

汇编代码:

ldr r0, =MEM_CTL_BASE

adr r1, sdram_config /* sdram_config的当前地址 */

add r3, r0, #(13*4)

1:

ldr r2, [r1], #4

str r2, [r0], #4

cmp r0, r3 // 比较r0和r1的值

bne 1b // bne 表示如果不相同跳转的标号为1的地方,后面跟一个b表示跳转到前面的1标号,如果跳转到后面去将b改为f即可

sdram_config:

.long 0x22011110 //BWSCON

.long 0x00000700 //BANKCON0

.long 0x00000700 //BANKCON1

.long 0x00000700 //BANKCON2

.long 0x00000700 //BANKCON3

.long 0x00000700 //BANKCON4

.long 0x00000700 //BANKCON5

.long 0x00018005 //BANKCON6

.long 0x00018005 //BANKCON7

.long 0x008C04F4 // REFRESH

.long 0x000000B1 //BANKSIZE

.long 0x00000030 //MRSRB6

.long 0x00000030 //MRSRB7

C代码:

void memsetup(void)

{

volatile unsigned long *p = (volatile unsigned long *)MEM_CTL_BASE;

/* 这个函数之所以这样赋值,而不是像前面的实验(比如mmu实验)那样将配置值

* 写在数组中,是因为要生成”位置无关的代码”,使得这个函数可以在被复制到

* SDRAM之前就可以在steppingstone中运行

*/

/* 存储控制器13个寄存器的值 */

p[0] = 0x22011110; //BWSCON

p[1] = 0x00000700; //BANKCON0

p[2] = 0x00000700; //BANKCON1

p[3] = 0x00000700; //BANKCON2

p[4] = 0x00000700; //BANKCON3

p[5] = 0x00000700; //BANKCON4

p[6] = 0x00000700; //BANKCON5

p[7] = 0x00018005; //BANKCON6

p[8] = 0x00018005; //BANKCON7

/* REFRESH,

* HCLK=12MHz: 0x008C07A3,

* HCLK=100MHz: 0x008C04F4

*/

p[9] = 0x008C04F4;

p[10] = 0x000000B1; //BANKSIZE

p[11] = 0x00000030; //MRSRB6

p[12] = 0x00000030; //MRSRB7

}

/*

* 初始化SDRAM后,必须重新设置栈,且将sp指针内存的指向最高,因为栈是重高地址向低地址向下增长的,

* 即使用命令ldr sp, =0x34000000 (将0x34000000赋值给sp指针,ldr是一条伪指令,当0x34000000数字很大的时候不能转换为一个立即数的时候,会通过几条汇编指令来完成)

*/

4. 初始化nand控制器

bl nand_init // 汇编调用C函数

/* 初始化NAND Flash */

void nand_init(void)

{

// 这三个值结合S3C2440手册和nand flash手册设置时序

#define TACLS 0

#define TWRPH0 1

#define TWRPH1 0

/* 设置时序 */

NFCONF = (TACLS12)|(TWRPH08)|(TWRPH14);

/* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */

NFCONT = (14)|(11)|(10);

}

5. 重定位代码

// 汇编中调用C函数时,r1传递函数的第一个参数,r2传递函数的第二个参数,r3传递函数的第三个参数

mov r0, #0

ldr r1, =_start // 来自汇编代码的第一行

// .text

// .global _start

// _start:

ldr r2, =__bss_start // __bss_start 来自链接脚本

sub r2, r2, r1

bl copy_code_to_sdram

void copy_code_to_sdram(unsigned char *src, unsigned char *dest, unsigned int len)

{

int i = 0;

/* 如果是NOR启动 */

if (isBootFromNorFlash())

{

while (i len)

{

dest[i] = src[i];

i++;

}

}

else

{

//nand_init();

nand_read((unsigned int)src, dest, len);

}

}

void nand_select(void)

{

NFCONT = ~(11);

}

void nand_deselect(void)

{

NFCONT |= (11);

}

void nand_cmd(unsigned char cmd)

{

volatile int i;

NFCMMD = cmd;

for (i = 0; i 10; i++);

}

void nand_addr(unsigned int addr)

{

unsigned int col = addr % 2048;

unsigned int page = addr / 2048;

volatile int i;

NFADDR = col 0xff;

for (i = 0; i 10; i++);

NFADDR = (col 8) 0xff;

for (i = 0; i 10; i++);

NFADDR = page 0xff;

for (i = 0; i 10; i++);

NFADDR = (page 8) 0xff;

for (i = 0; i 10; i++);

NFADDR = (page 16) 0xff;

for (i = 0; i 10; i++);

}

void nand_wait_ready(void)

{

while (!(NFSTAT 1));

}

unsigned char nand_data(void)

{

return NFDATA;

}

void nand_read(unsigned int addr, unsigned char *buf, unsigned int len)

{

int col = addr % 2048;

int i = 0;

/* 1. 选中 */

nand_select();

while (i len)

{

/* 2. 发出读命令00h */

nand_cmd(0x00);

/* 3. 发出地址(分5步发出) */

nand_addr(addr);

/* 4. 发出读命令30h */

nand_cmd(0x30);

/* 5. 判断状态 */

nand_wait_ready();

/* 6. 读数据 */

for (; (col 2048) (i len); col++)

{

buf[i] = nand_data();

i++;

addr++;

}

col = 0;

}

/* 7. 取消选中 */

nand_deselect();

}

链接脚本为:

SECTIONS {

. = 0x33f80000; // 起始链接地址

.text : { *(.text) } // 代码段

. = ALIGN(4); // 四字节对齐

.rodata : {*(.rodata*)} // 只读数据段

. = ALIGN(4);

.data : { *(.data) } // 数据段

. = ALIGN(4);

__bss_start = .; //bss段开始地址

.bss ALIGN(4) : { *(.bss) *(COMMON) }

__bss_end = .; //bss段结束地址

}

6. 清bss段(bss段是没有初始化的全局变量和初始化为零的全局变量)

void clear_bss(void)

{

extern int __bss_start, __bss_end; // __bss_start, __bss_end变量的值在链接脚本中设置的

int *p = __bss_start;

for (; p __bss_end; p++)

*p = 0;

}

7. 传递启动参数

a. 初始化串口

void uart0_init(void)

{

GPHCON |= 0xa0; // GPH2,GPH3用作TXD0,RXD0

GPHUP = 0x0c; // GPH2,GPH3内部上拉

ULCON0 = 0x03; // 8N1(8个数据位,无较验,1个停止位)

UCON0 = 0x05; // 查询方式,UART时钟源为PCLK

UFCON0 = 0x00; // 不使用FIFO

UMCON0 = 0x00; // 不使用流控

UBRDIV0 = UART_BRD; // 波特率为115200

}

b. 将内核从nand flash中读到SDRAM中

nand_read(0x60000+64, (unsigned char *)0x30008000, 0x200000);

读入的内核是uImage,它包含64字节的头部和内核文件。

c. 设置启动参数

/* 2. 设置参数 */

puts("Set boot params\n\r");

setup_start_tag();

setup_memory_tags();

setup_commandline_tag("noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0");

setup_end_tag();

static struct tag *params;

void setup_start_tag(void)

{

params = (struct tag *)0x30000100; // 设置传入参数的首地址

params-hdr.tag = ATAG_CORE;

params-hdr.size = tag_size (tag_core);

params-u.core.flags = 0;

params-u.core.pagesize = 0;

params-u.core.rootdev = 0;

params = tag_next (params);

}

void setup_memory_tags(void)

{

params-hdr.tag = ATAG_MEM;

params-hdr.size = tag_size (tag_mem32);

params-u.mem.start = 0x30000000; // 设置内存的首地址

params-u.mem.size = 64*1024*1024; // 设置内存的大小

params = tag_next (params);

}

int strlen(char *str)

{

int i = 0;

while (str[i])

{

i++;

}

return i;

}

void strcpy(char *dest, char *src)

{

while ((*dest++ = *src++) != '\0');

}

void setup_commandline_tag(char *cmdline) // 设置参数

{

int len = strlen(cmdline) + 1;

params-hdr.tag = ATAG_CMDLINE;

params-hdr.size = (sizeof (struct tag_header) + len + 3) 2;

strcpy (params-u.cmdline.cmdline, cmdline);

params = tag_next (params);

}

void setup_end_tag(void)

{

params-hdr.tag = ATAG_NONE;

params-hdr.size = 0;

8. 启动内核

void (*theKernel)(int zero, int arch, unsigned int params); // 定义一个函数指针

theKernel = (void (*)(int, int, unsigned int))0x30008000; // 设置函数指针的值

theKernel(0, 1999, 0x30000100); // 跳到该地址去执行,启动内核

关于bootloader代码和bootloader代码解读的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。

版权说明:如非注明,本站文章均为 AH站长 原创,转载请注明出处和附带本文链接;

本文地址:http://ahzz.com.cn/post/24676.html


取消回复欢迎 发表评论:

分享到

温馨提示

下载成功了么?或者链接失效了?

联系我们反馈

立即下载