UEFI下的FlashOperationProtocol的实现

UEFI下的FlashOperationProtocol的实现

这个驱动其实就是读写flash所需要的最底层的驱动,其操作的就是最底层的flash的芯片,flash芯片有好多中,我们这里采用的是spi协议的。每种芯片的读写函数可能不太一样,但是都是大体相同的。下面是几种flash的介绍,大家知道自己的芯片使用的是哪种就好。

几种flash芯片的介绍

1、IIC EEPROM------容量小,采用的是IIC通信协议;用于在掉电时,存系统配置参数,比如屏幕亮度等。常用芯片型号有 AT24C02、FM24C02、CAT24C02等,其常见的封装多为DIP8,SOP8,TSSOP8等;
2、SPI NorFlash------容量略大,采用的是SPI 通信协议;用于存放程序和数据。程序和数据可存放在同一芯片上,拥有独立的数据总线和地址总线,能快速随机读取,允许系统直接从Flash中读取代码执行;可以单字节或单字编程,但不能单字节擦除,必须以Sector为单位或对整片执行擦除操作。常见到的S25FL128,MX25L1605、W25Q64等型号都是SPI NorFlash。
3、SPI NandFlash------采用了SPI NorFlash一样的SPI的通信协议,用于存储数据;在读写的速度上没什么区别,但在存储结构上却采用了与Parallel NandFlash相同的结构,所以SPI nand相对于SPI norFlash具有擦写的次数多,擦写速度快的优势。
4、eMMC Flash------eMMC采用统一的MMC标准接口,eMMC相当于NandFlash+主控IC;自身集成MMC Controller,存储单元与NandFlash相同。常见到的KLMAG8DEDD、THGBMAG8B4JBAIM、EMMC04G-S100等型号都是eMMC Flash。
5、SD卡------它在MMC的基础上发展而来,有两个可选的通信协议:SD模式和SPI模式。
我们办卡上使用的是第二种,现在这种使用居多,即便宜又好用。

驱动的入口函数

下面的代码就是这个驱动的入口函数

EFI_STATUS
FlashServiceInit(
  IN EFI_HANDLE         ImageHandle,
  IN EFI_SYSTEM_TABLE   *SystemTable
  )
{
  EFI_STATUS                      Status;
  FLASH_DEVICE_OPERATION_PROTOCOL *SpiFlashServiceProtocol;

  SpiFlashServiceProtocol = NULL;
  Status = gBS->AllocatePool(EfiRuntimeServicesCode,sizeof (FLASH_DEVICE_OPERATION_PROTOCOL),(VOID **) &SpiFlashServiceProtocol);
  if (EFI_ERROR (Status)){
    return Status;
  }

  SpiFlashServiceProtocol->GetInfo = SpiGetInfo;
  SpiFlashServiceProtocol->Read    = SpiRead;
  SpiFlashServiceProtocol->Write   = SpiWrite;
  SpiFlashServiceProtocol->Erase   = SpiErase;

  Status = gBS->InstallMultipleProtocolInterfaces(
                  &mFlashHandle,
                  &gFlashDeviceOperationProtocolGuid,
                  SpiFlashServiceProtocol,
                  NULL
                  );  
  ASSERT_EFI_ERROR (Status);

  if (EFI_ERROR (Status)) {
    gBS->FreePool (SpiFlashServiceProtocol);
  }


  return Status;
}

从上面的代码可知,整个驱动的入口函数就是注册了这个protocol中的成员函数。现在来看看这个protocol中的成员都有什么。

struct _FLASH_DEVICE_OPERATION_PROTOCOL{
  FLASH_DEVICE_GET_INFO   GetInfo;
  FLASH_DEVICE_ERASE      Erase;
  FLASH_DEVICE_WRITE      Write;
  FLASH_DEVICE_READ       Read;
};

上面这个结构就是就是这个protocol的实体,里面包含了四个回调函数指针,要实现这个protocol的任务就是创建这几个函数的实体。这几个函数是需要根据使用的芯片来实现的,不同的芯片实现的方式可能不同。我们初始化这个函数实体的地方都是在驱动的入口函数做的。详细看上面的代码就清楚了。

实体函数的实现

Write函数

EFI_STATUS
SpiWrite(
  IN      FLASH_DEVICE_OPERATION_PROTOCOL *This,
  IN      UINTN                            Offset,
  IN      UINT8                           *Buffer,
  IN OUT  UINT32                          *BytesCount
  )
{
  EFI_STATUS        Status;
  EFI_TPL           OldTpl;
  Status = EFI_SUCCESS;

#if FLASH_DEBUG
  DbgPrint(DEBUG_INFO,"SpiWrite[Offset:0x%llx] [Count:%d]\n",Offset,*BytesCount);
#endif
  if(INVALID_ADDR(Offset))ASSERT(0);
  OldTpl = gBS->RaiseTPL(TPL_HIGH_LEVEL);
  SpiFlashWrite (Offset, Buffer, *BytesCount, FALSE, 256);
  gBS->RestoreTPL (OldTpl);
  ASSERT_EFI_ERROR (Status);
  return Status;
}

Read函数

EFI_STATUS
SpiRead(
  IN      FLASH_DEVICE_OPERATION_PROTOCOL *This,
  IN      UINTN                            Offset,
  IN      UINT8                           *Buffer,
  IN OUT  UINT32                          *BytesCount
  )
{
  EFI_STATUS        Status;
  EFI_TPL           OldTpl;

#if FLASH_DEBUG
  DbgPrint(DEBUG_INFO,"SpiRead[Offset:0x%llx]\n",Offset);
#endif
  if(INVALID_ADDR(Offset))ASSERT(0);
  OldTpl = gBS->RaiseTPL(TPL_HIGH_LEVEL);
  *BytesCount = SpiFlashRead (Offset, Buffer, *BytesCount);
  gBS->RestoreTPL (OldTpl);
  Status = EFI_SUCCESS;
  return Status;
}

Erase函数

EFI_STATUS
SpiErase(
  IN      FLASH_DEVICE_OPERATION_PROTOCOL *This,
  IN      UINTN                            Offset,
  IN OUT  UINTN                           *BytesCount
  )
{
  EFI_STATUS        Status;
  EFI_TPL           OldTpl;

#if FLASH_DEBUG
  DbgPrint(DEBUG_INFO,"SpiErase[Offset:0x%llx]\n",Offset);
#endif
  if(INVALID_ADDR(Offset))ASSERT(0);
  OldTpl = gBS->RaiseTPL(TPL_HIGH_LEVEL);
  SpiFlashErase (Offset, *BytesCount);
  gBS->RestoreTPL (OldTpl);
  Status = EFI_SUCCESS;
  return Status;
}

Getinfo函数

这个函数在一些芯片内,是没有用的,可以不实现,我们这里就没有实现,只是一个空函数。

上面函数内调用的其他函数就不一一列举了,具体的实现还是要考手册是写,这里之后提供一个框架。

调试中遇到的bug

(1)flash写入后寄存器的状态寄存器没有复位,导致下次再读取数据的时候,所出来的数据不正确的问题
(2)由于disable写保护含函数实现的有问题,不能重复写的问题
(3)写入的字节数大雨256后需要再次发送一个写使能命令,这样写的位置才能从上次写的位置后面开始继续写,否则从这个256字节开头的位置写。将第一次写入的数据冲刷掉的问题。

©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页