VirtualBox

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

Last change on this file since 27275 was 26728, checked in by vboxsync, 15 years ago

BIOS/DMI: fixed a bug where structures without strings were not properly terminated and increase the limit for DMI strings a little bit

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