u-boot分析三
繼續分析,u-boot怎么實現從網頁加載固件實現web升級呢!是嵌入式了uip小型web服務器,可以參看manfeel的博文,在u-boot上移植uip的過程: https://blog.csdn.net/manfeel/article/details/13096075
現分析u-boot_mod中的httpd的代碼:
u-boot上電初始化之后,進入board_init_r,如果想要通過web加載內核鏡像,則需要初始化網絡設備,在初始化完成后進入main_loop循環中:
#if defined(CONFIG_CMD_NET)all_led_on();eth_initialize(gd->bd);all_led_off(); #endif/* main_loop() can return to retry autoboot, if so just run it again */for (;;)main_loop(); 復制代碼在main_loop ,沒有u-boot命令執行,則加載網絡循環NetLoopHttpd();:
#if defined(CONFIG_CMD_HTTPD)puts(" Starting web server for update...\n\n");NetLoopHttpd(); #elseputs("\n"); #endif 復制代碼NetLoopHttpd()函數,對網絡進行初始化,加入uip web服務器,連接終端:
/* *************************************** HTTP web server for web failsafe mode****************************************/ int NetLoopHttpd(void){bd_t *bd = gd->bd;unsigned short int ip[2];unsigned char ethinit_attempt = 0;struct uip_eth_addr eaddr;#ifdef CONFIG_NET_MULTINetRestarted = 0;NetDevExists = 0; #endif/* XXX problem with bss workaround *///初始化網絡參數NetArpWaitPacketMAC = NULL;NetArpWaitTxPacket = NULL;NetArpWaitPacketIP = 0;NetArpWaitReplyIP = 0;NetArpWaitTxPacket = NULL;NetTxPacket = NULL;if(!NetTxPacket){int i;// Setup packet buffers, aligned correctly.NetTxPacket = &PktBuf[0] + (PKTALIGN - 1);NetTxPacket -= (ulong)NetTxPacket % PKTALIGN;for(i = 0; i < PKTBUFSRX; i++){NetRxPackets[i] = NetTxPacket + (i + 1) * PKTSIZE_ALIGN;}}if(!NetArpWaitTxPacket){NetArpWaitTxPacket = &NetArpWaitPacketBuf[0] + (PKTALIGN - 1);NetArpWaitTxPacket -= (ulong)NetArpWaitTxPacket % PKTALIGN;NetArpWaitTxPacketSize = 0;}// restart labelrestart:eth_halt();#ifdef CONFIG_NET_MULTIeth_set_current(); #endif // eth_init初始化網絡設備while(ethinit_attempt < 10){if(eth_init(bd)){ethinit_attempt = 0;break;} else {ethinit_attempt++;eth_halt();milisecdelay(1000);}}if(ethinit_attempt > 0){eth_halt();printf_err("couldn't initialize eth (cable disconnected?)!\n\n");return(-1);}// get MAC address //獲取mac地址 #ifdef CONFIG_NET_MULTImemcpy(NetOurEther, eth_get_dev()->enetaddr, 6); #elseeth_getenv_enetaddr("ethaddr", NetOurEther); #endifeaddr.addr[0] = NetOurEther[0];eaddr.addr[1] = NetOurEther[1];eaddr.addr[2] = NetOurEther[2];eaddr.addr[3] = NetOurEther[3];eaddr.addr[4] = NetOurEther[4];eaddr.addr[5] = NetOurEther[5];// set MAC address 設置uip web的mac地址uip_setethaddr(eaddr);// set ip and other addresses// TODO: do we need this with uIP stack?NetCopyIP(&NetOurIP, &bd->bi_ip_addr);NetOurGatewayIP = getenv_IPaddr("gatewayip");NetOurSubnetMask = getenv_IPaddr("netmask");NetOurVLAN = getenv_VLAN("vlan");NetOurNativeVLAN = getenv_VLAN("nvlan");// start server...printf("HTTP server is starting at IP: %ld.%ld.%ld.%ld\n", (bd->bi_ip_addr & 0xff000000) >> 24, (bd->bi_ip_addr & 0x00ff0000) >> 16, (bd->bi_ip_addr & 0x0000ff00) >> 8, (bd->bi_ip_addr & 0x000000ff));HttpdStart(); // HttpdStart()函數初開始進入web的http服務// set local host ip address 為連接的主機終端分配IP地址ip[0] = ((bd->bi_ip_addr & 0xFFFF0000) >> 16);ip[1] = (bd->bi_ip_addr & 0x0000FFFF);uip_sethostaddr(ip);// set network mask (255.255.255.0 -> local network)ip[0] = ((0xFFFFFF00 & 0xFFFF0000) >> 16);ip[1] = (0xFFFFFF00 & 0x0000FFFF);uip_setnetmask(ip);// should we also set default router ip address?//uip_setdraddr();// show current progress of the processdo_http_progress(WEBFAILSAFE_PROGRESS_START);webfailsafe_is_running = 1;int led_off = 0;int cnt_up = 1;int cnt = 0;// infinite loopfor(;;){if (cnt == led_off)all_led_off();else if (cnt == 0)all_led_on();cnt++;if (cnt == 1024) {cnt = 0;if (cnt_up) {led_off++;if (led_off == 1024)cnt_up = 0;} else {led_off--;if (led_off == 0)cnt_up = 1;}}/** Check the ethernet for a new packet.* The ethernet receive routine will process it.*/if(eth_rx() > 0){HttpdHandler();}// if CTRL+C was pressed -> return!if(ctrlc()){eth_halt();// reset global variables to default statewebfailsafe_is_running = 0;webfailsafe_ready_for_upgrade = 0;webfailsafe_upgrade_type = WEBFAILSAFE_UPGRADE_TYPE_FIRMWARE;/* Invalidate the last protocol */eth_set_last_protocol(BOOTP);all_led_off();printf("\nWeb failsafe mode aborted!\n\n");return(-1);}// until upload is not completed, get back to the start of the loopif(!webfailsafe_ready_for_upgrade){continue;}// stop eth interfaceeth_halt();// show progressdo_http_progress(WEBFAILSAFE_PROGRESS_UPLOAD_READY);// try to make upgrade!if(do_http_upgrade(NetBootFileXferSize, webfailsafe_upgrade_type) >= 0){milisecdelay(500);do_http_progress(WEBFAILSAFE_PROGRESS_UPGRADE_READY);milisecdelay(500);/* reset the board */do_reset(NULL, 0, 0, NULL);}break;}// reset global variables to default statewebfailsafe_is_running = 0;webfailsafe_ready_for_upgrade = 0;webfailsafe_upgrade_type = WEBFAILSAFE_UPGRADE_TYPE_FIRMWARE;NetBootFileXferSize = 0;do_http_progress(WEBFAILSAFE_PROGRESS_UPGRADE_FAILED);all_led_off();// go to restartgoto restart;return(-1); }復制代碼HttpdStart()函數,啟動了uip http服務的初始化:
// start http daemon void HttpdStart(void){uip_init(); //初始化uip的基本屬性和參數httpd_init(); // } 復制代碼httpd_init()函數開始初始化web服務器,并設置端口號80:
// http server init void httpd_init(void){fs_init();uip_listen(HTONS(80)); } 復制代碼初始化完成之后,使用函數do_http_progress()監控當前進程的運行狀態, WEBFAILSAFE_PROGRESS_START為啟動進程:
// show current progress of the processdo_http_progress(WEBFAILSAFE_PROGRESS_START); 復制代碼進入for(;;)循環之后,在HttpdHandler()函數中調用uip_periodic()函數,從這個函數開始,啟動web服務器,向終端發送數據,進行交互操作:
for(i = 0; i < UIP_CONNS; i++){uip_periodic(i);if(uip_len > 0){uip_arp_out();NetSendHttpd();}}if(++arptimer == 20){uip_arp_timer();arptimer = 0;} 復制代碼而實際uip_periodic()開啟了uip TCP的網絡進程uip_process :
#define uip_periodic(conn) do { uip_conn = &uip_conns[conn]; \uip_process(UIP_TIMER); } while (0) 復制代碼uip_process()中進行一些列檢測后通過調用回調函數http_appcall,從主機終端獲取通過tftp傳輸過來的固件數據。
// called for http server appvoid httpd_appcall(void) 復制代碼httpd_appcall()中httpd_findandstore_firstchunk()加載固件,
if(httpd_findandstore_firstchunk()){data_start_found = 1;} else {data_start_found = 0;} 復制代碼如果能夠獲取固件,并進行檢測和校驗成功,則在繼續在NetLoopHttpd中執行下一步,將有效固件NetBootFileXferSize傳入do_http_upgrade開始執行upgrade
// try to make upgrade!if(do_http_upgrade(NetBootFileXferSize, webfailsafe_upgrade_type) >= 0){milisecdelay(500);do_http_progress(WEBFAILSAFE_PROGRESS_UPGRADE_READY);milisecdelay(500);/* reset the board */do_reset(NULL, 0, 0, NULL);} 復制代碼do_http_progress()通過執行u-boot命令行命令erase擦除數據,cp.d 命令寫入數據,至此,upgrade完成,
總結
- 上一篇: 小程序之图片懒加载[完美方案,你不来看看
- 下一篇: Java并发机制底层实现原理-volat