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完成,

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,377评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,390评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,967评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,344评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,441评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,492评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,497评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,274评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,732评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,008评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,184评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,837评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,520评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,156评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,407评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,056评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,074评论 2 352

推荐阅读更多精彩内容