hackedteam/vector-edk

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

Summary

Maintainability
F
1 wk
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/spi.py
# =========================
# Access to SPI Flash parts
# ~~~
# #usage:
#     read_spi( spi_fla, length )
#     write_spi( spi_fla, buf )
#     erase_spi_block( spi_fla )
# ~~~
#
__version__ = '1.0'

import struct
import sys
import time
from chipsec.cfg.common import *
from chipsec.logger import *
from chipsec.hal.mmio import *
from chipsec.file import *

#
# !! IMPORTANT:
# Size of the data chunk used in SPI read cycle (in bytes)
# default = maximum 64 bytes (remainder is read in 4 byte chunks)
#
# If you want to change logic to read SPI Flash in 4 byte chunks:
# SPI_READ_WRITE_MAX_DBC = 4
#
# SPI write cycles operate on 4 byte chunks (not optimized yet)
#
# Approximate performance (on 2 core HT Sandy Bridge CPU 2.6GHz):
#   SPI read:  ~25 sec per 1MB (DBC=64)
#   SPI write: ~140 sec per 1MB (DBC=4)
# 
SPI_READ_WRITE_MAX_DBC = 64
SPI_READ_WRITE_MIN_DBC = 4
SPI_READ_WRITE_DEF_DBC = 64

##############################################################################################################
# SPI Host Interface Registers
##############################################################################################################

PCH_RCBA_SPI_BFPR                  = 0x00  # BIOS Flash Primary Region Register (= FREG1)

PCH_RCBA_SPI_HSFSTS                = 0x04  # Hardware Sequencing Flash Status Register
PCH_RCBA_SPI_HSFSTS_FLOCKDN        = Cfg.BIT15                         # Flash Configuration Lock-Down
PCH_RCBA_SPI_HSFSTS_FDV            = Cfg.BIT14                         # Flash Descriptor Valid
PCH_RCBA_SPI_HSFSTS_FDOPSS         = Cfg.BIT13                         # Flash Descriptor Override Pin-Strap Status
PCH_RCBA_SPI_HSFSTS_SCIP           = Cfg.BIT5                          # SPI cycle in progress
PCH_RCBA_SPI_HSFSTS_BERASE_MASK    = (Cfg.BIT4 | Cfg.BIT3)                 # Block/Sector Erase Size
PCH_RCBA_SPI_HSFSTS_BERASE_256B    = 0x00                          # Block/Sector = 256 Bytes
PCH_RCBA_SPI_HSFSTS_BERASE_4K      = 0x01                          # Block/Sector = 4K Bytes
PCH_RCBA_SPI_HSFSTS_BERASE_8K      = 0x10                          # Block/Sector = 8K Bytes
PCH_RCBA_SPI_HSFSTS_BERASE_64K     = 0x11                          # Block/Sector = 64K Bytes
PCH_RCBA_SPI_HSFSTS_AEL            = Cfg.BIT2                          # Access Error Log
PCH_RCBA_SPI_HSFSTS_FCERR          = Cfg.BIT1                          # Flash Cycle Error
PCH_RCBA_SPI_HSFSTS_FDONE          = Cfg.BIT0                          # Flash Cycle Done

PCH_RCBA_SPI_HSFCTL                = 0x06  # Hardware Sequencing Flash Control Register
PCH_RCBA_SPI_HSFCTL_FSMIE          = Cfg.BIT15                         # Flash SPI SMI Enable
PCH_RCBA_SPI_HSFCTL_FDBC_MASK      = 0x3F00                        # Flash Data Byte Count, Count = FDBC + 1.
PCH_RCBA_SPI_HSFCTL_FCYCLE_MASK    = 0x0006                        # Flash Cycle
PCH_RCBA_SPI_HSFCTL_FCYCLE_READ    = 0                             # Flash Cycle Read
PCH_RCBA_SPI_HSFCTL_FCYCLE_WRITE   = 2                             # Flash Cycle Write
PCH_RCBA_SPI_HSFCTL_FCYCLE_ERASE   = 3                             # Flash Cycle Block Erase
PCH_RCBA_SPI_HSFCTL_FCYCLE_FGO     = Cfg.BIT0                          # Flash Cycle GO

PCH_RCBA_SPI_FADDR               = 0x08  # SPI Flash Address
PCH_RCBA_SPI_FADDR_MASK          = 0x07FFFFFF                      # SPI Flash Address Mask [0:26]

PCH_RCBA_SPI_FDATA00             = 0x10  # SPI Data 00 (32 bits)
PCH_RCBA_SPI_FDATA01             = 0x14  
PCH_RCBA_SPI_FDATA02             = 0x18  
PCH_RCBA_SPI_FDATA03             = 0x1C  
PCH_RCBA_SPI_FDATA04             = 0x20  
PCH_RCBA_SPI_FDATA05             = 0x24  
PCH_RCBA_SPI_FDATA06             = 0x28  
PCH_RCBA_SPI_FDATA07             = 0x2C  
PCH_RCBA_SPI_FDATA08             = 0x30  
PCH_RCBA_SPI_FDATA09             = 0x34  
PCH_RCBA_SPI_FDATA10             = 0x38  
PCH_RCBA_SPI_FDATA11             = 0x3C  
PCH_RCBA_SPI_FDATA12             = 0x40  
PCH_RCBA_SPI_FDATA13             = 0x44  
PCH_RCBA_SPI_FDATA14             = 0x48  
PCH_RCBA_SPI_FDATA15             = 0x4C  

