VirtualBox

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

Last change on this file since 43143 was 43143, checked in by vboxsync, 12 years ago

EFI: expose NVRAM stuff in dedicated structure, lightweighted EFIVAR structure.

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