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