VirtualBox

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

Last change on this file since 2392 was 1735, checked in by vboxsync, 18 years ago

Partly revert previous CHS translation and shuffle around 16383 cylinder
clipping.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 42.7 KB
Line 
1/** @file
2 *
3 * VBox basic PC devices:
4 * PC BIOS device
5 */
6
7/*
8 * Copyright (C) 2006 InnoTek Systemberatung GmbH
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License as published by the Free Software Foundation,
14 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
15 * distribution. VirtualBox OSE is distributed in the hope that it will
16 * be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * If you received this file as part of a commercial VirtualBox
19 * distribution, then only the terms of your commercial VirtualBox
20 * license agreement apply instead of the previous paragraph.
21 */
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#define LOG_GROUP LOG_GROUP_DEV_PC_BIOS
27#include <VBox/pdm.h>
28#include <VBox/mm.h>
29
30#include <VBox/log.h>
31#include <iprt/assert.h>
32#include <iprt/alloc.h>
33#include <iprt/file.h>
34#include <iprt/string.h>
35#include <VBox/err.h>
36
37#include "vl_vbox.h"
38#include "Builtins.h"
39#include "Builtins2.h"
40#include "DevPcBios.h"
41
42
43/*******************************************************************************
44* Structures and Typedefs *
45*******************************************************************************/
46
47/**
48 * The boot device.
49 */
50typedef enum DEVPCBIOSBOOT
51{
52 DEVPCBIOSBOOT_NONE,
53 DEVPCBIOSBOOT_FLOPPY,
54 DEVPCBIOSBOOT_HD,
55 DEVPCBIOSBOOT_DVD,
56 DEVPCBIOSBOOT_LAN
57} DEVPCBIOSBOOT;
58
59/**
60 * PC Bios instance data structure.
61 */
62typedef struct DEVPCBIOS
63{
64 /** Pointer back to the device instance. */
65 PPDMDEVINS pDevIns;
66
67 /** Boot devices (ordered). */
68 DEVPCBIOSBOOT aenmBootDevice[4];
69 /** Ram Size (in bytes). */
70 uint64_t cbRam;
71 /** Bochs shutdown index. */
72 uint32_t iShutdown;
73 /** Floppy device. */
74 char *pszFDDevice;
75 /** Harddisk device. */
76 char *pszHDDevice;
77 /** Bios message buffer. */
78 char szMsg[256];
79 /** Bios message buffer index. */
80 uint32_t iMsg;
81 /** Current logo data memory bank. */
82 uint8_t u8LogoBank;
83 /** The size of the BIOS logo data. */
84 uint32_t cbLogo;
85 /** The BIOS logo data. */
86 uint8_t *pu8Logo;
87 /** The name of the logo file. */
88 char *pszLogoFile;
89 /** The LAN boot ROM data. */
90 uint8_t *pu8LanBoot;
91 /** The name of the LAN boot ROM file. */
92 char *pszLanBootFile;
93 /** The DMI tables. */
94 uint8_t au8DMIPage[0x1000];
95 /** The boot countdown (in seconds). */
96 uint8_t uBootDelay;
97} DEVPCBIOS, *PDEVPCBIOS;
98
99
100/** @todo The logo stuff shared with the BIOS goes into a header of course. */
101
102/**
103 * PC Bios logo data structure.
104 */
105#pragma pack(2) /* pack(2) is important! (seems that bios compiled with pack(2)...) */
106typedef struct LOGOHDR
107{
108 /** Signature (0x66BB). */
109 uint16_t u16Signature;
110 /** Fade in - boolean. */
111 uint8_t u8FadeIn;
112 /** Fade out - boolean. */
113 uint8_t u8FadeOut;
114 /** Logo time (msec). */
115 uint16_t u16LogoMillies;
116 /** Show setup - boolean. */
117 uint8_t u8ShowBootMenu;
118 /** Logo file size. */
119 uint32_t cbLogo;
120} LOGOHDR, *PLOGOHDR;
121#pragma pack()
122
123/** The value of the LOGOHDR::u16Signature field. */
124#define LOGOHDR_MAGIC 0x66BB
125
126/** Size of a logo bank. */
127#define LOGO_BANK_SIZE 0xffff
128/** Logo offset mask. */
129#define LOGO_BANK_OFFSET 0xffff
130/** The last bank for custom logo data. */
131#define LOGO_BANK_LAST 254
132/** The bank which will give you the default logo. */
133#define LOGO_BANK_DEFAULT_LOGO 255
134
135#pragma pack(1)
136
137typedef struct DMIHDR
138{
139 uint8_t u8Type;
140 uint8_t u8Length;
141 uint16_t u16Handle;
142} *PDMIHDR;
143
144typedef struct DMIBIOSINF
145{
146 DMIHDR header;
147 uint8_t u8Vendor;
148 uint8_t u8Version;
149 uint16_t u16Start;
150 uint8_t u8Release;
151 uint8_t u8ROMSize;
152 uint64_t u64Characteristics;
153 uint8_t u8CharacteristicsByte1;
154 uint8_t u8CharacteristicsByte2;
155} *PDMIBIOSINF;
156
157typedef struct DMISYSTEMINF
158{
159 DMIHDR header;
160 uint8_t u8Manufacturer;
161 uint8_t u8ProductName;
162 uint8_t u8Version;
163 uint8_t u8SerialNumber;
164 uint8_t au8Uuid[16];
165 uint8_t u8WakeupType;
166 uint8_t u8SKUNumber;
167 uint8_t u8Family;
168} *PDMISYSTEMINF;
169
170#pragma pack()
171
172
173/*******************************************************************************
174* Internal Functions *
175*******************************************************************************/
176__BEGIN_DECLS
177
178static DECLCALLBACK(int) logoMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
179static DECLCALLBACK(int) logoMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
180
181__END_DECLS
182
183
184/**
185 * Write to CMOS memory.
186 * This is used by the init complete code.
187 */
188static void pcbiosCmosWrite(PPDMDEVINS pDevIns, int off, uint32_t u32Val)
189{
190 Assert(off < 128);
191 Assert(u32Val < 256);
192
193#if 1
194 int rc = PDMDevHlpCMOSWrite(pDevIns, off, u32Val);
195 AssertRC(rc);
196#else
197 PVM pVM = PDMDevHlpGetVM(pDevIns);
198 IOMIOPortWrite(pVM, 0x70, off, 1);
199 IOMIOPortWrite(pVM, 0x71, u32Val, 1);
200 IOMIOPortWrite(pVM, 0x70, 0, 1);
201#endif
202}
203
204/* -=-=-=-=-=-=- based on code from pc.c -=-=-=-=-=-=- */
205
206/**
207 * Initializes the CMOS data for one harddisk.
208 */
209static void pcbiosCmosInitHardDisk(PPDMDEVINS pDevIns, int offType, int offInfo, PPDMIBLOCKBIOS pBlockBios)
210{
211 if ( pBlockBios->pfnGetType(pBlockBios) == PDMBLOCKTYPE_HARD_DISK
212 && pBlockBios->pfnIsVisible(pBlockBios))
213 {
214 uint32_t cCylinders;
215 uint32_t cHeads;
216 uint32_t cSectors;
217 int rc = pBlockBios->pfnGetGeometry(pBlockBios, &cCylinders, &cHeads, &cSectors);
218 if (VBOX_SUCCESS(rc))
219 {
220 Log2(("pcbiosCmosInitHardDisk: offInfo=%#x: CHS=%d/%d/%d\n", offInfo, cCylinders, cHeads, cSectors));
221 pcbiosCmosWrite(pDevIns, offType, 47); /* 19h - First Extended Hard Disk Drive Type */
222 pcbiosCmosWrite(pDevIns, offInfo + 0, RT_MIN(cCylinders, 16383) & 0xff); /* 1Bh - (AMI) First Hard Disk (type 47) user defined: # of Cylinders, LSB */
223 pcbiosCmosWrite(pDevIns, offInfo + 1, RT_MIN(cCylinders, 16383) >> 8); /* 1Ch - (AMI) First Hard Disk user defined: # of Cylinders, High Byte */
224 pcbiosCmosWrite(pDevIns, offInfo + 2, cHeads); /* 1Dh - (AMI) First Hard Disk user defined: Number of Heads */
225 pcbiosCmosWrite(pDevIns, offInfo + 3, 0xff); /* 1Eh - (AMI) First Hard Disk user defined: Write Precompensation Cylinder, Low Byte */
226 pcbiosCmosWrite(pDevIns, offInfo + 4, 0xff); /* 1Fh - (AMI) First Hard Disk user defined: Write Precompensation Cylinder, High Byte */
227 pcbiosCmosWrite(pDevIns, offInfo + 5, 0xc0 | ((cHeads > 8) << 3)); /* 20h - (AMI) First Hard Disk user defined: Control Byte */
228 pcbiosCmosWrite(pDevIns, offInfo + 6, 0xff); /* 21h - (AMI) First Hard Disk user defined: Landing Zone, Low Byte */
229 pcbiosCmosWrite(pDevIns, offInfo + 7, 0xff); /* 22h - (AMI) First Hard Disk user defined: Landing Zone, High Byte */
230 pcbiosCmosWrite(pDevIns, offInfo + 8, cSectors); /* 23h - (AMI) First Hard Disk user defined: # of Sectors per track */
231 return;
232 }
233 }
234 pcbiosCmosWrite(pDevIns, offType, 0);
235}
236
237
238/**
239 * Get BIOS boot code from enmBootDevice in order
240 *
241 * @todo r=bird: This is a rather silly function since the conversion is 1:1.
242 */
243static uint8_t getBiosBootCode(PDEVPCBIOS pData, unsigned iOrder)
244{
245 switch (pData->aenmBootDevice[iOrder])
246 {
247 case DEVPCBIOSBOOT_NONE:
248 return 0;
249 case DEVPCBIOSBOOT_FLOPPY:
250 return 1;
251 case DEVPCBIOSBOOT_HD:
252 return 2;
253 case DEVPCBIOSBOOT_DVD:
254 return 3;
255 case DEVPCBIOSBOOT_LAN:
256 return 4;
257 default:
258 AssertMsgFailed(("aenmBootDevice[%d]=%d\n", iOrder, pData->aenmBootDevice[iOrder]));
259 return 0;
260 }
261}
262
263
264/**
265 * Init complete notification.
266 * This routine will write information needed by the bios to the CMOS.
267 *
268 * @returns VBOX status code.
269 * @param pDevIns The device instance.
270 * @see http://www.brl.ntt.co.jp/people/takehiko/interrupt/CMOS.LST.txt for
271 * a description of standard and non-standard CMOS registers.
272 */
273static DECLCALLBACK(int) pcbiosInitComplete(PPDMDEVINS pDevIns)
274{
275 PDEVPCBIOS pData = PDMINS2DATA(pDevIns, PDEVPCBIOS);
276 uint32_t u32;
277 unsigned i;
278 PVM pVM = PDMDevHlpGetVM(pDevIns);
279 PPDMIBLOCKBIOS apHDs[4] = {0};
280 PPDMIBLOCKBIOS apFDs[2] = {0};
281 AssertRelease(pVM);
282 LogFlow(("pcbiosInitComplete:\n"));
283
284 /*
285 * Memory sizes.
286 */
287 /* base memory. */
288 u32 = pData->cbRam > 640 ? 640 : (uint32_t)pData->cbRam / _1K;
289 pcbiosCmosWrite(pDevIns, 0x15, u32 & 0xff); /* 15h - Base Memory in K, Low Byte */
290 pcbiosCmosWrite(pDevIns, 0x16, u32 >> 8); /* 16h - Base Memory in K, High Byte */
291
292 /* Extended memory, up to 65MB */
293 u32 = pData->cbRam >= 65 * _1M ? 0xffff : ((uint32_t)pData->cbRam - _1M) / _1K;
294 pcbiosCmosWrite(pDevIns, 0x17, u32 & 0xff); /* 17h - Extended Memory in K, Low Byte */
295 pcbiosCmosWrite(pDevIns, 0x18, u32 >> 8); /* 18h - Extended Memory in K, High Byte */
296 pcbiosCmosWrite(pDevIns, 0x30, u32 & 0xff); /* 30h - Extended Memory in K, Low Byte */
297 pcbiosCmosWrite(pDevIns, 0x31, u32 >> 8); /* 31h - Extended Memory in K, High Byte */
298
299 /* Bochs BIOS specific? Anyway, it's the amount of memory above 16MB */
300 if (pData->cbRam > 16 * _1M)
301 {
302 u32 = (uint32_t)( (pData->cbRam - 16 * _1M) / _64K );
303 u32 = RT_MIN(u32, 0xffff);
304 }
305 else
306 u32 = 0;
307 pcbiosCmosWrite(pDevIns, 0x34, u32 & 0xff);
308 pcbiosCmosWrite(pDevIns, 0x35, u32 >> 8);
309
310 /*
311 * Bochs BIOS specifics - boot device.
312 * We do both new and old (ami-style) settings.
313 * See rombios.c line ~7215 (int19_function).
314 */
315
316 uint8_t reg3d = getBiosBootCode(pData, 0) | (getBiosBootCode(pData, 1) << 4);
317 uint8_t reg38 = /* pcbiosCmosRead(pDevIns, 0x38) | */ getBiosBootCode(pData, 2) << 4;
318 /* This is an extension. Bochs BIOS normally supports only 3 boot devices. */
319 uint8_t reg3c = getBiosBootCode(pData, 3) | (pData->uBootDelay << 4);
320 pcbiosCmosWrite(pDevIns, 0x3d, reg3d);
321 pcbiosCmosWrite(pDevIns, 0x38, reg38);
322 pcbiosCmosWrite(pDevIns, 0x3c, reg3c);
323
324 /*
325 * Floppy drive type.
326 */
327 for (i = 0; i < ELEMENTS(apFDs); i++)
328 {
329 PPDMIBASE pBase;
330 int rc = PDMR3QueryLun(pVM, pData->pszFDDevice, 0, i, &pBase);
331 if (VBOX_SUCCESS(rc))
332 apFDs[i] = (PPDMIBLOCKBIOS)pBase->pfnQueryInterface(pBase, PDMINTERFACE_BLOCK_BIOS);
333 }
334 u32 = 0;
335 if (apFDs[0])
336 switch (apFDs[0]->pfnGetType(apFDs[0]))
337 {
338 case PDMBLOCKTYPE_FLOPPY_360: u32 |= 1 << 4; break;
339 case PDMBLOCKTYPE_FLOPPY_1_20: u32 |= 2 << 4; break;
340 case PDMBLOCKTYPE_FLOPPY_720: u32 |= 3 << 4; break;
341 case PDMBLOCKTYPE_FLOPPY_1_44: u32 |= 4 << 4; break;
342 case PDMBLOCKTYPE_FLOPPY_2_88: u32 |= 5 << 4; break;
343 default: AssertFailed(); break;
344 }
345 if (apFDs[1])
346 switch (apFDs[1]->pfnGetType(apFDs[1]))
347 {
348 case PDMBLOCKTYPE_FLOPPY_360: u32 |= 1; break;
349 case PDMBLOCKTYPE_FLOPPY_1_20: u32 |= 2; break;
350 case PDMBLOCKTYPE_FLOPPY_720: u32 |= 3; break;
351 case PDMBLOCKTYPE_FLOPPY_1_44: u32 |= 4; break;
352 case PDMBLOCKTYPE_FLOPPY_2_88: u32 |= 5; break;
353 default: AssertFailed(); break;
354 }
355 pcbiosCmosWrite(pDevIns, 0x10, u32); /* 10h - Floppy Drive Type */
356
357 /*
358 * Equipment byte.
359 */
360 u32 = !!apFDs[0] + !!apFDs[1];
361 switch (u32)
362 {
363 case 1: u32 = 0x01; break; /* floppy installed, 1 drive. */
364 case 2: u32 = 0x41; break; /* floppy installed, 2 drives. */
365 default:u32 = 0; break; /* floppy not installed. */
366 }
367 u32 |= BIT(1); /* math coprocessor installed */
368 u32 |= BIT(2); /* keyboard enabled (or mouse?) */
369 u32 |= BIT(3); /* display enabled (monitory type is 0, i.e. vga) */
370 pcbiosCmosWrite(pDevIns, 0x14, u32); /* 14h - Equipment Byte */
371
372 /*
373 * Harddisks.
374 */
375 for (i = 0; i < ELEMENTS(apHDs); i++)
376 {
377 PPDMIBASE pBase;
378 int rc = PDMR3QueryLun(pVM, pData->pszHDDevice, 0, i, &pBase);
379 if (VBOX_SUCCESS(rc))
380 apHDs[i] = (PPDMIBLOCKBIOS)pBase->pfnQueryInterface(pBase, PDMINTERFACE_BLOCK_BIOS);
381 }
382
383 u32 = (apHDs[0] ? 0xf0 : 0) | (apHDs[1] ? 0x0f : 0); /* 0Fh means extended and points to 1Ah, 1Bh */
384 pcbiosCmosWrite(pDevIns, 0x12, u32); /* 12h - Hard Disk Data (type) */
385 if (apHDs[0])
386 pcbiosCmosInitHardDisk(pDevIns, 0x19, 0x1b, apHDs[0]); /* 19h - First Extended Hard Disk Drive Type */
387 if (apHDs[1])
388 pcbiosCmosInitHardDisk(pDevIns, 0x1a, 0x24, apHDs[1]); /* 1Ah - Second Extended Hard Disk Drive Type */
389
390 /*
391 * Translation type - Bochs BIOS specific.
392 */
393 u32 = 0;
394 for (i = 0; i < 4; i++)
395 {
396 if (apHDs[i])
397 {
398 PDMBIOSTRANSLATION enmTranslation;
399 int rc = apHDs[i]->pfnGetTranslation(apHDs[i], &enmTranslation);
400 if (VBOX_FAILURE(rc) || enmTranslation == PDMBIOSTRANSLATION_AUTO)
401 {
402 uint32_t cCylinders, cHeads, cSectors;
403 rc = apHDs[i]->pfnGetGeometry(apHDs[i], &cCylinders, &cHeads, &cSectors);
404 if (VBOX_FAILURE(rc))
405 {
406 AssertMsg(rc == VERR_PDM_MEDIA_NOT_MOUNTED, ("This shouldn't happen! rc=%Vrc\n", rc));
407 enmTranslation = PDMBIOSTRANSLATION_NONE;
408 }
409 else if (cCylinders <= 1024 && cHeads <= 16 && cSectors <= 63)
410 {
411 /* Disk <= 512 MByte not needing LBA translation. */
412 enmTranslation = PDMBIOSTRANSLATION_NONE;
413 }
414 else if (cSectors != 63 || (cHeads != 16 && cHeads != 32 && cHeads != 64 && cHeads != 128 && cHeads != 255))
415 {
416 /* Disk with strange geometry. Using LBA here can
417 * break booting of the guest OS. Especially operating
418 * systems from Microsoft are sensitive to BIOS CHS not
419 * matching what the partition table says. */
420 enmTranslation = PDMBIOSTRANSLATION_NONE;
421 }
422 else
423 enmTranslation = PDMBIOSTRANSLATION_LBA;
424 }
425 switch (enmTranslation)
426 {
427 case PDMBIOSTRANSLATION_AUTO: /* makes gcc happy */
428 case PDMBIOSTRANSLATION_NONE:
429 /* u32 |= 0 << (i * 2) */
430 break;
431 default:
432 AssertMsgFailed(("bad enmTranslation=%d\n", enmTranslation));
433 case PDMBIOSTRANSLATION_LBA:
434 u32 |= 1 << (i * 2);
435 break;
436 }
437 }
438 }
439 Log2(("pcbiosInitComplete: translation byte: %#02x\n", u32));
440 pcbiosCmosWrite(pDevIns, 0x39, u32);
441
442 LogFlow(("pcbiosInitComplete: returns VINF_SUCCESS\n"));
443 return VINF_SUCCESS;
444}
445
446
447/**
448 * Port I/O Handler for IN operations.
449 *
450 * @returns VBox status code.
451 *
452 * @param pDevIns The device instance.
453 * @param pvUser User argument - ignored.
454 * @param Port Port number used for the IN operation.
455 * @param pu32 Where to store the result.
456 * @param cb Number of bytes read.
457 */
458static DECLCALLBACK(int) pcbiosIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
459{
460 NOREF(pDevIns);
461 NOREF(pvUser);
462 NOREF(Port);
463 NOREF(pu32);
464 NOREF(cb);
465 return VERR_IOM_IOPORT_UNUSED;
466}
467
468
469/**
470 * Port I/O Handler for OUT operations.
471 *
472 * @returns VBox status code.
473 *
474 * @param pDevIns The device instance.
475 * @param pvUser User argument - ignored.
476 * @param Port Port number used for the IN operation.
477 * @param u32 The value to output.
478 * @param cb The value size in bytes.
479 */
480static DECLCALLBACK(int) pcbiosIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
481{
482 /*
483 * Bochs BIOS Panic
484 */
485 if ( cb == 2
486 && ( Port == 0x400
487 || Port == 0x401))
488 {
489 Log(("pcbios: PC BIOS panic at rombios.c(%d)\n", u32));
490 AssertReleaseMsgFailed(("PC BIOS panic at rombios.c(%d)\n", u32));
491 return VERR_INTERNAL_ERROR;
492 }
493
494 /*
495 * Bochs BIOS char printing.
496 */
497 if ( cb == 1
498 && ( Port == 0x402
499 || Port == 0x403))
500 {
501 PDEVPCBIOS pData = PDMINS2DATA(pDevIns, PDEVPCBIOS);
502 /* The raw version. */
503 switch (u32)
504 {
505 case '\r': Log2(("pcbios: <return>\n")); break;
506 case '\n': Log2(("pcbios: <newline>\n")); break;
507 case '\t': Log2(("pcbios: <tab>\n")); break;
508 default: Log2(("pcbios: %c (%02x)\n", u32, u32)); break;
509 }
510
511 /* The readable, buffered version. */
512 if (u32 == '\n' || u32 == '\r')
513 {
514 pData->szMsg[pData->iMsg] = '\0';
515 if (pData->iMsg)
516 Log(("pcbios: %s\n", pData->szMsg));
517 pData->iMsg = 0;
518 }
519 else
520 {
521 if (pData->iMsg >= sizeof(pData->szMsg))
522 {
523 pData->szMsg[pData->iMsg] = '\0';
524 Log(("pcbios: %s\n", pData->szMsg));
525 pData->iMsg = 0;
526 }
527 pData->szMsg[pData->iMsg] = (char )u32;
528 pData->szMsg[++pData->iMsg] = '\0';
529 }
530 return VINF_SUCCESS;
531 }
532
533 /*
534 * Bochs BIOS shutdown request.
535 */
536 if (cb == 1 && Port == 0x8900)
537 {
538 static const unsigned char szShutdown[] = "Shutdown";
539 PDEVPCBIOS pData = PDMINS2DATA(pDevIns, PDEVPCBIOS);
540 if (u32 == szShutdown[pData->iShutdown])
541 {
542 pData->iShutdown++;
543 if (pData->iShutdown == 8)
544 {
545#if 0
546 PVM pVM = PDMDevHlpGetVM(pDevIns);
547 AssertRelease(pVM);
548 VM_FF_SET(pVM, VM_FF_TERMINATE);
549#endif
550 pData->iShutdown = 0;
551 return VINF_EM_TERMINATE;
552 }
553 }
554 else
555 pData->iShutdown = 0;
556 return VINF_SUCCESS;
557 }
558
559 /* not in use. */
560 return VINF_SUCCESS;
561}
562
563
564/**
565 * Legacy LOGO memory (0xd0000 - 0xdffff) read hook, to be called from IOM.
566 *
567 * @returns VBox status code.
568 * @param pDevIns Pointer device instance.
569 * @param pvUser User argument - ignored.
570 * @param GCPhysAddr Physical address of memory to read.
571 * @param pv Where to store readed data.
572 * @param cb Bytes to read.
573 */
574static DECLCALLBACK(int) logoMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
575{
576 PDEVPCBIOS pData = PDMINS2DATA(pDevIns, PDEVPCBIOS);
577 Log(("logoMMIORead call GCPhysAddr:%x pv:%x cb:%d (%d)\n", GCPhysAddr, pv, cb, pData->u8LogoBank));
578
579 uint32_t offLogo = GCPhysAddr & LOGO_BANK_OFFSET;
580 if (pData->u8LogoBank != LOGO_BANK_DEFAULT_LOGO)
581 {
582 /*
583 * Banked logo.
584 */
585 offLogo += pData->u8LogoBank * LOGO_BANK_SIZE;
586 if ( offLogo > pData->cbLogo
587 || offLogo + cb > pData->cbLogo)
588 {
589 Log(("logoMMIORead: Requested address is out of Logo data!!! offLogo=%#x(%d) cbLogo=%#x(%d)\n",
590 offLogo, offLogo, pData->cbLogo, pData->cbLogo));
591 return VINF_SUCCESS;
592 }
593
594 memcpy(pv, &pData->pu8Logo[offLogo], cb);
595 Log(("logoMMIORead: offLogo=%#x(%d) cb=%#x %.*Vhxs\n", offLogo, offLogo, cb, cb, &pData->pu8Logo[offLogo]));
596 }
597 else
598 {
599 /*
600 * Default bios logo.
601 */
602 if (offLogo > g_cbPcDefBiosLogo || offLogo + cb > g_cbPcDefBiosLogo)
603 {
604 Log(("logoMMIORead: Requested address is out of Logo data!!! offLogo=%#x(%d) max:%#x(%d)\n",
605 offLogo, offLogo, g_cbPcDefBiosLogo, g_cbPcDefBiosLogo));
606 return VINF_SUCCESS;
607 }
608
609 memcpy(pv, &g_abPcDefBiosLogo[offLogo], cb);
610 Log(("logoMMIORead: offLogo=%#x(%d) cb=%#x %.*Vhxs\n", offLogo, offLogo, cb, cb, &g_abPcDefBiosLogo[offLogo]));
611 }
612
613 return VINF_SUCCESS;
614}
615
616
617/**
618 * Legacy LOGO memory (0xd0000 - 0xdffff) write hook, to be called from IOM.
619 *
620 * @returns VBox status code.
621 * @param pDevIns Pointer device instance.
622 * @param pvUser User argument - ignored.
623 * @param GCPhysAddr Physical address of memory to write.
624 * @param pv Pointer to data.
625 * @param cb Bytes to write.
626 */
627static DECLCALLBACK(int) logoMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
628{
629 PDEVPCBIOS pData = PDMINS2DATA(pDevIns, PDEVPCBIOS);
630 Log(("logoMMIOWrite: GCPhysAddr=%x cb=%d pv[0]=%#04x (byte)\n", GCPhysAddr, pv, cb, *(uint8_t *)pv));
631
632 /*
633 * Byte write to off 0: Switch the logo bank.
634 */
635 if ((GCPhysAddr & LOGO_BANK_OFFSET) == 0 && cb == 1)
636 {
637 uint8_t u8Bank = *(uint8_t *)pv;
638 uint32_t off = u8Bank * LOGO_BANK_SIZE;
639
640 if ( u8Bank != LOGO_BANK_DEFAULT_LOGO
641 && off > pData->cbLogo)
642 {
643 Log(("logoMMIOWrite: The requested bank is outside the logo image! (cbLogo=%d off=%d)\n", pData->cbLogo, off));
644 return VINF_SUCCESS;
645 }
646
647 pData->u8LogoBank = u8Bank;
648 }
649
650 return VINF_SUCCESS;
651}
652
653
654/**
655 * Reset notification.
656 *
657 * @returns VBox status.
658 * @param pDevIns The device instance data.
659 */
660static DECLCALLBACK(void) pcbiosReset(PPDMDEVINS pDevIns)
661{
662 PDEVPCBIOS pData = PDMINS2DATA(pDevIns, PDEVPCBIOS);
663 LogFlow(("pcbiosReset:\n"));
664
665 pData->u8LogoBank = 0;
666 /** @todo Should we perhaps do pcbiosInitComplete() on reset? */
667
668#if 1
669 /*
670 * Paranoia: Check that the BIOS ROM hasn't changed.
671 */
672 PVM pVM = PDMDevHlpGetVM(pDevIns);
673 /* the low ROM mapping. */
674 unsigned cb = RT_MIN(g_cbPcBiosBinary, 128 * _1K);
675 const uint8_t *pb1 = (uint8_t *)MMPhysGCPhys2HCVirt(pVM, 0x00100000 - cb, cb);
676 AssertRelease(pb1);
677 const uint8_t *pb2 = &g_abPcBiosBinary[g_cbPcBiosBinary - cb];
678 if (memcmp(pb1, pb2, cb))
679 {
680 AssertMsg2("low ROM mismatch! cb=%#x\n", cb);
681 for (unsigned off = 0; off < cb; off++)
682 if (pb1[off] != pb2[off])
683 AssertMsg2("%05x: %02x expected %02x\n", off, pb1[off], pb2[off]);
684 AssertReleaseFailed();
685 }
686
687 /* the high ROM mapping. */
688 pb1 = (uint8_t *)MMPhysGCPhys2HCVirt(pVM, (uint32_t)-g_cbPcBiosBinary, g_cbPcBiosBinary);
689 AssertRelease(pb1);
690 pb2 = &g_abPcBiosBinary[0];
691 if (memcmp(pb1, pb2, g_cbPcBiosBinary))
692 {
693 AssertMsg2("high ROM mismatch! g_cbPcBiosBinary=%#x\n", g_cbPcBiosBinary);
694 for (unsigned off = 0; off < g_cbPcBiosBinary; off++)
695 if (pb1[off] != pb2[off])
696 AssertMsg2("%05x: %02x expected %02x\n", off, pb1[off], pb2[off]);
697 AssertReleaseFailed();
698 }
699#endif
700}
701
702
703/**
704 * Destruct a device instance.
705 *
706 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
707 * resources can be freed correctly.
708 *
709 * @param pDevIns The device instance data.
710 */
711static DECLCALLBACK(int) pcbiosDestruct(PPDMDEVINS pDevIns)
712{
713 PDEVPCBIOS pData = PDMINS2DATA(pDevIns, PDEVPCBIOS);
714 LogFlow(("pcbiosDestruct:\n"));
715
716 /*
717 * Free MM heap pointers.
718 */
719 if (pData->pu8LanBoot)
720 {
721 MMR3HeapFree(pData->pu8LanBoot);
722 pData->pu8LanBoot = NULL;
723 }
724
725 if (pData->pszLanBootFile)
726 {
727 MMR3HeapFree(pData->pszLanBootFile);
728 pData->pszLanBootFile = NULL;
729 }
730
731 if (pData->pu8Logo)
732 {
733 MMR3HeapFree(pData->pu8Logo);
734 pData->pu8Logo = NULL;
735 }
736
737 if (pData->pszLogoFile)
738 {
739 MMR3HeapFree(pData->pszLogoFile);
740 pData->pszLogoFile = NULL;
741 }
742
743 return VINF_SUCCESS;
744}
745
746
747/**
748 * Convert config value to DEVPCBIOSBOOT.
749 *
750 * @returns VBox status code.
751 * @param pCfgHandle Configuration handle.
752 * @param pszParam The name of the value to read.
753 * @param penmBoot Where to store the boot method.
754 */
755static int pcbiosBootFromCfg(PPDMDEVINS pDevIns, PCFGMNODE pCfgHandle, const char *pszParam, DEVPCBIOSBOOT *penmBoot)
756{
757 char *psz;
758 int rc = CFGMR3QueryStringAlloc(pCfgHandle, pszParam, &psz);
759 if (VBOX_FAILURE(rc))
760 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
761 N_("Configuration error: Querying \"%s\" as a string failed"),
762 pszParam);
763 if (!strcmp(psz, "DVD") || !strcmp(psz, "CDROM"))
764 *penmBoot = DEVPCBIOSBOOT_DVD;
765 else if (!strcmp(psz, "IDE"))
766 *penmBoot = DEVPCBIOSBOOT_HD;
767 else if (!strcmp(psz, "FLOPPY"))
768 *penmBoot = DEVPCBIOSBOOT_FLOPPY;
769 else if (!strcmp(psz, "LAN"))
770 *penmBoot = DEVPCBIOSBOOT_LAN;
771 else if (!strcmp(psz, "NONE"))
772 *penmBoot = DEVPCBIOSBOOT_NONE;
773 else
774 {
775 PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
776 N_("Configuration error: The \"%s\" value \"%s\" is unknown.\n"),
777 pszParam, psz);
778 rc = VERR_INTERNAL_ERROR;
779 }
780 MMR3HeapFree(psz);
781 return rc;
782}
783
784#define STRCPY(p, s) do { memcpy (p, s, sizeof(s)); p += sizeof(s); } while (0)
785static void pcbiosPlantDMITable(uint8_t *table)
786{
787 char *pszStr = (char*)table;
788 int iStrNr;
789
790 PDMIBIOSINF pBIOSInf = (PDMIBIOSINF)pszStr;
791 pszStr = (char*)(pBIOSInf+1);
792 iStrNr = 1;
793 pBIOSInf->header.u8Type = 0; /* BIOS Information */
794 pBIOSInf->header.u8Length = sizeof(*pBIOSInf);
795 pBIOSInf->header.u16Handle = 0x0000;
796 pBIOSInf->u8Vendor = iStrNr++;
797 STRCPY(pszStr, "InnoTek Systemberatung GmbH");
798 pBIOSInf->u8Version = iStrNr++;
799 STRCPY(pszStr, "VirtualBox");
800 pBIOSInf->u16Start = 0xE000;
801 pBIOSInf->u8Release = iStrNr++;
802 STRCPY(pszStr, "12/01/2006");
803 pBIOSInf->u8ROMSize = 1; /* 128K */
804 pBIOSInf->u64Characteristics = BIT(4) /* ISA is supported */
805 | BIT(7) /* PCI is supported */
806 | BIT(15) /* Boot from CD is supported */
807 | BIT(16) /* Selectable Boot is supported */
808 | BIT(27) /* Int 9h, 8042 Keyboard services supported */
809 | BIT(30) /* Int 10h, CGA/Mono Video Services supported */
810 /* any more?? */
811 ;
812 pBIOSInf->u8CharacteristicsByte1 = BIT(0) /* ACPI is supported */
813 /* any more?? */
814 ;
815 pBIOSInf->u8CharacteristicsByte2 = 0
816 /* any more?? */
817 ;
818 *pszStr++ = '\0';
819
820
821 PDMISYSTEMINF pSystemInf = (PDMISYSTEMINF)pszStr;
822 pszStr = (char*)(pSystemInf+1);
823 iStrNr = 1;
824 pSystemInf->header.u8Type = 1; /* System Information */
825 pSystemInf->header.u8Length = sizeof(*pSystemInf);
826 pSystemInf->header.u16Handle = 0x0001;
827 pSystemInf->u8Manufacturer = iStrNr++;
828 STRCPY(pszStr, "InnoTek Systemberatung GmbH");
829 pSystemInf->u8ProductName = iStrNr++;
830 STRCPY(pszStr, "VirtualBox");
831 pSystemInf->u8Version = iStrNr++;
832 STRCPY(pszStr, "1.2");
833 pSystemInf->u8SerialNumber = iStrNr++;
834 STRCPY(pszStr, "0");
835 pSystemInf->u8WakeupType = 6; /* Power Switch */
836 pSystemInf->u8SKUNumber = 0;
837 pSystemInf->u8Family = iStrNr++;
838 STRCPY(pszStr, "Virtual Machine");
839 *pszStr++ = '\0';
840
841 AssertMsg(pszStr - (char*)table == VBOX_DMI_TABLE_SIZE,
842 ("VBOX_DMI_TABLE_SIZE=%d, actual DMI table size is %d",
843 VBOX_DMI_TABLE_SIZE, pszStr - (char*)table));
844}
845
846AssertCompile(VBOX_DMI_TABLE_ENTR == 2);
847
848
849/**
850 * Construct a device instance for a VM.
851 *
852 * @returns VBox status.
853 * @param pDevIns The device instance data.
854 * If the registration structure is needed, pDevIns->pDevReg points to it.
855 * @param iInstance Instance number. Use this to figure out which registers and such to use.
856 * The device number is also found in pDevIns->iInstance, but since it's
857 * likely to be freqently used PDM passes it as parameter.
858 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
859 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
860 * iInstance it's expected to be used a bit in this function.
861 */
862static DECLCALLBACK(int) pcbiosConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
863{
864 unsigned i;
865 PDEVPCBIOS pData = PDMINS2DATA(pDevIns, PDEVPCBIOS);
866 int rc;
867 int cb;
868 // char *psz;
869
870 Assert(iInstance == 0);
871
872 /*
873 * Validate configuration.
874 */
875 if (!CFGMR3AreValuesValid(pCfgHandle,
876 "BootDevice0\0"
877 "BootDevice1\0"
878 "BootDevice2\0"
879 "BootDevice3\0"
880 "RamSize\0"
881 "HardDiskDevice\0"
882 "FloppyDevice\0"
883 "FadeIn\0"
884 "FadeOut\0"
885 "LogoTime\0"
886 "LogoFile\0"
887 "ShowBootMenu\0"
888 "DelayBoot\0"
889 "LanBootRom\0"))
890 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
891 N_("Invalid configuraton for device pcbios device"));
892
893 /*
894 * Init the data.
895 */
896 rc = CFGMR3QueryU64(pCfgHandle, "RamSize", &pData->cbRam);
897 if (VBOX_FAILURE(rc))
898 return PDMDEV_SET_ERROR(pDevIns, rc,
899 N_("Configuration error: Querying \"RamSize\" as integer failed"));
900
901 static const char * const s_apszBootDevices[] = { "BootDevice0", "BootDevice1", "BootDevice2", "BootDevice3" };
902 Assert(ELEMENTS(s_apszBootDevices) == ELEMENTS(pData->aenmBootDevice));
903 for (i = 0; i < ELEMENTS(pData->aenmBootDevice); i++)
904 {
905 rc = pcbiosBootFromCfg(pDevIns, pCfgHandle, s_apszBootDevices[i], &pData->aenmBootDevice[i]);
906 if (VBOX_FAILURE(rc))
907 return rc;
908 }
909
910 rc = CFGMR3QueryStringAlloc(pCfgHandle, "HardDiskDevice", &pData->pszHDDevice);
911 if (VBOX_FAILURE(rc))
912 return PDMDEV_SET_ERROR(pDevIns, rc,
913 N_("Configuration error: Querying \"HardDiskDevice\" as a string failed"));
914
915 rc = CFGMR3QueryStringAlloc(pCfgHandle, "FloppyDevice", &pData->pszFDDevice);
916 if (VBOX_FAILURE(rc))
917 return PDMDEV_SET_ERROR(pDevIns, rc,
918 N_("Configuration error: Querying \"FloppyDevice\" as a string failed"));
919
920 /*
921 * Register I/O Ports and PC BIOS.
922 */
923 rc = PDMDevHlpIOPortRegister(pDevIns, 0x400, 4, NULL, pcbiosIOPortWrite, pcbiosIOPortRead,
924 NULL, NULL, "Bochs PC BIOS - Panic & Debug");
925 if (VBOX_FAILURE(rc))
926 return rc;
927 rc = PDMDevHlpIOPortRegister(pDevIns, 0x8900, 1, NULL, pcbiosIOPortWrite, pcbiosIOPortRead,
928 NULL, NULL, "Bochs PC BIOS - Shutdown");
929 if (VBOX_FAILURE(rc))
930 return rc;
931
932 pcbiosPlantDMITable(pData->au8DMIPage);
933
934 rc = PDMDevHlpROMRegister(pDevIns, VBOX_DMI_TABLE_BASE, 0x1000, pData->au8DMIPage, "DMI tables");
935 if (VBOX_FAILURE(rc))
936 return rc;
937
938 /*
939 * Map the BIOS into memory.
940 * There are two mappings:
941 * 1. 0x000e0000 to 0x000fffff contains the last 128 kb of the bios.
942 * The bios code might be 64 kb in size, and will then start at 0xf0000.
943 * 2. 0xfffxxxxx to 0xffffffff contains the entire bios.
944 */
945 AssertReleaseMsg(g_cbPcBiosBinary >= _64K, ("g_cbPcBiosBinary=%#x\n", g_cbPcBiosBinary));
946 AssertReleaseMsg(RT_ALIGN_Z(g_cbPcBiosBinary, _64K) == g_cbPcBiosBinary,
947 ("g_cbPcBiosBinary=%#x\n", g_cbPcBiosBinary));
948 cb = RT_MIN(g_cbPcBiosBinary, 128 * _1K);
949 rc = PDMDevHlpROMRegister(pDevIns, 0x00100000 - cb, cb,
950 &g_abPcBiosBinary[g_cbPcBiosBinary - cb], "PC BIOS - 0xfffff");
951 if (VBOX_FAILURE(rc))
952 return rc;
953 rc = PDMDevHlpROMRegister(pDevIns, (uint32_t)-g_cbPcBiosBinary, g_cbPcBiosBinary,
954 &g_abPcBiosBinary[0], "PC BIOS - 0xffffffff");
955 if (VBOX_FAILURE(rc))
956 return rc;
957
958 /*
959 * Register the MMIO region for the BIOS Logo: 0x000d0000 to 0x000dffff (64k)
960 */
961 rc = PDMDevHlpMMIORegister(pDevIns, 0x000d0000, 0x00010000, 0,
962 logoMMIOWrite, logoMMIORead, NULL, "PC BIOS - Logo Buffer");
963 if (VBOX_FAILURE(rc))
964 return rc;
965
966 /*
967 * Construct the logo header.
968 */
969 LOGOHDR LogoHdr = { LOGOHDR_MAGIC, 0, 0, 0, 0, 0 };
970
971 rc = CFGMR3QueryU8(pCfgHandle, "FadeIn", &LogoHdr.u8FadeIn);
972 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
973 LogoHdr.u8FadeIn = 1;
974 else if (VBOX_FAILURE(rc))
975 return PDMDEV_SET_ERROR(pDevIns, rc,
976 N_("Configuration error: Querying \"FadeIn\" as integer failed"));
977
978 rc = CFGMR3QueryU8(pCfgHandle, "FadeOut", &LogoHdr.u8FadeOut);
979 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
980 LogoHdr.u8FadeOut = 1;
981 else if (VBOX_FAILURE(rc))
982 return PDMDEV_SET_ERROR(pDevIns, rc,
983 N_("Configuration error: Querying \"FadeOut\" as integer failed"));
984
985 rc = CFGMR3QueryU16(pCfgHandle, "LogoTime", &LogoHdr.u16LogoMillies);
986 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
987 LogoHdr.u16LogoMillies = 1;
988 else if (VBOX_FAILURE(rc))
989 return PDMDEV_SET_ERROR(pDevIns, rc,
990 N_("Configuration error: Querying \"LogoTime\" as integer failed"));
991
992 rc = CFGMR3QueryU8(pCfgHandle, "ShowBootMenu", &LogoHdr.u8ShowBootMenu);
993 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
994 LogoHdr.u8ShowBootMenu = 0;
995 else if (VBOX_FAILURE(rc))
996 return PDMDEV_SET_ERROR(pDevIns, rc,
997 N_("Configuration error: Querying \"ShowBootMenu\" as integer failed"));
998
999 /*
1000 * Get the Logo file name.
1001 */
1002 rc = CFGMR3QueryStringAlloc(pCfgHandle, "LogoFile", &pData->pszLogoFile);
1003 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1004 pData->pszLogoFile = NULL;
1005 else if (VBOX_FAILURE(rc))
1006 return PDMDEV_SET_ERROR(pDevIns, rc,
1007 N_("Configuration error: Querying \"LogoFile\" as a string failed"));
1008 else if (!*pData->pszLogoFile)
1009 {
1010 MMR3HeapFree(pData->pszLogoFile);
1011 pData->pszLogoFile = NULL;
1012 }
1013
1014 /*
1015 * Determine the logo size, open any specified logo file in the process.
1016 */
1017 LogoHdr.cbLogo = g_cbPcDefBiosLogo;
1018 RTFILE FileLogo = NIL_RTFILE;
1019 if (pData->pszLogoFile)
1020 {
1021 rc = RTFileOpen(&FileLogo, pData->pszLogoFile,
1022 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
1023 if (VBOX_SUCCESS(rc))
1024 {
1025 uint64_t cbFile;
1026 rc = RTFileGetSize(FileLogo, &cbFile);
1027 if (VBOX_SUCCESS(rc))
1028 {
1029 if ( cbFile > 0
1030 && cbFile < ((LOGO_BANK_LAST + 1) * LOGO_BANK_SIZE) - sizeof(LogoHdr))
1031 LogoHdr.cbLogo = (uint32_t)cbFile;
1032 else
1033 rc = VERR_TOO_MUCH_DATA;
1034 }
1035 }
1036 if (VBOX_FAILURE(rc))
1037 {
1038 /*
1039 * Ignore failure and fall back to the default logo.
1040 */
1041 LogRel(("pcbiosConstruct: Failed to open logo file '%s', rc=%Vrc!\n", pData->pszLogoFile, rc));
1042 RTFileClose(FileLogo);
1043 FileLogo = NIL_RTFILE;
1044 MMR3HeapFree(pData->pszLogoFile);
1045 pData->pszLogoFile = NULL;
1046 }
1047 }
1048
1049 /*
1050 * Allocate buffer for the logo data.
1051 * RT_MAX() is applied to let us fall back to default logo on read failure.
1052 */
1053 pData->cbLogo = sizeof(LogoHdr) + LogoHdr.cbLogo;
1054 pData->pu8Logo = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, RT_MAX(pData->cbLogo, g_cbPcDefBiosLogo + sizeof(LogoHdr)));
1055 if (pData->pu8Logo)
1056 {
1057 /*
1058 * Write the logo header.
1059 */
1060 PLOGOHDR pLogoHdr = (PLOGOHDR)pData->pu8Logo;
1061 *pLogoHdr = LogoHdr;
1062
1063 /*
1064 * Write the logo bitmap.
1065 */
1066 if (pData->pszLogoFile)
1067 {
1068 rc = RTFileRead(FileLogo, pLogoHdr + 1, LogoHdr.cbLogo, NULL);
1069 if (VBOX_FAILURE(rc))
1070 {
1071 AssertMsgFailed(("RTFileRead(,,%d,NULL) -> %Vrc\n", LogoHdr.cbLogo, rc));
1072 pLogoHdr->cbLogo = LogoHdr.cbLogo = g_cbPcDefBiosLogo;
1073 memcpy(pLogoHdr + 1, g_abPcDefBiosLogo, LogoHdr.cbLogo);
1074 }
1075 }
1076 else
1077 memcpy(pLogoHdr + 1, g_abPcDefBiosLogo, LogoHdr.cbLogo);
1078
1079 /*
1080 * Call reset to set values and stuff.
1081 */
1082 pcbiosReset(pDevIns);
1083 rc = VINF_SUCCESS;
1084 }
1085 else
1086 rc = VERR_NO_MEMORY;
1087
1088 /* cleanup */
1089 if (FileLogo != NIL_RTFILE)
1090 RTFileClose(FileLogo);
1091
1092 /*
1093 * Get the LAN boot ROM file name.
1094 */
1095 rc = CFGMR3QueryStringAlloc(pCfgHandle, "LanBootRom", &pData->pszLanBootFile);
1096 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1097 {
1098 pData->pszLanBootFile = NULL;
1099 rc = VINF_SUCCESS;
1100 }
1101 else if (VBOX_FAILURE(rc))
1102 return PDMDEV_SET_ERROR(pDevIns, rc,
1103 N_("Configuration error: Querying \"LanBootRom\" as a string failed"));
1104 else if (!*pData->pszLanBootFile)
1105 {
1106 MMR3HeapFree(pData->pszLanBootFile);
1107 pData->pszLanBootFile = NULL;
1108 }
1109
1110 const uint8_t *pu8LanBoot = NULL;
1111 uint64_t cbFileLanBoot;
1112#ifdef VBOX_DO_NOT_LINK_LANBOOT
1113 /*
1114 * Determine the LAN boot ROM size, open specified ROM file in the process.
1115 */
1116 RTFILE FileLanBoot = NIL_RTFILE;
1117 if (pData->pszLanBootFile)
1118 {
1119 rc = RTFileOpen(&FileLanBoot, pData->pszLanBootFile,
1120 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
1121 if (VBOX_SUCCESS(rc))
1122 {
1123 rc = RTFileGetSize(FileLanBoot, &cbFileLanBoot);
1124 if (VBOX_SUCCESS(rc))
1125 {
1126 if ( RT_ALIGN(cbFileLanBoot, _4K) != cbFileLanBoot
1127 || cbFileLanBoot > _32K)
1128 rc = VERR_TOO_MUCH_DATA;
1129 }
1130 }
1131 if (VBOX_FAILURE(rc))
1132 {
1133 /*
1134 * Ignore failure and fall back to no LAN boot ROM.
1135 */
1136 Log(("pcbiosConstruct: Failed to open LAN boot ROM file '%s', rc=%Vrc!\n", pData->pszLanBootFile, rc));
1137 RTFileClose(FileLanBoot);
1138 FileLanBoot = NIL_RTFILE;
1139 MMR3HeapFree(pData->pszLanBootFile);
1140 pData->pszLanBootFile = NULL;
1141 }
1142 }
1143
1144 /*
1145 * Get the LAN boot ROM data.
1146 */
1147 if (pData->pszLanBootFile)
1148 {
1149 /*
1150 * Allocate buffer for the LAN boot ROM data.
1151 */
1152 pu8LanBoot = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, cbFileLanBoot);
1153 pData->pu8LanBoot = pu8LanBoot;
1154 if (pu8LanBoot)
1155 {
1156 rc = RTFileRead(FileLanBoot, pData->pu8LanBoot, cbFileLanBoot, NULL);
1157 if (VBOX_FAILURE(rc))
1158 {
1159 AssertMsgFailed(("RTFileRead(,,%d,NULL) -> %Vrc\n", cbFileLanBoot, rc));
1160 MMR3HeapFree(pu8LanBoot);
1161 pu8LanBoot = NULL;
1162 pData->pu8LanBoot = NULL;
1163 }
1164 rc = VINF_SUCCESS;
1165 }
1166 else
1167 rc = VERR_NO_MEMORY;
1168 }
1169 else
1170 pData->pu8LanBoot = NULL;
1171
1172 /* cleanup */
1173 if (FileLanBoot != NIL_RTFILE)
1174 RTFileClose(FileLanBoot);
1175
1176#else /* !VBOX_DO_NOT_LINK_LANBOOT */
1177 pData->pu8LanBoot = NULL;
1178 pu8LanBoot = g_abNetBiosBinary;
1179 cbFileLanBoot = g_cbNetBiosBinary;
1180#endif /* !VBOX_DO_NOT_LINK_LANBOOT */
1181
1182 /*
1183 * Map the Network Boot ROM into memory.
1184 * Currently there is a fixed mapping: 0x000c8000 to 0x000cffff contains
1185 * the (up to) 32 kb ROM image.
1186 */
1187 if (pu8LanBoot)
1188 rc = PDMDevHlpROMRegister(pDevIns, VBOX_LANBOOT_SEG << 4, cbFileLanBoot, pu8LanBoot, "Net Boot ROM");
1189
1190 rc = CFGMR3QueryU8(pCfgHandle, "DelayBoot", &pData->uBootDelay);
1191 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1192 {
1193 pData->uBootDelay = 0;
1194 rc = VINF_SUCCESS;
1195 }
1196 else
1197 {
1198 if (VBOX_FAILURE(rc))
1199 return PDMDEV_SET_ERROR(pDevIns, rc,
1200 N_("Configuration error: Querying \"DelayBoot\" as integer failed"));
1201 if (pData->uBootDelay > 15)
1202 pData->uBootDelay = 15;
1203 }
1204
1205 return rc;
1206}
1207
1208
1209/**
1210 * The device registration structure.
1211 */
1212const PDMDEVREG g_DevicePcBios =
1213{
1214 /* u32Version */
1215 PDM_DEVREG_VERSION,
1216 /* szDeviceName */
1217 "pcbios",
1218 /* szGCMod */
1219 "",
1220 /* szR0Mod */
1221 "",
1222 /* pszDescription */
1223 "Bochs PC BIOS",
1224 /* fFlags */
1225 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64,
1226 /* fClass */
1227 PDM_DEVREG_CLASS_ARCH_BIOS,
1228 /* cMaxInstances */
1229 1,
1230 /* cbInstance */
1231 sizeof(DEVPCBIOS),
1232 /* pfnConstruct */
1233 pcbiosConstruct,
1234 /* pfnDestruct */
1235 pcbiosDestruct,
1236 /* pfnRelocate */
1237 NULL,
1238 /* pfnIOCtl */
1239 NULL,
1240 /* pfnPowerOn */
1241 NULL,
1242 /* pfnReset */
1243 pcbiosReset,
1244 /* pfnSuspend */
1245 NULL,
1246 /* pfnResume */
1247 NULL,
1248 /* pfnAttach */
1249 NULL,
1250 /* pfnDetach */
1251 NULL,
1252 /* pfnQueryInterface. */
1253 NULL,
1254 /* pfnInitComplete. */
1255 pcbiosInitComplete
1256};
1257
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