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 Width Signifies the width of the I/O or Memory operation.
103 @param Address The base address of the I/O or Memory operation.
104 @param Count The number of I/O or Memory operations to perform.
105 The number of bytes moved is Width size * Count, starting at Address.
106 @param Buffer For read operations, the destination buffer to store the results.
107 For write operations, the source buffer from which to write data.
108 @param MmioOperation TRUE for an MMIO operation, FALSE for I/O Port operation.
110 @retval EFI_SUCCESS The parameters for this request pass the checks.
111 @retval EFI_INVALID_PARAMETER Buffer is NULL or Width is not valid.
112 @retval EFI_UNSUPPORTED The address range specified by Address, Width, and Count exceeds Limit.
113 The Buffer is not aligned for the given Width.
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
> 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 oveflow conditions.
161 // The follwing 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 @param This A pointer to the EFI_SMM_CPU_IO2_PROTOCOL instance.
193 @param Width Signifies the width of the I/O or Memory operation.
194 @param Address The base address of the I/O or Memoryoperation.
195 @param Count The number of I/O or Memory operations to perform.
196 The number of bytes moved is Width size * Count, starting at Address.
197 @param Buffer For read operations, the destination buffer to store the results.
198 For write operations, the source buffer from which to write data.
200 @retval EFI_SUCCESS The data was read from or written to the EFI system.
201 @retval EFI_INVALID_PARAMETER Width is invalid for this EFI system.Or Buffer is NULL.
202 @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
203 Or,The address range specified by Address, Width, and Count is not valid for this EFI system.
208 CpuMemoryServiceRead (
209 IN CONST EFI_SMM_CPU_IO2_PROTOCOL
*This
,
210 IN EFI_SMM_IO_WIDTH Width
,
220 Status
= CpuIoCheckParameter (TRUE
, Width
, Address
, Count
, Buffer
);
221 if (EFI_ERROR (Status
)) {
226 // Select loop based on the width of the transfer
228 Stride
= mStride
[Width
];
229 for (Uint8Buffer
= Buffer
; Count
> 0; Address
+= Stride
, Uint8Buffer
+= Stride
, Count
--) {
230 if (Width
== SMM_IO_UINT8
) {
231 *Uint8Buffer
= MmioRead8 ((UINTN
)Address
);
232 } else if (Width
== SMM_IO_UINT16
) {
233 *((UINT16
*)Uint8Buffer
) = MmioRead16 ((UINTN
)Address
);
234 } else if (Width
== SMM_IO_UINT32
) {
235 *((UINT32
*)Uint8Buffer
) = MmioRead32 ((UINTN
)Address
);
236 } else if (Width
== SMM_IO_UINT64
) {
237 *((UINT64
*)Uint8Buffer
) = MmioRead64 ((UINTN
)Address
);
244 Writes memory-mapped registers.
246 @param This A pointer to the EFI_SMM_CPU_IO2_PROTOCOL instance.
247 @param Width Signifies the width of the I/O or Memory operation.
248 @param Address The base address of the I/O or Memoryoperation.
249 @param Count The number of I/O or Memory operations to perform.
250 The number of bytes moved is Width size * Count, starting at Address.
251 @param Buffer For read operations, the destination buffer to store the results.
252 For write operations, the source buffer from which to write data.
254 @retval EFI_SUCCESS The data was read from or written to the EFI system.
255 @retval EFI_INVALID_PARAMETER Width is invalid for this EFI system.Or Buffer is NULL.
256 @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
257 Or,The address range specified by Address, Width, and Count is not valid for this EFI system.
262 CpuMemoryServiceWrite (
263 IN CONST EFI_SMM_CPU_IO2_PROTOCOL
*This
,
264 IN EFI_SMM_IO_WIDTH Width
,
274 Status
= CpuIoCheckParameter (TRUE
, Width
, Address
, Count
, Buffer
);
275 if (EFI_ERROR (Status
)) {
280 // Select loop based on the width of the transfer
282 Stride
= mStride
[Width
];
283 for (Uint8Buffer
= Buffer
; Count
> 0; Address
+= Stride
, Uint8Buffer
+= Stride
, Count
--) {
284 if (Width
== SMM_IO_UINT8
) {
285 MmioWrite8 ((UINTN
)Address
, *Uint8Buffer
);
286 } else if (Width
== SMM_IO_UINT16
) {
287 MmioWrite16 ((UINTN
)Address
, *((UINT16
*)Uint8Buffer
));
288 } else if (Width
== SMM_IO_UINT32
) {
289 MmioWrite32 ((UINTN
)Address
, *((UINT32
*)Uint8Buffer
));
290 } else if (Width
== SMM_IO_UINT64
) {
291 MmioWrite64 ((UINTN
)Address
, *((UINT64
*)Uint8Buffer
));
300 @param This A pointer to the EFI_SMM_CPU_IO2_PROTOCOL instance.
301 @param Width Signifies the width of the I/O or Memory operation.
302 @param Address The base address of the I/O or Memoryoperation.
303 @param Count The number of I/O or Memory operations to perform.
304 The number of bytes moved is Width size * Count, starting at Address.
305 @param Buffer For read operations, the destination buffer to store the results.
306 For write operations, the source buffer from which to write data.
308 @retval EFI_SUCCESS The data was read from or written to the EFI system.
309 @retval EFI_INVALID_PARAMETER Width is invalid for this EFI system.Or Buffer is NULL.
310 @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
311 Or,The address range specified by Address, Width, and Count is not valid for this EFI system.
317 IN CONST EFI_SMM_CPU_IO2_PROTOCOL
*This
,
318 IN EFI_SMM_IO_WIDTH Width
,
328 Status
= CpuIoCheckParameter (FALSE
, Width
, Address
, Count
, Buffer
);
329 if (EFI_ERROR (Status
)) {
334 // Select loop based on the width of the transfer
336 Stride
= mStride
[Width
];
337 for (Uint8Buffer
= Buffer
; Count
> 0; Address
+= Stride
, Uint8Buffer
+= Stride
, Count
--) {
338 if (Width
== SMM_IO_UINT8
) {
339 *Uint8Buffer
= IoRead8 ((UINTN
)Address
);
340 } else if (Width
== SMM_IO_UINT16
) {
341 *((UINT16
*)Uint8Buffer
) = IoRead16 ((UINTN
)Address
);
342 } else if (Width
== SMM_IO_UINT32
) {
343 *((UINT32
*)Uint8Buffer
) = IoRead32 ((UINTN
)Address
);
353 @param This A pointer to the EFI_SMM_CPU_IO2_PROTOCOL instance.
354 @param Width Signifies the width of the I/O or Memory operation.
355 @param Address The base address of the I/O or Memoryoperation.
356 @param Count The number of I/O or Memory operations to perform.
357 The number of bytes moved is Width size * Count, starting at Address.
358 @param Buffer For read operations, the destination buffer to store the results.
359 For write operations, the source buffer from which to write data.
361 @retval EFI_SUCCESS The data was read from or written to the EFI system.
362 @retval EFI_INVALID_PARAMETER Width is invalid for this EFI system.Or Buffer is NULL.
363 @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
364 Or,The address range specified by Address, Width, and Count is not valid for this EFI system.
370 IN CONST EFI_SMM_CPU_IO2_PROTOCOL
*This
,
371 IN EFI_SMM_IO_WIDTH Width
,
382 // Make sure the parameters are valid
384 Status
= CpuIoCheckParameter (FALSE
, Width
, Address
, Count
, Buffer
);
385 if (EFI_ERROR (Status
)) {
390 // Select loop based on the width of the transfer
392 Stride
= mStride
[Width
];
393 for (Uint8Buffer
= (UINT8
*)Buffer
; Count
> 0; Address
+= Stride
, Uint8Buffer
+= Stride
, Count
--) {
394 if (Width
== SMM_IO_UINT8
) {
395 IoWrite8 ((UINTN
)Address
, *Uint8Buffer
);
396 } else if (Width
== SMM_IO_UINT16
) {
397 IoWrite16 ((UINTN
)Address
, *((UINT16
*)Uint8Buffer
));
398 } else if (Width
== SMM_IO_UINT32
) {
399 IoWrite32 ((UINTN
)Address
, *((UINT32
*)Uint8Buffer
));
407 The module Entry Point SmmCpuIoProtocol driver
409 @param ImageHandle The firmware allocated handle for the EFI image.
410 @param SystemTable A pointer to the EFI System Table.
412 @retval EFI_SUCCESS The entry point is executed successfully.
413 @retval Other Some error occurs when executing this entry point.
418 SmmCpuIo2Initialize (
419 IN EFI_HANDLE ImageHandle
,
420 IN EFI_SYSTEM_TABLE
*SystemTable
426 // Copy the SMM CPU I/O Protocol instance into the System Management System Table
428 CopyMem (&gSmst
->SmmIo
, &mSmmCpuIo2
, sizeof (mSmmCpuIo2
));
431 // Install the SMM CPU I/O Protocol into the SMM protocol database
433 Status
= gSmst
->SmmInstallProtocolInterface (
435 &gEfiSmmCpuIo2ProtocolGuid
,
436 EFI_NATIVE_INTERFACE
,
439 ASSERT_EFI_ERROR (Status
);