Code refinement.
[mirror_edk2.git] / UefiCpuPkg / CpuIo2Dxe / CpuIo2Dxe.c
1 /** @file
2 Produces the CPU I/O 2 Protocol.
3
4 Copyright (c) 2009 - 2010, 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 //
179 if (((UINTN)Buffer & (mInStride[Width] - 1)) != 0) {
180 return EFI_UNSUPPORTED;
181 }
182
183 return EFI_SUCCESS;
184 }
185
186 /**
187 Reads memory-mapped registers.
188
189 The I/O operations are carried out exactly as requested. The caller is responsible
190 for satisfying any alignment and I/O width restrictions that a PI System on a
191 platform might require. For example on some platforms, width requests of
192 EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
193 be handled by the driver.
194
195 If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
196 or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
197 each of the Count operations that is performed.
198
199 If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
200 EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
201 incremented for each of the Count operations that is performed. The read or
202 write operation is performed Count times on the same Address.
203
204 If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
205 EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
206 incremented for each of the Count operations that is performed. The read or
207 write operation is performed Count times from the first element of Buffer.
208
209 @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance.
210 @param[in] Width Signifies the width of the I/O or Memory operation.
211 @param[in] Address The base address of the I/O operation.
212 @param[in] Count The number of I/O operations to perform. The number of
213 bytes moved is Width size * Count, starting at Address.
214 @param[out] Buffer For read operations, the destination buffer to store the results.
215 For write operations, the source buffer from which to write data.
216
217 @retval EFI_SUCCESS The data was read from or written to the PI system.
218 @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
219 @retval EFI_INVALID_PARAMETER Buffer is NULL.
220 @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
221 @retval EFI_UNSUPPORTED The address range specified by Address, Width,
222 and Count is not valid for this PI system.
223
224 **/
225 EFI_STATUS
226 EFIAPI
227 CpuMemoryServiceRead (
228 IN EFI_CPU_IO2_PROTOCOL *This,
229 IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
230 IN UINT64 Address,
231 IN UINTN Count,
232 OUT VOID *Buffer
233 )
234 {
235 EFI_STATUS Status;
236 UINT8 InStride;
237 UINT8 OutStride;
238 EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth;
239 UINT8 *Uint8Buffer;
240
241 Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer);
242 if (EFI_ERROR (Status)) {
243 return Status;
244 }
245
246 //
247 // Select loop based on the width of the transfer
248 //
249 InStride = mInStride[Width];
250 OutStride = mOutStride[Width];
251 OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
252 for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
253 if (OperationWidth == EfiCpuIoWidthUint8) {
254 *Uint8Buffer = MmioRead8 ((UINTN)Address);
255 } else if (OperationWidth == EfiCpuIoWidthUint16) {
256 *((UINT16 *)Uint8Buffer) = MmioRead16 ((UINTN)Address);
257 } else if (OperationWidth == EfiCpuIoWidthUint32) {
258 *((UINT32 *)Uint8Buffer) = MmioRead32 ((UINTN)Address);
259 } else if (OperationWidth == EfiCpuIoWidthUint64) {
260 *((UINT64 *)Uint8Buffer) = MmioRead64 ((UINTN)Address);
261 }
262 }
263 return EFI_SUCCESS;
264 }
265
266 /**
267 Writes memory-mapped registers.
268
269 The I/O operations are carried out exactly as requested. The caller is responsible
270 for satisfying any alignment and I/O width restrictions that a PI System on a
271 platform might require. For example on some platforms, width requests of
272 EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
273 be handled by the driver.
274
275 If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
276 or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
277 each of the Count operations that is performed.
278
279 If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
280 EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
281 incremented for each of the Count operations that is performed. The read or
282 write operation is performed Count times on the same Address.
283
284 If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
285 EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
286 incremented for each of the Count operations that is performed. The read or
287 write operation is performed Count times from the first element of Buffer.
288
289 @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance.
290 @param[in] Width Signifies the width of the I/O or Memory operation.
291 @param[in] Address The base address of the I/O operation.
292 @param[in] Count The number of I/O operations to perform. The number of
293 bytes moved is Width size * Count, starting at Address.
294 @param[in] Buffer For read operations, the destination buffer to store the results.
295 For write operations, the source buffer from which to write data.
296
297 @retval EFI_SUCCESS The data was read from or written to the PI system.
298 @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
299 @retval EFI_INVALID_PARAMETER Buffer is NULL.
300 @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
301 @retval EFI_UNSUPPORTED The address range specified by Address, Width,
302 and Count is not valid for this PI system.
303
304 **/
305 EFI_STATUS
306 EFIAPI
307 CpuMemoryServiceWrite (
308 IN EFI_CPU_IO2_PROTOCOL *This,
309 IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
310 IN UINT64 Address,
311 IN UINTN Count,
312 IN VOID *Buffer
313 )
314 {
315 EFI_STATUS Status;
316 UINT8 InStride;
317 UINT8 OutStride;
318 EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth;
319 UINT8 *Uint8Buffer;
320
321 Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer);
322 if (EFI_ERROR (Status)) {
323 return Status;
324 }
325
326 //
327 // Select loop based on the width of the transfer
328 //
329 InStride = mInStride[Width];
330 OutStride = mOutStride[Width];
331 OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
332 for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
333 if (OperationWidth == EfiCpuIoWidthUint8) {
334 MmioWrite8 ((UINTN)Address, *Uint8Buffer);
335 } else if (OperationWidth == EfiCpuIoWidthUint16) {
336 MmioWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer));
337 } else if (OperationWidth == EfiCpuIoWidthUint32) {
338 MmioWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer));
339 } else if (OperationWidth == EfiCpuIoWidthUint64) {
340 MmioWrite64 ((UINTN)Address, *((UINT64 *)Uint8Buffer));
341 }
342 }
343 return EFI_SUCCESS;
344 }
345
346 /**
347 Reads I/O registers.
348
349 The I/O operations are carried out exactly as requested. The caller is responsible
350 for satisfying any alignment and I/O width restrictions that a PI System on a
351 platform might require. For example on some platforms, width requests of
352 EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
353 be handled by the driver.
354
355 If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
356 or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
357 each of the Count operations that is performed.
358
359 If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
360 EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
361 incremented for each of the Count operations that is performed. The read or
362 write operation is performed Count times on the same Address.
363
364 If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
365 EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
366 incremented for each of the Count operations that is performed. The read or
367 write operation is performed Count times from the first element of Buffer.
368
369 @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance.
370 @param[in] Width Signifies the width of the I/O or Memory operation.
371 @param[in] Address The base address of the I/O operation.
372 @param[in] Count The number of I/O operations to perform. The number of
373 bytes moved is Width size * Count, starting at Address.
374 @param[out] Buffer For read operations, the destination buffer to store the results.
375 For write operations, the source buffer from which to write data.
376
377 @retval EFI_SUCCESS The data was read from or written to the PI system.
378 @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
379 @retval EFI_INVALID_PARAMETER Buffer is NULL.
380 @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
381 @retval EFI_UNSUPPORTED The address range specified by Address, Width,
382 and Count is not valid for this PI system.
383
384 **/
385 EFI_STATUS
386 EFIAPI
387 CpuIoServiceRead (
388 IN EFI_CPU_IO2_PROTOCOL *This,
389 IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
390 IN UINT64 Address,
391 IN UINTN Count,
392 OUT VOID *Buffer
393 )
394 {
395 EFI_STATUS Status;
396 UINT8 InStride;
397 UINT8 OutStride;
398 EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth;
399 UINT8 *Uint8Buffer;
400
401 Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer);
402 if (EFI_ERROR (Status)) {
403 return Status;
404 }
405
406 //
407 // Select loop based on the width of the transfer
408 //
409 InStride = mInStride[Width];
410 OutStride = mOutStride[Width];
411 OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
412 for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
413 if (OperationWidth == EfiCpuIoWidthUint8) {
414 *Uint8Buffer = IoRead8 ((UINTN)Address);
415 } else if (OperationWidth == EfiCpuIoWidthUint16) {
416 *((UINT16 *)Uint8Buffer) = IoRead16 ((UINTN)Address);
417 } else if (OperationWidth == EfiCpuIoWidthUint32) {
418 *((UINT32 *)Uint8Buffer) = IoRead32 ((UINTN)Address);
419 }
420 }
421
422 return EFI_SUCCESS;
423 }
424
425 /**
426 Write I/O registers.
427
428 The I/O operations are carried out exactly as requested. The caller is responsible
429 for satisfying any alignment and I/O width restrictions that a PI System on a
430 platform might require. For example on some platforms, width requests of
431 EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
432 be handled by the driver.
433
434 If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
435 or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
436 each of the Count operations that is performed.
437
438 If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
439 EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
440 incremented for each of the Count operations that is performed. The read or
441 write operation is performed Count times on the same Address.
442
443 If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
444 EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
445 incremented for each of the Count operations that is performed. The read or
446 write operation is performed Count times from the first element of Buffer.
447
448 @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance.
449 @param[in] Width Signifies the width of the I/O or Memory operation.
450 @param[in] Address The base address of the I/O operation.
451 @param[in] Count The number of I/O operations to perform. The number of
452 bytes moved is Width size * Count, starting at Address.
453 @param[in] Buffer For read operations, the destination buffer to store the results.
454 For write operations, the source buffer from which to write data.
455
456 @retval EFI_SUCCESS The data was read from or written to the PI system.
457 @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
458 @retval EFI_INVALID_PARAMETER Buffer is NULL.
459 @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
460 @retval EFI_UNSUPPORTED The address range specified by Address, Width,
461 and Count is not valid for this PI system.
462
463 **/
464 EFI_STATUS
465 EFIAPI
466 CpuIoServiceWrite (
467 IN EFI_CPU_IO2_PROTOCOL *This,
468 IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
469 IN UINT64 Address,
470 IN UINTN Count,
471 IN VOID *Buffer
472 )
473 {
474 EFI_STATUS Status;
475 UINT8 InStride;
476 UINT8 OutStride;
477 EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth;
478 UINT8 *Uint8Buffer;
479
480 //
481 // Make sure the parameters are valid
482 //
483 Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer);
484 if (EFI_ERROR (Status)) {
485 return Status;
486 }
487
488 //
489 // Select loop based on the width of the transfer
490 //
491 InStride = mInStride[Width];
492 OutStride = mOutStride[Width];
493 OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
494 for (Uint8Buffer = (UINT8 *)Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
495 if (OperationWidth == EfiCpuIoWidthUint8) {
496 IoWrite8 ((UINTN)Address, *Uint8Buffer);
497 } else if (OperationWidth == EfiCpuIoWidthUint16) {
498 IoWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer));
499 } else if (OperationWidth == EfiCpuIoWidthUint32) {
500 IoWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer));
501 }
502 }
503
504 return EFI_SUCCESS;
505 }
506
507 /**
508 The user Entry Point for module CpuIo2Dxe. The user code starts with this function.
509
510 @param[in] ImageHandle The firmware allocated handle for the EFI image.
511 @param[in] SystemTable A pointer to the EFI System Table.
512
513 @retval EFI_SUCCESS The entry point is executed successfully.
514 @retval other Some error occurs when executing this entry point.
515
516 **/
517 EFI_STATUS
518 EFIAPI
519 CpuIo2Initialize (
520 IN EFI_HANDLE ImageHandle,
521 IN EFI_SYSTEM_TABLE *SystemTable
522 )
523 {
524 EFI_STATUS Status;
525
526 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiCpuIo2ProtocolGuid);
527 Status = gBS->InstallMultipleProtocolInterfaces (
528 &mHandle,
529 &gEfiCpuIo2ProtocolGuid, &mCpuIo2,
530 NULL
531 );
532 ASSERT_EFI_ERROR (Status);
533
534 return Status;
535 }