x58添加uefi_在看UEFI CODE
efi code里面有關于init 8259的code,也就是legacy8259protocol的實作
對8259的編程,我們是對其相應端口發送ICW(初始化命令字)來完成的,
總共需要發送4個ICW,而且必須按次序發送,這里提一下8259a編程的一些東西,2片8259a級連,一個為主片,一個為從片,從片的INT端口與主片的IRQ2相連,主片的訪問端口為0x20和0x21,從片為0xa和0xa1
在legacy bios中IRQ0-IRQ7被分配了0x8-0xf的中斷矢量(中斷號),
IRQ-8-IRQF
被分配為0x70-0x78,這也可以看做是實模式下是這樣來分的,但當cpu轉到保護模式的時候,中斷號0x8-0xf都被cpu用來處理錯誤了,所以我們必須從新對8259進行編程,設置中斷號的起始地址,
EFI_LEGACY_8259_PROTOCOL 中的SetVectorBase就是干這種事情的,
從字面的意思也可以看出來,“設置中斷矢量的基地址”
在EFI BIOS中我們將master interrupt base 設置為0x58,slave interr
base設置為0x70,linux中我們是將master interrupt base設置0xf0,slave設置為0xf8
設置這些base address的時候,我們就要對8259進行編程,也就是要發四個ICW了
EFI_STATUS SetVectorBase(
IN
EFI_LEGACY_8259_PROTOCOL?*This,
IN UINT8
MasterBase,
IN UINT8
SlaveBase
)
{
//8259 Master
if (MasterBase != gMasterBase)
{
IoWrite8(0x20,ICW1);?//Start
8259 Master Initialization.
IoWrite8(0x21,MasterBase);?//Set
Interrupt Offset
IoWrite8(0x21,ICW3_M);?//Set
Slave IRQ.
IoWrite8(0x21,ICW4);?//Set
8259 mode. See ICW4 comments with #define.
gMasterBase = MasterBase;
}
//8259 Slave
if (SlaveBase != gSlaveBase)
{
IoWrite8(0xa0,ICW1);?//Start
8259 Slave?Initialization.
IoWrite8(0xa1,SlaveBase);?//Set
Interrupt Offset
IoWrite8(0xa1,ICW3_S);?//Set
Slave IRQ.
IoWrite8(0xa1,ICW4);?//Set
8259 mode. See ICW4 comments with #define.
gSlaveBase = SlaveBase;
}
return EFI_SUCCESS;
}
ICW1:發送到0x20(主片)及0xa0(從片)端口
7 6 5 4 3 2 1 0
0 0 0 1 M 0 C I
I 位:若置位,表示ICW4 會被發送。(ICW4 等下解釋)
C 位:若清零,表示工作在級聯環境下。
M 位:指出中斷請求的電平觸發模式,在PC 機中,它應當被置零,表示采用“邊沿觸發模
式”。
ICW2:發送到0x21(主片)及0xa1(從片)端口
7 6 5 4 3 2 1 0
A7 A6 A5 A4 A3 0 0 0
ICW2 用來指示出IRQ0 使用的中斷號是什么,因為最后三位均是零,因此要求IRQ0 的中
斷號必須是8,的倍數,這又是一個很巧妙的設計。因為IRQ1 的中斷號就是IRQ0 的中斷
號+1,IRQ2 的中斷號就是IRQ0 的中斷號+2,……,IRQ7 的中斷號就是IRQ0 的中斷號+1,
剛好填滿一個8 個的中斷向量號空間。
ICW3:發送到0x21(主片)及0xa1(從片)端口
ICW3 只有在級聯工作的時候才會被發送,它主要用來建立兩處PIC 之間的連接,對于主片
與從片,它結構是不一樣的。
(主片結構:)
7 6 5 4 3 2 1 0
IRQ7 IRQ6 IRQ5 IRQ4 IRQ3 IRQ2 IRQ1 IRQ0
上面,如果相應的位被置1,則相應的IRQ 線就被用于與從片連接,若清零則表示被連接到
外圍設備。
(從片結構:)
7 6 5 4 3 2 1 0
0 0 0 0 0 IRQ
IRQ 位指出了是主片的哪一個IRQ 連到了從片,這需要同主片上發送的上面的主片結構字
一致。
ICW4:發送到0x21(主片)及0xa1(從片)端口
7 6 5 4 3 2 1 0
0 0 0 0 0 0 EOI 80x86
80x86 位:若置位表示工作在80x86 架構下。
EOI 位:若置位表示自動結束,在PC 上這位需要被清零。
在EFI BIOS code中的定義為
#define
ICW1?0x11
#define
ICW3_M?1<<2
#define
ICW3_S?2
#define
ICW4?1
與上面的說明是一致的
EFI_LEGACY_8259_PROTOCOL中SetMode這個function,是設置現在的8259處于實模式還是處于保護模式下,要中斷屏蔽那些IRQ,中斷觸發的方式是什么樣的(邊沿還是水平)
其中這個會用到2個全局變量
UINT16?gIrqMask[2]?=
{0xffff,0xffff};?UINT16?gIrqTrigger[2]?=
{0,0};?一個是控制中斷屏蔽regisgter的,一個是控制中斷觸發的方式,數組為2,一個用于real
mode,一個用于protect mode
看一下setmode的函數實作
EFI_STATUS SetMode(
IN
EFI_LEGACY_8259_PROTOCOL?*This,
IN
EFI_8259_MODE?Mode,
IN UINT16
*Mask
OPTIONAL,
IN
UINT16?*EdgeLevel?OPTIONAL
)
{
if (Mode >= Efi8259MaxMode) return
EFI_INVALID_PARAMETER;
gMode = Mode;
if (Mask) gIrqMask[Mode] = *Mask;
if (EdgeLevel) gIrqTrigger[Mode] =
*EdgeLevel;
ProgramIrqMaskTrigger();
return EFI_SUCCESS;
}
可以猜想?ProgramIrqMaskTrigger()就是操作8259
register的函數
VOID ProgramIrqMaskTrigger()
{
IoWrite8(0x21,(UINT8)gIrqMask[gMode]);
IoWrite8(0xa1,(UINT8)(gIrqMask[gMode]>>8));
//
// 4d0 can not be accessed as by IoWrite16, we
have to split
//
IoWrite8(0x4d0,(UINT8)gIrqTrigger[gMode]);
IoWrite8(0x4d1,(UINT8)(gIrqTrigger[gMode]>>8));
}
其中
IoWrite8(0x21,(UINT8)gIrqMask[gMode]);
IoWrite8(0xa1,(UINT8)(gIrqMask[gMode]>>8));
為操作8259a OCW命令register
OCW1:中斷屏蔽,發送到0x21(主片)或0xa1(從片)端口
7 6 5 4 3 2 1 0
IRQ7 IRQ6 IRQ5 IRQ4 IRQ3 IRQ2 IRQ1 IRQ0
如果相應的位置1,則表示屏蔽相應的IRQ 請求。
EFI_LEGACY_8259_PROTOCOL中GetMask和SetMask,也是操作mask和trigger的,原理和以上相同
GetVector字面意思,得到中斷號,也就是上面說的我們設置IRQ0對應的中斷號為0x58,我們現在要得到這個0x58,就靠這個函數了,無非就是倒過來運算而已
Master的IRQ對應得中斷好號為IRQ+masterbase
Slave上的IRQ為IRQ+slavebase-8 而已
EnableIRQ() DisableIRQ()這些函數的都是操作OCW1
GetInterruptLine()為讀配置空間,得到IRQ編號
EndOfInterrupt()在中斷處理函數里面發送EOI命令
如果 EOI 被設為自動的,那么ISR 中的位總是被清零的(在EOI 被置位的情況下,8259A
只要向CPU 發送了中斷號就會將ISR 中的相應位清零),也就是如果有中斷來,芯片就會馬
上再向CPU 發出中斷請求,即使CPU 正在處理IRQ0 的中斷,CPU 并不知道誰的優先級高,
它只會簡單的響應8259A 送來的中斷,因此,這種情況下低優先級的中斷就可能會中斷高
優先級的中斷服務程序。所以在PC 中,我們總是將EOI 位清零,而在中斷服務程序結束的
時候才發送EOI 消息。
注意一點,發EOI命令的時候,先發送給從片,再發送給主片
總結
以上是生活随笔為你收集整理的x58添加uefi_在看UEFI CODE的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 网易云课堂学习-TCP/UDP协议
- 下一篇: webupload 上传插件 完美版 -