1# Copyright (C) 2019-2022 Intel Corporation.
2#
3# SPDX-License-Identifier: BSD-3-Clause
4#
5
6import os
7import sys
8import shutil
9import argparse
10import pci_dev
11import dmi
12import acpi
13import clos
14import misc
15import parser_lib
16import logging
17from inspectorlib import external_tools
18
19OUTPUT = "./out/"
20PY_CACHE = "__pycache__"
21
22CPU_VENDOR = "GenuineIntel"
23
24def check_permission():
25    """Check if it is root permission"""
26    if os.getuid():
27        logging.critical("Run this tool with root privileges (sudo).")
28        sys.exit(1)
29
30def vendor_check():
31    """Check the CPU vendor"""
32    with open("/proc/cpuinfo", 'r') as f_node:
33        while True:
34            line = f_node.readline()
35            if len(line.split(':')) == 2:
36                if line.split(':')[0].strip() == "vendor_id":
37                    vendor_name = line.split(':')[1].strip()
38                    return vendor_name == CPU_VENDOR
39
40def check_msr_nodes(cpu_dirs):
41    cpu_list_of_no_msr_node = []
42    for cpu_num in os.listdir(cpu_dirs):
43        if cpu_num.isdigit():
44            if os.path.exists(os.path.join(cpu_dirs, "{}/msr".format(cpu_num))):
45                continue
46            else:
47                cpu_list_of_no_msr_node.append(cpu_num)
48    return cpu_list_of_no_msr_node
49
50def check_env():
51    """Check if there is appropriate environment on this system"""
52    if os.path.exists(PY_CACHE):
53        shutil.rmtree(PY_CACHE)
54
55    if not external_tools.locate_tools(['cpuid', 'rdmsr', 'lspci', 'dmidecode', 'blkid', 'stty', 'modprobe']):
56        sys.exit(1)
57
58    # check cpu msr file
59    cpu_dirs = "/dev/cpu"
60    if check_msr_nodes(cpu_dirs):
61        res = external_tools.run("modprobe msr")
62        err_msg = res.stderr.readline().decode('ascii')
63        if err_msg:
64            logging.critical("{}".format(err_msg))
65            exit(-1)
66    msr_node_unavailable_cpus = check_msr_nodes(cpu_dirs)
67    if msr_node_unavailable_cpus:
68        for cpu_num in msr_node_unavailable_cpus:
69            logging.critical("Missing CPU MSR file at {}/{}/msr".format(cpu_dirs, cpu_num))
70        logging.critical("Missing CPU MSR file /dev/cpu/#/msr. Check the value of CONFIG_X86_MSR in the kernel config." \
71        "  Set it to 'Y' and rebuild the OS. Then rerun the Board Inspector.")
72        exit(-1)
73
74    # check cpu vendor id
75    if not vendor_check():
76        logging.critical(f"Unsupported processor {CPU_VENDOR} found.  ACRN requires using a {CPU_VENDOR} processor.")
77        sys.exit(1)
78
79    if os.path.exists(OUTPUT):
80        shutil.rmtree(OUTPUT)
81
82
83if __name__ == '__main__':
84    check_permission()
85
86    check_env()
87
88    # arguments to parse
89    PARSER = argparse.ArgumentParser(usage='%(prog)s <board_name> [--out board_info_file]')
90    PARSER.add_argument('board_name', help=":  the name of the board that runs the ACRN hypervisor")
91    PARSER.add_argument('--out', help=":  the name of board info file.")
92    ARGS = PARSER.parse_args()
93
94    if not ARGS.out:
95        os.makedirs(OUTPUT)
96        BOARD_INFO = OUTPUT + ARGS.board_name + ".xml"
97    else:
98        BOARD_INFO = ARGS.out
99
100    with open(BOARD_INFO, 'w+') as f:
101        print('<acrn-config board="{}">'.format(ARGS.board_name), file=f)
102
103    # Get bios and base board info and store to board info
104    dmi.generate_info(BOARD_INFO)
105
106    # Get pci devicse table and store pci info to board info
107    pci_dev.generate_info(BOARD_INFO)
108
109    # Generate board info
110    acpi.generate_info(BOARD_INFO)
111
112    # Generate clos info
113    clos.generate_info(BOARD_INFO)
114
115    # Generate misc info
116    misc.generate_info(BOARD_INFO)
117
118    with open(BOARD_INFO, 'a+') as f:
119        print("</acrn-config>", file=f)
120