移植lwIP至U-Boot

来源:互联网 发布:matlab 初始化零矩阵 编辑:程序博客网 时间:2024/05/17 08:56
原文地址:http://www.wl-chuang.com/blog/2011/11/04/porting-lwip-to-uboot/

U-Boot是嵌入式系統上被廣為運用的boot loader,它擁有極為活躍的開發社群,也支援許多不同類型的CPU核心架構。U-Boot目前並不支援完整的TCP/IP,僅有限度地支援TFTP,方便開發者上傳韌體或是網路開機(BOOTP)。U-Boot身為boot loader非嵌入式作業系統,依據開放原始碼社群秉持地「精簡就是美」原則,不支援TCP/IP是可以理解的。萬一真的需要網路功能,移植一套完整的TCP/IP協定堆疊的任務雖然富有挑戰性,實務上亦是可行之道。

麻雀雖小五臟俱全的「lwIP」

lightweight IP(lwIP)是一個輕巧的開放原始碼之TCP/IP通訊協定之實作。lwIP首先由Adam Dunkels發表,目前則是以Kieran Mansley為計畫主持人,帶領開放原始碼社群進行該專案的維護與開發。

目前lwIP已實做的協定如下:

  • IP (Internet Protocol) including packet forwarding over multiple network interfaces
  • ICMP (Internet Control Message Protocol) for network maintenance and debugging
  • IGMP (Internet Group Management Protocol) for multicast traffic management
  • UDP (User Datagram Protocol) including experimental UDP-lite extensions
  • TCP (Transmission Control Protocol) with congestion control, RTT estimation and fast recovery/fast retransmit
  • Raw/native API for enhanced performance
  • DNS (Domain names resolver)
  • SNMP (Simple Network Management Protocol)
  • DHCP (Dynamic Host Configuration Protocol)
  • AUTOIP (for IPv4, conform with RFC 3927)
  • PPP (Point-to-Point Protocol)
  • ARP (Address Resolution Protocol) for Ethernet
  • Optional Berkeley-like socket API

lwIP設計理念主要是希望於支援TCP/IP協定的同時,於執行時期也能精簡記憶體之運用,以達成支援小型的嵌入式裝置、平台或即時作業系統(RTOS)的目標;除此之外,lwIP也已經移植到眾多RTOS平台上,例如:eCos…等等。由此這些特性來看,使用lwIP搭配U-Boot是一個好的選擇。

lwIP移植步驟

lwIP的的核心部份由ANSI C撰寫,使用目前的GCC應該可以直接交叉編譯(cross compiling)。整體來說要將lwIP移植到不同平台上,只要完成三件工作即可。首先要決定lwIP的組態;接著,補完lwIP需要之OS抽象層的實作;最後,撰寫lwIP之網路卡驅動程式lwIP architecture

一、選擇你要的lwIP組態

移植lwIP的第一步,要先決定將要啟用之lwIP的功能。由於lwIP包含許多通訊協定堆疊的實作以及許多系統開發除錯(debug)相關的功能,有些功能可能暫時使用不到,我們可以選擇將之關閉。

首先,建立並編輯「lwipopts.h」。以下為範例:

