VirtualBox

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

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

PC/DevPcBios: Compilation error fixed

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

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