1# Copyright (C) 2019-2022 Intel Corporation.
2#
3# SPDX-License-Identifier: BSD-3-Clause
4#
5
6import sys
7import enum
8import board_cfg_lib
9import acrn_config_utilities
10from defusedxml.lxml import parse
11import os
12from acrn_config_utilities import get_node
13
14class RDT(enum.Enum):
15    L2 = 0
16    L3 = 1
17    MBA = 2
18
19INCLUDE_HEADER = """
20#include <asm/board.h>
21#include <asm/vtd.h>
22#include <asm/msr.h>
23#include <asm/rdt.h>
24#include <pci.h>
25#include <misc_cfg.h>
26"""
27
28MSR_IA32_L2_MASK_BASE = 0x00000D10
29MSR_IA32_L2_MASK_END = 0x00000D4F
30MSR_IA32_L3_MASK_BASE = 0x00000C90
31MSR_IA32_L3_MASK_END = 0x00000D0F
32
33
34def gen_dmar_structure(config):
35    """Generate dmar structure information"""
36
37    dmar_info_lines = board_cfg_lib.get_info(acrn_config_utilities.BOARD_INFO_FILE, "<DRHD_INFO>", "</DRHD_INFO>")
38    drhd_cnt = 0
39    drhd_dev_scope_cnt = []
40    dev_scope_type = []
41
42    if not dmar_info_lines:
43        print("\n#ifndef CONFIG_ACPI_PARSE_ENABLED", file=config)
44        print("#error \"DMAR info is not available, please set ACPI_PARSE_ENABLED to y. \\", file=config)
45        print("\tOr use acrn-config tool to generate platform DMAR info.\"", file=config)
46        print("#endif\n", file=config)
47
48        print("struct dmar_info plat_dmar_info;\n", file=config)
49        return
50
51    # parse to get DRHD count and dev scope count
52    for dmar_line in dmar_info_lines:
53        if "DRHD_COUNT" in dmar_line and not drhd_cnt:
54            drhd_cnt = int(dmar_line.split()[2].strip('U'))
55
56    for i_cnt in range(drhd_cnt):
57        for dmar_line in dmar_info_lines:
58            dev_scope_cnt_str = "DRHD{}_DEV_CNT".format(i_cnt)
59
60            if dev_scope_cnt_str in dmar_line:
61                tmp_dev_scope_cnt = int(dmar_line.split()[2].strip('U'), 16)
62                drhd_dev_scope_cnt.append(tmp_dev_scope_cnt)
63
64    # gen dmar structure information
65    for i_drhd_cnt in range(drhd_cnt):
66        dev_cnt = drhd_dev_scope_cnt[i_drhd_cnt]
67        print("static struct dmar_dev_scope drhd{}_dev_scope[DRHD{}_DEV_CNT] = {{".format(
68            i_drhd_cnt, i_drhd_cnt), file=config)
69        for i_dev_cnt in range(dev_cnt):
70            print("\t{", file=config)
71            print("\t\t.type   = DRHD{}_DEVSCOPE{}_TYPE,".format(i_drhd_cnt, i_dev_cnt), file=config)
72            print("\t\t.id     = DRHD{}_DEVSCOPE{}_ID,".format(i_drhd_cnt, i_dev_cnt), file=config)
73            print("\t\t.bus    = DRHD{}_DEVSCOPE{}_BUS,".format(i_drhd_cnt, i_dev_cnt), file=config)
74            print("\t\t.devfun = DRHD{}_DEVSCOPE{}_PATH,".format(i_drhd_cnt, i_dev_cnt), file=config)
75            print("\t},", file=config)
76
77        print("};", file=config)
78        print("", file=config)
79
80    print("static struct dmar_drhd drhd_info_array[DRHD_COUNT] = {", file=config)
81    for i_drhd_cnt in range(drhd_cnt):
82        print("\t{", file=config)
83        print("\t\t.dev_cnt       = DRHD{}_DEV_CNT,".format(i_drhd_cnt), file=config)
84        print("\t\t.segment       = DRHD{}_SEGMENT,".format(i_drhd_cnt), file=config)
85        print("\t\t.flags         = DRHD{}_FLAGS,".format(i_drhd_cnt), file=config)
86        print("\t\t.reg_base_addr = DRHD{}_REG_BASE,".format(i_drhd_cnt), file=config)
87        print("\t\t.ignore        = DRHD{}_IGNORE,".format(i_drhd_cnt), file=config)
88        print("\t\t.devices       = drhd{}_dev_scope".format(i_drhd_cnt), file=config)
89        print("\t},", file=config)
90
91    print("};", file=config)
92    print("", file=config)
93    print("struct dmar_info plat_dmar_info = {", file=config)
94    print("\t.drhd_count = DRHD_COUNT,", file=config)
95    print("\t.drhd_units = drhd_info_array,", file=config)
96    print("};", file=config)
97
98
99def populate_clos_mask_msr(rdt_res, cat_mask_list, config):
100    """
101    Populate the clos bitmask and msr index for a given RDT resource
102    :param rdt_res: it is a string representing the RDT resource
103    :param cat_mask_list: cache mask list corresponding to each CLOS
104    :param config: it is a file pointer of board information for writing to
105    """
106    idx = 0
107    for cat_mask in cat_mask_list:
108        print("\t{", file=config)
109        print("\t\t.clos_mask = {},".format(cat_mask), file=config)
110        print("\t},", file=config)
111        idx += 1
112
113def populate_mba_delay_mask(rdt_res, mba_delay_list, config):
114    """
115    Populate the mba delay mask and msr index for memory resource
116    :param rdt_res: it is a string representing the RDT resource
117    :param mba_delay_list: mba delay value list corresponding to each CLOS
118    :param config: it is a file pointer of board information for writing to
119    """
120    idx = 0
121    for mba_delay_mask in mba_delay_list:
122        print("\t{", file=config)
123        print("\t\t.mba_delay = ,".format(mba_delay_mask), file=config)
124        print("\t},", file=config)
125        idx += 1
126
127def get_rdt_enabled():
128    scenario_etree = parse(acrn_config_utilities.SCENARIO_INFO_FILE)
129    enable = scenario_etree.xpath(f"//RDT_ENABLED/text()")
130    if enable[0] == "y":
131        return "true"
132    else:
133        return "false"
134
135def get_cdp_enabled():
136    scenario_etree = parse(acrn_config_utilities.SCENARIO_INFO_FILE)
137    enable = scenario_etree.xpath(f"//CDP_ENABLED/text()")
138    if enable[0] == "y":
139        return "true"
140    else:
141        return "false"
142
143def get_common_clos_max(clos_number, capability_id):
144
145    common_clos_max = 0
146    if get_rdt_enabled() and not get_cdp_enabled():
147        common_clos_max = clos_number
148    if get_cdp_enabled() and capability_id != 'MBA':
149        common_clos_max = clos_number / 2
150
151    return common_clos_max
152
153def gen_rdt_str(cache, config):
154    err_dic = {}
155    cat_mask_list = {}
156
157    board_etree = parse(acrn_config_utilities.BOARD_INFO_FILE)
158    mask_length = get_node(f"./capability[@id='CAT']/capacity_mask_length/text()", cache)
159    clos_number = get_node(f"./capability[@id='CAT']/clos_number/text()", cache)
160
161    bitmask = (1 << int(mask_length)) - 1
162    cache_level = get_node(f"./@level", cache)
163    cache_id = get_node(f"./@id", cache)
164    processor_list = board_etree.xpath(f"//cache[@level = '{cache_level}' and @id = '{cache_id}']/processors/processor/text()")
165    capability_list = board_etree.xpath(f"//cache[@level = '{cache_level}' and @id = '{cache_id}']/capability/@id")
166
167    for capability_id in capability_list:
168
169        common_clos_max = get_common_clos_max(int(clos_number), capability_id)
170        if capability_id == "CAT":
171            if common_clos_max > MSR_IA32_L2_MASK_END - MSR_IA32_L2_MASK_BASE or\
172                common_clos_max > MSR_IA32_L3_MASK_END - MSR_IA32_L3_MASK_BASE:
173                err_dic["board config: Failed to generate board.c"] = "CLOS Mask Number is more then the reserved address region length of L2/L3 cache"
174                return err_dic
175
176            cdp_enable = get_cdp_enabled()
177            cat_mask_list = get_mask_list(cache_level, cache_id)
178            if len(cat_mask_list) > int(clos_number):
179                    err_dic['board config: Failed to generate board.c'] = "CLOS Mask Number too bigger then the supported of L2/L3 cache"
180                    return err_dic;
181
182            if cache_level == "2":
183                rdt_res = "l2"
184            elif cache_level == "3":
185                rdt_res = "l3"
186
187            clos_config_array = "platform_l{0}_clos_array_{1}".format(cache_level, int(cache_id, 16))
188
189            print("\t{", file=config)
190            print("\t\t.res.cache = {", file=config)
191            print("\t\t\t.bitmask = {0},".format(hex(bitmask)), file=config)
192            print("\t\t\t.cbm_len = {0},".format(mask_length), file=config)
193            print("\t\t\t.is_cdp_enabled = {0},".format(cdp_enable), file=config)
194            print("\t\t},", file=config)
195        elif capability_id == "MBA":
196            max_throttling_value = get_node(f"./capability/max_throttling_value/text()", cache)
197            rdt_res = "mba"
198            clos_config_array = "platform_mba_clos_array"
199            print("\t{", file=config)
200            print("\t\t.res.membw = {", file=config)
201            print("\t\t\t.mba_max = {0},".format(clos_number), file=config)
202            print("\t\t\t.delay_linear = {0}".format(max_throttling_value), file=config)
203            print("\t\t},", file=config)
204
205    print("\t\t.num_closids = {0},".format(clos_number), file=config)
206    print("\t\t.num_clos_config = {0},".format(len(cat_mask_list)), file=config)
207    print("\t\t.clos_config_array = {0},".format(clos_config_array), file=config)
208
209    cpu_mask = 0
210    for processor in processor_list:
211        core_id = get_node(f"//thread[apic_id = '{processor}']/cpu_id/text()", board_etree)
212        if core_id is None:
213            continue
214        else:
215            cpu_mask = cpu_mask | (1 << int(core_id))
216    print("\t\t.cpu_mask = {0},".format(hex(cpu_mask)), file=config)
217    print("\t},", file=config)
218
219    return err_dic;
220
221def get_mask_list(cache_level, cache_id):
222    allocation_dir = os.path.split(acrn_config_utilities.SCENARIO_INFO_FILE)[0] + "/configs/allocation.xml"
223    allocation_etree = parse(allocation_dir)
224    if cache_level == "3":
225        clos_list = allocation_etree.xpath(f"//clos_mask[@id = 'l3']/clos/text()")
226    else:
227        clos_list = allocation_etree.xpath(f"//clos_mask[@id = '{cache_id}']/clos/text()")
228    return clos_list
229def gen_clos_array(cache_list, config):
230    err_dic = {}
231    res_present = [0, 0, 0]
232    if len(cache_list) == 0:
233        print("union clos_config platform_{0}_clos_array[MAX_CACHE_CLOS_NUM_ENTRIES];".format("l2"), file=config)
234        print("union clos_config platform_{0}_clos_array[MAX_CACHE_CLOS_NUM_ENTRIES];".format("l3"), file=config)
235        print("union clos_config platform_{0}_clos_array[MAX_MBA_CLOS_NUM_ENTRIES];".format("mba"), file=config)
236        print("struct rdt_info res_infos[RDT_INFO_NUMBER];", file=config)
237    else:
238        for idx, cache in enumerate(cache_list):
239            cache_level = get_node(f"./@level", cache)
240            cache_id = get_node(f"./@id", cache)
241            clos_number = get_node(f"./capability/clos_number/text()", cache)
242            if cache_level == "2":
243
244                cat_mask_list = get_mask_list(cache_level, cache_id)
245                array_size = len(cat_mask_list)
246
247                print("union clos_config platform_l2_clos_array_{0}[{1}] = {{".format(int(cache_id, 16), clos_number), file=config)
248
249                populate_clos_mask_msr("L2", cat_mask_list, config)
250
251                print("};\n", file=config)
252                res_present[RDT.L2.value] += 1
253            elif cache_level == "3":
254                cat_mask_list = get_mask_list(cache_level, cache_id)
255
256                print("union clos_config platform_l3_clos_array_{0}[{1}] = {{".format(int(cache_id, 16), clos_number), file=config)
257
258                populate_clos_mask_msr("L3", cat_mask_list, config)
259
260                print("};\n", file=config)
261                res_present[RDT.L3.value] += 1
262            elif cache_level == "MBA":
263                print("union clos_config platform_mba_clos_array[MAX_MBA_CLOS_NUM_ENTRIES] = {", file=config)
264                err_dic = populate_mba_delay_mask("mba", mba_delay_list, config)
265                print("};\n", file=config)
266                res_present[RDT.MBA.value] = 1
267            else:
268                err_dic['board config: generate board.c failed'] = "The input of {} was corrupted!".format(acrn_config_utilities.BOARD_INFO_FILE)
269                return err_dic
270
271        if res_present[RDT.L2.value] == 0:
272            print("union clos_config platform_l2_clos_array[MAX_CACHE_CLOS_NUM_ENTRIES];", file=config)
273        if res_present[RDT.L3.value] == 0:
274            print("union clos_config platform_l3_clos_array[MAX_CACHE_CLOS_NUM_ENTRIES];", file=config)
275        if res_present[RDT.MBA.value] == 0:
276            print("union clos_config platform_mba_clos_array[MAX_MBA_CLOS_NUM_ENTRIES];", file=config)
277    return 0
278
279def gen_rdt_res(config):
280    """
281    Get RDT resource (L2, L3, MBA) information
282    :param config: it is a file pointer of board information for writing to
283    """
284    print("\n#ifdef CONFIG_RDT_ENABLED", file=config)
285    err_dic = {}
286    res_present = [0, 0, 0]
287
288    scenario_etree = parse(acrn_config_utilities.SCENARIO_INFO_FILE)
289    allocation_etree = parse(acrn_config_utilities.SCENARIO_INFO_FILE)
290    board_etree = parse(acrn_config_utilities.BOARD_INFO_FILE)
291
292    cache_list = board_etree.xpath(f"//cache[capability/@id = 'CAT' or capability/@id = 'MBA']")
293    gen_clos_array(cache_list, config)
294
295    cache_list = board_etree.xpath(f"//cache[capability/@id = 'CAT' and @level = '2']")
296    if len(cache_list) > 0:
297        res_present[RDT.L2.value] = len(cache_list)
298        rdt_ins_name = "rdt_ins_l2[" + str(len(cache_list)) + "] = {"
299        print("struct rdt_ins {}".format(rdt_ins_name), file=config)
300        for idx, cache in enumerate(cache_list):
301            err_dic = gen_rdt_str(cache, config)
302            if err_dic:
303                return err_dic;
304        print("};\n", file=config)
305
306    cache_list = board_etree.xpath(f"//cache[capability/@id = 'CAT' and @level = '3']")
307    if len(cache_list) > 0:
308        res_present[RDT.L3.value] = len(cache_list)
309        rdt_ins_name = "rdt_ins_l3[" + str(len(cache_list)) + "] = {"
310        print("struct rdt_ins {}".format(rdt_ins_name), file=config)
311        for idx, cache in enumerate(cache_list):
312            err_dic = gen_rdt_str(cache, config)
313            if err_dic:
314                return err_dic;
315        print("};\n", file=config)
316
317    cache_list = board_etree.xpath(f"//cache[capability/@id = 'MBA']")
318    if len(cache_list) > 0:
319        res_present[RDT.L2.value] = 1
320        rdt_ins_name = "rdt_ins_mba[" + str(len(cache_list)) + "] = {"
321        print("struct rdt_ins {}".format(rdt_ins_name), file=config)
322        for idx, cache in enumerate(cache_list):
323            err_dic = gen_rdt_str(cache, config)
324            if err_dic:
325                return err_dic;
326        print("};\n", file=config)
327
328    print("struct rdt_type res_cap_info[RDT_NUM_RESOURCES] = {", file=config)
329    if res_present[RDT.L2.value] > 0:
330        print("\t{", file=config)
331        print("\t\t.res_id = RDT_RESID_L2,", file=config)
332        print("\t\t.msr_qos_cfg = MSR_IA32_L2_QOS_CFG,", file=config)
333        print("\t\t.msr_base = MSR_IA32_L2_MASK_BASE,", file=config)
334        print("\t\t.num_ins = {},".format(res_present[RDT.L2.value]), file=config)
335        print("\t\t.ins_array = rdt_ins_l2,", file=config)
336        print("\t},", file=config)
337    if res_present[RDT.L3.value] > 0:
338        print("\t{", file=config)
339        print("\t\t.res_id = RDT_RESID_L3,", file=config)
340        print("\t\t.msr_qos_cfg = MSR_IA32_L3_QOS_CFG,", file=config)
341        print("\t\t.msr_base = MSR_IA32_L3_MASK_BASE,", file=config)
342        print("\t\t.num_ins = {},".format(res_present[RDT.L3.value]), file=config)
343        print("\t\t.ins_array = rdt_ins_l3,", file=config)
344        print("\t},", file=config)
345    if res_present[RDT.MBA.value] > 0:
346        print("\t{", file=config)
347        print("\t\t.res_id = RDT_RESID_MBA,", file=config)
348        print("\t\t.msr_qos_cfg = MSR_IA32_MBA_QOS_CFG,", file=config)
349        print("\t\t.msr_base = MSR_IA32_MBA_MASK_BASE,", file=config)
350        print("\t\t.num_ins = {},".format(res_present[RDT.MBA.value]), file=config)
351        print("\t\t.ins_array = rdt_ins_mba,", file=config)
352        print("\t},", file=config)
353    print("};\n", file=config)
354
355    print("#endif\n", file=config)
356
357    return err_dic
358
359def gen_single_data(data_lines, domain_str, config):
360    line_i = 0
361    data_statues = True
362    data_len = len(data_lines)
363
364    if data_len == 0:
365        return
366
367    for data_l in data_lines:
368        if line_i == 0:
369            if "not available" in data_l:
370                print(data_l.strip(), file=config)
371                print("static const struct acrn_{}state_data board_cpu_{}x[0];".format(domain_str, domain_str), file=config)
372                print("", file=config)
373                data_statues = False
374                break
375            else:
376                print("static const struct acrn_{}state_data board_cpu_{}x[{}] = {{".format(domain_str, domain_str, data_len), file=config)
377        print("\t{0}".format(data_l.strip()), file=config)
378        line_i += 1
379    if data_statues:
380        print("};\n", file=config)
381
382
383def gen_px_cx(config):
384    """
385    Get Px/Cx and store them to board.c
386    :param config: it is a file pointer of board information for writing to
387    """
388    cpu_brand_lines = board_cfg_lib.get_info(
389        acrn_config_utilities.BOARD_INFO_FILE, "<CPU_BRAND>", "</CPU_BRAND>")
390    cx_lines = board_cfg_lib.get_info(acrn_config_utilities.BOARD_INFO_FILE, "<CX_INFO>", "</CX_INFO>")
391    px_lines = board_cfg_lib.get_info(acrn_config_utilities.BOARD_INFO_FILE, "<PX_INFO>", "</PX_INFO>")
392
393    gen_single_data(cx_lines, 'c', config)
394    gen_single_data(px_lines, 'p', config)
395
396    if not cpu_brand_lines:
397        print("\nconst struct cpu_state_table board_cpu_state_tbl;\n", file=config)
398        return
399
400    for brand_line in cpu_brand_lines:
401        cpu_brand = brand_line
402
403    print("const struct cpu_state_table board_cpu_state_tbl = {", file=config)
404    print("\t{0},".format(cpu_brand.strip()), file=config)
405    print("\t{(uint8_t)ARRAY_SIZE(board_cpu_px), board_cpu_px,", file=config)
406    print("\t(uint8_t)ARRAY_SIZE(board_cpu_cx), board_cpu_cx}", file=config)
407    print("};", file=config)
408
409
410def gen_pci_hide(config):
411    """Generate hide pci information for this platform"""
412
413    scenario_etree = parse(acrn_config_utilities.SCENARIO_INFO_FILE)
414    hidden_pdev_list = [x.replace('.', ':') for x in scenario_etree.xpath(f"//HIDDEN_PDEV/text()")]
415
416    if board_cfg_lib.BOARD_NAME in list(board_cfg_lib.KNOWN_HIDDEN_PDEVS_BOARD_DB.keys()) and board_cfg_lib.KNOWN_HIDDEN_PDEVS_BOARD_DB[board_cfg_lib.BOARD_NAME] != 0:
417        hidden_pdev_list += board_cfg_lib.KNOWN_HIDDEN_PDEVS_BOARD_DB[board_cfg_lib.BOARD_NAME]
418
419    if len(hidden_pdev_list) > 0:
420        hidden_pdev_num = len(hidden_pdev_list)
421        print("const union pci_bdf plat_hidden_pdevs[MAX_HIDDEN_PDEVS_NUM] = {", file=config)
422        for hidden_pdev_i in range(hidden_pdev_num):
423            bus = hex(int(hidden_pdev_list[hidden_pdev_i].split(':')[0], 16))
424            dev = hex(int(hidden_pdev_list[hidden_pdev_i].split(':')[1], 16))
425            fun = hex(int(hidden_pdev_list[hidden_pdev_i].split(':')[2], 16))
426            print("\t{", file=config)
427            print("\t\t.bits.b = {}U,".format(bus), file=config)
428            print("\t\t.bits.d = {}U,".format(dev), file=config)
429            print("\t\t.bits.f = {}U,".format(fun), file=config)
430            print("\t},", file=config)
431        print("};", file=config)
432    else:
433        print("const union pci_bdf plat_hidden_pdevs[MAX_HIDDEN_PDEVS_NUM];", file=config)
434
435
436def gen_known_caps_pci_devs(config):
437    """Generate information for known capabilities of pci devices"""
438    known_caps_pci_devs = board_cfg_lib.get_known_caps_pci_devs()
439    for dev,bdf_list in known_caps_pci_devs.items():
440        if dev == "VMSIX":
441            print("", file=config)
442            bdf_list_len = len(bdf_list)
443            if bdf_list_len == 0:
444                print("const struct vmsix_on_msi_info vmsix_on_msi_devs[MAX_VMSIX_ON_MSI_PDEVS_NUM];", file=config)
445                break
446            for i in range(bdf_list_len):
447                b = bdf_list[i].split(":")[0]
448                d = bdf_list[i].split(":")[1].split(".")[0]
449                f = bdf_list[i].split(".")[1]
450                print("#define VMSIX_ON_MSI_DEV{}\t.bdf.bits = {{.b = 0x{}U, .d = 0x{}U, .f =0x{}U}},".format(i, b, d, f), file=config)
451
452            for i in range(bdf_list_len):
453                if i == 0:
454                    print("const struct vmsix_on_msi_info vmsix_on_msi_devs[MAX_VMSIX_ON_MSI_PDEVS_NUM] = {", file=config)
455                print("\t{{VMSIX_ON_MSI_DEV{}}},".format(i), file=config)
456                if i == (bdf_list_len - 1):
457                    print("};", file=config)
458
459def gen_cpufreq_limits(config):
460    allocation_dir = os.path.split(acrn_config_utilities.SCENARIO_INFO_FILE)[0] + "/configs/allocation.xml"
461    allocation_etree = parse(allocation_dir)
462    cpu_list = board_cfg_lib.get_processor_info()
463    max_cpu_num = len(cpu_list)
464
465    print("\nstruct acrn_cpufreq_limits cpufreq_limits[MAX_PCPU_NUM] = {", file=config)
466    for cpu_id in range(max_cpu_num):
467        limit_node = get_node(f"//cpufreq/CPU[@id='{cpu_id}']/limits", allocation_etree)
468        if limit_node != None:
469            limit_guaranteed_lvl = get_node("./limit_guaranteed_lvl/text()", limit_node)
470            limit_highest_lvl = get_node("./limit_highest_lvl/text()", limit_node)
471            limit_lowest_lvl = get_node("./limit_lowest_lvl/text()", limit_node)
472            limit_nominal_pstate = get_node("./limit_nominal_pstate/text()", limit_node)
473            limit_highest_pstate = get_node("./limit_highest_pstate/text()", limit_node)
474            limit_lowest_pstate = get_node("./limit_lowest_pstate/text()", limit_node)
475
476            print("\t{", file=config)
477            print(f"\t\t.guaranteed_hwp_lvl = {limit_guaranteed_lvl},", file=config)
478            print(f"\t\t.highest_hwp_lvl = {limit_highest_lvl},", file=config)
479            print(f"\t\t.lowest_hwp_lvl = {limit_lowest_lvl},", file=config)
480            print(f"\t\t.nominal_pstate = {limit_nominal_pstate},", file=config)
481            print(f"\t\t.performance_pstate = {limit_highest_pstate},", file=config)
482            print("\t},", file=config)
483    print("};", file=config)
484
485def generate_file(config):
486    """
487    Start to generate board.c
488    :param config: it is a file pointer of board information for writing to
489    """
490    err_dic = {}
491    print("{0}".format(board_cfg_lib.HEADER_LICENSE), file=config)
492
493    # insert bios info into board.c
494    board_cfg_lib.handle_bios_info(config)
495    print(INCLUDE_HEADER, file=config)
496
497    # start to parse DMAR info
498    gen_dmar_structure(config)
499
500    # start to parse RDT resource info
501    err_dic = gen_rdt_res(config)
502    if err_dic:
503        return err_dic
504
505    # start to parse PX/CX info
506    gen_px_cx(config)
507
508    # gen hide pci info for platform
509    gen_pci_hide(config)
510
511    # gen known caps of pci dev info for platform
512    gen_known_caps_pci_devs(config)
513
514    gen_cpufreq_limits(config)
515
516    return err_dic
517