u-boot网络固件还原功能

一、任务简介:在UBOOT中使用UDP协议与服务器实现通讯,并获取服务器的特定配置文件并执行其中的命令,从而应用于生产辅助、进行维护、升级等等。


二、流程:


三、注意几点:

1、INI文件格式(b开头的命令不是致命命令,执行不成功会跳到下一条命令),下面是一个例子:

::this is a inifile
s00=setenv serverip 192.168.1.68
s01=setenv ipaddr 192.168.1.10
s02=sa
s10=sf probe 0
s11=sf read 0x84800000 0xc0000 0x20000
s12=sf read 0x84900000 0xe0000 0x20000
s13=logo
s20=sf probe 0
s21=sf read 0x82000000 0x180000 0x280000
s22=sf read 0x81000000 0x400000 0x800000
b23=bootm 0x82000000 0x81000000
s30=bzr 200 1
s31=bzr 55 2
t32=tftp 0x83000000 FWHI2104HF_20151104_DVR_R5104-AHD_2_2_7_2_413221.flash
s40=sf probe 0
s41=sf erase 0x80000 0xF80000
s42=sf write 0x83080000 0x80000 0xF80000
s50=bzr 55 2
s51=bzr 500 1
s52=bzr 500 3
s53=reset


2、配置文件大小不要超过设定的字节数

3、为了不使每次开机慢,udp的处理尽量要快点,udp主要要处理两点:

1)网络不在(没插网线):重连4次,间隔大约1秒,每次分别响应蜂鸣器1、2、3、4次

2)服务器不在(或者传输过程中服务器不在了):重发5次之后重启net(蜂鸣器响一声,重启3次),历时大约10秒


4、由于命令集中可能包含tftp命令,而tftp命令的使用工程中可能发生很多意外,所以要对tftp命令进一步的完善处理,以下是对一些情况的处理方式:
1)网络不在(没插网线):重连4次,间隔大约1秒,每次分别响应蜂鸣器1、2、3、4次
2)服务器不在(或者传输过程中服务器不在了):1秒重发一次,10次之后重启net,重启3次。重启时蜂 鸣器响一声。
3)在传输过程中网络中断:1秒会重发一次,重发10次之后会重启网络,重启之后再重发10次,重启3次 。重启时蜂鸣器响一声。
4)其他情况:
找不到文件或发完ACK包服务器没回应:默认方式处理


四、实现步骤:

 1、添加一条查询服务器的命令和发送UDP包的命令

udp包中的数据是不同型号板子的信息,做法是在输出文件(u-boot.bin)中定义一个16字节的message段,用来存放板子信息,不能定义过大的空间以免覆盖其他重要信息。

修改/u-boot-2010.06/arch/arm/cpu/hi3520d/u-boot.lds文件:

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
	. = 0x00000000;

	. = ALIGN(4);
	.text	:
	{
		arch/arm/cpu/hi3520d/start.o	(.text)
		*(.text)
	}

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

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

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

	. = ALIGN(4);
	__setting_message_start = 0x90;                    //在偏移量为0x90(144字节)位置开始是message段
	.message : 
	{  
		arch/arm/cpu/hi3520d/hi3520d_message.o	(.message)      //此段的入口是hi3520d_message.S

	} 
	__setting_message_end = 0xA0;                     //在偏移量为0xA0(160字节)位置是message段的结束,一共16字节
	
	
	__u_boot_cmd_start = .;
	.u_boot_cmd : { *(.u_boot_cmd) }
	__u_boot_cmd_end = .;

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

}
hi3520d_message.S:

.section .message,#alloc

.globl	_setting_message_start	
_setting_message_start:
.word __setting_message_start

.globl    _setting_message_end
_setting_message_end:
.word __setting_message_end


然后在需要访问的地方声明即可:

<span style="white-space:pre">	</span>extern ulong _setting_message_start;
	extern ulong _setting_message_end;
	printf("_setting_env_start=%08lX\n", _setting_env_start);
	printf("_setting_env_end=%08lX\n", _setting_env_end);
	ulong len = _setting_env_end - _setting_env_start;

 

验证是否已经定义到此段的方法是修改此段的内容然后再打印此段的内容看是否一致:

可以通过windwHEX软件或打开u-boot.bin二进制文件修改此段的数据,下面是后者的代码:

#include <stdio.h>
#include <errno.h>

int main(int argv, char *argc[])
{
	FILE *fp;
	char *str = "abcdefghijklmnop";
	fp = fopen("/nfs/opt/U-BOOT/u-boot/u-boot-2010.06/u-boot.bin","rb+");    //以可读写的方式打开一个二进制文件

	if( fp == NULL){
		printf("open failure!\n");
		fclose(fp);
	}
	printf("open succeed\n");
	fseek(fp , 144, SEEK_SET);                       //将光标移到第144字节处即0x90处

	if(fwrite(str, sizeof(char), 16, fp) != 16){     //写16字节,成功返回16
		printf("write failure\n");
		fclose(fp);
	}
	printf("write succeed!\n");
	fclose(fp);

	return 0;
}

uboot启动时cpu会把flash里面的uboot拿到ddr相对应的地址(TEXT_BASE)开始执行,这个TEXT_BASE在u-boot/u-boot-2010.06/board/hi3520d/config.mk中定义,不同型号可能不一样,hi3520d定义的TEXT_BASE=0x80800000。

所以在uboot跑的时候可以在对应的地址(TEXT_BASE+段的地址偏移量),就是说可以在0x80800090处获取message段的数据:

