From e1bdd809b6d7005379d3f147f4f95ec7865e1cca Mon Sep 17 00:00:00 2001
From: Ivan-Velickovic <i.velickovic@unsw.edu.au>
Date: Fri, 16 Jun 2023 16:51:21 +1000
Subject: [PATCH] Output JSON for hardware configuration

Signed-off-by: Ivan-Velickovic <i.velickovic@unsw.edu.au>
---
 CMakeLists.txt                 |  3 ++
 config.cmake                   |  7 +++-
 tools/hardware/outputs/json.py | 64 ++++++++++++++++++++++++++++++++++
 tools/hardware_gen.py          |  3 +-
 4 files changed, 75 insertions(+), 2 deletions(-)
 create mode 100644 tools/hardware/outputs/json.py

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 98818cf2e..19e0f684e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -767,5 +767,8 @@ if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
     if(DEFINED platform_yaml)
         install(FILES ${platform_yaml} DESTINATION support)
     endif()
+    if(DEFINED platform_json)
+        install(FILES ${platform_json} DESTINATION support)
+    endif()
 
 endif()
diff --git a/config.cmake b/config.cmake
index f07cec723..a6565b8b2 100644
--- a/config.cmake
+++ b/config.cmake
@@ -116,6 +116,10 @@ if(DEFINED KernelDTSList AND (NOT "${KernelDTSList}" STREQUAL ""))
         platform_yaml "${CMAKE_CURRENT_BINARY_DIR}/gen_headers/plat/machine/platform_gen.yaml"
         CACHE INTERNAL "Location of platform YAML description"
     )
+    set(
+        platform_json "${CMAKE_CURRENT_BINARY_DIR}/gen_headers/plat/machine/platform_gen.json"
+        CACHE INTERNAL "Location of platform JSON description"
+    )
     set(config_file "${CMAKE_CURRENT_SOURCE_DIR}/tools/hardware.yml")
     set(config_schema "${CMAKE_CURRENT_SOURCE_DIR}/tools/hardware_schema.yml")
     set(
@@ -202,7 +206,8 @@ if(DEFINED KernelDTSList AND (NOT "${KernelDTSList}" STREQUAL ""))
                 --compat-strings-out "${compatibility_outfile}" --c-header --header-out
                 "${device_dest}" --hardware-config "${config_file}" --hardware-schema
                 "${config_schema}" --yaml --yaml-out "${platform_yaml}" --sel4arch
-                "${KernelSel4Arch}" --addrspace-max "${KernelPaddrUserTop}"
+                "${KernelSel4Arch}" --addrspace-max "${KernelPaddrUserTop}" --json --json-out
+                "${platform_json}"
             RESULT_VARIABLE error
         )
         if(error)
diff --git a/tools/hardware/outputs/json.py b/tools/hardware/outputs/json.py
new file mode 100644
index 000000000..d10fcae88
--- /dev/null
+++ b/tools/hardware/outputs/json.py
@@ -0,0 +1,64 @@
+#
+# Copyright 2023, UNSW
+#
+# SPDX-License-Identifier: GPL-2.0-only
+#
+
+''' Generate a JSON file with memory region info from the device tree '''
+
+import argparse
+import json
+from typing import List
+import hardware
+from hardware.config import Config
+from hardware.fdt import FdtParser
+from hardware.utils.rule import HardwareYaml
+
+
+def make_json_list_of_regions(regions) -> List:
+    return [
+        {
+            'start': r.base,
+            'end':   r.base + r.size
+        }
+        for r in regions if r.size > 0
+    ]
+
+
+def create_json_file(dev_mem, phys_mem, output_stream):
+    json_obj = {
+        'devices': make_json_list_of_regions(dev_mem),
+        'memory':  make_json_list_of_regions(phys_mem)
+    }
+
+    with output_stream:
+        json.dump(json_obj, output_stream)
+
+
+def get_kernel_devices(tree: FdtParser, hw_yaml: HardwareYaml):
+    kernel_devices = tree.get_kernel_devices()
+
+    groups = []
+    for dev in kernel_devices:
+        rule = hw_yaml.get_rule(dev)
+        groups += rule.get_regions(dev)
+
+    return groups
+
+
+def run(tree: FdtParser, hw_yaml: HardwareYaml, config: Config,
+        args: argparse.Namespace):
+    if not args.json_out:
+        raise ValueError('you need to provide a json-out to use the JSON output method')
+
+    phys_mem, reserved, _ = hardware.utils.memory.get_physical_memory(tree, config)
+    kernel_devs = get_kernel_devices(tree, hw_yaml)
+    dev_mem = hardware.utils.memory.get_addrspace_exclude(
+        list(reserved) + phys_mem + kernel_devs, config)
+
+    create_json_file(dev_mem, phys_mem, args.json_out)
+
+
+def add_args(parser):
+    parser.add_argument('--json-out', help='output file for memory represented in JSON',
+                        type=argparse.FileType('w'))
diff --git a/tools/hardware_gen.py b/tools/hardware_gen.py
index a97d23f0d..6eb91f384 100644
--- a/tools/hardware_gen.py
+++ b/tools/hardware_gen.py
@@ -13,7 +13,7 @@ import yaml
 import hardware
 from hardware.config import Config
 from hardware.fdt import FdtParser
-from hardware.outputs import c_header, compat_strings, yaml as yaml_out, elfloader
+from hardware.outputs import c_header, compat_strings, yaml as yaml_out, json as json_out, elfloader
 from hardware.utils.rule import HardwareYaml
 
 
@@ -22,6 +22,7 @@ OUTPUTS = {
     'compat_strings': compat_strings,
     'elfloader': elfloader,
     'yaml': yaml_out,
+    'json': json_out,
 }
 
 
-- 
GitLab