全志sun8iw11p1 start.S

.globl	_TEXT_BASE   //声明连接入口
_TEXT_BASE:
	.word	CONFIG_SYS_TEXT_BASE

	.globl	reset     //上电后跳转到reset

reset:
	bl	save_boot_params
//BL 指令的格式为:
//BL{条件} 目标地址
//BL 是另一个跳转指令,但跳转之前,会在寄存器R14 中保存PC 的当前内容,因此,可以通过将R14 的内容重新加载到PC 中,来返回到跳转指令之后的那个指令处执行。该指令是实现子程序调用的一个基本但常用的手段
	/*
	 * disable interrupts (FIQ and IRQ), also set the cpu to SVC32 mode,
	 * except if in HYP mode already
	 */
	mrs	r0, cpsr   //将当前状态寄存器的值读到r0
	and	r1, r0, #0x1f		@ mask mode bits  //将r0的低五位状态赋值r1,也就是cpsr的低五位状态
	teq	r1, #0x1a		@ test for HYP mode  //比较CPSR的低五位状态是否等于0x1a,该状态说明对应HYP模式,一种非安全状态行运行的新模式。
	bicne	r0, r0, #0x1f		@ clear all mode bits //如果不等于那就清除低五位
	orrne	r0, r0, #0x13		@ set SVC mode  //同样设置低五位为0x13,也就是10011,对应的是ARM的SVC管理模式
	orr	r0, r0, #0xc0		@ disable FIQ and IRQ
	msr	cpsr,r0  //将通用寄存器r0的值保存到状态寄存器cpsr

ARM v6引入了security extension,把硬件资源划分成了两个部分secure world和normal world。当CPU运行在secure world的时候,它可以访问所以的硬件资源,但当CPU运行在normal world的时候,它只能访问normal world的资源。ARM v7引入了virtualization extension,在normal world里面加入了一个新的CPUmode:HYP mode。这样CPU 在normal world运行的时候就有三种模式:USR mode, SVC mode和HYP mode,分别对应PL0, PL1, PL2(PL:privilege level),number越大,权限越高。我对这里所说的权限的理解是:寄存器的访问和指令的执行。比如说一些特殊的寄存器(HVBAR)只能再HYP mode里面才能访问,一些特殊的指令(HVC)只能再SVC 或者 HYP mode执行。而CPU处于哪个模式是由CPSR这个寄存器决定的
————————————————

状态寄存器传送至通用寄存器类指令 功能:将状态寄存器的内容传送至通用寄存器。 格式: MRS{<条件码>}Rd,CPSR}SPSR

