mirror of
https://github.com/chipsec/chipsec
synced 2026-06-08 13:31:00 +00:00
Update Register objects
Signed-off-by: brentholtsclaw <brent.holtsclaw@intel.com>
This commit is contained in:
committed by
Nathaniel Mitchell
parent
513fa89384
commit
da143f80da
@@ -17,33 +17,200 @@
|
||||
# Contact information:
|
||||
# chipsec@intel.com
|
||||
|
||||
"""
|
||||
Control Register Helper configuration parser and accessor.
|
||||
|
||||
This module provides CONTROLHelper class for parsing and accessing control register fields
|
||||
in the CHIPSEC framework. Control helpers provide access to specific fields within registers.
|
||||
"""
|
||||
|
||||
from typing import Dict, Any, Optional
|
||||
from chipsec.parsers import BaseConfigHelper
|
||||
from chipsec.library.exceptions import CSConfigError
|
||||
|
||||
|
||||
class ControlHelperError(CSConfigError):
|
||||
"""Exception raised for control helper-specific errors."""
|
||||
pass
|
||||
|
||||
|
||||
class CONTROLHelper(BaseConfigHelper):
|
||||
def __init__(self, cfg_obj, reg_obj):
|
||||
super(CONTROLHelper, self).__init__(cfg_obj)
|
||||
self.name = cfg_obj['name']
|
||||
self.value = None
|
||||
self.desc = cfg_obj['desc']
|
||||
self.__reg = reg_obj
|
||||
self.instance = self.__reg.instance
|
||||
self.field = cfg_obj['field']
|
||||
"""
|
||||
Control Register Helper configuration parser and accessor.
|
||||
|
||||
def read(self):
|
||||
"""Read the object"""
|
||||
self.value = self.__reg.read_field(self.field)
|
||||
This class handles parsing and access to specific fields within registers,
|
||||
extending the base configuration helper with field-specific functionality.
|
||||
|
||||
Attributes:
|
||||
name (str): The name of the control
|
||||
desc (str): Description of the control
|
||||
value (Optional[int]): Current control field value
|
||||
field (str): Name of the register field
|
||||
instance (Optional[int]): Register instance identifier
|
||||
|
||||
Example:
|
||||
>>> control = CONTROLHelper(
|
||||
... {'name': 'LOCK_BIT', 'desc': 'Lock control bit', 'field': 'LOCK'},
|
||||
... register_object
|
||||
... )
|
||||
>>> value = control.read()
|
||||
"""
|
||||
|
||||
def __init__(self, cfg_obj: Dict[str, Any], reg_obj: Any) -> None:
|
||||
"""
|
||||
Initialize control helper configuration.
|
||||
|
||||
Args:
|
||||
cfg_obj: Dictionary containing control configuration data
|
||||
reg_obj: Register object that contains the field
|
||||
|
||||
Raises:
|
||||
ControlHelperError: If configuration validation fails
|
||||
"""
|
||||
try:
|
||||
super().__init__(cfg_obj)
|
||||
self.name = cfg_obj['name']
|
||||
self.value: Optional[int] = None
|
||||
self.desc = cfg_obj['desc']
|
||||
self.__reg = reg_obj
|
||||
self.instance = getattr(reg_obj, 'instance', None)
|
||||
self.field = cfg_obj['field']
|
||||
self._validate_control_config()
|
||||
except KeyError as e:
|
||||
raise ControlHelperError(f"Missing required field in control configuration: {e}") from e
|
||||
except Exception as e:
|
||||
raise ControlHelperError(f"Failed to initialize control helper configuration: {e}") from e
|
||||
|
||||
def _validate_control_config(self) -> None:
|
||||
"""
|
||||
Validate control helper-specific configuration requirements.
|
||||
|
||||
Raises:
|
||||
ControlHelperError: If configuration is invalid
|
||||
"""
|
||||
if not self.name:
|
||||
raise ControlHelperError("Control helper configuration must have a valid name")
|
||||
|
||||
if not self.field:
|
||||
raise ControlHelperError("Control helper configuration must have a valid field name")
|
||||
|
||||
if self.__reg is None:
|
||||
raise ControlHelperError("Control helper must have a valid register object")
|
||||
|
||||
# Verify that the register has the required field access methods
|
||||
if not hasattr(self.__reg, 'read_field') or not hasattr(self.__reg, 'write_field'):
|
||||
raise ControlHelperError("Register object must support field read/write operations")
|
||||
|
||||
def get_register_name(self) -> str:
|
||||
"""
|
||||
Get the name of the associated register.
|
||||
|
||||
Returns:
|
||||
Name of the register containing this control field
|
||||
"""
|
||||
return getattr(self.__reg, 'name', 'Unknown')
|
||||
|
||||
def get_field_name(self) -> str:
|
||||
"""
|
||||
Get the name of the register field.
|
||||
|
||||
Returns:
|
||||
Name of the register field
|
||||
"""
|
||||
return self.field
|
||||
|
||||
def get_register_object(self) -> Any:
|
||||
"""
|
||||
Get the associated register object.
|
||||
|
||||
Returns:
|
||||
Register object containing this control field
|
||||
"""
|
||||
return self.__reg
|
||||
|
||||
def is_field_available(self) -> bool:
|
||||
"""
|
||||
Check if the field is available in the register.
|
||||
|
||||
Returns:
|
||||
True if field is available, False otherwise
|
||||
"""
|
||||
try:
|
||||
# Try to check if the field exists in the register
|
||||
if hasattr(self.__reg, 'fields') and self.field in self.__reg.fields:
|
||||
return True
|
||||
# If we can't determine availability, assume it's available
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def read(self) -> int:
|
||||
"""
|
||||
Read the control field value.
|
||||
|
||||
Returns:
|
||||
Current field value
|
||||
|
||||
Raises:
|
||||
ControlHelperError: If read operation fails
|
||||
"""
|
||||
try:
|
||||
if not self.is_field_available():
|
||||
raise ControlHelperError(f"Field '{self.field}' not available in register '{self.get_register_name()}'")
|
||||
|
||||
self.value = self.__reg.read_field(self.field)
|
||||
return self.value
|
||||
except Exception as e:
|
||||
raise ControlHelperError(f"Failed to read control field '{self.field}' from register '{self.get_register_name()}': {e}") from e
|
||||
|
||||
def write(self, value: int) -> None:
|
||||
"""
|
||||
Write a value to the control field.
|
||||
|
||||
Args:
|
||||
value: Value to write to the field
|
||||
|
||||
Raises:
|
||||
ControlHelperError: If write operation fails
|
||||
"""
|
||||
try:
|
||||
if not self.is_field_available():
|
||||
raise ControlHelperError(f"Field '{self.field}' not available in register '{self.get_register_name()}'")
|
||||
|
||||
self.__reg.write_field(self.field, value)
|
||||
self.value = value
|
||||
except Exception as e:
|
||||
raise ControlHelperError(f"Failed to write to control field '{self.field}' in register '{self.get_register_name()}': {e}") from e
|
||||
|
||||
def get_current_value(self) -> Optional[int]:
|
||||
"""
|
||||
Get the current cached value without reading from hardware.
|
||||
|
||||
Returns:
|
||||
Current cached value, or None if not read yet
|
||||
"""
|
||||
return self.value
|
||||
|
||||
def write(self, value):
|
||||
"""Write the object"""
|
||||
self.__reg.write_field(self.field, value)
|
||||
|
||||
def get_register_name(self):
|
||||
return self.__reg.name
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"""Name {self.name}
|
||||
Register {self.__reg.name}
|
||||
Field {self.field}
|
||||
Value {self.value}"""
|
||||
"""
|
||||
String representation of control helper.
|
||||
|
||||
Returns:
|
||||
Formatted string with control details
|
||||
"""
|
||||
value_str = f"0x{self.value:X}" if self.value is not None else "Not Read"
|
||||
return (f"Control: {self.name}\n"
|
||||
f" Register: {self.get_register_name()}\n"
|
||||
f" Field: {self.field}\n"
|
||||
f" Value: {value_str}\n"
|
||||
f" Description: {self.desc}")
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""
|
||||
Detailed string representation for debugging.
|
||||
|
||||
Returns:
|
||||
Detailed string representation
|
||||
"""
|
||||
return (f"CONTROLHelper(name='{self.name}', field='{self.field}', "
|
||||
f"register='{self.get_register_name()}', value={self.value})")
|
||||
|
||||
@@ -17,52 +17,183 @@
|
||||
# Contact information:
|
||||
# chipsec@intel.com
|
||||
|
||||
"""
|
||||
I/O Register configuration parser and accessor.
|
||||
|
||||
This module provides IORegisters class for parsing and accessing I/O port-based registers
|
||||
in the CHIPSEC framework. I/O registers are accessed through CPU I/O port instructions.
|
||||
"""
|
||||
|
||||
from typing import Dict, Any
|
||||
from chipsec.library.register import BaseConfigRegisterHelper
|
||||
from chipsec.library.exceptions import CSConfigError
|
||||
from chipsec.chipset import cs
|
||||
|
||||
|
||||
class IORegisterError(CSConfigError):
|
||||
"""Exception raised for I/O register-specific errors."""
|
||||
pass
|
||||
|
||||
|
||||
class IORegisters(BaseConfigRegisterHelper):
|
||||
def __init__(self, cfg_obj):
|
||||
super(IORegisters, self).__init__(cfg_obj)
|
||||
self.io_port = cfg_obj['port']
|
||||
self.size = cfg_obj['size']
|
||||
self.bar_size = None
|
||||
"""
|
||||
I/O Register configuration parser and accessor.
|
||||
|
||||
This class handles parsing and access to I/O port-based registers, extending
|
||||
the base register helper with I/O-specific functionality.
|
||||
|
||||
Attributes:
|
||||
name (str): The name of the register
|
||||
desc (str): Description of the register
|
||||
io_port (int): I/O port address
|
||||
size (int): Size of the register in bytes
|
||||
value (Optional[int]): Current register value
|
||||
default (Optional[int]): Default register value
|
||||
bar_size (Optional[int]): BAR size (always None for I/O registers)
|
||||
|
||||
Example:
|
||||
>>> io_reg = IORegisters({'name': 'PM1_STS', 'port': 0x400, 'size': 2})
|
||||
>>> value = io_reg.read()
|
||||
"""
|
||||
|
||||
def __init__(self, cfg_obj: Dict[str, Any]) -> None:
|
||||
"""
|
||||
Initialize I/O register configuration.
|
||||
|
||||
Args:
|
||||
cfg_obj: Dictionary containing I/O register configuration data
|
||||
|
||||
Raises:
|
||||
IORegisterError: If configuration validation fails
|
||||
"""
|
||||
try:
|
||||
super().__init__(cfg_obj)
|
||||
self.io_port = cfg_obj['port']
|
||||
self.size = cfg_obj['size']
|
||||
self.bar_size = None # I/O registers don't have BAR size
|
||||
self._validate_io_config()
|
||||
except KeyError as e:
|
||||
raise IORegisterError(f"Missing required field in I/O register configuration: {e}") from e
|
||||
except Exception as e:
|
||||
raise IORegisterError(f"Failed to initialize I/O register configuration: {e}") from e
|
||||
|
||||
def _validate_io_config(self) -> None:
|
||||
"""
|
||||
Validate I/O register-specific configuration requirements.
|
||||
|
||||
Raises:
|
||||
IORegisterError: If configuration is invalid
|
||||
"""
|
||||
if not self.name:
|
||||
raise IORegisterError("I/O register configuration must have a valid name")
|
||||
|
||||
if not isinstance(self.io_port, int) or self.io_port < 0 or self.io_port > 0xFFFF:
|
||||
raise IORegisterError(f"Invalid I/O port: {self.io_port}. Must be 0-65535 range")
|
||||
|
||||
if not isinstance(self.size, int) or self.size not in [1, 2, 4]:
|
||||
raise IORegisterError(f"Invalid register size: {self.size}. Must be 1, 2, or 4 bytes")
|
||||
|
||||
def get_port_address(self) -> int:
|
||||
"""
|
||||
Get the I/O port address.
|
||||
|
||||
Returns:
|
||||
I/O port address as integer
|
||||
"""
|
||||
return self.io_port
|
||||
|
||||
def get_port_hex(self) -> str:
|
||||
"""
|
||||
Get the I/O port address as hexadecimal string.
|
||||
|
||||
Returns:
|
||||
I/O port address as hex string (e.g., '0x400')
|
||||
"""
|
||||
return f"0x{self.io_port:X}"
|
||||
|
||||
def is_valid_port(self) -> bool:
|
||||
"""
|
||||
Check if the I/O port address is valid.
|
||||
|
||||
Returns:
|
||||
True if port is valid, False otherwise
|
||||
"""
|
||||
return isinstance(self.io_port, int) and 0 <= self.io_port <= 0xFFFF
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""
|
||||
Detailed string representation for debugging.
|
||||
|
||||
Returns:
|
||||
Formatted string with register details including fields
|
||||
"""
|
||||
reg_str = ''
|
||||
if self.value is not None:
|
||||
reg_val_str = f'0x{self.value:0{self.size * 2}X}'
|
||||
else:
|
||||
reg_val_str = self.value
|
||||
reg_val_str = str(self.value)
|
||||
|
||||
if self.default is not None:
|
||||
default = f'{self.default:X}'
|
||||
else:
|
||||
default = 'Not Provided'
|
||||
reg_str = f'[*] {self.name} = {reg_val_str} << {self.desc} (I/O port 0x{self.io_port:X}) [default: {default}]'
|
||||
|
||||
reg_str = (f'[*] {self.name} = {reg_val_str} << {self.desc} '
|
||||
f'(I/O port 0x{self.io_port:X}) [default: {default}]')
|
||||
|
||||
reg_str += self._register_fields_str(True)
|
||||
return reg_str
|
||||
|
||||
def __str__(self) -> str:
|
||||
"""
|
||||
String representation of I/O register.
|
||||
|
||||
Returns:
|
||||
Formatted string with register details
|
||||
"""
|
||||
reg_str = ''
|
||||
if self.value is not None:
|
||||
reg_val_str = f'0x{self.value:0{self.size * 2}X}'
|
||||
else:
|
||||
reg_val_str = self.value
|
||||
reg_val_str = str(self.value)
|
||||
|
||||
reg_str = f'[*] {self.name} = {reg_val_str} << {self.desc} (I/O port 0x{self.io_port:X})'
|
||||
|
||||
reg_str += self._register_fields_str()
|
||||
return reg_str
|
||||
|
||||
def read(self):
|
||||
"""Read the object"""
|
||||
self.logger.log_debug(f'reading {self.name}')
|
||||
_cs = cs()
|
||||
self.value = _cs.hals.Io.read(self.io_port, self.size)
|
||||
return self.value
|
||||
def read(self) -> int:
|
||||
"""
|
||||
Read the I/O register value.
|
||||
|
||||
def write(self, value):
|
||||
"""Write the object"""
|
||||
_cs = cs()
|
||||
_cs.hals.Io.write(self.io_port, value, self.size)
|
||||
Returns:
|
||||
Current register value
|
||||
|
||||
Raises:
|
||||
IORegisterError: If read operation fails
|
||||
"""
|
||||
try:
|
||||
self.logger.log_debug(f'reading {self.name}')
|
||||
_cs = cs()
|
||||
self.value = _cs.hals.Io.read(self.io_port, self.size)
|
||||
return self.value
|
||||
except Exception as e:
|
||||
raise IORegisterError(f"Failed to read I/O register {self.name} at port 0x{self.io_port:X}: {e}") from e
|
||||
|
||||
def write(self, value: int) -> None:
|
||||
"""
|
||||
Write a value to the I/O register.
|
||||
|
||||
Args:
|
||||
value: Value to write to the register
|
||||
|
||||
Raises:
|
||||
IORegisterError: If write operation fails
|
||||
"""
|
||||
try:
|
||||
self.logger.log_debug(f'writing 0x{value:X} to {self.name}')
|
||||
_cs = cs()
|
||||
_cs.hals.Io.write(self.io_port, value, self.size)
|
||||
self.value = value
|
||||
except Exception as e:
|
||||
raise IORegisterError(f"Failed to write to I/O register {self.name} at port 0x{self.io_port:X}: {e}") from e
|
||||
|
||||
@@ -17,42 +17,189 @@
|
||||
# Contact information:
|
||||
# chipsec@intel.com
|
||||
|
||||
"""
|
||||
I/O BAR Register configuration parser and accessor.
|
||||
|
||||
This module provides IOBARRegisters class for parsing and accessing I/O Base Address Register (BAR) registers
|
||||
in the CHIPSEC framework. I/O BAR registers provide access to device registers through I/O port spaces.
|
||||
"""
|
||||
|
||||
from typing import Dict, Any, Optional, Tuple
|
||||
from chipsec.library.register import BaseConfigRegisterHelper
|
||||
from chipsec.library.exceptions import CSConfigError
|
||||
from chipsec.chipset import cs
|
||||
|
||||
|
||||
class IOBARRegisterError(CSConfigError):
|
||||
"""Exception raised for I/O BAR register-specific errors."""
|
||||
pass
|
||||
|
||||
|
||||
class IOBARRegisters(BaseConfigRegisterHelper):
|
||||
def __init__(self, cfg_obj):
|
||||
super(IOBARRegisters, self).__init__(cfg_obj)
|
||||
self.size = cfg_obj['size']
|
||||
self.offset = cfg_obj['offset']
|
||||
self.bar = cfg_obj['bar']
|
||||
self.bar_base = None
|
||||
self.bar_size = None
|
||||
self.io_port = None
|
||||
"""
|
||||
I/O BAR Register configuration parser and accessor.
|
||||
|
||||
This class handles parsing and access to I/O Base Address Register (BAR) registers,
|
||||
extending the base register helper with I/O BAR-specific functionality.
|
||||
|
||||
Attributes:
|
||||
name (str): The name of the register
|
||||
desc (str): Description of the register
|
||||
size (int): Size of the register in bytes
|
||||
offset (int): Offset within the I/O BAR
|
||||
bar (str): BAR identifier or name
|
||||
bar_base (Optional[int]): Base address of the I/O BAR
|
||||
bar_size (Optional[int]): Size of the I/O BAR
|
||||
io_port (Optional[int]): Effective I/O port address
|
||||
value (Optional[int]): Current register value
|
||||
default (Optional[int]): Default register value
|
||||
|
||||
Example:
|
||||
>>> iobar_reg = IOBARRegisters({
|
||||
... 'name': 'CMD_REG', 'size': 4, 'offset': 0x04, 'bar': 'BAR0',
|
||||
... 'FIELDS': {}
|
||||
... })
|
||||
>>> value = iobar_reg.read()
|
||||
"""
|
||||
|
||||
def __init__(self, cfg_obj: Dict[str, Any]) -> None:
|
||||
"""
|
||||
Initialize I/O BAR register configuration.
|
||||
|
||||
Args:
|
||||
cfg_obj: Dictionary containing I/O BAR register configuration data
|
||||
|
||||
Raises:
|
||||
IOBARRegisterError: If configuration validation fails
|
||||
"""
|
||||
try:
|
||||
super().__init__(cfg_obj)
|
||||
self.size = cfg_obj['size']
|
||||
self.offset = cfg_obj['offset']
|
||||
self.bar = cfg_obj['bar']
|
||||
self.bar_base: Optional[int] = None
|
||||
self.bar_size: Optional[int] = None
|
||||
self.io_port: Optional[int] = None
|
||||
self._validate_iobar_config()
|
||||
except KeyError as e:
|
||||
raise IOBARRegisterError(f"Missing required field in I/O BAR register configuration: {e}") from e
|
||||
except Exception as e:
|
||||
raise IOBARRegisterError(f"Failed to initialize I/O BAR register configuration: {e}") from e
|
||||
|
||||
def _validate_iobar_config(self) -> None:
|
||||
"""
|
||||
Validate I/O BAR register-specific configuration requirements.
|
||||
|
||||
Raises:
|
||||
IOBARRegisterError: If configuration is invalid
|
||||
"""
|
||||
if not self.name:
|
||||
raise IOBARRegisterError("I/O BAR register configuration must have a valid name")
|
||||
|
||||
if not isinstance(self.size, int) or self.size not in [1, 2, 4, 8]:
|
||||
raise IOBARRegisterError(f"Invalid register size: {self.size}. Must be 1, 2, 4, or 8 bytes")
|
||||
|
||||
if not isinstance(self.offset, int) or self.offset < 0:
|
||||
raise IOBARRegisterError(f"Invalid offset: {self.offset}. Must be a non-negative integer")
|
||||
|
||||
if not self.bar:
|
||||
raise IOBARRegisterError("I/O BAR register configuration must have a valid BAR identifier")
|
||||
|
||||
def get_bar_info(self) -> Tuple[Optional[int], Optional[int]]:
|
||||
"""
|
||||
Get BAR base address and size information.
|
||||
|
||||
Returns:
|
||||
Tuple of (base_address, size) or (None, None) if not available
|
||||
"""
|
||||
return (self.bar_base, self.bar_size)
|
||||
|
||||
def get_effective_port(self) -> Optional[int]:
|
||||
"""
|
||||
Get the effective I/O port address.
|
||||
|
||||
Returns:
|
||||
Effective I/O port address, or None if not computed yet
|
||||
"""
|
||||
return self.io_port
|
||||
|
||||
def get_effective_port_hex(self) -> str:
|
||||
"""
|
||||
Get the effective I/O port address as hexadecimal string.
|
||||
|
||||
Returns:
|
||||
Effective I/O port address as hex string, or 'Unknown' if not available
|
||||
"""
|
||||
return f"0x{self.io_port:X}" if self.io_port is not None else "Unknown"
|
||||
|
||||
def is_bar_resolved(self) -> bool:
|
||||
"""
|
||||
Check if the BAR has been resolved to a base address.
|
||||
|
||||
Returns:
|
||||
True if BAR base address is available, False otherwise
|
||||
"""
|
||||
return self.bar_base is not None
|
||||
|
||||
def is_valid_port(self) -> bool:
|
||||
"""
|
||||
Check if the effective port address is valid for I/O operations.
|
||||
|
||||
Returns:
|
||||
True if port address is valid, False otherwise
|
||||
"""
|
||||
return self.io_port is not None and 0 <= self.io_port <= 0xFFFF
|
||||
|
||||
def _resolve_bar_address(self) -> None:
|
||||
"""
|
||||
Resolve the BAR base address using CHIPSEC HAL.
|
||||
|
||||
Raises:
|
||||
IOBARRegisterError: If BAR resolution fails
|
||||
"""
|
||||
try:
|
||||
_cs = cs()
|
||||
(self.bar_base, self.bar_size) = _cs.hals.IOBAR.get_IO_BAR_base_address(self.bar, self.get_instance())
|
||||
self.io_port = self.bar_base + self.offset
|
||||
except Exception as e:
|
||||
raise IOBARRegisterError(f"Failed to resolve BAR {self.bar} for register {self.name}: {e}") from e
|
||||
|
||||
def __repr__(self) -> str:
|
||||
reg_str = ''
|
||||
"""
|
||||
Detailed string representation for debugging.
|
||||
|
||||
Returns:
|
||||
Formatted string with register details including fields
|
||||
"""
|
||||
if self.value is not None:
|
||||
reg_val_str = f'0x{self.value:0{self.size * 2}X}'
|
||||
else:
|
||||
reg_val_str = self.value
|
||||
reg_val_str = str(self.value)
|
||||
|
||||
instance = f'{self.instance}' if self.instance is not None else 'Fixed'
|
||||
|
||||
if self.default is not None:
|
||||
default = f'{self.default:X}'
|
||||
else:
|
||||
default = 'Not Provided'
|
||||
reg_str = f'[*] {self.name} = {reg_val_str} << {self.desc} ({self.bar} + 0x{self.offset:X} Bus {instance}) [default: {default}]'
|
||||
|
||||
reg_str = (f'[*] {self.name} = {reg_val_str} << {self.desc} '
|
||||
f'({self.bar} + 0x{self.offset:X} Bus {instance}) [default: {default}]')
|
||||
|
||||
reg_str += self._register_fields_str(True)
|
||||
return reg_str
|
||||
|
||||
def __str__(self) -> str:
|
||||
reg_str = ''
|
||||
"""
|
||||
String representation of I/O BAR register.
|
||||
|
||||
Returns:
|
||||
Formatted string with register details
|
||||
"""
|
||||
if self.value is not None:
|
||||
reg_val_str = f'0x{self.value:0{self.size * 2}X}'
|
||||
else:
|
||||
reg_val_str = self.value
|
||||
reg_val_str = str(self.value)
|
||||
|
||||
instance = f'{self.instance}' if self.instance is not None else 'Fixed'
|
||||
reg_str = f'[*] {self.name} = {reg_val_str} << {self.desc} ({self.bar} + 0x{self.offset:X} Bus {instance})'
|
||||
@@ -60,21 +207,57 @@ class IOBARRegisters(BaseConfigRegisterHelper):
|
||||
reg_str += self._register_fields_str()
|
||||
return reg_str
|
||||
|
||||
def read(self):
|
||||
"""Read the object"""
|
||||
self.logger.log_debug(f'reading {self.name}')
|
||||
_cs = cs()
|
||||
if self.io_port is None:
|
||||
(self.bar_base, self.bar_size) = _cs.hals.IOBAR.get_IO_BAR_base_address(self.bar, self.get_instance())
|
||||
self.io_port = self.bar_base + self.offset
|
||||
self.value = _cs.hals.Io.read(self.io_port, self.size)
|
||||
self.logger.log_debug('done reading')
|
||||
return self.value
|
||||
def read(self) -> int:
|
||||
"""
|
||||
Read the I/O BAR register value.
|
||||
|
||||
def write(self, value):
|
||||
"""Write the object"""
|
||||
_cs = cs()
|
||||
if self.io_port is None:
|
||||
(self.bar_base, self.bar_size) = _cs.hals.IOBAR.get_IO_BAR_base_address(self.bar, self.get_instance())
|
||||
self.io_port = self.bar_base + self.offset
|
||||
_cs.hals.Io.write(self.io_port, value, self.size)
|
||||
Returns:
|
||||
Current register value
|
||||
|
||||
Raises:
|
||||
IOBARRegisterError: If read operation fails
|
||||
"""
|
||||
try:
|
||||
self.logger.log_debug(f'reading {self.name}')
|
||||
|
||||
# Resolve BAR address if not already done
|
||||
if self.io_port is None:
|
||||
self._resolve_bar_address()
|
||||
|
||||
if not self.is_valid_port():
|
||||
raise IOBARRegisterError(f"Invalid I/O port for register {self.name}: {self.get_effective_port_hex()}")
|
||||
|
||||
_cs = cs()
|
||||
self.value = _cs.hals.Io.read(self.io_port, self.size)
|
||||
self.logger.log_debug('done reading')
|
||||
|
||||
return self.value
|
||||
except Exception as e:
|
||||
raise IOBARRegisterError(f"Failed to read I/O BAR register {self.name}: {e}") from e
|
||||
|
||||
def write(self, value: int) -> None:
|
||||
"""
|
||||
Write a value to the I/O BAR register.
|
||||
|
||||
Args:
|
||||
value: Value to write to the register
|
||||
|
||||
Raises:
|
||||
IOBARRegisterError: If write operation fails
|
||||
"""
|
||||
try:
|
||||
self.logger.log_debug(f'writing 0x{value:X} to {self.name}')
|
||||
|
||||
# Resolve BAR address if not already done
|
||||
if self.io_port is None:
|
||||
self._resolve_bar_address()
|
||||
|
||||
if not self.is_valid_port():
|
||||
raise IOBARRegisterError(f"Invalid I/O port for register {self.name}: {self.get_effective_port_hex()}")
|
||||
|
||||
_cs = cs()
|
||||
_cs.hals.Io.write(self.io_port, value, self.size)
|
||||
self.value = value
|
||||
|
||||
except Exception as e:
|
||||
raise IOBARRegisterError(f"Failed to write to I/O BAR register {self.name}: {e}") from e
|
||||
|
||||
@@ -17,17 +17,212 @@
|
||||
# Contact information:
|
||||
# chipsec@intel.com
|
||||
|
||||
"""
|
||||
Lock Register Helper configuration parser and accessor.
|
||||
|
||||
This module provides LOCKSHelper class for parsing and managing lock register configurations
|
||||
in the CHIPSEC framework. Lock helpers provide access to lock bits and dependency management.
|
||||
"""
|
||||
|
||||
from typing import Optional
|
||||
from collections import namedtuple
|
||||
from chipsec.library.exceptions import CSConfigError
|
||||
|
||||
|
||||
class LockHelperError(CSConfigError):
|
||||
"""Exception raised for lock helper-specific errors."""
|
||||
pass
|
||||
|
||||
|
||||
class LOCKSHelper(namedtuple('LocksHelper', 'register field attributes lock_value dependency dependency_value')):
|
||||
"""
|
||||
Lock Register Helper configuration parser and accessor.
|
||||
|
||||
This class handles parsing and access to lock register configurations, providing
|
||||
functionality for lock bit management and dependency tracking.
|
||||
|
||||
Attributes:
|
||||
register (str): Name of the register containing the lock
|
||||
field (str): Name of the field within the register
|
||||
attributes (str): Access attributes for the lock
|
||||
lock_value (Optional[int]): Value that indicates locked state
|
||||
dependency (Optional[str]): Name of dependency register/field
|
||||
dependency_value (Optional[int]): Value of dependency that enables this lock
|
||||
|
||||
Example:
|
||||
>>> lock = LOCKSHelper(
|
||||
... register='CONTROL_REG',
|
||||
... field='LOCK_BIT',
|
||||
... attributes='RW1S',
|
||||
... lock_value=1,
|
||||
... dependency=None,
|
||||
... dependency_value=None
|
||||
... )
|
||||
>>> print(lock.has_lock_value())
|
||||
True
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
def has_lock_value(self):
|
||||
def has_lock_value(self) -> bool:
|
||||
"""
|
||||
Check if this lock has a defined lock value.
|
||||
|
||||
Returns:
|
||||
True if lock_value is defined, False otherwise
|
||||
"""
|
||||
return self.lock_value is not None
|
||||
|
||||
def is_access_type(self, attributes):
|
||||
def is_access_type(self, attributes: str) -> bool:
|
||||
"""
|
||||
Check if this lock matches the specified access attributes.
|
||||
|
||||
Args:
|
||||
attributes: Access attributes to check against
|
||||
|
||||
Returns:
|
||||
True if attributes match, False otherwise
|
||||
"""
|
||||
return self.attributes == attributes
|
||||
|
||||
def has_dependency(self) -> bool:
|
||||
"""
|
||||
Check if this lock has a dependency.
|
||||
|
||||
Returns:
|
||||
True if dependency is defined, False otherwise
|
||||
"""
|
||||
return self.dependency is not None
|
||||
|
||||
def has_dependency_value(self) -> bool:
|
||||
"""
|
||||
Check if this lock has a dependency value defined.
|
||||
|
||||
Returns:
|
||||
True if dependency_value is defined, False otherwise
|
||||
"""
|
||||
return self.dependency_value is not None
|
||||
|
||||
def is_read_only(self) -> bool:
|
||||
"""
|
||||
Check if this lock is read-only.
|
||||
|
||||
Returns:
|
||||
True if attributes indicate read-only access
|
||||
"""
|
||||
return self.attributes in ['RO', 'ROS']
|
||||
|
||||
def is_write_once(self) -> bool:
|
||||
"""
|
||||
Check if this lock is write-once (write 1 to set).
|
||||
|
||||
Returns:
|
||||
True if attributes indicate write-once behavior
|
||||
"""
|
||||
return self.attributes in ['RW1S', 'WO1S']
|
||||
|
||||
def is_clearable(self) -> bool:
|
||||
"""
|
||||
Check if this lock can be cleared.
|
||||
|
||||
Returns:
|
||||
True if attributes allow clearing the lock
|
||||
"""
|
||||
return self.attributes in ['RW', 'RW1C', 'WO1C']
|
||||
|
||||
def get_lock_info(self) -> dict:
|
||||
"""
|
||||
Get comprehensive lock information.
|
||||
|
||||
Returns:
|
||||
Dictionary containing lock configuration details
|
||||
"""
|
||||
return {
|
||||
'register': self.register,
|
||||
'field': self.field,
|
||||
'attributes': self.attributes,
|
||||
'lock_value': self.lock_value,
|
||||
'dependency': self.dependency,
|
||||
'dependency_value': self.dependency_value,
|
||||
'has_lock_value': self.has_lock_value(),
|
||||
'has_dependency': self.has_dependency(),
|
||||
'is_read_only': self.is_read_only(),
|
||||
'is_write_once': self.is_write_once(),
|
||||
'is_clearable': self.is_clearable()
|
||||
}
|
||||
|
||||
def __str__(self) -> str:
|
||||
return super().__str__()
|
||||
"""
|
||||
String representation of lock helper.
|
||||
|
||||
Returns:
|
||||
Formatted string with lock details
|
||||
"""
|
||||
parts = [f"Lock: {self.register}.{self.field}"]
|
||||
parts.append(f"Attributes: {self.attributes}")
|
||||
|
||||
if self.has_lock_value():
|
||||
parts.append(f"Lock Value: 0x{self.lock_value:X}")
|
||||
|
||||
if self.has_dependency():
|
||||
dep_str = f"Dependency: {self.dependency}"
|
||||
if self.has_dependency_value():
|
||||
dep_str += f" = 0x{self.dependency_value:X}"
|
||||
parts.append(dep_str)
|
||||
|
||||
return f"LOCKSHelper({', '.join(parts)})"
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""
|
||||
Detailed string representation for debugging.
|
||||
|
||||
Returns:
|
||||
Detailed string representation
|
||||
"""
|
||||
return (f"LOCKSHelper(register='{self.register}', field='{self.field}', "
|
||||
f"attributes='{self.attributes}', lock_value={self.lock_value}, "
|
||||
f"dependency={self.dependency}, dependency_value={self.dependency_value})")
|
||||
|
||||
|
||||
def create_lock_helper(register: str, field: str, attributes: str,
|
||||
lock_value: Optional[int] = None,
|
||||
dependency: Optional[str] = None,
|
||||
dependency_value: Optional[int] = None) -> LOCKSHelper:
|
||||
"""
|
||||
Create a LOCKSHelper instance with validation.
|
||||
|
||||
Args:
|
||||
register: Name of the register containing the lock
|
||||
field: Name of the field within the register
|
||||
attributes: Access attributes for the lock
|
||||
lock_value: Value that indicates locked state
|
||||
dependency: Name of dependency register/field
|
||||
dependency_value: Value of dependency that enables this lock
|
||||
|
||||
Returns:
|
||||
LOCKSHelper instance
|
||||
|
||||
Raises:
|
||||
LockHelperError: If configuration is invalid
|
||||
"""
|
||||
if not register:
|
||||
raise LockHelperError("Register name cannot be empty")
|
||||
|
||||
if not field:
|
||||
raise LockHelperError("Field name cannot be empty")
|
||||
|
||||
if not attributes:
|
||||
raise LockHelperError("Attributes cannot be empty")
|
||||
|
||||
valid_attributes = ['RO', 'RW', 'ROS', 'RW1S', 'RW1C', 'WO1S', 'WO1C']
|
||||
if attributes not in valid_attributes:
|
||||
raise LockHelperError(f"Invalid attributes '{attributes}'. Must be one of: {', '.join(valid_attributes)}")
|
||||
|
||||
return LOCKSHelper(
|
||||
register=register,
|
||||
field=field,
|
||||
attributes=attributes,
|
||||
lock_value=lock_value,
|
||||
dependency=dependency,
|
||||
dependency_value=dependency_value
|
||||
)
|
||||
|
||||
@@ -17,62 +17,222 @@
|
||||
# Contact information:
|
||||
# chipsec@intel.com
|
||||
|
||||
"""
|
||||
Memory Register configuration parser and accessor.
|
||||
|
||||
This module provides MEMORYRegisters class for parsing and accessing memory-mapped registers
|
||||
in the CHIPSEC framework. Memory registers can be accessed through DRAM or MMIO methods.
|
||||
"""
|
||||
|
||||
from typing import Dict, Any
|
||||
from chipsec.library.exceptions import CSConfigError
|
||||
from chipsec.library.register import BaseConfigRegisterHelper
|
||||
from chipsec.chipset import cs
|
||||
|
||||
|
||||
class MemoryRegisterError(CSConfigError):
|
||||
"""Exception raised for memory register-specific errors."""
|
||||
pass
|
||||
|
||||
|
||||
class MEMORYRegisters(BaseConfigRegisterHelper):
|
||||
def __init__(self, cfg_obj):
|
||||
super(MEMORYRegisters, self).__init__(cfg_obj)
|
||||
self.offset = cfg_obj['offset']
|
||||
self.range = cfg_obj['range']
|
||||
self.size = cfg_obj['size']
|
||||
self.address = cfg_obj['address']
|
||||
self.limit = cfg_obj['limit']
|
||||
self.access = cfg_obj['access']
|
||||
"""
|
||||
Memory Register configuration parser and accessor.
|
||||
|
||||
This class handles parsing and access to memory-mapped registers, extending
|
||||
the base register helper with memory-specific functionality including both
|
||||
DRAM and MMIO access methods.
|
||||
|
||||
Attributes:
|
||||
name (str): The name of the register
|
||||
desc (str): Description of the register
|
||||
offset (int): Offset within the memory range
|
||||
range (int): Memory range identifier
|
||||
size (int): Size of the register in bytes
|
||||
address (int): Base memory address
|
||||
limit (int): Memory limit
|
||||
access (str): Access method ('dram' or 'mmio')
|
||||
value (int): Current register value
|
||||
default (int): Default register value
|
||||
|
||||
Example:
|
||||
>>> mem_reg = MEMORYRegisters({
|
||||
... 'name': 'TOLUD', 'address': 0xFED00000, 'offset': 0x100,
|
||||
... 'size': 4, 'access': 'mmio'
|
||||
... })
|
||||
>>> value = mem_reg.read()
|
||||
"""
|
||||
|
||||
def __init__(self, cfg_obj: Dict[str, Any]) -> None:
|
||||
"""
|
||||
Initialize memory register configuration.
|
||||
|
||||
Args:
|
||||
cfg_obj: Dictionary containing memory register configuration data
|
||||
|
||||
Raises:
|
||||
MemoryRegisterError: If configuration validation fails
|
||||
"""
|
||||
try:
|
||||
super().__init__(cfg_obj)
|
||||
self.offset = cfg_obj['offset']
|
||||
self.range = cfg_obj['range']
|
||||
self.size = cfg_obj['size']
|
||||
self.address = cfg_obj['address']
|
||||
self.limit = cfg_obj['limit']
|
||||
self.access = cfg_obj['access']
|
||||
self._validate_memory_config()
|
||||
except KeyError as e:
|
||||
raise MemoryRegisterError(f"Missing required field in memory register configuration: {e}") from e
|
||||
except Exception as e:
|
||||
raise MemoryRegisterError(f"Failed to initialize memory register configuration: {e}") from e
|
||||
|
||||
def _validate_memory_config(self) -> None:
|
||||
"""
|
||||
Validate memory register-specific configuration requirements.
|
||||
|
||||
Raises:
|
||||
MemoryRegisterError: If configuration is invalid
|
||||
"""
|
||||
if not self.name:
|
||||
raise MemoryRegisterError("Memory register configuration must have a valid name")
|
||||
|
||||
if not isinstance(self.address, int) or self.address < 0:
|
||||
raise MemoryRegisterError(f"Invalid address: {self.address}. Must be a positive integer")
|
||||
|
||||
if not isinstance(self.offset, int) or self.offset < 0:
|
||||
raise MemoryRegisterError(f"Invalid offset: {self.offset}. Must be a non-negative integer")
|
||||
|
||||
if not isinstance(self.size, int) or self.size not in [1, 2, 4, 8]:
|
||||
raise MemoryRegisterError(f"Invalid register size: {self.size}. Must be 1, 2, 4, or 8 bytes")
|
||||
|
||||
if self.access not in ['dram', 'mmio']:
|
||||
raise MemoryRegisterError(f"Invalid access method: {self.access}. Must be 'dram' or 'mmio'")
|
||||
|
||||
def get_physical_address(self) -> int:
|
||||
"""
|
||||
Get the physical memory address (base + offset).
|
||||
|
||||
Returns:
|
||||
Physical memory address as integer
|
||||
"""
|
||||
return self.address + self.offset
|
||||
|
||||
def get_address_hex(self) -> str:
|
||||
"""
|
||||
Get the physical memory address as hexadecimal string.
|
||||
|
||||
Returns:
|
||||
Physical memory address as hex string (e.g., '0xFED00100')
|
||||
"""
|
||||
return f"0x{self.get_physical_address():X}"
|
||||
|
||||
def is_dram_access(self) -> bool:
|
||||
"""
|
||||
Check if this register uses DRAM access method.
|
||||
|
||||
Returns:
|
||||
True if access method is 'dram', False otherwise
|
||||
"""
|
||||
return self.access == 'dram'
|
||||
|
||||
def is_mmio_access(self) -> bool:
|
||||
"""
|
||||
Check if this register uses MMIO access method.
|
||||
|
||||
Returns:
|
||||
True if access method is 'mmio', False otherwise
|
||||
"""
|
||||
return self.access == 'mmio'
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""
|
||||
Detailed string representation for debugging.
|
||||
|
||||
Returns:
|
||||
Formatted string with register details including fields
|
||||
"""
|
||||
reg_str = ''
|
||||
if self.value is not None:
|
||||
reg_val_str = f'0x{self.value:08X}'
|
||||
else:
|
||||
reg_val_str = self.value
|
||||
reg_val_str = str(self.value)
|
||||
|
||||
if self.default is not None:
|
||||
default = f'{self.default:X}'
|
||||
else:
|
||||
default = 'Not Provided'
|
||||
reg_str = f'[*] {self.name} = {reg_val_str} << {self.desc} (0x{self.address:X} + 0x{self.offset:X}) [default: {default}]'
|
||||
|
||||
reg_str = (f'[*] {self.name} = {reg_val_str} << {self.desc} '
|
||||
f'(0x{self.address:X} + 0x{self.offset:X}) [default: {default}]')
|
||||
|
||||
reg_str += self._register_fields_str(True)
|
||||
return reg_str
|
||||
|
||||
def __str__(self) -> str:
|
||||
"""
|
||||
String representation of memory register.
|
||||
|
||||
Returns:
|
||||
Formatted string with register details
|
||||
"""
|
||||
reg_str = ''
|
||||
if self.value is not None:
|
||||
reg_val_str = f'0x{self.value:08X}'
|
||||
else:
|
||||
reg_val_str = self.value
|
||||
reg_val_str = str(self.value)
|
||||
|
||||
reg_str = f'[*] {self.name} = {reg_val_str} << {self.desc} (0x{self.address:X} + 0x{self.offset:X})'
|
||||
|
||||
reg_str += self._register_fields_str()
|
||||
return reg_str
|
||||
|
||||
def read(self):
|
||||
"""Read the object"""
|
||||
self.logger.log_debug(f'reading {self.name}')
|
||||
_cs = cs()
|
||||
if self.access == 'dram':
|
||||
self.value = _cs.hals.MemRange.read(self.address + self.offset, self.size)
|
||||
elif self.access == 'mmio':
|
||||
self.value = _cs.hals.MMIO.read_MMIO_reg(self.address, self.offset, self.size)
|
||||
return self.value
|
||||
def read(self) -> int:
|
||||
"""
|
||||
Read the memory register value.
|
||||
|
||||
def write(self, value):
|
||||
"""Write the object"""
|
||||
_cs = cs()
|
||||
if self.access == 'dram':
|
||||
_cs = _cs.hals.Memory.write_physical_mem(self.address + self.offset, self.size, value)
|
||||
elif self.access == 'mmio':
|
||||
_cs.hals.MMIO.write_MMIO_reg(self.address, self.offset, value, self.size, None)
|
||||
Returns:
|
||||
Current register value
|
||||
|
||||
Raises:
|
||||
MemoryRegisterError: If read operation fails
|
||||
"""
|
||||
try:
|
||||
self.logger.log_debug(f'reading {self.name}')
|
||||
_cs = cs()
|
||||
|
||||
if self.access == 'dram':
|
||||
self.value = _cs.hals.MemRange.read(self.address + self.offset, self.size)
|
||||
elif self.access == 'mmio':
|
||||
self.value = _cs.hals.MMIO.read_MMIO_reg(self.address, self.offset, self.size)
|
||||
else:
|
||||
raise MemoryRegisterError(f"Unsupported access method: {self.access}")
|
||||
|
||||
return self.value
|
||||
except Exception as e:
|
||||
raise MemoryRegisterError(f"Failed to read memory register {self.name} at {self.get_address_hex()}: {e}") from e
|
||||
|
||||
def write(self, value: int) -> None:
|
||||
"""
|
||||
Write a value to the memory register.
|
||||
|
||||
Args:
|
||||
value: Value to write to the register
|
||||
|
||||
Raises:
|
||||
MemoryRegisterError: If write operation fails
|
||||
"""
|
||||
try:
|
||||
self.logger.log_debug(f'writing 0x{value:X} to {self.name}')
|
||||
_cs = cs()
|
||||
|
||||
if self.access == 'dram':
|
||||
_cs.hals.Memory.write_physical_mem(self.address + self.offset, self.size, value)
|
||||
elif self.access == 'mmio':
|
||||
_cs.hals.MMIO.write_MMIO_reg(self.address, self.offset, value, self.size, None)
|
||||
else:
|
||||
raise MemoryRegisterError(f"Unsupported access method: {self.access}")
|
||||
|
||||
self.value = value
|
||||
except Exception as e:
|
||||
raise MemoryRegisterError(f"Failed to write to memory register {self.name} at {self.get_address_hex()}: {e}") from e
|
||||
|
||||
@@ -17,56 +17,197 @@
|
||||
# Contact information:
|
||||
# chipsec@intel.com
|
||||
|
||||
"""
|
||||
MM_MSGBUS Register configuration parser and accessor.
|
||||
|
||||
This module provides MM_MSGBUSRegisters class for parsing and accessing memory-mapped message bus registers
|
||||
in the CHIPSEC framework. MM_MSGBUS registers provide access to various hardware interfaces through
|
||||
memory-mapped message bus protocols.
|
||||
"""
|
||||
|
||||
from typing import Dict, Any
|
||||
from chipsec.library.register import BaseConfigRegisterHelper
|
||||
from chipsec.library.exceptions import CSConfigError
|
||||
from chipsec.chipset import cs
|
||||
|
||||
|
||||
class MM_MSGBUSRegisterError(CSConfigError):
|
||||
"""Exception raised for MM_MSGBUS register-specific errors."""
|
||||
pass
|
||||
|
||||
|
||||
class MM_MSGBUSRegisters(BaseConfigRegisterHelper):
|
||||
def __init__(self, cfg_obj):
|
||||
super(MM_MSGBUSRegisters, self).__init__(cfg_obj)
|
||||
self.offset = cfg_obj['offset']
|
||||
self.bar_size = None
|
||||
self.port = cfg_obj['port']
|
||||
if 'size' in cfg_obj:
|
||||
self.size = cfg_obj['size']
|
||||
else:
|
||||
self.size = 4
|
||||
"""
|
||||
MM_MSGBUS Register configuration parser and accessor.
|
||||
|
||||
This class handles parsing and access to memory-mapped message bus registers, extending
|
||||
the base register helper with MM_MSGBUS-specific functionality including port management
|
||||
and memory-mapped message bus protocol operations.
|
||||
|
||||
Attributes:
|
||||
name (str): The name of the register
|
||||
desc (str): Description of the register
|
||||
offset (int): Offset within the MM_MSGBUS address space
|
||||
size (int): Size of the register in bytes (default 4)
|
||||
port (int): MM_MSGBUS port identifier
|
||||
value (int): Current register value
|
||||
default (int): Default register value
|
||||
bar_size (Optional[int]): Size of the BAR (if applicable)
|
||||
|
||||
Example:
|
||||
>>> mm_msgbus_reg = MM_MSGBUSRegisters({
|
||||
... 'name': 'PUNIT_REG', 'port': 0x04, 'offset': 0x100, 'size': 4
|
||||
... })
|
||||
>>> value = mm_msgbus_reg.read()
|
||||
"""
|
||||
|
||||
def __init__(self, cfg_obj: Dict[str, Any]) -> None:
|
||||
"""
|
||||
Initialize MM_MSGBUS register configuration.
|
||||
|
||||
Args:
|
||||
cfg_obj: Dictionary containing MM_MSGBUS register configuration data
|
||||
|
||||
Raises:
|
||||
MM_MSGBUSRegisterError: If configuration validation fails
|
||||
"""
|
||||
try:
|
||||
super().__init__(cfg_obj)
|
||||
self.offset = cfg_obj['offset']
|
||||
self.port = cfg_obj['port']
|
||||
self.size = cfg_obj.get('size', 4) # Default to 4 bytes
|
||||
self.bar_size = None
|
||||
self._validate_mm_msgbus_config()
|
||||
except KeyError as e:
|
||||
raise MM_MSGBUSRegisterError(f"Missing required field in MM_MSGBUS register configuration: {e}") from e
|
||||
except Exception as e:
|
||||
raise MM_MSGBUSRegisterError(f"Failed to initialize MM_MSGBUS register configuration: {e}") from e
|
||||
|
||||
def _validate_mm_msgbus_config(self) -> None:
|
||||
"""
|
||||
Validate MM_MSGBUS register-specific configuration requirements.
|
||||
|
||||
Raises:
|
||||
MM_MSGBUSRegisterError: If configuration is invalid
|
||||
"""
|
||||
if not self.name:
|
||||
raise MM_MSGBUSRegisterError("MM_MSGBUS register configuration must have a valid name")
|
||||
|
||||
if not isinstance(self.offset, int) or self.offset < 0:
|
||||
raise MM_MSGBUSRegisterError(f"Invalid offset: {self.offset}. Must be a non-negative integer")
|
||||
|
||||
if not isinstance(self.port, int) or self.port < 0:
|
||||
raise MM_MSGBUSRegisterError(f"Invalid port: {self.port}. Must be a non-negative integer")
|
||||
|
||||
if not isinstance(self.size, int) or self.size not in [1, 2, 4, 8]:
|
||||
raise MM_MSGBUSRegisterError(f"Invalid register size: {self.size}. Must be 1, 2, 4, or 8 bytes")
|
||||
|
||||
def get_port_hex(self) -> str:
|
||||
"""
|
||||
Get the MM_MSGBUS port as hexadecimal string.
|
||||
|
||||
Returns:
|
||||
Port as hex string (e.g., '0x04')
|
||||
"""
|
||||
return f"0x{self.port:X}"
|
||||
|
||||
def get_offset_hex(self) -> str:
|
||||
"""
|
||||
Get the register offset as hexadecimal string.
|
||||
|
||||
Returns:
|
||||
Offset as hex string (e.g., '0x100')
|
||||
"""
|
||||
return f"0x{self.offset:X}"
|
||||
|
||||
def get_address_info(self) -> str:
|
||||
"""
|
||||
Get formatted address information for this register.
|
||||
|
||||
Returns:
|
||||
Formatted string with port and offset information
|
||||
"""
|
||||
return f"mm_msgbus port {self.get_port_hex()}, off {self.get_offset_hex()}"
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""
|
||||
Detailed string representation for debugging.
|
||||
|
||||
Returns:
|
||||
Formatted string with register details including fields
|
||||
"""
|
||||
reg_str = ''
|
||||
if self.value is not None:
|
||||
reg_val_str = f'0x{self.value:08X}'
|
||||
else:
|
||||
reg_val_str = self.value
|
||||
reg_val_str = str(self.value)
|
||||
|
||||
if self.default is not None:
|
||||
default = f'{self.default:X}'
|
||||
else:
|
||||
default = 'Not Provided'
|
||||
reg_str = f'[*] {self.name} = {reg_val_str} << {self.desc} (mm_msgbus port 0x{self.port:X}, off 0x{self.offset:X}) [default: {default}]'
|
||||
|
||||
reg_str = (f'[*] {self.name} = {reg_val_str} << {self.desc} '
|
||||
f'({self.get_address_info()}) [default: {default}]')
|
||||
|
||||
reg_str += self._register_fields_str(True)
|
||||
return reg_str
|
||||
|
||||
def __str__(self) -> str:
|
||||
"""
|
||||
String representation of MM_MSGBUS register.
|
||||
|
||||
Returns:
|
||||
Formatted string with register details
|
||||
"""
|
||||
reg_str = ''
|
||||
if self.value is not None:
|
||||
reg_val_str = f'0x{self.value:08X}'
|
||||
else:
|
||||
reg_val_str = self.value
|
||||
reg_val_str = str(self.value)
|
||||
|
||||
reg_str = f'[*] {self.name} = {reg_val_str} << {self.desc} (mm_msgbus port 0x{self.port:X}, off 0x{self.offset:X})'
|
||||
reg_str = (f'[*] {self.name} = {reg_val_str} << {self.desc} '
|
||||
f'({self.get_address_info()})')
|
||||
|
||||
reg_str += self._register_fields_str()
|
||||
return reg_str
|
||||
|
||||
def read(self):
|
||||
"""Read the object"""
|
||||
self.logger.log_debug(f'reading {self.name}')
|
||||
_cs = cs()
|
||||
self.value = _cs.hals.MMMsgBus.read(self.port, self.offset)
|
||||
return self.value
|
||||
def read(self) -> int:
|
||||
"""
|
||||
Read the MM_MSGBUS register value.
|
||||
|
||||
def write(self, value):
|
||||
"""Write the object"""
|
||||
_cs = cs()
|
||||
_cs.hals.MMMsgBus.write(self.port, self.offset, value)
|
||||
Returns:
|
||||
Current register value
|
||||
|
||||
Raises:
|
||||
MM_MSGBUSRegisterError: If read operation fails
|
||||
"""
|
||||
try:
|
||||
self.logger.log_debug(f'reading {self.name}')
|
||||
_cs = cs()
|
||||
self.value = _cs.hals.MMMsgBus.read(self.port, self.offset)
|
||||
return self.value
|
||||
except Exception as e:
|
||||
raise MM_MSGBUSRegisterError(
|
||||
f"Failed to read MM_MSGBUS register {self.name} at {self.get_address_info()}: {e}"
|
||||
) from e
|
||||
|
||||
def write(self, value: int) -> None:
|
||||
"""
|
||||
Write a value to the MM_MSGBUS register.
|
||||
|
||||
Args:
|
||||
value: Value to write to the register
|
||||
|
||||
Raises:
|
||||
MM_MSGBUSRegisterError: If write operation fails
|
||||
"""
|
||||
try:
|
||||
self.logger.log_debug(f'writing 0x{value:X} to {self.name}')
|
||||
_cs = cs()
|
||||
_cs.hals.MMMsgBus.write(self.port, self.offset, value)
|
||||
self.value = value
|
||||
except Exception as e:
|
||||
raise MM_MSGBUSRegisterError(
|
||||
f"Failed to write to MM_MSGBUS register {self.name} at {self.get_address_info()}: {e}"
|
||||
) from e
|
||||
|
||||
@@ -17,76 +17,237 @@
|
||||
# Contact information:
|
||||
# chipsec@intel.com
|
||||
|
||||
"""
|
||||
MMCFG Register configuration parser and accessor.
|
||||
|
||||
This module provides MMCFGRegisters class for parsing and accessing memory-mapped configuration
|
||||
space registers in the CHIPSEC framework. MMCFG registers provide access to PCI configuration
|
||||
space through memory-mapped I/O.
|
||||
"""
|
||||
|
||||
from typing import Dict, Any
|
||||
from chipsec.chipset import cs
|
||||
from chipsec.library.register import BaseConfigRegisterHelper
|
||||
from chipsec.library.exceptions import CSReadError
|
||||
from chipsec.library.exceptions import CSReadError, CSConfigError
|
||||
|
||||
|
||||
class MMCFGRegisterError(CSConfigError):
|
||||
"""Exception raised for MMCFG register-specific errors."""
|
||||
pass
|
||||
|
||||
|
||||
class MMCFGRegisters(BaseConfigRegisterHelper):
|
||||
def __init__(self, cfg_obj, pci_obj):
|
||||
super(MMCFGRegisters, self).__init__(cfg_obj)
|
||||
self.size = cfg_obj['size']
|
||||
self.offset = cfg_obj['offset']
|
||||
self.pci = pci_obj
|
||||
"""
|
||||
MMCFG Register configuration parser and accessor.
|
||||
|
||||
This class handles parsing and access to memory-mapped configuration space registers,
|
||||
extending the base register helper with MMCFG-specific functionality including PCI
|
||||
device management and memory-mapped configuration space operations.
|
||||
|
||||
Attributes:
|
||||
name (str): The name of the register
|
||||
desc (str): Description of the register
|
||||
size (int): Size of the register in bytes
|
||||
offset (int): Offset within the MMCFG address space
|
||||
pci: PCI device object containing bus, device, and function information
|
||||
value (int): Current register value
|
||||
default (int): Default register value
|
||||
|
||||
Example:
|
||||
>>> mmcfg_reg = MMCFGRegisters({
|
||||
... 'name': 'PCI_REG', 'size': 4, 'offset': 0x10
|
||||
... }, pci_obj)
|
||||
>>> value = mmcfg_reg.read()
|
||||
"""
|
||||
|
||||
def __init__(self, cfg_obj: Dict[str, Any], pci_obj: Any) -> None:
|
||||
"""
|
||||
Initialize MMCFG register configuration.
|
||||
|
||||
Args:
|
||||
cfg_obj: Dictionary containing MMCFG register configuration data
|
||||
pci_obj: PCI device object with bus, device, and function information
|
||||
|
||||
Raises:
|
||||
MMCFGRegisterError: If configuration validation fails
|
||||
"""
|
||||
try:
|
||||
super().__init__(cfg_obj)
|
||||
self.size = cfg_obj['size']
|
||||
self.offset = cfg_obj['offset']
|
||||
self.pci = pci_obj
|
||||
self._validate_mmcfg_config()
|
||||
except KeyError as e:
|
||||
raise MMCFGRegisterError(f"Missing required field in MMCFG register configuration: {e}") from e
|
||||
except Exception as e:
|
||||
raise MMCFGRegisterError(f"Failed to initialize MMCFG register configuration: {e}") from e
|
||||
|
||||
def _validate_mmcfg_config(self) -> None:
|
||||
"""
|
||||
Validate MMCFG register-specific configuration requirements.
|
||||
|
||||
Raises:
|
||||
MMCFGRegisterError: If configuration is invalid
|
||||
"""
|
||||
if not self.name:
|
||||
raise MMCFGRegisterError("MMCFG register configuration must have a valid name")
|
||||
|
||||
if not isinstance(self.size, int) or self.size not in [1, 2, 4, 8]:
|
||||
raise MMCFGRegisterError(f"Invalid register size: {self.size}. Must be 1, 2, 4, or 8 bytes")
|
||||
|
||||
if not isinstance(self.offset, int) or self.offset < 0:
|
||||
raise MMCFGRegisterError(f"Invalid offset: {self.offset}. Must be a non-negative integer")
|
||||
|
||||
if self.pci is None:
|
||||
raise MMCFGRegisterError("PCI object must be provided for MMCFG register")
|
||||
|
||||
def is_device_present(self) -> bool:
|
||||
"""
|
||||
Check if the PCI device is present and accessible.
|
||||
|
||||
Returns:
|
||||
True if device is present, False otherwise
|
||||
"""
|
||||
return self.pci is not None and self.pci.bus is not None
|
||||
|
||||
def get_pci_address(self) -> str:
|
||||
"""
|
||||
Get the PCI device address in b:d.f format.
|
||||
|
||||
Returns:
|
||||
PCI address string (e.g., '00:1f.0')
|
||||
"""
|
||||
if not self.is_device_present():
|
||||
return "Device not present"
|
||||
return f"{self.pci.bus:02d}:{self.pci.dev:02d}.{self.pci.fun:d}"
|
||||
|
||||
def get_mmcfg_offset(self) -> int:
|
||||
"""
|
||||
Calculate the MMCFG offset for this register.
|
||||
|
||||
Returns:
|
||||
MMCFG offset value
|
||||
"""
|
||||
if not self.is_device_present():
|
||||
return 0
|
||||
return (self.pci.bus * 32 * 8 + self.pci.dev * 8 + self.pci.fun) * 0x1000 + self.offset
|
||||
|
||||
def get_address_info(self) -> str:
|
||||
"""
|
||||
Get formatted address information for this register.
|
||||
|
||||
Returns:
|
||||
Formatted string with PCI and MMCFG address information
|
||||
"""
|
||||
if not self.is_device_present():
|
||||
return "Device not present"
|
||||
|
||||
mmcfg_offset = self.get_mmcfg_offset()
|
||||
return (f"b:d.f {self.get_pci_address()} + 0x{self.offset:X}, "
|
||||
f"MMCFG + 0x{mmcfg_offset:X}")
|
||||
|
||||
def _get_formatted_value(self) -> str:
|
||||
"""
|
||||
Get formatted register value based on size.
|
||||
|
||||
Returns:
|
||||
Formatted value string
|
||||
"""
|
||||
if self.value is not None:
|
||||
return f'0x{self.value:0{self.size * 2}X}'
|
||||
return str(self.value)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
reg_str = ''
|
||||
if self.value is not None:
|
||||
reg_val_str = f'0x{self.value:0{self.size * 2}X}'
|
||||
else:
|
||||
reg_val_str = self.value
|
||||
if self.pci.bus is not None:
|
||||
b = self.pci.bus
|
||||
else:
|
||||
"""
|
||||
Detailed string representation for debugging.
|
||||
|
||||
Returns:
|
||||
Formatted string with register details including fields
|
||||
"""
|
||||
if not self.is_device_present():
|
||||
return 'Device not present'
|
||||
|
||||
d = self.pci.dev
|
||||
f = self.pci.fun
|
||||
o = self.offset
|
||||
mmcfg_off_str = ''
|
||||
mmcfg_off_str += f', MMCFG + 0x{(b * 32 * 8 + d * 8 + f) * 0x1000 + o:X}'
|
||||
reg_val_str = self._get_formatted_value()
|
||||
|
||||
if self.default is not None:
|
||||
default = f'{self.default:X}'
|
||||
else:
|
||||
default = 'Not Provided'
|
||||
reg_str = f'[*] {self.name} = {reg_val_str} << {self.desc} (b:d.f {b:02d}:{d:02d}.{f:d} + 0x{o:X}{mmcfg_off_str}) [default: {default}]'
|
||||
|
||||
reg_str = (f'[*] {self.name} = {reg_val_str} << {self.desc} '
|
||||
f'({self.get_address_info()}) [default: {default}]')
|
||||
reg_str += self._register_fields_str(True)
|
||||
return reg_str
|
||||
|
||||
def __str__(self) -> str:
|
||||
reg_str = ''
|
||||
if self.value is not None:
|
||||
reg_val_str = f'0x{self.value:0{self.size * 2}X}'
|
||||
else:
|
||||
reg_val_str = self.value
|
||||
if self.pci.bus is not None:
|
||||
b = self.pci.bus
|
||||
else:
|
||||
"""
|
||||
String representation of MMCFG register.
|
||||
|
||||
Returns:
|
||||
Formatted string with register details
|
||||
"""
|
||||
if not self.is_device_present():
|
||||
return 'Device not present'
|
||||
|
||||
d = self.pci.dev
|
||||
f = self.pci.fun
|
||||
o = self.offset
|
||||
mmcfg_off_str = ''
|
||||
mmcfg_off_str += f', MMCFG + 0x{(b * 32 * 8 + d * 8 + f) * 0x1000 + o:X}'
|
||||
reg_str = f'[*] {self.name} = {reg_val_str} << {self.desc} (b:d.f {b:02d}:{d:02d}.{f:d} + 0x{o:X}{mmcfg_off_str})'
|
||||
reg_val_str = self._get_formatted_value()
|
||||
|
||||
reg_str = (f'[*] {self.name} = {reg_val_str} << {self.desc} '
|
||||
f'({self.get_address_info()})')
|
||||
reg_str += self._register_fields_str()
|
||||
return reg_str
|
||||
|
||||
def read(self):
|
||||
"""Read the object"""
|
||||
self.logger.log_debug(f'reading {self.name}')
|
||||
_cs = cs()
|
||||
if self.pci.bus is not None:
|
||||
self.value = _cs.hals.MMCFG.read_mmcfg_reg(self.pci.bus, self.pci.dev, self.pci.fun, self.offset, self.size)
|
||||
else:
|
||||
raise CSReadError(f'PCI Device is not available ({self.pci.bus}:{self.pci.dev}.{self.pci.fun})')
|
||||
return self.value
|
||||
def read(self) -> int:
|
||||
"""
|
||||
Read the MMCFG register value.
|
||||
|
||||
def write(self, value):
|
||||
"""Write the object"""
|
||||
_cs = cs()
|
||||
if self.pci.bus is not None:
|
||||
_cs.hals.MMCFG.write_mmcfg_reg(self.pci.bus, self.pci.dev, self.pci.fun, self.offset, self.size, value)
|
||||
else:
|
||||
raise CSReadError(f'PCI Device is not available ({self.pci.bus}:{self.pci.dev}.{self.pci.fun})')
|
||||
Returns:
|
||||
Current register value
|
||||
|
||||
Raises:
|
||||
MMCFGRegisterError: If read operation fails or device is not present
|
||||
"""
|
||||
try:
|
||||
self.logger.log_debug(f'reading {self.name}')
|
||||
|
||||
if not self.is_device_present():
|
||||
raise MMCFGRegisterError(
|
||||
f'PCI Device is not available ({self.get_pci_address()})'
|
||||
)
|
||||
|
||||
_cs = cs()
|
||||
self.value = _cs.hals.MMCFG.read_mmcfg_reg(
|
||||
self.pci.bus, self.pci.dev, self.pci.fun, self.offset, self.size
|
||||
)
|
||||
return self.value
|
||||
except CSReadError as e:
|
||||
raise MMCFGRegisterError(f"Failed to read MMCFG register {self.name}: {e}") from e
|
||||
except Exception as e:
|
||||
raise MMCFGRegisterError(f"Failed to read MMCFG register {self.name}: {e}") from e
|
||||
|
||||
def write(self, value: int) -> None:
|
||||
"""
|
||||
Write a value to the MMCFG register.
|
||||
|
||||
Args:
|
||||
value: Value to write to the register
|
||||
|
||||
Raises:
|
||||
MMCFGRegisterError: If write operation fails or device is not present
|
||||
"""
|
||||
try:
|
||||
self.logger.log_debug(f'writing 0x{value:X} to {self.name}')
|
||||
|
||||
if not self.is_device_present():
|
||||
raise MMCFGRegisterError(
|
||||
f'PCI Device is not available ({self.get_pci_address()})'
|
||||
)
|
||||
|
||||
_cs = cs()
|
||||
_cs.hals.MMCFG.write_mmcfg_reg(
|
||||
self.pci.bus, self.pci.dev, self.pci.fun, self.offset, self.size, value
|
||||
)
|
||||
self.value = value
|
||||
except CSReadError as e:
|
||||
raise MMCFGRegisterError(f"Failed to write to MMCFG register {self.name}: {e}") from e
|
||||
except Exception as e:
|
||||
raise MMCFGRegisterError(f"Failed to write to MMCFG register {self.name}: {e}") from e
|
||||
|
||||
@@ -17,64 +17,206 @@
|
||||
# Contact information:
|
||||
# chipsec@intel.com
|
||||
|
||||
from typing import Any
|
||||
"""
|
||||
MMIO Register configuration parser and accessor.
|
||||
|
||||
This module provides MMIORegisters class for parsing and accessing Memory-Mapped I/O registers
|
||||
in the CHIPSEC framework. MMIO registers provide access to hardware interfaces through
|
||||
memory-mapped address spaces.
|
||||
"""
|
||||
|
||||
from typing import Dict, Any
|
||||
from chipsec.chipset import cs
|
||||
from chipsec.library.register import BaseConfigRegisterHelper
|
||||
from chipsec.library.exceptions import CSReadError, CSConfigError
|
||||
from chipsec.library.exceptions import CSConfigError
|
||||
|
||||
|
||||
class MMIORegisterError(CSConfigError):
|
||||
"""Exception raised for MMIO register-specific errors."""
|
||||
pass
|
||||
|
||||
|
||||
class MMIORegisters(BaseConfigRegisterHelper):
|
||||
def __init__(self, cfg_obj):
|
||||
super(MMIORegisters, self).__init__(cfg_obj)
|
||||
self.cs = cs()
|
||||
self.size = cfg_obj['size']
|
||||
self.offset = cfg_obj['offset']
|
||||
self.bar_base = None
|
||||
self.bar_size = None
|
||||
self.bar = None
|
||||
self.range = None
|
||||
if 'bar' in cfg_obj:
|
||||
self.bar = cfg_obj['bar']
|
||||
elif 'range' in cfg_obj:
|
||||
self.range = cfg_obj['range']
|
||||
|
||||
"""
|
||||
MMIO Register configuration parser and accessor.
|
||||
|
||||
This class handles parsing and access to Memory-Mapped I/O registers, extending
|
||||
the base register helper with MMIO-specific functionality including BAR management,
|
||||
memory range handling, and MMIO protocol operations.
|
||||
|
||||
Attributes:
|
||||
name (str): The name of the register
|
||||
desc (str): Description of the register
|
||||
size (int): Size of the register in bytes
|
||||
offset (int): Offset within the MMIO address space
|
||||
bar (Optional[str]): BAR identifier for MMIO access
|
||||
range (Optional[str]): Memory range identifier
|
||||
bar_base (Optional[int]): Base address of the BAR
|
||||
bar_size (Optional[int]): Size of the BAR
|
||||
value (int): Current register value
|
||||
default (int): Default register value
|
||||
instance: Instance identifier for the register
|
||||
cs: Chipset interface object
|
||||
|
||||
Example:
|
||||
>>> mmio_reg = MMIORegisters({
|
||||
... 'name': 'MMIO_REG', 'size': 4, 'offset': 0x100, 'bar': 'MMIO_BAR'
|
||||
... })
|
||||
>>> value = mmio_reg.read()
|
||||
"""
|
||||
|
||||
def __init__(self, cfg_obj: Dict[str, Any]) -> None:
|
||||
"""
|
||||
Initialize MMIO register configuration.
|
||||
|
||||
Args:
|
||||
cfg_obj: Dictionary containing MMIO register configuration data
|
||||
|
||||
Raises:
|
||||
MMIORegisterError: If configuration validation fails
|
||||
"""
|
||||
try:
|
||||
super().__init__(cfg_obj)
|
||||
self.cs = cs()
|
||||
self.size = cfg_obj['size']
|
||||
self.offset = cfg_obj['offset']
|
||||
self.bar_base = None
|
||||
self.bar_size = None
|
||||
self.bar = cfg_obj.get('bar')
|
||||
self.range = cfg_obj.get('range')
|
||||
self._validate_mmio_config()
|
||||
except KeyError as e:
|
||||
raise MMIORegisterError(f"Missing required field in MMIO register configuration: {e}") from e
|
||||
except Exception as e:
|
||||
raise MMIORegisterError(f"Failed to initialize MMIO register configuration: {e}") from e
|
||||
|
||||
def _validate_mmio_config(self) -> None:
|
||||
"""
|
||||
Validate MMIO register-specific configuration requirements.
|
||||
|
||||
Raises:
|
||||
MMIORegisterError: If configuration is invalid
|
||||
"""
|
||||
if not self.name:
|
||||
raise MMIORegisterError("MMIO register configuration must have a valid name")
|
||||
|
||||
if not isinstance(self.size, int) or self.size not in [1, 2, 4, 8]:
|
||||
raise MMIORegisterError(f"Invalid register size: {self.size}. Must be 1, 2, 4, or 8 bytes")
|
||||
|
||||
if not isinstance(self.offset, int) or self.offset < 0:
|
||||
raise MMIORegisterError(f"Invalid offset: {self.offset}. Must be a non-negative integer")
|
||||
|
||||
if not self.bar and not self.range:
|
||||
raise MMIORegisterError("MMIO register must specify either 'bar' or 'range'")
|
||||
|
||||
if self.bar and self.range:
|
||||
raise MMIORegisterError("MMIO register cannot specify both 'bar' and 'range'")
|
||||
|
||||
def get_offset_hex(self) -> str:
|
||||
"""
|
||||
Get the register offset as hexadecimal string.
|
||||
|
||||
Returns:
|
||||
Offset as hex string (e.g., '0x100')
|
||||
"""
|
||||
return f"0x{self.offset:X}"
|
||||
|
||||
def get_instance_str(self) -> str:
|
||||
"""
|
||||
Get the instance as a formatted string.
|
||||
|
||||
Returns:
|
||||
Instance as string ('Fixed' if None, otherwise the instance value)
|
||||
"""
|
||||
return f'{self.instance}' if self.instance is not None else 'Fixed'
|
||||
|
||||
def get_address_info(self) -> str:
|
||||
"""
|
||||
Get formatted address information for this register.
|
||||
|
||||
Returns:
|
||||
Formatted string with BAR/range and offset information
|
||||
"""
|
||||
if self.bar:
|
||||
return f"{self.bar} + {self.get_offset_hex()} {self.get_instance_str()}"
|
||||
elif self.range:
|
||||
return f"Range:{self.range} + {self.get_offset_hex()} {self.get_instance_str()}"
|
||||
else:
|
||||
return f"Unknown + {self.get_offset_hex()} {self.get_instance_str()}"
|
||||
|
||||
def _get_formatted_value(self) -> str:
|
||||
"""
|
||||
Get formatted register value based on size.
|
||||
|
||||
Returns:
|
||||
Formatted value string
|
||||
"""
|
||||
if self.value is not None:
|
||||
return f'0x{self.value:0{self.size * 2}X}'
|
||||
return str(self.value)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
reg_str = ''
|
||||
if self.value is not None:
|
||||
reg_val_str = f'0x{self.value:0{self.size * 2}X}'
|
||||
else:
|
||||
reg_val_str = self.value
|
||||
instance = f'{self.instance}' if self.instance is not None else 'Fixed'
|
||||
"""
|
||||
Detailed string representation for debugging.
|
||||
|
||||
Returns:
|
||||
Formatted string with register details including fields
|
||||
"""
|
||||
reg_val_str = self._get_formatted_value()
|
||||
|
||||
if self.default is not None:
|
||||
default = f'{self.default:X}'
|
||||
else:
|
||||
default = 'Not Provided'
|
||||
reg_str = f'[*] {self.name} = {reg_val_str} << {self.desc} ({self.bar} + 0x{self.offset:X} {instance}) [default: {default}]'
|
||||
|
||||
reg_str = (f'[*] {self.name} = {reg_val_str} << {self.desc} '
|
||||
f'({self.get_address_info()}) [default: {default}]')
|
||||
|
||||
reg_str += self._register_fields_str(True)
|
||||
return reg_str
|
||||
|
||||
def __str__(self) -> str:
|
||||
reg_str = ''
|
||||
if self.value is not None:
|
||||
reg_val_str = f'0x{self.value:0{self.size * 2}X}'
|
||||
else:
|
||||
reg_val_str = self.value
|
||||
"""
|
||||
String representation of MMIO register.
|
||||
|
||||
instance = f'{self.instance}' if self.instance is not None else 'Fixed'
|
||||
reg_str = f'[*] {self.name} = {reg_val_str} << {self.desc} ({self.bar} + 0x{self.offset:X} {instance})'
|
||||
Returns:
|
||||
Formatted string with register details
|
||||
"""
|
||||
reg_val_str = self._get_formatted_value()
|
||||
|
||||
reg_str = (f'[*] {self.name} = {reg_val_str} << {self.desc} '
|
||||
f'({self.get_address_info()})')
|
||||
|
||||
reg_str += self._register_fields_str()
|
||||
return reg_str
|
||||
|
||||
def get_instance(self) -> Any:
|
||||
"""
|
||||
Get the instance value, handling nested instance attributes.
|
||||
|
||||
Returns:
|
||||
The instance value
|
||||
"""
|
||||
return self.instance if not hasattr(self.instance, 'instance') else self.instance.instance
|
||||
|
||||
def populate_base_address(self):
|
||||
if self.bar_base is None:
|
||||
def populate_base_address(self) -> None:
|
||||
"""
|
||||
Populate the base address for MMIO operations.
|
||||
|
||||
This method resolves the BAR or memory range to get the actual base address
|
||||
for MMIO register access.
|
||||
|
||||
Raises:
|
||||
MMIORegisterError: If base address cannot be populated
|
||||
"""
|
||||
if self.bar_base is not None:
|
||||
return # Already populated
|
||||
|
||||
try:
|
||||
if self.bar:
|
||||
(self.bar_base, self.bar_size) = self.cs.hals.MMIO.get_MMIO_BAR_base_address(self.bar, self.get_instance())
|
||||
self.bar_base, self.bar_size = self.cs.hals.MMIO.get_MMIO_BAR_base_address(
|
||||
self.bar, self.get_instance()
|
||||
)
|
||||
elif self.range:
|
||||
mem_range_def = self.cs.hals.MemRange.get_def(self.range)
|
||||
if mem_range_def:
|
||||
@@ -82,28 +224,77 @@ class MMIORegisters(BaseConfigRegisterHelper):
|
||||
self.bar_size = mem_range_def.size
|
||||
self.bar_base = mem_range_def.address
|
||||
else:
|
||||
raise CSConfigError(f"Memory Range ({self.range}) access type ({mem_range_def.access}) is not MMIO.")
|
||||
raise MMIORegisterError(
|
||||
f"Memory Range ({self.range}) access type ({mem_range_def.access}) is not MMIO."
|
||||
)
|
||||
else:
|
||||
raise CSConfigError(f"Memory Range ({self.range}) cannot be found.")
|
||||
raise MMIORegisterError(f"Memory Range ({self.range}) cannot be found.")
|
||||
else:
|
||||
raise CSConfigError(f"Unable to populate MMIO Base Address: {self.name}")
|
||||
raise MMIORegisterError(f"Unable to populate MMIO Base Address: {self.name}")
|
||||
except Exception as e:
|
||||
raise MMIORegisterError(f"Failed to populate base address for {self.name}: {e}") from e
|
||||
|
||||
def read(self):
|
||||
"""Read the object"""
|
||||
self.logger.log_debug(f'reading {self.name}')
|
||||
self.populate_base_address()
|
||||
self.value = self.cs.hals.MMIO.read_MMIO_reg(self.bar_base, self.offset, self.size)
|
||||
self.logger.log_debug('done reading')
|
||||
return self.value
|
||||
def read(self) -> int:
|
||||
"""
|
||||
Read the MMIO register value.
|
||||
|
||||
def write(self, value):
|
||||
"""Write the object"""
|
||||
self.populate_base_address()
|
||||
self.cs.hals.MMIO.write_MMIO_reg(self.bar_base, self.offset, value, self.size)
|
||||
Returns:
|
||||
Current register value
|
||||
|
||||
def write_subset(self, value, size, offset=0):
|
||||
if offset < self.size and size <= self.size - offset:
|
||||
Raises:
|
||||
MMIORegisterError: If read operation fails
|
||||
"""
|
||||
try:
|
||||
self.logger.log_debug(f'reading {self.name}')
|
||||
self.populate_base_address()
|
||||
self.value = self.cs.hals.MMIO.read_MMIO_reg(self.bar_base, self.offset, self.size)
|
||||
self.logger.log_debug('done reading')
|
||||
return self.value
|
||||
except Exception as e:
|
||||
raise MMIORegisterError(f"Failed to read MMIO register {self.name}: {e}") from e
|
||||
|
||||
def write(self, value: int) -> None:
|
||||
"""
|
||||
Write a value to the MMIO register.
|
||||
|
||||
Args:
|
||||
value: Value to write to the register
|
||||
|
||||
Raises:
|
||||
MMIORegisterError: If write operation fails
|
||||
"""
|
||||
try:
|
||||
self.logger.log_debug(f'writing 0x{value:X} to {self.name}')
|
||||
self.populate_base_address()
|
||||
self.cs.hals.MMIO.write_MMIO_reg(self.bar_base, self.offset, value, self.size)
|
||||
self.value = value
|
||||
except Exception as e:
|
||||
raise MMIORegisterError(f"Failed to write to MMIO register {self.name}: {e}") from e
|
||||
|
||||
def write_subset(self, value: int, size: int, offset: int = 0) -> None:
|
||||
"""
|
||||
Write a subset of the MMIO register.
|
||||
|
||||
Args:
|
||||
value: Value to write
|
||||
size: Size of the write operation in bytes
|
||||
offset: Offset within the register for the write operation
|
||||
|
||||
Raises:
|
||||
MMIORegisterError: If write operation fails or parameters are invalid
|
||||
"""
|
||||
try:
|
||||
if offset < 0 or size <= 0:
|
||||
raise MMIORegisterError("Offset must be non-negative and size must be positive")
|
||||
|
||||
if offset >= self.size or size > self.size - offset:
|
||||
raise MMIORegisterError(
|
||||
f"Improper Offset ({offset}) or Size ({size}) requested in write subset for {self.name}. "
|
||||
f"Register size is {self.size} bytes."
|
||||
)
|
||||
|
||||
self.logger.log_debug(f'writing subset 0x{value:X} to {self.name} at offset {offset}, size {size}')
|
||||
self.populate_base_address()
|
||||
self.cs.hals.MMIO.write_MMIO_reg(self.bar_base, self.offset + offset, value, size)
|
||||
else:
|
||||
raise CSReadError(f"Improper Offset or Size requested in write subset for {self.name}")
|
||||
except Exception as e:
|
||||
raise MMIORegisterError(f"Failed to write subset to MMIO register {self.name}: {e}") from e
|
||||
|
||||
@@ -17,52 +17,192 @@
|
||||
# Contact information:
|
||||
# chipsec@intel.com
|
||||
|
||||
"""
|
||||
MSGBUS Register configuration parser and accessor.
|
||||
|
||||
This module provides MSGBUSRegisters class for parsing and accessing message bus registers
|
||||
in the CHIPSEC framework. Message bus registers provide access to various hardware interfaces
|
||||
through Intel's Message Bus protocol.
|
||||
"""
|
||||
|
||||
from typing import Dict, Any
|
||||
from chipsec.chipset import cs
|
||||
from chipsec.library.register import BaseConfigRegisterHelper
|
||||
from chipsec.library.exceptions import CSConfigError
|
||||
|
||||
|
||||
class MSGBUSRegisterError(CSConfigError):
|
||||
"""Exception raised for MSGBUS register-specific errors."""
|
||||
pass
|
||||
|
||||
|
||||
class MSGBUSRegisters(BaseConfigRegisterHelper):
|
||||
def __init__(self, cfg_obj):
|
||||
super(MSGBUSRegisters, self).__init__(cfg_obj)
|
||||
self.offset = cfg_obj['offset']
|
||||
self.bar_size = None
|
||||
self.port = cfg_obj['port']
|
||||
"""
|
||||
MSGBUS Register configuration parser and accessor.
|
||||
|
||||
This class handles parsing and access to message bus registers, extending the base
|
||||
register helper with MSGBUS-specific functionality including port management and
|
||||
message bus protocol operations.
|
||||
|
||||
Attributes:
|
||||
name (str): The name of the register
|
||||
desc (str): Description of the register
|
||||
offset (int): Offset within the MSGBUS address space
|
||||
port (int): MSGBUS port identifier
|
||||
value (int): Current register value
|
||||
default (int): Default register value
|
||||
bar_size (Optional[int]): Size of the BAR (if applicable)
|
||||
|
||||
Example:
|
||||
>>> msgbus_reg = MSGBUSRegisters({
|
||||
... 'name': 'PUNIT_REG', 'port': 0x04, 'offset': 0x100
|
||||
... })
|
||||
>>> value = msgbus_reg.read()
|
||||
"""
|
||||
|
||||
def __init__(self, cfg_obj: Dict[str, Any]) -> None:
|
||||
"""
|
||||
Initialize MSGBUS register configuration.
|
||||
|
||||
Args:
|
||||
cfg_obj: Dictionary containing MSGBUS register configuration data
|
||||
|
||||
Raises:
|
||||
MSGBUSRegisterError: If configuration validation fails
|
||||
"""
|
||||
try:
|
||||
super().__init__(cfg_obj)
|
||||
self.offset = cfg_obj['offset']
|
||||
self.port = cfg_obj['port']
|
||||
self.bar_size = None
|
||||
self._validate_msgbus_config()
|
||||
except KeyError as e:
|
||||
raise MSGBUSRegisterError(f"Missing required field in MSGBUS register configuration: {e}") from e
|
||||
except Exception as e:
|
||||
raise MSGBUSRegisterError(f"Failed to initialize MSGBUS register configuration: {e}") from e
|
||||
|
||||
def _validate_msgbus_config(self) -> None:
|
||||
"""
|
||||
Validate MSGBUS register-specific configuration requirements.
|
||||
|
||||
Raises:
|
||||
MSGBUSRegisterError: If configuration is invalid
|
||||
"""
|
||||
if not self.name:
|
||||
raise MSGBUSRegisterError("MSGBUS register configuration must have a valid name")
|
||||
|
||||
if not isinstance(self.offset, int) or self.offset < 0:
|
||||
raise MSGBUSRegisterError(f"Invalid offset: {self.offset}. Must be a non-negative integer")
|
||||
|
||||
if not isinstance(self.port, int) or self.port < 0:
|
||||
raise MSGBUSRegisterError(f"Invalid port: {self.port}. Must be a non-negative integer")
|
||||
|
||||
def get_port_hex(self) -> str:
|
||||
"""
|
||||
Get the MSGBUS port as hexadecimal string.
|
||||
|
||||
Returns:
|
||||
Port as hex string (e.g., '0x04')
|
||||
"""
|
||||
return f"0x{self.port:X}"
|
||||
|
||||
def get_offset_hex(self) -> str:
|
||||
"""
|
||||
Get the register offset as hexadecimal string.
|
||||
|
||||
Returns:
|
||||
Offset as hex string (e.g., '0x100')
|
||||
"""
|
||||
return f"0x{self.offset:X}"
|
||||
|
||||
def get_address_info(self) -> str:
|
||||
"""
|
||||
Get formatted address information for this register.
|
||||
|
||||
Returns:
|
||||
Formatted string with port and offset information
|
||||
"""
|
||||
return f"mm_msgbus port {self.get_port_hex()}, off {self.get_offset_hex()}"
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""
|
||||
Detailed string representation for debugging.
|
||||
|
||||
Returns:
|
||||
Formatted string with register details including fields
|
||||
"""
|
||||
reg_str = ''
|
||||
if self.value is not None:
|
||||
reg_val_str = f'0x{self.value:08X}'
|
||||
else:
|
||||
reg_val_str = self.value
|
||||
reg_val_str = str(self.value)
|
||||
|
||||
if self.default is not None:
|
||||
default = f'{self.default:X}'
|
||||
else:
|
||||
default = 'Not Provided'
|
||||
reg_str = f'[*] {self.name} = {reg_val_str} << {self.desc} (mm_msgbus port 0x{self.port:X}, off 0x{self.offset:X}) [default: {default}]'
|
||||
|
||||
reg_str = (f'[*] {self.name} = {reg_val_str} << {self.desc} '
|
||||
f'({self.get_address_info()}) [default: {default}]')
|
||||
|
||||
reg_str += self._register_fields_str(True)
|
||||
return reg_str
|
||||
|
||||
def __str__(self) -> str:
|
||||
"""
|
||||
String representation of MSGBUS register.
|
||||
|
||||
Returns:
|
||||
Formatted string with register details
|
||||
"""
|
||||
reg_str = ''
|
||||
if self.value is not None:
|
||||
reg_val_str = f'0x{self.value:08X}'
|
||||
else:
|
||||
reg_val_str = self.value
|
||||
reg_val_str = str(self.value)
|
||||
|
||||
reg_str = f'[*] {self.name} = {reg_val_str} << {self.desc} (mm_msgbus port 0x{self.port:X}, off 0x{self.offset:X})'
|
||||
reg_str = (f'[*] {self.name} = {reg_val_str} << {self.desc} '
|
||||
f'({self.get_address_info()})')
|
||||
|
||||
reg_str += self._register_fields_str()
|
||||
return reg_str
|
||||
|
||||
def read(self):
|
||||
"""Read the object"""
|
||||
self.logger.log_debug(f'reading {self.name}')
|
||||
_cs = cs()
|
||||
self.value = _cs.hals.MsgBus.msgbus_reg_read(self.port, self.offset)
|
||||
return self.value
|
||||
def read(self) -> int:
|
||||
"""
|
||||
Read the MSGBUS register value.
|
||||
|
||||
def write(self, value):
|
||||
"""Write the object"""
|
||||
_cs = cs()
|
||||
_cs.hals.MsgBus.msgbus_reg_write(self.port, self.offset, value)
|
||||
Returns:
|
||||
Current register value
|
||||
|
||||
Raises:
|
||||
MSGBUSRegisterError: If read operation fails
|
||||
"""
|
||||
try:
|
||||
self.logger.log_debug(f'reading {self.name}')
|
||||
_cs = cs()
|
||||
self.value = _cs.hals.MsgBus.msgbus_reg_read(self.port, self.offset)
|
||||
return self.value
|
||||
except Exception as e:
|
||||
raise MSGBUSRegisterError(
|
||||
f"Failed to read MSGBUS register {self.name} at {self.get_address_info()}: {e}"
|
||||
) from e
|
||||
|
||||
def write(self, value: int) -> None:
|
||||
"""
|
||||
Write a value to the MSGBUS register.
|
||||
|
||||
Args:
|
||||
value: Value to write to the register
|
||||
|
||||
Raises:
|
||||
MSGBUSRegisterError: If write operation fails
|
||||
"""
|
||||
try:
|
||||
self.logger.log_debug(f'writing 0x{value:X} to {self.name}')
|
||||
_cs = cs()
|
||||
_cs.hals.MsgBus.msgbus_reg_write(self.port, self.offset, value)
|
||||
self.value = value
|
||||
except Exception as e:
|
||||
raise MSGBUSRegisterError(
|
||||
f"Failed to write to MSGBUS register {self.name} at {self.get_address_info()}: {e}"
|
||||
) from e
|
||||
|
||||
@@ -17,58 +17,227 @@
|
||||
# Contact information:
|
||||
# chipsec@intel.com
|
||||
|
||||
"""
|
||||
MSR Register configuration parser and accessor.
|
||||
|
||||
This module provides MSRRegisters class for parsing and accessing Model Specific Registers (MSRs)
|
||||
in the CHIPSEC framework. MSR registers provide access to processor-specific configuration and
|
||||
control settings.
|
||||
"""
|
||||
|
||||
from typing import Dict, Any, Tuple
|
||||
from chipsec.chipset import cs
|
||||
from chipsec.library.register import BaseConfigRegisterHelper
|
||||
from chipsec.library.exceptions import CSConfigError
|
||||
|
||||
|
||||
class MSRRegisterError(CSConfigError):
|
||||
"""Exception raised for MSR register-specific errors."""
|
||||
pass
|
||||
|
||||
|
||||
class MSRRegisters(BaseConfigRegisterHelper):
|
||||
def __init__(self, cfg_obj):
|
||||
super(MSRRegisters, self).__init__(cfg_obj)
|
||||
if 'size' in cfg_obj:
|
||||
self.size = cfg_obj['size']
|
||||
else:
|
||||
self.size = 8
|
||||
self.thread = cfg_obj['instance']
|
||||
self.msr = cfg_obj['msr']
|
||||
"""
|
||||
MSR Register configuration parser and accessor.
|
||||
|
||||
This class handles parsing and access to Model Specific Registers (MSRs), extending
|
||||
the base register helper with MSR-specific functionality including thread management
|
||||
and MSR protocol operations.
|
||||
|
||||
Attributes:
|
||||
name (str): The name of the register
|
||||
desc (str): Description of the register
|
||||
size (int): Size of the register in bytes (default 8 for MSRs)
|
||||
thread (int): Thread/CPU instance identifier
|
||||
msr (int): MSR register number
|
||||
value (int): Current register value
|
||||
default (int): Default register value
|
||||
|
||||
Example:
|
||||
>>> msr_reg = MSRRegisters({
|
||||
... 'name': 'IA32_FEATURE_CONTROL', 'msr': 0x3A, 'instance': 0
|
||||
... })
|
||||
>>> value = msr_reg.read()
|
||||
"""
|
||||
|
||||
def __init__(self, cfg_obj: Dict[str, Any]) -> None:
|
||||
"""
|
||||
Initialize MSR register configuration.
|
||||
|
||||
Args:
|
||||
cfg_obj: Dictionary containing MSR register configuration data
|
||||
|
||||
Raises:
|
||||
MSRRegisterError: If configuration validation fails
|
||||
"""
|
||||
try:
|
||||
super().__init__(cfg_obj)
|
||||
self.size = cfg_obj.get('size', 8) # MSRs are typically 8 bytes
|
||||
self.thread = cfg_obj['instance']
|
||||
self.msr = cfg_obj['msr']
|
||||
self._validate_msr_config()
|
||||
except KeyError as e:
|
||||
raise MSRRegisterError(f"Missing required field in MSR register configuration: {e}") from e
|
||||
except Exception as e:
|
||||
raise MSRRegisterError(f"Failed to initialize MSR register configuration: {e}") from e
|
||||
|
||||
def _validate_msr_config(self) -> None:
|
||||
"""
|
||||
Validate MSR register-specific configuration requirements.
|
||||
|
||||
Raises:
|
||||
MSRRegisterError: If configuration is invalid
|
||||
"""
|
||||
if not self.name:
|
||||
raise MSRRegisterError("MSR register configuration must have a valid name")
|
||||
|
||||
if not isinstance(self.thread, int) or self.thread < 0:
|
||||
raise MSRRegisterError(f"Invalid thread/instance: {self.thread}. Must be a non-negative integer")
|
||||
|
||||
if not isinstance(self.msr, int) or self.msr < 0:
|
||||
raise MSRRegisterError(f"Invalid MSR number: {self.msr}. Must be a non-negative integer")
|
||||
|
||||
if not isinstance(self.size, int) or self.size not in [1, 2, 4, 8]:
|
||||
raise MSRRegisterError(f"Invalid register size: {self.size}. Must be 1, 2, 4, or 8 bytes")
|
||||
|
||||
def get_msr_hex(self) -> str:
|
||||
"""
|
||||
Get the MSR number as hexadecimal string.
|
||||
|
||||
Returns:
|
||||
MSR number as hex string (e.g., '0x3A')
|
||||
"""
|
||||
return f"0x{self.msr:X}"
|
||||
|
||||
def get_thread_hex(self) -> str:
|
||||
"""
|
||||
Get the thread/instance as hexadecimal string.
|
||||
|
||||
Returns:
|
||||
Thread number as hex string (e.g., '0x0')
|
||||
"""
|
||||
return f"0x{self.thread:X}"
|
||||
|
||||
def get_address_info(self) -> str:
|
||||
"""
|
||||
Get formatted address information for this register.
|
||||
|
||||
Returns:
|
||||
Formatted string with MSR and thread information
|
||||
"""
|
||||
return f"MSR {self.get_msr_hex()} Thread {self.get_thread_hex()}"
|
||||
|
||||
def _get_formatted_value(self) -> str:
|
||||
"""
|
||||
Get formatted register value based on size.
|
||||
|
||||
Returns:
|
||||
Formatted value string
|
||||
"""
|
||||
if self.value is not None:
|
||||
return f'0x{self.value:0{self.size * 2}X}'
|
||||
return str(self.value)
|
||||
|
||||
def _split_64bit_value(self, value: int) -> Tuple[int, int]:
|
||||
"""
|
||||
Split a 64-bit value into EAX (low 32-bits) and EDX (high 32-bits).
|
||||
|
||||
Args:
|
||||
value: 64-bit value to split
|
||||
|
||||
Returns:
|
||||
Tuple of (eax, edx) values
|
||||
"""
|
||||
eax = value & 0xFFFFFFFF
|
||||
edx = (value >> 32) & 0xFFFFFFFF
|
||||
return eax, edx
|
||||
|
||||
def _combine_32bit_values(self, eax: int, edx: int) -> int:
|
||||
"""
|
||||
Combine EAX and EDX values into a 64-bit value.
|
||||
|
||||
Args:
|
||||
eax: Low 32-bit value
|
||||
edx: High 32-bit value
|
||||
|
||||
Returns:
|
||||
Combined 64-bit value
|
||||
"""
|
||||
return (edx << 32) | eax
|
||||
|
||||
def __repr__(self) -> str:
|
||||
reg_str = ''
|
||||
if self.value is not None:
|
||||
reg_val_str = f'0x{self.value:0{self.size * 2}X}'
|
||||
else:
|
||||
reg_val_str = self.value
|
||||
"""
|
||||
Detailed string representation for debugging.
|
||||
|
||||
Returns:
|
||||
Formatted string with register details including fields
|
||||
"""
|
||||
reg_val_str = self._get_formatted_value()
|
||||
|
||||
if self.default is not None:
|
||||
default = f'{self.default:X}'
|
||||
else:
|
||||
default = 'Not Provided'
|
||||
reg_str = f'[*] {self.name} = {reg_val_str} << {self.desc} (MSR 0x{self.msr:X} Thread 0x{self.thread:X}) [default: {default}]'
|
||||
|
||||
reg_str = (f'[*] {self.name} = {reg_val_str} << {self.desc} '
|
||||
f'({self.get_address_info()}) [default: {default}]')
|
||||
|
||||
reg_str += self._register_fields_str(True)
|
||||
return reg_str
|
||||
|
||||
def __str__(self) -> str:
|
||||
reg_str = ''
|
||||
if self.value is not None:
|
||||
reg_val_str = f'0x{self.value:0{self.size * 2}X}'
|
||||
else:
|
||||
reg_val_str = self.value
|
||||
"""
|
||||
String representation of MSR register.
|
||||
|
||||
reg_str = f'[*] {self.name} = {reg_val_str} << {self.desc} (MSR 0x{self.msr:X} Thread 0x{self.thread:X})'
|
||||
Returns:
|
||||
Formatted string with register details
|
||||
"""
|
||||
reg_val_str = self._get_formatted_value()
|
||||
|
||||
reg_str = (f'[*] {self.name} = {reg_val_str} << {self.desc} '
|
||||
f'({self.get_address_info()})')
|
||||
|
||||
reg_str += self._register_fields_str()
|
||||
return reg_str
|
||||
|
||||
def read(self):
|
||||
"""Read the object"""
|
||||
self.logger.log_debug(f'reading {self.name}')
|
||||
_cs = cs()
|
||||
(eax, edx) = _cs.hals.Msr.read_msr(self.thread, self.msr)
|
||||
self.value = (edx << 32) | eax
|
||||
return self.value
|
||||
def read(self) -> int:
|
||||
"""
|
||||
Read the MSR register value.
|
||||
|
||||
def write(self, value):
|
||||
"""Write the object"""
|
||||
_cs = cs()
|
||||
eax = value & 0xFFFFFFFF
|
||||
edx = (value >> 32) & 0xFFFFFFFF
|
||||
_cs.hals.Msr.write(self.thread, self.msr, eax, edx)
|
||||
Returns:
|
||||
Current register value
|
||||
|
||||
Raises:
|
||||
MSRRegisterError: If read operation fails
|
||||
"""
|
||||
try:
|
||||
self.logger.log_debug(f'reading {self.name}')
|
||||
_cs = cs()
|
||||
eax, edx = _cs.hals.Msr.read_msr(self.thread, self.msr)
|
||||
self.value = self._combine_32bit_values(eax, edx)
|
||||
return self.value
|
||||
except Exception as e:
|
||||
raise MSRRegisterError(
|
||||
f"Failed to read MSR register {self.name} at {self.get_address_info()}: {e}"
|
||||
) from e
|
||||
|
||||
def write(self, value: int) -> None:
|
||||
"""
|
||||
Write a value to the MSR register.
|
||||
|
||||
Args:
|
||||
value: Value to write to the register
|
||||
|
||||
Raises:
|
||||
MSRRegisterError: If write operation fails
|
||||
"""
|
||||
try:
|
||||
self.logger.log_debug(f'writing 0x{value:X} to {self.name}')
|
||||
_cs = cs()
|
||||
eax, edx = self._split_64bit_value(value)
|
||||
_cs.hals.Msr.write(self.thread, self.msr, eax, edx)
|
||||
self.value = value
|
||||
except Exception as e:
|
||||
raise MSRRegisterError(
|
||||
f"Failed to write to MSR register {self.name} at {self.get_address_info()}: {e}"
|
||||
) from e
|
||||
|
||||
@@ -17,17 +17,164 @@
|
||||
# Contact information:
|
||||
# chipsec@intel.com
|
||||
|
||||
"""
|
||||
PCI Register Configuration Helper
|
||||
|
||||
Provides PCI configuration space register-specific functionality.
|
||||
"""
|
||||
|
||||
from typing import Dict, Any, Union
|
||||
|
||||
from chipsec.chipset import cs
|
||||
from chipsec.library.register import BaseConfigRegisterHelper
|
||||
from chipsec.library.exceptions import CSReadError
|
||||
from chipsec.library.exceptions import CSReadError, CSConfigError
|
||||
|
||||
|
||||
class PCIRegisterError(CSConfigError):
|
||||
"""Custom exception for PCI register configuration errors."""
|
||||
pass
|
||||
|
||||
|
||||
class PCIRegisters(BaseConfigRegisterHelper):
|
||||
def __init__(self, cfg_obj, pci_obj):
|
||||
super(PCIRegisters, self).__init__(cfg_obj)
|
||||
self.size = cfg_obj['size']
|
||||
self.offset = cfg_obj['offset']
|
||||
self.pci = pci_obj
|
||||
"""
|
||||
PCI register configuration helper for PCI configuration space registers.
|
||||
|
||||
Manages PCI configuration space register access including bus, device,
|
||||
function addressing and register offset handling.
|
||||
"""
|
||||
|
||||
def __init__(self, cfg_obj: Dict[str, Any], pci_obj):
|
||||
"""
|
||||
Initialize PCI register configuration helper.
|
||||
|
||||
Args:
|
||||
cfg_obj: Configuration object containing PCI register fields
|
||||
pci_obj: PCI object containing bus/device/function information
|
||||
|
||||
Raises:
|
||||
PCIRegisterError: If PCI register configuration is invalid
|
||||
"""
|
||||
try:
|
||||
super().__init__(cfg_obj)
|
||||
|
||||
# Required fields for PCI registers
|
||||
required_fields = ['size', 'offset']
|
||||
missing_fields = [field for field in required_fields
|
||||
if field not in cfg_obj]
|
||||
if missing_fields:
|
||||
raise PCIRegisterError(
|
||||
f"Missing required PCI register fields: {missing_fields}")
|
||||
|
||||
self.size: int = cfg_obj['size']
|
||||
self.offset: Union[int, str] = cfg_obj['offset']
|
||||
self.pci = pci_obj
|
||||
|
||||
# Validate configuration
|
||||
if not self.validate_pci_register_config():
|
||||
raise PCIRegisterError("Invalid PCI register configuration")
|
||||
|
||||
except Exception as e:
|
||||
if isinstance(e, (PCIRegisterError, CSConfigError)):
|
||||
raise
|
||||
raise PCIRegisterError(
|
||||
f"Error initializing PCI register: {str(e)}") from e
|
||||
|
||||
def validate_pci_register_config(self) -> bool:
|
||||
"""
|
||||
Validate PCI register-specific configuration.
|
||||
|
||||
Returns:
|
||||
True if PCI register configuration is valid, False otherwise
|
||||
"""
|
||||
try:
|
||||
# Validate size
|
||||
if not isinstance(self.size, int) or self.size <= 0:
|
||||
return False
|
||||
|
||||
# Validate offset
|
||||
if isinstance(self.offset, str):
|
||||
try:
|
||||
int(self.offset, 16 if self.offset.startswith('0x') else 10)
|
||||
except ValueError:
|
||||
return False
|
||||
elif not isinstance(self.offset, int):
|
||||
return False
|
||||
|
||||
# Validate PCI object
|
||||
if self.pci is None:
|
||||
return False
|
||||
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def get_offset_int(self) -> int:
|
||||
"""
|
||||
Get register offset as integer value.
|
||||
|
||||
Returns:
|
||||
Offset as integer
|
||||
|
||||
Raises:
|
||||
PCIRegisterError: If offset cannot be converted to integer
|
||||
"""
|
||||
try:
|
||||
if isinstance(self.offset, int):
|
||||
return self.offset
|
||||
elif isinstance(self.offset, str):
|
||||
return int(self.offset,
|
||||
16 if self.offset.startswith('0x') else 10)
|
||||
else:
|
||||
raise PCIRegisterError(
|
||||
f"Invalid offset type: {type(self.offset)}")
|
||||
except ValueError as e:
|
||||
raise PCIRegisterError(
|
||||
f"Cannot convert offset to integer: {self.offset}") from e
|
||||
|
||||
def get_bdf_string(self) -> str:
|
||||
"""
|
||||
Get Bus:Device:Function as formatted string.
|
||||
|
||||
Returns:
|
||||
BDF string or 'Unknown' if PCI object is invalid
|
||||
"""
|
||||
try:
|
||||
if self.pci and hasattr(self.pci, 'bus') and self.pci.bus is not None:
|
||||
bus = f'{self.pci.bus:02d}'
|
||||
dev = f'{self.pci.dev:02d}' if self.pci.dev is not None else 'XX'
|
||||
fun = f'{self.pci.fun:01d}' if self.pci.fun is not None else 'X'
|
||||
return f'{bus}:{dev}.{fun}'
|
||||
return 'Unknown'
|
||||
except Exception:
|
||||
return 'Unknown'
|
||||
|
||||
def get_register_summary(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Get summary of PCI register configuration.
|
||||
|
||||
Returns:
|
||||
Dictionary with PCI register configuration summary
|
||||
"""
|
||||
try:
|
||||
return {
|
||||
'name': self.name,
|
||||
'bdf': self.get_bdf_string(),
|
||||
'offset': self.get_offset_int(),
|
||||
'size': self.size,
|
||||
'desc': getattr(self, 'desc', None),
|
||||
'is_valid': self.validate_pci_register_config(),
|
||||
'has_value': self.value is not None
|
||||
}
|
||||
except Exception:
|
||||
return {
|
||||
'name': getattr(self, 'name', 'Unknown'),
|
||||
'bdf': 'Unknown',
|
||||
'offset': 0,
|
||||
'size': 0,
|
||||
'desc': None,
|
||||
'is_valid': False,
|
||||
'has_value': False
|
||||
}
|
||||
|
||||
def __repr__(self) -> str:
|
||||
reg_str = ''
|
||||
|
||||
Reference in New Issue
Block a user