#
# SPDX-FileCopyrightText: <text>Copyright 2025 Arm Limited
# and/or its affiliates <open-source-office@arm.com></text>
#
# SPDX-License-Identifier: MIT
#
import os
from pathlib import Path
import logging
import sys
from test_automation.targets.fvp.autofvpnetworking import (
TelnetSessionManager as TM,
)
from test_automation.targets.fvp.fvp_controller import LocalFVP
from test_automation.targets.registry import (
register_platform,
DriverBundle,
)
[docs]
logger = logging.getLogger(__name__)
@register_platform("fvp")
[docs]
def make_fvp_bundle(platform_dict, cfg) -> DriverBundle:
"""
Build and return a driver instance for the ``fvp`` platform.
:param platform_dict: Platform configuration mapping as loaded from YAML.
:param cfg: Global configuration object and forwarded to the telnet session
manager for context.
:returns: A :class:`DriverBundle`.
"""
platform_name = platform_dict["name"]
telnet = TM(config=cfg, platform=platform_name, test_name="session")
fvp_device = LocalFVP(platform_config=platform_dict, telnet_manager=telnet)
def _login_primary(mgr: TM, plat: dict):
"""
Log in on the primary console using the session manager's prompt maps.
:param mgr: Active :class:`TelnetSessionManager` that manages console
sessions.
:param plat: Platform configuration mapping (expects ``port_map`` with
``default_console``).
:raises AssertionError: If the expected prompts are not observed on the
primary console during login.
:returns: ``None``.
"""
mapping = mgr.terminal_to_port
primary_console = plat["port_map"]["default_console"]
assert (
primary_console in mapping
), f"Primary console ({primary_console}) not found"
port = mapping[primary_console]
login_prompt = mgr.login_prompt_map.get(
primary_console, mgr.default_login_prompt
)
shell_prompt = mgr.shell_prompt_map.get(
primary_console, mgr.default_shell_prompt
)
assert mgr.wait_for_prompt_in_log(port, login_prompt, timeout=100), (
f"Login prompt '{login_prompt}' not seen on "
f"{primary_console}:{port}"
)
assert mgr.wait_for_prompt_in_log(port, login_prompt, timeout=100), (
f"Login prompt '{login_prompt}' not seen on "
f"{primary_console}:{port}"
)
mgr.sessions[port].sendline("root")
assert mgr.wait_for_prompt_in_log(port, shell_prompt, timeout=100), (
f"Shell prompt '{shell_prompt}' not seen on "
f"{primary_console}:{port}"
)
logger.info("Logged in on %s:%d", primary_console, port)
def _export_env(pytestconfig, plat: dict) -> None:
"""
Optionally export environment variables for FVP execution.
Sets ``FVP_BINARY`` from ``--fvp-binary`` or existing environment, and
attempts to locate ``Crypto.so`` under the model base directory. If the
provided binary path does not exist, the process exits.
:param pytestconfig: Pytest configuration object used to read
command-line options.
:param plat: Platform configuration mapping
(context only; not modified).
:returns: ``None``.
:raises SystemExit: If an invalid FVP binary path is supplied.
"""
fvp_bin_cli = pytestconfig.getoption("--fvp-binary")
fvp_bin = fvp_bin_cli or os.environ.get("FVP_BINARY")
if not fvp_bin:
logger.info("No --fvp-binary provided; skipping FVP env export")
return
bin_path = Path(fvp_bin).expanduser().resolve()
if not bin_path.exists():
logger.warning("FVP binary does not exist: %s", bin_path)
sys.exit(1)
model_dir = bin_path.parent
fvp_base_dir = model_dir.parent.parent
os.environ["FVP_BINARY"] = str(bin_path)
# Optional Crypto.so autodiscovery
crypto_path = None
try:
for p in fvp_base_dir.rglob("Crypto.so"):
crypto_path = str(p.resolve())
break
except Exception as e:
logger.warning("Error searching for Crypto.so: %s", e)
if crypto_path:
os.environ["FVP_CRYPTO_PATH"] = crypto_path
logger.debug("Found Crypto.so at: %s", crypto_path)
else:
logger.warning("Crypto.so not found under %s", fvp_base_dir)
return DriverBundle(
driver=fvp_device,
manager=telnet,
login_primary=_login_primary,
export_env=_export_env,
)