acrn-config: offline tool to generate ACPI tables for pre-launched VMs

use offline tool to generate one binary of ACPI tables for pre-launched
VMs, then load the ACPI binary into guest physical memory as grub module.
Users can configure the resources or devices like TPM2 for the
pre-launched VM from sceanrio XMLs or UI, and the offline tool will
generate ASL code of the ACPI tables with the configured resources or
devices, then compile the ASL code to one binary when building ACRN.

Tracked-On: #5266

Signed-off-by: Shuang Zheng <shuang.zheng@intel.com>
Acked-by: Victor Sun <victor.sun@intel.com>
This commit is contained in:
Shuang Zheng 2020-09-01 15:44:09 +08:00 committed by Fuzhong Liu
parent 2c0bc146ce
commit 061091a489
15 changed files with 1088 additions and 1 deletions

View File

@ -0,0 +1,7 @@
# Copyright (C) 2019 Intel Corporation.
# SPDX-License-Identifier: BSD-3-Clause
"""__init__ for acpi generator.
"""

View File

@ -0,0 +1,49 @@
# Copyright (C) 2019 Intel Corporation.
# SPDX-License-Identifier: BSD-3-Clause
"""constant for offline ACPI generator.
"""
import os, sys
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'library'))
import common
VM_CONFIGS_PATH = os.path.join(common.SOURCE_ROOT_DIR, 'misc', 'vm_configs')
TEMPLATE_ACPI_PATH = os.path.join(VM_CONFIGS_PATH, 'acpi', 'template')
ACPI_TABLE_LIST = [('rsdp.asl', 'rsdp.aml'), ('xsdt.asl', 'xsdt.aml'), ('facp.asl', 'facp.aml'),
('mcfg.asl', 'mcfg.aml'), ('apic.asl', 'apic.aml'), ('tpm2.asl', 'tpm2.aml'),
('dsdt.asl', 'dsdt.aml')]
ACPI_BASE = 0x7ff00000
ACPI_RSDP_ADDR_OFFSET = 0x0 # (36 bytes fixed)
ACPI_XSDT_ADDR_OFFSET = 0x80 # (36 bytes + 8*7 table addrs)
ACPI_FADT_ADDR_OFFSET = 0x100 # (244 bytes)
ACPI_MCFG_ADDR_OFFSET = 0x300 # (60 bytes)
ACPI_MADT_ADDR_OFFSET = 0x340 # (depends on #CPUs)
ACPI_TPM2_ADDR_OFFSET = 0x1000 # (52 bytes)
ACPI_DSDT_ADDR_OFFSET = 0x200 # (variable - can go up to 0x100000)
ACPI_RSDP_ADDR = (ACPI_BASE + ACPI_RSDP_ADDR_OFFSET)
ACPI_XSDT_ADDR = (ACPI_BASE + ACPI_XSDT_ADDR_OFFSET)
ACPI_FADT_ADDR = (ACPI_BASE + ACPI_FADT_ADDR_OFFSET)
ACPI_MCFG_ADDR = (ACPI_BASE + ACPI_MCFG_ADDR_OFFSET)
ACPI_MADT_ADDR = (ACPI_BASE + ACPI_MADT_ADDR_OFFSET)
ACPI_TPM2_ADDR = (ACPI_BASE + ACPI_TPM2_ADDR_OFFSET)
ACPI_DSDT_ADDR = (ACPI_BASE + ACPI_DSDT_ADDR_OFFSET)
ACPI_FACS_ADDR = 0x0
PM1A_EVN_LEN = 0x4
PM1A_CNT_LEN = 0x2
FADT_FLAGS = 0x00001125
VIRT_PCI_MMCFG_BASE = 0xE0000000
ACPI_MADT_TYPE_IOAPIC = 1
VIOAPIC_BASE = 0xFEC00000
ACPI_MADT_TYPE_LOCAL_APIC = 0
ACPI_MADT_TYPE_LOCAL_APIC_NMI = 4

View File

