vector-uefi/fd/tool/chipsec/hal/pci.py
#!/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/pci.py
# ===============================================
# Access to PCIe configuration spaces of I/O devices
# usage:
# read_pci_dword( 0, 0, 0, 0x88 )
# write_pci_dword( 0, 0, 0, 0x88, 0x1A )
#
#
__version__ = '1.0'
import struct
import sys
import os.path
from chipsec.logger import logger
from chipsec.cfg.common import *
from chipsec.hal.pcidb import *
#class PCI_BDF(Structure):
# _fields_ = [("BUS", c_ushort, 16), # Bus
# ("DEV", c_ushort, 16), # Device
# ("FUNC", c_ushort, 16), # Function
# ("OFF", c_ushort, 16)] # Offset
class PciRuntimeError (RuntimeError):
pass
def get_vendor_name_by_vid( vid ):
if vid in VENDORS:
return VENDORS[vid]
return ''
def get_device_name_by_didvid( vid, did ):
if vid in VENDORS:
if did in DEVICES[vid]:
return DEVICES[vid][did]
return ''
def print_pci_devices( _devices ):
logger().log( "BDF | VID:DID | Vendor | Device" )
logger().log( "-------------------------------------------------------------------------------------" )
for (b, d, f, vid, did) in _devices:
vendor_name = get_vendor_name_by_vid( vid )
device_name = get_device_name_by_didvid( vid, did )
logger().log( "%02X:%02X.%X | %04X:%04X | %-40s | %s" % (b, d, f, vid, did, vendor_name, device_name) )
class Pci:
def __init__( self, helper ):
self.helper = helper
#self.devices = []
def read_dword(self, bus, device, function, address ):
value = self.helper.read_pci_reg( bus, device, function, address, 4 )
if logger().VERBOSE:
logger().log( "[pci] reading B/D/F: %d/%d/%d, offset: 0x%02X, value: 0x%08X" % (bus, device, function, address, value) )
return value
def read_word(self, bus, device, function, address ):
word_value = self.helper.read_pci_reg( bus, device, function, address, 2 )
if logger().VERBOSE:
logger().log( "[pci] reading B/D/F: %d/%d/%d, offset: 0x%02X, value: 0x%04X" % (bus, device, function, address, word_value) )
return word_value
def read_byte(self, bus, device, function, address ):
byte_value = self.helper.read_pci_reg( bus, device, function, address, 1 )
if logger().VERBOSE:
logger().log( "[pci] reading B/D/F: %d/%d/%d, offset: 0x%02X, value: 0x%02X" % (bus, device, function, address, byte_value) )
return byte_value
def write_byte(self, bus, device, function, address, byte_value ):
self.helper.write_pci_reg( bus, device, function, address, byte_value, 1 )
if logger().VERBOSE:
logger().log( "[pci] writing B/D/F: %d/%d/%d, offset: 0x%02X, value: 0x%02X" % (bus, device, function, address, byte_value) )
return
def write_word(self, bus, device, function, address, word_value ):
self.helper.write_pci_reg( bus, device, function, address, word_value, 2 )
if logger().VERBOSE:
logger().log( "[pci] writing B/D/F: %d/%d/%d, offset: 0x%02X, value: 0x%04X" % (bus, device, function, address, word_value) )
return
def write_dword( self, bus, device, function, address, dword_value ):
self.helper.write_pci_reg( bus, device, function, address, dword_value, 4 )
if logger().VERBOSE:
logger().log( "[pci] writing B/D/F: %d/%d/%d, offset: 0x%02X, value: 0x%08X" % (bus, device, function, address, dword_value) )
return
def enumerate_devices( self ):
devices = []
for b in range(256):
for d in range(32):
for f in range(8):
did_vid = self.read_dword( b, d, f, 0x0 )
#didvid = read_mmcfg_reg( cs, b, d, f, 0x0 )
if 0xFFFFFFFF != did_vid:
vid = did_vid&0xFFFF
did = (did_vid >> 16)&0xFFFF
devices.append( (b, d, f, vid, did) )
return devices
#
# Returns all I/O and MMIO BARs defined in the PCIe header of the device
# Returns array of elements in format (bar_address, isMMIO_BAR, is64bit_BAR, pcie_BAR_reg_offset)
# @TODO: need to account for Type 0 vs Type 1 headers
def get_device_bars( self, bus, dev, fun ):
_bars = []
off = 0x10
while (off < 0x28):
base_lo = self.read_dword( bus, dev, fun, off )
if base_lo:
# BAR is initialized
if (0 == (base_lo & 0x1)):
# MMIO BAR
is64bit = ( (base_lo>>1) & 0x3 )
if 0x2 == is64bit:
# 64-bit MMIO BAR
off += 4
base_hi = self.read_dword( bus, dev, fun, off )
base = ((base_hi << 32) | (base_lo & 0xFFFFFFF0))
_bars.append( (base, True, True, off-4) )
elif 1 == is64bit:
# MMIO BAR below 1MB
pass
elif 0 == is64bit:
# 32-bit only MMIO BAR
_bars.append( (base_lo, True, False, off) )
else:
# I/O BAR
_bars.append( (base_lo&0xFFFFFFFE, False, False, off) )
off += 4
return _bars
def get_DIDVID( self, bus, dev, fun ):
didvid = self.read_dword( bus, dev, fun, 0x0 )
vid = didvid & 0xFFFF
did = (didvid >> 16) & 0xFFFF
return (did, vid)
def is_enabled( self, bus, dev, fun ):
(did, vid) = self.get_DIDVID( bus, dev, fun )
if (0xFFFF == vid) or (0xFFFF == did):
return False
return True
"""
##################################################################################
# PCIEXBAR - technically not MMIO but Memory-mapped CFG space (MMCFG)
# but defined by BAR similarly to MMIO BARs
##################################################################################
def get_PCIEXBAR_base_address( self ):
base_lo = self.read_dword( 0, 0, 0, Cfg.PCI_PCIEXBAR_REG_OFF )
base_hi = self.read_dword( 0, 0, 0, Cfg.PCI_PCIEXBAR_REG_OFF + 4 )
if (0 == base_lo & 0x1):
logger().warn('PCIEXBAR is disabled')
base_lo &= Cfg.PCI_PCIEXBAR_REG_ADMSK256
if (Cfg.PCI_PCIEXBAR_REG_LENGTH_128MB == (base_lo & Cfg.PCI_PCIEXBAR_REG_LENGTH_MASK) >> 1):
base_lo |= Cfg.PCI_PCIEXBAR_REG_ADMSK128
elif (Cfg.PCI_PCIEXBAR_REG_LENGTH_64MB == (base_lo & Cfg.PCI_PCIEXBAR_REG_LENGTH_MASK) >> 1):
base_lo |= (Cfg.PCI_PCIEXBAR_REG_ADMSK128|Cfg.PCI_PCIEXBAR_REG_ADMSK64)
base = (base_hi << 32) | base_lo
if logger().VERBOSE:
logger().log( '[mmio] PCIEXBAR (MMCFG): 0x%016X' % base )
return base
##################################################################################
# Read/write memory mapped PCIe configuration registers
##################################################################################
def read_mmcfg_reg( self, bus, dev, fun, off, size ):
pciexbar = self.get_PCIEXBAR_base_address()
pciexbar_off = (bus * 32 * 8 + dev * 8 + fun) * 0x1000 + off
#value = read_MMIO_reg( cs, pciexbar, pciexbar_off )
value = self.helper.read_physical_mem_dword( pciexbar + pciexbar_off )
if logger().VERBOSE:
logger().log( "[mmcfg] reading B/D/F %d/%d/%d + %02X (PCIEXBAR + %08X): 0x%08X" % (bus, dev, fun, off, pciexbar_off, value) )
if 1 == size:
return (value & 0xFF)
elif 2 == size:
return (value & 0xFFFF)
return value
def write_mmcfg_reg( self, bus, dev, fun, off, size, value ):
pciexbar = self.get_PCIEXBAR_base_address()
pciexbar_off = (bus * 32 * 8 + dev * 8 + fun) * 0x1000 + off
#write_MMIO_reg( cs, pciexbar, pciexbar_off, (value&0xFFFFFFFF) )
self.helper.write_physical_mem_dword( pciexbar + pciexbar_off, value )
if logger().VERBOSE:
logger().log( "[mmcfg] writing B/D/F %d/%d/%d + %02X (PCIEXBAR + %08X): 0x%08X" % (bus, dev, fun, off, pciexbar_off, value) )
return
"""