#!/usr/bin/python #CHIPSEC: Platform Security Assessment Framework #Copyright (c) 2010-2018, 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-2018 Intel Corporation # # ------------------------------------------------------------------------------- """ Access to message bus (IOSF sideband) interface registers on Intel SoCs References: - Intel(R) Atom(TM) Processor E3800 Product Family Datasheet, May 2016, Revision 4.0 http://www.intel.com/content/www/us/en/embedded/products/bay-trail/atom-e3800-family-datasheet.html (sections 3.6 and 13.4.6 - 13.4.8) - Intel(R) Atom(TM) Processor D2000 and N2000 Series Datasheet, Volume 2, July 2012, Revision 003 http://www.intel.com/content/dam/doc/datasheet/atom-d2000-n2000-vol-2-datasheet.pdf (section 1.10.2) usage: >>> msgbus_reg_read( port, register ) >>> msgbus_reg_write( port, register, data ) >>> msgbus_read_message( port, register, opcode ) >>> msgbus_write_message( port, register, opcode, data ) >>> msgbus_send_message( port, register, opcode, data ) """ import struct import sys import os.path from chipsec.hal import hal_base from chipsec.logger import logger # # IOSF Message bus message opcodes # Reference: http://lxr.free-electrons.com/source/arch/x86/include/asm/iosf_mbi.h # class MessageBusOpcode: MB_OPCODE_MMIO_READ = 0x00 MB_OPCODE_MMIO_WRITE = 0x01 MB_OPCODE_IO_READ = 0x02 MB_OPCODE_IO_WRITE = 0x03 MB_OPCODE_CFG_READ = 0x04 MB_OPCODE_CFG_WRITE = 0x05 MB_OPCODE_CR_READ = 0x06 MB_OPCODE_CR_WRITE = 0x07 MB_OPCODE_REG_READ = 0x10 MB_OPCODE_REG_WRITE = 0x11 MB_OPCODE_ESRAM_READ = 0x12 MB_OPCODE_ESRAM_WRITE = 0x13 # # IOSF Message bus unit ports # Reference: http://lxr.free-electrons.com/source/arch/x86/include/asm/iosf_mbi.h # @TODO: move these to per-platform XML config? # class MessageBusPort_Atom: UNIT_AUNIT = 0x00 UNIT_SMC = 0x01 UNIT_CPU = 0x02 UNIT_BUNIT = 0x03 UNIT_PMC = 0x04 UNIT_GFX = 0x06 UNIT_SMI = 0x0C UNIT_USB = 0x43 UNIT_SATA = 0xA3 UNIT_PCIE = 0xA6 class MessageBusPort_Quark: UNIT_HBA = 0x00 UNIT_HB = 0x03 UNIT_RMU = 0x04 UNIT_MM = 0x05 UNIT_SOC = 0x31 class MsgBusRuntimeError (RuntimeError): pass class MsgBus(hal_base.HALBase): def __init__(self, cs): super(MsgBus, self).__init__(cs) self.helper = cs.helper def __MB_MESSAGE_MCR(self, port, reg, opcode): mcr = 0x0 mcr = self.cs.set_register_field( 'MSG_CTRL_REG', mcr, 'MESSAGE_WR_BYTE_ENABLES', 0xF ) mcr = self.cs.set_register_field( 'MSG_CTRL_REG', mcr, 'MESSAGE_ADDRESS_OFFSET', reg ) mcr = self.cs.set_register_field( 'MSG_CTRL_REG', mcr, 'MESSAGE_PORT', port ) mcr = self.cs.set_register_field( 'MSG_CTRL_REG', mcr, 'MESSAGE_OPCODE', opcode ) return mcr def __MB_MESSAGE_MCRX(self, reg): mcrx = 0x0 mcrx = self.cs.set_register_field( 'MSG_CTRL_REG_EXT', mcrx, 'MESSAGE_ADDRESS_OFFSET_EXT', reg, preserve_field_position=True ) return mcrx def __MB_MESSAGE_MDR(self, data): mdr = 0x0 mdr = self.cs.set_register_field( 'MSG_DATA_REG', mdr, 'MESSAGE_DATA', data ) return mdr def __hide_p2sb(self, hide): hidden = not self.cs.is_device_enabled('P2SBC') if hide: self.cs.write_register_field('P2SB_HIDE', 'HIDE', 1) else: self.cs.write_register_field('P2SB_HIDE', 'HIDE', 0) return hidden # # Issues read message on the message bus # def msgbus_read_message( self, port, register, opcode ): mcr = self.__MB_MESSAGE_MCR(port, register, opcode) mcrx = self.__MB_MESSAGE_MCRX(register) if logger().HAL: logger().log( "[msgbus] read: port 0x{:02X} + 0x{:08X} (op = 0x{:02X})".format(port, register, opcode) ) logger().log( "[msgbus] MCR = 0x{:08X}, MCRX = 0x{:08X}".format(mcr, mcrx) ) mdr_out = self.helper.msgbus_send_read_message( mcr, mcrx ) if logger().HAL: logger().log( "[msgbus] < 0x{:08X}".format(mdr_out) ) return mdr_out # # Issues write message on the message bus # def msgbus_write_message( self, port, register, opcode, data ): mcr = self.__MB_MESSAGE_MCR(port, register, opcode) mcrx = self.__MB_MESSAGE_MCRX(register) mdr = self.__MB_MESSAGE_MDR (data) if logger().HAL: logger().log( "[msgbus] write: port 0x{:02X} + 0x{:08X} (op = 0x{:02X}) < data = 0x{:08X}".format(port, register, opcode, data) ) logger().log( "[msgbus] MCR = 0x{:08X}, MCRX = 0x{:08X}, MDR = 0x{:08X}".format(mcr, mcrx, mdr) ) return self.helper.msgbus_send_write_message( mcr, mcrx, mdr ) # # Issues generic message on the message bus # def msgbus_send_message( self, port, register, opcode, data=None ): mcr = self.__MB_MESSAGE_MCR(port, register, opcode) mcrx = self.__MB_MESSAGE_MCRX(register) mdr = None if data is None else self.__MB_MESSAGE_MDR(data) if logger().HAL: logger().log( "[msgbus] message: port 0x{:02X} + 0x{:08X} (op = 0x{:02X})".format(port, register, opcode) ) if data is not None: logger().log( "[msgbus] data = 0x{:08X}".format(data) ) logger().log( "[msgbus] MCR = 0x{:08X}, MCRX = 0x{:08X}, MDR = 0x{:08X}".format(mcr, mcrx, mdr) ) mdr_out = self.helper.msgbus_send_message( mcr, mcrx, mdr ) if logger().HAL: logger().log( "[msgbus] < 0x{:08X}".format(mdr_out) ) return mdr_out # # Message bus register read/write # def msgbus_reg_read(self, port, register): return self.msgbus_read_message(port, register, MessageBusOpcode.MB_OPCODE_REG_READ) def msgbus_reg_write(self, port, register, data): return self.msgbus_write_message(port, register, MessageBusOpcode.MB_OPCODE_REG_WRITE, data) def mm_msgbus_reg_read(self, port, register): was_hidden = False if self.cs.is_register_defined('P2SBC'): was_hidden = self.__hide_p2sb(False) mmio_addr = self.cs.mmio.get_MMIO_BAR_base_address('SBREGBAR')[0] reg_val = self.cs.mmio.read_MMIO_reg_dword(mmio_addr, ((port & 0xFF) << 16) | (register & 0xFFFF)) if self.cs.is_register_defined('P2SBC') and was_hidden: self.__hide_p2sb(True) return reg_val def mm_msgbus_reg_write(self, port, register, data): was_hidden = False if self.cs.is_register_defined('P2SBC'): was_hidden = self.__hide_p2sb(False) mmio_addr = self.cs.mmio.get_MMIO_BAR_base_address('SBREGBAR')[0] reg_val = self.cs.mmio.write_MMIO_reg_dword(mmio_addr, ((port & 0xFF) << 16) | (register & 0xFFFF), data) if self.cs.is_register_defined('P2SBC') and was_hidden: self.__hide_p2sb(True) return reg_val """ # py implementation of msgbus -- doesn't seem to work properly becaise it's not atomic def msgbus_send_message( self, port, register, opcode, data=None ): if logger().HAL: logger().log( "[msgbus] message - port: 0x{:02X}, reg: 0x{:08X} (op: 0x{:02X})".format(port, register, opcode) ) if data is not None: logger().log( "[msgbus] message - data: 0x{:08X}".format(data) ) if (register & 0xFFFFFF00): # write extended register address (bits [31:08]) to Message Control Register Extension (MCRX) chipsec.chipset.write_register_field( self.cs, 'MSG_CTRL_REG_EXT', 'MESSAGE_ADDRESS_OFFSET_EXT', register, preserve_field_position=True ) res = None # write data to Message Data Register (MDR) for writes if data is not None: chipsec.chipset.write_register( self.cs, 'MSG_DATA_REG', data ) # write message (byte enables, address bits [08:00], port and opcode) to Message Control Register (MCR) chipsec.chipset.write_register( self.cs, 'MSG_CTRL_REG', MB_MESSAGE(self.cs, port, register, opcode) ) # read the data from Message Data Register (MDR) for reads if data is None: res = chipsec.chipset.read_register( self.cs, 'MSG_DATA_REG' ) return res """