2 Produces the SMM CPU I/O Protocol.
4 Copyright (c) 2009 - 2010, Intel Corporation
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include <Protocol/SmmCpuIo2.h>
19 #include <Library/BaseLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/IoLib.h>
22 #include <Library/SmmServicesTableLib.h>
23 #include <Library/BaseMemoryLib.h>
25 #define MAX_IO_PORT_ADDRESS 0xFFFF
28 // Function Prototypes
32 CpuMemoryServiceRead (
33 IN CONST EFI_SMM_CPU_IO2_PROTOCOL
*This
,
34 IN EFI_SMM_IO_WIDTH Width
,
42 CpuMemoryServiceWrite (
43 IN CONST EFI_SMM_CPU_IO2_PROTOCOL
*This
,
44 IN EFI_SMM_IO_WIDTH Width
,
53 IN CONST EFI_SMM_CPU_IO2_PROTOCOL
*This
,
54 IN EFI_SMM_IO_WIDTH Width
,
63 IN CONST EFI_SMM_CPU_IO2_PROTOCOL
*This
,
64 IN EFI_SMM_IO_WIDTH Width
,
71 // Handle for the SMM CPU I/O Protocol
73 EFI_HANDLE mHandle
= NULL
;
76 // SMM CPU I/O Protocol instance
78 EFI_SMM_CPU_IO2_PROTOCOL mSmmCpuIo2
= {
90 // Lookup table for increment values based on transfer widths
100 Check parameters to a SMM CPU I/O Protocol service request.
102 @param[in] MmioOperation TRUE for an MMIO operation, FALSE for I/O Port operation.
103 @param[in] Width Signifies the width of the I/O operations.
104 @param[in] Address The base address of the I/O operations. The caller is
105 responsible for aligning the Address if required.
106 @param[in] Count The number of I/O operations to perform.
107 @param[out] Buffer For read operations, the destination buffer to store
108 the results. For write operations, the source buffer
109 from which to write data.
111 @retval EFI_SUCCESS The data was read from or written to the device.
112 @retval EFI_UNSUPPORTED The Address is not valid for this system.
113 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
117 CpuIoCheckParameter (
118 IN BOOLEAN MmioOperation
,
119 IN EFI_SMM_IO_WIDTH Width
,
129 // Check to see if Buffer is NULL
131 if (Buffer
== NULL
) {
132 return EFI_INVALID_PARAMETER
;
136 // Check to see if Width is in the valid range
138 if (Width
< 0 || Width
> SMM_IO_UINT64
) {
139 return EFI_INVALID_PARAMETER
;
143 // Check to see if Width is in the valid range for I/O Port operations
145 if (!MmioOperation
&& (Width
== SMM_IO_UINT64
)) {
146 return EFI_INVALID_PARAMETER
;
150 // Check to see if any address associated with this transfer exceeds the maximum
151 // allowed address. The maximum address implied by the parameters passed in is
152 // Address + Size * Count. If the following condition is met, then the transfer
155 // Address + Size * Count > (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS) + 1
157 // Since MAX_ADDRESS can be the maximum integer value supported by the CPU and Count
158 // can also be the maximum integer value supported by the CPU, this range
159 // check must be adjusted to avoid all overflow conditions.
161 // The following form of the range check is equivalent but assumes that
162 // MAX_ADDRESS and MAX_IO_PORT_ADDRESS are of the form (2^n - 1).
164 Limit
= (MmioOperation
? MAX_ADDRESS
: MAX_IO_PORT_ADDRESS
);
166 if (Address
> Limit
) {
167 return EFI_UNSUPPORTED
;
170 MaxCount
= RShiftU64 (Limit
, Width
);
171 if (MaxCount
< (Count
- 1)) {
172 return EFI_UNSUPPORTED
;
174 if (Address
> LShiftU64 (MaxCount
- Count
+ 1, Width
)) {
175 return EFI_UNSUPPORTED
;
180 // Check to see if Address is aligned
182 if ((Address
& (UINT64
)(mStride
[Width
] - 1)) != 0) {
183 return EFI_UNSUPPORTED
;
190 Reads memory-mapped registers.
192 The I/O operations are carried out exactly as requested. The caller is
193 responsible for any alignment and I/O width issues that the bus, device,
194 platform, or type of I/O might require.
196 @param[in] This The EFI_SMM_CPU_IO2_PROTOCOL instance.
197 @param[in] Width Signifies the width of the I/O operations.
198 @param[in] Address The base address of the I/O operations. The caller is
199 responsible for aligning the Address if required.
200 @param[in] Count The number of I/O operations to perform.
201 @param[out] Buffer For read operations, the destination buffer to store
202 the results. For write operations, the source buffer
203 from which to write data.
205 @retval EFI_SUCCESS The data was read from or written to the device.
206 @retval EFI_UNSUPPORTED The Address is not valid for this system.
207 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
208 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
214 CpuMemoryServiceRead (
215 IN CONST EFI_SMM_CPU_IO2_PROTOCOL
*This
,
216 IN EFI_SMM_IO_WIDTH Width
,
226 Status
= CpuIoCheckParameter (TRUE
, Width
, Address
, Count
, Buffer
);
227 if (EFI_ERROR (Status
)) {
232 // Select loop based on the width of the transfer
234 Stride
= mStride
[Width
];
235 for (Uint8Buffer
= Buffer
; Count
> 0; Address
+= Stride
, Uint8Buffer
+= Stride
, Count
--) {
236 if (Width
== SMM_IO_UINT8
) {
237 *Uint8Buffer
= MmioRead8 ((UINTN
)Address
);
238 } else if (Width
== SMM_IO_UINT16
) {
239 *((UINT16
*)Uint8Buffer
) = MmioRead16 ((UINTN
)Address
);
240 } else if (Width
== SMM_IO_UINT32
) {
241 *((UINT32
*)Uint8Buffer
) = MmioRead32 ((UINTN
)Address
);
242 } else if (Width
== SMM_IO_UINT64
) {
243 *((UINT64
*)Uint8Buffer
) = MmioRead64 ((UINTN
)Address
);
250 Writes memory-mapped registers.
252 The I/O operations are carried out exactly as requested. The caller is
253 responsible for any alignment and I/O width issues that the bus, device,
254 platform, or type of I/O might require.
256 @param[in] This The EFI_SMM_CPU_IO2_PROTOCOL instance.
257 @param[in] Width Signifies the width of the I/O operations.
258 @param[in] Address The base address of the I/O operations. The caller is
259 responsible for aligning the Address if required.
260 @param[in] Count The number of I/O operations to perform.
261 @param[in] Buffer For read operations, the destination buffer to store
262 the results. For write operations, the source buffer
263 from which to write data.
265 @retval EFI_SUCCESS The data was read from or written to the device.
266 @retval EFI_UNSUPPORTED The Address is not valid for this system.
267 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
268 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
274 CpuMemoryServiceWrite (
275 IN CONST EFI_SMM_CPU_IO2_PROTOCOL
*This
,
276 IN EFI_SMM_IO_WIDTH Width
,
286 Status
= CpuIoCheckParameter (TRUE
, Width
, Address
, Count
, Buffer
);
287 if (EFI_ERROR (Status
)) {
292 // Select loop based on the width of the transfer
294 Stride
= mStride
[Width
];
295 for (Uint8Buffer
= Buffer
; Count
> 0; Address
+= Stride
, Uint8Buffer
+= Stride
, Count
--) {
296 if (Width
== SMM_IO_UINT8
) {
297 MmioWrite8 ((UINTN
)Address
, *Uint8Buffer
);
298 } else if (Width
== SMM_IO_UINT16
) {
299 MmioWrite16 ((UINTN
)Address
, *((UINT16
*)Uint8Buffer
));
300 } else if (Width
== SMM_IO_UINT32
) {
301 MmioWrite32 ((UINTN
)Address
, *((UINT32
*)Uint8Buffer
));
302 } else if (Width
== SMM_IO_UINT64
) {
303 MmioWrite64 ((UINTN
)Address
, *((UINT64
*)Uint8Buffer
));
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[out] 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
,
346 Status
= CpuIoCheckParameter (FALSE
, Width
, Address
, Count
, Buffer
);
347 if (EFI_ERROR (Status
)) {
352 // Select loop based on the width of the transfer
354 Stride
= mStride
[Width
];
355 for (Uint8Buffer
= Buffer
; Count
> 0; Address
+= Stride
, Uint8Buffer
+= Stride
, Count
--) {
356 if (Width
== SMM_IO_UINT8
) {
357 *Uint8Buffer
= IoRead8 ((UINTN
)Address
);
358 } else if (Width
== SMM_IO_UINT16
) {
359 *((UINT16
*)Uint8Buffer
) = IoRead16 ((UINTN
)Address
);
360 } else if (Width
== SMM_IO_UINT32
) {
361 *((UINT32
*)Uint8Buffer
) = IoRead32 ((UINTN
)Address
);
371 The I/O operations are carried out exactly as requested. The caller is
372 responsible for any alignment and I/O width issues that the bus, device,
373 platform, or type of I/O might require.
375 @param[in] This The EFI_SMM_CPU_IO2_PROTOCOL instance.
376 @param[in] Width Signifies the width of the I/O operations.
377 @param[in] Address The base address of the I/O operations. The caller is
378 responsible for aligning the Address if required.
379 @param[in] Count The number of I/O operations to perform.
380 @param[in] Buffer For read operations, the destination buffer to store
381 the results. For write operations, the source buffer
382 from which to write data.
384 @retval EFI_SUCCESS The data was read from or written to the device.
385 @retval EFI_UNSUPPORTED The Address is not valid for this system.
386 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
387 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
394 IN CONST EFI_SMM_CPU_IO2_PROTOCOL
*This
,
395 IN EFI_SMM_IO_WIDTH Width
,
406 // Make sure the parameters are valid
408 Status
= CpuIoCheckParameter (FALSE
, Width
, Address
, Count
, Buffer
);
409 if (EFI_ERROR (Status
)) {
414 // Select loop based on the width of the transfer
416 Stride
= mStride
[Width
];
417 for (Uint8Buffer
= (UINT8
*)Buffer
; Count
> 0; Address
+= Stride
, Uint8Buffer
+= Stride
, Count
--) {
418 if (Width
== SMM_IO_UINT8
) {
419 IoWrite8 ((UINTN
)Address
, *Uint8Buffer
);
420 } else if (Width
== SMM_IO_UINT16
) {
421 IoWrite16 ((UINTN
)Address
, *((UINT16
*)Uint8Buffer
));
422 } else if (Width
== SMM_IO_UINT32
) {
423 IoWrite32 ((UINTN
)Address
, *((UINT32
*)Uint8Buffer
));
431 The module Entry Point SmmCpuIoProtocol driver
433 @param[in] ImageHandle The firmware allocated handle for the EFI image.
434 @param[in] SystemTable A pointer to the EFI System Table.
436 @retval EFI_SUCCESS The entry point is executed successfully.
437 @retval Other Some error occurs when executing this entry point.
442 SmmCpuIo2Initialize (
443 IN EFI_HANDLE ImageHandle
,
444 IN EFI_SYSTEM_TABLE
*SystemTable
450 // Copy the SMM CPU I/O Protocol instance into the System Management System Table
452 CopyMem (&gSmst
->SmmIo
, &mSmmCpuIo2
, sizeof (mSmmCpuIo2
));
455 // Install the SMM CPU I/O Protocol into the SMM protocol database
457 Status
= gSmst
->SmmInstallProtocolInterface (
459 &gEfiSmmCpuIo2ProtocolGuid
,
460 EFI_NATIVE_INTERFACE
,
463 ASSERT_EFI_ERROR (Status
);