# SPI Flash Regions Access Permisions Register
PCH_RCBA_SPI_FRAP                = 0x50
PCH_RCBA_SPI_FRAP_BMWAG_MASK     = 0xFF000000                    
PCH_RCBA_SPI_FRAP_BMWAG_GBE      = Cfg.BIT27                         
PCH_RCBA_SPI_FRAP_BMWAG_ME       = Cfg.BIT26                         
PCH_RCBA_SPI_FRAP_BMWAG_BIOS     = Cfg.BIT25                         
PCH_RCBA_SPI_FRAP_BMRAG_MASK     = 0x00FF0000                    
PCH_RCBA_SPI_FRAP_BMRAG_GBE      = Cfg.BIT19                         
PCH_RCBA_SPI_FRAP_BMRAG_ME       = Cfg.BIT18                         
PCH_RCBA_SPI_FRAP_BMRAG_BIOS     = Cfg.BIT17                         
PCH_RCBA_SPI_FRAP_BRWA_MASK      = 0x0000FF00                    
PCH_RCBA_SPI_FRAP_BRWA_SB        = Cfg.BIT14                         
PCH_RCBA_SPI_FRAP_BRWA_DE        = Cfg.BIT13                         
PCH_RCBA_SPI_FRAP_BRWA_PD        = Cfg.BIT12                         
PCH_RCBA_SPI_FRAP_BRWA_GBE       = Cfg.BIT11                         
PCH_RCBA_SPI_FRAP_BRWA_ME        = Cfg.BIT10                         
PCH_RCBA_SPI_FRAP_BRWA_BIOS      = Cfg.BIT9                          
PCH_RCBA_SPI_FRAP_BRWA_FLASHD    = Cfg.BIT8                          
PCH_RCBA_SPI_FRAP_BRRA_MASK      = 0x000000FF                    
PCH_RCBA_SPI_FRAP_BRRA_SB        = Cfg.BIT6                          
PCH_RCBA_SPI_FRAP_BRRA_DE        = Cfg.BIT5                          
PCH_RCBA_SPI_FRAP_BRRA_PD        = Cfg.BIT4                          
PCH_RCBA_SPI_FRAP_BRRA_GBE       = Cfg.BIT3                          
PCH_RCBA_SPI_FRAP_BRRA_ME        = Cfg.BIT2                          
PCH_RCBA_SPI_FRAP_BRRA_BIOS      = Cfg.BIT1                          
PCH_RCBA_SPI_FRAP_BRRA_FLASHD    = Cfg.BIT0                          

# Flash Region Registers
PCH_RCBA_SPI_FREG0_FLASHD           = 0x54  # Flash Region 0 (Flash Descriptor)
PCH_RCBA_SPI_FREG1_BIOS             = 0x58  # Flash Region 1 (BIOS)
PCH_RCBA_SPI_FREG2_ME               = 0x5C  # Flash Region 2 (ME)
PCH_RCBA_SPI_FREG3_GBE              = 0x60  # Flash Region 3 (GbE)
PCH_RCBA_SPI_FREG4_PLATFORM_DATA    = 0x64  # Flash Region 4 (Platform Data)
PCH_RCBA_SPI_FREG5_DEVICE_EXPANSION = 0x68  # Flash Region 5 (Device Expansion)
PCH_RCBA_SPI_FREG6_SECONDARY_BIOS   = 0x6C  # Flash Region 6 (Secondary BIOS)

PCH_RCBA_SPI_FREGx_LIMIT_MASK    = 0x7FFF0000                    # Size
PCH_RCBA_SPI_FREGx_BASE_MASK     = 0x00007FFF                    # Base

# Protected Range Registers
PCH_RCBA_SPI_PR0                 = 0x74  # Protected Region 0 Register
PCH_RCBA_SPI_PR0_WPE             = Cfg.BIT31                         # Write Protection Enable
PCH_RCBA_SPI_PR0_PRL_MASK        = 0x7FFF0000                    # Protected Range Limit Mask
PCH_RCBA_SPI_PR0_RPE             = Cfg.BIT15                         # Read Protection Enable
PCH_RCBA_SPI_PR0_PRB_MASK        = 0x00007FFF                    # Protected Range Base Mask
PCH_RCBA_SPI_PR1                 = 0x78
PCH_RCBA_SPI_PR1_WPE             = Cfg.BIT31
PCH_RCBA_SPI_PR1_PRL_MASK        = 0x7FFF0000
PCH_RCBA_SPI_PR1_RPE             = Cfg.BIT15
PCH_RCBA_SPI_PR1_PRB_MASK        = 0x00007FFF
PCH_RCBA_SPI_PR2                 = 0x7C
PCH_RCBA_SPI_PR2_WPE             = Cfg.BIT31
PCH_RCBA_SPI_PR2_PRL_MASK        = 0x7FFF0000
PCH_RCBA_SPI_PR2_RPE             = Cfg.BIT15 
PCH_RCBA_SPI_PR2_PRB_MASK        = 0x00007FFF
PCH_RCBA_SPI_PR3                 = 0x80
PCH_RCBA_SPI_PR3_WPE             = Cfg.BIT31
PCH_RCBA_SPI_PR3_PRL_MASK        = 0x7FFF0000
PCH_RCBA_SPI_PR3_RPE             = Cfg.BIT15                         
PCH_RCBA_SPI_PR3_PRB_MASK        = 0x00007FFF                    
PCH_RCBA_SPI_PR4                 = 0x84  
PCH_RCBA_SPI_PR4_WPE             = Cfg.BIT31 
PCH_RCBA_SPI_PR4_PRL_MASK        = 0x7FFF0000
PCH_RCBA_SPI_PR4_RPE             = Cfg.BIT15     
PCH_RCBA_SPI_PR4_PRB_MASK        = 0x00007FFF

