VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/DevOVMF.cpp@ 44581

最後變更 在這個檔案從44581是 44581,由 vboxsync 提交於 12 年 前

DevOVMF.cpp: updates

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 55.7 KB
 
1/* $Id: DevOVMF.cpp 44581 2013-02-07 11:53:04Z vboxsync $ */
2/** @file
3 * DevEFI - EFI <-> VirtualBox Integration Framework.
4 */
5
6/*
7 * Copyright (C) 2006-2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21#define LOG_GROUP LOG_GROUP_DEV_EFI
22
23#include <VBox/vmm/pdmdev.h>
24#include <VBox/vmm/pgm.h>
25#include <VBox/vmm/mm.h>
26#include <VBox/log.h>
27#include <VBox/err.h>
28#include <VBox/param.h>
29#include <VBox/vmm/dbgf.h>
30#include <VBox/vmm/pdmnvram.h>
31
32#include <iprt/asm.h>
33#include <iprt/assert.h>
34#include <iprt/file.h>
35#include <iprt/mem.h>
36#include <iprt/string.h>
37#include <iprt/uuid.h>
38#include <iprt/path.h>
39#include <iprt/string.h>
40#include <iprt/mp.h>
41#include <iprt/list.h>
42#ifdef DEBUG
43# include <iprt/stream.h>
44# define DEVEFI_WITH_VBOXDBG_SCRIPT
45#endif
46
47#include "Firmware2/VBoxPkg/Include/DevEFI.h"
48#include "VBoxDD.h"
49#include "VBoxDD2.h"
50#include "../PC/DevFwCommon.h"
51
52/* EFI includes */
53#include <ProcessorBind.h>
54#include <Common/UefiBaseTypes.h>
55#include <Common/PiFirmwareVolume.h>
56#include <Common/PiFirmwareFile.h>
57
58
59/*******************************************************************************
60* Structures and Typedefs *
61*******************************************************************************/
62typedef struct {
63 RTLISTNODE List;
64 int idxVariable;
65 RTUUID uuid;
66 char szVariableName[EFI_VARIABLE_NAME_MAX];
67 uint32_t cbVariableName;
68 uint8_t au8Value[EFI_VARIABLE_VALUE_MAX];
69 uint32_t cbValue;
70 uint32_t u32Attribute;
71} EFIVAR, *PEFIVAR;
72
73typedef PEFIVAR *PPEFIVAR;
74
75typedef struct {
76 EFIVAROP enmOp;
77 uint32_t u32Status;
78 uint32_t idxOpBuffer;
79 EFIVAR OperationVarOp;
80 int cNvramVariables;
81 int iNvramLastIndex;
82 EFIVAR NvramVariableList;
83 int idxCurrentVar;
84 PEFIVAR pCurrentVarOp;
85} NVRAMDESC;
86
87typedef struct DEVEFI
88{
89 /** Pointer back to the device instance. */
90 PPDMDEVINS pDevIns;
91 /** EFI message buffer. */
92 char szMsg[VBOX_EFI_DEBUG_BUFFER];
93 /** EFI message buffer index. */
94 uint32_t iMsg;
95 /** EFI panic message buffer. */
96 char szPanicMsg[2048];
97 /** EFI panic message buffer index. */
98 uint32_t iPanicMsg;
99 /** The system EFI ROM data. */
100 uint8_t *pu8EfiRom;
101 /** The size of the system EFI ROM. */
102 uint64_t cbEfiRom;
103 /** The name of the EFI ROM file. */
104 char *pszEfiRomFile;
105 /** Thunk page pointer. */
106 uint8_t *pu8EfiThunk;
107 /** First entry point of the EFI firmware. */
108 RTGCPHYS GCEntryPoint0;
109 /** Second Entry Point (PeiCore)*/
110 RTGCPHYS GCEntryPoint1;
111 /** EFI firmware physical load address. */
112 RTGCPHYS GCLoadAddress;
113 /** Current info selector. */
114 uint32_t iInfoSelector;
115 /** Current info position. */
116 int32_t offInfo;
117
118 /** Number of virtual CPUs. (Config) */
119 uint32_t cCpus;
120 /** RAM below 4GB (in bytes). (Config) */
121 uint32_t cbBelow4GB;
122 /** RAM above 4GB (in bytes). (Config) */
123 uint64_t cbAbove4GB;
124 /** The total amount of memory. */
125 uint64_t cbRam;
126 /** The size of the RAM hole below 4GB. */
127 uint64_t cbRamHole;
128
129 /** The size of the DMI tables. */
130 uint16_t cbDmiTables;
131 /** The DMI tables. */
132 uint8_t au8DMIPage[0x1000];
133
134 /** I/O-APIC enabled? */
135 uint8_t u8IOAPIC;
136
137 /** Boot parameters passed to the firmware. */
138 char szBootArgs[256];
139
140 /** Host UUID (for DMI). */
141 RTUUID aUuid;
142
143 /** Device properties buffer. */
144 R3PTRTYPE(uint8_t *) pbDeviceProps;
145 /** Device properties buffer size. */
146 uint32_t cbDeviceProps;
147
148 /** Virtual machine front side bus frequency. */
149 uint64_t u64FsbFrequency;
150 /** Virtual machine time stamp counter frequency. */
151 uint64_t u64TscFrequency;
152 /** Virtual machine CPU frequency. */
153 uint64_t u64CpuFrequency;
154 /** GOP mode. */
155 uint32_t u32GopMode;
156 /** Uga mode horisontal resolution. */
157 uint32_t cxUgaResolution;
158 /** Uga mode vertical resolution. */
159 uint32_t cyUgaResolution;
160
161 NVRAMDESC NVRAM;
162 struct
163 {
164 PPDMIBASE pDrvBase;
165 PDMIBASE IBase;
166 PPDMINVRAM pNvramDown;
167 } Lun0;
168} DEVEFI;
169typedef DEVEFI *PDEVEFI;
170
171
172/*******************************************************************************
173* Defined Constants And Macros *
174*******************************************************************************/
175/** The saved state version. */
176#define EFI_SSM_VERSION 1
177
178
179/*******************************************************************************
180* Global Variables *
181*******************************************************************************/
182/** Saved state NVRAMDESC field descriptors. */
183static SSMFIELD const g_aEfiNvramDescField[] =
184{
185 SSMFIELD_ENTRY (NVRAMDESC, enmOp),
186 SSMFIELD_ENTRY (NVRAMDESC, u32Status),
187 SSMFIELD_ENTRY (NVRAMDESC, idxOpBuffer),
188 SSMFIELD_ENTRY_IGNORE (NVRAMDESC, OperationVarOp),
189 SSMFIELD_ENTRY (NVRAMDESC, cNvramVariables),
190 SSMFIELD_ENTRY (NVRAMDESC, iNvramLastIndex),
191 SSMFIELD_ENTRY_IGNORE (NVRAMDESC, NvramVariableList),
192 SSMFIELD_ENTRY (NVRAMDESC, idxCurrentVar),
193 SSMFIELD_ENTRY_IGNORE (NVRAMDESC, pCurrentVarOp),
194 SSMFIELD_ENTRY_TERM()
195};
196
197/** Saved state EFIVAR field descriptors. */
198static SSMFIELD const g_aEfiVariableDescFields[] =
199{
200 SSMFIELD_ENTRY_IGNORE (EFIVAR, List),
201 SSMFIELD_ENTRY (EFIVAR, idxVariable),
202 SSMFIELD_ENTRY (EFIVAR, uuid),
203 SSMFIELD_ENTRY (EFIVAR, szVariableName),
204 SSMFIELD_ENTRY (EFIVAR, cbVariableName),
205 SSMFIELD_ENTRY (EFIVAR, au8Value),
206 SSMFIELD_ENTRY (EFIVAR, cbValue),
207 SSMFIELD_ENTRY (EFIVAR, u32Attribute),
208 SSMFIELD_ENTRY_TERM()
209};
210
211
212
213/**
214 * Write to CMOS memory.
215 * This is used by the init complete code.
216 */
217static void cmosWrite(PPDMDEVINS pDevIns, int off, uint32_t u32Val)
218{
219 Assert(off < 128);
220 Assert(u32Val < 256);
221
222 int rc = PDMDevHlpCMOSWrite(pDevIns, off, u32Val);
223 AssertRC(rc);
224}
225
226DECLINLINE(void) nvramFlushDeviceVariableList(PDEVEFI pThis)
227{
228 PEFIVAR pEfiVar = NULL;
229 while (!RTListIsEmpty(&pThis->NVRAM.NvramVariableList.List))
230 {
231 pEfiVar = RTListNodeGetNext(&pThis->NVRAM.NvramVariableList.List, EFIVAR, List);
232 RTListNodeRemove(&pEfiVar->List);
233 RTMemFree(pEfiVar);
234 }
235}
236
237/**
238 * This function looks up variable in NVRAM list
239 */
240static int nvramLookupVariableByUuidAndName(PDEVEFI pThis, char *pszVariableName, PCRTUUID pUuid, PPEFIVAR ppEfiVar)
241{
242 int rc = VERR_NOT_FOUND;
243 PEFIVAR pEfiVar = NULL;
244 LogFlowFunc(("pszVariableName:%s, pUuid:%RTuuid\n", pszVariableName, pUuid));
245 int idxVar = 0;
246 RTListForEach((PRTLISTNODE)&pThis->NVRAM.NvramVariableList.List, pEfiVar, EFIVAR, List)
247 {
248 LogFlowFunc(("pEfiVar:%p\n", pEfiVar));
249 idxVar++;
250 if ( pEfiVar
251 && RTUuidCompare(pUuid, &pEfiVar->uuid) == 0
252 && RTStrCmp(pszVariableName, pEfiVar->szVariableName) == 0)
253 {
254 *ppEfiVar = pEfiVar;
255 rc = VINF_SUCCESS;
256 break;
257 }
258 }
259 Assert(pThis->NVRAM.cNvramVariables >= idxVar);
260 LogFlowFuncLeaveRC(rc);
261 return rc;
262}
263
264static int nvramLoad(PDEVEFI pThis)
265{
266 int rc = VINF_SUCCESS;
267 PEFIVAR pEfiVar = NULL;
268 int idxValue = 0;
269 while(idxValue < 100)
270 {
271 pEfiVar = (PEFIVAR)RTMemAllocZ(sizeof(EFIVAR));
272 if (!pEfiVar)
273 {
274 LogRel(("EFI: Can't allocate space for stored EFI variable\n"));
275 return VERR_NO_MEMORY;
276 }
277 pEfiVar->cbVariableName = EFI_VARIABLE_NAME_MAX;
278 pEfiVar->cbValue = EFI_VARIABLE_VALUE_MAX;
279 rc = pThis->Lun0.pNvramDown->pfnLoadNvramValue(pThis->Lun0.pNvramDown,
280 idxValue,
281 &pEfiVar->uuid,
282 pEfiVar->szVariableName,
283 (size_t *)&pEfiVar->cbVariableName,
284 pEfiVar->au8Value,
285 (size_t *)&pEfiVar->cbValue);
286 idxValue++;
287 if (RT_FAILURE(rc))
288 {
289 RTMemFree(pEfiVar);
290 break;
291 }
292 pThis->NVRAM.cNvramVariables++;
293 RTListAppend((PRTLISTNODE)&pThis->NVRAM.NvramVariableList.List, &pEfiVar->List);
294 }
295 if ( RT_FAILURE(rc)
296 && rc == VERR_NOT_FOUND)
297 rc = VINF_SUCCESS;
298 AssertRCReturn(rc, rc);
299 return rc;
300}
301
302static int nvramStore(PDEVEFI pThis)
303{
304 int rc = VINF_SUCCESS;
305 PEFIVAR pEfiVar = NULL;
306 int idxVar = 0;
307 pThis->Lun0.pNvramDown->pfnFlushNvramStorage(pThis->Lun0.pNvramDown);
308
309 RTListForEach((PRTLISTNODE)&pThis->NVRAM.NvramVariableList.List, pEfiVar, EFIVAR, List)
310 {
311 pThis->Lun0.pNvramDown->pfnStoreNvramValue(pThis->Lun0.pNvramDown,
312 idxVar,
313 &pEfiVar->uuid,
314 pEfiVar->szVariableName,
315 pEfiVar->cbVariableName,
316 pEfiVar->au8Value,
317 pEfiVar->cbValue);
318 idxVar++;
319 }
320 Assert((pThis->NVRAM.cNvramVariables == idxVar));
321 return VINF_SUCCESS;
322}
323
324
325/**
326 * Gets the info item size.
327 *
328 * @returns Size in bytes, UINT32_MAX on error.
329 * @param pThis .
330 */
331static uint32_t efiInfoSize(PDEVEFI pThis)
332{
333 switch (pThis->iInfoSelector)
334 {
335 case EFI_INFO_INDEX_VOLUME_BASE:
336 case EFI_INFO_INDEX_VOLUME_SIZE:
337 case EFI_INFO_INDEX_TEMPMEM_BASE:
338 case EFI_INFO_INDEX_TEMPMEM_SIZE:
339 case EFI_INFO_INDEX_STACK_BASE:
340 case EFI_INFO_INDEX_STACK_SIZE:
341 case EFI_INFO_INDEX_GOP_MODE:
342 case EFI_INFO_INDEX_UGA_VERTICAL_RESOLUTION:
343 case EFI_INFO_INDEX_UGA_HORISONTAL_RESOLUTION:
344 return 4;
345 case EFI_INFO_INDEX_BOOT_ARGS:
346 return (uint32_t)RTStrNLen(pThis->szBootArgs, sizeof(pThis->szBootArgs)) + 1;
347 case EFI_INFO_INDEX_DEVICE_PROPS:
348 return pThis->cbDeviceProps;
349 case EFI_INFO_INDEX_FSB_FREQUENCY:
350 case EFI_INFO_INDEX_CPU_FREQUENCY:
351 case EFI_INFO_INDEX_TSC_FREQUENCY:
352 return 8;
353 }
354 return UINT32_MAX;
355}
356
357
358/**
359 * efiInfoNextByte for a uint64_t value.
360 *
361 * @returns Next (current) byte.
362 * @param pThis The EFI instance data.
363 * @param u64 The value.
364 */
365static uint8_t efiInfoNextByteU64(PDEVEFI pThis, uint64_t u64)
366{
367 uint64_t off = pThis->offInfo;
368 if (off >= 4)
369 return 0;
370 return (uint8_t)(off >> (off * 8));
371}
372
373/**
374 * efiInfoNextByte for a uint32_t value.
375 *
376 * @returns Next (current) byte.
377 * @param pThis The EFI instance data.
378 * @param u32 The value.
379 */
380static uint8_t efiInfoNextByteU32(PDEVEFI pThis, uint32_t u32)
381{
382 uint32_t off = pThis->offInfo;
383 if (off >= 4)
384 return 0;
385 return (uint8_t)(off >> (off * 8));
386}
387
388/**
389 * efiInfoNextByte for a buffer.
390 *
391 * @returns Next (current) byte.
392 * @param pThis The EFI instance data.
393 * @param pvBuf The buffer.
394 * @param cbBuf The buffer size.
395 */
396static uint8_t efiInfoNextByteBuf(PDEVEFI pThis, void const *pvBuf, size_t cbBuf)
397{
398 uint32_t off = pThis->offInfo;
399 if (off >= cbBuf)
400 return 0;
401 return ((uint8_t const *)pvBuf)[off];
402}
403
404/**
405 * Gets the next info byte.
406 *
407 * @returns Next (current) byte.
408 * @param pThis The EFI instance data.
409 */
410static uint8_t efiInfoNextByte(PDEVEFI pThis)
411{
412 switch (pThis->iInfoSelector)
413 {
414
415 case EFI_INFO_INDEX_VOLUME_BASE: return efiInfoNextByteU64(pThis, pThis->GCLoadAddress);
416 case EFI_INFO_INDEX_VOLUME_SIZE: return efiInfoNextByteU64(pThis, pThis->cbEfiRom);
417 case EFI_INFO_INDEX_TEMPMEM_BASE: return efiInfoNextByteU32(pThis, VBOX_EFI_TOP_OF_STACK); /* just after stack */
418 case EFI_INFO_INDEX_TEMPMEM_SIZE: return efiInfoNextByteU32(pThis, _512K);
419 case EFI_INFO_INDEX_FSB_FREQUENCY: return efiInfoNextByteU64(pThis, pThis->u64FsbFrequency);
420 case EFI_INFO_INDEX_TSC_FREQUENCY: return efiInfoNextByteU64(pThis, pThis->u64TscFrequency);
421 case EFI_INFO_INDEX_CPU_FREQUENCY: return efiInfoNextByteU64(pThis, pThis->u64CpuFrequency);
422 case EFI_INFO_INDEX_BOOT_ARGS: return efiInfoNextByteBuf(pThis, pThis->szBootArgs, sizeof(pThis->szBootArgs));
423 case EFI_INFO_INDEX_DEVICE_PROPS: return efiInfoNextByteBuf(pThis, pThis->pbDeviceProps, pThis->cbDeviceProps);
424 case EFI_INFO_INDEX_GOP_MODE: return efiInfoNextByteU32(pThis, pThis->u32GopMode);
425 case EFI_INFO_INDEX_UGA_HORISONTAL_RESOLUTION: return efiInfoNextByteU32(pThis, pThis->cxUgaResolution);
426 case EFI_INFO_INDEX_UGA_VERTICAL_RESOLUTION: return efiInfoNextByteU32(pThis, pThis->cyUgaResolution);
427
428 /* Keep in sync with value in EfiThunk.asm */
429 case EFI_INFO_INDEX_STACK_BASE: return efiInfoNextByteU32(pThis, VBOX_EFI_TOP_OF_STACK - _128K); /* 2M - 128 K */
430 case EFI_INFO_INDEX_STACK_SIZE: return efiInfoNextByteU32(pThis, _128K);
431
432 default:
433 PDMDevHlpDBGFStop(pThis->pDevIns, RT_SRC_POS, "%#x", pThis->iInfoSelector);
434 return 0;
435 }
436}
437
438static DECLCALLBACK(int) efiSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
439{
440 int rc = VINF_SUCCESS;
441 PEFIVAR pEfiVar = NULL;
442 LogFlowFuncEnter();
443 PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
444 rc = SSMR3PutStructEx(pSSM, &pThis->NVRAM, sizeof(NVRAMDESC), 0, g_aEfiNvramDescField, NULL);
445 AssertRCReturn(rc, rc);
446 rc = SSMR3PutStructEx(pSSM, &pThis->NVRAM.OperationVarOp, sizeof(EFIVAR), 0, g_aEfiVariableDescFields, NULL);
447 AssertRCReturn(rc, rc);
448 int idxV = 0;
449 RTListForEach(&pThis->NVRAM.NvramVariableList.List, pEfiVar, EFIVAR, List)
450 {
451 rc = SSMR3PutStructEx(pSSM, pEfiVar, sizeof(EFIVAR), 0, g_aEfiVariableDescFields, NULL);
452 AssertRCReturn(rc, rc);
453 idxV++;
454 }
455 Assert((pThis->NVRAM.cNvramVariables == idxV));
456 Log2(("idxV: %d\n", idxV));
457 LogFlowFuncLeaveRC(rc);
458 return rc;
459}
460
461static DECLCALLBACK(int) efiLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
462{
463 int rc = VINF_SUCCESS;
464 NOREF(uPass);
465 LogFlowFunc(("ENTER: uVersion:%d, uPass:%d\n", uVersion, uPass));
466 PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
467 if (uPass != SSM_PASS_FINAL)
468 return rc;
469 /* we should clean up the loaded values */
470 nvramFlushDeviceVariableList(pThis);
471 if (uVersion == 1)
472 {
473 rc = SSMR3GetStructEx(pSSM, &pThis->NVRAM, sizeof(NVRAMDESC), 0, g_aEfiNvramDescField, NULL);
474 AssertRCReturn(rc, rc);
475 rc = SSMR3GetStructEx(pSSM, &pThis->NVRAM.OperationVarOp, sizeof(EFIVAR), 0, g_aEfiVariableDescFields, NULL);
476 AssertRCReturn(rc, rc);
477 int idxVariable = 0;
478 Assert(RTListIsEmpty(&pThis->NVRAM.NvramVariableList.List));
479 RTListInit(&pThis->NVRAM.NvramVariableList.List);
480 for (idxVariable = 0; idxVariable < pThis->NVRAM.cNvramVariables; ++idxVariable)
481 {
482 PEFIVAR pEfiVar = (PEFIVAR)RTMemAllocZ(sizeof(EFIVAR));
483 AssertPtrReturn(pEfiVar, VERR_NO_MEMORY);
484
485 rc = SSMR3GetStructEx(pSSM, pEfiVar, sizeof(EFIVAR), 0, g_aEfiVariableDescFields, NULL);
486 AssertRCReturn(rc, rc);
487
488 RTListInit(&pEfiVar->List);
489 RTListAppend(&pThis->NVRAM.NvramVariableList.List, &pEfiVar->List);
490
491 if (pThis->NVRAM.idxCurrentVar == pEfiVar->idxVariable)
492 pThis->NVRAM.pCurrentVarOp = pEfiVar;
493 }
494 }
495 LogFlowFuncLeaveRC(rc);
496 return rc;
497}
498
499#if 0
500static DECLCALLBACK(int) efiLoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
501{
502 int rc = VINF_SUCCESS;
503 PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
504 LogFlowFuncEnter();
505 if (RTListIsEmpty(&pThis->NVRAM.NvramVariableList.List))
506 nvramLoad(pThis);
507 LogFlowFuncLeaveRC(rc);
508 return rc;
509}
510#endif
511
512/**
513 * Port I/O Handler for IN operations.
514 *
515 * @returns VBox status code.
516 *
517 * @param pDevIns The device instance.
518 * @param pvUser User argument - ignored.
519 * @param Port Port number used for the IN operation.
520 * @param pu32 Where to store the result.
521 * @param cb Number of bytes read.
522 */
523static DECLCALLBACK(int) efiIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
524{
525 PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
526 Log4(("EFI in: %x %x\n", Port, cb));
527
528 switch (Port)
529 {
530 case EFI_INFO_PORT:
531 if (pThis->offInfo == -1 && cb == 4)
532 {
533 pThis->offInfo = 0;
534 uint32_t cbInfo = *pu32 = efiInfoSize(pThis);
535 if (cbInfo == UINT32_MAX)
536 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "iInfoSelector=%#x (%d)\n",
537 pThis->iInfoSelector, pThis->iInfoSelector);
538 }
539 else
540 {
541 if (cb != 1)
542 return VERR_IOM_IOPORT_UNUSED;
543 *pu32 = efiInfoNextByte(pThis);
544 pThis->offInfo++;
545 }
546 return VINF_SUCCESS;
547
548 case EFI_PANIC_PORT:
549#ifdef IN_RING3
550 LogRel(("EFI panic port read!\n"));
551 /* Insert special code here on panic reads */
552 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "EFI Panic: panic port read!\n");
553#else
554 /* Reschedule to R3 */
555 return VINF_IOM_R3_IOPORT_READ;
556#endif
557 case EFI_VARIABLE_OP:
558 switch (pThis->NVRAM.enmOp)
559 {
560 case EFI_VM_VARIABLE_OP_START:
561 /* @todo: nop ? */
562 *pu32 = pThis->NVRAM.u32Status;
563 break;
564 case EFI_VM_VARIABLE_OP_END:
565 break;
566 case EFI_VM_VARIABLE_OP_INDEX:
567 break;
568 case EFI_VM_VARIABLE_OP_GUID:
569 *pu32 = pThis->NVRAM.OperationVarOp.uuid.au8[pThis->NVRAM.idxOpBuffer];
570 pThis->NVRAM.idxOpBuffer++;
571 break;
572 case EFI_VM_VARIABLE_OP_ATTRIBUTE:
573 *pu32 = pThis->NVRAM.OperationVarOp.u32Attribute;
574 break;
575 case EFI_VM_VARIABLE_OP_NAME:
576 *pu32 = pThis->NVRAM.OperationVarOp.szVariableName[pThis->NVRAM.idxOpBuffer];
577 pThis->NVRAM.idxOpBuffer++;
578 break;
579 case EFI_VM_VARIABLE_OP_NAME_LENGTH:
580 *pu32 = pThis->NVRAM.OperationVarOp.cbVariableName;
581 break;
582 case EFI_VM_VARIABLE_OP_VALUE:
583 *pu32 = pThis->NVRAM.OperationVarOp.au8Value[pThis->NVRAM.idxOpBuffer];
584 pThis->NVRAM.idxOpBuffer++;
585 break;
586 case EFI_VM_VARIABLE_OP_VALUE_LENGTH:
587 *pu32 = pThis->NVRAM.OperationVarOp.cbValue;
588 break;
589 default:
590 break;
591 }
592 return VINF_SUCCESS;
593 case EFI_VARIABLE_PARAM:
594 {
595 break;
596 }
597 return VINF_SUCCESS;
598 }
599
600 return VERR_IOM_IOPORT_UNUSED;
601}
602
603
604/**
605 * Port I/O Handler for OUT operations.
606 *
607 * @returns VBox status code.
608 *
609 * @param pDevIns The device instance.
610 * @param pvUser User argument - ignored.
611 * @param Port Port number used for the IN operation.
612 * @param u32 The value to output.
613 * @param cb The value size in bytes.
614 */
615static DECLCALLBACK(int) efiIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
616{
617 PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
618 Log4(("efi: out %x %x %d\n", Port, u32, cb));
619
620 switch (Port)
621 {
622 case EFI_INFO_PORT:
623 pThis->iInfoSelector = u32;
624 pThis->offInfo = -1;
625 break;
626 case EFI_DEBUG_PORT:
627 {
628 /* The raw version. */
629 switch (u32)
630 {
631 case '\r': Log3(("efi: <return>\n")); break;
632 case '\n': Log3(("efi: <newline>\n")); break;
633 case '\t': Log3(("efi: <tab>\n")); break;
634 default: Log3(("efi: %c (%02x)\n", u32, u32)); break;
635 }
636 /* The readable, buffered version. */
637 if (u32 == '\n' || u32 == '\r')
638 {
639 pThis->szMsg[pThis->iMsg] = '\0';
640 if (pThis->iMsg)
641 {
642 Log(("efi: %s\n", pThis->szMsg));
643#ifdef DEVEFI_WITH_VBOXDBG_SCRIPT
644 const char *pszVBoxDbg = strstr(pThis->szMsg, "VBoxDbg> ");
645 if (pszVBoxDbg)
646 {
647 pszVBoxDbg += sizeof("VBoxDbg> ") - 1;
648
649 PRTSTREAM pStrm;
650 int rc = RTStrmOpen("./DevEFI.VBoxDbg", "a", &pStrm);
651 if (RT_SUCCESS(rc))
652 {
653 RTStrmPutStr(pStrm, pszVBoxDbg);
654 RTStrmPutCh(pStrm, '\n');
655 RTStrmClose(pStrm);
656 }
657 }
658#endif
659 }
660 pThis->iMsg = 0;
661 }
662 else
663 {
664 if (pThis->iMsg >= sizeof(pThis->szMsg)-1)
665 {
666 pThis->szMsg[pThis->iMsg] = '\0';
667 Log(("efi: %s\n", pThis->szMsg));
668 pThis->iMsg = 0;
669 }
670 pThis->szMsg[pThis->iMsg] = (char )u32;
671 pThis->szMsg[++pThis->iMsg] = '\0';
672 }
673 break;
674 }
675
676 case EFI_PANIC_PORT:
677 {
678 switch (u32)
679 {
680 case EFI_PANIC_CMD_BAD_ORG: /* Legacy */
681 case EFI_PANIC_CMD_THUNK_TRAP:
682 LogRel(("EFI Panic: Unexpected trap!!\n"));
683#ifdef VBOX_STRICT
684 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "EFI Panic: Unexpected trap during early bootstrap!\n");
685#else
686 AssertReleaseMsgFailed(("Unexpected trap during early EFI bootstrap!!\n"));
687#endif
688 break;
689
690 case EFI_PANIC_CMD_START_MSG:
691 pThis->iPanicMsg = 0;
692 pThis->szPanicMsg[0] = '\0';
693 break;
694
695 case EFI_PANIC_CMD_END_MSG:
696 LogRel(("EFI Panic: %s\n", pThis->szPanicMsg));
697#ifdef VBOX_STRICT
698 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "EFI Panic: %s\n", pThis->szPanicMsg);
699#else
700 return VERR_INTERNAL_ERROR;
701#endif
702
703 default:
704 if ( u32 >= EFI_PANIC_CMD_MSG_FIRST
705 && u32 <= EFI_PANIC_CMD_MSG_LAST)
706 {
707 /* Add the message char to the buffer. */
708 uint32_t i = pThis->iPanicMsg;
709 if (i + 1 < sizeof(pThis->szPanicMsg))
710 {
711 char ch = EFI_PANIC_CMD_MSG_GET_CHAR(u32);
712 if ( ch == '\n'
713 && i > 0
714 && pThis->szPanicMsg[i - 1] == '\r')
715 i--;
716 pThis->szPanicMsg[i] = ch;
717 pThis->szPanicMsg[i + 1] = '\0';
718 pThis->iPanicMsg = i + 1;
719 }
720 }
721 else
722 Log(("EFI: Unknown panic command: %#x (cb=%d)\n", u32, cb));
723 break;
724 }
725 break;
726 }
727 case EFI_VARIABLE_OP:
728 {
729 /* clear buffer index */
730 Assert(u32 < EFI_VM_VARIABLE_OP_MAX);
731 if (u32 >= EFI_VM_VARIABLE_OP_MAX)
732 {
733 u32 = EFI_VARIABLE_OP_STATUS_ERROR;
734 break;
735 }
736 pThis->NVRAM.idxOpBuffer = 0;
737 pThis->NVRAM.enmOp = (EFIVAROP)u32;
738 }
739 break;
740 case EFI_VARIABLE_PARAM:
741 {
742 switch (pThis->NVRAM.enmOp)
743 {
744 case EFI_VM_VARIABLE_OP_START:
745 {
746 pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_BSY;
747 switch (u32)
748 {
749 case EFI_VARIABLE_OP_QUERY:
750 {
751 LogRel(("EFI: variable lookup %RTuuid, %s\n",
752 &pThis->NVRAM.OperationVarOp.uuid,
753 pThis->NVRAM.OperationVarOp.szVariableName));
754 pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_BSY;
755 PEFIVAR pEfiVar = NULL;
756 memset(pThis->NVRAM.OperationVarOp.au8Value, 0, EFI_VARIABLE_NAME_MAX);
757 int nvramRc = nvramLookupVariableByUuidAndName(
758 pThis,
759 pThis->NVRAM.OperationVarOp.szVariableName,
760 &pThis->NVRAM.OperationVarOp.uuid,
761 &pEfiVar);
762 if (RT_SUCCESS(nvramRc))
763 {
764 pThis->NVRAM.OperationVarOp.u32Attribute = pEfiVar->u32Attribute;
765 pThis->NVRAM.OperationVarOp.cbVariableName = pEfiVar->cbVariableName;
766 pThis->NVRAM.OperationVarOp.cbValue = pEfiVar->cbValue;
767 memcpy(pThis->NVRAM.OperationVarOp.au8Value,
768 pEfiVar->au8Value, pEfiVar->cbValue);
769 pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_OK;
770 pThis->NVRAM.pCurrentVarOp = pEfiVar;
771 pThis->NVRAM.idxCurrentVar = pEfiVar->idxVariable;
772 LogFlowFunc(("OperationVar: au8Value:%.*Rhxs\n",
773 pThis->NVRAM.OperationVarOp.cbValue,
774 pThis->NVRAM.OperationVarOp.au8Value));
775 }
776 else
777 pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_NOT_FOUND;
778 }
779 break;
780 case EFI_VARIABLE_OP_ADD:
781 {
782 LogRel(("EFI: variable add %RTuuid, %s\n", &pThis->NVRAM.OperationVarOp.uuid, pThis->NVRAM.OperationVarOp.szVariableName));
783 PEFIVAR pEfiVar = NULL;
784 LogFlowFunc(("OperationVar: au8Value:%.*Rhxs\n",
785 pThis->NVRAM.OperationVarOp.cbValue,
786 pThis->NVRAM.OperationVarOp.au8Value));
787 int nvramRc = nvramLookupVariableByUuidAndName(
788 pThis,
789 pThis->NVRAM.OperationVarOp.szVariableName,
790 &pThis->NVRAM.OperationVarOp.uuid,
791 &pEfiVar);
792 if (RT_SUCCESS(nvramRc))
793 {
794 /* delete or update ? */
795 /* @todo: check whether pEfiVar is WP */
796 LogFlowFunc(("pEfiVar: au8Value:%.*Rhxs\n",
797 pEfiVar->cbValue,
798 pEfiVar->au8Value));
799 if (pThis->NVRAM.OperationVarOp.cbValue == 0)
800 {
801 /* delete */
802 RTListNodeRemove(&pEfiVar->List);
803 RTMemFree(pEfiVar);
804 pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_OK;
805 pThis->NVRAM.cNvramVariables--;
806 }
807 else
808 {
809 /* update */
810 pEfiVar->cbValue = pThis->NVRAM.OperationVarOp.cbValue;
811 memcpy(pEfiVar->au8Value, pThis->NVRAM.OperationVarOp.au8Value, pEfiVar->cbValue);
812 pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_OK;
813 }
814 }
815 else
816 {
817 if (pThis->NVRAM.OperationVarOp.cbValue != 0)
818 {
819 pEfiVar = (PEFIVAR)RTMemAllocZ(sizeof(EFIVAR));
820 if (!pEfiVar)
821 {
822 pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
823 break;
824 }
825 }
826 else
827 {
828 pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_OK;
829 break;
830 }
831
832 memcpy(pEfiVar, &pThis->NVRAM.OperationVarOp, sizeof(EFIVAR));
833 RTListInit(&pEfiVar->List);
834 RTListAppend(&pThis->NVRAM.NvramVariableList.List, &pEfiVar->List);
835 pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_OK;
836 pThis->NVRAM.cNvramVariables++;
837 pEfiVar->idxVariable = pThis->NVRAM.iNvramLastIndex;
838 pThis->NVRAM.iNvramLastIndex++;
839 }
840 }
841 LogFunc(("cNvramVariables:%d, iNvramLastIndex:%d\n", pThis->NVRAM.cNvramVariables, pThis->NVRAM.iNvramLastIndex));
842 break;
843 case EFI_VARIABLE_OP_QUERY_NEXT:
844 {
845 PEFIVAR pEfiVar = RTListNodeGetNext(&pThis->NVRAM.pCurrentVarOp->List, EFIVAR, List);
846 if (pEfiVar)
847 {
848 memcpy(&pThis->NVRAM.OperationVarOp, pEfiVar, sizeof(EFIVAR));
849 pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_OK;
850 }
851 else
852 pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_NOT_FOUND;
853 }
854 break;
855 default:
856 /* @todo: return error */
857 break;
858 }
859 }
860 case EFI_VM_VARIABLE_OP_END:
861 break;
862 case EFI_VM_VARIABLE_OP_INDEX:
863 break;
864 case EFI_VM_VARIABLE_OP_GUID:
865 pThis->NVRAM.OperationVarOp.uuid.au8[pThis->NVRAM.idxOpBuffer] = (uint8_t)u32;
866 pThis->NVRAM.idxOpBuffer++;
867 break;
868 case EFI_VM_VARIABLE_OP_ATTRIBUTE:
869 pThis->NVRAM.OperationVarOp.u32Attribute = u32;
870 break;
871 case EFI_VM_VARIABLE_OP_NAME:
872 pThis->NVRAM.OperationVarOp.szVariableName[pThis->NVRAM.idxOpBuffer] = (uint8_t)u32;
873 pThis->NVRAM.idxOpBuffer++;
874 break;
875 case EFI_VM_VARIABLE_OP_NAME_LENGTH:
876 pThis->NVRAM.OperationVarOp.cbVariableName = u32;
877 memset(pThis->NVRAM.OperationVarOp.szVariableName, 0, EFI_VARIABLE_NAME_MAX);
878 break;
879 case EFI_VM_VARIABLE_OP_VALUE:
880 pThis->NVRAM.OperationVarOp.au8Value[pThis->NVRAM.idxOpBuffer] = (uint8_t)u32;
881 pThis->NVRAM.idxOpBuffer++;
882 break;
883 case EFI_VM_VARIABLE_OP_VALUE_LENGTH:
884 pThis->NVRAM.OperationVarOp.cbValue = u32;
885 memset(pThis->NVRAM.OperationVarOp.au8Value, 0, EFI_VARIABLE_VALUE_MAX);
886 break;
887 default:
888 break;
889 }
890 }
891 break;
892
893 default:
894 Log(("EFI: Write to reserved port %RTiop: %#x (cb=%d)\n", Port, u32, cb));
895 break;
896 }
897 return VINF_SUCCESS;
898}
899
900/**
901 * Init complete notification.
902 *
903 * @returns VBOX status code.
904 * @param pDevIns The device instance.
905 */
906static DECLCALLBACK(int) efiInitComplete(PPDMDEVINS pDevIns)
907{
908 /* PC Bios */
909 PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
910 uint32_t u32;
911
912 /*
913 * Memory sizes.
914 */
915 uint64_t const offRamHole = _4G - pThis->cbRamHole;
916 if (pThis->cbRam > 16 * _1M)
917 u32 = (uint32_t)( (RT_MIN(RT_MIN(pThis->cbRam, offRamHole), UINT32_C(0xffe00000)) - 16U * _1M) / _64K );
918 else
919 u32 = 0;
920 cmosWrite(pDevIns, 0x34, u32 & 0xff);
921 cmosWrite(pDevIns, 0x35, u32 >> 8);
922
923 /*
924 * Number of CPUs.
925 */
926 cmosWrite(pDevIns, 0x60, pThis->cCpus & 0xff);
927
928 return VINF_SUCCESS;
929}
930
931/**
932 * Reset notification.
933 *
934 * @returns VBox status.
935 * @param pDevIns The device instance data.
936 */
937static DECLCALLBACK(void) efiReset(PPDMDEVINS pDevIns)
938{
939 PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
940 int rc;
941
942 LogFlow(("efiReset\n"));
943
944 pThis->iInfoSelector = 0;
945 pThis->offInfo = -1;
946
947 pThis->iMsg = 0;
948 pThis->szMsg[0] = '\0';
949 pThis->iPanicMsg = 0;
950 pThis->szPanicMsg[0] = '\0';
951
952 /*
953 * Plan some structures in RAM.
954 */
955 FwCommonPlantSmbiosAndDmiHdrs(pDevIns, pThis->cbDmiTables);
956 if (pThis->u8IOAPIC)
957 FwCommonPlantMpsFloatPtr(pDevIns);
958
959 /*
960 * Re-shadow the Firmware Volume and make it RAM/RAM.
961 */
962 uint32_t cPages = RT_ALIGN_64(pThis->cbEfiRom, PAGE_SIZE) >> PAGE_SHIFT;
963 RTGCPHYS GCPhys = pThis->GCLoadAddress;
964 while (cPages > 0)
965 {
966 uint8_t abPage[PAGE_SIZE];
967
968 /* Read the (original) ROM page and write it back to the RAM page. */
969 rc = PDMDevHlpROMProtectShadow(pDevIns, GCPhys, PAGE_SIZE, PGMROMPROT_READ_ROM_WRITE_RAM);
970 AssertLogRelRC(rc);
971
972 rc = PDMDevHlpPhysRead(pDevIns, GCPhys, abPage, PAGE_SIZE);
973 AssertLogRelRC(rc);
974 if (RT_FAILURE(rc))
975 memset(abPage, 0xcc, sizeof(abPage));
976
977 rc = PDMDevHlpPhysWrite(pDevIns, GCPhys, abPage, PAGE_SIZE);
978 AssertLogRelRC(rc);
979
980 /* Switch to the RAM/RAM mode. */
981 rc = PDMDevHlpROMProtectShadow(pDevIns, GCPhys, PAGE_SIZE, PGMROMPROT_READ_RAM_WRITE_RAM);
982 AssertLogRelRC(rc);
983
984 /* Advance */
985 GCPhys += PAGE_SIZE;
986 cPages--;
987 }
988}
989
990/**
991 * Destruct a device instance.
992 *
993 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
994 * resources can be freed correctly.
995 *
996 * @param pDevIns The device instance data.
997 */
998static DECLCALLBACK(int) efiDestruct(PPDMDEVINS pDevIns)
999{
1000 PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
1001 nvramStore(pThis);
1002 nvramFlushDeviceVariableList(pThis);
1003
1004 /*
1005 * Free MM heap pointers.
1006 */
1007 if (pThis->pu8EfiRom)
1008 {
1009 RTFileReadAllFree(pThis->pu8EfiRom, (size_t)pThis->cbEfiRom);
1010 pThis->pu8EfiRom = NULL;
1011 }
1012
1013 if (pThis->pszEfiRomFile)
1014 {
1015 MMR3HeapFree(pThis->pszEfiRomFile);
1016 pThis->pszEfiRomFile = NULL;
1017 }
1018
1019 if (pThis->pu8EfiThunk)
1020 {
1021 MMR3HeapFree(pThis->pu8EfiThunk);
1022 pThis->pu8EfiThunk = NULL;
1023 }
1024
1025 if (pThis->pbDeviceProps)
1026 {
1027 MMR3HeapFree(pThis->pbDeviceProps);
1028 pThis->pbDeviceProps = NULL;
1029 pThis->cbDeviceProps = 0;
1030 }
1031
1032 return VINF_SUCCESS;
1033}
1034
1035/**
1036 * Helper that searches for a FFS file of a given type.
1037 *
1038 * @returns Pointer to the FFS file header if found, NULL if not.
1039 *
1040 * @param pFfsFile Pointer to the FFS file header to start searching at.
1041 * @param pbEnd The end of the firmware volume.
1042 * @param FileType The file type to look for.
1043 * @param pcbFfsFile Where to store the FFS file size (includes header).
1044 */
1045DECLINLINE(EFI_FFS_FILE_HEADER const *)
1046efiFwVolFindFileByType(EFI_FFS_FILE_HEADER const *pFfsFile, uint8_t const *pbEnd, EFI_FV_FILETYPE FileType, uint32_t *pcbFile)
1047{
1048#define FFS_SIZE(hdr) RT_MAKE_U32_FROM_U8((hdr)->Size[0], (hdr)->Size[1], (hdr)->Size[2], 0)
1049 while ((uintptr_t)pFfsFile < (uintptr_t)pbEnd)
1050 {
1051 if (pFfsFile->Type == FileType)
1052 {
1053 *pcbFile = FFS_SIZE(pFfsFile);
1054 LogFunc(("Found %RTuuid of type:%d\n", &pFfsFile->Name, FileType));
1055 return pFfsFile;
1056 }
1057 pFfsFile = (EFI_FFS_FILE_HEADER *)((uintptr_t)pFfsFile + RT_ALIGN(FFS_SIZE(pFfsFile), 8));
1058 }
1059#undef FFS_SIZE
1060 return NULL;
1061}
1062
1063
1064/**
1065 * Parse EFI ROM headers and find entry points.
1066 *
1067 * @returns VBox status.
1068 * @param pThis The device instance data.
1069 */
1070static int efiParseFirmware(PDEVEFI pThis)
1071{
1072 EFI_FIRMWARE_VOLUME_HEADER const *pFwVolHdr = (EFI_FIRMWARE_VOLUME_HEADER const *)pThis->pu8EfiRom;
1073
1074 /*
1075 * Validate firmware volume header.
1076 */
1077 AssertLogRelMsgReturn(pFwVolHdr->Signature == RT_MAKE_U32_FROM_U8('_', 'F', 'V', 'H'),
1078 ("%#x, expected %#x\n", pFwVolHdr->Signature, RT_MAKE_U32_FROM_U8('_', 'F', 'V', 'H')),
1079 VERR_INVALID_MAGIC);
1080 AssertLogRelMsgReturn(pFwVolHdr->Revision == EFI_FVH_REVISION,
1081 ("%#x, expected %#x\n", pFwVolHdr->Signature, EFI_FVH_REVISION),
1082 VERR_VERSION_MISMATCH);
1083 /** @todo check checksum, see PE spec vol. 3 */
1084 AssertLogRelMsgReturn(pFwVolHdr->FvLength <= pThis->cbEfiRom,
1085 ("%#llx, expected %#llx\n", pFwVolHdr->FvLength, pThis->cbEfiRom),
1086 VERR_INVALID_PARAMETER);
1087 AssertLogRelMsgReturn( pFwVolHdr->BlockMap[0].Length > 0
1088 && pFwVolHdr->BlockMap[0].NumBlocks > 0,
1089 ("%#x, %x\n", pFwVolHdr->BlockMap[0].Length, pFwVolHdr->BlockMap[0].NumBlocks),
1090 VERR_INVALID_PARAMETER);
1091
1092 AssertLogRelMsgReturn(!(pThis->cbEfiRom & PAGE_OFFSET_MASK), ("%RX64\n", pThis->cbEfiRom), VERR_INVALID_PARAMETER);
1093
1094 uint8_t const * const pbFwVolEnd = pThis->pu8EfiRom + pFwVolHdr->FvLength;
1095 pThis->GCLoadAddress = UINT32_C(0xfffff000) - pThis->cbEfiRom + PAGE_SIZE;
1096
1097 return VINF_SUCCESS;
1098}
1099
1100/**
1101 * Load EFI ROM file into the memory.
1102 *
1103 * @returns VBox status.
1104 * @param pThis The device instance data.
1105 * @param pCfg Configuration node handle for the device.
1106 */
1107static int efiLoadRom(PDEVEFI pThis, PCFGMNODE pCfg)
1108{
1109 /*
1110 * Read the entire firmware volume into memory.
1111 */
1112 void *pvFile;
1113 size_t cbFile;
1114 int rc = RTFileReadAllEx(pThis->pszEfiRomFile,
1115 0 /*off*/,
1116 RTFOFF_MAX /*cbMax*/,
1117 RTFILE_RDALL_O_DENY_WRITE,
1118 &pvFile,
1119 &cbFile);
1120 if (RT_FAILURE(rc))
1121 return PDMDevHlpVMSetError(pThis->pDevIns, rc, RT_SRC_POS,
1122 N_("Loading the EFI firmware volume '%s' failed with rc=%Rrc"),
1123 pThis->pszEfiRomFile, rc);
1124 pThis->pu8EfiRom = (uint8_t *)pvFile;
1125 pThis->cbEfiRom = cbFile;
1126
1127 /*
1128 * Validate firmware volume and figure out the load address as well as the SEC entry point.
1129 */
1130 rc = efiParseFirmware(pThis);
1131 if (RT_FAILURE(rc))
1132 return PDMDevHlpVMSetError(pThis->pDevIns, rc, RT_SRC_POS,
1133 N_("Parsing the EFI firmware volume '%s' failed with rc=%Rrc"),
1134 pThis->pszEfiRomFile, rc);
1135
1136 /*
1137 * Map the firmware volume into memory as shadowed ROM.
1138 */
1139 /** @todo fix PGMR3PhysRomRegister so it doesn't mess up in SUPLib when mapping a big ROM image. */
1140 RTGCPHYS cbQuart = RT_ALIGN_64(pThis->cbEfiRom / 4, PAGE_SIZE);
1141 rc = PDMDevHlpROMRegister(pThis->pDevIns,
1142 pThis->GCLoadAddress,
1143 cbQuart,
1144 pThis->pu8EfiRom,
1145 cbQuart,
1146 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY,
1147 "EFI Firmware Volume");
1148 AssertRCReturn(rc, rc);
1149 rc = PDMDevHlpROMProtectShadow(pThis->pDevIns, pThis->GCLoadAddress, (uint32_t)cbQuart, PGMROMPROT_READ_RAM_WRITE_IGNORE);
1150 AssertRCReturn(rc, rc);
1151 rc = PDMDevHlpROMRegister(pThis->pDevIns,
1152 pThis->GCLoadAddress + cbQuart,
1153 cbQuart,
1154 pThis->pu8EfiRom + cbQuart,
1155 cbQuart,
1156 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY,
1157 "EFI Firmware Volume (Part 2)");
1158 if (RT_FAILURE(rc))
1159 return rc;
1160 rc = PDMDevHlpROMRegister(pThis->pDevIns,
1161 pThis->GCLoadAddress + cbQuart * 2,
1162 cbQuart,
1163 pThis->pu8EfiRom + cbQuart * 2,
1164 cbQuart,
1165 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY,
1166 "EFI Firmware Volume (Part 3)");
1167 if (RT_FAILURE(rc))
1168 return rc;
1169 rc = PDMDevHlpROMRegister(pThis->pDevIns,
1170 pThis->GCLoadAddress + cbQuart * 3,
1171 pThis->cbEfiRom - cbQuart * 3,
1172 pThis->pu8EfiRom + cbQuart * 3,
1173 pThis->cbEfiRom - cbQuart * 3,
1174 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY,
1175 "EFI Firmware Volume (Part 4)");
1176 if (RT_FAILURE(rc))
1177 return rc;
1178 return VINF_SUCCESS;
1179}
1180
1181static uint8_t efiGetHalfByte(char ch)
1182{
1183 uint8_t val;
1184
1185 if (ch >= '0' && ch <= '9')
1186 val = ch - '0';
1187 else if (ch >= 'A' && ch <= 'F')
1188 val = ch - 'A' + 10;
1189 else if(ch >= 'a' && ch <= 'f')
1190 val = ch - 'a' + 10;
1191 else
1192 val = 0xff;
1193
1194 return val;
1195
1196}
1197
1198
1199static int efiParseDeviceString(PDEVEFI pThis, char *pszDeviceProps)
1200{
1201 int rc = 0;
1202 uint32_t iStr, iHex, u32OutLen;
1203 uint8_t u8Value = 0; /* (shut up gcc) */
1204 bool fUpper = true;
1205
1206 u32OutLen = (uint32_t)RTStrNLen(pszDeviceProps, RTSTR_MAX) / 2 + 1;
1207
1208 pThis->pbDeviceProps = (uint8_t *)PDMDevHlpMMHeapAlloc(pThis->pDevIns, u32OutLen);
1209 if (!pThis->pbDeviceProps)
1210 return VERR_NO_MEMORY;
1211
1212 for (iStr=0, iHex = 0; pszDeviceProps[iStr]; iStr++)
1213 {
1214 uint8_t u8Hb = efiGetHalfByte(pszDeviceProps[iStr]);
1215 if (u8Hb > 0xf)
1216 continue;
1217
1218 if (fUpper)
1219 u8Value = u8Hb << 4;
1220 else
1221 pThis->pbDeviceProps[iHex++] = u8Hb | u8Value;
1222
1223 Assert(iHex < u32OutLen);
1224 fUpper = !fUpper;
1225 }
1226
1227 Assert(iHex == 0 || fUpper);
1228 pThis->cbDeviceProps = iHex;
1229
1230 return rc;
1231}
1232
1233/**
1234 * @copydoc(PDMIBASE::pfnQueryInterface)
1235 */
1236static DECLCALLBACK(void *) devEfiQueryInterface(PPDMIBASE pInterface, const char *pszIID)
1237{
1238 LogFlowFunc(("ENTER: pIBase: %p, pszIID:%p\n", __FUNCTION__, pInterface, pszIID));
1239 PDEVEFI pThis = RT_FROM_MEMBER(pInterface, DEVEFI, Lun0.IBase);
1240
1241 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->Lun0.IBase);
1242 return NULL;
1243}
1244
1245/**
1246 * @interface_method_impl{PDMDEVREG,pfnConstruct}
1247 */
1248static DECLCALLBACK(int) efiConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1249{
1250 PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
1251 int rc;
1252
1253 Assert(iInstance == 0);
1254
1255 pThis->pDevIns = pDevIns;
1256
1257 /*
1258 * Validate and read the configuration.
1259 */
1260 if (!CFGMR3AreValuesValid(pCfg,
1261 "EfiRom\0"
1262 "RamSize\0"
1263 "RamHoleSize\0"
1264 "NumCPUs\0"
1265 "UUID\0"
1266 "IOAPIC\0"
1267 "DmiBIOSFirmwareMajor\0"
1268 "DmiBIOSFirmwareMinor\0"
1269 "DmiBIOSReleaseDate\0"
1270 "DmiBIOSReleaseMajor\0"
1271 "DmiBIOSReleaseMinor\0"
1272 "DmiBIOSVendor\0"
1273 "DmiBIOSVersion\0"
1274 "DmiSystemFamily\0"
1275 "DmiSystemProduct\0"
1276 "DmiSystemSerial\0"
1277 "DmiSystemSKU\0"
1278 "DmiSystemUuid\0"
1279 "DmiSystemVendor\0"
1280 "DmiSystemVersion\0"
1281 "DmiBoardAssetTag\0"
1282 "DmiBoardBoardType\0"
1283 "DmiBoardLocInChass\0"
1284 "DmiBoardProduct\0"
1285 "DmiBoardSerial\0"
1286 "DmiBoardVendor\0"
1287 "DmiBoardVersion\0"
1288 "DmiChassisAssetTag\0"
1289 "DmiChassisSerial\0"
1290 "DmiChassisVendor\0"
1291 "DmiChassisVersion\0"
1292 "DmiProcManufacturer\0"
1293 "DmiProcVersion\0"
1294 "DmiOEMVBoxVer\0"
1295 "DmiOEMVBoxRev\0"
1296 "DmiUseHostInfo\0"
1297 "DmiExposeMemoryTable\0"
1298 "DmiExposeProcInf\0"
1299 "64BitEntry\0"
1300 "BootArgs\0"
1301 "DeviceProps\0"
1302 "GopMode\0"
1303 "UgaHorizontalResolution\0"
1304 "UgaVerticalResolution\0"))
1305 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
1306 N_("Configuration error: Invalid config value(s) for the EFI device"));
1307
1308 /* CPU count (optional). */
1309 rc = CFGMR3QueryU32Def(pCfg, "NumCPUs", &pThis->cCpus, 1);
1310 AssertLogRelRCReturn(rc, rc);
1311
1312 rc = CFGMR3QueryU8Def(pCfg, "IOAPIC", &pThis->u8IOAPIC, 1);
1313 if (RT_FAILURE (rc))
1314 return PDMDEV_SET_ERROR(pDevIns, rc,
1315 N_("Configuration error: Failed to read \"IOAPIC\""));
1316
1317 /*
1318 * Query the machine's UUID for SMBIOS/DMI use.
1319 */
1320 RTUUID uuid;
1321 rc = CFGMR3QueryBytes(pCfg, "UUID", &uuid, sizeof(uuid));
1322 if (RT_FAILURE(rc))
1323 return PDMDEV_SET_ERROR(pDevIns, rc,
1324 N_("Configuration error: Querying \"UUID\" failed"));
1325
1326 /*
1327 * Convert the UUID to network byte order. Not entirely straightforward as
1328 * parts are MSB already...
1329 */
1330 uuid.Gen.u32TimeLow = RT_H2BE_U32(uuid.Gen.u32TimeLow);
1331 uuid.Gen.u16TimeMid = RT_H2BE_U16(uuid.Gen.u16TimeMid);
1332 uuid.Gen.u16TimeHiAndVersion = RT_H2BE_U16(uuid.Gen.u16TimeHiAndVersion);
1333 memcpy(&pThis->aUuid, &uuid, sizeof pThis->aUuid);
1334 RTListInit((PRTLISTNODE)&pThis->NVRAM.NvramVariableList.List);
1335
1336
1337 /*
1338 * RAM sizes
1339 */
1340 rc = CFGMR3QueryU64(pCfg, "RamSize", &pThis->cbRam);
1341 AssertLogRelRCReturn(rc, rc);
1342 rc = CFGMR3QueryU64(pCfg, "RamHoleSize", &pThis->cbRamHole);
1343 AssertLogRelRCReturn(rc, rc);
1344 pThis->cbBelow4GB = RT_MIN(pThis->cbRam, _4G - pThis->cbRamHole);
1345 pThis->cbAbove4GB = pThis->cbRam - pThis->cbBelow4GB;
1346
1347 /*
1348 * Get the system EFI ROM file name.
1349 */
1350 rc = CFGMR3QueryStringAlloc(pCfg, "EfiRom", &pThis->pszEfiRomFile);
1351 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1352 {
1353 pThis->pszEfiRomFile = (char *)PDMDevHlpMMHeapAlloc(pDevIns, RTPATH_MAX);
1354 if (!pThis->pszEfiRomFile)
1355 return VERR_NO_MEMORY;
1356
1357 rc = RTPathAppPrivateArchTop(pThis->pszEfiRomFile, RTPATH_MAX);
1358 AssertRCReturn(rc, rc);
1359 rc = RTPathAppend(pThis->pszEfiRomFile, RTPATH_MAX, "VBoxEFI32.fd");
1360 AssertRCReturn(rc, rc);
1361 }
1362 else if (RT_FAILURE(rc))
1363 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1364 N_("Configuration error: Querying \"EfiRom\" as a string failed"));
1365 else if (!*pThis->pszEfiRomFile)
1366 {
1367 MMR3HeapFree(pThis->pszEfiRomFile);
1368 pThis->pszEfiRomFile = NULL;
1369 }
1370
1371 /*
1372 * NVRAM processing.
1373 */
1374 pThis->Lun0.IBase.pfnQueryInterface = devEfiQueryInterface;
1375
1376#if 0
1377 rc = PDMDevHlpSSMRegisterEx(pDevIns, EFI_SSM_VERSION, sizeof(*pThis), NULL /*pszBefore*/,
1378 NULL /*pfnLivePrep*/, NULL /*pfnLiveExec*/, NULL /*pfnLiveDone*/,
1379 NULL /*pfnSavePrep*/, efiSaveExec, NULL /*pfnSaveDone*/,
1380 NULL /*pfnLoadPrep*/, efiLoadExec, efiLoadDone);
1381#else
1382 rc = PDMDevHlpSSMRegister(pDevIns, EFI_SSM_VERSION, sizeof(*pThis), efiSaveExec, efiLoadExec);
1383#endif
1384 AssertRCReturn(rc, rc);
1385
1386 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->Lun0.IBase, &pThis->Lun0.pDrvBase, "NvramStorage");
1387 if (RT_FAILURE(rc))
1388 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, N_("Can't attach Nvram Storage driver"));
1389
1390 pThis->Lun0.pNvramDown = (PPDMINVRAM)pThis->Lun0.pDrvBase->pfnQueryInterface(pThis->Lun0.pDrvBase, PDMINVRAM_IID);
1391 AssertPtrReturn(pThis->Lun0.pNvramDown, VERR_PDM_MISSING_INTERFACE_BELOW);
1392
1393 nvramLoad(pThis);
1394
1395 /*
1396 * Get boot args.
1397 */
1398 rc = CFGMR3QueryString(pCfg, "BootArgs",
1399 pThis->szBootArgs, sizeof pThis->szBootArgs);
1400 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1401 {
1402 strcpy(pThis->szBootArgs, "");
1403 rc = VINF_SUCCESS;
1404 }
1405 if (RT_FAILURE(rc))
1406 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1407 N_("Configuration error: Querying \"BootArgs\" as a string failed"));
1408
1409 LogRel(("EFI boot args: %s\n", pThis->szBootArgs));
1410
1411 /*
1412 * Get device props.
1413 */
1414 char* pszDeviceProps;
1415 rc = CFGMR3QueryStringAlloc(pCfg, "DeviceProps", &pszDeviceProps);
1416 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1417 {
1418 pszDeviceProps = NULL;
1419 rc = VINF_SUCCESS;
1420 }
1421 if (RT_FAILURE(rc))
1422 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1423 N_("Configuration error: Querying \"DeviceProps\" as a string failed"));
1424 if (pszDeviceProps)
1425 {
1426 LogRel(("EFI device props: %s\n", pszDeviceProps));
1427 rc = efiParseDeviceString(pThis, pszDeviceProps);
1428 MMR3HeapFree(pszDeviceProps);
1429 if (RT_FAILURE(rc))
1430 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1431 N_("Configuration error: Cannot parse device properties"));
1432 }
1433 else
1434 {
1435 pThis->pbDeviceProps = NULL;
1436 pThis->cbDeviceProps = 0;
1437 }
1438
1439 /*
1440 * CPU frequencies
1441 */
1442 /// @todo: we need to have VMM API to access TSC increase speed, for now provide reasonable default
1443 pThis->u64TscFrequency = RTMpGetMaxFrequency(0) * 1000 * 1000;// TMCpuTicksPerSecond(PDMDevHlpGetVM(pDevIns));
1444 if (pThis->u64TscFrequency == 0)
1445 pThis->u64TscFrequency = UINT64_C(2500000000);
1446 /* Multiplier is read from MSR_IA32_PERF_STATUS, and now is hardcoded as 4 */
1447 pThis->u64FsbFrequency = pThis->u64TscFrequency / 4;
1448 pThis->u64CpuFrequency = pThis->u64TscFrequency;
1449
1450 /*
1451 * GOP graphics
1452 */
1453 rc = CFGMR3QueryU32(pCfg, "GopMode", &pThis->u32GopMode);
1454 AssertRC(rc);
1455 if (pThis->u32GopMode == UINT32_MAX)
1456 {
1457 pThis->u32GopMode = 2; /* 1024x768 */
1458 }
1459
1460 /*
1461 * Uga graphics
1462 */
1463 rc = CFGMR3QueryU32Def(pCfg, "UgaHorizontalResolution", &pThis->cxUgaResolution, 0); AssertRC(rc);
1464 if (pThis->cxUgaResolution == 0)
1465 pThis->cxUgaResolution = 1024; /* 1024x768 */
1466 rc = CFGMR3QueryU32Def(pCfg, "UgaVerticalResolution", &pThis->cyUgaResolution, 0); AssertRC(rc);
1467 if (pThis->cyUgaResolution == 0)
1468 pThis->cyUgaResolution = 768; /* 1024x768 */
1469
1470#ifdef DEVEFI_WITH_VBOXDBG_SCRIPT
1471 /*
1472 * Zap the debugger script
1473 */
1474 RTFileDelete("./DevEFI.VBoxDbg");
1475#endif
1476
1477 /*
1478 * Load firmware volume and thunk ROM.
1479 */
1480 rc = efiLoadRom(pThis, pCfg);
1481 if (RT_FAILURE(rc))
1482 return rc;
1483
1484 /*
1485 * Register our communication ports.
1486 */
1487 rc = PDMDevHlpIOPortRegister(pDevIns, EFI_PORT_BASE, EFI_PORT_COUNT, NULL,
1488 efiIOPortWrite, efiIOPortRead,
1489 NULL, NULL, "EFI communication ports");
1490 if (RT_FAILURE(rc))
1491 return rc;
1492
1493 /*
1494 * Plant DMI and MPS tables
1495 */
1496 /** @todo XXX I wonder if we really need these tables as there is no SMBIOS header... */
1497 rc = FwCommonPlantDMITable(pDevIns, pThis->au8DMIPage, VBOX_DMI_TABLE_SIZE, &pThis->aUuid,
1498 pDevIns->pCfg, pThis->cCpus, &pThis->cbDmiTables);
1499 AssertRCReturn(rc, rc);
1500 if (pThis->u8IOAPIC)
1501 FwCommonPlantMpsTable(pDevIns,
1502 pThis->au8DMIPage + VBOX_DMI_TABLE_SIZE,
1503 _4K - VBOX_DMI_TABLE_SIZE, pThis->cCpus);
1504 rc = PDMDevHlpROMRegister(pDevIns, VBOX_DMI_TABLE_BASE, _4K, pThis->au8DMIPage, _4K,
1505 PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "DMI tables");
1506
1507 AssertRCReturn(rc, rc);
1508
1509 /*
1510 * Call reset to set things up.
1511 */
1512 efiReset(pDevIns);
1513
1514 return VINF_SUCCESS;
1515}
1516
1517/**
1518 * The device registration structure.
1519 */
1520const PDMDEVREG g_DeviceEFI =
1521{
1522 /* u32Version */
1523 PDM_DEVREG_VERSION,
1524 /* szName */
1525 "efi",
1526 /* szRCMod */
1527 "",
1528 /* szR0Mod */
1529 "",
1530 /* pszDescription */
1531 "Extensible Firmware Interface Device",
1532 /* fFlags */
1533 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64,
1534 /* fClass */
1535 PDM_DEVREG_CLASS_ARCH_BIOS,
1536 /* cMaxInstances */
1537 1,
1538 /* cbInstance */
1539 sizeof(DEVEFI),
1540 /* pfnConstruct */
1541 efiConstruct,
1542 /* pfnDestruct */
1543 efiDestruct,
1544 /* pfnRelocate */
1545 NULL,
1546 /* pfnIOCtl */
1547 NULL,
1548 /* pfnPowerOn */
1549 NULL,
1550 /* pfnReset */
1551 efiReset,
1552 /* pfnSuspend */
1553 NULL,
1554 /* pfnResume */
1555 NULL,
1556 /* pfnAttach */
1557 NULL,
1558 /* pfnDetach */
1559 NULL,
1560 /* pfnQueryInterface. */
1561 NULL,
1562 /* pfnInitComplete. */
1563 efiInitComplete,
1564 /* pfnPowerOff */
1565 NULL,
1566 /* pfnSoftReset */
1567 NULL,
1568 /* u32VersionEnd */
1569 PDM_DEVREG_VERSION
1570};
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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