VirtualBox

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

Last change on this file since 1031 was 1014, checked in by vboxsync, 18 years ago

Fixed physical CHS detection. Hopefully without breaking existing VDIs.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 42.6 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, cCylinders & 0xff); /* 1Bh - (AMI) First Hard Disk (type 47) user defined: # of Cylinders, LSB */
223 pcbiosCmosWrite(pDevIns, offInfo + 1, cCylinders >> 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, cCylinders & 0xff); /* 21h - (AMI) First Hard Disk user defined: Landing Zone, Low Byte */
229 pcbiosCmosWrite(pDevIns, offInfo + 7, cCylinders >> 8); /* 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 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
890 N_("Invalid configuraton for device pcbios device"));
891
892 /*
893 * Init the data.
894 */
895 rc = CFGMR3QueryU64(pCfgHandle, "RamSize", &pData->cbRam);
896 if (VBOX_FAILURE(rc))
897 return PDMDEV_SET_ERROR(pDevIns, rc,
898 N_("Configuration error: Querying \"RamSize\" as integer failed"));
899
900 static const char * const s_apszBootDevices[] = { "BootDevice0", "BootDevice1", "BootDevice2", "BootDevice3" };
901 Assert(ELEMENTS(s_apszBootDevices) == ELEMENTS(pData->aenmBootDevice));
902 for (i = 0; i < ELEMENTS(pData->aenmBootDevice); i++)
903 {
904 rc = pcbiosBootFromCfg(pDevIns, pCfgHandle, s_apszBootDevices[i], &pData->aenmBootDevice[i]);
905 if (VBOX_FAILURE(rc))
906 return rc;
907 }
908
909 rc = CFGMR3QueryStringAlloc(pCfgHandle, "HardDiskDevice", &pData->pszHDDevice);
910 if (VBOX_FAILURE(rc))
911 return PDMDEV_SET_ERROR(pDevIns, rc,
912 N_("Configuration error: Querying \"HardDiskDevice\" as a string failed"));
913
914 rc = CFGMR3QueryStringAlloc(pCfgHandle, "FloppyDevice", &pData->pszFDDevice);
915 if (VBOX_FAILURE(rc))
916 return PDMDEV_SET_ERROR(pDevIns, rc,
917 N_("Configuration error: Querying \"FloppyDevice\" as a string failed"));
918
919 /*
920 * Register I/O Ports and PC BIOS.
921 */
922 rc = PDMDevHlpIOPortRegister(pDevIns, 0x400, 4, NULL, pcbiosIOPortWrite, pcbiosIOPortRead,
923 NULL, NULL, "Bochs PC BIOS - Panic & Debug");
924 if (VBOX_FAILURE(rc))
925 return rc;
926 rc = PDMDevHlpIOPortRegister(pDevIns, 0x8900, 1, NULL, pcbiosIOPortWrite, pcbiosIOPortRead,
927 NULL, NULL, "Bochs PC BIOS - Shutdown");
928 if (VBOX_FAILURE(rc))
929 return rc;
930
931 pcbiosPlantDMITable(pData->au8DMIPage);
932
933 rc = PDMDevHlpROMRegister(pDevIns, VBOX_DMI_TABLE_BASE, 0x1000, pData->au8DMIPage, "DMI tables");
934 if (VBOX_FAILURE(rc))
935 return rc;
936
937 /*
938 * Map the BIOS into memory.
939 * There are two mappings:
940 * 1. 0x000e0000 to 0x000fffff contains the last 128 kb of the bios.
941 * The bios code might be 64 kb in size, and will then start at 0xf0000.
942 * 2. 0xfffxxxxx to 0xffffffff contains the entire bios.
943 */
944 AssertReleaseMsg(g_cbPcBiosBinary >= _64K, ("g_cbPcBiosBinary=%#x\n", g_cbPcBiosBinary));
945 AssertReleaseMsg(RT_ALIGN_Z(g_cbPcBiosBinary, _64K) == g_cbPcBiosBinary,
946 ("g_cbPcBiosBinary=%#x\n", g_cbPcBiosBinary));
947 cb = RT_MIN(g_cbPcBiosBinary, 128 * _1K);
948 rc = PDMDevHlpROMRegister(pDevIns, 0x00100000 - cb, cb,
949 &g_abPcBiosBinary[g_cbPcBiosBinary - cb], "PC BIOS - 0xfffff");
950 if (VBOX_FAILURE(rc))
951 return rc;
952 rc = PDMDevHlpROMRegister(pDevIns, (uint32_t)-g_cbPcBiosBinary, g_cbPcBiosBinary,
953 &g_abPcBiosBinary[0], "PC BIOS - 0xffffffff");
954 if (VBOX_FAILURE(rc))
955 return rc;
956
957 /*
958 * Register the MMIO region for the BIOS Logo: 0x000d0000 to 0x000dffff (64k)
959 */
960 rc = PDMDevHlpMMIORegister(pDevIns, 0x000d0000, 0x00010000, 0,
961 logoMMIOWrite, logoMMIORead, NULL, "PC BIOS - Logo Buffer");
962 if (VBOX_FAILURE(rc))
963 return rc;
964
965 /*
966 * Construct the logo header.
967 */
968 LOGOHDR LogoHdr = { LOGOHDR_MAGIC, 0, 0, 0, 0, 0 };
969
970 rc = CFGMR3QueryU8(pCfgHandle, "FadeIn", &LogoHdr.u8FadeIn);
971 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
972 LogoHdr.u8FadeIn = 1;
973 else if (VBOX_FAILURE(rc))
974 return PDMDEV_SET_ERROR(pDevIns, rc,
975 N_("Configuration error: Querying \"FadeIn\" as integer failed"));
976
977 rc = CFGMR3QueryU8(pCfgHandle, "FadeOut", &LogoHdr.u8FadeOut);
978 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
979 LogoHdr.u8FadeOut = 1;
980 else if (VBOX_FAILURE(rc))
981 return PDMDEV_SET_ERROR(pDevIns, rc,
982 N_("Configuration error: Querying \"FadeOut\" as integer failed"));
983
984 rc = CFGMR3QueryU16(pCfgHandle, "LogoTime", &LogoHdr.u16LogoMillies);
985 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
986 LogoHdr.u16LogoMillies = 1;
987 else if (VBOX_FAILURE(rc))
988 return PDMDEV_SET_ERROR(pDevIns, rc,
989 N_("Configuration error: Querying \"LogoTime\" as integer failed"));
990
991 rc = CFGMR3QueryU8(pCfgHandle, "ShowBootMenu", &LogoHdr.u8ShowBootMenu);
992 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
993 LogoHdr.u8ShowBootMenu = 0;
994 else if (VBOX_FAILURE(rc))
995 return PDMDEV_SET_ERROR(pDevIns, rc,
996 N_("Configuration error: Querying \"ShowBootMenu\" as integer failed"));
997
998 /*
999 * Get the Logo file name.
1000 */
1001 rc = CFGMR3QueryStringAlloc(pCfgHandle, "LogoFile", &pData->pszLogoFile);
1002 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1003 pData->pszLogoFile = NULL;
1004 else if (VBOX_FAILURE(rc))
1005 return PDMDEV_SET_ERROR(pDevIns, rc,
1006 N_("Configuration error: Querying \"LogoFile\" as a string failed"));
1007 else if (!*pData->pszLogoFile)
1008 {
1009 MMR3HeapFree(pData->pszLogoFile);
1010 pData->pszLogoFile = NULL;
1011 }
1012
1013 /*
1014 * Determine the logo size, open any specified logo file in the process.
1015 */
1016 LogoHdr.cbLogo = g_cbPcDefBiosLogo;
1017 RTFILE FileLogo = NIL_RTFILE;
1018 if (pData->pszLogoFile)
1019 {
1020 rc = RTFileOpen(&FileLogo, pData->pszLogoFile,
1021 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
1022 if (VBOX_SUCCESS(rc))
1023 {
1024 uint64_t cbFile;
1025 rc = RTFileGetSize(FileLogo, &cbFile);
1026 if (VBOX_SUCCESS(rc))
1027 {
1028 if ( cbFile > 0
1029 && cbFile < ((LOGO_BANK_LAST + 1) * LOGO_BANK_SIZE) - sizeof(LogoHdr))
1030 LogoHdr.cbLogo = (uint32_t)cbFile;
1031 else
1032 rc = VERR_TOO_MUCH_DATA;
1033 }
1034 }
1035 if (VBOX_FAILURE(rc))
1036 {
1037 /*
1038 * Ignore failure and fall back to the default logo.
1039 */
1040 LogRel(("pcbiosConstruct: Failed to open logo file '%s', rc=%Vrc!\n", pData->pszLogoFile, rc));
1041 RTFileClose(FileLogo);
1042 FileLogo = NIL_RTFILE;
1043 MMR3HeapFree(pData->pszLogoFile);
1044 pData->pszLogoFile = NULL;
1045 }
1046 }
1047
1048 /*
1049 * Allocate buffer for the logo data.
1050 * RT_MAX() is applied to let us fall back to default logo on read failure.
1051 */
1052 pData->cbLogo = sizeof(LogoHdr) + LogoHdr.cbLogo;
1053 pData->pu8Logo = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, RT_MAX(pData->cbLogo, g_cbPcDefBiosLogo + sizeof(LogoHdr)));
1054 if (pData->pu8Logo)
1055 {
1056 /*
1057 * Write the logo header.
1058 */
1059 PLOGOHDR pLogoHdr = (PLOGOHDR)pData->pu8Logo;
1060 *pLogoHdr = LogoHdr;
1061
1062 /*
1063 * Write the logo bitmap.
1064 */
1065 if (pData->pszLogoFile)
1066 {
1067 rc = RTFileRead(FileLogo, pLogoHdr + 1, LogoHdr.cbLogo, NULL);
1068 if (VBOX_FAILURE(rc))
1069 {
1070 AssertMsgFailed(("RTFileRead(,,%d,NULL) -> %Vrc\n", LogoHdr.cbLogo, rc));
1071 pLogoHdr->cbLogo = LogoHdr.cbLogo = g_cbPcDefBiosLogo;
1072 memcpy(pLogoHdr + 1, g_abPcDefBiosLogo, LogoHdr.cbLogo);
1073 }
1074 }
1075 else
1076 memcpy(pLogoHdr + 1, g_abPcDefBiosLogo, LogoHdr.cbLogo);
1077
1078 /*
1079 * Call reset to set values and stuff.
1080 */
1081 pcbiosReset(pDevIns);
1082 rc = VINF_SUCCESS;
1083 }
1084 else
1085 rc = VERR_NO_MEMORY;
1086
1087 /* cleanup */
1088 if (FileLogo != NIL_RTFILE)
1089 RTFileClose(FileLogo);
1090
1091 /*
1092 * Get the LAN boot ROM file name.
1093 */
1094 rc = CFGMR3QueryStringAlloc(pCfgHandle, "LanBootRom", &pData->pszLanBootFile);
1095 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1096 {
1097 pData->pszLanBootFile = NULL;
1098 rc = VINF_SUCCESS;
1099 }
1100 else if (VBOX_FAILURE(rc))
1101 return PDMDEV_SET_ERROR(pDevIns, rc,
1102 N_("Configuration error: Querying \"LanBootRom\" as a string failed"));
1103 else if (!*pData->pszLanBootFile)
1104 {
1105 MMR3HeapFree(pData->pszLanBootFile);
1106 pData->pszLanBootFile = NULL;
1107 }
1108
1109 const uint8_t *pu8LanBoot = NULL;
1110 uint64_t cbFileLanBoot;
1111#ifdef VBOX_DO_NOT_LINK_LANBOOT
1112 /*
1113 * Determine the LAN boot ROM size, open specified ROM file in the process.
1114 */
1115 RTFILE FileLanBoot = NIL_RTFILE;
1116 if (pData->pszLanBootFile)
1117 {
1118 rc = RTFileOpen(&FileLanBoot, pData->pszLanBootFile,
1119 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
1120 if (VBOX_SUCCESS(rc))
1121 {
1122 rc = RTFileGetSize(FileLanBoot, &cbFileLanBoot);
1123 if (VBOX_SUCCESS(rc))
1124 {
1125 if ( RT_ALIGN(cbFileLanBoot, _4K) != cbFileLanBoot
1126 || cbFileLanBoot > _32K)
1127 rc = VERR_TOO_MUCH_DATA;
1128 }
1129 }
1130 if (VBOX_FAILURE(rc))
1131 {
1132 /*
1133 * Ignore failure and fall back to no LAN boot ROM.
1134 */
1135 Log(("pcbiosConstruct: Failed to open LAN boot ROM file '%s', rc=%Vrc!\n", pData->pszLanBootFile, rc));
1136 RTFileClose(FileLanBoot);
1137 FileLanBoot = NIL_RTFILE;
1138 MMR3HeapFree(pData->pszLanBootFile);
1139 pData->pszLanBootFile = NULL;
1140 }
1141 }
1142
1143 /*
1144 * Get the LAN boot ROM data.
1145 */
1146 if (pData->pszLanBootFile)
1147 {
1148 /*
1149 * Allocate buffer for the LAN boot ROM data.
1150 */
1151 pu8LanBoot = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, cbFileLanBoot);
1152 pData->pu8LanBoot = pu8LanBoot;
1153 if (pu8LanBoot)
1154 {
1155 rc = RTFileRead(FileLanBoot, pData->pu8LanBoot, cbFileLanBoot, NULL);
1156 if (VBOX_FAILURE(rc))
1157 {
1158 AssertMsgFailed(("RTFileRead(,,%d,NULL) -> %Vrc\n", cbFileLanBoot, rc));
1159 MMR3HeapFree(pu8LanBoot);
1160 pu8LanBoot = NULL;
1161 pData->pu8LanBoot = NULL;
1162 }
1163 rc = VINF_SUCCESS;
1164 }
1165 else
1166 rc = VERR_NO_MEMORY;
1167 }
1168 else
1169 pData->pu8LanBoot = NULL;
1170
1171 /* cleanup */
1172 if (FileLanBoot != NIL_RTFILE)
1173 RTFileClose(FileLanBoot);
1174
1175#else /* !VBOX_DO_NOT_LINK_LANBOOT */
1176 pData->pu8LanBoot = NULL;
1177 pu8LanBoot = g_abNetBiosBinary;
1178 cbFileLanBoot = g_cbNetBiosBinary;
1179#endif /* !VBOX_DO_NOT_LINK_LANBOOT */
1180
1181 /*
1182 * Map the Network Boot ROM into memory.
1183 * Currently there is a fixed mapping: 0x000c8000 to 0x000cffff contains
1184 * the (up to) 32 kb ROM image.
1185 */
1186 if (pu8LanBoot)
1187 rc = PDMDevHlpROMRegister(pDevIns, VBOX_LANBOOT_SEG << 4, cbFileLanBoot, pu8LanBoot, "Net Boot ROM");
1188
1189 rc = CFGMR3QueryU8(pCfgHandle, "DelayBoot", &pData->uBootDelay);
1190 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1191 {
1192 pData->uBootDelay = 0;
1193 rc = VINF_SUCCESS;
1194 }
1195 else
1196 {
1197 if (VBOX_FAILURE(rc))
1198 return PDMDEV_SET_ERROR(pDevIns, rc,
1199 N_("Configuration error: Querying \"DelayBoot\" as integer failed"));
1200 if (pData->uBootDelay > 15)
1201 pData->uBootDelay = 15;
1202 }
1203
1204 return rc;
1205}
1206
1207
1208/**
1209 * The device registration structure.
1210 */
1211const PDMDEVREG g_DevicePcBios =
1212{
1213 /* u32Version */
1214 PDM_DEVREG_VERSION,
1215 /* szDeviceName */
1216 "pcbios",
1217 /* szGCMod */
1218 "",
1219 /* szR0Mod */
1220 "",
1221 /* pszDescription */
1222 "Bochs PC BIOS",
1223 /* fFlags */
1224 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64,
1225 /* fClass */
1226 PDM_DEVREG_CLASS_ARCH_BIOS,
1227 /* cMaxInstances */
1228 1,
1229 /* cbInstance */
1230 sizeof(DEVPCBIOS),
1231 /* pfnConstruct */
1232 pcbiosConstruct,
1233 /* pfnDestruct */
1234 pcbiosDestruct,
1235 /* pfnRelocate */
1236 NULL,
1237 /* pfnIOCtl */
1238 NULL,
1239 /* pfnPowerOn */
1240 NULL,
1241 /* pfnReset */
1242 pcbiosReset,
1243 /* pfnSuspend */
1244 NULL,
1245 /* pfnResume */
1246 NULL,
1247 /* pfnAttach */
1248 NULL,
1249 /* pfnDetach */
1250 NULL,
1251 /* pfnQueryInterface. */
1252 NULL,
1253 /* pfnInitComplete. */
1254 pcbiosInitComplete
1255};
1256
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