| /* | |
| * 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 |