FVP Linux and TFTF YAML Support

Introduce support for fvp-[linux|tftf]-yaml generation, the latter to be
consumed by an FVP LAVA device on behalf of TF-A CI (Jenkins).

Two build configs and one run config are instrumented for RFC
purposes, but once patch is more mature, many more will come.

This work is part of M2 (FVP Support (TF-M ID3, TF-A ID26)), and
M3 (Run TF-TF tests "bare metal" on FVP (TF-A ID24)) of [1].

Note: Testing and review is on-going so patchset may required some
changes if needed.

[1] https://developer.trustedfirmware.org/w/collaboration/openci/

Change-Id: I613cd2e4028f6cef3e96976cf5f3f1180e156440
Signed-off-by: Leonardo Sandoval <leonardo.sandoval@linaro.org>
diff --git a/fvp_utils.sh b/fvp_utils.sh
index 8c146cd..06a6018 100644
--- a/fvp_utils.sh
+++ b/fvp_utils.sh
@@ -207,4 +207,97 @@
 	mv "$fvp_romlib_jmptbl_backup" "${tf_root:?}/plat/arm/board/fvp/jmptbl.i"
 }
 
+
+fvp_gen_bin_url() {
+    local bin_mode="${bin_mode:?}"
+    local bin="${1:?}"
+
+    if upon "$jenkins_run"; then
+        echo "$jenkins_url/job/$JOB_NAME/$BUILD_NUMBER/artifact/artefacts/$bin_mode/$bin"
+    else
+        echo "file://$workspace/artefacts/$bin_mode/$bin"
+    fi
+}
+
+gen_fvp_yaml_template() {
+    local yaml_template_file="$workspace/fvp_template.yaml"
+
+    # must parameters for yaml generation
+    local payload_type="${payload_type:?}"
+
+    "$ci_root/script/gen_fvp_${payload_type}_yaml.sh" > "$yaml_template_file"
+
+    archive_file "$yaml_template_file"
+}
+
+gen_fvp_yaml() {
+    local yaml_template_file="$workspace/fvp_template.yaml"
+    local yaml_file="$workspace/fvp.yaml"
+
+    # must parameters for yaml generation
+    local model="${model:?}"
+    local dtb="${dtb:?}"
+    local container_name="${container_name:?}"
+    local container_model_params="${container_model_params:?}"
+    local container_entrypoint="${container_entrypoint:?}"
+    local archive="${archive:?}"
+
+    # general artefacts
+    bl1="$(fvp_gen_bin_url bl1.bin)"
+    fip="$(fvp_gen_bin_url fip.bin)"
+
+    # linux artefacts
+    dtb="$(fvp_gen_bin_url $dtb)"
+    image="$(fvp_gen_bin_url kernel.bin)"
+    ramdisk="$(fvp_gen_bin_url initrd.bin)"
+
+    # tftf's ns_bl[1|2]u.bin artefacts
+    ns_bl1u="$(fvp_gen_bin_url ns_bl1u.bin)"
+    ns_bl2u="$(fvp_gen_bin_url ns_bl2u.bin)"
+
+    docker_registry="${docker_registry:-}"
+    docker_registry="$(docker_registry_append)"
+
+    docker_name="${docker_registry}$container_name"
+
+    version_string="\"ARM ${model}"' [^\\n]+'"\""
+
+    sed -e "s|\${ACTIONS_DEPLOY_IMAGES_BL1}|${bl1}|" \
+        -e "s|\${ACTIONS_DEPLOY_IMAGES_FIP}|${fip}|" \
+        -e "s|\${ACTIONS_DEPLOY_IMAGES_DTB}|${dtb}|" \
+        -e "s|\${ACTIONS_DEPLOY_IMAGES_IMAGE}|${image}|" \
+        -e "s|\${ACTIONS_DEPLOY_IMAGES_RAMDISK}|${ramdisk}|" \
+        -e "s|\${ACTIONS_DEPLOY_IMAGES_NS_BL1U}|${ns_bl1u}|" \
+        -e "s|\${ACTIONS_DEPLOY_IMAGES_NS_BL2U}|${ns_bl2u}|" \
+        -e "s|\${BOOT_DOCKER_NAME}|${docker_name}|" \
+        -e "s|\${BOOT_IMAGE}|${container_entrypoint}|" \
+        -e "s|\${BOOT_VERSION_STRING}|${version_string}|" \
+        < "$yaml_template_file" \
+        > "$yaml_file"
+
+    # include the model parameters
+    while read -r line; do
+        if [ -n "$line" ]; then
+	    yaml_line="- \"${line}\""
+            sed -i -e "/\${BOOT_ARGUMENTS}/i \ \ \ \ $yaml_line" "$yaml_file"
+        fi
+    done < "$archive/model_params"
+    sed -i -e '/\${BOOT_ARGUMENTS}/d' "$yaml_file"
+
+    archive_file "$yaml_file"
+}
+
+docker_registry_append() {
+    # if docker_registry is empty, just use local docker registry
+    [ -z "$docker_registry" ] && return
+
+    local last=-1
+    local last_char="${docker_registry:last}"
+
+    if [ "$last_char" != '/' ]; then
+        docker_registry="${docker_registry}/";
+    fi
+    echo "$docker_registry"
+}
+
 set +u
