Microsoft Windows CE .NET 中的中斷體繫結構

來源:互聯網
上載者:User
文章目錄
  • Microsoft Windows CE .NET 中的中斷體繫結構
Microsoft Windows CE .NET 中的中斷體繫結構

發布日期: 7/23/2004 | 更新日期: 7/23/2004

Nat Frampton(Windows Embedded MVP
Real Time Development Corp. 總裁)

適用於:
Microsoft Windows CE .NET with Microsoft Platform Builder 4.0

本頁內容


概述


中斷體繫結構


OAL ISR 處理


可安裝的 ISR


IST 中斷處理


導致延遲的因素


小結

概述

通過 Microsoft Windows CE .NET,Microsoft 已經升級了 Windows CE 的中斷體繫結構。該作業系統 (OS) 所具有的處理共用中斷的能力極大地擴充了 Windows CE .NET 支援許多中斷體繫結構的能力。本文從原始裝置製造商 (OEM) 和應用程式開發人員的角度探討了處理中斷的方案。本文還探討了 OEM 適配層 (OAL) 插斷服務常式 (ISR) 處理;提供了可安裝 ISR,包括一個簡單的入門級外殼程式;介紹了中斷服務線程 (IST) 中斷處理,並提供了一個初始化和執行模板。最後,本文分析了 ISR 和 IST 的延遲根源。

返回頁首

中斷體繫結構

探討 Microsoft Windows CE .NET 中斷體繫結構的第一步是定義中斷過程中硬體、核心、OAL 和線程互動的總體模型。大概說明了這些不同層級的職責以及導致狀態變化的轉換。

1.

該圖闡述了中斷過程中的主要轉換,時間按從左至右的順序遞增。該圖的最低層為硬體和中斷控制器的狀態。次低層是中斷服務過程中的核心互動。OAL 描述了主板支援軟體包 (BSP) 的職責。最頂層闡述了中斷服務所需的應用程式或驅動程式線程互動。該圖闡述了單個中斷過程中的互動;它表示了 Windows CE .NET 擁有共用中斷的新能力。

活動從該圖最左側部分以直線表示的中斷開始。產生了一個異常,導致核心 ISR 向量被載入到處理器中。核心 ISR 與硬體互動,禁用所有處理器上的所有具有相同和較低優先順序的中斷(ARM 和 Strong ARM 體繫結構除外)。然後,核心推進到已為該特定中斷註冊的 OAL ISR。此後,OAL ISR 既可以直接處理中斷,也可以使用 NKCallIntChain 遍曆已安裝的 ISR 列表。主 ISR 或任何已安裝的 ISR 隨後執行任意工作,並且為該裝置返回名為 SYSINTR 的映射中斷。如果該 ISR 確定其相關裝置沒有導致該中斷,該 ISR 將返回 SYSINTR_CHAIN,這會使 NKCallIntChain( ) 遍曆 ISR 列表以到達鏈中的下一個中斷。ISR 按照它們的安裝順序調用(它們在安裝時會在調用列表上建立一個優先順序)。

在調用了單個 ISR 或其相關 ISR 鏈之後,傳回值可能為下列值之一:

傳回值
操作

SYSINTR_NOP

中斷不與裝置的任何登入 ISR 關聯。核心啟用所有其他中斷。

SYSINTR

中斷與已知的登入 ISR 和裝置關聯。

SYSINTR_RESCHED

中斷是由請求 OS 重新調度的計時器到期引起的。

SYSINTR 傳回值是我們討論的重點。一旦 ISR 完成,核心將重新啟用處理器上除已識別的中斷之外的所有中斷。然後,核心將通知與 SYSINTR 值關聯的事件。

然後,驅動程式或應用程式的 IST 將能夠運行(假設它是準備好啟動並執行最高優先順序線程)。IST 將與相關裝置通訊,並從完成它的中斷互動的裝置中讀取所有必要的資料。然後,IST 用關聯的 SYSINTR 值來調用 InterruptDone( ),以通知它已完成。

核心在接收到 SYSINTR 值的 InterruptDone 時,將重新啟用指定的中斷。只有從這時開始,才能接收該裝置的其他中斷。

這隻是對 Windows CE .NET 內部活動的中斷序列的一個粗略介紹。現在,我們將詳細研究上述每個組件及其職責。

返回頁首

OAL ISR 處理

OAL ISR 是屬於平台的基本中斷處理常式。下面是 X86 平台的實際 ISR。配置分析和 ILTiming 支援已被刪除。X86 ISR 是所有基於 Windows CE 的平台的代表。它示範了能夠處理系統中所有中斷的單個 ISR。

該 ISR 的目標是向核心交還引起中斷的相關裝置的 SYSINTR 號。ISR 執行以下活動序列。

PICGetCurrentInterrupt (PIC) 中擷取當前硬體中斷

如果該中斷是 INTR_TIMER0(系統計時器)

更新OS 的 CurMSec 保持時間

檢查並確認是否已經註冊了重新啟動地址 (RebootHandler)

如果中斷是 INTR_RTC

ISR 檢查並確認鬧鐘是否已到期 (SYSINTR_RTC_ALARM)

如果中斷小於 INTR_MAXIMUM

調用中斷鏈 (NKCallIntrChain)

NKCallIntrChain 的傳回值設定為該傳回值

如果中斷鏈未包含中斷:(SYSINTR_CHAIN)

映射當前硬體中斷 (OEMTranslateIRQ)

如果該中斷被註冊到 OEMInit 中的 HookInterrupt

OEMTranslateIRQ 返回 SYINTR

如果該中斷未註冊,則返回 SYSINTR_NOP

啟用除當前中斷以外的所有中斷。(PICEnableInterrupt}

完成恰當的中斷結束工作以通知 PIC 中斷已完成 (EOI)

ISR 返回下列值之一:

SYSINTR_NOP — 沒有任何 ISR 包含該中斷

SYSINTR_RESCHED — 重新調度計時器已到期

SYSINTR — ISR 已經包含該中斷

SYSINTR_RTC_ALARM — 鬧鐘已到期

ULONG PeRPISR(void){ULONG ulRet = SYSINTR_NOP;UCHAR ucCurrentInterrupt;ucCurrentInterrupt = PICGetCurrentInterrupt();if (ucCurrentInterrupt == INTR_TIMER0) {            CurMSec += SYSTEM_TICK_MS;            CurTicks.QuadPart += TIMER_COUNT;            if ((int) (CurMSec - dwReschedTime) >= 0)                ulRet = SYSINTR_RESCHED;        }        //        // Check if a reboot was requested.        //        if (dwRebootAddress) {          RebootHandler();        }   } else if (ucCurrentInterrupt == INTR_RTC) {          UCHAR cStatusC;         // Check to see if this was an alarm interrupt          cStatusC = CMOS_Read( RTC_STATUS_C);          if((cStatusC & (RTC_SRC_IRQ)) == (RTC_SRC_IRQ))                ulRet = SYSINTR_RTC_ALARM;      } else if (ucCurrentInterrupt <= INTR_MAXIMUM) {            // We have a physical interrupt ID, return a SYSINTR_ID          // Call interrupt chain to see if any installed ISRs handle this  // interrupt          ulRet = NKCallIntChain(ucCurrentInterrupt);          if (ulRet == SYSINTR_CHAIN) {            ulRet = OEMTranslateIrq(ucCurrentInterrupt);           if (ulRet != -1)             PICEnableInterrupt(ucCurrentInterrupt, FALSE);           else              ulRet = SYSINTR_NOP;          } else {            PICEnableInterrupt(ucCurrentInterrupt, FALSE);          }      }      if (ucCurrentInterrupt > 7 || ucCurrentInterrupt == -2) {          __asm {                mov al, 020h    ; Nonspecific EOI                out 0A0h, al          }      }     __asm {          mov al, 020h        ; Nonspecific EOI          out 020h, al      }      return ulRet;}

如果 ISR 沒有為已經用 OAL 的 OEMInit 中的 HookInterrupt 初始化的中斷安裝,則該 ISR 將返回適當的 SYSINTR 值。

如果只能通過 IST 互動為裝置提供服務,則不需要為中斷安裝可安裝的 ISR。通過對 OALOEMInit 中的 HookInterrupt 進行調用以啟用中斷就足夠了。

ISR 代碼是一段非常小且快速的代碼。它的執行時間將直接影響整個系統中的中斷的延遲。Windows CE 3.0 中引入的中斷體繫結構更改是能夠嵌套中斷。在進入 OAL ISR 的那一刻,所有具有較高優先順序的中斷都已被啟用。ISR 可能被佔先。如果該 ISR 內部的計時非常關鍵,則可能要求在該時間段內禁用中斷。就像 ISR 執行時間一樣,中斷被關閉的這一時間將增加平台的最差情形延遲。

當 ISR 交還與特定裝置相關的 SYSINTR 時,核心將通知 IST 醒來。處理驅動程式或應用程式內部代碼的 IST 中斷負責結束中斷互動。

返回頁首

可安裝的 ISR

可安裝的 ISR 是為響應 Windows CE .NET 為嵌入式空間帶來的開放性而建立的。OEM 再也不必完全負責平台和應用程式代碼了。現在平台供應商和應用程式開發人員都可涉及嵌入式空間這一領域的工作。如果某個應用程式開發人員在使用 Windows CE 3.0 的平台上向開放匯流排添加了新的裝置,OEM 將必須說服該 OEM 將 ISR 添加到該平台。

要將 ISR 安裝到平台中,需要完成兩個步驟:

調用 LoadIntChainHandler 函數以載入包含 ISR 代碼的 DLL。

必須將 ISR 編碼為用 SYSINTR_ . . . 響應進行響應,就像在 OAL ISR 中一樣。

LoadIntChainHandler 函數將 ISR 動態連結程式庫 (DLL) 載入到核心的地址空間中。這意味著代碼不能調用任何非核心功能,包括任何 C 語言執行階段程式庫函數。記住,某些結構到結構賦值會降格為 memcpy 調用,必須檢查所有代碼以確保不需要任何外部庫(即使這些庫是由編譯器建立的)。

下面的原始碼樣本說明了一個用於建立可安裝的 ISR 的基本外殼程式。有四個函數:

DLLEntry — 接收進程和線程附加訊息

InfoCopy — 在進行任何結構賦值時使用的複製常式

IOControl — 任何使用 KernelLibIOControl 的 IST 調用的處理常式

ISRHandler — 實際的 ISR

BOOL __stdcall  DllEntry(   HINSTANCE hinstDll,        DWORD dwReason,        LPVOID lpReserved ){     if (dwReason == DLL_PROCESS_ATTACH) {}     if (dwReason == DLL_PROCESS_DETACH) {}     return TRUE;}// The compiler generates a call to memcpy() for assignments of large   objects.// Since this library is not linked to the CRT, define our own copy   routine.void  InfoCopy( PVOID  dst, PVOID  src, DWORD size  ){    while (size--) {*((PBYTE)dst)++ = *((PBYTE)src)++;}}BOOL IOControl(     DWORD   InstanceIndex,         DWORD   IoControlCode,           LPVOID  pInBuf,           DWORD   InBufSize,         LPVOID  pOutBuf,           DWORD   OutBufSize,           LPDWORD pBytesReturned ) {switch (IoControlCode) {    case IOCTL_DEMO_DRIVER:              // Your I/O Code Here            return TRUE;            break;    default:            // Invalid IOCTL            return FALSE;}    return TRUE;}DWORD   ISRHandler(  DWORD InstanceIndex  ){  BYTE  Value;Value = READ_PORT_UCHAR((PUCHAR)IntrAddress );// If interrupt bit set, return corresponding SYSINTRif ( Value & 0x01 ){  return SYSINTR_DEMO;}else{  return SYSINTR_CHAIN;}}

ISR 處理常式代碼使用連接埠 I/O 調用來檢查裝置的狀態。您的方案可能要求複雜得多的詢問。如果該裝置不是中斷源,則傳回值將是 SYSINTR_CHAIN。此傳回值告訴 NKChainIntr 函數該裝置不是中斷源,應該評估鏈中的其他 ISR。如果 ISR 返回有效 SYSINTR,則 NKChainIntr 將立即返回並且不調用列表中的任何其他 ISR。這將提供優先順序排序。第一個載入的可安裝 ISR 被首先載入到該列表中(或具有最高優先順序),然後將後續可安裝 ISR 添加到該列表的底部。由於優先順序和執行速度這兩方面的原因,應該首先安裝鏈中具有最高優先順序的可安裝 ISR。

返回頁首

IST 中斷處理

處理來自應用程式或驅動程式的中斷需要進行兩個步驟的處理。首先,必須使用關聯的事件初始化中斷。其次,IST 必須等待中斷事件以響應核心中的中斷。

中斷初始化

以下範例程式碼將設定 IST 並將 IST 與特定的中斷相關聯。初始化中斷的關鍵步驟包括:

建立事件

擷取 IRO 的系統中斷號

建立掛起的中斷線程 (IST)

調用 InterruptInitialize 以建立 IRQ 與事件之間的關聯

建立未掛起的 IST 可能會導致 InterruptInitialize 失敗,因為該事件已經處於被等待狀態

將線程優先順序設定為相應的優先順序

恢複 IST

Void SetupInterrupt( void ){// Create an event//g_hevInterrupt = CreateEvent(NULL, FALSE, FALSE, NULL);if (g_hevInterrupt == NULL) {    RETAILMSG(1, (TEXT("DEMO: Event creation failed!!!\r\n")));    return;}// Have the OAL Translate the IRQ to a system irq//fRetVal    = KernelIoControl( IOCTL_HAL_TRANSLATE_IRQ,                 &dwIrq,                sizeof( dwIrq ),                &g_dwSysInt,                sizeof( g_dwSysInt ),                NULL );// Create a thread that waits for signaling//g_fRun  = TRUE;g_htIST      = CreateThread(NULL,  // Security          0,     // No Stack Size          ThreadIST,  // Interrupt Thread                NULL,    // No  Parameters          Create_SUSPENDED, // Create Suspended          &dwThreadID  // Thread Id          );// Set the thread priority – arbitrarily 5//m_nISTPriority = 5;if( !CeSetThreadPriority( g_htIST, m_nISTPriority )){    RETAILMSG(1,(TEXT("DEMO: Failed setting Thread Priority.\r\n")));    return;}// Initialize the interrupt//if ( !InterruptInitialize(g_dwSysInt,g_hevInterrupt,NULL,0) ) {    RETAILMSG (1, (TEXT("DEMO: InterruptInitialize failed!!!\r\n")));    return;}// Get the thread started//ResumeThread( g_htIST );}

需要注意的是,對 InterruptInitialize 的調用僅採用 SYSINTR 值和事件作為參數。核心不知道或者不關心將要等待該事件的線程。這樣,就可以建立多種應用程式和驅動程式體繫結構。應用程式的簡單主迴圈可以初始化中斷, 然後立即等待該事件。中斷只能與一個事件關聯,並且該事件不能用於對 WaitForMultipleObjects 的調用中。我們將觀察一個簡單的為中斷提供服務的線程。這是大多數實現中的標準解決方案。

IST - 插斷服務常式

本節提供了一個 IST 的範例程式碼。該 IST 中斷處理線程的關鍵組件包括:

等待中斷事件。

確認有一個來自 OS 的脈動性事件

執行任何必要的板級中斷處理以完成中斷。在該樣本中,我們將確認該中斷。

在儘可能短的時間內處理該中斷

建立 CELOGDATA 以供在 Kernel Tracker 中查看。

檢查並確認是否設定了 g_fPRRunning 標誌,然後設定 g_hevPRStart 事件。

調用 InterruptDone()。

在調用 InterruptDone 之前,OS 不會提供此 IRQ 上的其他中斷。

再次等待中斷事件。

DWORD  WINAPI  ThreadIST( LPVOID lpvParam ){  DWORD  dwStatus;  BOOL  fState = TRUE;  // Always chec the running flag  //  while( g_fRun )  {    dwStatus  = WaitForSingleObject(g_hevInterrupt, INFINITE);    // Check to see if we are finished    //    if(!g_fRun ) return 0;    // Make sure we have the object    //    if( dwStatus == WAIT_OBJECT_0 )    {      // Do all interrupt processing to complete the interaction      // with the board so we can receive another interrupt.      //      if (!( READ_REGISTER_ULONG(g_pBoard Register) & INTR_MASK))      {        RETAILMSG(1, (TEXT("DEMO: Interrupt...")));        g_dwInterruptCount ++;      }      // Finish the interrupt      //      InterruptDone( g_dwSysInt );    }  }  return 0;}

該樣本讀取一個 ULONG 寄存器以確定中斷狀態。您只需用您的代碼替換該程式碼片段。非常關鍵的一點是,要使 IST 處理儘可能地簡單。如果將來需要處理來自該裝置的資料:

在 IST 中儘可能快速地從該裝置擷取資料。

建立一個事件,以通知某個優先順序較低的線程完成該工作。

通過 InterruptDone 從該 IST 中立即返回。

讓優先順序較低的線程進一步處理資料。

在 IST 與優先順序較低的線程之間放置 FIFO 以處理溢出。

返回頁首

導致延遲的因素

從 Windows CE .NET 中的中斷體繫結構中,可以瞭解硬體、核心、OAL 與驅動程式/應用程式線程之間的互動。Microsoft 已經提供了多種工具(包括 ILTiming、CEBench 和 Kernel Tracker),以便協助您評定平台上的 Windows CE .NET 的效能。通過瞭解導致 ISR 和 IST 延遲的因素,有助於確定調查領域。

ISR 延遲

正如您在本文前面的中斷體繫結構中可以看到的,ISR 延遲被定義為從發生中斷到 OAL ISR 首次執行之間的時間。因為當中斷被關閉時,中斷不會在處理器中引發異常,所以第一個導致延遲的因素是系統中的中斷被關閉的總時間。在每個機器指令開始執行 時都將檢查是否有處理器中斷。如果調用了長字串移動指令,則會鎖定中斷,從而造成第二個延遲源,即匯流排訪問鎖定處理器的時間量。第三個因素是核心導向 OAL ISR 處理常式所花費的時間量。這是一個進程環境切換。總之,導致 ISR 延遲的因素包括:

中斷被關閉的時間。

匯流排指令鎖定處理器的時間。

核心 ISR 的執行時間加上導向 OAL ISR 的時間。

IST 延遲

本文前面的體繫結構中顯示,IST 延遲是從中斷髮生到執行 IST 中的第一行代碼之間的時間量。這與 Windows CE .NET 中的 Microsoft 度量工具的輸出不同。Microsoft 工具將 IST 延遲定義為從 OAL ISR 執行結束到 IST 開始之間的時間。因為標準的 ISR 花費的時間很少,您需要將 ISR 延遲和 Microsoft 度量工具所得到的 IST 延遲加起來,才能獲得“中斷體繫結構”中所定義的 IST 延遲。

導致 IST 延遲的第一個因素是本文前面定義的 ISR 延遲。第二個因素是 ISR 執行時間。根據共用中斷調用鏈的長度的不同,此時間是可變的。對於延遲較小的情況,沒有必要對永遠不會被共用的中斷調用 NKCallIntChain

Windows CE 中的核心功能(如排程器)被稱為 KCALL。在這些 KCALL 執行期間,將設定一個軟體標誌,以便讓排程器知道它此時不能被中斷。仍然將調用 ISR,但用於重新調度 OS 或調度 IST 的傳回值將被延遲,直至 KCALL 完成為止。這一不可佔先的時間是導致 IST 延遲的第三個因素。最後,核心必須調度 IST。這一環境切換是導致延遲的最後一個因素。總之,導致 IST 延遲的因素包括:

ISR 延遲時間

OAL ISR 執行時間

OS 執行 KCALL 的時間

調度 IST 的時間

返回頁首

小結

通過 Windows CE .NET,Microsoft 已經升級了 Windows CE 中斷體繫結構。該 OS 所具有的處理共用中斷的能力極大地擴充了 Windows CE .NET 支援許多中斷體繫結構的能力。這一中斷體繫結構方面的知識可以大大加快調查驅動程式和延遲問題的速度。作業系統互動模型是瞭解該體繫結構的關鍵。共用中斷 已經大大提高了 Windows CE .NET 的開放性,能夠支援遍佈於不同公司之間以及公司內部的平台供應商和應用程式開發人員方案。瞭解延遲根源將有助於診斷驅動程式和即時問題。Windows CE .NET 中的中斷結構定義完善且易於理解。簡而言之,“它不是魔術!”

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.