VirtualBox

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

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

EFI/OVMF: introduces NVRAM mechanism in DevOVMF.

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