S5P6818学习-------1 启动模式

根据芯片手册,S5P6818的启动模式有很多种:

S5P6818学习-------1 启动模式_第1张图片

因为我的板子是使用SD/eMMC boot的,所以对此模式深入分析, internal ROM Boot模式也是大同小异的。

S5P6818学习-------1 启动模式_第2张图片

 

(1). 由芯片手册可知SD卡的启动过程:板子上电后, 是从SD卡的第二个扇区开始自动复制56kb的代码数据到芯片的内部的SRAM,然后从0xFFFF0000出开始运行。从图中可以看到芯片在复制SD卡中的代码时,自动得忽略了512字节的数据,这是因为这512字节的数据是SD卡的MBR主引导记录,也是SD卡的第一个扇区。

(2).芯片把SD卡的56kb数据复制过来,然后在0xFFFF0000处开始执行,(如果复制过来的是uboot的部分代码,那么执行的操作一般有: 1.做一些芯片的初始化 和芯片外设必要的初始化(如SDRAM); 2.把SD卡上的代码全部复制到内存SDRAM中,然后跳转到SDRAM中继续执行。)但是在此主要分析 芯片启动过程的最基本最主要的原来,uboot的启动分析将在后续详细介绍。

注意:

S5P6818学习-------1 启动模式_第3张图片

在复制512bytes后,芯片会对复制的代码进行数字签名的检查,具体的做法就是检查这512bytes中的最后16个字节是否为0x4849534E。若是,则为正确代码,跳转到内部RAM即地址0xFFFF0000处运行;否则,选择下一个外部存储器进行判断测试。我使用UltraEdit打开可以正常工作的uboot二进制文件,可以发现代码里面确实是这样的:

S5P6818学习-------1 启动模式_第4张图片

知道这个原理以后,我们就可以在这芯片内的56kb的SRAM做任何想做的事情了。下面开始写一个汇编裸机的点亮led灯的程序。

 点亮led灯程序的思路为:

(1)根据开发板的电路图和芯片手册,使用汇编语言设计点亮led灯的程序

(2)编译链接成leds.bin文件

(3)在虚拟机Ubuntu中制作添加boot header的工具,然后使用工具为leds.bin添加boot header,生成芯片可以识别的bootleds.bin文件

(4)制作SD启动卡

下面为具体的操作过程:

1) 我使用粤嵌的开发板,根据原理图和芯片手册,点亮D7灯。

 代码文件:leds.S, main.c, Makefile, leds.lds

leds.S:

/*leds.S*/

//GPIOE13 ---- D7
#define	GPIOEOUT		0xC001E000
#define	GPIOEOUTENB		0xC001E004
#define	GPIOEALTFN0		0xC001E020
#define	GPIOEALTFN1		0xC001E024

#define	CONFIG_SP_BASE 	0xFFFFE000 //栈深  最多不超过56kb

.text
.global _start
_start:
	/* disable watchdog */
	ldr	r0, =0xC0019000
	mov	r1, #0
	str	r1, [r0]  			//加一个[]表示一个内存地址

	/* 配置GPIOE13为gpio模式 此处也可使用c语言实现*/
	mov r1, #3
	mov r0, r1, lsl#26
	mvn r1, r0
	ldr	r0, =GPIOEALTFN0   //把GPIOEALTFN0地址保存到r0
	ldr	r2,	[r0]		   //读取GPIOEALTFN0地址中的值
	and r2, r2, r1		   //r2 = r2&r1
	str r2,	[r0]

	/* 配置GPIOE13为输出模式 此处也可使用c语言实现*/
	mov r1, #1
	mov r0, r1, lsl#13
	ldr	r1,	=GPIOEOUTENB
	ldr r2,	[r1]
	orr r2,	r0,	r2
	str r2,	[r1]
	/*设置栈*/
	ldr	sp, =CONFIG_SP_BASE
	bl      main			//调用c函数
halt_loop:
            b       halt_loop

main.c:

/*main.c*/

//GPIOE13 ---- D7
#define	GPIOEOUT	(*(volatile unsigned int *)0xC001E000)
#define	GPIOEOUTENB	(*(volatile unsigned int *)0xC001E004)
#define	GPIOEALTFN0	(*(volatile unsigned int *)0xC001E020)
#define	GPIOEALTFN1	(*(volatile unsigned int *)0xC001E024)


#define	DELAY_TIME 	0X400000

void delay(int val)
{
	volatile int i=val;
	while(i--);
}

void main(void)
{
	while(1)
	{
		GPIOEOUT &= ~(1<<13);//GPIOE13 output 0
		delay(DELAY_TIME);
		
		GPIOEOUT |= (1<<13);//GPIOE13 output 1
		delay(DELAY_TIME);		
	}
}