通用寄存器传送至状态寄存器传送指令 功能:将通用寄存器的内容传送至状态寄存器。 格式:
MSR{<条件码>CPSR_f|SPSR_f,<#ommed_8r>
MSR{<条件码>CPSR_|SPSR_,Rm

汇编弹簧床机制:先跳转到save_boot_params,bl跳转后会返回回来继续执行

ENTRY(save_boot_params)
	bx	lr			@ back to my caller
ENDPROC(save_boot_params)
	.weak	save_boot_params

这里bx lr就直接返回跳转来之前的地址,也就是什么都不做,下面的.weak关键字作用是如果其他地方定义了save_boot_params那就调用,如果没有定义,这就是个空函数。

#if !(defined(CONFIG_OMAP44XX) && defined(CONFIG_SPL_BUILD))
	/* Set V=0 in CP15 SCTRL register - for VBAR to point to vector */
	mrc	p15, 0, r0, c1, c0, 0	@ Read CP15 SCTRL Register
	bic	r0, #CR_V		@ V = 0
	mcr	p15, 0, r0, c1, c0, 0	@ Write CP15 SCTRL Register

	/* Set vector address in CP15 VBAR register */
	ldr	r0, =_start
	mcr	p15, 0, r0, c12, c0, 0	@Set VBAR
#endif

	/* the mask ROM code should have PLL and others stable */
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
	bl	cpu_init_cp15
	bl	cpu_init_crit
#endif

	bl	_main

这里我们没有定义CONFIG_OMAP44XX和CONFIG_SPL_BUILD,因此执行
mrc p15, 0, r0, c1, c0, 0,这是协处理器操作,只有mrc和mcr才能对arm的协处理器进行操作:

      MRC {条件}协处理器编码,协处理器操作码1,目的寄存器,源寄存器1,源寄存器2,{协处理器操作码2}
      MCR {条件}协处理器编码,协处理器操作码1,源寄存器,目的寄存器1,目的寄存器2,{协处理器操作码2}
这两个指令一般是成对使用,读出来在写进去,设置CP15协处理器的C1寄存器V位为0,查看寄存器手册:

设置地段一场中断向量0x0~0x1c。
然后将_start的地址给r0,再将该地址写到c12寄存器,也就是设置异常向量的基地址:
紧接着,这里没有定义skip_lowlevel_init,跳入cpu_init_cp15 ,顾名思义还是对cp15协处理器的设置。
————————————————

MOV(双操作数指令) 格式:MOV 目的操作数,源操作数
其中:MOV为操作码:目的操作数,可以是寄存器、存储器、累加器:源操作数,可|以是寄存器、存储器、累加器和立即数。
功能:将一个源操作数(字或字节)送到目的操作数中。


BIC―――――位清除指令 指令格式: BIC{cond}{S} Rd,Rn,operand2 BIC指令将Rn
的值与操作数operand2 的反码按位逻辑”与”,结果存放到目的寄存器Rd 中。指令示例:BIC R0,R0,#0x0F
;将R0最低4位清零,其余位不变


ORR 指令的格式为: ORR{条件}{S} 目的寄存器,操作数 1,操作数 2 ORR
指令用于在两个操作数上进行逻辑或运算,并把结果放置到目的寄存器中。操作数 1 应是一个寄存器,操作数 2
可以是一个寄存器,被移位的寄存器,或一个立即数。该指令常用于设置操作数 1 的某些位。 指令示例: ORR R0,R0,#3
; 该指令设置R0的0、1位,其余位保持不变。

ENTRY(cpu_init_cp15)
	/*
	 * Invalidate L1 I/D
	 * 使无效整个数据和指令TLB,然后使无效整个指令cache,清空整个跳转目标的cache,清空预取缓冲区,清空写缓冲区
	 */
	mov	r0, #0			@ set up for MCR  //首先对r0清零
	mcr	p15, 0, r0, c8, c7, 0	@ invalidate TLBs //使无效整个数据和指令TLB
	mcr	p15, 0, r0, c7, c5, 0	@ invalidate icache //使无效整个指令cache
	mcr	p15, 0, r0, c7, c5, 6	@ invalidate BP array //
	mcr     p15, 0, r0, c7, c10, 4	@ DSB
	mcr     p15, 0, r0, c7, c5, 4	@ ISB

	/*
	 * disable MMU stuff and caches
	 * 设置低端异常中断向量,禁止MMU,禁止地址对齐检查,禁止数据Cache,前面已经禁止了指令cache。紧接着使能地址对齐检查,使能跳转预测功能   
	 */
	mrc	p15, 0, r0, c1, c0, 0
	bic	r0, r0, #0x00002000	@ clear bits 13 (--V-)
	bic	r0, r0, #0x00000007	@ clear bits 2:0 (-CAM)
	orr	r0, r0, #0x00000002	@ set bit 1 (--A-) Align
	orr	r0, r0, #0x00000800	@ set bit 11 (Z---) BTB
#ifdef CONFIG_SYS_ICACHE_OFF
	bic	r0, r0, #0x00001000	@ clear bit 12 (I) I-cache
#else
	orr	r0, r0, #0x00001000	@ set bit 12 (I) I-cache  //这里没有定义ICACHE_OFF,因此这里使能指令Cache
#endif
	mcr	p15, 0, r0, c1, c0, 0

#ifdef CONFIG_ARM_A53
	/*
	 *clear AFE,TRE bit in sctrl
	 *non-secure: reset value is unknow
	 *secure    : default value is 0
	 *notice    : we must set the TRE bit to enable the memory
	 *            arttribute configuration from the section table.
	 */
	MRC     p15, 0, r0, c1, c0, 0   @Read SCTLR
	BIC     r0, r0, #(1<<28)        @clr TRE bit
	BIC     r0, r0, #(1<<29)        @clr AEF bit
	MCR     p15, 0, r0, c1, c0, 0   @Write SCTLR
#endif

#ifdef CONFIG_ARM_ERRATA_716044   //没有定义该号码的宏
	mrc	p15, 0, r0, c1, c0, 0	@ read system control register
	orr	r0, r0, #1 << 11	@ set bit #11
	mcr	p15, 0, r0, c1, c0, 0	@ write system control register
#endif
/*
* 这里是对CP15的C15寄存器进行了操作,这里叫做诊断寄存器,然后将4,6,15都置位
*/
#if (defined(CONFIG_ARM_ERRATA_742230) || defined(CONFIG_ARM_ERRATA_794072))
	mrc	p15, 0, r0, c15, c0, 1	@ read diagnostic register
	orr	r0, r0, #1 << 4		@ set bit #4
	mcr	p15, 0, r0, c15, c0, 1	@ write diagnostic register
#endif

#ifdef CONFIG_ARM_ERRATA_743622
	mrc	p15, 0, r0, c15, c0, 1	@ read diagnostic register
	orr	r0, r0, #1 << 6		@ set bit #6
	mcr	p15, 0, r0, c15, c0, 1	@ write diagnostic register
#endif

#ifdef CONFIG_ARM_ERRATA_751472
	mrc	p15, 0, r0, c15, c0, 1	@ read diagnostic register
	orr	r0, r0, #1 << 11	@ set bit #11
	mcr	p15, 0, r0, c15, c0, 1	@ write diagnostic register
#endif
#ifdef CONFIG_ARM_ERRATA_761320
	mrc	p15, 0, r0, c15, c0, 1	@ read diagnostic register
	orr	r0, r0, #1 << 21	@ set bit #21
	mcr	p15, 0, r0, c15, c0, 1	@ write diagnostic register
#endif

	mov	pc, lr			@ back to my caller
ENDPROC(cpu_init_cp15)

完了之后,跳回子函数,然后顺序执行到函数cpu_init_crit:

ENTRY(cpu_init_crit)
	/*
	 * Jump to board specific initialization...
	 * The Mask ROM will have already initialized
	 * basic memory. Go here to bump up clock rate and handle
	 * wake up conditions.
	 */
	b	lowlevel_init		@ go setup pll,mux,memory
ENDPROC(cpu_init_crit)

跳转到lowlevel_init去了,lowlevel_init的作用就是引导加载c函数做进一步的初始化
/home/milo/miloworkplace/Toyota/yb_rls/brandy/u-boot-2014.07/arch/arm/cpu/armv7/low_level_init.S

ARM是RISC结构,数据从内存到CPU之间的移动只能通过L/S指令来完成,也就是ldr/str指令。
比如想把数据从内存中某处读取到寄存器中,只能使用ldr 比如: ldr r0, 0x12345678
就是把0x12345678这个地址中的值存放到r0中。

ENTRY(lowlevel_init)
	/*
	 * Setup a temporary stack
	 */
	ldr	sp, =CONFIG_SYS_INIT_SP_ADDR
	bic	sp, sp, #7 /* 8-byte alignment for ABI compliance设置SP八个字节对齐 */
#ifdef CONFIG_SPL_BUILD
	ldr	r9, =gdata //定义了CONFIG_SPL_BUILD。将gdata赋值给r9
#else
	sub	sp, sp, #GD_SIZE
	bic	sp, sp, #7
	mov	r9, sp
#endif
	/*
	 * Save the old lr(passed in ip) and the current lr to stack
	 */
	push	{ip, lr}

	/*
	 * go setup pll, mux, memory
	 */
	bl	s_init  跳转到s_init函数
	pop	{ip, pc}
ENDPROC(lowlevel_init)

跳转到s_init函数
s_init在/home/milo/miloworkplace/Toyota/yb_rls/brandy/u-boot-2014.07/arch/arm/cpu/armv7/sunxi/的board.c中,s_init主要是对sun8iw11p1的PFDs进行了板级设置。

void s_init(void)
{
#if !defined CONFIG_SPL_BUILD && (defined CONFIG_SUN7I || defined CONFIG_SUN6I)
	/* Enable SMP mode for CPU0, by setting bit 6 of Auxiliary Ctl reg */
	asm volatile(
		"mrc p15, 0, r0, c1, c0, 1\n"
		"orr r0, r0, #1 << 6\n"
		"mcr p15, 0, r0, c1, c0, 1\n");
#endif

	clock_init();
	timer_init();
	gpio_init();

#ifdef CONFIG_SPL_BUILD
	gd = &gdata;
	preloader_console_init();

	sunxi_board_init();
#endif
}

调用结束s_init之后,程序跳转到到_main函数arch/arm/lib/crt0.S
重新对SP赋值, 确认sp是8字对齐
在栈顶保留一个global_data的大小, 这个global_data是uboot里面的一个全局数据, 很多地方都会用到. 俗称 gd_t
确认更新后的sp是8字对齐
r9指向global_data, 后面别的地方想用global_data时候, 可以直接从r9里面获取地址.
r0赋值0
bl board_init_f: 跳转到board_init_f. 在编译SPL时, 分析Makefile可以看出, 该函数的实现是在<arch/arm/lib/spl.c>.
————————————————

ENTRY(_main)

/*
 * Set up initial C runtime environment and call board_init_f(0).
 */

#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
	ldr	sp, =(CONFIG_SPL_STACK)
#else
	ldr	sp, =(CONFIG_SYS_INIT_SP_ADDR)
#endif
	bic	sp, sp, #7	/* 8-byte alignment for ABI compliance */
	sub	sp, sp, #GD_SIZE	/* allocate one GD above SP */
	bic	sp, sp, #7	/* 8-byte alignment for ABI compliance */
	mov	r9, sp		/* GD is above SP */
	mov	r0, #0
	bl	board_init_f

#if ! defined(CONFIG_SPL_BUILD)

/*
 * Set up intermediate environment (new sp and gd) and call
 * relocate_code(addr_moni). Trick here is that we'll return
 * 'here' but relocated.
 */
	ldr	sp, [r9, #GD_START_ADDR_SP]	/* sp = gd->start_addr_sp */
	bic	sp, sp, #7	/* 8-byte alignment for ABI compliance */
	ldr	r9, [r9, #GD_BD]		/* r9 = gd->bd */
	sub	r9, r9, #GD_SIZE		/* new GD is below bd */

	adr	lr, here
	ldr	r0, [r9, #GD_RELOC_OFF]		/* r0 = gd->reloc_off */
	add	lr, lr, r0
	ldr	r0, [r9, #GD_RELOCADDR]		/* r0 = gd->relocaddr */
	b	relocate_code
here:

/* Set up final (full) environment */

	bl	c_runtime_cpu_setup	/* we still call old routine here */

	ldr	r0, =__bss_start	/* this is auto-relocated! */
	ldr	r1, =__bss_end		/* this is auto-relocated! */

	mov	r2, #0x00000000		/* prepare zero to clear BSS */

clbss_l:cmp	r0, r1			/* while not at end of BSS */
	strlo	r2, [r0]		/* clear 32-bit BSS word */
	addlo	r0, r0, #4		/* move to next */
	blo	clbss_l

	bl coloured_LED_init
	bl red_led_on

	/* call board_init_r(gd_t *id, ulong dest_addr) */
	mov     r0, r9                  /* gd_t */
	ldr	r1, [r9, #GD_RELOCADDR]	/* dest_addr */
	/* call board_init_r */
	ldr	pc, =board_init_r	/* this is auto-relocated! */

	/* we should not return here. */

#endif

ENDPROC(_main)

/home/milo/miloworkplace/Toyota/yb_rls/brandy/u-boot-2014.07/arch/arm/lib/spl.c

void __weak board_init_f(ulong dummy)
{
	/* Clear the BSS. */
	memset(__bss_start, 0, __bss_end - __bss_start);

	/* Set global data pointer. */
	gd = &gdata;

	board_init_r(NULL, 0);
}

对BSS段进行清零操作
gd = &gdata;
gd的定义在DECLARE_GLOBAL_DATA_PTR <arch/arm/include/asm/global_data.h>
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm (“r9”)
r9之前初始化了
gdata的定义在本文件中: gd_t gdata attribute ((section(".data")));
它是一个 gd_t 也就是global_data类型的变量
__attribute__表示这个变量会被放到".data"这个输入段中. 连接器会把输入段按照链接脚本(u-boot-spl.lds)里面指定的规则存放到输出段
————————————————
跳转到board_init_r,在common/spl/spl.c
对memory,timer初始化,选择在什么介质启动,最后判断image的类型,是u-boot还是linux

void board_init_r(gd_t *dummy1, ulong dummy2)
{
	u32 boot_device;
	debug(">>spl:board_init_r()\n");

#ifdef CONFIG_SYS_SPL_MALLOC_START
	mem_malloc_init(CONFIG_SYS_SPL_MALLOC_START,
			CONFIG_SYS_SPL_MALLOC_SIZE);
#endif

#ifndef CONFIG_PPC
	/*
	 * timer_init() does not exist on PPC systems. The timer is initialized
	 * and enabled (decrementer) in interrupt_init() here.
	 */
	timer_init();
#endif

#ifdef CONFIG_SPL_BOARD_INIT
	spl_board_init();
#endif

	boot_device = spl_boot_device();
	debug("boot device - %d\n", boot_device);
	switch (boot_device) {
#ifdef CONFIG_SPL_RAM_DEVICE
	case BOOT_DEVICE_RAM:
		spl_ram_load_image();
		break;
#endif
#ifdef CONFIG_SPL_MMC_SUPPORT
	case BOOT_DEVICE_MMC1:
	case BOOT_DEVICE_MMC2:
	case BOOT_DEVICE_MMC2_2:
		spl_mmc_load_image();
		break;
#endif
#ifdef CONFIG_SPL_NAND_SUPPORT
	case BOOT_DEVICE_NAND:
		spl_nand_load_image();
		break;
#endif
#ifdef CONFIG_SPL_ONENAND_SUPPORT
	case BOOT_DEVICE_ONENAND:
		spl_onenand_load_image();
		break;
#endif
#ifdef CONFIG_SPL_NOR_SUPPORT
	case BOOT_DEVICE_NOR:
		spl_nor_load_image();
		break;
#endif
#ifdef CONFIG_SPL_YMODEM_SUPPORT
	case BOOT_DEVICE_UART:
		spl_ymodem_load_image();
		break;
#endif
#ifdef CONFIG_SPL_SPI_SUPPORT
	case BOOT_DEVICE_SPI:
		spl_spi_load_image();
		break;
#endif
#ifdef CONFIG_SPL_ETH_SUPPORT
	case BOOT_DEVICE_CPGMAC:
#ifdef CONFIG_SPL_ETH_DEVICE
		spl_net_load_image(CONFIG_SPL_ETH_DEVICE);
#else
		spl_net_load_image(NULL);
#endif
		break;
#endif
#ifdef CONFIG_SPL_USBETH_SUPPORT
	case BOOT_DEVICE_USBETH:
		spl_net_load_image("usb_ether");
		break;
#endif
#ifdef CONFIG_SPL_USB_SUPPORT
	case BOOT_DEVICE_USB:
		spl_usb_load_image();
		break;
#endif
#ifdef CONFIG_SPL_SATA_SUPPORT
	case BOOT_DEVICE_SATA:
		spl_sata_load_image();
		break;
#endif
	default:
		debug("SPL: Un-supported Boot Device\n");
		hang();
	}

	switch (spl_image.os) {
	case IH_OS_U_BOOT:
		debug("Jumping to U-Boot\n");
		break;
#ifdef CONFIG_SPL_OS_BOOT
	case IH_OS_LINUX:
		debug("Jumping to Linux\n");
		spl_board_prepare_for_linux();
		jump_to_image_linux((void *)CONFIG_SYS_SPL_ARGS_ADDR);
#endif
	default:
		debug("Unsupported OS image.. Jumping nevertheless..\n");
	}
	jump_to_image_no_args(&spl_image);
}
### 回答1: sun8iw11p1_linuxa40i 是一款基于ARM架构的嵌入式操作系统。要下载 sun8iw11p1_linuxa40i,可以按照以下步骤进行: 1. 首先,在互联网上搜索 sun8iw11p1_linuxa40i 的下载链接。可以尝试在开源软件仓库、嵌入式开发者社区或者相应的官方网站上查找。 2. 找到下载链接后,点击链接进入下载页面。 3. 在下载页面,可能会提供多个版本的sun8iw11p1_linuxa40i供选择。根据自己的需求,选择适合的版本进行下载。通常可以根据操作系统、架构、编译器版本等来选择。 4. 点击下载按钮,开始下载 sun8iw11p1_linuxa40i。 5. 下载完成后,根据软件包的文件格式进行安装或解压。可以参考相关的安装文档或说明来完成安装过程。 6. 安装完成后,你就可以使用 sun8iw11p1_linuxa40i 进行开发或者其他相关操作了。 总的来说,要下载 sun8iw11p1_linuxa40i,需要找到官方或者可信赖的来源,并按照相应的步骤进行下载和安装。 ### 回答2: sun8iw11p1_linuxa40i是一种基于Linux操作系统的开源软件,用于下载和安装在Allwinner sun8iw11p1芯片平台上。它是该平台的特定版本,旨在提供更好的性能和兼容性。 下载sun8iw11p1_linuxa40i需要在计算机上执行相关步骤。首先,确保计算机上已安装了合适的开发环境,并且具备编译和构建软件的能力。接下来,需要在官方网站或相关论坛上找到sun8iw11p1_linuxa40i的下载链接或源码文件。 下载sun8iw11p1_linuxa40i时,应注意下载源的可靠性和完整性,最好从官方网站或官方认可的渠道获取软件。下载完成后,可以将源码文件解压到计算机上的目标文件夹中。 在解压完成后,打开命令行终端,并导航到源码文件所在的目录。在这里,可以执行相应的构建命令,将源码编译为可执行文件或软件包。根据具体情况,可能需要指定编译选项和配置文件。 完成编译后,可以根据需要将软件安装到目标设备上,可能需要通过网络连接或其他途径将软件传输到设备上。在设备上安装过程中,可能需要根据设备的配置进行相关设置和配置。 总之,要下载sun8iw11p1_linuxa40i,需要通过合适的渠道获取源码文件,并在计算机上进行编译和安装。这样,用户就可以在Allwinner sun8iw11p1芯片平台上使用和运行该软件。 ### 回答3: sun8iw11p1_linuxa40i是Allwinner科技推出的一款适用于系统开发的Linux内核。下载sun8iw11p1_linuxa40i主要有两个步骤。 首先,我们需要在Allwinner科技的官方网站上找到sun8iw11p1_linuxa40i的下载页面。一般来说,这个页面会提供Linux内核的下载链接、相关的文档和工具等。我们可以通过搜索引擎或者直接访问Allwinner科技的官方网站来找到这个页面。 其次,我们需要根据我们自己的需求选择适合的版本进行下载。一般来说,Allwinner科技会提供不同的版本,包括最新的稳定版本和一些测试版本。我们可以根据自己的需求选择合适的版本进行下载。 下载sun8iw11p1_linuxa40i的时候,需要注意以下几点: 首先,保证下载的是合法、官方的版本。在互联网上存在着各种非官方的版本和修改版,我们应该避免下载和使用这些非官方版本,以免造成安全风险或者不兼容的问题。 其次,我们应该根据系统和硬件的需求选择合适的版本。不同版本的Linux内核可能在功能和兼容性方面有所差异,我们需要根据自己的需求选择合适的版本。 最后,在下载完成后,我们应该仔细阅读Allwinner科技提供的文档和指南,以便正确地安装和配置sun8iw11p1_linuxa40i。 总之,下载sun8iw11p1_linuxa40i需要访问Allwinner科技官方网站,并根据自己的需求选择合适的版本进行下载,并在下载完成后进行正确的安装和配置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值