char *addr;
char *file_address;
file_address = (char *)simple_strtoul("0x80800090", NULL, 16);
addr = file_address;
memgetinfo(mes, MAX_DATA, &addr, &file_size);           //此函数是从特定地址读取特定大小数据
printf("info = %s\n", mes);


 2、完善tftp命令,主要是超时处理

 3、创建一些有关板子信息的环境变量

 4、区别FLASH的分区:

一般flash大小是16M:

Hi3521 DDR-SDRAM Momery Mapping
BLOCK 1 (DDRA 0x80000000~0x8FFFFFFF, 256MB Total, 32Bit Width)
0x8000 0000 - - | - - +0x0480 0000  (72MB) Linux OS
0x8480 0000 - - | - - +0x1B80 0000 (440MB) MMZ0
Hi3521 SPI Flash Mapping For JUAN (0x5800 0000~0x58FF FFFF,16MB Total)
Base   Address: 0x5800 0000
OffSet Address:
0x0000 0000 - - | - - +0x008 0000 (512KB)  U-boot Master
0x0008 0000 - - | - - +0x004 0000 (256KB)  U-boot Master Env
0x000C 0000 - - | - - +0x004 0000 (256KB)  U-boot Logo
0x0010 0000 - - | - - +0x008 0000 (512KB)  App Config
0x0018 0000 - - | - - +0x028 0000 (2.5MB)  Kernel Master
0x0040 0000 - - | - - +0x0C0 0000 (12MB)   Rootfs Master

0~0x80000是UBOOT(512k),0x80000~0xc0000是U-boot Environment(256k),0xc0000~0x100000是U-boot Logo(256k),0x100000~0x180000是App Config(512k),0x180000~0x400000是 Kernel Binary Image(2.5M),0x400000~0x1000000是Rootfs Binary Image(12M)。

但是hi3520dv300、hi3521a、hi3531a有所改变:

Hi3521A DDR-SDRAM Momery Mapping
BLOCK 1 (DDRA 0x80000000~0xFFFFFFFF, 2GB Total, 32Bit Width)
0x8000 0000 - - | - - +0x0480 0000  (72MB) Linux OS
0x8480 0000 - - | - - +0x1B80 0000 (440MB) MMZ0
0xC000 0000 - - | - - +0x2000 0000 (512MB) MMZ1

Hi3520Dv300 & Hi3521A & Hi3531A  SPI Flash Mapping For JUAN
OffSet Address:
0x0000 0000 - - | - - +0x005 0000 (320KB)  U-boot Binary Image(Last 64KB Size for S/N)
0x0005 0000 - - | - - +0x001 0000 (64KB)   U-boot Environment
0x0006 0000 - - | - - +0x002 0000 (128KB)  U-boot Logo
0x0008 0000 - - | - - +0x006 0000 (384KB)   App Config(192KB AppEnv /64KB User Management/128KB ODM)
0x000E 0000 - - | - - +0x028 0000 (2.5MB)        Kernel Binary Image
0x0036 0000 - - | - - +0x0CA 0000 (12MB+640KB)   Rootfs Binary Image(Last 4MB Size for Resource)

5、 在PC端写一个UDP服务器

/ udp.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include<stdio.h>
#include<string.h>
#include<Winsock2.h>

#pragma comment(lib, "ws2_32.lib") 

typedef struct { 
		char*       flag;
		char*       client_ip;
		int         client_port;
		char*		board;		// model	
		int		    flash;		//  flash size
		char*       cpu;
} Data_t;

char *find_char_or_comment(const char *s, char c)
{
	int was_whitespace = 0;

	while (*s && *s != c && !(was_whitespace && *s == ';')) {
		was_whitespace = isspace(*s);
		s++;
	}
	return (char *)s;
}
/* Strip whitespace chars off end of given string, in place. Return s. */
static char *rstrip(char *s)
{
	char *p = s + strlen(s);

	while (p > s && isspace(*--p))
		*p = '\0';
	return s;
}

/* Return pointer to first non-whitespace char in given string. */
static char *lskip(const char *s)
{
	while (*s && isspace(*s))
		s++;
	return (char *)s;
}

