Update ip objects

Signed-off-by: brentholtsclaw <brent.holtsclaw@intel.com>
This commit is contained in:
brentholtsclaw
2025-07-07 10:44:30 -07:00
committed by Nathaniel Mitchell
parent da143f80da
commit 97aa48963c
10 changed files with 2374 additions and 261 deletions
+257 -12
View File
@@ -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
}
+135 -7
View File
@@ -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
View File
@@ -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}'
+190 -10
View File
@@ -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)})")
+127 -6
View File
@@ -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})"
+321 -63
View File
@@ -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)})")
+118 -6
View File
@@ -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})"
+113 -5
View File
@@ -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})"
+342 -30
View File
@@ -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)})")
+488 -99
View File
@@ -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}')