PCH_RCBA_SPI_OPTYPE              = 0x96  # Opcode Type Configuration
PCH_RCBA_SPI_OPTYPE7_MASK        = (Cfg.BIT15 | Cfg.BIT14)
PCH_RCBA_SPI_OPTYPE6_MASK        = (Cfg.BIT13 | Cfg.BIT12)
PCH_RCBA_SPI_OPTYPE5_MASK        = (Cfg.BIT11 | Cfg.BIT10)
PCH_RCBA_SPI_OPTYPE4_MASK        = (Cfg.BIT9 | Cfg.BIT8)  
PCH_RCBA_SPI_OPTYPE3_MASK        = (Cfg.BIT7 | Cfg.BIT6)  
PCH_RCBA_SPI_OPTYPE2_MASK        = (Cfg.BIT5 | Cfg.BIT4)  
PCH_RCBA_SPI_OPTYPE1_MASK        = (Cfg.BIT3 | Cfg.BIT2)  
PCH_RCBA_SPI_OPTYPE0_MASK        = (Cfg.BIT1 | Cfg.BIT0)  
PCH_RCBA_SPI_OPTYPE_RDNOADDR     = 0x00
PCH_RCBA_SPI_OPTYPE_WRNOADDR     = 0x01
PCH_RCBA_SPI_OPTYPE_RDADDR       = 0x02
PCH_RCBA_SPI_OPTYPE_WRADDR       = 0x03

PCH_RCBA_SPI_OPMENU              = 0x98  # Opcode Menu Configuration

PCH_RCBA_SPI_FDOC                = 0xB0  # Flash Descriptor Observability Control Register
PCH_RCBA_SPI_FDOC_FDSS_MASK      = (Cfg.BIT14 | Cfg.BIT13 | Cfg.BIT12)       # Flash Descritor Section Select
PCH_RCBA_SPI_FDOC_FDSS_FSDM      = 0x0000                        # Flash Signature and Descriptor Map
PCH_RCBA_SPI_FDOC_FDSS_COMP      = 0x1000                        # Component
PCH_RCBA_SPI_FDOC_FDSS_REGN      = 0x2000                        # Region
PCH_RCBA_SPI_FDOC_FDSS_MSTR      = 0x3000                        # Master
PCH_RCBA_SPI_FDOC_FDSI_MASK      = 0x0FFC                        # Flash Descriptor Section Index

PCH_RCBA_SPI_FDOD                = 0xB4  # Flash Descriptor Observability Data Register

# agregated SPI Flash commands
HSFCTL_READ_CYCLE = ( (PCH_RCBA_SPI_HSFCTL_FCYCLE_READ<<1) | PCH_RCBA_SPI_HSFCTL_FCYCLE_FGO)
HSFCTL_WRITE_CYCLE = ( (PCH_RCBA_SPI_HSFCTL_FCYCLE_WRITE<<1) | PCH_RCBA_SPI_HSFCTL_FCYCLE_FGO)
HSFCTL_ERASE_CYCLE = ( (PCH_RCBA_SPI_HSFCTL_FCYCLE_ERASE<<1) | PCH_RCBA_SPI_HSFCTL_FCYCLE_FGO)

# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# FGO bit cleared (for safety ;)
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#HSFCTL_WRITE_CYCLE = ( (PCH_RCBA_SPI_HSFCTL_FCYCLE_WRITE<<1) )
#HSFCTL_ERASE_CYCLE = ( (PCH_RCBA_SPI_HSFCTL_FCYCLE_ERASE<<1) )

HSFSTS_CLEAR = (PCH_RCBA_SPI_HSFSTS_AEL | PCH_RCBA_SPI_HSFSTS_FCERR | PCH_RCBA_SPI_HSFSTS_FDONE)

#
# Hardware Sequencing Flash Status (HSFSTS)
#
SPI_HSFSTS_OFFSET = 0x04
# HSFSTS bit masks
SPI_HSFSTS_FLOCKDN_MASK = (1 << 15)
SPI_HSFSTS_FDOPSS_MASK  = (1 << 13)

SPI_REGION_NUMBER       = 7
SPI_REGION_NUMBER_IN_FD = 5

FLASH_DESCRIPTOR  = 0
BIOS              = 1
ME                = 2
GBE               = 3
PLATFORM_DATA     = 4
DEVICE_EXPANSION  = 5
SECONDARY_BIOS    = 6

SPI_REGION = {
 FLASH_DESCRIPTOR  : PCH_RCBA_SPI_FREG0_FLASHD,
 BIOS              : PCH_RCBA_SPI_FREG1_BIOS,
 ME                : PCH_RCBA_SPI_FREG2_ME,
 GBE               : PCH_RCBA_SPI_FREG3_GBE,
 PLATFORM_DATA     : PCH_RCBA_SPI_FREG4_PLATFORM_DATA,
 DEVICE_EXPANSION  : PCH_RCBA_SPI_FREG5_DEVICE_EXPANSION,
 SECONDARY_BIOS    : PCH_RCBA_SPI_FREG6_SECONDARY_BIOS
}

SPI_REGION_NAMES = {
 FLASH_DESCRIPTOR  : 'Flash Descriptor',
 BIOS              : 'BIOS',
 ME                : 'Intel ME',
 GBE               : 'GBe',
 PLATFORM_DATA     : 'Platform Data',
 DEVICE_EXPANSION  : 'Device Expansion',
 SECONDARY_BIOS    : 'Secondary BIOS'
}

#
# Flash Descriptor Master Defines
#
SPI_MASTER_NUMBER_IN_FD = 3

MASTER_HOST_CPU_BIOS    = 0
MASTER_ME               = 1
MASTER_GBE              = 2

SPI_MASTER_NAMES = {
 MASTER_HOST_CPU_BIOS : 'CPU/BIOS',
 MASTER_ME            : 'ME',
 MASTER_GBE           : 'GBe'
}


class SpiRuntimeError (RuntimeError):
    pass
class SpiAccessError (RuntimeError):
    pass


def get_SPI_region( flreg ):
    range_base  = (flreg & PCH_RCBA_SPI_FREGx_BASE_MASK) << 12
    range_limit = ((flreg & PCH_RCBA_SPI_FREGx_LIMIT_MASK) >> 4)
    range_limit = range_limit + 0xFFF # + 4kB
    return (range_base, range_limit)

