• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            milkyway的窩

            最初想法的誕生地

             

            Kitl是怎樣工作的?

            ?---------------by nasiry??
            ?????來自 http://www.cnblogs.com/nasiry/archive/2004/09/22/45473.aspx????????????????????????????????
            ---------------------------------
            注:由于我們主要是分析kitl的工作原理我們就電源管理的代碼不做分析,以加電啟動(dòng)的程序流進(jìn)行分析。
            part1.
            kitl初始化
            -------------
            Kitl的加載于其他調(diào)試服務(wù)之前,以提供為這些調(diào)試服務(wù)發(fā)布調(diào)試信息和接收主機(jī)調(diào)試命令的的通道。通常kitl在系統(tǒng)HAL初始化工作完成后進(jìn)行加載,MS建議在OEMInit中啟動(dòng)kitl。這樣就可以使用NIC或者是serial/Pal作為kitl的物理傳輸介質(zhì)。
            kitl的初始化由KitlInit完成,這部分代碼主要負(fù)責(zé):(to be fill later)
            下面我們來看看kitl的具體代碼,這些代碼位于%CEROOT%\PRIVATE\WINCEOS\COREOS\NK\KITL下。
            BOOL KitlInit (BOOL fStartKitl)
            {
            ??? // just initialize function pointers
            ??? pKITLRegisterDfltClient? = KITLRegisterDfltClient;
            ??? pKITLIoCtl = KITLIoctl;
            ??? pfnIsDesktopDbgrExist = IsDesktopDbgrExist;

            ??? // Initialize default clients
            ??? NewClient (KITL_SVC_DBGMSG, KITL_SVCNAME_DBGMSG, FALSE);
            ??? NewClient (KITL_SVC_PPSH,?? KITL_SVCNAME_PPSH,?? FALSE);
            ??? NewClient (KITL_SVC_KDBG,?? KITL_SVCNAME_KDBG,?? FALSE);


            ??? return fStartKitl? StartKitl (TRUE) : TRUE;
            }
            這段代碼主要完成兩個(gè)動(dòng)作:
            1.裝載函數(shù)指針,為后續(xù)代碼的執(zhí)行裝載入口點(diǎn)。
            2.注冊(cè)kitl客戶端,這些客戶端實(shí)現(xiàn)傳輸層以后就是我們所需要的調(diào)試界面。
            輸入?yún)?shù)決定是否立即啟動(dòng)KITL服務(wù),如果false的話就僅僅進(jìn)行初始化等待后續(xù)動(dòng)作使用startKitl來啟動(dòng)kitl.

            我們?cè)賮砜纯碞ewClient的原型
            static PKITL_CLIENT NewClient (UCHAR uId, LPCSTR pszSvcName, BOOL fAlloc)
            {
            ??? DEBUGCHK(IS_VALID_ID(uId));
            ??? DEBUGCHK (!KITLClients[uId]);
            ??? if (!fAlloc) {
            ??????? DEBUGCHK(IS_DFLT_SVC(uId));
            ??????? KITLClients[uId] = &DfltClnts[uId];
            ??? } else if (!(KITLClients[uId] = (PKITL_CLIENT) AllocMem (HEAP_KITLCLIENT))) {
            ??????? return NULL;
            ??? }
            ??? memset (KITLClients[uId], 0, sizeof(KITL_CLIENT));
            ??? KITLClients[uId]->ServiceId = uId;
            ??? strcpy (KITLClients[uId]->ServiceName, pszSvcName);

            ??? return KITLClients[uId];
            }
            這個(gè)被稱為NewClient的函數(shù)所完成的功能十分的簡(jiǎn)單,先檢查所需要?jiǎng)?chuàng)建的結(jié)構(gòu)是否是系統(tǒng)默認(rèn)服務(wù)所需要的,如果是的話就直接將該結(jié)構(gòu)的指針指向全局結(jié)構(gòu)DfltClnts并初始化結(jié)構(gòu),如果不是就申請(qǐng)相應(yīng)的空間完成該結(jié)構(gòu)的初始化。默認(rèn)的服務(wù)有 KITL_SVCNAME_DBGMSG, KITL_SVCNAME_PPSH, KITL_SVCNAME_KDBG分別對(duì)應(yīng)Debug信息的發(fā)布通道(Debug message),文本控制臺(tái)界面(PPshell),和內(nèi)核調(diào)試界面(kernel debug),在這里大家可能會(huì)問:為什么不統(tǒng)一使用固定的全局結(jié)構(gòu)來存放這些服務(wù)的信息呢?原因很簡(jiǎn)單,因?yàn)檫@些"client"在WindowSCE下是可以注冊(cè)擴(kuò)充和注銷的,這樣用AllocMem所分配的內(nèi)存空間在不再需要這些服務(wù)的時(shí)候可以釋放掉,就可以避免不必要的浪費(fèi)。另外KITLClients是這樣定義的PKITL_CLIENT KITLClients[MAX_KITL_CLIENTS];所以kitl所能注冊(cè)的client連同3個(gè)默認(rèn)的服務(wù)一共最多可以有MAX_KITL_CLIENTS--128個(gè)。

            下面繼續(xù)沿著程序流往下看吧,kitlInit完成最基本的初始化動(dòng)作即可啟動(dòng)kitl服務(wù)了。再看一下這個(gè)函數(shù)的原型。
            static BOOL StartKitl (BOOL fInit)
            {
            ??? // KITL already started?
            ??? if (!fInit && (KITLGlobalState & KITL_ST_DESKTOP_CONNECTED)) {
            ??????? return TRUE;
            ??? }

            ??? /*
            ???? * When this function is called, the kernel hasn't yet been initialized,
            ???? * so can't make any system calls.? Once the system has come up far
            ???? * enough to handle system calls, KITLInitializeInterrupt() is called to complete
            ???? * initialization.? This is indicated by the KITL_ST_MULTITHREADED flag in KITLGlobalState.
            ???? */
            ??? // Detect/initialize ethernet hardware, and return address information
            ??? if (!OEMKitlInit (&Kitl))
            ??????? return FALSE;

            ??? // verify that the Kitl structure is initialized.
            ??? if (!Kitl.pfnDecode || !Kitl.pfnEncode || !Kitl.pfnEnableInt || !Kitl.pfnRecv || !Kitl.pfnSend
            ??????? || !Kitl.dwPhysBuffer || !Kitl.dwPhysBufLen || !Kitl.WindowSize || !Kitl.pfnGetDevCfg || !Kitl.pfnSetHostCfg) {
            ??????? return FALSE;
            ??? }

            ??? // Validate that address is not in free RAM area - the HAL should put it in a reserved
            ??? // section of memory conditional on some environment var.
            ??? if ((pTOC->ulRAMStart < Kitl.dwPhysBuffer + Kitl.dwPhysBufLen)
            ??????? && (pTOC->ulRAMEnd > Kitl.dwPhysBuffer)) {
            ??????? KITLOutputDebugString("\r\n!Debug Ethernet packet buffers in free RAM area - must set IMGEBOOT=1\r\n");
            ??????? return FALSE;
            ??? }

            ??? if (Kitl.dwPhysBufLen < (DWORD) 3 * KITL_BUFFER_POOL_SIZE) {
            ??????? KITLOutputDebugString("\r\n!Debug Ethernet buffer size too small, must be at least 0x%x bytes (3 * WindowSize * 2 * KITL_MTU)\r\n",
            ??????????? 3 * KITL_BUFFER_POOL_SIZE);
            ??????? return FALSE;
            ??? }

            ??? KITLGlobalState |= KITL_ST_KITLSTARTED; // indicate (to kdstub) that KITL has started

            ??? // If the initialized flag is already set, we are being called from the power on routine,
            ??? // so reinit the HW, but not any state.
            ??? if (!(KITLGlobalState & KITL_ST_ADAPTER_INITIALIZED)) {
            ??????? // perform the initial handshake with the desktop
            ??????? if (!KITLConnectToDesktop ()) {
            ??????????? KITLOutputDebugString ("\r\n!Unable to establish KITL connection with desktop!\r\n");
            ??????????? return FALSE;
            ??????? }
            ???????
            ??????? // Set up kernel function pointers
            ??????? pKITLInitializeInterrupt = KITLInitializeInterrupt;
            ??????? pKITLSend = KITLSend;
            ??????? pKITLRecv = KITLRecv;

            ??????? KITLGlobalState |= KITL_ST_ADAPTER_INITIALIZED;

            ??????? if (Kitl.dwBootFlags & KITL_FL_DBGMSG)
            ??????????? SetKernelCommDev (KERNEL_SVC_DBGMSG, KERNEL_COMM_ETHER);
            ??????? if (Kitl.dwBootFlags & KITL_FL_PPSH)
            ??????????? SetKernelCommDev (KERNEL_SVC_PPSH, KERNEL_COMM_ETHER);
            ??????? if (Kitl.dwBootFlags & KITL_FL_KDBG)
            ??????????? SetKernelCommDev (KERNEL_SVC_KDBG, KERNEL_COMM_ETHER);

            ??????? // only perform cleanboot if it's connected at boot. Cleanboot flag is
            ??????? // ignored if it's started dynamically.
            ??????? if (fInit && (Kitl.dwBootFlags & KITL_FL_CLEANBOOT)) {
            ??????????? extern ROMHDR *const volatile pTOC;???? // Gets replaced by RomLoader with real address
            ??????????? // just clear the magic nOEMKitlInitumber (see SC_SetCleanRebootFlag)
            ??????????? // NOTE: We can NOT call SC_SetCleanRebootFlag here since logPtr isn't
            ??????????? // initialized yet.
            ??????????? ((fslog_t *)((pTOC->ulRAMFree + MemForPT) | 0x20000000))->magic1 = 0;
            ??????? }
            ??????? // if OEM calls KitlInit (FALSE), KITLInitializeInterrupt will
            ??????? // not be called in SystemStartupFuc. We need to initialize
            ??????? // interrupt here (when RegisterClient is called)
            ??????? if (fKITLcsInitialized && !InSysCall ()) {
            ??????????? KITLInitializeInterrupt ();
            ??????? }
            ??? }

            ??? LOG (KITLGlobalState);
            ??? return TRUE;
            }
            啟動(dòng)代碼首先判斷是否已經(jīng)啟動(dòng)kitl服務(wù),之后調(diào)用OEMKitlInit,該函數(shù)并不在private目錄下實(shí)現(xiàn),通常windowsCE需要用戶定制的代碼都是這種結(jié)構(gòu)---MS提供的代碼接口,用戶自己完成相應(yīng)的OEM部分,通常這些代碼都是與具體的硬件平臺(tái)相關(guān)的代碼。kitl的OEM代碼在HAL中實(shí)現(xiàn),通常在platform\kernel\hal\.下,這部分的代碼我們先跳過,看完startkitl的全貌再回過頭逐個(gè)說明。OEMkitlInit為kitl初始化硬件傳輸介質(zhì),同時(shí)分配初始化一些kitl所需要的全局結(jié)構(gòu)。隨后startkitl繼續(xù)檢查OEMkitlInit所分配和初始化的KITL結(jié)構(gòu)和內(nèi)存區(qū)域是否有效后設(shè)置kitl的全局標(biāo)示KITL_ST_KITLSTARTED;之后設(shè)置終端服務(wù)程序以及接收和發(fā)送程序的入口點(diǎn)后設(shè)置全局標(biāo)示KITL_ST_ADAPTER_INITIALIZED。現(xiàn)在傳輸介質(zhì)已經(jīng)全部就緒,通過SetKernelCommDev設(shè)置kernel通過ethernet傳送調(diào)試信息,調(diào)試輸入,以及CESH控制臺(tái)。再后調(diào)用KITLInitializeInterrupt完成中斷的初始化kitl啟動(dòng)的過程就結(jié)束了。
            ?? 緊接著我們來看看,OEMkitlInit都須要我們干什么。下面用SMDK2440的kitl為實(shí)例來進(jìn)行分析:
            BOOL OEMKitlInit (PKITLTRANSPORT pKitl)
            {
            ??? KITLOutputDebugString ("+OEMKitlInit\n");
            ??? RETAILMSG(1, (_T("+OEMKitlInit\r\n")));
            ??? // try to find a transport available
            ??? if (!InitEther (pKitl)
            ??????? && !InitParallelSerial (pKitl)) {
            ??????? KITLOutputDebugString ("Unable to initialize KITL Transports!\n");
            ??????? return FALSE;
            ??? }

            ??? gpKitl = pKitl;
            ??? KITLOutputDebugString ("-OEMKitlInit\n");
            ??? RETAILMSG(1, (_T("-OEMKitlInit\r\n")));
            ??? return TRUE;
            }

            事實(shí)上工作很簡(jiǎn)單,調(diào)用InitEther (pKitl) 和 !InitParallelSerial (pKitl)初始化網(wǎng)卡直接把初始化的KITL全局結(jié)構(gòu)返回就是所有的工作。這兒的InitParallelSerial是一個(gè)dummy永遠(yuǎn)返回false,也就是說這里沒有對(duì)serial&parallel transport進(jìn)行支持。真正的工作量集中在InitEther之后。事實(shí)上InitEther 和 InitParallelSerial只要任意的實(shí)現(xiàn)一個(gè)就可以達(dá)到建立傳輸界面的目的.下面,我們繼續(xù)看后面的代碼。
            BOOL InitEther(PKITLTRANSPORT pKitl)
            {
            ??? EDBG_ADAPTER adp;
            ??? DWORD dwDHCPLeaseTime;
            ??? DWORD dwSubnetMask;

            ??? KITLOutputDebugString ("+InitEther\n");

            ??? memset (&adp, 0, sizeof(adp));
            ??? memset (pKitl, 0, sizeof (KITLTRANSPORT));

            ??? // use existing code for ether initialization
            ??? if (!OEMEthInit (&adp))
            ??????? return FALSE;

            ??? // we are going to completely ignore the info in bootargs and the adaptor info
            ??? // returned from OEMEthInit, except MAC address. Just to prove that KITL will connect standalone

            ??? // get the MAC address
            ??? MyAddr.wMAC[0] = adp.Addr.wMAC[0];
            ??? MyAddr.wMAC[1] = adp.Addr.wMAC[1];
            ??? MyAddr.wMAC[2] = adp.Addr.wMAC[2];
            ??? //MyAddr = adp.Addr;
            ???
            ??? CreateDeviceName(&MyAddr, pKitl->szName);
            ??? KITLOutputDebugString ("Using device name: %s\n", pKitl->szName);

            ??? // If we haven't been given an IP address from our loader (or if we're not using static IP), get an IP address
            ??? // from a DHCP server.
            ??? if (adp.Addr.dwIP)
            ??? {
            ??????? // Static IP or we got the IP from our bootloader...
            ??????? MyAddr.dwIP???? = adp.Addr.dwIP;
            ??????? dwSubnetMask??? = 0;??? // Don't care about subnet mask...
            ??????? dwDHCPLeaseTime = adp.DHCPLeaseTime;
            ??? }
            ??? else
            ??? {
            ??????? // Get a DHCP address...
            ??????? if (!EbootGetDHCPAddr (&MyAddr, &dwSubnetMask, &dwDHCPLeaseTime))
            ??????????? return FALSE;
            ??? }
            ???
            ??? MyAddr.wPort = htons (EDBG_SVC_PORT);
            ??? KITLOutputDebugString ("Device %s, IP %s, Port %d\n", pKitl->szName, inet_ntoa (MyAddr.dwIP), htons (MyAddr.wPort));

            ??? // initialize KITL Ethernet transport layer
            ??? if (!KitlEtherInit (&MyAddr, dwDHCPLeaseTime)) {
            ??????? KITLOutputDebugString ("Unable to initialize KITL Ether transport\n");
            ??????? return FALSE;
            ??? }
            ???
            ??? // fill in the blanks in KITLTRANSPORT structure.
            ??? pKitl->FrmHdrSize = KitlEtherGetFrameHdrSize ();
            ??? pKitl->Interrupt = (UCHAR) adp.SysIntrVal;
            ??? pKitl->dwPhysBuffer = EDBG_PHYSICAL_MEMORY_START;
            ??? pKitl->dwPhysBufLen = 0x20000;????????????????????? // 128K of buffer available
            ??? pKitl->dwBootFlags = 0;
            ??? pKitl->WindowSize = EDBG_WINDOW_SIZE;
            ??? pKitl->pfnDecode = KitlEtherDecodeUDP;
            ??? pKitl->pfnEncode = KitlEtherEncodeUDP;
            ??? pKitl->pfnSend = EthSend;
            ??? pKitl->pfnRecv = OEMEthGetFrame;
            ??? pKitl->pfnEnableInt = KitlEthEnableInts;
            ??? pKitl->pfnSetHostCfg = SetHostCfg;
            ??? pKitl->pfnGetDevCfg = GetDevCfg;

            ??? KITLOutputDebugString ("-InitEther\n");


            ??? return TRUE;
            }
            這個(gè)函數(shù)完成的工作主要是調(diào)用OEMEthInit初始化網(wǎng)卡的服務(wù)程序及獲得相應(yīng)的IP和MAC,如果IP無效則用DHCP動(dòng)態(tài)獲得IP.通過MAC值產(chǎn)生一個(gè)標(biāo)示,這個(gè)標(biāo)示用來給PB的IDE使用。剛才的我們?cè)趉itlInit中看到除了檢查OEMkitlInit的返回值之外還檢查了KITL結(jié)構(gòu),該結(jié)構(gòu)的這些特征值正是在這兒設(shè)置的。在這兒可以看到pKitl->pfnDecode pKitl->pfnEncode pKitl->pfnSetHostCfg pKitl->pfnGetDevCfg 以及kitl所用的中斷號(hào)這些都是OEM代碼,也就是用于傳輸?shù)木幋a和解碼形式以及配置函數(shù)都是可以自己定義的,這樣一來也就無所謂使用什么傳輸介質(zhì)作為KITK
            的transport了,這就為使用1394或者是USB這一類的傳輸鏈路也能充當(dāng)傳輸界面作了準(zhǔn)備。 OEMEthInit函數(shù)是用于初始化傳輸介質(zhì)--以太網(wǎng)卡。這部分代碼直接是硬件控制代碼,我們來簡(jiǎn)單的看一下。
            BOOL
            OEMEthInit(EDBG_ADAPTER *pAdapter)
            {
            ?PBYTE pBaseIOAddress;

            ?// Driver globals from the bootloader.
            ?//
            ?if (pDriverGlobals->eth.EbootMagicNum == EBOOT_MAGIC_NUM)
            ?{
            ??memcpy(pAdapter, &pDriverGlobals->eth.TargetAddr, sizeof(EDBG_ADAPTER));

            ??switch(pDriverGlobals->misc.EbootDevice)
            ??{
            ??case(DOWNLOAD_DEVICE_PCMCIA):?// NE2000 CF card.
            ???pBaseIOAddress? = (PBYTE)PCMCIA_Init();
            ???if (pBaseIOAddress)
            ???{
            ????// Initialize the built-in Ethenet controller.
            ????//
            ????if (!NE2000Init((PBYTE)pBaseIOAddress, 1, pAdapter->Addr.wMAC))
            ????{
            ?????EdbgOutputDebugString("ERROR: OEMEthInit: Failed to initialize Ethernet controller.\r\n");
            ?????return(FALSE);
            ????}
            ???}
            ???pfnEDbgInit?????????? ?= NE2000Init;
            ???pfnEDbgEnableInts???? ?= NE2000EnableInts;
            ???pfnEDbgDisableInts??? ?= NE2000DisableInts;
            ???pfnEDbgGetPendingInts ?= NE2000GetPendingInts;
            ???pfnEDbgGetFrame?????? ?= NE2000GetFrame;
            ???pfnEDbgSendFrame????? ?= NE2000SendFrame;
            ???pfnEDbgReadEEPROM???? ?= NE2000ReadEEPROM;
            ???pfnEDbgWriteEEPROM??? ?= NE2000WriteEEPROM;
            ???pfnEDbgSetOptions???? ?= NE2000SetOptions;
            ??#ifdef IMGSHAREETH
            ???pfnCurrentPacketFilter?= Ne2000CurrentPacketFilter;
            ???pfnMulticastList??= NE2000MulticastList;
            ??#endif?// IMGSHAREETH.
            ???break;
            ??case(DOWNLOAD_DEVICE_CS8900):?// CS8900A.
            ???// Initialize the CS8900.
            ???//
            ???if (!CS8900DBG_Init((PBYTE)CS8900DBG_IOBASE, CS8900DBG_MEMBASE, pAdapter->Addr.wMAC))
            ???{
            ????EdbgOutputDebugString("ERROR: OEMEthInit: CS8900 initialization failed.\r\n");
            ????return(FALSE);
            ???}

            ???pfnEDbgInit??= CS8900DBG_Init;
            ???pfnEDbgEnableInts???? ?= CS8900DBG_EnableInts;
            ???pfnEDbgDisableInts??? ?= CS8900DBG_DisableInts;
            ???pfnEDbgGetFrame??= CS8900DBG_GetFrame;
            ???pfnEDbgSendFrame?= CS8900DBG_SendFrame;
            ???pfnEDbgGetPendingInts ?= CS8900DBG_GetPendingInts;
            ??#ifdef IMGSHAREETH
            ???pfnCurrentPacketFilter?= CS8900DBG_CurrentPacketFilter;
            ???pfnMulticastList?= CS8900DBG_MulticastList;
            ??#endif?// IMGSHAREETH.
            ???break;
            ??default:
            ???EdbgOutputDebugString("ERROR: OEMInit: Unknown download NIC (0x%x).\r\n", pDriverGlobals->misc.EbootDevice);
            ???return(FALSE);
            ?
            ?}}
            ?else
            ?{
            ??// TODO - retrieve CS8900 MAC address from flash...
            ??// TODO - intialize the CS8900 from scratch...
            ?}

            ?EdbgOutputDebugString("::: OEMEthInit() IP Address : %s\r\n", inet_ntoa(pAdapter->Addr.dwIP));
            ?EdbgOutputDebugString("::: OEMEthInit() Netmask??? : %s\r\n", inet_ntoa(pDriverGlobals->eth.SubnetMask));

            ?if (pDriverGlobals->misc.EbootDevice == DOWNLOAD_DEVICE_PCMCIA)
            ??pAdapter->SysIntrVal??? = SYSINTR_PCMCIA_LEVEL;
            ?else
            ??pAdapter->SysIntrVal??? = SYSINTR_ETHER;

            ?pAdapter->DHCPLeaseTime = DEFAULT_DHCP_LEASE;
            ?pAdapter->EdbgFlags???? = pDriverGlobals->eth.EdbgFlags;
            ??
            #ifdef IMGSHAREETH
            ??? VBridgeInit();
            ??? VBridgeKSetLocalMacAddress((char *)pAdapter->Addr.wMAC);
            #endif?// IMGSHAREETH.

            ?return(TRUE);
            }
            ? ?
            這個(gè)函數(shù)看起來很復(fù)雜其實(shí)真正的工作并不多,首先判斷是不是由eboot啟動(dòng)的,如果已經(jīng)eboot中已經(jīng)完成了對(duì)以太網(wǎng)卡的初始化動(dòng)作就直接使用網(wǎng)卡并裝載/掛接網(wǎng)卡所需的函數(shù)和網(wǎng)卡信息,否則就需要自己設(shè)置網(wǎng)卡的MAC地址和初始化網(wǎng)卡(事實(shí)上以上函數(shù)并沒有對(duì)這部分代碼進(jìn)行實(shí)現(xiàn),這就是很多使用2410/2440的用戶在不使用eboot啟動(dòng)的情況下總是不能使用kitl的原因--找不到eboot在DriverGlobal中留下的magic NUMBER)。這兒之所以有NE2000和Cs8900的區(qū)分是因?yàn)镾MDK2440可以使用PCMICA掛接Ne2000兼容的NIC或板載CS8900,后面設(shè)置中斷標(biāo)示有兩個(gè)分支也是這個(gè)原因。
            IMGSHAREETH的部分是Vbridge的部分,為什么要使用這個(gè)叫vbridge的東西呢?我們看看下面的假設(shè)。
            為了建立kitl占用了一個(gè)網(wǎng)卡資源,而該資源如果在windowsCE下復(fù)用(該設(shè)備同時(shí)被兩個(gè)驅(qū)動(dòng)使用1.kitl 2.windowsCE NIC driver)的話會(huì)不會(huì)導(dǎo)致問題呢?看看下面的兩個(gè)函數(shù)。
            ??? VBridgeInit();
            ??? VBridgeKSetLocalMacAddress((char *)pAdapter->Addr.wMAC);
            ??? 該函數(shù)在內(nèi)核調(diào)試傳輸通道和tcp/ip&windsock之間建立一個(gè)虛擬的網(wǎng)橋v-bridge,在外部看來vbridge就像在mac層一樣,vbridge一方面和硬件通訊建立傳輸?shù)奈锢斫缑妫硪环矫婧驼{(diào)試所需的EDBG和vmini.dll提供相同的邏輯界面,在更高的層面vmini.dll就像一個(gè)專門的網(wǎng)卡一樣支持NDIS以至于tcp/ip協(xié)議棧。這樣我們就可以一方面使用網(wǎng)卡做調(diào)試另外一方面仍然能讓windowsCE使用網(wǎng)卡通訊,對(duì)于windowCE而言所使用的網(wǎng)卡不在是與底層對(duì)應(yīng)的網(wǎng)絡(luò)設(shè)備,而是通過vbridge虛擬出來的網(wǎng)絡(luò)設(shè)備,所以在直接使用SMDK24XX的bsp編譯出來的系統(tǒng)網(wǎng)卡顯示為vmini就是這個(gè)原因。這個(gè)時(shí)候網(wǎng)卡驅(qū)動(dòng)怎么配置呢?答案很簡(jiǎn)單,就是不要網(wǎng)卡驅(qū)動(dòng),因?yàn)槲覀円呀?jīng)從vbridge中抽象(虛擬---用一個(gè)網(wǎng)卡)出一個(gè)網(wǎng)卡了,原來的網(wǎng)卡驅(qū)動(dòng)也就不在需要了。
            ???
            從上面的OemKitlInit到InitEther都是OEM代碼,目的在于使Kitl與相應(yīng)的transport的物理介質(zhì)聯(lián)系起來,也就是構(gòu)建kitl的硬件抽象層,在一個(gè)kitl初始化代碼中中只有這部分工作(OEM代碼)是必要的,其余的代碼直接使用MS編譯好的lib就可以了。盡管如此我們還是繼續(xù)看下面的代碼,雖然這對(duì)我們來說不是必須的不過對(duì)一個(gè)程序要有全面的認(rèn)識(shí),框架上的重要模塊都是需要了解和認(rèn)識(shí)的。


            看完了這一系列的OEM代碼,繼續(xù)看看StartKitl里面我們沒有看完的部分在設(shè)置啟動(dòng)標(biāo)示位之前做了2個(gè)檢查分別是檢查buffer的位置是否在編譯系統(tǒng)的時(shí)候預(yù)留下來以及是否有足夠的長(zhǎng)度可用。這個(gè)內(nèi)存區(qū)域不是動(dòng)態(tài)分配的,而是在bsp的內(nèi)存配置文件中指定并保留下來的(見bsp file目錄下的config.bib)。再下來進(jìn)行一個(gè)KITLConnectToDesktop的動(dòng)作,這個(gè)看名字就知道作用了。就是和PC連接。同樣看看代碼:
            static BOOL KITLConnectToDesktop (void)
            {
            ??? // we'll use the PpfsFmtBuf for send buffer since ppfs can't be started yet at this stage
            ??? //
            ??? PKITL_HDR pHdr = (PKITL_HDR) (PpfsFmtBuf + Kitl.FrmHdrSize);
            ??? PKITL_DEV_TRANSCFG pCfg = (PKITL_DEV_TRANSCFG) KITLDATA(pHdr);
            ??? USHORT cbData = sizeof (PpfsFmtBuf) - Kitl.FrmHdrSize - sizeof (KITL_HDR) - sizeof (KITL_DEV_TRANSCFG);

            ??? if (!Kitl.pfnGetDevCfg ((LPBYTE) (pCfg+1), &cbData))
            ??????? return FALSE;

            ??? memset (pHdr, 0, sizeof (KITL_HDR));
            ??? pHdr->Id = KITL_ID;
            ??? pHdr->Service = KITL_SVC_ADMIN;
            ??? pHdr->Cmd = KITL_CMD_TRAN_CONFIG;
            ??? cbData += sizeof (KITL_DEV_TRANSCFG);
            ??? pCfg->wLen = cbData;
            ??? pCfg->wCpuId = KITL_CPUID;
            ??? memcpy (pCfg->szDevName, Kitl.szName, KITL_MAX_DEV_NAMELEN);
            ??? cbData += sizeof (KITL_HDR);

            ??? return KitlSendFrame (PpfsFmtBuf, cbData)
            ??????? && KITLPollResponse (FALSE, ChkCnxDsktp, TranCnxDsktp, (LPVOID) cbData);
            }
            結(jié)構(gòu)PKITL_HDR就是kilt的傳輸頭格式,而PKITL_DEV_TRANSCFG信息則是傳輸設(shè)備的設(shè)置。首先通過調(diào)用Kitl.pfnGetDevCfg得到傳輸設(shè)備的信息,Kitl.pfnGetDevCfg是函數(shù)指針,在對(duì)以太網(wǎng)卡初始化的時(shí)候指向OEM代碼中的GetDevCfg函數(shù)。通過這個(gè)函數(shù)得到設(shè)備信息(smdk2410的bsp中這兒返回的就是IP地址)。然后再繼續(xù)設(shè)置傳輸頭的標(biāo)示,類型,命令等等信息,然后就是發(fā)送數(shù)據(jù)了,具體的動(dòng)作就是調(diào)用KitlSendFrame。(To be continue...)

            BOOL KitlSendFrame (LPBYTE pbFrame, WORD cbData)
            {
            ??? if (!Kitl.pfnEncode (pbFrame, cbData)) {
            ??????? KITLOutputDebugString ("!KitlSendFrame: transport failed to encode the data frame\r\n");
            ??????? return FALSE;
            ??? }

            ??? return KitlSendRawData (pbFrame, (USHORT) (cbData + Kitl.FrmHdrSize + Kitl.FrmTlrSize));
            }
            這個(gè)函數(shù)首先調(diào)用KitlEtherEncodeUDP對(duì)數(shù)據(jù)幀進(jìn)行編碼為UDP協(xié)議需要的格式。然后調(diào)用 KitlSendRawData將數(shù)據(jù)送出至PC.
            BOOL KitlSendRawData (LPBYTE pbData, WORD wLength)
            {
            ??? BOOL fRet;
            ??? if (!(KITLGlobalState & KITL_ST_MULTITHREADED) || InSysCall())
            ??????? fRet = Kitl.pfnSend (pbData, wLength);
            ??? else if (IsDesktopDbgrExist ())
            ??????? fRet = KCall((PKFN) Kitl.pfnSend, pbData, wLength);
            ??? else {
            ??????? EnterCriticalSection (&KITLKCallcs);
            ??????? fRet = Kitl.pfnSend (pbData, wLength);
            ??????? LeaveCriticalSection (&KITLKCallcs);
            ??? }
            ??? return fRet;
            }
            首先判定系統(tǒng)沒有在調(diào)度中且當(dāng)前代碼在不可剝奪狀態(tài)狀態(tài)運(yùn)行,通過EthSend調(diào)用OEMEthSendFrame將數(shù)據(jù)送出就完成了工作。另外兩個(gè)分支與我們分析的程序流沒有關(guān)系先放一下。
            BOOL
            OEMEthSendFrame(
            ??? BYTE *pData,???? // IN - Data buffer
            ??? DWORD dwLength)? // IN - Length of buffer
            {
            ??? int retries = 0;

            ??? while (retries++ < 4) {
            ??????? if (!pfnEDbgSendFrame(pData, dwLength))
            ??{
            #ifdef IMGSHAREETH
            ???ProcessVMiniSend();
            #endif //IMGSHAREETH
            ??????????? return TRUE;
            ??}
            ??????? else
            ??????????? EdbgOutputDebugString("!OEMEthSendFrame failure, retry %u\n",retries);
            ??? }
            ??? return FALSE;
            }
            在發(fā)送數(shù)據(jù)幀的過程中專門有處理vMini發(fā)送的過程。由于kitl本身就不是很簡(jiǎn)單我們以后后面再用專門的文章說明vbridge的工作過程。完成了發(fā)送,我們繼續(xù)下面的過程。
            BOOL KITLPollResponse (BOOL fUseSysCalls, PFN_CHECK pfnCheck, PFN_TRANSMIT pfnTransmit, LPVOID pData)
            {
            ??? DWORD dwLoopCnt = 0, dwLoopMax = MIN_POLL_ITER;
            ??? DWORD dwStartTime = CurMSec;
            ??? int?? nTimeMax = MIN_POLL_TIME;? // start with 1 sec
            ??? BOOL? fUseIter = FALSE, fUseTick = FALSE;

            ??? while (!pfnCheck (pData)) {
            ??????? //
            ??????? // if we've already connected with desktop, use the desktop
            ??????? // "Retransmit" package to determine if we need to retransmit
            ??????? //
            ??????? if (!(KITLGlobalState & KITL_ST_DESKTOP_CONNECTED)) {
            ??????????? if (fUseTick) {
            ??????????????? if ((int) (CurMSec - dwStartTime) > nTimeMax) {
            ??????????????????? // retransmit
            ??????????????????? if (!pfnTransmit (pData, fUseSysCalls))
            ??????????????????????? return FALSE;
            ??????????????????? dwStartTime = CurMSec;
            ??????????????????? if (nTimeMax < MAX_POLL_TIME)
            ??????????????????????? nTimeMax <<= 1;
            ??????????????? }
            ??????????? } else if (fUseIter || (dwStartTime == CurMSec)) {
            ??????????????? // if time isn't moving for a while, we'll
            ??????????????? // use iteration.
            ??????????????? if (dwLoopCnt ++ > dwLoopMax) {
            ??????????????????? if (!pfnTransmit (pData, fUseSysCalls))
            ??????????????????????? return FALSE;
            ??????????????????? if (dwLoopMax < MAX_POLL_ITER)
            ??????????????????????? dwLoopMax <<= 1;
            ??????????????????? dwLoopCnt = 0;
            ??????????????????? fUseIter = TRUE;
            ??????????????? }
            ??????????? } else {
            ??????????????? // time is moving, just use tick from here
            ??????????????? fUseTick = TRUE;
            ??????????? }
            ??????? }
            ??????? if (!KITLPollData(fUseSysCalls, pfnTransmit, pData)) {
            ??????????? return FALSE;
            ??????? }
            ??? }
            ??? return TRUE;
            }
            static BOOL TranCnxDsktp (LPVOID pParam, BOOL fUseSysCalls)
            {
            ??? return KitlSendFrame (PpfsFmtBuf, (WORD) (DWORD) pParam);
            }
            這個(gè)函數(shù)的主體是一個(gè)循環(huán),終止的條件是!pfnCheck (pData),這個(gè)函數(shù)是由前面?zhèn)鬟f進(jìn)來的,返回值為KITLGlobalState & KITL_ST_DESKTOP_CONNECTED,也就是說在得到桌面連接之前是不會(huì)返回的也就是說啟動(dòng)kitl以后不與桌面計(jì)算機(jī)連接windowsCE的是無法啟動(dòng)的。由于從dwStartTime定義到dwStartTime == CurMSec的判定僅僅需要很少的時(shí)間就可以完成這段時(shí)間內(nèi)CurMSec是不會(huì)被改寫的就可以通過循環(huán)進(jìn)行超時(shí)檢查
            并通過TranCnxDsktp重新發(fā)送數(shù)據(jù),直到KITLPollData設(shè)置KITLGlobalState。
            static BOOL KITLPollData(BOOL fUseSysCalls, PFN_TRANSMIT pfnTransmit, LPVOID pData)
            {
            ??? LPBYTE pRecvBuf = PollRecvBuf;
            ???
            ??? if (fUseSysCalls && (KITLGlobalState & KITL_ST_MULTITHREADED)
            ??????? && !(pRecvBuf = _alloca(KITL_MTU))) {
            ??????? KITLOutputDebugString("!KITLPollData: STACK OVERFLOW!\r\n");
            ??????? return FALSE;
            ??? }
            ??? HandleRecvInterrupt(pRecvBuf, fUseSysCalls, pfnTransmit, pData);
            ??? return TRUE;
            }
            由于我們上面?zhèn)鱽淼膄UseSysCalls參數(shù)為false所以前一段檢查操作并不進(jìn)行。直接調(diào)用 HandleRecvInterrupt。

            void HandleRecvInterrupt(UCHAR *pRecvBuf, BOOL fUseSysCalls, PFN_TRANSMIT pfnTransmit, LPVOID pData)
            {
            ??? WORD wLen = KITL_MTU;
            ??? BOOL fFrameRecvd;

            ??? // Receive data into buffer
            ??? do {
            ??????? if (!fUseSysCalls)
            ??????????? fFrameRecvd = Kitl.pfnRecv (pRecvBuf, &wLen);
            ??????? else if (IsDesktopDbgrExist ())
            ??????????? fFrameRecvd = KCall((PKFN) Kitl.pfnRecv, pRecvBuf, &wLen);
            ??????? else {
            ??????????? EnterCriticalSection (&KITLKCallcs);
            ??????????? fFrameRecvd = Kitl.pfnRecv (pRecvBuf, &wLen);
            ??????????? LeaveCriticalSection (&KITLKCallcs);
            ??????? }
            ??????? if (fFrameRecvd) {
            ??????????? ProcessRecvFrame (pRecvBuf,wLen,fUseSysCalls, pfnTransmit, pData);
            ??????????? wLen = KITL_MTU;
            ??????? }
            ??? } while (fFrameRecvd);
            }
            通過Kitl.pfnRecv調(diào)用pfnEDbgGetFrame指向的CS8900DBG_GetFrame讀取當(dāng)前的數(shù)據(jù)幀送交ProcessRecvFrame處理。注意,這兒的pfnEDbgGetFrame并不是通過DMA或者是網(wǎng)卡傳來的中斷啟動(dòng)的而是使用查詢的方法進(jìn)行的,這就是為什么這兒并沒有啟動(dòng)中斷仍然能夠使用以太網(wǎng)卡進(jìn)行數(shù)據(jù)傳輸數(shù)據(jù)的原因。隨后,我們將計(jì)算機(jī)端送來的數(shù)據(jù)送交ProcessRecvFrame處理。

            static BOOL ProcessRecvFrame(UCHAR *pFrame, WORD wMsgLen, BOOL fUseSysCalls, PFN_TRANSMIT pfnTransmit, LPVOID pData)
            {
            ??? KITL_HDR *pMsg;
            ??? KITL_CLIENT *pClient = NULL;
            ??? BOOL fRet = TRUE;
            ??? UCHAR RxBufOffset;
            ??? WORD? wDataLen;
            ??? UCHAR ClientIdx;
            ??? // let the transport layer decode the frame
            ??? if (!(pMsg = (KITL_HDR *) Kitl.pfnDecode (pFrame, &wMsgLen))) {
            ??????? KITL_DEBUGMSG(ZONE_RECV, ("ProcessRecvFrame: Received Unhandled frame\n"));
            ??????? return FALSE;
            ??? }

            ??? // is it a valid KITL message?
            ??? if (pMsg->Id != KITL_ID) {
            ??????? KITL_DEBUGMSG(ZONE_WARNING,("KITL: Got unrecognized Id: %X\r\n",pMsg->Id));
            ??????? return FALSE;
            ??? }
            ???
            ??? // Validate length
            ??? if (wMsgLen < KITL_DATA_OFFSET) {
            ??????? KITL_DEBUGMSG(ZONE_WARNING,("KITL: Invalid length %u\n",wMsgLen));
            ??????? return FALSE;
            ??? }
            ??? if (KITLDebugZone & ZONE_FRAMEDUMP)
            ??????? KITLDecodeFrame("<<KITLRecv",pMsg, wMsgLen);
            ???
            ??? // Check for administrative messages
            ??? if (pMsg->Service == KITL_SVC_ADMIN)
            ??????? return ProcessAdminMsg(pMsg, wMsgLen, fUseSysCalls, pfnTransmit, pData);

            ??? // Service Id is index into KITLClients array
            ??? ClientIdx = pMsg->Service;
            ??? if (ClientIdx >= MAX_KITL_CLIENTS) {
            ??????? KITL_DEBUGMSG(ZONE_WARNING,("!ProcessKITLMsg: Invalid ServiceId: %u\n",pMsg->Service));
            ??????? return FALSE;
            ??? }

            ??? pClient = KITLClients[ClientIdx];
            ???
            ??? // Until we complete registering, only handle administrative messages
            ??? if (!pClient || !(pClient->State & KITL_CLIENT_REGISTERED)) {
            ??????? KITL_DEBUGMSG(ZONE_WARNING,("!ProcessKITLMsg: Client %u not registered\n",ClientIdx));
            ??????? return FALSE;
            ??? }
            ??? if (pMsg->Service != pClient->ServiceId) {
            ??????? KITL_DEBUGMSG(ZONE_WARNING,("!ProcessKITLMsg: Mismatch in service Id for Client %u (Got %u, expect %u)\n",
            ??????????????????????????????????? ClientIdx,pMsg->Service,pClient->ServiceId));
            ??????? return FALSE;
            ??? }

            ??? if (pClient->State & KITL_USE_SYSCALLS) {
            ??????? if (fUseSysCalls)?
            ??????????? EnterCriticalSection(&pClient->ClientCS);
            ??????? else if (pClient->ClientCS.OwnerThread) {
            ??????????? // We can't get the client CS, and it is owned - just toss frame
            ??????????? KITL_DEBUGMSG(ZONE_WARNING,("!KITL(%u) tossing msg %u (Can't get CS)\n",ClientIdx, pMsg->SeqNum));
            ??????????? return FALSE;
            ??????? }
            ??? }

            ??? // we've being in sync with the desktop
            ??? pClient->State |= KITL_SYNCED;
            ???
            ??? // Put flags and seq # to LEDs
            ??? KITL_DEBUGLED(LED_PEM_SEQ, ((DWORD) pMsg->Flags << 24) | pMsg->SeqNum);
            ???
            ??? // OK, valid message, see if it's an ACK
            ??? if (pMsg->Flags & KITL_FL_ACK) {
            ??????? KITL_DEBUGMSG(ZONE_RECV,("KITL(%u): Received ack for msg %u, Tx window: %u,%u\n",
            ???????????????????????????????? ClientIdx,pMsg->SeqNum, pClient->AckExpected,pClient->TxSeqNum));
            ??????? // ACKs acknowledge all data up to the ACK sequence #
            ??????? while (SEQ_BETWEEN(pClient->AckExpected, pMsg->SeqNum, pClient->TxSeqNum)) {???????
            ??????????? if ((pClient->State & KITL_USE_SYSCALLS) &&
            ??????????????? ((pClient->CfgFlags & KITL_CFGFL_STOP_AND_WAIT) ||
            ???????????????? (SEQ_DELTA(pClient->AckExpected, pClient->TxSeqNum) >= pClient->WindowSize-1) ||
            ???????????????? !(KITLGlobalState & KITL_ST_INT_ENABLED))) {
            ??????????????? if (fUseSysCalls)
            ??????????????????? SetClientEvent(pClient,pClient->evTxFull);
            ??????????????? else {
            ??????????????????? // Can't process message at this time...
            ??????????????????? KITL_DEBUGMSG(ZONE_WARNING,("!KITL(%u): Tossing ACK %u (Can't set event)\n",
            ??????????????????????????????????????????????? ClientIdx, pMsg->SeqNum));
            ??????????????????? return FALSE;
            ??????????????? }
            ??????????? }
            ??????????? // Stop retransmission timer.
            ??????????? TimerStop(pClient, (UCHAR)(pClient->AckExpected % pClient->WindowSize),fUseSysCalls);
            ??????????? SEQ_INC(pClient->AckExpected);
            ??????? }
            ??????? goto ProcessKITLMsg_exit;
            ??? }

            ??? // Handle NACKs - retransmit requested frame if it is in our Tx window
            ??? if (pMsg->Flags & KITL_FL_NACK) {
            ??????? KITL_DEBUGMSG(ZONE_WARNING,("KITL(%u): Received NACK for msg %u, Tx window: %u,%u\n",
            ??????????????????????????????????? ClientIdx,pMsg->SeqNum, pClient->AckExpected,pClient->TxSeqNum));
            ??????? if (SEQ_BETWEEN(pClient->AckExpected, pMsg->SeqNum, pClient->TxSeqNum)) {
            ??????????? UCHAR Index = pMsg->SeqNum % pClient->WindowSize;
            ??????????? if (pClient->TxFrameLen[Index]) {
            ??????????????? // Restart retransmission timer (note we can't start timers if syscalls
            ??????????????? // are disabled, but this shouldn't screw us up, we'll just potentially
            ??????????????? // retransmit an extra frame if the timer fires before we get the ACK)
            ??????????????? if (fUseSysCalls)
            ??????????????????? TimerStop(pClient,Index,fUseSysCalls);
            ??????????????? RetransmitFrame(pClient, Index, fUseSysCalls);
            ??????????????? if (fUseSysCalls)
            ??????????????????? TimerStart(pClient,Index,KITL_RETRANSMIT_INTERVAL_MS,fUseSysCalls);
            ??????????? }
            ??????????? else
            ??????????????? KITL_DEBUGMSG(ZONE_WARNING,("!KITL(%u): NACK in window, but TxFrameLen empty!\n",ClientIdx));
            ??????? }
            ??????? else
            ??????????? KITL_DEBUGMSG(ZONE_WARNING,("!KITL(%u): Received NACK outside of TX window: Seq: %u, Window: %u,%u\n",
            ??????????????????????????????????????? ClientIdx,pMsg->SeqNum,pClient->AckExpected,pClient->TxSeqNum));
            ??????? goto ProcessKITLMsg_exit;
            ??? }
            ???
            ??? // Data frame.? Place in appropriate slot in Rx buffer pool. Note that we defer acking
            ??? // received frames until they are read from the buffer, in KITLRecv.
            ??? RxBufOffset = pMsg->SeqNum % pClient->WindowSize;

            ??? if (! SEQ_BETWEEN(pClient->RxSeqNum, pMsg->SeqNum, pClient->RxWinEnd)) {
            ??????? UCHAR uLastACK = (UCHAR) (pClient->RxWinEnd - pClient->WindowSize - 1);

            ??????? KITL_DEBUGMSG (ZONE_WARNING, ("KITL(%u): Received msg outside window: Seq:%u, Win:%u,%u\n",
            ????????????????????????????? ClientIdx,pMsg->SeqNum,pClient->RxSeqNum,pClient->RxWinEnd));

            ??????? // Special case to handle lost ACKs - if an ack is dropped, our Rx window will have
            ??????? // advanced beyond the seq # of the retransmitted frame.? Since ACKs ack all messages
            ??????? // up to the ack #, we only need to check the last frame.
            ??????? if (pMsg->SeqNum == uLastACK) {
            ??????????? KITL_DEBUGMSG(ZONE_WARNING,("KITL(%u): Lost ACK (seq: %u, win: %u,%u)\n",ClientIdx,
            ??????????????????????????????????????? pMsg->SeqNum,uLastACK,pClient->RxWinEnd));
            ??????????? SendAckNack (TRUE, pClient, uLastACK);
            ??????? }
            ??? } else if (pClient->RxFrameLen[RxBufOffset] != 0) {
            ??????? // If all our buffers are full, toss frame (will be acked when data is read in KITLRecv)
            ??????? KITL_DEBUGMSG(ZONE_WARNING,("KITL(%u): Received duplicate (Seq:%u), slot %u already full. Win: %u,%u\n",
            ??????????????????????????????????? ClientIdx,pMsg->SeqNum,RxBufOffset,pClient->RxSeqNum,pClient->RxWinEnd));
            ??? } else {
            ??????? DWORD OldProcPerms;

            ??????? // If we're in non-preemptible mode, can't set the receive event, so just toss message
            ??????? // and wait for retry.
            ??????? if (!fUseSysCalls && (pClient->State & KITL_USE_SYSCALLS)) {
            ??????????? KITL_DEBUGMSG(ZONE_WARNING,("KITL(%u): Tossing frame %u (Can't signal Rx event)\n",
            ??????????????????????????????????????? ClientIdx,pMsg->SeqNum));
            ??????????? return FALSE;
            ??????? }

            ??????? KITL_DEBUGMSG(ZONE_RECV,("KITL(%u): Received frame Seq: %u, len: %u, putting in slot %u\n",
            ???????????????????????????????? ClientIdx, pMsg->SeqNum, wMsgLen, RxBufOffset));
            ??????? // If frames were dropped, send NACK (only allow one outstanding NACK)
            ??????? if (pMsg->SeqNum != pClient->RxSeqNum) {
            ??????????? KITL_DEBUGMSG(ZONE_WARNING,("!KITL(%u): Dropped frame (seq: %u, win: %u,%u)\n",
            ??????????????????????????????????????? ClientIdx,pMsg->SeqNum,pClient->RxSeqNum, pClient->RxWinEnd));

            ??????????? if (!(pClient->State & KITL_NACK_SENT)) {
            ??????????????? SendAckNack(FALSE, pClient, pClient->RxSeqNum);
            ??????????????? pClient->State |= KITL_NACK_SENT;??????????
            ??????????? }
            ??????? }
            ??????? else
            ??????????? pClient->State &= ~KITL_NACK_SENT;
            ???????
            ??????? // Copy data to receive buffer, unblock anyone waiting, and close receive window
            ??????? wDataLen = wMsgLen - (WORD)KITL_DATA_OFFSET;
            ??????? if (wDataLen == 0)
            ??????????? KITL_DEBUGMSG(ZONE_WARNING,("!KITL: Received data message with 0 length!\n"));
            ??????? if (pClient->ProcPerms) {
            ??????????? // acquire permission of pClient and add it to current thread
            ??????????? ACCESSKEY aKey = GETCURKEY() | pClient->ProcPerms;
            ??????????? SWITCHKEY (OldProcPerms, aKey);
            ??????? }
            ??????? memcpy(pClient->pRxBufferPool + RxBufOffset*KITL_MTU,KITLDATA(pMsg), wDataLen);
            ??????? if (pClient->ProcPerms) {
            ??????????? SETCURKEY (OldProcPerms);???????????
            ??????? }
            ??????? pClient->RxFrameLen[RxBufOffset] = wDataLen;

            ??????? if (pClient->State & KITL_USE_SYSCALLS)
            ??????????? // If we get here, we know that fUseSysCalls is TRUE
            ??????????? SetClientEvent(pClient,pClient->evRecv);
            ???????
            ??????? // Close receive window
            ??????? while (pClient->RxFrameLen[pClient->RxSeqNum % pClient->WindowSize] &&
            ?????????????? (SEQ_DELTA(pClient->RxSeqNum, pClient->RxWinEnd) >= 1)) {
            ??????????? KITL_DEBUGMSG(ZONE_RECV,("Rx win: %u,%u, usesyscalls: %u\n",pClient->RxSeqNum, pClient->RxWinEnd, fUseSysCalls));
            ??????????? SEQ_INC(pClient->RxSeqNum);
            ??????? }
            ??? }
            ???
            ProcessKITLMsg_exit:

            ??? if (fUseSysCalls && (pClient->State & KITL_USE_SYSCALLS))
            ??????? LeaveCriticalSection(&pClient->ClientCS);
            ???
            ??? return fRet;
            }
            ProcessRecvFramed是一個(gè)近200行的函數(shù),樣子很嚇人。它是數(shù)據(jù)幀的解析和處理模塊的主體。我們從上到下看看都干了些什么。先調(diào)用KitlEtherDecodeUDP將來自主機(jī)的數(shù)據(jù)幀解碼為KITL_HDR結(jié)構(gòu),然后效驗(yàn)?zāi)Х〝?shù)KITL_ID,確認(rèn)該幀的信息的有效性以及數(shù)據(jù)長(zhǎng)度是否有效,如果ZONE_FRAMEDUMP標(biāo)簽是打開的則需要?jiǎng)t解析Frame的內(nèi)容并記錄下來(輸出到調(diào)試界面,初始化流程并不包含該信息),然后判定該數(shù)據(jù)幀描述的信息是否屬于管理命令(連接桌面,新建client等等),如果是則調(diào)用ProcessAdminMsg進(jìn)行處理。
            static BOOL ProcessAdminMsg(KITL_HDR *pHdr, WORD wMsgLen, BOOL fUseSysCalls, PFN_TRANSMIT pfnTransmit, LPVOID pData)
            {
            ??? KITL_CLIENT *pClient = NULL;???
            ???
            ??? switch (pHdr->Cmd)
            ??? {
            ??????? case KITL_CMD_SVC_CONFIG:
            ??????? {
            ??????????? KITL_SVC_CONFIG_DATA *pCfg = (KITL_SVC_CONFIG_DATA *) KITLDATA (pHdr);
            ??????????? int i, iStart;
            ???????????
            ??????????? if (wMsgLen != (KITL_DATA_OFFSET + sizeof(KITL_SVC_CONFIG_DATA))) {
            ??????????????? KITL_DEBUGMSG(ZONE_WARNING,("!ProcessAdminMsg: Invalid legnth for CONFIG msg: %u\n",wMsgLen));
            ??????????????? return FALSE;
            ??????????? }

            ??????????? // Find client struct
            ??????????? if ((i = ChkDfltSvc (pCfg->ServiceName)) < 0)
            ??????????????? i = HASH(pCfg->ServiceName[0]);

            ??????????? iStart = i;

            ??????????? while (KITLClients[i]) {
            ??????????????? // For multi instanced services, skip clients that are already registered
            ??????????????? if (!strcmp(KITLClients[i]->ServiceName,pCfg->ServiceName) &&
            ??????????????????? (!(KITLClients[i]->State & KITL_CLIENT_REGISTERED) || !(KITLClients[i]->CfgFlags & KITL_CFGFL_MULTIINST))) {
            ??????????????????? pClient = KITLClients[i];
            ??????????????????? break;
            ??????????????? }
            ??????????????? if (i < NUM_DFLT_KITL_SERVICES)
            ??????????????????? // no dups for default services
            ??????????????????? break;

            ??????????????? if (MAX_KITL_CLIENTS == ++ i)
            ??????????????????? i = NUM_DFLT_KITL_SERVICES;

            ??????????????? if (iStart == i)
            ??????????????????? break;? // couldn't find a client
            ??????????? }

            ??????????? if (!pClient || !(pClient->State & (KITL_CLIENT_REGISTERING|KITL_CLIENT_REGISTERED))) {
            ??????????????? KITL_DEBUGMSG(ZONE_WARNING,("!Received config for unrecognized service %s\n",
            ??????????????????????????????????????????? pCfg->ServiceName));
            ??????????????? return TRUE;
            ??????????? }

            ??????????? if (fUseSysCalls)
            ??????????????? EnterCriticalSection(&pClient->ClientCS);

            ??????????? // Send config to peer, unless this was a response to our cmd
            ??????????? if (!(pHdr->Flags & KITL_FL_ADMIN_RESP)) {
            ??????????????? // ack this config message
            ??????????????? SendConfig(pClient,TRUE);

            ??????????????? // Stop any pending transfers, reset sequence #s, etc

            ??????????????? // WARNING - can cause lost transmit data if the other side doesn't get
            ??????????????? // our config, and retries the config command.
            ??????????????? if (pClient->State & KITL_SYNCED) {
            ??????????????????? ResetClientState(pClient);
            ??????????????? }
            ??????????? }

            ??????????? //
            ??????????? // we got the response from desktop, connecting the client
            ??????????? //
            ??????????? KITL_DEBUGMSG(ZONE_INIT, ("ProcessAdminMsg: Receive Config message for service %s\n", pClient->ServiceName));
            ??????????? pClient->State &= ~(KITL_WAIT_CFG|KITL_CLIENT_REGISTERING);
            ??????????? pClient->State |= KITL_CLIENT_REGISTERED;
            ??????????? // Set our event in case anyone is waiting for config info
            ??????????? if (fUseSysCalls)
            ??????????????? SetClientEvent(pClient,pClient->evCfg);

            ???????????
            ??????????? if (fUseSysCalls)???????????
            ??????????????? LeaveCriticalSection(&pClient->ClientCS);
            ??????????? break;
            ??????? }
            ??????? case KITL_CMD_RESET:
            ??????????? {
            ??????????????? KITL_RESET_DATA *pResetData =? (KITL_RESET_DATA *) KITLDATA (pHdr);

            ??????????????? KITLOutputDebugString("KITL: Got RESET command\n");

            ??????????????? // Set for clean boot if requested
            ??????????????? if (pResetData->Flags & KITL_RESET_CLEAN)
            ??????????????????? SC_SetCleanRebootFlag();
            ???????????????
            ??????????????? // This function never returns
            ??????????????? KernelIoctl(IOCTL_HAL_REBOOT, NULL,0,NULL,0,NULL);
            ??????????????? KITLOutputDebugString("KITL: IOCTL_HAL_REBOOT not supported on this platform\n");
            ??????????????? break;
            ??????????? }

            ??????? case KITL_CMD_DEBUGBREAK:
            ??????????? if (fUseSysCalls && IsDesktopDbgrExist ())
            ??????????????? DebugBreak ();
            ??????????? break;

            ??????? case KITL_CMD_TRAN_CONFIG:
            ??????????? {
            ??????????????? int i;
            ???????????????
            ??????????????? PKITL_HOST_TRANSCFG pCfg = (PKITL_HOST_TRANSCFG) KITLDATA(pHdr);
            ??????????????? wMsgLen -= KITL_DATA_OFFSET;
            ??????????????? if (pCfg->dwLen != wMsgLen) {
            ??????????????????? KITLOutputDebugString ("!Host config message size mismatch %d, %d\r\n", pCfg->dwLen, wMsgLen);
            ??????????????????? return FALSE;
            ??????????????? }
            ??????????????? wMsgLen -= sizeof (KITL_HOST_TRANSCFG);
            ??????????????? if (!Kitl.pfnSetHostCfg ((LPBYTE) (pCfg+1), wMsgLen))
            ??????????????????? return FALSE;
            ??????????????? Kitl.dwBootFlags = pCfg->dwFlags;

            ??????????????? if (pCfg->dwKeySig == HOST_TRANSCFG_KEYSIG) {
            ??????????????????? for (i = 0; i < HOST_TRANSCFG_NUM_REGKEYS; i++) {
            ??????????????????????? g_dwKeys[i] = pCfg->dwKeys[i];
            ??????????????????????? KITL_DEBUGMSG (ZONE_INIT, (" KeyIndex %d = %d \n", i, g_dwKeys[i]));
            ??????????????????? }
            ??????????????? }???
            ??????????????? KITLGlobalState |= KITL_ST_DESKTOP_CONNECTED;
            ??????????? }
            ??????????? break;

            ??????? // in case we're polling (pfnTransmit && pData only set to non-null if we're polling)
            ??????? // we'll use desktop as our timer (desktop sends a retransmit packet to us every 2 seconds).
            ??????? case KITL_CMD_RETRASMIT:
            ??????????? if (pfnTransmit && pData) {
            ??????????????? // KITLOutputDebugString ("Retrasmitting packets....\n");
            ??????????????? pfnTransmit (pData, fUseSysCalls);
            ??????????? }
            ??????????? break;
            ??????? default:
            ??????????? KITL_DEBUGMSG(ZONE_WARNING,("!ProcessAdminMsg: Unhandled command 0x%X\n",pHdr->Cmd));
            ??????????? return FALSE;
            ??? }
            ??? return TRUE;
            }
            我們直接看KITL_CMD_TRAN_CONFIG分支,目前我們的主要工作仍然是配置連接。首先得到PKITL_HOST_TRANSCFG結(jié)構(gòu)指針,并送SetHostCfg設(shè)置主機(jī)信息之后,讀入從主機(jī)送出的8個(gè)key值后設(shè)置以及kitl啟動(dòng)選項(xiàng)和KITL_ST_DESKTOP_CONNECTED標(biāo)示位。繞了這么大一圈也就干了個(gè)初始化連接的工作,現(xiàn)在我們繼續(xù)回到startKitl。首先先是設(shè)置三個(gè)函數(shù)指針供后面程序調(diào)用,并設(shè)置標(biāo)示位KITL_ST_ADAPTER_INITIALIZED;然后通過SetKernelCommDev從定位KERNEL_SVC_DBGMSG,KERNEL_SVC_PPSH,KERNEL_SVC_KDBG的transport,注意:這個(gè)函數(shù)并不是kitl的函數(shù),而是windowsCE kernel的系統(tǒng)函數(shù)在WINCE420\PRIVATE\WINCEOS\COREOS\NK\KERNELkwin32.c下,作用是從定位系統(tǒng)調(diào)試信息的發(fā)布通道,有興趣可以自己看看。之后StartKitl的過程就結(jié)束了,這個(gè)時(shí)候你肯定想問那kitl的中斷初始化函數(shù)是什么時(shí)候才運(yùn)行呢?沒有中斷的支持kitl是如何通訊和工作的呢,事實(shí)上KITLInitializeInterrupt就負(fù)責(zé)這部分的工作,但是由于系統(tǒng)內(nèi)核還沒有完成初始化的動(dòng)作,所以這個(gè)時(shí)候起動(dòng)kitl的中斷是會(huì)影響kernel的工作。因此在后面由SystemStartupFunc()調(diào)用KITLInitializeInterrupt來完成初始化的動(dòng)作。
            BOOL
            KITLInitializeInterrupt()
            {

            ??? int i;
            ??? if (!(KITLGlobalState & KITL_ST_ADAPTER_INITIALIZED))
            ??????? return FALSE;
            ???
            ??? // Check if we are coming up for the first time, or resuming interrupts (e.g. when coming
            ??? // back from OEMPowerOff)
            ??? if (KITLGlobalState & KITL_ST_MULTITHREADED) {
            ??????? // Just enable interrupt and return
            ??????? EnableInts();
            ??????? return TRUE;
            ??? }
            ???
            ??? KITLOutputDebugString("KITL: Leaving polling mode...\n");

            ??? InitializeCriticalSection(&KITLODScs);
            ??? InitializeCriticalSection(&KITLKCallcs);

            ??? KITLGlobalState |= KITL_ST_MULTITHREADED;
            ???
            ??? KITL_DEBUGMSG(ZONE_INIT,("KITL Checking client registrations\n"));
            ??? // Some clients may have registered already, finish initialization now that
            ??? // the system is up. KDBG continues to run in polling mode.
            ??? for (i=0; i< MAX_KITL_CLIENTS; i++) {
            ??????? if (KITLClients[i] && (i != KITL_SVC_KDBG)
            ??????????? && (KITLClients[i]->State & (KITL_CLIENT_REGISTERED|KITL_CLIENT_REGISTERING))) {
            ??????????? if (!RegisterClientPart2((UCHAR)i))
            ??????????????? return FALSE;
            ??????? }
            ??? }

            ??? // Start interrupt thread. If we have clients registered, also turn on receive interrupts
            ??? // from the ethernet controller, otherwise leave them disabled.
            ??? if ((UCHAR) KITL_SYSINTR_NOINTR != Kitl.Interrupt) {
            ??????? KITL_DEBUGMSG(ZONE_INIT,("KITL Creating IST\n"));
            ??????? if ((hIntrThread = CreateKernelThread((LPTHREAD_START_ROUTINE)KITLInterruptThread,
            ????????????????????????????????????????????? NULL, (WORD)g_dwKITLThreadPriority, 0)) == NULL) {
            ??????????? KITLOutputDebugString("Error creating interrupt thread\n");
            ??????????? return FALSE;
            ??????? }
            ??? }

            ??? return TRUE;
            }
            由于將會(huì)有IST為kitl專門服務(wù),所以也就需要臨界區(qū)來完成線程的操作,這兒創(chuàng)建了KITLODScs\KITLKCallcs兩個(gè)臨界區(qū)。之后標(biāo)記 KITL_ST_MULTITHREADED。檢查注冊(cè)了的服務(wù),完成后就創(chuàng)建IST.

            kitl的初始化,啟動(dòng)的大致過程就是如此,start-->注冊(cè)服務(wù)-〉初始化transport->創(chuàng)建IST

            最后我們來看看IST里面我們都干些什么
            static DWORD KITLInterruptThread (DWORD Dummy)
            {
            ??? HANDLE hIntEvent;
            ??? DWORD dwRet;

            ??? KITL_DEBUGMSG(ZONE_INIT,("KITL Interrupt thread started (hTh: 0x%X, pTh: 0x%X), using SYSINTR %u\n",
            ???????????????????????????? hCurThread,pCurThread, Kitl.Interrupt));

            ??? pCurThread->bDbgCnt = 1;?? // no entry messages
            ???
            ??? if ((hIntEvent = CreateEvent(0,FALSE,FALSE,EDBG_INTERRUPT_EVENT)) == NULL) {
            ??????? KITLOutputDebugString("KITL CreateEvent failed!\n");
            ??????? return 0;
            ??? }
            ??? if (!SC_InterruptInitialize(Kitl.Interrupt, hIntEvent, NULL,0)) {
            ??????? CloseHandle(hIntEvent);
            ??????? KITLOutputDebugString("KITL InterruptInitialize failed\n");
            ??????? return 0;
            ??? }

            ??? // always enable interrupt as long as OEM told us so
            ??? EnableInts();
            ???
            ??? KITLGlobalState |= KITL_ST_IST_STARTED;
            ???
            ??? while ((dwRet = SC_WaitForMultiple (1,&hIntEvent,0,INFINITE)) == WAIT_OBJECT_0) {

            ??????? KITL_DEBUGLED(LED_IST_ENTRY,0);
            ??????? KITL_DEBUGMSG(ZONE_INTR,("KITL Interrupt event\n"));

            ??????? // no need to check pending, just call HandleRecvInterrupts because it'll
            ??????? // just return if there is no interrupt pending
            ??????? HandleRecvInterrupt(ISTRecvBuf,TRUE, NULL, NULL);

            ??????? SC_InterruptDone(Kitl.Interrupt);
            ???????
            ??????? KITL_DEBUGMSG(ZONE_INTR,("Processed Interrupt event\n"));
            ??? }
            ??? KITLOutputDebugString("!KITL Interrupt thread got error in WaitForMultipleObjects: dwRet:%u, GLE:%u\n",
            ????????????????????????? dwRet,GetLastError());
            ??? return 0;
            }
            首先是創(chuàng)建該IST所屬的事件,并將該事件與所屬的中斷聯(lián)系起來,再后自然是啟動(dòng)中斷了。設(shè)定KITL_ST_IST_STARTED標(biāo)記后的代碼就是IST的實(shí)際內(nèi)容,當(dāng)中斷發(fā)生,交付HandleRecvInterrupt處理,返回中斷。和多數(shù)IST一樣該調(diào)用永遠(yuǎn)不會(huì)返回,除非結(jié)束該線程,所以后面的調(diào)試信息輸出的是錯(cuò)誤。

            void HandleRecvInterrupt(UCHAR *pRecvBuf, BOOL fUseSysCalls, PFN_TRANSMIT pfnTransmit, LPVOID pData)
            {
            ??? WORD wLen = KITL_MTU;
            ??? BOOL fFrameRecvd;

            ??? // Receive data into buffer
            ??? do {
            ??????? if (!fUseSysCalls)
            ??????????? fFrameRecvd = Kitl.pfnRecv (pRecvBuf, &wLen);
            ??????? else if (IsDesktopDbgrExist ())
            ??????????? fFrameRecvd = KCall((PKFN) Kitl.pfnRecv, pRecvBuf, &wLen);
            ??????? else {
            ??????????? EnterCriticalSection (&KITLKCallcs);
            ??????????? fFrameRecvd = Kitl.pfnRecv (pRecvBuf, &wLen);
            ??????????? LeaveCriticalSection (&KITLKCallcs);
            ??????? }
            ??????? if (fFrameRecvd) {
            ??????????? ProcessRecvFrame (pRecvBuf,wLen,fUseSysCalls, pfnTransmit, pData);
            ??????????? wLen = KITL_MTU;
            ??????? }
            ??? } while (fFrameRecvd);
            }
            HandleRecvInterrupt是中斷處理程序的實(shí)體,將transport送來的數(shù)據(jù)填入緩沖區(qū)待處理。上面所提到的中斷在OEM代碼中指定,在SMDK2440bsp中該中斷對(duì)應(yīng)以太網(wǎng)卡中斷。

            posted on 2007-01-16 10:08 milkyway 閱讀(2261) 評(píng)論(1)  編輯 收藏 引用 所屬分類: wince(別人的文章技巧總結(jié))

            評(píng)論

            # re: Kitl是怎樣工作的? 2007-07-23 13:51 milkyway

            FAQ:


            問:什么是KITL?
            答:在Windows CE.NET以前的版本,用戶只能使用預(yù)先確定的傳輸端口,比如串口、并口或者以太網(wǎng)口來調(diào)試一個(gè)平臺(tái)。在Windows CE.NET中,引入了KITL(Kernel Independent Transport Layer,內(nèi)核無關(guān)傳輸層)技術(shù),其設(shè)計(jì)目標(biāo)是向用戶提供一種簡(jiǎn)單的方式以支持任意的調(diào)試服務(wù)。KITL將調(diào)試服務(wù)的通信協(xié)議與直接提供調(diào)試服務(wù)通信功能的硬件層分開,這樣就減少了用戶在產(chǎn)生一個(gè)硬件傳輸層時(shí)需要了解的數(shù)據(jù)傳輸原理。硬件傳輸層被置于KITL層之下以保證KITL不需要關(guān)心使用哪種通信硬件傳送調(diào)試數(shù)據(jù)。舉例來說,桌面電腦端和Windows CE設(shè)備端的傳輸機(jī)制可以都由OEM用戶實(shí)現(xiàn)。在桌面端,KITL傳輸機(jī)制是一個(gè)導(dǎo)出一些KITL必需的特定API函數(shù)的動(dòng)態(tài)鏈接庫(kù),這個(gè)動(dòng)態(tài)鏈接庫(kù)還必須在系統(tǒng)中注冊(cè)以通知它是為KITL功能傳輸端口服務(wù)的。在設(shè)備端,KITL在OAL中初始化并被編譯進(jìn)操作系統(tǒng)Kernel。設(shè)備端的KITL依賴傳輸端口以支持一個(gè)API級(jí)的函數(shù)調(diào)用,這些函數(shù)調(diào)用是實(shí)現(xiàn)系統(tǒng)的調(diào)試服務(wù)所必需的。

              回復(fù)  更多評(píng)論   

            導(dǎo)航

            統(tǒng)計(jì)

            公告

            隨筆皆原創(chuàng),文章乃轉(zhuǎn)載. 歡迎留言!

            常用鏈接

            留言簿(37)

            隨筆分類(104)

            隨筆檔案(101)

            文章分類(51)

            文章檔案(53)

            wince牛人

            搜索

            積分與排名

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            久久97久久97精品免视看秋霞| 日产久久强奸免费的看| 97久久精品无码一区二区天美| 一本久久综合亚洲鲁鲁五月天| 久久久精品免费国产四虎| 日韩人妻无码一区二区三区久久| 麻豆久久| 奇米影视7777久久精品人人爽| 久久影视综合亚洲| 亚洲AV无码1区2区久久| 色欲久久久天天天综合网精品| 热久久国产精品| 中文字幕乱码人妻无码久久| 久久久久久久精品成人热色戒 | 国产毛片欧美毛片久久久| 国产精品久久久久久福利69堂| 久久无码人妻精品一区二区三区| 久久人妻少妇嫩草AV无码专区| 久久久久久人妻无码| 无码人妻久久一区二区三区蜜桃| 狠狠狠色丁香婷婷综合久久五月| 久久线看观看精品香蕉国产| 久久男人Av资源网站无码软件| 日韩欧美亚洲综合久久| 久久丝袜精品中文字幕| 99久久国产热无码精品免费久久久久 | 久久亚洲AV无码精品色午夜 | 国产精品青草久久久久福利99| 一级做a爰片久久毛片人呢| 性色欲网站人妻丰满中文久久不卡| 性高朝久久久久久久久久| 久久综合综合久久97色| 婷婷久久综合九色综合98| 99久久精品国产麻豆| 久久久久久毛片免费播放| 久久AV高清无码| 无码任你躁久久久久久老妇| 国内精品久久久久久中文字幕 | 无码人妻精品一区二区三区久久久 | www久久久天天com| 久久国产精品一国产精品金尊|