#!/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 .