hackedteam/vector-edk

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

Summary

Maintainability
C
1 day
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/mmio.py
# =============================================
# Access to MMIO (Memory Mapped IO) BARs and Memory-Mapped PCI Configuration Space (MMCFG)
# ~~~
# #usage:
#     read_MMIOBAR_reg( cs, mmio.MMIO_BAR_MCHBAR, 0x0 )
#     write_MMIOBAR_reg( cs, mmio.MMIO_BAR_MCHBAR, 0xFFFFFFFF )
#     read_MMIO_reg( bar_base, 0x0 )
#     write_MMIO_reg( bar_base, 0x0, 0xFFFFFFFF )
#
#     get_MMIO_base_address( cs, mmio.MMIO_BAR_MCHBAR )
#     is_MMIOBAR_enabled( cs, mmio.MMIO_BAR_MCHBAR )
#     is_MMIOBAR_programmed( cs, mmio.MMIO_BAR_MCHBAR )
#
#     read_MMIOBAR( cs, mmio.MMIO_BAR_MCHBAR, 0x1000 )
#     read_MMIO( cs, bar_base, 0x1000 )
#     dump_MMIO( cs, bar_base, 0x1000 )
#
#     read_mmcfg_reg( cs, 0, 0, 0, 0x10, 4 ):
#     read_mmcfg_reg( cs, 0, 0, 0, 0x10, 4, 0xFFFFFFFF )
# ~~~
#
__version__ = '1.0'

import struct
import sys

from chipsec.logger import logger
#from chipsec.pci import PCI_BDF

from chipsec.cfg.common import *


##################################################################################
# Dev0 BARs: MCHBAR, DMIBAR
##################################################################################
def get_MCHBAR_base_address(cs):
    #bar = PCI_BDF( 0, 0, 0, Cfg.PCI_MCHBAR_REG_OFF )
    base = cs.pci.read_dword( 0, 0, 0, Cfg.PCI_MCHBAR_REG_OFF )
    if (0 == base & 0x1):
       logger().warn('MCHBAR is disabled')
    base = base & 0xFFFFF000
    if logger().VERBOSE:
       logger().log( '[mmio] MCHBAR: 0x%016X' % base )
    return base

def get_DMIBAR_base_address(cs):
    #bar = PCI_BDF( 0, 0, 0, Cfg.PCI_DMIBAR_REG_OFF )
    base_lo = cs.pci.read_dword( 0, 0, 0, Cfg.PCI_DMIBAR_REG_OFF )
    base_hi = cs.pci.read_dword( 0, 0, 0, Cfg.PCI_DMIBAR_REG_OFF + 4 )
    if (0 == base_lo & 0x1):
       logger().warn('DMIBAR is disabled')
    base = (base_hi << 32) | (base_lo & 0xFFFFF000)
    if logger().VERBOSE:
       logger().log( '[mmio] DMIBAR: 0x%016X' % base )
    return base


##################################################################################
# PCH LPC Interface Root Complex base address (RCBA)
##################################################################################

def get_LPC_RCBA_base_address(cs):
    reg_value = cs.pci.read_dword( 0, 31, 0, Cfg.LPC_RCBA_REG_OFFSET )
    #RcbaReg = LPC_RCBA_REG( (reg_value>>14)&0x3FFFF, (reg_value>>1)&0x1FFF, reg_value&0x1 )
    #rcba_base = RcbaReg.BaseAddr << Cfg.RCBA_BASE_ADDR_SHIFT
    rcba_base = (reg_value >> Cfg.RCBA_BASE_ADDR_SHIFT) << Cfg.RCBA_BASE_ADDR_SHIFT
    if logger().VERBOSE:
      logger().log( "[mmio] LPC RCBA: 0x%08X" % rcba_base )
    return rcba_base


##################################################################################
# Base of SPI Controller MMIO registers
##################################################################################

def get_PCH_RCBA_SPI_base(cs):
    rcba_spi_base = get_LPC_RCBA_base_address(cs) + Cfg.PCH_RCRB_SPI_BASE
    if logger().VERBOSE:
       logger().log( "[mmio] RCBA SPI base: 0x%08X (assuming below 4GB)" % rcba_spi_base )
    return rcba_spi_base


