mirror of
https://github.com/chipsec/chipsec
synced 2026-06-08 13:31:00 +00:00
ea7d64da75
Like in line 275 we need to convert to string before finding. In Python3 bytes and strings are not the same and thus it would break.
562 lines
22 KiB
Python
562 lines
22 KiB
Python
#!/usr/bin/python
|
|
#CHIPSEC: Platform Security Assessment Framework
|
|
#Copyright (c) 2010-2019, 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
|
|
#
|
|
|
|
|
|
|
|
|
|
# -------------------------------------------------------------------------------
|
|
#
|
|
# CHIPSEC: Platform Hardware Security Assessment Framework
|
|
# (c) 2010-2018 Intel Corporation
|
|
#
|
|
# -------------------------------------------------------------------------------
|
|
|
|
"""
|
|
HAL component providing access to and decoding of ACPI tables
|
|
"""
|
|
|
|
__version__ = '0.1'
|
|
|
|
import struct
|
|
import sys
|
|
|
|
from collections import defaultdict
|
|
from collections import namedtuple
|
|
|
|
from chipsec.logger import *
|
|
from chipsec.file import *
|
|
from chipsec.defines import bytestostring
|
|
|
|
from chipsec.hal import acpi_tables, hal_base, uefi
|
|
from chipsec.helper import oshelper
|
|
|
|
class AcpiRuntimeError (RuntimeError):
|
|
pass
|
|
|
|
# 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):
|
|
return """ Table Header
|
|
------------------------------------------------------------------
|
|
Signature : {}
|
|
Length : 0x{:08X}
|
|
Revision : 0x{:02X}
|
|
Checksum : 0x{:02X}
|
|
OEM ID : {}
|
|
OEM Table ID : {}
|
|
OEM Revision : 0x{:08X}
|
|
Creator ID : {}
|
|
Creator Revision : 0x{:08X}
|
|
""".format( self.Signature, self.Length, self.Revision, self.Checksum, self.OEMID, self.OEMTableID, self.OEMRevision, self.CreatorID, self.CreatorRevision )
|
|
|
|
|
|
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_SPMI = 'SPMI'
|
|
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 = {
|
|
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_SPMI: 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.ACPI_TABLE,
|
|
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 '
|
|
# RSDP Format
|
|
ACPI_RSDP_FORMAT = '<8sB6sBI'
|
|
ACPI_RSDP_EXT_FORMAT = 'IQB3s'
|
|
ACPI_RSDP_SIZE = struct.calcsize(ACPI_RSDP_FORMAT)
|
|
ACPI_RSDP_EXT_SIZE = struct.calcsize(ACPI_RSDP_FORMAT + ACPI_RSDP_EXT_FORMAT)
|
|
assert ACPI_RSDP_EXT_SIZE == 36
|
|
|
|
class RSDP():
|
|
def __init__( self, table_content ):
|
|
if len(table_content) == ACPI_RSDP_SIZE:
|
|
(self.Signature, self.Checksum, self.OEMID,
|
|
self.Revision, self.RsdtAddress) = struct.unpack(ACPI_RSDP_FORMAT, table_content)
|
|
else:
|
|
(self.Signature, self.Checksum, self.OEMID,
|
|
self.Revision, self.RsdtAddress, self.Length,
|
|
self.XsdtAddress, self.ExtChecksum, self.Reserved) = struct.unpack(ACPI_RSDP_FORMAT + ACPI_RSDP_EXT_FORMAT, table_content)
|
|
def __str__( self ):
|
|
default = ("==================================================================\n"
|
|
" Root System Description Pointer (RSDP)\n"
|
|
"==================================================================\n"
|
|
" Signature : {}\n"
|
|
" Checksum : 0x{:02X}\n"
|
|
" OEM ID : {}\n"
|
|
" Revision : 0x{:02X}\n"
|
|
" RSDT Address : 0x{:08X}\n"
|
|
).format(self.Signature, self.Checksum, self.OEMID, self.Revision, self.RsdtAddress)
|
|
if hasattr(self, "Length"):
|
|
default += (" Length : 0x{:08X}\n"
|
|
" XSDT Address : 0x{:016X}\n"
|
|
" Extended Checksum: 0x{:02X}\n"
|
|
" Reserved : {}\n"
|
|
).format(self.Length, self.XsdtAddress, self.ExtChecksum, self.Reserved.encode("hex") if ( isinstance(self.Reserved,str) ) else self.Reserved.hex() )
|
|
return default
|
|
|
|
# some sanity checking on RSDP
|
|
def is_RSDP_valid(self ):
|
|
return (0 != self.Checksum and (0x0 == self.Revision or 0x2 == self.Revision) )
|
|
|
|
|
|
########################################################################################################
|
|
#
|
|
# ACPI HAL Component
|
|
#
|
|
########################################################################################################
|
|
|
|
class ACPI(hal_base.HALBase):
|
|
def __init__(self, cs):
|
|
super(ACPI, self).__init__(cs)
|
|
self.uefi = uefi.UEFI(self.cs)
|
|
self.tableList = defaultdict(list)
|
|
self.get_ACPI_table_list()
|
|
|
|
def read_RSDP(self, rsdp_pa):
|
|
rsdp_buf = self.cs.mem.read_physical_mem( rsdp_pa, ACPI_RSDP_SIZE)
|
|
rsdp = RSDP(rsdp_buf)
|
|
if rsdp.Revision >= 0x2:
|
|
rsdp_buf = self.cs.mem.read_physical_mem( rsdp_pa, ACPI_RSDP_EXT_SIZE)
|
|
rsdp = RSDP(rsdp_buf)
|
|
return rsdp
|
|
|
|
#
|
|
# Check RSDP in Extended BIOS Data Area
|
|
#
|
|
def _find_RSDP_in_EBDA(self):
|
|
rsdp_pa = None
|
|
rsdp = None
|
|
if logger().HAL: logger().log( "[acpi] searching RSDP in EBDA.." )
|
|
ebda_ptr_addr = 0x40E
|
|
ebda_addr = struct.unpack('<H', self.cs.mem.read_physical_mem( ebda_ptr_addr, 2 ))[0] << 4
|
|
if ebda_addr > 0x400 and ebda_addr < 0xA0000:
|
|
membuf = self.cs.mem.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():
|
|
if logger().HAL: logger().log( "[acpi] found RSDP in EBDA at: 0x{:016X}".format(rsdp_pa) )
|
|
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):
|
|
rsdp_pa = None
|
|
rsdp = None
|
|
membuf = self.cs.mem.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():
|
|
if logger().HAL: logger().log( "[acpi] found RSDP in BIOS E/F segments: 0x{:016X}".format(rsdp_pa) )
|
|
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):
|
|
rsdp_pa = None
|
|
rsdp = None
|
|
if logger().HAL: logger().log( '[acpi] searching RSDP pointers in EFI Configuration Table..' )
|
|
(isFound,ect_pa,ect,ect_buf) = self.uefi.find_EFI_Configuration_Table()
|
|
if isFound:
|
|
if RSDP_GUID_ACPI2_0 in ect.VendorTables:
|
|
rsdp_pa = ect.VendorTables[ RSDP_GUID_ACPI2_0 ]
|
|
if logger().HAL: logger().log( '[acpi] ACPI 2.0+ RSDP {{{}}} in EFI Config Table: 0x{:016X}'.format(RSDP_GUID_ACPI2_0,rsdp_pa) )
|
|
elif RSDP_GUID_ACPI1_0 in ect.VendorTables:
|
|
rsdp_pa = ect.VendorTables[ RSDP_GUID_ACPI1_0 ]
|
|
if logger().HAL: logger().log( '[acpi] ACPI 1.0 RSDP {{{}}} in EFI Config Table: 0x{:016X}'.format(RSDP_GUID_ACPI1_0,rsdp_pa) )
|
|
|
|
rsdp = self.read_RSDP(rsdp_pa)
|
|
if rsdp.is_RSDP_valid():
|
|
if logger().HAL: logger().log( "[acpi] found RSDP in EFI Config Table: 0x{:016X}".format(rsdp_pa) )
|
|
else:
|
|
rsdp_pa = None
|
|
return rsdp, rsdp_pa
|
|
|
|
#
|
|
# Search for RSDP in all EFI memory
|
|
#
|
|
def _find_RSDP_in_EFI(self):
|
|
rsdp_pa = None
|
|
rsdp = None
|
|
if logger().HAL: logger().log( "[acpi] searching all EFI memory for RSDP (this may take a minute).." )
|
|
CHUNK_SZ = 1024*1024 # 1MB
|
|
(smram_base, smram_limit, smram_size) = self.cs.cpu.get_SMRAM()
|
|
pa = smram_base - CHUNK_SZ
|
|
while pa > CHUNK_SZ:
|
|
membuf = self.cs.mem.read_physical_mem( pa, CHUNK_SZ )
|
|
pos = bytestostring(membuf).find( ACPI_RSDP_SIG )
|
|
if -1 != pos:
|
|
rsdp_pa = pa + pos
|
|
if logger().HAL: logger().log( "[acpi] found '{}' signature at 0x{:16X}. Checking if valid RSDP..".format(ACPI_RSDP_SIG,rsdp_pa) )
|
|
rsdp = self.read_RSDP(rsdp_pa)
|
|
if rsdp.is_RSDP_valid():
|
|
if logger().HAL: logger().log( "[acpi] found RSDP in EFI memory: 0x{:016X}".format(rsdp_pa) )
|
|
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 ):
|
|
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_pa is not None:
|
|
if logger().HAL: logger().log( rsdp )
|
|
|
|
return (rsdp_pa, rsdp)
|
|
|
|
#
|
|
# Retrieves System Description Table (RSDT or XSDT) either from RSDP or using OS API
|
|
#
|
|
def get_SDT( self, search_rsdp=True ):
|
|
if search_rsdp:
|
|
(rsdp_pa, rsdp) = self.find_RSDP()
|
|
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)
|
|
if logger().HAL: logger().log( "[acpi] found {} at PA: 0x{:016X}".format('XSDT' if is_xsdt else 'RSDT', sdt_pa) )
|
|
sdt_header_buf = self.cs.mem.read_physical_mem( sdt_pa, ACPI_TABLE_HEADER_SIZE )
|
|
sdt_header = self._parse_table_header( sdt_header_buf )
|
|
sdt_buf = self.cs.mem.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.cs.helper.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)
|
|
|
|
|
|
#
|
|
# Populates a list of ACPI tables available on the system
|
|
#
|
|
def get_ACPI_table_list( self ):
|
|
try:
|
|
# 1. Try to extract ACPI table(s) from physical memory
|
|
# read_physical_mem can be implemented using both
|
|
# CHIPSEC kernel module and OS native API
|
|
if logger().HAL: logger().log( "[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: self.tableList[ bytestostring(sdt_header.Signature) ].append(sdt_pa)
|
|
|
|
self.get_table_list_from_SDT(sdt, is_xsdt)
|
|
self.get_DSDT_from_FADT()
|
|
except oshelper.UnimplementedNativeAPIError:
|
|
# 2. If didn't work, try using get_ACPI_table if a helper implemented
|
|
# reading ACPI tables via native API which some OS may provide
|
|
if self.cs.use_native_api():
|
|
if logger().HAL: logger().log( "[acpi] trying to enumerate ACPI tables using get_ACPI_table..." )
|
|
for t in ACPI_TABLES.keys():
|
|
table = self.cs.helper.get_ACPI_table( t )
|
|
if table: self.tableList[ t ].append( 0 )
|
|
|
|
return self.tableList
|
|
|
|
#
|
|
# Gets table list from entries in RSDT/XSDT
|
|
#
|
|
def get_table_list_from_SDT(self, sdt, is_xsdt):
|
|
if logger().HAL: logger().log( '[acpi] Getting table list from entries in {}'.format('XSDT' if is_xsdt else 'RSDT') )
|
|
for a in sdt.Entries:
|
|
_sig = self.cs.mem.read_physical_mem( a, ACPI_TABLE_SIG_SIZE )
|
|
_sig = bytestostring(_sig)
|
|
if _sig not in ACPI_TABLES.keys():
|
|
if logger().HAL: logger().warn( 'Unknown ACPI table signature: {}'.format(_sig) )
|
|
self.tableList[ _sig ].append(a)
|
|
|
|
#
|
|
# Gets DSDT from FADT
|
|
#
|
|
def get_DSDT_from_FADT(self):
|
|
if logger().HAL: logger().log( '[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: logger().warn( 'Cannot find FADT in {}'.format('XSDT' if ACPI_TABLE_SIG_XSDT in self.tableList else 'RSDT') )
|
|
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().error( 'Unable to determine the correct DSDT address' )
|
|
if logger().HAL: logger().error( ' DSDT address = 0x{:08X}'.format(dsdt_address) )
|
|
if logger().HAL: logger().error( ' X_DSDT address = 0x{}'.format("{:16X}".format(x_dsdt_address)) if x_dsdt_address is not None else 'Not found')
|
|
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 ):
|
|
return (name in self.tableList)
|
|
|
|
#
|
|
# Prints a list of ACPI tables available on the system
|
|
#
|
|
def print_ACPI_table_list(self):
|
|
if len( self.tableList ) == 0:
|
|
logger().error("Couldn't get a list of ACPI tables")
|
|
else:
|
|
if logger().HAL: logger().log( "[acpi] Found the following ACPI tables:" )
|
|
for tableName in sorted(self.tableList.keys()):
|
|
logger().log( " - {}: {}".format(tableName, ", ".join([("0x{:016X}".format(addr) ) for addr in self.tableList[tableName]])) )
|
|
|
|
#
|
|
# Retrieves contents of ACPI table from memory or from file
|
|
#
|
|
def get_parse_ACPI_table( self, name, isfile = False ):
|
|
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, isfile = False ):
|
|
acpi_tables_data = []
|
|
if isfile:
|
|
acpi_tables_data.append(read_file( name ))
|
|
else:
|
|
try:
|
|
# 1. Try to extract ACPI table(s) from physical memory
|
|
# read_physical_mem can be implemented using both
|
|
# CHIPSEC kernel module and OS native API
|
|
if logger().HAL: logger().log( "[acpi] trying to extract ACPI table from physical memory..." )
|
|
for table_address in self.tableList[name]:
|
|
t_size = self.cs.mem.read_physical_mem_dword( table_address + 4 )
|
|
t_data = self.cs.mem.read_physical_mem( table_address, t_size )
|
|
acpi_tables_data.append( t_data )
|
|
except oshelper.UnimplementedNativeAPIError:
|
|
# 2. If didn't work, try using get_ACPI_table if a helper implemented
|
|
# reading ACPI tables via native API which some OS may provide
|
|
if self.cs.use_native_api():
|
|
if logger().HAL: logger().log( "[acpi] trying to extract ACPI table using get_ACPI_table..." )
|
|
t_data = self.cs.helper.get_ACPI_table( name )
|
|
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, isfile = False ):
|
|
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( "ACPI Table: {}".format(name) )
|
|
logger().log( "==================================================================" )
|
|
# print table header
|
|
logger().log( table_header )
|
|
print_buffer( bytestostring(table_header_blob) )
|
|
# print table contents
|
|
logger().log( '' )
|
|
logger().log( table )
|
|
print_buffer( bytestostring(table_blob) )
|
|
logger().log( '' )
|
|
|
|
# --------------------------------------------------------------------
|
|
# Internal ACPI table parsing functions
|
|
# --------------------------------------------------------------------
|
|
|
|
def _parse_table( self, name, table_header_blob, table_blob ):
|
|
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 ):
|
|
acpi_table_hdr = ACPI_TABLE_HEADER( *struct.unpack_from( ACPI_TABLE_HEADER_FORMAT, header ) )
|
|
if logger().HAL: logger().log( acpi_table_hdr )
|
|
return acpi_table_hdr
|
|
|
|
|
|
def _parse_table_contents( self, signature, contents, header ):
|
|
table = None
|
|
if ACPI_TABLES.__contains__(signature):
|
|
if logger().HAL: logger().log('{}'.format(signature))
|
|
if 'BERT' in signature:
|
|
table = (ACPI_TABLES[signature])(self.cs)
|
|
elif 'NFIT' in signature:
|
|
table = (ACPI_TABLES[signature])(header)
|
|
else:
|
|
table = (ACPI_TABLES[signature])()
|
|
table.parse( contents )
|
|
return table
|