2 Produces the SMM CPU I/O Protocol.
4 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
12 // Handle for the SMM CPU I/O Protocol
14 EFI_HANDLE mHandle
= NULL
;
17 // SMM CPU I/O Protocol instance
19 EFI_SMM_CPU_IO2_PROTOCOL mSmmCpuIo2
= {
31 // Lookup table for increment values based on transfer widths
41 Check parameters to a SMM CPU I/O Protocol service request.
43 @param[in] MmioOperation TRUE for an MMIO operation, FALSE for I/O Port operation.
44 @param[in] Width Signifies the width of the I/O operations.
45 @param[in] Address The base address of the I/O operations. The caller is
46 responsible for aligning the Address if required.
47 @param[in] Count The number of I/O operations to perform.
48 @param[in] Buffer For read operations, the destination buffer to store
49 the results. For write operations, the source buffer
50 from which to write data.
52 @retval EFI_SUCCESS The data was read from or written to the device.
53 @retval EFI_UNSUPPORTED The Address is not valid for this system.
54 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
59 IN BOOLEAN MmioOperation
,
60 IN EFI_SMM_IO_WIDTH Width
,
70 // Check to see if Buffer is NULL
73 return EFI_INVALID_PARAMETER
;
77 // Check to see if Width is in the valid range
79 if ((UINT32
)Width
> SMM_IO_UINT64
) {
80 return EFI_INVALID_PARAMETER
;
84 // Check to see if Width is in the valid range for I/O Port operations
86 if (!MmioOperation
&& (Width
== SMM_IO_UINT64
)) {
87 return EFI_INVALID_PARAMETER
;
91 // Check to see if any address associated with this transfer exceeds the maximum
92 // allowed address. The maximum address implied by the parameters passed in is
93 // Address + Size * Count. If the following condition is met, then the transfer
96 // Address + Size * Count > (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS) + 1
98 // Since MAX_ADDRESS can be the maximum integer value supported by the CPU and Count
99 // can also be the maximum integer value supported by the CPU, this range
100 // check must be adjusted to avoid all overflow conditions.
102 // The following form of the range check is equivalent but assumes that
103 // MAX_ADDRESS and MAX_IO_PORT_ADDRESS are of the form (2^n - 1).
105 Limit
= (MmioOperation
? MAX_ADDRESS
: MAX_IO_PORT_ADDRESS
);
107 if (Address
> Limit
) {
108 return EFI_UNSUPPORTED
;
111 MaxCount
= RShiftU64 (Limit
, Width
);
112 if (MaxCount
< (Count
- 1)) {
113 return EFI_UNSUPPORTED
;
115 if (Address
> LShiftU64 (MaxCount
- Count
+ 1, Width
)) {
116 return EFI_UNSUPPORTED
;
121 // Check to see if Address is aligned
123 if ((Address
& ((UINT64
)mStride
[Width
] - 1)) != 0) {
124 return EFI_UNSUPPORTED
;
131 Reads memory-mapped registers.
133 The I/O operations are carried out exactly as requested. The caller is
134 responsible for any alignment and I/O width issues that the bus, device,
135 platform, or type of I/O might require.
137 @param[in] This The EFI_SMM_CPU_IO2_PROTOCOL instance.
138 @param[in] Width Signifies the width of the I/O operations.
139 @param[in] Address The base address of the I/O operations. The caller is
140 responsible for aligning the Address if required.
141 @param[in] Count The number of I/O operations to perform.
142 @param[out] Buffer For read operations, the destination buffer to store
143 the results. For write operations, the source buffer
144 from which to write data.
146 @retval EFI_SUCCESS The data was read from or written to the device.
147 @retval EFI_UNSUPPORTED The Address is not valid for this system.
148 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
149 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
155 CpuMemoryServiceRead (
156 IN CONST EFI_SMM_CPU_IO2_PROTOCOL
*This
,
157 IN EFI_SMM_IO_WIDTH Width
,
167 Status
= CpuIoCheckParameter (TRUE
, Width
, Address
, Count
, Buffer
);
168 if (EFI_ERROR (Status
)) {
173 // Select loop based on the width of the transfer
175 Stride
= mStride
[Width
];
176 for (Uint8Buffer
= Buffer
; Count
> 0; Address
+= Stride
, Uint8Buffer
+= Stride
, Count
--) {
177 if (Width
== SMM_IO_UINT8
) {
178 *Uint8Buffer
= MmioRead8 ((UINTN
)Address
);
179 } else if (Width
== SMM_IO_UINT16
) {
180 *((UINT16
*)Uint8Buffer
) = MmioRead16 ((UINTN
)Address
);
181 } else if (Width
== SMM_IO_UINT32
) {
182 *((UINT32
*)Uint8Buffer
) = MmioRead32 ((UINTN
)Address
);
183 } else if (Width
== SMM_IO_UINT64
) {
184 *((UINT64
*)Uint8Buffer
) = MmioRead64 ((UINTN
)Address
);
191 Writes memory-mapped registers.
193 The I/O operations are carried out exactly as requested. The caller is
194 responsible for any alignment and I/O width issues that the bus, device,
195 platform, or type of I/O might require.
197 @param[in] This The EFI_SMM_CPU_IO2_PROTOCOL instance.
198 @param[in] Width Signifies the width of the I/O operations.
199 @param[in] Address The base address of the I/O operations. The caller is
200 responsible for aligning the Address if required.
201 @param[in] Count The number of I/O operations to perform.
202 @param[in] Buffer For read operations, the destination buffer to store
203 the results. For write operations, the source buffer
204 from which to write data.
206 @retval EFI_SUCCESS The data was read from or written to the device.
207 @retval EFI_UNSUPPORTED The Address is not valid for this system.
208 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
209 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
215 CpuMemoryServiceWrite (
216 IN CONST EFI_SMM_CPU_IO2_PROTOCOL
*This
,
217 IN EFI_SMM_IO_WIDTH Width
,
227 Status
= CpuIoCheckParameter (TRUE
, Width
, Address
, Count
, Buffer
);
228 if (EFI_ERROR (Status
)) {
233 // Select loop based on the width of the transfer
235 Stride
= mStride
[Width
];
236 for (Uint8Buffer
= Buffer
; Count
> 0; Address
+= Stride
, Uint8Buffer
+= Stride
, Count
--) {
237 if (Width
== SMM_IO_UINT8
) {
238 MmioWrite8 ((UINTN
)Address
, *Uint8Buffer
);
239 } else if (Width
== SMM_IO_UINT16
) {
240 MmioWrite16 ((UINTN
)Address
, *((UINT16
*)Uint8Buffer
));
241 } else if (Width
== SMM_IO_UINT32
) {
242 MmioWrite32 ((UINTN
)Address
, *((UINT32
*)Uint8Buffer
));
243 } else if (Width
== SMM_IO_UINT64
) {
244 MmioWrite64 ((UINTN
)Address
, *((UINT64
*)Uint8Buffer
));
253 The I/O operations are carried out exactly as requested. The caller is
254 responsible for any alignment and I/O width issues that the bus, device,
255 platform, or type of I/O might require.
257 @param[in] This The EFI_SMM_CPU_IO2_PROTOCOL instance.
258 @param[in] Width Signifies the width of the I/O operations.
259 @param[in] Address The base address of the I/O operations. The caller is
260 responsible for aligning the Address if required.
261 @param[in] Count The number of I/O operations to perform.
262 @param[out] Buffer For read operations, the destination buffer to store
263 the results. For write operations, the source buffer
264 from which to write data.
266 @retval EFI_SUCCESS The data was read from or written to the device.
267 @retval EFI_UNSUPPORTED The Address is not valid for this system.
268 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
269 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
276 IN CONST EFI_SMM_CPU_IO2_PROTOCOL
*This
,
277 IN EFI_SMM_IO_WIDTH Width
,
287 Status
= CpuIoCheckParameter (FALSE
, Width
, Address
, Count
, Buffer
);
288 if (EFI_ERROR (Status
)) {
293 // Select loop based on the width of the transfer
295 Stride
= mStride
[Width
];
296 for (Uint8Buffer
= Buffer
; Count
> 0; Address
+= Stride
, Uint8Buffer
+= Stride
, Count
--) {
297 if (Width
== SMM_IO_UINT8
) {
298 *Uint8Buffer
= IoRead8 ((UINTN
)Address
);
299 } else if (Width
== SMM_IO_UINT16
) {
300 *((UINT16
*)Uint8Buffer
) = IoRead16 ((UINTN
)Address
);
301 } else if (Width
== SMM_IO_UINT32
) {
302 *((UINT32
*)Uint8Buffer
) = IoRead32 ((UINTN
)Address
);
312 The I/O operations are carried out exactly as requested. The caller is
313 responsible for any alignment and I/O width issues that the bus, device,
314 platform, or type of I/O might require.
316 @param[in] This The EFI_SMM_CPU_IO2_PROTOCOL instance.
317 @param[in] Width Signifies the width of the I/O operations.
318 @param[in] Address The base address of the I/O operations. The caller is
319 responsible for aligning the Address if required.
320 @param[in] Count The number of I/O operations to perform.
321 @param[in] Buffer For read operations, the destination buffer to store
322 the results. For write operations, the source buffer
323 from which to write data.
325 @retval EFI_SUCCESS The data was read from or written to the device.
326 @retval EFI_UNSUPPORTED The Address is not valid for this system.
327 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
328 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
335 IN CONST EFI_SMM_CPU_IO2_PROTOCOL
*This
,
336 IN EFI_SMM_IO_WIDTH Width
,
347 // Make sure the parameters are valid
349 Status
= CpuIoCheckParameter (FALSE
, Width
, Address
, Count
, Buffer
);
350 if (EFI_ERROR (Status
)) {
355 // Select loop based on the width of the transfer
357 Stride
= mStride
[Width
];
358 for (Uint8Buffer
= (UINT8
*)Buffer
; Count
> 0; Address
+= Stride
, Uint8Buffer
+= Stride
, Count
--) {
359 if (Width
== SMM_IO_UINT8
) {
360 IoWrite8 ((UINTN
)Address
, *Uint8Buffer
);
361 } else if (Width
== SMM_IO_UINT16
) {
362 IoWrite16 ((UINTN
)Address
, *((UINT16
*)Uint8Buffer
));
363 } else if (Width
== SMM_IO_UINT32
) {
364 IoWrite32 ((UINTN
)Address
, *((UINT32
*)Uint8Buffer
));
372 The module Entry Point SmmCpuIoProtocol driver
374 @param[in] ImageHandle The firmware allocated handle for the EFI image.
375 @param[in] SystemTable A pointer to the EFI System Table.
377 @retval EFI_SUCCESS The entry point is executed successfully.
378 @retval Other Some error occurs when executing this entry point.
383 SmmCpuIo2Initialize (
384 IN EFI_HANDLE ImageHandle
,
385 IN EFI_SYSTEM_TABLE
*SystemTable
391 // Copy the SMM CPU I/O Protocol instance into the System Management System Table
393 CopyMem (&gSmst
->SmmIo
, &mSmmCpuIo2
, sizeof (mSmmCpuIo2
));
396 // Install the SMM CPU I/O Protocol into the SMM protocol database
398 Status
= gSmst
->SmmInstallProtocolInterface (
400 &gEfiSmmCpuIo2ProtocolGuid
,
401 EFI_NATIVE_INTERFACE
,
404 ASSERT_EFI_ERROR (Status
);