@ -0,0 +1,464 @@
# Copyright (C) 2019 Intel Corporation.
# SPDX-License-Identifier: BSD-3-Clause
"""the tool to generate ASL code of ACPI tables for Pre-launched VMs.
"""
import os, re, argparse, shutil
import xml.etree.ElementTree as ElementTree
from acpi_const import *
def calculate_checksum8():
'''
this function is implemented in iasl.
:return:
'''
pass
def gen_rsdp(dest_vm_acpi_path):
'''
generate rsdp.asl
:param dest_vm_acpi_path: the path to store generated ACPI asl code
:return:
'''
rsdp_asl = 'rsdp.asl'
p_xsdt_addr = r'XSDT Address : ([0-9a-fA-F]{16})'
with open(os.path.join(dest_vm_acpi_path, rsdp_asl), 'w') as dest:
lines = []
with open(os.path.join(TEMPLATE_ACPI_PATH, rsdp_asl), 'r') as src:
for line in src.readlines():
if re.search(p_xsdt_addr, line):
print('ACPI_XSDT_ADDR: ', ACPI_XSDT_ADDR)
lines.append(re.sub(p_xsdt_addr, 'XSDT Address : {0:016X}'.format(ACPI_XSDT_ADDR), line))
else:
lines.append(line)
dest.writelines(lines)
def gen_xsdt(dest_vm_acpi_path, passthru_devices):
'''
generate xsdt.asl
:param dest_vm_acpi_path: the path to store generated ACPI asl code
:param passthru_devices: dict to store passthru device list
:return:
'''
xsdt_asl = 'xsdt.asl'
p_fadt_addr = r'ACPI Table Address 0 : ([0-9a-fA-F]{16})'
p_mcfg_addr = r'ACPI Table Address 1 : ([0-9a-fA-F]{16})'
p_madt_addr = r'ACPI Table Address 2 : ([0-9a-fA-F]{16})'
p_tpm2_addr = r'ACPI Table Address 3 : ([0-9a-fA-F]{16})'
with open(os.path.join(dest_vm_acpi_path, xsdt_asl), 'w') as dest:
lines = []
with open(os.path.join(TEMPLATE_ACPI_PATH, xsdt_asl), 'r') as src:
for line in src.readlines():
if re.search(p_fadt_addr, line):
lines.append(re.sub(p_fadt_addr, 'ACPI Table Address 0 : {0:016X}'.format(ACPI_FADT_ADDR), line))
elif re.search(p_mcfg_addr, line):
lines.append(re.sub(p_mcfg_addr, 'ACPI Table Address 1 : {0:016X}'.format(ACPI_MCFG_ADDR), line))
elif re.search(p_madt_addr, line):
lines.append(re.sub(p_madt_addr, 'ACPI Table Address 2 : {0:016X}'.format(ACPI_MADT_ADDR), line))
elif re.search(p_tpm2_addr, line):
if 'TPM2' in passthru_devices:
lines.append(re.sub(p_tpm2_addr, 'ACPI Table Address 3 : {0:016X}'.format(ACPI_TPM2_ADDR), line))
else:
lines.append(line)
dest.writelines(lines)
def gen_fadt(dest_vm_acpi_path, board_root):
'''
generate facp.asl
:param dest_vm_acpi_path: the path to store generated ACPI asl code
:param board_root: the root element of board xml
:return:
'''
fadt_asl = 'facp.asl'
p_facs_addr = r'FACS Address : ([0-9a-fA-F]{8})'
p_dsdt_addr = r'DSDT Address : ([0-9a-fA-F]{8})$'
p_pm1a_event_block_addr = r'PM1A Event Block Address : (\d+)'
p_pm1a_control_block_addr = r'PM1A Control Block Address : (\d+)'
p_pm1_event_length = r'PM1 Event Block Length : (\d+)'
p_pm1_control_length = r'PM1 Control Block Length : (\d+)'
p_flasg = r' Flags (decoded below) : (\d+)'
PM1A_EVT_ADDRESS = 0x0
PM1A_CNT_ADDRESS = 0x0
e_pm_info = board_root.find('PM_INFO')
for line in e_pm_info.text.split('\n'):
s = re.search(r'#define PM1A_EVT_ADDRESS (0x\d+)UL', line)
if s is not None and len(s.groups()) > 0:
PM1A_EVT_ADDRESS = int(s.groups()[0], 16)
continue
s = re.search(r'#define PM1A_CNT_ADDRESS (0x\d+)UL', line)
if s is not None and len(s.groups()) > 0:
PM1A_CNT_ADDRESS = int(s.groups()[0], 16)
continue
with open(os.path.join(dest_vm_acpi_path, fadt_asl), 'w') as dest:
lines = []
with open(os.path.join(TEMPLATE_ACPI_PATH, fadt_asl), 'r') as src:
for line in src.readlines():
if re.search(p_facs_addr, line):
lines.append(re.sub(p_facs_addr, 'FACS Address : {0:08X}'.format(ACPI_FACS_ADDR), line))
elif re.search(p_dsdt_addr, line):
lines.append(re.sub(p_dsdt_addr, 'DSDT Address : {0:08X}'.format(ACPI_DSDT_ADDR), line))
elif re.search(p_pm1a_event_block_addr, line):
lines.append(re.sub(p_pm1a_event_block_addr, 'PM1A Event Block Address : {0:08X}'.format(PM1A_EVT_ADDRESS), line))
elif re.search(p_pm1a_control_block_addr, line):
lines.append(re.sub(p_pm1a_control_block_addr, 'PM1A Control Block Address : {0:08X}'.format(PM1A_CNT_ADDRESS), line))
elif re.search(p_pm1_event_length, line):
lines.append(re.sub(p_pm1_event_length, 'PM1 Event Block Length : {0:02X}'.format(PM1A_EVN_LEN), line))
elif re.search(p_pm1_control_length, line):
lines.append(re.sub(p_pm1_control_length, 'PM1 Control Block Length : {0:02X}'.format(PM1A_CNT_LEN), line))
elif re.search(p_flasg, line):
lines.append(re.sub(p_flasg, 'Flags (decoded below) : {0:08X}'.format(FADT_FLAGS), line))
else:
lines.append(line)
dest.writelines(lines)
def gen_mcfg(dest_vm_acpi_path):
'''
generate mcfg.asl
:param dest_vm_acpi_path: the path to store generated ACPI asl code
:return:
'''
mcfg_asl = 'mcfg.asl'
p_base_addr = r'Base Address : ([0-9a-fA-F]{16})'
p_segment_group_num = r'Segment Group Number : (\d+)'
p_start_bus_num = r'Start Bus Number : (\d+)'
p_end_bus_num = r'End Bus Number : ([0-9a-fA-F]{2})'
with open(os.path.join(dest_vm_acpi_path, mcfg_asl), 'w') as dest:
lines = []
with open(os.path.join(TEMPLATE_ACPI_PATH, mcfg_asl), 'r') as src:
for line in src.readlines():
if re.search(p_base_addr, line):
lines.append(re.sub(p_base_addr, 'Base Address : {0:016X}'.format(VIRT_PCI_MMCFG_BASE), line))
elif re.search(p_segment_group_num, line):
lines.append(re.sub(p_segment_group_num, 'Segment Group Number : {0:04X}'.format(0), line))
elif re.search(p_start_bus_num, line):
lines.append(re.sub(p_start_bus_num, 'Start Bus Number : {0:02X}'.format(0), line))
elif re.search(p_end_bus_num, line):
lines.append(re.sub(p_end_bus_num, 'End Bus Number : {0:02X}'.format(0xff), line))
else:
lines.append(line)
dest.writelines(lines)
def gen_madt(dest_vm_acpi_path, max_cpu_num):
'''
generate apic.asl
:param dest_vm_acpi_path: the path to store generated ACPI asl code
:return:
'''
madt_asl = 'apic.asl'
lapic_index = 0
p_lapic_addr = r'Local Apic Address : ([0-9a-fA-F]{8})'
p_flags = r'\[0004\] Flags (decoded below) : (\d{8})' # dup flags
flags_index = 0
p_lapic_index = 0
p_lapic_type = r'Subtable Type : (\d+) \[Processor Local APIC\]'
p_lapic_len = r'\[0001\] Length : ([0-9a-fA-F]{2})' # dup len
p_lapic_len_index = 0
p_lapic_flags_index = 0
p_lapic_process_id = r'\[0001\] Processor ID : (\d+)' # dup processor
p_lapic_process_id_index = 0
p_lapic_id = r'Local Apic ID : ([0-9a-fA-F]{2})'
p_lapic_line_index = 0
lapic_lines = []
ioapic_index = 0
p_ioapic_type = r'Subtable Type : (\d+) \[I/O APIC\]'
p_ioapic_len_index = 0
p_ioapic_id = r'I/O Apic ID : (\d+)'
p_ioapic_addr = r'\[0004\] Address : ([0-9a-fA-F]{8})'
lapic_nmi_index = 0
p_lapic_nmi_type = r'Subtable Type : (\d+) \[Local APIC NMI\]'
p_lapic_nmi_len_index = 0
p_lapic_nmi_processor_id_index = 0
p_lapic_nmi_flags = r'\[0002\] Flags (decoded below) : ([0-9a-fA-F]{4})'
p_lapic_nmi_flags_index = 0
p_lapic_nmi_lint = r'Interrupt Input LINT : (\d+)'
with open(os.path.join(dest_vm_acpi_path, madt_asl), 'w') as dest:
lines = []
with open(os.path.join(TEMPLATE_ACPI_PATH, madt_asl), 'r') as src:
for line in src.readlines():
if re.search(p_lapic_addr, line):
lapic_index += 1
lines.append(re.sub(p_lapic_addr, 'Local Apic Address : {0:08X}'.format(0xFEE00000), line))
elif re.search(p_flags, line):
if lapic_index == 1 and flags_index == 0:
lines.append(
re.sub(p_flags, '[0004] Flags (decoded below) : {0:08X}'.format(0x1), line))
flags_index += 1
elif p_lapic_index == 1 and p_lapic_flags_index == 0:
lines.append(
re.sub(p_flags, '[0004] Flags (decoded below) : {0:08X}'.format(0x1),
line))
p_lapic_flags_index += 1
else:
lines.append(line)
elif re.search(p_lapic_type, line):
p_lapic_index += 1
if lapic_index == 1:
lines.append(re.sub(p_lapic_type, 'Subtable Type : {0:02X} [Processor Local APIC]'.format(
ACPI_MADT_TYPE_LOCAL_APIC), line))
else:
lines.append(line)
elif re.search(p_lapic_len, line):
if p_lapic_index == 1 and p_lapic_len_index == 0:
lines.append(
re.sub(p_lapic_len, '[0001] Length : {0:02X}'.format(0x8),
line))
p_lapic_len_index += 1
elif ioapic_index == 1 and p_ioapic_len_index == 0:
lines.append(
re.sub(p_lapic_len, '[0001] Length : {0:02X}'.format(0x0C),
line))
p_ioapic_len_index += 1
elif lapic_nmi_index == 1 and p_lapic_nmi_len_index == 0:
lines.append(
re.sub(p_lapic_len, '[0001] Length : {0:02X}'.format(0x06),
line))
p_lapic_nmi_len_index += 1
else:
lines.append(line)
elif re.search(p_lapic_process_id, line):
if p_lapic_index == 1 and p_lapic_process_id_index == 0:
lines.append(re.sub(p_lapic_process_id,
'[0001] Processor ID : {0:02X}'.format(0x0),
line))
p_lapic_process_id_index += 1
elif lapic_nmi_index == 1 and p_lapic_nmi_processor_id_index == 0:
lines.append(
re.sub(p_lapic_process_id,
'[0001] Processor ID : {0:02X}'.format(0xFF),
line))
p_lapic_nmi_processor_id_index += 1
else:
lines.append(line)
elif re.search(p_lapic_id, line):
lines.append(re.sub(p_lapic_id, 'Local Apic ID : {0:02X}'.format(0x0), line))
elif re.search(p_ioapic_type, line):
ioapic_index += 1
lines.append(
re.sub(p_ioapic_type, 'Subtable Type : {0:02X} [I/O APIC]'.format(ACPI_MADT_TYPE_IOAPIC), line))
elif re.search(p_ioapic_id, line):
lines.append(re.sub(p_ioapic_id, 'I/O Apic ID : {0:02X}'.format(0x01), line))
elif re.search(p_ioapic_addr, line):
lines.append(re.sub(p_ioapic_addr,
'[0004] Address : {0:02X}'.format(VIOAPIC_BASE),
line))
elif re.search(p_lapic_nmi_type, line):
lapic_nmi_index += 1
if lapic_nmi_index == 1:
lines.append(re.sub(p_lapic_nmi_type, 'Subtable Type : {0:02X} [Local APIC NMI]'.format(
ACPI_MADT_TYPE_LOCAL_APIC_NMI), line))
else:
lines.append(line)
elif re.search(p_lapic_nmi_flags, line):
if lapic_nmi_index == 1 and p_lapic_nmi_flags_index == 0:
lines.append(
re.sub(p_lapic_nmi_flags, '[0002] Flags (decoded below) : {0:04X}'.format(0x5),
line))
p_lapic_nmi_flags_index += 1
else:
lines.append(line)
elif re.search(p_lapic_nmi_lint, line):
if lapic_nmi_index == 1:
lines.append(re.sub(p_lapic_nmi_lint, 'Interrupt Input LINT : {0:02X}'.format(0x1), line))
else:
lines.append(line)
else:
lines.append(line)
if p_lapic_index == 1 and p_lapic_line_index < 7:
lapic_lines.append(line)
p_lapic_line_index += 1
if p_lapic_index == 1 and p_lapic_line_index == 7:
p_lapic_line_index = 0
for process_id in range(1, max_cpu_num):
p_lapic_index = process_id + 1
lines.append('\n')
for lapic_line in lapic_lines:
if re.search(p_lapic_type, lapic_line):
lines.append(re.sub(p_lapic_type,
'Subtable Type : {0:02X} [Processor Local APIC]'.format(
ACPI_MADT_TYPE_LOCAL_APIC), lapic_line))
elif re.search(p_lapic_len, lapic_line):
lines.append(
re.sub(p_lapic_len,
'[0001] Length : {0:02X}'.format(0x8),
lapic_line))
elif re.search(p_flags, lapic_line):
lines.append(
re.sub(p_flags,
'[0004] Flags (decoded below) : {0:08X}'.format(0x1),
lapic_line))
elif re.search(p_lapic_process_id, lapic_line):
lines.append(re.sub(p_lapic_process_id,
'[0001] Processor ID : {0:02X}'.format(
process_id), lapic_line))
elif re.search(p_lapic_id, lapic_line):
lines.append(
re.sub(p_lapic_id, 'Local Apic ID : {0:02X}'.format(process_id), lapic_line))
else:
lines.append(lapic_line)
dest.writelines(lines)
def gen_tpm2(dest_vm_acpi_path, passthru_devices):
'''
generate tpm2.asl
:param dest_vm_acpi_path: the path to store generated ACPI asl code
:param passthru_devices: dict to store passthru device list
:return:
'''
tpm2_asl = 'tpm2.asl'
p_control_addr = r'Control Address : ([0-9a-fA-F]{16})'
p_start_method = r'Start Method : (.*)'
if 'TPM2' not in passthru_devices:
if os.path.isfile(os.path.join(dest_vm_acpi_path, tpm2_asl)):
os.remove(os.path.join(dest_vm_acpi_path, tpm2_asl))
return
with open(os.path.join(dest_vm_acpi_path, tpm2_asl), 'w') as dest:
lines = []
with open(os.path.join(TEMPLATE_ACPI_PATH, tpm2_asl), 'r') as src:
for line in src.readlines():
if re.search(p_control_addr, line):
lines.append(re.sub(p_control_addr, 'Control Address : {0:016X}'.format(0xFED40040), line))
elif re.search(p_start_method, line):
lines.append(re.sub(p_start_method, 'Start Method : {0:02X}'.format(0x7), line))
else:
lines.append(line)
dest.writelines(lines)
def gen_dsdt(dest_vm_acpi_path, passthru_devices):
'''
generate dsdt.asl
:param dest_vm_acpi_path: the path to store generated ACPI asl code
:param passthru_devices:
:return:
'''
dsdt_asl = 'dsdt.asl'
p_dsdt_start = r'{'
with open(os.path.join(dest_vm_acpi_path, dsdt_asl), 'w') as dest:
lines = []
with open(os.path.join(TEMPLATE_ACPI_PATH, dsdt_asl), 'r') as src:
for line in src.readlines():
lines.append(line)
if line.startswith(p_dsdt_start):
for passthru_device in passthru_devices:
if passthru_device in ['TPM2']:
tpm2_asl = os.path.join(dest_vm_acpi_path, 'dsdt_tpm2.asl')
if not os.path.isfile(tpm2_asl):
tpm2_asl = os.path.join(TEMPLATE_ACPI_PATH, 'dsdt_tpm2.asl')
start = False
with open(tpm2_asl, 'r') as tpm2_src:
for tpm2_line in tpm2_src.readlines():
if tpm2_line.startswith('{'):
start = True
continue
if tpm2_line.startswith('}'):
start = False
continue
if start:
lines.append(tpm2_line)
else:
pass
dest.writelines(lines)
def main(args):
err_dic = {}
(err_dic, params) = common.get_param(args)
if err_dic:
return err_dic
board = params['--board']
scenario= params['--scenario']
out = params['--out']
board_root = ElementTree.parse(board).getroot()
scenario_root = ElementTree.parse(scenario).getroot()
board_type = board_root.attrib['board']
scenario_name = scenario_root.attrib['scenario']
pcpu_list = board_root.find('CPU_PROCESSOR_INFO').text.strip().split(',')
if isinstance(pcpu_list, list):
pcpu_list = [x.strip() for x in pcpu_list]
if out is None or out == '':
DEST_ACPI_PATH = os.path.join(VM_CONFIGS_PATH, 'scenarios', scenario_name, board_type)
else:
DEST_ACPI_PATH = os.path.join(common.SOURCE_ROOT_DIR, out, 'scenarios', scenario_name, board_type)
if os.path.isdir(DEST_ACPI_PATH):
for config in os.listdir(DEST_ACPI_PATH):
if config.startswith('VM') and os.path.isdir(os.path.join(DEST_ACPI_PATH, config)):
shutil.rmtree(os.path.join(DEST_ACPI_PATH, config))
dict_passthru_devices = {}
dict_vcpu_list = {}
for vm in scenario_root.findall('vm'):
vm_id = vm.attrib['id']
vm_type_node = vm.find('vm_type')
if (vm_type_node is not None) and (vm_type_node.text in ['PRE_STD_VM', 'SAFETY_VM', 'PRE_RT_VM']):
dict_passthru_devices[vm_id] = []
for pci_dev_node in vm.findall('pci_devs/pci_dev'):
if pci_dev_node is not None and pci_dev_node.text is not None and pci_dev_node.text.strip():
dict_passthru_devices[vm_id].append(pci_dev_node.text)
mmio_dev_nodes = vm.find('mmio_resources')
if mmio_dev_nodes is not None:
for mmio_dev_node in mmio_dev_nodes.getchildren():
if mmio_dev_node is not None and mmio_dev_node.text.strip() == 'y':
dict_passthru_devices[vm_id].append(mmio_dev_node.tag)
dict_vcpu_list[vm_id] = []
for pcpu_id in vm.findall('cpu_affinity/pcpu_id'):
if pcpu_id is not None and pcpu_id.text.strip() in pcpu_list:
dict_vcpu_list[vm_id].append(pcpu_id)
for vm_id, passthru_devices in dict_passthru_devices.items():
print('start to generate ACPI ASL code for VM{}'.format(vm_id))
dest_vm_acpi_path = os.path.join(DEST_ACPI_PATH, 'VM'+vm_id)
if not os.path.isdir(dest_vm_acpi_path):
os.makedirs(dest_vm_acpi_path)
gen_rsdp(dest_vm_acpi_path)
gen_xsdt(dest_vm_acpi_path, passthru_devices)
gen_fadt(dest_vm_acpi_path, board_root)
gen_mcfg(dest_vm_acpi_path)
vcpu_len = 0
if vm_id in dict_vcpu_list:
vcpu_len = len(dict_vcpu_list[vm_id])
else:
emsg = 'no cpu affinity config for VM {}'.format(vm_id)
print(emsg)
err_dic['vm,cpu_affinity,pcpu_id'] = emsg
gen_madt(dest_vm_acpi_path, vcpu_len)
gen_tpm2(dest_vm_acpi_path, passthru_devices)
gen_dsdt(dest_vm_acpi_path, passthru_devices)
print('generate ASL code of ACPI tables for VM {} into {}'.format(vm_id, dest_vm_acpi_path))
return err_dic
if __name__ == '__main__':
main(sys.argv)

