Skip to content

Commit

Permalink
Update how ACPI Tables are found
Browse files Browse the repository at this point in the history
Signed-off-by: Nathaniel Mitchell <nathaniel.p.mitchell@intel.com>
  • Loading branch information
npmitche authored and dscott90 committed Apr 17, 2024
1 parent 5558244 commit ed9c6e2
Show file tree
Hide file tree
Showing 13 changed files with 91 additions and 65 deletions.
47 changes: 29 additions & 18 deletions chipsec/hal/acpi.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
__version__ = '0.1'

import struct
from typing import Dict, List, Tuple, Optional, Callable, Union
from typing import Dict, List, Tuple, Optional, Callable, Union, TYPE_CHECKING
from collections import defaultdict
from collections import namedtuple

Expand All @@ -38,6 +38,9 @@
from chipsec.library.logger import logger, print_buffer_bytes
from chipsec.hal.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
Expand Down Expand Up @@ -346,20 +349,36 @@ def get_SDT(self, search_rsdp: bool = True) -> Tuple[bool, Optional[int], Option
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_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. Try to extract ACPI table(s) from physical memory
# 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...")
Expand All @@ -372,14 +391,6 @@ def get_ACPI_table_list(self) -> Dict[str, List[int]]:
if sdt is not None:
self.get_table_list_from_SDT(sdt, is_xsdt)
self.get_DSDT_from_FADT()
except UnimplementedAPIError:
# 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
logger().log_hal("[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

Expand Down Expand Up @@ -457,20 +468,20 @@ def get_ACPI_table(self, name: str, isfile: bool = False) -> List[Tuple[bytes, b
acpi_tables_data.append(read_file(name))
else:
try:
# 1. Try to extract ACPI table(s) from physical memory
# 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)
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.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 UnimplementedAPIError:
# 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
logger().log_hal("[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:
Expand Down
2 changes: 1 addition & 1 deletion chipsec/helper/basehelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ def list_EFI_variables(self) -> Optional[Dict[str, List['EfiVariableType']]]:
# ACPI
#
@abstractmethod
def get_ACPI_SDT(self) -> Tuple[Optional['Array'], bool]:
def enum_ACPI_tables(self) -> Optional['Array']:
pass

@abstractmethod
Expand Down
12 changes: 7 additions & 5 deletions chipsec/helper/dal/dalhelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@
except:
pass
from ctypes import c_char
from typing import Tuple
from typing import Optional, Tuple, TYPE_CHECKING
if TYPE_CHECKING:
from ctypes import Array
from chipsec.helper.basehelper import Helper
from chipsec.library.exceptions import DALHelperError, UnimplementedAPIError

Expand Down Expand Up @@ -371,11 +373,11 @@ def get_affinity(self):
#
# ACPI tables access
#
def get_ACPI_SDT(self):
raise UnimplementedAPIError('get_ACPI_SDT')

def get_ACPI_table(self, table_name):
def get_ACPI_table(self, table_name: str) -> Optional['Array']:
raise UnimplementedAPIError('get_ACPI_table')

def enum_ACPI_tables(self) -> Optional['Array']:
raise UnimplementedAPIError('enum_ACPI_table')

#
# IOSF Message Bus access
Expand Down
9 changes: 5 additions & 4 deletions chipsec/helper/efi/efihelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@

from typing import Dict, List, Optional, Tuple, TYPE_CHECKING
if TYPE_CHECKING:
from ctypes import Array
from chipsec.library.types import EfiVariableType
from chipsec.library.logger import logger
from chipsec.helper.oshelper import get_tools_path
Expand Down Expand Up @@ -348,9 +349,6 @@ def list_EFI_variables(self) -> Optional[Dict[str, List['EfiVariableType']]]:
# ACPI tables access
#

def get_ACPI_SDT(self) -> Tuple[None, bool]:
raise UnimplementedAPIError('get_ACPI_SDT')

#
# IOSF Message Bus access
#
Expand All @@ -370,8 +368,11 @@ def set_affinity(self, value: int) -> None:
def free_phys_mem(self, physical_address):
raise UnimplementedAPIError('free_phys_mem')

def get_ACPI_table(self, table_name):
def get_ACPI_table(self, table_name: str) -> Optional['Array']:
raise UnimplementedAPIError('get_ACPI_table')

def enum_ACPI_tables(self) -> Optional['Array']:
raise UnimplementedAPIError('enum_ACPI_table')

def get_affinity(self):
raise UnimplementedAPIError('get_affinity')
Expand Down
9 changes: 5 additions & 4 deletions chipsec/helper/linux/linuxhelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
from typing import Dict, List, Optional, Tuple, Iterable, TYPE_CHECKING
if TYPE_CHECKING:
from chipsec.library.types import EfiVariableType
from ctypes import Array
from chipsec.library import defines
from chipsec.helper.oshelper import get_tools_path
from chipsec.library.exceptions import OsHelperError, UnimplementedAPIError
Expand Down Expand Up @@ -395,11 +396,11 @@ def write_mmio_reg(self, phys_address: int, size: int, value: int):
in_buf = struct.pack(f'3{self._pack}', phys_address, size, value)
out_buf = self.ioctl(IOCTL_WRMMIO, in_buf)

def get_ACPI_SDT(self):
raise UnimplementedAPIError("get_ACPI_SDT")

def get_ACPI_table(self, table_name):
def get_ACPI_table(self, table_name:str) -> Optional['Array']:
raise UnimplementedAPIError("get_ACPI_table")

def enum_ACPI_tables(self) -> Optional['Array']:
raise UnimplementedAPIError('enum_ACPI_table')

#
# IOSF Message Bus access
Expand Down
10 changes: 6 additions & 4 deletions chipsec/helper/linuxnative/linuxnativehelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@
import resource
import struct
import sys
from typing import Optional, Tuple
from typing import Optional, Tuple, TYPE_CHECKING
if TYPE_CHECKING:
from ctypes import Array

from chipsec.library import defines
from chipsec.library.exceptions import OsHelperError
Expand Down Expand Up @@ -389,10 +391,10 @@ def delete_EFI_variable(self, name, guid):
def list_EFI_variables(self):
raise NotImplementedError()

def get_ACPI_SDT(self):
def get_ACPI_table(self, table_name: str) -> Optional['Array']:
raise NotImplementedError()

def get_ACPI_table(self, table_name):
def enum_ACPI_tables(self) -> Optional['Array']:
raise NotImplementedError()

def cpuid(self, eax: int, ecx: int) -> Tuple[int, int, int, int]:
Expand Down
5 changes: 3 additions & 2 deletions chipsec/helper/nonehelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,12 @@ def list_EFI_variables(self) -> Optional[Dict[str, List['EfiVariableType']]]:
#
# ACPI
#
def get_ACPI_SDT(self) -> Tuple[Optional['Array'], bool]:
raise UnimplementedAPIError('NoneHelper')

def get_ACPI_table(self, table_name: str) -> Optional['Array']:
raise UnimplementedAPIError('NoneHelper')

def enum_ACPI_tables(self) -> Optional['Array']:
raise UnimplementedAPIError('NoneHelper')

#
# CPUID
Expand Down
1 change: 0 additions & 1 deletion chipsec/helper/oshelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import platform
import traceback
import sys
from ctypes import Array
from typing import Tuple, List, Dict, Optional, AnyStr, Any, TYPE_CHECKING
if TYPE_CHECKING:
from chipsec.library.types import EfiVariableType
Expand Down
13 changes: 8 additions & 5 deletions chipsec/helper/record/recordhelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@

from json import dumps, loads
import os
from typing import Any, Dict, List, Optional, Tuple
from typing import Any, Dict, List, Optional, Tuple, TYPE_CHECKING
if TYPE_CHECKING:
from ctypes import Array
from datetime import datetime

from chipsec.library.logger import logger
Expand Down Expand Up @@ -242,15 +244,16 @@ def list_EFI_variables(self) -> Optional[Dict[str, List['EfiVariableType']]]:
#
# ACPI
#
def get_ACPI_SDT(self) -> Tuple[Optional['Array'], bool]:
ret = self._subhelper.get_ACPI_SDT()
self._add_element("get_ACPI_SDT", (), ret)
return ret

def get_ACPI_table(self, table_name: str) -> Optional['Array']:
ret = self._subhelper.get_ACPI_table(table_name)
self._add_element("get_ACPI_table", (table_name), ret)
return ret

def enum_ACPI_tables(self) -> Optional['Array']:
ret = self._subhelper.enum_ACPI_table()
self._add_element("enum_ACPI_table", (), ret)
return ret

#
# CPUID
Expand Down
5 changes: 3 additions & 2 deletions chipsec/helper/replay/replayhelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,11 +182,12 @@ def list_EFI_variables(self) -> Optional[Dict[str, List['EfiVariableType']]]:
#
# ACPI
#
def get_ACPI_SDT(self) -> Tuple[Optional['Array'], bool]:
return self._get_element_eval("get_ACPI_SDT", ())

def get_ACPI_table(self, table_name: str) -> Optional['Array']:
return self._get_element_eval("get_ACPI_table", (table_name))

def enum_ACPI_tables(self) -> Optional['Array']:
return self._get_element_eval("enum_ACPI_table", ())

#
# CPUID
Expand Down
29 changes: 17 additions & 12 deletions chipsec/helper/windows/windowshelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -848,14 +848,23 @@ def cpuid(self, eax: int, ecx: int) -> Tuple[int, int, int, int]:
(eax, ebx, ecx, edx) = struct.unpack('4I', out_buf)
return (eax, ebx, ecx, edx)

def get_ACPI_SDT(self) -> Tuple[Optional[Array], bool]:
sdt = self.native_get_ACPI_table('XSDT') # FirmwareTableID_XSDT
xsdt = sdt is not None
if not xsdt:
sdt = self.native_get_ACPI_table('RSDT') # FirmwareTableID_RSDT
return sdt, xsdt

def native_get_ACPI_table(self, table_name: str) -> Optional[Array]:
def enum_ACPI_tables(self) -> Optional[Array]:
table_size = 36
tBuffer = create_string_buffer(table_size)
retVal = self.EnumSystemFirmwareTbls(FirmwareTableProviderSignature_ACPI, tBuffer, table_size)
if retVal == 0:
if logger().DEBUG:
logger().log_error(f'EnumSystemFirmwareTbls() returned error: {WinError()}')
return None
if retVal > table_size:
table_size = retVal
tBuffer = create_string_buffer(table_size)
retVal = self.EnumSystemFirmwareTbls(FirmwareTableProviderSignature_ACPI, tBuffer, table_size)
tables_array = [tBuffer[i:i+4] for i in range(0, retVal, 4)]
return tables_array

# ACPI access is implemented through ACPI HAL rather than through kernel module
def get_ACPI_table(self, table_name: str) -> Optional[Array]:
table_size = 36
tBuffer = create_string_buffer(table_size)
tbl = struct.unpack("<I", bytes(table_name, 'ascii'))[0]
Expand All @@ -870,10 +879,6 @@ def native_get_ACPI_table(self, table_name: str) -> Optional[Array]:
retVal = self.GetSystemFirmwareTbl(FirmwareTableProviderSignature_ACPI, tbl, tBuffer, table_size)
return tBuffer[:retVal]

# ACPI access is implemented through ACPI HAL rather than through kernel module
def get_ACPI_table(self, table_name):
raise UnimplementedAPIError("get_ACPI_table")

#
# IOSF Message Bus access
#
Expand Down
3 changes: 0 additions & 3 deletions tests/helpers/test_linuxhelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,9 +246,6 @@ def test_read_mmio_reg(self, _, lh_ioctl):
def test_write_mmio_reg(self, _, lh_ioctl):
lh_ioctl.side_effect = LinuxHelperTest.ioctlret
self.lhelper.write_mmio_reg(0x123,0x1, 0x22)

def test_get_ACPI_SDT(self, _, lh_ioctl):
self.assertRaises(UnimplementedAPIError, self.lhelper.get_ACPI_SDT)

def test_get_ACPI_table(self, _, lh_ioctl):
self.assertRaises(UnimplementedAPIError, self.lhelper.get_ACPI_table, "SDEV")
Expand Down
11 changes: 7 additions & 4 deletions tests/software/mock_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@

from chipsec.helper.basehelper import Helper
from chipsec.library.exceptions import UnimplementedAPIError
from typing import Optional, TYPE_CHECKING
if TYPE_CHECKING:
from ctypes import Array


class TestHelper(Helper):
Expand Down Expand Up @@ -146,11 +149,11 @@ def delete_EFI_variable(self, name, guid):
def list_EFI_variables(self):
raise UnimplementedAPIError('list_EFI_variables')

def get_ACPI_SDT(self):
raise UnimplementedAPIError('get_ACPI_SDT')

def get_ACPI_table(self, table_name):
def get_ACPI_table(self, table_name: str) -> Optional['Array']:
raise UnimplementedAPIError('get_ACPI_table')

def enum_ACPI_tables(self) -> Optional['Array']:
raise UnimplementedAPIError('enum_ACPI_table')

def msgbus_send_read_message(self, mcr, mcrx):
raise UnimplementedAPIError('msgbus_send_read_message')
Expand Down

0 comments on commit ed9c6e2

Please sign in to comment.