u-boot网络固件还原功能
2015-12-09 17:28
543 查看
一、任务简介:在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文件:
然后在需要访问的地方声明即可:
验证是否已经定义到此段的方法是修改此段的内容然后再打印此段的内容看是否一致:
可以通过windwHEX软件或打开u-boot.bin二进制文件修改此段的数据,下面是后者的代码:
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段的数据:
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服务器
五、代码实现
1、在cmd_net.c 中添加udp命令和query命令:
2、udp接收到的包交给net/udp.c处理:
3、tftp.c的完善:
1)增加了服务器不在的处理
2)限制了NetStartAgain()的次数,超过次数终止接收数据报
3)超时处理函数的修改
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:
2)除了hi3520dv300、hi3521a、hi3531a之外其他的可以在u-boot-2010.06\include\configs中各自的.h中修改:
六、编译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工具烧录
二、流程:
三、注意几点:
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工具烧录
相关文章推荐
- TCP/IP详解卷1 读书笔记:第二十一章 TCP超时与重传
- 每个程序员都该知道的网络同步知识
- 【计算机网络复习】:链路层
- 网络层访问权限控制技术-ACL详解
- 树莓派python,tornado,返回json数据代码,初级网络编程。
- [Servlet&JSP] HttpServletResponse的使用
- Block类型变量 - 缓存Http请求与回调
- java运用HttpClient 调用http post 包含header调用
- 详解基本TCP套接字函数
- jmeter之http请求-文件上传脚本编写
- java http调用方式get post 包含带header
- http://cssload.net/----动画
- Java——常见的HTTP状态码:
- Volley的初级使用(从网络下载图片)
- 用httpPost对JSON发送和接收的例子
- memcached 网络模型 --转载处:
- 质问微软 WP8.1开发HTTPS 真费劲
- UVA-10779 Collectors Problem (网络流建模)
- UDP和TCP
- 操作系统与网络实现 之十一