MIPS Uboot 入门及移植(1)

今年就在网上淘了一块板,但是一直没有时间玩,况且自己在Linux这方面还是个门外汉,前一段时间也在换工作,学习新的电路画图软件,所以一直没空。

今天抽空玩起来。

首先下载源码:https://github.com/widora/u-boot-mt7688

里面需要编译工具,这个需要在MTK的SDK里面找,需要的可以发邮件给我,或者在百度云上面搜索MTK的SDK。

在SourceInsight中同步所有的文件。

第一步:

首先看Makefile。前面就是一些定义和条件编译,真正有用的是从这句话开始:

#########################################################################
# U-Boot objects....order is important (i.e. start must be first)

ifeq ($(MT7621_MP), y)
OBJS  = cpu/$(CPU)/start_1004k.o
else
OBJS  = cpu/$(CPU)/start.o
endif

在make menuconfig改写.config文件里面的内容时,这些参数是怎么传到Makefile里面的呢?这个后面再讲。

PS:如果你实在找不到,可以直接在源码里面Make一遍,编译结束后,往上翻,找到链接的命令,譬如我的:

/opt/buildroot-gcc342/bin/mipsel-linux-ld -Bstatic -T /home/linux/openwrt/widora/u-boot-mt7688/board/rt2880/u-boot.lds -Ttext 0xBC000000  $UNDEF_SYM cpu/ralink_soc/start.o


你只需要注意的是在/cpu/ralink_soc文件下找到start.c或者start.s,因为只有这两个文件能生成start.o.

第二步:

有了Makefile,要知道链接脚本在哪。

关于链接脚本,这里有一个例子,来自Redhat官网上的例子:https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/4/html/Using_ld_the_GNU_Linker/simple-example.html

Simple Linker Script Example
Many linker scripts are fairly simple.

The simplest possible linker script has just one command: SECTIONS. You use the SECTIONS command to describe the memory layout of the output file.

The SECTIONS command is a powerful command. Here we will describe a simple use of it. Let's assume your program consists only of code, initialized data, and uninitialized data. These will be in the .text, .data, and .bss sections, respectively. Let's assume further that these are the only sections which appear in your input files.

For this example, let's say that the code should be loaded at address 0x10000, and that the data should start at address 0x8000000. Here is a linker script which will do that:

SECTIONS
{
  . = 0x10000;
  .text : { *(.text) }
  . = 0x8000000;
  .data : { *(.data) }
  .bss : { *(.bss) }
}
You write the SECTIONS command as the keyword SECTIONS, followed by a series of symbol assignments and output section descriptions enclosed in curly braces.

The first line inside the SECTIONS command of the above example sets the value of the special symbol ., which is the location counter. If you do not specify the address of an output section in some other way (other ways are described later), the address is set from the current value of the location counter. The location counter is then incremented by the size of the output section. At the start of the SECTIONS command, the location counter has the value 0.

The second line defines an output section, .text. The colon is required syntax which may be ignored for now. Within the curly braces after the output section name, you list the names of the input sections which should be placed into this output section. The * is a wildcard which matches any file name. The expression *(.text) means all .text input sections in all input files.

Since the location counter is 0x10000 when the output section .text is defined, the linker will set the address of the .text section in the output file to be 0x10000.

The remaining lines define the .data and .bss sections in the output file. The linker will place the .data output section at address 0x8000000. After the linker places the .data output section, the value of the location counter will be 0x8000000 plus the size of the .data output section. The effect is that the linker will place the .bss output section immediately after the .data output section in memory

The linker will ensure that each output section has the required alignment, by increasing the location counter if necessary. In this example, the specified addresses for the .text and .data sections will probably satisfy any alignment constraints, but the linker may have to create a small gap between the .data and .bss sections.

That's it! That's a simple and complete linker script.

在这里,我找到了u-boot.lds,(在u-boot-mt7688\board\rt2880目录下)其实在链接器脚本里面也可以看出第一个启动文件,也就是程序的入口是什么:

放源码:

OUTPUT_FORMAT("elf32-tradlittlemips", "elf32-tradbigmips", "elf32-tradlittlemips")
OUTPUT_ARCH(mips)
ENTRY(_start)

SECTIONS
{
	. = 0x00000000;

	. = ALIGN(4);
	.text       :
	{
	  *(.text)
	}

	. = ALIGN(4);
	.rodata  : { *(.rodata) }

	. = ALIGN(4);

	.data  : { *(.data) }

	. = ALIGN(4);
	.sdata  : { *(.sdata) }

	_gp = ALIGN(16);

	.got  : {
	__got_start = .;
		*(.got)
	__got_end = .;
	}

	.sdata  : { *(.sdata) }

	__u_boot_cmd_start = .;
	.u_boot_cmd : { *(.u_boot_cmd) }
	__u_boot_cmd_end = .;

	uboot_end_data = .;
	num_got_entries = (__got_end - __got_start) >> 2;

	. = ALIGN(4);
	.sbss  : { *(.sbss) }
	.bss  : { *(.bss) }

	uboot_end = .;
}