View File

@ -0,0 +1,195 @@
# Copyright (C) 2019 Intel Corporation.
# SPDX-License-Identifier: BSD-3-Clause
"""the tool to generate ACPI binary for Pre-launched VMs.
"""
import os, sys, subprocess, argparse, re, shutil
from acpi_const import *
def asl_to_aml(dest_vm_acpi_path, dest_vm_acpi_bin_path):
'''
compile asl code of ACPI table to aml code.
:param dest_vm_acpi_path: the path of the asl code of ACPI tables
:param dest_vm_acpi_bin_path: the path of the aml code of ACPI tables
:param passthru_devices: passthrough devce list
:return:
'''
curr_path = os.getcwd()
rmsg = ''
os.chdir(dest_vm_acpi_path)
for acpi_table in ACPI_TABLE_LIST:
if acpi_table[0] == 'tpm2.asl':
if 'tpm2.asl' in os.listdir(dest_vm_acpi_path):
rc = exec_command('iasl {}'.format(acpi_table[0]))
if rc == 0 and os.path.isfile(os.path.join(dest_vm_acpi_path, acpi_table[1])):
shutil.move(os.path.join(dest_vm_acpi_path, acpi_table[1]),
os.path.join(dest_vm_acpi_bin_path, acpi_table[1]))
else:
if os.path.isfile(os.path.join(dest_vm_acpi_path, acpi_table[1])):
os.remove(os.path.join(dest_vm_acpi_path, acpi_table[1]))
rmsg = 'failed to compile {}'.format(acpi_table[0])
break
else:
rc = exec_command('iasl {}'.format(acpi_table[0]))
if rc == 0 and os.path.isfile(os.path.join(dest_vm_acpi_path, acpi_table[1])):
shutil.move(os.path.join(dest_vm_acpi_path, acpi_table[1]),
os.path.join(dest_vm_acpi_bin_path, acpi_table[1]))
else:
if os.path.isfile(os.path.join(dest_vm_acpi_path, acpi_table[1])):
os.remove(os.path.join(dest_vm_acpi_path, acpi_table[1]))
rmsg = 'failed to compile {}'.format(acpi_table[0])
break
os.chdir(curr_path)
if not rmsg:
print('compile ACPI ASL code to {} successfully'.format(dest_vm_acpi_bin_path))
return rmsg
def aml_to_bin(dest_vm_acpi_path, dest_vm_acpi_bin_path, acpi_bin_name):
'''
create the binary of ACPI table.
:param dest_vm_acpi_bin_path: the path of the aml code of ACPI tables
:param acpi_bin: the binary file name of ACPI tables
:param passthru_devices: passthrough devce list
:return:
'''
acpi_bin_file = os.path.join(dest_vm_acpi_bin_path, acpi_bin_name)
if os.path.isfile(acpi_bin_file):
os.remove(acpi_bin_file)
with open(acpi_bin_file, 'wb') as acpi_bin:
# acpi_bin.seek(ACPI_RSDP_ADDR_OFFSET)
# with open(os.path.join(dest_vm_acpi_bin_path, ACPI_TABLE_LIST[0][1]), 'rb') as asl:
# acpi_bin.write(asl.read())
acpi_bin.seek(ACPI_XSDT_ADDR_OFFSET)
with open(os.path.join(dest_vm_acpi_bin_path, ACPI_TABLE_LIST[1][1]), 'rb') as asl:
acpi_bin.write(asl.read())
acpi_bin.seek(ACPI_FADT_ADDR_OFFSET)
with open(os.path.join(dest_vm_acpi_bin_path, ACPI_TABLE_LIST[2][1]), 'rb') as asl:
acpi_bin.write(asl.read())
acpi_bin.seek(ACPI_MCFG_ADDR_OFFSET)
with open(os.path.join(dest_vm_acpi_bin_path, ACPI_TABLE_LIST[3][1]), 'rb') as asl:
acpi_bin.write(asl.read())
acpi_bin.seek(ACPI_MADT_ADDR_OFFSET)
with open(os.path.join(dest_vm_acpi_bin_path, ACPI_TABLE_LIST[4][1]), 'rb') as asl:
acpi_bin.write(asl.read())
if 'tpm2.asl' in os.listdir(dest_vm_acpi_path):
acpi_bin.seek(ACPI_TPM2_ADDR_OFFSET)
with open(os.path.join(dest_vm_acpi_bin_path, ACPI_TABLE_LIST[5][1]), 'rb') as asl:
acpi_bin.write(asl.read())
acpi_bin.seek(ACPI_DSDT_ADDR_OFFSET)
with open(os.path.join(dest_vm_acpi_bin_path, ACPI_TABLE_LIST[6][1]), 'rb') as asl:
acpi_bin.write(asl.read())
acpi_bin.seek(0xfffff)
acpi_bin.write(b'\0')
shutil.move(acpi_bin_file, os.path.join(dest_vm_acpi_bin_path, '..', acpi_bin_name))
print('write ACPI binary to {} successfully'.format(os.path.join(dest_vm_acpi_bin_path, '..', acpi_bin_name)))
def exec_command(cmd):
'''
execute the command and output logs.
:param cmd: the command to execute.
:return:
'''
print('exec: ', cmd)
p_compile_result = r'Compilation successful. (\d+) Errors, (\d+) Warnings, (\d+) Remarks'
cmd_list = cmd.split()
rc = 1
r_lines = []
try:
for line in subprocess.check_output(cmd_list).decode('utf8').split('\n'):
r_lines.append(line)
m = re.match(p_compile_result, line)
if m and len(m.groups()) == 3:
rc = int(m.groups()[0])
break
except Exception as e:
print('exception when exec {}'.format(cmd), e)
rc = -1
if rc > 0:
print('\n'.join(r_lines))
return rc
def check_iasl():
'''
check iasl installed
:return: True if iasl installed.
'''
try:
output = subprocess.check_output(['iasl', '-h']).decode('utf8')
if 'Usage: iasl [Options] [Files]' in output:
return True
elif 'command not found' in output:
return False
else:
print(output)
return False
except Exception as e:
print(e)
return False
def main(args):
board_type = args.board
scenario_name = args.scenario
if args.asl is None:
DEST_ACPI_PATH = os.path.join(VM_CONFIGS_PATH, 'scenarios', scenario_name, board_type)
else:
DEST_ACPI_PATH = os.path.join(common.SOURCE_ROOT_DIR, args.asl, 'scenarios', scenario_name, board_type)
if args.out is None:
DEST_ACPI_BIN_PATH = os.path.join(os.getcwd(), 'build', 'acpi')
else:
DEST_ACPI_BIN_PATH = args.out
if os.path.isdir(DEST_ACPI_BIN_PATH):
shutil.rmtree(DEST_ACPI_BIN_PATH)
if not check_iasl():
print("Please install iasl tool from https://www.acpica.org/downloads before ACPI generation.")
return 1
for config in os.listdir(DEST_ACPI_PATH):
if os.path.isdir(os.path.join(DEST_ACPI_PATH, config)) and config.startswith('VM'):
print('start to generate ACPI binary for {}'.format(config))
dest_vm_acpi_path = os.path.join(DEST_ACPI_PATH, config)
dest_vm_acpi_bin_path = os.path.join(DEST_ACPI_BIN_PATH, config)
os.makedirs(dest_vm_acpi_bin_path)
if asl_to_aml(dest_vm_acpi_path, dest_vm_acpi_bin_path):
return 1
aml_to_bin(dest_vm_acpi_path, dest_vm_acpi_bin_path, 'ACPI_'+config+'.bin')
return 0
if __name__ == '__main__':
parser = argparse.ArgumentParser(usage="python3 bin_gen.py --board [board] --scenario [scenario]"
"[ --out [output dir of acpi ASL code]]",
description="the tool to generate ACPI binary for Pre-launched VMs.")
parser.add_argument("--board", required=True, help="the board type.")
parser.add_argument("--scenario", required=True, help="the scenario name.")
parser.add_argument("--asl", default=None, help="the input folder to store the ACPI ASL code. "
"If not specified, the path for the ASL code is"
"misc/vm_configs/scenarios/[scenario]/[board]/")
parser.add_argument("--out", default="build/hypervisor/", help="the output folder to store the ACPI binary code. "
"If not specified, the path for the binary code is"
"build/acpi/")
args = parser.parse_args()
rc = main(args)
sys.exit(rc)

