mirror of
https://github.com/chipsec/chipsec
synced 2026-06-08 13:31:00 +00:00
47db665f0d
Add test for CMOS dump
235 lines
9.0 KiB
Python
235 lines
9.0 KiB
Python
import os
|
|
import struct
|
|
import tempfile
|
|
import unittest
|
|
|
|
from tests.software import mock_helper
|
|
|
|
import chipsec_util
|
|
from chipsec import logger
|
|
from chipsec import chipset
|
|
from chipsec.helper import oshelper
|
|
|
|
class TestChipsecUtil(unittest.TestCase):
|
|
"""Test the commands exposed by chipsec_utils.
|
|
|
|
Each test may define its virtual helper and then call the _chipsec_util
|
|
method with the command line arguments.
|
|
"""
|
|
|
|
def setUp(self):
|
|
"""Setup the environment for the utils tests.
|
|
|
|
We mock the helper registry to only contain our emulated helper.
|
|
"""
|
|
fileno, self.log_file = tempfile.mkstemp()
|
|
os.close(fileno)
|
|
self.old_registry = oshelper.Helper.registry
|
|
oshelper.Helper.registry = []
|
|
oshelper._helper = None
|
|
chipset._chipset = None
|
|
|
|
def tearDown(self):
|
|
os.remove(self.log_file)
|
|
oshelper._helper = None
|
|
chipset._chipset = None
|
|
chipsec_util._cs = None
|
|
oshelper.Helper.registry = self.old_registry
|
|
|
|
def _chipsec_util(self, arg, helper_class=mock_helper.TestHelper):
|
|
"""Run the chipsec_util command with the arguments.
|
|
|
|
Each test may setup a virtual helper to emulate the expected behaviour
|
|
from the hardware. If no helper is provided, TestHelper will be used.
|
|
It verifies that no error is being reported. self.log will be populated
|
|
with the output.
|
|
"""
|
|
oshelper.Helper.registry = [(helper_class.__name__, helper_class)]
|
|
chipsec_util._cs = chipset.cs()
|
|
util = chipsec_util.ChipsecUtil()
|
|
util.VERBOSE = True
|
|
util.set_logfile(self.log_file)
|
|
err_code = util.main(["chipsec_utils.py"] + arg.split())
|
|
logger.logger().close()
|
|
self.log = open(self.log_file).read()
|
|
self.assertEqual(err_code, 0)
|
|
|
|
def test_acpi_xsdt_list(self):
|
|
|
|
class ACPIHelper(mock_helper.TestHelper):
|
|
|
|
RSDP_DESCRIPTOR = ("RSD PTR " + # Signature
|
|
struct.pack("<B", 0x1) + # Checksum
|
|
"TEST00" + # OEMID
|
|
struct.pack("<B", 0x2) + # Revision
|
|
struct.pack("<I", 0x200) + # RSDT Address
|
|
struct.pack("<I", 0x0) + # Length
|
|
struct.pack("<Q", 0x100) + # XSDT Address
|
|
struct.pack("<B", 0x0) + # Extended Checksum
|
|
"AAA") # Reserved
|
|
|
|
XSDT_DESCRIPTOR = ("XSDT" + # Signature
|
|
struct.pack("<I", 0x32) + # Length
|
|
struct.pack("<B", 0x1) + # Revision
|
|
struct.pack("<B", 0x1) + # Checksum
|
|
"OEMIDT" + # OEMID
|
|
"OEMTBLID" + # OEM Table ID
|
|
"OEMR" + # OEM Revision
|
|
"CRID" + # Creator ID
|
|
"CRRV" + # Creator Revision
|
|
struct.pack("<Q", 0x400)) # Address of table
|
|
|
|
EBDA_ADDRESS = 0x96000
|
|
EBDA_PADDING = 0x100
|
|
RSDP_ADDRESS = EBDA_ADDRESS + EBDA_PADDING
|
|
|
|
def read_phys_mem(self, pa_hi, pa_lo, length):
|
|
if pa_lo == 0x40E:
|
|
return struct.pack("<H", self.EBDA_ADDRESS >> 4)
|
|
elif pa_lo >= self.EBDA_ADDRESS and \
|
|
pa_lo < self.RSDP_ADDRESS + len(self.RSDP_DESCRIPTOR):
|
|
mem = "\x00" * self.EBDA_PADDING + self.RSDP_DESCRIPTOR
|
|
offset = pa_lo - self.EBDA_ADDRESS
|
|
return mem[offset:offset+length]
|
|
elif pa_lo == 0x100:
|
|
return self.XSDT_DESCRIPTOR[:length]
|
|
elif pa_lo == 0x400:
|
|
return "EFGH"
|
|
|
|
self._chipsec_util("acpi list", ACPIHelper)
|
|
self.assertIn("EFGH: 0x0000000000000400", self.log)
|
|
|
|
def test_acpi_rsdt_list(self):
|
|
|
|
class ACPIHelper(mock_helper.TestHelper):
|
|
|
|
RSDP_DESCRIPTOR = ("RSD PTR " + # Signature
|
|
struct.pack("<B", 0x1) + # Checksum
|
|
"TEST00" + # OEMID
|
|
struct.pack("<B", 0x0) + # Revision
|
|
struct.pack("<I", 0x200)) # RSDT Address
|
|
|
|
RSDT_DESCRIPTOR = ("RSDT" + # Signature
|
|
struct.pack("<I", 0x28) + # Length
|
|
struct.pack("<B", 0x1) + # Revision
|
|
struct.pack("<B", 0x1) + # Checksum
|
|
"OEMIDT" + # OEMID
|
|
"OEMTBLID" + # OEM Table ID
|
|
"OEMR" + # OEM Revision
|
|
"CRID" + # Creator ID
|
|
"CRRV" + # Creator Revision
|
|
struct.pack("<I", 0x300)) # Address of table
|
|
|
|
def read_phys_mem(self, pa_hi, pa_lo, length):
|
|
if pa_lo == 0xE0000:
|
|
return self.RSDP_DESCRIPTOR[:length]
|
|
elif pa_lo == 0x200:
|
|
return self.RSDT_DESCRIPTOR[:length]
|
|
elif pa_lo == 0x300:
|
|
return "ABCD"
|
|
else:
|
|
return "\xFF" * length
|
|
|
|
self._chipsec_util("acpi list", ACPIHelper)
|
|
self.assertIn("ABCD: 0x0000000000000300", self.log)
|
|
|
|
def test_platform(self):
|
|
self._chipsec_util("platform")
|
|
|
|
|
|
def test_cmos_dump(self):
|
|
"""Test to verify the output of 'cmos dump'.
|
|
|
|
Check that we only access CMOS IO ports.
|
|
"""
|
|
|
|
class CMOSHelper(mock_helper.TestHelper):
|
|
def read_io_port(self, io_port, size):
|
|
if io_port < 0x70 or io_port > 0x73:
|
|
raise Exception("Reading outside CMOS IO port")
|
|
return io_port
|
|
|
|
def write_io_port(self, io_port, value, size):
|
|
if io_port < 0x70 or io_port > 0x73:
|
|
raise Exception("Writing outside CMOS IO port")
|
|
|
|
self._chipsec_util("cmos dump", CMOSHelper)
|
|
|
|
def test_msr(self):
|
|
|
|
class MSRHelper(mock_helper.TestHelper):
|
|
|
|
def get_threads_count(self):
|
|
return 1
|
|
|
|
def read_msr(self, thread_id, msr_addr):
|
|
if msr_addr == 0x2FF:
|
|
return [0x1234, 0xcdef]
|
|
else:
|
|
return [0x0, 0x0]
|
|
|
|
self._chipsec_util("msr 0x2FF", MSRHelper)
|
|
self.assertIn("EAX=00001234, EDX=0000CDEF", self.log)
|
|
|
|
def test_gdt(self):
|
|
|
|
class GDTHelper(mock_helper.TestHelper):
|
|
|
|
def get_descriptor_table(self, cpu_thread_id, desc_table_code):
|
|
return (63, 0x1000, 0x0)
|
|
|
|
def read_phys_mem(self, pa_hi, pa_lo, length):
|
|
return "\xff" * length
|
|
|
|
self._chipsec_util("gdt 0", GDTHelper)
|
|
self.assertIn("# of entries : 4", self.log)
|
|
|
|
|
|
def test_spi_info(self):
|
|
"""Test to verify the ouput of 'spi info'.
|
|
|
|
Validates that BC and FRAP are correctly read.
|
|
"""
|
|
|
|
class SPIHelper(mock_helper.TestHelper):
|
|
|
|
RCBA_ADDR = 0xFED0000
|
|
SPIBAR_ADDR = RCBA_ADDR + 0x3800
|
|
SPIBAR_END = SPIBAR_ADDR + 0x200
|
|
FRAP = SPIBAR_ADDR + 0x50
|
|
FREG0 = SPIBAR_ADDR + 0x54
|
|
LPC_BRIDGE_DEVICE = (0, 0x1F, 0)
|
|
|
|
def read_pci_reg(self, bus, device, function, address, size):
|
|
if (bus, device, function) == self.LPC_BRIDGE_DEVICE:
|
|
if address == 0xF0:
|
|
return self.RCBA_ADDR
|
|
elif address == 0xDC:
|
|
return 0xDEADBEEF
|
|
else:
|
|
raise Exception("Unexpected PCI read")
|
|
else:
|
|
return super(SPIHelper, self).read_pci_reg(bus, device,
|
|
function,
|
|
address, size)
|
|
|
|
def read_mmio_reg(self, pa, size):
|
|
if pa == self.FREG0:
|
|
return 0x11111111
|
|
elif pa == self.FREG0 + 4:
|
|
return 0x22222222
|
|
elif pa == self.FRAP:
|
|
return 0xEEEEEEEE
|
|
elif pa >= self.SPIBAR_ADDR and pa < self.SPIBAR_END:
|
|
return 0x0
|
|
else:
|
|
raise Exception("Unexpected address")
|
|
|
|
def write_mmio_reg(self, pa, size, value):
|
|
if pa < self.SPIBAR_ADDR or pa > self.SPIBAR_END:
|
|
raise Exception("Write to outside of SPIBAR")
|
|
|
|
self._chipsec_util("spi info", SPIHelper)
|
|
self.assertIn("BC = 0xDEADBEEF", self.log)
|
|
self.assertIn("FRAP = 0xEEEEEEEE", self.log)
|