Update Register objects

Signed-off-by: brentholtsclaw <brent.holtsclaw@intel.com>
This commit is contained in:
brentholtsclaw
2025-07-07 10:41:55 -07:00
committed by Nathaniel Mitchell
parent 513fa89384
commit da143f80da
11 changed files with 2067 additions and 282 deletions
+189 -22
View File
@@ -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})")
+149 -18
View File
@@ -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
+213 -30
View File
@@ -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
+198 -3
View File
@@ -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
)
+187 -27
View File
@@ -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
+164 -23
View File
@@ -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
+211 -50
View File
@@ -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
+242 -51
View File
@@ -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
+159 -19
View File
@@ -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
+202 -33
View File
@@ -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
+153 -6
View File
@@ -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 = ''