1#!/usr/bin/env python3
2#
3# Copyright (C) 2021-2022 Intel Corporation.
4#
5# SPDX-License-Identifier: BSD-3-Clause
6#
7
8
9import sys, os, re
10sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'library'))
11import acrn_config_utilities, board_cfg_lib
12from collections import namedtuple
13from acrn_config_utilities import get_node
14
15PRE_LAUNCHED_VMS_TYPE = ["SAFETY_VM", "PRE_RT_VM", "PRE_STD_VM"]
16POST_LAUNCHED_VMS_TYPE = ["POST_STD_VM", "POST_RT_VM"]
17SERVICE_VM_TYPE = ["SERVICE_VM"]
18
19class BusDevFunc(namedtuple(
20        "BusDevFunc", [
21            "bus",
22            "dev",
23            "func"])):
24
25    PATTERN = re.compile(r"(?P<bus>[0-9a-f]{2}):(?P<dev>[0-9a-f]{2})\.(?P<func>[0-7]{1})")
26
27    @classmethod
28    def from_str(cls, value):
29        if not(isinstance(value, str)):
30            raise ValueError("value must be a str: {}".format(type(value)))
31
32        match = cls.PATTERN.fullmatch(value)
33        if match:
34            return BusDevFunc(
35                bus=int(match.group("bus"), 16),
36                dev=int(match.group("dev"), 16),
37                func=int(match.group("func"), 16))
38        else:
39            raise ValueError("not a bdf: {!r}".format(value))
40
41    def __init__(self, *args, **kwargs):
42        if not (0x00 <= self.bus <= 0xff):
43            raise ValueError(f"Invalid bus number (0x00 ~ 0xff): {self.bus:#04x}")
44        if not (0x00 <= self.dev <= 0x1f):
45            raise ValueError(f"Invalid device number (0x00 ~ 0x1f): {self.dev:#04x}")
46        if not (0x0 <= self.func <= 0x7):
47            raise ValueError(f"Invalid function number (0 ~ 7): {self.func:#x}")
48
49    def __str__(self):
50        return f"PTDEV_{self.bus:02x}:{self.dev:02x}.{self.func:x}"
51
52    def __repr__(self):
53        return "BusDevFunc.from_str({!r})".format(str(self))
54
55def parse_hv_console(scenario_etree):
56    """
57    There may be 4 types in the console item
58    1. BDF:(00:18.2) seri:/dev/ttyS2
59    2. /dev/ttyS2
60    3. ttyS2
61    4. "None"
62    """
63    ttys_n = ''
64    ttys = get_node("//SERIAL_CONSOLE/text()", scenario_etree)
65
66    if not ttys or ttys == None or ttys == 'None':
67        return ttys_n
68
69    if ttys and 'BDF' in ttys or '/dev' in ttys:
70        ttys_n = ttys.split('/')[2]
71    else:
72        ttys_n = ttys
73
74    return ttys_n
75
76def get_native_ttys():
77    native_ttys = {}
78    ttys_lines = board_cfg_lib.get_info(acrn_config_utilities.BOARD_INFO_FILE, "<TTYS_INFO>", "</TTYS_INFO>")
79    if ttys_lines:
80        for tty_line in ttys_lines:
81            tmp_dic = {}
82            #seri:/dev/ttySx type:mmio base:0x91526000 irq:4 [bdf:"00:18.0"]
83            #seri:/dev/ttySy type:portio base:0x2f8 irq:5
84            tty = tty_line.split('/')[2].split()[0]
85            ttys_type = tty_line.split()[1].split(':')[1].strip()
86            ttys_base = tty_line.split()[2].split(':')[1].strip()
87            ttys_irq = tty_line.split()[3].split(':')[1].strip()
88            tmp_dic['type'] = ttys_type
89            tmp_dic['base'] = ttys_base
90            tmp_dic['irq'] = int(ttys_irq)
91            native_ttys[tty] = tmp_dic
92    return native_ttys
93
94def get_ivshmem_regions_by_tree(etree):
95    ivshmem_enabled = get_ivshmem_enabled_by_tree(etree)
96    if ivshmem_enabled == 'n':
97        return {}
98
99    ivshmem_regions = etree.xpath("//IVSHMEM_REGION")
100    shmem_regions = {}
101    for idx in range(len(ivshmem_regions)):
102        provided_by = get_node("./PROVIDED_BY/text()", ivshmem_regions[idx])
103        if provided_by != "Hypervisor":
104            continue
105        shm_name = get_node("./NAME/text()", ivshmem_regions[idx])
106        if shm_name is None:
107            continue
108        shm_size = get_node("./IVSHMEM_SIZE/text()", ivshmem_regions[idx])
109        shm_vm_list = ivshmem_regions[idx].xpath(".//IVSHMEM_VM")
110        for shm_vm in shm_vm_list:
111            vm_name = get_node("./VM_NAME/text()", shm_vm)
112            vm_id = get_node(f"//vm[name = '{vm_name}']/@id", etree)
113            vbdf =  get_node("./VBDF/text()", shm_vm)
114            if vm_id not in shmem_regions:
115                shmem_regions[vm_id] = {}
116            shmem_regions[vm_id][shm_name] = {'id' : str(idx), 'size' : shm_size, 'vbdf' : vbdf}
117    return shmem_regions
118
119def get_ivshmem_enabled_by_tree(etree):
120    ivshmem_vms = etree.xpath("//IVSHMEM_VM")
121    shmem_enabled = 'n'
122    if len(ivshmem_vms) != 0:
123        shmem_enabled = 'y'
124    return shmem_enabled
125
126def is_pre_launched_vm(vm_type):
127    if vm_type == 'PRE_LAUNCHED_VM':
128        return True
129    return False
130
131def is_post_launched_vm(vm_type):
132    if vm_type == 'POST_LAUNCHED_VM':
133        return True
134    return False
135
136def is_service_vm(vm_type):
137    if vm_type == 'SERVICE_VM':
138        return True
139    return False
140