Files
chipsec-chipsec/chipsec/hal/common/acpi.py
T
William Leara 79f81bbb7e fix for flake8 rules related to whitespace
This commit fixes whitespace errors from checkers W291,W292,W293,W391.  They were found by running "flake8 ." from the root directory.  These are errors defined by "pycodestyle", and have no functional impact to the source.  This is simply fixing whitespace as defined by CHIPSEC's .flake8 configuration.

background:
https://www.flake8rules.com/rules/W291.html
https://www.flake8rules.com/rules/W292.html
https://www.flake8rules.com/rules/W293.html
https://www.flake8rules.com/rules/W391.html

tool versions: flake8 v7.3.0, python v3.13.11

Signed-off-by: William Leara <william.leara@dell.com>
2026-03-10 14:20:23 -07:00

626 lines
26 KiB
Python

# CHIPSEC: Platform Security Assessment Framework
# Copyright (c) 2010-2021, Intel Corporation
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; Version 2.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# Contact information:
# chipsec@intel.com
#
"""
HAL component providing access to and decoding of ACPI tables
"""
__version__ = '0.1'
import struct
from collections import defaultdict, namedtuple
from collections.abc import Callable
from typing import Dict, List, Tuple, Optional, Union, TYPE_CHECKING
from chipsec.library.defines import bytestostring
from chipsec.library.exceptions import UnimplementedAPIError
from chipsec.library.file import read_file
from chipsec.library import acpi_tables
from chipsec.hal.hal_base import HALBase
from chipsec.hal.common.uefi import UEFI
from chipsec.library.logger import logger, print_buffer_bytes
from chipsec.library.acpi_tables import ACPI_TABLE
if TYPE_CHECKING:
from ctypes import Array
# ACPI Table Header Format
ACPI_TABLE_HEADER_FORMAT = '=4sIBB6s8sI4sI'
ACPI_TABLE_HEADER_SIZE = struct.calcsize(ACPI_TABLE_HEADER_FORMAT) # 36
assert 36 == ACPI_TABLE_HEADER_SIZE
class ACPI_TABLE_HEADER(namedtuple('ACPI_TABLE_HEADER', 'Signature Length Revision Checksum OEMID OEMTableID OEMRevision CreatorID CreatorRevision')):
__slots__ = ()
def __str__(self) -> str:
return f""" Table Header
------------------------------------------------------------------
Signature : {self.Signature}
Length : 0x{self.Length:08X}
Revision : 0x{self.Revision:02X}
Checksum : 0x{self.Checksum:02X}
OEM ID : {self.OEMID}
OEM Table ID : {self.OEMTableID}
OEM Revision : 0x{self.OEMRevision:08X}
Creator ID : {self.CreatorID}
Creator Revision : 0x{self.CreatorRevision:08X}
"""
ACPI_TABLE_SIG_SIZE = 0x4
ACPI_TABLE_SIG_ROOT = 'ROOT'
ACPI_TABLE_SIG_RSDP = 'RSDP'
ACPI_TABLE_SIG_RSDT = 'RSDT'
ACPI_TABLE_SIG_XSDT = 'XSDT'
ACPI_TABLE_SIG_FACP = 'FACP'
ACPI_TABLE_SIG_FACS = 'FACS'
ACPI_TABLE_SIG_DSDT = 'DSDT'
ACPI_TABLE_SIG_SSDT = 'SSDT'
ACPI_TABLE_SIG_PSDT = 'PSDT'
ACPI_TABLE_SIG_APIC = 'APIC'
ACPI_TABLE_SIG_SBST = 'SBST'
ACPI_TABLE_SIG_ECDT = 'ECDT'
ACPI_TABLE_SIG_SRAT = 'SRAT'
ACPI_TABLE_SIG_SLIC = 'SLIC'
ACPI_TABLE_SIG_SLIT = 'SLIT'
ACPI_TABLE_SIG_BOOT = 'BOOT'
ACPI_TABLE_SIG_CPEP = 'CPEP'
ACPI_TABLE_SIG_DBGP = 'DBGP'
ACPI_TABLE_SIG_ETDT = 'ETDT'
ACPI_TABLE_SIG_HPET = 'HPET'
ACPI_TABLE_SIG_MCFG = 'MCFG'
ACPI_TABLE_SIG_SPCR = 'SPCR'
ACPI_TABLE_SIG_SPMI = 'SPMI'
ACPI_TABLE_SIG_TCPA = 'TCPA'
ACPI_TABLE_SIG_WDAT = 'WDAT'
ACPI_TABLE_SIG_WDRT = 'WDRT'
ACPI_TABLE_SIG_WSPT = 'WSPT'
ACPI_TABLE_SIG_WDDT = 'WDDT'
ACPI_TABLE_SIG_ASF = 'ASF!'
ACPI_TABLE_SIG_MSEG = 'MSEG'
ACPI_TABLE_SIG_DMAR = 'DMAR'
ACPI_TABLE_SIG_UEFI = 'UEFI'
ACPI_TABLE_SIG_FPDT = 'FPDT'
ACPI_TABLE_SIG_PCCT = 'PCCT'
ACPI_TABLE_SIG_MSDM = 'MSDM'
ACPI_TABLE_SIG_BATB = 'BATB'
ACPI_TABLE_SIG_BGRT = 'BGRT'
ACPI_TABLE_SIG_LPIT = 'LPIT'
ACPI_TABLE_SIG_ASPT = 'ASPT'
ACPI_TABLE_SIG_FIDT = 'FIDT'
ACPI_TABLE_SIG_HEST = 'HEST'
ACPI_TABLE_SIG_BERT = 'BERT'
ACPI_TABLE_SIG_ERST = 'ERST'
ACPI_TABLE_SIG_EINJ = 'EINJ'
ACPI_TABLE_SIG_TPM2 = 'TPM2'
ACPI_TABLE_SIG_WSMT = 'WSMT'
ACPI_TABLE_SIG_DBG2 = 'DBG2'
ACPI_TABLE_SIG_NHLT = 'NHLT'
ACPI_TABLE_SIG_MSCT = 'MSCT'
ACPI_TABLE_SIG_RASF = 'RASF'
ACPI_TABLE_SIG_OEM1 = 'OEM1'
ACPI_TABLE_SIG_OEM2 = 'OEM2'
ACPI_TABLE_SIG_OEM3 = 'OEM3'
ACPI_TABLE_SIG_OEM4 = 'OEM4'
ACPI_TABLE_SIG_NFIT = 'NFIT'
ACPI_TABLES: Dict[str, Callable] = {
ACPI_TABLE_SIG_ROOT: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_RSDT: acpi_tables.RSDT,
ACPI_TABLE_SIG_XSDT: acpi_tables.XSDT,
ACPI_TABLE_SIG_FACP: acpi_tables.FADT,
ACPI_TABLE_SIG_FACS: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_DSDT: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_SSDT: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_PSDT: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_APIC: acpi_tables.APIC,
ACPI_TABLE_SIG_SBST: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_ECDT: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_SRAT: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_SLIC: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_SLIT: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_BOOT: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_CPEP: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_DBGP: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_ETDT: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_HPET: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_MCFG: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_SPCR: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_TCPA: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_WDAT: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_WDRT: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_WSPT: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_WDDT: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_ASF: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_MSEG: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_DMAR: acpi_tables.DMAR,
ACPI_TABLE_SIG_UEFI: acpi_tables.UEFI_TABLE,
ACPI_TABLE_SIG_FPDT: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_PCCT: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_MSDM: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_BATB: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_BGRT: acpi_tables.BGRT,
ACPI_TABLE_SIG_LPIT: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_ASPT: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_FIDT: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_HEST: acpi_tables.HEST,
ACPI_TABLE_SIG_BERT: acpi_tables.BERT,
ACPI_TABLE_SIG_ERST: acpi_tables.ERST,
ACPI_TABLE_SIG_EINJ: acpi_tables.EINJ,
ACPI_TABLE_SIG_TPM2: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_WSMT: acpi_tables.WSMT,
ACPI_TABLE_SIG_DBG2: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_NHLT: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_MSCT: acpi_tables.MSCT,
ACPI_TABLE_SIG_RASF: acpi_tables.RASF,
ACPI_TABLE_SIG_SPMI: acpi_tables.SPMI,
ACPI_TABLE_SIG_OEM1: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_OEM2: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_OEM3: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_OEM4: acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_NFIT: acpi_tables.NFIT
}
########################################################################################################
#
# RSDP
#
########################################################################################################
RSDP_GUID_ACPI2_0 = '8868E871-E4F1-11D3-BC22-0080C73C8881'
RSDP_GUID_ACPI1_0 = 'EB9D2D31-2D88-11D3-9A16-0090273FC14D'
ACPI_RSDP_SIG = 'RSD PTR '
########################################################################################################
#
# ACPI HAL Component
#
########################################################################################################
class ACPI(HALBase):
def __init__(self, cs):
super(ACPI, self).__init__(cs)
self.uefi = UEFI(self.cs)
self.tableList: Dict[str, List[int]] = defaultdict(list)
self.get_ACPI_table_list()
def read_RSDP(self, rsdp_pa: int) -> acpi_tables.RSDP:
rsdp_buf = self.cs.hals.memory.read_physical_mem(rsdp_pa, acpi_tables.ACPI_RSDP_SIZE)
rsdp = acpi_tables.RSDP()
rsdp.parse(rsdp_buf)
if rsdp.Revision >= 0x2:
rsdp_buf = self.cs.hals.memory.read_physical_mem(rsdp_pa, acpi_tables.ACPI_RSDP_EXT_SIZE)
rsdp = acpi_tables.RSDP()
rsdp.parse(rsdp_buf)
return rsdp
#
# Check RSDP in Extended BIOS Data Area
#
def _find_RSDP_in_EBDA(self) -> Tuple[Optional[acpi_tables.RSDP], Optional[int]]:
rsdp_pa = None
rsdp = None
logger().log_hal('[acpi] searching RSDP in EBDA...')
ebda_ptr_addr = 0x40E
ebda_addr = struct.unpack('<H', self.cs.hals.memory.read_physical_mem(ebda_ptr_addr, 2))[0] << 4
if ebda_addr > 0x400 and ebda_addr < 0xA0000:
membuf = self.cs.hals.memory.read_physical_mem(ebda_addr, 0xA0000 - ebda_addr)
pos = bytestostring(membuf).find(ACPI_RSDP_SIG)
if -1 != pos:
rsdp_pa = ebda_addr + pos
rsdp = self.read_RSDP(rsdp_pa)
if rsdp.is_RSDP_valid():
logger().log_hal(f'[acpi] found RSDP in EBDA at: 0x{rsdp_pa:016X}')
else:
rsdp_pa = None
return rsdp, rsdp_pa
#
# Search RSDP in legacy BIOS E/F segments (0xE0000 - 0xFFFFF)
#
def _find_RSDP_in_legacy_BIOS_segments(self) -> Tuple[Optional[acpi_tables.RSDP], Optional[int]]:
rsdp_pa = None
rsdp = None
membuf = self.cs.hals.memory.read_physical_mem(0xE0000, 0x20000)
membuf = bytestostring(membuf)
pos = bytestostring(membuf).find(ACPI_RSDP_SIG)
if -1 != pos:
rsdp_pa = 0xE0000 + pos
rsdp = self.read_RSDP(rsdp_pa)
if rsdp.is_RSDP_valid():
logger().log_hal(f'[acpi] Found RSDP in BIOS E/F segments: 0x{rsdp_pa:016X}')
else:
rsdp_pa = None
return rsdp, rsdp_pa
#
# Search for RSDP in the EFI memory (EFI Configuration Table)
#
def _find_RSDP_in_EFI_config_table(self) -> Tuple[Optional[acpi_tables.RSDP], Optional[int]]:
rsdp_pa = None
rsdp = None
logger().log_hal('[acpi] Searching RSDP pointers in EFI Configuration Table...')
(isFound, _, ect, _) = self.uefi.find_EFI_Configuration_Table()
if isFound and (ect is not None):
if RSDP_GUID_ACPI2_0 in ect.VendorTables:
rsdp_pa = ect.VendorTables[RSDP_GUID_ACPI2_0]
logger().log_hal(f'[acpi] ACPI 2.0+ RSDP {{{RSDP_GUID_ACPI2_0}}} in EFI Config Table: 0x{rsdp_pa:016X}')
elif RSDP_GUID_ACPI1_0 in ect.VendorTables:
rsdp_pa = ect.VendorTables[RSDP_GUID_ACPI1_0]
logger().log_hal('[acpi] ACPI 1.0 RSDP {{{RSDP_GUID_ACPI1_0}}} in EFI Config Table: 0x{rsdp_pa:016X}')
if rsdp_pa:
rsdp = self.read_RSDP(rsdp_pa)
if rsdp.is_RSDP_valid():
logger().log_hal(f'[acpi] Found RSDP in EFI Config Table: 0x{rsdp_pa:016X}')
else:
rsdp_pa = None
return rsdp, rsdp_pa
#
# Search for RSDP in all EFI memory
#
def _find_RSDP_in_EFI(self) -> Tuple[Optional[acpi_tables.RSDP], Optional[int]]:
rsdp_pa = None
rsdp = None
logger().log_hal("[acpi] Searching all EFI memory for RSDP (this may take a minute).")
CHUNK_SZ = 1024 * 1024 # 1MB
(smram_base, _, _) = self.cs.hals.cpu.get_SMRAM()
pa = smram_base - CHUNK_SZ
while pa > CHUNK_SZ:
membuf = self.cs.hals.memory.read_physical_mem(pa, CHUNK_SZ)
pos = bytestostring(membuf).find(ACPI_RSDP_SIG)
if -1 != pos:
rsdp_pa = pa + pos
logger().log_hal(f"[acpi] Found '{ACPI_RSDP_SIG}' signature at 0x{rsdp_pa:16X}. Checking if valid RSDP.")
rsdp = self.read_RSDP(rsdp_pa)
if rsdp.is_RSDP_valid():
logger().log_hal(f'[acpi] Found RSDP in EFI memory: 0x{rsdp_pa:016X}')
break
pa -= CHUNK_SZ
return rsdp, rsdp_pa
#
# Searches for Root System Description Pointer (RSDP) in various locations for legacy/EFI systems
#
def find_RSDP(self) -> Tuple[Optional[int], Optional[acpi_tables.RSDP]]:
rsdp, rsdp_pa = self._find_RSDP_in_EBDA()
if rsdp_pa is None:
rsdp, rsdp_pa = self._find_RSDP_in_legacy_BIOS_segments()
if rsdp_pa is None:
rsdp, rsdp_pa = self._find_RSDP_in_EFI_config_table()
if rsdp_pa is None:
rsdp, rsdp_pa = self._find_RSDP_in_EFI()
if rsdp is not None:
logger().log_hal(str(rsdp))
return (rsdp_pa, rsdp)
RsdtXsdt = Union[acpi_tables.RSDT, acpi_tables.XSDT]
#
# Retrieves System Description Table (RSDT or XSDT) either from RSDP or using OS API
#
def get_SDT(self, search_rsdp: bool = True) -> Tuple[bool, Optional[int], Optional[RsdtXsdt], Optional[ACPI_TABLE_HEADER]]:
is_xsdt = False
sdt_pa = None
sdt_header = None
sdt_buf = b''
if search_rsdp:
(_, rsdp) = self.find_RSDP()
if rsdp is not None:
if 0x0 == rsdp.Revision:
sdt_pa = rsdp.RsdtAddress
is_xsdt = False
elif 0x2 == rsdp.Revision:
sdt_pa = rsdp.XsdtAddress
is_xsdt = True
else:
return (False, None, None, None)
found_str = 'XSDT' if is_xsdt else 'RSDT'
logger().log_hal(f'[acpi] Found {found_str} at PA: 0x{sdt_pa:016X}')
sdt_header_buf = self.cs.hals.memory.read_physical_mem(sdt_pa, ACPI_TABLE_HEADER_SIZE)
sdt_header = self._parse_table_header(sdt_header_buf)
sdt_buf = self.cs.hals.memory.read_physical_mem(sdt_pa, sdt_header.Length)
else:
sdt_pa = None
if logger().HAL:
logger().log("[acpi] Reading RSDT/XSDT using OS API...")
(sdt_buf, is_xsdt) = self.get_ACPI_SDT()
sdt_header = self._parse_table_header(sdt_buf[:ACPI_TABLE_HEADER_SIZE])
sdt_contents = sdt_buf[ACPI_TABLE_HEADER_SIZE:]
sdt = ACPI_TABLES[ACPI_TABLE_SIG_XSDT if is_xsdt else ACPI_TABLE_SIG_RSDT]()
sdt.parse(sdt_contents)
return (is_xsdt, sdt_pa, sdt, sdt_header)
def get_ACPI_SDT(self) -> Tuple[Optional['Array'], bool]:
sdt = self.cs.helper.get_acpi_table('XSDT') # FirmwareTableID_XSDT
xsdt = sdt is not None
if not xsdt:
sdt = self.get_acpi_table('RSDT') # FirmwareTableID_RSDT
return sdt, xsdt
#
# Populates a list of ACPI tables available on the system
#
def get_ACPI_table_list(self) -> Dict[str, List[int]]:
try:
# 1. If didn't work, try using get_ACPI_table if a helper implemented
# reading ACPI tables via native API which some OS may provide
# raise UnimplementedAPIError("asdf")
logger().log_hal("[acpi] Trying to enumerate ACPI tables using get_ACPI_table...")
for table_name in self.cs.helper.enum_ACPI_tables():
self.tableList[table_name.decode("utf-8")].append(0)
except UnimplementedAPIError:
# 2. Try to extract ACPI table(s) from physical memory
# read_physical_mem can be implemented using both
# CHIPSEC kernel module and OS native API
logger().log_hal("[acpi] Trying to enumerate ACPI tables from physical memory...")
# find RSDT/XSDT table
(is_xsdt, sdt_pa, sdt, sdt_header) = self.get_SDT()
# cache RSDT/XSDT in the list of ACPI tables
if (sdt_pa is not None) and (sdt_header is not None):
self.tableList[bytestostring(sdt_header.Signature)].append(sdt_pa)
if sdt is not None:
self.get_table_list_from_SDT(sdt, is_xsdt)
self.get_DSDT_from_FADT()
return self.tableList
#
# Gets table list from entries in RSDT/XSDT
#
def get_table_list_from_SDT(self, sdt: RsdtXsdt, is_xsdt: bool) -> None:
logger().log_hal(f'[acpi] Getting table list from entries in {"XSDT" if is_xsdt else "RSDT"}')
for a in sdt.Entries:
_sig = self.cs.hals.memory.read_physical_mem(a, ACPI_TABLE_SIG_SIZE)
_sig = bytestostring(_sig)
if _sig not in ACPI_TABLES.keys():
if logger().HAL:
logger().log_warning(f'Unknown ACPI table signature: {_sig}')
self.tableList[_sig].append(a)
#
# Gets DSDT from FADT
#
def get_DSDT_from_FADT(self) -> None:
logger().log_hal('[acpi] Getting DSDT from FADT')
if ACPI_TABLE_SIG_FACP in self.tableList:
(_, parsed_fadt_content, _, _) = self.get_parse_ACPI_table('FACP')[0]
else:
if logger().HAL:
found_table = 'XSDT' if ACPI_TABLE_SIG_XSDT in self.tableList else 'RSDT'
logger().log_warning(f'Cannot find FADT in {found_table}')
return
dsdt_address_to_use = parsed_fadt_content.get_DSDT_address_to_use()
if dsdt_address_to_use is None:
dsdt_address = parsed_fadt_content.dsdt
x_dsdt_address = parsed_fadt_content.x_dsdt
if logger().HAL:
logger().log_error('Unable to determine the correct DSDT address')
if logger().HAL:
logger().log_error(f' DSDT address = 0x{dsdt_address:08X}')
if logger().HAL:
address_str = f'{x_dsdt_address:16X}' if x_dsdt_address is not None else 'Not found'
logger().log_error(f' X_DSDT address = 0x{address_str}')
return
self.tableList[ACPI_TABLE_SIG_DSDT].append(dsdt_address_to_use)
#
# Checks is ACPI table with <name> is available on the system
#
def is_ACPI_table_present(self, name: str) -> bool:
return (name in self.tableList)
#
# Prints a list of ACPI tables available on the system
#
def print_ACPI_table_list(self) -> None:
if len(self.tableList) == 0:
logger().log_error("Couldn't get a list of ACPI tables")
else:
logger().log_hal('[acpi] Found the following ACPI tables:')
for tableName in sorted(self.tableList.keys()):
table_values_str = ', '.join([f'0x{addr:016X}' for addr in self.tableList[tableName]])
logger().log(f' - {tableName}: {table_values_str}')
#
# Retrieves contents of ACPI table from memory or from file
#
def get_parse_ACPI_table(self, name: str, isfile: bool = False) -> List['ParseTable']:
acpi_tables = self.get_ACPI_table(name, isfile)
return [self._parse_table(name, table_header_blob, table_blob) for (table_header_blob, table_blob) in acpi_tables if table_header_blob is not None]
def get_ACPI_table(self, name: str, isfile: bool = False) -> List[Tuple[bytes, bytes]]:
acpi_tables_data: List[bytes] = []
if isfile:
acpi_tables_data.append(read_file(name))
else:
try:
# 1. Try to extract ACPI table(s) using get_ACPI_table if a helper implemented
# reading ACPI tables via native API which some OS may provide
logger().log_hal("[acpi] trying to extract ACPI table using get_ACPI_table...")
t_data = self.cs.helper.get_ACPI_table(name)
if t_data is None:
raise TypeError
acpi_tables_data.append(t_data)
except UnimplementedAPIError:
# 2. If didn't work, try scrubbing physical memory
# read_physical_mem can be implemented using both
# CHIPSEC kernel module and OS native API
logger().log_hal('[acpi] trying to extract ACPI table from physical memory...')
for table_address in self.tableList[name]:
t_size = self.cs.hals.memory.read_physical_mem_dword(table_address + 4)
t_data = self.cs.hals.memory.read_physical_mem(table_address, t_size)
acpi_tables_data.append(t_data)
acpi_tables = []
for data in acpi_tables_data:
acpi_tables.append((data[: ACPI_TABLE_HEADER_SIZE], data[ACPI_TABLE_HEADER_SIZE:]))
return acpi_tables
#
# Dumps contents of ACPI table
#
def dump_ACPI_table(self, name: str, isfile: bool = False) -> None:
acpi_tables = self.get_parse_ACPI_table(name, isfile)
for acpi_table in acpi_tables:
(table_header, table, table_header_blob, table_blob) = acpi_table
logger().log("==================================================================")
logger().log(f'ACPI Table: {name}')
logger().log("==================================================================")
# print table header
logger().log(str(table_header))
print_buffer_bytes(table_header_blob)
# print table contents
logger().log('')
logger().log(str(table))
print_buffer_bytes(table_blob)
logger().log('')
# --------------------------------------------------------------------
# Internal ACPI table parsing functions
# --------------------------------------------------------------------
ParseTable = Tuple[ACPI_TABLE_HEADER, Optional[ACPI_TABLE], bytes, bytes]
def _parse_table(self, name: str, table_header_blob: bytes, table_blob: bytes) -> ParseTable:
table_header = self._parse_table_header(table_header_blob)
table = self._parse_table_contents(name, table_blob, table_header_blob)
return (table_header, table, table_header_blob, table_blob)
def _parse_table_header(self, header: bytes) -> ACPI_TABLE_HEADER:
acpi_table_hdr = ACPI_TABLE_HEADER(*struct.unpack_from(ACPI_TABLE_HEADER_FORMAT, header))
logger().log_hal(str(acpi_table_hdr))
return acpi_table_hdr
def _parse_table_contents(self, signature: str, contents: bytes, header: bytes) -> Optional[ACPI_TABLE]:
table = None
if ACPI_TABLES.__contains__(signature):
logger().log_hal(f'{signature}')
if 'BERT' in signature:
BootRegionLen = struct.unpack('<L', contents[0:4])[0]
BootRegionAddr = struct.unpack('<Q', contents[4:12])[0]
bootRegion = self.cs.hals.memory.read_physical_mem(BootRegionAddr, BootRegionLen)
table = (ACPI_TABLES[signature])(bootRegion)
elif 'NFIT' in signature:
table = (ACPI_TABLES[signature])(header)
else:
table = (ACPI_TABLES[signature])()
table.parse(contents)
return table
# ========================================================================
# ACPI OperationRegion Analysis
# ========================================================================
def list_operation_regions(self, include_ssdt: bool = True, include_crs: bool = True) -> List[Dict]:
"""
Extract all OperationRegion definitions and optionally _CRS resource descriptors from DSDT/SSDTs.
Args:
include_ssdt: Include SSDT tables (default True)
include_crs: Include _CRS method resource descriptors (default True)
Returns:
List of dicts: [{name, space_type, space_type_name, base, length, source}, ...]
where source is "OperationRegion" or "CRS Descriptor"
"""
from chipsec.library.acpi_aml_parser import parse_operation_regions, CRSResourceParser
regions = []
tables_to_parse = []
aml_tables = [] # Keep track of AML content for CRS extraction
# Add DSDT
try:
if ACPI_TABLE_SIG_DSDT in self.tableList:
dsdt_tables = self.get_ACPI_table(ACPI_TABLE_SIG_DSDT)
if dsdt_tables:
for dsdt_header, dsdt_content in dsdt_tables:
full_table = dsdt_header + dsdt_content
tables_to_parse.append(full_table)
aml_tables.append(dsdt_content)
except Exception as e:
logger().log_warning(f"[acpi] Error reading DSDT: {e}")
# Add SSDTs if requested
if include_ssdt:
try:
if ACPI_TABLE_SIG_SSDT in self.tableList:
ssdt_tables = self.get_ACPI_table(ACPI_TABLE_SIG_SSDT)
if ssdt_tables:
for ssdt_header, ssdt_content in ssdt_tables:
full_table = ssdt_header + ssdt_content
tables_to_parse.append(full_table)
aml_tables.append(ssdt_content)
except Exception as e:
logger().log_warning(f"[acpi] Error reading SSDTs: {e}")
if not tables_to_parse:
return regions
# Parse OperationRegion definitions
regions = parse_operation_regions(tables_to_parse)
# Extract _CRS resource descriptors if enabled
if include_crs and aml_tables:
try:
for aml_content in aml_tables:
# Extract _CRS buffer from each AML table
crs_buffer = CRSResourceParser.extract_crs_buffer(aml_content)
if crs_buffer:
# Decode resource descriptors
resources = CRSResourceParser.decode_crs_buffer(crs_buffer)
for res in resources:
if 'address' in res:
# Convert CRS resource to region dict format
crs_region = {
'name': f"CRS_{res.get('type', 'Unknown')}_{res['address']:08X}",
'space_type': 0 if res.get('type', '').startswith('Memory') else 1,
'space_type_name': 'SystemMemory' if res.get('type', '').startswith('Memory') else 'SystemIO',
'base': res['address'],
'length': res['size'],
'source': 'CRS Descriptor'
}
regions.append(crs_region)
except Exception as e:
logger().log_warning(f"[acpi] Error extracting _CRS resources: {e}")
return regions
haldata = {"arch":[HALBase.MfgIds.Any], 'name': {'acpi':'ACPI'}}