]> git.proxmox.com Git - mirror_edk2.git/blob - DuetPkg/CpuIoDxe/CpuIo.c
f95697130cefbde4105ed2d05f379c241f58e43e
[mirror_edk2.git] / DuetPkg / CpuIoDxe / CpuIo.c
1 /*++
2
3 Copyright (c) 2004 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13 CpuIo.c
14
15 Abstract:
16
17 This is the code that publishes the CPU I/O Protocol.
18 The intent herein is to have a single I/O service that can load
19 as early as possible, extend into runtime, and be layered upon by
20 the implementations of architectural protocols and the PCI Root
21 Bridge I/O Protocol.
22
23 --*/
24
25 #include "CpuIo.h"
26 #include "CpuIoAccess.h"
27
28 #define IA32_MAX_IO_ADDRESS 0xFFFF
29
30 EFI_CPU_IO_PROTOCOL mCpuIo = {
31 {
32 CpuMemoryServiceRead,
33 CpuMemoryServiceWrite
34 },
35 {
36 CpuIoServiceRead,
37 CpuIoServiceWrite
38 }
39 };
40
41 STATIC
42 EFI_STATUS
43 CpuIoMemRW (
44 IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
45 IN UINTN Count,
46 IN BOOLEAN DestinationStrideFlag,
47 OUT PTR Destination,
48 IN BOOLEAN SourceStrideFlag,
49 IN PTR Source
50 )
51 /*++
52
53 Routine Description:
54
55 Private service to perform memory mapped I/O read/write
56
57 Arguments:
58
59 Width - Width of the memory mapped I/O operation
60 Count - Count of the number of accesses to perform
61 DestinationStrideFlag - Boolean flag indicates if the destination is to be incremented
62 Destination - Destination of the memory mapped I/O operation
63 SourceStrideFlag - Boolean flag indicates if the source is to be incremented
64 Source - Source of the memory mapped I/O operation
65
66 Returns:
67
68 EFI_SUCCESS - Successful operation
69 EFI_INVALID_PARAMETER - Width is invalid
70
71 --*/
72 {
73 UINTN Stride;
74 UINTN DestinationStride;
75 UINTN SourceStride;
76
77 Width = Width & 0x03;
78 Stride = (UINTN)1 << Width;
79 DestinationStride = DestinationStrideFlag ? Stride : 0;
80 SourceStride = SourceStrideFlag ? Stride : 0;
81
82 //
83 // Loop for each iteration and move the data
84 //
85 switch (Width) {
86 case EfiCpuIoWidthUint8:
87 for (; Count > 0; Count--, Destination.buf += DestinationStride, Source.buf += SourceStride) {
88 MemoryFence();
89 *Destination.ui8 = *Source.ui8;
90 MemoryFence();
91 }
92 break;
93
94 case EfiCpuIoWidthUint16:
95 for (; Count > 0; Count--, Destination.buf += DestinationStride, Source.buf += SourceStride) {
96 MemoryFence ();
97 *Destination.ui16 = *Source.ui16;
98 MemoryFence ();
99 }
100 break;
101
102 case EfiCpuIoWidthUint32:
103 for (; Count > 0; Count--, Destination.buf += DestinationStride, Source.buf += SourceStride) {
104 MemoryFence ();
105 *Destination.ui32 = *Source.ui32;
106 MemoryFence ();
107 }
108 break;
109
110 case EfiCpuIoWidthUint64:
111 for (; Count > 0; Count--, Destination.buf += DestinationStride, Source.buf += SourceStride) {
112 MemoryFence ();
113 *Destination.ui64 = *Source.ui64;
114 MemoryFence ();
115 }
116 break;
117
118 default:
119 return EFI_INVALID_PARAMETER;
120 }
121
122 return EFI_SUCCESS;
123 }
124
125 EFI_STATUS
126 EFIAPI
127 CpuMemoryServiceRead (
128 IN EFI_CPU_IO_PROTOCOL *This,
129 IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
130 IN UINT64 Address,
131 IN UINTN Count,
132 OUT VOID *Buffer
133 )
134 /*++
135
136 Routine Description:
137
138 Perform the memory mapped I/O read service
139
140 Arguments:
141
142 This - Pointer to an instance of the CPU I/O Protocol
143 Width - Width of the memory mapped I/O operation
144 Address - Base address of the memory mapped I/O operation
145 Count - Count of the number of accesses to perform
146 Buffer - Pointer to the destination buffer to store the results
147
148 Returns:
149
150 EFI_SUCCESS - The data was read.
151 EFI_INVALID_PARAMETER - Width is invalid.
152 EFI_INVALID_PARAMETER - Buffer is NULL.
153 EFI_UNSUPPORTED - The Buffer is not aligned for the given Width.
154 EFI_UNSUPPORTED - The address range specified by Address, Width,
155 and Count is not valid.
156
157 --*/
158 {
159 PTR Source;
160 PTR Destination;
161 EFI_STATUS Status;
162
163 Status = CpuIoCheckParameter (Width, Address, Count, Buffer, EFI_MAX_ADDRESS);
164 if (EFI_ERROR (Status)) {
165 return Status;
166 }
167
168 Destination.buf = Buffer;
169 Source.buf = (VOID *) (UINTN) Address;
170
171 if (Width >= EfiCpuIoWidthUint8 && Width <= EfiCpuIoWidthUint64) {
172 return CpuIoMemRW (Width, Count, TRUE, Destination, TRUE, Source);
173 }
174
175 if (Width >= EfiCpuIoWidthFifoUint8 && Width <= EfiCpuIoWidthFifoUint64) {
176 return CpuIoMemRW (Width, Count, TRUE, Destination, FALSE, Source);
177 }
178
179 if (Width >= EfiCpuIoWidthFillUint8 && Width <= EfiCpuIoWidthFillUint64) {
180 return CpuIoMemRW (Width, Count, FALSE, Destination, TRUE, Source);
181 }
182
183 return EFI_INVALID_PARAMETER;
184 }
185
186 EFI_STATUS
187 EFIAPI
188 CpuMemoryServiceWrite (
189 IN EFI_CPU_IO_PROTOCOL *This,
190 IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
191 IN UINT64 Address,
192 IN UINTN Count,
193 IN VOID *Buffer
194 )
195 /*++
196
197 Routine Description:
198
199 Perform the memory mapped I/O write service
200
201 Arguments:
202
203 This - Pointer to an instance of the CPU I/O Protocol
204 Width - Width of the memory mapped I/O operation
205 Address - Base address of the memory mapped I/O operation
206 Count - Count of the number of accesses to perform
207 Buffer - Pointer to the source buffer from which to write data
208
209 Returns:
210
211 EFI_SUCCESS - The data was written.
212 EFI_INVALID_PARAMETER - Width is invalid.
213 EFI_INVALID_PARAMETER - Buffer is NULL.
214 EFI_UNSUPPORTED - The Buffer is not aligned for the given Width.
215 EFI_UNSUPPORTED - The address range specified by Address, Width,
216 and Count is not valid.
217
218 --*/
219 {
220 PTR Source;
221 PTR Destination;
222 EFI_STATUS Status;
223
224 Status = CpuIoCheckParameter (Width, Address, Count, Buffer, EFI_MAX_ADDRESS);
225 if (EFI_ERROR (Status)) {
226 return Status;
227 }
228
229 Destination.buf = (VOID *) (UINTN) Address;
230 Source.buf = Buffer;
231
232 if (Width >= EfiCpuIoWidthUint8 && Width <= EfiCpuIoWidthUint64) {
233 return CpuIoMemRW (Width, Count, TRUE, Destination, TRUE, Source);
234 }
235
236 if (Width >= EfiCpuIoWidthFifoUint8 && Width <= EfiCpuIoWidthFifoUint64) {
237 return CpuIoMemRW (Width, Count, FALSE, Destination, TRUE, Source);
238 }
239
240 if (Width >= EfiCpuIoWidthFillUint8 && Width <= EfiCpuIoWidthFillUint64) {
241 return CpuIoMemRW (Width, Count, TRUE, Destination, FALSE, Source);
242 }
243
244 return EFI_INVALID_PARAMETER;
245 }
246
247 EFI_STATUS
248 EFIAPI
249 CpuIoServiceRead (
250 IN EFI_CPU_IO_PROTOCOL *This,
251 IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
252 IN UINT64 UserAddress,
253 IN UINTN Count,
254 OUT VOID *UserBuffer
255 )
256 /*++
257
258 Routine Description:
259
260 Perform the port I/O read service
261
262 Arguments:
263
264 This - Pointer to an instance of the CPU I/O Protocol
265 Width - Width of the port I/O operation
266 Address - Base address of the port I/O operation
267 Count - Count of the number of accesses to perform
268 Buffer - Pointer to the destination buffer to store the results
269
270 Returns:
271
272 EFI_SUCCESS - The data was read.
273 EFI_INVALID_PARAMETER - Width is invalid.
274 EFI_INVALID_PARAMETER - Buffer is NULL.
275 EFI_UNSUPPORTED - The Buffer is not aligned for the given Width.
276 EFI_UNSUPPORTED - The address range specified by Address, Width,
277 and Count is not valid.
278
279 --*/
280 {
281 UINTN InStride;
282 UINTN OutStride;
283 UINTN Address;
284 PTR Buffer;
285 EFI_STATUS Status;
286
287 Buffer.buf = (UINT8 *) UserBuffer;
288
289 if (Width >= EfiCpuIoWidthMaximum) {
290 return EFI_INVALID_PARAMETER;
291 }
292
293 Status = CpuIoCheckParameter (Width, UserAddress, Count, UserBuffer, IA32_MAX_IO_ADDRESS);
294 if (EFI_ERROR (Status)) {
295 return Status;
296 }
297
298 Address = (UINTN) UserAddress;
299 InStride = (UINTN)1 << (Width & 0x03);
300 OutStride = InStride;
301 if (Width >= EfiCpuIoWidthFifoUint8 && Width <= EfiCpuIoWidthFifoUint64) {
302 InStride = 0;
303 }
304
305 if (Width >= EfiCpuIoWidthFillUint8 && Width <= EfiCpuIoWidthFillUint64) {
306 OutStride = 0;
307 }
308
309 Width = Width & 0x03;
310
311 //
312 // Loop for each iteration and move the data
313 //
314 switch (Width) {
315 case EfiCpuIoWidthUint8:
316 for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) {
317 *Buffer.ui8 = CpuIoRead8 ((UINT16) Address);
318 }
319 break;
320
321 case EfiCpuIoWidthUint16:
322 for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) {
323 *Buffer.ui16 = CpuIoRead16 ((UINT16) Address);
324 }
325 break;
326
327 case EfiCpuIoWidthUint32:
328 for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) {
329 *Buffer.ui32 = CpuIoRead32 ((UINT16) Address);
330 }
331 break;
332
333 default:
334 return EFI_INVALID_PARAMETER;
335 }
336
337 return EFI_SUCCESS;
338 }
339
340 EFI_STATUS
341 EFIAPI
342 CpuIoServiceWrite (
343 IN EFI_CPU_IO_PROTOCOL *This,
344 IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
345 IN UINT64 UserAddress,
346 IN UINTN Count,
347 IN VOID *UserBuffer
348 )
349 /*++
350
351 Routine Description:
352
353 Perform the port I/O write service
354
355 Arguments:
356
357 This - Pointer to an instance of the CPU I/O Protocol
358 Width - Width of the port I/O operation
359 Address - Base address of the port I/O operation
360 Count - Count of the number of accesses to perform
361 Buffer - Pointer to the source buffer from which to write data
362
363 Returns:
364
365 EFI_SUCCESS - The data was written.
366 EFI_INVALID_PARAMETER - Width is invalid.
367 EFI_INVALID_PARAMETER - Buffer is NULL.
368 EFI_UNSUPPORTED - The Buffer is not aligned for the given Width.
369 EFI_UNSUPPORTED - The address range specified by Address, Width,
370 and Count is not valid.
371
372 --*/
373 {
374 UINTN InStride;
375 UINTN OutStride;
376 UINTN Address;
377 PTR Buffer;
378 EFI_STATUS Status;
379
380 Buffer.buf = (UINT8 *) UserBuffer;
381
382 if (Width >= EfiCpuIoWidthMaximum) {
383 return EFI_INVALID_PARAMETER;
384 }
385
386 Status = CpuIoCheckParameter (Width, UserAddress, Count, UserBuffer, IA32_MAX_IO_ADDRESS);
387 if (EFI_ERROR (Status)) {
388 return Status;
389 }
390
391 Address = (UINTN) UserAddress;
392 InStride = (UINTN)1 << (Width & 0x03);
393 OutStride = InStride;
394 if (Width >= EfiCpuIoWidthFifoUint8 && Width <= EfiCpuIoWidthFifoUint64) {
395 InStride = 0;
396 }
397
398 if (Width >= EfiCpuIoWidthFillUint8 && Width <= EfiCpuIoWidthFillUint64) {
399 OutStride = 0;
400 }
401
402 Width = Width & 0x03;
403
404 //
405 // Loop for each iteration and move the data
406 //
407 switch (Width) {
408 case EfiCpuIoWidthUint8:
409 for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) {
410 CpuIoWrite8 ((UINT16) Address, *Buffer.ui8);
411 }
412 break;
413
414 case EfiCpuIoWidthUint16:
415 for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) {
416 CpuIoWrite16 ((UINT16) Address, *Buffer.ui16);
417 }
418 break;
419
420 case EfiCpuIoWidthUint32:
421 for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) {
422 CpuIoWrite32 ((UINT16) Address, *Buffer.ui32);
423 }
424 break;
425
426 default:
427 return EFI_INVALID_PARAMETER;
428 }
429
430 return EFI_SUCCESS;
431 }
432
433 EFI_STATUS
434 EFIAPI
435 CpuIoInitialize (
436 IN EFI_HANDLE ImageHandle,
437 IN EFI_SYSTEM_TABLE *SystemTable
438 )
439 /*++
440
441 Routine Description:
442
443 CpuIo driver entry point.
444
445 Arguments:
446
447 ImageHandle - The firmware allocated handle for the EFI image.
448 SystemTable - A pointer to the EFI System Table.
449
450 Returns:
451
452 EFI_SUCCESS - The driver was initialized.
453 EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of resources.
454
455 --*/
456 {
457 EFI_STATUS Status;
458 EFI_HANDLE Handle;
459
460 Handle = NULL;
461 Status = SystemTable->BootServices->InstallProtocolInterface (
462 &Handle,
463 &gEfiCpuIoProtocolGuid,
464 EFI_NATIVE_INTERFACE,
465 &mCpuIo
466 );
467 ASSERT_EFI_ERROR (Status);
468
469 return Status;
470 }
471
472 EFI_STATUS
473 CpuIoCheckParameter (
474 IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
475 IN UINT64 Address,
476 IN UINTN Count,
477 IN VOID *Buffer,
478 IN UINT64 Limit
479 )
480 /*++
481
482 Routine Description:
483
484 Check the validation of parameters for CPU I/O interface functions.
485
486 Arguments:
487
488 Width - Width of the Memory Access
489 Address - Address of the Memory access
490 Count - Count of the number of accesses to perform
491 Buffer - Pointer to the buffer to read from memory
492 Buffer - Memory buffer for the I/O operation
493 Limit - Maximum address supported
494
495 Returns:
496
497 EFI_INVALID_PARAMETER - Buffer is NULL
498 EFI_UNSUPPORTED - The address range specified by Width, Address and Count is invalid
499 EFI_UNSUPPORTED - The memory buffer is not aligned
500 EFI_SUCCESS - Parameters are OK
501
502 --*/
503 {
504 UINTN AlignMask;
505
506 if (Buffer == NULL) {
507 return EFI_INVALID_PARAMETER;
508 }
509
510 if (Address > Limit) {
511 return EFI_UNSUPPORTED;
512 }
513
514 //
515 // For FiFo type, the target address won't increase during the access,
516 // so treat count as 1
517 //
518 if (Width >= EfiCpuIoWidthFifoUint8 && Width <= EfiCpuIoWidthFifoUint64) {
519 Count = 1;
520 }
521
522 Width = Width & 0x03;
523 if (Address - 1 + ((UINTN)1 << Width) * Count > Limit) {
524 return EFI_UNSUPPORTED;
525 }
526
527 AlignMask = ((UINTN)1 << Width) - 1;
528 if ((UINTN) Buffer & AlignMask) {
529 return EFI_UNSUPPORTED;
530 }
531
532 return EFI_SUCCESS;
533 }