EC与SIO都可以通过4E/4F 2E/2F去访问特定的地址空间;
EC被访问的地址空间一般是0x400,默认是通过4E/4F访问;SIO默认是通过2E/2F访问,这个访问的通道在EC/SIO里面可以通过更改寄存器来更改;
图为SIO更改访问通道的寄存器:
既然知道了访问地址空间的通道是什么,接下来看Spec,查看通过通道访问的规范;
图中说明了寄存器的访问方式,需要先向2E写入,再从2F读取;
即:
//假设读的寄存器offset为0x01
IoWrite8(0x2E,0x01);
SIORead = IoRead8(0x2F);
因为0x2E/0x2F这两个通道地址我们需要经常用到,且有概率变更为4E/4F,所以可以定义一个宏定义,方便后续更改;
即:
#define SIO_Index 0x2E
#define SIO_Data 0x2F
IoWrite8(SIO_Index,0x01);
SIORead = IoRead8(SIO_Data);
Spec中又提到,需要往写IO地址中写入两次0x87,进入扩展模式后,才能对数据进行更新;
退出扩展模式,需要往IO地址中写入0xAA;
即:
#define SIO_Index 0x2E
#define SIO_Data 0x2F
IoWrite8(SIO_Index,0x87);
IoWrite8(SIO_Index,0x87);
IoWrite8(SIO_Index,0x01);
SIORead = IoRead8(SIO_Data);
IoWrite8(SIO_Index,0xAA);
访问SIO的方式已经知道了,接下来实际操作一下,用以上的code去访问并Print出SIO address的value;
我的code为:
//.inf
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = SIO
FILE_GUID = dd6c3ae0-296d-47d4-a491-d3c5b457059c
MODULE_TYPE = UEFI_APPLICATION
VERSION_STRING = 1.0
ENTRY_POINT = UefiMain
[Sources]
SIO.c
[Packages]
MdePkg/MdePkg.dec
[LibraryClasses]
UefiApplicationEntryPoint
UefiLib
IoLib
//.h
#ifndef __SIO_H__
#define __SIO_H__
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/IoLib.h>
extern UINTN ReadSIO(UINT8 offset);
extern UINTN ExpansionMode(UINT8 EMValue);
#endif //SIO_H
//.c
#include "SIO.h"
#include "SIO.h"
#define SIO_Index 0x2E
#define SIO_Data 0x2F
#define SIO_Entry_EM 0x01
#define SIO_Break_EM 0x00
EFI_STATUS
EFIAPI UefiMain (IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
{
UINT8 SIO_ID_H;
UINT8 SIO_ID_L;
ExpansionMode(SIO_Entry_EM);
SIO_ID_H = (UINT8)ReadSIO(0x20);
SIO_ID_L = (UINT8)ReadSIO(0x21);
ExpansionMode(SIO_Break_EM);
Print(L"%x%x",SIO_ID_H,SIO_ID_L);
return TRUE;
}
UINTN ReadSIO(UINT8 offset)
{
IoWrite8(SIO_Index,offset);
return IoRead8(SIO_Data);
}
UINTN ExpansionMode(UINT8 EMValue)
{
if (EMValue == SIO_Entry_EM)
{
IoWrite8(SIO_Index,0x87);
IoWrite8(SIO_Index,0x87);
}
else if (EMValue == SIO_Break_EM)
{
IoWrite8(SIO_Index,0xAA);
}
else
{
//return FALSE;
}
return TRUE;
}
code内读取的是EC Chip ID;
写SIO就直接调用IOWrite8,往Index里面写就行了,相对于读来说比较简单;
示例:
void WriteSIO(UINT8 offest,UINT8 value)
{
IoWrite8(SIO_Index,offest);
IoWrite8(SIO_Data,value);
}
下一篇继续说一下SIO的Read与Write中关于device和CONFIGURATION REGISTER的东西;