四十二.移植bootm命令

0.一开始tftp能下载东西,但是很慢,做的调整有
(1)将下载地址改写成局部变量,并且每次都利用当前块编号进行重定位
(2)加上了原版u-boot里dm9000发送函数里发送前后都要清除发送标志
(3)取消了老师说的要对包进行判断,实际上不判断效果还要好一点,那一部分,要求只要在空读前后有20微妙的时间间隔就好了,经我实际测试,我的开发板确实只用空读一次就满足该条件。
(4)取消了中断处理函数里之前为了验证进的是什么中断的打印部分。时的不容易丢包,不然一直在中断,当下一个包来的时候还未跳出中断,会有丢包现象,最后导致传输失败。



1.在uboot中参考cmd_bootm.c,它主要是检查信息头。在

2.uImage和zImage的区别是uImage比后者多了一个头部信息,里面包含了OS类型,幻数,文件类型,压缩方式(从而进行解压缩),

3.找到内核的起始地址
要和tftp下载的目标地址一样。


4.设置启动参数

一开始都要先设置hdr的两个成员,在针对不同的参数类型(flag),去填写其他参数

struct tag_header {
	unsigned int size;
	unsigned int tag;
};
struct tag {
	struct tag_header hdr;
	union {
		struct tag_core		core;
		struct tag_mem32	mem;
		struct tag_cmdline	cmdline;
	} u;
};
4.1 核心参数
struct tag_core {
	unsigned int flags;		/* bit 0 = read-only */
	unsigned int pagesize;
	unsigned int rootdev;
};


void setup_start_tag()
{
	params = (struct tag*)ATAGS_START_ADDR;
	
	
	params->hdr.tag = ATAG_CORE;
	params->hdr.size = tag_size(tag_core);

	params->u.core.flags = 0;
	params->u.core.pagesize = 4096;
	params->u.core.rootdev = 0;
	
	params = tag_next(params);
}

4.2内存参数
struct tag_mem32 {
	unsigned int	size;
	unsigned int	start;	/* physical start address */
};

void setup_memory_tags()
{
	params->hdr.tag = ATAG_MEM;
	params->hdr.size = tag_size(tag_mem32);
	
	params->u.mem.start = SDRAM_START_ADDR;
	params->u.mem.size = SDRAM_SIZE;

	params = tag_next(params);
}

4.3命令行参数
struct tag_cmdline {
	char	cmdline[1];	/* this is the minimum size */
};
void setup_commandline_tag()
{

	params->hdr.tag = ATAG_CMDLINE;
	params->hdr.size = (sizeof (struct tag_header) + strlen(cmdline) + 1 + 3) >> 2;
	
	strcpy(params->u.cmdline.cmdline, cmdline);
	
	params = tag_next(params);
	
}


4.4结束标志

void setup_end_tag()
{
	params->hdr.tag = ATAG_NONE;
	params->hdr.size = 0;
}

5.将CPU机器码和启动参数地址传给内核,启动内核
kernel_entry(0,2520,ATAGS_START_ADDR);


这个函数原型和实现在linux内核,所以只要给这个函数指针指定启动参数起始地址,linux就会一句这些参数启动内核。
6.总的启动函数
void boot_linux()
{
	/*1.传递内核起始地址*/
	kernel_entry = (void (*)(int, int, uint))LINUX_START_ADDR;
	
	/*2.设置核心参数*/
	setup_start_tag();
	
	
	/*3.设置内存参数*/
	setup_memory_tags();
	
	/*4.设置命令行参数*/
	setup_commandline_tag();
	
	/*5.写入参数结束标志*/
	setup_end_tag();
	
	/*6.传入机器码启动内核*/
	
	kernel_entry(0,2520,ATAGS_START_ADDR);	//用的mini6410的ID====2250。mini2440的ID是1999。tiny6410原本是2251,但是我的zImage是mini6410的内核文件。
}

7.结合前面的tftp的实现,对放在windows上的内核文件进行下载



下载完成

输入数字2启动内核

内核启动完成



6410代码

atag.h
//#define unsigned int unsigned int;

struct tag_header {
	unsigned int size;
	unsigned int tag;
};

struct tag_core {
	unsigned int flags;		/* bit 0 = read-only */
	unsigned int pagesize;
	unsigned int rootdev;
};

struct tag_mem32 {
	unsigned int	size;
	unsigned int	start;	/* physical start address */
};

struct tag_cmdline {
	char	cmdline[1];	/* this is the minimum size */
};

struct tag {
	struct tag_header hdr;
	union {
		struct tag_core		core;
		struct tag_mem32	mem;
		struct tag_cmdline	cmdline;
	} u;
};


boot.c

#include "string.h"
#include "atag.h"
#include "common.h"

#define uint unsigned int
#define LINUX_START_ADDR 0x51000000
#define ATAGS_START_ADDR 0x50000100
#define SDRAM_START_ADDR 0x50000000
#define SDRAM_SIZE	 0x0FF00000

#define ATAG_NONE	0x00000000
#define ATAG_CORE	0x54410001
#define ATAG_MEM	0x54410002
#define ATAG_CMDLINE	0x54410009

#define tag_size(type)	((sizeof(struct tag_header) + sizeof(struct type)) >> 2)

#define tag_next(t)	((struct tag *)((unsigned int *)(t) + (t)->hdr.size))

