blob: 5a7a1c57aa17fe3b2d2c39886f9b1d7301f158b5 [file] [log] [blame]
/*
* Copyright (c) 2012-2013, 2021 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2001-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __MEM_FLASH_MEM_HH__
#define __MEM_FLASH_MEM_HH__
#include "mem/abstract_mem.hh"
#include "params/CfiMemory.hh"
namespace gem5
{
namespace memory
{
/**
* CfiMemory: This is modelling a flash memory adhering to the
* Common Flash Interface (CFI):
*
* JEDEC JESD68.01
* JEDEC JEP137B
* Intel Application Note 646
*
* This is as of now a pure functional model of a flash controller:
* no timing/power information has been encoded in it and it is therefore
* not representive of a real device. Some voltage/timing values have
* nevertheless been encoded in the CFI table.
* This is just a requirement from the CFI specification: guest software
* might query those entries, but they are not reflected in gem5 statistics.
*
* The model is meant to be used to allow execution of flash drivers
* (e.g. UEFI firmware storing EFI variables in non volatile memory)
*/
class CfiMemory : public AbstractMemory
{
private:
enum class CfiCommand
{
NO_CMD = 0,
LOCK_BLOCK = 0x1,
ERASE_BLOCK_SETUP = 0x20,
WORD_PROGRAM = 0x40,
CLEAR_STATUS_REG = 0x50,
LOCK_BLOCK_SETUP = 0x60,
READ_STATUS_REG = 0x70,
READ_DEVICE_ID = 0x90,
READ_CFI_QUERY = 0x98,
BUFFERED_PROGRAM_SETUP = 0xE8,
BUFFERED_PROGRAM_CONFIRM = 0xD0,
BLOCK_ERASE_CONFIRM = 0xD0,
UNLOCK_BLOCK = 0xD0,
AMD_RESET=0xF0,
READ_ARRAY = 0xFF,
/** This is not a real command, but it is used by the internal
* model only to represent the 2nd write cycle state for a buffered
* program (when the buffer size is supplied) */
BUFFER_SIZE_READ,
};
/** Possible in the status register */
static const uint8_t STATUS_ERASE_ERROR = 0x30;
static const uint8_t STATUS_LOCK_ERROR = 0x12;
static const uint8_t STATUS_READY = 0x80;
static const uint8_t STATUS_PROGRAM_LOCK_BIT = 0x10;
/** Metadata about the erase blocks in flash */
struct BlockData : public Serializable
{
BlockData(const CfiMemory &_parent, ssize_t number, ssize_t size)
: Serializable(), locked(number, false), blockSize(size),
parent(_parent)
{}
/**
* Return true if the block pointed by the block_address
* parameter is locked
*
* @params block_address address of the erase block in flash
* memory: first block starts ad address 0x0
* @return true if block is locked
*/
bool isLocked(Addr block_address) const;
/**
* Lock the block pointed by the block_address
* parameter
*
* @params block_address address of the erase block in flash
* memory: first block starts ad address 0x0
*/
void lock(Addr block_address);
/**
* Unlock the block pointed by the block_address
* parameter
*
* @params block_address address of the erase block in flash
* memory: first block starts ad address 0x0
*/
void unlock(Addr block_address);
/** Erase a single block. The address of the block
* is supplied by the packet address.
*
* @params pkt memory packet targeting the erase block
*/
void erase(PacketPtr pkt);
/** Number of erase blocks in flash memory */
ssize_t number() const { return locked.size(); }
/** Size in bytes of a single erase block */
ssize_t size() const { return blockSize; }
private: // Serializable
void serialize(CheckpointOut &cp) const override;
void unserialize(CheckpointIn &cp) override;
private:
uint32_t blockIdx(Addr block_address) const;
// Per block flag. True if the block is locked
std::vector<bool> locked;
// Size of the block in bytes
const ssize_t blockSize;
const CfiMemory &parent;
};
/**
* Word Buffer used by the BUFFERED PROGRAM command
* to write (program) chunks of words to flash
*/
struct ProgramBuffer : public Serializable
{
public:
// program buffer max size = 32 words
static const ssize_t MAX_BUFFER_SIZE = 32 * 4;
ProgramBuffer(const CfiMemory &_parent)
: Serializable(), parent(_parent)
{}
/**
* Start buffering
* @param buffer_size new size (in bytes) of the program buffer
*/
void setup(ssize_t buffer_size);
/**
* Write data into the buffer. If the buffer is full, the
* method will return true, meaning it's time to write
* back the buffer into memory
*
* @params flash_address address in flash (relative to the start)
* @params data_ptr pointer to the data
* @params size number of bytes to be written to the buffer
*
* @return true if buffer needs to be written back to flash
*/
bool write(Addr flash_address, void *data_ptr, ssize_t size);
bool writeback();
private:
void serialize(CheckpointOut &cp) const override;
void unserialize(CheckpointIn &cp) override;
private:
// program buffer
std::vector<uint8_t> buffer;
// Number of bytes written in the buffer
ssize_t bytesWritten = 0;
// Pointing to the latest written word in the buffer
Addr blockPointer = 0;
const CfiMemory &parent;
};
/**
* A deferred packet stores a packet along with its scheduled
* transmission time
*/
class DeferredPacket
{
public:
const Tick tick;
const PacketPtr pkt;
DeferredPacket(PacketPtr _pkt, Tick _tick) : tick(_tick), pkt(_pkt)
{ }
};
class MemoryPort : public ResponsePort
{
private:
CfiMemory& mem;
public:
MemoryPort(const std::string& _name, CfiMemory& _memory);
protected:
Tick recvAtomic(PacketPtr pkt) override;
Tick recvAtomicBackdoor(
PacketPtr pkt, MemBackdoorPtr &_backdoor) override;
void recvFunctional(PacketPtr pkt) override;
bool recvTimingReq(PacketPtr pkt) override;
void recvRespRetry() override;
AddrRangeList getAddrRanges() const override;
};
MemoryPort port;
/**
* Latency from that a request is accepted until the response is
* ready to be sent.
*/
const Tick latency;
/**
* Fudge factor added to the latency.
*/
const Tick latency_var;
/**
* Internal (unbounded) storage to mimic the delay caused by the
* actual memory access. Note that this is where the packet spends
* the memory latency.
*/
std::list<DeferredPacket> packetQueue;
/**
* Bandwidth in ticks per byte. The regulation affects the
* acceptance rate of requests and the queueing takes place after
* the regulation.
*/
const double bandwidth;
/**
* Track the state of the memory as either idle or busy, no need
* for an enum with only two states.
*/
bool isBusy;
/**
* Remember if we have to retry an outstanding request that
* arrived while we were busy.
*/
bool retryReq;
/**
* Remember if we failed to send a response and are awaiting a
* retry. This is only used as a check.
*/
bool retryResp;
/**
* Release the memory after being busy and send a retry if a
* request was rejected in the meanwhile.
*/
void release();
EventFunctionWrapper releaseEvent;
/**
* Dequeue a packet from our internal packet queue and move it to
* the port where it will be sent as soon as possible.
*/
void dequeue();
EventFunctionWrapper dequeueEvent;
/**
* Detemine the latency.
*
* @return the latency seen by the current packet
*/
Tick getLatency() const;
/**
* Upstream caches need this packet until true is returned, so
* hold it for deletion until a subsequent call
*/
std::unique_ptr<Packet> pendingDelete;
const uint8_t numberOfChips;
const uint16_t vendorID;
const uint16_t deviceID;
const uint16_t bankWidth;
/** Previous command (issued in the previous write cycle) */
CfiCommand readState;
CfiCommand writeState;
uint8_t statusRegister;
BlockData blocks;
ProgramBuffer programBuffer;
uint8_t cfiQueryTable[61];
public:
CfiMemory(const CfiMemoryParams &p);
DrainState drain() override;
Port &getPort(const std::string &if_name,
PortID idx=InvalidPortID) override;
void init() override;
void serialize(CheckpointOut &cp) const override;
void unserialize(CheckpointIn &cp) override;
protected:
Tick recvAtomic(PacketPtr pkt);
Tick recvAtomicBackdoor(PacketPtr pkt, MemBackdoorPtr &_backdoor);
void recvFunctional(PacketPtr pkt);
bool recvTimingReq(PacketPtr pkt);
void recvRespRetry();
/** Make a read/write access to the CFI Memory */
void cfiAccess(PacketPtr pkt);
/** Write request to the CFI Memory */
void write(PacketPtr pkt);
/** Read request to the CFI Memory */
void read(PacketPtr pkt);
/**
* Helper function to read the device identifier after the
* read state machine is put in the CfiCommand::READ_DEVICE_ID
* mode.
*
* @param flash_address: The flash address LSBits encode the
* the information the software is trying
* to read
*/
uint64_t readDeviceID(Addr flash_address) const;
/**
* Service a new command issued to the flash device
*
* @param command: new command issued to the flash device
*/
void handleCommand(CfiCommand command);
/** Return the selected entry in the CFI table
*
* @param addr: offset in the CFI table
*/
uint64_t cfiQuery(Addr addr);
};
} // namespace memory
} // namespace gem5
#endif