##################################################################################
# GFx MMIO: GMADR/GTTMMADR
##################################################################################

def get_GFx_base_address(cs, dev2_offset):
    #bar = PCI_BDF( 0, 2, 0, dev2_offset )
    base_lo = cs.pci.read_dword( 0, 2, 0, dev2_offset )
    base_hi = cs.pci.read_dword( 0, 2, 0, dev2_offset + 4 )
    base = base_hi | (base_lo & 0xFF000000)
    return base
def get_GMADR_base_address( cs ):
    base = get_GFx_base_address(cs, Cfg.PCI_GMADR_REG_OFF)
    if logger().VERBOSE:
       logger().log( '[mmio] GMADR: 0x%016X' % base )
    return base
def get_GTTMMADR_base_address( cs ):
    base = get_GFx_base_address(cs, Cfg.PCI_GTTMMADR_REG_OFF)
    if logger().VERBOSE:
       logger().log( '[mmio] GTTMMADR: 0x%016X' % base )
    return base

##################################################################################
# HD Audio MMIO
##################################################################################

def get_HDAudioBAR_base_address(cs):
    base = cs.pci.read_dword( 0, Cfg.PCI_HDA_DEV, 0, Cfg.PCI_HDAUDIOBAR_REG_OFF )
    base = base & (0xFFFFFFFF << 14)
    if logger().VERBOSE:
       logger().log( '[mmio] HD Audio MMIO: 0x%08X' % base )
    return base


##################################################################################
# PCIEXBAR - technically not MMIO but Memory-mapped CFG space (MMCFG)
# but defined by BAR similarly to MMIO BARs
##################################################################################

def get_PCIEXBAR_base_address(cs):
    base_lo = cs.pci.read_dword( 0, 0, 0, Cfg.PCI_PCIEXBAR_REG_OFF )
    base_hi = cs.pci.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


##################################################################################
#
# To add your own MMIO bar:
#   1. Add new MMIO BAR id (any)
#   2. Write a function get_yourBAR_base_address() with no args that returns base addres of new bar
#   3. Add a pointer to this function to MMIO_BAR_base map
#   4. Don't touch read/write_MMIO_reg functions ;)
#
##################################################################################

# CPU
# Device 0
MMIO_BAR_MCHBAR      = 1   # MCHBAR
MMIO_BAR_DMIBAR      = 2   # DMIBAR
MMIO_BAR_PCIEXBAR    = 3   # PCIEXBAR
# Device 1
# @TODO
# Device 2
MMIO_BAR_GTTMMADR    = 10  # GFx MMIO
MMIO_BAR_GMADR       = 11  # GFx Aperture
# Device 3 (Device 27)
MMIO_BAR_HDABAR      = 20  # HD Audio MMIO BAR
# PCH
# @TODO
# Device 31
MMIO_BAR_LPCRCBA     = 100 # ICH LPC Interface Root Complex (RCBA)
MMIO_BAR_LPCRCBA_SPI = 101 # RCBA SPIBASE

MMIO_BAR_base = {
                  MMIO_BAR_MCHBAR      : get_MCHBAR_base_address,
                  MMIO_BAR_DMIBAR      : get_DMIBAR_base_address,
                  MMIO_BAR_PCIEXBAR    : get_PCIEXBAR_base_address,
                  MMIO_BAR_GMADR       : get_GMADR_base_address,
                  MMIO_BAR_GTTMMADR    : get_GTTMMADR_base_address,
                  MMIO_BAR_HDABAR      : get_HDAudioBAR_base_address,
                  MMIO_BAR_LPCRCBA     : get_LPC_RCBA_base_address,
                  MMIO_BAR_LPCRCBA_SPI : get_PCH_RCBA_SPI_base
                }
MMIO_BAR_name = {
                  MMIO_BAR_MCHBAR      : "MCHBAR",
                  MMIO_BAR_DMIBAR      : "DMIBAR",
                  MMIO_BAR_PCIEXBAR    : "PCIEXBAR",
                  MMIO_BAR_GMADR       : "GMADR",
                  MMIO_BAR_GTTMMADR    : "GTTMMADR",
                  MMIO_BAR_HDABAR      : "HDABAR",
                  MMIO_BAR_LPCRCBA     : "RCBA",
                  MMIO_BAR_LPCRCBA_SPI : "SPIBAR"
                }
#MMIO_BAR_name = dict( MMIO_BAR_base+[(e[1], e[0]) for e in MMIO_BAR_base] )


def get_MMIO_base_address( cs, bar_id ):
    return MMIO_BAR_base[ bar_id ](cs)

def is_MMIOBAR_enabled( cs, bar_id ):
    bar_base  = MMIO_BAR_base[ bar_id ](cs)
    return (0 != bar_base)


def is_MMIOBAR_programmed( cs, bar_id ):
    bar_base  = MMIO_BAR_base[ bar_id ](cs)
    return (0 != bar_base)

def read_MMIOBAR_reg(cs, bar_id, offset ):
    bar_base  = MMIO_BAR_base[ bar_id ](cs)
    reg_addr  = bar_base + offset 
    reg_value = cs.mem.read_physical_mem_dword( reg_addr )
    if logger().VERBOSE:
      logger().log( '[mmio] %s + 0x%08X (0x%08X) = 0x%08X' % (MMIO_BAR_name[bar_id], offset, reg_addr, reg_value) )
    return reg_value
def read_MMIO_reg(cs, bar_base, offset ):
    reg_value = cs.mem.read_physical_mem_dword( bar_base + offset )
    if logger().VERBOSE:
      logger().log( '[mmio] 0x%08X + 0x%08X = 0x%08X' % (bar_base, offset, reg_value) )
    return reg_value
    
def write_MMIOBAR_reg(cs, bar_id, offset, dword_value ):
    bar_base  = MMIO_BAR_base[ bar_id ]()
    reg_addr  = bar_base + offset
    if logger().VERBOSE:
       logger().log( '[mmio] write %s + 0x%08X (0x%08X) = 0x%08X' % (MMIO_BAR_name[bar_id], offset, reg_addr, dword_value) )
    cs.mem.write_physical_mem_dword( reg_addr, dword_value )
    return 1
def write_MMIO_reg(cs, bar_base, offset, dword_value ):
    if logger().VERBOSE:
       logger().log( '[mmio] write 0x%08X + 0x%08X = 0x%08X' % (bar_base, offset, dword_value) )
    cs.mem.write_physical_mem_dword( bar_base + offset, dword_value )
    return 1

def read_MMIOBAR( cs, bar_id, size ):
    regs = []
    size = size - size%4
    bar_base  = MMIO_BAR_base[ bar_id ]()
    for offset in range(0,size,4):
        regs.append( read_MMIO_reg( cs, bar_base, offset ) )
    return regs
def read_MMIO( cs, bar_base, size ):
    regs = []
    size = size - size%4
    for offset in range(0,size,4):
        regs.append( read_MMIO_reg( cs, bar_base, offset ) )
    return regs

def dump_MMIO( cs, bar_base, size ):
    regs = read_MMIO( cs, bar_base, size )
    off = 0
    for r in regs:
        logger().log( '0x%04x: %08x' % (off, r) )
        off = off + 4



##################################################################################
# Read/write memory mapped PCIe configuration registers
##################################################################################

def read_mmcfg_reg( cs, bus, dev, fun, off, size ):
    pciexbar = get_PCIEXBAR_base_address( cs )
    pciexbar_off = (bus * 32 * 8 + dev * 8 + fun) * 0x1000 + off
    value = read_MMIO_reg( cs, 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( cs, bus, dev, fun, off, size, value ):
    pciexbar = get_PCIEXBAR_base_address( cs )
    pciexbar_off = (bus * 32 * 8 + dev * 8 + fun) * 0x1000 + off
    write_MMIO_reg( cs, pciexbar, pciexbar_off, (value&0xFFFFFFFF) )
    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 True