1# Copyright (C) 2019-2022 Intel Corporation.
2#
3# SPDX-License-Identifier: BSD-3-Clause
4#
5
6import os
7import getopt
8import re
9
10import acrn_config_utilities
11import board_cfg_lib
12import scenario_cfg_lib
13import lxml
14from defusedxml.lxml import parse
15
16ERR_LIST = {}
17BOOT_TYPE = ['no', 'ovmf']
18RTOS_TYPE = ['no', 'Soft RT', 'Hard RT']
19DM_VUART0 = ['Disable', 'Enable']
20y_n = ['y', 'n']
21USER_VM_TYPES = ['CLEARLINUX', 'ANDROID', 'ALIOS', 'PREEMPT-RT LINUX', 'VXWORKS', 'WINDOWS', 'ZEPHYR', 'YOCTO', 'UBUNTU', 'GENERIC LINUX']
22LINUX_LIKE_OS = ['CLEARLINUX', 'PREEMPT-RT LINUX', 'YOCTO', 'UBUNTU', 'GENERIC LINUX']
23
24PT_SUB_PCI = {}
25PT_SUB_PCI['usb_xdci'] = ['USB controller']
26PT_SUB_PCI['gpu'] = ['VGA compatible controller']
27PT_SUB_PCI['ipu'] = ['Multimedia controller']
28PT_SUB_PCI['ipu_i2c'] = ['Signal processing controller']
29PT_SUB_PCI['cse'] = ['Communication controller']
30PT_SUB_PCI['audio'] = ['Audio device', 'Multimedia audio controller']
31PT_SUB_PCI['audio_codec'] = ['Signal processing controller']
32PT_SUB_PCI['sd_card'] = ['SD Host controller']
33PT_SUB_PCI['wifi'] = ['Ethernet controller', 'Network controller', '802.1a controller',
34                        '802.1b controller', 'Wireless controller']
35PT_SUB_PCI['bluetooth'] = ['Signal processing controller']
36PT_SUB_PCI['ethernet'] = ['Ethernet controller', 'Network controller']
37PT_SUB_PCI['sata'] = ['SATA controller']
38PT_SUB_PCI['nvme'] = ['Non-Volatile memory controller']
39
40# passthrough devices for board
41PASSTHRU_DEVS = ['usb_xdci', 'gpu', 'ipu', 'ipu_i2c', 'cse', 'audio', 'sata',
42                    'nvme', 'audio_codec', 'sd_card', 'ethernet', 'wifi', 'bluetooth']
43
44PT_SLOT = {
45        "hostbridge":0,
46        "lpc":1,
47        "pci-gvt":2,
48        "virtio-blk":3,
49        "igd-lpc":31,
50    }
51
52
53MOUNT_FLAG_DIC = {}
54
55
56def usage(file_name):
57    """ This is usage for how to use this tool """
58    print("usage= {} [h]".format(file_name), end="")
59    print("--board <board_info_file> --scenario <scenario_info_file> --launch <launch_info_file> --user_vmid <user_vmid id> --out [output folder]")
60    print('board_info_file :  file name of the board info')
61    print('scenario_info_file :  file name of the scenario info')
62    print('launch_info_file :  file name of the launch info')
63    print('user_vmid :  this is the relative id for post launch vm in scenario info XML:[1..max post launch vm]')
64    print('output folder :  path to acrn-hypervisor_folder')
65
66
67def get_param(args):
68    """
69    Get the script parameters from command line
70    :param args: this the command line of string for the script without script name
71    """
72    vm_th = '0'
73    err_dic = {}
74    board_info_file = False
75    scenario_info_file = False
76    launch_info_file = False
77    output_folder = False
78    param_list = ['--board', '--scenario', '--launch', '--user_vmid']
79
80    for arg_str in param_list:
81
82        if arg_str not in args:
83            usage(args[0])
84            err_dic['acrn_config_utilities error: wrong parameter'] = "wrong usage"
85            return (err_dic, board_info_file, scenario_info_file, launch_info_file, int(vm_th), output_folder)
86
87    args_list = args[1:]
88    (optlist, args_list) = getopt.getopt(args_list, '', ['board=', 'scenario=', 'launch=', 'user_vmid=', 'out='])
89    for arg_k, arg_v in optlist:
90        if arg_k == '--board':
91            board_info_file = arg_v
92        if arg_k == '--scenario':
93            scenario_info_file = arg_v
94        if arg_k == '--launch':
95            launch_info_file = arg_v
96        if arg_k == '--out':
97            output_folder = arg_v
98        if '--user_vmid' in args:
99            if arg_k == '--user_vmid':
100                vm_th = arg_v
101                if not vm_th.isnumeric():
102                    err_dic['common error: wrong parameter'] = "--user_vmid should be a number"
103                    return (err_dic, board_info_file, scenario_info_file, launch_info_file, int(vm_th), output_folder)
104
105    if not board_info_file or not scenario_info_file or not launch_info_file:
106        usage(args[0])
107        err_dic['common error: wrong parameter'] = "wrong usage"
108        return (err_dic, board_info_file, scenario_info_file, launch_info_file, int(vm_th), output_folder)
109
110    if not os.path.exists(board_info_file):
111        err_dic['common error: wrong parameter'] = "{} does not exist!".format(board_info_file)
112        return (err_dic, board_info_file, scenario_info_file, launch_info_file, int(vm_th), output_folder)
113
114    if not os.path.exists(scenario_info_file):
115        err_dic['common error: wrong parameter'] = "{} does not exist!".format(scenario_info_file)
116        return (err_dic, board_info_file, scenario_info_file, launch_info_file, int(vm_th), output_folder)
117
118    if not os.path.exists(launch_info_file):
119        err_dic['common error: wrong parameter'] = "{} does not exist!".format(launch_info_file)
120        return (err_dic, board_info_file, scenario_info_file, launch_info_file, int(vm_th), output_folder)
121
122    return (err_dic, board_info_file, scenario_info_file, launch_info_file, int(vm_th), output_folder)
123
124
125def launch_vm_cnt(config_file):
126    """
127    Get post vm number
128    :param config_file: it is a file what contains information for script to read from
129    :return: total post vm number in launch file
130    """
131    post_vm_count = 0
132
133    # get post vm number
134    root = acrn_config_utilities.get_config_root(config_file)
135    for item in root:
136        if item.tag == "user_vm":
137            post_vm_count += 1
138
139    return post_vm_count
140
141
142def get_post_num_list():
143    """
144    Get post vm number list
145    :return: total post dic: {launch_id:scenario_id} in launch file
146    """
147    post_vm_list = []
148
149    # get post vm number
150    root = acrn_config_utilities.get_config_root(acrn_config_utilities.LAUNCH_INFO_FILE)
151    for item in root:
152        if item.tag == "user_vm":
153            post_vm_list.append(int(item.attrib['id']))
154
155    return post_vm_list
156
157
158def post_vm_cnt(config_file):
159    """
160    Calculate the pre launched vm number
161    :param config_file: it is a file what contains information for script to read from
162    :return: number of post launched vm
163    """
164    post_launch_cnt = 0
165
166    for load_order in acrn_config_utilities.LOAD_ORDER.values():
167        if load_order == "POST_LAUNCHED_VM":
168            post_launch_cnt += 1
169
170    return post_launch_cnt
171
172
173def get_post_vm_cnt():
174    """
175    Get board name from launch.xml at fist line
176    :param scenario_file: it is a file what contains scenario information for script to read from
177    """
178    launch_vm_count = launch_vm_cnt(acrn_config_utilities.LAUNCH_INFO_FILE)
179    post_vm_count = post_vm_cnt(acrn_config_utilities.SCENARIO_INFO_FILE)
180    return (launch_vm_count, post_vm_count)
181
182
183def get_sos_vmid():
184
185    sos_id = ''
186    for vm_i,load_order in acrn_config_utilities.LOAD_ORDER.items():
187        if load_order == "SERVICE_VM":
188            sos_id = vm_i
189            break
190
191    return sos_id
192
193
194def get_bdf_from_tag(config_file, branch_tag, tag_str):
195    bdf_list = {}
196    bdf_list = acrn_config_utilities.get_leaf_tag_map(config_file, branch_tag, tag_str)
197
198    # split b:d:f from pci description
199    for idx, bdf_v in bdf_list.items():
200        if bdf_v:
201            bdf_list[idx] = bdf_v.split()[0]
202
203    return bdf_list
204
205
206def get_vpid_from_bdf(bdf_vpid_map, bdf_list):
207    vpid_list = {}
208    post_vm_list = get_post_num_list()
209    for p_id in post_vm_list:
210        for bdf_k, vpid_v in bdf_vpid_map.items():
211            if bdf_k == bdf_list[p_id]:
212                #    print("k:{}, v{}".format(bdf_k, bdf_list[p_id]))
213                # convert "808x:0xxx" to "808x 0xxx"
214                tmp_vpid = " ".join(vpid_v.split(':'))
215                vpid_list[p_id] = tmp_vpid
216            elif not bdf_list[p_id]:
217                vpid_list[p_id] = ''
218
219    return vpid_list
220
221
222def get_user_vm_type():
223    """
224    Get User VM name from launch.xml at fist line
225    """
226    user_vm_types = acrn_config_utilities.get_leaf_tag_map(acrn_config_utilities.LAUNCH_INFO_FILE, "user_vm_type")
227
228    return user_vm_types
229
230
231def get_user_vm_names():
232    user_vm_names = acrn_config_utilities.get_leaf_tag_map(acrn_config_utilities.LAUNCH_INFO_FILE, "vm_name")
233    return user_vm_names
234
235
236def is_bdf_format(bdf_str):
237    bdf_len = 7
238    status = True
239    if not bdf_str:
240        return status
241
242    bdf_str_len = len(bdf_str)
243    if ':' in bdf_str and '.' in bdf_str and bdf_len == bdf_str_len:
244        status = True
245    else:
246        status = False
247
248    return status
249
250
251def is_vpid_format(vpid_str):
252    status = True
253    if not vpid_str:
254        return status
255
256    vpid_len = 9
257    vpid_str_len = len(vpid_str)
258
259    if ' ' in vpid_str and vpid_len == vpid_str_len:
260        status = True
261    else:
262        status = False
263
264    return status
265
266
267def pt_devs_check(bdf_list, vpid_list, item):
268    i_cnt = 1
269
270    # check bdf
271    for bdf_str in bdf_list.values():
272        if is_bdf_format(bdf_str):
273            continue
274        else:
275            key = "user_vm:id={},passthrough_devices,{}".format(i_cnt, item)
276            ERR_LIST[key] = "Unkonw the BDF format of {} device".format(item)
277        i_cnt += 1
278
279    # check vpid
280    i_cnt = 1
281    for vpid_str in vpid_list.values():
282        if is_vpid_format(vpid_str):
283            continue
284        else:
285            key = "user_vm:id={},passthrough_devices,{}".format(i_cnt, item)
286            ERR_LIST[key] = "Unkonw the Vendor:Product ID format of {} device".format(item)
287
288        i_cnt += 1
289
290
291def empty_err(i_cnt, item):
292    """
293    add empty error message into ERR_LIST
294    :param i_cnt: the launch vm index from config xml
295    :param item: the item of tag from config xml
296    :return: None
297    """
298    key = "user_vm:id={},{}".format(i_cnt, item)
299    ERR_LIST[key] = "The parameter should not be empty"
300
301
302def args_aval_check(arg_list, item, avl_list):
303    """
304    check arguments from config xml are available and validate
305    :param arg_list: the list of arguments from config xml
306    :param item: the item of tag from config xml
307    :param avl_list: available argument which are allowed to chose
308    :return: None
309    """
310    # args should be set into launch xml from webUI
311    i_cnt = 1
312    skip_check_list = ['']
313    if item in skip_check_list:
314        return
315
316    for arg_str in arg_list.values():
317        if arg_str == None or not arg_str.strip():
318            empty_err(i_cnt, item)
319            i_cnt += 1
320            continue
321
322        if arg_str not in avl_list:
323            key = "user_vm:id={},{}".format(i_cnt, item)
324            ERR_LIST[key] = "The {} is invalidate".format(item)
325        i_cnt += 1
326
327
328def mem_size_check(arg_list, item):
329    """
330     check memory size list which are set from webUI
331     :param arg_list: the list of arguments from config xml
332     :param item: the item of tag from config xml
333     :return: None
334     """
335    # get total memory information
336    total_mem_mb = board_cfg_lib.get_total_mem()
337
338    # available check
339    i_cnt = 1
340    for arg_str in arg_list.values():
341        if arg_str == None or not arg_str.strip():
342            empty_err(i_cnt, item)
343            i_cnt += 1
344            continue
345
346        mem_size_set = int(arg_str.strip())
347        if mem_size_set > total_mem_mb:
348            key = "user_vm:id={},{}".format(i_cnt, item)
349            ERR_LIST[key] = "{}MB should be less than total memory {}MB".format(item)
350        i_cnt += 1
351
352
353def virtual_dev_slot(dev):
354    max_slot = 31
355    base_slot = 3
356
357    # get devices slot which already stored
358    if dev in list(PT_SLOT.keys()):
359        return PT_SLOT[dev]
360
361    # alloc a new slot for device
362    for slot_num in range(base_slot, max_slot):
363        if slot_num not in list(PT_SLOT.values()):
364
365            if (slot_num == 6 and 14 in list(PT_SLOT.values())) or (slot_num == 14 and 6 in list(PT_SLOT.values())):
366                continue
367            if (slot_num == 7 and 15 in list(PT_SLOT.values())) or (slot_num == 15 and 7 in list(PT_SLOT.values())):
368                continue
369
370            PT_SLOT[dev] = slot_num
371            break
372
373    return slot_num
374
375
376def get_slot(bdf_list, dev):
377
378    slot_list = {}
379    post_vm_list = get_post_num_list()
380    for p_id in post_vm_list:
381        if not bdf_list[p_id]:
382            slot_list[p_id] = ''
383        else:
384            slot_fun = virtual_dev_slot(dev)
385            PT_SLOT[dev] = slot_fun
386            slot_list[p_id] = slot_fun
387
388    return slot_list
389
390
391def reset_pt_slot():
392
393    global PT_SLOT
394
395    PT_SLOT = {
396        "hostbridge":0,
397        "lpc":1,
398        "pci-gvt":2,
399        "virtio-blk":3,
400        "igd-lpc":31,
401    }
402
403
404def get_pt_dev():
405    """ Get passthrough device list """
406    cap_pt = PASSTHRU_DEVS
407
408    return cap_pt
409
410
411def get_vuart1_from_scenario(vmid):
412    """Get the vmid's  vuart1 base"""
413    vuart1 = acrn_config_utilities.get_vuart_info_id(acrn_config_utilities.SCENARIO_INFO_FILE, 1)
414    return vuart1[vmid]['base']
415
416
417def pt_devs_check_audio(audio_map, audio_codec_map):
418    """
419    Check the connections about audio/audio_codec pass-through devices
420    If audio_codec is selected as pass-through device, the audio device
421    must to be chosen as pass-through device either.
422    :param audio_map: the dictionary contains vmid and bdf of audio device
423    :param audio_codec_map: the dictionary contains vmid and bdf of audio_codec device
424    """
425    for vmid in list(audio_map.keys()):
426        bdf_audio = audio_map[vmid]
427        bdf_codec = audio_codec_map[vmid]
428        if not bdf_audio and bdf_codec:
429            key = "user_vm:id={},passthrough_devices,{}".format(vmid, 'audio_codec')
430            ERR_LIST[key] = "Audio codec device should be pass through together with Audio devcie!"
431
432
433def check_block_mount(virtio_blk_dic):
434    (blk_dev_list, num) = board_cfg_lib.get_rootfs(acrn_config_utilities.BOARD_INFO_FILE)
435    for vmid in list(virtio_blk_dic.keys()):
436        mount_flags = []
437        for blk in virtio_blk_dic[vmid]:
438            rootfs_img = ''
439            if not blk:
440                mount_flags.append(False)
441                continue
442
443            if ':' in blk:
444                blk_dev = blk.split(':')[0]
445                rootfs_img = blk.split(':')[1]
446            else:
447                blk_dev = blk
448
449            if blk_dev in blk_dev_list and rootfs_img:
450                mount_flags.append(True)
451            else:
452                mount_flags.append(False)
453
454        MOUNT_FLAG_DIC[vmid] = mount_flags
455
456
457def check_sriov_param(sriov_dev, pt_sel):
458    for dev_type in ['gpu', 'network']:
459        for vm_id, dev_bdf in sriov_dev[dev_type].items():
460            if not dev_bdf:
461                continue
462            pt_devname = dev_type
463            if pt_devname == 'network':
464                pt_devname = 'ethernet'
465            if pt_sel.bdf[pt_devname][vm_id]:
466                ERR_LIST[
467                    'vmid:{} sriov {}'.format(vm_id, dev_type)
468                ] = 'this vm has {} passthrough and sriov {} at same time!'.format(pt_devname, dev_type)
469            if not re.match(r'^[\da-fA-F]{2}:[0-3][\da-fA-F]\.[0-7]$', dev_bdf):
470                ERR_LIST['vmid:{} sriov {}'.format(vm_id, dev_type)] = 'sriov {} bdf error'.format(dev_type)
471
472
473def bdf_duplicate_check(bdf_dic):
474    """
475    Check if exist duplicate slot
476    :param bdf_dic: contains all selected pass-through devices
477    :return: None
478    """
479    bdf_used = []
480    for dev in bdf_dic.keys():
481        dev_bdf_dic = bdf_dic[dev]
482        for vm_i in dev_bdf_dic.keys():
483            dev_bdf = dev_bdf_dic[vm_i]
484            if not dev_bdf:
485                continue
486
487            if dev_bdf in bdf_used:
488                key = "user_vm:id={},{},{}".format(vm_i, 'passthrough_devices', dev)
489                ERR_LIST[key] = "You select the same device for {} pass-through !".format(dev)
490                return
491            else:
492                bdf_used.append(dev_bdf)
493
494
495def get_gpu_bdf():
496
497    pci_lines = board_cfg_lib.get_info(acrn_config_utilities.BOARD_INFO_FILE, "<PCI_DEVICE>", "</PCI_DEVICE>")
498
499    for line in pci_lines:
500        if "VGA compatible controller" in line:
501            global gpu_bdf
502            gpu_bdf = line.split('\t')[1]
503            gpu_bdf = gpu_bdf[0:7]
504    return gpu_bdf
505
506
507def get_vpid_by_bdf(bdf):
508    vpid = ''
509    vpid_lines = board_cfg_lib.get_info(acrn_config_utilities.BOARD_INFO_FILE, "<PCI_VID_PID>", "</PCI_VID_PID>")
510
511    for vpid_line in vpid_lines:
512        if bdf in vpid_line:
513            vpid = " ".join(vpid_line.split()[2].split(':'))
514    return vpid
515
516
517def get_gpu_vpid():
518    gpu_bdf = get_gpu_bdf()
519    return get_vpid_by_bdf(gpu_bdf)
520
521
522def user_vm_cpu_affinity(user_vmid_cpu_affinity):
523
524    cpu_affinity = {}
525    sos_vm_id = get_sos_vmid()
526    for user_vmid,cpu_affinity_list in user_vmid_cpu_affinity.items():
527        cpu_affinity[int(user_vmid) + int(sos_vm_id)] = cpu_affinity_list
528    return cpu_affinity
529
530
531def check_slot(slot_db):
532
533    slot_values = {}
534    # init list of slot values for Post VM
535    for dev in slot_db.keys():
536        for user_vmid in slot_db[dev].keys():
537            slot_values[user_vmid] = []
538        break
539
540    # get slot values for Passthrough devices
541    for dev in PASSTHRU_DEVS:
542        if dev == 'gpu':
543            continue
544        for user_vmid,slot_str in slot_db[dev].items():
545            if not slot_str:
546                continue
547            slot_values[user_vmid].append(slot_str)
548
549    # update slot values and replace the fun=0 if there is no fun 0 in bdf list
550    for dev in PASSTHRU_DEVS:
551        if dev == 'gpu':
552            continue
553        for user_vmid,slot_str in slot_db[dev].items():
554            if not slot_str or ':' not in str(slot_str):
555                continue
556            bus_slot = slot_str[0:-1]
557            bus_slot_fun0 = bus_slot + "0"
558            if bus_slot_fun0 not in slot_values[user_vmid]:
559                slot_db[dev][user_vmid] = bus_slot_fun0
560                slot_values[user_vmid].append(bus_slot_fun0)
561
562
563def is_linux_like(user_vm_type):
564
565    is_linux = False
566    if user_vm_type in LINUX_LIKE_OS:
567        is_linux = True
568
569    return is_linux
570
571
572def set_shm_regions(launch_item_values, scenario_info):
573
574    try:
575        raw_shmem_regions = acrn_config_utilities.get_hv_item_tag(scenario_info, "FEATURES", "IVSHMEM", "IVSHMEM_REGION")
576        load_orders = acrn_config_utilities.get_leaf_tag_map(scenario_info, "load_order")
577        shm_enabled = acrn_config_utilities.get_hv_item_tag(scenario_info, "FEATURES", "IVSHMEM", "IVSHMEM_ENABLED")
578    except:
579        return
580
581    sos_vm_id = 0
582    for vm_id,load_order in load_orders.items():
583        if load_order in ['SERVICE_VM']:
584            sos_vm_id = vm_id
585        elif load_order in ['POST_LAUNCHED_VM']:
586            user_vmid = vm_id - sos_vm_id
587            shm_region_key = 'user_vm:id={},shm_regions,shm_region'.format(user_vmid)
588            launch_item_values[shm_region_key] = ['']
589            if shm_enabled == 'y':
590                for shmem_region in raw_shmem_regions:
591                    if shmem_region is None or shmem_region.strip() == '':
592                        continue
593                    try:
594                        shm_splited = shmem_region.split(',')
595                        name = shm_splited[0].strip()
596                        size = shm_splited[1].strip()
597                        vm_id_list = [x.strip() for x in shm_splited[2].split(':')]
598                        if str(vm_id) in vm_id_list:
599                            launch_item_values[shm_region_key].append(','.join([name, size]))
600                    except Exception as e:
601                        print(e)
602
603
604def set_pci_vuarts(launch_item_values, scenario_info):
605    try:
606        launch_item_values['user_vm,console_vuart'] = DM_VUART0
607        load_orders = acrn_config_utilities.get_leaf_tag_map(scenario_info, 'load_order')
608        sos_vm_id = 0
609        for vm_id,load_order in load_orders.items():
610            if load_order in ['SERVICE_VM']:
611                sos_vm_id = vm_id
612        for vm in list(acrn_config_utilities.get_config_root(scenario_info)):
613            if vm.tag == 'vm' and load_orders[int(vm.attrib['id'])] == 'POST_LAUNCHED_VM':
614                user_vmid = int(vm.attrib['id']) - sos_vm_id
615                pci_vuart_key = 'user_vm:id={},communication_vuarts,communication_vuart'.format(user_vmid)
616                for elem in list(vm):
617                    if elem.tag == 'communication_vuart':
618                        for sub_elem in list(elem):
619                            if sub_elem.tag == 'base' and sub_elem.text == 'PCI_VUART':
620                                if pci_vuart_key not in launch_item_values.keys():
621                                    launch_item_values[pci_vuart_key] = ['', elem.attrib['id']]
622                                else:
623                                    launch_item_values[pci_vuart_key].append(elem.attrib['id'])
624    except:
625        return
626
627
628def check_shm_regions(launch_shm_regions, scenario_info):
629    launch_item_values = {}
630    set_shm_regions(launch_item_values, scenario_info)
631
632    for user_vmid, shm_regions in launch_shm_regions.items():
633        shm_region_key = 'user_vm:id={},shm_regions,shm_region'.format(user_vmid)
634        for shm_region in shm_regions:
635            if shm_region_key not in launch_item_values.keys() or shm_region not in launch_item_values[shm_region_key]:
636                ERR_LIST[shm_region_key] = "shm {} should be configured in scenario setting and the size should be decimal" \
637                                           "in MB and spaces should not exist.".format(shm_region)
638                return
639
640
641def check_console_vuart(launch_console_vuart, vuart0, scenario_info):
642    vuarts = acrn_config_utilities.get_vuart_info(scenario_info)
643
644    for user_vmid, console_vuart_enable in launch_console_vuart.items():
645        key = 'user_vm:id={},console_vuart'.format(user_vmid)
646        if console_vuart_enable == "Enable" and vuart0[user_vmid] == "Enable":
647            ERR_LIST[key] = "vuart0 and console_vuart of user_vm {} should not be enabled " \
648                 "at the same time".format(user_vmid)
649            return
650        if console_vuart_enable == "Enable" and int(user_vmid) in vuarts.keys() \
651             and 0 in vuarts[user_vmid] and vuarts[user_vmid][0]['base'] == "INVALID_PCI_BASE":
652            ERR_LIST[key] = "console_vuart of user_vm {} should be enabled in scenario setting".format(user_vmid)
653            return
654
655
656def check_communication_vuart(launch_communication_vuarts, scenario_info):
657    vuarts = acrn_config_utilities.get_vuart_info(scenario_info)
658    vuart1_setting = acrn_config_utilities.get_vuart_info_id(acrn_config_utilities.SCENARIO_INFO_FILE, 1)
659
660    for user_vmid, vuart_list in launch_communication_vuarts.items():
661        vuart_key = 'user_vm:id={},communication_vuarts,communication_vuart'.format(user_vmid)
662        for vuart_id in vuart_list:
663            if not vuart_id:
664                return
665            if int(vuart_id) not in vuarts[user_vmid].keys():
666                ERR_LIST[vuart_key] = "communication_vuart {} of user_vm {} should be configured" \
667                     "in scenario setting.".format(vuart_id, user_vmid)
668                return
669            if int(vuart_id) == 1 and vuarts[user_vmid][1]['base'] != "INVALID_PCI_BASE":
670                if user_vmid in vuart1_setting.keys() and vuart1_setting[user_vmid]['base'] != "INVALID_COM_BASE":
671                    ERR_LIST[vuart_key] = "user_vm {}'s communication_vuart 1 and legacy_vuart 1 should " \
672                        "not be configured at the same time.".format(user_vmid)
673                return
674
675def check_enable_ptm(launch_enable_ptm, scenario_info):
676    scenario_etree = parse(scenario_info)
677    enable_ptm_vm_list = scenario_etree.xpath("//vm[PTM = 'y']/@id")
678    for user_vmid, enable_ptm in launch_enable_ptm.items():
679        key = 'user_vm:id={},enable_ptm'.format(user_vmid)
680        if enable_ptm == 'y' and str(user_vmid) not in enable_ptm_vm_list:
681            ERR_LIST[key] = "PTM of user_vm:{} set to 'n' in scenario xml".format(user_vmid)
682