VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxSysTables/TableConversion.c

Last change on this file was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.2 KB
Line 
1/* $Id: TableConversion.c 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * TableConversion.c
4 */
5
6/*
7 * Copyright (C) 2009-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37/*++
38
39 This code is baed on:
40
41 Copyright (c) 2006 - 2007, Intel Corporation
42 All rights reserved. This program and the accompanying materials
43 are licensed and made available under the terms and conditions of the BSD License
44 which accompanies this distribution. The full text of the license may be found at
45 http://opensource.org/licenses/bsd-license.php
46
47 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
48 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
49 --*/
50
51#include <IndustryStandard/Pci.h>
52#include <IndustryStandard/Acpi.h>
53#include <IndustryStandard/SmBios.h>
54#include "LegacyBiosMpTable.h"
55
56#include <Library/DebugLib.h>
57#include <Library/BaseMemoryLib.h>
58#include <Library/UefiBootServicesTableLib.h>
59#include <Library/MemoryAllocationLib.h>
60#include <Library/BaseLib.h>
61
62#include <Guid/Acpi.h>
63#include <Guid/SmBios.h>
64#include <Guid/Mps.h>
65#include <Guid/HobList.h>
66#include <Guid/GlobalVariable.h>
67
68#define SYS_TABLE_PAD(ptr) (((~ptr) +1) & 0x07 )
69#define EFI_SYSTEM_TABLE_MAX_ADDRESS 0xFFFFFFFF
70
71EFI_STATUS
72ConvertAcpiTable (
73 IN UINTN TableLen,
74 IN OUT VOID **Table
75 )
76/*++
77
78 Routine Description:
79 Convert RSDP of ACPI Table if its location is lower than Address:0x100000
80 Assumption here:
81 As in legacy Bios, ACPI table is required to place in E/F Seg,
82 So here we just check if the range is E/F seg,
83 and if Not, assume the Memory type is EfiACPIReclaimMemory/EfiACPIMemoryNVS
84
85 Arguments:
86 TableLen - Acpi RSDP length
87 Table - pointer to the table
88
89 Returns:
90 EFI_SUCCESS - Convert Table successfully
91 Other - Failed
92
93 --*/
94{
95 VOID *AcpiTableOri;
96 VOID *AcpiTableNew;
97 EFI_STATUS Status;
98 EFI_PHYSICAL_ADDRESS BufferPtr;
99
100
101 AcpiTableOri = (VOID *)(UINTN)((*Table));
102
103 BufferPtr = EFI_SYSTEM_TABLE_MAX_ADDRESS;
104 Status = gBS->AllocatePages (
105 AllocateMaxAddress,
106 EfiACPIMemoryNVS,
107 EFI_SIZE_TO_PAGES(TableLen),
108 &BufferPtr
109 );
110 ASSERT_EFI_ERROR (Status);
111 AcpiTableNew = (VOID *)(UINTN)BufferPtr;
112 CopyMem (AcpiTableNew, AcpiTableOri, TableLen);
113
114 //
115 // Change configuration table Pointer
116 //
117 *Table = AcpiTableNew;
118
119 return EFI_SUCCESS;
120}
121
122EFI_STATUS
123ConvertSmbiosTable (
124 IN OUT VOID **Table
125 )
126/*++
127
128 Routine Description:
129
130 Convert Smbios Table if the Location of the SMBios Table is lower than Address 0x100000
131 Assumption here:
132 As in legacy Bios, Smbios table is required to place in E/F Seg,
133 So here we just check if the range is F seg,
134 and if Not, assume the Memory type is EfiACPIMemoryNVS/EfiRuntimeServicesData
135 Arguments:
136 Table - pointer to the table
137
138 Returns:
139 EFI_SUCCESS - Convert Table successfully
140 Other - Failed
141
142 --*/
143{
144 SMBIOS_TABLE_ENTRY_POINT *SmbiosTableNew;
145 SMBIOS_TABLE_ENTRY_POINT *SmbiosTableOri;
146 EFI_STATUS Status;
147 UINT32 SmbiosEntryLen;
148 UINT32 BufferLen;
149 EFI_PHYSICAL_ADDRESS BufferPtr;
150
151 SmbiosTableNew = NULL;
152 SmbiosTableOri = NULL;
153
154 //
155 // Get Smibos configuration Table
156 //
157 SmbiosTableOri = (SMBIOS_TABLE_ENTRY_POINT *)(UINTN)((*Table));
158
159
160 ASSERT(CalculateSum8((UINT8*)SmbiosTableOri, sizeof(SMBIOS_TABLE_ENTRY_POINT)) == 0);
161 //
162 // Relocate the Smibos memory
163 //
164 BufferPtr = EFI_SYSTEM_TABLE_MAX_ADDRESS;
165 if (SmbiosTableOri->SmbiosBcdRevision != 0x21) {
166 SmbiosEntryLen = SmbiosTableOri->EntryPointLength;
167 } else {
168 //
169 // According to Smbios Spec 2.4, we should set entry point length as 0x1F if version is 2.1
170 //
171 SmbiosEntryLen = 0x1F;
172 }
173 BufferLen = SmbiosEntryLen + SYS_TABLE_PAD(SmbiosEntryLen) + SmbiosTableOri->TableLength;
174 Status = gBS->AllocatePages (
175 AllocateMaxAddress,
176 EfiACPIMemoryNVS,
177 EFI_SIZE_TO_PAGES(BufferLen),
178 &BufferPtr
179 );
180 ASSERT_EFI_ERROR (Status);
181 SmbiosTableNew = (SMBIOS_TABLE_ENTRY_POINT *)(UINTN)BufferPtr;
182 CopyMem (
183 SmbiosTableNew,
184 SmbiosTableOri,
185 SmbiosEntryLen
186 );
187 //
188 // Get Smbios Structure table address, and make sure the start address is 32-bit align
189 //
190 BufferPtr += SmbiosEntryLen + SYS_TABLE_PAD(SmbiosEntryLen);
191 CopyMem (
192 (VOID *)(UINTN)BufferPtr,
193 (VOID *)(UINTN)(SmbiosTableOri->TableAddress),
194 SmbiosTableOri->TableLength
195 );
196 SmbiosTableNew->TableAddress = (UINT32)BufferPtr;
197 SmbiosTableNew->IntermediateChecksum = 0;
198 SmbiosTableNew->IntermediateChecksum =
199 CalculateCheckSum8 ((UINT8*)SmbiosTableNew + 0x10, SmbiosEntryLen -0x10);
200 //
201 // Change the SMBIOS pointer
202 //
203 *Table = SmbiosTableNew;
204
205 return EFI_SUCCESS;
206}
207
208EFI_STATUS
209ConvertMpsTable (
210 IN OUT VOID **Table
211 )
212/*++
213
214 Routine Description:
215
216 Convert MP Table if the Location of the SMBios Table is lower than Address 0x100000
217 Assumption here:
218 As in legacy Bios, MP table is required to place in E/F Seg,
219 So here we just check if the range is E/F seg,
220 and if Not, assume the Memory type is EfiACPIMemoryNVS/EfiRuntimeServicesData
221 Arguments:
222 Table - pointer to the table
223
224 Returns:
225 EFI_SUCCESS - Convert Table successfully
226 Other - Failed
227
228 --*/
229{
230 UINT32 Data32;
231 UINT32 FPLength;
232 EFI_LEGACY_MP_TABLE_FLOATING_POINTER *MpsFloatingPointerOri;
233 EFI_LEGACY_MP_TABLE_FLOATING_POINTER *MpsFloatingPointerNew;
234 EFI_LEGACY_MP_TABLE_HEADER *MpsTableOri;
235 EFI_LEGACY_MP_TABLE_HEADER *MpsTableNew;
236 VOID *OemTableOri;
237 VOID *OemTableNew;
238 EFI_STATUS Status;
239 EFI_PHYSICAL_ADDRESS BufferPtr;
240
241 //
242 // Get MP configuration Table
243 //
244 MpsFloatingPointerOri = (EFI_LEGACY_MP_TABLE_FLOATING_POINTER *)(UINTN)(*Table);
245 //
246 // Get Floating pointer structure length
247 //
248 FPLength = MpsFloatingPointerOri->Length * 16;
249 ASSERT(CalculateSum8((UINT8*)MpsFloatingPointerOri, FPLength) == 0);
250 Data32 = FPLength + SYS_TABLE_PAD (FPLength);
251 MpsTableOri = (EFI_LEGACY_MP_TABLE_HEADER *)(UINTN)(MpsFloatingPointerOri->PhysicalAddress);
252 ASSERT(MpsTableOri != NULL);
253 ASSERT(CalculateSum8((UINT8*)MpsTableOri, MpsTableOri->BaseTableLength) == 0);
254
255 Data32 += MpsTableOri->BaseTableLength;
256 Data32 += MpsTableOri->ExtendedTableLength;
257 if (MpsTableOri->OemTablePointer != 0x00) {
258 Data32 += SYS_TABLE_PAD (Data32);
259 Data32 += MpsTableOri->OemTableSize;
260 }
261
262 //
263 // Relocate memory
264 //
265 BufferPtr = EFI_SYSTEM_TABLE_MAX_ADDRESS;
266 Status = gBS->AllocatePages (
267 AllocateMaxAddress,
268 EfiACPIMemoryNVS,
269 EFI_SIZE_TO_PAGES(Data32),
270 &BufferPtr
271 );
272 ASSERT_EFI_ERROR (Status);
273 MpsFloatingPointerNew = (EFI_LEGACY_MP_TABLE_FLOATING_POINTER *)(UINTN)BufferPtr;
274 CopyMem (MpsFloatingPointerNew, MpsFloatingPointerOri, FPLength);
275 //
276 // If Mp Table exists
277 //
278 if (MpsTableOri != NULL) {
279 //
280 // Get Mps table length, including Ext table
281 //
282 BufferPtr = BufferPtr + FPLength + SYS_TABLE_PAD (FPLength);
283 MpsTableNew = (EFI_LEGACY_MP_TABLE_HEADER *)(UINTN)BufferPtr;
284 CopyMem (MpsTableNew, MpsTableOri, MpsTableOri->BaseTableLength + MpsTableOri->ExtendedTableLength);
285
286 if ((MpsTableOri->OemTableSize != 0x0000) && (MpsTableOri->OemTablePointer != 0x0000)){
287 BufferPtr += MpsTableOri->BaseTableLength + MpsTableOri->ExtendedTableLength;
288 BufferPtr += SYS_TABLE_PAD (BufferPtr);
289 OemTableNew = (VOID *)(UINTN)BufferPtr;
290 OemTableOri = (VOID *)(UINTN)MpsTableOri->OemTablePointer;
291 CopyMem (OemTableNew, OemTableOri, MpsTableOri->OemTableSize);
292 MpsTableNew->OemTablePointer = (UINT32)(UINTN)OemTableNew;
293 }
294 MpsTableNew->Checksum = 0;
295 MpsTableNew->Checksum = CalculateCheckSum8 ((UINT8*)MpsTableNew, MpsTableOri->BaseTableLength);
296 MpsFloatingPointerNew->PhysicalAddress = (UINT32)(UINTN)MpsTableNew;
297 MpsFloatingPointerNew->Checksum = 0;
298 MpsFloatingPointerNew->Checksum = CalculateCheckSum8 ((UINT8*)MpsFloatingPointerNew, FPLength);
299 }
300 //
301 // Change the pointer
302 //
303 *Table = MpsFloatingPointerNew;
304
305 return EFI_SUCCESS;
306}
307
308EFI_STATUS
309ConvertSystemTable (
310 IN EFI_GUID *TableGuid,
311 IN OUT VOID **Table
312 )
313/*++
314
315 Routine Description:
316 Convert ACPI Table /Smbios Table /MP Table if its location is lower than Address:0x100000
317 Assumption here:
318 As in legacy Bios, ACPI/Smbios/MP table is required to place in E/F Seg,
319 So here we just check if the range is E/F seg,
320 and if Not, assume the Memory type is EfiACPIReclaimMemory/EfiACPIMemoryNVS
321
322 Arguments:
323 TableGuid - Guid of the table
324 Table - pointer to the table
325
326 Returns:
327 EFI_SUCCESS - Convert Table successfully
328 Other - Failed
329
330 --*/
331{
332 EFI_STATUS Status = EFI_SUCCESS;
333 VOID *AcpiHeader;
334 UINTN AcpiTableLen;
335
336 //
337 // If match acpi guid (1.0, 2.0, or later), Convert ACPI table according to version.
338 //
339
340 if (CompareGuid(TableGuid, &gEfiAcpiTableGuid) || CompareGuid(TableGuid, &gEfiAcpi20TableGuid)){
341 AcpiHeader = (VOID*)(UINTN)(*Table);
342
343 if (((EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)AcpiHeader)->Reserved == 0x00){
344 //
345 // If Acpi 1.0 Table, then RSDP structure doesn't contain Length field, use structure size
346 //
347 AcpiTableLen = sizeof (EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER);
348 } else if (((EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)AcpiHeader)->Reserved >= 0x02){
349 //
350 // If Acpi 2.0 or later, use RSDP Length fied.
351 //
352 AcpiTableLen = ((EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)AcpiHeader)->Length;
353 } else {
354 //
355 // Invalid Acpi Version, return
356 //
357 return EFI_UNSUPPORTED;
358 }
359 Status = ConvertAcpiTable (AcpiTableLen, Table);
360 return Status;
361 }
362
363 //
364 // If matches smbios guid, convert Smbios table.
365 //
366 if (CompareGuid(TableGuid, &gEfiSmbiosTableGuid)){
367 Status = ConvertSmbiosTable (Table);
368 return Status;
369 }
370
371 //
372 // If the table is MP table?
373 //
374 if (CompareGuid(TableGuid, &gEfiMpsTableGuid)){
375 Status = ConvertMpsTable (Table);
376 return Status;
377 }
378
379 return EFI_UNSUPPORTED;
380}
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