View File

@ -8,6 +8,7 @@ import sys
import copy
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'library'))
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'hv_config'))
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'acpi_gen'))
from scenario_item import HwInfo, VmInfo
import board_cfg_lib
import scenario_cfg_lib
@ -19,6 +20,7 @@ import common
import hv_cfg_lib
import board_defconfig
from hv_item import HvInfo
import asl_gen
ACRN_PATH = common.SOURCE_ROOT_DIR
ACRN_CONFIG_DEF = ACRN_PATH + 'misc/vm_configs/scenarios/'
@ -53,6 +55,7 @@ def get_scenario_item_values(board_info, scenario_info):
scenario_item_values["vm,pci_devs"] = scenario_cfg_lib.avl_pci_devs()
scenario_item_values["vm,os_config,kern_type"] = scenario_cfg_lib.KERN_TYPE_LIST
scenario_item_values["vm,mmio_resources,p2sb"] = hv_cfg_lib.N_Y
scenario_item_values["vm,mmio_resources,TPM2"] = hv_cfg_lib.N_Y
scenario_item_values.update(scenario_cfg_lib.avl_vuart_ui_select(scenario_info))
# board
@ -201,6 +204,9 @@ def main(args):
with open(pci_config_c, 'w') as config:
pci_dev_c.generate_file(scenario_items['vm'], config)
# generate ASL code of ACPI tables for Pre-launched VMs
asl_gen.main(args)
if not err_dic:
print("Scenario configuration files were created successfully.")
else:
@ -211,7 +217,7 @@ def main(args):
def ui_entry_api(board_info, scenario_info, out=''):
arg_list = ['board_cfg_gen.py', '--board', board_info, '--scenario', scenario_info, '--out', out]
arg_list = ['scenario_cfg_gen.py', '--board', board_info, '--scenario', scenario_info, '--out', out]
err_dic = common.prepare()
if err_dic:

View File

@ -337,6 +337,9 @@ def gen_pre_launch_vm(vm_type, vm_i, scenario_items, config):
print("\t\t\t.bootargs = ", end="", file=config)
split_cmdline(vm_info.os_cfg.kern_args[vm_i].strip(), config)
print("\t\t},", file=config)
print("\t\t.acpi_config = {", file=config)
print('\t\t\t.acpi_mod_tag = "ACPI_VM{}",'.format(vm_i), file=config)
print("\t\t},", file=config)
# VUART
err_dic = vuart_output(vm_type, vm_i, vm_info, config)
if err_dic:

View File

@ -591,6 +591,21 @@ def store_mmcfg_base_data(mmcfg_node, config):
print("\t#define DEFAULT_PCI_MMCFG_BASE {}UL".format(hex(mmcfg_base_addr)), file=config)
def read_tpm_data(config):
'''get TPM information from ACPI tables
:param config: file pointer that opened for writing board config information
:return:
'''
try:
acpi_table_output = subprocess.check_output(['ls -l /sys/firmware/acpi/tables/']).decode('utf8')
except:
acpi_table_output = ''
if 'TPM2' in acpi_table_output:
print("\tTPM2", file=config)
else:
print("\t/* no TPM device */", file=config)
def gen_acpi_info(config):
"""This will parser the sys node form SYS_PATH and generate ACPI info
:param config: file pointer that opened for writing board config information
@ -625,6 +640,10 @@ def gen_acpi_info(config):
store_mmcfg_base_data(SYS_PATH[1] + 'MCFG', config)
print("{0}".format("\t</MMCFG_BASE_INFO>\n"), file=config)
print("{0}".format("\t<TPM_INFO>"), file=config)
read_tpm_data(config)
print("{0}".format("\t</TPM_INFO>\n"), file=config)
def generate_info(board_file):
"""This will generate ACPI info from board file

