From e46c5ac350bac793368311b3b5fff1f1d7d52205 Mon Sep 17 00:00:00 2001 From: Shuang Zheng Date: Tue, 4 Aug 2020 14:45:12 +0800 Subject: [PATCH] acrn-config: support configuration for Inter-VM communication This patch is to support the Inter-VM communication by IVSHMEM in config tool. Users can configure IVSHMEM_ENABLE to enable or disable Inter-VM communication by IVSHMEM; users can configure the name, size, communication VM IDs of the IVSHMEM devices in the VM settings of scenario xmls, then config tool will generate the related IVSHMEM configurations for Inter-VM communication. The config tool will do sanity check including when saving the xmls: the format of shared memory region configuration is [name],[size],[VM ID]:[VM ID](:[VM ID]...); the max size of the name is 32 bytes; the names should not be duplicated; the mininum value of shared memory region size is 2M; the value of shared memory region is a power of 2; the size of share memory region should not extended the size of available ram. Tracked-On: #4853 Signed-off-by: Shuang Zheng Acked-by: Victor Sun --- .../acrn-config/board_config/pci_devices_h.py | 11 ++ misc/acrn-config/board_config/vbar_base_h.py | 22 +++ misc/acrn-config/hv_config/board_defconfig.py | 56 +------ misc/acrn-config/hv_config/hv_item.py | 5 + misc/acrn-config/library/board_cfg_lib.py | 111 ++++++++++++++ misc/acrn-config/library/common.py | 27 +++- misc/acrn-config/library/scenario_cfg_lib.py | 144 ++++++++++++++++++ .../scenario_config/ivshmem_cfg_h.py | 96 ++++++++++++ misc/acrn-config/scenario_config/pci_dev_c.py | 66 +++++++- .../scenario_config/scenario_cfg_gen.py | 23 ++- .../scenario_config/scenario_item.py | 42 +++++ .../scenario_config/vm_configurations_c.py | 18 ++- .../scenario_config/vm_configurations_h.py | 11 +- 13 files changed, 566 insertions(+), 66 deletions(-) create mode 100644 misc/acrn-config/scenario_config/ivshmem_cfg_h.py diff --git a/misc/acrn-config/board_config/pci_devices_h.py b/misc/acrn-config/board_config/pci_devices_h.py index a6628df01..86372a916 100644 --- a/misc/acrn-config/board_config/pci_devices_h.py +++ b/misc/acrn-config/board_config/pci_devices_h.py @@ -62,5 +62,16 @@ def generate_file(config): i_cnt += 1 + ivshmem_enabled = common.get_hv_item_tag(common.SCENARIO_INFO_FILE, "FEATURES", "IVSHMEM", "IVSHMEM_ENABLED") + raw_shmem_regions = common.get_hv_item_tag(common.SCENARIO_INFO_FILE, "FEATURES", "IVSHMEM", "IVSHMEM_REGION") + if ivshmem_enabled == 'y': + shmem_cnt = 0 + for raw_shmem_region in raw_shmem_regions: + if raw_shmem_region and raw_shmem_region.strip != '': + name = raw_shmem_region.split(',')[0].strip() + print("", file=config) + print("#define IVSHMEM_SHM_REGION_%-21d"%shmem_cnt, end="", file=config) + print('"{}"'.format(name), file=config) + shmem_cnt += 1 # write the end to the pci devices print("{0}".format(PCI_END_HEADER), file=config) diff --git a/misc/acrn-config/board_config/vbar_base_h.py b/misc/acrn-config/board_config/vbar_base_h.py index 2dd646d26..360525a09 100644 --- a/misc/acrn-config/board_config/vbar_base_h.py +++ b/misc/acrn-config/board_config/vbar_base_h.py @@ -78,4 +78,26 @@ def generate_file(config): i_cnt += 1 + ivshmem_enabled = common.get_hv_item_tag(common.SCENARIO_INFO_FILE, "FEATURES", "IVSHMEM", "IVSHMEM_ENABLED") + if ivshmem_enabled == 'y': + board_cfg_lib.parse_mem() + for shm_name, bar_attr_dic in board_cfg_lib.PCI_DEV_BAR_DESC.shm_bar_dic.items(): + index = shm_name[:shm_name.find('_')] + i_cnt = 0 + for bar_i, bar_attr in bar_attr_dic.items(): + i_cnt += 1 + if bar_i == 0: + if len(bar_attr_dic.keys()) == 1: + print("#define IVSHMEM_DEVICE_%-23s" % (str(index) + "_VBAR"), + " .vbar_base[{}] = {}UL".format(bar_i, bar_attr.addr), file=config) + else: + print("#define IVSHMEM_DEVICE_%-23s" % (str(index) + "_VBAR"), + " .vbar_base[{}] = {}UL, \\".format(bar_i, bar_attr.addr), file=config) + elif i_cnt == len(bar_attr_dic.keys()): + print("{}.vbar_base[{}] = {}UL".format(' ' * 54, bar_i, bar_attr.addr), file=config) + else: + print("{}.vbar_base[{}] = {}UL, \\".format(' ' * 54, bar_i, bar_attr.addr), file=config) + + print("", file=config) + print(VBAR_INFO_ENDIF, file=config) diff --git a/misc/acrn-config/hv_config/board_defconfig.py b/misc/acrn-config/hv_config/board_defconfig.py index 7a17ab06d..3d51ce4bd 100644 --- a/misc/acrn-config/hv_config/board_defconfig.py +++ b/misc/acrn-config/hv_config/board_defconfig.py @@ -33,52 +33,6 @@ VM_NUM_MAP_TOTAL_HV_RAM_SIZE = { MEM_ALIGN = 2 * common.SIZE_M -def find_avl_memory(ram_range, hpa_size, hv_start_offset): - """ - This is get hv address from System RAM as host physical size - :param ram_range: System RAM mapping - :param hpa_size: fixed host physical size - :param hv_start_offset: base address of HV RAM start - :return: start host physical address - """ - ret_start_addr = 0 - tmp_order_key = 0 - - tmp_order_key = sorted(ram_range) - for start_addr in tmp_order_key: - mem_range = ram_range[start_addr] - if start_addr < hv_start_offset < start_addr + ram_range[start_addr]: - # 256M address located in this start ram range - if start_addr + mem_range - hv_start_offset > int(hpa_size, 10): - ret_start_addr = hv_start_offset - break - elif start_addr > hv_start_offset: - # above 256M address, than return the start address of this ram range - ret_start_addr = start_addr - break - - return hex(ret_start_addr) - - -def get_ram_range(): - """ Get System RAM range mapping """ - # read system ram from board_info.xml - ram_range = {} - - io_mem_lines = board_cfg_lib.get_info( - common.BOARD_INFO_FILE, "", "") - - for line in io_mem_lines: - if 'System RAM' not in line: - continue - start_addr = int(line.split('-')[0], 16) - end_addr = int(line.split('-')[1].split(':')[0], 16) - mem_range = end_addr - start_addr - ram_range[start_addr] = mem_range - - return ram_range - - def get_serial_type(): """ Get serial console type specified by user """ ttys_type = '' @@ -123,17 +77,20 @@ def get_memory(hv_info, config): err_dic["board config: total vm number error"] = "VM num should not be greater than 8" return err_dic - ram_range = get_ram_range() - # reseve 16M memory for hv sbuf, ramoops, etc. reserved_ram = 0x1000000 # We recommend to put hv ram start address high than 0x10000000 to # reduce memory conflict with GRUB/SOS Kernel. hv_start_offset = 0x10000000 total_size = reserved_ram + hv_ram_size - avl_start_addr = find_avl_memory(ram_range, str(total_size), hv_start_offset) + for start_addr in list(board_cfg_lib.USED_RAM_RANGE): + if hv_start_offset <= start_addr < 0x80000000: + del board_cfg_lib.USED_RAM_RANGE[start_addr] + ram_range = board_cfg_lib.get_ram_range() + avl_start_addr = board_cfg_lib.find_avl_memory(ram_range, str(total_size), hv_start_offset) hv_start_addr = int(avl_start_addr, 16) + int(hex(reserved_ram), 16) hv_start_addr = common.round_up(hv_start_addr, MEM_ALIGN) + board_cfg_lib.USED_RAM_RANGE[hv_start_addr] = total_size if not hv_info.mem.hv_ram_start: print("CONFIG_HV_RAM_START={}".format(hex(hv_start_addr)), file=config) @@ -149,6 +106,7 @@ def get_memory(hv_info, config): print("CONFIG_SOS_RAM_SIZE={}".format(hv_info.mem.sos_ram_size), file=config) print("CONFIG_UOS_RAM_SIZE={}".format(hv_info.mem.uos_ram_size), file=config) print("CONFIG_STACK_SIZE={}".format(hv_info.mem.stack_size), file=config) + print("CONFIG_IVSHMEM_ENABLED={}".format(hv_info.mem.ivshmem_enable), file=config) def get_serial_console(config): diff --git a/misc/acrn-config/hv_config/hv_item.py b/misc/acrn-config/hv_config/hv_item.py index 720337a8f..acedae8f7 100644 --- a/misc/acrn-config/hv_config/hv_item.py +++ b/misc/acrn-config/hv_config/hv_item.py @@ -153,6 +153,8 @@ class Memory: self.platform_ram_size = 0 self.sos_ram_size = 0 self.uos_ram_size = 0 + self.ivshmem_enable = 'n' + self.ivshmem_region = [] def get_info(self): self.stack_size = common.get_hv_item_tag(self.hv_file, "MEMORY", "STACK_SIZE") @@ -162,6 +164,8 @@ class Memory: self.platform_ram_size = common.get_hv_item_tag(self.hv_file, "MEMORY", "PLATFORM_RAM_SIZE") self.sos_ram_size = common.get_hv_item_tag(self.hv_file, "MEMORY", "SOS_RAM_SIZE") self.uos_ram_size = common.get_hv_item_tag(self.hv_file, "MEMORY", "UOS_RAM_SIZE") + self.ivshmem_enable = common.get_hv_item_tag(self.hv_file, "FEATURES", "IVSHMEM", "IVSHMEM_ENABLED") + self.ivshmem_region = common.get_hv_item_tag(self.hv_file, "FEATURES", "IVSHMEM", "IVSHMEM_REGION") def check_item(self): hv_cfg_lib.hv_size_check(self.stack_size, "MEMORY", "STACK_SIZE") @@ -169,6 +173,7 @@ class Memory: hv_cfg_lib.hv_size_check(self.platform_ram_size, "MEMORY", "PLATFORM_RAM_SIZE") hv_cfg_lib.hv_size_check(self.sos_ram_size, "MEMORY", "SOS_RAM_SIZE") hv_cfg_lib.hv_size_check(self.uos_ram_size, "MEMORY", "UOS_RAM_SIZE") + hv_cfg_lib.ny_support_check(self.ivshmem_enable, "FEATURES", "IVSHMEM", "IVSHMEM_ENABLED") class HvInfo: diff --git a/misc/acrn-config/library/board_cfg_lib.py b/misc/acrn-config/library/board_cfg_lib.py index 3b891b9de..921a0fe0b 100644 --- a/misc/acrn-config/library/board_cfg_lib.py +++ b/misc/acrn-config/library/board_cfg_lib.py @@ -21,6 +21,7 @@ LEGACY_TTYS = { VALID_LEGACY_IRQ = [] ERR_LIST = {} +USED_RAM_RANGE = {} HEADER_LICENSE = common.open_license() + "\n" @@ -363,6 +364,7 @@ class Pci_Dev_Bar_Desc: def __init__(self): self.pci_dev_dic = {} self.pci_bar_dic = {} + self.shm_bar_dic = {} PCI_DEV_BAR_DESC = Pci_Dev_Bar_Desc() SUB_NAME_COUNT = {} @@ -472,6 +474,47 @@ def parser_pci(): PCI_DEV_BAR_DESC.pci_bar_dic[cur_bdf] = tmp_bar_dic +def parse_mem(): + raw_shmem_regions = common.get_hv_item_tag(common.SCENARIO_INFO_FILE, "FEATURES", "IVSHMEM", "IVSHMEM_REGION") + + global USED_RAM_RANGE + for shm_name, shm_bar_dic in PCI_DEV_BAR_DESC.shm_bar_dic.items(): + if 0 in shm_bar_dic.keys() and int(shm_bar_dic[0].addr, 16) in USED_RAM_RANGE.keys(): + del USED_RAM_RANGE[int(shm_bar_dic[0].addr, 16)] + if 2 in shm_bar_dic.keys() and int(shm_bar_dic[2].addr, 16)-0xC in USED_RAM_RANGE.keys(): + del USED_RAM_RANGE[int(shm_bar_dic[2].addr, 16)-0xC] + + idx = 0 + for shm in raw_shmem_regions: + if shm is None or shm.strip() == '': + continue + shm_splited = shm.split(',') + name = shm_splited[0].strip() + size = shm_splited[1].strip() + + if size.isdecimal(): + int_size = int(size) + else: + int_size = int(size, 16) + ram_range = get_ram_range() + tmp_bar_dict = {} + hv_start_offset = 0x80000000 + ret_start_addr = find_avl_memory(ram_range, str(0x200100), hv_start_offset) + bar_mem_0 = Bar_Mem() + bar_mem_0.addr = hex(common.round_up(int(ret_start_addr, 16), 0x200000)) + USED_RAM_RANGE[int(bar_mem_0.addr, 16)] = 0x100 + tmp_bar_dict[0] = bar_mem_0 + ram_range = get_ram_range() + hv_start_offset2 = 0x100000000 + ret_start_addr2 = find_avl_memory(ram_range, str(int_size + 0x200000), hv_start_offset2) + bar_mem_2 = Bar_Mem() + bar_mem_2.addr = hex(common.round_up(int(ret_start_addr2, 16), 0x200000) + 0xC) + USED_RAM_RANGE[common.round_up(int(ret_start_addr2, 16), 0x20000)] = int_size + tmp_bar_dict[2] = bar_mem_2 + PCI_DEV_BAR_DESC.shm_bar_dic[str(idx)+'_'+name] = tmp_bar_dict + idx += 1 + + def is_rdt_supported(): """ Returns True if platform supports RDT else False @@ -569,3 +612,71 @@ def is_tpm_passthru(): tpm_passthru = True return tpm_passthru + + +def find_avl_memory(ram_range, hpa_size, hv_start_offset): + """ + This is get hv address from System RAM as host physical size + :param ram_range: System RAM mapping + :param hpa_size: fixed host physical size + :param hv_start_offset: base address of HV RAM start + :return: start host physical address + """ + ret_start_addr = 0 + tmp_order_key = 0 + int_hpa_size = int(hpa_size, 10) + + tmp_order_key = sorted(ram_range) + for start_addr in tmp_order_key: + mem_range = ram_range[start_addr] + if start_addr <= hv_start_offset and hv_start_offset + int_hpa_size <= start_addr + mem_range: + ret_start_addr = hv_start_offset + break + elif start_addr >= hv_start_offset and mem_range >= int_hpa_size: + ret_start_addr = start_addr + break + + return hex(ret_start_addr) + + +def get_ram_range(): + """ Get System RAM range mapping """ + # read system ram from board_info.xml + ram_range = {} + + io_mem_lines = get_info( + common.BOARD_INFO_FILE, "", "") + + for line in io_mem_lines: + if 'System RAM' not in line: + continue + start_addr = int(line.split('-')[0], 16) + end_addr = int(line.split('-')[1].split(':')[0], 16) + mem_range = end_addr - start_addr + ram_range[start_addr] = mem_range + + global USED_RAM_RANGE + tmp_order_key_used = sorted(USED_RAM_RANGE) + for start_addr_used in tmp_order_key_used: + mem_range_used = USED_RAM_RANGE[start_addr_used] + tmp_order_key = sorted(ram_range) + for start_addr in tmp_order_key: + mem_range = ram_range[start_addr] + if start_addr < start_addr_used and start_addr_used + mem_range_used < start_addr + mem_range: + ram_range[start_addr] = start_addr_used - start_addr + ram_range[start_addr_used+mem_range_used] = start_addr + mem_range - start_addr_used - mem_range_used + break + elif start_addr == start_addr_used and start_addr_used + mem_range_used < start_addr + mem_range: + del ram_range[start_addr] + ram_range[start_addr_used + mem_range_used] = start_addr + mem_range - start_addr_used - mem_range_used + break + elif start_addr < start_addr_used and start_addr_used + mem_range_used == start_addr + mem_range: + ram_range[start_addr] = start_addr_used - start_addr + break + elif start_addr == start_addr_used and start_addr_used + mem_range_used == start_addr + mem_range: + del ram_range[start_addr] + break + else: + continue + + return ram_range diff --git a/misc/acrn-config/library/common.py b/misc/acrn-config/library/common.py index 9a9fb7943..70f4d526f 100644 --- a/misc/acrn-config/library/common.py +++ b/misc/acrn-config/library/common.py @@ -19,7 +19,7 @@ PY_CACHES = ["__pycache__", "../board_config/__pycache__", "../scenario_config/_ GUEST_FLAG = ["0UL", "GUEST_FLAG_SECURE_WORLD_ENABLED", "GUEST_FLAG_LAPIC_PASSTHROUGH", "GUEST_FLAG_IO_COMPLETION_POLLING", "GUEST_FLAG_HIDE_MTRR", "GUEST_FLAG_RT"] -MULTI_ITEM = ["guest_flag", "pcpu_id", "vcpu_clos", "input", "block", "network", "pci_dev"] +MULTI_ITEM = ["guest_flag", "pcpu_id", "vcpu_clos", "input", "block", "network", "pci_dev", "shmem_region"] SIZE_K = 1024 SIZE_M = SIZE_K * 1024 @@ -45,6 +45,7 @@ class MultiItem(): self.vir_console = [] self.vir_network = [] self.pci_dev = [] + self.shmem_region = [] class TmpItem(): @@ -282,6 +283,10 @@ def get_leaf_value(tmp, tag_str, leaf): if leaf.tag == "pci_dev" and tag_str == "pci_dev": tmp.multi.pci_dev.append(leaf.text) + # get shmem_region for vm + if leaf.tag == "shmem_region" and tag_str == "shmem_region": + tmp.multi.shmem_region.append(leaf.text) + def get_sub_value(tmp, tag_str, vm_id): @@ -313,6 +318,10 @@ def get_sub_value(tmp, tag_str, vm_id): if tmp.multi.pci_dev and tag_str == "pci_dev": tmp.tag[vm_id] = tmp.multi.pci_dev + # append shmem_region for vm + if tmp.multi.shmem_region and tag_str == "shmem_region": + tmp.tag[vm_id] = tmp.multi.shmem_region + def get_leaf_tag_map(config_file, branch_tag, tag_str=''): """ @@ -409,6 +418,7 @@ def get_hv_item_tag(config_file, branch_tag, tag_str='', leaf_str=''): tmp = '' root = get_config_root(config_file) + for item in root: # for each 2th level item for sub in item: @@ -421,26 +431,35 @@ def get_hv_item_tag(config_file, branch_tag, tag_str='', leaf_str=''): continue # for each 3rd level item + tmp_list = [] for leaf in sub: if leaf.tag == tag_str: if not leaf_str: if leaf.tag == tag_str and leaf.text and leaf.text != None: - tmp = leaf.text + if tag_str == "IVSHMEM_REGION": + tmp_list.append(leaf.text) + else: + tmp = leaf.text + else: # for each 4rd level item tmp_list = [] for leaf_s in leaf: if leaf_s.tag == leaf_str and leaf_s.text and leaf_s.text != None: - if leaf_str == "CLOS_MASK" or leaf_str == "MBA_DELAY": + if leaf_str == "CLOS_MASK" or leaf_str == "MBA_DELAY" or leaf_str == "IVSHMEM_REGION": tmp_list.append(leaf_s.text) else: tmp = leaf_s.text continue - if leaf_str == "CLOS_MASK" or leaf_str == "MBA_DELAY": + if leaf_str == "CLOS_MASK" or leaf_str == "MBA_DELAY" or leaf_str == "IVSHMEM_REGION": tmp = tmp_list break + if tag_str == "IVSHMEM_REGION": + tmp = tmp_list + break + return tmp diff --git a/misc/acrn-config/library/scenario_cfg_lib.py b/misc/acrn-config/library/scenario_cfg_lib.py index 45e4b50a1..f91e79bdb 100644 --- a/misc/acrn-config/library/scenario_cfg_lib.py +++ b/misc/acrn-config/library/scenario_cfg_lib.py @@ -3,6 +3,7 @@ # SPDX-License-Identifier: BSD-3-Clause # +import math import common import board_cfg_lib @@ -92,6 +93,41 @@ def get_pci_num(pci_devs): return pci_devs_num +def get_shmem_regions(raw_shmem_regions): + shmem_regions = {'err': []} + for raw_shmem_region in raw_shmem_regions: + if raw_shmem_region and raw_shmem_region.strip(): + shm_splited = raw_shmem_region.split(',') + if len(shm_splited) == 3 and (shm_splited[0].strip() != '' and shm_splited[1].strip() != '' + and len(shm_splited[2].split(':')) >= 2): + name = shm_splited[0].strip() + size = shm_splited[1].strip() + vmid_list = shm_splited[2].split(':') + for i in range(len(vmid_list)): + try: + int_vm_id = int(vmid_list[i]) + except: + shmem_regions['err'].append(raw_shmem_region) + break + if int_vm_id not in shmem_regions.keys(): + shmem_regions[int_vm_id] = [','.join([name, size, ':'.join(vmid_list[0:i]+vmid_list[i+1:])])] + else: + shmem_regions[int_vm_id].append(','.join([name, size, ':'.join(vmid_list[0:i]+vmid_list[i+1:])])) + elif raw_shmem_region.strip() != '': + shmem_regions['err'].append(raw_shmem_region) + + return shmem_regions + + +def get_shmem_num(shmem_regions): + + shmem_num = {} + for shm_i, shm_list in shmem_regions.items(): + shmem_num[shm_i] = len(shm_list) + + return shmem_num + + def check_board_private_info(): if 'SOS_VM' not in common.VM_TYPES.values(): @@ -648,3 +684,111 @@ def vcpu_clos_check(cpus_per_vm, clos_per_vm, prime_item, item): key = "vm:id={},{},{}".format(vm_i, prime_item, item) ERR_LIST[key] = "CDP_ENABLED=y, the clos value should not be greater than {} for VM{}".format(common_clos_max - 1, vm_i) return + + +def share_mem_check(shmem_regions, raw_shmem_regions, vm_type_info, prime_item, item, sub_item): + + shmem_names = {} + for shm_i, shm_list in shmem_regions.items(): + for shm_str in shm_list: + index = -1 + if shm_i == 'err': + for i in range(len(raw_shmem_regions)): + if raw_shmem_regions[i] == shm_str: + index = i + break + if index == -1: + try: + for i in range(len(raw_shmem_regions)): + if raw_shmem_regions[i].split(',')[0].strip() == shm_str.split(',')[0].strip(): + index = i + break + except: + index = 0 + key = "hv,{},{},{}".format(prime_item, item, sub_item, index) + + shm_str_splited = shm_str.split(',') + if len(shm_str_splited) < 3: + ERR_LIST[key] = "The name, size, communication VM IDs of the share memory should be separated " \ + "by comma and not be empty." + return + try: + curr_vm_id = int(shm_i) + except: + ERR_LIST[key] = "share memory region should be configure with format like this: VM0_VM2,0x20000,0:2" + return + name = shm_str_splited[0].strip() + size = shm_str_splited[1].strip() + vmid_list = shm_str_splited[2].split(':') + int_vmid_list = [] + for vmid in vmid_list: + try: + int_vmid = int(vmid) + int_vmid_list.append(int_vmid) + except: + ERR_LIST[key] = "The communication VM IDs of the share memory should be decimal and separated by comma." + return + if not int_vmid_list: + ERR_LIST[key] = "The communication VM IDs of the share memory should be decimal and separated by comma." + return + if curr_vm_id in int_vmid_list or len(set(int_vmid_list)) != len(int_vmid_list): + ERR_LIST[key] = "The communication VM IDs of the share memory should not be duplicated." + return + for target_vm_id in int_vmid_list: + if curr_vm_id not in vm_type_info.keys() or target_vm_id not in vm_type_info.keys() \ + or vm_type_info[curr_vm_id] in ['SOS_VM'] or vm_type_info[target_vm_id] in ['SOS_VM']: + ERR_LIST[key] = "Shared Memory can be only configured for existed Pre-launched VMs and Post-launched VMs." + return + + if name =='' or size == '': + ERR_LIST[key] = "The name, size of the share memory should not be empty." + return + name_len = len(name) + if name_len > 32 or name_len == 0: + ERR_LIST[key] = "The size of share Memory name should be in range [1,32] bytes." + return + + int_size = 0 + try: + if size.isdecimal(): + int_size = int(size) + else: + int_size = int(size, 16) + except: + ERR_LIST[key] = "The size of share Memory region should be decimal or hexadecimal." + return + if int_size < 0x200000 or int_size > 0x40000000: + ERR_LIST[key] = "The size of share Memory region should be in [2M, 1G]." + return + if not math.log(int_size, 2).is_integer(): + ERR_LIST[key] = "The size of share Memory region should be a power of 2." + return + + if name in shmem_names.keys(): + shmem_names[name] += 1 + else: + shmem_names[name] = 1 + if shmem_names[name] > len(vmid_list)+1: + ERR_LIST[key] = "The names of share memory regions should not be duplicated: {}".format(name) + return + + board_cfg_lib.parse_mem() + for shm_i, shm_list in shmem_regions.items(): + for shm_str in shm_list: + shm_str_splited = shm_str.split(',') + name = shm_str_splited[0].strip() + index = 0 + try: + for i in range(len(raw_shmem_regions)): + if raw_shmem_regions[i].split(',')[0].strip() == shm_str.split(',')[0].strip(): + index = i + break + except: + index = 0 + key = "hv,{},{},{}".format(prime_item, item, sub_item, index) + if 'IVSHMEM_'+name in board_cfg_lib.PCI_DEV_BAR_DESC.shm_bar_dic.keys(): + bar_attr_dic = board_cfg_lib.PCI_DEV_BAR_DESC.shm_bar_dic['IVSHMEM_'+name] + if (0 in bar_attr_dic.keys() and int(bar_attr_dic[0].addr, 16) < 0x80000000) \ + or (2 in bar_attr_dic.keys() and int(bar_attr_dic[2].addr, 16) < 0x100000000): + ERR_LIST[key] = "Failed to get the start address of the shared memory, please check the size of it." + return diff --git a/misc/acrn-config/scenario_config/ivshmem_cfg_h.py b/misc/acrn-config/scenario_config/ivshmem_cfg_h.py new file mode 100644 index 000000000..950f50006 --- /dev/null +++ b/misc/acrn-config/scenario_config/ivshmem_cfg_h.py @@ -0,0 +1,96 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +import common +import scenario_cfg_lib +import board_cfg_lib + +IVSHMEM_HEADER_DEFINE = scenario_cfg_lib.HEADER_LICENSE + r""" +#ifndef IVSHMEM_CFG_H +#define IVSHMEM_CFG_H +""" +IVSHMEM_END_DEFINE = r"""#endif /* IVSHMEM_CFG_H */""" + + +def gen_common_header(config): + """ + This is common header for ivshmem_cfg.h + :param config: it is the pointer which file write to + :return: None + """ + print("{0}".format(IVSHMEM_HEADER_DEFINE), file=config) + + +def write_shmem_regions(config): + raw_shmem_regions = common.get_hv_item_tag(common.SCENARIO_INFO_FILE, "FEATURES", "IVSHMEM", "IVSHMEM_REGION") + shmem_regions = [] + shmem_dev_num = 0 + for raw_shm in raw_shmem_regions: + if raw_shm is None or raw_shm.strip() == '': + continue + raw_shm_splited = raw_shm.split(',') + if len(raw_shm_splited) == 3 and raw_shm_splited[0].strip() != '' \ + and raw_shm_splited[1].strip() != '' and len(raw_shm_splited[2].strip().split(':')) >= 1: + shmem_regions.append((raw_shm_splited[0].strip(), raw_shm_splited[1].strip(), raw_shm_splited[2].strip().split(':'))) + shmem_dev_num += len(raw_shm_splited[2].strip().split(':')) + + print("", file=config) + print("/*", file=config) + print(" * The IVSHMEM_SHM_SIZE is the sum of all memory regions.", file=config) + print(" * The size range of each memory region is [2M, 1G) and is a power of 2.", file=config) + print(" */", file=config) + total_shm_size = 0 + if len(shmem_regions) > 0: + for shmem_region in shmem_regions: + int_size = 0 + size = shmem_region[1] + try: + if size.isdecimal(): + int_size = int(size) + else: + int_size = int(size, 16) + except Exception as e: + print('the format of shm size error: ', str(e)) + total_shm_size += int_size + + print("#define IVSHMEM_SHM_SIZE\t{}UL".format(hex(total_shm_size)), file=config) + print("#define IVSHMEM_DEV_NUM\t\t{}UL".format(shmem_dev_num), file=config) + print("", file=config) + print("/* All user defined memory regions */", file=config) + print("\nstruct ivshmem_shm_region mem_regions[] = {", file=config) + shmem_cnt = 0 + for shmem in shmem_regions: + print("\t{", file=config) + print('\t\t.name = IVSHMEM_SHM_REGION_{},'.format(shmem_cnt), file=config) + try: + if shmem[1].isdecimal(): + int_m_size = int(int(shmem[1])/0x100000) + else: + int_m_size = int(int(shmem[1], 16)/0x100000) + except: + int_m_size = 0 + print('\t\t.size = {}UL,\t\t/* {}M */'.format(shmem[1], int_m_size), file=config) + print("\t},", file=config) + shmem_cnt += 1 + print("};", file=config) + print("", file=config) + + +def generate_file(scenario_items, config): + """ + Start to generate ivshmem_cfg.h + :param scenario_items: it is the class which contain all user setting information + :param config: it is a file pointer of scenario information for writing to + """ + vm_info = scenario_items['vm'] + gen_common_header(config) + + if vm_info.shmem.shmem_enabled == 'y': + print("#include ", file=config) + print("#include ", file=config) + print("#include ", file=config) + write_shmem_regions(config) + + print("{0}".format(IVSHMEM_END_DEFINE), file=config) diff --git a/misc/acrn-config/scenario_config/pci_dev_c.py b/misc/acrn-config/scenario_config/pci_dev_c.py index 0d7f6d0c5..b6da82b0a 100644 --- a/misc/acrn-config/scenario_config/pci_dev_c.py +++ b/misc/acrn-config/scenario_config/pci_dev_c.py @@ -27,6 +27,7 @@ def generate_file(vm_info, config): :return: None """ board_cfg_lib.parser_pci() + board_cfg_lib.parse_mem() compared_bdf = [] @@ -51,14 +52,24 @@ def generate_file(vm_info, config): print("#include ", file=config) print("#include ", file=config) print("#include ", file=config) + if vm_info.shmem.shmem_enabled == 'y': + print("#include ", file=config) for vm_i, pci_bdf_devs_list in vm_info.cfg_pci.pci_devs.items(): if not pci_bdf_devs_list: continue pci_cnt = 1 if idx == 0: print("", file=config) + print("/*", file=config) + print(" * TODO: remove PTDEV macro and add DEV_PRIVINFO macro to initialize pbdf for", file=config) + print(" * passthrough device configuration and shm_name for ivshmem device configuration.", file=config) + print(" */", file=config) print("#define PTDEV(PCI_DEV)\t\tPCI_DEV, PCI_DEV##_VBAR",file=config) print("", file=config) + print("/*", file=config) + print(" * TODO: add DEV_PCICOMMON macro to initialize emu_type, vbdf and vdev_ops", file=config) + print(" * to simplify the code.", file=config) + print(" */", file=config) print("struct acrn_vm_pci_dev_config " + "vm{}_pci_devs[VM{}_CONFIG_PCI_DEV_NUM] = {{".format(vm_i, vm_i), file=config) print("\t{", file=config) @@ -76,7 +87,7 @@ def generate_file(vm_info, config): fun = int(pci_bdf_dev.split('.')[1], 16) print("\t{", file=config) print("\t\t.emu_type = {},".format(PCI_DEV_TYPE[1]), file=config) - print("\t\t.vbdf.bits = {{.b = 0x00U, .d = 0x0{}U, .f = 0x00U}},".format(pci_cnt), file=config) + print("\t\t.vbdf.bits = {{.b = 0x00U, .d = 0x{0:02d}U, .f = 0x00U}},".format(pci_cnt), file=config) for bdf, bar_attr in board_cfg_lib.PCI_DEV_BAR_DESC.pci_dev_dic.items(): if bdf == pci_bdf_dev: print("\t\tPTDEV({}),".format(board_cfg_lib.PCI_DEV_BAR_DESC.pci_dev_dic[bdf].name_w_i_cnt), file=config) @@ -85,4 +96,57 @@ def generate_file(vm_info, config): print("\t},", file=config) pci_cnt += 1 + if vm_info.shmem.shmem_enabled == 'y' and vm_i in vm_info.shmem.shmem_regions.keys() \ + and len(vm_info.shmem.shmem_regions[vm_i]) > 0: + raw_shm_list = vm_info.shmem.shmem_regions[vm_i] + for shm in raw_shm_list: + shm_splited = shm.split(',') + print("\t{", file=config) + print("\t\t.emu_type = {},".format(PCI_DEV_TYPE[0]), file=config) + print("\t\t.vbdf.bits = {{.b = 0x00U, .d = 0x{0:02d}U, .f = 0x00U}},".format(pci_cnt), file=config) + print("\t\t.vdev_ops = &vpci_ivshmem_ops,", file=config) + for shm_name, bar_attr in board_cfg_lib.PCI_DEV_BAR_DESC.shm_bar_dic.items(): + index = shm_name[:shm_name.find('_')] + shm_name = shm_name[shm_name.find('_') + 1:] + if shm_name == shm_splited[0].strip(): + print("\t\t.shm_region_name = IVSHMEM_SHM_REGION_{},".format(index), file=config) + print("\t\tIVSHMEM_DEVICE_{}_VBAR".format(index), file=config) + # print("\t\t.vbar_size[0] = 0x100,", file=config) + # print("\t\t.vbar_size[2] = {},".format(shm_splited[1].strip()), file=config) + # print('\t\t.shm_name = "{}",'.format(shm_splited[0].strip()), file=config) + print("\t},", file=config) + pci_cnt += 1 + print("};", file=config) + + if vm_info.shmem.shmem_enabled == 'y': + for shm_i, raw_shm_list in vm_info.shmem.shmem_regions.items(): + shm_cnt = 0 + if shm_i not in vm_info.cfg_pci.pci_devs.keys() and len(raw_shm_list) > 0: + print("", file=config) + print("struct acrn_vm_pci_dev_config " + + "vm{}_pci_devs[VM{}_CONFIG_PCI_DEV_NUM] = {{".format(shm_i, shm_i), file=config) + for shm in raw_shm_list: + shm_splited = shm.split(',') + print("\t{", file=config) + print("\t\t.emu_type = {},".format(PCI_DEV_TYPE[0]), file=config) + if shm_i in common.VM_TYPES.keys() and common.VM_TYPES[shm_i] in ['PRE_RT_VM', 'PRE_STD_VM', 'SAFETY_VM']: + print("\t\t.vbdf.bits = {{.b = 0x00U, .d = 0x{0:02d}U, .f = 0x00U}},".format(shm_cnt), file=config) + else: + print("\t\t.vbdf.value = UNASSIGNED_VBDF,".format(shm_cnt), file=config) + print("\t\t.vdev_ops = &vpci_ivshmem_ops,", file=config) + for shm_name, bar_attr in board_cfg_lib.PCI_DEV_BAR_DESC.shm_bar_dic.items(): + index = shm_name[:shm_name.find('_')] + shm_name = shm_name[shm_name.find('_')+1:] + if shm_name == shm_splited[0].strip(): + if shm_i in common.VM_TYPES.keys() and common.VM_TYPES[shm_i] in ['PRE_RT_VM', 'PRE_STD_VM', + 'SAFETY_VM']: + print("\t\t.shm_region_name = IVSHMEM_SHM_REGION_{},".format(index), file=config) + print("\t\tIVSHMEM_DEVICE_{}_VBAR".format(index), file=config) + break + else: + print("\t\t.shm_region_name = IVSHMEM_SHM_REGION_{}".format(index), file=config) + break + shm_cnt += 1 + print("\t},", file=config) + print("};", file=config) \ No newline at end of file diff --git a/misc/acrn-config/scenario_config/scenario_cfg_gen.py b/misc/acrn-config/scenario_config/scenario_cfg_gen.py index de9e4fa38..b924d05f2 100755 --- a/misc/acrn-config/scenario_config/scenario_cfg_gen.py +++ b/misc/acrn-config/scenario_config/scenario_cfg_gen.py @@ -14,6 +14,7 @@ import scenario_cfg_lib import vm_configurations_c import vm_configurations_h import pci_dev_c +import ivshmem_cfg_h import common import hv_cfg_lib import board_defconfig @@ -21,7 +22,7 @@ from hv_item import HvInfo ACRN_PATH = common.SOURCE_ROOT_DIR ACRN_CONFIG_DEF = ACRN_PATH + 'misc/vm_configs/scenarios/' -GEN_FILE = ["vm_configurations.h", "vm_configurations.c", "pci_dev.c", ".config"] +GEN_FILE = ["vm_configurations.h", "vm_configurations.c", "pci_dev.c", ".config", "ivshmem_cfg.h"] def get_scenario_item_values(board_info, scenario_info): @@ -73,6 +74,7 @@ def get_scenario_item_values(board_info, scenario_info): scenario_item_values["hv,FEATURES,L1D_VMENTRY_ENABLED"] = hv_cfg_lib.N_Y scenario_item_values["hv,FEATURES,MCE_ON_PSC_DISABLED"] = hv_cfg_lib.N_Y scenario_item_values["hv,FEATURES,IOMMU_ENFORCE_SNP"] = hv_cfg_lib.N_Y + scenario_item_values["hv,FEATURES,IVSHMEM,IVSHMEM_ENABLED"] = hv_cfg_lib.N_Y scenario_cfg_lib.ERR_LIST.update(hv_cfg_lib.ERR_LIST) return scenario_item_values @@ -90,15 +92,16 @@ def validate_scenario_setting(board_info, scenario_info): common.BOARD_INFO_FILE = board_info common.SCENARIO_INFO_FILE = scenario_info - scenario_info_items = {} - vm_info = VmInfo(board_info, scenario_info) - vm_info.get_info() - vm_info.check_item() - hv_info = HvInfo(scenario_info) hv_info.get_info() hv_info.check_item() + scenario_info_items = {} + vm_info = VmInfo(board_info, scenario_info) + vm_info.get_info() + vm_info.set_ivshmem(hv_info.mem.ivshmem_region) + vm_info.check_item() + scenario_info_items['vm'] = vm_info scenario_info_items['hv'] = hv_info @@ -151,7 +154,7 @@ def main(args): else: scen_output = ACRN_PATH + params['--out'] + "/scenarios/" + scenario + "/" else: - scen_output = ACRN_CONFIG_DEF + "/scenarios/" + scenario + "/" + scen_output = ACRN_CONFIG_DEF + "/" + scenario + "/" scen_board = scen_output + board_name + "/" common.mkdir(scen_board) @@ -161,6 +164,7 @@ def main(args): vm_config_c = scen_output + GEN_FILE[1] pci_config_c = scen_board + GEN_FILE[2] config_hv = scen_board + board_name + GEN_FILE[3] + ivshmem_config_h = scen_board + GEN_FILE[4] # parse the scenario.xml get_scenario_item_values(params['--board'], params['--scenario']) @@ -185,6 +189,11 @@ def main(args): if err_dic: return err_dic + # generate ivshmem_cfg.h + print(ivshmem_config_h) + with open(ivshmem_config_h, 'w') as config: + ivshmem_cfg_h.generate_file(scenario_items, config) + # generate pci_dev.c with open(pci_config_c, 'w') as config: pci_dev_c.generate_file(scenario_items['vm'], config) diff --git a/misc/acrn-config/scenario_config/scenario_item.py b/misc/acrn-config/scenario_config/scenario_item.py index 2b3f9415c..174989ad1 100644 --- a/misc/acrn-config/scenario_config/scenario_item.py +++ b/misc/acrn-config/scenario_config/scenario_item.py @@ -228,6 +228,38 @@ class EpcSection: self.size = common.get_leaf_tag_map(self.scenario_info, "epc_section", "size") +class ShareMem: + """ This is the class to get Share Memory regions for VMs """ + shmem_enabled = 'n' + raw_shmem_regions = [] + shmem_regions = {} + shmem_num = {} + + def __init__(self, scenario_info): + self.scenario_info = scenario_info + + def set_ivshmem(self, ivshmem_regions): + """ + set ivshmem regions for VMs. + :param ivshmem_regions: + :return: + """ + self.raw_shmem_regions = ivshmem_regions + self.shmem_enabled = common.get_hv_item_tag(self.scenario_info, "FEATURES", "IVSHMEM", "IVSHMEM_ENABLED") + self.shmem_regions = scenario_cfg_lib.get_shmem_regions(ivshmem_regions) + self.shmem_num = scenario_cfg_lib.get_shmem_num(self.shmem_regions) + + def check_items(self): + ''' + check the configurations for share memories. + :return: + ''' + if self.shmem_enabled == 'y': + vm_type_info = common.get_leaf_tag_map(self.scenario_info, "vm_type") + scenario_cfg_lib.share_mem_check(self.shmem_regions, self.raw_shmem_regions, vm_type_info, + "FEATURES", "IVSHMEM", "IVSHMEM_REGION") + + class LoadOrderNum: """ This is Abstract of VM number for different load order """ def __init__(self): @@ -259,6 +291,7 @@ class VmInfo: self.vuart = VuartInfo(self.scenario_info) self.cfg_pci = CfgPci(self.scenario_info) self.load_order_cnt = LoadOrderNum() + self.shmem = ShareMem(self.scenario_info) def get_info(self): """ @@ -281,6 +314,14 @@ class VmInfo: self.cfg_pci.get_info() self.load_order_cnt.get_info(self.load_vm) + def set_ivshmem(self, ivshmem_regions): + """ + set ivshmem regions for VMs + :param ivshmem_regions: + :return: + """ + self.shmem.set_ivshmem(ivshmem_regions) + def get_cpu_bitmap(self, index): """ :param index: index list in GUESF_FLAGS @@ -310,4 +351,5 @@ class VmInfo: self.os_cfg.check_item() self.cfg_pci.check_item() self.vuart.check_item() + self.shmem.check_items() scenario_cfg_lib.ERR_LIST.update(err_dic) diff --git a/misc/acrn-config/scenario_config/vm_configurations_c.py b/misc/acrn-config/scenario_config/vm_configurations_c.py index 323dd4fb7..19c5ec5a8 100644 --- a/misc/acrn-config/scenario_config/vm_configurations_c.py +++ b/misc/acrn-config/scenario_config/vm_configurations_c.py @@ -340,7 +340,9 @@ def gen_pre_launch_vm(vm_type, vm_i, scenario_items, config): if err_dic: return err_dic - if vm_info.cfg_pci.pci_devs[vm_i] and vm_info.cfg_pci.pci_devs[vm_i] != None: + if (vm_i in vm_info.cfg_pci.pci_devs.keys() and vm_info.cfg_pci.pci_devs[vm_i]) or \ + (vm_info.shmem.shmem_enabled == 'y' and vm_i in vm_info.shmem.shmem_regions.keys() \ + and vm_info.shmem.shmem_regions[vm_i]): print("\t\t.pci_dev_num = VM{}_CONFIG_PCI_DEV_NUM,".format(vm_i), file=config) print("\t\t.pci_devs = vm{}_pci_devs,".format(vm_i), file=config) @@ -363,6 +365,11 @@ def gen_post_launch_vm(vm_type, vm_i, scenario_items, config): print("\t{{\t/* VM{} */".format(vm_i), file=config) print("\t\t{},".format(post_vm_type), file=config) clos_output(scenario_items, vm_i, config) + if vm_info.shmem.shmem_enabled == 'y' and vm_i in vm_info.shmem.shmem_regions.keys() \ + and vm_info.shmem.shmem_regions[vm_i]: + print("\t\t/* The PCI device configuration is only for in-hypervisor vPCI devices. */", file=config) + print("\t\t.pci_dev_num = VM{}_CONFIG_PCI_DEV_NUM,".format(vm_i), file=config) + print("\t\t.pci_devs = vm{}_pci_devs,".format(vm_i), file=config) cpu_affinity_output(vm_info, vm_i, config) is_need_epc(vm_info.epc_section, vm_i, config) # VUART @@ -376,10 +383,13 @@ def gen_post_launch_vm(vm_type, vm_i, scenario_items, config): def pre_launch_definiation(vm_info, config): for vm_i,vm_type in common.VM_TYPES.items(): - if "PRE_LAUNCHED_VM" != scenario_cfg_lib.VM_DB[vm_type]['load_type']: + if scenario_cfg_lib.VM_DB[vm_type]['load_type'] not in ["PRE_LAUNCHED_VM", "POST_LAUNCHED_VM"]: continue - print("extern struct acrn_vm_pci_dev_config " + - "vm{}_pci_devs[VM{}_CONFIG_PCI_DEV_NUM];".format(vm_i, vm_i), file=config) + if (vm_i in vm_info.cfg_pci.pci_devs.keys() and vm_info.cfg_pci.pci_devs[vm_i]) \ + or (vm_info.shmem.shmem_enabled == 'y' and vm_i in vm_info.shmem.shmem_regions.keys() \ + and vm_info.shmem.shmem_regions[vm_i]): + print("extern struct acrn_vm_pci_dev_config " + + "vm{}_pci_devs[VM{}_CONFIG_PCI_DEV_NUM];".format(vm_i, vm_i), file=config) print("", file=config) def generate_file(scenario_items, config): diff --git a/misc/acrn-config/scenario_config/vm_configurations_h.py b/misc/acrn-config/scenario_config/vm_configurations_h.py index b5de6c328..719c2072c 100644 --- a/misc/acrn-config/scenario_config/vm_configurations_h.py +++ b/misc/acrn-config/scenario_config/vm_configurations_h.py @@ -91,7 +91,12 @@ def gen_pre_launch_vm(scenario_items, config): print("#define VM{0}_CONFIG_MEM_SIZE_HPA2 {1}UL".format( vm_i, vm_info.mem_info.mem_size_hpa2[vm_i]), file=config) - print("#define VM{}_CONFIG_PCI_DEV_NUM {}U".format(vm_i, vm_info.cfg_pci.pci_dev_num[vm_i]), file=config) + shmem_num_i = 0 + if vm_info.shmem.shmem_enabled == 'y' and vm_i in vm_info.shmem.shmem_num.keys(): + shmem_num_i = vm_info.shmem.shmem_num[vm_i] + + print("#define VM{}_CONFIG_PCI_DEV_NUM {}U".format(vm_i, + vm_info.cfg_pci.pci_dev_num[vm_i] + shmem_num_i), file=config) print("", file=config) vm_i += 1 @@ -108,6 +113,10 @@ def gen_post_launch_header(scenario_items, config): is_post_vm_available = True cpu_affinity_output(vm_info, vm_i, config) clos_config_output(scenario_items, vm_i, config) + + if vm_info.shmem.shmem_enabled == 'y' and vm_i in vm_info.shmem.shmem_num.keys(): + print("#define VM{}_CONFIG_PCI_DEV_NUM {}U".format(vm_i, + vm_info.shmem.shmem_num[vm_i]), file=config) vm_i += 1 if is_post_vm_available: