| /* |
| * inteltool - dump all registers on an Intel CPU + chipset based system. |
| * |
| * Copyright (C) 2017 secunet Security Networks AG |
| * |
| * 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 of the License. |
| * |
| * 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. |
| */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <stdint.h> |
| #include <stdbool.h> |
| #include <inttypes.h> |
| #include <assert.h> |
| #include "pcr.h" |
| |
| const uint8_t *sbbar = NULL; |
| |
| uint32_t read_pcr32(const uint8_t port, const uint16_t offset) |
| { |
| assert(sbbar); |
| return *(const uint32_t *)(sbbar + (port << 16) + offset); |
| } |
| |
| static void print_pcr_port(const uint8_t port) |
| { |
| size_t i = 0; |
| uint32_t last_reg = 0; |
| bool last_printed = true; |
| |
| printf("PCR port offset: 0x%06zx\n\n", (size_t)port << 16); |
| |
| for (i = 0; i < PCR_PORT_SIZE; i += 4) { |
| const uint32_t reg = read_pcr32(port, i); |
| const bool rep = i && last_reg == reg; |
| if (!rep) { |
| if (!last_printed) |
| printf("*\n"); |
| printf("0x%04zx: 0x%08"PRIx32"\n", i, reg); |
| } |
| |
| last_reg = reg; |
| last_printed = !rep; |
| } |
| if (!last_printed) |
| printf("*\n"); |
| } |
| |
| void print_pcr_ports(struct pci_dev *const sb, |
| const uint8_t *const ports, const size_t count) |
| { |
| size_t i; |
| |
| pcr_init(sb); |
| |
| for (i = 0; i < count; ++i) { |
| printf("\n========== PCR 0x%02x ==========\n\n", ports[i]); |
| print_pcr_port(ports[i]); |
| } |
| } |
| |
| void pcr_init(struct pci_dev *const sb) |
| { |
| bool error_exit = false; |
| bool p2sb_revealed = false; |
| struct pci_dev *p2sb; |
| bool use_p2sb = true; |
| pciaddr_t sbbar_phys; |
| |
| if (sbbar) |
| return; |
| |
| switch (sb->device_id) { |
| case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_PRE: |
| case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_PRE: |
| case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_U_BASE_SKL: |
| case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_Y_PREM_SKL: |
| case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_U_PREM_SKL: |
| case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_U_BASE_KBL: |
| case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_U_PREM_KBL: |
| case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_Y_PREM_KBL: |
| case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_U_IHDCP_BASE: |
| case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_U_IHDCP_PREM: |
| case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_Y_IHDCP_PREM: |
| case PCI_DEVICE_ID_INTEL_H110: |
| case PCI_DEVICE_ID_INTEL_H170: |
| case PCI_DEVICE_ID_INTEL_Z170: |
| case PCI_DEVICE_ID_INTEL_Q170: |
| case PCI_DEVICE_ID_INTEL_Q150: |
| case PCI_DEVICE_ID_INTEL_B150: |
| case PCI_DEVICE_ID_INTEL_C236: |
| case PCI_DEVICE_ID_INTEL_C232: |
| case PCI_DEVICE_ID_INTEL_QM170: |
| case PCI_DEVICE_ID_INTEL_HM170: |
| case PCI_DEVICE_ID_INTEL_CM236: |
| case PCI_DEVICE_ID_INTEL_HM175: |
| case PCI_DEVICE_ID_INTEL_QM175: |
| case PCI_DEVICE_ID_INTEL_CM238: |
| case PCI_DEVICE_ID_INTEL_C621: |
| case PCI_DEVICE_ID_INTEL_C622: |
| case PCI_DEVICE_ID_INTEL_C624: |
| case PCI_DEVICE_ID_INTEL_C625: |
| case PCI_DEVICE_ID_INTEL_C626: |
| case PCI_DEVICE_ID_INTEL_C627: |
| case PCI_DEVICE_ID_INTEL_C628: |
| case PCI_DEVICE_ID_INTEL_C629: |
| case PCI_DEVICE_ID_INTEL_C624_SUPER: |
| case PCI_DEVICE_ID_INTEL_C627_SUPER_1: |
| case PCI_DEVICE_ID_INTEL_C621_SUPER: |
| case PCI_DEVICE_ID_INTEL_C627_SUPER_2: |
| case PCI_DEVICE_ID_INTEL_C628_SUPER: |
| case PCI_DEVICE_ID_INTEL_DNV_LPC: |
| p2sb = pci_get_dev(sb->access, 0, 0, 0x1f, 1); |
| break; |
| case PCI_DEVICE_ID_INTEL_APL_LPC: |
| p2sb = pci_get_dev(sb->access, 0, 0, 0x0d, 0); |
| break; |
| case PCI_DEVICE_ID_INTEL_H310: |
| case PCI_DEVICE_ID_INTEL_H370: |
| case PCI_DEVICE_ID_INTEL_Z390: |
| case PCI_DEVICE_ID_INTEL_Q370: |
| case PCI_DEVICE_ID_INTEL_B360: |
| case PCI_DEVICE_ID_INTEL_C246: |
| case PCI_DEVICE_ID_INTEL_C242: |
| case PCI_DEVICE_ID_INTEL_QM370: |
| case PCI_DEVICE_ID_INTEL_HM370: |
| case PCI_DEVICE_ID_INTEL_CM246: |
| case PCI_DEVICE_ID_INTEL_CANNONPOINT_LP_U_PREM: |
| case PCI_DEVICE_ID_INTEL_ICELAKE_LP_U: |
| sbbar_phys = 0xfd000000; |
| use_p2sb = false; |
| break; |
| default: |
| perror("Unknown LPC device."); |
| exit(1); |
| } |
| |
| if (use_p2sb) { |
| if (!p2sb) { |
| perror("Can't allocate device node for P2SB."); |
| exit(1); |
| } |
| |
| /* do not fill bases here, libpci refuses to refill later */ |
| pci_fill_info(p2sb, PCI_FILL_IDENT); |
| if (p2sb->vendor_id == 0xffff && p2sb->device_id == 0xffff) { |
| printf("Trying to reveal Primary to Sideband Bridge " |
| "(P2SB),\nlet's hope the OS doesn't mind... "); |
| /* Do not use pci_write_long(). Bytes |
| surrounding 0xe0 must be maintained. */ |
| pci_write_byte(p2sb, 0xe0 + 1, 0); |
| |
| pci_fill_info(p2sb, PCI_FILL_IDENT | PCI_FILL_RESCAN); |
| if (p2sb->vendor_id != 0xffff || |
| p2sb->device_id != 0xffff) { |
| printf("done.\n"); |
| p2sb_revealed = true; |
| } else { |
| printf("failed.\n"); |
| exit(1); |
| } |
| } |
| pci_fill_info(p2sb, PCI_FILL_BASES | PCI_FILL_CLASS); |
| |
| sbbar_phys = p2sb->base_addr[0] & ~0xfULL; |
| } |
| |
| printf("SBREG_BAR = 0x%08"PRIx64" (MEM)\n\n", (uint64_t)sbbar_phys); |
| sbbar = map_physical(sbbar_phys, SBBAR_SIZE); |
| if (sbbar == NULL) { |
| perror("Error mapping SBREG_BAR"); |
| error_exit = true; |
| } |
| |
| if (use_p2sb) { |
| if (p2sb_revealed) { |
| printf("Hiding Primary to Sideband Bridge (P2SB).\n"); |
| pci_write_byte(p2sb, 0xe0 + 1, 1); |
| } |
| pci_free_dev(p2sb); |
| } |
| |
| if (error_exit) |
| exit(1); |
| } |
| |
| void pcr_cleanup(void) |
| { |
| if (sbbar) |
| unmap_physical((void *)sbbar, SBBAR_SIZE); |
| } |