View File

@ -0,0 +1,46 @@
/*
* Intel ACPI Component Architecture
* AML/ASL+ Disassembler version 20190703 (64-bit version)
* Copyright (c) 2000 - 2019 Intel Corporation
*
* ACPI Data Table [APIC]
*
* Format: [HexOffset DecimalOffset ByteLength] FieldName : FieldValue
*/
[0004] Signature : "APIC" [Multiple APIC Description Table (MADT)]
[0004] Table Length : 0000004E
[0001] Revision : 03
[0001] Checksum : 9B
[0006] Oem ID : "ACRN "
[0008] Oem Table ID : "ACRNMADT"
[0004] Oem Revision : 00000001
[0004] Asl Compiler ID : "INTL"
[0004] Asl Compiler Revision : 20190703
[0004] Local Apic Address : FEE00000
[0004] Flags (decoded below) : 00000001
PC-AT Compatibility : 1
[0001] Subtable Type : 01 [I/O APIC]
[0001] Length : 0C
[0001] I/O Apic ID : 01
[0001] Reserved : 00
[0004] Address : FEC00000
[0004] Interrupt : 00000000
[0001] Subtable Type : 04 [Local APIC NMI]
[0001] Length : 06
[0001] Processor ID : FF
[0002] Flags (decoded below) : 0005
Polarity : 1
Trigger Mode : 1
[0001] Interrupt Input LINT : 01
[0001] Subtable Type : 00 [Processor Local APIC]
[0001] Length : 08
[0001] Processor ID : 00
[0001] Local Apic ID : 00
[0004] Flags (decoded below) : 00000001
Processor Enabled : 1
Runtime Online Capable : 0

