hackedteam/vector-edk

View on GitHub
vector-uefi/fd/tool/chipsec/hal/smbus.py

Summary

Maintainability
A
2 hrs
Test Coverage
#!/usr/local/bin/python
#CHIPSEC: Platform Security Assessment Framework
#Copyright (c) 2010-2014, Intel Corporation
# 
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
#as published by the Free Software Foundation; Version 2.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with this program; if not, write to the Free Software
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
#Contact information:
#chipsec@intel.com
#



# -------------------------------------------------------------------------------
#
# CHIPSEC: Platform Hardware Security Assessment Framework
# (c) 2010-2012 Intel Corporation
#
# -------------------------------------------------------------------------------
## \addtogroup hal
# chipsec/hal/smbus.py
# ================================
# Access to SMBus Controller
#
#
#



from chipsec.logger import *
from chipsec.cfg.common import *

class SMBus:
    def __init__( self, cs ):
        self.cs = cs

    def get_SMBus_Base_Address( self ):
        #
        # B0:D31:F3 + 0x20 SMBus Base Address (SBA)
        #
        reg_value = self.cs.pci.read_byte( 0, Cfg.PCI_B0D31F3_SMBUS_CTRLR_DEV, Cfg.PCI_B0D31F3_SMBUS_CTRLR_FUN, Cfg.CFG_REG_PCH_SMB_SBA )
        return (reg_value & Cfg.CFG_REG_PCH_SMB_SBA_BASE_ADDRESS_MASK) 

    def get_SMBus_HCFG( self ):
        #
        # B0:D31:F3 + 0x40 SMBus Host Configuration (HCFG)
        #
        reg_value = self.cs.pci.read_byte( 0, Cfg.PCI_B0D31F3_SMBUS_CTRLR_DEV, Cfg.PCI_B0D31F3_SMBUS_CTRLR_FUN, Cfg.CFG_REG_PCH_SMB_HCFG )
        hcfg = Cfg.SMB_HCFG_REG( reg_value, (reg_value&Cfg.CFG_REG_PCH_SMB_HCFG_SPD_WD > 0), (reg_value&Cfg.CFG_REG_PCH_SMB_HCFG_SSRESET > 0), (reg_value&Cfg.CFG_REG_PCH_SMB_HCFG_I2C_EN > 0), (reg_value&Cfg.CFG_REG_PCH_SMB_HCFG_SMB_SMI_EN > 0), (reg_value&Cfg.CFG_REG_PCH_SMB_HCFG_HST_EN > 0) )
        return hcfg

    def display_SMBus_info( self ):
        logger().log( "[smbus] SMBus Base Address: 0x%04X" % self.get_SMBus_Base_Address() )
        logger().log( self.get_SMBus_HCFG() )

    def is_SMBus_enabled( self ):
        return self.cs.pci.is_enabled( 0, Cfg.PCI_B0D31F3_SMBUS_CTRLR_DEV, Cfg.PCI_B0D31F3_SMBUS_CTRLR_FUN )

    def is_SMBus_supported( self ):
        (did,vid) = self.cs.pci.get_DIDVID( 0, Cfg.PCI_B0D31F3_SMBUS_CTRLR_DEV, Cfg.PCI_B0D31F3_SMBUS_CTRLR_FUN )
        if logger().VERBOSE:
           logger().log( "[*] SMBus Controller (DID,VID) = (0x%04X,0x%04X)" % (did,vid) )

        # @TODO: check correct DIDs
        #if (0x8086 == vid and Cfg.PCI_B0D31F3_SMBUS_CTRLR_DID == did):
        if (0x8086 == vid):
          return True
        else:
          logger().error( "Unknown SMBus Controller (DID,VID) = (0x%04X,0x%04X)" % (did,vid) )
          return False

    def is_SMBus_host_controller_enabled( self ):
        hcfg = self.get_SMBus_HCFG()
        return hcfg.CFG_REG_PCH_SMB_HCFG_HST_EN

    def enable_SMBus_host_controller( self ):
        # Enable SMBus Host Controller Interface in HCFG
        hcfg = self.get_SMBus_HCFG()
        if 0 == hcfg.HST_EN:
            hcfg.HST_EN = 1
            self.cs.pci.write_byte( 0, Cfg.PCI_B0D31F3_SMBUS_CTRLR_DEV, Cfg.PCI_B0D31F3_SMBUS_CTRLR_FUN, Cfg.CFG_REG_PCH_SMB_HCFG, hcfg )

        # @TODO: check SBA is programmed
        sba = self.get_SMBus_Base_Address()

        # Enable I/O Space in CMD
        cmd = self.cs.pci.read_word( 0, Cfg.PCI_B0D31F3_SMBUS_CTRLR_DEV, Cfg.PCI_B0D31F3_SMBUS_CTRLR_FUN, Cfg.CFG_REG_PCH_SMB_CMD )
        if (cmd & 0x1): self.cs.pci.write_byte( 0, Cfg.PCI_B0D31F3_SMBUS_CTRLR_DEV, Cfg.PCI_B0D31F3_SMBUS_CTRLR_FUN, Cfg.CFG_REG_PCH_SMB_CMD, 0x1 )


    def _wait_for_cycle( self, smbus_io_base ):
        # wait for cycle to complete
        #while True:
        for i in range(10):
            sts = self.cs.io.read_port_byte( smbus_io_base )
            if   (sts & 0x02): break
            elif (sts & 0x04): logger().error( "SMBus cycle failed: Device error" )
            elif (sts & 0x08): logger().error( "SMBus cycle failed: Bus Error" )
            elif (sts & 0x10): logger().error( "SMBus cycle failed: Unknown Error" )
        if (0x02 == sts): return True
        else: return False

    def _read_byte( self, smbus_io_base, target_address, offset ):
        self.cs.io.write_port_byte( smbus_io_base + 0x0, 0xFF )                   # Clear status bits
        ##self.cs.io.write_port_byte( smbus_io_base + 0x1, 0x1F )
        #for i in range(100):
        #    self.cs.io.write_port_byte( smbus_io_base + 0x0, 0xFF )                   # Clear status bits
        #    sts = self.cs.io.read_port_byte( smbus_io_base )
        #    if (0 == (sts & 0x9F)): break
        #if (sts & 0x9F):
        #    logger().error( "SMBus is not ready for whatever reason" ) 
        #    return 0xFF

        self.cs.io.write_port_byte( smbus_io_base + 0x4, (target_address | 0x1) ) # Byte Read from SMBus device at target_address
        self.cs.io.write_port_byte( smbus_io_base + 0x3, offset )                 # Byte offset
        self.cs.io.write_port_byte( smbus_io_base + 0x2, 0x48 )                   # Send command
        # wait for cycle to complete
        if not self._wait_for_cycle( smbus_io_base ): return 0xFF
        # read the data
        value = self.cs.io.read_port_byte( smbus_io_base + 0x5 )
        # Clear status bits
        self.cs.io.write_port_byte( smbus_io_base + 0x0, 0xFF )
        return value

    def _write_byte( self, smbus_io_base, target_address, offset, value ):
        self.cs.io.write_port_byte( smbus_io_base + 0x0, 0xFF )            # Clear status bits
        self.cs.io.write_port_byte( smbus_io_base + 0x4, target_address )  # Byte Write to SMBus device at target_address
        self.cs.io.write_port_byte( smbus_io_base + 0x3, offset )          # Byte offset
        self.cs.io.write_port_byte( smbus_io_base + 0x5, value )           # Byte data to write
        self.cs.io.write_port_byte( smbus_io_base + 0x2, 0x48 )            # Send command
        # wait for cycle to complete
        if not self._wait_for_cycle( smbus_io_base ): return False
        # Clear status bits
        self.cs.io.write_port_byte( smbus_io_base + 0x0, 0xFF )
        return True

    def read_byte( self, target_address, offset ):
        smbus_io_base = self.cs.pci.read_word( 0, Cfg.PCI_B0D31F3_SMBUS_CTRLR_DEV, Cfg.PCI_B0D31F3_SMBUS_CTRLR_FUN, 0x20 ) & 0xFFFE
        value = self._read_byte( smbus_io_base, target_address, offset )
        if logger().VERBOSE: logger().log( "[smbus] read device %X off %X = %X" % (target_address, offset, value) )
        return value

    def write_byte( self, target_address, offset, value ):
        smbus_io_base = self.cs.pci.read_word( 0, Cfg.PCI_B0D31F3_SMBUS_CTRLR_DEV, Cfg.PCI_B0D31F3_SMBUS_CTRLR_FUN, 0x20 ) & 0xFFFE
        sts = self._write_byte( smbus_io_base, target_address, offset, value )
        if logger().VERBOSE: logger().log( "[smbus] write to device %X off %X = %X" % (target_address, offset, value) )
        return sts

    def read_range( self, target_address, start_offset, size ):
        buffer = [chr(0xFF)]*size
        smbus_io_base = self.cs.pci.read_word( 0, Cfg.PCI_B0D31F3_SMBUS_CTRLR_DEV, Cfg.PCI_B0D31F3_SMBUS_CTRLR_FUN, 0x20 ) & 0xFFFE
        for i in range (size):
            buffer[i] = chr( self._read_byte( smbus_io_base, target_address, start_offset + i ) )
        if logger().VERBOSE:
            logger().log( "[smbus] read device %X from offset %X size %X:" % (target_address, start_offset, size) )
            print_buffer( buffer )
        return buffer

    def write_range( self, target_address, start_offset, buffer ):
        size = len(buffer)
        smbus_io_base = self.cs.pci.read_word( 0, Cfg.PCI_B0D31F3_SMBUS_CTRLR_DEV, Cfg.PCI_B0D31F3_SMBUS_CTRLR_FUN, 0x20 ) & 0xFFFE
        for i in range(size):
            self._write_byte( smbus_io_base, target_address, start_offset + i, ord(buffer[i]) )
        if logger().VERBOSE:
            logger().log( "[smbus] write device %X to offset %X size %X:" % (target_address, start_offset, size) )
            print_buffer( buffer )
        return True