diff --git a/run_config/fvp-cortexa35x4 b/run_config/fvp-cortexa35x4
index 0e33a77..10daf78 100644
--- a/run_config/fvp-cortexa35x4
+++ b/run_config/fvp-cortexa35x4
@@ -6,6 +6,14 @@
 #
 
 post_fetch_tf_resource() {
-	model="cortex-a35x4" gen_model_params
+	local model="cortex-a35x4"
+	model="$model" gen_model_params
 	uart="0" set_expect_variable "num_cpus" "4"
+
+	model="$model" \
+	dtb="fvp-base-gicv3-psci.dtb" \
+	container_name="fvp:fvp_base_cortex-a35x124_11.11_34" \
+	container_model_params="$archive/model_params" \
+	container_entrypoint="/opt/model/FVP_Base_Cortex-A35x124/models/Linux64_GCC-6.4/FVP_Base_Cortex-A35x4" \
+	gen_fvp_yaml
 }
diff --git a/run_config/fvp-linux b/run_config/fvp-linux
index ec823c6..426df4f 100644
--- a/run_config/fvp-linux
+++ b/run_config/fvp-linux
@@ -9,4 +9,6 @@
 	kernel_type="fvp-busybox-uboot" get_kernel
 	initrd_type="default" get_initrd
 	uart="0" file="linux-rd-busybox.exp" track_expect
+
+	payload_type="linux" gen_fvp_yaml_template
 }
diff --git a/run_config/fvp-tftf b/run_config/fvp-tftf
index cbf5086..3d53188 100644
--- a/run_config/fvp-tftf
+++ b/run_config/fvp-tftf
@@ -8,4 +8,6 @@
 fetch_tf_resource() {
 	uart="0" file="tftf.exp" track_expect
 	uart="1" file="hold_uart.exp" track_expect
+
+	payload_type="tftf" gen_fvp_yaml_template
 }
