]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/CpuHotplugSmm/CpuHotplug.c
OvmfPkg/CpuHotplugSmm: add hotplug register block helper functions
[mirror_edk2.git] / OvmfPkg / CpuHotplugSmm / CpuHotplug.c
CommitLineData
17efae27
LE
1/** @file\r
2 Root SMI handler for VCPU hotplug SMIs.\r
3\r
4 Copyright (c) 2020, Red Hat, Inc.\r
5\r
6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
7**/\r
8\r
9#include <IndustryStandard/Q35MchIch9.h> // ICH9_APM_CNT\r
10#include <Library/BaseLib.h> // CpuDeadLoop()\r
11#include <Library/DebugLib.h> // ASSERT()\r
12#include <Library/MmServicesTableLib.h> // gMmst\r
13#include <Library/PcdLib.h> // PcdGetBool()\r
14#include <Protocol/MmCpuIo.h> // EFI_MM_CPU_IO_PROTOCOL\r
15#include <Uefi/UefiBaseType.h> // EFI_STATUS\r
16\r
17//\r
18// We use this protocol for accessing IO Ports.\r
19//\r
20STATIC EFI_MM_CPU_IO_PROTOCOL *mMmCpuIo;\r
21//\r
22// Represents the registration of the CPU Hotplug MMI handler.\r
23//\r
24STATIC EFI_HANDLE mDispatchHandle;\r
25\r
26\r
27/**\r
28 CPU Hotplug MMI handler function.\r
29\r
30 This is a root MMI handler.\r
31\r
32 @param[in] DispatchHandle The unique handle assigned to this handler by\r
33 EFI_MM_SYSTEM_TABLE.MmiHandlerRegister().\r
34\r
35 @param[in] Context Context passed in by\r
36 EFI_MM_SYSTEM_TABLE.MmiManage(). Due to\r
37 CpuHotplugMmi() being a root MMI handler,\r
38 Context is ASSERT()ed to be NULL.\r
39\r
40 @param[in,out] CommBuffer Ignored, due to CpuHotplugMmi() being a root\r
41 MMI handler.\r
42\r
43 @param[in,out] CommBufferSize Ignored, due to CpuHotplugMmi() being a root\r
44 MMI handler.\r
45\r
46 @retval EFI_SUCCESS The MMI was handled and the MMI\r
47 source was quiesced. When returned\r
48 by a non-root MMI handler,\r
49 EFI_SUCCESS terminates the\r
50 processing of MMI handlers in\r
51 EFI_MM_SYSTEM_TABLE.MmiManage().\r
52 For a root MMI handler (i.e., for\r
53 the present function too),\r
54 EFI_SUCCESS behaves identically to\r
55 EFI_WARN_INTERRUPT_SOURCE_QUIESCED,\r
56 as further root MMI handlers are\r
57 going to be called by\r
58 EFI_MM_SYSTEM_TABLE.MmiManage()\r
59 anyway.\r
60\r
61 @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The MMI source has been quiesced,\r
62 but other handlers should still\r
63 be called.\r
64\r
65 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The MMI source is still pending,\r
66 and other handlers should still\r
67 be called.\r
68\r
69 @retval EFI_INTERRUPT_PENDING The MMI source could not be\r
70 quiesced.\r
71**/\r
72STATIC\r
73EFI_STATUS\r
74EFIAPI\r
75CpuHotplugMmi (\r
76 IN EFI_HANDLE DispatchHandle,\r
77 IN CONST VOID *Context OPTIONAL,\r
78 IN OUT VOID *CommBuffer OPTIONAL,\r
79 IN OUT UINTN *CommBufferSize OPTIONAL\r
80 )\r
81{\r
82 EFI_STATUS Status;\r
83 UINT8 ApmControl;\r
84\r
85 //\r
86 // Assert that we are entering this function due to our root MMI handler\r
87 // registration.\r
88 //\r
89 ASSERT (DispatchHandle == mDispatchHandle);\r
90 //\r
91 // When MmiManage() is invoked to process root MMI handlers, the caller (the\r
92 // MM Core) is expected to pass in a NULL Context. MmiManage() then passes\r
93 // the same NULL Context to individual handlers.\r
94 //\r
95 ASSERT (Context == NULL);\r
96 //\r
97 // Read the MMI command value from the APM Control Port, to see if this is an\r
98 // MMI we should care about.\r
99 //\r
100 Status = mMmCpuIo->Io.Read (mMmCpuIo, MM_IO_UINT8, ICH9_APM_CNT, 1,\r
101 &ApmControl);\r
102 if (EFI_ERROR (Status)) {\r
103 DEBUG ((DEBUG_ERROR, "%a: failed to read ICH9_APM_CNT: %r\n", __FUNCTION__,\r
104 Status));\r
105 //\r
106 // We couldn't even determine if the MMI was for us or not.\r
107 //\r
108 goto Fatal;\r
109 }\r
110\r
111 if (ApmControl != ICH9_APM_CNT_CPU_HOTPLUG) {\r
112 //\r
113 // The MMI is not for us.\r
114 //\r
115 return EFI_WARN_INTERRUPT_SOURCE_QUIESCED;\r
116 }\r
117\r
118 //\r
119 // We've handled this MMI.\r
120 //\r
121 return EFI_SUCCESS;\r
122\r
123Fatal:\r
124 ASSERT (FALSE);\r
125 CpuDeadLoop ();\r
126 //\r
127 // We couldn't handle this MMI.\r
128 //\r
129 return EFI_INTERRUPT_PENDING;\r
130}\r
131\r
132\r
133//\r
134// Entry point function of this driver.\r
135//\r
136EFI_STATUS\r
137EFIAPI\r
138CpuHotplugEntry (\r
139 IN EFI_HANDLE ImageHandle,\r
140 IN EFI_SYSTEM_TABLE *SystemTable\r
141 )\r
142{\r
143 EFI_STATUS Status;\r
144\r
145 //\r
146 // This module should only be included when SMM support is required.\r
147 //\r
148 ASSERT (FeaturePcdGet (PcdSmmSmramRequire));\r
149 //\r
150 // This driver depends on the dynamically detected "SMRAM at default SMBASE"\r
151 // feature.\r
152 //\r
153 if (!PcdGetBool (PcdQ35SmramAtDefaultSmbase)) {\r
154 return EFI_UNSUPPORTED;\r
155 }\r
156\r
157 //\r
158 // Errors from here on are fatal; we cannot allow the boot to proceed if we\r
159 // can't set up this driver to handle CPU hotplug.\r
160 //\r
161 // First, collect the protocols needed later. All of these protocols are\r
162 // listed in our module DEPEX.\r
163 //\r
164 Status = gMmst->MmLocateProtocol (&gEfiMmCpuIoProtocolGuid,\r
165 NULL /* Registration */, (VOID **)&mMmCpuIo);\r
166 if (EFI_ERROR (Status)) {\r
167 DEBUG ((DEBUG_ERROR, "%a: locate MmCpuIo: %r\n", __FUNCTION__, Status));\r
168 goto Fatal;\r
169 }\r
170\r
171 //\r
172 // Register the handler for the CPU Hotplug MMI.\r
173 //\r
174 Status = gMmst->MmiHandlerRegister (\r
175 CpuHotplugMmi,\r
176 NULL, // HandlerType: root MMI handler\r
177 &mDispatchHandle\r
178 );\r
179 if (EFI_ERROR (Status)) {\r
180 DEBUG ((DEBUG_ERROR, "%a: MmiHandlerRegister(): %r\n", __FUNCTION__,\r
181 Status));\r
182 goto Fatal;\r
183 }\r
184\r
185 return EFI_SUCCESS;\r
186\r
187Fatal:\r
188 ASSERT (FALSE);\r
189 CpuDeadLoop ();\r
190 return Status;\r
191}\r