2 Produces the SMM CPU I/O Protocol.
4 Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>
5 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.
15 #include "CpuIo2Smm.h"
18 // Handle for the SMM CPU I/O Protocol
20 EFI_HANDLE mHandle
= NULL
;
23 // SMM CPU I/O Protocol instance
25 EFI_SMM_CPU_IO2_PROTOCOL mSmmCpuIo2
= {
37 // Lookup table for increment values based on transfer widths
47 Check parameters to a SMM CPU I/O Protocol service request.
49 @param[in] MmioOperation TRUE for an MMIO operation, FALSE for I/O Port operation.
50 @param[in] Width Signifies the width of the I/O operations.
51 @param[in] Address The base address of the I/O operations. The caller is
52 responsible for aligning the Address if required.
53 @param[in] Count The number of I/O operations to perform.
54 @param[in] Buffer For read operations, the destination buffer to store
55 the results. For write operations, the source buffer
56 from which to write data.
58 @retval EFI_SUCCESS The data was read from or written to the device.
59 @retval EFI_UNSUPPORTED The Address is not valid for this system.
60 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
65 IN BOOLEAN MmioOperation
,
66 IN EFI_SMM_IO_WIDTH Width
,
76 // Check to see if Buffer is NULL
79 return EFI_INVALID_PARAMETER
;
83 // Check to see if Width is in the valid range
85 if ((UINT32
)Width
> SMM_IO_UINT64
) {
86 return EFI_INVALID_PARAMETER
;
90 // Check to see if Width is in the valid range for I/O Port operations
92 if (!MmioOperation
&& (Width
== SMM_IO_UINT64
)) {
93 return EFI_INVALID_PARAMETER
;
97 // Check to see if any address associated with this transfer exceeds the maximum
98 // allowed address. The maximum address implied by the parameters passed in is
99 // Address + Size * Count. If the following condition is met, then the transfer
102 // Address + Size * Count > (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS) + 1
104 // Since MAX_ADDRESS can be the maximum integer value supported by the CPU and Count
105 // can also be the maximum integer value supported by the CPU, this range
106 // check must be adjusted to avoid all overflow conditions.
108 // The following form of the range check is equivalent but assumes that
109 // MAX_ADDRESS and MAX_IO_PORT_ADDRESS are of the form (2^n - 1).
111 Limit
= (MmioOperation
? MAX_ADDRESS
: MAX_IO_PORT_ADDRESS
);
113 if (Address
> Limit
) {
114 return EFI_UNSUPPORTED
;
117 MaxCount
= RShiftU64 (Limit
, Width
);
118 if (MaxCount
< (Count
- 1)) {
119 return EFI_UNSUPPORTED
;
121 if (Address
> LShiftU64 (MaxCount
- Count
+ 1, Width
)) {
122 return EFI_UNSUPPORTED
;
127 // Check to see if Address is aligned
129 if ((Address
& (UINT64
)(mStride
[Width
] - 1)) != 0) {
130 return EFI_UNSUPPORTED
;
137 Reads memory-mapped registers.
139 The I/O operations are carried out exactly as requested. The caller is
140 responsible for any alignment and I/O width issues that the bus, device,
141 platform, or type of I/O might require.
143 @param[in] This The EFI_SMM_CPU_IO2_PROTOCOL instance.
144 @param[in] Width Signifies the width of the I/O operations.
145 @param[in] Address The base address of the I/O operations. The caller is
146 responsible for aligning the Address if required.
147 @param[in] Count The number of I/O operations to perform.
148 @param[out] Buffer For read operations, the destination buffer to store
149 the results. For write operations, the source buffer
150 from which to write data.
152 @retval EFI_SUCCESS The data was read from or written to the device.
153 @retval EFI_UNSUPPORTED The Address is not valid for this system.
154 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
155 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
161 CpuMemoryServiceRead (
162 IN CONST EFI_SMM_CPU_IO2_PROTOCOL
*This
,
163 IN EFI_SMM_IO_WIDTH Width
,
173 Status
= CpuIoCheckParameter (TRUE
, Width
, Address
, Count
, Buffer
);
174 if (EFI_ERROR (Status
)) {
179 // Select loop based on the width of the transfer
181 Stride
= mStride
[Width
];
182 for (Uint8Buffer
= Buffer
; Count
> 0; Address
+= Stride
, Uint8Buffer
+= Stride
, Count
--) {
183 if (Width
== SMM_IO_UINT8
) {
184 *Uint8Buffer
= MmioRead8 ((UINTN
)Address
);
185 } else if (Width
== SMM_IO_UINT16
) {
186 *((UINT16
*)Uint8Buffer
) = MmioRead16 ((UINTN
)Address
);
187 } else if (Width
== SMM_IO_UINT32
) {
188 *((UINT32
*)Uint8Buffer
) = MmioRead32 ((UINTN
)Address
);
189 } else if (Width
== SMM_IO_UINT64
) {
190 *((UINT64
*)Uint8Buffer
) = MmioRead64 ((UINTN
)Address
);
197 Writes memory-mapped registers.
199 The I/O operations are carried out exactly as requested. The caller is
200 responsible for any alignment and I/O width issues that the bus, device,
201 platform, or type of I/O might require.
203 @param[in] This The EFI_SMM_CPU_IO2_PROTOCOL instance.
204 @param[in] Width Signifies the width of the I/O operations.
205 @param[in] Address The base address of the I/O operations. The caller is
206 responsible for aligning the Address if required.
207 @param[in] Count The number of I/O operations to perform.
208 @param[in] Buffer For read operations, the destination buffer to store
209 the results. For write operations, the source buffer
210 from which to write data.
212 @retval EFI_SUCCESS The data was read from or written to the device.
213 @retval EFI_UNSUPPORTED The Address is not valid for this system.
214 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
215 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
221 CpuMemoryServiceWrite (
222 IN CONST EFI_SMM_CPU_IO2_PROTOCOL
*This
,
223 IN EFI_SMM_IO_WIDTH Width
,
233 Status
= CpuIoCheckParameter (TRUE
, Width
, Address
, Count
, Buffer
);
234 if (EFI_ERROR (Status
)) {
239 // Select loop based on the width of the transfer
241 Stride
= mStride
[Width
];
242 for (Uint8Buffer
= Buffer
; Count
> 0; Address
+= Stride
, Uint8Buffer
+= Stride
, Count
--) {
243 if (Width
== SMM_IO_UINT8
) {
244 MmioWrite8 ((UINTN
)Address
, *Uint8Buffer
);
245 } else if (Width
== SMM_IO_UINT16
) {
246 MmioWrite16 ((UINTN
)Address
, *((UINT16
*)Uint8Buffer
));
247 } else if (Width
== SMM_IO_UINT32
) {
248 MmioWrite32 ((UINTN
)Address
, *((UINT32
*)Uint8Buffer
));
249 } else if (Width
== SMM_IO_UINT64
) {
250 MmioWrite64 ((UINTN
)Address
, *((UINT64
*)Uint8Buffer
));
259 The I/O operations are carried out exactly as requested. The caller is
260 responsible for any alignment and I/O width issues that the bus, device,
261 platform, or type of I/O might require.
263 @param[in] This The EFI_SMM_CPU_IO2_PROTOCOL instance.
264 @param[in] Width Signifies the width of the I/O operations.
265 @param[in] Address The base address of the I/O operations. The caller is
266 responsible for aligning the Address if required.
267 @param[in] Count The number of I/O operations to perform.
268 @param[out] Buffer For read operations, the destination buffer to store
269 the results. For write operations, the source buffer
270 from which to write data.
272 @retval EFI_SUCCESS The data was read from or written to the device.
273 @retval EFI_UNSUPPORTED The Address is not valid for this system.
274 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
275 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
282 IN CONST EFI_SMM_CPU_IO2_PROTOCOL
*This
,
283 IN EFI_SMM_IO_WIDTH Width
,
293 Status
= CpuIoCheckParameter (FALSE
, Width
, Address
, Count
, Buffer
);
294 if (EFI_ERROR (Status
)) {
299 // Select loop based on the width of the transfer
301 Stride
= mStride
[Width
];
302 for (Uint8Buffer
= Buffer
; Count
> 0; Address
+= Stride
, Uint8Buffer
+= Stride
, Count
--) {
303 if (Width
== SMM_IO_UINT8
) {
304 *Uint8Buffer
= IoRead8 ((UINTN
)Address
);
305 } else if (Width
== SMM_IO_UINT16
) {
306 *((UINT16
*)Uint8Buffer
) = IoRead16 ((UINTN
)Address
);
307 } else if (Width
== SMM_IO_UINT32
) {
308 *((UINT32
*)Uint8Buffer
) = IoRead32 ((UINTN
)Address
);
318 The I/O operations are carried out exactly as requested. The caller is
319 responsible for any alignment and I/O width issues that the bus, device,
320 platform, or type of I/O might require.
322 @param[in] This The EFI_SMM_CPU_IO2_PROTOCOL instance.
323 @param[in] Width Signifies the width of the I/O operations.
324 @param[in] Address The base address of the I/O operations. The caller is
325 responsible for aligning the Address if required.
326 @param[in] Count The number of I/O operations to perform.
327 @param[in] Buffer For read operations, the destination buffer to store
328 the results. For write operations, the source buffer
329 from which to write data.
331 @retval EFI_SUCCESS The data was read from or written to the device.
332 @retval EFI_UNSUPPORTED The Address is not valid for this system.
333 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
334 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
341 IN CONST EFI_SMM_CPU_IO2_PROTOCOL
*This
,
342 IN EFI_SMM_IO_WIDTH Width
,
353 // Make sure the parameters are valid
355 Status
= CpuIoCheckParameter (FALSE
, Width
, Address
, Count
, Buffer
);
356 if (EFI_ERROR (Status
)) {
361 // Select loop based on the width of the transfer
363 Stride
= mStride
[Width
];
364 for (Uint8Buffer
= (UINT8
*)Buffer
; Count
> 0; Address
+= Stride
, Uint8Buffer
+= Stride
, Count
--) {
365 if (Width
== SMM_IO_UINT8
) {
366 IoWrite8 ((UINTN
)Address
, *Uint8Buffer
);
367 } else if (Width
== SMM_IO_UINT16
) {
368 IoWrite16 ((UINTN
)Address
, *((UINT16
*)Uint8Buffer
));
369 } else if (Width
== SMM_IO_UINT32
) {
370 IoWrite32 ((UINTN
)Address
, *((UINT32
*)Uint8Buffer
));
378 The module Entry Point SmmCpuIoProtocol driver
380 @param[in] ImageHandle The firmware allocated handle for the EFI image.
381 @param[in] SystemTable A pointer to the EFI System Table.
383 @retval EFI_SUCCESS The entry point is executed successfully.
384 @retval Other Some error occurs when executing this entry point.
389 SmmCpuIo2Initialize (
390 IN EFI_HANDLE ImageHandle
,
391 IN EFI_SYSTEM_TABLE
*SystemTable
397 // Copy the SMM CPU I/O Protocol instance into the System Management System Table
399 CopyMem (&gSmst
->SmmIo
, &mSmmCpuIo2
, sizeof (mSmmCpuIo2
));
402 // Install the SMM CPU I/O Protocol into the SMM protocol database
404 Status
= gSmst
->SmmInstallProtocolInterface (
406 &gEfiSmmCpuIo2ProtocolGuid
,
407 EFI_NATIVE_INTERFACE
,
410 ASSERT_EFI_ERROR (Status
);