lwipopts.h
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
#ifndef __LWIPOPTS_H__#define __LWIPOPTS_H__#define NO_SYS                      1#define MEM_LIBC_MALLOC             1#define MEMP_MEM_MALLOC             0#define MEMP_SEPARATE_POOLS         0#define MEM_ALIGNMENT               4#define MEM_SIZE                    (4 * 1024 * 1024)#define MEMP_NUM_PBUF               1024#define MEMP_NUM_UDP_PCB            20#define MEMP_NUM_TCP_PCB            20#define MEMP_NUM_TCP_PCB_LISTEN     16#define MEMP_NUM_TCP_SEG            128#define MEMP_NUM_REASSDATA          32#define MEMP_NUM_ARP_QUEUE          10#define PBUF_POOL_SIZE              512#define LWIP_ARP                    1#define LWIP_TCP                    1#define LWIP_UDP                    1#define LWIP_DHCP                   1#define IP_REASS_MAX_PBUFS          64#define IP_FRAG_USES_STATIC_BUF     0#define IP_DEFAULT_TTL              255#define IP_SOF_BROADCAST            1#define IP_SOF_BROADCAST_RECV       1#define LWIP_ICMP                   1#define LWIP_BROADCAST_PING         1#define LWIP_MULTICAST_PING         1#define LWIP_RAW                    1#define TCP_WND                     (4 * TCP_MSS)#define TCP_MSS                     1460#define TCP_SND_BUF                 (8 * TCP_MSS)#define TCP_LISTEN_BACKLOG          1#define LWIP_NETIF_STATUS_CALLBACK  1#define LWIP_NETIF_LINK_CALLBACK    1#define LWIP_NETIF_HWADDRHINT       1#define LWIP_NETCONN                0#define LWIP_SOCKET                 0#define LWIP_STATS_DISPLAY          1#define MEM_STATS                   0#define SYS_STATS                   0#define MEMP_STATS                  0#define LINK_STATS                  0#define ETHARP_TRUST_IP_MAC         0#define ETH_PAD_SIZE                0#define LWIP_CHKSUM_ALGORITHM       2#define LWIP_TCP_KEEPALIVE          1#define MEMP_NUM_SYS_TIMEOUT        5// Keepalive values, compliant with RFC 1122. Don't change this unless you know what you're doing#define TCP_KEEPIDLE_DEFAULT        10000UL // Default KEEPALIVE timer in milliseconds#define TCP_KEEPINTVL_DEFAULT       2000UL  // Default Time between KEEPALIVE probes in milliseconds#define TCP_KEEPCNT_DEFAULT         9U      // Default Counter for KEEPALIVE probesextern void* dma_memory_alloc(unsigned int size);extern void* dma_memory_calloc(unsigned int size, unsigned int number);extern void  dma_memory_free(void* ptr);#define mem_init()#define mem_free                    dma_memory_free#define mem_malloc                  dma_memory_alloc#define mem_calloc(c, n)            dma_memory_calloc((c) * (n))#define mem_realloc(p, sz)          (p)#define LWIP_MEM_ALIGN(addr) ((void *)(((u32_t)(addr) + MEM_ALIGNMENT - 1) & ~(MEM_ALIGNMENT - 1)))#define LWIP_DEBUG                  0#define ETHARP_DEBUG                LWIP_DBG_OFF#define NETIF_DEBUG                 LWIP_DBG_OFF#define PBUF_DEBUG                  LWIP_DBG_OFF#define API_LIB_DEBUG               LWIP_DBG_OFF#define API_MSG_DEBUG               LWIP_DBG_OFF#define SOCKETS_DEBUG               LWIP_DBG_OFF#define ICMP_DEBUG                  LWIP_DBG_OFF#define INET_DEBUG                  LWIP_DBG_OFF#define IP_DEBUG                    LWIP_DBG_OFF#define IP_REASS_DEBUG              LWIP_DBG_OFF#define RAW_DEBUG                   LWIP_DBG_OFF#define MEM_DEBUG                   LWIP_DBG_OFF#define MEMP_DEBUG                  LWIP_DBG_OFF#define SYS_DEBUG                   LWIP_DBG_OFF#define TCP_DEBUG                   LWIP_DBG_OFF#define TCP_INPUT_DEBUG             LWIP_DBG_OFF#define TCP_OUTPUT_DEBUG            LWIP_DBG_OFF#define TCP_RTO_DEBUG               LWIP_DBG_OFF#define TCP_CWND_DEBUG              LWIP_DBG_OFF#define TCP_WND_DEBUG               LWIP_DBG_OFF#define TCP_FR_DEBUG                LWIP_DBG_OFF#define TCP_QLEN_DEBUG              LWIP_DBG_OFF#define TCP_RST_DEBUG               LWIP_DBG_OFF#define UDP_DEBUG                   LWIP_DBG_OFF#define TCPIP_DEBUG                 LWIP_DBG_OFF#define PPP_DEBUG                   LWIP_DBG_OFF#define SLIP_DEBUG                  LWIP_DBG_OFF#define DHCP_DEBUG                  LWIP_DBG_OFF#endif /* __LWIPOPTS_H__ */

