STM32工程师 LINUX学习笔记2 u-boot 启动流程

本文详细解释了STM32中u-boot的启动流程,重点介绍了如何通过链接脚本找到程序入口,以及中断向量表的设置过程,包括save_boot_params函数的作用。
摘要由CSDN通过智能技术生成

DAY 1

学习一定要利用好三分钟热血来学习。
寄存器级别的操作是stm32工程师熟悉的也是这次linux学习的重点。

u-boot 启动流程详解

通过分析 uboot 的启动流程可以了解 Linux 内核是如何被启动的。
要分析 uboot 的启动流程,首先要找到“入口”,找到第一行程序在哪里。程序的链接是由
链接脚本来决定的,所以通过链接脚本可以找到程序的入口。

  • u-boot.lds 就是u-boot链接文件。 该文件相当于STM32开发中的.sct 分散加载文件。
    定义中断向量表 起始地址也是 0X87800000,说明整个 uboot 的起始地址就是 0X87800000
    STM32中断向量表也是可设置的,默认是0x80000000
    将 arch/arm/cpu/armv7/start.s 编译出来的代码放到中断向量表后面
    在 u-boot.lds 中有一些跟地址有关的“变量”需要我们注意一下
    在这里插入图片描述
    “变量”值可以在 u-boot.map 文件中查找,除了__image_copy_start
    以外,其他的变量值每次编译的时候可能会变化,如果修改了 uboot 代码、修改了 uboot 配置、选用不同的优化等级等等都会影响到这些值。所以,一切以实际值为准!
  • u-boot.map 是 uboot 的映射文件,可以从此文件看到某个文件或者函数链接到了哪个地址。STM32也有.map文件。一样的用法。
/*
 * Copyright (c) 2004-2008 Texas Instruments
 *
 * (C) Copyright 2002
 * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
 *
 * SPDX-License-Identifier:	GPL-2.0+
 */

#include <config.h>

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
  • OUTPUT_FORMAT(“elf32-littlearm”, “elf32-littlearm”, “elf32-littlearm”)
    这行定义了输出文件的格式。在这里,它指定了三种可能的格式,但通常它们都设置为相同的格式。在这种情况下,输出文件的格式为elf32-littlearm,这是一个32位的小端(little-endian)ARM ELF格式。
  • OUTPUT_ARCH(arm)
    这行指定了目标架构为ARM。
  • ENTRY(_start)
    这指定了程序的入口点(即程序开始执行的地方)为_start符号。
    从 u-boot.lds 中我们已经知道了入口点是 arch/arm/lib/vectors.S 文件中的_start,stm32类似是Reset_Handler的调用
    _start代码如下:`
48 _start:
49
50 #ifdef CONFIG_SYS_DV_NOR_BOOT_CFG
51 .word CONFIG_SYS_DV_NOR_BOOT_CFG
52 #endif
53
54 b reset
55 ldr pc, _undefined_instruction
56 ldr pc, _software_interrupt
57 ldr pc, _prefetch_abort
58 ldr pc, _data_abort
59 ldr pc, _not_used
60 ldr pc, _irq
61 ldr pc, _fiq`
  • 第 48 行_start 开始的是中断向量表,其中 54~61 行就是中断向量表 与STM32 startup_stm32xx.s里面一样。54 行跳转到 reset 函数里面,reset 函数在 arch/arm/cpu/armv7/start.S 里面,代码如下:
32 .globl reset
33 .globl save_boot_params_ret
34
35 reset:
36 /* Allow the board to save important registers */
37 b save_boot_params
  • 第 35 行就是 reset 函数。
  • 第 37 行从 reset 函数跳转到了 save_boot_params 函数,而 save_boot_params 函数同样定义
    在 start.S 里面,定义如下:
91 /******************************************************************
92 *
93 * void save_boot_params(u32 r0, u32 r1, u32 r2, u32 r3)
94 * __attribute__((weak));
95 *
96 * Stack pointer is not yet initialized at this moment
97 * Don't save anything to stack even if compiled with -O0
98 *
99 ******************************************************************/
100 ENTRY(save_boot_params)
101 b save_boot_params_ret @ back to my caller

save_boot_params 函数也是只有一句跳转语句,跳转到 save_boot_params_ret 函数,
save_boot_params_ret 函数代码如下:

38 save_boot_params_ret:
39 /*
40 * disable interrupts (FIQ and IRQ), also set the cpu to SVC32 
41 * mode, except if in HYP mode already
42 */
43 mrs r0, cpsr
44 and r1, r0, #0x1f @ mask mode bits
45 teq r1, #0x1a @ test for HYP mode
46 bicne r0, r0, #0x1f @ clear all mode bits
47 orrne r0, r0, #0x13 @ set SVC mode
48 orr r0, r0, #0xc0 @ disable FIQ and IRQ
49 msr cpsr,r0
  • 第 43 行,读取寄存器 cpsr 中的值,并保存到 r0 寄存器中。

  • 第 44 行,将寄存器 r0 中的值与 0X1F 进行与运算,结果保存到 r1 寄存器中,目的就是提取 cpsr 的 bit0~bit4 这 5 位,这 5 位为 M4 M3 M2 M1 M0,M[4:0]这五位用来设置处理器的工作模式,如下所示:
    7种工作模式
    在这里插入图片描述

  • 第 45 行,判断 r1 寄存器的值是否等于 0X1A(0b11010),也就是判断当前处理器模式是否处于 Hyp 模式。

  • 第 46 行,如果 r1 和 0X1A 不相等,也就是 CPU 不处于 Hyp 模式的话就将 r0 寄存器的bit0~5 进行清零,其实就是清除模式位

  • 第 47 行,如果处理器不处于 Hyp 模式的话就将 r0 的寄存器的值与 0x13 进行或运算,0x13=0b10011,也就是设置处理器进入 SVC 模式。

  • 第 48 行,r0 寄存器的值再与 0xC0 进行或运算,那么 r0 寄存器此时的值就是 0xD3,cpsr的 I 为和 F 位分别控制 IRQ 和 FIQ 这两个中断的开关,设置为 1 就关闭了 FIQ 和 IRQ!

  • 第 49 行,将 r0 寄存器写回到 cpsr 寄存器中。完成设置 CPU 处于 SVC32 模式,并且关闭FIQ 和 IRQ 这两个中断

后面看不下去了。跳过详细调用流程这段。总之就是按照ARMV7架构进行一些中断向量表之类的设置。和STM32 .s启动文件类似

  • 20
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值