def get_SPI_MMIO_base( cs ):
    reg_value = cs.pci.read_dword( Cfg.SPI_MMIO_BUS, Cfg.SPI_MMIO_DEV, Cfg.SPI_MMIO_FUN, Cfg.SPI_MMIO_REG_OFFSET )
    spi_base = ((reg_value >> Cfg.SPI_BASE_ADDR_SHIFT) << Cfg.SPI_BASE_ADDR_SHIFT) + Cfg.SPI_MMIO_BASE_OFFSET
    if logger().VERBOSE: logger().log( "[spi] SPI MMIO base: 0x%016X (assuming below 4GB)" % spi_base )
    return spi_base


class SPI:
    def __init__( self, cs ):
        self.cs = cs
        #self.rcba_spi_base = get_MMIO_base_address( self.cs, MMIO_BAR_LPCRCBA_SPI )
        self.rcba_spi_base = get_SPI_MMIO_base( self.cs )

    def spi_reg_read( self, reg ):
        return read_MMIO_reg( self.cs, self.rcba_spi_base, reg )

    def spi_reg_write( self, reg, value ):
        return write_MMIO_reg( self.cs, self.rcba_spi_base, reg, value )


    def get_SPI_region( self, spi_region_id ):
        freg = self.spi_reg_read( SPI_REGION[ spi_region_id ] )
        #range_base  = (freg & PCH_RCBA_SPI_FREGx_BASE_MASK) << 12
        #range_limit = ((freg & PCH_RCBA_SPI_FREGx_LIMIT_MASK) >> 4)
        #range_limit = range_limit + 0xFFF # + 4kB
        ##if range_limit >= range_base:
        ##   range_limit = range_limit + 0xFFF # + 4kB
        (range_base, range_limit) = get_SPI_region( freg )
        return (range_base, range_limit, freg)

    # all_regions = True : return all SPI regions
    # all_regions = False: return only available SPI regions (limit >= base)
    def get_SPI_regions( self, all_regions ):
        spi_regions = {}
        for r in SPI_REGION:
            (range_base, range_limit, freg) = self.get_SPI_region( r )
            if all_regions or (range_limit >= range_base):
                range_size = range_limit - range_base + 1
                spi_regions[r] = (range_base, range_limit, range_size, SPI_REGION_NAMES[r])
        return spi_regions

    def get_SPI_Protected_Range( self, pr_num ):
        if ( pr_num > 5 ):
            return None

        pr_j_reg = PCH_RCBA_SPI_PR0 + pr_num*4
        pr_j  = self.spi_reg_read( pr_j_reg )
        base = (pr_j & PCH_RCBA_SPI_PR0_PRB_MASK) << 12
        limit = (pr_j & PCH_RCBA_SPI_PR0_PRL_MASK) >> 4
        wpe = ((pr_j & PCH_RCBA_SPI_PR0_WPE) != 0)
        rpe = ((pr_j & PCH_RCBA_SPI_PR0_RPE) != 0)
        return (base,limit,wpe,rpe,pr_j_reg,pr_j)

    ##############################################################################################################
    # SPI configuration
    ##############################################################################################################

    def display_SPI_Flash_Descriptor( self ):
        logger().log( "============================================================" )
        logger().log( "SPI Flash Descriptor" )
        logger().log( "------------------------------------------------------------" )
        logger().log( "\nFlash Signature and Descriptor Map:" )
        for j in range(5):
            self.spi_reg_write( PCH_RCBA_SPI_FDOC, (PCH_RCBA_SPI_FDOC_FDSS_FSDM|(j<<2)) )
            fdod = self.spi_reg_read( PCH_RCBA_SPI_FDOD )
            logger().log( "%08X" % fdod )

        logger().log( "\nComponents:" )
        for j in range(3):
            self.spi_reg_write( PCH_RCBA_SPI_FDOC, (PCH_RCBA_SPI_FDOC_FDSS_COMP|(j<<2)) )
            fdod = self.spi_reg_read( PCH_RCBA_SPI_FDOD )
            logger().log( "%08X" % fdod )

        logger().log( "\nRegions:" )
        for j in range(5):
            self.spi_reg_write( PCH_RCBA_SPI_FDOC, (PCH_RCBA_SPI_FDOC_FDSS_REGN|(j<<2)) )
            fdod = self.spi_reg_read( PCH_RCBA_SPI_FDOD )
            logger().log( "%08X" % fdod )

        logger().log( "\nMasters:" )
        for j in range(3):
            self.spi_reg_write( PCH_RCBA_SPI_FDOC, (PCH_RCBA_SPI_FDOC_FDSS_MSTR|(j<<2)) )
            fdod = self.spi_reg_read( PCH_RCBA_SPI_FDOD )
            logger().log( "%08X" % fdod )


    def display_SPI_opcode_info( self ):
        logger().log( "============================================================" )
        logger().log( "SPI Opcode Info" )
        logger().log( "------------------------------------------------------------" )
        optype = (self.spi_reg_read( PCH_RCBA_SPI_OPTYPE ) & 0xFFFF)
        logger().log( "OPTYPE = 0x%04X" % optype )
        opmenu_lo = self.spi_reg_read( PCH_RCBA_SPI_OPMENU )
        opmenu_hi = self.spi_reg_read( PCH_RCBA_SPI_OPMENU + 0x4 )
        opmenu = ((opmenu_hi << 32)|opmenu_lo)
        logger().log( "OPMENU = 0x%016X" % opmenu )

        logger().log( "------------------------------------------------------------" )
        logger().log( "Opcode # | Opcode | Optype | Description" )
        logger().log( "------------------------------------------------------------" )
        
        for j in range(8):
           optype_j = ((optype >> j*2) & 0x3)
           if (PCH_RCBA_SPI_OPTYPE_RDNOADDR == optype_j):
             desc = 'SPI read cycle without address'
           elif (PCH_RCBA_SPI_OPTYPE_WRNOADDR == optype_j):
             desc = 'SPI write cycle without address'
           elif (PCH_RCBA_SPI_OPTYPE_RDADDR == optype_j):
             desc = 'SPI read cycle with address'
           elif (PCH_RCBA_SPI_OPTYPE_WRADDR == optype_j):
             desc = 'SPI write cycle with address'
           logger().log( "Opcode%d  | 0x%02X   | %X      | %s " % (j,((opmenu >> j*8) & 0xFF),optype_j,desc) )

    def display_SPI_Flash_Regions( self ):
        logger().log( "------------------------------------------------------------" )
        logger().log( "Flash Region             | FREGx Reg | Base     | Limit     " )
        logger().log( "------------------------------------------------------------" )
        (base,limit,freg) = self.get_SPI_region( FLASH_DESCRIPTOR )
        logger().log( "0 Flash Descriptor (FD)  | %08X  | %08X | %08X " % (freg,base,limit) )
        (base,limit,freg) = self.get_SPI_region( BIOS )
        logger().log( "1 BIOS                   | %08X  | %08X | %08X " % (freg,base,limit) )
        (base,limit,freg) = self.get_SPI_region( ME )
        logger().log( "2 Management Engine (ME) | %08X  | %08X | %08X " % (freg,base,limit) )
        (base,limit,freg) = self.get_SPI_region( GBE )
        logger().log( "3 GBe                    | %08X  | %08X | %08X " % (freg,base,limit) )
        (base,limit,freg) = self.get_SPI_region( PLATFORM_DATA )
        logger().log( "4 Platform Data (PD)     | %08X  | %08X | %08X " % (freg,base,limit) )
        (base,limit,freg) = self.get_SPI_region( DEVICE_EXPANSION )
        logger().log( "5 Device Expansion (DE)  | %08X  | %08X | %08X " % (freg,base,limit) )
        (base,limit,freg) = self.get_SPI_region( SECONDARY_BIOS )
        logger().log( "6 Secondary BIOS (SB)    | %08X  | %08X | %08X " % (freg,base,limit) )

    def display_BIOS_region( self ):
        bfpreg = self.spi_reg_read( PCH_RCBA_SPI_BFPR )
        logger().log( "BIOS Flash Primary Region" )
        logger().log( "------------------------------------------------------------" )
        logger().log( "BFPREG = %08X:" % bfpreg )
        logger().log( "  Base  : %08X" % ((bfpreg & PCH_RCBA_SPI_FREGx_BASE_MASK) << 12) )
        logger().log( "  Limit : %08X" % ((bfpreg & PCH_RCBA_SPI_FREGx_LIMIT_MASK) >> 4) )
        logger().log( "  Shadowed BIOS Select: %d" % ((bfpreg & Cfg.BIT31)>>31) )


    def display_SPI_Ranges_Access_Permissions( self ):
        logger().log( "SPI Flash Region Access Permissions" )
        logger().log( "------------------------------------------------------------" )
        fracc  = self.spi_reg_read( PCH_RCBA_SPI_FRAP )
        logger().log( "FRAP = %08X" % fracc )
        logger().log( "BIOS Region Write Access Grant (%02X):" % ((fracc & PCH_RCBA_SPI_FRAP_BMWAG_MASK)>>16) )
        logger().log( "  BIOS: %1d" % (fracc&PCH_RCBA_SPI_FRAP_BMWAG_BIOS   != 0) )
        logger().log( "  ME  : %1d" % (fracc&PCH_RCBA_SPI_FRAP_BMWAG_ME     != 0) )
        logger().log( "  GBe : %1d" % (fracc&PCH_RCBA_SPI_FRAP_BMWAG_GBE    != 0) )
        logger().log( "BIOS Region Read Access Grant (%02X):" % ((fracc & PCH_RCBA_SPI_FRAP_BMRAG_MASK)>>16) )
        logger().log( "  BIOS: %1d" % (fracc&PCH_RCBA_SPI_FRAP_BMRAG_BIOS   != 0) )
        logger().log( "  ME  : %1d" % (fracc&PCH_RCBA_SPI_FRAP_BMRAG_ME     != 0) )
        logger().log( "  GBe : %1d" % (fracc&PCH_RCBA_SPI_FRAP_BMRAG_GBE    != 0) )
        logger().log( "BIOS Write Access (%02X):" % ((fracc & PCH_RCBA_SPI_FRAP_BRWA_MASK)>>8) )
        logger().log( "  FD  : %1d" % (fracc&PCH_RCBA_SPI_FRAP_BRWA_FLASHD != 0) )
        logger().log( "  BIOS: %1d" % (fracc&PCH_RCBA_SPI_FRAP_BRWA_BIOS   != 0) )
        logger().log( "  ME  : %1d" % (fracc&PCH_RCBA_SPI_FRAP_BRWA_ME     != 0) )
        logger().log( "  GBe : %1d" % (fracc&PCH_RCBA_SPI_FRAP_BRWA_GBE    != 0) )
        logger().log( "  PD  : %1d" % (fracc&PCH_RCBA_SPI_FRAP_BRWA_PD     != 0) )
        logger().log( "  DE  : %1d" % (fracc&PCH_RCBA_SPI_FRAP_BRWA_DE     != 0) )
        logger().log( "  SB  : %1d" % (fracc&PCH_RCBA_SPI_FRAP_BRWA_SB     != 0) )
        logger().log( "BIOS Read Access (%02X):" % (fracc & PCH_RCBA_SPI_FRAP_BRRA_MASK) )
        logger().log( "  FD  : %1d" % (fracc&PCH_RCBA_SPI_FRAP_BRRA_FLASHD != 0) )
        logger().log( "  BIOS: %1d" % (fracc&PCH_RCBA_SPI_FRAP_BRRA_BIOS   != 0) )
        logger().log( "  ME  : %1d" % (fracc&PCH_RCBA_SPI_FRAP_BRRA_ME     != 0) )
        logger().log( "  GBe : %1d" % (fracc&PCH_RCBA_SPI_FRAP_BRRA_GBE    != 0) )
        logger().log( "  PD  : %1d" % (fracc&PCH_RCBA_SPI_FRAP_BRRA_PD     != 0) )
        logger().log( "  DE  : %1d" % (fracc&PCH_RCBA_SPI_FRAP_BRRA_DE     != 0) )
        logger().log( "  SB  : %1d" % (fracc&PCH_RCBA_SPI_FRAP_BRRA_SB     != 0) )


    def display_SPI_Protected_Ranges( self ):
        logger().log( "SPI Protected Ranges" )
        logger().log( "------------------------------------------------------------" )
        logger().log( "PRx (offset) | Value    | Base     | Limit    | WP? | RP?" )
        logger().log( "------------------------------------------------------------" )
        for j in range(5):
           (base,limit,wpe,rpe,pr_reg_off,pr_reg_value) = self.get_SPI_Protected_Range( j )
           logger().log( "PR%d (%02X)     | %08X | %08X | %08X | %d   | %d " % (j,pr_reg_off,pr_reg_value,base,limit,wpe,rpe) )

    def display_SPI_map( self ):
        logger().log( "============================================================" )
        logger().log( "SPI Flash Map" )
        logger().log( "------------------------------------------------------------" )
        logger().log('')
        self.display_BIOS_region()
        logger().log('')
        self.display_SPI_Flash_Regions()
        logger().log('')
        self.display_SPI_Flash_Descriptor()
        logger().log('')
        self.display_SPI_opcode_info()
        logger().log('')
        logger().log( "============================================================" )
        logger().log( "SPI Flash Protection" )
        logger().log( "------------------------------------------------------------" )
        logger().log('')
        self.display_SPI_Ranges_Access_Permissions()
        logger().log('')
        logger().log( "BIOS Region Write Protection" )
        logger().log( "------------------------------------------------------------" )
        (BC, val) = self.get_BIOS_Control()
        logger().log( BC )
        self.display_SPI_Protected_Ranges()
        logger().log('')


    ##############################################################################################################
    # BIOS Write Protection
    ##############################################################################################################

    def get_BIOS_Control( self ):
        #
        # BIOS Control (BC) 0:31:0 PCIe CFG register
        #
        reg_value = self.cs.pci.read_byte( 0, 31, 0, Cfg.LPC_BC_REG_OFF )
        BcRegister = Cfg.LPC_BC_REG( reg_value, (reg_value>>5)&0x1, (reg_value>>4)&0x1, (reg_value>>2)&0x3, (reg_value>>1)&0x1, reg_value&0x1 )
        return (BcRegister, reg_value)

    def disable_BIOS_write_protection( self ):
        (BcRegister, reg_value) = self.get_BIOS_Control()
        if logger().VERBOSE:
           logger().log( BcRegister )

        if BcRegister.BLE and (not BcRegister.BIOSWE):
           logger().log( "[spi] BIOS write protection enabled" )
           return False
        elif BcRegister.BIOSWE:
           logger().log( "[spi] BIOS write protection not enabled. What a surprise" )
           return True
        else:
           logger().log( "[spi] BIOS write protection enabled but not locked. Disabling.." )

        reg_value |= 0x1
        self.cs.pci.write_byte( 0, 31, 0, Cfg.LPC_BC_REG_OFF, reg_value )
        (BcRegister, reg_value) = self.get_BIOS_Control()
        if logger().VERBOSE: logger().log( BcRegister )
        if BcRegister.BIOSWE:
           logger().log_important( "BIOS write protection is disabled" )
           return True
        else:
           return False

    ##############################################################################################################
    # SPI Controller access functions
    ##############################################################################################################

    def _wait_SPI_flash_cycle_done(self):
        if logger().VERBOSE:
           logger().log( "[spi] wait for SPI cycle ready/done.." )

        spi_base = self.rcba_spi_base

        for i in range(1000):
            #time.sleep(0.001)
            hsfsts = self.cs.mem.read_physical_mem_byte( spi_base + PCH_RCBA_SPI_HSFSTS )
            #hsfsts = self.spi_reg_read( PCH_RCBA_SPI_HSFSTS ) 
            #cycle_done = (hsfsts & PCH_RCBA_SPI_HSFSTS_FDONE) and (0 == (hsfsts & PCH_RCBA_SPI_HSFSTS_SCIP)) 
            cycle_done = not (hsfsts & PCH_RCBA_SPI_HSFSTS_SCIP)
            if cycle_done:
               break

        if not cycle_done:
           if logger().VERBOSE:
              logger().log( "[spi] SPI cycle still in progress. Waiting 0.1 sec.." )
           time.sleep(0.1)
           hsfsts = self.cs.mem.read_physical_mem_byte( spi_base + PCH_RCBA_SPI_HSFSTS )
           cycle_done = not (hsfsts & PCH_RCBA_SPI_HSFSTS_SCIP)

        if cycle_done:
           if logger().VERBOSE:
              logger().log( "[spi] clear FDONE/FCERR/AEL bits.." )
           self.cs.mem.write_physical_mem_byte( spi_base + PCH_RCBA_SPI_HSFSTS, HSFSTS_CLEAR )
           hsfsts = self.cs.mem.read_physical_mem_byte( spi_base + PCH_RCBA_SPI_HSFSTS )
           cycle_done = not ((hsfsts & PCH_RCBA_SPI_HSFSTS_AEL) or (hsfsts & PCH_RCBA_SPI_HSFSTS_FCERR))

        if logger().VERBOSE:
           logger().log( "[spi] HSFSTS: 0x%02X" % hsfsts )
              
        return cycle_done

    def _send_spi_cycle(self, hsfctl_spi_cycle_cmd, dbc, spi_fla ):
        if logger().VERBOSE:
           logger().log( "[spi] > send SPI cycle 0x%X to address 0x%08X.." % (hsfctl_spi_cycle_cmd, spi_fla) )

        spi_base = self.rcba_spi_base  

        # No need to check for SPI cycle DONE status before each cycle
        # DONE status is checked once before entire SPI operation
    
        self.cs.mem.write_physical_mem_dword( spi_base + PCH_RCBA_SPI_FADDR, (spi_fla & PCH_RCBA_SPI_FADDR_MASK) )
        _faddr = self.spi_reg_read( PCH_RCBA_SPI_FADDR ) 
        if logger().VERBOSE:
           logger().log( "[spi] FADDR: 0x%08X" % _faddr )
    
        if logger().VERBOSE:
           logger().log( "[spi] SPI cycle GO (DBC <- 0x%02X, HSFCTL <- 0x%X)" % (dbc, hsfctl_spi_cycle_cmd) )
        if ( HSFCTL_ERASE_CYCLE != hsfctl_spi_cycle_cmd ):
           self.cs.mem.write_physical_mem_byte( spi_base + PCH_RCBA_SPI_HSFCTL + 0x1, dbc ) 
        self.cs.mem.write_physical_mem_byte( spi_base + PCH_RCBA_SPI_HSFCTL, hsfctl_spi_cycle_cmd ) 
        # Read HSFCTL back
        hsfctl = self.cs.mem.read_physical_mem_word( spi_base + PCH_RCBA_SPI_HSFCTL )
        if logger().VERBOSE:
           logger().log( "[spi] HSFCTL: 0x%04X" % hsfctl )
    
        cycle_done = self._wait_SPI_flash_cycle_done()
        if not cycle_done:
           logger().warn( "SPI cycle not done" )
        else:
           if logger().VERBOSE:
              logger().log( "[spi] < SPI cycle done" )

        return cycle_done

    #
    # SPI Flash operations
    #

    def read_spi_to_file(self, spi_fla, data_byte_count, filename ):
        buf = self.read_spi( spi_fla, data_byte_count )
        if filename is not None:
           write_file( filename, struct.pack('c'*len(buf), *buf) )
        else:
           print_buffer( buf, 16 )
        return buf

    def write_spi_from_file(self, spi_fla, filename ):
        buf = read_file( filename )
        return self.write_spi( spi_fla, struct.unpack('c'*len(buf), buf) )
        #return self.write_spi( spi_fla, struct.unpack('B'*len(buf), buf) )

    def simulate_write_spi_from_file(self, spi_fla, filename ):
        buf = read_file( filename )
        return self.simulate_write_spi( spi_fla, struct.unpack('c'*len(buf), buf) )


    def read_spi(self, spi_fla, data_byte_count ):
        spi_base = self.rcba_spi_base  
        buf = []      

        dbc = SPI_READ_WRITE_DEF_DBC
        if (data_byte_count >= SPI_READ_WRITE_MAX_DBC):
           dbc = SPI_READ_WRITE_MAX_DBC

        n = data_byte_count / dbc
        r = data_byte_count % dbc
        if logger().UTIL_TRACE or logger().VERBOSE:
           logger().log( "[spi] reading 0x%x bytes from SPI at FLA = 0x%X (in %d 0x%x-byte chunks + 0x%x-byte remainder)" % (data_byte_count, spi_fla, n, dbc, r) )

        cycle_done = self._wait_SPI_flash_cycle_done()
        if not cycle_done:
           logger().error( "SPI cycle not ready" )
           return None

        for i in range(n):
           spi_fla_addr = spi_fla + i*dbc
           if (spi_fla_addr % 65536) == 0:
             if logger().UTIL_TRACE or logger().VERBOSE:
                logger().log( "[spi] reading @ 0x%x - 0x%x-byte remainder" % (spi_fla_addr, data_byte_count - (i*dbc) ))
                #self.erase_spi_block(spi_fla + i * dbc)

           if not self._send_spi_cycle( HSFCTL_READ_CYCLE, dbc-1, spi_fla + i*dbc ):
              logger().error( "SPI flash read failed" )
           else:
              #buf += self.cs.mem.read_physical_mem( spi_base + PCH_RCBA_SPI_FDATA00, dbc )
              for fdata_idx in range(0,dbc/4):
                  dword_value = self.spi_reg_read( PCH_RCBA_SPI_FDATA00 + fdata_idx*4 ) 
                  if logger().VERBOSE:
                     logger().log( "[spi] FDATA00 + 0x%x: 0x%X" % (fdata_idx*4, dword_value) )
                  buf += [ chr((dword_value>>(8*j))&0xff) for j in range(4) ]
                  #buf += tuple( struct.pack("I", dword_value) )
        if (0 != r):
           if logger().UTIL_TRACE or logger().VERBOSE:
              logger().log( "[spi] reading remaining 0x%x bytes from 0x%X" % (r, spi_fla + n*dbc) )
           if not self._send_spi_cycle( HSFCTL_READ_CYCLE, r-1, spi_fla + n*dbc ):
              logger().error( "SPI flash read failed" )
           else:
              t = 4
              n_dwords = (r+3)/4
              for fdata_idx in range(0, n_dwords):
                  dword_value = self.spi_reg_read( PCH_RCBA_SPI_FDATA00 + fdata_idx*4 ) 
                  if logger().VERBOSE:
                     logger().log( "[spi] FDATA00 + 0x%x: 0x%08X" % (fdata_idx*4, dword_value) )
                  if (fdata_idx == (n_dwords-1)) and (0 != r%4):
                     t = r%4  
                  buf += [ chr((dword_value >> (8*j)) & 0xff) for j in range(t) ]
           
        if logger().VERBOSE:
           logger().log( "[spi] buffer read from SPI:" )
           print_buffer( buf )

        return buf

    def write_spi(self, spi_fla, buf ):
        write_ok = True
        spi_base = self.rcba_spi_base  
        data_byte_count = len(buf)
        #modificata da 4 a 64 ByGio     
        #dbc = 64       
        dbc = SPI_READ_WRITE_MIN_DBC
        n = data_byte_count / dbc
        r = data_byte_count % dbc
        logprogress = data_byte_count / 4096

        if logger().UTIL_TRACE or logger().VERBOSE:
           logger().log( "[spi] writing 0x%x bytes to SPI at FLA = 0x%X (in %d 0x%x-byte chunks + 0x%x-byte remainder)" % (data_byte_count, spi_fla, n, dbc, r) )

        cycle_done = self._wait_SPI_flash_cycle_done()
        if not cycle_done:
           logger().error( "SPI cycle not ready" )
           return None

        for i in range(n):
           spi_fla_addr = spi_fla + i*dbc
           if (spi_fla_addr % 65536) == 0:
             if logger().UTIL_TRACE or logger().VERBOSE:
                logger().log( "[spi] writing @ 0x%x - 0x%x-byte remainder" % (spi_fla_addr, data_byte_count - (i*dbc) ))
                #self.erase_spi_block(spi_fla + i * dbc)

           dword_value = (ord(buf[i*dbc + 3]) << 24) | (ord(buf[i*dbc + 2]) << 16) | (ord(buf[i*dbc + 1]) << 8) | ord(buf[i*dbc])
           if logger().VERBOSE:
              logger().log( "[spi] in FDATA00 = 0x%08x" % dword_value )
           self.cs.mem.write_physical_mem_dword( spi_base + PCH_RCBA_SPI_FDATA00, dword_value )
           if not self._send_spi_cycle( HSFCTL_WRITE_CYCLE, dbc-1, spi_fla + i*dbc ):
              write_ok = False
              logger().error( "SPI flash write cycle failed" )

        if (0 != r):
           if logger().UTIL_TRACE or logger().VERBOSE:
              logger().log( "[spi] writing remaining 0x%x bytes to FLA = 0x%X" % (r, spi_fla + n*dbc) )
           dword_value = 0
           for j in range(r):
              dword_value |= (ord(buf[n*dbc + j]) << 8*j)
           if logger().VERBOSE:
              logger().log( "[spi] in FDATA00 = 0x%08x" % dword_value )
           self.cs.mem.write_physical_mem_dword( spi_base + PCH_RCBA_SPI_FDATA00, dword_value )
           if not self._send_spi_cycle( HSFCTL_WRITE_CYCLE, r-1, spi_fla + n*dbc ):
              write_ok = False
              logger().error( "SPI flash write cycle failed" )
           
        return write_ok

    def simulate_write_spi(self, spi_fla, buf ):
        write_ok = True
        spi_base = self.rcba_spi_base  
        data_byte_count = len(buf)
        
        dbc = 4       
        n = data_byte_count / dbc
        r = data_byte_count % dbc
        logprogress = data_byte_count / 4096

        if logger().UTIL_TRACE or logger().VERBOSE:
           logger().log( "[spi] writing 0x%x bytes to SPI at FLA = 0x%X (in %d 0x%x-byte chunks + 0x%x-byte remainder)" % (data_byte_count, spi_fla, n, dbc, r) )

        cycle_done = self._wait_SPI_flash_cycle_done()
        if not cycle_done:
           logger().error( "SPI cycle not ready" )
           return None

        for i in range(n):
           if i == 0 or ((i % logprogress) == 0):
             if logger().UTIL_TRACE or logger().VERBOSE:
                logger().log( "[spi] writing chunk %d of 0x%x bytes to 0x%X" % (i, dbc, spi_fla + i*dbc) )
                #self.erase_spi_block(spi_fla + i * dbc)

           dword_value = (ord(buf[i*dbc + 3]) << 24) | (ord(buf[i*dbc + 2]) << 16) | (ord(buf[i*dbc + 1]) << 8) | ord(buf[i*dbc])
           if logger().VERBOSE:
              logger().log( "[spi] in FDATA00 = 0x%08x" % dword_value )
           #self.cs.mem.write_physical_mem_dword( spi_base + PCH_RCBA_SPI_FDATA00, dword_value )
           #if not self._send_spi_cycle( HSFCTL_WRITE_CYCLE, dbc-1, spi_fla + i*dbc ):
           #   write_ok = False
           #   logger().error( "SPI flash write cycle failed" )

        if (0 != r):
           if logger().UTIL_TRACE or logger().VERBOSE:
              logger().log( "[spi] writing remaining 0x%x bytes to FLA = 0x%X" % (r, spi_fla + n*dbc) )
           dword_value = 0
           for j in range(r):
              dword_value |= (ord(buf[n*dbc + j]) << 8*j)
           if logger().VERBOSE:
              logger().log( "[spi] in FDATA00 = 0x%08x" % dword_value )
           #self.cs.mem.write_physical_mem_dword( spi_base + PCH_RCBA_SPI_FDATA00, dword_value )
           #if not self._send_spi_cycle( HSFCTL_WRITE_CYCLE, r-1, spi_fla + n*dbc ):
           #   write_ok = False
           #   logger().error( "SPI flash write cycle failed" )
           
        return write_ok

    def erase_spi_block(self, spi_fla ):
        if logger().UTIL_TRACE or logger().VERBOSE:
           logger().log( "[spi] Erasing SPI Flash block @ 0x%X" % spi_fla )

        cycle_done = self._wait_SPI_flash_cycle_done()
        if not cycle_done:
           logger().error( "SPI cycle not ready" )
           return None

        erase_ok = self._send_spi_cycle( HSFCTL_ERASE_CYCLE, 0, spi_fla )
        if not erase_ok:
           logger().error( "SPI Flash erase cycle failed" )

        return erase_ok

    def simulate_erase_spi_block(self, spi_fla ):
        if logger().UTIL_TRACE or logger().VERBOSE:
           logger().log( "[spi] Erasing SPI Flash block @ 0x%X" % spi_fla )

        cycle_done = self._wait_SPI_flash_cycle_done()
        if not cycle_done:
           logger().error( "SPI cycle not ready" )
           return None

        #erase_ok = self._send_spi_cycle( HSFCTL_ERASE_CYCLE, 0, spi_fla )
        #if not erase_ok:
        #   logger().error( "SPI Flash erase cycle failed" )
        erase_ok = 1
        return erase_ok