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