int main(int argc, char* argv[])
{
	Data_t data;
    WSADATA wsaData;
    WORD sockVersion = MAKEWORD(2,2);
    if(WSAStartup(sockVersion, &wsaData) != 0)
    {
        return 0;
    }

    SOCKET serSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 
    if(serSocket == INVALID_SOCKET)
    {
        printf("socket error !");
        return 0;
    }

    sockaddr_in serAddr;
    serAddr.sin_family = AF_INET;
    serAddr.sin_port = htons(75);
    serAddr.sin_addr.S_un.S_addr = INADDR_ANY;
    if(bind(serSocket, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR)
    {
        printf("bind error !");
        closesocket(serSocket);
        return 0;
    }
    
    sockaddr_in remoteAddr;
    int nAddrLen = sizeof(remoteAddr); 
	printf("Listening ....\n");
    while (true)
    {
        char recvData[500];
		char sendData[1000];
		char *buf[50];
		int allByte=0;
		int line=0;
		char *start;
		char *end;
		int i, count;

        int ret = recvfrom(serSocket, recvData,500, 0, (sockaddr *)&remoteAddr, &nAddrLen);
        if (ret > 0)
        {
            recvData[ret] = 0x00;
            printf("接受到一个连接:%s \r\n", inet_ntoa(remoteAddr.sin_addr));
            //printf("%s\n",recvData); 
			start = lskip(rstrip(recvData));

			for(i=0; i<50; i++){
				end = find_char_or_comment(start, '/');
				if ( *end == '/' && *(++end)) {
					*(--end) = '\0';
					buf[i] = rstrip(start);
					start = lskip(end + 1);
				}
				else{
					buf[i] = rstrip(start);
					break;
				}
			}

			printf(" %s\n %s\n %s\n %s\n %s\n %s\n %s\n %s\n",
				buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);

			end = find_char_or_comment(buf[0], '=');
			buf[0] = lskip(end + 1);
			end = find_char_or_comment(buf[1], '=');
			buf[1] = lskip(end + 1);

			if (!strcmp(buf[0], "ini")){
				FILE *fp;
				if(!strcmp(buf[1], "hi3520d")){
					fp = fopen("E:\\uboot_env_3520D_256m-hf.ini","rb");
				}
				else if(!strcmp(buf[1], "hi3521a")){
					fp = fopen("E:\\uboot_env_3521A_256m-hf.ini","rb");
				}
				if(!fp) {
					printf("open error!");
					return 1;
				}
				else
					printf("文件已经打开,等待传输...\n");
				
				while(!feof(fp))
				{	
					memset(sendData, 0, 1000);
					int numreads=fread(sendData, 1, 1000, fp);
					int sByte = sendto(serSocket, sendData, numreads, 0, (sockaddr*)&remoteAddr, sizeof(remoteAddr));
					allByte+=sByte;
					line++;
					if(SOCKET_ERROR==sByte)
					{
						printf("sendto()Failed:%d\n",WSAGetLastError());
						closesocket(serSocket);
						WSACleanup();
						return -1;
					}		
				}
				printf("传输完毕,总共字节=%d,次数=%d\n",allByte,line);
			}
			else if(buf[0] == "xml"){			
			}
			else if(buf[0] == "json"){			
			}
			
        }

       // char * sendData = "一个来自服务端的UDP数据包\n";
        //sendto(serSocket, sendData, strlen(sendData), 0, (sockaddr *)&remoteAddr, nAddrLen);    

    }
    closesocket(serSocket); 
    WSACleanup();
    return 0;
}


五、代码实现

1、在cmd_net.c 中添加udp命令和query命令:

int do_udp (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
	return netboot_UDP_TCP (UDP, cmdtp, argc, argv);
}

U_BOOT_CMD(
	udp,	6,	1,	do_udp,
	"send or receive message to/from server using UDP protocol",
	"[udp] [string] or [udp] <eth> <IP> [string]"
);

static int netboot_UDP_TCP (proto_t proto, cmd_tbl_t *cmdtp, int argc, char *argv[])
{
	
	char *s;
	int   size;

	switch (argc) {
	case 1:
		pkt_data = NULL;
		break;
	case 2:	
		pkt_data = argv[1]; 
		break;
	default: 
		cmd_usage(cmdtp);
		show_boot_progress (-80);
		return 1;
	}
	show_boot_progress (80);
	if ((size = NetLoop(proto)) < 0) {
		show_boot_progress (-81);
		return 1;
	}
	show_boot_progress (81);
	/* NetLoop ok, update environment */
	netboot_update_env();

	/* done if no file was loaded (no errors though) */
	if (size == 0) {
		show_boot_progress (-82);
		return 0;
	}
	
	return 0;
}
#define MAX_DATA 1000

typedef struct { 
		char		filetype[25];	
		char  		cpu_model[25];
		char 		flash_size[20];
		char 		flash_type[10];
		char     	dram_size[25];
		char	    serial_number[25];
		char		ouripaddr[25];
		char      	ourport[10];
} Data_t;

int do_query (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
	struct mtd_info_ex *spiinfo;
	static unsigned int ddr_size;
	Data_t info;
	char buf[MAX_DATA];
	int i;
	char *s;
	
	switch (argc) {
	case 1:
		strcpy(info.filetype, "ini");
		break;
	case 2:
		strcpy(info.filetype, argv[1]);
		break;
	default: 
		cmd_usage(cmdtp);	
		return 1;	
	}

	strcpy(info.cpu_model, CONFIG_PRODUCTNAME);
	
	spiinfo = get_spiflash_info();
	memset(info.flash_size, 0, 20);
	sprintf(info.flash_size, "%sB", ultohstr(spiinfo->chipsize));
	
	if(strcmp(info.flash_size, getenv("flashsize")) != 0){
		setenv("flashsize",info.flash_size);
	}
	switch(spiinfo->type){
		case MTD_NORFLASH:
			strcpy(info.flash_type, "norflash");
			break;
		case MTD_NANDFLASH:
			strcpy(info.flash_type, "nandflash");
			break;
		case MTD_DATAFLASH:
			strcpy(info.flash_type, "dataflash"); 
			break;
		default:
			strcpy(info.flash_type, "norflash"); 
			break;
	}
	if(strcmp(info.flash_type, getenv("flashtype")) != 0){
		setenv("flashtype",info.flash_type);
	}
	
	strcpy(info.dram_size, "0");
	strcpy(info.serial_number, "0");
	strcpy(info.ouripaddr, getenv("ipaddr")? getenv("ipaddr") : "192.168.1.114");
	strcpy(info.ourport, getenv("ourport")? getenv("ourport") : 1024);

	sprintf(buf,"udp filetype=%s/cpu_model=%s/flash_type=%s/flash_size=%s/dram_size=%s/serial_number=%s/ouripaddr=%s/ourport=%s\n",
		info.filetype, info.cpu_model,  info.flash_type, info.flash_size, 
		info.dram_size, info.serial_number, info.ouripaddr, info.ourport);
	
	if(run_command(buf, 0) == -1){	
		if ( ctrlc() ) {
			return 0;
		}
		printf("error, to upgrade the abnormal\n");
	}
	return 0;
}

/***************************************************/

U_BOOT_CMD(
	query,	3,	1,	do_query,
	"Whether there is server alive and get inifile form server",
	"query [filetype]"
	
);


2、udp接收到的包交给net/udp.c处理:

#include <common.h>
#include <command.h>
#include <net.h>
#include <environment.h>
#include <linux/ctype.h>
#include <linux/string.h>
#include <netdev.h>
#include "tftp.h"
#include "bootp.h"
#include "udp.h"

#define TIMEOUT	 	20000UL		/* Seconds to timeout for a lost pkt	*/
#ifndef	CONFIG_NET_RETRY_COUNT
# define TIMEOUT_COUNT	10		/* # of timeouts before giving up  */
#else
# define TIMEOUT_COUNT  (CONFIG_NET_RETRY_COUNT * 2)
#endif

static ulong UdpTimeoutMSecs = TIMEOUT;
static int UdpTimeoutCountMax = TIMEOUT_COUNT;

#define MAX_LINE 200
#define MAX_SECTION 100
#define MAX_NAME 100

static IPaddr_t UdpServerIP;
static int	UdpServerPort;		/* The UDP port at their end		*/
static int	UdpOurPort;		/* The UDP port at our end		*/
static int	UdpTimeoutCount;		

static void UdpSend (void);
static void UdpTimeout (void);

/**********************************************************************/

static void
UdpSend (void)
{
	volatile uchar *	pkt;
	int			len = 0;
	
	/*
	 *	We will always be sending some sort of packet, so
	 *	cobble together the packet headers now.
	 */
	pkt = NetTxPacket + NetEthHdrSize() + IP_HDR_SIZE;
	len = strlen(pkt_data);
	memcpy(pkt, pkt_data, len);
	NetSendUDPPacket(NetServerEther, UdpServerIP, UdpServerPort, UdpOurPort, len);
}


static int inifile_handler(void *user, char *section, char *name, char *value)
{
	
	char *requested_section = (char *)user;
	int i;

	 if ( *name == 's' || *name == 'b' || *name == 't') {
	 	if ( *name == 't' ){
			if(run_command(value, 0) == -1){
				return 0;
			}
			return 1;
		}
		for(i=0; i<10; i++){
			if(run_command(value, 0) == -1){	
				if ( *name == 'b' ) {
					printf("bootm kernel and rootfs failure!\n");
					return 1;
				}
				printf("error, try again After 1 seconds\n");
				udelay(1000000);
				if ((i==9) || ctrlc()) {
					puts ("\nAbort\n");
					return 0;
				}
				continue;
			}
			break;
		}
		
	}
	else{
		setenv(name, value);
	}

	/* success */
	return 1;
}

static void
UdpHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
{
	ushort proto;
	char line[MAX_LINE];
	char section[MAX_SECTION] = "";
	char prev_name[MAX_NAME] = "";
	char *start;
	char *end;
	char *name;
	char *value;
	int i, linelen;
	int newline = 1;
	int lineno = 0;
	int error = 0;
	int flag = 1;
	char *udpkt;
	char *udppkt;
	
	udpkt=(char *)malloc(1000*sizeof(char));
	udppkt = strcpy(udpkt,(char *)pkt);
	printf("receive udp packet\n");

	while(flag){
		end = memchr(udppkt, '\n', (size_t)len);
		if( *end != '\n')
			end = memchr(udppkt, '\r', (size_t)len);
		if (end == NULL) {
			if (len == 0)
				return;
			end = udppkt + len;
			newline = 0;
		}
		linelen = min((end - udppkt) + newline, MAX_LINE);
		memcpy(line, udppkt, linelen);
		if (linelen < MAX_LINE)
			line[linelen] = '\0';

		/* prepare the mem vars for the next call */
		len -= (end - udppkt) + newline;
		udppkt += (end - udppkt) + newline;
		
		lineno++;
		start = lskip(rstrip(line));	
loop:	
	    if (*start && *start != ':' && *start != '[' && *start != '#') {
		/* Not a comment, must be a name[=:]value pair */

			end = find_char_or_comment(start, '=');
			if (*end != '=')
				end = find_char_or_comment(start, ':');
			if (*end == '=' || *end == ':') {
				*end = '\0';
				name = rstrip(start);
				value = lskip(end + 1);
				end = find_char_or_comment(value, ';');
				if(*end == ';'){								//batch cmd
					*end = '\0';
					end = find_char_or_comment(value, '\0');
					rstrip(value);
					/* Strip double-quotes */
					if (value[0] == '"' &&
				   		value[strlen(value)-1] == '"') {
						value[strlen(value)-1] = '\0';
 							value += 1;
 					}

					/*
					 * Valid name[=:]value pair found, call handler
				 	*/
					strncpy0(prev_name, name, sizeof(prev_name));
					printf("start %d line:%s %s\n",lineno, name, value);
					if (inifile_handler(section, section, name, value) &&
				  	   !error){		
						start = ++end;
						goto loop;
					}
					else
						error = lineno;
				}
				else{
					end = find_char_or_comment(value, '\0');
					rstrip(value);
					/* Strip double-quotes */
					if (value[0] == '"' &&
				   		value[strlen(value)-1] == '"') {
						value[strlen(value)-1] = '\0';
 							value += 1;
 					}

					/*
					 * Valid name[=:]value pair found, call handler
				 	*/
					strncpy0(prev_name, name, sizeof(prev_name));
					printf("start %d line:%s\n",lineno, value);
					if (!inifile_handler(section, section, name, value) &&
				  	   !error)
							error = lineno;
						
				}
			} 
			else if (!error){
				/* No '=' or ':' found on name[=:]value line */
				error = lineno;
			}
		}
		else if ((*start == ':' && start[1] == ':') || *start == '#') {
			/*
			 * Per Python ConfigParser, allow '#' comments at start
			 * of line
			 */
		}
#if CONFIG_INI_ALLOW_MULTILINE
		else if (*prev_name && *start && start > line) {
			/*
			 * Non-blank line with leading whitespace, treat as
			 * continuation of previous name's value (as per Python
			 * ConfigParser).
			 */
		    
			if (!inifile_handler(section, section, prev_name, start) && !error)
				error = lineno;
		}
#endif
		else if (*start == '[') {
			/* A "[section]" line */
			end = find_char_or_comment(start + 1, ']');
			if (*end == ']') {
				*end = '\0';
				strncpy0(section, start + 1, sizeof(section));
				*prev_name = '\0';
			} else if (!error) {
				/* No ']' found on section line */
				error = lineno;
			}
		} 
		if(error){
			printf("error= %d\n", error);
			break;
		}
		printf("%d line done\n", lineno);
	}
	
	free(udpkt);
	udpkt = NULL;
	
	if ( error ){	
		Upgrade_flag = UPGRADE_FAILED;
		TftpNetReStartCount = 10;
	}
	else{
		Upgrade_flag = UPGRADE_SUCCESS;
		TftpNetReStartCount = 11;
	}	
}


/**
 * restart the current transfer due to an error
 *
 * @param msg	Message to print for user
 */
static void restart(const char *msg)
{
	printf("\n%s; Net starting again\n", msg);
#ifdef CONFIG_MCAST_TFTP
	mcast_cleanup();
#endif
	NetStartAgain();
}

static void
ICMPHandler (unsigned type, unsigned code, unsigned dport,
		 unsigned sport, unsigned len)
{
	
		if (type == ICMP_NOT_REACH && code == ICMP_NOT_REACH_PORT) {
			UdpTimeoutMSecs = 5000UL;
			NetSetTimeout (UdpTimeoutMSecs, UdpTimeout);
	}
	
}

static void
UdpTimeout (void)
{
	if (++UdpTimeoutCount > UdpTimeoutCountMax) {
		if ( ++TftpNetReStartCount > TftpNetReStartCountMax ){
			return;
		}
		switch(UdpTimeoutMSecs){
			case 5000:  
				buzzer_notify(200, 1);
				restart("UDP server died");
				break;
			case 20000:  
				buzzer_notify(200, 2);
				restart("GetPacke Retry count exceeded");
				break;
			default:
				buzzer_notify(200, 3);
				restart("Retry count exceeded");
				break;
		}
		
	} else {
		puts ("T ");
		NetSetTimeout (UdpTimeoutMSecs, UdpTimeout);
		UdpSend ();
	}
}


void
UdpStart (void)
{
	char *ep;             /* Environment pointer */

	/*
	 * Allow the user to choose UDP blocksize and timeout.
	 * UDP protocol has a minimal timeout of 1 second.
	 */

	if ((ep = getenv("udptimeout")) != NULL){
		printf("udptimeout = %d\n", UdpTimeoutMSecs);
		UdpTimeoutMSecs = simple_strtol(ep, NULL, 10);
	}
	if (UdpTimeoutMSecs < 20000) {
		printf("UDP timeout (%ld ms) too low, "
			"set minimum = 20000 ms\n",
			UdpTimeoutMSecs);
		UdpTimeoutMSecs = 20000;
	}

	UdpServerIP = NetServerIP;
	
#if defined(CONFIG_NET_MULTI)
	printf ("Using %s device\n", eth_get_name());
#endif		
	UdpTimeoutCountMax = 5;
	UdpTimeoutCount = 0;
	
	NetSetTimeout (UdpTimeoutMSecs, UdpTimeout);
	NetSetHandler (UdpHandler);
	NetSetIcmpHandler(ICMPHandler);  //NO server
	
	UdpServerPort = 75;
	UdpOurPort = getenv("ourport");
	
	/* zero out server ether in case the server ip has changed */
	memset(NetServerEther, 0, 6);

	UdpSend ();

3、tftp.c的完善:

 1)增加了服务器不在的处理

static void
IcmpHandler (unsigned type, unsigned code, unsigned dport,
		 unsigned sport, unsigned len)
{
	
		if (type == ICMP_NOT_REACH && code == ICMP_NOT_REACH_PORT) {
			TftpTimeoutMSecs = 3500UL;
			NetSetTimeout (TftpTimeoutMSecs, TftpTimeout);
	}
	
}

 2)限制了NetStartAgain()的次数,超过次数终止接收数据报

