Felix Held | 90bcdb4 | 2021-03-08 23:54:18 +0100 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
| 2 | |
Fred Reitberger | f73a3a5 | 2022-10-14 14:04:04 -0400 | [diff] [blame] | 3 | #include <acpi/acpi.h> |
| 4 | #include <amdblocks/acpi.h> |
| 5 | #include <amdblocks/psp.h> |
Felix Held | 90bcdb4 | 2021-03-08 23:54:18 +0100 | [diff] [blame] | 6 | #include <amdblocks/smm.h> |
Fred Reitberger | f73a3a5 | 2022-10-14 14:04:04 -0400 | [diff] [blame] | 7 | #include <arch/io.h> |
Felix Held | 90bcdb4 | 2021-03-08 23:54:18 +0100 | [diff] [blame] | 8 | #include <cpu/amd/amd64_save_state.h> |
| 9 | #include <cpu/x86/smm.h> |
| 10 | #include <elog.h> |
| 11 | #include <smmstore.h> |
| 12 | #include <types.h> |
| 13 | |
| 14 | /* bits in smm_io_trap */ |
| 15 | #define SMM_IO_TRAP_PORT_OFFSET 16 |
| 16 | #define SMM_IO_TRAP_PORT_ADDRESS_MASK 0xffff |
| 17 | #define SMM_IO_TRAP_RW (1 << 0) |
| 18 | #define SMM_IO_TRAP_VALID (1 << 1) |
| 19 | |
| 20 | static inline u16 get_io_address(u32 info) |
| 21 | { |
| 22 | return ((info >> SMM_IO_TRAP_PORT_OFFSET) & |
| 23 | SMM_IO_TRAP_PORT_ADDRESS_MASK); |
| 24 | } |
| 25 | |
| 26 | static void *find_save_state(int cmd) |
| 27 | { |
| 28 | unsigned int core; |
| 29 | amd64_smm_state_save_area_t *state; |
| 30 | u32 smm_io_trap; |
| 31 | u8 reg_al; |
| 32 | |
| 33 | /* Check all nodes looking for the one that issued the IO */ |
| 34 | for (core = 0; core < CONFIG_MAX_CPUS; core++) { |
| 35 | state = smm_get_save_state(core); |
| 36 | smm_io_trap = state->smm_io_trap_offset; |
| 37 | /* Check for Valid IO Trap Word (bit1==1) */ |
| 38 | if (!(smm_io_trap & SMM_IO_TRAP_VALID)) |
| 39 | continue; |
| 40 | /* Make sure it was a write (bit0==0) */ |
| 41 | if (smm_io_trap & SMM_IO_TRAP_RW) |
| 42 | continue; |
| 43 | /* Check for APMC IO port */ |
| 44 | if (pm_acpi_smi_cmd_port() != get_io_address(smm_io_trap)) |
| 45 | continue; |
| 46 | /* Check AL against the requested command */ |
| 47 | reg_al = state->rax; |
| 48 | if (reg_al == cmd) |
| 49 | return state; |
| 50 | } |
| 51 | return NULL; |
| 52 | } |
| 53 | |
| 54 | void handle_smi_gsmi(void) |
| 55 | { |
| 56 | u8 sub_command; |
| 57 | amd64_smm_state_save_area_t *io_smi; |
| 58 | u32 reg_ebx; |
| 59 | |
| 60 | io_smi = find_save_state(APM_CNT_ELOG_GSMI); |
| 61 | if (!io_smi) |
| 62 | return; |
| 63 | /* Command and return value in EAX */ |
| 64 | sub_command = (io_smi->rax >> 8) & 0xff; |
| 65 | |
| 66 | /* Parameter buffer in EBX */ |
| 67 | reg_ebx = io_smi->rbx; |
| 68 | |
| 69 | /* drivers/elog/gsmi.c */ |
| 70 | io_smi->rax = gsmi_exec(sub_command, ®_ebx); |
| 71 | } |
| 72 | |
| 73 | void handle_smi_store(void) |
| 74 | { |
| 75 | u8 sub_command; |
| 76 | amd64_smm_state_save_area_t *io_smi; |
| 77 | u32 reg_ebx; |
| 78 | |
| 79 | io_smi = find_save_state(APM_CNT_SMMSTORE); |
| 80 | if (!io_smi) |
| 81 | return; |
| 82 | /* Command and return value in EAX */ |
| 83 | sub_command = (io_smi->rax >> 8) & 0xff; |
| 84 | |
| 85 | /* Parameter buffer in EBX */ |
| 86 | reg_ebx = io_smi->rbx; |
| 87 | |
| 88 | /* drivers/smmstore/smi.c */ |
Arthur Heymans | 4c68487 | 2022-04-19 21:44:22 +0200 | [diff] [blame] | 89 | io_smi->rax = smmstore_exec(sub_command, (void *)(uintptr_t)reg_ebx); |
Felix Held | 90bcdb4 | 2021-03-08 23:54:18 +0100 | [diff] [blame] | 90 | } |
Fred Reitberger | f73a3a5 | 2022-10-14 14:04:04 -0400 | [diff] [blame] | 91 | |
| 92 | void fch_apmc_smi_handler(void) |
| 93 | { |
| 94 | const uint8_t cmd = inb(pm_acpi_smi_cmd_port()); |
| 95 | |
| 96 | switch (cmd) { |
| 97 | case APM_CNT_ACPI_ENABLE: |
| 98 | acpi_clear_pm_gpe_status(); |
| 99 | acpi_enable_sci(); |
| 100 | break; |
| 101 | case APM_CNT_ACPI_DISABLE: |
| 102 | acpi_disable_sci(); |
| 103 | break; |
| 104 | case APM_CNT_ELOG_GSMI: |
| 105 | if (CONFIG(ELOG_GSMI)) |
| 106 | handle_smi_gsmi(); |
| 107 | break; |
| 108 | case APM_CNT_SMMSTORE: |
| 109 | if (CONFIG(SMMSTORE)) |
| 110 | handle_smi_store(); |
| 111 | break; |
| 112 | case APM_CNT_SMMINFO: |
| 113 | psp_notify_smm(); |
| 114 | break; |
| 115 | } |
| 116 | |
| 117 | mainboard_smi_apmc(cmd); |
| 118 | } |