UEFI学习(四)-- SIO的Read与Write(2)

上个博客里面说明了SIO的Read和Write,但是没有说清楚SIO的定义;

SIO其实相当于一个弱化版本的EC,属于半定制化的FW,很多程序,例如时序还有一些功能都是在FW中已经固化好的,可以被我们所定制的东西就是逻辑设备里面的寄存器,在开机的时候,先运行SIO已经固化好的时序,时序运行完后进入S0状态,才能开始加载BIOS配置的;

SIO的功能框图为:
SIO Block Diagram

SIO下面挂载有很多的逻辑设备,可以理解为上面功能框图里的功能,读到的Space即功能用到的一些寄存器Value;

每一个逻辑设备都有256个byte可以进行配置,但是从0x00 ~ 0x2F的寄存器值为通用的全局寄存器,这部分寄存器是所有设备共享,所以实际上每个逻辑设备可以进行配置的寄存器仅仅为0x30 ~ 0xFF,即208个;

根据Spec里面的说明,访问逻辑设备需要在全局寄存器的0x07内写值;
SIO Default Value of Global Control RegisterLogical Device Selection
即:

UINTN ReadSIODevice(UINT8 DeviceID,UINT8 offest)
{
    WriteSIO(DeviceID,offest);  //Read/Write SIO 为封装好的函数,具体实现在上一篇
    return ReadSIO(offest);
}

Spec显示,当前的逻辑设备一共有16个;
CONFIGURATION REGISTER
这个时候可以尝试读写逻辑设备的寄存器;
即:


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的值,然后访问该地址;
HARDWARE MONITOR REGISTER SET
即:

#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;
Bank Select Register
即:

void SelectsBank(UINT8 Data)
{
    WriteSIOBank(0x4E,Data);
}

我们尝试访问一下Fan空间的地址,可以从spec中得到SYSFANIN Target Speed_L是在Bank4的C1H,SYSFANIN Target Speed_H是在Bank1的C0H;
SYSFAN Target Speed_LSYSFAN Target Speed_H

尝试读取一下Fan Speed;
即:

UINTN ReadSYSFanSpeed()
{
    SelectsBank(0x04);

    return (UINT16)(ReadSIOBank(0xC0) << 8) + ReadSIOBank(0xC1);
}

至此,访问SIO的基础操作已经全部完成了,将这些基础操作巧妙组合,就能得到一个非常好用的efi APP;

我的APP还没有完成,code先暂时不放,之后有什么想加入的功能或者奇思妙想再发新的博客;

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值