在net.c中定义int TftpNetReStartCount = 0;  int TftpNetReStartCountMax  = 3;
在net.h中定义extern int TftpNetReStartCount;         extern int TftpNetReStartCountMax;

 3)超时处理函数的修改

static void restart(const char *msg)
{
	printf("\n%s; Net starting again\n", msg);
#ifdef CONFIG_MCAST_TFTP
	mcast_cleanup();
#endif
	NetStartAgain();
}
static void TftpTimeout (void)
{
	if (++TftpTimeoutCount > TftpTimeoutCountMax) {
		if ( ++TftpNetReStartCount > TftpNetReStartCountMax ){
			return;
		}
		switch(TftpTimeoutMSecs){
			case 3500:  
				buzzer_notify(200, 1);
				restart("TFTP server died");
				break;
			case 3000:  
				buzzer_notify(200, 2);
				restart("GetPacke Retry count exceeded");
				break;
			default:
				buzzer_notify(200, 3);
				restart("Retry count exceeded");
				break;
		}
		
	} else {
		puts ("T ");
		NetSetTimeout (TftpTimeoutMSecs, TftpTimeout);
		TftpSend ();
	}
}

4、对一开始就没插网线情况的处理:

在u-boot-2010.06\drivers\net\hisfv300的net-drv.c中的int eth_init(bd_t * bd)函数中修改。

