1# Copyright (C) 2020-2022 Intel Corporation.
2#
3# SPDX-License-Identifier: BSD-3-Clause
4#
5
6import os
7import sys
8import acrn_config_utilities
9import getopt
10import board_cfg_lib
11
12
13ERR_LIST = {}
14N_Y = ['n', 'y']
15SCHEDULER_TYPE = ['SCHED_NOOP', 'SCHED_IORR', 'SCHED_BVT', 'SCHED_PRIO']
16
17RANGE_DB = {
18    'LOG_LEVEL':{'min':0,'max':5},
19    'EMULATED_MMIO_REGIONS':{'min':0,'max':128},
20    'PT_IRQ_ENTRIES':{'min':0,'max':256},
21    'IOAPIC_NUM':{'min':1,'max':10},
22    'IOAPIC_LINES':{'min':1,'max':120},
23    'PCI_DEV_NUM':{'min':1,'max':1024},
24    'MSIX_TABLE_NUM':{'min':1,'max':2048},
25}
26
27
28def empty_check(val, prime_item, item, sub_item=''):
29    if not val or val == None:
30        if sub_item:
31            key = 'hv,{},{},{}'.format(prime_item, item, sub_item)
32            ERR_LIST[key] = "{} should not be empty".format(sub_item)
33        else:
34            key = 'hv,{},{}'.format(prime_item, item)
35            ERR_LIST[key] = "{} should not be empty".format(item)
36        return True
37
38    return False
39
40
41def is_numeric_check(str_value, prime_item, item):
42
43    # to skip for strip 0x/0X
44    if str_value == '0':
45        return True
46    str_hex_0x = str_value.lstrip('0x')
47    str_hex_0X = str_value.lstrip('0X')
48
49    if not str_hex_0x.isnumeric() and not str_hex_0X.isnumeric():
50        if not isinstance(int(str_hex_0x, 16), int) and not isinstance(int(str_hex_0X, 16), int):
51            key = 'hv,{},{}'.format(prime_item, item)
52            ERR_LIST[key] = "{} should be a numeric".format(item)
53            return False
54    return True
55
56
57def range_check(str_value, prime_item, item, range_val):
58
59    value = acrn_config_utilities.num2int(str_value)
60    if value < range_val['min'] or value > range_val['max']:
61        key = 'hv,{},{}'.format(prime_item, item)
62        ERR_LIST[key] = "{} should be in range[{},{}]".format(item, range_val['min'], range_val['max'])
63
64
65def release_check(sel_str, dbg_opt, rel_str):
66    if empty_check(sel_str, dbg_opt, rel_str):
67        return
68    if sel_str not in N_Y:
69        key = 'hv,{},{}'.format(dbg_opt, rel_str)
70        ERR_LIST[key] = "{} should be in {}".format(rel_str, N_Y)
71
72
73def hv_range_check(str_val, branch_tag, item, range_db, empty_check_enable=True):
74
75    if empty_check_enable:
76        if empty_check(str_val, branch_tag, item):
77            return
78    if not is_numeric_check(str_val, branch_tag, item):
79        return
80    range_check(str_val, branch_tag, item, range_db)
81
82
83def hv_size_check(str_val, branch_tag, item):
84
85    if empty_check(str_val, branch_tag, item):
86        return
87    if not is_numeric_check(str_val, branch_tag, item):
88        return
89
90def hv_ram_start_check(hv_ram_start, prime_item, item):
91
92    err_dic = {}
93    if '0x' not in hv_ram_start and '0X' not in hv_ram_start:
94        key = "hv,{},{}".format(prime_item, item)
95        ERR_LIST[key] = "Address should be Hex format"
96
97    to_mb = (int(hv_ram_start, 16) / (1024 * 1024))
98    is_aligned = to_mb % 2
99    if to_mb < 2 or is_aligned != 0:
100        key = "hv,{},{}".format(prime_item, item)
101        ERR_LIST[key] = "Address should be larger than or equal to 2MB and 2MB-aligned."
102
103def ir_entries_check(str_num, cap, cap_ir_entries):
104    hv_size_check(str_num, cap, cap_ir_entries)
105    val = acrn_config_utilities.num2int(str_num)
106    if val % 2 != 0:
107        key = 'hv,{},{}'.format(cap, cap_ir_entries)
108        ERR_LIST[key] = "{} should be a value of 2^n".format(cap_ir_entries)
109
110
111def ny_support_check(sel_str, feat, feat_item, feat_sub_leaf=''):
112    if empty_check(sel_str, feat, feat_item, feat_sub_leaf):
113        return
114    if sel_str not in N_Y:
115        key = 'hv,{},{}'.format(feat, feat_item)
116        ERR_LIST[key] = "{} should be in {}".format(feat_item, N_Y)
117
118
119def scheduler_check(sel_str, feat, feat_scheduler):
120    if empty_check(sel_str, feat, feat_scheduler):
121        return
122    if sel_str not in SCHEDULER_TYPE:
123        key = 'hv,{},{}'.format(feat, feat_scheduler)
124        ERR_LIST[key] = "{} should be in {}".format(feat_scheduler, SCHEDULER_TYPE)
125
126
127def get_select_range(branch_tag, range_key):
128
129    range_list = []
130    if range_key not in RANGE_DB.keys():
131        key = "hv,{},{}".format(branch_tag, range_key)
132        ERR_LIST[key] = "It is invalid for {}.".format(range_key)
133        return range_list
134
135    for range_i in range(RANGE_DB[range_key]['min'], RANGE_DB[range_key]['max'] + 1):
136        range_list.append(str(range_i))
137
138    return range_list
139
140
141def is_contiguous_bit_set(value):
142
143    bit_1_cnt = 0
144    tmp_val = value
145    is_contiguous = False
146
147    first_p = 0
148    last_p = 0
149
150    while tmp_val > 0:
151        tmp_val &= (tmp_val - 1)
152        bit_1_cnt += 1
153
154    for shift_i in range(32):
155        mask = (0x1 << shift_i)
156        if value & mask:
157            if first_p == 0 and last_p == 0:
158                first_p = shift_i + 1
159            elif first_p != 0:
160                last_p = shift_i + 1
161        else:
162            if first_p == 0 and last_p == 0:
163                continue
164            break
165
166
167    contiguous_cnt = last_p - first_p + 1
168    if bit_1_cnt == contiguous_cnt or bit_1_cnt in (0, 1):
169        is_contiguous = True
170
171    return is_contiguous
172
173
174def cat_max_mask_check(cat_mask_list, feature, cat_str, max_mask_str):
175
176    (res_info, rdt_res_clos_max, clos_max_mask_list) = board_cfg_lib.clos_info_parser(acrn_config_utilities.BOARD_INFO_FILE)
177    if not board_cfg_lib.is_rdt_enabled() or ("L2" not in res_info and "L3" not in res_info):
178        return
179
180    if board_cfg_lib.is_cdp_enabled():
181        clos_max_set_entry = 2 * board_cfg_lib.get_common_clos_max()
182    else:
183        clos_max_set_entry = board_cfg_lib.get_common_clos_max()
184
185    cat_max_mask_settings_len = len(cat_mask_list)
186    if clos_max_set_entry != cat_max_mask_settings_len:
187        key = 'hv,{},{},{}'.format(feature, cat_str, max_mask_str)
188        ERR_LIST[key] = "Number of Cache mask entries should be equal to MAX_CACHE_CLOS_NUM_ENTRIES={}".format(clos_max_set_entry)
189        return
190
191    clos_max_mask_str = clos_max_mask_list[0].strip('"').strip("'")
192    clos_max_mask = acrn_config_utilities.num2int(clos_max_mask_str)
193    for val_str in cat_mask_list:
194        if empty_check(val_str, feature, cat_str, max_mask_str):
195            return
196        value = acrn_config_utilities.num2int(val_str)
197        if value < 0 or value > clos_max_mask:
198            key = 'hv,{},{},{}'.format(feature, cat_str, max_mask_str)
199            ERR_LIST[key] = "{} should be in range[0,{}]".format(max_mask_str, clos_max_mask_str)
200            return
201
202        if not is_contiguous_bit_set(value):
203            key = 'hv,{},{},{}'.format(feature, cat_str, max_mask_str)
204            ERR_LIST[key] = "CLOS_MASK {} should be contiguous bit set.".format(max_mask_str, clos_max_mask_str)
205            return
206
207
208def mba_delay_check(mba_delay_list, feature, mba_str, max_mask_str):
209
210    (res_info, rdt_res_clos_max, clos_max_mask_list) = board_cfg_lib.clos_info_parser(acrn_config_utilities.BOARD_INFO_FILE)
211    if not board_cfg_lib.is_rdt_enabled() or "MBA" not in res_info:
212        return
213
214    clos_max = board_cfg_lib.get_common_clos_max()
215    mba_delay_settings_len = len(mba_delay_list)
216    if clos_max != mba_delay_settings_len:
217        key = 'hv,{},{},{}'.format(feature, mba_str, max_mask_str)
218        ERR_LIST[key] = "Number of MBA delay entries should be equal to MAX_MBA_CLOS_NUM_ENTRIES={}".format(clos_max)
219        return
220
221    mba_idx = res_info.index("MBA")
222    mba_delay_str = clos_max_mask_list[mba_idx].strip('"').strip("'")
223    mba_delay = acrn_config_utilities.num2int(mba_delay_str)
224    for val_str in mba_delay_list:
225        if empty_check(val_str, feature, mba_str, max_mask_str):
226            return
227        value = acrn_config_utilities.num2int(val_str)
228        if value > mba_delay:
229            key = 'hv,{},{},{}'.format(feature, mba_str, max_mask_str)
230            ERR_LIST[key] = "{} should be in range[0,{}]".format(max_mask_str, mba_delay_str)
231            return
232
233
234def max_msix_table_num_check(max_msix_table_num, cap_str, max_msi_num_str):
235    native_max_msix_line = board_cfg_lib.get_info(acrn_config_utilities.BOARD_INFO_FILE, "<MAX_MSIX_TABLE_NUM>", "</MAX_MSIX_TABLE_NUM>")
236    if not native_max_msix_line and not max_msix_table_num:
237        empty_check(max_msix_table_num, cap_str, max_msi_num_str)
238        return
239
240    if max_msix_table_num:
241        hv_range_check(max_msix_table_num, cap_str, max_msi_num_str, RANGE_DB['MSIX_TABLE_NUM'], False)
242    if native_max_msix_line:
243        native_max_msix_num = native_max_msix_line[0].strip()
244        range_check(native_max_msix_num, "In board xml", max_msi_num_str, RANGE_DB['MSIX_TABLE_NUM'])
245
246
247def hv_ssram_check(ssram_enabled, cpd_enabled, feature, tag, leaf):
248    key = 'hv,{},{},{}'.format(feature, tag, leaf)
249    if ssram_enabled == 'y' and cpd_enabled == 'y':
250        ERR_LIST[key] = "SSRAM_ENABLED should not be y when CDP_ENABLED is y."
251        return
252