1、编写Makefile
链接时使用-T参数指明链接器脚本
CC = arm-linux-gnueabihf-gcc
LD = arm-linux-gnueabihf-ld
OBJCOPY = arm-linux-gnueabihf-objcopy
all : start.o
$(LD) -Tgboot.lds -o gboot.elf $^
$(OBJCOPY) -O binary gboot.elf gboot.bin
%.o : %.S
$(CC) -g -c $^
%.o : %.c
$(CC) -g -c $^
clean:
rm -rf gboot.elf gboot.bin *.o
2、编写链接器脚本gboot.lds
指定输出格式,使用的架构,定义代码段、数据段、bss段
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start) /*指明运行的第一个文件中的_start*/
SECTIONS
{
. = 0x00000000;
. = ALIGN(4);
.text :
{
start.o(.text*) /*指明运行的第一个文件是start.o*/
*(.text*)
}
. = ALIGN(4);
.data :
{
*(.data*)
}
. = ALIGN(4);
bss_start = .;
.bss :
{
*(.bss*)
}
bss_end = .;
}
3、编写start.S点亮LED
led使用原理图中的STATUS-LED
对应的GPIO为PA15
查看GPIO控制寄存器和数据寄存器地址
PA15控制寄存器,最高位配置001时为输出模式
PA15数据寄存器
编写start.S点亮LED
.global _start
_start :
/*循环闪烁*/
main_loop :
bl led_on
bl delay
bl led_off
bl delay
b main_loop
#define PACFG1 0x01C20804
#define PADAT 0x01C20810
led_on :
ldr r0, = 0x17777777 /* 这里ldr 为伪指令 */
ldr r1, = PACFG1
str r0, [r1] /* 寄存器间接寻址 将r0的值给r1所指地址的内存中,配置GPIO PA15为输出模式 */
ldr r0, = (1<<15) /* PA15, 在数据寄存器的第15位输出高电平 */
ldr r1, = PADAT
str r0, [r1] /* 点亮 */
mov pc, lr
led_off :
ldr r0, = 0x17777777 /* 这里ldr 为伪指令 */
ldr r1, = PACFG1
str r0, [r1] /* 寄存器间接寻址 将r0的值给r1所指地址的内存中,配置GPIO PA15为输出模式 */
ldr r0, = (0<<15) /* PA15, 在数据寄存器的第15位输出低电平 */
ldr r1, = PADAT
str r0, [r1] /* 灭灯 */
mov pc, lr
delay:
mov r2, #0x40000
mov r3, #0
delay_loop:
sub r2, r2, #1 /* r2=r2-1 */
cmp r2, r3 /* cmp 比较r2 r3 如果相等 Z 为1 */
bne delay_loop /* bne 为当Z为1时执行跳转 bne 为 b+后缀 */
mov pc, lr /* 函数调用返回 mov 为 寄存器间寻址 */
执行make编译,编译完成生成gboot.bin文件,直接烧写到SD卡,从SD卡启动没有点亮LED
4、需要添加校验
校验代码mksunxiboot.c
/*
* (C) Copyright 2007-2011
* Allwinner Technology Co., Ltd.
* Tom Cubie
*
* a simple tool to generate bootable image for sunxi platform.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include
#include
#include
#include
#include
#include
#include
#include
typedef unsigned char u8;
typedef unsigned int u32;
/* boot head definition from sun4i boot code */
typedef struct boot_file_head
{
u32 jump_instruction; // one intruction jumping to real code
u8 magic[8]; // ="eGON.BT0" or "eGON.BT1", not C-style string.
u32 check_sum; // generated by PC
u32 length; // generated by PC
u32 pub_head_size; // the size of boot_file_head_t
u8 pub_head_vsn[4]; // the version of boot_file_head_t
u8 file_head_vsn[4]; // the version of boot0_file_head_t or boot1_file_head_t
u8 Boot_vsn[4]; // Boot version
u8 eGON_vsn[4]; // eGON version
u8 platform[8]; // platform information
}boot_file_head_t;
#define BOOT0_MAGIC "eGON.BT0"
#define STAMP_VALUE 0x5F0A6C39
/* check sum functon from sun4i boot code */
int gen_check_sum( void *boot_buf )
{
boot_file_head_t *head_p;
u32 length;
u32 *buf;
u32 loop;
u32 i;
u32 sum;
head_p = (boot_file_head_t *)boot_buf;
length = head_p->length;
if( ( length & 0x3 ) != 0 ) // must 4-byte-aligned
return -1;
buf = (u32 *)boot_buf;
head_p->check_sum = STAMP_VALUE; // fill stamp
loop = length >> 2;
/* calculate the sum */
for( i = 0, sum = 0; i < loop; i++ )
sum += buf[i];
/* write back check sum */
head_p->check_sum = sum;
return 0;
}
#define ALIGN(x,a) __ALIGN_MASK((x),(typeof(x))(a)-1)
#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask))
#define SUN4I_SRAM_SIZE (24 * 1024)
#define SRAM_LOAD_MAX_SIZE (SUN4I_SRAM_SIZE - sizeof(boot_file_head_t))
#define BLOCK_SIZE 512
struct boot_img {
boot_file_head_t header;
char code[SRAM_LOAD_MAX_SIZE];
char pad[BLOCK_SIZE];
};
int main(int argc, char * argv[])
{
int fd_in, fd_out;
struct boot_img img;
unsigned file_size, load_size;
int count;
if(argc < 2) {
printf("\tThis program makes an input bin file to sun4i bootable image.\n"
"\tUsage: %s input_file out_putfile\n", argv[0]);
return EXIT_FAILURE;
}
fd_in = open(argv[1], O_RDONLY);
if(fd_in < 0) {
perror("Open input file:");
return EXIT_FAILURE;
}
fd_out = open(argv[2], O_WRONLY|O_CREAT, 0666);
if(fd_out < 0) {
perror("Open output file:");
return EXIT_FAILURE;
}
memset((void *)img.pad, 0, BLOCK_SIZE);
/* get input file size */
file_size = lseek(fd_in, 0, SEEK_END);
printf("File size: 0x%x \n", file_size);
if(file_size > SRAM_LOAD_MAX_SIZE) {
load_size = SRAM_LOAD_MAX_SIZE;
} else {
load_size = ALIGN(file_size, sizeof(int));
}
printf("Load size: 0x%x \n", load_size);
/* read file to buffer to calculate checksum */
lseek(fd_in, 0, SEEK_SET);
count = read(fd_in, img.code, load_size);
printf("Read 0x%x bytes\n", count);
/* fill the header */
img.header.jump_instruction = /* b instruction */
0xEA000000 | /* jump to the first instruction after the header */
(
(sizeof(boot_file_head_t) / sizeof(int) - 2)
& 0x00FFFFFF
);
memcpy(img.header.magic, BOOT0_MAGIC, 8); /* no '0' termination */
img.header.length = ALIGN(load_size + sizeof(boot_file_head_t), BLOCK_SIZE);
gen_check_sum((void *)&img);
count = write(fd_out, (void *)&img, img.header.length);
printf("Write 0x%x bytes\n", count);
close(fd_in);
close(fd_out);
return EXIT_SUCCESS;
}
编译mksunxiboot.c文件,注意这里不是交叉编译
gcc mksunxiboot.c -o mksunxiboot
添加校验
./mksunxiboot gboot.bin gboot-sdcard.bin
烧写到sd卡启动
sudo dd if=gboot-sdcard.bin of=/dev/sdb bs=1k seek=8
全部代码可以在以下链接下载:
https://download.csdn.net/download/wujiewei2342/11005419
5、总结
为学习uboot铺垫
1、链接器脚本是在Makefile中指定的,uboot也是
2、这里start.S没有关闭看门狗,因为orangepi one看门狗是默认关闭的
3、点亮led方便移植uboot时进行调试