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();
#else
        puts("\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_MULTI
    NetRestarted = 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 label
    restart:

    eth_halt();

#ifdef CONFIG_NET_MULTI
    eth_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_MULTI
    memcpy(NetOurEther, eth_get_dev()->enetaddr, 6);
#else
    eth_getenv_enetaddr("ethaddr", NetOurEther);
#endif

    eaddr.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 process
    do_http_progress(WEBFAILSAFE_PROGRESS_START);

    webfailsafe_is_running = 1;

    int led_off = 0;
    int cnt_up = 1;
    int cnt = 0;

    // infinite loop
    for(;;){
        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 state
            webfailsafe_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 loop
        if(!webfailsafe_ready_for_upgrade){
            continue;
        }

        // stop eth interface
        eth_halt();

        // show progress
        do_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 state
    webfailsafe_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 restart
    goto 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 process
    do_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 app
  void 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完成,

你可能感兴趣的:(u-boot分析三)