1 /**@file
2 
3 Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
4 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 
14   CpuIo.c
15 
16 Abstract:
17 
18   This is the code that publishes the CPU I/O Protocol.
19   The intent herein is to have a single I/O service that can load
20   as early as possible, extend into runtime, and be layered upon by
21   the implementations of architectural protocols and the PCI Root
22   Bridge I/O Protocol.
23 
24 **/
25 
26 #include <CpuDriver.h>
27 
28 #define IA32_MAX_IO_ADDRESS   0xFFFF
29 #define IA32_MAX_MEM_ADDRESS  0xFFFFFFFF
30 
31 EFI_STATUS
32 CpuIoCheckAddressRange (
33   IN  EFI_CPU_IO_PROTOCOL_WIDTH         Width,
34   IN  UINT64                            Address,
35   IN  UINTN                             Count,
36   IN  VOID                              *Buffer,
37   IN  UINT64                            Limit
38   );
39 
40 EFI_STATUS
41 EFIAPI
CpuMemoryServiceRead(IN EFI_CPU_IO2_PROTOCOL * This,IN EFI_CPU_IO_PROTOCOL_WIDTH Width,IN UINT64 Address,IN UINTN Count,IN OUT VOID * Buffer)42 CpuMemoryServiceRead (
43   IN  EFI_CPU_IO2_PROTOCOL              *This,
44   IN  EFI_CPU_IO_PROTOCOL_WIDTH         Width,
45   IN  UINT64                            Address,
46   IN  UINTN                             Count,
47   IN  OUT VOID                          *Buffer
48   )
49 /*++
50 
51 Routine Description:
52 
53   Perform the Memory Access Read service for the CPU I/O Protocol
54 
55 Arguments:
56 
57   Pointer to an instance of the CPU I/O Protocol
58   Width of the Memory Access
59   Address of the Memory access
60   Count of the number of accesses to perform
61   Pointer to the buffer to read or write from memory
62 
63 Returns:
64 
65   Status
66 
67   EFI_SUCCESS             - The data was read from or written to the EFI
68                             System.
69   EFI_INVALID_PARAMETER   - Width is invalid for this EFI System.
70   EFI_INVALID_PARAMETER   - Buffer is NULL.
71   EFI_UNSUPPORTED         - The Buffer is not aligned for the given Width.
72   EFI_UNSUPPORTED         - The address range specified by Address, Width,
73                             and Count is not valid for this EFI System.
74 
75 --*/
76 // TODO:    This - add argument and description to function comment
77 {
78   EFI_STATUS  Status;
79 
80   if (!Buffer) {
81     return EFI_INVALID_PARAMETER;
82   }
83 
84   if ((Width < 0) || (Width >= EfiCpuIoWidthMaximum)) {
85     return EFI_INVALID_PARAMETER;
86   }
87 
88   Status = CpuIoCheckAddressRange (Width, Address, Count, Buffer, IA32_MAX_MEM_ADDRESS);
89   if (EFI_ERROR (Status)) {
90     return Status;
91   }
92 
93   //
94   // Do nothing for Nt32 version
95   //
96   return EFI_UNSUPPORTED;
97 }
98 
99 EFI_STATUS
100 EFIAPI
CpuMemoryServiceWrite(IN EFI_CPU_IO2_PROTOCOL * This,IN EFI_CPU_IO_PROTOCOL_WIDTH Width,IN UINT64 Address,IN UINTN Count,IN OUT VOID * Buffer)101 CpuMemoryServiceWrite (
102   IN EFI_CPU_IO2_PROTOCOL               *This,
103   IN  EFI_CPU_IO_PROTOCOL_WIDTH         Width,
104   IN  UINT64                            Address,
105   IN  UINTN                             Count,
106   IN  OUT VOID                          *Buffer
107   )
108 /*++
109 
110 Routine Description:
111 
112   Perform the Memory Access Read service for the CPU I/O Protocol
113 
114 Arguments:
115 
116   Pointer to an instance of the CPU I/O Protocol
117   Width of the Memory Access
118   Address of the Memory access
119   Count of the number of accesses to perform
120   Pointer to the buffer to read or write from memory
121 
122 Returns:
123 
124   Status
125 
126   EFI_SUCCESS             - The data was read from or written to the EFI System.
127   EFI_INVALID_PARAMETER   - Width is invalid for this EFI System.
128   EFI_INVALID_PARAMETER   - Buffer is NULL.
129   EFI_UNSUPPORTED         - The Buffer is not aligned for the given Width.
130   EFI_UNSUPPORTED         - The address range specified by Address, Width, and
131                             Count is not valid for this EFI System.
132 
133 --*/
134 // TODO:    This - add argument and description to function comment
135 {
136   EFI_STATUS  Status;
137 
138   if (!Buffer) {
139     return EFI_INVALID_PARAMETER;
140   }
141 
142   if ((Width < 0) || (Width >= EfiCpuIoWidthMaximum)) {
143     return EFI_INVALID_PARAMETER;
144   }
145 
146   Status = CpuIoCheckAddressRange (Width, Address, Count, Buffer, IA32_MAX_MEM_ADDRESS);
147   if (EFI_ERROR (Status)) {
148     return Status;
149   }
150 
151   //
152   // Do nothing for Nt32 version
153   //
154   return EFI_UNSUPPORTED;
155 }
156 
157 EFI_STATUS
158 EFIAPI
CpuIoServiceRead(IN EFI_CPU_IO2_PROTOCOL * This,IN EFI_CPU_IO_PROTOCOL_WIDTH Width,IN UINT64 UserAddress,IN UINTN Count,IN OUT VOID * UserBuffer)159 CpuIoServiceRead (
160   IN EFI_CPU_IO2_PROTOCOL               *This,
161   IN  EFI_CPU_IO_PROTOCOL_WIDTH         Width,
162   IN  UINT64                            UserAddress,
163   IN  UINTN                             Count,
164   IN  OUT VOID                          *UserBuffer
165   )
166 /*++
167 
168 Routine Description:
169 
170   This is the service that implements the I/O read
171 
172 Arguments:
173 
174   Pointer to an instance of the CPU I/O Protocol
175   Width of the Memory Access
176   Address of the I/O access
177   Count of the number of accesses to perform
178   Pointer to the buffer to read or write from I/O space
179 
180 Returns:
181 
182   Status
183   EFI_SUCCESS             - The data was read from or written to the EFI System.
184   EFI_INVALID_PARAMETER   - Width is invalid for this EFI System.
185   EFI_INVALID_PARAMETER   - Buffer is NULL.
186   EFI_UNSUPPORTED         - The Buffer is not aligned for the given Width.
187   EFI_UNSUPPORTED         - The address range specified by Address, Width, and
188                             Count is not valid for this EFI System.
189 --*/
190 // TODO:    This - add argument and description to function comment
191 // TODO:    UserAddress - add argument and description to function comment
192 // TODO:    UserBuffer - add argument and description to function comment
193 {
194   UINTN       Address;
195   EFI_STATUS  Status;
196 
197   if (!UserBuffer) {
198     return EFI_INVALID_PARAMETER;
199   }
200 
201   Address = (UINTN) UserAddress;
202 
203   if ((Width < 0) || (Width >= EfiCpuIoWidthMaximum)) {
204     return EFI_INVALID_PARAMETER;
205   }
206 
207   Status = CpuIoCheckAddressRange (Width, Address, Count, UserBuffer, IA32_MAX_IO_ADDRESS);
208   if (EFI_ERROR (Status)) {
209     return Status;
210   }
211 
212   //
213   // Do nothing for Nt32 version
214   //
215   return EFI_UNSUPPORTED;
216 }
217 
218 EFI_STATUS
219 EFIAPI
CpuIoServiceWrite(IN EFI_CPU_IO2_PROTOCOL * This,IN EFI_CPU_IO_PROTOCOL_WIDTH Width,IN UINT64 UserAddress,IN UINTN Count,IN OUT VOID * UserBuffer)220 CpuIoServiceWrite (
221   IN EFI_CPU_IO2_PROTOCOL               *This,
222   IN  EFI_CPU_IO_PROTOCOL_WIDTH         Width,
223   IN  UINT64                            UserAddress,
224   IN  UINTN                             Count,
225   IN  OUT VOID                          *UserBuffer
226   )
227 /*++
228 
229 Routine Description:
230 
231 
232   This is the service that implements the I/O Write
233 
234 Arguments:
235 
236   Pointer to an instance of the CPU I/O Protocol
237   Width of the Memory Access
238   Address of the I/O access
239   Count of the number of accesses to perform
240   Pointer to the buffer to read or write from I/O space
241 
242 Returns:
243 
244   Status
245 
246   Status
247   EFI_SUCCESS             - The data was read from or written to the EFI System.
248   EFI_INVALID_PARAMETER   - Width is invalid for this EFI System.
249   EFI_INVALID_PARAMETER   - Buffer is NULL.
250   EFI_UNSUPPORTED         - The Buffer is not aligned for the given Width.
251   EFI_UNSUPPORTED         - The address range specified by Address, Width, and
252                             Count is not valid for this EFI System.
253 
254 --*/
255 // TODO:    This - add argument and description to function comment
256 // TODO:    UserAddress - add argument and description to function comment
257 // TODO:    UserBuffer - add argument and description to function comment
258 {
259   UINTN       Address;
260   EFI_STATUS  Status;
261 
262   if (!UserBuffer) {
263     return EFI_INVALID_PARAMETER;
264   }
265 
266   Address = (UINTN) UserAddress;
267 
268   if ((Width < 0) || (Width >= EfiCpuIoWidthMaximum)) {
269     return EFI_INVALID_PARAMETER;
270   }
271 
272   Status = CpuIoCheckAddressRange (Width, Address, Count, UserBuffer, IA32_MAX_IO_ADDRESS);
273   if (EFI_ERROR (Status)) {
274     return Status;
275   }
276 
277   //
278   // Do nothing for Nt32 version
279   //
280   return EFI_UNSUPPORTED;
281 }
282 
283 
284 EFI_STATUS
CpuIoCheckAddressRange(IN EFI_CPU_IO_PROTOCOL_WIDTH Width,IN UINT64 Address,IN UINTN Count,IN VOID * Buffer,IN UINT64 Limit)285 CpuIoCheckAddressRange (
286   IN  EFI_CPU_IO_PROTOCOL_WIDTH         Width,
287   IN  UINT64                            Address,
288   IN  UINTN                             Count,
289   IN  VOID                              *Buffer,
290   IN  UINT64                            Limit
291   )
292 /*++
293 
294 Routine Description:
295 
296   TODO: Add function description
297 
298 Arguments:
299 
300   Width   - TODO: add argument description
301   Address - TODO: add argument description
302   Count   - TODO: add argument description
303   Buffer  - TODO: add argument description
304   Limit   - TODO: add argument description
305 
306 Returns:
307 
308   EFI_UNSUPPORTED - TODO: Add description for return value
309   EFI_UNSUPPORTED - TODO: Add description for return value
310   EFI_UNSUPPORTED - TODO: Add description for return value
311   EFI_SUCCESS - TODO: Add description for return value
312 
313 --*/
314 {
315   UINTN AlignMask;
316 
317   if (Address > Limit) {
318     return EFI_UNSUPPORTED;
319   }
320 
321   //
322   // For FiFo type, the target address won't increase during the access, so treat count as 1
323   //
324   if (Width >= EfiCpuIoWidthFifoUint8 && Width <= EfiCpuIoWidthFifoUint64) {
325     Count = 1;
326   }
327 
328   Width = (EFI_CPU_IO_PROTOCOL_WIDTH)(Width & 0x03);
329   if (Address - 1 + ((UINTN)1 << Width) * Count > Limit) {
330     return EFI_UNSUPPORTED;
331   }
332 
333   AlignMask = ((UINTN)1 << Width) - 1;
334   if ((UINTN) Buffer & AlignMask) {
335     return EFI_UNSUPPORTED;
336   }
337 
338   return EFI_SUCCESS;
339 }
340 
341 
342