blob: 0eab86c9da81ecd986f5170627eeb2102b370684 [file] [log] [blame]
Felix Held90bcdb42021-03-08 23:54:18 +01001/* SPDX-License-Identifier: GPL-2.0-or-later */
2
Fred Reitbergerf73a3a52022-10-14 14:04:04 -04003#include <acpi/acpi.h>
4#include <amdblocks/acpi.h>
5#include <amdblocks/psp.h>
Felix Held90bcdb42021-03-08 23:54:18 +01006#include <amdblocks/smm.h>
Fred Reitbergerf73a3a52022-10-14 14:04:04 -04007#include <arch/io.h>
Felix Held90bcdb42021-03-08 23:54:18 +01008#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
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
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
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, &reg_ebx);
71}
72
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 */
Arthur Heymans4c684872022-04-19 21:44:22 +020089 io_smi->rax = smmstore_exec(sub_command, (void *)(uintptr_t)reg_ebx);
Felix Held90bcdb42021-03-08 23:54:18 +010090}
Fred Reitbergerf73a3a52022-10-14 14:04:04 -040091
92void 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}