1# Copyright (C) 2019-2022 Intel Corporation.
2#
3# SPDX-License-Identifier: BSD-3-Clause
4#
5
6import logging
7
8import board_cfg_lib
9import acrn_config_utilities
10
11PLATFORM_HEADER = r"""/* DO NOT MODIFY THIS FILE UNLESS YOU KNOW WHAT YOU ARE DOING!
12 */
13
14#ifndef PLATFORM_ACPI_INFO_H
15#define PLATFORM_ACPI_INFO_H
16"""
17
18PLATFORM_END_HEADER = "#endif /* PLATFORM_ACPI_INFO_H */"
19
20
21class OverridAccessSize():
22    """ The Pm access size which are needed to redefine """
23    def __init__(self):
24        self.pm1a_cnt_ac_sz = True
25        self.pm1b_cnt_ac_sz = True
26        self.pm1b_evt_ac_sz = True
27
28    def style_check_1(self):
29        """ Style check if have public method """
30        self.pm1a_cnt_ac_sz = True
31
32    def style_check_2(self):
33        """ Style check if have public method """
34        self.pm1a_cnt_ac_sz = True
35
36
37def multi_parser(line, s_line, pm_ac_sz, config):
38    """
39    Multi parse the line
40    :param line: it is a line read from default_acpi_info.h
41    :param s_line: it is a line read from board information file
42    :param pm_ac_sz: it is a class for access size which would be override
43    :param config: it is a file pointer to write acpi information
44    """
45    addr = ['PM1A_EVT_ADDRESS', 'PM1B_EVT_ADDRESS', 'PM1A_CNT_ADDRESS', 'PM1B_CNT_ADDRESS']
46    space_id = ['PM1A_EVT_SPACE_ID', 'PM1B_EVT_SPACE_ID', 'PM1A_CNT_SPACE_ID', 'PM1B_CNT_SPACE_ID']
47
48    if line.split()[1] in space_id and line.split()[1] == s_line.split()[1]:
49        if line.split()[2] != s_line.split()[2]:
50            print("#undef {}".format(s_line.split()[1]), file=config)
51            print("{}".format(s_line.strip()), file=config)
52        return
53
54    if line.split()[1] in addr and line.split()[1] == s_line.split()[1]:
55        if int(line.split()[2].strip('UL'), 16) != \
56                int(s_line.split()[2].strip('UL'), 16) and \
57                int(s_line.split()[2].strip('UL'), 16) != 0:
58            print("#undef {}".format(s_line.split()[1]), file=config)
59            print("{}".format(s_line.strip()), file=config)
60        else:
61            if "PM1B_EVT" in line.split()[1]:
62                pm_ac_sz.pm1b_evt_ac_sz = False
63            if "PM1B_CNT" in line.split()[1]:
64                pm_ac_sz.pm1b_cnt_ac_sz = False
65
66        return
67
68    if line.split()[1] == s_line.split()[1]:
69        if "PM1B_EVT" in line.split()[1] and not pm_ac_sz.pm1b_evt_ac_sz:
70            return
71
72        if "PM1B_CNT" in line.split()[1] and not pm_ac_sz.pm1b_cnt_ac_sz:
73            return
74
75        if "PM1A_CNT" in line.split()[1] and not pm_ac_sz.pm1a_cnt_ac_sz:
76            return
77
78        if int(line.split()[2].strip('U'), 16) != int(s_line.split()[2].strip('U'), 16):
79            print("#undef {}".format(s_line.split()[1]), file=config)
80            print("{}".format(s_line.strip()), file=config)
81
82
83def multi_info_parser(config, default_platform, msg_s, msg_e):
84    """
85    Parse multi information
86    :param config: it is a file pointer to write acpi information
87    :param default_platform: it is the default_acpi_info.h in acrn-hypervisor
88    :param msg_s: it is a pattern of key stings what start to match from board information
89    :param msg_e: it is a pattern of key stings what end to match from board information
90    """
91    write_direct = ['PM1A_EVT_ACCESS_SIZE', 'PM1A_EVT_ADDRESS', 'PM1A_CNT_ADDRESS']
92
93    pm_ac_sz = OverridAccessSize()
94    multi_lines = board_cfg_lib.get_info(acrn_config_utilities.BOARD_INFO_FILE, msg_s, msg_e)
95
96    msg_name = msg_s.split('_')[0].strip('<')
97
98    # Set defaults for PM1A registers if not present in target xml file
99    if not multi_lines and msg_name in ("PM1A"):
100        print("#define PM1A_EVT_ACCESS_SIZE\t0U", file=config)
101        print("#define PM1A_EVT_ADDRESS\t0UL", file=config)
102        print("#define PM1A_CNT_ADDRESS\t0UL", file=config)
103        return
104
105    # S3/S5 not supported by BIOS
106    if not multi_lines and msg_name in ("S3", "S5"):
107        print("/* {} is not supported by BIOS */".format(msg_name), file=config)
108        return
109
110    for s_line in multi_lines:
111        # parse the commend line
112        if '/*' in s_line:
113            print("{}".format(s_line), file=config)
114            continue
115
116        if s_line.split()[1] in write_direct:
117            if "PM1A_CNT" in s_line.split()[1] and int(s_line.split()[2].strip('UL'), 16) == 0:
118                pm_ac_sz.pm1a_cnt_ac_sz = False
119
120            print("{}".format(s_line.strip()), file=config)
121            continue
122
123        with open(default_platform, 'r') as default:
124            while True:
125                line = default.readline()
126
127                if not line:
128                    break
129
130                if len(line.split()) < 2:
131                    continue
132
133                multi_parser(line, s_line, pm_ac_sz, config)
134
135
136def write_direct_info_parser(config, msg_s, msg_e):
137    """
138    Direct to write
139    :param config: it is a file pointer to write acpi information
140    :param msg_s: it is a pattern of key stings what start to match from board information
141    :param msg_e: it is a pattern of key stings what end to match from board information
142    """
143    vector_lines = board_cfg_lib.get_info(acrn_config_utilities.BOARD_INFO_FILE, msg_s, msg_e)
144    msg_name = msg_s.split('_')[0].strip('<')
145
146    # Set defaults if not present in target xml file
147    if not vector_lines and msg_name in ("WAKE"):
148        print("\n#define WAKE_VECTOR_32\t\t0UL", file=config)
149        print("#define WAKE_VECTOR_64\t\t0UL", file=config)
150        return
151
152    if not vector_lines and msg_name in ("RESET"):
153        print("\n#define RESET_REGISTER_ADDRESS\t0UL", file=config)
154        print("#define RESET_REGISTER_VALUE\t0UL", file=config)
155        print("#define RESET_REGISTER_SPACE_ID\t0UL", file=config)
156        return
157
158    if not vector_lines and msg_name in ("MMCFG"):
159        print("\n#define DEFAULT_PCI_MMCFG_BASE\t0UL", file=config)
160        return
161
162    if msg_name in ("IOMEM"):
163        if vector_lines:
164            for vector in vector_lines:
165                if "MMCONFIG" in vector:
166                    try:
167                        bus_list = vector.split("bus")[1].strip().split("-")
168                        start_bus_number = int(bus_list[0].strip(), 16)
169                        end_bus_number = int(bus_list[1].strip("]"), 16)
170                        print("/* PCI mmcfg bus number of MCFG */", file=config)
171                        print("#define DEFAULT_PCI_MMCFG_START_BUS \t 0x{:X}U".format(start_bus_number), file=config)
172                        print("#define DEFAULT_PCI_MMCFG_END_BUS   \t 0x{:X}U\n".format(end_bus_number), file=config)
173                        print("", file=config)
174                        return
175                    except:
176                        pass
177
178        print("/* PCI mmcfg bus number of MCFG */", file=config)
179        print("#define DEFAULT_PCI_MMCFG_START_BUS\t0U", file=config)
180        print("#define DEFAULT_PCI_MMCFG_END_BUS\t0U", file=config)
181        print("", file=config)
182        return
183
184    for vector in vector_lines:
185        print("{}".format(vector.strip()), file=config)
186
187    print("", file=config)
188
189
190def drhd_info_parser(config):
191    """
192    Parse DRHD information
193    :param config: it is a file pointer to write acpi information
194    """
195    has_drhd_max_devscope_count = False
196
197    drhd_lines = board_cfg_lib.get_info(
198        acrn_config_utilities.BOARD_INFO_FILE, "<DRHD_INFO>", "</DRHD_INFO>")
199
200    # write DRHD
201    print("/* DRHD of DMAR */", file=config)
202
203    if not drhd_lines:
204        print("\n#define DRHD_COUNT\t\t8U", file=config)
205        print("\n#define DRHD_MAX_DEVSCOPE_COUNT\t16U", file=config)
206        return
207
208    for drhd in drhd_lines:
209        if "DRHD_MAX_DEVSCOPE_COUNT" in drhd:
210            has_drhd_max_devscope_count = True
211            break
212
213    if not has_drhd_max_devscope_count:
214        logging.warning("DRHD_MAX_DEVSCOPE_COUNT is not defined in board.xml, using default 16U. "
215                        "Generate board.xml with latest board inspector to remove this warning.")
216        print("\n#define DRHD_MAX_DEVSCOPE_COUNT\t16U", file=config)
217
218    for drhd in drhd_lines:
219        print(drhd.strip(), file=config)
220
221
222def platform_info_parser(config, default_platform):
223    """
224    Parse ACPI information
225    :param config: it is a file pointer to write acpi information
226    :param default_platform: it is the default_acpi_info.h in acrn-hypervisor
227    """
228    print("\n/* pm sstate data */", file=config)
229    multi_info_parser(config, default_platform, "<PM_INFO>", "</PM_INFO>")
230    multi_info_parser(config, default_platform, "<S3_INFO>", "</S3_INFO>")
231    multi_info_parser(config, default_platform, "<S5_INFO>", "</S5_INFO>")
232    print("", file=config)
233
234    write_direct_info_parser(config, "<WAKE_VECTOR_INFO>", "</WAKE_VECTOR_INFO>")
235    write_direct_info_parser(config, "<RESET_REGISTER_INFO>", "</RESET_REGISTER_INFO>")
236    drhd_info_parser(config)
237    write_direct_info_parser(config, "<MMCFG_BASE_INFO>", "</MMCFG_BASE_INFO>")
238    write_direct_info_parser(config, "<IOMEM_INFO>", "</IOMEM_INFO>")
239
240
241def generate_file(config, default_platform):
242    """
243    write board_name_acpi_info.h
244    :param config: it is a file pointer to write acpi information
245    :param default_platform: it is the default_acpi_info.h in acrn-hypervisor
246    """
247    print("{}".format(board_cfg_lib.HEADER_LICENSE), file=config)
248
249    print("{}".format(PLATFORM_HEADER), file=config)
250
251    board_cfg_lib.handle_bios_info(config)
252    # parse for the platform info
253    platform_info_parser(config, default_platform)
254
255    print("{}".format(PLATFORM_END_HEADER), file=config)
256