diff --git a/script/gen_fvp_linux_yaml.sh b/script/gen_fvp_linux_yaml.sh
new file mode 100755
index 0000000..7cf1315
--- /dev/null
+++ b/script/gen_fvp_linux_yaml.sh
@@ -0,0 +1,63 @@
+#!/usr/bin/env bash
+#
+# Copyright (c) 2019, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Generate a FVP-Linux model agnostic YAML template. Note that this template is not ready to be
+# sent to LAVA by Jenkins so in order to produce file, variables in ${UPPERCASE} must be replaced
+# to correct values
+
+cat <<EOF
+device_type: fvp
+job_name: tf-fvp
+
+timeouts:
+  connection:
+    minutes: 3
+  job:
+    minutes: 10
+  actions:
+    auto-login-action:
+      minutes: 5
+    http-download:
+      minutes: 2
+    download-retry:
+      minutes: 2
+    fvp-deploy:
+      minutes: 5
+
+priority: medium
+visibility: public
+
+actions:
+- deploy:
+    to: fvp
+    images:
+      bl1:
+        url: \${ACTIONS_DEPLOY_IMAGES_BL1}
+      fip:
+        url: \${ACTIONS_DEPLOY_IMAGES_FIP}
+      dtb:
+        url: \${ACTIONS_DEPLOY_IMAGES_DTB}
+      image:
+        url: \${ACTIONS_DEPLOY_IMAGES_IMAGE}
+      ramdisk:
+        url: \${ACTIONS_DEPLOY_IMAGES_RAMDISK}
+
+- boot:
+    method: fvp
+    docker:
+      name: \${BOOT_DOCKER_NAME}
+      local: true
+    image: \${BOOT_IMAGE}
+    version_string: \${BOOT_VERSION_STRING}
+    timeout:
+      minutes: 7
+    console_string: 'terminal_0: Listening for serial connection on port (?P<PORT>\d+)'
+    arguments:
+\${BOOT_ARGUMENTS}
+    prompts:
+    - '/ #'
+EOF
diff --git a/script/gen_fvp_tftf_yaml.sh b/script/gen_fvp_tftf_yaml.sh
new file mode 100755
index 0000000..56b10ad
--- /dev/null
+++ b/script/gen_fvp_tftf_yaml.sh
@@ -0,0 +1,78 @@
+#!/usr/bin/env bash
+#
+# Copyright (c) 2019, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Generate a FVP-TFTF model agnostic YAML template. Note that this template is not ready to be
+# sent to LAVA by Jenkins so in order to produce file, variables in ${UPPERCASE} must be replaced
+# to correct values
+
+cat <<EOF
+device_type: fvp
+job_name: tf-fvp
+
+timeouts:
+  connection:
+    minutes: 3
+  job:
+    minutes: 10
+  actions:
+    auto-login-action:
+      minutes: 5
+    http-download:
+      minutes: 2
+    download-retry:
+      minutes: 2
+    fvp-deploy:
+      minutes: 5
+
+priority: medium
+visibility: public
+
+actions:
+- deploy:
+    to: fvp
+    images:
+      bl1:
+        url: \${ACTIONS_DEPLOY_IMAGES_BL1}
+      fip:
+        url: \${ACTIONS_DEPLOY_IMAGES_FIP}
+      ns_bl1u:
+        url: \${ACTIONS_DEPLOY_IMAGES_NS_BL1U}
+      ns_bl2u:
+        url: \${ACTIONS_DEPLOY_IMAGES_NS_BL2U}
+
+- boot:
+    method: fvp
+    docker:
+      name: \${BOOT_DOCKER_NAME}
+      local: true
+    image: \${BOOT_IMAGE}
+    version_string: \${BOOT_VERSION_STRING}
+    timeout:
+      minutes: 30
+
+    monitors:
+    - name: TFTF
+      # LAVA looks for a testsuite start string...
+      start: 'Booting trusted firmware test framework'
+      # ...and a testsuite end string.
+      end: 'Exiting tests.'
+
+      # For each test case, LAVA looks for a string which includes the testcase
+      # name and result.
+      pattern: "(?s)> Executing '(?P<test_case_id>.+?(?='))'(.*)  TEST COMPLETE\\\s+(?P<result>(Skipped|Passed|Failed|Crashed))"
+
+      # Teach to LAVA how to interpret the TFTF Tests results.
+      fixupdict:
+        Passed: pass
+        Failed: fail
+        Crashed: fail
+        Skipped: skip
+
+    arguments:
+\${BOOT_ARGUMENTS}
+
+EOF
diff --git a/utils.sh b/utils.sh
index 87129fa..5f594a5 100644
--- a/utils.sh
+++ b/utils.sh
@@ -334,6 +334,8 @@
 "--hfa"
 )
 
+docker_registry="${docker_registry:-}"
+
 # Define toolchain version and toolchain binary paths
 toolchain_version="9.2-2019.12"