在u-boot-2010.06\drivers\net\higmacv300的higmac.c中的int eth_init(bd_t * bd)函数中修改。


5、在各个平台指定环境变量的地址和大小

1)hi3520dv300、hi3521a、hi3531a:

#define CONFIG_ENV_OFFSET	0x50000      /* environment starts here */
#define CONFIG_ENV_SIZE		0x10000    /*include ENV_HEADER_SIZE */

2)除了hi3520dv300、hi3521a、hi3531a之外其他的可以在u-boot-2010.06\include\configs中各自的.h中修改:

#define CONFIG_ENV_OFFSET          0x80000      /* environment starts here */
#define CONFIG_ENV_SIZE            0x40000    /*include ENV_HEADER_SIZE */


 


六、编译uboot

1、在u-boot-2010.06\arch\arm\comfig.mk中修改交叉编译器路径

2、make clean

3、make ARCH=arm hi3520d_config

4、make

如果需要压缩uboot的话加上这5、6步

5、cd arch/arm/cpu/hi3520d/compressed

6、make     //第4步和这步生成压缩之后的u-boot.bin(这时uboot还没有对寄存器的初始化,烧写到板子是跑不起来的),不过可以tftp到板子然后用go命令跑

7、cp u-boot.bin ../u-boot.tools