Makefile:

leds.bin: main.o  leds.o
	arm-none-linux-gnueabi-ld -Tleds.lds -o leds.elf $^
	arm-none-linux-gnueabi-objcopy -O binary leds.elf leds.bin
	arm-none-linux-gnueabi-objdump -D leds.elf > leds.dis	
%.o : %.S
	arm-none-linux-gnueabi-gcc -o $@ $< -c -nostdlib

%.o : %.c
	arm-none-linux-gnueabi-gcc -o $@ $< -c -nostdlib -O3

clean:
	rm *.o *.elf *.bin *.dis -f

leds.lds:

SECTIONS {
	. = 0x00;
  	.text          :   { *(.text) }
	.rodata ALIGN(4) : {*(.rodata)} 
  	.data ALIGN(4) : { *(.data) }
  	.bss ALIGN(4)  : { *(.bss)  *(COMMON) }
}

2) 生成bin文件

make clean

make

3) 添加boot header

查看资料,使用原来的工具生成的 启动程序的结构为

S5P6818学习-------1 启动模式_第5张图片

图中的nsih.txt代表使用工具mk6818解析nsih.txt 文件得到的有效二进制数据; 2ndboot我查不到它的生成方式, 应该是官方资料直接提供的;而且nsih.txt和2ndboot这个文件已经对芯片做了一些初始化工作,比如:初始化芯片的内存控制器, 初始化外部SDRAM,初始化时钟等等, 以至于我在uboot中的自搬运代码之前看不到有对外部SDRAM的初始化操作。

mk6818的源码:

/*mk6818.c*/

#include 
#include 
#include 
#include 

#define BLKSIZE						(512)

#define SECBOOT_NSIH_POSITION		(1)
#define SECBOOT_POSITION			(2)
#define BOOTLOADER_NSIH_POSITION	(64)
#define BOOTLOADER_POSITION			(65)

struct nand_bootinfo_t
{
	uint8_t	addrstep;
	uint8_t	tcos;
	uint8_t	tacc;
	uint8_t	toch;
	uint32_t pagesize;
	uint32_t crc32;
};

struct spi_bootinfo_t
{
	uint8_t	addrstep;
	uint8_t	reserved0[3];
	uint32_t reserved1;
	uint32_t crc32;
};

struct sdmmc_bootinfo_t
{
	uint8_t	portnumber;
	uint8_t	reserved0[3];
	uint32_t reserved1;
	uint32_t crc32;
};

struct sdfs_bootinfo_t
{
	char bootfile[12];
};

union device_bootinfo_t
{
	struct nand_bootinfo_t nandbi;
	struct spi_bootinfo_t spibi;
	struct sdmmc_bootinfo_t sdmmcbi;
	struct sdfs_bootinfo_t sdfsbi;
};

struct ddr_initinfo_t
{
	uint8_t	chipnum;
	uint8_t	chiprow;
	uint8_t	buswidth;
	uint8_t	reserved0;

	uint16_t chipmask;
	uint16_t chipbase;

	uint8_t	cwl;
	uint8_t	wl;
	uint8_t	rl;
	uint8_t	ddrrl;

	uint32_t phycon4;
	uint32_t phycon6;

	uint32_t timingaref;
	uint32_t timingrow;
	uint32_t timingdata;
	uint32_t timingpower;
};

struct boot_info_t
{
	uint32_t vector[8];					// 0x000 ~ 0x01C
	uint32_t vector_rel[8];				// 0x020 ~ 0x03C

	uint32_t deviceaddr;				// 0x040
	uint32_t loadsize;					// 0x044
	uint32_t loadaddr;					// 0x048
	uint32_t launchaddr;				// 0x04C

	union device_bootinfo_t dbi;		// 0x050 ~ 0x058

	uint32_t pll[4];					// 0x05C ~ 0x068
	uint32_t pllspread[2];				// 0x06C ~ 0x070
	uint32_t dvo[5];					// 0x074 ~ 0x084

	struct ddr_initinfo_t dii;			// 0x088 ~ 0x0A8

	uint32_t axibottomslot[32];			// 0x0AC ~ 0x128
	uint32_t axidisplayslot[32];		// 0x12C ~ 0x1A8

	uint32_t stub[(0x1F8 - 0x1A8) / 4];	// 0x1AC ~ 0x1F8
	uint32_t signature;					// 0x1FC "NSIH"
};