View File

@ -0,0 +1,21 @@
/*
* Intel ACPI Component Architecture
* AML/ASL+ Disassembler version 20190703 (64-bit version)
* Copyright (c) 2000 - 2019 Intel Corporation
*
* Original Table Header:
* Signature "DSDT"
* Length 0x00000051 (81)
* Revision 0x03
* Checksum 0xF0
* OEM ID "ACRN "
* OEM Table ID "ACRNDSDT"
* OEM Revision 0x00000001 (1)
* Compiler ID "INTL"
* Compiler Version 0x20190703 (538511107)
*/
DefinitionBlock ("", "DSDT", 3, "ACRN ", "ACRNDSDT", 0x00000001)
{
}

View File

@ -0,0 +1,30 @@
/*
* Intel ACPI Component Architecture
* AML/ASL+ Disassembler version 20190703 (64-bit version)
*
* Original Table Header:
* Signature "DSDT"
* Length 0x00000051 (81)
* Revision 0x03
* Checksum 0xF0
* OEM ID "ACRN "
* OEM Table ID "ACRNDSDT"
* OEM Revision 0x00000001 (1)
* Compiler ID "INTL"
* Compiler Version 0x20190703 (538511107)
*/
DefinitionBlock ("", "DSDT", 3, "ACRN ", "ACRNDSDT", 0x00000001)
{
Device (TPM)
{
Name (_HID, "MSFT0101" /* TPM 2.0 Security Device */) // _HID: Hardware ID
Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings
{
Memory32Fixed (ReadWrite,
0xFED40000, // Address Base
0x00005000, // Address Length
)
})
}
}

View File

@ -0,0 +1,157 @@
/*
* Intel ACPI Component Architecture
* AML/ASL+ Disassembler version 20190703 (64-bit version)
* Copyright (c) 2000 - 2019 Intel Corporation
*
* ACPI Data Table [FACP]
*
* Format: [HexOffset DecimalOffset ByteLength] FieldName : FieldValue
*/
[0004] Signature : "FACP" [Fixed ACPI Description Table (FADT)]
[0004] Table Length : 000000F4
[0001] Revision : 03
[0001] Checksum : 28
[0006] Oem ID : "ACRN "
[0008] Oem Table ID : "ACRNFADT"
[0004] Oem Revision : 00000001
[0004] Asl Compiler ID : "INTL"
[0004] Asl Compiler Revision : 20190703
[0004] FACS Address : 00000000
[0004] DSDT Address : 000F3400
[0001] Model : 00
[0001] PM Profile : 00 [Unspecified]
[0002] SCI Interrupt : 0000
[0004] SMI Command Port : 00000000
[0001] ACPI Enable Value : 00
[0001] ACPI Disable Value : 00
[0001] S4BIOS Command : 00
[0001] P-State Control : 00
[0004] PM1A Event Block Address : 00001800
[0004] PM1B Event Block Address : 00000000
[0004] PM1A Control Block Address : 00001804
[0004] PM1B Control Block Address : 00000000
[0004] PM2 Control Block Address : 00000000
[0004] PM Timer Block Address : 00000000
[0004] GPE0 Block Address : 00000000
[0004] GPE1 Block Address : 00000000
[0001] PM1 Event Block Length : 04
[0001] PM1 Control Block Length : 02
[0001] PM2 Control Block Length : 00
[0001] PM Timer Block Length : 00
[0001] GPE0 Block Length : 00
[0001] GPE1 Block Length : 00
[0001] GPE1 Base Offset : 00
[0001] _CST Support : 00
[0002] C2 Latency : 0000
[0002] C3 Latency : 0000
[0002] CPU Cache Size : 0000
[0002] Cache Flush Stride : 0000
[0001] Duty Cycle Offset : 00
[0001] Duty Cycle Width : 00
[0001] RTC Day Alarm Index : 00
[0001] RTC Month Alarm Index : 00
[0001] RTC Century Index : 00
[0002] Boot Flags (decoded below) : 0000
Legacy Devices Supported (V2) : 0
8042 Present on ports 60/64 (V2) : 0
VGA Not Present (V4) : 0
MSI Not Supported (V4) : 0
PCIe ASPM Not Supported (V4) : 0
CMOS RTC Not Present (V5) : 0
[0001] Reserved : 00
[0004] Flags (decoded below) : 00001125
WBINVD instruction is operational (V1) : 1
WBINVD flushes all caches (V1) : 0
All CPUs support C1 (V1) : 1
C2 works on MP system (V1) : 0
Control Method Power Button (V1) : 0
Control Method Sleep Button (V1) : 1
RTC wake not in fixed reg space (V1) : 0
RTC can wake system from S4 (V1) : 0
32-bit PM Timer (V1) : 1
Docking Supported (V1) : 0
Reset Register Supported (V2) : 0
Sealed Case (V3) : 0
Headless - No Video (V3) : 1
Use native instr after SLP_TYPx (V3) : 0
PCIEXP_WAK Bits Supported (V4) : 0
Use Platform Timer (V4) : 0
RTC_STS valid on S4 wake (V4) : 0
Remote Power-on capable (V4) : 0
Use APIC Cluster Model (V4) : 0
Use APIC Physical Destination Mode (V4) : 0
Hardware Reduced (V5) : 0
Low Power S0 Idle (V5) : 0
[0012] Reset Register : [Generic Address Structure]
[0001] Space ID : 00 [SystemMemory]
[0001] Bit Width : 00
[0001] Bit Offset : 00
[0001] Encoded Access Width : 00 [Undefined/Legacy]
[0008] Address : 0000000000000000
[0001] Value to cause reset : 00
[0002] ARM Flags (decoded below) : 0000
PSCI Compliant : 0
Must use HVC for PSCI : 0
[0001] FADT Minor Revision : 00
[0008] FACS Address : 0000000000000000
[0008] DSDT Address : 0000000000000000
[0012] PM1A Event Block : [Generic Address Structure]
[0001] Space ID : 00 [SystemMemory]
[0001] Bit Width : 00
[0001] Bit Offset : 00
[0001] Encoded Access Width : 00 [Undefined/Legacy]
[0008] Address : 0000000000000000
[0012] PM1B Event Block : [Generic Address Structure]
[0001] Space ID : 00 [SystemMemory]
[0001] Bit Width : 00
[0001] Bit Offset : 00
[0001] Encoded Access Width : 00 [Undefined/Legacy]
[0008] Address : 0000000000000000
[0012] PM1A Control Block : [Generic Address Structure]
[0001] Space ID : 00 [SystemMemory]
[0001] Bit Width : 00
[0001] Bit Offset : 00
[0001] Encoded Access Width : 00 [Undefined/Legacy]
[0008] Address : 0000000000000000
[0012] PM1B Control Block : [Generic Address Structure]
[0001] Space ID : 00 [SystemMemory]
[0001] Bit Width : 00
[0001] Bit Offset : 00
[0001] Encoded Access Width : 00 [Undefined/Legacy]
[0008] Address : 0000000000000000
[0012] PM2 Control Block : [Generic Address Structure]
[0001] Space ID : 00 [SystemMemory]
[0001] Bit Width : 00
[0001] Bit Offset : 00
[0001] Encoded Access Width : 00 [Undefined/Legacy]
[0008] Address : 0000000000000000
[0012] PM Timer Block : [Generic Address Structure]
[0001] Space ID : 00 [SystemMemory]
[0001] Bit Width : 00
[0001] Bit Offset : 00
[0001] Encoded Access Width : 00 [Undefined/Legacy]
[0008] Address : 0000000000000000
[0012] GPE0 Block : [Generic Address Structure]
[0001] Space ID : 00 [SystemMemory]
[0001] Bit Width : 00
[0001] Bit Offset : 00
[0001] Encoded Access Width : 00 [Undefined/Legacy]
[0008] Address : 0000000000000000
[0012] GPE1 Block : [Generic Address Structure]
[0001] Space ID : 00 [SystemMemory]
[0001] Bit Width : 00
[0001] Bit Offset : 00
[0001] Encoded Access Width : 00 [Undefined/Legacy]
[0008] Address : 0000000000000000

