VirtualBox

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

Last change on this file was 99404, checked in by vboxsync, 19 months ago

Devices/EFI/FirmwareNew: Update to edk2-stable202302 and make it build, bugref:4643

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