Arthur Heymans | 279c3e1 | 2020-12-02 13:28:53 +0100 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
| 2 | |
| 3 | #define __SIMPLE_DEVICE__ |
| 4 | |
Angel Pons | cba669c | 2021-01-28 11:56:45 +0100 | [diff] [blame] | 5 | #include <assert.h> |
Arthur Heymans | 279c3e1 | 2020-12-02 13:28:53 +0100 | [diff] [blame] | 6 | #include <console/console.h> |
| 7 | #include <cpu/x86/smm.h> |
| 8 | #include <device/pci_ops.h> |
| 9 | #include <mainboard/emulation/qemu-i440fx/memory.h> |
| 10 | #include <mainboard/emulation/qemu-i440fx/fw_cfg.h> |
Arthur Heymans | e69d2df | 2020-12-01 18:29:13 +0100 | [diff] [blame] | 11 | #include <cpu/intel/smm_reloc.h> |
Arthur Heymans | 279c3e1 | 2020-12-02 13:28:53 +0100 | [diff] [blame] | 12 | |
Angel Pons | 816a41c | 2021-01-28 11:09:56 +0100 | [diff] [blame] | 13 | #include "q35.h" |
Arthur Heymans | 279c3e1 | 2020-12-02 13:28:53 +0100 | [diff] [blame] | 14 | |
Angel Pons | cba669c | 2021-01-28 11:56:45 +0100 | [diff] [blame] | 15 | static uint32_t encode_pciexbar_length(void) |
| 16 | { |
| 17 | switch (CONFIG_MMCONF_BUS_NUMBER) { |
| 18 | case 256: return 0 << 1; |
| 19 | case 128: return 1 << 1; |
| 20 | case 64: return 2 << 1; |
| 21 | default: return dead_code_t(uint32_t); |
| 22 | } |
| 23 | } |
| 24 | |
| 25 | uint32_t make_pciexbar(void) |
| 26 | { |
| 27 | return CONFIG_MMCONF_BASE_ADDRESS | encode_pciexbar_length() | 1; |
| 28 | } |
| 29 | |
| 30 | /* Check that MCFG is active. If it's not, QEMU was started for machine PC */ |
| 31 | void mainboard_machine_check(void) |
| 32 | { |
| 33 | if (pci_read_config32(HOST_BRIDGE, D0F0_PCIEXBAR_LO) != make_pciexbar()) |
| 34 | die("You must run qemu for machine Q35 (-M q35)"); |
| 35 | } |
| 36 | |
Angel Pons | 816a41c | 2021-01-28 11:09:56 +0100 | [diff] [blame] | 37 | /* QEMU-specific register */ |
| 38 | #define EXT_TSEG_MBYTES 0x50 |
Arthur Heymans | e69d2df | 2020-12-01 18:29:13 +0100 | [diff] [blame] | 39 | #define SMRAMC 0x9d |
| 40 | #define C_BASE_SEG ((0 << 2) | (1 << 1) | (0 << 0)) |
| 41 | #define G_SMRAME (1 << 3) |
| 42 | #define D_LCK (1 << 4) |
| 43 | #define D_CLS (1 << 5) |
| 44 | #define D_OPEN (1 << 6) |
| 45 | #define ESMRAMC 0x9e |
| 46 | #define T_EN (1 << 0) |
| 47 | #define TSEG_SZ_MASK (3 << 1) |
| 48 | #define H_SMRAME (1 << 7) |
Arthur Heymans | 279c3e1 | 2020-12-02 13:28:53 +0100 | [diff] [blame] | 49 | |
| 50 | void smm_region(uintptr_t *start, size_t *size) |
| 51 | { |
Angel Pons | 816a41c | 2021-01-28 11:09:56 +0100 | [diff] [blame] | 52 | uint8_t esmramc = pci_read_config8(HOST_BRIDGE, ESMRAMC); |
Arthur Heymans | 279c3e1 | 2020-12-02 13:28:53 +0100 | [diff] [blame] | 53 | |
| 54 | switch ((esmramc & TSEG_SZ_MASK) >> 1) { |
| 55 | case 0: |
| 56 | *size = 1 * MiB; |
| 57 | break; |
| 58 | case 1: |
| 59 | *size = 2 * MiB; |
| 60 | break; |
| 61 | case 2: |
| 62 | *size = 8 * MiB; |
| 63 | break; |
| 64 | default: |
Angel Pons | 816a41c | 2021-01-28 11:09:56 +0100 | [diff] [blame] | 65 | *size = pci_read_config16(HOST_BRIDGE, EXT_TSEG_MBYTES) * MiB; |
Arthur Heymans | 279c3e1 | 2020-12-02 13:28:53 +0100 | [diff] [blame] | 66 | } |
| 67 | |
| 68 | *start = qemu_get_memory_size() * KiB - *size; |
| 69 | printk(BIOS_SPEW, "SMM_BASE: 0x%08lx, SMM_SIZE: %zu MiB\n", *start, *size / MiB); |
| 70 | } |
Arthur Heymans | e69d2df | 2020-12-01 18:29:13 +0100 | [diff] [blame] | 71 | |
| 72 | void smm_lock(void) |
| 73 | { |
| 74 | /* |
| 75 | * LOCK the SMM memory window and enable normal SMM. |
| 76 | * After running this function, only a full reset can |
| 77 | * make the SMM registers writable again. |
| 78 | */ |
| 79 | printk(BIOS_DEBUG, "Locking SMM.\n"); |
| 80 | |
| 81 | pci_or_config8(PCI_DEV(0, 0, 0), ESMRAMC, T_EN); |
| 82 | pci_write_config8(PCI_DEV(0, 0, 0), SMRAMC, D_LCK | G_SMRAME | C_BASE_SEG); |
| 83 | } |