const char* cmdline = "console=ttySAC0,115200 init=/init root=/dev/nfs rw nfsroot=192.168.1.112:/NFS/rootfs_qtopia_qt4 ip=192.168.1.30:192.168.1.112:192.168.1.1:255.255.255.0:XiaoJunjun:eth0:off";
//const char* cmdline = "console=ttySAC0,115200 init=/init";

void (*kernel_entry)(int, int, uint);

struct tag* params = NULL;

void setup_start_tag()
{
	params = (struct tag*)ATAGS_START_ADDR;
	
	
	params->hdr.tag = ATAG_CORE;
	params->hdr.size = tag_size(tag_core);

	params->u.core.flags = 0;
	params->u.core.pagesize = 4096;
	params->u.core.rootdev = 0;
	
	params = tag_next(params);
}

void setup_memory_tags()
{
	params->hdr.tag = ATAG_MEM;
	params->hdr.size = tag_size(tag_mem32);
	
	params->u.mem.start = SDRAM_START_ADDR;
	params->u.mem.size = SDRAM_SIZE;

	params = tag_next(params);
}

void setup_commandline_tag()
{

	params->hdr.tag = ATAG_CMDLINE;
	params->hdr.size = (sizeof (struct tag_header) + strlen(cmdline) + 1 + 3) >> 2;
	
	strcpy(params->u.cmdline.cmdline, cmdline);
	
	params = tag_next(params);
	
}

void setup_end_tag()
{
	params->hdr.tag = ATAG_NONE;
	params->hdr.size = 0;
}

void boot_linux()
{
	/*1.传递内核起始地址*/
	kernel_entry = (void (*)(int, int, uint))LINUX_START_ADDR;
	
	/*2.设置核心参数*/
	setup_start_tag();
	
	
	/*3.设置内存参数*/
	setup_memory_tags();
	
	/*4.设置命令行参数*/
	setup_commandline_tag();
	
	/*5.写入参数结束标志*/
	setup_end_tag();
	
	/*6.传入机器码启动内核*/
	
	kernel_entry(0,2520,ATAGS_START_ADDR);	//用的mini6410的ID====2250。mini2440的ID是1999。tiny6410原本是2251,但是我的zImage是mini6410的内核文件。
}

/****************************
@File:main.c
@
@Tiny6410裸机下学期代码
@网卡测试文件
@Author:小君君
@****************************/

#include "common.h"

int main(void)
{
	int num = 1000;
	
	
	
	led_init();//LED的GPIO初始化
	
	button_init();//按键初始化
	
	
	
	led_on();//点亮4颗LED
	
	uart_init();//串口初始化
	
	putchar('a');
	putchar('\r');
	putchar('\n');
	putchar('b');
	putchar('\r');
	putchar('\n');
	
	
	dma_init();//DMA初始化
	dma_start();//启动DMA发送数据到串口
	
	uart_init();//串口再次初始化,使得串口恢复中断或者轮询模式
	
	lcd_init();
	lcd_clear_screen(0xFFFFFF);
	
	
	
	dm9000_init();
	
	//dm9000_arp();
	
	while(1){
		
		printf("=================================================\n\r");
		printf("===================JUN-BOOT======================\n\r");
		printf("0.Send the ARP to get yhe host's MAC address\n\r");
		printf("1.Download the linux kernel from tftp\n\r");
		printf("2.Boot linux OS from SDRAM\n\r");
		printf("3.Junjun is a houmorous\n\r");
		printf("=================================================\n\r");
		printf("===================LCD_TEST======================\n\r");
		printf("4.清屏\n\r");
		printf("5.画横线\n\r");
		printf("6.画竖线\n\r");
		printf("7.画十字架\n\r");
		printf("8.画同心圆\n\r");
		printf("9.AD转换\n\r");
		printf("10.Send the ARP to get yhe host's MAC address\n\r");
		printf("11.Download the linux kernel from tftp\n\r");
		printf("12.Boot linux OS from SDRAM\n\r");
		printf("                                                   \n\r");
		printf("请输入0-12任意一个数字:\n\r");
		
		scanf("%d",&num);	
		
		switch(num){
			case 0:
				printf("请支持成都国嵌\n\r");
				break;
			case 1:
				printf("国嵌学院=====打造你的嵌入式人生\n\r");
				break;
			case 2:
				printf("学ARM,学Linux,学C++,学安卓,学嵌入式,就到成都国嵌学院\n\r");
				break;
			case 3:
				printf("只要你肯努力,你的明天就会等你!!\n\r");
				break;
			case 4:
				lcd_clear_screen(0x000000);
				break;
			case 5:
				lcd_clear_screen(0x000000);
				lcd_draw_hline(HEIGHT/2, 100, WIDTHEIGHT-100, 0xff0000);
				break;
			case 6:
				lcd_clear_screen(0x000000);
				lcd_draw_vline(WIDTHEIGHT/2, 50, HEIGHT-50, 0xff0000);
				break;
			case 7:
				lcd_clear_screen(0x000000);
				lcd_draw_cross(HEIGHT/2, WIDTHEIGHT/2, 20, 0x777777);
				break;
			case 8:
				lcd_clear_screen(0x000000);
				lcd_draw_circle();
				break;
			case 9:
				read_adc(0);
				break;
			case 10:
				arp_request();
				break;
			case 11:
				tftp_request("zImage");//一定要放对位置,而且文件名要一致
				break;
			case 12:
				boot_linux();
				break;
			default:
				printf("只要你肯努力,你的明天就会等你!!\n\r");
				break;
			
		}
	}
	return 0;	
}

你可能感兴趣的:(四十二.移植bootm命令)