上个博客里面说明了SIO的Read和Write,但是没有说清楚SIO的定义;
SIO其实相当于一个弱化版本的EC,属于半定制化的FW,很多程序,例如时序还有一些功能都是在FW中已经固化好的,可以被我们所定制的东西就是逻辑设备里面的寄存器,在开机的时候,先运行SIO已经固化好的时序,时序运行完后进入S0状态,才能开始加载BIOS配置的;
SIO的功能框图为:
SIO下面挂载有很多的逻辑设备,可以理解为上面功能框图里的功能,读到的Space即功能用到的一些寄存器Value;
每一个逻辑设备都有256个byte可以进行配置,但是从0x00 ~ 0x2F的寄存器值为通用的全局寄存器,这部分寄存器是所有设备共享,所以实际上每个逻辑设备可以进行配置的寄存器仅仅为0x30 ~ 0xFF,即208个;
根据Spec里面的说明,访问逻辑设备需要在全局寄存器的0x07内写值;
即:
UINTN ReadSIODevice(UINT8 DeviceID,UINT8 offest)
{
WriteSIO(DeviceID,offest); //Read/Write SIO 为封装好的函数,具体实现在上一篇
return ReadSIO(offest);
}
Spec显示,当前的逻辑设备一共有16个;
这个时候可以尝试读写逻辑设备的寄存器;
即:
void WriteSIODevice(UINT8 DeviceID,UINT8 offset,UINT8 Data)
{
WriteSIO(0x07,DeviceID);
WriteSIO(offset,Data);
}
读取SIODevice的256个Byte;
即:
void ReadSIODeviceAllByte(CHAR16 **Argv)
{
UINT8 Step = 1;
UINT8 Count = 0;
UINT8 LDN = 0;
if (Argv[1][3])
{
LDN = (UINT8)(((Argv[1][2] - 0x30) << 4) + (Argv[1][3] - 0x30));
}
else
{
LDN = (UINT8)(Argv[1][2] - 0x30);
}
Print(L" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n00");
while(1)
{
ExpansionMode(SIO_Entry_EM);
if (Count < 0x100)
{
Print(L" %02x",ReadSIODevice(LDN,Count));
Count++;
if (Count%16 == 0)
{
if (Step < 0x10)
{
Print(L"\n%02x",Step);
Step++;
}
else
{
Step = 1;
break;
}
}
}
ExpansionMode(SIO_Break_EM);
}
}
另外,SIO除了LDN的逻辑设备以外,还存在一个空间,叫做Bank0,Fan寄存器就是存储在Bank0空间的;
从Spec中可以得知,想访问Bank0的寄存器,需要去获取逻辑设备B 0ffset 60H/61H的值,然后访问该地址;
即:
#define Bank_Index (UINT16)((ReadSIODevice(0x0B,0x60) << 8) + (ReadSIODevice(0x0B,0x61) + 5))
#define Bank_Data (UINT16)((ReadSIODevice(0x0B,0x60) << 8) + (ReadSIODevice(0x0B,0x61) + 6))
void WriteSIOBank(UINT8 offset,UINT8 Data)
{
IoWrite8(Bank_Index,offset);
IoWrite8(Bank_Data,Data);
}
UINTN ReadSIOBank(UINT8 offset)
{
IoWrite8(Bank_Index,offset);
return IoRead8(Bank_Data);
}
从spec可以得知,当offset = 0x4E时,可以去指定访问的bank;
即:
void SelectsBank(UINT8 Data)
{
WriteSIOBank(0x4E,Data);
}
我们尝试访问一下Fan空间的地址,可以从spec中得到SYSFANIN Target Speed_L是在Bank4的C1H,SYSFANIN Target Speed_H是在Bank1的C0H;
尝试读取一下Fan Speed;
即:
UINTN ReadSYSFanSpeed()
{
SelectsBank(0x04);
return (UINT16)(ReadSIOBank(0xC0) << 8) + ReadSIOBank(0xC1);
}
至此,访问SIO的基础操作已经全部完成了,将这些基础操作巧妙组合,就能得到一个非常好用的efi APP;
我的APP还没有完成,code先暂时不放,之后有什么想加入的功能或者奇思妙想再发新的博客;