/** Read BufferSize bytes from Offset into Buffer. @param This Protocol instance pointer. @param MediaId Id of the media, changes every time the media is replaced. @param Offset The starting byte offset to read from @param BufferSize Size of Buffer @param Buffer Buffer containing read data @retval EFI_SUCCESS The data was read correctly from the device. @retval EFI_DEVICE_ERROR The device reported an error while performing the read. @retval EFI_NO_MEDIA There is no media in the device. @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device. @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not valid for the device. **/ EFI_STATUS EFIAPI NorFlashDiskIoReadDisk ( IN EFI_DISK_IO_PROTOCOL *This, IN UINT32 MediaId, IN UINT64 DiskOffset, IN UINTN BufferSize, OUT VOID *Buffer ) { NOR_FLASH_INSTANCE *Instance; UINT32 BlockSize; UINT32 BlockOffset; EFI_LBA Lba; Instance = INSTANCE_FROM_DISKIO_THIS(This); if (MediaId != Instance->Media.MediaId) { return EFI_MEDIA_CHANGED; } BlockSize = Instance->Media.BlockSize; Lba = (EFI_LBA) DivU64x32Remainder (DiskOffset, BlockSize, &BlockOffset); return NorFlashRead (Instance, Lba, BlockOffset, BufferSize, Buffer); }
void restorSpeakParam() { NorFlashRead(XFS_PARAM_STORE_ADDR, (short *)&speakParam, sizeof(speakParam)); if (speakParam.speakTimes > 100) { speakParam.speakTimes = 3; } if (speakParam.speakPause > 100) { speakParam.speakPause = 3; } }
/** Reads the specified number of bytes into a buffer from the specified block. The Read() function reads the requested number of bytes from the requested block and stores them in the provided buffer. Implementations should be mindful that the firmware volume might be in the ReadDisabled state. If it is in this state, the Read() function must return the status code EFI_ACCESS_DENIED without modifying the contents of the buffer. The Read() function must also prevent spanning block boundaries. If a read is requested that would span a block boundary, the read must read up to the boundary but not beyond. The output parameter NumBytes must be set to correctly indicate the number of bytes actually read. The caller must be aware that a read may be partially completed. @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. @param Lba The starting logical block index from which to read. @param Offset Offset into the block at which to begin reading. @param NumBytes Pointer to a UINTN. At entry, *NumBytes contains the total size of the buffer. At exit, *NumBytes contains the total number of bytes read. @param Buffer Pointer to a caller-allocated buffer that will be used to hold the data that is read. @retval EFI_SUCCESS The firmware volume was read successfully, and contents are in Buffer. @retval EFI_BAD_BUFFER_SIZE Read attempted across an LBA boundary. On output, NumBytes contains the total number of bytes returned in Buffer. @retval EFI_ACCESS_DENIED The firmware volume is in the ReadDisabled state. @retval EFI_DEVICE_ERROR The block device is not functioning correctly and could not be read. **/ EFI_STATUS EFIAPI FvbRead ( IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, IN EFI_LBA Lba, IN UINTN Offset, IN OUT UINTN *NumBytes, IN OUT UINT8 *Buffer ) { EFI_STATUS TempStatus; UINTN BlockSize; NOR_FLASH_INSTANCE *Instance; Instance = INSTANCE_FROM_FVB_THIS(This); DEBUG ((DEBUG_BLKIO, "FvbRead(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n", Instance->StartLba + Lba, Offset, *NumBytes, Buffer)); TempStatus = EFI_SUCCESS; // Cache the block size to avoid de-referencing pointers all the time BlockSize = Instance->Media.BlockSize; DEBUG ((DEBUG_BLKIO, "FvbRead: Check if (Offset=0x%x + NumBytes=0x%x) <= BlockSize=0x%x\n", Offset, *NumBytes, BlockSize )); // The read must not span block boundaries. // We need to check each variable individually because adding two large values together overflows. if ((Offset >= BlockSize) || (*NumBytes > BlockSize) || ((Offset + *NumBytes) > BlockSize)) { DEBUG ((EFI_D_ERROR, "FvbRead: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset, *NumBytes, BlockSize )); return EFI_BAD_BUFFER_SIZE; } // We must have some bytes to read if (*NumBytes == 0) { return EFI_BAD_BUFFER_SIZE; } // Decide if we are doing full block reads or not. if (*NumBytes % BlockSize != 0) { TempStatus = NorFlashRead (Instance, Instance->StartLba + Lba, Offset, *NumBytes, Buffer); if (EFI_ERROR (TempStatus)) { return EFI_DEVICE_ERROR; } } else { // Read NOR Flash data into shadow buffer TempStatus = NorFlashReadBlocks (Instance, Instance->StartLba + Lba, BlockSize, Buffer); if (EFI_ERROR (TempStatus)) { // Return one of the pre-approved error statuses return EFI_DEVICE_ERROR; } } return EFI_SUCCESS; }
/* Write a full or portion of a block. It must not span block boundaries; that is, Offset + *NumBytes <= Instance->Media.BlockSize. */ EFI_STATUS NorFlashWriteSingleBlock ( IN NOR_FLASH_INSTANCE *Instance, IN EFI_LBA Lba, IN UINTN Offset, IN OUT UINTN *NumBytes, IN UINT8 *Buffer ) { EFI_STATUS TempStatus; UINT32 Tmp; UINT32 TmpBuf; UINT32 WordToWrite; UINT32 Mask; BOOLEAN DoErase; UINTN BytesToWrite; UINTN CurOffset; UINTN WordAddr; UINTN BlockSize; UINTN BlockAddress; UINTN PrevBlockAddress; PrevBlockAddress = 0; if (!Instance->Initialized && Instance->Initialize) { Instance->Initialize(Instance); } DEBUG ((DEBUG_BLKIO, "NorFlashWriteSingleBlock(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n", Lba, Offset, *NumBytes, Buffer)); // Detect WriteDisabled state if (Instance->Media.ReadOnly == TRUE) { DEBUG ((EFI_D_ERROR, "NorFlashWriteSingleBlock: ERROR - Can not write: Device is in WriteDisabled state.\n")); // It is in WriteDisabled state, return an error right away return EFI_ACCESS_DENIED; } // Cache the block size to avoid de-referencing pointers all the time BlockSize = Instance->Media.BlockSize; // The write must not span block boundaries. // We need to check each variable individually because adding two large values together overflows. if ( ( Offset >= BlockSize ) || ( *NumBytes > BlockSize ) || ( (Offset + *NumBytes) > BlockSize ) ) { DEBUG ((EFI_D_ERROR, "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset, *NumBytes, BlockSize )); return EFI_BAD_BUFFER_SIZE; } // We must have some bytes to write if (*NumBytes == 0) { DEBUG ((EFI_D_ERROR, "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset, *NumBytes, BlockSize )); return EFI_BAD_BUFFER_SIZE; } // Pick 128bytes as a good start for word operations as opposed to erasing the // block and writing the data regardless if an erase is really needed. // It looks like most individual NV variable writes are smaller than 128bytes. if (*NumBytes <= 128) { // Check to see if we need to erase before programming the data into NOR. // If the destination bits are only changing from 1s to 0s we can just write. // After a block is erased all bits in the block is set to 1. // If any byte requires us to erase we just give up and rewrite all of it. DoErase = FALSE; BytesToWrite = *NumBytes; CurOffset = Offset; while (BytesToWrite > 0) { // Read full word from NOR, splice as required. A word is the smallest // unit we can write. TempStatus = NorFlashRead (Instance, Lba, CurOffset & ~(0x3), sizeof(Tmp), &Tmp); if (EFI_ERROR (TempStatus)) { return EFI_DEVICE_ERROR; } // Physical address of word in NOR to write. WordAddr = (CurOffset & ~(0x3)) + GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, BlockSize); // The word of data that is to be written. TmpBuf = *((UINT32*)(Buffer + (*NumBytes - BytesToWrite))); // First do word aligned chunks. if ((CurOffset & 0x3) == 0) { if (BytesToWrite >= 4) { // Is the destination still in 'erased' state? if (~Tmp != 0) { // Check to see if we are only changing bits to zero. if ((Tmp ^ TmpBuf) & TmpBuf) { DoErase = TRUE; break; } } // Write this word to NOR WordToWrite = TmpBuf; CurOffset += sizeof(TmpBuf); BytesToWrite -= sizeof(TmpBuf); } else { // BytesToWrite < 4. Do small writes and left-overs Mask = ~((~0) << (BytesToWrite * 8)); // Mask out the bytes we want. TmpBuf &= Mask; // Is the destination still in 'erased' state? if ((Tmp & Mask) != Mask) { // Check to see if we are only changing bits to zero. if ((Tmp ^ TmpBuf) & TmpBuf) { DoErase = TRUE; break; } } // Merge old and new data. Write merged word to NOR WordToWrite = (Tmp & ~Mask) | TmpBuf; CurOffset += BytesToWrite; BytesToWrite = 0; } } else { // Do multiple words, but starting unaligned. if (BytesToWrite > (4 - (CurOffset & 0x3))) { Mask = ((~0) << ((CurOffset & 0x3) * 8)); // Mask out the bytes we want. TmpBuf &= Mask; // Is the destination still in 'erased' state? if ((Tmp & Mask) != Mask) { // Check to see if we are only changing bits to zero. if ((Tmp ^ TmpBuf) & TmpBuf) { DoErase = TRUE; break; } } // Merge old and new data. Write merged word to NOR WordToWrite = (Tmp & ~Mask) | TmpBuf; BytesToWrite -= (4 - (CurOffset & 0x3)); CurOffset += (4 - (CurOffset & 0x3)); } else { // Unaligned and fits in one word. Mask = (~((~0) << (BytesToWrite * 8))) << ((CurOffset & 0x3) * 8); // Mask out the bytes we want. TmpBuf = (TmpBuf << ((CurOffset & 0x3) * 8)) & Mask; // Is the destination still in 'erased' state? if ((Tmp & Mask) != Mask) { // Check to see if we are only changing bits to zero. if ((Tmp ^ TmpBuf) & TmpBuf) { DoErase = TRUE; break; } } // Merge old and new data. Write merged word to NOR WordToWrite = (Tmp & ~Mask) | TmpBuf; CurOffset += BytesToWrite; BytesToWrite = 0; } } // // Write the word to NOR. // BlockAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, BlockSize); if (BlockAddress != PrevBlockAddress) { TempStatus = NorFlashUnlockSingleBlockIfNecessary (Instance, BlockAddress); if (EFI_ERROR (TempStatus)) { return EFI_DEVICE_ERROR; } PrevBlockAddress = BlockAddress; } TempStatus = NorFlashWriteSingleWord (Instance, WordAddr, WordToWrite); if (EFI_ERROR (TempStatus)) { return EFI_DEVICE_ERROR; } } // Exit if we got here and could write all the data. Otherwise do the // Erase-Write cycle. if (!DoErase) { return EFI_SUCCESS; } } // Check we did get some memory. Buffer is BlockSize. if (Instance->ShadowBuffer == NULL) { DEBUG ((EFI_D_ERROR, "FvbWrite: ERROR - Buffer not ready\n")); return EFI_DEVICE_ERROR; } // Read NOR Flash data into shadow buffer TempStatus = NorFlashReadBlocks (Instance, Lba, BlockSize, Instance->ShadowBuffer); if (EFI_ERROR (TempStatus)) { // Return one of the pre-approved error statuses return EFI_DEVICE_ERROR; } // Put the data at the appropriate location inside the buffer area CopyMem ((VOID*)((UINTN)Instance->ShadowBuffer + Offset), Buffer, *NumBytes); // Write the modified buffer back to the NorFlash TempStatus = NorFlashWriteBlocks (Instance, Lba, BlockSize, Instance->ShadowBuffer); if (EFI_ERROR (TempStatus)) { // Return one of the pre-approved error statuses return EFI_DEVICE_ERROR; } return EFI_SUCCESS; }