View File

@ -0,0 +1,27 @@
/*
* Intel ACPI Component Architecture
* AML/ASL+ Disassembler version 20190703 (64-bit version)
* Copyright (c) 2000 - 2019 Intel Corporation
*
* ACPI Data Table [MCFG]
*
* Format: [HexOffset DecimalOffset ByteLength] FieldName : FieldValue
*/
[0004] Signature : "MCFG" [Memory Mapped Configuration table]
[0004] Table Length : 0000003C
[0001] Revision : 03
[0001] Checksum : A5
[0006] Oem ID : "ACRN "
[0008] Oem Table ID : "ACRNMCFG"
[0004] Oem Revision : 00000001
[0004] Asl Compiler ID : "INTL"
[0004] Asl Compiler Revision : 20190703
[0008] Reserved : 0000000000000000
[0008] Base Address : 00000000E0000000
[0002] Segment Group Number : 0000
[0001] Start Bus Number : 00
[0001] End Bus Number : FF
[0004] Reserved : 00000000

View File

@ -0,0 +1,16 @@
/*
* Intel ACPI Component Architecture
* iASL Compiler/Disassembler version 20190703 (64-bit version)
* Copyright (c) 2000 - 2019 Intel Corporation
*
* Template for [RSDP] ACPI Table (AML byte code table)
*/
[0008] Signature : "RSD PTR "
[0001] Checksum : 43
[0006] Oem ID : "ACRN "
[0001] Revision : 02
[0004] RSDT Address : 0000000000000000
[0004] Length : 00000024
[0008] XSDT Address : 00000000000F2480
[0001] Extended Checksum : DC
[0003] Reserved : 000000

View File

@ -0,0 +1,23 @@
/*
* Intel ACPI Component Architecture
* AML/ASL+ Disassembler version 20190703 (64-bit version)
* Copyright (c) 2000 - 2019 Intel Corporation
*
* ACPI Data Table [TPM2]
*
* Format: [HexOffset DecimalOffset ByteLength] FieldName : FieldValue
*/
[0004] Signature : "TPM2" [Trusted Platform Module hardware interface table]
[0004] Table Length : 00000034
[0001] Revision : 03
[0001] Checksum : 67
[0006] Oem ID : "ACRN "
[0008] Oem Table ID : "ACRNTPM2"
[0004] Oem Revision : 00000001
[0004] Asl Compiler ID : "INTL"
[0004] Asl Compiler Revision : 20190703
[0004] Reserved : 00000000
[0008] Control Address : 00000000FED40040
[0004] Start Method : 07 [Command Response Buffer]

View File

@ -0,0 +1,24 @@
/*
* Intel ACPI Component Architecture
* AML/ASL+ Disassembler version 20190703 (64-bit version)
* Copyright (c) 2000 - 2019 Intel Corporation
*
* ACPI Data Table [XSDT]
*
* Format: [HexOffset DecimalOffset ByteLength] FieldName : FieldValue
*/
[0004] Signature : "XSDT" [Extended System Description Table]
[0004] Table Length : 00000044
[0001] Revision : 01
[0001] Checksum : 75
[0006] Oem ID : "ACRN "
[0008] Oem Table ID : "ACRNXSDT"
[0004] Oem Revision : 00000001
[0004] Asl Compiler ID : "INTL"
[0004] Asl Compiler Revision : 20190703
[0008] ACPI Table Address 0 : 00000000000F2500
[0008] ACPI Table Address 1 : 00000000000F2640
[0008] ACPI Table Address 2 : 00000000000F2680
[0008] ACPI Table Address 3 : 00000000000F2800