mirror of
https://github.com/chipsec/chipsec
synced 2026-06-08 13:31:00 +00:00
1259e568de
Signed-off-by: Nathaniel Mitchell <nathaniel.p.mitchell@intel.com>
612 lines
23 KiB
Python
612 lines
23 KiB
Python
# CHIPSEC: Platform Security Assessment Framework
|
|
# Copyright (c) 2010-2021, 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
|
|
#
|
|
# -------------------------------------------------------------------------------
|
|
|
|
"""
|
|
Access to SMBus Controller
|
|
"""
|
|
from typing import List
|
|
from chipsec.hal import hal_base
|
|
from chipsec.hal.common import iobar
|
|
from chipsec.library.exceptions import IOBARNotFoundError, ObjectInstanceNotFoundError, RegisterNotFoundError
|
|
|
|
SMBUS_COMMAND_QUICK = 0
|
|
SMBUS_COMMAND_BYTE = 1
|
|
SMBUS_COMMAND_BYTE_DATA = 2
|
|
SMBUS_COMMAND_WORD_DATA = 3
|
|
SMBUS_COMMAND_PROCESS_CALL = 4
|
|
SMBUS_COMMAND_BLOCK = 5
|
|
SMBUS_COMMAND_I2C_READ = 6
|
|
SMBUS_COMMAND_BLOCK_PROCESS = 7
|
|
|
|
SMBUS_POLL_COUNT = 1000
|
|
|
|
SMBUS_COMMAND_WRITE = 0
|
|
SMBUS_COMMAND_READ = 1
|
|
|
|
|
|
class SMBus(hal_base.HALBase):
|
|
|
|
def __init__(self, cs):
|
|
super(SMBus, self).__init__(cs)
|
|
self.instance = None
|
|
self.set_instance()
|
|
self.get_common_registers()
|
|
self.get_registers()
|
|
self.i2c_mode = False
|
|
|
|
def set_i2c_mode(self, is_i2c_mode_enabled):
|
|
self.i2c_mode = is_i2c_mode_enabled
|
|
|
|
def get_instances(self):
|
|
smbus_obj = self.cs.device.get_list_by_name('8086.SMBUS')[0]
|
|
if smbus_obj and smbus_obj.instances:
|
|
return smbus_obj.instances
|
|
raise ObjectInstanceNotFoundError('SMBus instance not found')
|
|
|
|
def set_instance(self, instance=None):
|
|
_instances = self.get_instances()
|
|
if instance is None:
|
|
self.instance = _instances[0]
|
|
elif instance in _instances:
|
|
self.instance = instance
|
|
else:
|
|
raise RegisterNotFoundError(f'Instance {instance} is not within supported list {_instances}')
|
|
|
|
def get_registers(self):
|
|
self.smb_reg_status = self.cs.register.get_instance_by_name('8086.SMBUS.HST_STS', self.instance)
|
|
self.smb_reg_control = self.cs.register.get_instance_by_name('8086.SMBUS.HST_CNT', self.instance)
|
|
self.smb_reg_command = self.cs.register.get_instance_by_name('8086.SMBUS.HST_CMD', self.instance)
|
|
self.smb_reg_address = self.cs.register.get_instance_by_name('8086.SMBUS.HST_SLVA', self.instance)
|
|
self.smb_reg_data0 = self.cs.register.get_instance_by_name('8086.SMBUS.HST_D0', self.instance)
|
|
self.smb_reg_data1 = self.cs.register.get_instance_by_name('8086.SMBUS.HST_D1', self.instance)
|
|
self.smb_reg_aux_ctl = self.cs.register.get_instance_by_name('8086.SMBUS.HST_AUX_CTL', self.instance)
|
|
self.smb_reg_block_db = self.cs.register.get_instance_by_name('8086.SMBUS.HST_BLOCK_DB', self.instance)
|
|
self.smb_hcfg = self.cs.register.get_instance_by_name('8086.SMBUS.HCFG', self.instance)
|
|
|
|
def get_common_registers(self):
|
|
self.smb_cmd = self.cs.register.get_instance_by_name('8086.SMBUS.CMD', self.instance)
|
|
|
|
def enable(self):
|
|
self.logger.log_hal("[SMBUS] Enabling SMBus...")
|
|
if not self.is_SMBus_host_controller_enabled():
|
|
self.logger.log_hal("SMBus disabled; enabling...")
|
|
self.enable_SMBus_host_controller()
|
|
if self.i2c_mode is True:
|
|
self.logger.log_hal("i2c mode is selected")
|
|
if not self.is_pch_i2c_enabled():
|
|
self.logger.log_hal("Intel PCH is not enabled to communicate with i2c devices; enabling...")
|
|
self.enable_pch_i2c_comm()
|
|
else:
|
|
self.logger.log_hal("SMBUS mode is selected. disabling i2c mode")
|
|
if self.is_pch_i2c_enabled():
|
|
self.logger.log_hal("Intel PCH is enabled to communicate with i2c devices; disabling...")
|
|
self.disable_pch_i2c_comm()
|
|
if not self.is_SMBus_io_mem_space_enabled():
|
|
self.logger.log_hal("SMBus io/mem space disabled; enabling...")
|
|
self.enable_SMBus_io_mem_space()
|
|
|
|
if not self.is_SMBus_host_controller_enabled():
|
|
self.logger.log_hal("[SMBUS] SMBus disabled; enabling...")
|
|
self.enable_SMBus_host_controller()
|
|
self.logger.log_hal("[SMBUS] SMBus enabled attempted")
|
|
|
|
def _txn_rw_read(self, target_address):
|
|
self.smb_reg_address.set_value(0x0)
|
|
self.smb_reg_address.set_field('RW', SMBUS_COMMAND_READ)
|
|
hst_sa = self.smb_reg_address.set_field('Address', target_address)
|
|
self.smb_reg_address.write(hst_sa)
|
|
self.smb_reg_address.read()
|
|
self.logger.log_hal(self.smb_reg_address)
|
|
|
|
def _txn_rw_write(self, target_address):
|
|
self.smb_reg_address.set_value(0x0)
|
|
self.smb_reg_address.set_field('RW', SMBUS_COMMAND_WRITE)
|
|
hst_sa = self.smb_reg_address.set_field('Address', target_address)
|
|
self.smb_reg_address.write(hst_sa)
|
|
|
|
def get_SMBus_Base_Address(self):
|
|
if self.cs.hals.iobar.is_IO_BAR_defined('8086.SMBUS.SMBUS_BASE'):
|
|
(sba_base, _) = self.cs.hals.iobar.get_IO_BAR_base_address('8086.SMBUS.SMBUS_BASE', self.instance)
|
|
return sba_base
|
|
else:
|
|
raise IOBARNotFoundError('IOBARAccessError: SMBUS_BASE')
|
|
|
|
def display_SMBus_info(self):
|
|
self.logger.log(f"[smbus] SMBus Base Address: 0x{self.get_SMBus_Base_Address():04X}")
|
|
self.smb_hcfg.read()
|
|
self.logger.log(self.smb_hcfg)
|
|
|
|
def is_SMBus_enabled(self):
|
|
return self.cs.device.get_bus('8086.SMBUS')
|
|
|
|
def is_SMBus_supported(self):
|
|
if self.cs.device.get_bus('8086.SMBUS') is not None:
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def is_SMBus_host_controller_enabled(self):
|
|
return self.smb_hcfg.get_field("HST_EN") == 1
|
|
|
|
def is_pch_i2c_enabled(self):
|
|
return ((self.smb_hcfg.read() & 4) >> 2) == 1
|
|
|
|
def is_SMBus_io_mem_space_enabled(self):
|
|
cmd = self.smb_cmd.read()
|
|
self.logger.log_hal(self.smb_cmd)
|
|
return (cmd & 0x3) == 0x3
|
|
|
|
def enable_SMBus_host_controller(self):
|
|
# Enable SMBus Host Controller Interface in HCFG
|
|
reg_value = self.smb_hcfg.read()
|
|
if 0 == (reg_value & 0x1):
|
|
self.smb_hcfg.write(reg_value | 0x1)
|
|
|
|
def disable_pch_i2c_comm(self):
|
|
# Disable PCH connection to I2c devices
|
|
reg_value = self.smb_hcfg.read()
|
|
if not 0 == (reg_value & 0x04):
|
|
self.smb_hcfg.write(reg_value & ~ 0x4)
|
|
reg_value = self.smb_hcfg.read()
|
|
if not 0 == (reg_value & 0x04):
|
|
self.logger.log("PCH is enabled to connect with i2c devices")
|
|
else:
|
|
self.logger.log("PCH is disabled to connect with i2c devices")
|
|
|
|
def enable_pch_i2c_comm(self):
|
|
# Enable PCH connection to I2c devices
|
|
reg_value = self.smb_hcfg.read()
|
|
if 0 == (reg_value & 0x04):
|
|
self.smb_hcfg.write(reg_value | 0x05)
|
|
reg_value = self.smb_hcfg.read()
|
|
if not 0 == (reg_value & 0x04):
|
|
self.logger.log("PCH is enabled to connect with i2c devices")
|
|
else:
|
|
self.logger.log("PCH is not enabled to connect with i2c devices")
|
|
|
|
def enable_SMBus_io_mem_space(self):
|
|
# @TODO: check SBA is programmed
|
|
# sba = self.get_SMBus_Base_Address()
|
|
# Enable SMBus I/O Space
|
|
cmd = self.smb_cmd.read()
|
|
if 0 == (cmd & 0x1):
|
|
self.smb_cmd.write(cmd | 0x1)
|
|
|
|
def reset_SMBus_controller(self):
|
|
reg_value = self.smb_hcfg.read()
|
|
self.smb_hcfg.write(reg_value | 0x08)
|
|
for _ in range(SMBUS_POLL_COUNT):
|
|
if (self.smb_hcfg.read() & 0x08) == 0:
|
|
return True
|
|
return False
|
|
|
|
# waits for SMBus to become ready
|
|
def _is_smbus_ready(self):
|
|
for i in range(SMBUS_POLL_COUNT):
|
|
self.smb_reg_status.read()
|
|
self.logger.log_hal(f"Status: 0x{self.smb_reg_status.value:X}")
|
|
busy = self.smb_reg_status.get_field('BUSY')
|
|
if 1 == busy:
|
|
self.logger.log_hal("SMBus busy, waiting...")
|
|
continue
|
|
self.smb_reg_status.write(0xFF)
|
|
break
|
|
return 0 == busy
|
|
|
|
# waits for SMBus transaction to complete
|
|
def _wait_for_cycle(self):
|
|
for i in range(SMBUS_POLL_COUNT):
|
|
self.smb_reg_status.read()
|
|
busy = self.smb_reg_status.get_field('BUSY')
|
|
failed = self.smb_reg_status.get_field('FAILED')
|
|
if 1 == busy:
|
|
self.logger.log_hal("SMBus busy, waiting...")
|
|
continue
|
|
elif 1 == failed:
|
|
self.logger.log_hal("SMBus transaction failed (FAILED/ERROR bit = 1)")
|
|
reg_value = self.smb_hcfg.read()
|
|
self.smb_hcfg.write(reg_value | 0x08)
|
|
return False
|
|
|
|
if self.cs.register.has_field(self.smb_reg_status.name, 'DEV_ERR'):
|
|
if 1 == self.smb_reg_status.get_field('DEV_ERR'):
|
|
self.logger.log_hal("SMBus device error (invalid cmd, unclaimed cycle or time-out error)")
|
|
reg_value = self.smb_hcfg.read()
|
|
self.smb_hcfg.write(reg_value | 0x08)
|
|
return False
|
|
if self.cs.register.has_field(self.smb_reg_status.name, 'BUS_ERR'):
|
|
if 1 == self.smb_reg_status.get_field('BUS_ERR'):
|
|
self.logger.log_hal("SMBus bus error")
|
|
reg_value = self.smb_hcfg.read()
|
|
self.smb_hcfg.write(reg_value | 0x08)
|
|
return False
|
|
break
|
|
return (0 == busy)
|
|
|
|
#
|
|
# SMBus commands
|
|
#
|
|
def quick_write(self, target_address):
|
|
ret_code = False
|
|
if not self._is_smbus_ready():
|
|
return ret_code
|
|
|
|
self.logger.log_verbose(f"[smbus] quick write to device {target_address:X}")
|
|
|
|
# clear status bits
|
|
self.smb_reg_status.write(0xFF)
|
|
# SMBus txn RW direction = Write, SMBus slave address = target_address
|
|
self._txn_rw_write(target_address)
|
|
|
|
# command = Byte Data
|
|
self.smb_reg_control.write_field('SMB_CMD', SMBUS_COMMAND_QUICK)
|
|
self.smb_reg_control.read()
|
|
|
|
# send SMBus txn
|
|
self.smb_reg_control.write_field('START', 1)
|
|
self.smb_reg_control.read()
|
|
|
|
# wait for cycle to complete
|
|
ret_code = self._wait_for_cycle()
|
|
# clear status bits
|
|
self.smb_reg_data0.write(0x0)
|
|
self.smb_reg_data0.read()
|
|
self.logger.log_hal(f"[smbus] quick write to device {target_address:X} returned {str(ret_code)}")
|
|
return ret_code
|
|
|
|
def read_byte(self, target_address, offset):
|
|
if not self._is_smbus_ready():
|
|
self.logger.log(f"[smbus] controller is not ready {target_address:X}")
|
|
return False
|
|
|
|
# clear status bits
|
|
self.smb_reg_status.write(0xFF)
|
|
|
|
# SMBus txn RW direction = Read, SMBus slave address = target_address
|
|
self._txn_rw_read(target_address)
|
|
|
|
# command data = byte offset (bus txn address)
|
|
self.smb_reg_command.write_field('DataOffset', offset)
|
|
self.smb_reg_command.read()
|
|
self.logger.log_hal(self.smb_reg_command)
|
|
|
|
# command = Byte Data
|
|
self.smb_reg_control.write_field('SMB_CMD', SMBUS_COMMAND_BYTE_DATA)
|
|
self.smb_reg_control.read()
|
|
|
|
# send SMBus txn
|
|
self.smb_reg_control.write_field('START', 1)
|
|
self.smb_reg_control.read()
|
|
self.logger.log_hal(self.smb_reg_control)
|
|
|
|
# wait for cycle to complete
|
|
if not self._wait_for_cycle():
|
|
return False
|
|
|
|
# read the data
|
|
value = self.smb_reg_data0.read()
|
|
self.logger.log_hal(self.smb_reg_data0)
|
|
self.smb_reg_data0.write(0x00)
|
|
self.smb_reg_data0.read()
|
|
|
|
self.logger.log_hal(f"[smbus] read device {target_address:X} off {offset:X} = {value:X}")
|
|
return [value]
|
|
|
|
def read_word(self, target_address, offset):
|
|
if not self._is_smbus_ready():
|
|
return False
|
|
|
|
# clear status bits
|
|
self.smb_reg_status.write(0xFF)
|
|
self.smb_reg_status.read()
|
|
|
|
# SMBus txn RW direction = Read, SMBus slave address = target_address
|
|
self._txn_rw_read(target_address)
|
|
|
|
# command data = byte offset (bus txn address)
|
|
self.smb_reg_command.write_field('DataOffset', offset)
|
|
self.smb_reg_command.read()
|
|
self.logger.log_hal(self.smb_reg_command)
|
|
|
|
# command = Byte Data
|
|
self.smb_reg_control.write_field('SMB_CMD', SMBUS_COMMAND_WORD_DATA)
|
|
self.smb_reg_control.read()
|
|
|
|
# send SMBus txn
|
|
self.smb_reg_control.write_field('START', 1)
|
|
self.smb_reg_control.read()
|
|
self.logger.log_hal(self.smb_reg_control)
|
|
|
|
# wait for cycle to complete
|
|
if not self._wait_for_cycle():
|
|
return False
|
|
|
|
# read the data
|
|
valueL = self.smb_reg_data0.read()
|
|
self.logger.log_hal(self.smb_reg_data0)
|
|
self.smb_reg_data0.write(0x00)
|
|
self.smb_reg_data0.read()
|
|
valueH = self.smb_reg_data1.read()
|
|
self.logger.log_hal(self.smb_reg_data1)
|
|
self.smb_reg_data1.write(0x00)
|
|
self.smb_reg_data1.read()
|
|
|
|
self.logger.log_verbose(f"[smbus] read device {target_address:X} off {offset:X} = {valueH:X} {valueL:X}")
|
|
return [valueL, valueH]
|
|
|
|
def read_block(self, target_address, command):
|
|
if not self._is_smbus_ready():
|
|
return False
|
|
|
|
# clear status bits
|
|
self.smb_reg_status.write(0xFF)
|
|
self.smb_reg_control.write_field('LAST_BYTE', 0)
|
|
self.smb_reg_control.read()
|
|
|
|
# SMBus txn RW direction = Read, SMBus slave address = target_address
|
|
self._txn_rw_read(target_address)
|
|
|
|
# auxiliary control reg
|
|
self.smb_reg_aux_ctl.write_field('E32B', 1)
|
|
self.smb_reg_aux_ctl.read()
|
|
self.logger.log_hal(self.smb_reg_aux_ctl)
|
|
|
|
# command data = byte offset (bus txn address)
|
|
self.smb_reg_command.write_field('DataOffset', command)
|
|
self.smb_reg_command.read()
|
|
self.logger.log_hal(self.smb_reg_command)
|
|
|
|
# command = Byte Data
|
|
self.smb_reg_control.write_field('SMB_CMD', SMBUS_COMMAND_BLOCK)
|
|
self.smb_reg_control.read()
|
|
self.logger.log_hal(self.smb_reg_control)
|
|
|
|
# send SMBus txn
|
|
self.smb_reg_control.write_field('START', 1)
|
|
self.smb_reg_control.read()
|
|
self.logger.log_hal(self.smb_reg_control)
|
|
|
|
# wait for cycle to complete
|
|
if not self._wait_for_cycle():
|
|
return False
|
|
read_list = []
|
|
to_read = self.smb_reg_data0.read()
|
|
if to_read <= 0 or to_read > 32:
|
|
return False
|
|
|
|
while to_read:
|
|
read_list.append(self.smb_reg_block_db.read())
|
|
to_read -= 1
|
|
self.smb_reg_control.write_field('LAST_BYTE', 1)
|
|
self.smb_reg_control.read()
|
|
|
|
self.smb_reg_data0.write(0x00)
|
|
self.smb_reg_data0.read()
|
|
|
|
self.logger.log_verbose(f"[smbus] block read device 0x{target_address:x} off 0x{command:x} = " + " 0x".join(f"{c:02x}" for c in read_list))
|
|
return read_list
|
|
|
|
def write_byte(self, target_address, offset, value):
|
|
if not self._is_smbus_ready():
|
|
return False
|
|
|
|
# clear status bits
|
|
self.smb_reg_status.write(0xFF)
|
|
self.smb_reg_status.read()
|
|
|
|
# SMBus txn RW direction = Write, SMBus slave address = target_address
|
|
self._txn_rw_write(target_address)
|
|
self.smb_reg_address.read()
|
|
|
|
# command data = byte offset (bus txn address)
|
|
self.smb_reg_command.write_field('DataOffset', offset)
|
|
self.smb_reg_command.read()
|
|
|
|
# write the data
|
|
self.smb_reg_data0.write_field('Data', value)
|
|
self.smb_reg_data0.read()
|
|
|
|
# command = Byte Data
|
|
self.smb_reg_control.write_field('SMB_CMD', SMBUS_COMMAND_BYTE_DATA)
|
|
self.smb_reg_control.read()
|
|
|
|
# send SMBus txn
|
|
self.smb_reg_control.write_field('START', 1)
|
|
self.smb_reg_control.read()
|
|
|
|
# wait for cycle to complete
|
|
if not self._wait_for_cycle():
|
|
return False
|
|
|
|
# clear status bits
|
|
self.smb_reg_status.write(0x0)
|
|
self.smb_reg_status.read()
|
|
|
|
self.logger.log_verbose(f'[smbus] write to device {target_address:X} off {offset:X} = {value:X}')
|
|
return True
|
|
|
|
def write_word(self, target_address, offset, valueH, valueL):
|
|
if not self._is_smbus_ready():
|
|
return False
|
|
|
|
# clear status bits
|
|
self.smb_reg_status.write(0xFF)
|
|
|
|
# SMBus txn RW direction = Write, SMBus slave address = target_address
|
|
self._txn_rw_write(target_address)
|
|
self.smb_reg_address.read()
|
|
|
|
# command data = byte offset (bus txn address)
|
|
self.smb_reg_command.write_field('DataOffset', offset)
|
|
self.smb_reg_command.read()
|
|
|
|
# write the data
|
|
self.smb_reg_data0.write_field('Data', valueL)
|
|
self.smb_reg_data0.read()
|
|
self.smb_reg_data1.write_field('Data', valueH)
|
|
self.smb_reg_data1.read()
|
|
|
|
# command = Byte Data
|
|
self.smb_reg_control.write_field('SMB_CMD', SMBUS_COMMAND_WORD_DATA)
|
|
self.smb_reg_control.read()
|
|
|
|
# send SMBus txn
|
|
self.smb_reg_control.write_field('START', 1)
|
|
self.smb_reg_control.read()
|
|
|
|
# wait for cycle to complete
|
|
if not self._wait_for_cycle():
|
|
return False
|
|
|
|
# clear status bits
|
|
self.smb_reg_data0.write(0x00)
|
|
self.smb_reg_data0.read()
|
|
self.smb_reg_data1.write(0x00)
|
|
self.smb_reg_data1.read()
|
|
|
|
self.logger.log_verbose(f'[smbus] write to device {target_address:X} off {offset:X} = {valueH:X} {valueL:X}')
|
|
return True
|
|
|
|
def process_call(self, target_address, offset, valueH, valueL):
|
|
if not self._is_smbus_ready():
|
|
return False
|
|
|
|
# clear status bits
|
|
self.smb_reg_status.write(0xFF)
|
|
|
|
# SMBus txn RW direction = Write, SMBus slave address = target_address
|
|
self._txn_rw_write(target_address)
|
|
self.smb_reg_address.read()
|
|
|
|
# command data = byte offset (bus txn address)
|
|
self.smb_reg_command.write_field('DataOffset', offset)
|
|
self.smb_reg_command.read()
|
|
|
|
# write the data
|
|
self.smb_reg_data0.write(valueL)
|
|
self.smb_reg_data0.read()
|
|
self.logger.log_hal(self.smb_reg_data0)
|
|
self.smb_reg_data1.write(valueH)
|
|
self.smb_reg_data1.read()
|
|
self.logger.log_hal(self.smb_reg_data1)
|
|
|
|
# command = Byte Data
|
|
self.smb_reg_control.write_field('SMB_CMD', SMBUS_COMMAND_PROCESS_CALL)
|
|
self.smb_reg_control.read()
|
|
|
|
# send SMBus txn
|
|
self.smb_reg_control.write_field('START', 1)
|
|
self.smb_reg_control.read()
|
|
|
|
# wait for cycle to complete
|
|
if not self._wait_for_cycle():
|
|
return False
|
|
|
|
# read the data
|
|
valueL_R = self.smb_reg_data0.read()
|
|
self.logger.log_hal(self.smb_reg_data0)
|
|
valueH_R = self.smb_reg_data1.read()
|
|
self.logger.log_hal(self.smb_reg_data1)
|
|
|
|
# clear status bits
|
|
self.smb_reg_data0.write(0x00)
|
|
self.smb_reg_data0.read()
|
|
self.smb_reg_data1.write(0x00)
|
|
self.smb_reg_data1.read()
|
|
self.logger.log_debug(f"[smbus] read device {target_address:X} off {offset:X} = {valueH_R:X} {valueL_R:X}")
|
|
return [valueL_R, valueH_R]
|
|
|
|
|
|
class SMBusMMIO(SMBus):
|
|
def __init__(self, cs):
|
|
super(SMBusMMIO, self).__init__(cs)
|
|
|
|
def get_registers(self):
|
|
super(SMBusMMIO, self).get_registers()
|
|
self.smb_reg_status = self.cs.register.get_instance_by_name('8086.SMBUS.HST_STS_MMIO', self.instance)
|
|
self.smb_reg_control = self.cs.register.get_instance_by_name('8086.SMBUS.HST_CNT_MMIO', self.instance)
|
|
self.smb_reg_command = self.cs.register.get_instance_by_name('8086.SMBUS.HST_CMD_MMIO', self.instance)
|
|
self.smb_reg_address = self.cs.register.get_instance_by_name('8086.SMBUS.HST_SLVA_MMIO', self.instance)
|
|
self.smb_reg_data0 = self.cs.register.get_instance_by_name('8086.SMBUS.HST_D0_MMIO', self.instance)
|
|
self.smb_reg_data1 = self.cs.register.get_instance_by_name('8086.SMBUS.HST_D1_MMIO', self.instance)
|
|
self.smb_reg_aux_ctl = self.cs.register.get_instance_by_name('8086.SMBUS.HST_AUX_CTL_MMIO', self.instance)
|
|
self.smb_reg_block_db = self.cs.register.get_instance_by_name('8086.SMBUS.HST_BLOCK_DB_MMIO', self.instance)
|
|
|
|
def enable(self) -> None:
|
|
self.logger.log_hal("[SMBUSMMIO] Enabling SMBusMMIO...")
|
|
if not self.is_SMBus_mmio_mem_space_enabled():
|
|
self.logger.log_hal("SMBus mmio space disabled; enabling...")
|
|
self.enable_SMBus_mmio_mem_space()
|
|
else:
|
|
self.logger.log_hal("SMBus mmio space enabled...")
|
|
if not self.is_SMBus_host_controller_enabled():
|
|
self.logger.log_hal("SMBus disabled; enabling...")
|
|
self.enable_SMBus_host_controller()
|
|
if self.i2c_mode is True:
|
|
self.logger.log_hal("i2c mode is selected")
|
|
if not self.is_pch_i2c_enabled():
|
|
self.logger.log_hal("Intel PCH is not enabled to communicate with i2c devices; enabling...")
|
|
self.enable_pch_i2c_comm()
|
|
else:
|
|
self.logger.log_hal("SMBUS mode is selected. disabling i2c mode")
|
|
if self.is_pch_i2c_enabled():
|
|
self.logger.log_hal("Intel PCH is enabled to communicate with i2c devices; disabling...")
|
|
self.disable_pch_i2c_comm()
|
|
if not self.is_SMBus_io_mem_space_enabled():
|
|
self.logger.log_hal("SMBus io/mem space disabled; enabling...")
|
|
self.enable_SMBus_io_mem_space()
|
|
|
|
if not self.is_SMBus_host_controller_enabled():
|
|
self.logger.log_hal("SMBus disabled; enabling...")
|
|
self.enable_SMBus_host_controller()
|
|
self.logger.log_hal("[SMBUSMMIO] SMBusMMIO Enabled attempted")
|
|
|
|
def is_SMBus_mmio_mem_space_enabled(self):
|
|
cmd = self.smb_cmd.read()
|
|
self.logger.log_hal(self.smb_cmd)
|
|
return (cmd.value & 0x3) == 0x3
|
|
|
|
def get_SMBus_mmio_Base_Address(self):
|
|
if self.cs.hals.mmio.is_MMIO_BAR_defined('8086.SMBUS.SMBUS_MMIOBAR'):
|
|
(smb_mmio_base, _) = self.cs.hals.mmio.get_MMIO_BAR_base_address('8086.SMBUS.SMBUS_MMIOBAR', self.instance)
|
|
self.logger.log_hal(f"SMBUS MMIO base: 0x{smb_mmio_base:016X} (assuming below 4GB)")
|
|
return smb_mmio_base
|
|
else:
|
|
return False
|
|
|
|
def enable_SMBus_mmio_mem_space(self):
|
|
# @TODO: check SBA is programmed
|
|
# sba = self.get_SMBus_mmio_Base_Address()
|
|
# Enable SMBus I/O Space
|
|
cmd = self.smb_cmd.read()
|
|
if 0 == (cmd.value & 0x2):
|
|
self.smb_cmd.write(cmd.value | 0x2)
|
|
|
|
|
|
|
|
haldata = {"arch":[hal_base.HALBase.MfgIds.Any], 'name': {'smbus': "SMBus", 'smbusmmio': "SMBusMMIO"}}
|