static int process_nsih(const char * filename, unsigned char * outdata)
{
	FILE * fp;
	char ch;
	int writesize, skipline, line, bytesize, i;
	unsigned int writeval;

	fp = fopen(filename, "r+b");
	if(!fp)
	{
		printf("Failed to open %s file.\n", filename);
		return 0;
	}

	bytesize = 0;
	writeval = 0;
	writesize = 0;
	skipline = 0;
	line = 0;

	while(0 == feof(fp))
	{
		ch = fgetc (fp);

		if (skipline == 0)
		{
			if (ch >= '0' && ch <= '9')
			{
				writeval = writeval * 16 + ch - '0';
				writesize += 4;
			}
			else if (ch >= 'a' && ch <= 'f')
			{
				writeval = writeval * 16 + ch - 'a' + 10;
				writesize += 4;
			}
			else if (ch >= 'A' && ch <= 'F')
			{
				writeval = writeval * 16 + ch - 'A' + 10;
				writesize += 4;
			}
			else
			{
				if(writesize == 8 || writesize == 16 || writesize == 32)
				{
					for(i=0 ; i>= 8;
					}
				}
				else
				{
					if (writesize != 0)
						printf("Error at %d line.\n", line + 1);
				}

				writesize = 0;
				skipline = 1;
			}
		}

		if(ch == '\n')
		{
			line++;
			skipline = 0;
			writeval = 0;
		}
	}

	printf("NSIH : %d line processed.\n", line + 1);
	printf("NSIH : %d bytes generated.\n", bytesize);

	fclose(fp);
	return bytesize;
}

static char * to_readable_msg(char * buf, int len)
{
    static char msg[4096];
	int i, n;

	for(i = 0; i < len; i++)
	{
		n = i % 5;
		if(n == 0)
			buf[i] ^= 0x24;
		else if (n == 1)
			buf[i] ^= 0x36;
		else if (n == 2)
			buf[i] ^= 0xAC;
		else if (n == 3)
			buf[i] ^= 0xB2;
		else if (n == 4)
			buf[i] ^= 0x58;
	}

    memset(msg, 0, sizeof(msg));
    memcpy(msg, buf, len);
    return msg;
}

/*
 * "Copyright(c) 2011-2014 http://www.9tripod.com\n"
 */
char msg_copyright[] = { 0x67, 0x59, 0xdc, 0xcb, 0x2a, 0x4d, 0x51, 0xc4, 0xc6,
		0x70, 0x47, 0x1f, 0x8c, 0x80, 0x68, 0x15, 0x07, 0x81, 0x80, 0x68, 0x15,
		0x02, 0x8c, 0xda, 0x2c, 0x50, 0x46, 0x96, 0x9d, 0x77, 0x53, 0x41, 0xdb,
		0x9c, 0x61, 0x50, 0x44, 0xc5, 0xc2, 0x37, 0x40, 0x18, 0xcf, 0xdd, 0x35,
		0x2e, };

/*
 * "Forum: http://xboot.org\n"
 */
char msg_forum[] = { 0x62, 0x59, 0xde, 0xc7, 0x35, 0x1e, 0x16, 0xc4, 0xc6, 0x2c,
		0x54, 0x0c, 0x83, 0x9d, 0x20, 0x46, 0x59, 0xc3, 0xc6, 0x76, 0x4b, 0x44,
		0xcb, 0xb8, };

/*
 * "Tel: 0755-33133436\n"
 */
char msg_tel[] = { 0x70, 0x53, 0xc0, 0x88, 0x78, 0x14, 0x01, 0x99, 0x87, 0x75,
		0x17, 0x05, 0x9d, 0x81, 0x6b, 0x10, 0x05, 0x9a, 0xb8, };

