mirror of
https://github.com/chipsec/chipsec
synced 2026-06-08 13:31:00 +00:00
Update ip objects
Signed-off-by: brentholtsclaw <brent.holtsclaw@intel.com>
This commit is contained in:
committed by
Nathaniel Mitchell
parent
da143f80da
commit
97aa48963c
@@ -17,19 +17,264 @@
|
||||
# Contact information:
|
||||
# chipsec@intel.com
|
||||
|
||||
"""
|
||||
Generic IP Configuration Helper
|
||||
|
||||
This module provides generic configuration management functionality for IP-based parsers.
|
||||
It serves as the base class for all IP-specific configuration helpers, offering common
|
||||
functionality like configuration validation, manipulation, and utility methods.
|
||||
"""
|
||||
|
||||
from typing import Dict, Any, List, Optional
|
||||
|
||||
from chipsec.parsers import BaseConfigHelper
|
||||
|
||||
|
||||
class GenericConfig(BaseConfigHelper):
|
||||
def __init__(self, cfg_obj):
|
||||
super(GenericConfig, self).__init__(cfg_obj)
|
||||
self.name = cfg_obj['name']
|
||||
if 'config' in cfg_obj:
|
||||
self.config = cfg_obj['config']
|
||||
else:
|
||||
self.config = []
|
||||
class GenericConfigError(Exception):
|
||||
"""Custom exception for generic configuration errors."""
|
||||
pass
|
||||
|
||||
def add_config(self, config):
|
||||
for cfg in config:
|
||||
if cfg not in self.config:
|
||||
self.config.append(cfg)
|
||||
|
||||
class GenericConfig(BaseConfigHelper):
|
||||
"""
|
||||
Generic configuration helper for IP-based parsers.
|
||||
|
||||
Provides basic configuration management functionality that can be
|
||||
extended by specific IP parsers.
|
||||
"""
|
||||
|
||||
def __init__(self, cfg_obj: Dict[str, Any]):
|
||||
"""
|
||||
Initialize generic configuration helper.
|
||||
|
||||
Args:
|
||||
cfg_obj: Configuration object containing name and optional config list
|
||||
|
||||
Raises:
|
||||
GenericConfigError: If required configuration is missing
|
||||
"""
|
||||
try:
|
||||
super().__init__(cfg_obj)
|
||||
|
||||
if 'name' not in cfg_obj:
|
||||
raise GenericConfigError("Missing required 'name' field in configuration object")
|
||||
|
||||
self.name: str = cfg_obj['name']
|
||||
self.config: List[Any] = cfg_obj.get('config', [])
|
||||
|
||||
except Exception as e:
|
||||
raise GenericConfigError(f"Error initializing generic configuration: {str(e)}") from e
|
||||
|
||||
def add_config(self, config: List[Any]) -> None:
|
||||
"""
|
||||
Add configurations to the current configuration list.
|
||||
|
||||
Args:
|
||||
config: List of configuration items to add
|
||||
|
||||
Raises:
|
||||
GenericConfigError: If configuration addition fails
|
||||
"""
|
||||
try:
|
||||
if not isinstance(config, list):
|
||||
raise GenericConfigError("Configuration must be a list")
|
||||
|
||||
for cfg in config:
|
||||
if cfg not in self.config:
|
||||
self.config.append(cfg)
|
||||
except Exception as e:
|
||||
raise GenericConfigError(f"Error adding configuration: {str(e)}") from e
|
||||
|
||||
def remove_config(self, config_item: Any) -> bool:
|
||||
"""
|
||||
Remove a configuration item from the configuration list.
|
||||
|
||||
Args:
|
||||
config_item: Configuration item to remove
|
||||
|
||||
Returns:
|
||||
True if item was removed, False if not found
|
||||
"""
|
||||
try:
|
||||
if config_item in self.config:
|
||||
self.config.remove(config_item)
|
||||
return True
|
||||
return False
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def clear_config(self) -> None:
|
||||
"""Clear all configuration items."""
|
||||
self.config.clear()
|
||||
|
||||
def get_config_count(self) -> int:
|
||||
"""Get the number of configuration items."""
|
||||
return len(self.config)
|
||||
|
||||
def has_config(self, config_item: Any) -> bool:
|
||||
"""
|
||||
Check if a configuration item exists.
|
||||
|
||||
Args:
|
||||
config_item: Configuration item to check
|
||||
|
||||
Returns:
|
||||
True if item exists, False otherwise
|
||||
"""
|
||||
return config_item in self.config
|
||||
|
||||
def get_config_copy(self) -> List[Any]:
|
||||
"""Get a copy of the current configuration list."""
|
||||
return self.config.copy()
|
||||
|
||||
def validate_config(self) -> bool:
|
||||
"""
|
||||
Validate the current configuration comprehensively.
|
||||
|
||||
Performs validation of:
|
||||
- Name field presence and type
|
||||
- Configuration list type and structure
|
||||
- Basic consistency checks
|
||||
|
||||
Returns:
|
||||
True if configuration is valid, False otherwise
|
||||
"""
|
||||
try:
|
||||
# Basic validation - ensure name exists and is a non-empty string
|
||||
if not self.name or not isinstance(self.name, str) or not self.name.strip():
|
||||
return False
|
||||
|
||||
# Ensure config is a list
|
||||
if not isinstance(self.config, list):
|
||||
return False
|
||||
|
||||
# Additional validation - check for None values in config
|
||||
if any(item is None for item in self.config):
|
||||
return False
|
||||
|
||||
# Check for duplicate configurations (if they're hashable)
|
||||
try:
|
||||
unique_configs = set()
|
||||
for item in self.config:
|
||||
if isinstance(item, (str, int, float, bool, tuple)):
|
||||
if item in unique_configs:
|
||||
# Found duplicate, but this might be intentional
|
||||
pass
|
||||
unique_configs.add(item)
|
||||
except (TypeError, AttributeError):
|
||||
# Items are not hashable, skip duplicate check
|
||||
pass
|
||||
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""Return detailed string representation of the configuration."""
|
||||
return f"GenericConfig(name='{self.name}', config_count={len(self.config)})"
|
||||
|
||||
def __str__(self) -> str:
|
||||
"""Return human-readable string representation of the configuration."""
|
||||
status = "valid" if self.validate_config() else "invalid"
|
||||
return f"GenericConfig '{self.name}' with {len(self.config)} items ({status})"
|
||||
|
||||
def update_config(self, config_updates: List[Any]) -> None:
|
||||
"""
|
||||
Update configuration by replacing existing items with new ones.
|
||||
|
||||
Args:
|
||||
config_updates: List of configuration items to update or add
|
||||
|
||||
Raises:
|
||||
GenericConfigError: If configuration update fails
|
||||
"""
|
||||
try:
|
||||
if not isinstance(config_updates, list):
|
||||
raise GenericConfigError("Configuration updates must be a list")
|
||||
|
||||
# Clear existing and add new configurations
|
||||
self.config.clear()
|
||||
self.config.extend(config_updates)
|
||||
|
||||
except Exception as e:
|
||||
raise GenericConfigError(f"Error updating configuration: {str(e)}") from e
|
||||
|
||||
def find_config(self, predicate) -> Optional[Any]:
|
||||
"""
|
||||
Find the first configuration item that matches the given predicate.
|
||||
|
||||
Args:
|
||||
predicate: Function that takes a config item and returns True/False
|
||||
|
||||
Returns:
|
||||
First matching configuration item, or None if not found
|
||||
"""
|
||||
try:
|
||||
for config_item in self.config:
|
||||
if predicate(config_item):
|
||||
return config_item
|
||||
return None
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def filter_config(self, predicate) -> List[Any]:
|
||||
"""
|
||||
Filter configuration items based on a predicate function.
|
||||
|
||||
Args:
|
||||
predicate: Function that takes a config item and returns True/False
|
||||
|
||||
Returns:
|
||||
List of configuration items that match the predicate
|
||||
"""
|
||||
try:
|
||||
return [item for item in self.config if predicate(item)]
|
||||
except Exception:
|
||||
return []
|
||||
|
||||
def merge_config(self, other_config: 'GenericConfig') -> None:
|
||||
"""
|
||||
Merge configuration from another GenericConfig instance.
|
||||
|
||||
Args:
|
||||
other_config: Another GenericConfig instance to merge from
|
||||
|
||||
Raises:
|
||||
GenericConfigError: If merge operation fails
|
||||
"""
|
||||
try:
|
||||
if not isinstance(other_config, GenericConfig):
|
||||
raise GenericConfigError("Can only merge with another GenericConfig instance")
|
||||
|
||||
# Add items from other config that don't already exist
|
||||
for item in other_config.config:
|
||||
if item not in self.config:
|
||||
self.config.append(item)
|
||||
|
||||
except Exception as e:
|
||||
raise GenericConfigError(f"Error merging configuration: {str(e)}") from e
|
||||
|
||||
def get_config_summary(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Get a summary of the current configuration.
|
||||
|
||||
Returns:
|
||||
Dictionary containing configuration summary information
|
||||
"""
|
||||
try:
|
||||
unique_types = set(type(item).__name__ for item in self.config)
|
||||
return {
|
||||
'name': self.name,
|
||||
'total_items': len(self.config),
|
||||
'unique_types': list(unique_types),
|
||||
'is_valid': self.validate_config(),
|
||||
'is_empty': len(self.config) == 0
|
||||
}
|
||||
except Exception:
|
||||
return {
|
||||
'name': getattr(self, 'name', 'Unknown'),
|
||||
'total_items': 0,
|
||||
'unique_types': [],
|
||||
'is_valid': False,
|
||||
'is_empty': True
|
||||
}
|
||||
|
||||
@@ -17,15 +17,143 @@
|
||||
# Contact information:
|
||||
# chipsec@intel.com
|
||||
|
||||
from chipsec.cfg.parsers.ip.generic import GenericConfig
|
||||
"""
|
||||
I/O Port IP Configuration Helper
|
||||
|
||||
Provides I/O port-specific configuration management functionality for
|
||||
I/O port-based IP parsers.
|
||||
"""
|
||||
|
||||
from typing import Dict, Any, Union
|
||||
|
||||
from chipsec.cfg.parsers.ip.generic import GenericConfig, GenericConfigError
|
||||
|
||||
|
||||
class IOConfigError(GenericConfigError):
|
||||
"""Custom exception for I/O configuration errors."""
|
||||
pass
|
||||
|
||||
|
||||
class IOConfig(GenericConfig):
|
||||
def __init__(self, cfg_obj):
|
||||
super(IOConfig, self).__init__(cfg_obj)
|
||||
self.port = cfg_obj['port']
|
||||
"""
|
||||
I/O configuration helper for I/O port-based IP regions.
|
||||
|
||||
Handles configuration of I/O port-based IP including port addresses
|
||||
and access management.
|
||||
"""
|
||||
|
||||
def __init__(self, cfg_obj: Dict[str, Any]):
|
||||
"""
|
||||
Initialize I/O configuration helper.
|
||||
|
||||
Args:
|
||||
cfg_obj: Configuration object containing I/O-specific fields
|
||||
|
||||
Raises:
|
||||
IOConfigError: If required I/O configuration is missing or invalid
|
||||
"""
|
||||
try:
|
||||
super().__init__(cfg_obj)
|
||||
|
||||
# Required field for I/O configuration
|
||||
if 'port' not in cfg_obj:
|
||||
raise IOConfigError("Missing required 'port' field")
|
||||
|
||||
self.port: Union[int, str] = cfg_obj['port']
|
||||
|
||||
# Validate configuration after initialization
|
||||
if not self.validate_io_config():
|
||||
raise IOConfigError("Invalid I/O configuration detected")
|
||||
|
||||
except Exception as e:
|
||||
if isinstance(e, IOConfigError):
|
||||
raise
|
||||
raise IOConfigError(
|
||||
f"Error initializing I/O configuration: {str(e)}") from e
|
||||
|
||||
def validate_io_config(self) -> bool:
|
||||
"""
|
||||
Validate I/O-specific configuration.
|
||||
|
||||
Returns:
|
||||
True if I/O configuration is valid, False otherwise
|
||||
"""
|
||||
try:
|
||||
# Call parent validation first
|
||||
if not self.validate_config():
|
||||
return False
|
||||
|
||||
# Validate port (can be int or hex string)
|
||||
if isinstance(self.port, str):
|
||||
try:
|
||||
int(self.port, 16 if self.port.startswith('0x') else 10)
|
||||
except ValueError:
|
||||
return False
|
||||
elif not isinstance(self.port, int):
|
||||
return False
|
||||
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def get_port_int(self) -> int:
|
||||
"""
|
||||
Get port as integer value.
|
||||
|
||||
Returns:
|
||||
Port as integer
|
||||
|
||||
Raises:
|
||||
IOConfigError: If port cannot be converted to integer
|
||||
"""
|
||||
try:
|
||||
if isinstance(self.port, int):
|
||||
return self.port
|
||||
elif isinstance(self.port, str):
|
||||
return int(self.port,
|
||||
16 if self.port.startswith('0x') else 10)
|
||||
else:
|
||||
raise IOConfigError(f"Invalid port type: {type(self.port)}")
|
||||
except ValueError as e:
|
||||
raise IOConfigError(
|
||||
f"Cannot convert port to integer: {self.port}") from e
|
||||
|
||||
def get_io_summary(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Get summary of I/O configuration.
|
||||
|
||||
Returns:
|
||||
Dictionary with I/O configuration summary
|
||||
"""
|
||||
try:
|
||||
return {
|
||||
'name': self.name,
|
||||
'port': self.get_port_int(),
|
||||
'is_valid': self.validate_io_config(),
|
||||
'config_items': len(self.config)
|
||||
}
|
||||
except Exception:
|
||||
return {
|
||||
'name': getattr(self, 'name', 'Unknown'),
|
||||
'port': 0,
|
||||
'is_valid': False,
|
||||
'config_items': 0
|
||||
}
|
||||
|
||||
def __str__(self) -> str:
|
||||
ret = f'name: {self.name}, port: {self.port}'
|
||||
ret += f', config: {self.config}'
|
||||
return ret
|
||||
"""Return human-readable string representation."""
|
||||
try:
|
||||
port_str = f"0x{self.get_port_int():x}"
|
||||
ret = f'name: {self.name}, port: {port_str}'
|
||||
ret += f', config: {len(self.config)} items'
|
||||
return ret
|
||||
except Exception:
|
||||
# Fallback to basic representation if conversion fails
|
||||
ret = f'name: {self.name}, port: {self.port}'
|
||||
ret += f', config: {self.config}'
|
||||
return ret
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""Return detailed string representation."""
|
||||
return (f"IOConfig(name='{self.name}', port={self.port}, "
|
||||
f"config_count={len(self.config)})")
|
||||
|
||||
+283
-23
@@ -17,48 +17,308 @@
|
||||
# Contact information:
|
||||
# chipsec@intel.com
|
||||
|
||||
from chipsec.cfg.parsers.ip.generic import GenericConfig
|
||||
"""
|
||||
I/O BAR IP Configuration Helper
|
||||
|
||||
Provides I/O BAR-specific configuration management functionality for
|
||||
I/O base address registers.
|
||||
"""
|
||||
|
||||
from typing import Dict, Any, Optional, Union, TYPE_CHECKING
|
||||
|
||||
from chipsec.cfg.parsers.ip.generic import GenericConfig, GenericConfigError
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from chipsec.cfg.parsers.ip.pci_device import PCIObj
|
||||
|
||||
|
||||
class IOBarConfigError(GenericConfigError):
|
||||
"""Custom exception for I/O BAR configuration errors."""
|
||||
pass
|
||||
|
||||
|
||||
class IOObj:
|
||||
"""
|
||||
I/O object representing an I/O port region.
|
||||
|
||||
Contains base address, size, and associated PCI instance information.
|
||||
"""
|
||||
|
||||
def __init__(self, instance: 'PCIObj'):
|
||||
self.base = None
|
||||
self.size = 0
|
||||
"""
|
||||
Initialize I/O object.
|
||||
|
||||
Args:
|
||||
instance: Associated PCI object instance
|
||||
"""
|
||||
self.base: Optional[int] = None
|
||||
self.size: int = 0
|
||||
self.instance = instance
|
||||
|
||||
def set_base_and_size(self, base: Optional[int], size: int) -> None:
|
||||
"""
|
||||
Set base address and size for the I/O region.
|
||||
|
||||
Args:
|
||||
base: Base address (can be None)
|
||||
size: Size of the I/O region
|
||||
|
||||
Raises:
|
||||
IOBarConfigError: If parameters are invalid
|
||||
"""
|
||||
try:
|
||||
if base is not None and not isinstance(base, int):
|
||||
raise IOBarConfigError(
|
||||
"Base address must be an integer or None")
|
||||
if not isinstance(size, int) or size < 0:
|
||||
raise IOBarConfigError(
|
||||
"Size must be a non-negative integer")
|
||||
|
||||
self.base = base
|
||||
self.size = size
|
||||
except Exception as e:
|
||||
if isinstance(e, IOBarConfigError):
|
||||
raise
|
||||
raise IOBarConfigError(
|
||||
f"Error setting I/O base and size: {str(e)}") from e
|
||||
|
||||
def is_valid(self) -> bool:
|
||||
"""
|
||||
Check if I/O object is valid.
|
||||
|
||||
Returns:
|
||||
True if I/O object has valid configuration
|
||||
"""
|
||||
return (self.base is not None and
|
||||
isinstance(self.size, int) and
|
||||
self.size >= 0 and
|
||||
self.instance is not None)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f'instance: {self.instance}, base: {self.base}'
|
||||
"""Return human-readable string representation."""
|
||||
basestr = f'0x{self.base:X}' if self.base else 'None'
|
||||
return (f'instance: {self.instance}, base: {basestr}, '
|
||||
f'size: 0x{self.size:X}')
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""Return detailed string representation."""
|
||||
return (f"IOObj(base={self.base}, size={self.size}, "
|
||||
f"instance={self.instance})")
|
||||
|
||||
def __eq__(self, other) -> bool:
|
||||
"""
|
||||
Check equality with another I/O object.
|
||||
|
||||
Args:
|
||||
other: Object to compare with
|
||||
|
||||
Returns:
|
||||
True if objects are equal, False otherwise
|
||||
"""
|
||||
if not isinstance(other, IOObj):
|
||||
return False
|
||||
return (self.base == other.base and
|
||||
self.size == other.size and
|
||||
self.instance == other.instance)
|
||||
|
||||
def __hash__(self) -> int:
|
||||
"""
|
||||
Generate a hash value for the IOObj instance.
|
||||
|
||||
This allows IOObj instances to be used as dictionary keys.
|
||||
|
||||
Returns:
|
||||
Hash value based on base, size, and instance
|
||||
"""
|
||||
# Use instance hash if it implements __hash__, otherwise use id()
|
||||
instance_hash = hash(self.instance) \
|
||||
if hasattr(self.instance, '__hash__') else id(self.instance)
|
||||
return hash((self.base, self.size, instance_hash))
|
||||
|
||||
|
||||
class IOBarConfig(GenericConfig):
|
||||
def __init__(self, cfg_obj):
|
||||
super(IOBarConfig, self).__init__(cfg_obj)
|
||||
self.device = cfg_obj['device']
|
||||
self.register = cfg_obj['register']
|
||||
self.base_field = cfg_obj['base_field']
|
||||
self.fixed_address = cfg_obj['fixed_address'] if 'fixed_address' in cfg_obj else None
|
||||
self.mask = cfg_obj['mask'] if 'mask' in cfg_obj else None
|
||||
self.offset = cfg_obj['offset'] if 'offset' in cfg_obj else None
|
||||
self.size = cfg_obj['size'] if 'did' in cfg_obj else None
|
||||
self.enable_field = cfg_obj['enable_field'] if 'enable_field' in cfg_obj else None
|
||||
self.desc = cfg_obj['desc']
|
||||
self.instances = {}
|
||||
for key in cfg_obj['ids']:
|
||||
self.add_obj(key)
|
||||
"""
|
||||
I/O BAR configuration helper for I/O base address registers.
|
||||
|
||||
def add_obj(self, key):
|
||||
self.instances[key] = IOObj(key)
|
||||
Manages I/O BAR configurations including register mappings, base fields,
|
||||
and device instances.
|
||||
"""
|
||||
|
||||
def update_base_address(self, base, instance):
|
||||
if instance in self.instances:
|
||||
def __init__(self, cfg_obj: Dict[str, Any]):
|
||||
"""
|
||||
Initialize I/O BAR configuration helper.
|
||||
|
||||
Args:
|
||||
cfg_obj: Configuration object containing I/O BAR-specific fields
|
||||
|
||||
Raises:
|
||||
IOBarConfigError: If I/O BAR configuration initialization fails
|
||||
"""
|
||||
try:
|
||||
super().__init__(cfg_obj)
|
||||
|
||||
# Required fields
|
||||
required_fields = ['device', 'register', 'base_field', 'desc']
|
||||
missing_fields = [field for field in required_fields
|
||||
if field not in cfg_obj]
|
||||
if missing_fields:
|
||||
raise IOBarConfigError(
|
||||
f"Missing required I/O BAR fields: {missing_fields}")
|
||||
|
||||
self.device: str = cfg_obj['device']
|
||||
self.register: str = cfg_obj['register']
|
||||
self.base_field: str = cfg_obj['base_field']
|
||||
self.desc: str = cfg_obj['desc']
|
||||
|
||||
# Optional fields
|
||||
self.fixed_address: Optional[Union[int, str]] = cfg_obj.get(
|
||||
'fixed_address')
|
||||
self.mask: Optional[Union[int, str]] = cfg_obj.get('mask')
|
||||
self.offset: Optional[Union[int, str]] = cfg_obj.get('offset')
|
||||
self.size: Optional[Union[int, str]] = cfg_obj.get('size')
|
||||
self.enable_field: Optional[str] = cfg_obj.get('enable_field')
|
||||
|
||||
# Initialize instances
|
||||
self.instances: Dict[Any, IOObj] = {}
|
||||
if 'ids' in cfg_obj:
|
||||
for key in cfg_obj['ids']:
|
||||
self.add_obj(key)
|
||||
|
||||
except Exception as e:
|
||||
if isinstance(e, (IOBarConfigError, GenericConfigError)):
|
||||
raise
|
||||
raise IOBarConfigError(
|
||||
f"Error initializing I/O BAR configuration: {str(e)}") from e
|
||||
|
||||
def add_obj(self, key) -> None:
|
||||
"""
|
||||
Add a new I/O object instance.
|
||||
|
||||
Args:
|
||||
key: Key identifier for the I/O instance
|
||||
|
||||
Raises:
|
||||
IOBarConfigError: If I/O object creation fails
|
||||
"""
|
||||
try:
|
||||
self.instances[key] = IOObj(key)
|
||||
except Exception as e:
|
||||
raise IOBarConfigError(
|
||||
f"Error adding I/O object: {str(e)}") from e
|
||||
|
||||
def remove_instance(self, key) -> bool:
|
||||
"""
|
||||
Remove an I/O instance by key.
|
||||
|
||||
Args:
|
||||
key: Key identifier for the instance to remove
|
||||
|
||||
Returns:
|
||||
True if instance was removed, False if not found
|
||||
"""
|
||||
if key in self.instances:
|
||||
del self.instances[key]
|
||||
return True
|
||||
return False
|
||||
|
||||
def update_base_address(self, base: Optional[int], instance) -> None:
|
||||
"""
|
||||
Update base address for a specific instance.
|
||||
|
||||
Args:
|
||||
base: New base address
|
||||
instance: Instance identifier
|
||||
|
||||
Raises:
|
||||
IOBarConfigError: If instance not found or update fails
|
||||
"""
|
||||
try:
|
||||
if instance not in self.instances:
|
||||
raise IOBarConfigError(f"Instance {instance} not found")
|
||||
self.instances[instance].base = base
|
||||
except Exception as e:
|
||||
if isinstance(e, IOBarConfigError):
|
||||
raise
|
||||
raise IOBarConfigError(
|
||||
f"Error updating base address: {str(e)}") from e
|
||||
|
||||
def get_base(self, instance):
|
||||
"""
|
||||
Get base address and size for a specific instance.
|
||||
|
||||
Args:
|
||||
instance: Instance identifier
|
||||
|
||||
Returns:
|
||||
Tuple of (base_address, size) or (None, 0) if not found
|
||||
"""
|
||||
if instance in self.instances:
|
||||
return self.instances[instance].base, self.instances[instance].size
|
||||
return self.instances[instance].base, self.size
|
||||
else:
|
||||
return (None, 0)
|
||||
|
||||
def get_instance_count(self) -> int:
|
||||
"""Get the total number of I/O instances."""
|
||||
return len(self.instances)
|
||||
|
||||
def validate_iobar_config(self) -> bool:
|
||||
"""
|
||||
Validate I/O BAR-specific configuration.
|
||||
|
||||
Returns:
|
||||
True if I/O BAR configuration is valid, False otherwise
|
||||
"""
|
||||
try:
|
||||
# Call parent validation first
|
||||
if not self.validate_config():
|
||||
return False
|
||||
|
||||
# Validate required fields
|
||||
required_attrs = ['device', 'register', 'base_field', 'desc']
|
||||
for attr in required_attrs:
|
||||
value = getattr(self, attr, None)
|
||||
if not value or not isinstance(value, str):
|
||||
return False
|
||||
|
||||
# Validate all I/O instances
|
||||
for inst in self.instances.values():
|
||||
if not inst.is_valid():
|
||||
return False
|
||||
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def get_iobar_summary(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Get summary of I/O BAR configuration.
|
||||
|
||||
Returns:
|
||||
Dictionary with I/O BAR configuration summary
|
||||
"""
|
||||
try:
|
||||
return {
|
||||
'name': self.name,
|
||||
'device': self.device,
|
||||
'register': self.register,
|
||||
'base_field': self.base_field,
|
||||
'size': self.size,
|
||||
'total_instances': len(self.instances),
|
||||
'is_valid': self.validate_iobar_config(),
|
||||
'config_items': len(self.config)
|
||||
}
|
||||
except Exception:
|
||||
return {
|
||||
'name': getattr(self, 'name', 'Unknown'),
|
||||
'device': getattr(self, 'device', None),
|
||||
'register': getattr(self, 'register', None),
|
||||
'base_field': getattr(self, 'base_field', None),
|
||||
'size': getattr(self, 'size', None),
|
||||
'total_instances': 0,
|
||||
'is_valid': False,
|
||||
'config_items': 0
|
||||
}
|
||||
|
||||
def __str__(self) -> str:
|
||||
ret = f'name: {self.name}, device: {self.device}'
|
||||
ret += f', register:{self.register}, base_field:{self.base_field}'
|
||||
|
||||
@@ -17,18 +17,198 @@
|
||||
# Contact information:
|
||||
# chipsec@intel.com
|
||||
|
||||
from chipsec.cfg.parsers.ip.generic import GenericConfig
|
||||
"""
|
||||
Memory IP Configuration Helper
|
||||
|
||||
Provides memory-specific configuration management functionality for
|
||||
memory-mapped regions.
|
||||
"""
|
||||
|
||||
from typing import Dict, Any, Union
|
||||
|
||||
from chipsec.cfg.parsers.ip.generic import GenericConfig, GenericConfigError
|
||||
|
||||
|
||||
class MemoryConfigError(GenericConfigError):
|
||||
"""Custom exception for memory configuration errors."""
|
||||
pass
|
||||
|
||||
|
||||
class MemoryConfig(GenericConfig):
|
||||
def __init__(self, cfg_obj):
|
||||
super(MemoryConfig, self).__init__(cfg_obj)
|
||||
self.access = cfg_obj['access']
|
||||
self.address = cfg_obj['address']
|
||||
self.limit = cfg_obj['limit']
|
||||
"""
|
||||
Memory configuration helper for memory-mapped IP regions.
|
||||
|
||||
Handles configuration of memory-mapped regions including access
|
||||
permissions, address ranges, and size limits.
|
||||
"""
|
||||
|
||||
def __init__(self, cfg_obj: Dict[str, Any]):
|
||||
"""
|
||||
Initialize memory configuration helper.
|
||||
|
||||
Args:
|
||||
cfg_obj: Configuration object containing memory-specific fields
|
||||
|
||||
Raises:
|
||||
MemoryConfigError: If required memory configuration is missing
|
||||
or invalid
|
||||
"""
|
||||
try:
|
||||
super().__init__(cfg_obj)
|
||||
|
||||
# Required fields for memory configuration
|
||||
required_fields = ['access', 'address', 'limit']
|
||||
missing_fields = [field for field in required_fields
|
||||
if field not in cfg_obj]
|
||||
if missing_fields:
|
||||
raise MemoryConfigError(
|
||||
f"Missing required memory configuration fields: "
|
||||
f"{missing_fields}")
|
||||
|
||||
self.access: str = cfg_obj['access']
|
||||
self.address: Union[int, str] = cfg_obj['address']
|
||||
self.limit: Union[int, str] = cfg_obj['limit']
|
||||
|
||||
# Validate configuration after initialization
|
||||
if not self.validate_memory_config():
|
||||
raise MemoryConfigError(
|
||||
"Invalid memory configuration detected")
|
||||
|
||||
except Exception as e:
|
||||
if isinstance(e, MemoryConfigError):
|
||||
raise
|
||||
raise MemoryConfigError(
|
||||
f"Error initializing memory configuration: {str(e)}") from e
|
||||
|
||||
def validate_memory_config(self) -> bool:
|
||||
"""
|
||||
Validate memory-specific configuration.
|
||||
|
||||
Returns:
|
||||
True if memory configuration is valid, False otherwise
|
||||
"""
|
||||
try:
|
||||
# Call parent validation first
|
||||
if not self.validate_config():
|
||||
return False
|
||||
|
||||
# Validate access field
|
||||
if not isinstance(self.access, str) or not self.access.strip():
|
||||
return False
|
||||
|
||||
# Validate address and limit (can be int or hex string)
|
||||
for field_name, field_value in [('address', self.address),
|
||||
('limit', self.limit)]:
|
||||
if isinstance(field_value, str):
|
||||
# Try to parse as hex if it's a string
|
||||
try:
|
||||
int(field_value,
|
||||
16 if field_value.startswith('0x') else 10)
|
||||
except ValueError:
|
||||
return False
|
||||
elif not isinstance(field_value, int):
|
||||
return False
|
||||
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def get_address_int(self) -> int:
|
||||
"""
|
||||
Get address as integer value.
|
||||
|
||||
Returns:
|
||||
Address as integer
|
||||
|
||||
Raises:
|
||||
MemoryConfigError: If address cannot be converted to integer
|
||||
"""
|
||||
try:
|
||||
if isinstance(self.address, int):
|
||||
return self.address
|
||||
elif isinstance(self.address, str):
|
||||
return int(self.address,
|
||||
16 if self.address.startswith('0x') else 10)
|
||||
else:
|
||||
raise MemoryConfigError(
|
||||
f"Invalid address type: {type(self.address)}")
|
||||
except ValueError as e:
|
||||
raise MemoryConfigError(
|
||||
f"Cannot convert address to integer: {self.address}") from e
|
||||
|
||||
def get_limit_int(self) -> int:
|
||||
"""
|
||||
Get limit as integer value.
|
||||
|
||||
Returns:
|
||||
Limit as integer
|
||||
|
||||
Raises:
|
||||
MemoryConfigError: If limit cannot be converted to integer
|
||||
"""
|
||||
try:
|
||||
if isinstance(self.limit, int):
|
||||
return self.limit
|
||||
elif isinstance(self.limit, str):
|
||||
return int(self.limit,
|
||||
16 if self.limit.startswith('0x') else 10)
|
||||
else:
|
||||
raise MemoryConfigError(
|
||||
f"Invalid limit type: {type(self.limit)}")
|
||||
except ValueError as e:
|
||||
raise MemoryConfigError(
|
||||
f"Cannot convert limit to integer: {self.limit}") from e
|
||||
|
||||
def get_memory_range(self) -> int:
|
||||
"""
|
||||
Calculate the memory range (limit - address).
|
||||
|
||||
Returns:
|
||||
Memory range size as integer
|
||||
|
||||
Raises:
|
||||
MemoryConfigError: If range calculation fails
|
||||
"""
|
||||
try:
|
||||
address_int = self.get_address_int()
|
||||
limit_int = self.get_limit_int()
|
||||
|
||||
if limit_int < address_int:
|
||||
raise MemoryConfigError(
|
||||
f"Invalid memory range: limit ({limit_int:x}) < "
|
||||
f"address ({address_int:x})")
|
||||
|
||||
return limit_int - address_int
|
||||
except Exception as e:
|
||||
if isinstance(e, MemoryConfigError):
|
||||
raise
|
||||
raise MemoryConfigError(
|
||||
f"Error calculating memory range: {str(e)}") from e
|
||||
|
||||
def __str__(self) -> str:
|
||||
ret = f'name: {self.name}, access: {self.access}'
|
||||
ret += f', address: {self.address}, limit: {self.limit}'
|
||||
ret += f', config: {self.config}'
|
||||
return ret
|
||||
"""Return human-readable string representation."""
|
||||
try:
|
||||
addr_str = (f"0x{self.get_address_int():x}"
|
||||
if isinstance(self.address, int)
|
||||
else str(self.address))
|
||||
limit_str = (f"0x{self.get_limit_int():x}"
|
||||
if isinstance(self.limit, int)
|
||||
else str(self.limit))
|
||||
range_size = self.get_memory_range()
|
||||
|
||||
ret = f'name: {self.name}, access: {self.access}'
|
||||
ret += f', address: {addr_str}, limit: {limit_str}'
|
||||
ret += f', range: 0x{range_size:x}, config: {len(self.config)} items'
|
||||
return ret
|
||||
except Exception:
|
||||
# Fallback to basic representation if conversion fails
|
||||
ret = f'name: {self.name}, access: {self.access}'
|
||||
ret += f', address: {self.address}, limit: {self.limit}'
|
||||
ret += f', config: {self.config}'
|
||||
return ret
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""Return detailed string representation."""
|
||||
return (f"MemoryConfig(name='{self.name}', access='{self.access}', "
|
||||
f"address={self.address}, limit={self.limit}, "
|
||||
f"config_count={len(self.config)})")
|
||||
|
||||
@@ -17,15 +17,136 @@
|
||||
# Contact information:
|
||||
# chipsec@intel.com
|
||||
|
||||
"""
|
||||
MM_MSGBUS (Memory-Mapped Message Bus) configuration parser.
|
||||
|
||||
This module provides MM_MSGBUSConfig class for parsing and managing memory-mapped message bus configurations
|
||||
in the CHIPSEC framework. Memory-mapped message buses provide MMIO-based communication interfaces.
|
||||
"""
|
||||
|
||||
from typing import Dict, Any, Optional
|
||||
from chipsec.cfg.parsers.ip.generic import GenericConfig
|
||||
from chipsec.library.exceptions import CSConfigError
|
||||
|
||||
|
||||
class MM_MSGBUSConfigError(CSConfigError):
|
||||
"""Exception raised for MM_MSGBUS configuration-specific errors."""
|
||||
pass
|
||||
|
||||
|
||||
class MM_MSGBUSConfig(GenericConfig):
|
||||
def __init__(self, cfg_obj):
|
||||
super(MM_MSGBUSConfig, self).__init__(cfg_obj)
|
||||
self.port = cfg_obj['port']
|
||||
"""
|
||||
MM_MSGBUS (Memory-Mapped Message Bus) configuration parser.
|
||||
|
||||
This class handles parsing and validation of memory-mapped message bus configurations,
|
||||
extending the base GenericConfig with MM_MSGBUS-specific functionality including port management.
|
||||
|
||||
Attributes:
|
||||
name (str): The name of the MM_MSGBUS configuration
|
||||
config (Dict[str, Any]): The raw configuration data
|
||||
port (Union[int, str]): The memory-mapped message bus port identifier
|
||||
|
||||
Example:
|
||||
>>> mm_msgbus_cfg = MM_MSGBUSConfig({'name': 'PUNIT_MM_MSGBUS', 'port': 0x04})
|
||||
>>> print(mm_msgbus_cfg.port)
|
||||
4
|
||||
"""
|
||||
|
||||
def __init__(self, cfg_obj: Dict[str, Any]) -> None:
|
||||
"""
|
||||
Initialize MM_MSGBUS configuration.
|
||||
|
||||
Args:
|
||||
cfg_obj: Dictionary containing MM_MSGBUS configuration data
|
||||
|
||||
Raises:
|
||||
MM_MSGBUSConfigError: If configuration validation fails
|
||||
"""
|
||||
try:
|
||||
super().__init__(cfg_obj)
|
||||
self.port = cfg_obj['port']
|
||||
self._validate_mm_msgbus_config()
|
||||
except KeyError as e:
|
||||
raise MM_MSGBUSConfigError(f"Missing required field in MM_MSGBUS configuration: {e}") from e
|
||||
except Exception as e:
|
||||
raise MM_MSGBUSConfigError(f"Failed to initialize MM_MSGBUS configuration: {e}") from e
|
||||
|
||||
def _validate_mm_msgbus_config(self) -> None:
|
||||
"""
|
||||
Validate MM_MSGBUS-specific configuration requirements.
|
||||
|
||||
Raises:
|
||||
MM_MSGBUSConfigError: If configuration is invalid
|
||||
"""
|
||||
if not self.name:
|
||||
raise MM_MSGBUSConfigError("MM_MSGBUS configuration must have a valid name")
|
||||
|
||||
if self.port is None:
|
||||
raise MM_MSGBUSConfigError("MM_MSGBUS configuration must have a valid port")
|
||||
|
||||
# Validate port format and range
|
||||
port_int = self.get_port_as_int()
|
||||
if port_int is None or port_int < 0 or port_int > 0xFF:
|
||||
raise MM_MSGBUSConfigError(f"Invalid port value: {self.port}. Must be 0-255 range")
|
||||
|
||||
def get_port_as_int(self) -> Optional[int]:
|
||||
"""
|
||||
Get the port as an integer value.
|
||||
|
||||
Returns:
|
||||
Port as integer, or None if conversion fails
|
||||
"""
|
||||
try:
|
||||
if isinstance(self.port, str):
|
||||
return int(self.port, 16) if self.port.startswith('0x') else int(self.port)
|
||||
return int(self.port)
|
||||
except (ValueError, TypeError):
|
||||
return None
|
||||
|
||||
def get_port_as_hex(self) -> str:
|
||||
"""
|
||||
Get the port as a hexadecimal string.
|
||||
|
||||
Returns:
|
||||
Port as hex string (e.g., '0x04')
|
||||
"""
|
||||
port_int = self.get_port_as_int()
|
||||
return f"0x{port_int:02X}" if port_int is not None else "0x00"
|
||||
|
||||
def is_valid_port(self) -> bool:
|
||||
"""
|
||||
Check if the port value is valid.
|
||||
|
||||
Returns:
|
||||
True if port is valid, False otherwise
|
||||
"""
|
||||
port_int = self.get_port_as_int()
|
||||
return port_int is not None and 0 <= port_int <= 0xFF
|
||||
|
||||
def is_memory_mapped(self) -> bool:
|
||||
"""
|
||||
Check if this is a memory-mapped message bus configuration.
|
||||
|
||||
Returns:
|
||||
True (always, as this is an MM_MSGBUS)
|
||||
"""
|
||||
return True
|
||||
|
||||
def __str__(self) -> str:
|
||||
ret = f'name: {self.name}, port: {self.port}'
|
||||
ret += f', config: {self.config}'
|
||||
return ret
|
||||
"""
|
||||
String representation of MM_MSGBUS configuration.
|
||||
|
||||
Returns:
|
||||
Formatted string with MM_MSGBUS details
|
||||
"""
|
||||
port_hex = self.get_port_as_hex()
|
||||
return f"MM_MSGBUSConfig(name='{self.name}', port={port_hex}, config={self.config})"
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""
|
||||
Detailed string representation for debugging.
|
||||
|
||||
Returns:
|
||||
Detailed string representation
|
||||
"""
|
||||
return f"MM_MSGBUSConfig(name='{self.name}', port={self.port}, config={self.config})"
|
||||
|
||||
@@ -17,95 +17,353 @@
|
||||
# Contact information:
|
||||
# chipsec@intel.com
|
||||
|
||||
from chipsec.cfg.parsers.ip.generic import GenericConfig
|
||||
"""
|
||||
MMIO BAR IP Configuration Helper
|
||||
|
||||
Provides MMIO BAR-specific configuration management functionality for
|
||||
memory-mapped I/O base address registers.
|
||||
"""
|
||||
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
|
||||
from chipsec.cfg.parsers.ip.generic import GenericConfig, GenericConfigError
|
||||
from chipsec.cfg.parsers.ip.platform import RegisterList
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from chipsec.cfg.parsers.ip.pci_device import PCIObj
|
||||
|
||||
|
||||
class MMIOBarConfigError(GenericConfigError):
|
||||
"""Custom exception for MMIO BAR configuration errors."""
|
||||
pass
|
||||
|
||||
|
||||
class MMIOObj:
|
||||
"""
|
||||
MMIO object representing a memory-mapped I/O region.
|
||||
|
||||
Contains base address, size, and associated PCI instance information.
|
||||
"""
|
||||
|
||||
def __init__(self, instance: 'PCIObj'):
|
||||
self.base = None
|
||||
self.size = 0
|
||||
"""
|
||||
Initialize MMIO object.
|
||||
|
||||
Args:
|
||||
instance: Associated PCI object instance
|
||||
"""
|
||||
self.base: Optional[int] = None
|
||||
self.size: int = 0
|
||||
self.instance = instance
|
||||
|
||||
def set_base_and_size(self, base: Optional[int], size: int) -> None:
|
||||
"""
|
||||
Set base address and size for the MMIO region.
|
||||
|
||||
Args:
|
||||
base: Base address (can be None)
|
||||
size: Size of the MMIO region
|
||||
|
||||
Raises:
|
||||
MMIOBarConfigError: If parameters are invalid
|
||||
"""
|
||||
try:
|
||||
if base is not None and not isinstance(base, int):
|
||||
raise MMIOBarConfigError(
|
||||
"Base address must be an integer or None")
|
||||
if not isinstance(size, int) or size < 0:
|
||||
raise MMIOBarConfigError(
|
||||
"Size must be a non-negative integer")
|
||||
|
||||
self.base = base
|
||||
self.size = size
|
||||
except Exception as e:
|
||||
if isinstance(e, MMIOBarConfigError):
|
||||
raise
|
||||
raise MMIOBarConfigError(
|
||||
f"Error setting MMIO base and size: {str(e)}") from e
|
||||
|
||||
def is_valid(self) -> bool:
|
||||
"""
|
||||
Check if MMIO object is valid.
|
||||
|
||||
Returns:
|
||||
True if MMIO object has valid configuration
|
||||
"""
|
||||
return (self.base is not None and
|
||||
isinstance(self.size, int) and
|
||||
self.size >= 0 and
|
||||
self.instance is not None)
|
||||
|
||||
def __str__(self) -> str:
|
||||
"""Return human-readable string representation."""
|
||||
basestr = f'0x{self.base:X}' if self.base else 'None'
|
||||
return f'instance: {self.instance}, base: {basestr}'
|
||||
return (f'instance: {self.instance}, base: {basestr}, '
|
||||
f'size: 0x{self.size:X}')
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""Return detailed string representation."""
|
||||
return (f"MMIOObj(base={self.base}, size={self.size}, "
|
||||
f"instance={self.instance})")
|
||||
|
||||
def __eq__(self, other) -> bool:
|
||||
"""
|
||||
Check equality with another MMIO object.
|
||||
|
||||
Args:
|
||||
other: Object to compare with
|
||||
|
||||
Returns:
|
||||
True if objects are equal, False otherwise
|
||||
"""
|
||||
if not isinstance(other, MMIOObj):
|
||||
return False
|
||||
return (self.base == other.base and
|
||||
self.size == other.size and
|
||||
self.instance == other.instance)
|
||||
|
||||
def __hash__(self) -> int:
|
||||
"""
|
||||
Generate a hash value for the MMIOObj instance.
|
||||
|
||||
This allows MMIOObj instances to be used as dictionary keys.
|
||||
|
||||
Returns:
|
||||
Hash value based on base, size, and instance
|
||||
"""
|
||||
# Use instance hash if it implements __hash__, otherwise use id()
|
||||
instance_hash = hash(self.instance) \
|
||||
if hasattr(self.instance, '__hash__') else id(self.instance)
|
||||
return hash((self.base, self.size, instance_hash))
|
||||
|
||||
|
||||
class MMIOBarConfig(GenericConfig, RegisterList):
|
||||
"""
|
||||
MMIO BAR configuration helper for memory-mapped I/O base address registers.
|
||||
|
||||
Manages MMIO BAR configurations including register mappings, base fields,
|
||||
size information, and device instances.
|
||||
"""
|
||||
|
||||
def __init__(self, cfg_obj):
|
||||
GenericConfig.__init__(self, cfg_obj)
|
||||
RegisterList.__init__(self)
|
||||
self.device = cfg_obj['device'] if 'device' in cfg_obj else cfg_obj['component'] if 'component' in cfg_obj else None
|
||||
self.register = cfg_obj['register']
|
||||
self.base_field = cfg_obj['base_field']
|
||||
self.size = cfg_obj['size'] if 'size' in cfg_obj else None
|
||||
self.desc = cfg_obj['desc'] if 'desc' in cfg_obj else self.name
|
||||
self.reg_align = cfg_obj['reg_align'] if 'reg_align' in cfg_obj else None
|
||||
self.registerh = cfg_obj['registerh'] if 'registerh' in cfg_obj else None
|
||||
self.reg_alignh = cfg_obj['reg_alignh'] if 'reg_alignh' in cfg_obj else None
|
||||
self.baseh_field = cfg_obj['baseh_field'] if 'baseh_field' in cfg_obj else None
|
||||
self.registertype = cfg_obj['registertype'] if 'registertype' in cfg_obj else None
|
||||
self.offset = cfg_obj['offset'] if 'offset' in cfg_obj else 0
|
||||
self.mmio_base = cfg_obj['mmio_base'] if 'mmio_base' in cfg_obj else None
|
||||
self.mmio_align = cfg_obj['mmio_align'] if 'mmio_align' in cfg_obj else None
|
||||
self.limit_field = cfg_obj['limit_field'] if 'limit_field' in cfg_obj else None
|
||||
self.limit_register = cfg_obj['limit_register'] if 'limit_register' in cfg_obj else None
|
||||
self.limit_align = cfg_obj['limit_align'] if 'limit_align' in cfg_obj else None
|
||||
self.fixed_address = cfg_obj['fixed_address'] if 'fixed_address' in cfg_obj else None
|
||||
self.enable_field = cfg_obj['enable_field'] if 'enable_field' in cfg_obj else None
|
||||
self.enable_bit = cfg_obj['enable_bit'] if 'enable_bit' in cfg_obj else None
|
||||
self.valid = cfg_obj['valid'] if 'valid' in cfg_obj else None
|
||||
self.instances = {}
|
||||
for key in cfg_obj['ids']:
|
||||
self.add_obj(key)
|
||||
"""
|
||||
Initialize MMIO BAR configuration helper.
|
||||
|
||||
Args:
|
||||
cfg_obj: Configuration object containing MMIO BAR-specific fields
|
||||
|
||||
Raises:
|
||||
MMIOBarConfigError: If MMIO BAR configuration initialization fails
|
||||
"""
|
||||
try:
|
||||
GenericConfig.__init__(self, cfg_obj)
|
||||
RegisterList.__init__(self)
|
||||
|
||||
# Required fields
|
||||
if 'register' not in cfg_obj or 'base_field' not in cfg_obj:
|
||||
raise MMIOBarConfigError(
|
||||
"Missing required fields: register and/or base_field")
|
||||
|
||||
# Device field (can be 'device' or 'component')
|
||||
self.device = (cfg_obj.get('device') or
|
||||
cfg_obj.get('component'))
|
||||
|
||||
# Core configuration
|
||||
self.register = cfg_obj['register']
|
||||
self.base_field = cfg_obj['base_field']
|
||||
self.size = cfg_obj.get('size')
|
||||
self.desc = cfg_obj.get('desc', self.name)
|
||||
self.reg_align = cfg_obj.get('reg_align')
|
||||
self.registerh = cfg_obj.get('registerh')
|
||||
self.reg_alignh = cfg_obj.get('reg_alignh')
|
||||
self.baseh_field = cfg_obj.get('baseh_field')
|
||||
self.registertype = cfg_obj.get('registertype')
|
||||
self.offset = cfg_obj.get('offset', 0)
|
||||
self.mmio_base = cfg_obj.get('mmio_base')
|
||||
self.mmio_align = cfg_obj.get('mmio_align')
|
||||
self.limit_field = cfg_obj.get('limit_field')
|
||||
self.limit_register = cfg_obj.get('limit_register')
|
||||
self.limit_align = cfg_obj.get('limit_align')
|
||||
self.fixed_address = cfg_obj.get('fixed_address')
|
||||
self.enable_field = cfg_obj.get('enable_field')
|
||||
self.enable_bit = cfg_obj.get('enable_bit')
|
||||
self.valid = cfg_obj.get('valid')
|
||||
|
||||
# Initialize instances
|
||||
self.instances = {}
|
||||
if 'ids' in cfg_obj:
|
||||
for key in cfg_obj['ids']:
|
||||
self.add_obj(key)
|
||||
|
||||
except Exception as e:
|
||||
if isinstance(e, (MMIOBarConfigError, GenericConfigError)):
|
||||
raise
|
||||
raise MMIOBarConfigError(
|
||||
f"Error initializing MMIO BAR configuration: {str(e)}") from e
|
||||
|
||||
def add_obj(self, key):
|
||||
self.instances[key] = MMIOObj(key)
|
||||
"""
|
||||
Add a new MMIO object instance.
|
||||
|
||||
def update_base_address(self, base, instance):
|
||||
if instance in self.instances:
|
||||
Args:
|
||||
key: Key identifier for the MMIO instance
|
||||
|
||||
Raises:
|
||||
MMIOBarConfigError: If MMIO object creation fails
|
||||
"""
|
||||
try:
|
||||
self.instances[key] = MMIOObj(key)
|
||||
except Exception as e:
|
||||
raise MMIOBarConfigError(
|
||||
f"Error adding MMIO object: {str(e)}") from e
|
||||
|
||||
def remove_instance(self, key) -> bool:
|
||||
"""
|
||||
Remove an MMIO instance by key.
|
||||
|
||||
Args:
|
||||
key: Key identifier for the instance to remove
|
||||
|
||||
Returns:
|
||||
True if instance was removed, False if not found
|
||||
"""
|
||||
if key in self.instances:
|
||||
del self.instances[key]
|
||||
return True
|
||||
return False
|
||||
|
||||
def update_base_address(self, base: Optional[int], instance) -> None:
|
||||
"""
|
||||
Update base address for a specific instance.
|
||||
|
||||
Args:
|
||||
base: New base address
|
||||
instance: Instance identifier
|
||||
|
||||
Raises:
|
||||
MMIOBarConfigError: If instance not found or update fails
|
||||
"""
|
||||
try:
|
||||
if instance not in self.instances:
|
||||
raise MMIOBarConfigError(f"Instance {instance} not found")
|
||||
self.instances[instance].base = base
|
||||
except Exception as e:
|
||||
if isinstance(e, MMIOBarConfigError):
|
||||
raise
|
||||
raise MMIOBarConfigError(
|
||||
f"Error updating base address: {str(e)}") from e
|
||||
|
||||
def get_base(self, instance):
|
||||
"""
|
||||
Get base address and size for a specific instance.
|
||||
|
||||
Args:
|
||||
instance: Instance identifier
|
||||
|
||||
Returns:
|
||||
Tuple of (base_address, size) or (None, 0) if not found
|
||||
"""
|
||||
if instance in self.instances:
|
||||
return self.instances[instance].base, self.size
|
||||
else:
|
||||
return (None, 0)
|
||||
|
||||
def get_instance_count(self) -> int:
|
||||
"""Get the total number of MMIO instances."""
|
||||
return len(self.instances)
|
||||
|
||||
def validate_mmio_config(self) -> bool:
|
||||
"""
|
||||
Validate MMIO BAR-specific configuration.
|
||||
|
||||
Returns:
|
||||
True if MMIO BAR configuration is valid, False otherwise
|
||||
"""
|
||||
try:
|
||||
# Call parent validation first
|
||||
if not self.validate_config():
|
||||
return False
|
||||
|
||||
# Validate required fields
|
||||
if not self.register or not self.base_field:
|
||||
return False
|
||||
|
||||
# Validate all MMIO instances
|
||||
for inst in self.instances.values():
|
||||
if not inst.is_valid():
|
||||
return False
|
||||
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def get_mmio_summary(self):
|
||||
"""
|
||||
Get summary of MMIO BAR configuration.
|
||||
|
||||
Returns:
|
||||
Dictionary with MMIO BAR configuration summary
|
||||
"""
|
||||
try:
|
||||
return {
|
||||
'name': self.name,
|
||||
'device': self.device,
|
||||
'register': self.register,
|
||||
'base_field': self.base_field,
|
||||
'size': self.size,
|
||||
'total_instances': len(self.instances),
|
||||
'is_valid': self.validate_mmio_config(),
|
||||
'config_items': len(self.config)
|
||||
}
|
||||
except Exception:
|
||||
return {
|
||||
'name': getattr(self, 'name', 'Unknown'),
|
||||
'device': getattr(self, 'device', None),
|
||||
'register': getattr(self, 'register', None),
|
||||
'base_field': getattr(self, 'base_field', None),
|
||||
'size': getattr(self, 'size', None),
|
||||
'total_instances': 0,
|
||||
'is_valid': False,
|
||||
'config_items': 0
|
||||
}
|
||||
|
||||
def __str__(self) -> str:
|
||||
"""Return human-readable string representation."""
|
||||
ret = f'name: {self.name}, device: {self.device}'
|
||||
ret += f', register:{self.register}, base_field:{self.base_field}'
|
||||
ret += f', size:{self.size}'
|
||||
ret += f', config: {self.config}'
|
||||
if self.reg_align:
|
||||
ret += f', reg_align:{self.reg_align}'
|
||||
if self.registerh:
|
||||
ret += f', registerh:{self.registerh}'
|
||||
if self.reg_alignh:
|
||||
ret += f', reg_alignh:{self.reg_alignh}'
|
||||
if self.baseh_field:
|
||||
ret += f', baseh_field:{self.baseh_field}'
|
||||
if self.registertype:
|
||||
ret += f', registertype:{self.registertype}'
|
||||
if self.mmio_base:
|
||||
ret += f', mmio_base:{self.mmio_base}'
|
||||
if self.mmio_align:
|
||||
ret += f', mmio_align:{self.mmio_align}'
|
||||
if self.limit_field:
|
||||
ret += f', limit_field:{self.limit_field}'
|
||||
if self.limit_register:
|
||||
ret += f', limit_register:{self.limit_register}'
|
||||
if self.limit_align:
|
||||
ret += f', limit_align:{self.limit_align}'
|
||||
if self.fixed_address:
|
||||
ret += f', fixed_address:{self.fixed_address}'
|
||||
if self.enable_field:
|
||||
ret += f', enable_field:{self.enable_field}'
|
||||
if self.valid:
|
||||
ret += f', valid:{self.valid}'
|
||||
ret += f', desc:{self.desc}'
|
||||
ret += f', register: {self.register}, base_field: {self.base_field}'
|
||||
ret += f', size: {self.size}'
|
||||
ret += f', config: {len(self.config)} items'
|
||||
|
||||
# Add optional fields if present
|
||||
optional_fields = [
|
||||
('reg_align', self.reg_align),
|
||||
('registerh', self.registerh),
|
||||
('reg_alignh', self.reg_alignh),
|
||||
('baseh_field', self.baseh_field),
|
||||
('registertype', self.registertype),
|
||||
('mmio_base', self.mmio_base),
|
||||
('mmio_align', self.mmio_align),
|
||||
('limit_field', self.limit_field),
|
||||
('limit_register', self.limit_register),
|
||||
('limit_align', self.limit_align),
|
||||
('fixed_address', self.fixed_address),
|
||||
('enable_field', self.enable_field),
|
||||
('valid', self.valid)
|
||||
]
|
||||
|
||||
for field_name, field_value in optional_fields:
|
||||
if field_value:
|
||||
ret += f', {field_name}: {field_value}'
|
||||
|
||||
ret += f', desc: {self.desc}'
|
||||
ret += ', instances: ['
|
||||
ret += ' '.join(f'{{{str(inst)}}}' for (_, inst) in self.instances.items())
|
||||
ret += ' '.join(f'{{{str(inst)}}}'
|
||||
for (_, inst) in self.instances.items())
|
||||
ret += ']'
|
||||
return ret
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""Return detailed string representation."""
|
||||
return (f"MMIOBarConfig(name='{self.name}', device='{self.device}', "
|
||||
f"register='{self.register}', instances={len(self.instances)}, "
|
||||
f"config_count={len(self.config)})")
|
||||
|
||||
@@ -17,15 +17,127 @@
|
||||
# Contact information:
|
||||
# chipsec@intel.com
|
||||
|
||||
"""
|
||||
MSGBUS (Message Bus) configuration parser.
|
||||
|
||||
This module provides MSGBUSConfig class for parsing and managing message bus configurations in the CHIPSEC framework.
|
||||
Message buses provide communication interfaces between different platform components.
|
||||
"""
|
||||
|
||||
from typing import Dict, Any, Optional
|
||||
from chipsec.cfg.parsers.ip.generic import GenericConfig
|
||||
from chipsec.library.exceptions import CSConfigError
|
||||
|
||||
|
||||
class MSGBUSConfigError(CSConfigError):
|
||||
"""Exception raised for MSGBUS configuration-specific errors."""
|
||||
pass
|
||||
|
||||
|
||||
class MSGBUSConfig(GenericConfig):
|
||||
def __init__(self, cfg_obj):
|
||||
super(MSGBUSConfig, self).__init__(cfg_obj)
|
||||
self.port = cfg_obj['port']
|
||||
"""
|
||||
MSGBUS (Message Bus) configuration parser.
|
||||
|
||||
This class handles parsing and validation of message bus configurations, extending
|
||||
the base GenericConfig with MSGBUS-specific functionality including port management.
|
||||
|
||||
Attributes:
|
||||
name (str): The name of the MSGBUS configuration
|
||||
config (Dict[str, Any]): The raw configuration data
|
||||
port (Union[int, str]): The message bus port identifier
|
||||
|
||||
Example:
|
||||
>>> msgbus_cfg = MSGBUSConfig({'name': 'PUNIT_MSGBUS', 'port': 0x04})
|
||||
>>> print(msgbus_cfg.port)
|
||||
4
|
||||
"""
|
||||
|
||||
def __init__(self, cfg_obj: Dict[str, Any]) -> None:
|
||||
"""
|
||||
Initialize MSGBUS configuration.
|
||||
|
||||
Args:
|
||||
cfg_obj: Dictionary containing MSGBUS configuration data
|
||||
|
||||
Raises:
|
||||
MSGBUSConfigError: If configuration validation fails
|
||||
"""
|
||||
try:
|
||||
super().__init__(cfg_obj)
|
||||
self.port = cfg_obj['port']
|
||||
self._validate_msgbus_config()
|
||||
except KeyError as e:
|
||||
raise MSGBUSConfigError(f"Missing required field in MSGBUS configuration: {e}") from e
|
||||
except Exception as e:
|
||||
raise MSGBUSConfigError(f"Failed to initialize MSGBUS configuration: {e}") from e
|
||||
|
||||
def _validate_msgbus_config(self) -> None:
|
||||
"""
|
||||
Validate MSGBUS-specific configuration requirements.
|
||||
|
||||
Raises:
|
||||
MSGBUSConfigError: If configuration is invalid
|
||||
"""
|
||||
if not self.name:
|
||||
raise MSGBUSConfigError("MSGBUS configuration must have a valid name")
|
||||
|
||||
if self.port is None:
|
||||
raise MSGBUSConfigError("MSGBUS configuration must have a valid port")
|
||||
|
||||
# Validate port format and range
|
||||
port_int = self.get_port_as_int()
|
||||
if port_int is None or port_int < 0 or port_int > 0xFF:
|
||||
raise MSGBUSConfigError(f"Invalid port value: {self.port}. Must be 0-255 range")
|
||||
|
||||
def get_port_as_int(self) -> Optional[int]:
|
||||
"""
|
||||
Get the port as an integer value.
|
||||
|
||||
Returns:
|
||||
Port as integer, or None if conversion fails
|
||||
"""
|
||||
try:
|
||||
if isinstance(self.port, str):
|
||||
return int(self.port, 16) if self.port.startswith('0x') else int(self.port)
|
||||
return int(self.port)
|
||||
except (ValueError, TypeError):
|
||||
return None
|
||||
|
||||
def get_port_as_hex(self) -> str:
|
||||
"""
|
||||
Get the port as a hexadecimal string.
|
||||
|
||||
Returns:
|
||||
Port as hex string (e.g., '0x04')
|
||||
"""
|
||||
port_int = self.get_port_as_int()
|
||||
return f"0x{port_int:02X}" if port_int is not None else "0x00"
|
||||
|
||||
def is_valid_port(self) -> bool:
|
||||
"""
|
||||
Check if the port value is valid.
|
||||
|
||||
Returns:
|
||||
True if port is valid, False otherwise
|
||||
"""
|
||||
port_int = self.get_port_as_int()
|
||||
return port_int is not None and 0 <= port_int <= 0xFF
|
||||
|
||||
def __str__(self) -> str:
|
||||
ret = f'name: {self.name}, port: {self.port}'
|
||||
ret += f', config: {self.config}'
|
||||
return ret
|
||||
"""
|
||||
String representation of MSGBUS configuration.
|
||||
|
||||
Returns:
|
||||
Formatted string with MSGBUS details
|
||||
"""
|
||||
port_hex = self.get_port_as_hex()
|
||||
return f"MSGBUSConfig(name='{self.name}', port={port_hex}, config={self.config})"
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""
|
||||
Detailed string representation for debugging.
|
||||
|
||||
Returns:
|
||||
Detailed string representation
|
||||
"""
|
||||
return f"MSGBUSConfig(name='{self.name}', port={self.port}, config={self.config})"
|
||||
|
||||
@@ -17,14 +17,122 @@
|
||||
# Contact information:
|
||||
# chipsec@intel.com
|
||||
|
||||
"""
|
||||
MSR (Model Specific Register) configuration parser.
|
||||
|
||||
This module provides MSRConfig class for parsing and managing MSR configurations in the CHIPSEC framework.
|
||||
MSRs are CPU-specific registers that provide access to processor features and debugging capabilities.
|
||||
"""
|
||||
|
||||
from typing import Dict, Any, Optional
|
||||
from chipsec.cfg.parsers.ip.generic import GenericConfig
|
||||
from chipsec.library.exceptions import CSConfigError
|
||||
|
||||
|
||||
class MSRConfigError(CSConfigError):
|
||||
"""Exception raised for MSR configuration-specific errors."""
|
||||
pass
|
||||
|
||||
|
||||
class MSRConfig(GenericConfig):
|
||||
def __init__(self, cfg_obj):
|
||||
super(MSRConfig, self).__init__(cfg_obj)
|
||||
"""
|
||||
MSR (Model Specific Register) configuration parser.
|
||||
|
||||
This class handles parsing and validation of MSR configurations, extending
|
||||
the base GenericConfig with MSR-specific functionality.
|
||||
|
||||
Attributes:
|
||||
name (str): The name of the MSR configuration
|
||||
config (Dict[str, Any]): The raw configuration data
|
||||
|
||||
Example:
|
||||
>>> msr_cfg = MSRConfig({'name': 'IA32_MTRR_CAP', 'address': 0xFE})
|
||||
>>> print(msr_cfg.name)
|
||||
IA32_MTRR_CAP
|
||||
"""
|
||||
|
||||
def __init__(self, cfg_obj: Dict[str, Any]) -> None:
|
||||
"""
|
||||
Initialize MSR configuration.
|
||||
|
||||
Args:
|
||||
cfg_obj: Dictionary containing MSR configuration data
|
||||
|
||||
Raises:
|
||||
MSRConfigError: If configuration validation fails
|
||||
"""
|
||||
try:
|
||||
self._cfg_obj = cfg_obj # Store original config for reference
|
||||
super().__init__(cfg_obj)
|
||||
self._validate_msr_config()
|
||||
except Exception as e:
|
||||
raise MSRConfigError(f"Failed to initialize MSR configuration: {e}") from e
|
||||
|
||||
def _validate_msr_config(self) -> None:
|
||||
"""
|
||||
Validate MSR-specific configuration requirements.
|
||||
|
||||
Raises:
|
||||
MSRConfigError: If configuration is invalid
|
||||
"""
|
||||
if not self.name:
|
||||
raise MSRConfigError("MSR configuration must have a valid name")
|
||||
|
||||
# MSRs typically should have an address or some identifier
|
||||
# Check both in config dict and as top-level attributes
|
||||
has_address = ('address' in self.config or 'msr' in self.config or
|
||||
hasattr(self, 'address') or hasattr(self, 'msr'))
|
||||
if not has_address:
|
||||
# This is a warning rather than an error for backward compatibility
|
||||
pass
|
||||
|
||||
def get_address(self) -> Optional[int]:
|
||||
"""
|
||||
Get the MSR address.
|
||||
|
||||
Returns:
|
||||
MSR address as integer, or None if not specified
|
||||
"""
|
||||
# First check in the original cfg_obj if available
|
||||
if hasattr(self, '_cfg_obj'):
|
||||
address = self._cfg_obj.get('address') or self._cfg_obj.get('msr')
|
||||
else:
|
||||
# Fallback to checking if we have direct attributes
|
||||
address = getattr(self, 'address', None) or getattr(self, 'msr', None)
|
||||
|
||||
if address is not None:
|
||||
try:
|
||||
return int(address, 16) if isinstance(address, str) else int(address)
|
||||
except (ValueError, TypeError):
|
||||
return None
|
||||
return None
|
||||
|
||||
def is_valid_address(self) -> bool:
|
||||
"""
|
||||
Check if the MSR has a valid address.
|
||||
|
||||
Returns:
|
||||
True if address is valid, False otherwise
|
||||
"""
|
||||
address = self.get_address()
|
||||
return address is not None and 0 <= address <= 0xFFFFFFFF
|
||||
|
||||
def __str__(self) -> str:
|
||||
ret = f'name: {self.name}'
|
||||
ret += f', config: {self.config}'
|
||||
return ret
|
||||
"""
|
||||
String representation of MSR configuration.
|
||||
|
||||
Returns:
|
||||
Formatted string with MSR details
|
||||
"""
|
||||
address = self.get_address()
|
||||
address_str = f"0x{address:X}" if address is not None else "N/A"
|
||||
return f"MSRConfig(name='{self.name}', address={address_str}, config={self.config})"
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""
|
||||
Detailed string representation for debugging.
|
||||
|
||||
Returns:
|
||||
Detailed string representation
|
||||
"""
|
||||
return f"MSRConfig(name='{self.name}', config={self.config})"
|
||||
|
||||
@@ -17,67 +17,379 @@
|
||||
# Contact information:
|
||||
# chipsec@intel.com
|
||||
|
||||
from chipsec.cfg.parsers.ip.generic import GenericConfig
|
||||
"""
|
||||
PCI Device IP Configuration Helper
|
||||
|
||||
Provides PCI device-specific configuration management functionality for
|
||||
PCI-based IP parsers.
|
||||
"""
|
||||
|
||||
from typing import Dict, Any, Optional, List, Union
|
||||
|
||||
from chipsec.cfg.parsers.ip.generic import GenericConfig, GenericConfigError
|
||||
|
||||
|
||||
class PCIConfigError(GenericConfigError):
|
||||
"""Custom exception for PCI configuration errors."""
|
||||
pass
|
||||
|
||||
|
||||
class PCIObj:
|
||||
def __init__(self, cfg_obj):
|
||||
self.bus = cfg_obj['bus']
|
||||
self.dev = cfg_obj['dev']
|
||||
self.fun = cfg_obj['fun']
|
||||
self.rid = cfg_obj['rid'] if 'rid' in cfg_obj else 0xff
|
||||
"""
|
||||
PCI device object representing a single PCI device instance.
|
||||
|
||||
Contains bus, device, function, and revision ID information for a
|
||||
PCI device.
|
||||
"""
|
||||
|
||||
def __init__(self, cfg_obj: Dict[str, Any]):
|
||||
"""
|
||||
Initialize PCI device object.
|
||||
|
||||
Args:
|
||||
cfg_obj: Configuration object containing PCI device information
|
||||
|
||||
Raises:
|
||||
PCIConfigError: If required PCI configuration is missing
|
||||
"""
|
||||
try:
|
||||
required_fields = ['bus', 'dev', 'fun']
|
||||
missing_fields = [field for field in required_fields
|
||||
if field not in cfg_obj]
|
||||
if missing_fields:
|
||||
raise PCIConfigError(
|
||||
f"Missing required PCI fields: {missing_fields}")
|
||||
|
||||
self.bus: Union[int, str] = cfg_obj['bus']
|
||||
self.dev: Union[int, str] = cfg_obj['dev']
|
||||
self.fun: Union[int, str] = cfg_obj['fun']
|
||||
self.rid: Union[int, str] = cfg_obj.get('rid', 0xff)
|
||||
|
||||
except Exception as e:
|
||||
if isinstance(e, PCIConfigError):
|
||||
raise
|
||||
raise PCIConfigError(
|
||||
f"Error initializing PCI object: {str(e)}") from e
|
||||
|
||||
def get_bdf_tuple(self) -> tuple:
|
||||
"""
|
||||
Get Bus:Device:Function as a tuple.
|
||||
|
||||
Returns:
|
||||
Tuple of (bus, dev, fun)
|
||||
"""
|
||||
return (self.bus, self.dev, self.fun)
|
||||
|
||||
def get_bdf_string(self) -> str:
|
||||
"""
|
||||
Get Bus:Device:Function as a formatted string.
|
||||
|
||||
Returns:
|
||||
BDF string in format "bus:dev.fun"
|
||||
"""
|
||||
return f"{self.bus:02x}:{self.dev:02x}.{self.fun}"
|
||||
|
||||
def validate_pci_obj(self) -> bool:
|
||||
"""
|
||||
Validate PCI object configuration.
|
||||
|
||||
Returns:
|
||||
True if PCI object is valid, False otherwise
|
||||
"""
|
||||
try:
|
||||
# Check that all fields are present and valid
|
||||
for field_name, field_value in [('bus', self.bus),
|
||||
('dev', self.dev),
|
||||
('fun', self.fun),
|
||||
('rid', self.rid)]:
|
||||
if isinstance(field_value, str):
|
||||
try:
|
||||
int(field_value,
|
||||
16 if field_value.startswith('0x') else 10)
|
||||
except ValueError:
|
||||
return False
|
||||
elif not isinstance(field_value, int):
|
||||
return False
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def __str__(self) -> str:
|
||||
"""Return human-readable string representation."""
|
||||
ret = f'bus: {self.bus}, dev: {self.dev}, func: {self.fun}'
|
||||
ret += f', rid:{self.rid}'
|
||||
ret += f', rid: {self.rid}'
|
||||
return ret
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return str(self)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""Return detailed string representation."""
|
||||
return (f"PCIObj(bus={self.bus}, dev={self.dev}, "
|
||||
f"fun={self.fun}, rid={self.rid})")
|
||||
|
||||
def __eq__(self, other) -> bool:
|
||||
"""Check equality with another PCI object."""
|
||||
if not isinstance(other, PCIObj):
|
||||
return False
|
||||
return (self.bus == other.bus and self.dev == other.dev and
|
||||
self.fun == other.fun and self.rid == other.rid)
|
||||
|
||||
def __hash__(self) -> int:
|
||||
"""
|
||||
Generate a hash value for the PCIObj instance.
|
||||
|
||||
This allows PCIObj instances to be used as dictionary keys.
|
||||
|
||||
Returns:
|
||||
Hash value based on bus, device, function, and revision ID
|
||||
"""
|
||||
# Convert fields to integers for consistent hashing
|
||||
bus = self._convert_to_int(self.bus)
|
||||
dev = self._convert_to_int(self.dev)
|
||||
fun = self._convert_to_int(self.fun)
|
||||
rid = self._convert_to_int(self.rid)
|
||||
|
||||
return hash((bus, dev, fun, rid))
|
||||
|
||||
def _convert_to_int(self, value: Union[int, str]) -> int:
|
||||
"""
|
||||
Convert a value to integer for hashing purposes.
|
||||
|
||||
Args:
|
||||
value: Value to convert (int or str)
|
||||
|
||||
Returns:
|
||||
Integer representation of the value
|
||||
"""
|
||||
if isinstance(value, str):
|
||||
base = 16 if value.startswith('0x') else 10
|
||||
return int(value, base)
|
||||
return value
|
||||
|
||||
|
||||
class PCIConfig(GenericConfig):
|
||||
def __init__(self, cfg_obj):
|
||||
self.did = cfg_obj['did'] if 'did' in cfg_obj else None
|
||||
if 'name' not in cfg_obj:
|
||||
cfg_obj['name'] = self.did
|
||||
super(PCIConfig, self).__init__(cfg_obj)
|
||||
self.instances = {}
|
||||
self.component = cfg_obj['component'] if 'component' in cfg_obj else None
|
||||
self.__instCounter = 0
|
||||
self.add_obj(cfg_obj)
|
||||
"""
|
||||
PCI configuration helper for PCI device-based IP regions.
|
||||
|
||||
def add_obj(self, cfg_obj):
|
||||
self.instances[self.__instCounter] = PCIObj(cfg_obj)
|
||||
self.__instCounter += 1
|
||||
Manages PCI device configurations including device IDs, components,
|
||||
and multiple device instances.
|
||||
"""
|
||||
|
||||
def get_rid(self, bus, dev, fun):
|
||||
def __init__(self, cfg_obj: Dict[str, Any]):
|
||||
"""
|
||||
Initialize PCI configuration helper.
|
||||
|
||||
Args:
|
||||
cfg_obj: Configuration object containing PCI-specific fields
|
||||
|
||||
Raises:
|
||||
PCIConfigError: If PCI configuration initialization fails
|
||||
"""
|
||||
try:
|
||||
# Handle device ID and name
|
||||
self.did: Optional[Union[int, str]] = cfg_obj.get('did', None)
|
||||
if 'name' not in cfg_obj and self.did is not None:
|
||||
cfg_obj['name'] = str(self.did)
|
||||
|
||||
super().__init__(cfg_obj)
|
||||
|
||||
self.instances: Dict[int, PCIObj] = {}
|
||||
self.component: Optional[str] = cfg_obj.get('component', None)
|
||||
self.__instCounter: int = 0
|
||||
|
||||
# Add the initial PCI object
|
||||
self.add_obj(cfg_obj)
|
||||
|
||||
except Exception as e:
|
||||
if isinstance(e, (PCIConfigError, GenericConfigError)):
|
||||
raise
|
||||
raise PCIConfigError(
|
||||
f"Error initializing PCI configuration: {str(e)}") from e
|
||||
|
||||
def add_obj(self, cfg_obj: Dict[str, Any]) -> int:
|
||||
"""
|
||||
Add a new PCI object instance.
|
||||
|
||||
Args:
|
||||
cfg_obj: Configuration object for the PCI device
|
||||
|
||||
Returns:
|
||||
Instance counter for the added object
|
||||
|
||||
Raises:
|
||||
PCIConfigError: If PCI object creation fails
|
||||
"""
|
||||
try:
|
||||
pci_obj = PCIObj(cfg_obj)
|
||||
self.instances[self.__instCounter] = pci_obj
|
||||
current_counter = self.__instCounter
|
||||
self.__instCounter += 1
|
||||
return current_counter
|
||||
except Exception as e:
|
||||
raise PCIConfigError(
|
||||
f"Error adding PCI object: {str(e)}") from e
|
||||
|
||||
def remove_instance(self, instance_id: int) -> bool:
|
||||
"""
|
||||
Remove a PCI instance by ID.
|
||||
|
||||
Args:
|
||||
instance_id: Instance ID to remove
|
||||
|
||||
Returns:
|
||||
True if instance was removed, False if not found
|
||||
"""
|
||||
if instance_id in self.instances:
|
||||
del self.instances[instance_id]
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_rid(self, bus: Union[int, str], dev: Union[int, str],
|
||||
fun: Union[int, str]) -> Union[int, str]:
|
||||
"""
|
||||
Get revision ID for a specific Bus:Device:Function.
|
||||
|
||||
Args:
|
||||
bus: PCI bus number
|
||||
dev: PCI device number
|
||||
fun: PCI function number
|
||||
|
||||
Returns:
|
||||
Revision ID if found, 0xff otherwise
|
||||
"""
|
||||
rid = 0xff
|
||||
for inst in self.instances.values():
|
||||
if inst.bus == bus and inst.dev == dev and inst.fun == fun:
|
||||
rid = inst.rid
|
||||
break
|
||||
return rid
|
||||
|
||||
def get_enabled_instances(self) -> bool:
|
||||
|
||||
def get_enabled_instances(self) -> List[PCIObj]:
|
||||
"""
|
||||
Get list of enabled PCI instances (those with valid bus numbers).
|
||||
|
||||
Returns:
|
||||
List of enabled PCI objects
|
||||
"""
|
||||
enabled = []
|
||||
for inst in self.instances.values():
|
||||
if inst.bus is not None:
|
||||
enabled.append(inst)
|
||||
return enabled
|
||||
|
||||
def get_instance_count(self) -> int:
|
||||
"""Get the total number of PCI instances."""
|
||||
return len(self.instances)
|
||||
|
||||
def update_name(self, name):
|
||||
self.name = name
|
||||
def find_instance_by_bdf(self, bus: Union[int, str],
|
||||
dev: Union[int, str],
|
||||
fun: Union[int, str]) -> Optional[PCIObj]:
|
||||
"""
|
||||
Find PCI instance by Bus:Device:Function.
|
||||
|
||||
Args:
|
||||
bus: PCI bus number
|
||||
dev: PCI device number
|
||||
fun: PCI function number
|
||||
|
||||
Returns:
|
||||
PCIObj if found, None otherwise
|
||||
"""
|
||||
for inst in self.instances.values():
|
||||
if inst.bus == bus and inst.dev == dev and inst.fun == fun:
|
||||
return inst
|
||||
return None
|
||||
|
||||
def validate_pci_config(self) -> bool:
|
||||
"""
|
||||
Validate PCI-specific configuration.
|
||||
|
||||
Returns:
|
||||
True if PCI configuration is valid, False otherwise
|
||||
"""
|
||||
try:
|
||||
# Call parent validation first
|
||||
if not self.validate_config():
|
||||
return False
|
||||
|
||||
# Validate all PCI instances
|
||||
for inst in self.instances.values():
|
||||
if not inst.validate_pci_obj():
|
||||
return False
|
||||
|
||||
# Validate component if present
|
||||
if self.component is not None and not isinstance(self.component, str):
|
||||
return False
|
||||
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def update_name(self, name: str) -> None:
|
||||
"""
|
||||
Update the configuration name.
|
||||
|
||||
Args:
|
||||
name: New name for the configuration
|
||||
|
||||
Raises:
|
||||
PCIConfigError: If name update fails
|
||||
"""
|
||||
try:
|
||||
if not isinstance(name, str) or not name.strip():
|
||||
raise PCIConfigError("Name must be a non-empty string")
|
||||
self.name = name
|
||||
except Exception as e:
|
||||
if isinstance(e, PCIConfigError):
|
||||
raise
|
||||
raise PCIConfigError(
|
||||
f"Error updating name: {str(e)}") from e
|
||||
|
||||
def get_pci_summary(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Get summary of PCI configuration.
|
||||
|
||||
Returns:
|
||||
Dictionary with PCI configuration summary
|
||||
"""
|
||||
try:
|
||||
enabled_instances = self.get_enabled_instances()
|
||||
return {
|
||||
'name': self.name,
|
||||
'did': self.did,
|
||||
'component': self.component,
|
||||
'total_instances': len(self.instances),
|
||||
'enabled_instances': len(enabled_instances),
|
||||
'is_valid': self.validate_pci_config(),
|
||||
'config_items': len(self.config)
|
||||
}
|
||||
except Exception:
|
||||
return {
|
||||
'name': getattr(self, 'name', 'Unknown'),
|
||||
'did': getattr(self, 'did', None),
|
||||
'component': getattr(self, 'component', None),
|
||||
'total_instances': 0,
|
||||
'enabled_instances': 0,
|
||||
'is_valid': False,
|
||||
'config_items': 0
|
||||
}
|
||||
|
||||
def __str__(self) -> str:
|
||||
"""Return human-readable string representation."""
|
||||
if self.did:
|
||||
ret = f'name:{self.name}, did:{self.did:04X}'
|
||||
if isinstance(self.did, int):
|
||||
ret = f'name: {self.name}, did: {self.did:04X}'
|
||||
else:
|
||||
ret = f'name: {self.name}, did: {self.did}'
|
||||
else:
|
||||
ret = f'name:{self.name}, did:{self.did}'
|
||||
ret = f'name: {self.name}, did: {self.did}'
|
||||
ret += f', component: {self.component}'
|
||||
ret += f', config: {self.config}'
|
||||
ret += f', config: {len(self.config)} items'
|
||||
ret += ', instances: ['
|
||||
ret += ' '.join(f'{{{str(inst)}}}' for inst in self.instances.values())
|
||||
ret += ']'
|
||||
return ret
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""Return detailed string representation."""
|
||||
return (f"PCIConfig(name='{self.name}', did={self.did}, "
|
||||
f"component='{self.component}', instances={len(self.instances)}, "
|
||||
f"config_count={len(self.config)})")
|
||||
|
||||
@@ -17,51 +17,156 @@
|
||||
# Contact information:
|
||||
# chipsec@intel.com
|
||||
|
||||
from chipsec.library.exceptions import CSConfigError, RegisterNotFoundError, ScopeNotFoundError, NonRegisterInScopeError, BARNotFoundError
|
||||
from chipsec.library.register import BaseConfigRegisterHelper, ObjList
|
||||
from chipsec.library.logger import logger
|
||||
"""
|
||||
Platform configuration parser and hierarchy management.
|
||||
|
||||
This module provides classes for managing platform configurations in a hierarchical structure:
|
||||
Platform -> Vendor -> IP -> Bar -> Register. It supports pattern matching, scoping,
|
||||
and register access across the configuration hierarchy.
|
||||
"""
|
||||
|
||||
from typing import List, Union, Any
|
||||
from re import match
|
||||
|
||||
class Recursable:
|
||||
def _get_next_level_list(self) -> list:
|
||||
raise NotImplementedError('get_next_level_list() not implemented')
|
||||
|
||||
def get_next_levels(self, key):
|
||||
key = key.replace('*', '.*')
|
||||
next_options = []
|
||||
next_options_list = [key] if '*' not in key and key in self._get_next_level_list() else self._get_next_level_list()
|
||||
for option in next_options_list:
|
||||
if match(key, option):
|
||||
next_option = self._get_next_level(option)
|
||||
if isinstance(next_option, list):
|
||||
next_options.extend(next_option)
|
||||
else:
|
||||
next_options.append(next_option)
|
||||
return next_options
|
||||
from chipsec.library.exceptions import (
|
||||
CSConfigError, RegisterNotFoundError, ScopeNotFoundError, BARNotFoundError
|
||||
)
|
||||
from chipsec.library.register import ObjList
|
||||
from chipsec.library.logger import logger
|
||||
|
||||
|
||||
class PlatformConfigError(CSConfigError):
|
||||
"""Exception raised for platform configuration-specific errors."""
|
||||
pass
|
||||
|
||||
|
||||
class Recursable:
|
||||
"""
|
||||
Base class for objects that support recursive navigation and pattern matching.
|
||||
|
||||
This class provides the foundation for hierarchical traversal of platform configurations,
|
||||
supporting wildcard matching and recursive object discovery.
|
||||
"""
|
||||
|
||||
def _get_next_level_list(self) -> List[str]:
|
||||
"""
|
||||
Get list of available keys at the next level.
|
||||
|
||||
Returns:
|
||||
List of string keys for the next hierarchy level
|
||||
|
||||
Raises:
|
||||
NotImplementedError: Must be implemented by subclasses
|
||||
"""
|
||||
raise NotImplementedError('_get_next_level_list() not implemented')
|
||||
|
||||
def get_next_levels(self, key: str) -> List['Recursable']:
|
||||
"""
|
||||
Get objects matching the given key pattern.
|
||||
|
||||
Args:
|
||||
key: Key pattern, supports wildcards (*)
|
||||
|
||||
Returns:
|
||||
List of matching objects at the next level
|
||||
"""
|
||||
key = key.replace('*', '.*')
|
||||
next_options = []
|
||||
|
||||
# Determine search scope
|
||||
if '*' not in key and key in self._get_next_level_list():
|
||||
next_options_list = [key]
|
||||
else:
|
||||
next_options_list = self._get_next_level_list()
|
||||
|
||||
# Find matching options
|
||||
for option in next_options_list:
|
||||
if match(key, option):
|
||||
next_option = self._get_next_level(option)
|
||||
if isinstance(next_option, list):
|
||||
next_options.extend(next_option)
|
||||
else:
|
||||
next_options.append(next_option)
|
||||
|
||||
return next_options
|
||||
|
||||
def _get_next_level(self, key: str) -> Union['Recursable', List['Recursable']]:
|
||||
"""
|
||||
Get the object(s) at the next level for a specific key.
|
||||
|
||||
Args:
|
||||
key: Specific key to retrieve
|
||||
|
||||
Returns:
|
||||
Object or list of objects at the next level
|
||||
|
||||
Raises:
|
||||
NotImplementedError: Must be implemented by subclasses
|
||||
"""
|
||||
raise NotImplementedError("_get_next_level() not implemented")
|
||||
|
||||
|
||||
def _get_next_level(self):
|
||||
raise NotImplementedError("get_next_level() not implemented")
|
||||
|
||||
class RegisterList:
|
||||
def __init__(self):
|
||||
"""
|
||||
Container for managing register objects with pattern matching support.
|
||||
|
||||
This class provides functionality to add, retrieve, and search for registers
|
||||
using both exact names and wildcard patterns.
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
"""Initialize empty register list."""
|
||||
self.register_list = {}
|
||||
|
||||
def add_register(self, register_name, register_object):
|
||||
def add_register(self, register_name: str, register_object: Any) -> None:
|
||||
"""
|
||||
Add a register to the list.
|
||||
|
||||
Args:
|
||||
register_name: Name of the register
|
||||
register_object: Register object to add
|
||||
"""
|
||||
self.register_list[register_name] = register_object
|
||||
self.__setattr__(register_name, register_object)
|
||||
|
||||
def get_register(self, register_name):
|
||||
def get_register(self, register_name: str) -> ObjList:
|
||||
"""
|
||||
Get a specific register by name.
|
||||
|
||||
Args:
|
||||
register_name: Name of the register to retrieve
|
||||
|
||||
Returns:
|
||||
ObjList containing the register
|
||||
|
||||
Raises:
|
||||
RegisterNotFoundError: If register not found
|
||||
"""
|
||||
if register_name in self.register_list:
|
||||
return ObjList(self.__getattribute__(register_name))
|
||||
else:
|
||||
raise RegisterNotFoundError(f'Invalid register name: {register_name}')
|
||||
|
||||
def get_register_matches(self, register_name):
|
||||
|
||||
def get_register_matches(self, register_name: str) -> ObjList:
|
||||
"""
|
||||
Get registers matching a pattern.
|
||||
|
||||
Args:
|
||||
register_name: Register name pattern (supports wildcards)
|
||||
|
||||
Returns:
|
||||
ObjList containing matching registers
|
||||
|
||||
Raises:
|
||||
RegisterNotFoundError: If no matches found
|
||||
"""
|
||||
registers = ObjList()
|
||||
reg_name = register_name.replace('*', '.*')
|
||||
|
||||
for reg in self.register_list:
|
||||
if match(reg_name, reg):
|
||||
registers.extend(self.get_register(reg))
|
||||
|
||||
if registers:
|
||||
return registers
|
||||
else:
|
||||
@@ -69,48 +174,125 @@ class RegisterList:
|
||||
|
||||
|
||||
class Platform(Recursable):
|
||||
def __init__(self):
|
||||
"""
|
||||
Top-level platform configuration container.
|
||||
|
||||
This class manages vendors and provides hierarchical access to the entire
|
||||
platform configuration structure. It supports complex scope resolution
|
||||
and pattern matching across the configuration hierarchy.
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
"""Initialize empty platform."""
|
||||
super().__init__()
|
||||
self.vendor_list = []
|
||||
|
||||
def add_vendor(self, vendor):
|
||||
if isinstance(vendor, Vendor):
|
||||
self.vendor_list.append(vendor.name)
|
||||
self.__setattr__(f'_{vendor.name}', vendor)
|
||||
else:
|
||||
raise CSConfigError(f'Invalid vendor object: {vendor}')
|
||||
|
||||
def get_vendor(self, vendor_name) -> 'Vendor':
|
||||
|
||||
def add_vendor(self, vendor: 'Vendor') -> None:
|
||||
"""
|
||||
Add a vendor to the platform.
|
||||
|
||||
Args:
|
||||
vendor: Vendor object to add
|
||||
|
||||
Raises:
|
||||
PlatformConfigError: If vendor object is invalid
|
||||
"""
|
||||
if not isinstance(vendor, Vendor):
|
||||
raise PlatformConfigError(f'Invalid vendor object: {vendor}')
|
||||
|
||||
self.vendor_list.append(vendor.name)
|
||||
self.__setattr__(f'_{vendor.name}', vendor)
|
||||
|
||||
def get_vendor(self, vendor_name: str) -> 'Vendor':
|
||||
"""
|
||||
Get a vendor by name.
|
||||
|
||||
Args:
|
||||
vendor_name: Name of the vendor
|
||||
|
||||
Returns:
|
||||
Vendor object
|
||||
|
||||
Raises:
|
||||
PlatformConfigError: If vendor not found
|
||||
"""
|
||||
if vendor_name in self.vendor_list:
|
||||
return self.__getattribute__(f'_{vendor_name}')
|
||||
else:
|
||||
raise CSConfigError(f'Invalid vendor name: {vendor_name}')
|
||||
|
||||
def remove_vendor(self, vendor):
|
||||
if isinstance(vendor, Vendor) and vendor in self.vendor_list:
|
||||
self.vendor_list.remove(vendor.name)
|
||||
self.__delattr__(f'_{vendor.name}')
|
||||
else:
|
||||
raise CSConfigError(f'Invalid vendor object: {vendor}')
|
||||
|
||||
def _get_next_level_list(self):
|
||||
raise PlatformConfigError(f'Invalid vendor name: {vendor_name}')
|
||||
|
||||
def remove_vendor(self, vendor: 'Vendor') -> None:
|
||||
"""
|
||||
Remove a vendor from the platform.
|
||||
|
||||
Args:
|
||||
vendor: Vendor object to remove
|
||||
|
||||
Raises:
|
||||
PlatformConfigError: If vendor object is invalid
|
||||
"""
|
||||
if not isinstance(vendor, Vendor) or vendor.name not in self.vendor_list:
|
||||
raise PlatformConfigError(f'Invalid vendor object: {vendor}')
|
||||
|
||||
self.vendor_list.remove(vendor.name)
|
||||
self.__delattr__(f'_{vendor.name}')
|
||||
|
||||
def _get_next_level_list(self) -> List[str]:
|
||||
"""Get list of vendor names."""
|
||||
return self.vendor_list
|
||||
|
||||
def _get_next_level(self, name):
|
||||
|
||||
def _get_next_level(self, name: str) -> 'Vendor':
|
||||
"""Get vendor by name."""
|
||||
return self.get_vendor(name)
|
||||
|
||||
def get_obj_from_fullname(self, full_name: str):
|
||||
|
||||
def get_obj_from_fullname(self, full_name: str) -> Any:
|
||||
"""
|
||||
Get object from full dotted name.
|
||||
|
||||
Args:
|
||||
full_name: Dotted name path (e.g., 'vendor.ip.bar.register')
|
||||
|
||||
Returns:
|
||||
Object at the specified path
|
||||
"""
|
||||
return self.get_obj_from_scope(full_name.split('.'))
|
||||
|
||||
def get_obj_from_scope(self, scope: list):
|
||||
def get_obj_from_scope(self, scope: List[str]) -> Any:
|
||||
"""
|
||||
Get object from scope list.
|
||||
|
||||
Args:
|
||||
scope: List of scope components
|
||||
|
||||
Returns:
|
||||
Object at the specified scope
|
||||
|
||||
Raises:
|
||||
ScopeNotFoundError: If scope contains wildcards or is invalid
|
||||
"""
|
||||
logger().log_debug(f'Getting obj from scope: {scope}')
|
||||
if any('*' in s for s in scope):
|
||||
raise Exception(f'Invalid scope: {scope}. No wildcards allowed for this function.')
|
||||
raise ScopeNotFoundError(f'Invalid scope: {scope}. No wildcards allowed for this function.')
|
||||
return Platform._get_obj_from_split_scope(self, scope)
|
||||
|
||||
@staticmethod
|
||||
def _get_obj_from_split_scope(obj, scope: list):
|
||||
def _get_obj_from_split_scope(obj: Any, scope: List[str]) -> Any:
|
||||
"""
|
||||
Recursively traverse scope to find object.
|
||||
|
||||
Args:
|
||||
obj: Current object in traversal
|
||||
scope: Remaining scope components
|
||||
|
||||
Returns:
|
||||
Object at the end of scope traversal
|
||||
|
||||
Raises:
|
||||
ScopeNotFoundError: If scope cannot be resolved
|
||||
"""
|
||||
if not scope:
|
||||
raise ScopeNotFoundError(f'Scope {scope} on obj {obj} was not found')
|
||||
|
||||
root_scope = scope.pop(0)
|
||||
next_level = obj._get_next_level(root_scope)
|
||||
|
||||
@@ -118,17 +300,49 @@ class Platform(Recursable):
|
||||
return next_level
|
||||
return Platform._get_obj_from_split_scope(next_level, scope)
|
||||
|
||||
def get_matches_from_fullname(self, full_name: str):
|
||||
def get_matches_from_fullname(self, full_name: str) -> List[Any]:
|
||||
"""
|
||||
Get matching objects from full dotted name with wildcards.
|
||||
|
||||
Args:
|
||||
full_name: Dotted name path with wildcards (e.g., 'vendor.*.register')
|
||||
|
||||
Returns:
|
||||
List of matching objects
|
||||
"""
|
||||
return self.get_matches_from_scope(full_name.split('.'))
|
||||
|
||||
def get_matches_from_scope(self, scope: list):
|
||||
def get_matches_from_scope(self, scope: List[str]) -> List[Any]:
|
||||
"""
|
||||
Get matching objects from scope list with wildcards.
|
||||
|
||||
Args:
|
||||
scope: List of scope components with wildcards
|
||||
|
||||
Returns:
|
||||
List of matching objects
|
||||
"""
|
||||
logger().log_debug(f'Getting matches from scope: {scope}')
|
||||
return Platform._get_matches_from_split_scope([self], scope)
|
||||
|
||||
@staticmethod
|
||||
def _get_matches_from_split_scope(objs: list, scope: list):
|
||||
def _get_matches_from_split_scope(objs: List[Any], scope: List[str]) -> List[Any]:
|
||||
"""
|
||||
Recursively find matching objects in scope.
|
||||
|
||||
Args:
|
||||
objs: Current objects in traversal
|
||||
scope: Remaining scope components
|
||||
|
||||
Returns:
|
||||
List of matching objects
|
||||
|
||||
Raises:
|
||||
ScopeNotFoundError: If scope cannot be resolved
|
||||
"""
|
||||
if not scope:
|
||||
raise ScopeNotFoundError(f'Scope {scope} on objs: {objs} was not found')
|
||||
|
||||
root_scope = scope.pop(0)
|
||||
next_level_list = []
|
||||
for obj in objs:
|
||||
@@ -137,20 +351,55 @@ class Platform(Recursable):
|
||||
if len(scope) == 0:
|
||||
return next_level_list
|
||||
return Platform._get_matches_from_split_scope(next_level_list, scope)
|
||||
|
||||
def get_register_from_fullname(self, full_name: str):
|
||||
|
||||
def get_register_from_fullname(self, full_name: str) -> ObjList:
|
||||
"""
|
||||
Get register from full dotted name.
|
||||
|
||||
Args:
|
||||
full_name: Dotted name path to register
|
||||
|
||||
Returns:
|
||||
Register object list
|
||||
"""
|
||||
return self.get_register_from_scope(full_name.split('.'))
|
||||
|
||||
def get_register_from_scope(self, scope: str):
|
||||
def get_register_from_scope(self, scope: List[str]) -> ObjList:
|
||||
"""
|
||||
Get register from scope list.
|
||||
|
||||
Args:
|
||||
scope: List of scope components to register
|
||||
|
||||
Returns:
|
||||
Register object list
|
||||
|
||||
Raises:
|
||||
ScopeNotFoundError: If scope contains wildcards or is invalid
|
||||
"""
|
||||
logger().log_debug(f'Getting register from scope: {scope}')
|
||||
if any('*' in s for s in scope):
|
||||
raise Exception(f'Invalid scope: {scope}. No wildcards allowed for this function.')
|
||||
raise ScopeNotFoundError(f'Invalid scope: {scope}. No wildcards allowed for this function.')
|
||||
return Platform._get_register_from_split_scope(self, scope)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def _get_register_from_split_scope(obj, scope: list):
|
||||
def _get_register_from_split_scope(obj: Any, scope: List[str]) -> ObjList:
|
||||
"""
|
||||
Recursively traverse scope to find register.
|
||||
|
||||
Args:
|
||||
obj: Current object in traversal
|
||||
scope: Remaining scope components
|
||||
|
||||
Returns:
|
||||
Register object list
|
||||
|
||||
Raises:
|
||||
ScopeNotFoundError: If scope cannot be resolved
|
||||
"""
|
||||
if not scope:
|
||||
raise ScopeNotFoundError(f'Scope {scope} on obj {obj} was not found')
|
||||
|
||||
root_scope = scope.pop(0)
|
||||
if len(scope) == 0:
|
||||
return obj.get_register(root_scope)
|
||||
@@ -159,18 +408,50 @@ class Platform(Recursable):
|
||||
|
||||
return Platform._get_register_from_split_scope(next_level, scope)
|
||||
|
||||
def get_register_matches_from_fullname(self, full_name: str):
|
||||
def get_register_matches_from_fullname(self, full_name: str) -> ObjList:
|
||||
"""
|
||||
Get matching registers from full dotted name with wildcards.
|
||||
|
||||
Args:
|
||||
full_name: Dotted name path with wildcards
|
||||
|
||||
Returns:
|
||||
List of matching register objects
|
||||
"""
|
||||
return self.get_register_matches_from_scope(full_name.split('.'))
|
||||
|
||||
def get_register_matches_from_scope(self, scope: list):
|
||||
def get_register_matches_from_scope(self, scope: List[str]) -> ObjList:
|
||||
"""
|
||||
Get matching registers from scope list with wildcards.
|
||||
|
||||
Args:
|
||||
scope: List of scope components with wildcards
|
||||
|
||||
Returns:
|
||||
List of matching register objects
|
||||
"""
|
||||
logger().log_debug(f'Getting registers from matchscope: {scope}')
|
||||
objects = Platform._get_register_matches_from_split_scope([self], scope)
|
||||
return ObjList(objects)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def _get_register_matches_from_split_scope(objs: list, scope: list):
|
||||
def _get_register_matches_from_split_scope(objs: List[Any], scope: List[str]) -> List[Any]:
|
||||
"""
|
||||
Recursively find matching registers in scope.
|
||||
|
||||
Args:
|
||||
objs: Current objects in traversal
|
||||
scope: Remaining scope components
|
||||
|
||||
Returns:
|
||||
List of matching register objects
|
||||
|
||||
Raises:
|
||||
ScopeNotFoundError: If scope cannot be resolved
|
||||
"""
|
||||
if not scope:
|
||||
raise ScopeNotFoundError(f'Scope {scope} on objs: {objs} was not found')
|
||||
|
||||
root_scope = scope.pop(0)
|
||||
next_level_list = []
|
||||
if len(scope) == 0:
|
||||
@@ -184,70 +465,178 @@ class Platform(Recursable):
|
||||
return Platform._get_register_matches_from_split_scope(next_level_list, scope)
|
||||
|
||||
|
||||
|
||||
|
||||
class Vendor(Recursable):
|
||||
def __init__(self, name):
|
||||
"""
|
||||
Vendor configuration container.
|
||||
|
||||
This class manages IP configurations for a specific vendor and provides
|
||||
hierarchical access to vendor-specific platform components.
|
||||
"""
|
||||
|
||||
def __init__(self, name: str) -> None:
|
||||
"""
|
||||
Initialize vendor configuration.
|
||||
|
||||
Args:
|
||||
name: Name of the vendor
|
||||
"""
|
||||
super().__init__()
|
||||
self.ip_list = []
|
||||
self.name = name
|
||||
|
||||
def add_ip(self, ip_name: str, obj):
|
||||
def add_ip(self, ip_name: str, obj: Any) -> None:
|
||||
"""
|
||||
Add an IP configuration to the vendor.
|
||||
|
||||
Args:
|
||||
ip_name: Name of the IP
|
||||
obj: IP configuration object
|
||||
"""
|
||||
ip = IP(ip_name, obj)
|
||||
self.ip_list.append(ip.name)
|
||||
self.__setattr__(ip.name, ip)
|
||||
|
||||
def get_ip(self, ip_name) -> 'IP':
|
||||
|
||||
def get_ip(self, ip_name: str) -> 'IP':
|
||||
"""
|
||||
Get an IP configuration by name.
|
||||
|
||||
Args:
|
||||
ip_name: Name of the IP
|
||||
|
||||
Returns:
|
||||
IP configuration object
|
||||
|
||||
Raises:
|
||||
PlatformConfigError: If IP not found
|
||||
"""
|
||||
if ip_name in self.ip_list:
|
||||
return self.__getattribute__(ip_name)
|
||||
else:
|
||||
raise CSConfigError(f'Device: {ip_name} not found in Vendor: {self.name}')
|
||||
|
||||
def _get_next_level_list(self):
|
||||
raise PlatformConfigError(f'Device: {ip_name} not found in Vendor: {self.name}')
|
||||
|
||||
def _get_next_level_list(self) -> List[str]:
|
||||
"""Get list of IP names."""
|
||||
return self.ip_list
|
||||
|
||||
def _get_next_level(self, ip_name):
|
||||
|
||||
def _get_next_level(self, ip_name: str) -> 'IP':
|
||||
"""Get IP by name."""
|
||||
return self.get_ip(ip_name)
|
||||
|
||||
|
||||
class IP(Recursable, RegisterList):
|
||||
def __init__(self, name, ipobj):
|
||||
"""
|
||||
IP (Intellectual Property) configuration container.
|
||||
|
||||
This class manages BAR configurations and registers for a specific IP block,
|
||||
providing hierarchical access to IP-specific components.
|
||||
"""
|
||||
|
||||
def __init__(self, name: str, ipobj: Any) -> None:
|
||||
"""
|
||||
Initialize IP configuration.
|
||||
|
||||
Args:
|
||||
name: Name of the IP
|
||||
ipobj: IP configuration object
|
||||
"""
|
||||
super().__init__()
|
||||
RegisterList.__init__(self)
|
||||
self.bar_list = []
|
||||
self.name = name
|
||||
self.obj = ipobj
|
||||
|
||||
def add_bar(self, bar_name: str, barobj):
|
||||
def add_bar(self, bar_name: str, barobj: Any) -> None:
|
||||
"""
|
||||
Add a BAR configuration to the IP.
|
||||
|
||||
Args:
|
||||
bar_name: Name of the BAR
|
||||
barobj: BAR configuration object
|
||||
"""
|
||||
bar = Bar(bar_name, barobj)
|
||||
self.bar_list.append(bar.name)
|
||||
self.__setattr__(f'{bar.name}_', bar)
|
||||
|
||||
def get_bar(self, bar_name: str):
|
||||
|
||||
def get_bar(self, bar_name: str) -> 'Bar':
|
||||
"""
|
||||
Get a BAR configuration by name.
|
||||
|
||||
Args:
|
||||
bar_name: Name of the BAR
|
||||
|
||||
Returns:
|
||||
BAR configuration object
|
||||
|
||||
Raises:
|
||||
BARNotFoundError: If BAR not found
|
||||
"""
|
||||
if bar_name in self.bar_list:
|
||||
return self.__getattribute__(f'{bar_name}_')
|
||||
else:
|
||||
raise BARNotFoundError(f'Bar: {bar_name} not found in IP: {self.name}')
|
||||
|
||||
def _get_next_level_list(self):
|
||||
|
||||
def _get_next_level_list(self) -> List[str]:
|
||||
"""Get list of BAR names."""
|
||||
return self.bar_list
|
||||
|
||||
def _get_next_level(self, id):
|
||||
if id in self._get_next_level_list():
|
||||
return self.get_bar(id)
|
||||
|
||||
def _get_next_level(self, bar_id: str) -> 'Bar':
|
||||
"""
|
||||
Get next level object (BAR) by ID.
|
||||
|
||||
Args:
|
||||
bar_id: BAR identifier
|
||||
|
||||
Returns:
|
||||
BAR object
|
||||
|
||||
Raises:
|
||||
PlatformConfigError: If BAR not found
|
||||
"""
|
||||
if bar_id in self._get_next_level_list():
|
||||
return self.get_bar(bar_id)
|
||||
else:
|
||||
raise CSConfigError(f'Next Level: {id} not found in in IP: {self.name}')
|
||||
|
||||
raise PlatformConfigError(f'Next Level: {bar_id} not found in IP: {self.name}')
|
||||
|
||||
|
||||
class Bar(Recursable, RegisterList):
|
||||
def __init__(self, name, barobj):
|
||||
"""
|
||||
BAR (Base Address Register) configuration container.
|
||||
|
||||
This class manages registers within a specific BAR and provides
|
||||
hierarchical access to BAR-specific registers.
|
||||
"""
|
||||
|
||||
def __init__(self, name: str, barobj: Any) -> None:
|
||||
"""
|
||||
Initialize BAR configuration.
|
||||
|
||||
Args:
|
||||
name: Name of the BAR
|
||||
barobj: BAR configuration object
|
||||
"""
|
||||
super().__init__()
|
||||
RegisterList.__init__(self)
|
||||
self.name = name
|
||||
self.obj = barobj
|
||||
|
||||
def _get_next_level_list(self):
|
||||
return self.register_list
|
||||
|
||||
def _get_next_level(self, id):
|
||||
if id in self.register_list.keys():
|
||||
return self.get_register(id)
|
||||
def _get_next_level_list(self) -> List[str]:
|
||||
"""Get list of register names."""
|
||||
return list(self.register_list.keys())
|
||||
|
||||
def _get_next_level(self, register_id: str) -> ObjList:
|
||||
"""
|
||||
Get next level object (register) by ID.
|
||||
|
||||
Args:
|
||||
register_id: Register identifier
|
||||
|
||||
Returns:
|
||||
Register object list
|
||||
|
||||
Raises:
|
||||
PlatformConfigError: If register not found
|
||||
"""
|
||||
if register_id in self.register_list.keys():
|
||||
return self.get_register(register_id)
|
||||
else:
|
||||
raise CSConfigError(f'Bar: {id} not found in in IP: {self.name}')
|
||||
|
||||
raise PlatformConfigError(f'Register: {register_id} not found in BAR: {self.name}')
|
||||
|
||||
Reference in New Issue
Block a user