8、sh make.sh   //生成20D.bin(这时的uboot可以烧写进flash了),hi3520d用fastBoot烧录,hi3521a、hi3531a和hi3510dv300(烧录时选21A芯片)用HiTool工具烧录




  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
[2015-01-15 更新] 添加 QCA9533 v2 支持 (暂无固件支持) 添加 TP-LINK TL-WR2041N v2 (QCA9558 + AR8236) 支持 修复在 32M Flash 上打开 TP-LINK 设置页面卡死的 BUG 修复使用新版 Flash 驱动后无法在 32M Flash 上启动固件的 BUG [2014-11-23 更新] AR2317 增加内存大小自适应的功能 AR7161 WNDR3700V2/WNDR3800/WNDRMAC 专用版修复 USB 灯常亮的问题 [2014-11-18 更新] 刷入编程器固件时如果不选择保留 U-Boot,不再检测固件是否合法,以便刷入其它闪存布局的固件。 [2014-11-16 更新] AR7240 再次修复刷原厂固件丢无线的 BUG (手抖造成的) 底层小更新 (所有芯片) [2014-10-26 更新] AR724x 添加 UBNT 编程器固件自动识别功能 [2014-10-7 更新] AR2317 修复无法刷入部分固件的 BUG 修复刷入编程器固件取消选择保留 U-Boot 却仍然保留 U-Boot 的 BUG 增加更多 Flash 支持 [2014-9-24 更新] WNDR3800 修复 OpenWrt 可能无法保存设置的 BUG WNDR3800 增加 CH 机型支持 增加品胜云座易充 (WMM003N) 及品胜无线音乐路由 (WPR001N) 支持 (先开机,再按复位键,否则无法开机,硬件问题) [2014-9-21 更新] 360 安全路由 C301 专用版完善恢复出厂设置的功能,支持 360 官方固件恢复出厂设置 修复小 BUG [2014-9-20 更新] 360 安全路由 C301 专用版增加刷写/备份第二 Flash 功能 360 安全路由 C301 专用版增加从第二 Flash 启动的功能 (目前无固件支持) 360 安全路由 C301 专用版增加刷写官方加密固件功能 [2014-9-4 更新] 添加 DHCP 服务功能,连接到路由的设备可自动获取 IP 地址 增强网页稳定性,解决页面多次刷新后失去响应的问题 修复 AR9341/AR9344 内存初始化 BUG,增强稳定性,解决部分 MW300R v3/v4 FW300R v3/v4 无法启动的问题 [2014-8-31 更新] 360 安全路由 C301 专用版增加 NVRAM 修改功能,可修改 MAC 地址等设置 [2014-8-30 更新] 增加 360 安全路由 C301 专用版 [2014-8-28 更新] 修复 AR9344 通电有时无法开机 (灯全亮) 的问题 增加 AR9344 + AR8035 (上海贝尔 MSA2K-3513NA 专用版) 支持 U-Boot 选择说明 ** 请根据以下列出的硬件配置选择合适的 U-Boot 文件进行刷机 ** 选择 Flash 时,请在下方的列表中检查是否支持。 ** 在已列出的生产商中,绝大多数未列出的 Flash 型号是因为其 JEDEC ID 与已列出的 Flash 相同,因此可以直接使用 ** 凡在 U-Boot 控制台 [系统信息] 页中看到已识别出 Flash 型号,则表明使用此 Flash 没有问题 U-Boot 适用的硬件配置、机型、及原厂固件如下: [u-boot-ar2317.bin] 硬件配置: AR2317 + 88E6060 AR2317 + AR8236 AR2317 + ADM6996 内存: SDRAM / DDR 16-bit 大小自适应 机型: 山寨 UBNT: TP-LINK TL-WR541G+ v1/v2/v3 TP-LINK TL-WR340G+ v1/v2/v3/v4 Netgear WGR614v7 原厂固件: UBNT XS2 系列原厂升级固件 其他固件: OpenWrt atheros 平台的 sysupgrade 固件 DD-WRT 固件 说明: u-boot-ar2317-32m.bin 可用在 32M 及 64M 内存的路由上,但只能使用 32M 内存 u-boot-ar2317-64m.bin 只能用在 64M 内存的路由上,在 32M 内存路由上不能开机 此 U-Boot 支持最大 16M Flash;支持在大容量 Flash 上刷写小容量固件,如在 8M Flash 上刷写 4M 固件,则 4M 固件会被自动扩展成 8M [u-boot-ar7161-wndr3800.bin] 硬件配置: AR7161 + RTL8366SR 内存: SDRAM 16-bit 大小自适应 机型: Netgear WNDR3700 v2 Netgear WNDR3800 Netgear WNDRMAC 原厂固件: 同机型支持的固件 其他固件: OpenWrt / DD-WRT 固件 [u-boot-ar7240_ar7241.bin] 硬件配置: AR7240 / AR7241 内存: DDR / DDR2 16-bit 大小自适应 机型: AR7240: TP-LINK TL-WR740N v1/v2/v3 TP-LINK TL-WR740N v4 (中国版) TP-LINK TL-WR741N v1/v2/v3 TP-LINK TL-WR841N v5 TP-LINK TL-WR940N v1 TP-LINK TL-WR941N v4 TP-LINK TL-WR941N v5 AR7241: TP-LINK TL-WA801N v1 TP-LINK TL-MR3220 v1 TP-LINK TL-MR3420 v1 TP-LINK TL-WR840N v1 TP-LINK TL-WR841N v7 TP-LINK TL-WR842N v1 以及水星、迅捷马甲路由 原厂固件: 同机型支持的固件 UBNT XM 原厂升级固件 [u-boot-ar913x-88e6060.bin] 硬件配置: AR9132 / AR9130 + 88E6060 内存: DDR 16-bit 大小自适应 机型: TP-LINK TL-WR941N v1/v2/v3 TP-LINK TL-WR841N v3 原厂固件: 同机型支持的固件 [u-boot-ar9331.bin] [u-boot-ar9331-pisen.bin] 硬件配置: AR9331 内存: SDRAM / DDR / DDR2 16-bit 大小自适应 机型: TP-LINK TL-MR3020 v1 TP-LINK TL-MR3040 v1/v2 TP-LINK TL-MR3220 v2 TP-LINK TL-WR340G+ v7 TP-LINK TL-WR700N TP-LINK TL-WR702N TP-LINK TL-WR703N TP-LINK TL-WR740N v4 (国际版) TP-LINK TL-WR740N v5/v6/v7 TP-LINK TL-WR741N v4 TP-LINK TL-WR742N v5/v6 TP-LINK TL-WR743N v2 TP-LINK TL-WR745N v2 品胜云座易充 (WMM003N) 品胜单网口无线音乐路由 (WPR001N) 以及水星、迅捷马甲路由 原厂固件: TP-LINK TL-MR3020 v1 (国际版) TP-LINK TL-MR3040 v1/v2 (国际版) TP-LINK TL-MR3220 v2 (国际版) TP-LINK TL-WR703N 品胜云座易充 (WMM003N) 品胜单网口无线音乐路由 (WPR001N) 说明: u-boot-ar9331-pisen.bin 专用于品胜无线路由以解决其复位按钮无法使用的问题 u-boot-ar9331-pisen.bin 品胜路由进入 U-Boot 控制台,请先开机再按复位键,否则无法开机,这是硬件设计造成的。可以超频,但限制到 500MHz 不能用于 TP-LINK TL-WR720N v3 和 TP-LINK TL-WR710N,否则无法开机。 [u-boot-ar9331-wr720nv3_wr710n.bin] 硬件配置: AR9331 内存: DDR 16-bit 大小自适应 机型: TP-LINK TL-WR710N TP-LINK TL-WR720 v3 原厂固件: 同 u-boot-ar9331.bin 适用的原厂固件 说明: 针对 TP-LINK TL-WR720 v3 和 TP-LINK TL-WR710N 定制的,以解决其内存类型识别的 BUG。 [u-boot-ar9341.bin] 硬件配置: AR9341 内存: SDRAM / DDR / DDR2 16-bit 大小自适应 机型: TP-LINK TL-MR3420 v2 TP-LINK TL-WR841N v8 TP-LINK TL-WR842N v2 TP-LINK TL-WR843N TP-LINK TL-WR847N v3 TP-LINK TL-WR940N v2 以及水星、迅捷马甲路由 原厂固件: TP-LINK TL-MR3420 v2 (国际版) TP-LINK TL-WR841N v8 (国际版) TP-LINK TL-WR842N v2 (国际版) TP-LINK TL-WR843N (国际版) TP-LINK TL-WR940N v2 (国际版) [u-boot-ar9342-ar8327.bin] 硬件配置: AR9342 + AR8327 内存: SDRAM / DDR / DDR2 16-bit 大小自适应 机型: TP-LINK TL-WR1041N v2 原厂固件: TP-LINK TL-WR1041N v2 [u-boot-ar9344.bin] [u-boot-ar9344-wr941nv6.bin] [u-boot-ar9344-wdr3320v2.bin] [u-boot-ar9344-mw4530r.bin] [u-boot-ar9344-msa2k-3513na.bin] [u-boot-ar9344-qihoo-c301.bin] 硬件配置: AR9344 AR9344 + AR8327N AR9344 + AR8035 内存: SDRAM / DDR / DDR2 16-bit 大小自适应 机型: 百兆有线: TP-LINK TL-WR941N v6 TP-LINK TL-WR2041N v1 TP-LINK TL-WDR3310 TP-LINK TL-WDR3320 v2 TP-LINK TL-WDR3500 TP-LINK TL-WDR3600 TP-LINK TL-WDR5300 TP-LINK TL-WDR6300 v2 水星 MAC1200R 360 安全路由 C301 千兆有线: D-LINK DIR-825 C1 TP-LINK TL-WDR4300/TL-WDR4310/TL-WDR4320 水星 MW4530R 单口千兆: 上海贝尔 MSA2K-3513NA 原厂固件: 同机型支持的固件 说明: 所有 AR9344 的 U-Boot 都自动检测有线网络类型,为百兆千兆自适应的 凡未提到使用专用版的,全部使用通用版 u-boot-ar9344.bin ! u-boot-ar9344-wr941nv6.bin 专用于 TP-LINK TL-WR941N v6 以解决其复位按钮无法使用的问题 u-boot-ar9344-wdr3320v2.bin 专用于 TP-LINK TL-WDR3320 v2 以解决其 LED 不正常和 PCI-E 初始化的问题 u-boot-ar9344-mw4530r.bin 用于 水星 MW4530R 和 D-LINK DIR-825 C1,以便能够使用 WPS/QSS 和 RESET 按钮 u-boot-ar9344-msa2k-3513na.bin 专用于 上海贝尔 MSA2K-3513NA,以便 LED 和 RESET 按钮能正常使用;现在只能刷写原厂编程器固件 u-boot-ar9344-qihoo-c301.bin 专用于 360 安全路由 C301,支持刷写官方固件或 OpenWrt 固件 [u-boot-qca953x.bin] 硬件配置: QCA9531 / QCA9533 内存: SDRAM / DDR / DDR2 16-bit 大小自适应 机型: TP-LINK TL-WR802N v1 TP-LINK TL-WR841N v9/v10/v11 TP-LINK TL-WR842N v4 水星 MW305R v3 水星 MW316R v1 迅捷 FR300R v9 原厂固件: TP-LINK TL-WR802N v1 TP-LINK TL-WR841N v9 (国际版) [u-boot-qca9558-ar8236.bin] 硬件配置: QCA9558 + AR8236 内存: SDRAM / DDR / DDR2 16-bit 大小自适应 机型: TP-LINK TL-WR941N v7 TP-LINK TL-WR881N v1 TP-LINK TL-WR2041N v2 迅捷 FW450R v1 水星 MW450R v1 原厂固件: 同机型支持的固件 [u-boot-qca9558-ar8327n.bin] 硬件配置: QCA9558 + AR8327N 内存: SDRAM / DDR / DDR2 16-bit 大小自适应 机型: TP-LINK Archer C5 TP-LINK Archer C7 v1/v2 TP-LINK TL-WDR4900 TP-LINK TL-WDR7500 v2 TP-LINK TL-WDR7500 v3 TP-LINK TL-WR1043N v2 原厂固件: 同机型支持的固件 [u-boot-tp9343.bin] 硬件配置: TP9343 内存: SDRAM / DDR / DDR2 16-bit 大小自适应 机型: TP-LINK TL-WR880N v3 TP-LINK TL-WR882N v1 TP-LINK TL-WR885N v1 TP-LINK TL-WR941N v8 TP-LINK TL-WR2041N v3 迅捷 FW450R V2 原厂固件: 无 U-Boot 支持的 Flash 列表及说明: 制造商 4M 8M 16M 32M Atmel AT25DF321 AT25DF321A AT25DF641 EN25Q128 EN25QH256 EON (cFeon) EN25F32 EN25P64 EN25QH128 EN25P32 EN25Q64 EN25Q32 EN25QH64 EN25QH32 ESMT F25L32PA F25L64QA F25L32QA GigaDevice GD25Q32 GD25Q64 GD25Q128 Macronix MX25L3205D MX25L6405D MX25L12805D MX25L3235E MX25L6435E MX25L12835E MX25L25635E MX25L3255E MX25L6455E MX25L12855E MX25L25655E Micron M25P32 M25P64 M25P128 N25Q256A M25PX32 M25PX64 N25Q128A13 N25Q032A N25Q064A N25Q128A11 PMC PM25LQ032 SST SST25VF032B SST25VF064C SST26VF032 SST26VF064B SST26VF032B Spansion S25FL032A S25FL064A S25SL128P1 S25FL256S1 S25FL132K S25FL164K S25SL128S1 S25SL032K * S25SL064K ** S25SL128K *** Winbond W25X32 W25X64 W25Q128 W25Q256 W25Q32 W25Q64 * S25SL032K 被识别为 W25Q32 ** S25SL064K 被识别为 W25Q64 *** S25SL128K 被识别为 W25Q128
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值