VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.c@ 61497

Last change on this file since 61497 was 58466, checked in by vboxsync, 9 years ago

EFI/Firmware: Merged in the svn:eol-style, svn:mime-type and trailing whitespace cleanup that was done after the initial UDK2014.SP1 import: svn merge /vendor/edk2/UDK2014.SP1 /vendor/edk2/current .

  • Property svn:eol-style set to native
File size: 13.2 KB
Line 
1/** @file
2 Produces the SMM CPU I/O Protocol.
3
4Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>
5This program and the accompanying materials
6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution. The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13**/
14
15#include "CpuIo2Smm.h"
16
17//
18// Handle for the SMM CPU I/O Protocol
19//
20EFI_HANDLE mHandle = NULL;
21
22//
23// SMM CPU I/O Protocol instance
24//
25EFI_SMM_CPU_IO2_PROTOCOL mSmmCpuIo2 = {
26 {
27 CpuMemoryServiceRead,
28 CpuMemoryServiceWrite
29 },
30 {
31 CpuIoServiceRead,
32 CpuIoServiceWrite
33 }
34};
35
36//
37// Lookup table for increment values based on transfer widths
38//
39UINT8 mStride[] = {
40 1, // SMM_IO_UINT8
41 2, // SMM_IO_UINT16
42 4, // SMM_IO_UINT32
43 8 // SMM_IO_UINT64
44};
45
46/**
47 Check parameters to a SMM CPU I/O Protocol service request.
48
49 @param[in] MmioOperation TRUE for an MMIO operation, FALSE for I/O Port operation.
50 @param[in] Width Signifies the width of the I/O operations.
51 @param[in] Address The base address of the I/O operations. The caller is
52 responsible for aligning the Address if required.
53 @param[in] Count The number of I/O operations to perform.
54 @param[in] Buffer For read operations, the destination buffer to store
55 the results. For write operations, the source buffer
56 from which to write data.
57
58 @retval EFI_SUCCESS The data was read from or written to the device.
59 @retval EFI_UNSUPPORTED The Address is not valid for this system.
60 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
61
62**/
63EFI_STATUS
64CpuIoCheckParameter (
65 IN BOOLEAN MmioOperation,
66 IN EFI_SMM_IO_WIDTH Width,
67 IN UINT64 Address,
68 IN UINTN Count,
69 IN VOID *Buffer
70 )
71{
72 UINT64 MaxCount;
73 UINT64 Limit;
74
75 //
76 // Check to see if Buffer is NULL
77 //
78 if (Buffer == NULL) {
79 return EFI_INVALID_PARAMETER;
80 }
81
82 //
83 // Check to see if Width is in the valid range
84 //
85 if ((UINT32)Width > SMM_IO_UINT64) {
86 return EFI_INVALID_PARAMETER;
87 }
88
89 //
90 // Check to see if Width is in the valid range for I/O Port operations
91 //
92 if (!MmioOperation && (Width == SMM_IO_UINT64)) {
93 return EFI_INVALID_PARAMETER;
94 }
95
96 //
97 // Check to see if any address associated with this transfer exceeds the maximum
98 // allowed address. The maximum address implied by the parameters passed in is
99 // Address + Size * Count. If the following condition is met, then the transfer
100 // is not supported.
101 //
102 // Address + Size * Count > (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS) + 1
103 //
104 // Since MAX_ADDRESS can be the maximum integer value supported by the CPU and Count
105 // can also be the maximum integer value supported by the CPU, this range
106 // check must be adjusted to avoid all overflow conditions.
107 //
108 // The following form of the range check is equivalent but assumes that
109 // MAX_ADDRESS and MAX_IO_PORT_ADDRESS are of the form (2^n - 1).
110 //
111 Limit = (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS);
112 if (Count == 0) {
113 if (Address > Limit) {
114 return EFI_UNSUPPORTED;
115 }
116 } else {
117 MaxCount = RShiftU64 (Limit, Width);
118 if (MaxCount < (Count - 1)) {
119 return EFI_UNSUPPORTED;
120 }
121 if (Address > LShiftU64 (MaxCount - Count + 1, Width)) {
122 return EFI_UNSUPPORTED;
123 }
124 }
125
126 //
127 // Check to see if Address is aligned
128 //
129 if ((Address & (UINT64)(mStride[Width] - 1)) != 0) {
130 return EFI_UNSUPPORTED;
131 }
132
133 return EFI_SUCCESS;
134}
135
136/**
137 Reads memory-mapped registers.
138
139 The I/O operations are carried out exactly as requested. The caller is
140 responsible for any alignment and I/O width issues that the bus, device,
141 platform, or type of I/O might require.
142
143 @param[in] This The EFI_SMM_CPU_IO2_PROTOCOL instance.
144 @param[in] Width Signifies the width of the I/O operations.
145 @param[in] Address The base address of the I/O operations. The caller is
146 responsible for aligning the Address if required.
147 @param[in] Count The number of I/O operations to perform.
148 @param[out] Buffer For read operations, the destination buffer to store
149 the results. For write operations, the source buffer
150 from which to write data.
151
152 @retval EFI_SUCCESS The data was read from or written to the device.
153 @retval EFI_UNSUPPORTED The Address is not valid for this system.
154 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
155 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
156 lack of resources
157
158**/
159EFI_STATUS
160EFIAPI
161CpuMemoryServiceRead (
162 IN CONST EFI_SMM_CPU_IO2_PROTOCOL *This,
163 IN EFI_SMM_IO_WIDTH Width,
164 IN UINT64 Address,
165 IN UINTN Count,
166 OUT VOID *Buffer
167 )
168{
169 EFI_STATUS Status;
170 UINT8 Stride;
171 UINT8 *Uint8Buffer;
172
173 Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer);
174 if (EFI_ERROR (Status)) {
175 return Status;
176 }
177
178 //
179 // Select loop based on the width of the transfer
180 //
181 Stride = mStride[Width];
182 for (Uint8Buffer = Buffer; Count > 0; Address += Stride, Uint8Buffer += Stride, Count--) {
183 if (Width == SMM_IO_UINT8) {
184 *Uint8Buffer = MmioRead8 ((UINTN)Address);
185 } else if (Width == SMM_IO_UINT16) {
186 *((UINT16 *)Uint8Buffer) = MmioRead16 ((UINTN)Address);
187 } else if (Width == SMM_IO_UINT32) {
188 *((UINT32 *)Uint8Buffer) = MmioRead32 ((UINTN)Address);
189 } else if (Width == SMM_IO_UINT64) {
190 *((UINT64 *)Uint8Buffer) = MmioRead64 ((UINTN)Address);
191 }
192 }
193 return EFI_SUCCESS;
194}
195
196/**
197 Writes memory-mapped registers.
198
199 The I/O operations are carried out exactly as requested. The caller is
200 responsible for any alignment and I/O width issues that the bus, device,
201 platform, or type of I/O might require.
202
203 @param[in] This The EFI_SMM_CPU_IO2_PROTOCOL instance.
204 @param[in] Width Signifies the width of the I/O operations.
205 @param[in] Address The base address of the I/O operations. The caller is
206 responsible for aligning the Address if required.
207 @param[in] Count The number of I/O operations to perform.
208 @param[in] Buffer For read operations, the destination buffer to store
209 the results. For write operations, the source buffer
210 from which to write data.
211
212 @retval EFI_SUCCESS The data was read from or written to the device.
213 @retval EFI_UNSUPPORTED The Address is not valid for this system.
214 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
215 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
216 lack of resources
217
218**/
219EFI_STATUS
220EFIAPI
221CpuMemoryServiceWrite (
222 IN CONST EFI_SMM_CPU_IO2_PROTOCOL *This,
223 IN EFI_SMM_IO_WIDTH Width,
224 IN UINT64 Address,
225 IN UINTN Count,
226 IN VOID *Buffer
227 )
228{
229 EFI_STATUS Status;
230 UINT8 Stride;
231 UINT8 *Uint8Buffer;
232
233 Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer);
234 if (EFI_ERROR (Status)) {
235 return Status;
236 }
237
238 //
239 // Select loop based on the width of the transfer
240 //
241 Stride = mStride[Width];
242 for (Uint8Buffer = Buffer; Count > 0; Address += Stride, Uint8Buffer += Stride, Count--) {
243 if (Width == SMM_IO_UINT8) {
244 MmioWrite8 ((UINTN)Address, *Uint8Buffer);
245 } else if (Width == SMM_IO_UINT16) {
246 MmioWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer));
247 } else if (Width == SMM_IO_UINT32) {
248 MmioWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer));
249 } else if (Width == SMM_IO_UINT64) {
250 MmioWrite64 ((UINTN)Address, *((UINT64 *)Uint8Buffer));
251 }
252 }
253 return EFI_SUCCESS;
254}
255
256/**
257 Reads I/O registers.
258
259 The I/O operations are carried out exactly as requested. The caller is
260 responsible for any alignment and I/O width issues that the bus, device,
261 platform, or type of I/O might require.
262
263 @param[in] This The EFI_SMM_CPU_IO2_PROTOCOL instance.
264 @param[in] Width Signifies the width of the I/O operations.
265 @param[in] Address The base address of the I/O operations. The caller is
266 responsible for aligning the Address if required.
267 @param[in] Count The number of I/O operations to perform.
268 @param[out] Buffer For read operations, the destination buffer to store
269 the results. For write operations, the source buffer
270 from which to write data.
271
272 @retval EFI_SUCCESS The data was read from or written to the device.
273 @retval EFI_UNSUPPORTED The Address is not valid for this system.
274 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
275 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
276 lack of resources
277
278**/
279EFI_STATUS
280EFIAPI
281CpuIoServiceRead (
282 IN CONST EFI_SMM_CPU_IO2_PROTOCOL *This,
283 IN EFI_SMM_IO_WIDTH Width,
284 IN UINT64 Address,
285 IN UINTN Count,
286 OUT VOID *Buffer
287 )
288{
289 EFI_STATUS Status;
290 UINT8 Stride;
291 UINT8 *Uint8Buffer;
292
293 Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer);
294 if (EFI_ERROR (Status)) {
295 return Status;
296 }
297
298 //
299 // Select loop based on the width of the transfer
300 //
301 Stride = mStride[Width];
302 for (Uint8Buffer = Buffer; Count > 0; Address += Stride, Uint8Buffer += Stride, Count--) {
303 if (Width == SMM_IO_UINT8) {
304 *Uint8Buffer = IoRead8 ((UINTN)Address);
305 } else if (Width == SMM_IO_UINT16) {
306 *((UINT16 *)Uint8Buffer) = IoRead16 ((UINTN)Address);
307 } else if (Width == SMM_IO_UINT32) {
308 *((UINT32 *)Uint8Buffer) = IoRead32 ((UINTN)Address);
309 }
310 }
311
312 return EFI_SUCCESS;
313}
314
315/**
316 Write I/O registers.
317
318 The I/O operations are carried out exactly as requested. The caller is
319 responsible for any alignment and I/O width issues that the bus, device,
320 platform, or type of I/O might require.
321
322 @param[in] This The EFI_SMM_CPU_IO2_PROTOCOL instance.
323 @param[in] Width Signifies the width of the I/O operations.
324 @param[in] Address The base address of the I/O operations. The caller is
325 responsible for aligning the Address if required.
326 @param[in] Count The number of I/O operations to perform.
327 @param[in] Buffer For read operations, the destination buffer to store
328 the results. For write operations, the source buffer
329 from which to write data.
330
331 @retval EFI_SUCCESS The data was read from or written to the device.
332 @retval EFI_UNSUPPORTED The Address is not valid for this system.
333 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
334 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
335 lack of resources
336
337**/
338EFI_STATUS
339EFIAPI
340CpuIoServiceWrite (
341 IN CONST EFI_SMM_CPU_IO2_PROTOCOL *This,
342 IN EFI_SMM_IO_WIDTH Width,
343 IN UINT64 Address,
344 IN UINTN Count,
345 IN VOID *Buffer
346 )
347{
348 EFI_STATUS Status;
349 UINT8 Stride;
350 UINT8 *Uint8Buffer;
351
352 //
353 // Make sure the parameters are valid
354 //
355 Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer);
356 if (EFI_ERROR (Status)) {
357 return Status;
358 }
359
360 //
361 // Select loop based on the width of the transfer
362 //
363 Stride = mStride[Width];
364 for (Uint8Buffer = (UINT8 *)Buffer; Count > 0; Address += Stride, Uint8Buffer += Stride, Count--) {
365 if (Width == SMM_IO_UINT8) {
366 IoWrite8 ((UINTN)Address, *Uint8Buffer);
367 } else if (Width == SMM_IO_UINT16) {
368 IoWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer));
369 } else if (Width == SMM_IO_UINT32) {
370 IoWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer));
371 }
372 }
373
374 return EFI_SUCCESS;
375}
376
377/**
378 The module Entry Point SmmCpuIoProtocol driver
379
380 @param[in] ImageHandle The firmware allocated handle for the EFI image.
381 @param[in] SystemTable A pointer to the EFI System Table.
382
383 @retval EFI_SUCCESS The entry point is executed successfully.
384 @retval Other Some error occurs when executing this entry point.
385
386**/
387EFI_STATUS
388EFIAPI
389SmmCpuIo2Initialize (
390 IN EFI_HANDLE ImageHandle,
391 IN EFI_SYSTEM_TABLE *SystemTable
392 )
393{
394 EFI_STATUS Status;
395
396 //
397 // Copy the SMM CPU I/O Protocol instance into the System Management System Table
398 //
399 CopyMem (&gSmst->SmmIo, &mSmmCpuIo2, sizeof (mSmmCpuIo2));
400
401 //
402 // Install the SMM CPU I/O Protocol into the SMM protocol database
403 //
404 Status = gSmst->SmmInstallProtocolInterface (
405 &mHandle,
406 &gEfiSmmCpuIo2ProtocolGuid,
407 EFI_NATIVE_INTERFACE,
408 &mSmmCpuIo2
409 );
410 ASSERT_EFI_ERROR (Status);
411
412 return Status;
413}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette