匯編學習筆記(26) - APIC


Local APIC

Local APIC 是在CPU內部的,每個邏輯處理核心都配有一的對應的local APIC。
Local APIC 能產生、發送和接受中斷,CPU之間的通訊IPI也是通過Local APIC來實現的。
Local APIC 使用一組寄存器來控制,之前的APIC 是將寄存器映射到內存來使用,新的x2APIC模式則是將寄存器映射到MSR空間中了,適應RDMSR和WRMSR指令進行讀寫了。
Local APIC 有地址編號,這個編號同時也是CPU核心的編號。
在 xAPIC 模式下,APIC寄存器是映射到一塊連續的4K內存中的,由 IA32_APIC_BASE (0x1B)這個MSR寄存器提供控制。
在x2APIC模式下,所有寄存器全被映射到了MSR空間中,地址從802H 到 83FH。

IA32_APIC_BASE提供了一些基本的控制

 

 

 


第8位: 是否是主核心BSP標志位
第10位:是否啟用x2APIC模式
第11位:APIC的global啟用,雖然是global但是只是正對本核心
第12開始:是xAPIC模式的時候的APIC_BASE的地址,具體是幾位取決於地址線的寬度,這是物理地址

APIC寄存器參考x86/x64體系探索及編程 page. 606
以下介紹幾個重要的寄存器

APIC ID寄存器(APIC_BASE+ 20H)
  APIC 是根據 Cluster、Package、Core、SMT(邏輯運算單元)多級來組織的,每一級占一定的位數,所以實際上每個邏輯運算單元的編號就不連續了
  xAPIC 中是沒有Cluster這個層級的並且APIC ID只有8位有效,是數據的最高8位,而x2APIC則是32位都有效的。CLuster應該是對應的多CPU多主板
  具體是幾級,每一級別的位寬都需要通過CPUID指令來獲取。

  

 

 

 

APIC 版本寄存器(APIC_BASE+30H)

 

  version:指示Local APIC使用外部8249DX芯片還是內部APIC
  Max LVT Entry: 則是LVT寄存器的數量,這個值需要+1才是真實數量
  24位:SVR寄存器的Bit12位是否支持(bit12 被置位將抑制EOI命令被發送到IO APIC)

LVT Entry寄存器組
  一般是7個LVT 寄存器,用於對7種中斷的配置,根據不同的中斷有不同位的解釋也不太同,但是他們都提供了一個中斷向量值用於指示當本中斷對應的IDT中斷向量。
  

  Timer mode: 值用於Timer 用於設置時間計數的模式
    00: 一次性計數
    01: 周期計數
    10: tsc指定計數

  mask: 屏蔽位,當置位的時候屏蔽本中斷

  Trigger mode:僅用於LINT0和LINT1寄存器,設置他們的觸發模式
    0: edge觸發
    1: level觸發

  Remote IRR flag: 僅用於LINT0和LINT1寄存器,只有在delivery mode = fixed 並且 Trigger mode = level時有效
    1: 表示Local APIC 已經接受並處理 本中斷
    0: 表示接受到EOI命令

  Interrupt input pin polary: 僅用於LINT0和LINT1寄存器,設置Trigger mode = level時到觸發條件
    0: high-level,低電平轉高電平觸發
    1: low-level,高電平轉低電平觸發

  Delivery status:指定交付的狀態
    0: IDLE 當前沒有待提交給CPU的終端,可能是沒中中斷,也可能是中斷已經提交給CPU,CPU還在處理。
    1: Send Pending 當前有中斷要需要提交給CPU

  Delivery mode:配置中斷的交付模式
    000: Fixed,允許vector里提供自定義的vector值
    010: SMI,vector的值必須為0
    100: NMI,vector被忽略,強制認為值是 2
    111: ExtInt,使用外部中斷器發送過來的vector值
    101: INIT,vectort的值必須是0

  vector: 指定本中斷的在IDT的中斷向量,如果不是交付模式配置,則0-15是無效內容

ICR(APIC_LOCA + 300H / 310H)
  因為ICR寄存器是64位的,所以分為高低兩部分占兩個地址。
  這個寄存器是用來發送核心間通訊指令 IPI的
  

 

 

 

  Destination Field: 配合 Destination ShortHand 來指定發送的目標

  Destination ShortHand:
    00: No ShortHand,用戶指定發送的目標
    01: Self ,發送給自己
    10: All Includeing Self, 發送給所有核心包括自己
    11: All Exclude Self,發送給出了自己以外的所有核心

  Trigger Mode: 同LVT的解釋,設置他們的觸發模式
    0: Edge
    1: Level

  Level:
    0: De-assert
    1: Assert

  Delivery Status: 同LVT的解釋,指定交付的狀態
    0: IDLE,當前沒有待提交給CPU的終端,可能是沒中中斷,也可能是中斷已經提交給CPU,CPU還在處理。
    1: end Pending, 當前有中斷要需要提交給CPU

  Destination Mode: 當使用 No ShortHand 的時候,指示如何解釋 Destination Field 指定的目標
    0: Physical, 物理ID,就是APIC ID
    1: Logincal,邏輯ID,這個邏輯ID可以在LDR和DFR寄存器中由軟件指定

  Delivery Mode: 配置中斷的交付模式
    000: Fixed,允許vector使用自定義的值
    001: Lowest Priority,目標核心運行中斷的時候將運行在較低的特權級,允許vector使用自定義的值
    010: SMI, vector的值必須為0
    011: Reserved
    100: NMI NMI,vector被忽略,強制認為值是 2
    101: INIT,初始化核心,初始化完的核心將運行在實模式
    110: Start up,啟動核心(SPIPI),當處理完INIT中斷之后,核心處於Wait-For-SIPI狀態,使用這個模式將指示核心從 Vector * 100H的物理內存地址執行Start-up代碼,進行核心的啟動。
    111: Reserved

  Vector: 指定目標核心接收到本IPI中斷的時候執行IDT中的哪個中斷,當IPI是SIPI即 Delivery Mode = Start up 的時候 Vector指定的是要執行的代碼的物理地址,實際地址需要vector * 100H(這是由於在Start up執行之前,核心剛初始化完成,還是實模式,並沒有IDT,所以直接執行指定位置的代碼),如果不是交付模式配置,則0-15是無效內容

優先級
  優先級是根據vector的大小來決定的,vector的越大優先級越高,同時vector被分為2級,前四位制定優先級的成為中斷優先等級,在同一等級之下在根據后四位的值來確定優先級。
  同時還又一個TPR寄存器用來屏蔽中斷,之后vector大於這個值的中斷才能被相應,當然實際能不能相應還要看ISR寄存器也就是當前正在相應的中斷的等級。
  在64位模式下CR8 = TPR寄存器,寫CR8寄存器會將值同步到TPR寄存器中

  IPI的工作機制
    IPI 是核心之間的通訊機制,也是采用中斷的形式的
    1. 首先使用通過 Destination ShortHand 來指定確定目標的方式,除了No ShortHand以外,目標都是固定的
    2. 如果采用了 No ShortHand 模式,則是要使用Destination Field的值確定目標核心
    3. 然后根據 Destination Mode 來解釋 Destination Field的值
      Physical: 說明Field的值就是 APIC ID
      Logincal:Destinal Field 就是一個MASK值
        在LDR寄存器的23-31位可以給這個核心定義個邏輯ID,當使用Logical模式的時候 就用Destianal Field中的MASK和LDR中的邏輯ID進行匹配,如果匹配成功就表明這是核心是目標核心
        匹配的規則則由DFR寄存器的 28-31位給出
        1111B: 與匹配,MASK和LDR進行AND匹配,結果為TRUE表示匹配,這表示可以多匹配
        0000B:等於匹配:MASK = ID 匹配

  多核心的初始化工作
    當CPU啟動的時候會優先執行CPU內部的代碼,他的主要作用是枚舉出所有的核心並給這些核心分配APIC ID號,同時會推舉一個核心作為主核心成為BSP,並將BSP核心的IA32_APIC_BASE寄存器的第八位置1 ,其余核心稱為AP,並清理AP處理器IA32_APIC_BASE的第8位,然后與BSP處理器開始執行BIOS的代碼。
    當我們結果BSP處理的控制權以后,一般要執行以下步驟
    1. 初始化BSP寄存器使其進入保護模式
    2. 通過ICR寄存器 發送 Delivery Mod = INIT,Destination ShortHand = 11(All Exclude Self) 的INIT廣播指令
    3. 延遲至少10MS 后 發送兩次 Delivery Mod = Start Up,Destination ShortHand = 11(All Exclude Self)(SIPI)指令,這兩個指令要間隔10US發送,內容是一樣的,其中vector 需要指定在一個用於AP初始化時運行的代碼地址,這段代碼需要在BSP初始化的時候就配置好
    4. 接下來就是AP之行初始化代碼,AP初始化的主要工作就是也將之際進入保護模式,這里有兩種策略,可以所有核心共用頁表,IDT,GDT等,這樣AP的初始化就是簡單的給個寄存器賦值,當然也可以各核心設置各自的數據,這樣就要求各AP進行完整的初始化,
      注意: 由於消息時廣播的,所以核心的執行順序是不一定,這里要處理號數據的同步問題,可以使用帶LOCK的匯編之行來進行同步操作
    5. BSP等待所有AP初始化完成之后CPU的初始化就完成了。

  中斷的處理
    APIC的LVT寄存器能產生中斷,其中LVT LINT0 能接受8259控制器的中斷請求,而LVT LINT1能接受NMI中斷請求。
    所以中斷有本地中斷和來自system bus上的中斷兩種。根據這兩種來源的不同有不同的處理流程
    

  Fixed 模式下的流程:

    IRR,ISR,TMR(tigger Mode Register) 都是255位了,所以可以記錄所有255個中斷的狀態
    1. 當中斷發生的時候會設置IRR寄存器的相應位
    2. 判斷MASK屏蔽位
    3. 判斷優先級
    4. 清理IRR位置ISR位提交CPU運行
    5. 發送EOI清理ISR相應位。

  其他模式流程
    其他模式是不判斷優先級也不設置IRR和ISR寄存器的,也不用發送EOI命令
    本地:判斷MSAK標志
    SYSTEM BUS:啥都不判斷直接執行
  注意:他們都能被標志寄存器的IF標志位屏蔽


  LVT TIME / LVT ERROR page.663


  LVT LINT0 / LINT1
    這兩個寄存器連接了8259和NMI口,實際上是只鏈接了BSP芯片,所以只有BSP芯片才能收到這兩個中斷。
    觸發模式只有在使用fixed模式時能設置0:edge 1:level,其余模式默認使用edge模式觸發。
    Remote IRR 也只有Fixed模式並且觸發模式時:level時可用,用來指示 中斷服務是否運行中,ISR時是否提交。
    一般lint0 使用 ExtINT模式。LINT1使用NMI模式。

I/O APIC

  8259已經不適合多核的處理器了,所以I/O APIC 取代了8259,I/O APIC能發送指定的中斷到指定的核心上(通過核心的LOCAL APIC)。

  直接訪問的寄存器
    寄存器映射到了內存地址空間上
    訪問方式通過向index寄存器寫入要訪問的地址,然后通過data寄存器獲取值,和IO端口的操作差不多
    

    其中的xx是可變的地址,這個xx記錄在OIC寄存器中
    

    OIC寄存器的地址又位於RCBA寄存器的31FEh位置,而RCBA(root complex base address)寄存器又位於PCI BUS的device 31 設備的0f0偏移處。(關於PCI設備看 下一章節)

  間接訪問的寄存器
    間接訪問的寄存器就是通過上面直接訪問的寄存器的 index 和 data訪問的寄存器,一共三組
    

    1. ID寄存器,用於唯一標識一個IO APIC,IO APIC可以存在多個?,有一張叫MADT的配置表,這里面有詳細的關系IO APIC的信息,包括多少個IO APIC和對應的直接訪問寄存器的地址,參見文末的文獻

    

    2. version寄存器,主要確定了硬件的連接方式

    

 

 

    3. 24個 中斷轉發寄存器,interrupt redirection table 寄存器
    

    他是local APIC中的LVT和ICR寄存器的結合,他首先和LVT寄存器一樣配置了一些中斷觸發時的配置信息,然后每個中斷轉發寄存器都和一條IRQ線相連,當對應的IRQ線觸發中斷的時候,就會向ICR寄存器一樣,將對應的信息發送到對應的核心處,其中IRQ0 是連接着8259芯片的,所以irq0可以使用ExtInt模式,直接使用8259提交的Vector。


  中斷過程
    IO APIC對中斷的仲裁 是有Local APIC來完成的,IO APIC將中斷提交到Local APIC后他的工作就結束了。所以IO APIC的捉妖責任就是當IRQ先觸發中斷,IO APIC根據對應的interrupt redirection table 的配置向指定的LOCAL APIC提交中斷,之后就全是LOCAL APIC的工作了。


其他文獻
https://wiki.osdev.org/IOAPIC
https://wiki.osdev.org/MADT
https://blog.csdn.net/gaojy19881225/article/details/80018761
http://blog.chinaunix.net/uid-20499746-id-786.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM