VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/DevPcBios.cpp@ 33223

Last change on this file since 33223 was 32720, checked in by vboxsync, 14 years ago

Devices/BIOS: allow to overwrite DmiSystemSKU

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 47.1 KB
Line 
1/* $Id: DevPcBios.cpp 32720 2010-09-23 13:17:35Z vboxsync $ */
2/** @file
3 * PC BIOS Device.
4 */
5
6/*
7 * Copyright (C) 2006-2008 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_PC_BIOS
22#include <VBox/pdmdev.h>
23#include <VBox/mm.h>
24#include <VBox/pgm.h>
25
26#include <VBox/log.h>
27#include <iprt/asm.h>
28#include <iprt/assert.h>
29#include <iprt/buildconfig.h>
30#include <iprt/file.h>
31#include <iprt/mem.h>
32#include <iprt/string.h>
33#include <iprt/uuid.h>
34#include <VBox/err.h>
35#include <VBox/param.h>
36
37#include "../Builtins.h"
38#include "../Builtins2.h"
39#include "DevPcBios.h"
40#include "DevFwCommon.h"
41
42#define NET_BOOT_DEVS 4
43
44
45/** @page pg_devbios_cmos_assign CMOS Assignments (BIOS)
46 *
47 * The BIOS uses a CMOS to store configuration data.
48 * It is currently used as follows:
49 *
50 * @verbatim
51 First CMOS bank (offsets 0x00 to 0x7f):
52 Base memory:
53 0x15
54 0x16
55 Extended memory:
56 0x17
57 0x18
58 0x30
59 0x31
60 Amount of memory above 16M and below 4GB in 64KB units:
61 0x34
62 0x35
63 Boot device (BOCHS bios specific):
64 0x3d
65 0x38
66 0x3c
67 PXE debug:
68 0x3f
69 Floppy drive type:
70 0x10
71 Equipment byte:
72 0x14
73 First HDD:
74 0x19
75 0x1e - 0x25
76 Second HDD:
77 0x1a
78 0x26 - 0x2d
79 Third HDD:
80 0x67 - 0x6e
81 Fourth HDD:
82 0x70 - 0x77
83 Extended:
84 0x12
85 First Sata HDD:
86 0x40 - 0x47
87 Second Sata HDD:
88 0x48 - 0x4f
89 Third Sata HDD:
90 0x50 - 0x57
91 Fourth Sata HDD:
92 0x58 - 0x5f
93 Number of CPUs:
94 0x60
95 RAM above 4G in 64KB units:
96 0x61 - 0x65
97
98 Second CMOS bank (offsets 0x80 to 0xff):
99 Reserved for internal use by PXE ROM:
100 0x80 - 0x81
101 First net boot device PCI bus/dev/fn:
102 0x82 - 0x83
103 Second to third net boot devices:
104 0x84 - 0x89
105@endverbatim
106 *
107 * @todo Mark which bits are compatible with which BIOSes and
108 * which are our own definitions.
109 */
110
111
112/*******************************************************************************
113* Structures and Typedefs *
114*******************************************************************************/
115
116/**
117 * The boot device.
118 */
119typedef enum DEVPCBIOSBOOT
120{
121 DEVPCBIOSBOOT_NONE,
122 DEVPCBIOSBOOT_FLOPPY,
123 DEVPCBIOSBOOT_HD,
124 DEVPCBIOSBOOT_DVD,
125 DEVPCBIOSBOOT_LAN
126} DEVPCBIOSBOOT;
127
128/**
129 * PC Bios instance data structure.
130 */
131typedef struct DEVPCBIOS
132{
133 /** Pointer back to the device instance. */
134 PPDMDEVINS pDevIns;
135
136 /** Boot devices (ordered). */
137 DEVPCBIOSBOOT aenmBootDevice[4];
138 /** RAM size (in bytes). */
139 uint64_t cbRam;
140 /** RAM hole size (in bytes). */
141 uint32_t cbRamHole;
142 /** Bochs shutdown index. */
143 uint32_t iShutdown;
144 /** Floppy device. */
145 char *pszFDDevice;
146 /** Harddisk device. */
147 char *pszHDDevice;
148 /** Sata harddisk device. */
149 char *pszSataDevice;
150 /** LUN of the four harddisks which are emulated as IDE. */
151 uint32_t iSataHDLUN[4];
152 /** Bios message buffer. */
153 char szMsg[256];
154 /** Bios message buffer index. */
155 uint32_t iMsg;
156 /** The system BIOS ROM data. */
157 uint8_t *pu8PcBios;
158 /** The size of the system BIOS ROM. */
159 uint64_t cbPcBios;
160 /** The name of the BIOS ROM file. */
161 char *pszPcBiosFile;
162 /** The LAN boot ROM data. */
163 uint8_t *pu8LanBoot;
164 /** The name of the LAN boot ROM file. */
165 char *pszLanBootFile;
166 /** The size of the LAN boot ROM. */
167 uint64_t cbLanBoot;
168 /** The DMI tables. */
169 uint8_t au8DMIPage[0x1000];
170 /** The boot countdown (in seconds). */
171 uint8_t uBootDelay;
172 /** I/O-APIC enabled? */
173 uint8_t u8IOAPIC;
174 /** PXE debug logging enabled? */
175 uint8_t u8PXEDebug;
176 /** PXE boot PCI bus/dev/fn list. */
177 uint16_t au16NetBootDev[NET_BOOT_DEVS];
178 /** Number of logical CPUs in guest */
179 uint16_t cCpus;
180} DEVPCBIOS, *PDEVPCBIOS;
181
182
183/* Attempt to guess the LCHS disk geometry from the MS-DOS master boot
184 * record (partition table). */
185static int biosGuessDiskLCHS(PPDMIBLOCK pBlock, PPDMMEDIAGEOMETRY pLCHSGeometry)
186{
187 uint8_t aMBR[512], *p;
188 int rc;
189 uint32_t iEndHead, iEndSector, cLCHSCylinders, cLCHSHeads, cLCHSSectors;
190
191 if (!pBlock)
192 return VERR_INVALID_PARAMETER;
193 rc = pBlock->pfnRead(pBlock, 0, aMBR, sizeof(aMBR));
194 if (RT_FAILURE(rc))
195 return rc;
196 /* Test MBR magic number. */
197 if (aMBR[510] != 0x55 || aMBR[511] != 0xaa)
198 return VERR_INVALID_PARAMETER;
199 for (uint32_t i = 0; i < 4; i++)
200 {
201 /* Figure out the start of a partition table entry. */
202 p = &aMBR[0x1be + i * 16];
203 iEndHead = p[5];
204 iEndSector = p[6] & 63;
205 if ((p[12] | p[13] | p[14] | p[15]) && iEndSector & iEndHead)
206 {
207 /* Assumption: partition terminates on a cylinder boundary. */
208 cLCHSHeads = iEndHead + 1;
209 cLCHSSectors = iEndSector;
210 cLCHSCylinders = RT_MIN(1024, pBlock->pfnGetSize(pBlock) / (512 * cLCHSHeads * cLCHSSectors));
211 if (cLCHSCylinders >= 1)
212 {
213 pLCHSGeometry->cCylinders = cLCHSCylinders;
214 pLCHSGeometry->cHeads = cLCHSHeads;
215 pLCHSGeometry->cSectors = cLCHSSectors;
216 Log(("%s: LCHS=%d %d %d\n", __FUNCTION__, cLCHSCylinders, cLCHSHeads, cLCHSSectors));
217 return VINF_SUCCESS;
218 }
219 }
220 }
221 return VERR_INVALID_PARAMETER;
222}
223
224
225/**
226 * Write to CMOS memory.
227 * This is used by the init complete code.
228 */
229static void pcbiosCmosWrite(PPDMDEVINS pDevIns, int off, uint32_t u32Val)
230{
231 Assert(off < 256);
232 Assert(u32Val < 256);
233
234#if 1
235 int rc = PDMDevHlpCMOSWrite(pDevIns, off, u32Val);
236 AssertRC(rc);
237#else
238 PVM pVM = PDMDevHlpGetVM(pDevIns);
239 IOMIOPortWrite(pVM, 0x70, off, 1);
240 IOMIOPortWrite(pVM, 0x71, u32Val, 1);
241 IOMIOPortWrite(pVM, 0x70, 0, 1);
242#endif
243}
244
245/* -=-=-=-=-=-=- based on code from pc.c -=-=-=-=-=-=- */
246
247/**
248 * Initializes the CMOS data for one harddisk.
249 */
250static void pcbiosCmosInitHardDisk(PPDMDEVINS pDevIns, int offType, int offInfo, PCPDMMEDIAGEOMETRY pLCHSGeometry)
251{
252 Log2(("%s: offInfo=%#x: LCHS=%d/%d/%d\n", __FUNCTION__, offInfo, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
253 if (offType)
254 pcbiosCmosWrite(pDevIns, offType, 48);
255 /* Cylinders low */
256 pcbiosCmosWrite(pDevIns, offInfo + 0, RT_MIN(pLCHSGeometry->cCylinders, 1024) & 0xff);
257 /* Cylinders high */
258 pcbiosCmosWrite(pDevIns, offInfo + 1, RT_MIN(pLCHSGeometry->cCylinders, 1024) >> 8);
259 /* Heads */
260 pcbiosCmosWrite(pDevIns, offInfo + 2, pLCHSGeometry->cHeads);
261 /* Landing zone low */
262 pcbiosCmosWrite(pDevIns, offInfo + 3, 0xff);
263 /* Landing zone high */
264 pcbiosCmosWrite(pDevIns, offInfo + 4, 0xff);
265 /* Write precomp low */
266 pcbiosCmosWrite(pDevIns, offInfo + 5, 0xff);
267 /* Write precomp high */
268 pcbiosCmosWrite(pDevIns, offInfo + 6, 0xff);
269 /* Sectors */
270 pcbiosCmosWrite(pDevIns, offInfo + 7, pLCHSGeometry->cSectors);
271}
272
273/**
274 * Set logical CHS geometry for a hard disk
275 *
276 * @returns VBox status code.
277 * @param pBase Base interface for the device.
278 * @param pHardDisk The hard disk.
279 * @param pLCHSGeometry Where to store the geometry settings.
280 */
281static int setLogicalDiskGeometry(PPDMIBASE pBase, PPDMIBLOCKBIOS pHardDisk, PPDMMEDIAGEOMETRY pLCHSGeometry)
282{
283 PDMMEDIAGEOMETRY LCHSGeometry;
284 int rc = VINF_SUCCESS;
285
286 rc = pHardDisk->pfnGetLCHSGeometry(pHardDisk, &LCHSGeometry);
287 if ( rc == VERR_PDM_GEOMETRY_NOT_SET
288 || LCHSGeometry.cCylinders == 0
289 || LCHSGeometry.cHeads == 0
290 || LCHSGeometry.cHeads > 255
291 || LCHSGeometry.cSectors == 0
292 || LCHSGeometry.cSectors > 63)
293 {
294 PPDMIBLOCK pBlock;
295 pBlock = PDMIBASE_QUERY_INTERFACE(pBase, PDMIBLOCK);
296 /* No LCHS geometry, autodetect and set. */
297 rc = biosGuessDiskLCHS(pBlock, &LCHSGeometry);
298 if (RT_FAILURE(rc))
299 {
300 /* Try if PCHS geometry works, otherwise fall back. */
301 rc = pHardDisk->pfnGetPCHSGeometry(pHardDisk, &LCHSGeometry);
302 }
303 if ( RT_FAILURE(rc)
304 || LCHSGeometry.cCylinders == 0
305 || LCHSGeometry.cCylinders > 1024
306 || LCHSGeometry.cHeads == 0
307 || LCHSGeometry.cHeads > 16
308 || LCHSGeometry.cSectors == 0
309 || LCHSGeometry.cSectors > 63)
310 {
311 uint64_t cSectors = pBlock->pfnGetSize(pBlock) / 512;
312 if (cSectors / 16 / 63 <= 1024)
313 {
314 LCHSGeometry.cCylinders = RT_MAX(cSectors / 16 / 63, 1);
315 LCHSGeometry.cHeads = 16;
316 }
317 else if (cSectors / 32 / 63 <= 1024)
318 {
319 LCHSGeometry.cCylinders = RT_MAX(cSectors / 32 / 63, 1);
320 LCHSGeometry.cHeads = 32;
321 }
322 else if (cSectors / 64 / 63 <= 1024)
323 {
324 LCHSGeometry.cCylinders = cSectors / 64 / 63;
325 LCHSGeometry.cHeads = 64;
326 }
327 else if (cSectors / 128 / 63 <= 1024)
328 {
329 LCHSGeometry.cCylinders = cSectors / 128 / 63;
330 LCHSGeometry.cHeads = 128;
331 }
332 else
333 {
334 LCHSGeometry.cCylinders = RT_MIN(cSectors / 255 / 63, 1024);
335 LCHSGeometry.cHeads = 255;
336 }
337 LCHSGeometry.cSectors = 63;
338
339 }
340 rc = pHardDisk->pfnSetLCHSGeometry(pHardDisk, &LCHSGeometry);
341 if (rc == VERR_VD_IMAGE_READ_ONLY)
342 {
343 LogRel(("DevPcBios: ATA failed to update LCHS geometry, read only\n"));
344 rc = VINF_SUCCESS;
345 }
346 else if (rc == VERR_PDM_GEOMETRY_NOT_SET)
347 {
348 LogRel(("DevPcBios: ATA failed to update LCHS geometry, backend refused\n"));
349 rc = VINF_SUCCESS;
350 }
351 }
352
353 *pLCHSGeometry = LCHSGeometry;
354
355 return rc;
356}
357
358/**
359 * Get BIOS boot code from enmBootDevice in order
360 *
361 * @todo r=bird: This is a rather silly function since the conversion is 1:1.
362 */
363static uint8_t getBiosBootCode(PDEVPCBIOS pThis, unsigned iOrder)
364{
365 switch (pThis->aenmBootDevice[iOrder])
366 {
367 case DEVPCBIOSBOOT_NONE:
368 return 0;
369 case DEVPCBIOSBOOT_FLOPPY:
370 return 1;
371 case DEVPCBIOSBOOT_HD:
372 return 2;
373 case DEVPCBIOSBOOT_DVD:
374 return 3;
375 case DEVPCBIOSBOOT_LAN:
376 return 4;
377 default:
378 AssertMsgFailed(("aenmBootDevice[%d]=%d\n", iOrder, pThis->aenmBootDevice[iOrder]));
379 return 0;
380 }
381}
382
383
384/**
385 * Init complete notification.
386 * This routine will write information needed by the bios to the CMOS.
387 *
388 * @returns VBOX status code.
389 * @param pDevIns The device instance.
390 * @see http://www.brl.ntt.co.jp/people/takehiko/interrupt/CMOS.LST.txt for
391 * a description of standard and non-standard CMOS registers.
392 */
393static DECLCALLBACK(int) pcbiosInitComplete(PPDMDEVINS pDevIns)
394{
395 PDEVPCBIOS pThis = PDMINS_2_DATA(pDevIns, PDEVPCBIOS);
396 uint32_t u32;
397 unsigned i;
398 PVM pVM = PDMDevHlpGetVM(pDevIns);
399 PPDMIBLOCKBIOS apHDs[4] = {0};
400 PPDMIBLOCKBIOS apFDs[2] = {0};
401 AssertRelease(pVM);
402 LogFlow(("pcbiosInitComplete:\n"));
403
404 /*
405 * Memory sizes.
406 */
407 /* base memory. */
408 u32 = pThis->cbRam > 640 ? 640 : (uint32_t)pThis->cbRam / _1K; /* <-- this test is wrong, but it doesn't matter since we never assign less than 1MB */
409 pcbiosCmosWrite(pDevIns, 0x15, u32 & 0xff); /* 15h - Base Memory in K, Low Byte */
410 pcbiosCmosWrite(pDevIns, 0x16, u32 >> 8); /* 16h - Base Memory in K, High Byte */
411
412 /* Extended memory, up to 65MB */
413 u32 = pThis->cbRam >= 65 * _1M ? 0xffff : ((uint32_t)pThis->cbRam - _1M) / _1K;
414 pcbiosCmosWrite(pDevIns, 0x17, u32 & 0xff); /* 17h - Extended Memory in K, Low Byte */
415 pcbiosCmosWrite(pDevIns, 0x18, u32 >> 8); /* 18h - Extended Memory in K, High Byte */
416 pcbiosCmosWrite(pDevIns, 0x30, u32 & 0xff); /* 30h - Extended Memory in K, Low Byte */
417 pcbiosCmosWrite(pDevIns, 0x31, u32 >> 8); /* 31h - Extended Memory in K, High Byte */
418
419 /* Bochs BIOS specific? Anyway, it's the amount of memory above 16MB
420 and below 4GB (as it can only hold 4GB+16M). We have to chop off the
421 top 2MB or it conflict with what the ACPI tables return. (Should these
422 be adjusted, we still have to chop it at 0xfffc0000 or it'll conflict
423 with the high BIOS mapping.) */
424 uint64_t const offRamHole = _4G - pThis->cbRamHole;
425 if (pThis->cbRam > 16 * _1M)
426 u32 = (uint32_t)( (RT_MIN(RT_MIN(pThis->cbRam, offRamHole), UINT32_C(0xffe00000)) - 16U * _1M) / _64K );
427 else
428 u32 = 0;
429 pcbiosCmosWrite(pDevIns, 0x34, u32 & 0xff);
430 pcbiosCmosWrite(pDevIns, 0x35, u32 >> 8);
431
432 /* Bochs/VBox BIOS specific way of specifying memory above 4GB in 64KB units.
433 Bochs got these in a different location which we've already used for SATA,
434 it also lacks the last two. */
435 uint64_t c64KBAbove4GB;
436 if (pThis->cbRam <= offRamHole)
437 c64KBAbove4GB = 0;
438 else
439 {
440 c64KBAbove4GB = (pThis->cbRam - offRamHole) / _64K;
441 /* Make sure it doesn't hit the limits of the current BIOS code. */
442 AssertLogRelMsgReturn((c64KBAbove4GB >> (3 * 8)) < 255, ("%#RX64\n", c64KBAbove4GB), VERR_OUT_OF_RANGE);
443 }
444 pcbiosCmosWrite(pDevIns, 0x61, c64KBAbove4GB & 0xff);
445 pcbiosCmosWrite(pDevIns, 0x62, (c64KBAbove4GB >> 8) & 0xff);
446 pcbiosCmosWrite(pDevIns, 0x63, (c64KBAbove4GB >> 16) & 0xff);
447 pcbiosCmosWrite(pDevIns, 0x64, (c64KBAbove4GB >> 24) & 0xff);
448 pcbiosCmosWrite(pDevIns, 0x65, (c64KBAbove4GB >> 32) & 0xff);
449
450 /*
451 * Number of CPUs.
452 */
453 pcbiosCmosWrite(pDevIns, 0x60, pThis->cCpus & 0xff);
454
455 /*
456 * Bochs BIOS specifics - boot device.
457 * We do both new and old (ami-style) settings.
458 * See rombios.c line ~7215 (int19_function).
459 */
460
461 uint8_t reg3d = getBiosBootCode(pThis, 0) | (getBiosBootCode(pThis, 1) << 4);
462 uint8_t reg38 = /* pcbiosCmosRead(pDevIns, 0x38) | */ getBiosBootCode(pThis, 2) << 4;
463 /* This is an extension. Bochs BIOS normally supports only 3 boot devices. */
464 uint8_t reg3c = getBiosBootCode(pThis, 3) | (pThis->uBootDelay << 4);
465 pcbiosCmosWrite(pDevIns, 0x3d, reg3d);
466 pcbiosCmosWrite(pDevIns, 0x38, reg38);
467 pcbiosCmosWrite(pDevIns, 0x3c, reg3c);
468
469 /*
470 * PXE debug option.
471 */
472 pcbiosCmosWrite(pDevIns, 0x3f, pThis->u8PXEDebug);
473
474 /*
475 * Network boot device list.
476 */
477 for (i = 0; i < NET_BOOT_DEVS; ++i)
478 {
479 pcbiosCmosWrite(pDevIns, 0x82 + i * 2, pThis->au16NetBootDev[i] & 0xff);
480 pcbiosCmosWrite(pDevIns, 0x83 + i * 2, pThis->au16NetBootDev[i] >> 8);
481 }
482
483 /*
484 * Floppy drive type.
485 */
486 for (i = 0; i < RT_ELEMENTS(apFDs); i++)
487 {
488 PPDMIBASE pBase;
489 int rc = PDMR3QueryLun(pVM, pThis->pszFDDevice, 0, i, &pBase);
490 if (RT_SUCCESS(rc))
491 apFDs[i] = PDMIBASE_QUERY_INTERFACE(pBase, PDMIBLOCKBIOS);
492 }
493 u32 = 0;
494 if (apFDs[0])
495 switch (apFDs[0]->pfnGetType(apFDs[0]))
496 {
497 case PDMBLOCKTYPE_FLOPPY_360: u32 |= 1 << 4; break;
498 case PDMBLOCKTYPE_FLOPPY_1_20: u32 |= 2 << 4; break;
499 case PDMBLOCKTYPE_FLOPPY_720: u32 |= 3 << 4; break;
500 case PDMBLOCKTYPE_FLOPPY_1_44: u32 |= 4 << 4; break;
501 case PDMBLOCKTYPE_FLOPPY_2_88: u32 |= 5 << 4; break;
502 default: AssertFailed(); break;
503 }
504 if (apFDs[1])
505 switch (apFDs[1]->pfnGetType(apFDs[1]))
506 {
507 case PDMBLOCKTYPE_FLOPPY_360: u32 |= 1; break;
508 case PDMBLOCKTYPE_FLOPPY_1_20: u32 |= 2; break;
509 case PDMBLOCKTYPE_FLOPPY_720: u32 |= 3; break;
510 case PDMBLOCKTYPE_FLOPPY_1_44: u32 |= 4; break;
511 case PDMBLOCKTYPE_FLOPPY_2_88: u32 |= 5; break;
512 default: AssertFailed(); break;
513 }
514 pcbiosCmosWrite(pDevIns, 0x10, u32); /* 10h - Floppy Drive Type */
515
516 /*
517 * Equipment byte.
518 */
519 u32 = !!apFDs[0] + !!apFDs[1];
520 switch (u32)
521 {
522 case 1: u32 = 0x01; break; /* floppy installed, 2 drives. */
523 default:u32 = 0; break; /* floppy not installed. */
524 }
525 u32 |= RT_BIT(1); /* math coprocessor installed */
526 u32 |= RT_BIT(2); /* keyboard enabled (or mouse?) */
527 u32 |= RT_BIT(3); /* display enabled (monitory type is 0, i.e. vga) */
528 pcbiosCmosWrite(pDevIns, 0x14, u32); /* 14h - Equipment Byte */
529
530 /*
531 * Harddisks.
532 */
533 for (i = 0; i < RT_ELEMENTS(apHDs); i++)
534 {
535 PPDMIBASE pBase;
536 int rc = PDMR3QueryLun(pVM, pThis->pszHDDevice, 0, i, &pBase);
537 if (RT_SUCCESS(rc))
538 apHDs[i] = PDMIBASE_QUERY_INTERFACE(pBase, PDMIBLOCKBIOS);
539 if ( apHDs[i]
540 && ( apHDs[i]->pfnGetType(apHDs[i]) != PDMBLOCKTYPE_HARD_DISK
541 || !apHDs[i]->pfnIsVisible(apHDs[i])))
542 apHDs[i] = NULL;
543 if (apHDs[i])
544 {
545 PDMMEDIAGEOMETRY LCHSGeometry;
546 int rc2 = setLogicalDiskGeometry(pBase, apHDs[i], &LCHSGeometry);
547 AssertRC(rc2);
548
549 if (i < 4)
550 {
551 /* Award BIOS extended drive types for first to fourth disk.
552 * Used by the BIOS for setting the logical geometry. */
553 int offType, offInfo;
554 switch (i)
555 {
556 case 0:
557 offType = 0x19;
558 offInfo = 0x1e;
559 break;
560 case 1:
561 offType = 0x1a;
562 offInfo = 0x26;
563 break;
564 case 2:
565 offType = 0x00;
566 offInfo = 0x67;
567 break;
568 case 3:
569 default:
570 offType = 0x00;
571 offInfo = 0x70;
572 break;
573 }
574 pcbiosCmosInitHardDisk(pDevIns, offType, offInfo,
575 &LCHSGeometry);
576 }
577 LogRel(("DevPcBios: ATA LUN#%d LCHS=%u/%u/%u\n", i, LCHSGeometry.cCylinders, LCHSGeometry.cHeads, LCHSGeometry.cSectors));
578 }
579 }
580
581 /* 0Fh means extended and points to 19h, 1Ah */
582 u32 = (apHDs[0] ? 0xf0 : 0) | (apHDs[1] ? 0x0f : 0);
583 pcbiosCmosWrite(pDevIns, 0x12, u32);
584
585 /*
586 * Sata Harddisks.
587 */
588 if (pThis->pszSataDevice)
589 {
590 /* Clear pointers to IDE controller. */
591 for (i = 0; i < RT_ELEMENTS(apHDs); i++)
592 apHDs[i] = NULL;
593
594 for (i = 0; i < RT_ELEMENTS(apHDs); i++)
595 {
596 PPDMIBASE pBase;
597 int rc = PDMR3QueryLun(pVM, pThis->pszSataDevice, 0, pThis->iSataHDLUN[i], &pBase);
598 if (RT_SUCCESS(rc))
599 apHDs[i] = PDMIBASE_QUERY_INTERFACE(pBase, PDMIBLOCKBIOS);
600 if ( apHDs[i]
601 && ( apHDs[i]->pfnGetType(apHDs[i]) != PDMBLOCKTYPE_HARD_DISK
602 || !apHDs[i]->pfnIsVisible(apHDs[i])))
603 apHDs[i] = NULL;
604 if (apHDs[i])
605 {
606 PDMMEDIAGEOMETRY LCHSGeometry;
607 rc = setLogicalDiskGeometry(pBase, apHDs[i], &LCHSGeometry);
608 AssertRC(rc);
609
610 if (i < 4)
611 {
612 /* Award BIOS extended drive types for first to fourth disk.
613 * Used by the BIOS for setting the logical geometry. */
614 int offInfo;
615 switch (i)
616 {
617 case 0:
618 offInfo = 0x40;
619 break;
620 case 1:
621 offInfo = 0x48;
622 break;
623 case 2:
624 offInfo = 0x50;
625 break;
626 case 3:
627 default:
628 offInfo = 0x58;
629 break;
630 }
631 pcbiosCmosInitHardDisk(pDevIns, 0x00, offInfo,
632 &LCHSGeometry);
633 }
634 LogRel(("DevPcBios: SATA LUN#%d LCHS=%u/%u/%u\n", i, LCHSGeometry.cCylinders, LCHSGeometry.cHeads, LCHSGeometry.cSectors));
635 }
636 }
637 }
638
639 LogFlow(("%s: returns VINF_SUCCESS\n", __FUNCTION__));
640 return VINF_SUCCESS;
641}
642
643
644/**
645 * Port I/O Handler for IN operations.
646 *
647 * @returns VBox status code.
648 *
649 * @param pDevIns The device instance.
650 * @param pvUser User argument - ignored.
651 * @param Port Port number used for the IN operation.
652 * @param pu32 Where to store the result.
653 * @param cb Number of bytes read.
654 */
655static DECLCALLBACK(int) pcbiosIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
656{
657 NOREF(pDevIns);
658 NOREF(pvUser);
659 NOREF(Port);
660 NOREF(pu32);
661 NOREF(cb);
662 return VERR_IOM_IOPORT_UNUSED;
663}
664
665
666/**
667 * Port I/O Handler for OUT operations.
668 *
669 * @returns VBox status code.
670 *
671 * @param pDevIns The device instance.
672 * @param pvUser User argument - ignored.
673 * @param Port Port number used for the IN operation.
674 * @param u32 The value to output.
675 * @param cb The value size in bytes.
676 */
677static DECLCALLBACK(int) pcbiosIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
678{
679 /*
680 * Bochs BIOS Panic
681 */
682 if ( cb == 2
683 && ( Port == 0x400
684 || Port == 0x401))
685 {
686 Log(("pcbios: PC BIOS panic at rombios.c(%d)\n", u32));
687 AssertReleaseMsgFailed(("PC BIOS panic at rombios.c(%d)\n", u32));
688 return VERR_INTERNAL_ERROR;
689 }
690
691 /*
692 * Bochs BIOS char printing.
693 */
694 if ( cb == 1
695 && ( Port == 0x402
696 || Port == 0x403))
697 {
698 PDEVPCBIOS pThis = PDMINS_2_DATA(pDevIns, PDEVPCBIOS);
699 /* The raw version. */
700 switch (u32)
701 {
702 case '\r': Log2(("pcbios: <return>\n")); break;
703 case '\n': Log2(("pcbios: <newline>\n")); break;
704 case '\t': Log2(("pcbios: <tab>\n")); break;
705 default: Log2(("pcbios: %c (%02x)\n", u32, u32)); break;
706 }
707
708 /* The readable, buffered version. */
709 if (u32 == '\n' || u32 == '\r')
710 {
711 pThis->szMsg[pThis->iMsg] = '\0';
712 if (pThis->iMsg)
713 Log(("pcbios: %s\n", pThis->szMsg));
714 pThis->iMsg = 0;
715 }
716 else
717 {
718 if (pThis->iMsg >= sizeof(pThis->szMsg)-1)
719 {
720 pThis->szMsg[pThis->iMsg] = '\0';
721 Log(("pcbios: %s\n", pThis->szMsg));
722 pThis->iMsg = 0;
723 }
724 pThis->szMsg[pThis->iMsg] = (char )u32;
725 pThis->szMsg[++pThis->iMsg] = '\0';
726 }
727 return VINF_SUCCESS;
728 }
729
730 /*
731 * Bochs BIOS shutdown request.
732 */
733 if (cb == 1 && Port == 0x8900)
734 {
735 static const unsigned char szShutdown[] = "Shutdown";
736 PDEVPCBIOS pThis = PDMINS_2_DATA(pDevIns, PDEVPCBIOS);
737 if (u32 == szShutdown[pThis->iShutdown])
738 {
739 pThis->iShutdown++;
740 if (pThis->iShutdown == 8)
741 {
742 pThis->iShutdown = 0;
743 LogRel(("8900h shutdown request.\n"));
744 return PDMDevHlpVMPowerOff(pDevIns);
745 }
746 }
747 else
748 pThis->iShutdown = 0;
749 return VINF_SUCCESS;
750 }
751
752 /* not in use. */
753 return VINF_SUCCESS;
754}
755
756/**
757 * Reset notification.
758 *
759 * @returns VBox status.
760 * @param pDevIns The device instance data.
761 */
762static DECLCALLBACK(void) pcbiosReset(PPDMDEVINS pDevIns)
763{
764 PDEVPCBIOS pThis = PDMINS_2_DATA(pDevIns, PDEVPCBIOS);
765 LogFlow(("pcbiosReset:\n"));
766
767 if (pThis->u8IOAPIC)
768 FwCommonPlantMpsFloatPtr(pDevIns);
769
770 /*
771 * Re-shadow the LAN ROM image and make it RAM/RAM.
772 *
773 * This is normally done by the BIOS code, but since we're currently lacking
774 * the chipset support for this we do it here (and in the constructor).
775 */
776 uint32_t cPages = RT_ALIGN_64(pThis->cbLanBoot, PAGE_SIZE) >> PAGE_SHIFT;
777 RTGCPHYS GCPhys = VBOX_LANBOOT_SEG << 4;
778 while (cPages > 0)
779 {
780 uint8_t abPage[PAGE_SIZE];
781 int rc;
782
783 /* Read the (original) ROM page and write it back to the RAM page. */
784 rc = PDMDevHlpROMProtectShadow(pDevIns, GCPhys, PAGE_SIZE, PGMROMPROT_READ_ROM_WRITE_RAM);
785 AssertLogRelRC(rc);
786
787 rc = PDMDevHlpPhysRead(pDevIns, GCPhys, abPage, PAGE_SIZE);
788 AssertLogRelRC(rc);
789 if (RT_FAILURE(rc))
790 memset(abPage, 0xcc, sizeof(abPage));
791
792 rc = PDMDevHlpPhysWrite(pDevIns, GCPhys, abPage, PAGE_SIZE);
793 AssertLogRelRC(rc);
794
795 /* Switch to the RAM/RAM mode. */
796 rc = PDMDevHlpROMProtectShadow(pDevIns, GCPhys, PAGE_SIZE, PGMROMPROT_READ_RAM_WRITE_RAM);
797 AssertLogRelRC(rc);
798
799 /* Advance */
800 GCPhys += PAGE_SIZE;
801 cPages--;
802 }
803}
804
805
806/**
807 * Destruct a device instance.
808 *
809 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
810 * resources can be freed correctly.
811 *
812 * @param pDevIns The device instance data.
813 */
814static DECLCALLBACK(int) pcbiosDestruct(PPDMDEVINS pDevIns)
815{
816 PDEVPCBIOS pThis = PDMINS_2_DATA(pDevIns, PDEVPCBIOS);
817 LogFlow(("pcbiosDestruct:\n"));
818 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
819
820 /*
821 * Free MM heap pointers.
822 */
823 if (pThis->pu8PcBios)
824 {
825 MMR3HeapFree(pThis->pu8PcBios);
826 pThis->pu8PcBios = NULL;
827 }
828
829 if (pThis->pszPcBiosFile)
830 {
831 MMR3HeapFree(pThis->pszPcBiosFile);
832 pThis->pszPcBiosFile = NULL;
833 }
834
835 if (pThis->pu8LanBoot)
836 {
837 MMR3HeapFree(pThis->pu8LanBoot);
838 pThis->pu8LanBoot = NULL;
839 }
840
841 if (pThis->pszLanBootFile)
842 {
843 MMR3HeapFree(pThis->pszLanBootFile);
844 pThis->pszLanBootFile = NULL;
845 }
846
847 if (pThis->pszHDDevice)
848 {
849 MMR3HeapFree(pThis->pszHDDevice);
850 pThis->pszHDDevice = NULL;
851 }
852
853 if (pThis->pszFDDevice)
854 {
855 MMR3HeapFree(pThis->pszFDDevice);
856 pThis->pszFDDevice = NULL;
857 }
858
859 if (pThis->pszSataDevice)
860 {
861 MMR3HeapFree(pThis->pszSataDevice);
862 pThis->pszSataDevice = NULL;
863 }
864
865 return VINF_SUCCESS;
866}
867
868
869/**
870 * Convert config value to DEVPCBIOSBOOT.
871 *
872 * @returns VBox status code.
873 * @param pCfg Configuration handle.
874 * @param pszParam The name of the value to read.
875 * @param penmBoot Where to store the boot method.
876 */
877static int pcbiosBootFromCfg(PPDMDEVINS pDevIns, PCFGMNODE pCfg, const char *pszParam, DEVPCBIOSBOOT *penmBoot)
878{
879 char *psz;
880 int rc = CFGMR3QueryStringAlloc(pCfg, pszParam, &psz);
881 if (RT_FAILURE(rc))
882 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
883 N_("Configuration error: Querying \"%s\" as a string failed"),
884 pszParam);
885 if (!strcmp(psz, "DVD") || !strcmp(psz, "CDROM"))
886 *penmBoot = DEVPCBIOSBOOT_DVD;
887 else if (!strcmp(psz, "IDE"))
888 *penmBoot = DEVPCBIOSBOOT_HD;
889 else if (!strcmp(psz, "FLOPPY"))
890 *penmBoot = DEVPCBIOSBOOT_FLOPPY;
891 else if (!strcmp(psz, "LAN"))
892 *penmBoot = DEVPCBIOSBOOT_LAN;
893 else if (!strcmp(psz, "NONE"))
894 *penmBoot = DEVPCBIOSBOOT_NONE;
895 else
896 {
897 PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
898 N_("Configuration error: The \"%s\" value \"%s\" is unknown"),
899 pszParam, psz);
900 rc = VERR_INTERNAL_ERROR;
901 }
902 MMR3HeapFree(psz);
903 return rc;
904}
905
906/**
907 * @interface_method_impl{PDMDEVREG,pfnConstruct}
908 */
909static DECLCALLBACK(int) pcbiosConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
910{
911 unsigned i;
912 PDEVPCBIOS pThis = PDMINS_2_DATA(pDevIns, PDEVPCBIOS);
913 int rc;
914 int cb;
915
916 Assert(iInstance == 0);
917 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
918
919 /*
920 * Validate configuration.
921 */
922 if (!CFGMR3AreValuesValid(pCfg,
923 "BootDevice0\0"
924 "BootDevice1\0"
925 "BootDevice2\0"
926 "BootDevice3\0"
927 "RamSize\0"
928 "RamHoleSize\0"
929 "HardDiskDevice\0"
930 "SataHardDiskDevice\0"
931 "SataPrimaryMasterLUN\0"
932 "SataPrimarySlaveLUN\0"
933 "SataSecondaryMasterLUN\0"
934 "SataSecondarySlaveLUN\0"
935 "FloppyDevice\0"
936 "DelayBoot\0"
937 "BiosRom\0"
938 "LanBootRom\0"
939 "PXEDebug\0"
940 "UUID\0"
941 "IOAPIC\0"
942 "NumCPUs\0"
943 "DmiBIOSVendor\0"
944 "DmiBIOSVersion\0"
945 "DmiBIOSReleaseDate\0"
946 "DmiBIOSReleaseMajor\0"
947 "DmiBIOSReleaseMinor\0"
948 "DmiBIOSFirmwareMajor\0"
949 "DmiBIOSFirmwareMinor\0"
950 "DmiSystemSKU\0"
951 "DmiSystemFamily\0"
952 "DmiSystemProduct\0"
953 "DmiSystemSerial\0"
954 "DmiSystemUuid\0"
955 "DmiSystemVendor\0"
956 "DmiSystemVersion\0"
957 "DmiChassisVendor\0"
958 "DmiChassisVersion\0"
959 "DmiChassisSerial\0"
960 "DmiChassisAssetTag\0"
961#ifdef VBOX_WITH_DMI_OEMSTRINGS
962 "DmiOEMVBoxVer\0"
963 "DmiOEMVBoxRev\0"
964#endif
965 "DmiUseHostInfo\0"
966 "DmiExposeMemoryTable\0"
967 ))
968 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
969 N_("Invalid configuration for device pcbios device"));
970
971 /*
972 * Init the data.
973 */
974 rc = CFGMR3QueryU64(pCfg, "RamSize", &pThis->cbRam);
975 if (RT_FAILURE(rc))
976 return PDMDEV_SET_ERROR(pDevIns, rc,
977 N_("Configuration error: Querying \"RamSize\" as integer failed"));
978
979 rc = CFGMR3QueryU32Def(pCfg, "RamHoleSize", &pThis->cbRamHole, MM_RAM_HOLE_SIZE_DEFAULT);
980 if (RT_FAILURE(rc))
981 return PDMDEV_SET_ERROR(pDevIns, rc,
982 N_("Configuration error: Querying \"RamHoleSize\" as integer failed"));
983
984 rc = CFGMR3QueryU16Def(pCfg, "NumCPUs", &pThis->cCpus, 1);
985 if (RT_FAILURE(rc))
986 return PDMDEV_SET_ERROR(pDevIns, rc,
987 N_("Configuration error: Querying \"NumCPUs\" as integer failed"));
988
989 LogRel(("[SMP] BIOS with %u CPUs\n", pThis->cCpus));
990
991 rc = CFGMR3QueryU8Def(pCfg, "IOAPIC", &pThis->u8IOAPIC, 1);
992 if (RT_FAILURE (rc))
993 return PDMDEV_SET_ERROR(pDevIns, rc,
994 N_("Configuration error: Failed to read \"IOAPIC\""));
995
996 static const char * const s_apszBootDevices[] = { "BootDevice0", "BootDevice1", "BootDevice2", "BootDevice3" };
997 Assert(RT_ELEMENTS(s_apszBootDevices) == RT_ELEMENTS(pThis->aenmBootDevice));
998 for (i = 0; i < RT_ELEMENTS(pThis->aenmBootDevice); i++)
999 {
1000 rc = pcbiosBootFromCfg(pDevIns, pCfg, s_apszBootDevices[i], &pThis->aenmBootDevice[i]);
1001 if (RT_FAILURE(rc))
1002 return rc;
1003 }
1004
1005 rc = CFGMR3QueryStringAlloc(pCfg, "HardDiskDevice", &pThis->pszHDDevice);
1006 if (RT_FAILURE(rc))
1007 return PDMDEV_SET_ERROR(pDevIns, rc,
1008 N_("Configuration error: Querying \"HardDiskDevice\" as a string failed"));
1009
1010 rc = CFGMR3QueryStringAlloc(pCfg, "FloppyDevice", &pThis->pszFDDevice);
1011 if (RT_FAILURE(rc))
1012 return PDMDEV_SET_ERROR(pDevIns, rc,
1013 N_("Configuration error: Querying \"FloppyDevice\" as a string failed"));
1014
1015 rc = CFGMR3QueryStringAlloc(pCfg, "SataHardDiskDevice", &pThis->pszSataDevice);
1016 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1017 pThis->pszSataDevice = NULL;
1018 else if (RT_FAILURE(rc))
1019 return PDMDEV_SET_ERROR(pDevIns, rc,
1020 N_("Configuration error: Querying \"SataHardDiskDevice\" as a string failed"));
1021
1022 if (pThis->pszSataDevice)
1023 {
1024 static const char * const s_apszSataDisks[] =
1025 { "SataPrimaryMasterLUN", "SataPrimarySlaveLUN", "SataSecondaryMasterLUN", "SataSecondarySlaveLUN" };
1026 Assert(RT_ELEMENTS(s_apszSataDisks) == RT_ELEMENTS(pThis->iSataHDLUN));
1027 for (i = 0; i < RT_ELEMENTS(pThis->iSataHDLUN); i++)
1028 {
1029 rc = CFGMR3QueryU32(pCfg, s_apszSataDisks[i], &pThis->iSataHDLUN[i]);
1030 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1031 pThis->iSataHDLUN[i] = i;
1032 else if (RT_FAILURE(rc))
1033 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1034 N_("Configuration error: Querying \"%s\" as a string failed"), s_apszSataDisks);
1035 }
1036 }
1037 /*
1038 * Register I/O Ports and PC BIOS.
1039 */
1040 rc = PDMDevHlpIOPortRegister(pDevIns, 0x400, 4, NULL, pcbiosIOPortWrite, pcbiosIOPortRead,
1041 NULL, NULL, "Bochs PC BIOS - Panic & Debug");
1042 if (RT_FAILURE(rc))
1043 return rc;
1044 rc = PDMDevHlpIOPortRegister(pDevIns, 0x8900, 1, NULL, pcbiosIOPortWrite, pcbiosIOPortRead,
1045 NULL, NULL, "Bochs PC BIOS - Shutdown");
1046 if (RT_FAILURE(rc))
1047 return rc;
1048
1049 /*
1050 * Query the machine's UUID for SMBIOS/DMI use.
1051 */
1052 RTUUID uuid;
1053 rc = CFGMR3QueryBytes(pCfg, "UUID", &uuid, sizeof(uuid));
1054 if (RT_FAILURE(rc))
1055 return PDMDEV_SET_ERROR(pDevIns, rc,
1056 N_("Configuration error: Querying \"UUID\" failed"));
1057
1058
1059 /* Convert the UUID to network byte order. Not entirely straightforward as parts are MSB already... */
1060 uuid.Gen.u32TimeLow = RT_H2BE_U32(uuid.Gen.u32TimeLow);
1061 uuid.Gen.u16TimeMid = RT_H2BE_U16(uuid.Gen.u16TimeMid);
1062 uuid.Gen.u16TimeHiAndVersion = RT_H2BE_U16(uuid.Gen.u16TimeHiAndVersion);
1063 rc = FwCommonPlantDMITable(pDevIns, pThis->au8DMIPage,
1064 VBOX_DMI_TABLE_SIZE, &uuid, pCfg);
1065 if (RT_FAILURE(rc))
1066 return rc;
1067 if (pThis->u8IOAPIC)
1068 FwCommonPlantMpsTable(pDevIns, pThis->au8DMIPage + VBOX_DMI_TABLE_SIZE,
1069 _4K - VBOX_DMI_TABLE_SIZE, pThis->cCpus);
1070
1071 rc = PDMDevHlpROMRegister(pDevIns, VBOX_DMI_TABLE_BASE, _4K, pThis->au8DMIPage,
1072 PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "DMI tables");
1073 if (RT_FAILURE(rc))
1074 return rc;
1075
1076 /*
1077 * Read the PXE debug logging option.
1078 */
1079 rc = CFGMR3QueryU8Def(pCfg, "PXEDebug", &pThis->u8PXEDebug, false);
1080 if (RT_FAILURE(rc))
1081 return PDMDEV_SET_ERROR(pDevIns, rc,
1082 N_("Configuration error: Querying \"PXEDebug\" as integer failed"));
1083
1084 /* Clear the net boot device list. All bits set invokes old behavior,
1085 * as if no second CMOS bank was present.
1086 */
1087 memset(&pThis->au16NetBootDev, 0xff, sizeof(pThis->au16NetBootDev));
1088
1089 /*
1090 * Determine the network boot order.
1091 */
1092 PCFGMNODE pCfgNetBoot = CFGMR3GetChild(pCfg, "NetBoot");
1093 if (pCfgNetBoot == NULL)
1094 {
1095 /* Do nothing. */
1096 rc = VINF_SUCCESS;
1097 }
1098 else
1099 {
1100 PCFGMNODE pCfgNetBootDevice;
1101 uint8_t u8PciDev;
1102 uint8_t u8PciFn;
1103 uint16_t u16BusDevFn;
1104 char szIndex[] = "?";
1105
1106 Assert(pCfgNetBoot);
1107 for (i = 0; i < NET_BOOT_DEVS; ++i)
1108 {
1109 szIndex[0] = '0' + i;
1110 pCfgNetBootDevice = CFGMR3GetChild(pCfgNetBoot, szIndex);
1111 rc = CFGMR3QueryU8(pCfgNetBootDevice, "PCIDeviceNo", &u8PciDev);
1112 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
1113 {
1114 /* Do nothing and stop iterating. */
1115 rc = VINF_SUCCESS;
1116 break;
1117 }
1118 else if (RT_FAILURE(rc))
1119 return PDMDEV_SET_ERROR(pDevIns, rc,
1120 N_("Configuration error: Querying \"Netboot/x/PCIDeviceNo\" as integer failed"));
1121 rc = CFGMR3QueryU8(pCfgNetBootDevice, "PCIFunctionNo", &u8PciFn);
1122 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
1123 {
1124 /* Do nothing and stop iterating. */
1125 rc = VINF_SUCCESS;
1126 break;
1127 }
1128 else if (RT_FAILURE(rc))
1129 return PDMDEV_SET_ERROR(pDevIns, rc,
1130 N_("Configuration error: Querying \"Netboot/x/PCIFunctionNo\" as integer failed"));
1131 u16BusDevFn = ((u8PciDev & 0x1F) << 3) | (u8PciFn & 0x7);
1132 pThis->au16NetBootDev[i] = u16BusDevFn;
1133 }
1134 }
1135
1136 /*
1137 * Get the system BIOS ROM file name.
1138 */
1139 rc = CFGMR3QueryStringAlloc(pCfg, "BiosRom", &pThis->pszPcBiosFile);
1140 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1141 {
1142 pThis->pszPcBiosFile = NULL;
1143 rc = VINF_SUCCESS;
1144 }
1145 else if (RT_FAILURE(rc))
1146 return PDMDEV_SET_ERROR(pDevIns, rc,
1147 N_("Configuration error: Querying \"BiosRom\" as a string failed"));
1148 else if (!*pThis->pszPcBiosFile)
1149 {
1150 MMR3HeapFree(pThis->pszPcBiosFile);
1151 pThis->pszPcBiosFile = NULL;
1152 }
1153
1154 const uint8_t *pu8PcBiosBinary = NULL;
1155 uint64_t cbPcBiosBinary;
1156 /*
1157 * Determine the system BIOS ROM size, open specified ROM file in the process.
1158 */
1159 RTFILE FilePcBios = NIL_RTFILE;
1160 if (pThis->pszPcBiosFile)
1161 {
1162 rc = RTFileOpen(&FilePcBios, pThis->pszPcBiosFile,
1163 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
1164 if (RT_SUCCESS(rc))
1165 {
1166 rc = RTFileGetSize(FilePcBios, &pThis->cbPcBios);
1167 if (RT_SUCCESS(rc))
1168 {
1169 /* The following checks should be in sync the AssertReleaseMsg's below. */
1170 if ( RT_ALIGN(pThis->cbPcBios, _64K) != pThis->cbPcBios
1171 || pThis->cbPcBios > 32 * _64K
1172 || pThis->cbPcBios < _64K)
1173 rc = VERR_TOO_MUCH_DATA;
1174 }
1175 }
1176 if (RT_FAILURE(rc))
1177 {
1178 /*
1179 * In case of failure simply fall back to the built-in BIOS ROM.
1180 */
1181 Log(("pcbiosConstruct: Failed to open system BIOS ROM file '%s', rc=%Rrc!\n", pThis->pszPcBiosFile, rc));
1182 RTFileClose(FilePcBios);
1183 FilePcBios = NIL_RTFILE;
1184 MMR3HeapFree(pThis->pszPcBiosFile);
1185 pThis->pszPcBiosFile = NULL;
1186 }
1187 }
1188
1189 /*
1190 * Attempt to get the system BIOS ROM data from file.
1191 */
1192 if (pThis->pszPcBiosFile)
1193 {
1194 /*
1195 * Allocate buffer for the system BIOS ROM data.
1196 */
1197 pThis->pu8PcBios = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, pThis->cbPcBios);
1198 if (pThis->pu8PcBios)
1199 {
1200 rc = RTFileRead(FilePcBios, pThis->pu8PcBios, pThis->cbPcBios, NULL);
1201 if (RT_FAILURE(rc))
1202 {
1203 AssertMsgFailed(("RTFileRead(,,%d,NULL) -> %Rrc\n", pThis->cbPcBios, rc));
1204 MMR3HeapFree(pThis->pu8PcBios);
1205 pThis->pu8PcBios = NULL;
1206 }
1207 rc = VINF_SUCCESS;
1208 }
1209 else
1210 rc = VERR_NO_MEMORY;
1211 }
1212 else
1213 pThis->pu8PcBios = NULL;
1214
1215 /* cleanup */
1216 if (FilePcBios != NIL_RTFILE)
1217 RTFileClose(FilePcBios);
1218
1219 /* If we were unable to get the data from file for whatever reason, fall
1220 back to the built-in ROM image. */
1221 uint32_t fFlags = 0;
1222 if (pThis->pu8PcBios == NULL)
1223 {
1224 pu8PcBiosBinary = g_abPcBiosBinary;
1225 cbPcBiosBinary = g_cbPcBiosBinary;
1226 fFlags = PGMPHYS_ROM_FLAGS_PERMANENT_BINARY;
1227 }
1228 else
1229 {
1230 pu8PcBiosBinary = pThis->pu8PcBios;
1231 cbPcBiosBinary = pThis->cbPcBios;
1232 }
1233
1234 /*
1235 * Map the BIOS into memory.
1236 * There are two mappings:
1237 * 1. 0x000e0000 to 0x000fffff contains the last 128 kb of the bios.
1238 * The bios code might be 64 kb in size, and will then start at 0xf0000.
1239 * 2. 0xfffxxxxx to 0xffffffff contains the entire bios.
1240 */
1241 AssertReleaseMsg(cbPcBiosBinary >= _64K, ("cbPcBiosBinary=%#x\n", cbPcBiosBinary));
1242 AssertReleaseMsg(RT_ALIGN_Z(cbPcBiosBinary, _64K) == cbPcBiosBinary,
1243 ("cbPcBiosBinary=%#x\n", cbPcBiosBinary));
1244 cb = RT_MIN(cbPcBiosBinary, 128 * _1K); /* Effectively either 64 or 128K. */
1245 rc = PDMDevHlpROMRegister(pDevIns, 0x00100000 - cb, cb, &pu8PcBiosBinary[cbPcBiosBinary - cb],
1246 fFlags, "PC BIOS - 0xfffff");
1247 if (RT_FAILURE(rc))
1248 return rc;
1249 rc = PDMDevHlpROMRegister(pDevIns, (uint32_t)-(int32_t)cbPcBiosBinary, cbPcBiosBinary, pu8PcBiosBinary,
1250 fFlags, "PC BIOS - 0xffffffff");
1251 if (RT_FAILURE(rc))
1252 return rc;
1253
1254 /*
1255 * Get the LAN boot ROM file name.
1256 */
1257 rc = CFGMR3QueryStringAlloc(pCfg, "LanBootRom", &pThis->pszLanBootFile);
1258 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1259 {
1260 pThis->pszLanBootFile = NULL;
1261 rc = VINF_SUCCESS;
1262 }
1263 else if (RT_FAILURE(rc))
1264 return PDMDEV_SET_ERROR(pDevIns, rc,
1265 N_("Configuration error: Querying \"LanBootRom\" as a string failed"));
1266 else if (!*pThis->pszLanBootFile)
1267 {
1268 MMR3HeapFree(pThis->pszLanBootFile);
1269 pThis->pszLanBootFile = NULL;
1270 }
1271
1272 uint64_t cbFileLanBoot;
1273 const uint8_t *pu8LanBootBinary = NULL;
1274 uint64_t cbLanBootBinary;
1275
1276 /*
1277 * Determine the LAN boot ROM size, open specified ROM file in the process.
1278 */
1279 RTFILE FileLanBoot = NIL_RTFILE;
1280 if (pThis->pszLanBootFile)
1281 {
1282 rc = RTFileOpen(&FileLanBoot, pThis->pszLanBootFile,
1283 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
1284 if (RT_SUCCESS(rc))
1285 {
1286 rc = RTFileGetSize(FileLanBoot, &cbFileLanBoot);
1287 if (RT_SUCCESS(rc))
1288 {
1289 if ( RT_ALIGN(cbFileLanBoot, _4K) != cbFileLanBoot
1290 || cbFileLanBoot > _64K)
1291 rc = VERR_TOO_MUCH_DATA;
1292 }
1293 }
1294 if (RT_FAILURE(rc))
1295 {
1296 /*
1297 * Ignore failure and fall back to the built-in LAN boot ROM.
1298 */
1299 Log(("pcbiosConstruct: Failed to open LAN boot ROM file '%s', rc=%Rrc!\n", pThis->pszLanBootFile, rc));
1300 RTFileClose(FileLanBoot);
1301 FileLanBoot = NIL_RTFILE;
1302 MMR3HeapFree(pThis->pszLanBootFile);
1303 pThis->pszLanBootFile = NULL;
1304 }
1305 }
1306
1307 /*
1308 * Get the LAN boot ROM data.
1309 */
1310 if (pThis->pszLanBootFile)
1311 {
1312 /*
1313 * Allocate buffer for the LAN boot ROM data.
1314 */
1315 pThis->pu8LanBoot = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, cbFileLanBoot);
1316 if (pThis->pu8LanBoot)
1317 {
1318 rc = RTFileRead(FileLanBoot, pThis->pu8LanBoot, cbFileLanBoot, NULL);
1319 if (RT_FAILURE(rc))
1320 {
1321 AssertMsgFailed(("RTFileRead(,,%d,NULL) -> %Rrc\n", cbFileLanBoot, rc));
1322 MMR3HeapFree(pThis->pu8LanBoot);
1323 pThis->pu8LanBoot = NULL;
1324 }
1325 rc = VINF_SUCCESS;
1326 }
1327 else
1328 rc = VERR_NO_MEMORY;
1329 }
1330 else
1331 pThis->pu8LanBoot = NULL;
1332
1333 /* cleanup */
1334 if (FileLanBoot != NIL_RTFILE)
1335 RTFileClose(FileLanBoot);
1336
1337 /* If we were unable to get the data from file for whatever reason, fall
1338 * back to the built-in LAN boot ROM image.
1339 */
1340 if (pThis->pu8LanBoot == NULL)
1341 {
1342 pu8LanBootBinary = g_abNetBiosBinary;
1343 cbLanBootBinary = g_cbNetBiosBinary;
1344 }
1345 else
1346 {
1347 pu8LanBootBinary = pThis->pu8LanBoot;
1348 cbLanBootBinary = cbFileLanBoot;
1349 }
1350
1351 /*
1352 * Map the Network Boot ROM into memory.
1353 * Currently there is a fixed mapping: 0x000c8000 to 0x000cffff contains
1354 * the (up to) 32 kb ROM image.
1355 */
1356 if (pu8LanBootBinary)
1357 {
1358 pThis->cbLanBoot = cbLanBootBinary;
1359
1360 rc = PDMDevHlpROMRegister(pDevIns, VBOX_LANBOOT_SEG << 4, cbLanBootBinary, pu8LanBootBinary,
1361 PGMPHYS_ROM_FLAGS_SHADOWED, "Net Boot ROM");
1362 AssertRCReturn(rc, rc);
1363 }
1364
1365 rc = CFGMR3QueryU8Def(pCfg, "DelayBoot", &pThis->uBootDelay, 0);
1366 if (RT_FAILURE(rc))
1367 return PDMDEV_SET_ERROR(pDevIns, rc,
1368 N_("Configuration error: Querying \"DelayBoot\" as integer failed"));
1369 if (pThis->uBootDelay > 15)
1370 pThis->uBootDelay = 15;
1371
1372 /*
1373 * Call reset plant tables and shadow the PXE ROM.
1374 */
1375 pcbiosReset(pDevIns);
1376
1377 return VINF_SUCCESS;
1378}
1379
1380
1381/**
1382 * The device registration structure.
1383 */
1384const PDMDEVREG g_DevicePcBios =
1385{
1386 /* u32Version */
1387 PDM_DEVREG_VERSION,
1388 /* szName */
1389 "pcbios",
1390 /* szRCMod */
1391 "",
1392 /* szR0Mod */
1393 "",
1394 /* pszDescription */
1395 "PC BIOS Device",
1396 /* fFlags */
1397 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64,
1398 /* fClass */
1399 PDM_DEVREG_CLASS_ARCH_BIOS,
1400 /* cMaxInstances */
1401 1,
1402 /* cbInstance */
1403 sizeof(DEVPCBIOS),
1404 /* pfnConstruct */
1405 pcbiosConstruct,
1406 /* pfnDestruct */
1407 pcbiosDestruct,
1408 /* pfnRelocate */
1409 NULL,
1410 /* pfnIOCtl */
1411 NULL,
1412 /* pfnPowerOn */
1413 NULL,
1414 /* pfnReset */
1415 pcbiosReset,
1416 /* pfnSuspend */
1417 NULL,
1418 /* pfnResume */
1419 NULL,
1420 /* pfnAttach */
1421 NULL,
1422 /* pfnDetach */
1423 NULL,
1424 /* pfnQueryInterface. */
1425 NULL,
1426 /* pfnInitComplete. */
1427 pcbiosInitComplete,
1428 /* pfnPowerOff */
1429 NULL,
1430 /* pfnSoftReset */
1431 NULL,
1432 /* u32VersionEnd */
1433 PDM_DEVREG_VERSION
1434};
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