# 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 # """ >>> chipsec_util mmio list >>> chipsec_util mmio dump [offset] [length] >>> chipsec_util mmio dump-abs [offset] [length] >>> chipsec_util mmio read >>> chipsec_util mmio read-abs >>> chipsec_util mmio write >>> chipsec_util mmio write-abs Examples: >>> chipsec_util mmio list >>> chipsec_util mmio dump MCHBAR >>> chipsec_util mmio dump-abs 0xFE010000 0x70 0x10 >>> chipsec_util mmio read SPIBAR 0x74 0x4 >>> chipsec_util mmio read-abs 0xFE010000 0x74 0x04 >>> chipsec_util mmio write SPIBAR 0x74 0x4 0xFFFF0000 >>> chipsec_util mmio write-abs 0xFE010000 0x74 0x04 0xFFFF0000 """ from chipsec.command import BaseCommand, toLoad from chipsec.hal.common import mmio from argparse import ArgumentParser # ################################################################### # # Access to Memory Mapped PCIe Configuration Space (MMCFG) # # ################################################################### class MMIOCommand(BaseCommand): def requirements(self) -> toLoad: return toLoad.All def parse_arguments(self) -> None: parser = ArgumentParser(prog='chipsec_util mmio', usage=__doc__) subparsers = parser.add_subparsers() parser_list = subparsers.add_parser('list') parser_list.set_defaults(func=self.list_bars) parser_dump = subparsers.add_parser('dump') parser_dump.add_argument('bar_name', type=str, help='MMIO BAR to dump') parser_dump.add_argument('offset', type=lambda x: int(x, 16), nargs='?', default=0, help='Offset in BAR to start dump') parser_dump.add_argument('length', type=lambda x: int(x, 16), nargs='?', default=None, help='Length of the region to dump') parser_dump.set_defaults(func=self.dump_bar) parser_dump_abs = subparsers.add_parser('dump-abs') parser_dump_abs.add_argument('base', type=lambda x: int(x, 16), help='MMIO region base address') parser_dump_abs.add_argument('offset', type=lambda x: int(x, 16), nargs='?', default=0, help='Offset in BAR to start dump') parser_dump_abs.add_argument('length', type=lambda x: int(x, 16), nargs='?', default=None, help='Length of the region to dump') parser_dump_abs.set_defaults(func=self.dump_bar_abs) parser_read = subparsers.add_parser('read') parser_read.add_argument('bar_name', type=str, help='MMIO BAR to read') parser_read.add_argument('offset', type=lambda x: int(x, 16), help='Offset value (hex)') parser_read.add_argument('width', type=lambda x: int(x, 16), choices=[1, 2, 4, 8], help='Width value [1, 2, 4, 8] (hex)') parser_read.add_argument('bus', type=lambda x: int(x, 16), nargs='?', default=None, help='bus value') parser_read.set_defaults(func=self.read_bar) parser_read_abs = subparsers.add_parser('read-abs') parser_read_abs.add_argument('base', type=lambda x: int(x, 16), help='MMIO region base address') parser_read_abs.add_argument('offset', type=lambda x: int(x, 16), help='MMIO register offset') parser_read_abs.add_argument('width', type=lambda x: int(x, 16), choices=[1, 2, 4, 8], help='Data width to read') parser_read_abs.set_defaults(func=self.read_abs) parser_write = subparsers.add_parser('write') parser_write.add_argument('bar_name', type=str, help='MMIO BAR to write') parser_write.add_argument('offset', type=lambda x: int(x, 16), help='Offset value (hex)') parser_write.add_argument('width', type=lambda x: int(x, 16), choices=[1, 2, 4, 8], help='Width value [1, 2, 4, 8] (hex)') parser_write.add_argument('value', type=lambda x: int(x, 16), help='Value to write (hex)') parser_write.add_argument('bus', type=lambda x: int(x, 16), nargs='?', default=None, help='bus value') parser_write.set_defaults(func=self.write_bar) parser_write_abs = subparsers.add_parser('write-abs') parser_write_abs.add_argument('base', type=lambda x: int(x, 16), help='MMIO region base address') parser_write_abs.add_argument('offset', type=lambda x: int(x, 16), help='MMIO register offset') parser_write_abs.add_argument('width', type=lambda x: int(x, 16), choices=[1, 2, 4, 8], help='Data width to read') parser_write_abs.add_argument('value', type=lambda x: int(x, 16), help='Value to write (hex)') parser_write_abs.set_defaults(func=self.write_abs) parser.parse_args(self.argv, namespace=self) def set_up(self) -> None: self._mmio = mmio.MMIO(self.cs) def list_bars(self): self._mmio.list_MMIO_BARs() def dump_bar(self): self.logger.log("[CHIPSEC] Dumping {} MMIO space..".format(self.bar_name.upper())) (bar_base, bar_size) = self._mmio.get_MMIO_BAR_base_address(self.bar_name.upper()) if self.length is not None: bar_size = self.length else: bar_size -= self.offset bar_base += self.offset self._mmio.dump_MMIO(bar_base, bar_size) def dump_bar_abs(self): tmp_base = self.base + self.offset if self.length is None: tmp_length = 0x1000 else: tmp_length = self.length self.logger.log("[CHIPSEC] Dumping MMIO space 0x{:08X} to 0x{:08X}".format(tmp_base, tmp_base + tmp_length)) self._mmio.dump_MMIO(tmp_base, tmp_length) def read_bar(self): bar = self.bar_name.upper() reg = self._mmio.read_MMIO_BAR_reg(bar, self.offset, self.width, self.bus) self.logger.log("[CHIPSEC] Read {} + 0x{:X}: 0x{:08X}".format(bar, self.offset, reg)) def read_abs(self): if self.width == 1: reg = self._mmio.read_MMIO_reg_byte(self.base, self.offset) elif self.width == 2: reg = self._mmio.read_MMIO_reg_word(self.base, self.offset) elif self.width == 4: reg = self._mmio.read_MMIO_reg_dword(self.base, self.offset) elif self.width == 8: reg = self._mmio.read_MMIO_reg_dword(self.base, self.offset) reg |= self._mmio.read_MMIO_reg_dword(self.base, self.offset + 4) << 32 self.logger.log("[CHIPSEC] Read 0x{:X} + 0x{:X}: 0x{:08X}".format(self.base, self.offset, reg)) def write_bar(self): bar = self.bar_name.upper() self.logger.log("[CHIPSEC] Write {} + 0x{:X}: 0x{:08X}".format(bar, self.offset, self.value)) self._mmio.write_MMIO_BAR_reg(bar, self.offset, self.value, self.width, self.bus) def write_abs(self): self.logger.log("[CHIPSEC] Write 0x{:X} + 0x{:X}: 0x{:08X}".format(self.base, self.offset, self.value)) if self.width == 1: self._mmio.write_MMIO_reg_byte(self.base, self.offset, self.value & 0xFF) elif self.width == 2: self._mmio.write_MMIO_reg_word(self.base, self.offset, self.value & 0xFFFF) elif self.width == 4: self._mmio.write_MMIO_reg_dword(self.base, self.offset, self.value & 0xFFFFFFFF) elif self.width == 8: self._mmio.write_MMIO_reg_dword(self.base, self.offset, self.value & 0xFFFFFFFF) self._mmio.write_MMIO_reg_dword(self.base, self.offset + 4, (self.value >> 32) & 0xFFFFFFFF) commands = {'mmio': MMIOCommand}