不懂链接器脚本的,可以看这个:http://blog.csdn.net/firefly_cjd/article/details/51986746

可以看出程序的entry是_start标号的地方,那么回到start.s文件来,看看标号为_start的程序:

.text
_start:
	RVECENT(reset,0)	/* U-boot entry point */
	RVECENT(reset,1)	/* software reboot */
#if defined(CONFIG_INCA_IP)
	.word INFINEON_EBU_BOOTCFG /* EBU init code, fetched during booting */
	.word 0x00000000           /* phase of the flash                    */
#elif defined(CONFIG_PURPLE)
	.word INFINEON_EBU_BOOTCFG /* EBU init code, fetched during booting */
	.word INFINEON_EBU_BOOTCFG /* EBU init code, fetched during booting */
#else
	RVECENT(romReserved,2)
#endif
	RVECENT(romReserved,3)
	......(后面一样,我就不写了)
而根据前面的代码,可以看到RVECENT的定义:

#define RVECENT(f,n) \
   b f; nop
#define XVECENT(f,bev) \
   b f     ;           \
   li k0,bev
只是一个跳转指令,那么去reset标号去看看CPU要做什么:

reset:
#if defined (RT2883_FPGA_BOARD) || defined (RT2883_ASIC_BOARD) || \
    defined (RT3052_FPGA_BOARD) || defined (RT3052_ASIC_BOARD) || \
    defined (RT3352_FPGA_BOARD) || defined (RT3352_ASIC_BOARD) || \
    defined (RT5350_FPGA_BOARD) || defined (RT5350_ASIC_BOARD) || \
    defined (RT3883_FPGA_BOARD) || defined (RT3883_ASIC_BOARD) || \
    defined (RT6855_FPGA_BOARD) || defined (RT6855_ASIC_BOARD) || \
    defined (RT6855A_FPGA_BOARD) || defined (RT6855A_ASIC_BOARD) || \
    defined (MT7620_FPGA_BOARD) || defined (MT7620_ASIC_BOARD) || \
    defined (MT7628_FPGA_BOARD) || defined (MT7628_ASIC_BOARD)
	# Initialize the register file
	# should not be required with good software practices
	or	$1,$0, $0
	or	$2,$0, $0
	or	$3,$0, $0
	or	$4,$0, $0
	or	$5,$0, $0
	or	$6,$0, $0
	or	$7,$0, $0
	or	$8,$0, $0
	or	$9,$0, $0
	or	$10,$0, $0
	or	$11,$0, $0
	or	$12,$0, $0
	or	$13,$0, $0
	or	$14,$0, $0
	or	$15,$0, $0
	or	$16,$0, $0
	or	$17,$0, $0
	or	$18,$0, $0
	or	$19,$0, $0
	or	$20,$0, $0
	or	$21,$0, $0
	or	$22,$0, $0
	or	$23,$0, $0
	or	$24,$0, $0
	or	$25,$0, $0
	or	$26,$0, $0
	or	$27,$0, $0
	or	$28,$0, $0
	or	$29,$0, $0
	or	$30,$0, $0
	or	$31,$0, $0

也就是将所有寄存器清零。没什么好解释的。

接下来很长一段代码,是MIPS汇编写的,估计很难懂,我贴个代码:

# Initialize Misc. Cop0 state	

	# Read status register
	mfc0	$10, $12
	# Set up Status register:
	# Disable Coprocessor Usable bits
	# Turn off Reduce Power bit
	# Turn off reverse endian
	# Turn off BEV (use normal exception vectors)
	# Clear TS, SR, NMI bits
	# Clear Interrupt masks
	# Clear User Mode
	# Clear ERL
	# Set EXL
	# Clear Interrupt Enable
	# modify by Bruce
	#li	$11, 0x0000ff02
	li	$11, 0x00000004
	mtc0	$11, $12

	# Disable watch exceptions
	mtc0	$0, $18

	# Clear Watch Status bits
	li	$11, 0x3
	mtc0	$11, $19

	# Clear WP bit to avoid watch exception upon user code entry
	# Clear IV bit - Interrupts go to general exception vector
	# Clear software interrupts
	mtc0	$0, $13

	# Set KSeg0 to cacheable
	# Config.K0
	mfc0	$10, $16
	li	$11, 0x7
	not	$11
	and	$10, $11
	or	$10, 0x3
	mtc0	$10, $16

	# Clear Count register
	mtc0	$0, $9

	# Set compare to -1 to delay 1st count=compare
	# Also, clears timer interrupt
	li	$10, -1
	mtc0	$10, $11

	# Cache initialization routine
	# Long and needed on HW 
	# Can be skipped if using magic simulation cache flush

	# Determine how big the I$ is



你可能感兴趣的:(MIPS Uboot 入门及移植(1))