int main(int argc, char *argv[])
{
	FILE * fp;
	struct boot_info_t * bi;
	unsigned char nsih[512];
	char * buffer;
	int length, reallen;
	int nbytes, filelen;

	//printf("%s", to_readable_msg(msg_copyright, sizeof(msg_copyright)));
    //printf("%s", to_readable_msg(msg_forum, sizeof(msg_forum)));
    //printf("%s", to_readable_msg(msg_tel, sizeof(msg_tel)));

	if(argc != 5)
	{
		printf("Usage: mk6818   <2ndboot> \n");
		return -1;
	}

	if(process_nsih(argv[2], &nsih[0]) != 512)
		return -1;

	length = 32 * 1024 * 1024;
	buffer = malloc(length);
	memset(buffer, 0, length);

	/* 2ndboot nsih */
	memcpy(&buffer[(SECBOOT_NSIH_POSITION - 1) * BLKSIZE], &nsih[0], 512);

	/* 2ndboot */
	fp = fopen(argv[3], "r+b");
	if(fp == NULL)
	{
		printf("Open file 2ndboot error\n");
		free(buffer);
		return -1;
	}

	fseek(fp, 0L, SEEK_END);
	filelen = ftell(fp);
	fseek(fp, 0L, SEEK_SET);

	nbytes = fread(&buffer[(SECBOOT_POSITION - 1) * BLKSIZE], 1, filelen, fp);
	if(nbytes != filelen)
	{
		printf("Read file 2ndboot error\n");
		free(buffer);
		fclose(fp);
		return -1;
	}
	fclose(fp);

	/* fix 2ndboot nsih */
	bi = (struct boot_info_t *)(&buffer[(SECBOOT_NSIH_POSITION - 1) * BLKSIZE]);
	/* ... */

	/* bootloader nsih */
	memcpy(&buffer[(BOOTLOADER_NSIH_POSITION - 1) * BLKSIZE], &nsih[0], 512);

	/* bootloader */
	fp = fopen(argv[4], "r+b");
	if(fp == NULL)
	{
		printf("Open file bootloader error\n");
		free(buffer);
		return -1;
	}

	fseek(fp, 0L, SEEK_END);
	filelen = ftell(fp);
	reallen = (BOOTLOADER_POSITION - 1) * BLKSIZE + filelen;
	fseek(fp, 0L, SEEK_SET);

	nbytes = fread(&buffer[(BOOTLOADER_POSITION - 1) * BLKSIZE], 1, filelen, fp);
	if(nbytes != filelen)
	{
		printf("Read file bootloader error\n");
		free(buffer);
		fclose(fp);
		return -1;
	}
	fclose(fp);

	/* fix bootloader nsih */
	bi = (struct boot_info_t *)(&buffer[(BOOTLOADER_NSIH_POSITION - 1) * BLKSIZE]);
	bi->deviceaddr = 0x00008000;
	bi->loadsize = ((filelen + 512 + 512) >> 9) << 9;
	bi->loadaddr = 0x43C00000;
	bi->launchaddr = 0x43C00000;

	/* destination */
	fp = fopen(argv[1], "w+b");
	if(fp == NULL)
	{
		printf("Destination file open error\n");
		free(buffer);
		return -1;
	}

	nbytes = fwrite(buffer, 1, reallen, fp);
	if(nbytes != reallen)
	{
		printf("Destination file write error\n");
		free(buffer);
		fclose(fp);
		return -1;
	}

	free(buffer);
	fclose(fp);

	printf("Generate destination file: %s\n", argv[1]);

	return 0;
}

执行./mk6818  bootleds.bin  nsih.txt  2ndboot  leds.bin, 就可以生成包含boot header的bin文件bootleds.bin

4) 制作SD启动卡

在ubuntu下制作 

(1)cat /proc/partitions    查看系统原有的设备节点

major minor  #blocks  name

   8        0   52428800 sda
   8        1   51427328 sda1
   8        2          1 sda2
   8        5     998400 sda5
  11        0    1048575 sr0

 (2)插入SD卡到Ubuntu系统,再次执行 cat /proc/partitions

major minor  #blocks  name

   8        0   52428800 sda
   8        1   51427328 sda1
   8        2          1 sda2
   8        5     998400 sda5
  11        0    1048575 sr0
   8       16   30289920 sdb
   8       17   38758400 sdb1

 经过对比可见,SD卡的设备名称为sdb

(3)修改一下SD卡的分区

sudo fdisk /dev/sdb
返回:

Command (m for help):
输入 d 并回车, 删除所有分区。 返回:
Selected partition 1
Command (m for help):
输入 w 并回车, 保存所有已经修改的分区信息。 返回:
The partition table has been altered!
Calling ioctl() to re-read partition table.
Syncing disks
拨掉 SD 卡, 再插入 PC 机上, 输入如下命令查看现有的设备节点:
cat /proc/partitions
返回:

major minor  #blocks  name

   8        0   52428800 sda
   8        1   51427328 sda1
   8        2          1 sda2
   8        5     998400 sda5
  11        0    1048575 sr0
   8       16   30289920 sdb

至此, SD 卡原分区/dev/sdb1 被删除。

插上SD卡, 并执行:sudo ./GEC6818-sdmmc.sh /dev/sdb  bootleds.bin 

这样SD卡启动卡已经制作完成了。直接插到开发板的SD卡槽,上电执行,就会看到D7在闪烁了。

全部相关文件链接:链接 https://pan.baidu.com/s/15NNpWuebL-4TNe_0mSIR0Q  提取码:dqq2

你可能感兴趣的:(ARM芯片)