diff options
author | Thi Tran <thi@us.ibm.com> | 2012-01-13 10:29:25 -0600 |
---|---|---|
committer | A. Patrick Williams III <iawillia@us.ibm.com> | 2012-02-07 13:49:45 -0600 |
commit | 859335d953a59c25de64a414c344d0a22d0911cb (patch) | |
tree | c606dbbbe0cbbfa3275ca0d644ac417e258b84b9 /src/usr/pore/poreve/porevesrc | |
parent | 0f454c096f27c06cb93ad442c0e14fc734464867 (diff) | |
download | talos-hostboot-859335d953a59c25de64a414c344d0a22d0911cb.tar.gz talos-hostboot-859335d953a59c25de64a414c344d0a22d0911cb.zip |
Initial VSBE Supports
Fixed test case failure
Change-Id: Ie388aebddacba99dfc6cc04e5fe98f0e8ca8b4bd
Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/520
Tested-by: Jenkins Server
Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Diffstat (limited to 'src/usr/pore/poreve/porevesrc')
-rw-r--r-- | src/usr/pore/poreve/porevesrc/bus.C | 900 | ||||
-rw-r--r-- | src/usr/pore/poreve/porevesrc/bus.H | 661 | ||||
-rw-r--r-- | src/usr/pore/poreve/porevesrc/create.C | 46 | ||||
-rw-r--r-- | src/usr/pore/poreve/porevesrc/fasti2c.C | 604 | ||||
-rw-r--r-- | src/usr/pore/poreve/porevesrc/fasti2c.H | 564 | ||||
-rw-r--r-- | src/usr/pore/poreve/porevesrc/hookmanager.C | 575 | ||||
-rw-r--r-- | src/usr/pore/poreve/porevesrc/hookmanager.H | 859 | ||||
-rw-r--r-- | src/usr/pore/poreve/porevesrc/pib2cfam.C | 167 | ||||
-rw-r--r-- | src/usr/pore/poreve/porevesrc/pib2cfam.H | 94 | ||||
-rw-r--r-- | src/usr/pore/poreve/porevesrc/pore.C | 269 | ||||
-rw-r--r-- | src/usr/pore/poreve/porevesrc/pore.H | 259 | ||||
-rw-r--r-- | src/usr/pore/poreve/porevesrc/poreve.C | 480 | ||||
-rw-r--r-- | src/usr/pore/poreve/porevesrc/poreve.H | 535 | ||||
-rw-r--r-- | src/usr/pore/poreve/porevesrc/sbevital.C | 82 | ||||
-rw-r--r-- | src/usr/pore/poreve/porevesrc/sbevital.H | 85 |
15 files changed, 6180 insertions, 0 deletions
diff --git a/src/usr/pore/poreve/porevesrc/bus.C b/src/usr/pore/poreve/porevesrc/bus.C new file mode 100644 index 000000000..fdf3e90a5 --- /dev/null +++ b/src/usr/pore/poreve/porevesrc/bus.C @@ -0,0 +1,900 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/porevesrc/bus.C $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +// $Id: bus.C,v 1.22 2012/01/05 23:15:54 bcbrock Exp $ + +/// \file bus.C +/// \brief PoreVe bus and base device models + +#include "bus.H" +#include <fapi.H> +#include <transaction.H> + + + +using namespace vsbe; + +//----------------------------------------------------------------------------- +Bus::Bus() : + iv_primarySlaves(NULL), + iv_secondarySlaves(NULL) +{ +} + +//----------------------------------------------------------------------------- +Bus::~Bus() +{ +} + +//----------------------------------------------------------------------------- +void +Bus::attachPrimarySlave(Slave* i_slave) +{ + if( iv_primarySlaves == 0 ) + { + i_slave->iv_next = 0; + }else{ + i_slave->iv_next = iv_primarySlaves; + } + iv_primarySlaves = i_slave; +} + +//----------------------------------------------------------------------------- +void +Bus::attachSecondarySlave(Slave* i_slave) +{ + if( iv_secondarySlaves == 0 ) + { + i_slave->iv_next = 0; + }else{ + i_slave->iv_next = iv_secondarySlaves; + } + iv_secondarySlaves = i_slave; +} + + +//----------------------------------------------------------------------------- +fapi::ReturnCode +Bus::operation(Transaction& trans) +{ + fapi::ReturnCode rc; + Slave* slave= 0; + + do + { + for( slave = iv_primarySlaves; slave; slave = slave->iv_next ) + { + if( (trans.iv_address >= slave->iv_base) && (trans.iv_address < (slave->iv_base + slave->iv_size) ) ) + { + break; // found a primary slave + } + } + + if( slave == 0 ) + { // primary slaves did not hold the transaction address. Try using the secondary slaves. + for( slave = iv_secondarySlaves; slave; slave = slave->iv_next ) + { + if( (trans.iv_address >= slave->iv_base) && (trans.iv_address < (slave->iv_base + slave->iv_size) ) ) + { + break; // found a secondary slave + } + } + } + + break; + + }while(0); + + do + { + if( slave == 0 ) // neither primary nor secondary slaves held the address + { + trans.busError(ME_NOT_MAPPED_ON_BUS); + rc= 1; + break; + } + + if( (trans.iv_mode & slave->iv_permissions) == 0 ){ + trans.busError(ME_BUS_SLAVE_PERMISSION_DENIED); + rc= 1; + break; + } + + trans.iv_offset = trans.iv_address - slave->iv_base; + rc = slave->operation( trans ); + break; + }while(1); + + return rc; +} + +//----------------------------------------------------------------------------- +Slave::Slave() +:iv_base(0), iv_size(0), iv_permissions(0), +iv_next(NULL), iv_target(NULL), iv_dataBuffer(NULL) +{ + +} + +//----------------------------------------------------------------------------- +Slave::~Slave() +{ +} + +//----------------------------------------------------------------------------- +PibSlave::PibSlave() +{ +} + +//----------------------------------------------------------------------------- +PibSlave::~PibSlave() +{ +} + +//----------------------------------------------------------------------------- +fapi::ReturnCode +PibSlave::operation(Transaction& io_transaction) +{ + fapi::ReturnCode rc; + PibTransaction* pt = (PibTransaction*)&io_transaction; + + if( io_transaction.iv_mode & ACCESS_MODE_READ ) + { + rc = getScom( io_transaction.iv_address, io_transaction.iv_data ); + } + else + { + rc = putScom( io_transaction.iv_address, io_transaction.iv_data ); + } + + if( rc.ok() ) + { + pt->iv_pcbReturnCode = PCB_SUCCESS; + } + else + { + if( rc & fapi_PCB_RESOURCE_BUSY ){ + pt->iv_pcbReturnCode = PCB_RESOURCE_OCCUPIED; + }else if( rc & fapi_PCB_OFFLINE_ERROR ){ + pt->iv_pcbReturnCode = PCB_CHIPLET_OFFLINE; + }else if( rc & fapi_PCB_PARTIAL_ERROR ){ + pt->iv_pcbReturnCode = PCB_PARTIAL_GOOD; + }else if( rc & fapi_PCB_ADDRESS_ERROR ){ + pt->iv_pcbReturnCode = PCB_ADDRESS_ERROR; + }else if( rc & fapi_PCB_CLOCK_ERROR ){ + pt->iv_pcbReturnCode = PCB_CLOCK_ERROR; + }else if( rc & fapi_PCB_PARITY_ERROR ){ + pt->iv_pcbReturnCode = PCB_PACKET_ERROR; + }else if( rc & fapi_PCB_TIMEOUT_ERROR ){ + pt->iv_pcbReturnCode = PCB_TIMEOUT; + }else{ + pt->iv_pcbReturnCode = PCB_TIMEOUT; + } + rc = 0; + } + + io_transaction.iv_modelError = ME_SUCCESS; + return rc; +} + + +//----------------------------------------------------------------------------- +void +Slave::configure( + fapi::Target* i_target, + ecmdDataBufferBase* i_dataBuffer, + uint32_t i_base, + uint64_t i_size, + int i_permissions + ) +{ + iv_target = i_target; + iv_dataBuffer = i_dataBuffer; + iv_base = i_base; + iv_size = i_size; + iv_permissions = i_permissions; + iv_next = NULL; +} + + + +//----------------------------------------------------------------------------- +fapi::ReturnCode +PibSlave::getScom(const uint32_t i_offset, uint64_t& o_data) +{ + fapi::ReturnCode rc; + rc = fapiGetScom( *iv_target, i_offset, *iv_dataBuffer ); + o_data = iv_dataBuffer->getDoubleWord( 0 ); + + return rc; +} + +//----------------------------------------------------------------------------- +fapi::ReturnCode +PibSlave::putScom(const uint32_t i_offset, const uint64_t i_data) +{ + fapi::ReturnCode rc; + iv_dataBuffer->setDoubleWordLength( 1 ); + iv_dataBuffer->setDoubleWord( 0, i_data ); + rc = fapiPutScom( *iv_target, i_offset, *iv_dataBuffer ); + + return rc; +} + + +//----------------------------------------------------------------------------- +PibMemory::PibMemory() : +iv_passThrough(false),iv_memory(NULL) +{ +} + +//----------------------------------------------------------------------------- +PibMemory::~PibMemory() +{ +} + +//----------------------------------------------------------------------------- +void +PibMemory::setPassThrough(const bool i_enable) +{ + iv_passThrough = i_enable; +} + +//----------------------------------------------------------------------------- +void +PibMemory::configure( + fapi::Target* i_target, + ecmdDataBufferBase* i_dataBuffer, + uint32_t i_base, + uint64_t i_size, + int i_permissions, + Memory* i_memory + ) +{ + iv_target = i_target; + iv_dataBuffer = i_dataBuffer; + iv_base = i_base; + iv_size = i_size; + iv_permissions = i_permissions; + iv_memory = i_memory; + iv_next = NULL; +} + + +//----------------------------------------------------------------------------- +// +fapi::ReturnCode +PibMemory::operation(Transaction& io_transaction) +{ + fapi::ReturnCode rc; + ModelError me; + + if( io_transaction.iv_mode & ACCESS_MODE_READ ) + { + me = iv_memory->read( (uint32_t)(io_transaction.iv_offset * TRANSACTION_SIZE_IN_BYTES), io_transaction.iv_data, TRANSACTION_SIZE_IN_BYTES ); + if( me == ME_NOT_MAPPED_IN_MEMORY && iv_passThrough ) + { + rc = getScom( io_transaction.iv_address, io_transaction.iv_data ); + if( rc.ok() ) + { + me = ME_SUCCESS; + } + else + { + me = ME_FAILURE; + } + } + } + else if( io_transaction.iv_mode & ACCESS_MODE_WRITE ) + { + me = iv_memory->write( (uint32_t)(io_transaction.iv_offset * TRANSACTION_SIZE_IN_BYTES), io_transaction.iv_data, TRANSACTION_SIZE_IN_BYTES ); + if( me == ME_NOT_MAPPED_IN_MEMORY && iv_passThrough ) + { + rc = putScom( io_transaction.iv_address, io_transaction.iv_data ); + if( rc.ok() ) + { + me = ME_SUCCESS; + } + else + { + me = ME_FAILURE; + } + } + } + else + { + me = iv_memory->fetch( (uint32_t)(io_transaction.iv_offset * TRANSACTION_SIZE_IN_BYTES), io_transaction.iv_data, TRANSACTION_SIZE_IN_BYTES ); + if( me == ME_NOT_MAPPED_IN_MEMORY && iv_passThrough ) + { + rc = getScom( io_transaction.iv_address, io_transaction.iv_data ); + if( rc.ok() ) + { + me = ME_SUCCESS; + } + else + { + me = ME_FAILURE; + } + } + } + + io_transaction.busError( me ); + + if( me == ME_SUCCESS ) + { + rc = (uint32_t)0; // if read/write or getScom/putScom succeeded then set rc = 0 + } + + // if read/write failed then rc == 1 by default + // if read/write returned ME_NOT_MAPPED_IN_MEMORY && pass through true then rc == value returned from putScom or getScom + + return rc; +} + + +//----------------------------------------------------------------------------- +Memory::Memory() : + iv_images(0) +{ +#if POREVE_STATISTICS + resetStatistics(); +#endif +} + +//----------------------------------------------------------------------------- +Memory::~Memory() +{ +} + +//----------------------------------------------------------------------------- +bool +Memory::checkCrc() +{ + MemoryImage* mi = iv_images; + bool rc = true; + + do{ + + if( mi->checkCrc() == false ) + { + rc = false; + break; + } + mi = mi->iv_next; + + }while( mi != iv_images ); + + return rc; +} + + +//----------------------------------------------------------------------------- +ModelError +Memory::read( + uint32_t i_offset, + uint64_t& o_data, + size_t i_size + ) +{ + char* from_ptr; + char* to_ptr; + size_t cnt; + MemoryImage* mi; + ModelError me; + int mi_found; + + o_data = 0; // Assure all bytes are cleared + + me = ME_SUCCESS; + do{ + if( iv_images == 0 ) + { + me = ME_NOT_MAPPED_IN_MEMORY; + break; + } + mi = iv_images; + mi_found = 0; + do{ + + if( (i_offset >= mi->iv_base) && ((i_offset + i_size) <= (mi->iv_base + mi->iv_size) ) ) + { + mi_found= 1; + iv_images = mi; // have the Memory always point to the last MemoryImage that was used + break; // we found a chunk of memory containing the transaction address + } + mi = mi->iv_next; + + }while( mi != iv_images ); + + if( ! mi_found ) + { // There was no MemoryImage that contained the transaction address + me = ME_NOT_MAPPED_IN_MEMORY; + break; + } + + if( (mi->iv_permissions & ACCESS_MODE_READ ) == 0 ) + { // The permissions over the memory block do not allow the mode being used by the transaction + me = ME_MEMORY_IMAGE_PERMISSION_DENIED; + break; + } + + // Init the character pointer into the eprom image we are using. + from_ptr = (char*)mi->iv_image + (i_offset - mi->iv_base); + + // Init the character pointer into the o_data buffer. + // Take care of Endianess by moving to one or the other end of the buffer as appropriate. +#ifdef _BIG_ENDIAN + to_ptr = (char*)&o_data + (TRANSACTION_SIZE_IN_BYTES - i_size); +#else + to_ptr = ((char*)&o_data + i_size -1); +#endif + + for( cnt = 0; cnt < i_size; cnt++ ) + { + *to_ptr = *from_ptr++; + + // Move the to pointer either forward or backward as appropriate for Endianess +#ifdef _BIG_ENDIAN + to_ptr++; +#else + to_ptr--; +#endif + } + + me = ME_SUCCESS; + break; + }while(1); + +#if POREVE_STATISTICS + iv_reads++; +#endif + + return me; +} + +//----------------------------------------------------------------------------- +ModelError +Memory::fetch( + uint32_t i_offset, + uint64_t& o_data, + size_t i_size + ) +{ + char* from_ptr; + char* to_ptr; + size_t cnt; + MemoryImage* mi; + ModelError me; + int mi_found; + + o_data = 0; // Assure all bytes are cleared + + me = ME_SUCCESS; + do{ + if( iv_images == 0 ) + { + me = ME_NOT_MAPPED_IN_MEMORY; + break; + } + mi = iv_images; + mi_found = 0; + do{ + + if( (i_offset >= mi->iv_base) && ((i_offset + i_size) <= (mi->iv_base + mi->iv_size) ) ) + { + mi_found= 1; + iv_images = mi; // have the Memory always point to the last MemoryImage that was used + break; // we found a chunk of memory containing the transaction address + } + mi = mi->iv_next; + + }while( mi != iv_images ); + + if( ! mi_found ) + { // There was no MemoryImage that contained the transaction address + me = ME_NOT_MAPPED_IN_MEMORY; + break; + } + + if( (mi->iv_permissions & ACCESS_MODE_EXECUTE ) == 0 ) + { // The permissions over the memory block do not allow the mode being used by the transaction + me = ME_MEMORY_IMAGE_PERMISSION_DENIED; + break; + } + + // Init the character pointer into the eprom image we are using. + from_ptr = (char*)mi->iv_image + i_offset; + + // Init the character pointer into the o_data buffer. + // Take care of Endianess by moving to one or the other end of the buffer as appropriate. +#ifdef _BIG_ENDIAN + to_ptr = (char*)&o_data + (TRANSACTION_SIZE_IN_BYTES - i_size); +#else + to_ptr = ((char*)&o_data + i_size -1); +#endif + + for( cnt = 0; cnt < i_size; cnt++ ) + { + *to_ptr = *from_ptr++; + + // Move the to pointer either forward or backward as appropriate for Endianess +#ifdef _BIG_ENDIAN + to_ptr++; +#else + to_ptr--; +#endif + } + + me = ME_SUCCESS; + break; + }while(1); + +#if POREVE_STATISTICS + iv_fetches++; +#endif + + return me; +} + + + +//----------------------------------------------------------------------------- +ModelError +Memory::write( + uint32_t i_offset, // the address in the eprom image + uint64_t i_data, // data to write into the eprom image + size_t i_size // number of bytes to write (pretty much going to be TRANSACTION_SIZE_IN_BYTES) + ) +{ + char* to_ptr; + char* from_ptr; + size_t cnt; + MemoryImage* mi; + ModelError me; + int mi_found; + + me = ME_SUCCESS; + do{ + if( iv_images == 0 ) + { + me = ME_NOT_MAPPED_IN_MEMORY; + break; + } + mi = iv_images; + mi_found = 0; + do{ + + if( (i_offset >= mi->iv_base) && ((i_offset + i_size) <= (mi->iv_base + mi->iv_size) ) ) + { + mi_found= 1; + iv_images = mi; // have the Memory always point to the last MemoryImage that was used + break; // we found a chunk of memory containing the transaction address + } + mi = mi->iv_next; + + }while( mi != iv_images ); + + if( ! mi_found ) + { // There was no MemoryImage that contained the transaction address + me = ME_NOT_MAPPED_IN_MEMORY; + break; + } + + if( (mi->iv_permissions & ACCESS_MODE_WRITE ) == 0 ) + { // The permissions over the memory block do not allow the mode being used by the transaction + me = ME_MEMORY_IMAGE_PERMISSION_DENIED; + break; + } + + // Init the character pointer into the eprom image we are using. + to_ptr = (char*)mi->iv_image + i_offset; + + // Init the character pointer into the o_data buffer. + // Take care of Endianess by moving to one or the other end of the buffer as appropriate. +#ifdef _BIG_ENDIAN + from_ptr = (char*)&i_data + (TRANSACTION_SIZE_IN_BYTES - i_size); +#else + from_ptr = ((char*)&i_data + i_size -1); +#endif + + for( cnt = 0; cnt < i_size; cnt++ ) + { + *to_ptr++ = *from_ptr; + + // Move the to pointer either forward or backward as appropriate for Endianess +#ifdef _BIG_ENDIAN + from_ptr++; +#else + from_ptr--; +#endif + } + + me = ME_SUCCESS; + break; + + }while(1); + +#if POREVE_STATISTICS + iv_writes++; +#endif + + return me; +} + + +//----------------------------------------------------------------------------- +ModelError +Memory::map( + uint32_t i_base, // For direct memory this is the 0 based offset from the Slave iv_base + size_t i_size, // Size of this chunk of memory + int i_permissions, + void* i_image, + bool i_crcEnable + ) +{ + ModelError me = ME_SUCCESS; + MemoryImage* n; + MemoryImage* mi = new MemoryImage( i_base, i_size, i_permissions, i_image, i_crcEnable ); + + if( iv_images == 0 ) + { + iv_images = mi; + mi->iv_next = mi; + }else{ + n = iv_images->iv_next; + while( n->iv_next != iv_images ) + { + n = n->iv_next; + } + n->iv_next = mi; + mi->iv_next = iv_images; + } + + return me; +} + + +//----------------------------------------------------------------------------- +#if POREVE_STATISTICS +void +Memory::resetStatistics() +{ + iv_reads = 0; + iv_writes = 0; + iv_fetches = 0; +} +#endif // POREVE_STATISTICS + + +//----------------------------------------------------------------------------- +MemoryImage::MemoryImage( + uint32_t i_base, + size_t i_size, + int i_permissions, + void* i_image, + bool i_crcEnable + ) +{ + + iv_base = i_base; + iv_size = i_size; + iv_permissions = i_permissions; + iv_image = i_image; + iv_crcEnable = i_crcEnable; + iv_originalCrc = 0; + iv_next = NULL; + + if( i_crcEnable ) + { + iv_originalCrc = computeCrc(); + } + +} + +//----------------------------------------------------------------------------- +MemoryImage::~MemoryImage() +{ +} + +//----------------------------------------------------------------------------- +uint64_t +MemoryImage::computeCrc() +{ + return 0; +} + +//----------------------------------------------------------------------------- +bool +MemoryImage::checkCrc() +{ + bool result = true; + + if( iv_crcEnable == true ) + { + uint64_t current_crc = computeCrc(); + if( current_crc != iv_originalCrc ) + { + result = false; + } + } + + return result; +} + +//----------------------------------------------------------------------------- +OciMemory::OciMemory() : +iv_memory(NULL), iv_passThrough(false) +{ +} + +//----------------------------------------------------------------------------- +OciMemory::~OciMemory() +{ +} + +//----------------------------------------------------------------------------- +void +OciMemory::setPassThrough(const bool i_enable) +{ + iv_passThrough = i_enable; +} + +//----------------------------------------------------------------------------- +void +OciMemory::configure( + fapi::Target* i_target, + ecmdDataBufferBase* i_dataBuffer, + uint32_t i_base, + uint64_t i_size, + int i_permissions, + Memory* i_memory + ) +{ + iv_target = i_target; + iv_dataBuffer = i_dataBuffer; + iv_base = i_base; + iv_size = i_size; + iv_permissions = i_permissions; + iv_memory = i_memory; +} + + + +//----------------------------------------------------------------------------- +// +fapi::ReturnCode +OciMemory::operation(Transaction& io_transaction) +{ + fapi::ReturnCode rc; + + ModelError me; + + if( io_transaction.iv_mode & ACCESS_MODE_READ ) + { + me = iv_memory->read( (uint32_t)io_transaction.iv_offset, io_transaction.iv_data, TRANSACTION_SIZE_IN_BYTES ); + if( me == ME_NOT_MAPPED_IN_MEMORY && iv_passThrough ) + { + rc = read( io_transaction.iv_address, io_transaction.iv_data ); + if( rc.ok() ) + { + me = ME_SUCCESS; + } + else + { + me = ME_FAILURE; + } + } + } + else + { + me = iv_memory->write( (uint32_t)io_transaction.iv_offset, io_transaction.iv_data, TRANSACTION_SIZE_IN_BYTES ); + if( me == ME_NOT_MAPPED_IN_MEMORY && iv_passThrough ) + { + rc = write( io_transaction.iv_address, io_transaction.iv_data ); + if( rc.ok() ) + { + me = ME_SUCCESS; + } + else + { + me = ME_FAILURE; + } + } + } + + io_transaction.busError( me ); + + if( me == ME_SUCCESS ) + { + rc = (uint32_t)0; + } + + // if read/write failed then rc == 1 by default + // if read/write returned ME_NOT_MAPPED_IN_MEMORY && pass through true then + // rc == value returned from putScom or getScom + + return rc; +} + +//----------------------------------------------------------------------------- +fapi::ReturnCode +OciSlave::operation(Transaction& io_transaction) +{ + fapi::ReturnCode rc; + ModelError me; + + if( io_transaction.iv_mode & ACCESS_MODE_READ ) + { + rc = read( io_transaction.iv_address, io_transaction.iv_data ); + } + else + { + rc = write( io_transaction.iv_address, io_transaction.iv_data ); + } + + if( rc.ok() ) + { + me = ME_SUCCESS; + } + else + { + me = ME_FAILURE; + } + + io_transaction.busError( me ); + + return rc; +} + +//----------------------------------------------------------------------------- +OciSlave::~OciSlave() +{ +} + +//----------------------------------------------------------------------------- +fapi::ReturnCode +OciSlave::read(const uint32_t i_address, uint64_t& o_data) +{ + fapi::ReturnCode rc; + return rc; +} + +//----------------------------------------------------------------------------- +fapi::ReturnCode +OciSlave::write(const uint32_t i_address, const uint64_t i_data) +{ + fapi::ReturnCode rc; + return rc; +} + +//----------------------------------------------------------------------------- +fapi::ReturnCode +OciSlaveWritable::write(const uint32_t i_address, const uint64_t i_data) +{ + + // For this model, print out a message to confirm a write has been written is all it needs. + FAPI_INF("OciSlaveWritable::write(0x%08x, 0x%016llx)", + i_address, i_data); + fapi::ReturnCode rc; + return rc; +} + diff --git a/src/usr/pore/poreve/porevesrc/bus.H b/src/usr/pore/poreve/porevesrc/bus.H new file mode 100644 index 000000000..6370bae84 --- /dev/null +++ b/src/usr/pore/poreve/porevesrc/bus.H @@ -0,0 +1,661 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/porevesrc/bus.H $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#ifndef __VSBE_BUS_H +#define __VSBE_BUS_H + +// $Id: bus.H,v 1.14 2011/12/16 21:47:59 bcbrock Exp $ + +/// \file bus.H +/// \brief PoreVe bus and base device models + +#include <fapi.H> +#include "transaction.H" + + +namespace vsbe +{ + +class Slave; +class Memory; + +// Temporary FAPI return codes from getscom/putscom errors +#define fapi_PCB_RESOURCE_BUSY 0x02014003 +#define fapi_PCB_OFFLINE_ERROR 0x02014005 +#define fapi_PCB_PARTIAL_ERROR 0x02014007 +#define fapi_PCB_ADDRESS_ERROR 0x02014009 +#define fapi_PCB_CLOCK_ERROR 0x0201400B +#define fapi_PCB_PARITY_ERROR 0x0201400D +#define fapi_PCB_TIMEOUT_ERROR 0x0201400F + +//----------------------------------------------------------------------------- +/*! +The Pore hardware engine is connected via PIB bus and OCI bus. The Bus object +functions to group all entities on the bus. For example, the PIB has the ability +to run put/getscom via the PibSlave, as well as access OTPROM memory via the +PibMemory object and PNOR and SEEPROM via FastI2cMemory objects. +*/ +/// All pore hardware bus transactions are submitted through a Bus object. +class Bus +{ + +public: + + Bus(); + virtual ~Bus(); + + /*! Primary Slaves are searched first for a given Transaction Address */ + /// Primary Slaves are a linked list of Slave based objects + void attachPrimarySlave(Slave* i_slave); + + /*! If a Secondary slave cannot service the Transaction then the Transaction address + is not mapped on the bus at all. */ + /// Secondary Slaves are searched only if a Primary Slave did not support the Transaction Address + void attachSecondarySlave(Slave* i_slave); + + /*! + The PrimarySlaves attached to the bus are checked to find one that handles the + Transaction address. If no match, then the SecondarySlaves are checked. When a + Slave is found containing the address the Transaction::iv_offset is set to the + Transaction::iv_address - Slave::iv_base. The Slave operation method is then + executed. + + The return code from the Slave is passed back and becomes the return code of the + Bus operation. The Transaction ModelError is set by the Slave and is passed back + as well. + + @returns If any error occurs then the fapi::ReturnCode is not ok, and the + transaction ModelError indicates the kind of problem found. + + @returns rc=1 and Transaction ModelError=ME_NOT_MAPPED_ON_BUS if neither Primary + nor Secondary Slaves have mapped the transaction address. + + @returns rc=1 and Transaction ModelError=ME_BUS_SLAVE_PERMISSION_DENIED if the + transaction address is found on a Slave but the Slave permissions deny the + transaction mode. + + @returns rc=1 and Transaction ModelError= some other Model Error codes if the + Slave operation fails. + + @returns rc=0 and Transaction ModelError=ME_SUCCESS if the transaction was + successful. + */ + /// The basic method called to get a bus transaction done. + fapi::ReturnCode operation(Transaction& io_transaction); + + +protected: + + /// Primary list of "attached" bus elements like PibMemory, OciMemory and so forth + Slave* iv_primarySlaves; + + /// The Secondary list is used when the Primary list fails to contain a Transaction address + Slave* iv_secondarySlaves; + +}; + +//----------------------------------------------------------------------------- +/*! +Any kind of object attached to a Bus must be based upon the Slave class. +Each of the Bus devices must specify their base address, size, and permissions +as well as target and dataBuffer to be used for bus transactions. All these attributes +are defined by the base Slave class. +*/ +/// The Slave object contains the common attributes of all bus devices. +class Slave +{ +public: + + Slave(); + virtual ~Slave(); + + /// Slave based objects must be configured before use. + virtual void configure(fapi::Target* i_target, + ecmdDataBufferBase *i_dataBuffer, + uint32_t i_base, + uint64_t i_size, + int i_permissions); + + /*! + Notice that the operation is pure virtual in the Slave class. All derived bus attached + devices must define their own operation methods since they vary from one to the other. + */ + /// The Slave class also defines the fundamental operation that a Bus can call. + virtual fapi::ReturnCode operation(Transaction& io_transaction) = 0; // the slave instance will implement + + /*! + The iv_base address is specified in terms of the system, so for example it might be the first address + in a range beginning at 0x08000000 in the system memory, or it might be the first address in a range of + scom addresses in the system. + */ + /// The Bus devices base address. A System memory address or scom address, not an offset. + uint32_t iv_base; + + /// This specifies the number of bytes from the iv_base that this Bus device responds to. + uint64_t iv_size; + + /*! + For example: ACCESS_MODE_READ | ACCESS_MODE_WRITE | ACCESS_MODE_EXECUTE + */ + /// Establish the read/write/execute mode allowed upon this Bus device. + int iv_permissions; + + /// Points to the next Slave in a linked list that the Bus::operation will search + Slave* iv_next; + + /// A pointer to the fapi Target to be used when accessing this Bus device. + fapi::Target* iv_target; + + /// A pointer to the fapi DataBuffer to be used when accessing this Bus device. + ecmdDataBufferBase* iv_dataBuffer; + + +}; + + +//----------------------------------------------------------------------------- +/*! +The SCOM addresses of a system are defined by a call to configure to the PIB +slave for the system. There is no mapping done since there is no memory manager +involved. When the PIB bus manager is asked to perform an operation and if the +Transaction iv_address falls into the address range of the SCOM's then the +operation method for the Slave will be called, which will call the +PibSlave::getScom/putScom implemnted with fapiGet/Putscom. +*/ +/// Implements SCOM access to the system. +class PibSlave : public Slave +{ +public: + + PibSlave(); + virtual ~PibSlave(); + + /// Overriding Slave::operation + virtual fapi::ReturnCode operation(Transaction& io_transaction); + +protected: + + /*! + The i_offset is an actual scom address that has not been changed to implement + "core reduction" as an eCMD address might for certain chiplets. The address is + the raw native SCOM address used by the hardware. + + The calling Slave class object iv_target and iv_dataBuffer are used to perform + the operation. + + @returns rc= the value returned by fapi::GetScom + */ + /// PibSlave read calls fapi::GetScom + fapi::ReturnCode getScom(const uint32_t i_offset, uint64_t& o_data); + + /*! + The i_offset is an actual scom address that has not been changed to implement + "core reduction" as an eCMD address might for certain chiplets. The address is + the raw native SCOM address used by the hardware. + + The calling Slave class object iv_target and iv_dataBuffer are used to perform + the operation. + + @returns rc= the value returned by fapi::PutScom + */ + /// PibSlave write calls fapi::PutScom + fapi::ReturnCode putScom(const uint32_t i_offset, const uint64_t i_data); +}; + +//----------------------------------------------------------------------------- +/*! +This object has (virtual) methods to handle directly access memory. +*/ +/// Methods Used to access OTPROM. +class PibMemory : public PibSlave +{ +public: + + PibMemory(); + virtual ~PibMemory(); + + + /// Slave based objects must be configured before use. + virtual void configure(fapi::Target* i_target, + ecmdDataBufferBase *i_dataBuffer, + uint32_t i_base, + uint64_t i_size, + int i_permissions, + Memory* i_memory); + + /*! + Pass-through mode is established with a true value. This mode means that if a + PibMemory address is NOT_MAPPED_IN_MEMORY then the address of a transaction is + passed-through to the PibSlave::getScom or PibSlave::putScom method for resolution. + */ + /// Control the pass-through mode. True means pass-through mode is enabled. + void setPassThrough(const bool i_enable); + + /*! + Bus::operation already made sure the Transaction address is within our chunk of + memory and has set the Transaction::iv_offset. + + This operation accesses direct memory, like OTPROM. + + Transactions give us addresses on 64bit , or 8 byte, boundries. The address + passed into Memory::read or write is calculated as the Transaction::iv_offset * + 8. So, as example, if the Transaction::_iv_address was 0x08000000 and the + PibMemory Slave::iv_base were configured to 0x08000000 then the + Transaction::iv_offset would be 0x00000000. That multiplied by 8 remains + 0x00000000. If the Transaction address were 0x08000001, then the Transaction + offset would be 0x00000001, and that multiplied by 8 would be 0x00000008, the + reall offset into the eprom image we will read or write from. + + If a ACCESS_MODE_READ transaction is called for then the Memory::read method is + called passing the Transaction iv_offset to complete the operation. If Memory::read + returns ME_NOT_MAPPED_IN_MEMORY and if iv_passThrough is true then + PibSlave::getScom is called passing the Transaction iv_address. + + If a ACCESS_MODE_READ transaction is called for then the Memory::write method is + called passing the Transaction iv_offset to complete the operation. If Memory::write + returns ME_NOT_MAPPED_IN_MEMORY and if iv_passThrough is true then + PibSlave::putScom is called passing the Transaction iv_address. + + @returns rc=0 if transaction succeeded + @returns rc=1 if transaction failed and passThrough mode was not active + @returns rc!=0 if read/write failed and passThrough call to getScom/putScom also + failed. In this case the rc value is whatever getScom or putScom returns from + fapi. + + */ + /// Implement a PibMemory transaction. Called by the Bus::operation() + virtual fapi::ReturnCode operation(Transaction& io_transaction); + +protected: + + /// Remember the pass-through mode setting + bool iv_passThrough; + + /// Pointer to Memory manager storing a linked list of MemoryImage (s) "containing" mapped memory areas + Memory* iv_memory; + +}; + +//----------------------------------------------------------------------------- +/// Not sure what a OciSlave does yet +class OciSlave : public Slave +{ +public: + + virtual ~OciSlave(); + + /*! + Bus::operation already made sure the Transaction address is within our chunk of + memory and has set the Transaction::iv_offset. + + If a ACCESS_MODE_READ transaction is called for then the OciSlave::read method is + called passing the Transaction iv_address to complete the operation. + + If a ACCESS_MODE_WRITE transaction is called for then the OciSlave::write method is + called passing the Transaction iv_address to complete the operation. + + @returns rc=0 if transaction succeeded + @returns rc=1 if transaction failed + + */ + virtual fapi::ReturnCode operation(Transaction& io_transaction); + +protected: + + /*! + Called by OciSlave::operation. + */ + virtual fapi::ReturnCode read(const uint32_t i_address, uint64_t& o_data); + + /*! + Called by OciSlave::operation. + */ + virtual fapi::ReturnCode write(const uint32_t i_address, const uint64_t i_data); + +}; + +//----------------------------------------------------------------------------- +/// An OciSlave that accepts and simply swallows write transactions +class OciSlaveWritable : public OciSlave +{ +public: + virtual fapi::ReturnCode write(const uint32_t i_address, const uint64_t i_data); +}; + +//----------------------------------------------------------------------------- +/// Methods Used to access Mainstore/SRAM +class OciMemory : public OciSlave +{ +public: + + OciMemory(); + virtual ~OciMemory(); + + /// Slave based objects must be configured before use. + virtual void configure(fapi::Target* i_target, + ecmdDataBufferBase *i_dataBuffer, + uint32_t i_base, + uint64_t i_size, + int i_permissions, + Memory* i_memory); + + /*! + Bus::operation already made sure the Transaction address is within our chunk of + memory and has set the Transaction::iv_offset. + + This operation accesses memory like Mainstore or SRAM memory. + + Transactions to the OCI bus give us addresses on byte boundries. The offset + passed into Memory::read or write is therefore simply the + Transaction::iv_offset without modification. + + If a ACCESS_MODE_READ transaction is called for then the Memory::read method is + called passing the Transaction iv_offset to complete the operation. If Memory::read + returns ME_NOT_MAPPED_IN_MEMORY and if iv_passThrough is true then + OciSlave::read is called passing the Transaction iv_address. + + If a ACCESS_MODE_READ transaction is called for then the Memory::write method is + called passing the Transaction iv_offset to complete the operation. If Memory::write + returns ME_NOT_MAPPED_IN_MEMORY and if iv_passThrough is true then + OciSlave::write is called passing the Transaction iv_address. + + @returns rc=0 if transaction succeeded + @returns rc=1 if transaction failed and passThrough mode was not active + @returns rc!=0 if read/write failed and passThrough call to OciSlave::read/write also + failed. In this case the rc value is whatever OciSlave::read or OciSlave::write returns. + */ + /// Implement a OciMemory transaction. Called by the Bus::operation() + virtual fapi::ReturnCode operation(Transaction& io_transaction); + + /*! + Pass-through mode is established with a true value. This mode means that if a + OciMemory address is NOT_MAPPED_IN_MEMORY then the address of a transaction is + passed-through to the OciSlave::read or OciSlave::write method for resolution. + */ + /// Control the pass-through mode. True means pass-through mode is enabled. + void setPassThrough(const bool i_enable); + + /// Pointer to Memory manager storing a linked list of MemoryImage (s) "containing" mapped memory areas + Memory *iv_memory; + +protected: + + /// Remember the pass-through mode setting + bool iv_passThrough; +}; + + +//----------------------------------------------------------------------------- +/// Store details of a block of memory being managed by a Memory manager +class MemoryImage +{ +public: + + /*! + A MemoryImage is used to store information about a portion of Memory that has been mapped. + It is created by the Memory::map method. + + @param i_base A zero based offset from the Slave iv_base address + @param i_size Size of i_image in bytes + @param i_permissions The read/write/execute permissions over this block of memory + @param i_image A pointer to an allocated block of memory storing the content of the block of memory + @param i_crcEnable true or false indicating whether crc is to be calculated over the block of memory + */ + MemoryImage(uint32_t i_base, + size_t i_size, + int i_permissions, + void* i_image, + bool i_crcEnable ); + + virtual ~MemoryImage(); + + /*! + When this method is called the crc of the associated MemoryImage is calculated + and compared to iv_originalCrc which was the crc value at the time that the + MemoryImage was mapped into the Memory. + + @returns true if iv_originalCrc == the current crc of the MemoryImage or if crc + checking is not enabled for the MemoryImage. + @returns false if crc checking is enabled and the crc values do not match. + */ + /// true if iv_originalCrc == current crc, or if iv_crcEnable == false + virtual bool checkCrc(); + + /// base address associated with iv_image in the system (not real address of iv_image) + uint32_t iv_base; + + /// byte size of the block of memory pointed to by iv_image + size_t iv_size; + + /// Access permissions over this block of memory (ACCESS_MODE_READ | ACCESS_MODE_WRITE | ACCESS_MODE_EXECUTE) + int iv_permissions; + + /// Pointer to the chunk of memory a user has allocated and stored eprom image into + void* iv_image; + + /// Remember if told to compute crc or not via i_crcEnable + bool iv_crcEnable; + + /// Link to next MemoryImage in the Memory managers circular linked list + MemoryImage* iv_next; + +protected: + + /// Method to calculate crc over iv_image + virtual uint64_t computeCrc(); + + /// If iv_crcEnable is true this is the calculated crc over iv_image at the time it was mapped into Memory + uint64_t iv_originalCrc; +}; + +//----------------------------------------------------------------------------- +/// Contains one or many MemoryImages for a certain type of memory +class Memory +{ +public: + + Memory(); + virtual ~Memory(); + + /*! + The map method is used to register a pointer to a contiguous block of memory + that contains some part of an eeprom image, as well as to declare the offset + from the system base address, the size, and access permissions of that block of + memory. + + The iv_images pointer of the Memory manager points to one or many MemoryImages. + Each time this map method is called a new MemoryImage object is created to + remember all the details about the i_image being passed in. The new MemoryImage + is placed into a circular linked list owned by the Memory manager. + + The Memory manager is always associated with a particuliar kind of memory, like + PibMemory or OciMemory, so the i_image is some portion of PibMemory or + OciMemory. As an example, suppose OTPROM is 0x01000000 bytes in the system, + starting at address 0x80000000. Also suppose you have parts of the OTPROM from + 0x80000000 to 0x80000100 and from 0x80010000 to 0x80010500 in two image files + that you have read into program memory and you want to map into the OTPROM + Memory manager. When calling the configure method on the PibMemory you declare + OTPROM memory starts at 0x80000000 and has 0x01000000 bytes. Then you call map + on the PibMemory manager twice, first declaring an offset 0x00000000 for + 0x00000100 bytes, then again with offset 0x00010000 for 0x00000500 bytes. + + @param i_base A zero based offset from the Slave iv_base address + @param i_size Size of i_image in bytes + @param i_permissions The read/write/execute permissions over this block of memory + @param i_image A pointer to an allocated block of memory storing the content of the block of memory + @param i_crcEnable true or false indicating whether crc is to be calculated over the block of memory + @returns ME_SUCCESS if all's well (currently that's all it can return) + */ + /// Register a "chunk" of memory to the Memory manager + virtual ModelError map(uint32_t i_base, + size_t i_size, + int i_permissions, + void* i_image, + bool i_crcEnable); + + /*! + This method runs through every MemoryImage checking its crc. + + @returns true if all MemoryImage have the same crc as when they were originally mapped into Memory + @returns false if any MemoryImage has a crc that is different + */ + /// Check if crc of all MemoryImages is still the same as when it was originally mapped into Memory + virtual bool checkCrc(); + + /*! + This method is used to read Direct Memory out of an eprom image. An offset from + the base of the eprom memory image is passed in for the access, along with the + number of bytes to read. + + The memory storage may be split into more than one MemoryImage's that have been + mapped. This method runs through the circuliarly linked list of MemoryImage objects + looking for one that contains the block of memory being accessed. + + Upon successfully finding a containing MemoryImage the Memory::iv_images is set + to point to the MemoryImage just found. This should speed up operation assuming + a large number of transactions might occur on contiguous blocks of memory. + + The data are copied out of the MemoryImage::iv_image into the o_data buffer for + return. The Endianess of the host platform being used is considered as this + operation occurs. (It is assumed the MemoryImage::iv_image is stored in + BigEndian order.) + + @returns If there is no MemoryImage that contains the block of memory requested + then ME_NOT_MAPPED_IN_MEMORY is returned. + + @returns If the memory block is found within a MemoryImage but the + MemoryImage::iv_permissions do not permit ACCESS_MODE_READ then + ME_MEMORY_IMAGE_PERMISSION_DENIED is returned. + + @returns ME_SUCCESS if all bytes of the memory requested are contained in the + MemoryImage and the permissions of the MemoryImage allow ACCESS_MODE_READ. + + */ + /// Used to find a MemoryImage from which to read data + virtual ModelError read(uint32_t i_offset, + uint64_t& o_data, + size_t i_size + ); + + /*! + This method is used to fetch instructions from Direct Memory out of an eprom + image. An offset from the base of the eprom memory image is passed in for the + access, along with the number of bytes to read. + + The memory storage may be split into more than one MemoryImage's that have been + mapped. This method runs through the circuliarly linked list of MemoryImage objects + looking for one that contains the block of memory being accessed. + + Upon successfully finding a containing MemoryImage the Memory::iv_images is set + to point to the MemoryImage just found. This should speed up operation assuming + a large number of transactions might occur on contiguous blocks of memory. + + The data are copied out of the MemoryImage::iv_image into the o_data buffer for + return. The Endianess of the host platform being used is considered as this + operation occurs. (It is assumed the MemoryImage::iv_image is stored in + BigEndian order.) + + @returns If there is no MemoryImage that contains the block of memory requested + then ME_NOT_MAPPED_IN_MEMORY is returned. + + @returns If the memory block is found within a MemoryImage but the + MemoryImage::iv_permissions do not permit ACCESS_MODE_EXECUTE then + ME_MEMORY_IMAGE_PERMISSION_DENIED is returned. + + @returns ME_SUCCESS if all bytes of the memory requested are contained in the + MemoryImage and the permissions of the MemoryImage allow ACCESS_MODE_EXECUTE. + + */ + /// Used to find a MemoryImage from which to fetch instructions + virtual ModelError fetch(uint32_t i_offset, + uint64_t& o_data, + size_t i_size + ); + + /*! + This method is used to write Direct Memory out of an eprom image. An offset from + the base of the eprom memory image is passed in for the access, along with the + number of bytes to write. + + The memory storage may be split into more than one MemoryImage's that have been + mapped. This method runs through the circuliarly linked list of MemoryImage objects + looking for one that contains the block of memory being accessed. + + Upon successfully finding a containing MemoryImage the Memory::iv_images is set + to point to the MemoryImage just found. This should speed up operation assuming + a large number of transactions might occur on contiguous blocks of memory. + + The data are copied out of the i_data buffer into the MemoryImage::iv_image. The + Endianess of the host platform being used is considered as this operation + occurs. (It is assumed the MemoryImage::iv_image is stored in BigEndian order.) + + @returns If there is no MemoryImage that contains the block of memory requested + then ME_NOT_MAPPED_IN_MEMORY is returned. + + @returns If the memory block is found within a MemoryImage but the + MemoryImage::iv_permissions do not permit ACCESS_MODE_WRITE then + ME_MEMORY_IMAGE_PERMISSION_DENIED is returned. + + @returns ME_SUCCESS if all bytes of the memory requested are contained in the + MemoryImage and the permissions of the MemoryImage allow ACCESS_MODE_WRITE. + + */ + /// Used to find a MemoryImage to change + virtual ModelError write(uint32_t i_offset, + uint64_t i_data, + size_t i_size); + + /// Pointer to first MemoryImage in a circularly linked list + MemoryImage* iv_images; + +#if POREVE_STATISTICS + + /// Reset Memory usage statistics + /// + /// This API clears the instance variables iv_reads, iv_writes and + /// iv_fetches. + void + resetStatistics(); + + /// Number of read() calls for this memory + uint64_t iv_reads; + + /// Number of write() calls for this memory + uint64_t iv_writes; + + /// Number of fetch() calls for this memory + uint64_t iv_fetches; + +#endif // POREVE_STATISTICS + +}; + + + + + + + + + +} // end of namespace vsbe +#endif diff --git a/src/usr/pore/poreve/porevesrc/create.C b/src/usr/pore/poreve/porevesrc/create.C new file mode 100644 index 000000000..8e0d8d636 --- /dev/null +++ b/src/usr/pore/poreve/porevesrc/create.C @@ -0,0 +1,46 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/porevesrc/create.C $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +// $ID$ + +/// \file create.C +/// \brief The create method for PoreVe +/// +/// The PoreVe class declares a static create() method that allows link-time +/// selection of a normal vs. debug version of PoreVe. This is similar to the +/// same idea used to make a link-time selection of the Pore hardware model +/// (PMX vs. BOE). This create() method is linked into the poreve.so. The +/// create() method for PoreVeDbg is defined in dbg.C + +#include "poreve.H" + +using namespace vsbe; + +PoreVe* +PoreVe::create(const PoreIbufId i_id, + const fapi::Target i_masterTarget, + const void* i_arg) +{ + // i_arg is needed for subclass to instantiate and the (debug) subclass. + return new PoreVe(i_id, i_masterTarget); +} + diff --git a/src/usr/pore/poreve/porevesrc/fasti2c.C b/src/usr/pore/poreve/porevesrc/fasti2c.C new file mode 100644 index 000000000..676fdccda --- /dev/null +++ b/src/usr/pore/poreve/porevesrc/fasti2c.C @@ -0,0 +1,604 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/porevesrc/fasti2c.C $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +// $Id: fasti2c.C,v 1.5 2012/01/10 00:27:41 bcbrock Exp $ + +/// \file fasti2c.C +/// \brief The "fast-mode" I2C controllers and I2C memory models used +/// to implement the OTPROM, PNOR and SEEPROM interfaces. + +#include "fasti2c.H" + +/// Diagnostic aid for debugging fasti2c.C +#ifdef DEBUG_FASTI2C +#define BUG() \ + FAPI_ERR("\n>>> fasti2c:Bug trapped at %s:%d\n\n", \ + __FILE__, __LINE__) +#else +#define BUG() +#endif // DEBUG_FASTI2C + +using namespace vsbe; + +//////////////////////////////////////////////////////////////////////////// +// I2cMemory +//////////////////////////////////////////////////////////////////////////// + +I2cMemory::I2cMemory(const size_t i_addressBytes) : +iv_addressBytes(i_addressBytes), iv_address(0) +{ +} + + +I2cMemory::~I2cMemory() +{ +} + + +ModelError +I2cMemory::addressWrite(const size_t i_bytes, const uint32_t i_address) +{ + ModelError me; + + if (i_bytes != iv_addressBytes) { + BUG(); + me = ME_I2CMEMORY_ILLEGAL_ADDRESS; + } else { + me = ME_SUCCESS; + iv_address = i_address; + } + return me; +} + + +ModelError +I2cMemory::dataRead(const size_t i_bytes, uint64_t& o_data) +{ + ModelError me; + + me = read(iv_address, o_data, i_bytes); + if (me == 0) { + iv_address += i_bytes; + } + return me; +} + + +ModelError +I2cMemory::dataWrite(const size_t i_bytes, const uint64_t i_data) +{ + ModelError me; + + me = write(iv_address, i_data, i_bytes); + if (me == 0) { + iv_address += i_bytes; + } + return me; +} + + +//////////////////////////////////////////////////////////////////////////// +// FastI2cController +//////////////////////////////////////////////////////////////////////////// + +FastI2cController::FastI2cController() : + iv_devices(0), + iv_state(IDLE), iv_fifo(0) + +{ + iv_status.value = 0; + iv_control.value = 0; +} + + +// The destructor deletes the circular list of devices. + +FastI2cController::~FastI2cController() +{ + I2cDevice *p, *next; + + if (iv_devices != 0) { + for (p = iv_devices->next; p != iv_devices; p = next) { + next = p->next; + delete p; + } + delete iv_devices; + } +} + + +ModelError +FastI2cController::attachMemory(I2cMemory* i_memory, + const unsigned i_port, + const unsigned i_deviceAddress) +{ + ModelError me = ME_SUCCESS; + FastI2cControlRegister control; // Used to validate i_Port and i_deviceId + I2cDevice* device = new I2cDevice; + + control.fields.port_number = i_port; + control.fields.device_address = i_deviceAddress; + // Make sure input variables fits into control fields + if ((control.fields.port_number != i_port) || + (control.fields.device_address != i_deviceAddress)) { + BUG(); + me = ME_INVALID_ARGUMENT; + + } else { + + device->iv_port = i_port; + device->iv_deviceAddress = i_deviceAddress; + device->iv_memory = i_memory; + + if (iv_devices == 0) { + iv_devices = device; + device->next = device; + } else { + + if (findDevice(i_port, i_deviceAddress) != 0) { + BUG(); + me = ME_DUPLICATE_CONFIGURATION; + } else { + device->next = iv_devices->next; + iv_devices->next = device; + } + } + } + if (me != 0) { + delete device; + } + return me; +} + + +// Modeling notes: +// +// o The RESET register is not modeled here +// +// o Our models ignore the I2C Speed +// +// o Transactions complete in 0 time and polling always succeeds on the first +// read of the status register. This is done to simplify the PORE +// engine model. +// +// o Only the following types of control register actions are modeled: +// * Address write : with_start; with_address; !with_continue; with_stop; +// data_length == 0 +// * Data read : with_start; with_address; !with_continue; with_stop; +// data_length == [4,8] +// * Data write : with_start; with_address; !with_continue; with_stop; +// data_length == 8 +// +// o The memory models hold the last address written +// +// o Redundant reads of the STATUS register are allowed +// +// o PORE only does 4/8 byte reads and 8 byte writes, so any other data +// access is considered an error (although the models could easily be +// extended to allow them). + +fapi::ReturnCode +FastI2cController::operation(Transaction& io_transaction) +{ + ModelError me; + fapi::ReturnCode rc; + + if (0) { + if (io_transaction.iv_mode == ACCESS_MODE_WRITE) { + FAPI_DBG("FASTI2C : write : offset = %u, data = 0x%016llx\n", + io_transaction.iv_offset, + io_transaction.iv_data); + } else { + FAPI_DBG("FASTI2C : read : offset = %u\n", + io_transaction.iv_offset); + } + } + + switch (io_transaction.iv_offset) { + + case FASTI2C_CONTROL_OFFSET: + + if (io_transaction.iv_mode != ACCESS_MODE_WRITE) { + BUG(); + me = ME_WRITE_ONLY_REGISTER; + + } else if (iv_state != IDLE) { + BUG(); + me = ME_FASTI2C_SEQUENCE_ERROR; + + } else { + + iv_control.value = io_transaction.iv_data; + + if (!iv_control.fields.with_start || + !iv_control.fields.with_address || + iv_control.fields.read_continue || + !iv_control.fields.with_stop) { + BUG(); + me = ME_FASTI2C_CONTROL_ERROR; + + } else if (iv_control.fields.read_not_write == 0) { + + if (iv_control.fields.address_range == 0) { + BUG(); + me = ME_FASTI2C_CONTROL_ERROR; + + } else { + if (iv_control.fields.data_length == 0) { + me = addressWrite(); + + } else if (iv_control.fields.data_length != 8) { + BUG(); + me = ME_FASTI2C_CONTROL_ERROR; + + } else { + me = initialDataWrite(); + } + } + } else { + if ((iv_control.fields.data_length != 4) && + (iv_control.fields.data_length != 8)) { + BUG(); + me = ME_FASTI2C_CONTROL_ERROR; + } else { + me = dataRead(); + } + } + } + break; + + + case FASTI2C_STATUS_OFFSET: + + if (io_transaction.iv_mode != ACCESS_MODE_READ) { + BUG(); + me = ME_READ_ONLY_REGISTER; + + } else { + + switch (iv_state) { + + case ADDRESS_WRITE_ONGOING: + case DATA_WRITE_ONGOING: + iv_status.value = 0; + iv_status.fields.i2c_command_complete = 1; + io_transaction.iv_data = iv_status.value; + iv_state = IDLE; + me = ME_SUCCESS; + break; + + case DATA_READ_ONGOING: + iv_status.value = 0; + iv_status.fields.i2c_command_complete = 1; + iv_status.fields.i2c_fifo_entry_count = + iv_control.fields.data_length; + io_transaction.iv_data = iv_status.value; + iv_state = DATA_AVAILABLE; + me = ME_SUCCESS; + break; + + case IDLE: + io_transaction.iv_data = iv_status.value; + me = ME_SUCCESS; + break; + + default: + BUG(); + me = ME_FASTI2C_SEQUENCE_ERROR; + break; + } + } + break; + + + case FASTI2C_DATA_OFFSET: + + if ((io_transaction.iv_mode == ACCESS_MODE_READ) || + (io_transaction.iv_mode == ACCESS_MODE_EXECUTE)) { + + switch (iv_state) { + + case DATA_AVAILABLE: + io_transaction.iv_data = iv_fifo; + iv_state = IDLE; + me = ME_SUCCESS; + break; + + default: + BUG(); + me = ME_FASTI2C_SEQUENCE_ERROR; + break; + } + } else { + + switch (iv_state) { + + case WRITE_DATA_EXPECTED: + me = finalDataWrite(io_transaction.iv_data); + iv_state = DATA_WRITE_ONGOING; + + default: + BUG(); + me = ME_FASTI2C_SEQUENCE_ERROR; + break; + } + } + break; + + + default: + BUG(); + me = ME_ILLEGAL_REGISTER_OFFSET; + break; + } + + if (me != 0) { + iv_state = ERROR; + rc = 1; // \bug Fix this + } + io_transaction.busError(me); + return rc; +} + + +// Find the device in the circular device list and spin the device to the +// front of the list if found. + +I2cDevice* +FastI2cController::findDevice(const unsigned i_port, + const unsigned i_deviceAddress) +{ + I2cDevice* p; + + p = iv_devices; + if (p != 0) { + do { + if ((p->iv_port == i_port) && + (p->iv_deviceAddress == i_deviceAddress)) { + iv_devices = p; + break; + } + if (p == iv_devices) { + p = 0; + break; + } + } while(1); + } + return p; +} + + +uint32_t +FastI2cController::getI2cAddress(const FastI2cControlRegister i_control) +{ + size_t addressBytes = i_control.fields.address_range; + + return i_control.words.low_order >> ((4 - addressBytes) * 8); +} + + +// The address is left-justified in the low-order 32 bits of the control +// register. + +ModelError +FastI2cController::addressWrite() +{ + ModelError me; + unsigned port = iv_control.fields.port_number; + unsigned deviceAddress = iv_control.fields.device_address; + size_t addressBytes = iv_control.fields.address_range; + I2cDevice* p; + + p = findDevice(port, deviceAddress); + if (p == 0) { + BUG(); + me = ME_NOT_MAPPED_ON_FASTI2C_CONTROLLER; + } else { + me = p->iv_memory->addressWrite(addressBytes, + getI2cAddress(iv_control)); + iv_state = ADDRESS_WRITE_ONGOING; + } + return me; +} + + +ModelError +FastI2cController::dataRead() +{ + ModelError me; + unsigned port = iv_control.fields.port_number; + unsigned deviceAddress = iv_control.fields.device_address; + size_t dataBytes = iv_control.fields.data_length; + uint64_t data; + I2cDevice* p; + + p = findDevice(port, deviceAddress); + if (p == 0) { + BUG(); + me = ME_NOT_MAPPED_ON_FASTI2C_CONTROLLER; + } else { + me = p->iv_memory->dataRead(dataBytes, data); + iv_fifo = data << (64 - (dataBytes * 8)); + iv_state = DATA_READ_ONGOING; + } + return me; +} + + +// For addresses < 4 bytes, the first slug of data occupies the remainder of +// the low-order word of the control register. Any remaining bytes come in on +// the next transaction targeting the data register. This code assumes 8-byte +// only data writes. + +ModelError +FastI2cController::initialDataWrite() +{ + unsigned addressBytes = iv_control.fields.address_range; + + if (addressBytes < 4) { + iv_fifo = + BE64_GET_FIELD(iv_control.words.low_order, + 32 + (addressBytes * 8), + 63) << + ((4 - addressBytes) * 8); + } + iv_state = WRITE_DATA_EXPECTED; + return ME_SUCCESS; +} + + +// Assume 8-byte only write transactions + +ModelError +FastI2cController::finalDataWrite(const uint64_t i_data) +{ + ModelError me; + unsigned port = iv_control.fields.port_number; + unsigned deviceAddress = iv_control.fields.device_address; + size_t addressBytes = iv_control.fields.address_range; + I2cDevice* p; + + iv_fifo = + BE64_SET_FIELD(iv_fifo, addressBytes * 8, 63, + BE64_GET_FIELD(i_data, 0, + ((8 - addressBytes) * 8)) - 1); + + p = findDevice(port, deviceAddress); + if (p == 0) { + BUG(); + me = ME_NOT_MAPPED_ON_FASTI2C_CONTROLLER; + } else { + me = p->iv_memory->dataWrite(8, iv_fifo); + iv_state = DATA_WRITE_ONGOING; + } + return me; +} + + +//////////////////////////////////////////////////////////////////////////// +// LpcController +//////////////////////////////////////////////////////////////////////////// + +LpcController::LpcController() : + iv_eccStart(0), + iv_eccStop(LPC_MEMORY_MAX_SIZE) +{ +} + + +LpcController::~LpcController() +{ +} + + +fapi::ReturnCode +LpcController::operation(Transaction& io_transaction) +{ + ModelError me = ME_SUCCESS; + fapi::ReturnCode rc; + bool handledBySuperclass = false; + FastI2cControlRegister control; + uint32_t address; + + switch (io_transaction.iv_offset) { + + case LPCM_ECC_START_OFFSET: + + if (iv_state != IDLE) { + BUG(); + me = ME_FASTI2C_SEQUENCE_ERROR; + + } else if (io_transaction.iv_mode == ACCESS_MODE_READ) { + io_transaction.iv_data = iv_eccStart; + me = ME_SUCCESS; + + } else if (io_transaction.iv_mode == ACCESS_MODE_WRITE) { + iv_eccStart = io_transaction.iv_data; + me = ME_SUCCESS; + + } else { + BUG(); + me = ME_BUS_SLAVE_PERMISSION_DENIED; + } + break; + + case LPCM_ECC_STOP_OFFSET: + + if (iv_state != IDLE) { + BUG(); + me = ME_FASTI2C_SEQUENCE_ERROR; + + } else if (io_transaction.iv_mode == ACCESS_MODE_READ) { + io_transaction.iv_data = iv_eccStop; + me = ME_SUCCESS; + + } else if (io_transaction.iv_mode == ACCESS_MODE_WRITE) { + iv_eccStop = io_transaction.iv_data; + me = ME_SUCCESS; + + } else { + BUG(); + me = ME_BUS_SLAVE_PERMISSION_DENIED; + } + break; + + default: + + if ((io_transaction.iv_offset == FASTI2C_CONTROL_OFFSET) && + (io_transaction.iv_mode == ACCESS_MODE_WRITE)) { + + control.value = io_transaction.iv_data; + address = getI2cAddress(control); + if ((address < iv_eccStart) || (address >= iv_eccStop)) { + BUG(); + me = ME_LPC_ILLEGAL_ADDRESS; + + } else { + + handledBySuperclass = true; + rc = FastI2cController::operation(io_transaction); + } + } else { + + handledBySuperclass = true; + rc = FastI2cController::operation(io_transaction); + } + break; + } + if (!handledBySuperclass) { + if (me != 0) { + rc = 1; // \bug Fix this; + } + io_transaction.busError(me); + } + return rc; +} + + + + + + + + + + diff --git a/src/usr/pore/poreve/porevesrc/fasti2c.H b/src/usr/pore/poreve/porevesrc/fasti2c.H new file mode 100644 index 000000000..a21288e94 --- /dev/null +++ b/src/usr/pore/poreve/porevesrc/fasti2c.H @@ -0,0 +1,564 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/porevesrc/fasti2c.H $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#ifndef __VSBE_FASTI2C_H +#define __VSBE_FASTI2C_H + +// $Id: fasti2c.H,v 1.5 2011/12/16 20:27:26 bcbrock Exp $ + +/// \file fasti2c.H +/// \brief The "fast-mode" I2C controllers and memory models used +/// to implement the OTPROM, PNOR and SEEPROM interfaces. + +#include <fapi.H> + +#include <stddef.h> +#include <stdint.h> + +#include "bebits.H" +#include "bus.H" + +namespace vsbe { + + class FastI2cController; + class LpcController; + class I2cMemory; + + /// \defgroup fasti2c_speeds Fast-Mode I2C Controller Speeds + /// + /// Note that all speeds are considered "legal", and the model does not + /// interpret the speed setting. + /// + /// @{ + + const int FASTI2C_SPEED_100K = 0; + const int FASTI2C_SPEED_400K = 1; + const int FASTI2C_SPEED_3400K = 2; + const int FASTI2C_SPEED_50K = 3; + + /// @} + + /// \defgroup fasti2c_offsets Fast-Mode I2C Controller Register Offsets (PIB) and limits + /// + /// The last two offsets are only valid on the LpcController model. + /// @{ + + const uint32_t FASTI2C_CONTROL_OFFSET = 0x0; + const uint32_t FASTI2C_RESET_OFFSET = 0x1; + const uint32_t FASTI2C_STATUS_OFFSET = 0x2; + const uint32_t FASTI2C_DATA_OFFSET = 0x3; + const size_t FASTI2C_REGISTERS = 0x4; + + const uint32_t LPCM_ECC_START_OFFSET = 0x4; + const uint32_t LPCM_ECC_STOP_OFFSET = 0x5; + const size_t LPCM_REGISTERS = 0x6; + + /// @} + + /// The maximum memory size supported by the LPC controller (64MB) + const uint32_t LPC_MEMORY_MAX_SIZE = (1 << 26); + + + // These register layouts are copied/modified from the PMX model. If they + // need to be modified here then they will also need to be modified in the + // PMX model. + + /// Fast-Mode I2C Controller Control Register Layout + typedef union { + + uint64_t value; + struct { +#ifdef _BIG_ENDIAN + uint32_t high_order; + uint32_t low_order; +#else + uint32_t low_order; + uint32_t high_order; +#endif // _BIG_ENDIAN + } words; + struct { +#ifdef _BIG_ENDIAN + uint64_t with_start : 1; + uint64_t with_address : 1; + uint64_t read_continue : 1; + uint64_t with_stop : 1; + uint64_t data_length : 4; + uint64_t device_address : 7; + uint64_t read_not_write : 1; + uint64_t speed : 2; + uint64_t port_number : 5; + uint64_t address_range : 3; + uint64_t _reserved0 : 6; + uint64_t data0 : 8; + uint64_t data1 : 8; + uint64_t data2 : 8; + uint64_t data3 : 8; +#else + uint64_t data3 : 8; + uint64_t data2 : 8; + uint64_t data1 : 8; + uint64_t data0 : 8; + uint64_t _reserved0 : 6; + uint64_t address_range : 3; + uint64_t port_number : 5; + uint64_t speed : 2; + uint64_t read_not_write : 1; + uint64_t device_address : 7; + uint64_t data_length : 4; + uint64_t with_stop : 1; + uint64_t read_continue : 1; + uint64_t with_address : 1; + uint64_t with_start : 1; +#endif // _BIG_ENDIAN + } fields; + } FastI2cControlRegister; + + + /// Fast-Mode I2C Controller Reset Register Layout + typedef union { + + uint64_t value; + struct { +#ifdef _BIG_ENDIAN + uint32_t high_order; + uint32_t low_order; +#else + uint32_t low_order; + uint32_t high_order; +#endif // _BIG_ENDIAN + } words; + struct { +#ifdef _BIG_ENDIAN + uint64_t value : 64; +#else + uint64_t value : 64; +#endif // _BIG_ENDIAN + } fields; + } FastI2cResetRegister; + + + /// Fast-Mode I2C Controller Status Register Layout + typedef union { + + uint64_t value; + struct { +#ifdef _BIG_ENDIAN + uint32_t high_order; + uint32_t low_order; +#else + uint32_t low_order; + uint32_t high_order; +#endif // _BIG_ENDIAN + } words; + struct { +#ifdef _BIG_ENDIAN + uint64_t pib_address_invalid : 1; + uint64_t pib_write_invalid : 1; + uint64_t pib_read_invalid : 1; + uint64_t pib_address_parity_error : 1; + uint64_t pib_parity_error : 1; + uint64_t lb_parity_error : 1; + uint64_t read_data : 32; + uint64_t _reserved0 : 6; + uint64_t i2c_macro_busy : 1; + uint64_t i2c_invalid_command : 1; + uint64_t i2c_parity_error : 1; + uint64_t i2c_back_end_overrun_error : 1; + uint64_t i2c_back_end_access_error : 1; + uint64_t i2c_arbitration_lost : 1; + uint64_t i2c_nack_received : 1; + uint64_t i2c_data_request : 1; + uint64_t i2c_command_complete : 1; + uint64_t i2c_stop_error : 1; + uint64_t i2c_port_busy : 1; + uint64_t i2c_interface_busy : 1; + uint64_t i2c_fifo_entry_count : 8; +#else + uint64_t i2c_fifo_entry_count : 8; + uint64_t i2c_interface_busy : 1; + uint64_t i2c_port_busy : 1; + uint64_t i2c_stop_error : 1; + uint64_t i2c_command_complete : 1; + uint64_t i2c_data_request : 1; + uint64_t i2c_nack_received : 1; + uint64_t i2c_arbitration_lost : 1; + uint64_t i2c_back_end_access_error : 1; + uint64_t i2c_back_end_overrun_error : 1; + uint64_t i2c_parity_error : 1; + uint64_t i2c_invalid_command : 1; + uint64_t i2c_macro_busy : 1; + uint64_t _reserved0 : 6; + uint64_t read_data : 32; + uint64_t lb_parity_error : 1; + uint64_t pib_parity_error : 1; + uint64_t pib_address_parity_error : 1; + uint64_t pib_read_invalid : 1; + uint64_t pib_write_invalid : 1; + uint64_t pib_address_invalid : 1; +#endif // _BIG_ENDIAN + } fields; + } FastI2cStatusRegister; + +}; + + +//////////////////////////////////////////////////////////////////////////// +// I2cMemory +//////////////////////////////////////////////////////////////////////////// + + +/// An I2C memory model +/// +/// The I2cMemory is a subclass of the Memory. It adds a device address for +/// mapping onto an I2c bus, and also supports I2C memory operations such as +/// addressWrite() and dataRead(). + +class +vsbe::I2cMemory : public Memory +{ + +public: + + ////////////////////////////// Types ////////////////////////////// + + ////////////////////////////// Creators ////////////////////////////// + + /// Create an I2c Memory + /// + /// \param[in] i_addressBytes The number of bytes (1-4) in a memory + /// address for this memory. + I2cMemory(const size_t i_addressBytes); + + virtual ~I2cMemory(); + + ///////////////////////////// Accessors ////////////////////////////// + + //////////////////////////// Manipulators //////////////////////////// + + /// Perform an I2C address write to an attached device. + /// + /// \param[in] i_bytes The number of address bytes, which must match the + /// configuration. + /// + /// \param[in] i_address The memory address. + /// + /// \retval me ModelError return code + ModelError + addressWrite(const size_t i_bytes, const uint32_t i_address); + + /// Perform an I2C data read from an attached device. + /// + /// \param[in] i_bytes The number of data bytes to read + /// + /// \param[out] o_data The data, right justified + /// + /// The read has a side effect of incrementing the address held in the + /// device by \a i_bytes. + /// + /// \retval me ModelError return code + ModelError + dataRead(const size_t i_bytes, uint64_t& o_data); + + /// Perform an I2C data write to an attached device. + /// + /// \param[in] i_bytes The number of data bytes to write + /// + /// \param[in] i_data The data, right justified + /// + /// The write has a side effect of incrementing the address held in the + /// device by \a i_bytes. + /// + /// \retval me ModelError return code + ModelError + dataWrite(const size_t i_bytes, const uint64_t i_data); + + + ////////////////////////// Implementation //////////////////////////// + +protected: + + /// The number of address bytes (1-4) + const size_t iv_addressBytes; + + /// The address register, auto-incremented on data reads and writes + uint32_t iv_address; + + ///////////////////////////// Safety ////////////////////////////////// + +private: + I2cMemory(const I2cMemory& i_rhs); + I2cMemory& operator=(const I2cMemory& i_rhs); +}; + + +//////////////////////////////////////////////////////////////////////////// +// I2cDevice +//////////////////////////////////////////////////////////////////////////// + +namespace vsbe { + +/// A simple I2C device/bus model +/// +/// This simple device/bus model is used by the FastI2cController to model the +/// atachment of multiple I2cMemory to the physical busses (ports) controlled +/// by each controller. Normally only 1 or two devices are attached to each +/// controller so it's easiest to model all devices under control of a +/// controller as a single list. + +typedef struct I2cDevice { + + /// The controller port number - associated with a physical I2C bus + unsigned iv_port; + + /// The device address of the device on the bus + unsigned iv_deviceAddress; + + /// The I2cMemory + I2cMemory* iv_memory; + + /// The next I2cdevice in the list of devices + struct I2cDevice* next; + +} I2cDevice; + +}; + +//////////////////////////////////////////////////////////////////////////// +// FastI2cController +//////////////////////////////////////////////////////////////////////////// + + +/// A model of a "fast-mode" I2C Controller +/// +/// The PORE engine only uses the new "fast-mode" protocol to communicate with +/// "I2C Controllers" that implement the physical memory interfaces for SBE +/// memories. These controllers may be either real I2C controllers (like for +/// SEEPROM) or pseudo-I2C-controllers like the PNOR and OTPROM controllers. +/// The "fast-mode" is a new subset of the full I2C controller interface that +/// only uses 4 registers. This model only models fast-mode accesses, and +/// only in the precise way that PORE engines use fast-mode controllers for +/// memory fetches, loads and stores. It will return errors for use of the +/// legacy mode registers or otherwise legal sequences that are simply not +/// modeled. +/// +/// Each controller manages a number of "ports". Each port is a physical I2C +/// bus, and devices attached to each port (bus) must have unique device IDs. +/// We model the devices attached to a port independently. Each controller +/// maintains a list of I2cDevice mapped to its ports. The underlying +/// devices are currently all of the I2cMemory class. + +class +vsbe::FastI2cController : public PibSlave +{ + +public: + + ////////////////////////////// Types ////////////////////////////// + + /// \enum FastI2cState + /// + /// The state of the controller. Sequences of register operations are + /// only allowed in a prescribed sequence, depending on the state of the + /// controller. The ERROR state represents a bug in the model and is + /// non-recoverable. + enum FastI2cState { + ERROR, + IDLE, + ADDRESS_WRITE_ONGOING, + DATA_READ_ONGOING, + DATA_AVAILABLE, + WRITE_DATA_EXPECTED, + DATA_WRITE_ONGOING + }; + + ////////////////////////////// Creators ////////////////////////////// + + FastI2cController(); + + virtual ~FastI2cController(); + + ///////////////////////////// Accessors ////////////////////////////// + + //////////////////////////// Manipulators //////////////////////////// + + /// Attach a memory model to the controller + /// + /// \param[in] i_memory A configured I2cMemory + /// + /// \param[in] i_port The port (bus) number the memory is attached to + /// + /// \param[in] i_deviceAddress The device ID of the memory device on the bus + /// + /// \retval me Either 0 for success, ME_INVALID_ARGUMENT or + /// ME_AMBIGUOUS_CONFIGURATION. + ModelError + attachMemory(I2cMemory* i_memory, + const unsigned i_port, + const unsigned i_deviceAddress); + + /// Handle a PIB transaction + /// + /// \param[in,out] io_transaction An abstract PIB transaction + /// + /// The FastI2cController is an indirect memory. In general several PIB + /// transactions are required to fetch a single doubleword of code or data + /// from the memory. + /// + /// \retval rc Either an "OK" return code for success, or a code + /// describing the error. + virtual fapi::ReturnCode + operation(Transaction& io_transaction); + + ////////////////////////// Implementation //////////////////////////// + +protected: + + /// Find a device in the list of devices attached to this controller + /// + /// \param[in] i_port The port number to search + /// + /// \param[in] i_deviceAddress The device address to search + /// + /// \retval device A pointer to the device if found, otherwise 0. + I2cDevice* findDevice(const unsigned i_port, + const unsigned i_deviceAddress); + + /// Extract the I2C address from the CONTROL register + /// + /// \param[in] i_control The FastI2cControl register + /// + /// \retval address The indirect I2C address, taken from bytes 4-7 of the + /// control register depending on how many address bytes are indicated in + /// the control. + uint32_t getI2cAddress(const FastI2cControlRegister i_control); + + /// Perform an I2C address write to an attached device. + /// + /// \retval me A ModelError return code in the event of errors, otherwise + /// 0. + ModelError addressWrite(); + + /// Perform an I2C data read from an attached device. + /// + /// \retval me A ModelError return code in the event of errors, otherwise + /// 0. + ModelError dataRead(); + + /// Begin an I2C data write an attached device. + /// + /// \retval me A ModelError return code in the event of errors, otherwise + /// 0. + ModelError initialDataWrite(); + + /// Finalize an I2C data write an attached device. + /// + /// \param[in] i_data The final bytes of a data write, left justtified. + /// + /// \retval me A ModelError return code in the event of errors, otherwise + /// 0. + ModelError finalDataWrite(const uint64_t i_data); + + /// A list of I2cDevice, each of which is assigned to a controler port and + /// maintains a unique device ID for that port. + I2cDevice* iv_devices; + + /// The abstract state of the controller + FastI2cState iv_state; + + /// The last value written to the control register + FastI2cControlRegister iv_control; + + /// The last value generated in the status register + FastI2cStatusRegister iv_status; + + /// The data FIFO. Data is left-justified in this register. + uint64_t iv_fifo; + + ///////////////////////////// Safety ////////////////////////////////// + +private: + FastI2cController(const FastI2cController& i_rhs); + FastI2cController& operator=(const FastI2cController& i_rhs); +}; + + + +//////////////////////////////////////////////////////////////////////////// +// LpcController +//////////////////////////////////////////////////////////////////////////// + +/// Simplified model of the LPC controller as a fast-mode I2C controller +/// +/// The LPC controller appears as a pseudo-FastI2cController with a couple of +/// extra specializations. The fast-mode I2C controller specification +/// is extended with two extra registers : The ECC start and stop +/// addresses. We do not model ECC in our model, therefore this model only +/// allows accesses that fall within the ECC window. The SBE will never +/// address outside of the ECC window. + +class +vsbe::LpcController : public FastI2cController +{ + +public: + + ////////////////////////////// Types ////////////////////////////// + + ////////////////////////////// Creators ////////////////////////////// + + LpcController(); + + virtual ~LpcController(); + + ///////////////////////////// Accessors ////////////////////////////// + + //////////////////////////// Manipulators //////////////////////////// + + /// Handle a PIB transaction + /// + /// \param[in,out] io_transaction An abstract PIB transaction + /// + /// The LpcController is an indirect memory. In general several PIB + /// transactions are required to fetch a single doubleword of code or data + /// from the memory. The LpcController passes all transactions through to + /// the underlying FastI2cController except for reads/writes to the ECC + /// control registers. We require that any change to the ECC bounds be + /// made while the controller is in its IDLE state. + /// + /// \retval rc Either an "OK" return code for success, or a code + /// describing the error. + virtual fapi::ReturnCode + operation(Transaction& io_transaction); + + ////////////////////////// Implementation //////////////////////////// + +protected: + + /// The ECC start address register + uint64_t iv_eccStart; + + /// The ECC stop address register + uint64_t iv_eccStop; +}; + + +#endif // __VSBE_FASTI2C_H diff --git a/src/usr/pore/poreve/porevesrc/hookmanager.C b/src/usr/pore/poreve/porevesrc/hookmanager.C new file mode 100644 index 000000000..bf31e76b1 --- /dev/null +++ b/src/usr/pore/poreve/porevesrc/hookmanager.C @@ -0,0 +1,575 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/porevesrc/hookmanager.C $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +// $Id: hookmanager.C,v 1.12 2012/01/06 21:25:25 bcbrock Exp $ + +/// \file hookmanager.C +/// \brief A portable symbol table and hook execution facility + +#include <stdio.h> +#include <string.h> + +#include "hookmanager.H" + +using namespace vsbe; + + +#ifndef ULL +/// The printf() checker for 64-bit GCC throws a warning if a uint64_t is +/// printed as %llx - I have no idea why, but by casting them to (unsigned +/// long long) the warning goes away. +#define ULL(x) ((unsigned long long)(x)) +#endif + +fapi::ReturnCode vsbe::hookOk; +HookManager* HookManager::s_instance = 0; + + +//////////////////////////////////////////////////////////////////////////// +// CharPointerComparison +//////////////////////////////////////////////////////////////////////////// + +bool +CharPointerComparison::operator()(char const* i_lhs, + char const* i_rhs) const +{ + return strcmp(i_lhs, i_rhs) < 0; +} + + +//////////////////////////////////////////////////////////////////////////// +// HookManager +//////////////////////////////////////////////////////////////////////////// + +////////////////////////////// Creators ////////////////////////////// + +HookManager::HookManager() : + iv_error(HOOK_OK) +{ +} + + +HookManager::~HookManager() +{ +} + + +///////////////////////////// Accessors ////////////////////////////// + +fapi::ReturnCode +HookManager::runInstructionHook(const PoreAddress& i_address, + const uint32_t i_hook, + const uint64_t i_parameter, + Pore& io_pore, + const fapi::Target& i_target) +{ + InstructionHookMap::iterator ihmi; + fapi::ReturnCode rc; + + ihmi = instance()->iv_instructionHookMap.find(i_hook); + if (ihmi == instance()->iv_instructionHookMap.end()) { + rc = 0; + } else { + rc = (ihmi->second)(i_address, i_hook, i_parameter, io_pore, i_target); + } + return rc; +} + + +fapi::ReturnCode +HookManager::runReadHooks(const PoreAddress& i_address, + Pore& io_pore, + const fapi::Target& i_target) + +{ + return instance()->runHooks(HOOK_READ_INTERACTIVE, HOOK_READ_EXTRACTED, + i_address, io_pore, i_target); +} + + +fapi::ReturnCode +HookManager::runWriteHooks(const PoreAddress& i_address, + Pore& io_pore, + const fapi::Target& i_target) +{ + return instance()->runHooks(HOOK_WRITE_INTERACTIVE, HOOK_WRITE_EXTRACTED, + i_address, io_pore, i_target); +} + + +fapi::ReturnCode +HookManager::runFetchHooks(const PoreAddress& i_address, + Pore& io_pore, + const fapi::Target& i_target) +{ + return instance()->runHooks(HOOK_FETCH_INTERACTIVE, HOOK_FETCH_EXTRACTED, + i_address, io_pore, i_target); +} + + +HookError +HookManager::findGlobalSymbol(const char* i_symbol, + bool& o_found, + GlobalSymbolInfo& io_info) +{ + GlobalSymbolMap::iterator gsmi; + + o_found = false; + if (!instance()->iv_error) { + gsmi = instance()->iv_globalSymbolMap.find(i_symbol); + if (gsmi != instance()->iv_globalSymbolMap.end()) { + o_found = true; + io_info = *(gsmi->second); + } + } + return instance()->iv_error; +} + + +HookError +HookManager::globalSymbolList(GlobalSymbolList& io_symbols, const char* i_types) +{ + GlobalSymbolMap::iterator gsmi; + + if (!instance()->iv_error) { + for (gsmi = instance()->iv_globalSymbolMap.begin(); + gsmi != instance()->iv_globalSymbolMap.end(); + gsmi++) { + + if ((i_types == 0) || + (strchr(i_types, gsmi->second->iv_type) != 0)) { + io_symbols.push_back(*gsmi); + } + } + } + return instance()->iv_error; +} + + +void +HookManager::report(const int i_options) +{ + InstructionHookMap::iterator ihmi; + HookedAddressMap::iterator hami; + HookedFileMap::iterator hfmi; + GlobalSymbolMap::iterator gsmi; + Hook* hook; + const HookTable* table; + size_t entry; + char type; + ExtractedHook* exHook; + + if (i_options != 0) { + + FAPI_INF(""); + FAPI_INF("------------------------------------------------------"); + FAPI_INF("-- HookManager @ %p", instance()); + FAPI_INF("------------------------------------------------------"); + + if (i_options & HM_REPORT_HOOKED_ADDRESS_MAP) { + + FAPI_INF(""); + FAPI_INF("--- Hooked Address Map : %zu unique addresses ---", + instance()->iv_hookedAddressMap.size()); + FAPI_INF(""); + + for (hami = instance()->iv_hookedAddressMap.begin(); + hami != instance()->iv_hookedAddressMap.end(); + hami++) { + + for (hook = hami->second; hook != 0; hook = hook->iv_next) { + switch (hook->iv_type) { + + case HOOK_READ_INTERACTIVE: + case HOOK_WRITE_INTERACTIVE: + case HOOK_FETCH_INTERACTIVE: + switch (hook->iv_type) { + case HOOK_READ_INTERACTIVE: type = 'r'; break; + case HOOK_WRITE_INTERACTIVE: type = 'w'; break; + case HOOK_FETCH_INTERACTIVE: type = 'x'; break; + default: type = '?'; break; // For GCC -Wall + } + FAPI_INF("%04x:%08x %c %p", + hami->first.iv_memorySpace, + hami->first.iv_offset, + type, hook->iv_hook); + break; + + case HOOK_READ_EXTRACTED: + case HOOK_WRITE_EXTRACTED: + case HOOK_FETCH_EXTRACTED: + switch (hook->iv_type) { + case HOOK_READ_EXTRACTED: type = 'r'; break; + case HOOK_WRITE_EXTRACTED: type = 'w'; break; + case HOOK_FETCH_EXTRACTED: type = 'x'; break; + default: type = '?'; break; // For GCC -Wall + } + exHook = (ExtractedHook*)(hook->iv_hook); + FAPI_INF("%04x:%08x %8zu %s", + hami->first.iv_memorySpace, hami->first.iv_offset, + exHook->iv_index, exHook->iv_file); + break; + + default: break; // For GCC -Wall + } + } + } + } + + if (i_options & HM_REPORT_HOOK_TABLES) { + + FAPI_INF(""); + FAPI_INF("--- Hook Tables : %zu hooked files---", + instance()->iv_hookedFileMap.size()); + + for (hfmi = instance()->iv_hookedFileMap.begin(); + hfmi != instance()->iv_hookedFileMap.end(); + hfmi++) { + + FAPI_INF(""); + FAPI_INF("%s", hfmi->first); + + table = hfmi->second; + for (entry = 0; entry < table->iv_entries; entry++) { + FAPI_INF("%8zu %p", + entry, table->iv_hooks[entry]); + } + } + } + + if (i_options & HM_REPORT_INSTRUCTION_HOOK_MAP) { + + FAPI_INF(""); + FAPI_INF("--- Instruction Hook Map ---"); + FAPI_INF(""); + + for (ihmi = instance()->iv_instructionHookMap.begin(); + ihmi != instance()->iv_instructionHookMap.end(); + ihmi++) { + + FAPI_INF("%06x %p", + ihmi->first, ihmi->second); + } + } + + if (i_options & HM_REPORT_GLOBAL_SYMBOL_MAP) { + + FAPI_INF(""); + FAPI_INF("--- Global Symbol Map ---"); + FAPI_INF(""); + + for (gsmi = instance()->iv_globalSymbolMap.begin(); + gsmi != instance()->iv_globalSymbolMap.end(); + gsmi++) { + + FAPI_INF("%04x:%08x %c %s", + gsmi->second->iv_address.iv_memorySpace, + gsmi->second->iv_address.iv_offset, + gsmi->second->iv_type, + gsmi->first); + } + } + + FAPI_INF(""); + FAPI_INF("------------------------------------------------------"); + FAPI_INF(""); + } +} + + +//////////////////////////// Manipulators //////////////////////////// + +HookError +HookManager::registerInstructionHook(const uint32_t i_index, + HookInstructionHook i_hookRoutine) +{ + InstructionHookMap::iterator ihmi; + + if (!instance()->iv_error) { + + ihmi = instance()->iv_instructionHookMap.find(i_index); + if (ihmi == instance()->iv_instructionHookMap.end()) { + + instance()->iv_instructionHookMap[i_index] = i_hookRoutine; + + } else { + if (ihmi->second != i_hookRoutine) { + FAPI_ERR("%s : Static hook collision for index : %u", + __FUNCTION__, i_index); + instance()->iv_error = HOOK_STATIC_COLLISION; + } + } + } + return instance()->iv_error; +} + + +HookError +HookManager::registerHookTable(const char* i_file, + const HookTable* i_table) +{ + if (!instance()->iv_error) { + + if (instance()->iv_hookedFileMap.find(i_file) != + instance()->iv_hookedFileMap.end()) { + + FAPI_ERR("%s : File name collision : %s", + __FUNCTION__, i_file); + instance()->iv_error = HOOK_FILE_NAME_COLLISION; + } else { + instance()->iv_hookedFileMap[i_file] = i_table; + } + } + return instance()->iv_error; +} + + +HookError +HookManager::registerHook(const PoreAddress& i_address, + Hook* io_hook) +{ + HookedAddressMap::iterator hami; + Hook* hook; + + if (!instance()->iv_error) { + + hami = instance()->iv_hookedAddressMap.find(i_address); + if (hami != instance()->iv_hookedAddressMap.end()) { + for (hook = hami->second; + hook->iv_next != 0; + hook = hook->iv_next); + hook->iv_next = io_hook; + } else { + instance()->iv_hookedAddressMap[i_address] = io_hook; + } + io_hook->iv_next = 0; + } + return instance()->iv_error; +} + + +HookError +HookManager::registerGlobalSymbol(const char* i_symbol, + const GlobalSymbolInfo* i_info) +{ + if (!instance()->iv_error) { + + if (instance()->iv_globalSymbolMap.find(i_symbol) != + instance()->iv_globalSymbolMap.end()) { + + FAPI_ERR("%s : Multiply defined symbol : %s", + __FUNCTION__, i_symbol); + instance()->iv_error = HOOK_MULTIPLY_DEFINED_SYMBOL; + } else { + instance()->iv_globalSymbolMap[i_symbol] = i_info; + } + } + return instance()->iv_error; +} + + +HookError +HookManager::addInteractiveHook(const PoreAddress& i_address, + const HookType i_type, + const AddressBasedHook i_hookRoutine) +{ + Hook* hook = new Hook(); + HookError rc; + + instance()->iv_error = HOOK_OK; + if (hook == 0) { + rc = HOOK_MEMORY_ALLOCATION_FAILED; + } else { + switch (i_type) { + case HOOK_READ_INTERACTIVE: + case HOOK_WRITE_INTERACTIVE: + case HOOK_FETCH_INTERACTIVE: + rc = HOOK_OK; + hook->iv_type = i_type; + hook->iv_hook = (void*)i_hookRoutine; + registerHook(i_address, hook); + break; + default: + delete hook; + rc = HOOK_ILLEGAL_TYPE; + } + } + instance()->iv_error = rc; + return rc; +} + + +HookError +HookManager::deleteInteractiveHooks(const PoreAddress& i_address, + const HookType i_type, + const AddressBasedHook i_hookRoutine) +{ + HookedAddressMap::iterator hami; + Hook **last, *hook, *next; + HookError rc; + bool deleted = false; + + switch (i_type) { + case HOOK_READ_INTERACTIVE: + case HOOK_WRITE_INTERACTIVE: + case HOOK_FETCH_INTERACTIVE: + + hami = instance()->iv_hookedAddressMap.find(i_address); + if (hami != instance()->iv_hookedAddressMap.end()) { + for (last = &(hami->second), hook = hami->second; + hook != 0; + hook = next) { + next = hook->iv_next; + if ((hook->iv_type == i_type) && + ((i_hookRoutine == 0) || + (hook->iv_hook) == i_hookRoutine)) { + delete hook; + deleted = true; + *last = next; + } else { + last = &(hook->iv_next); + } + } + } + if ((i_hookRoutine == 0) || deleted) { + if (hami->second == 0) { + instance()->iv_hookedAddressMap.erase(hami); + } + rc = HOOK_OK; + } else { + rc = HOOK_INTERACTIVE_DELETE_FAILED; + } + break; + + default: + rc = HOOK_ILLEGAL_TYPE; + } + instance()->iv_error = rc; + return rc; +} + + +void +HookManager::clearError() +{ + instance()->iv_error = HOOK_OK; +} + + +////////////////////////// Implementation //////////////////////////// + +fapi::ReturnCode +HookManager::runHooks(const HookType i_interactiveType, + const HookType i_extractedType, + const PoreAddress& i_address, + Pore& io_pore, + const fapi::Target& i_target) +{ + HookedAddressMap::iterator hami; + Hook* hook; + ExtractedHook *exHook; + HookedFileMap::iterator hfmi; + const HookTable* table; + fapi::ReturnCode rc; + + hami = instance()->iv_hookedAddressMap.find(i_address); + if (hami != instance()->iv_hookedAddressMap.end()) { + + for (hook = hami->second; + (hook != 0) && rc.ok(); + hook = hook->iv_next) { + + if (hook->iv_type == i_interactiveType) { + + rc = ((AddressBasedHook)(hook->iv_hook))(i_address, + i_interactiveType, + io_pore, + i_target); + + } else if (hook->iv_type == i_extractedType) { + + exHook = (ExtractedHook*)(hook->iv_hook); + hfmi = instance()->iv_hookedFileMap.find(exHook->iv_file); + if (hfmi == instance()->iv_hookedFileMap.end()) { + + FAPI_ERR("%s : Address %04x:%08x is hooked from " + "file '%s', but no HookTable can be found " + "for the file.", + __FUNCTION__, + i_address.iv_memorySpace, + i_address.iv_offset, + exHook->iv_file); + instance()->iv_error = HOOK_TABLE_MISSING; + rc = 1; /// \todo Define this error + + } else { + + table = hfmi->second; + if (exHook->iv_index > table->iv_entries) { + + FAPI_ERR("%s : Address %04x:%08x is hooked from " + "file '%s' at index %zu, " + "but the index exceeds " + "the number of hooks indexed for the " + "file (%zu).", + __FUNCTION__, + i_address.iv_memorySpace, + i_address.iv_offset, + hfmi->first, exHook->iv_index, + table->iv_entries); + instance()->iv_error = HOOK_INDEX_FAILURE; + rc = 1; /// \todo Define this error + + } else { + + rc = + (table->iv_hooks[exHook->iv_index]) + (i_address, i_extractedType, io_pore, i_target); + } + } + } else { + + FAPI_ERR("%s : Bug in HookManager - Unexpected type", + __FUNCTION__); + instance()->iv_error = HOOK_BUG; + rc = 1; /// \todo Define this error + } + if (!rc.ok()) break; + } + } + return rc; +} + + +//////////////////////////////////////////////////////////////////////////// +// HookInitializer +//////////////////////////////////////////////////////////////////////////// + +HookInitializer::HookInitializer(HookManagerInitializer i_function) +{ + i_function(); +} + + +HookInitializer::~HookInitializer() +{ +} diff --git a/src/usr/pore/poreve/porevesrc/hookmanager.H b/src/usr/pore/poreve/porevesrc/hookmanager.H new file mode 100644 index 000000000..5323392c9 --- /dev/null +++ b/src/usr/pore/poreve/porevesrc/hookmanager.H @@ -0,0 +1,859 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/porevesrc/hookmanager.H $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#ifndef __VSBE_HOOKMANAGER_H +#define __VSBE_HOOKMANAGER_H + +// $Id: hookmanager.H,v 1.16 2012/01/06 21:25:25 bcbrock Exp $ + +/// \file hookmanager.H +/// \brief A portable symbol table and hook execution facility +/// +/// Although the concept of a HookManager is generic, this implementation is +/// specific to the FAPI PoreVe environment. +/// +/// A hook is a C/C++ subroutine called during execution of the PoreVe. A +/// hook is either associated with a HOOKI instruction, or with a particular +/// PORE effective address. Address-based hooks are either read, write or +/// fetch hooks, and may have either been installed interactively (e.g., by a +/// debugger or hand-written code) or extracted from a source file. We make a +/// distinction because extracted hooks are indexed via static tables created +/// by processing an assembler source file, whereas interactive hooks are +/// inserted individually. Extracted hooks are assumed to be characterized by +/// permanent static data structures and can not be deleted. Interactive +/// hooks can be created and deleted at will. +/// +/// \todo Once the HBI use of the HookManager is finalized, it may be +/// necessary to split this into 2 classes, one for HBI and another for Cronus +/// verisons of PoreVe. +/// +/// \todo Figure out if there is a way to make this more generic without having +/// to use a template. + +#include <stdarg.h> +#include <stdint.h> + +#include <list> +#include <map> +#include <utility> + +#include <fapi.H> + +#include "poremodel.H" + +namespace vsbe { + + struct HookTable; + struct ExtractedHook; + struct Hook; + struct GlobalSymbolInfo; + class HookManager; + class HookInitializer; + class PoreAddress; + class PoreAddressComparison; + class CharPointerComparison; + class Pore; + + /// An "OK" return code for use by hook routines + extern fapi::ReturnCode hookOk; + + /// \enum HookType + /// + /// The type of a hook. See the comments for the file hookmanager.H. + enum HookType { + HOOK_INSTRUCTION, + HOOK_READ_INTERACTIVE, + HOOK_WRITE_INTERACTIVE, + HOOK_FETCH_INTERACTIVE, + HOOK_READ_EXTRACTED, + HOOK_WRITE_EXTRACTED, + HOOK_FETCH_EXTRACTED + }; + + /// The type of a HOOK instruction hook + /// + /// \param[in] i_address The effective address of the HOOK instruction + /// + /// \param[in] i_hook The low-order 24 bits of the HOOK instruction + /// + /// \param[in] i_Parameter A 64-bit parameter for the hook + /// + /// \param[in,out] io_pore The Pore model, to allow the hook to examine or + /// modify the state of the PORE. + /// + /// \param[in] i_target A reference to the FAPI Target currently + /// associated with the virtual PORE. + typedef fapi::ReturnCode + (*HookInstructionHook)(const PoreAddress& i_address, + const uint32_t i_hook, + const uint64_t i_parameter, + Pore& io_pore, + const fapi::Target& i_target); + + /// The type of an address-based hook + /// + /// \param[in] i_address The effective address associated with the hook + /// + /// \param[in] i_type The type of the address-based hook + /// + /// \param[in,out] io_pore A reference to the Pore model, to allow the + /// hook to examine or modify the state of the PORE. + /// + /// \param[in] i_target A reference to the FAPI Target currently + /// associated with the virtual PORE. + typedef fapi::ReturnCode + (*AddressBasedHook)(const PoreAddress& i_address, + const HookType i_type, + Pore& io_pore, + const fapi::Target& i_target); + + /// \enum HookError + /// + /// These error conditions are recognized both while the hook manager is + /// being initialized, and at run time. The last error code generated is + /// stored in the iv_error field of the HookManager. + enum HookError { + HOOK_OK = 0, + /// File name collision between hooked files + HOOK_FILE_NAME_COLLISION = 1, + /// Multiply defined symbol + HOOK_MULTIPLY_DEFINED_SYMBOL = 2, + /// A HookTable for a file is missing, suggesting hooks are out of + /// sync with the hooked sources + HOOK_TABLE_MISSING = 3, + /// Hook index too large, suggesting hooks are out of sync with the + /// hooked sources + HOOK_INDEX_FAILURE = 4, + /// An attempt was made to map more than one hook to a static hook + /// index. + HOOK_STATIC_COLLISION = 5, + /// Deprecated: An instruction hook was called for but not found + HOOK_INSTRUCTION_NOT_FOUND = 6, + /// An illegal HookType was specified for an API + HOOK_ILLEGAL_TYPE = 7, + /// Memory allocation failure for a new interactive hook + HOOK_MEMORY_ALLOCATION_FAILED = 8, + /// A request to delete a specific interactive hook failed + HOOK_INTERACTIVE_DELETE_FAILED = 9, + /// There is a bug in the HookManager + HOOK_BUG = 10, + }; + + /// \defgroup hookmanager_report_options HookManager Report Options + /// + /// By default, the HookManager::report() method prints all elements of + /// the report. An OR-combination of these flags can also be supplied as + /// the argument to explicitly specify that individual sections of the + /// report be printed. + /// + /// @{ + + /// Print the hooked address map + const int HM_REPORT_HOOKED_ADDRESS_MAP = 0x1; + + /// Print the hook tables + const int HM_REPORT_HOOK_TABLES = 0x2; + + /// Print the instruction hook map + const int HM_REPORT_INSTRUCTION_HOOK_MAP = 0x4; + + /// Print the global symbol map + const int HM_REPORT_GLOBAL_SYMBOL_MAP = 0x8; + + /// @} +}; + + +//////////////////////////////////////////////////////////////////////////// +// HookTable +//////////////////////////////////////////////////////////////////////////// + +/// A table of AddressBasedHook function pointers associated with a source +/// file. +/// +/// These structures are created by the \e hook_extractor script as it +/// processes the input to the assembler. Therefore the size of the \a +/// iv_hooks table is constant and known at compile time. To save space the +/// name of the file is not included here - instead the file name is the map +/// key. + +struct +vsbe::HookTable { + + /// The number of hooks defined for the file + size_t iv_entries; + + /// The table of addresses of the hook routines + AddressBasedHook *iv_hooks; +}; + + +//////////////////////////////////////////////////////////////////////////// +// ExtractedHook +//////////////////////////////////////////////////////////////////////////// + +/// An index record for a hook extracted from a source file + +struct +vsbe::ExtractedHook { + + /// The file name of the hooked source file + const char* iv_file; + + /// The index of the hook within the file + size_t iv_index; +}; + + +//////////////////////////////////////////////////////////////////////////// +// Hook +//////////////////////////////////////////////////////////////////////////// + +/// A reference to a hook associated with a particular PORE address +/// +/// The hook architecture allows multiple hooks to be associated with a single +/// address. This situation could arise both by design and also by accident +/// depending for example on conditional compilation or macro expansion. To +/// support all of read, write and fetch hooks as well as static +/// initialization of extracted hooks, this structure holds a generic hook +/// pointer and a \a type field that indicates whether to interpret the +/// pointer as a pointer to an ExtractedHook, or a direct pointer to an +/// AddressBasedHook. + +struct +vsbe::Hook { + + /// The type of hook; See the enumeration HookType + HookType iv_type; + + /// Either an AddressBasedHook or a pointer to an ExtractedHook, depending + /// on the HookType + void* iv_hook; + + /// List linkage + struct Hook* iv_next; +}; + + +//////////////////////////////////////////////////////////////////////////// +// GlobalSymbolInfo +//////////////////////////////////////////////////////////////////////////// + +/// Global Symbol Information +/// +/// Global symbols are mapped by name. This structure includes the symbol +/// address as a PoreAddress plus type information. + +struct +vsbe::GlobalSymbolInfo { + + /// The symbol address + PoreAddress iv_address; + + /// The symbol type + /// + /// Symbol types are the character codes reported by \e nm: + /// + /// - \c B Global BSS (uninitialized data) + /// - \c C Global common (uninitialized data) + /// - \c D Global initialized data + /// - \c T Global text (code) + /// - \c R Global read only data + char iv_type; +}; + + +namespace vsbe { + /// An STL list of <const char *, const GlobalSymbolInfo*> pairs + /// + /// This structure is defined for use in calls to + /// HookManager::globalSymbolList(). + typedef std::list< std::pair<const char*, const GlobalSymbolInfo*> > + GlobalSymbolList; +} + + +//////////////////////////////////////////////////////////////////////////// +// PoreAddressComparison +//////////////////////////////////////////////////////////////////////////// + +/// PoreAddress comparison class +/// +/// This class defines the comparison operator for STL containers using a +/// PoreAddress as the key. + +//////////////////////////////////////////////////////////////////////////// +// CharPointerComparison +//////////////////////////////////////////////////////////////////////////// + +/// char* comparison class +/// +/// This class defines the comparison operator for STL containers using a +/// char* as the key. + +class +vsbe::CharPointerComparison { + +public: + + CharPointerComparison() {} + + ~CharPointerComparison() {} + + /// Compare CharPointer* + /// + /// \param[in] i_lhs Left hand side object + /// + /// \param[in] i_rhs Right hand side object + /// + /// \retval rc This is a simply strcmp(ilhs, irhs) < 0 + bool operator() (char const* i_lhs, + char const* i_rhs) const; + + + ///////////////////////////// Safety ////////////////////////////////// + +private: + // STL requires a copy operator + CharPointerComparison& operator=(const CharPointerComparison& rhs); +}; + + +//////////////////////////////////////////////////////////////////////////// +// HookManager +//////////////////////////////////////////////////////////////////////////// + +/// A singleton class for managing code hooks for PORE VE +/// +/// The hook manager is a portable C++ implementation of a symbol table for +/// hook functions, hooked instructions and global symbols. Only one +/// HookManager exists at any time. All methods are static and internally +/// reference a singleton instance of a HookManager. The HookManager supports +/// two main types of hooks: +/// +/// - Pre-defined hooks associated with the PORE HOOKI instruction. The HOOKI +/// instruction encodes an unsigned integer index of a hook routine to execute +/// at that point, and also includes an uninterpreted 64-bit parameter. The +/// mapping of hook indices to hook routines will likely be done +/// statically. The HOOK instruction is otherwise a NOP. +/// +/// - Address-based hooks are hooks that are attached to data loads and stores +/// or instruction fetches. These hooks are normally attached by a scripting +/// discipline that processes the input of the assembler to extract the hooks +/// into a separate build and load path. Debugging environments can also add +/// and delete hooks at run time. +/// +/// The symbol table architecure and layout were designed to simplify the +/// mapping and reduce space for the case that hooks are required during a +/// space-constrained HBI procedure. Most symbol table data are defined as +/// constants in the shared objects that initialize the hooks, and should +/// never need to be copied. +/// +/// The HookManager maintains 4 maps: +/// +/// - A map that maps predefined hook indices encoded in HOOKI instructions to +/// the routines that implement the hook. This map is created by calls of +/// registerInstructionHook(). +/// +/// - A map that maps a source file name to a HookTable, that is table of +/// function pointers to the routines that implement the hooks. This map is +/// created by calls of registerHookTable(). +/// +/// - A map that maps a 48-bit \e effective PORE address to a list of Hook +/// objects that identify the hook(s) associated with a PORE address. This map +/// is created by calls of registerHook(). +/// +/// - A map that maps a PORE global symbol name to a pair <address, type>. +/// This map is created by calls of registerGlobalSymbol(). + +class +vsbe::HookManager { + +public: + + ////////////////////////////// Types ////////////////////////////// + + /// A map of HOOKI instruction indices to a HookInstructionHook + /// + /// This map is created by calls of registerInstructionHook(). The + /// application that provides the semantics of each HOOKI instruction + /// index will make these calls. The map is used by the + /// runInstructionHook() API to locate the entry point associated with a + /// HOOKI index. + typedef std::map<uint32_t, HookInstructionHook> InstructionHookMap; + + /// A map of file names to hook routine tables + /// + /// This mapping is created by the *.hook.cc file that is generated by the + /// hook_extractor script for each file of assembler source code. Each + /// one of the *.hook.cc files maps the source code file name to a table + /// of entry points of the hooks extracted from that file. The + /// hook_indexer script references these tables to map hooked PORE + /// addresses to the entry point that implements the hook. + typedef std::map<const char*, const HookTable*> HookedFileMap; + + /// A map of PORE addresses to lists of hooks + /// + /// This map is created by the registerHook() API. For extracted hooks, + /// these calls are made from the *.hooks.cc file created by the + /// hook_indexer from the symbol table of the final link image. The + /// registerHook() API can also be called dynamically by advanced + /// applications like the PDBG debugger for PORE programs. This map is + /// referenced by the runHooks() API. + /// + /// \note The comparison operator being used here is '<' on the uint64_t + /// form of the PoreAddress. + typedef std::map<const PoreAddress, Hook*> HookedAddressMap; + + /// A map of global symbol names to their parameters + /// + /// This map is created by calls of registerGlobalSymbol(), called from + /// the *.hooks.cc file created by the hook_indexer script. This mapping + /// allows the allows the application to find global symbol addresses + /// using the findGlobalSymbol() API. + typedef std::map<const char*, const GlobalSymbolInfo*, + CharPointerComparison> GlobalSymbolMap; + + ////////////////////////////// Creators ////////////////////////////// + + virtual ~HookManager(); + + ///////////////////////////// Accessors ////////////////////////////// + + /// Access the singleton instance + /// + /// This is a standard design pattern: If the static singleton instance of + /// the class already exists, return it. Otherwise create it first. + static HookManager* instance() { + if (s_instance == 0) { + s_instance = new HookManager(); + } + return s_instance; + } + + /// Run a hook assigned to a HOOKI instruction encoding + /// + /// \param[in] i_address The effective address of the HOOKI instruction. + /// + /// \param[in] i_hook The index of the hook to run, taken from the + /// low-order 24 bits of the HOOKI instruction. + /// + /// \param[in] i_parameter A 64-bit parameter for the hook. + /// + /// \param[in,out] io_pore A reference to the Pore object, to allow hooks + /// to examine or alter the PORE state. + /// + /// \param[in] i_target A reference to the FAPI Target currently + /// associated with the virtual PORE. + /// + /// \retval rc If there is a hook routine associated with the hook index + /// \a i_hook, then this is the FAPI return code returned by the hook, + /// otherwise an "ok" (0) FAPI return code. There is no requirememt that + /// a hook routine be present in the Hookmanager for any instruction hook + /// index. + static fapi::ReturnCode + runInstructionHook(const PoreAddress& i_address, + const uint32_t i_hook, + const uint64_t i_parameter, + Pore& io_pore, + const fapi::Target& i_target); + + /// Run any hooks associated with a data read of an effective address + /// + /// \param[in] i_address The effective address of the data read + /// + /// \param[in,out] io_pore A reference to the Pore object, to allow hooks + /// to examine or alter the PORE state. + /// + /// \param[in] i_target A reference to the FAPI Target currently + /// associated with the virtual PORE. + /// + /// If supported by the environment this method will be called before + /// every data read to run any hooks associated with reading the address. + /// + /// \retval rc The FAPI return code returned by the first (if any) + /// hook routine to return a non-OK code, otherwise an OK return code. + static fapi::ReturnCode + runReadHooks(const PoreAddress& i_address, + Pore& io_pore, + const fapi::Target& i_target); + + /// Run any hooks associated with a data write of an effective address + /// + /// \param[in] i_address The effective address of the data write + /// + /// \param[in,out] io_pore A pointer to the Pore object, to allow hooks to + /// examine or alter the PORE state. + /// + /// \param[in] i_target A reference to the FAPI Target currently + /// associated with the virtual PORE. + /// + /// \retval rc The FAPI return code returned by the first (if any) + /// hook routine to return a non-OK code, otherwise an OK return code. + static fapi::ReturnCode + runWriteHooks(const PoreAddress& i_address, + Pore& io_pore, + const fapi::Target& i_target); + + /// Run any hooks associated with an instruction fetch of an effective + /// address + /// + /// \param[in] i_address The effective address of the instruction fetch + /// + /// \param[in,out] io_pore A pointer to the Pore object, to allow hooks to + /// examine or alter the PORE state. + /// + /// \param[in] i_target A reference to the FAPI Target currently + /// associated with the virtual PORE. + /// + /// If supported by the environment this method will be called before + /// every instruction fetch to run any hooks associated with executing the + /// address. + /// + /// \retval rc The FAPI return code returned by the first (if any) + /// hook routine to return a non-OK code, otherwise an OK return code. + static fapi::ReturnCode + runFetchHooks(const PoreAddress& i_address, + Pore& io_pore, + const fapi::Target& i_target); + + /// Find a global symbol in the HookManager symbol table + /// + /// \param[in] i_symbol The global symbol name to search for + /// + /// \param[out] o_found Indicates whether the symbol was found + /// + /// \param[in,out] io_info If the symbol is was found, this + /// reference is modified to contain the symbol information, otherwise the + /// reference is not modified. + /// + /// \retval rc HookManager sticky error status; This method fails + /// immediately if HookManager error status is set at entry. To clear the + /// error status use clearError(). + static HookError + findGlobalSymbol(const char* i_symbol, + bool& o_found, + GlobalSymbolInfo& io_info); + + /// Update a list of GlobalSymbolInfo based on the current state + /// + /// \param[in,out] io_symbols This is a reference to an instance of + /// GlobalSymbolList, an STL list of <const char*, const GlobalSymbolInfo*> + /// pairs. + /// + /// \param[in] i_types This optional parameter is a 0-terminated character + /// string containing 0 or more character codes of symbol types. Only + /// symbols whose type code is an element of the string are appended to \a + /// io_symbols. If \a i_types is 0 (or defaulted) then all global symbols + /// are returned. It probably doesn't make sense to call + /// globalSymbolList() with \a i_types as "" since this call would have no + /// effect. + /// + /// This routine takes a reference to a GlobalSymbolList, and operates by + /// appending (using the STL list push_back() method) a pair consisting of + /// the symbol name string and a pointer to a GlobalSymbolInfo structure + /// for each global symbol currently stored in the Global Symbol Table + /// that matches the symbol type filter. Type filtering is described with + /// the \a i_types argument. Global symbols are appended to \a io_symbols + /// in the lexicographic order defined by strcmp() < 0 on the character + /// string symbol names (i.e., they come back sorted by name). + /// + /// globalSymbolList() only appends to the list passed as the \a + /// io_symbols reference. Use the STL list clear() method to clear the + /// list if necessary prior to calling globalSymbolList(). + /// + /// \retval rc HookManager sticky error status; This method fails + /// immediately if HookManager error status is set at entry. To clear the + /// error status use clearError(). + static HookError + globalSymbolList(GlobalSymbolList& io_symbols, const char* i_types = 0); + + /// Report the HookManager state to the FAPI_INF() stream + /// + /// \param[in] i_options Options are selected as an OR-combination of the + /// options documented as \ref hookmanager_report_options. By default all + /// elements of the report are printed. + /// + /// \retval 0 Success + static void + report(const int i_options = -1); + + //////////////////////////// Manipulators //////////////////////////// + + /// Register a HOOKI instruction hook with the HookManager + /// + /// \param[in] i_index The hook index as it will be stored in the HOOKI + /// instruction. + /// + /// \param[in] i_hookRoutine The hook routine + /// + /// It is considered an immediate fatal error (HOOK_STATIC_COLLISION) if + /// an attempt is made to map a single index to different hooks. Although + /// the HookManager could be easily modified to support multiple static + /// hooks for a single index if required, the current thinking is that + /// this more likely represents an error in assigning hook indices rather + /// than a useful feature. + /// + /// \retval rc HookManager sticky error status; This method fails + /// immediately if HookManager error status is set. To clear the error + /// status use clearError(). + static HookError + registerInstructionHook(const uint32_t i_index, + HookInstructionHook i_hookRoutine); + + /// Register a hook table with the hook manager + /// + /// \param[in] i_file The file name associated with the HookTable. This + /// string is assumed to be a permanent static allocation and is not + /// copied or storage managed by the HookManager. + /// + /// \param[in] i_table A pointer to a HookTable structure. This structure + /// is assumed to be a permanent static allocation and is not copied or + /// storage managed by the HookManager. + /// + /// The table is mapped by the hook manager based on the file name stored + /// in the table. It is considered an immediate fatal error + /// (HOOK_FILE_NAME_COLLISION) if a file name collision is detected. + /// + /// \retval rc HookManager sticky error status; This method fails + /// immediately if HookManager error status is set. To clear the error + /// status use clearError(). + static HookError + registerHookTable(const char* i_file, + const HookTable* i_table); + + /// Register an extracted Hook structure with the hook manager + /// + /// \param[in] i_address The effective address of a hooked + /// instruction. + /// + /// \param[in,out] io_hook An initialized Hook structure. + /// + /// This method is used directly by code generated from an extraction + /// script to install a hook for an address, due to the fact that + /// extracted hooks are initialized from preconstructed static objects. + /// This is also used as an internal method by addInteractiveHook(). + /// + /// If more than one hook is associated with an address, later hooks are + /// added at the end of the list of hooks. When the hooks are run they + /// are run in list order. + /// + /// \retval rc HookManager sticky error status; This method fails + /// immediately if HookManager error status is set. To clear the error + /// status use clearError(). + static HookError + registerHook(const PoreAddress& i_address, + Hook* io_hook); + + /// Register a global symbol with the hook manager + /// + /// \param[in] i_symbol The symbol name. This string is assumed to be a + /// permanent static allocation and is not copied or storage managed by + /// the HookManager. + /// + /// \param[in] i_info Information about the symbol. This structure is + /// assumed to be a permanent static allocation and is not copied or + /// storage managed by the HookManager. + /// + /// For simplicity, it is considered an immediate fatal error + /// (HOOK_MULTIPLY_DEFINED_SYMBOL) to hook a symbol more than once. If we + /// need to provide similarly-named symbols in different address spaces + /// then we'll need to revisit the implementation. + /// + /// \retval rc HookManager sticky error status; This method fails + /// immediately if HookManager error status is set. To clear the error + /// status use clearError(). + static HookError + registerGlobalSymbol(const char* i_symbol, + const GlobalSymbolInfo* i_info); + + /// Add an interactive hook to a PoreAddress + /// + /// \param[in] i_address The effective address of the hooked + /// instruction or data. + /// + /// \param[in] i_type The hook type, which must be one of the *INTERACTIVE + /// types. + /// + /// \param[in] i_hookRoutine The AddressBasedHook that implements the hook. + /// + /// Create and install an interactive hook of \a i_type for an effective + /// PORE address. If more than one hook is associated with an address, + /// later hooks are added at the end of the list of hooks. When the hooks + /// are run they are run in list order. + /// + /// \retval rc A non-zero return value indicates any error that occurred. + /// This method fails immediately if HookManager error status is set at + /// entry. To clear the error status use clearError(). + static HookError + addInteractiveHook(const PoreAddress& i_address, + const HookType i_type, + const AddressBasedHook i_hookRoutine); + + /// Delete interactive hooks of a given type from a PoreAddress + /// + /// \param[in] i_address The effective address of the hooked + /// instruction or data. + /// + /// \param[in] i_type The hook type, which must be one of the *INTERACTIVE + /// types. + /// + /// \param[in] i_hookRoutine The AddressBasedHook that implements the + /// hook, or a default value of 0 which means to delete all interactive + /// hooks of the given type from the address. + /// + /// By default, delete all interactive hooks of \a i_type from an + /// effective PORE address. If \a i_hook is not 0, then all occurrences + /// of only that particular hook are deleted. + /// + /// \retval rc A non-zero return value indicates any error that occurred. + /// This method fails immediately if HookManager error status is set at + /// entry. To clear the error status use clearError(). + static HookError + deleteInteractiveHooks(const PoreAddress& i_address, + const HookType i_type, + const AddressBasedHook i_hookRoutine = 0); + + /// Clear the HookManager error status + /// + /// The HookManager has 'sticky' error status - new operations on the + /// HookManager will fail if the error status is non-zero. This method + /// clears the error status. + static void + clearError(); + + ////////////////////////// Implementation //////////////////////////// + + /// The last HookError encountered + /// + /// Many of the HookError conditions arise during load-time + /// initialization, when there's really no recourse for trapping or + /// handling them. Instead, if the iv_error is non-0 then all load-time + /// HookManager APIs return immediately, allowing some diagnosis (of the + /// first error) after initialization. The interactive methods set and + /// return \a iv_error with the final return code but do not block further + /// operations. + HookError iv_error; + + // NB: s_instance must be public for the Simics workaround + + /// The singleton instance of the HookManager + static HookManager* s_instance; + +protected: + + /// The instruction hook map + InstructionHookMap iv_instructionHookMap; + + /// The hooked file map + HookedFileMap iv_hookedFileMap; + + /// The hooked address map + /// + /// The HookManager system maintains an invariant that if an entry in this + /// map exists, then the list of hooks associated with that address is not + /// empty (i.e., the pointer is not 0). + HookedAddressMap iv_hookedAddressMap; + + /// The global symbol map + GlobalSymbolMap iv_globalSymbolMap; + + /// Run a specific type of hook + /// + /// \param[in] i_interactiveType One of the *INTERACTIVE HookType. + /// + /// \param[in] i_extractedType The *EXTRACTED counterpart of the + /// interactive type. + /// + /// \param[in] i_address The current effective address. + /// + /// \param[in,out] io_pore The Pore model, to allow the hook to examine or + /// modify the state of the PORE. + /// + /// \param[in] i_target A reference to the FAPI Target currently + /// associated with the virtual PORE. + /// + /// This is a helper method for runReadHooks(), runWriteHooks() and + /// runFetchHooks() that actually does the search and execution, given an + /// interactive and extracted hook type to search. + /// + /// \retval rc The FAPI return code returned by the first (if any) + /// hook routine to return a non-OK code, otherwise an OK return code. + fapi::ReturnCode + runHooks(const HookType i_interactiveType, + const HookType i_extractedType, + const PoreAddress& i_address, + Pore& io_pore, + const fapi::Target& i_target); + + + ///////////////////////////// Safety ////////////////////////////////// + +private: + HookManager(); + HookManager(const HookManager& i_rhs); + HookManager& operator=(const HookManager& i_rhs); +}; + + +//////////////////////////////////////////////////////////////////////////// +// HookInitializer +//////////////////////////////////////////////////////////////////////////// + +/// A dummy class used to initialize the HookManager +/// +/// Initialization of the HookManager depends on the ability of C++ to run +/// object constructors at load time. Each hook file and indexing file +/// contains an initialization function that installs information into the +/// symbol table. Each hook file also creates an instance of the +/// HookInitializer whose sole purpose is to run the initialization function +/// in its constructor at load time. + +class +vsbe::HookInitializer { + +public: + + ////////////////////////////// Types ////////////////////////////// + + /// The type of a HookManager initializer function + typedef void (*HookManagerInitializer)(); + + ////////////////////////////// Creators ////////////////////////////// + + /// Create an HookInitializer + /// + /// \param[in] i_function The function to call during construction of the + /// otherwise empty object. + HookInitializer(HookManagerInitializer i_function); + + ~HookInitializer(); + + ///////////////////////////// Safety ////////////////////////////////// + +private: + HookInitializer(const HookInitializer& rhs); + HookInitializer& operator=(const HookInitializer& rhs); +}; + + +#endif // __VSBE_HOOKMANAGER_H diff --git a/src/usr/pore/poreve/porevesrc/pib2cfam.C b/src/usr/pore/poreve/porevesrc/pib2cfam.C new file mode 100644 index 000000000..cf6100767 --- /dev/null +++ b/src/usr/pore/poreve/porevesrc/pib2cfam.C @@ -0,0 +1,167 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/porevesrc/pib2cfam.C $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +// -*- mode: C++; c-file-style: "linux"; -*- +// $Id: pib2cfam.C,v 1.9 2012/01/09 21:22:50 jeshua Exp $ + +/// \file pib2cfam.C +/// \brief A temporary hack while waiting for hardware updates - a simple +/// PibSlave that maps a small range of PIB addresses to CFAM addresses. +/// +/// \todo Verify the assumption that the high-order 32 bits of the 64-bit data +/// are the bits that are read and written to the CFAM register. + +#include "pib2cfam.H" +//JDS TODO - remove the ECMD headers once we've got attribute support +#ifndef __HOSTBOOT_MODULE +#include "fapiSharedUtils.H" +#include "ecmdUtils.H" +#endif +using namespace vsbe; + + +////////////////////////////// Creators ////////////////////////////// + +Pib2Cfam::Pib2Cfam() +{ +} + + +Pib2Cfam::~Pib2Cfam() +{ +} + + +//////////////////////////// Manipulators //////////////////////////// + +static uint32_t +translateAddress(uint32_t address, fapi::Target* i_target) +{ + //JDS TODO - change this to get attribute ATTR_FSI_GP_REG_SCOM_ACCESS + bool fsi_gpreg_scom_access = false; +#ifndef __HOSTBOOT_MODULE + ecmdChipData chipdata; + ecmdChipTarget e_target; + uint32_t rc; + std::string chip_type; + + fapiTargetToEcmdTarget( *i_target, e_target); + rc = ecmdGetChipData(e_target, chipdata); + if( rc ) printf( "Problem with getchipdata\n" ); + chip_type = chipdata.chipType; + + if( chip_type == "centaur" ) { + fsi_gpreg_scom_access = false; + } else { + fsi_gpreg_scom_access = true; + } +#endif + + if( fsi_gpreg_scom_access ) { + return (address - 0x00050000) + 0x2800; + } else { + return (address - 0x00050000) + 0x1000; + } +} + + +fapi::ReturnCode +Pib2Cfam::operation(Transaction& io_transaction) +{ + fapi::ReturnCode rc; + ModelError me; + + switch (io_transaction.iv_mode) { + + case ACCESS_MODE_READ: + + switch (io_transaction.iv_address) { + + case 0x00050012: + case 0x00050013: + case 0x00050014: + case 0x00050015: + case 0x00050016: + case 0x00050019: + case 0x0005001A: + case 0x0005001B: + rc = fapiGetCfamRegister(*iv_target, + translateAddress(io_transaction.iv_address, iv_target), + *iv_dataBuffer); + if (rc.ok()) { + io_transaction.iv_data = + ((uint64_t)iv_dataBuffer->getWord(0)) << 32; + me = ME_SUCCESS; + } else { + me = ME_FAILURE; + } + break; + default: + me = ME_NOT_MAPPED_IN_MEMORY; + } + break; + + case ACCESS_MODE_WRITE: + + switch (io_transaction.iv_address) { + + case 0x00050012: + case 0x00050013: + case 0x00050014: + case 0x00050015: + case 0x00050016: + case 0x0005001B: + iv_dataBuffer->setWordLength(1); + iv_dataBuffer->setWord(0, io_transaction.iv_data >> 32); + rc = fapiPutCfamRegister(*iv_target, + translateAddress(io_transaction.iv_address, iv_target), + *iv_dataBuffer); + if (rc.ok()) { + me = ME_SUCCESS; + } else { + me = ME_FAILURE; + } + break; + + case 0x00050019: + case 0x0005001A: + rc = 1; + me = ME_BUS_SLAVE_PERMISSION_DENIED; + break; + + default: + rc = 1; + me = ME_NOT_MAPPED_IN_MEMORY; + } + break; + + default: + rc = 1; + me = ME_BUS_SLAVE_PERMISSION_DENIED; + break; + } + io_transaction.busError(me); + return rc; +} +/* Local Variables: */ +/* c-basic-offset: 4 */ +/* End: */ diff --git a/src/usr/pore/poreve/porevesrc/pib2cfam.H b/src/usr/pore/poreve/porevesrc/pib2cfam.H new file mode 100644 index 000000000..329d3f0a3 --- /dev/null +++ b/src/usr/pore/poreve/porevesrc/pib2cfam.H @@ -0,0 +1,94 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/porevesrc/pib2cfam.H $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#ifndef __VSBE_PIB2CFAM_H +#define __VSBE_PIB2CFAM_H + +// $Id: pib2cfam.H,v 1.3 2011/06/21 00:07:35 bcbrock Exp $ + +/// \file pib2cfam.H +/// \brief A temporary hack while waiting for hardware updates - a simple +/// PibSlave that maps a small range of PIB addresses to CFAM addresses. + +#include "bus.H" + +namespace vsbe { + + class Pib2Cfam; + + /// PIB base address of PIB range mapped by Pib2Cfam + const uint32_t PIB2CFAM_PIB_BASE = 0x00050012; + + /// Number of PIB addresses mapped by Pib2Cfam + const int PIB2CFAM_PIB_SIZE = ((0x0005001b - 0x00050012) + 1); +} + + +/// Map PIB accesses to CFAM accesses + +class +vsbe::Pib2Cfam : public PibSlave { + +public: + + ////////////////////////////// Creators ////////////////////////////// + + Pib2Cfam(); + + virtual ~Pib2Cfam(); + + + //////////////////////////// Manipulators //////////////////////////// + + /// Pib2Cfam operation + /// + /// \param[in,out] io_transaction A PIB transaction object + /// + /// This object converts PIB transactions in a certain range in the + /// virtual environment to FAPI PutCfamregister() and GetCfamRegister() + /// calls, returning the FAPI return code from the translated calls. + /// + /// The following PIB registers are mapped to CFAM registers: + /// + /// - PIB 0x00050012 -> CFAM 0x1012, FSIGP3, R/W + /// - PIB 0x00050013 -> CFAM 0x1013, FSIGP4, R/W + /// - PIB 0x00050014 -> CFAM 0x1014, FSIGP5, R/W + /// - PIB 0x00050015 -> CFAM 0x1015, FSIGP6, R/W + /// - PIB 0x00050016 -> CFAM 0x1016, FSIGP7, R/W + /// - PIB 0x00050019 -> CFAM 0x1019, OSC switch sense 1, R + /// - PIB 0x0005001A -> CFAM 0x101A, OSC switch sense 2, R + /// - PIB 0x0005001B -> CFAM 0x101B, GP3 Mirror, R/W + /// + /// \retval rc The fapi::ReturnCode returned by the underlying + /// PutCfamRegister() or GetCfamRegister() call. + fapi::ReturnCode + operation(Transaction& io_transaction); + + + ///////////////////////////// Safety ////////////////////////////////// + +private: + Pib2Cfam(const Pib2Cfam& rhs); + Pib2Cfam& operator=(const Pib2Cfam& rhs); +}; + +#endif // __VSBE_PIB2CFAM_H diff --git a/src/usr/pore/poreve/porevesrc/pore.C b/src/usr/pore/poreve/porevesrc/pore.C new file mode 100644 index 000000000..8f09e2e29 --- /dev/null +++ b/src/usr/pore/poreve/porevesrc/pore.C @@ -0,0 +1,269 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/porevesrc/pore.C $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +// $Id: pore.C,v 1.13 2011/11/17 19:05:22 jeshua Exp $ + +/// \file pore.C +/// \brief The implementation of the PoreInterface for the PoreVe environment + +#include "pore.H" + +using namespace vsbe; + + +///////////////////////// Control Interface ///////////////////////// + +ModelError +Pore::forceBranch(const char* i_symbol) +{ + ModelError me; + HookError he; + bool found; + GlobalSymbolInfo info; + + he = HookManager::findGlobalSymbol(i_symbol, found, info); + if (he || !found) { + me = ME_ILLEGAL_FORCED_BRANCH; + } else { + me = PoreInterface::forceBranch(info.iv_address); + } + return me; +} + + +//////////////////// PoreInterface Methods ///////////////////////// + +/// \bug We need a FAPI return code for an illegaly configured model + +void +Pore::pibMaster(PibTransaction& io_transaction) +{ + ModelError me; + + if (iv_pib == 0) { + me = ME_NO_BUS_MODEL; + io_transaction.busError(me); + iv_fapiReturnCode = 1; /// \bug Need a return code + } else { + iv_fapiReturnCode = iv_pib->operation(io_transaction); + me = io_transaction.iv_modelError; + } + if (me != 0) { + modelError(me); + } +} + + +void +Pore::ociMaster(OciTransaction& io_transaction) +{ + ModelError me; + + if (iv_oci == 0) { + me = ME_NO_BUS_MODEL; + io_transaction.busError(me); + iv_fapiReturnCode = 1; /// \bug Need a return code + } else { + iv_fapiReturnCode = iv_oci->operation(io_transaction); + me = io_transaction.iv_modelError; + } + if (me != 0) { + modelError(me); + } +} + + +void +Pore::wait(const uint32_t i_count) +{ + uint64_t simCycles; + uint64_t nsDelay; + fapi::ReturnCode rc; + ModelError me; + + nsDelay = (uint64_t)((i_count * 1e9) / PORE_FREQUENCY); + + simCycles = (uint64_t) + (SIMULATOR_TICK_FREQUENCY * (i_count / PORE_FREQUENCY)); + nsDelay += 1; // Always round up the real delay. + iv_fapiReturnCode = fapiDelay(nsDelay, simCycles); + + if (iv_fapiReturnCode == 0) { + me = ME_SUCCESS; + } else { + me = ME_WAIT_FAILURE; + } + if (me != 0) { + modelError(me); + } +} + + +void +Pore::hookInstruction(const PoreAddress& i_address, + const uint32_t i_hook, + const uint64_t i_parameter) +{ + ModelError me; + + iv_fapiReturnCode = + HookManager::runInstructionHook(i_address, i_hook, i_parameter, + *this, *iv_target); + if (iv_fapiReturnCode.ok()) { + me = ME_SUCCESS; + } else { + me = ME_HOOK_INSTRUCTION_ERROR; + } + if (me != 0) { + modelError(me); + } +} + + +void +Pore::hookRead(const PoreAddress& i_address) +{ + ModelError me; + + iv_fapiReturnCode = + HookManager::runReadHooks(i_address, *this, *iv_target); + if (iv_fapiReturnCode.ok()) { + me = ME_SUCCESS; + } else { + me = ME_HOOK_READ_ERROR; + } + if (me != 0) { + modelError(me); + } +} + + +void +Pore::hookWrite(const PoreAddress& i_address) +{ + ModelError me; + + iv_fapiReturnCode = + HookManager::runWriteHooks(i_address, *this, *iv_target); + if (iv_fapiReturnCode.ok()) { + me = ME_SUCCESS; + } else { + me = ME_HOOK_WRITE_ERROR; + } + if (me != 0) { + modelError(me); + } +} + + +void +Pore::hookFetch(const PoreAddress& i_address) +{ + ModelError me; + + iv_fapiReturnCode = + HookManager::runFetchHooks(i_address, *this, *iv_target); + if (iv_fapiReturnCode.ok()) { + me = ME_SUCCESS; + } else { + me = ME_HOOK_FETCH_ERROR; + } + if (me != 0) { + modelError(me); + } +} + + +//////////////////////// PibSlave Methods //////////////////////////// + +// All offsets are known to be legal. PIB offsets are converted to OCI +// offsets used in the register read/write methods. + +fapi::ReturnCode +Pore::operation(Transaction& io_transaction) +{ + ModelError me; + fapi::ReturnCode rc; + + switch (io_transaction.iv_mode) { + + case ACCESS_MODE_READ: + me = registerRead((PoreRegisterOffset)(io_transaction.iv_offset * 8), + io_transaction.iv_data); + break; + + case ACCESS_MODE_WRITE: + me = registerWrite((PoreRegisterOffset)(io_transaction.iv_offset * 8), + io_transaction.iv_data); + break; + + default: + me = ME_BUS_SLAVE_PERMISSION_DENIED; + break; + } + + if (me) { + rc = 1; /// \bug Fix this + } + io_transaction.busError(me); + return rc; +} + + +////////////////////////////// Creators ////////////////////////////// + +Pore::Pore(PoreIbufId i_id) : + PoreInterface(i_id), + iv_pib(0), + iv_oci(0), + iv_target(NULL) +{ +} + + +Pore::~Pore() +{ +} + + +//////////////////// Interface Extensions ///////////////////////// + +void +Pore::configure(fapi::Target* i_target, Bus* i_pib, Bus* i_oci, + ecmdDataBufferBase* i_dataBuffer, + uint32_t i_base, uint64_t i_size, int i_permissions) +{ + iv_target = i_target; + iv_pib = i_pib; + iv_oci = i_oci; + PibSlave::configure(i_target, i_dataBuffer, + i_base, i_size, i_permissions); +} + + +fapi::ReturnCode +Pore::getFapiReturnCode() +{ + return iv_fapiReturnCode; +} + + diff --git a/src/usr/pore/poreve/porevesrc/pore.H b/src/usr/pore/poreve/porevesrc/pore.H new file mode 100644 index 000000000..7b773d0ad --- /dev/null +++ b/src/usr/pore/poreve/porevesrc/pore.H @@ -0,0 +1,259 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/porevesrc/pore.H $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#ifndef __VSBE_PORE_H +#define __VSBE_PORE_H + +// $Id: pore.H,v 1.14 2011/11/17 19:04:47 jeshua Exp $ + +/// \file pore.H +/// \brief The implementation of the PoreInterface for the PoreVe environment + +#include <fapi.H> + +#include "bus.H" +#include "poremodel.H" +#include "hookmanager.H" + + #ifdef VBU_HACKS + #include "fapiSharedUtils.H" + #include "ecmdUtils.H" + #endif // VBU_HACKS + + +namespace vsbe { + + class Pore; + + /// This is the putative tick frequency of the simulation environment, + /// used to model the wait() method. + const double SIMULATOR_TICK_FREQUENCY = 12e9; + + /// This is the expected operating frequency of the PORE hardware engine, + /// used to model the wait() method. + const double PORE_FREQUENCY = 600e6; +}; + + +/// The implementation of the PoreInterface for the PoreVe environment +/// +/// This class provides implementations of the virtual interface to the +/// PoreModel for the PoreVe environment. The Pore is configured by providing +/// pointers to the PIB and OCI bus models of the environment. The Pore also +/// contains the last FAPI return code produced by an operation in the virtual +/// environment. +/// +/// The Pore class is also derived from the PibSlave class. This enables the +/// PORE engine to 'self-SCOM' PORE control registers that are not visible as +/// part of the architected state. Since our PoreVe environment does not +/// included a generic OCB bridge, all self-SCOM must be programmed using PIB +/// addresses. + +class +vsbe::Pore : public PoreInterface, + public PibSlave +{ + +public: + + ///////////////////////// Control Interface ///////////////////////// + + /// Force a branch to a global symbol name + /// + /// \param[in] i_symbol A global symbol name; the branch target + /// + /// Pore provides a variant of PoreModel::forceBranch() that forces a + /// branch to a global symbol, assuming the global symbol is known to + /// HookManager. The error code ME_ILLEGAL_FORCED_BRANCH is returned if + /// the symbol is not known to the HookManager. + /// + /// See PoreModel::forceBranch() for more information + /// + /// \retval me Either 0 for success or a ModelError code. + virtual ModelError + forceBranch(const char* i_symbol); + + + //////////////////// PoreInterface Methods ///////////////////////// + + /// See PoreModel::pibMaster() for the interface specification + /// + /// Run the transaction on the PoreVe PIB Bus model. FAPI errors from + /// running PIB/PCB transactions are converted to PCB return codes and + /// stored in the \a iv_pcbReturnCode field of the \a io_transaction. + void + pibMaster(PibTransaction& io_transaction); + + /// See PoreModel::ociMaster() for the interface specification + /// + /// Run the transaction on the PoreVe OCI Bus model. FAPI errors from + /// running OCI transactions are converted to abstract return codes and + /// stored in the \a iv_ociReturnCode field of the \a io_transaction. + + void + ociMaster(OciTransaction& io_transaction); + + /// See PoreModel::wait() for the interface specification + /// + /// Simulate a WAIT of \a i_count PORE cycles. The implementation + /// attempts to accurately model the wait based on the assumed PORE clock + /// frequency, and for simulation, the assumed simulation clock frequency. + /// If execution of the WAIT results in a FAPI error, the FAPI error is + /// stored in the \a iv_fapiReturnCode. + + void + wait(const uint32_t i_count); + + /// See PoreModel::hookInstruction() for the interface specification + /// + /// Use the HookManager to run the numbered hook called out by a PORE + /// HOOKI instruction. It is not considered an error to request a hook + /// that is not mapped in the HookManager. If execution of the hook + /// results in a FAPI error, the FAPI error is stored in the + /// \a iv_fapiReturnCode. + void + hookInstruction(const PoreAddress& i_address, + const uint32_t i_hook, + const uint64_t i_parameter); + + /// See PoreModel::hookRead() for the interface specification + /// + /// Run any hooks associated with a read of the given effective address. + /// If execution of the hook results in a FAPI error, the FAPI error is + /// stored in the \a iv_fapiReturnCode. + void + hookRead(const PoreAddress& i_address); + + /// See PoreModel::hookWrite() for the interface specification + /// + /// Run any hooks associated with a write of the given effective address. + /// If execution of the hook results in a FAPI error, the FAPI error is + /// stored in the \a iv_fapiReturnCode. + void + hookWrite(const PoreAddress& i_address); + + /// See PoreModel::hookFetch() for the interface specification + /// + /// Run any hooks associated with an instruction fetch of the given + /// effective address. If execution of the hook results in a FAPI error, + /// the FAPI error is stored in the \a iv_fapiReturnCode. + void + hookFetch(const PoreAddress& i_address); + + /// See PoreModel::errorIntr() for the interface specification + /// + /// Currently not implemented by Pore. + void + errorIntr(void) {} + + /// See PoreModel::fatalErrorIntr() for the interface specification + /// + /// Currently not implemented by Pore. + void + fatalErrorIntr(void) {} + + + //////////////////////// PibSlave Methods //////////////////////////// + + /// See Slave::operation() for the interface specification + virtual fapi::ReturnCode + operation(Transaction& io_transaction); + + + ////////////////////////////// Creators ////////////////////////////// + + /// Create the Pore + /// + /// \param[in] i_id The IBUF ID (PORE engine type) of the PORE model to + /// create. + Pore(PoreIbufId i_id); + + virtual ~Pore(); + + //////////////////// Interface Extensions ///////////////////////// + + /// Configure the Pore model by providing pointers to the Bus models + /// + /// \param[in] i_target A pointer to the FAPI target object associated + /// with the PORE model, for use in hooks and for purposes of the + /// PibSlave. + /// + /// \param[in] i_pib A Bus model (to be) configured as a PIB bus. + /// + /// \param[in] i_oci A Bus model (to be) configured as an OCI bus. + /// + /// \param[in] i_dataBuffer See Slave::configure() + /// + /// \param[in] i_base See Slave::configure() + /// + /// \param[in] i_size See Slave::configure() + /// + /// \param[in] i_permissions See Slave::configure() + /// + /// This interface is introduced simply to encapsulate everything about + /// the Pore that needs to be configured to create a system. + void + configure(fapi::Target* i_target, Bus* i_pib, Bus* i_oci, + ecmdDataBufferBase* i_dataBuffer, + uint32_t i_base, uint64_t i_size, int i_permissions); + + /// Get the FAPI return code from the model + /// + /// \retval rc The last FAPI return code from any PORE operations in the + /// environment. + fapi::ReturnCode + getFapiReturnCode(); + + + ////////////////////////// Implementation //////////////////////////// + +protected: + + /// The PoreVe PIB Bus model + Bus* iv_pib; + + /// The PoreVe OCI Bus model + Bus* iv_oci; + + /// The last FAPI return code + /// + /// Operations in the PoreVe environment return FAPI ReturnCode objects. + /// The FAPI return code is stored here, and the ModelError returned to + /// the PoreModel dependson the type of error. + fapi::ReturnCode iv_fapiReturnCode; + + /// A pointer to the FAPI target associated with this PORE engine + /// + /// The Pore object holds this pointer for use as an argument to hook + /// routines. + fapi::Target* iv_target; + + + ///////////////////////////// Safety ////////////////////////////////// + +private: + + Pore(const Pore& i_rhs); + Pore& operator=(const Pore& i_rhs); +}; + +#endif // __VSBE_PORE_H diff --git a/src/usr/pore/poreve/porevesrc/poreve.C b/src/usr/pore/poreve/porevesrc/poreve.C new file mode 100644 index 000000000..e0a841cdd --- /dev/null +++ b/src/usr/pore/poreve/porevesrc/poreve.C @@ -0,0 +1,480 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/porevesrc/poreve.C $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +// $Id: poreve.C,v 1.15 2011/12/14 22:11:51 bcbrock Exp $ + +/// \file poreve.C +/// \brief The PORE Virtual Environment + +#include "poreve.H" + +using namespace vsbe; + + +//////////////////////////////////////////////////////////////////////////// +// PoreVeBase +//////////////////////////////////////////////////////////////////////////// + + +PoreVeBase::PoreVeBase(const PoreIbufId i_id, + const fapi::Target i_masterTarget) : + iv_pore(i_id), + iv_pnorMemory(PNOR_ADDRESS_BYTES), + iv_id(i_id), + iv_masterTarget(i_masterTarget), + iv_slaveTarget(i_masterTarget) +{ + uint32_t porePibBase; + + // Configure the PORE. Only the PIB bus is connected, the OCI bus remains + // unconnected (0). The PIB self-SCOM interface configuration is a + // function of which PORE egine is being configured. Technically we should + // barf if \a i_id is not PORE_SBE or PORE_SLW, but HBI doesn't want any + // throw()s. + + if (i_id == PORE_SLW) { + porePibBase = PORE_SLW_PIB_BASE; + } else { + porePibBase = PORE_SBE_PIB_BASE; + } + + iv_pore.configure(&iv_slaveTarget, &iv_pib, 0, + &iv_dataBuffer, + porePibBase, PORE_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachPrimarySlave(&iv_pore); + + // Configure the PNOR controller and attach its memory + + iv_pnorController.configure(&iv_masterTarget, + &iv_dataBuffer, + PNOR_PIB_BASE, + PNOR_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachPrimarySlave(&iv_pnorController); + + iv_pnorController.attachMemory(&iv_pnorMemory, + PNOR_I2C_PORT, + PNOR_I2C_DEVICE_ADDRESS); + + + // Configure the PIB catch-all model + + iv_pibDefault.configure(&iv_slaveTarget, + &iv_dataBuffer, + PIB_DEFAULT_PIB_BASE, + PIB_DEFAULT_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachSecondarySlave(&iv_pibDefault); +} + + +PoreVeBase::~PoreVeBase() +{ +} + + +// This is a temporary hack: Until the final specification of the reset state +// of the PORE-SBE engine is available, we initialize the PORE-SBE engine +// here. This is simpler than trying to keep the PMX model up to date as we +// mess with chaging requirements, and it's also better for PMX to assume +// that the PORE-SBE is halted at PMX-IPL, since PMX/Simics is really a model +// for OCC firmware. This initializaton of PORE-SBE is done here rather than +// in the PoreModel because we have the memory address assumptions here. +// +// If this is a PORE-SBE, then the machine comes up running from OTPROM. + +/// \bug Temporary hack + +void +PoreVeBase::reset(fapi::Target i_slaveTarget) +{ + iv_slaveTarget = i_slaveTarget; + iv_pore.restart(); + HookManager::clearError(); + + if (iv_id == PORE_SBE) { + + // The PMX model comes up halted in OCI space. We set the PC to + // OTPROM space and run() 0 instructions. This will clear the stop bit + // to start execution. + + PoreAddress pc; + uint64_t ran; + + pc.setFromPibAddress(OTPROM_PIB_BASE); + iv_pore.setPc(pc); + iv_pore.run(0, ran); + } +} + + +int +PoreVeBase::run(uint64_t i_instructions, uint64_t& o_ran) +{ + return iv_pore.run(i_instructions, o_ran); +} + + +ModelError +PoreVeBase::getscom(const uint32_t i_address, uint64_t& o_data, int& o_rc) +{ + PibTransaction t; + + t.iv_address = i_address; + t.iv_mode = ACCESS_MODE_READ; + + iv_pib.operation(t); + + o_data = t.iv_data; + o_rc = t.iv_pcbReturnCode; + return t.iv_modelError; +} + + +ModelError +PoreVeBase::putscom(const uint32_t i_address, const uint64_t i_data, int& o_rc) +{ + PibTransaction t; + + t.iv_address = i_address; + t.iv_data = i_data; + t.iv_mode = ACCESS_MODE_WRITE; + + iv_pib.operation(t); + + o_rc = t.iv_pcbReturnCode; + return t.iv_modelError; +} + + +//////////////////////////////////////////////////////////////////////////// +// PoreVe +//////////////////////////////////////////////////////////////////////////// + +PoreVe::PoreVe(const PoreIbufId i_id, + const fapi::Target i_masterTarget) : + PoreVeBase(i_id, i_masterTarget), + iv_seepromMemory(SEEPROM_ADDRESS_BYTES) +{ + uint32_t porePibBase; + + // Reconfigure the Pore - this doesn't hurt anything in the previous + // configuration in the base class as this is a set of simple pointer and + // data assignments. But it's another reason to jettison the requirement + // for the base class. The PORE was attached to the PIB in the base + // class. + + if (i_id == PORE_SLW) { + porePibBase = PORE_SLW_PIB_BASE; + } else { + porePibBase = PORE_SBE_PIB_BASE; + } + + iv_pore.configure(&iv_slaveTarget, &iv_pib, &iv_oci, + &iv_dataBuffer, + porePibBase, PORE_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + // Configure the OTPROM + + iv_otprom.configure(&iv_slaveTarget, + &iv_dataBuffer, + OTPROM_PIB_BASE, + OTPROM_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_EXECUTE, + &iv_otpromMemory); + + iv_pib.attachPrimarySlave(&iv_otprom); + + + // Configure the PIBMEM + + iv_pibmem.configure(&iv_slaveTarget, + &iv_dataBuffer, + PIBMEM_PIB_BASE, + PIBMEM_PIB_SIZE, + ACCESS_MODE_READ | + ACCESS_MODE_WRITE | + ACCESS_MODE_EXECUTE, + &iv_pibmemMemory); + + iv_pib.attachPrimarySlave(&iv_pibmem); + + + // Configure the SEEPROM controller + + iv_seepromController.configure(&iv_slaveTarget, + &iv_dataBuffer, + SEEPROM_PIB_BASE, + SEEPROM_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachPrimarySlave(&iv_seepromController); + + iv_seepromController.attachMemory(&iv_seepromMemory, + SEEPROM_I2C_PORT, + SEEPROM_I2C_DEVICE_ADDRESS); + + // Configure Mainstore + + iv_main.configure(&iv_slaveTarget, + &iv_dataBuffer, + MAINSTORE_OCI_BASE, + MAINSTORE_OCI_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE, + &iv_mainMemory); + + iv_oci.attachPrimarySlave(&iv_main); + + + // Configure SRAM + + iv_sram.configure(&iv_slaveTarget, + &iv_dataBuffer, + SRAM_OCI_BASE, + SRAM_OCI_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE, + &iv_sramMemory); + + iv_oci.attachPrimarySlave(&iv_sram); + + +#ifdef PM_HACKS + // This device provides write-only access to a single control register in + // the PMC. + + iv_pmc.configure(&iv_slaveTarget, + &iv_dataBuffer, + PMC_OCI_BASE, + PMC_OCI_SIZE, + ACCESS_MODE_WRITE); + + iv_oci.attachPrimarySlave(&iv_pmc); +#endif // PM_HACKS + + +#ifdef VBU_HACKS + // Configure the temporary Pib2Cfam component + + iv_pib2Cfam.configure(&iv_slaveTarget, + &iv_dataBuffer, + PIB2CFAM_PIB_BASE, + PIB2CFAM_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachPrimarySlave(&iv_pib2Cfam); + + // Configure the temporary sbeVital component + + iv_sbeVital.configure(&iv_slaveTarget, + &iv_dataBuffer, + SBEVITAL_PIB_BASE, + SBEVITAL_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachPrimarySlave(&iv_sbeVital); + +#ifndef SIMPLE_VBU_HACKS_ONLY + + // The VBU_HACKS above are simple - they don't require complex eCMD support so + // we can test them easily with the poreve/test/fapistub test case. + + // The VBU hacks below are complicated to emulate, so we don't even try in + // the test/fapistub test case. + + // Configure the Broadside scan component if using BROADSIDE scan + //JDS TODO - add a check for broadside scan mode + ecmdConfigValid_t validOutput; + std::string tmpStr; + uint32_t tmpNum; + uint32_t rc; + ecmdChipTarget e_target; + + //JDS TODO - change this to get attribute + fapiTargetToEcmdTarget( iv_slaveTarget, e_target); + rc = ecmdGetConfiguration(e_target, "SIM_BROADSIDE_MODE", + validOutput, tmpStr, tmpNum ); + if( rc || + validOutput == ECMD_CONFIG_VALID_FIELD_NONE || + validOutput == ECMD_CONFIG_VALID_FIELD_NUMERIC ) + { + FAPI_ERR( "Unable to determine SIM_BROADSIDE_MODE\n" ); + } + else + { + size_t pos = tmpStr.find( "scan" ); + if( pos != (uint32_t)-1 ) + { +// iv_bsscan_ex00.configure(&iv_slaveTarget, +// &iv_dataBuffer, +// BSSCAN_PIB_BASE | EX00_PIB_BASE, +// BSSCAN_PIB_SIZE, +// ACCESS_MODE_READ | ACCESS_MODE_WRITE); + +// iv_pib.attachPrimarySlave(&iv_bsscan_ex00); + + iv_bsscan_ex01.configure(&iv_slaveTarget, + &iv_dataBuffer, + BSSCAN_PIB_BASE | EX01_PIB_BASE, + BSSCAN_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachPrimarySlave(&iv_bsscan_ex01); + + iv_bsscan_ex02.configure(&iv_slaveTarget, + &iv_dataBuffer, + BSSCAN_PIB_BASE | EX02_PIB_BASE, + BSSCAN_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachPrimarySlave(&iv_bsscan_ex02); + + iv_bsscan_ex03.configure(&iv_slaveTarget, + &iv_dataBuffer, + BSSCAN_PIB_BASE | EX03_PIB_BASE, + BSSCAN_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachPrimarySlave(&iv_bsscan_ex03); + + iv_bsscan_ex04.configure(&iv_slaveTarget, + &iv_dataBuffer, + BSSCAN_PIB_BASE | EX04_PIB_BASE, + BSSCAN_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachPrimarySlave(&iv_bsscan_ex04); + + iv_bsscan_ex05.configure(&iv_slaveTarget, + &iv_dataBuffer, + BSSCAN_PIB_BASE | EX05_PIB_BASE, + BSSCAN_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachPrimarySlave(&iv_bsscan_ex05); + + iv_bsscan_ex06.configure(&iv_slaveTarget, + &iv_dataBuffer, + BSSCAN_PIB_BASE | EX06_PIB_BASE, + BSSCAN_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachPrimarySlave(&iv_bsscan_ex06); + +// iv_bsscan_ex07.configure(&iv_slaveTarget, +// &iv_dataBuffer, +// BSSCAN_PIB_BASE | EX07_PIB_BASE, +// BSSCAN_PIB_SIZE, +// ACCESS_MODE_READ | ACCESS_MODE_WRITE); + +// iv_pib.attachPrimarySlave(&iv_bsscan_ex07); + +// iv_bsscan_ex08.configure(&iv_slaveTarget, +// &iv_dataBuffer, +// BSSCAN_PIB_BASE | EX08_PIB_BASE, +// BSSCAN_PIB_SIZE, +// ACCESS_MODE_READ | ACCESS_MODE_WRITE); + +// iv_pib.attachPrimarySlave(&iv_bsscan_ex08); + + iv_bsscan_ex09.configure(&iv_slaveTarget, + &iv_dataBuffer, + BSSCAN_PIB_BASE | EX09_PIB_BASE, + BSSCAN_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachPrimarySlave(&iv_bsscan_ex09); + + iv_bsscan_ex10.configure(&iv_slaveTarget, + &iv_dataBuffer, + BSSCAN_PIB_BASE | EX10_PIB_BASE, + BSSCAN_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachPrimarySlave(&iv_bsscan_ex10); + + iv_bsscan_ex11.configure(&iv_slaveTarget, + &iv_dataBuffer, + BSSCAN_PIB_BASE | EX11_PIB_BASE, + BSSCAN_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachPrimarySlave(&iv_bsscan_ex11); + + iv_bsscan_ex12.configure(&iv_slaveTarget, + &iv_dataBuffer, + BSSCAN_PIB_BASE | EX12_PIB_BASE, + BSSCAN_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachPrimarySlave(&iv_bsscan_ex12); + + iv_bsscan_ex13.configure(&iv_slaveTarget, + &iv_dataBuffer, + BSSCAN_PIB_BASE | EX13_PIB_BASE, + BSSCAN_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachPrimarySlave(&iv_bsscan_ex13); + + iv_bsscan_ex14.configure(&iv_slaveTarget, + &iv_dataBuffer, + BSSCAN_PIB_BASE | EX14_PIB_BASE, + BSSCAN_PIB_SIZE, + ACCESS_MODE_READ | ACCESS_MODE_WRITE); + + iv_pib.attachPrimarySlave(&iv_bsscan_ex14); + +// iv_bsscan_ex15.configure(&iv_slaveTarget, +// &iv_dataBuffer, +// BSSCAN_PIB_BASE | EX15_PIB_BASE, +// BSSCAN_PIB_SIZE, +// ACCESS_MODE_READ | ACCESS_MODE_WRITE); + +// iv_pib.attachPrimarySlave(&iv_bsscan_ex15); + } //end SIM_BROADSIDE_MODE has scan + } //end was able to read SIM_BROADSIDE_MODE + +#endif // SIMPLE_VBU_HACKS_ONLY +#endif // VBU_HACKS +} + + +PoreVe::~PoreVe() +{ +} + + + + + + + + + + + + diff --git a/src/usr/pore/poreve/porevesrc/poreve.H b/src/usr/pore/poreve/porevesrc/poreve.H new file mode 100644 index 000000000..4c2281940 --- /dev/null +++ b/src/usr/pore/poreve/porevesrc/poreve.H @@ -0,0 +1,535 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/porevesrc/poreve.H $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#ifndef __VSBE_POREVE_H +#define __VSBE_POREVE_H + +// $Id: poreve.H,v 1.18 2011/12/16 21:47:59 bcbrock Exp $ + +/// \file poreve.H +/// \brief The PORE Virtual Environment +/// +/// The PORE Virtual Environment is a container class that contains a Pore +/// model along with the Bus and Memory models that comprise a Pore system. +/// These system models offer very little in the way of interfaces other than +/// a way to reset() the simulation and a run() method to clock the +/// simulation. Instead, most operations on the PORE (including setting up the +/// initial state) are performed directly on the Pore model data member \a +/// iv_pore itself. Similarly, memories are configured by map() operations +/// directly on the memory objects. +/// +/// The system components are created and interconnected in a simple two-step +/// process: +/// +/// - When objects are created any truly static configuration parameters are +/// passed as arguments of the constructor. +/// +/// - After all components are constructed, simple code sequences stitch +/// together the components using a configure() method provided by each class +/// of component. +/// +/// This two-step sequence eliminates the problem of loops that would arise if +/// we tried to configure the network in the constructor, and is very similar +/// to the way that Simics models are configured. +/// +/// The final PoreVe model is constructed in two steps. We first define a +/// PoreVeBase model. This is a stripped down environment that only contains +/// a PORE engine and the exact components required for the HBI application of +/// PORE-SBE. The Vsbe facade class is later provided as the interface to +/// PoreVeBase. +/// +/// The second step of the derivation is to add all of the remaining +/// components to create the full PoreVe model for use in VBU and lab +/// applications. The derivation is done this way to make the PoreVeBase as +/// small as possible in terms of both code and data size. Ideally however +/// the differences (in code and data size) will turn out to be small enough +/// such that we can drop the separate models and simply always create the +/// full PoreVe model, using the Vsbe facade as the high-level interface for +/// HBI. Frankly, the system design would probably be more robust if we had +/// only one model - we may go ahead and merge the models anyway. + +#include <stdint.h> +#include <stdarg.h> + +#include "fapi.H" + +#include "fasti2c.H" +#include "poremodel.H" +#include "pore.H" + +#ifdef VBU_HACKS +#include "pib2cfam.H" +#include "bsscan.H" +#include "sbevital.H" +#endif // VBU_HACKS + +#ifndef POREVE_STATISTICS +#define POREVE_STATISTICS 0 +#endif + +namespace vsbe { + + class PoreVeBase; + class PoreVe; + + /// \defgroup poreve_config Parameters of PoreVe Configurations + /// + /// These parameters are required for configuring the PoreVe system model. + /// + /// \bug Many of these parameters are fake for now and will be system + /// dependent. + /// + /// @{ + + ////////////////////////////////////////////////////////////////////// + // PORE + ////////////////////////////////////////////////////////////////////// + + /// The PIB base address of PORE-SBE control registers + const uint32_t PORE_SBE_PIB_BASE = 0x000e0000; + + /// The PIB base address of PORE-SLW control registers + const uint32_t PORE_SLW_PIB_BASE = 0x00068000; + + /// The size of the PORE control register space. + const uint64_t PORE_PIB_SIZE = ((uint64_t)SIZEOF_VISIBLE_PORE_STATE) / 8; + + + ////////////////////////////////////////////////////////////////////// + // OTPROM + ////////////////////////////////////////////////////////////////////// + + /// The PIB base address of the OTPROM memory controller + const uint32_t OTPROM_PIB_BASE = 0x00010000; + + /// The number of PIB \e registers defined by the OTPROM memory controller + /// + /// PIB memories are 8-byte \e word addressed. The maximum amount of + /// memory accessible through the controller is (OTPROM_PIB_SIZE * 8) + /// bytes. + const uint64_t OTPROM_PIB_SIZE = 0x200; + + + ////////////////////////////////////////////////////////////////////// + // PIBMEM + ////////////////////////////////////////////////////////////////////// + + /// The PIB base address of the PIBMEM memory controller + const uint32_t PIBMEM_PIB_BASE = 0x00080000; + + /// The number of PIB \e registers defined by the PIBMEM memory controller + /// + /// PIB memories are 8-byte \e word addressed. The maximum amount of + /// memory accessible through the controller is (PIBMEM_PIB_SIZE * 8) + /// bytes (3KB). + const uint64_t PIBMEM_PIB_SIZE = 0x180; + + + ////////////////////////////////////////////////////////////////////// + // PNOR + ////////////////////////////////////////////////////////////////////// + + /// The PIB base address of the PNOR (LPCM) memory controller + const uint32_t PNOR_PIB_BASE = 0x000b0000; + + /// The number of registers defined by the PNOR memory controller + const size_t PNOR_PIB_SIZE = LPCM_REGISTERS; + + /// The number of bytes in a PNOR address (actually a parameter of the + /// memory attached to the controller) + const size_t PNOR_ADDRESS_BYTES = 4; + + /// The PNOR I2C Port Number + const unsigned PNOR_I2C_PORT = 0; + + /// The PNOR I2C Device Address + const unsigned PNOR_I2C_DEVICE_ADDRESS = 0; + + + ////////////////////////////////////////////////////////////////////// + // SEEPROM + ////////////////////////////////////////////////////////////////////// + + /// The PIB base address of the SEEPROM memory controller + const uint32_t SEEPROM_PIB_BASE = 0x000c0000; + + /// The number of registers defined by the SEEPROM memory controller + const uint64_t SEEPROM_PIB_SIZE = FASTI2C_REGISTERS; + + /// The number of bytes in an SEEPROM address + const uint64_t SEEPROM_ADDRESS_BYTES = 2; + + /// The SEEPROM I2C Port Number + const unsigned SEEPROM_I2C_PORT = 0; + + /// The SEEPROM I2C Device Address + /// + /// \bug This value (0) is bogus, need the real value from the system + /// design. + const unsigned SEEPROM_I2C_DEVICE_ADDRESS = 0; + + + ////////////////////////////////////////////////////////////////////// + // PIB Default Catch-All Model + ////////////////////////////////////////////////////////////////////// + + /// The PIB base address of the default PIB slave + const uint32_t PIB_DEFAULT_PIB_BASE = 0x0; + + /// The number of registers defined by the default PIB slave + const uint64_t PIB_DEFAULT_PIB_SIZE = 0x100000000ull; + + + ////////////////////////////////////////////////////////////////////// + // OCI-Attached Components + ////////////////////////////////////////////////////////////////////// + + /// The OCI base address of the OCI PBA->Mainstore bridge + /// + /// We go ahead and map the entire 1GB. During configuration the actual + /// memory area in use will be defined by Memory::map() calls. + const uint32_t MAINSTORE_OCI_BASE = 0x00000000; + + /// The OCI PBA->Mainstore bridge maps 1GB of the address space + const uint64_t MAINSTORE_OCI_SIZE = 0x40000000; + + + /// The OCI base address of the SRAM + const uint32_t SRAM_OCI_BASE = 0xfff80000; + + /// The OCI SRAM is 512KB + const uint64_t SRAM_OCI_SIZE = 0x00080000; + + /// The OCI address of the PMC_PORE_REQ_STAT_REG Register + /// + /// This is the only OCI control register that PORE-SLW should access, so + /// its size is limited to 8 bytes. + const uint32_t PMC_OCI_BASE = 0x40010480; + + /// PORE-SLW is only allowed to access a specific 8 bytes of the OCI + /// control register space. + const uint64_t PMC_OCI_SIZE = 8; + + /// @} +}; + + +//////////////////////////////////////////////////////////////////////////// +// PoreVeBase +//////////////////////////////////////////////////////////////////////////// + +/// The base class (HBI-only components) of PoreVe. +/// +/// This model contains only those components required for HBI applications +/// of the PORE virtual environment. Currently this is only +/// +/// - A Pore +/// - A PIB bus +/// - A PNOR memory model +/// - A PibSlave to catch any getscom()/putscom() destined for the PIB + +class +vsbe::PoreVeBase { + +public: + + ////////////////////////////// Creators ////////////////////////////// + + /// Construct the PoreVeBase + /// + /// \param[in] i_id The PORE IBUF_ID (engine type) of the Pore component. + /// This will be PORE_SBE for host boot/SBE applications, and PORE_SLW for + /// testing Sleep/Winkle applications. + /// + /// \param[in] i_masterTarget The fapi::Target associated with the master + /// chip in an HBI master/slave configuration. This target is also + /// installed into \a iv_slaveTarget by the constructor. + PoreVeBase(const PoreIbufId i_id, const fapi::Target i_masterTarget); + + virtual ~PoreVeBase(); + + + //////////////////// Simulation Interface ///////////////////////// + + /// Reset the simulation to target a new slave + /// + /// \param[in] i_slaveTarget The slave target of the new slave + /// + /// The reset() method is provided to cleanly reset the simulation for + /// simulation with a new slave target. Once reset, the application is + /// responsible for setting up the register state of the Pore and invoking + /// the run() method to begin simulation. + virtual void + reset(fapi::Target i_slaveTarget); + + + /// See PoreModel::run() + /// + /// This API is provided as a convenience. Currently the only model in + /// the system that is 'clocked' is the PoreModel. + virtual int + run(const uint64_t i_instructions, uint64_t& o_ran); + + + /// Run a 'getscom' on the virtual PIB + /// + /// \param[in] i_address A 32-bit SCOM address + /// + /// \param[out] o_data The 64-bit SCOM data returned from the read + /// + /// \param[out] o_rc The 3-bit PIB/PCB error code returned from the PIB + /// transaction, see the PcbReturnCode enum in transaction.H. + /// + /// This method allows a caller to run a read transaction on the virtual + /// PIB bus, observing the same PIB configuration seen by the virtual PORE + /// engine. Accesses of PIB/PCB addresses that are modeled in the virtual + /// model return modeled results, and accesses of non-modeled addresses + /// are converted into FAPI calls. + /// + /// \returns A return value of 0 indicates success of the method call, but + /// does not guarantee that the PIB transaction succeeded. It will also be + /// necessary to also observe that PIB/PCB return code \a o_rc was + /// returned as 0. A non-0 return code from the method indicates a + /// modeling error. + virtual ModelError + getscom(const uint32_t i_address, uint64_t& o_data, int& o_rc); + + + /// Run a 'putscom' on the virtual PIB + /// + /// \param[in] i_address A 32-bit SCOM address + /// + /// \param[out] i_data The 64-bit SCOM write data + /// + /// \param[out] o_rc The 3-bit PIB/PCB error code returned from the PIB + /// transaction, see the PcbReturnCode enum in transaction.H. + /// + /// This method allows a caller to run a write transaction on the virtual + /// PIB bus, observing the same PIB configuration seen by the virtual PORE + /// engine. Accesses of PIB/PCB addresses that are modeled in the virtual + /// model update modeled registers, and accesses of non-modeled addresses + /// are converted into FAPI calls. + /// + /// \returns A return value of 0 indicates success of the method call, but + /// does not guarantee that the PIB transaction succeeded. It will also be + /// necessary to also observe that PIB/PCB return code \a o_rc was + /// returned as 0. A non-0 return code from the method indicates a + /// modeling error. + virtual ModelError + putscom(const uint32_t i_address, const uint64_t i_data, int& o_rc); + + + //////////////////// Public Implementation //////////////////////////// + + /// The Pore model + Pore iv_pore; + + /// The PIB bus model + Bus iv_pib; + + /// The PNOR controller model + FastI2cController iv_pnorController; + + /// The PNOR memory model + I2cMemory iv_pnorMemory; + + /// The secondary PIB slave. + /// + /// This slave routes all operations that do not hit in a PIB-attached + /// memory model to hardware via FAPI getscom/putcom. + PibSlave iv_pibDefault; + + + //////////////////// Protected Implementation /////////////////////////// + +protected: + + /// The PORE IBUF ID of the PORE engine + PoreIbufId iv_id; + + /// The master fapi::Target + /// + /// HBI applications differentiate between the \e master chip that is + /// brought up first, and the \e slave chips that the master then + /// initializes. The master target is considered a constant and is + /// provided in the constructor. The master target is always associated + /// with the PNOR; the other memory components are associated with the + /// slave target. A pointer to this data member is provided to the PNOR + /// model during configuration. + fapi::Target iv_masterTarget; + + + /// The slave fapi::Target + /// + /// HBI applications differentiate between the \e master chip that is + /// brought up first, and the \e slave chips that the master then + /// initializes. The slave target is considered a variable and the + /// reset() method is provided to safely reset the system and modify the + /// slave target after construction. Note that the slave target is + /// initialized to be identical to the master target by the constructor. + /// A pointer to this data member is provided to all slaves other that the + /// PNOR model during configuration. + fapi::Target iv_slaveTarget; + + + /// The common ecmdDataBufferBase for all FAPI APIs + /// + /// To save memory space we only allocate one FAPI data buffer that is + /// used by all FAPI APIs that require a ecmdDataBuffer. A pointer to + /// this data member is provided to all slaves during configuration. + ecmdDataBufferBase iv_dataBuffer; + + + ///////////////////////////// Safety ////////////////////////////////// + +private: + PoreVeBase(const PoreVeBase& i_rhs); + PoreVeBase& operator=(const PoreVeBase& i_rhs); +}; + + +//////////////////////////////////////////////////////////////////////////// +// PoreVe +//////////////////////////////////////////////////////////////////////////// + + +/// The full PoreVe configuration +/// +/// This derivation from PoreVeBase adds the remaining PIB models not required +/// by the HBI application, as well as all of the OCI models. Note that +/// unlike the PIB there is no catch-all for OCI accesses; An access must hit +/// within one of the defined memory maps, otherwise the access is considered +/// an error. + +class +vsbe::PoreVe : public vsbe::PoreVeBase { + +public: + + ////////////////////////////// Creators ////////////////////////////// + + /// Construct the PoreVe + /// + /// \param[in] i_id The PORE IBUF_ID (engine type) of the Pore component. + /// This will be PORE_SBE for host boot/SBE applications, and PORE_SLW for + /// testing Sleep/Winkle applications. + /// + /// \param[in] i_masterTarget The fapi::Target associated with the master + /// chip in an HBI master/slave configuration. This target is also + /// installed into \a iv_slaveTarget by the constructor. + PoreVe(const PoreIbufId i_id, const fapi::Target i_masterTarget); + + virtual ~PoreVe(); + + /// Create a PoreVe (subclass) by static link-time selection + /// + /// \param[in] i_id The PORE IBUF_ID (engine type) of the Pore component. + /// This will be PORE_SBE for host boot/SBE applications, and PORE_SLW for + /// testing Sleep/Winkle applications. + /// + /// \param[in] i_masterTarget The fapi::Target associated with the master + /// chip in an HBI master/slave configuration. This target is also + /// installed into \a iv_slaveTarget by the constructor. + /// + /// \param[in] i_arg A private argument for the created model. In the + /// case of a debugged model this is a character string naming a script to + /// be run when the debugger starts. The PoreVe ignores this argument. + /// + /// The static create() method is provided to enable link-time selection + /// of a subclass of PoreVe, in particular to allow a common FAPI PoreVe + /// procedure to create either a 'normal' or 'debug' version of PoreVe. + static PoreVe* create(const PoreIbufId i_id, + const fapi::Target i_masterTarget, + const void* i_arg); + + //////////////////// Public Implementation //////////////////////////// + + /// The OTPROM controller model + PibMemory iv_otprom; + + /// The OTPROM memory model + Memory iv_otpromMemory; + + /// The PIBMEM controller model - No advanced functions implemented for now + PibMemory iv_pibmem; + + /// The PIPMEM memory model + Memory iv_pibmemMemory; + + /// The SEEPROM controller model + FastI2cController iv_seepromController; + + /// The SEEPROM memory model + I2cMemory iv_seepromMemory; + + /// The OCI bus model + Bus iv_oci; + + /// The Mainstore memory controller model + OciMemory iv_main; + + /// The Mainstore memory model + Memory iv_mainMemory; + + /// The SRAM controller model + OciMemory iv_sram; + + /// The SRAM memory model + Memory iv_sramMemory; + +#ifdef PM_HACKS + OciSlaveWritable iv_pmc; +#endif // PM_HACKS + +#ifdef VBU_HACKS + /// The temporary Pib2Cfam PIB Slave + Pib2Cfam iv_pib2Cfam; + + /// The temporary sbeVital PIB Slave + SbeVital iv_sbeVital; + + /// The Broadside Scan components for each EX + // Bsscan iv_bsscan_ex00; + Bsscan iv_bsscan_ex01; + Bsscan iv_bsscan_ex02; + Bsscan iv_bsscan_ex03; + Bsscan iv_bsscan_ex04; + Bsscan iv_bsscan_ex05; + Bsscan iv_bsscan_ex06; + // Bsscan iv_bsscan_ex07; + // Bsscan iv_bsscan_ex08; + Bsscan iv_bsscan_ex09; + Bsscan iv_bsscan_ex10; + Bsscan iv_bsscan_ex11; + Bsscan iv_bsscan_ex12; + Bsscan iv_bsscan_ex13; + Bsscan iv_bsscan_ex14; + // Bsscan iv_bsscan_ex15; +#endif + ///////////////////////////// Safety ////////////////////////////////// + +private: + PoreVe(const PoreVe& i_rhs); + PoreVe& operator=(const PoreVe& i_rhs); +}; + +#endif // __VSBE_POREVE_H diff --git a/src/usr/pore/poreve/porevesrc/sbevital.C b/src/usr/pore/poreve/porevesrc/sbevital.C new file mode 100644 index 000000000..1a80337db --- /dev/null +++ b/src/usr/pore/poreve/porevesrc/sbevital.C @@ -0,0 +1,82 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/porevesrc/sbevital.C $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +// -*- mode: C++; c-file-style: "linux"; -*- +// $Id: sbevital.C,v 1.1 2011/09/19 00:25:32 jeshua Exp $ + +/// \file sbevital.C +/// \brief A temporary hack to create the SBE vital reg before HW has it +/// +#ifdef VBU_HACKS + +#include "sbevital.H" +#include "fapiSharedUtils.H" +#include "ecmdUtils.H" +using namespace vsbe; + + +////////////////////////////// Creators ////////////////////////////// + +SbeVital::SbeVital() +{ + iv_data = 0; +} + + +SbeVital::~SbeVital() +{ +} + + +//////////////////////////// Manipulators //////////////////////////// + +fapi::ReturnCode +SbeVital::operation(Transaction& io_transaction) +{ + fapi::ReturnCode rc=0; + ModelError me; + + FAPI_INF("In sbeVital\n"); + + //On a ring write, put the data into the ring + if( io_transaction.iv_mode == ACCESS_MODE_WRITE) + { + iv_data = io_transaction.iv_data >> 32; + me = ME_SUCCESS; + } + else if( io_transaction.iv_mode == ACCESS_MODE_READ ) + { + io_transaction.iv_data = ((uint64_t)(iv_data)) << 32; + me = ME_SUCCESS; + } + else + { + me = ME_FAILURE; + } + + io_transaction.busError(me); + return rc; +} +#endif +/* Local Variables: */ +/* c-basic-offset: 4 */ +/* End: */ diff --git a/src/usr/pore/poreve/porevesrc/sbevital.H b/src/usr/pore/poreve/porevesrc/sbevital.H new file mode 100644 index 000000000..66aa83f96 --- /dev/null +++ b/src/usr/pore/poreve/porevesrc/sbevital.H @@ -0,0 +1,85 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/pore/poreve/porevesrc/sbevital.H $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#ifndef __VSBE_SBEVITAL_H +#define __VSBE_SBEVITAL_H + +// $Id: sbevital.H,v 1.1 2011/09/19 00:25:32 jeshua Exp $ + +/// \file sbevital.H +/// \brief A hack to intercept scan operations and make them broadside + +#include "bus.H" + +namespace vsbe { + + class SbeVital; + + /// PIB base address of PIB range mapped by SbeVital + const uint32_t SBEVITAL_PIB_BASE = 0x0005001C; + + /// Number of PIB addresses mapped by SbeVital + const int SBEVITAL_PIB_SIZE = 1; + +} + + +/// Map PIB accesses to CFAM accesses + +class +vsbe::SbeVital : public PibSlave { + +public: + + ////////////////////////////// Creators ////////////////////////////// + + SbeVital(); + + virtual ~SbeVital(); + + + //////////////////////////// Manipulators //////////////////////////// + + /// SbeVital operation + /// + /// \param[in,out] io_transaction A PIB transaction object + /// + /// This object converts PIB transactions in a certain range in the + /// virtual environment to broadside getRing and putRing operations, + /// returning the FAPI return code from the translated calls. + /// + /// \retval rc The fapi::ReturnCode returned by the underlying + /// getRing() or putRing() call. + fapi::ReturnCode + operation(Transaction& io_transaction); + + + ///////////////////////////// Safety ////////////////////////////////// + +private: + SbeVital(const SbeVital& rhs); + SbeVital& operator=(const SbeVital& rhs); + + uint32_t iv_data; +}; + +#endif // __VSBE_SBEVITAL_H |