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