1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 3 #include <acpi/acpi.h> 4 #include <amdblocks/acpi.h> 5 #include <amdblocks/psp.h> 6 #include <amdblocks/smm.h> 7 #include <arch/io.h> 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 get_io_address(u32 info)20static 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 find_save_state(int cmd)26static 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 handle_smi_gsmi(void)54void 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 handle_smi_store(void)73void 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 */ 89 io_smi->rax = smmstore_exec(sub_command, (void *)(uintptr_t)reg_ebx); 90 } 91 fch_apmc_smi_handler(void)92void fch_apmc_smi_handler(void) 93 { 94 const uint8_t cmd = apm_get_apmc(); 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 } 119