在lwipopts.h中,我們可以選擇開啟或關閉某些lwIP的模組、決定debug訊息的層級以及lwIP執行時的記憶體配置模型。尤有甚者,U-Boot缺乏多工、多執行緒能力,僅能支援lwIP提供之Raw API,所以需要關閉BSD socket支援。關於每個選項的意義,可以交叉參考「lwip/src/include/lwip/opt.h」裡的說明。

二、移植lwIP之OS抽象層

移植之抽象層至U-Boot並不會太複雜,且U-Boot並沒有多執行緒及其衍生之關於資源競爭(race condition)的議題,移植工程的複雜度可以大幅減輕。所以在這個階段,基本上我們只要解決C compiler的互通性問題即可。lwIP將與此議題相關的選項歸納於cc.h。

cc.h
1234567891011121314151617181920212223242526272829303132333435363738394041424344
#ifndef __ARCH_CC_H__#define __ARCH_CC_H__// Includes definition of macro to do printfextern int printf(const char *fmt, ...);#define BYTE_ORDER               LITTLE_ENDIAN#define LWIP_PLATFORM_BYTESWAP   0typedef unsigned char  u8_t;typedef char           s8_t;typedef unsigned short u16_t;typedef short          s16_t;typedef unsigned int   u32_t;typedef int            s32_t;typedef unsigned int*  mem_ptr_t;#define LWIP_ERR_T  int/* Define (sn)printf formatters for these lwIP types */#define U16_F "u"#define S16_F "d"#define X16_F "x"#define U32_F "u"#define S32_F "d"#define X32_F "x"/* Compiler hints for packing structures */#define PACK_STRUCT_FIELD(x)    x#define PACK_STRUCT_STRUCT  __attribute__((packed))#define PACK_STRUCT_BEGIN#define PACK_STRUCT_END/* Plaform specific diagnostic output */#define LWIP_PLATFORM_DIAG(x, ...)   do {                \        printf(x, ##__VA_ARGS__);                   \    } while (0)#define LWIP_PLATFORM_ASSERT(x) do {                \        printf("Assert \"%s\" failed at line %d in %s\n",   \                x, __LINE__, __FILE__);             \    } while (0)#endif /* __ARCH_CC_H__ */

移植時,需指定平台的「BYTE_ORDER」,可為”LITTLE_ENDIAN”或”BIG_ENDIAN”,與此選項相依的有「LWIP_PLATFORM_BYTESWAP」。若移植平台為32-bits little-endian ARM,將BYTE_ORDER設為LITTLE_ENDIAN,LWIP_PLATFORM_BYTESWAP指定為0即可。相關設定,可以參考範例。

三、移植timer相關函式

移植工作至此,除了驅動程式的撰寫外,僅剩下timer的移植。由於lwIP之通訊協定堆疊大多仰賴timer,因此timer的移植於lwIP重要性不言而喻。以U-Boot來說,關於timer的運用並無標準之API,彈性很大,移植者可以視平台狀況啟動timer,並撰寫合適的函式。有關此類函式,可集中於sys_arch.c

sys_arch.c
123456789
#include "lwip/sys.h"extern unsigned int timer2_now();extern unsigned int timer2_interval();u32_t sys_now(void){ return timer2_now() * timer2_interval();}

四、撰寫網路卡驅動程式

lwIP透過網路卡驅動程式由實體層收送封包,關於驅動程式的撰寫方式,可參考lwIP原始碼提供之「netif/ethernetif.c」。

結論

整體來說,移植lwIP至U-Boot並不複雜,但是相關文件不多,需要些許耐心地閱讀甚至追蹤、觀察原始碼的運作。但由於lwIP設計完備,些許心力即可換來與U-Boot的良好搭配,在在顯示open source的彈性與優點。


0 0
原创粉丝点击