802342caaebd1396f17cdd6144a90e1c67d8571c
[mirror_edk2.git] / UefiCpuPkg / CpuIo2Dxe / CpuIo2Dxe.c
1 /** @file
2 Produces the CPU I/O 2 Protocol.
3
4 Copyright (c) 2009 - 2011, 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
9
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.
12
13 **/
14
15 #include "CpuIo2Dxe.h"
16
17 //
18 // Handle for the CPU I/O 2 Protocol
19 //
20 EFI_HANDLE mHandle = NULL;
21
22 //
23 // CPU I/O 2 Protocol instance
24 //
25 EFI_CPU_IO2_PROTOCOL mCpuIo2 = {
26 {
27 CpuMemoryServiceRead,
28 CpuMemoryServiceWrite
29 },
30 {
31 CpuIoServiceRead,
32 CpuIoServiceWrite
33 }
34 };
35
36 //
37 // Lookup table for increment values based on transfer widths
38 //
39 UINT8 mInStride[] = {
40 1, // EfiCpuIoWidthUint8
41 2, // EfiCpuIoWidthUint16
42 4, // EfiCpuIoWidthUint32
43 8, // EfiCpuIoWidthUint64
44 0, // EfiCpuIoWidthFifoUint8
45 0, // EfiCpuIoWidthFifoUint16
46 0, // EfiCpuIoWidthFifoUint32
47 0, // EfiCpuIoWidthFifoUint64
48 1, // EfiCpuIoWidthFillUint8
49 2, // EfiCpuIoWidthFillUint16
50 4, // EfiCpuIoWidthFillUint32
51 8 // EfiCpuIoWidthFillUint64
52 };
53
54 //
55 // Lookup table for increment values based on transfer widths
56 //
57 UINT8 mOutStride[] = {
58 1, // EfiCpuIoWidthUint8
59 2, // EfiCpuIoWidthUint16
60 4, // EfiCpuIoWidthUint32
61 8, // EfiCpuIoWidthUint64
62 1, // EfiCpuIoWidthFifoUint8
63 2, // EfiCpuIoWidthFifoUint16
64 4, // EfiCpuIoWidthFifoUint32
65 8, // EfiCpuIoWidthFifoUint64
66 0, // EfiCpuIoWidthFillUint8
67 0, // EfiCpuIoWidthFillUint16
68 0, // EfiCpuIoWidthFillUint32
69 0 // EfiCpuIoWidthFillUint64
70 };
71
72 /**
73 Check parameters to a CPU I/O 2 Protocol service request.
74
75 The I/O operations are carried out exactly as requested. The caller is responsible
76 for satisfying any alignment and I/O width restrictions that a PI System on a
77 platform might require. For example on some platforms, width requests of
78 EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
79 be handled by the driver.
80
81 @param[in] MmioOperation TRUE for an MMIO operation, FALSE for I/O Port operation.
82 @param[in] Width Signifies the width of the I/O or Memory operation.
83 @param[in] Address The base address of the I/O operation.
84 @param[in] Count The number of I/O operations to perform. The number of
85 bytes moved is Width size * Count, starting at Address.
86 @param[in] Buffer For read operations, the destination buffer to store the results.
87 For write operations, the source buffer from which to write data.
88
89 @retval EFI_SUCCESS The parameters for this request pass the checks.
90 @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
91 @retval EFI_INVALID_PARAMETER Buffer is NULL.
92 @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
93 @retval EFI_UNSUPPORTED The address range specified by Address, Width,
94 and Count is not valid for this PI system.
95
96 **/
97 EFI_STATUS
98 CpuIoCheckParameter (
99 IN BOOLEAN MmioOperation,
100 IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
101 IN UINT64 Address,
102 IN UINTN Count,
103 IN VOID *Buffer
104 )
105 {
106 UINT64 MaxCount;
107 UINT64 Limit;
108
109 //
110 // Check to see if Buffer is NULL
111 //
112 if (Buffer == NULL) {
113 return EFI_INVALID_PARAMETER;
114 }
115
116 //
117 // Check to see if Width is in the valid range
118 //
119 if (Width < 0 || Width >= EfiCpuIoWidthMaximum) {
120 return EFI_INVALID_PARAMETER;
121 }
122
123 //
124 // For FIFO type, the target address won't increase during the access,
125 // so treat Count as 1
126 //
127 if (Width >= EfiCpuIoWidthFifoUint8 && Width <= EfiCpuIoWidthFifoUint64) {
128 Count = 1;
129 }
130
131 //
132 // Check to see if Width is in the valid range for I/O Port operations
133 //
134 Width = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
135 if (!MmioOperation && (Width == EfiCpuIoWidthUint64)) {
136 return EFI_INVALID_PARAMETER;
137 }
138
139 //
140 // Check to see if Address is aligned
141 //
142 if ((Address & (UINT64)(mInStride[Width] - 1)) != 0) {
143 return EFI_UNSUPPORTED;
144 }
145
146 //
147 // Check to see if any address associated with this transfer exceeds the maximum
148 // allowed address. The maximum address implied by the parameters passed in is
149 // Address + Size * Count. If the following condition is met, then the transfer
150 // is not supported.
151 //
152 // Address + Size * Count > (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS) + 1
153 //
154 // Since MAX_ADDRESS can be the maximum integer value supported by the CPU and Count
155 // can also be the maximum integer value supported by the CPU, this range
156 // check must be adjusted to avoid all oveflow conditions.
157 //
158 // The following form of the range check is equivalent but assumes that
159 // MAX_ADDRESS and MAX_IO_PORT_ADDRESS are of the form (2^n - 1).
160 //
161 Limit = (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS);
162 if (Count == 0) {
163 if (Address > Limit) {
164 return EFI_UNSUPPORTED;
165 }
166 } else {
167 MaxCount = RShiftU64 (Limit, Width);
168 if (MaxCount < (Count - 1)) {
169 return EFI_UNSUPPORTED;
170 }
171 if (Address > LShiftU64 (MaxCount - Count + 1, Width)) {
172 return EFI_UNSUPPORTED;
173 }
174 }
175
176 //
177 // Check to see if Buffer is aligned
178 // (IA-32 allows UINT64 and INT64 data types to be 32-bit aligned.)
179 //
180 if (((UINTN)Buffer & ((MIN (sizeof (UINTN), mInStride[Width]) - 1))) != 0) {
181 return EFI_UNSUPPORTED;
182 }
183
184 return EFI_SUCCESS;
185 }
186
187 /**
188 Reads memory-mapped registers.
189
190 The I/O operations are carried out exactly as requested. The caller is responsible
191 for satisfying any alignment and I/O width restrictions that a PI System on a
192 platform might require. For example on some platforms, width requests of
193 EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
194 be handled by the driver.
195
196 If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
197 or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
198 each of the Count operations that is performed.
199
200 If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
201 EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
202 incremented for each of the Count operations that is performed. The read or
203 write operation is performed Count times on the same Address.
204
205 If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
206 EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
207 incremented for each of the Count operations that is performed. The read or
208 write operation is performed Count times from the first element of Buffer.
209
210 @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance.
211 @param[in] Width Signifies the width of the I/O or Memory operation.
212 @param[in] Address The base address of the I/O operation.
213 @param[in] Count The number of I/O operations to perform. The number of
214 bytes moved is Width size * Count, starting at Address.
215 @param[out] Buffer For read operations, the destination buffer to store the results.
216 For write operations, the source buffer from which to write data.
217
218 @retval EFI_SUCCESS The data was read from or written to the PI system.
219 @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
220 @retval EFI_INVALID_PARAMETER Buffer is NULL.
221 @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
222 @retval EFI_UNSUPPORTED The address range specified by Address, Width,
223 and Count is not valid for this PI system.
224
225 **/
226 EFI_STATUS
227 EFIAPI
228 CpuMemoryServiceRead (
229 IN EFI_CPU_IO2_PROTOCOL *This,
230 IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
231 IN UINT64 Address,
232 IN UINTN Count,
233 OUT VOID *Buffer
234 )
235 {
236 EFI_STATUS Status;
237 UINT8 InStride;
238 UINT8 OutStride;
239 EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth;
240 UINT8 *Uint8Buffer;
241
242 Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer);
243 if (EFI_ERROR (Status)) {
244 return Status;
245 }
246
247 //
248 // Select loop based on the width of the transfer
249 //
250 InStride = mInStride[Width];
251 OutStride = mOutStride[Width];
252 OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
253 for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
254 if (OperationWidth == EfiCpuIoWidthUint8) {
255 *Uint8Buffer = MmioRead8 ((UINTN)Address);
256 } else if (OperationWidth == EfiCpuIoWidthUint16) {
257 *((UINT16 *)Uint8Buffer) = MmioRead16 ((UINTN)Address);
258 } else if (OperationWidth == EfiCpuIoWidthUint32) {
259 *((UINT32 *)Uint8Buffer) = MmioRead32 ((UINTN)Address);
260 } else if (OperationWidth == EfiCpuIoWidthUint64) {
261 *((UINT64 *)Uint8Buffer) = MmioRead64 ((UINTN)Address);
262 }
263 }
264 return EFI_SUCCESS;
265 }
266
267 /**
268 Writes memory-mapped registers.
269
270 The I/O operations are carried out exactly as requested. The caller is responsible
271 for satisfying any alignment and I/O width restrictions that a PI System on a
272 platform might require. For example on some platforms, width requests of
273 EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
274 be handled by the driver.
275
276 If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
277 or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
278 each of the Count operations that is performed.
279
280 If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
281 EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
282 incremented for each of the Count operations that is performed. The read or
283 write operation is performed Count times on the same Address.
284
285 If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
286 EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
287 incremented for each of the Count operations that is performed. The read or
288 write operation is performed Count times from the first element of Buffer.
289
290 @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance.
291 @param[in] Width Signifies the width of the I/O or Memory operation.
292 @param[in] Address The base address of the I/O operation.
293 @param[in] Count The number of I/O operations to perform. The number of
294 bytes moved is Width size * Count, starting at Address.
295 @param[in] Buffer For read operations, the destination buffer to store the results.
296 For write operations, the source buffer from which to write data.
297
298 @retval EFI_SUCCESS The data was read from or written to the PI system.
299 @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
300 @retval EFI_INVALID_PARAMETER Buffer is NULL.
301 @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
302 @retval EFI_UNSUPPORTED The address range specified by Address, Width,
303 and Count is not valid for this PI system.
304
305 **/
306 EFI_STATUS
307 EFIAPI
308 CpuMemoryServiceWrite (
309 IN EFI_CPU_IO2_PROTOCOL *This,
310 IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
311 IN UINT64 Address,
312 IN UINTN Count,
313 IN VOID *Buffer
314 )
315 {
316 EFI_STATUS Status;
317 UINT8 InStride;
318 UINT8 OutStride;
319 EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth;
320 UINT8 *Uint8Buffer;
321
322 Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer);
323 if (EFI_ERROR (Status)) {
324 return Status;
325 }
326
327 //
328 // Select loop based on the width of the transfer
329 //
330 InStride = mInStride[Width];
331 OutStride = mOutStride[Width];
332 OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
333 for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
334 if (OperationWidth == EfiCpuIoWidthUint8) {
335 MmioWrite8 ((UINTN)Address, *Uint8Buffer);
336 } else if (OperationWidth == EfiCpuIoWidthUint16) {
337 MmioWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer));
338 } else if (OperationWidth == EfiCpuIoWidthUint32) {
339 MmioWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer));
340 } else if (OperationWidth == EfiCpuIoWidthUint64) {
341 MmioWrite64 ((UINTN)Address, *((UINT64 *)Uint8Buffer));
342 }
343 }
344 return EFI_SUCCESS;
345 }
346
347 /**
348 Reads I/O registers.
349
350 The I/O operations are carried out exactly as requested. The caller is responsible
351 for satisfying any alignment and I/O width restrictions that a PI System on a
352 platform might require. For example on some platforms, width requests of
353 EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
354 be handled by the driver.
355
356 If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
357 or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
358 each of the Count operations that is performed.
359
360 If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
361 EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
362 incremented for each of the Count operations that is performed. The read or
363 write operation is performed Count times on the same Address.
364
365 If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
366 EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
367 incremented for each of the Count operations that is performed. The read or
368 write operation is performed Count times from the first element of Buffer.
369
370 @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance.
371 @param[in] Width Signifies the width of the I/O or Memory operation.
372 @param[in] Address The base address of the I/O operation.
373 @param[in] Count The number of I/O operations to perform. The number of
374 bytes moved is Width size * Count, starting at Address.
375 @param[out] Buffer For read operations, the destination buffer to store the results.
376 For write operations, the source buffer from which to write data.
377
378 @retval EFI_SUCCESS The data was read from or written to the PI system.
379 @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
380 @retval EFI_INVALID_PARAMETER Buffer is NULL.
381 @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
382 @retval EFI_UNSUPPORTED The address range specified by Address, Width,
383 and Count is not valid for this PI system.
384
385 **/
386 EFI_STATUS
387 EFIAPI
388 CpuIoServiceRead (
389 IN EFI_CPU_IO2_PROTOCOL *This,
390 IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
391 IN UINT64 Address,
392 IN UINTN Count,
393 OUT VOID *Buffer
394 )
395 {
396 EFI_STATUS Status;
397 UINT8 InStride;
398 UINT8 OutStride;
399 EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth;
400 UINT8 *Uint8Buffer;
401
402 Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer);
403 if (EFI_ERROR (Status)) {
404 return Status;
405 }
406
407 //
408 // Select loop based on the width of the transfer
409 //
410 InStride = mInStride[Width];
411 OutStride = mOutStride[Width];
412 OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
413 for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
414 if (OperationWidth == EfiCpuIoWidthUint8) {
415 *Uint8Buffer = IoRead8 ((UINTN)Address);
416 } else if (OperationWidth == EfiCpuIoWidthUint16) {
417 *((UINT16 *)Uint8Buffer) = IoRead16 ((UINTN)Address);
418 } else if (OperationWidth == EfiCpuIoWidthUint32) {
419 *((UINT32 *)Uint8Buffer) = IoRead32 ((UINTN)Address);
420 }
421 }
422
423 return EFI_SUCCESS;
424 }
425
426 /**
427 Write I/O registers.
428
429 The I/O operations are carried out exactly as requested. The caller is responsible
430 for satisfying any alignment and I/O width restrictions that a PI System on a
431 platform might require. For example on some platforms, width requests of
432 EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
433 be handled by the driver.
434
435 If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
436 or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
437 each of the Count operations that is performed.
438
439 If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
440 EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
441 incremented for each of the Count operations that is performed. The read or
442 write operation is performed Count times on the same Address.
443
444 If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
445 EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
446 incremented for each of the Count operations that is performed. The read or
447 write operation is performed Count times from the first element of Buffer.
448
449 @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance.
450 @param[in] Width Signifies the width of the I/O or Memory operation.
451 @param[in] Address The base address of the I/O operation.
452 @param[in] Count The number of I/O operations to perform. The number of
453 bytes moved is Width size * Count, starting at Address.
454 @param[in] Buffer For read operations, the destination buffer to store the results.
455 For write operations, the source buffer from which to write data.
456
457 @retval EFI_SUCCESS The data was read from or written to the PI system.
458 @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
459 @retval EFI_INVALID_PARAMETER Buffer is NULL.
460 @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
461 @retval EFI_UNSUPPORTED The address range specified by Address, Width,
462 and Count is not valid for this PI system.
463
464 **/
465 EFI_STATUS
466 EFIAPI
467 CpuIoServiceWrite (
468 IN EFI_CPU_IO2_PROTOCOL *This,
469 IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
470 IN UINT64 Address,
471 IN UINTN Count,
472 IN VOID *Buffer
473 )
474 {
475 EFI_STATUS Status;
476 UINT8 InStride;
477 UINT8 OutStride;
478 EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth;
479 UINT8 *Uint8Buffer;
480
481 //
482 // Make sure the parameters are valid
483 //
484 Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer);
485 if (EFI_ERROR (Status)) {
486 return Status;
487 }
488
489 //
490 // Select loop based on the width of the transfer
491 //
492 InStride = mInStride[Width];
493 OutStride = mOutStride[Width];
494 OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
495 for (Uint8Buffer = (UINT8 *)Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
496 if (OperationWidth == EfiCpuIoWidthUint8) {
497 IoWrite8 ((UINTN)Address, *Uint8Buffer);
498 } else if (OperationWidth == EfiCpuIoWidthUint16) {
499 IoWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer));
500 } else if (OperationWidth == EfiCpuIoWidthUint32) {
501 IoWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer));
502 }
503 }
504
505 return EFI_SUCCESS;
506 }
507
508 /**
509 The user Entry Point for module CpuIo2Dxe. The user code starts with this function.
510
511 @param[in] ImageHandle The firmware allocated handle for the EFI image.
512 @param[in] SystemTable A pointer to the EFI System Table.
513
514 @retval EFI_SUCCESS The entry point is executed successfully.
515 @retval other Some error occurs when executing this entry point.
516
517 **/
518 EFI_STATUS
519 EFIAPI
520 CpuIo2Initialize (
521 IN EFI_HANDLE ImageHandle,
522 IN EFI_SYSTEM_TABLE *SystemTable
523 )
524 {
525 EFI_STATUS Status;
526
527 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiCpuIo2ProtocolGuid);
528 Status = gBS->InstallMultipleProtocolInterfaces (
529 &mHandle,
530 &gEfiCpuIo2ProtocolGuid, &mCpuIo2,
531 NULL
532 );
533 ASSERT_EFI_ERROR (Status);
534
535 return Status;
536 }