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