VirtualBox

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

Last change on this file since 895 was 837, checked in by vboxsync, 18 years ago

GC Phys to HC virt conversion changes for dynamic RAM allocation.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 42.0 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 enmTranslation = PDMBIOSTRANSLATION_NONE;
411 else
412 enmTranslation = PDMBIOSTRANSLATION_LBA;
413 }
414 switch (enmTranslation)
415 {
416 case PDMBIOSTRANSLATION_AUTO: /* makes gcc happy */
417 case PDMBIOSTRANSLATION_NONE:
418 /* u32 |= 0 << (i * 2) */
419 break;
420 default:
421 AssertMsgFailed(("bad enmTranslation=%d\n", enmTranslation));
422 case PDMBIOSTRANSLATION_LBA:
423 u32 |= 1 << (i * 2);
424 break;
425 }
426 }
427 }
428 Log2(("pcbiosInitComplete: translation byte: %#02x\n", u32));
429 pcbiosCmosWrite(pDevIns, 0x39, u32);
430
431 LogFlow(("pcbiosInitComplete: returns VINF_SUCCESS\n"));
432 return VINF_SUCCESS;
433}
434
435
436/**
437 * Port I/O Handler for IN operations.
438 *
439 * @returns VBox status code.
440 *
441 * @param pDevIns The device instance.
442 * @param pvUser User argument - ignored.
443 * @param Port Port number used for the IN operation.
444 * @param pu32 Where to store the result.
445 * @param cb Number of bytes read.
446 */
447static DECLCALLBACK(int) pcbiosIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
448{
449 NOREF(pDevIns);
450 NOREF(pvUser);
451 NOREF(Port);
452 NOREF(pu32);
453 NOREF(cb);
454 return VERR_IOM_IOPORT_UNUSED;
455}
456
457
458/**
459 * Port I/O Handler for OUT operations.
460 *
461 * @returns VBox status code.
462 *
463 * @param pDevIns The device instance.
464 * @param pvUser User argument - ignored.
465 * @param Port Port number used for the IN operation.
466 * @param u32 The value to output.
467 * @param cb The value size in bytes.
468 */
469static DECLCALLBACK(int) pcbiosIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
470{
471 /*
472 * Bochs BIOS Panic
473 */
474 if ( cb == 2
475 && ( Port == 0x400
476 || Port == 0x401))
477 {
478 Log(("pcbios: PC BIOS panic at rombios.c(%d)\n", u32));
479 AssertReleaseMsgFailed(("PC BIOS panic at rombios.c(%d)\n", u32));
480 return VERR_INTERNAL_ERROR;
481 }
482
483 /*
484 * Bochs BIOS char printing.
485 */
486 if ( cb == 1
487 && ( Port == 0x402
488 || Port == 0x403))
489 {
490 PDEVPCBIOS pData = PDMINS2DATA(pDevIns, PDEVPCBIOS);
491 /* The raw version. */
492 switch (u32)
493 {
494 case '\r': Log2(("pcbios: <return>\n")); break;
495 case '\n': Log2(("pcbios: <newline>\n")); break;
496 case '\t': Log2(("pcbios: <tab>\n")); break;
497 default: Log2(("pcbios: %c (%02x)\n", u32, u32)); break;
498 }
499
500 /* The readable, buffered version. */
501 if (u32 == '\n' || u32 == '\r')
502 {
503 pData->szMsg[pData->iMsg] = '\0';
504 if (pData->iMsg)
505 Log(("pcbios: %s\n", pData->szMsg));
506 pData->iMsg = 0;
507 }
508 else
509 {
510 if (pData->iMsg >= sizeof(pData->szMsg))
511 {
512 pData->szMsg[pData->iMsg] = '\0';
513 Log(("pcbios: %s\n", pData->szMsg));
514 pData->iMsg = 0;
515 }
516 pData->szMsg[pData->iMsg] = (char )u32;
517 pData->szMsg[++pData->iMsg] = '\0';
518 }
519 return VINF_SUCCESS;
520 }
521
522 /*
523 * Bochs BIOS shutdown request.
524 */
525 if (cb == 1 && Port == 0x8900)
526 {
527 static const unsigned char szShutdown[] = "Shutdown";
528 PDEVPCBIOS pData = PDMINS2DATA(pDevIns, PDEVPCBIOS);
529 if (u32 == szShutdown[pData->iShutdown])
530 {
531 pData->iShutdown++;
532 if (pData->iShutdown == 8)
533 {
534#if 0
535 PVM pVM = PDMDevHlpGetVM(pDevIns);
536 AssertRelease(pVM);
537 VM_FF_SET(pVM, VM_FF_TERMINATE);
538#endif
539 pData->iShutdown = 0;
540 return VINF_EM_TERMINATE;
541 }
542 }
543 else
544 pData->iShutdown = 0;
545 return VINF_SUCCESS;
546 }
547
548 /* not in use. */
549 return VINF_SUCCESS;
550}
551
552
553/**
554 * Legacy LOGO memory (0xd0000 - 0xdffff) read hook, to be called from IOM.
555 *
556 * @returns VBox status code.
557 * @param pDevIns Pointer device instance.
558 * @param pvUser User argument - ignored.
559 * @param GCPhysAddr Physical address of memory to read.
560 * @param pv Where to store readed data.
561 * @param cb Bytes to read.
562 */
563static DECLCALLBACK(int) logoMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
564{
565 PDEVPCBIOS pData = PDMINS2DATA(pDevIns, PDEVPCBIOS);
566 Log(("logoMMIORead call GCPhysAddr:%x pv:%x cb:%d (%d)\n", GCPhysAddr, pv, cb, pData->u8LogoBank));
567
568 uint32_t offLogo = GCPhysAddr & LOGO_BANK_OFFSET;
569 if (pData->u8LogoBank != LOGO_BANK_DEFAULT_LOGO)
570 {
571 /*
572 * Banked logo.
573 */
574 offLogo += pData->u8LogoBank * LOGO_BANK_SIZE;
575 if ( offLogo > pData->cbLogo
576 || offLogo + cb > pData->cbLogo)
577 {
578 Log(("logoMMIORead: Requested address is out of Logo data!!! offLogo=%#x(%d) cbLogo=%#x(%d)\n",
579 offLogo, offLogo, pData->cbLogo, pData->cbLogo));
580 return VINF_SUCCESS;
581 }
582
583 memcpy(pv, &pData->pu8Logo[offLogo], cb);
584 Log(("logoMMIORead: offLogo=%#x(%d) cb=%#x %.*Vhxs\n", offLogo, offLogo, cb, cb, &pData->pu8Logo[offLogo]));
585 }
586 else
587 {
588 /*
589 * Default bios logo.
590 */
591 if (offLogo > g_cbPcDefBiosLogo || offLogo + cb > g_cbPcDefBiosLogo)
592 {
593 Log(("logoMMIORead: Requested address is out of Logo data!!! offLogo=%#x(%d) max:%#x(%d)\n",
594 offLogo, offLogo, g_cbPcDefBiosLogo, g_cbPcDefBiosLogo));
595 return VINF_SUCCESS;
596 }
597
598 memcpy(pv, &g_abPcDefBiosLogo[offLogo], cb);
599 Log(("logoMMIORead: offLogo=%#x(%d) cb=%#x %.*Vhxs\n", offLogo, offLogo, cb, cb, &g_abPcDefBiosLogo[offLogo]));
600 }
601
602 return VINF_SUCCESS;
603}
604
605
606/**
607 * Legacy LOGO memory (0xd0000 - 0xdffff) write hook, to be called from IOM.
608 *
609 * @returns VBox status code.
610 * @param pDevIns Pointer device instance.
611 * @param pvUser User argument - ignored.
612 * @param GCPhysAddr Physical address of memory to write.
613 * @param pv Pointer to data.
614 * @param cb Bytes to write.
615 */
616static DECLCALLBACK(int) logoMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
617{
618 PDEVPCBIOS pData = PDMINS2DATA(pDevIns, PDEVPCBIOS);
619 Log(("logoMMIOWrite: GCPhysAddr=%x cb=%d pv[0]=%#04x (byte)\n", GCPhysAddr, pv, cb, *(uint8_t *)pv));
620
621 /*
622 * Byte write to off 0: Switch the logo bank.
623 */
624 if ((GCPhysAddr & LOGO_BANK_OFFSET) == 0 && cb == 1)
625 {
626 uint8_t u8Bank = *(uint8_t *)pv;
627 uint32_t off = u8Bank * LOGO_BANK_SIZE;
628
629 if ( u8Bank != LOGO_BANK_DEFAULT_LOGO
630 && off > pData->cbLogo)
631 {
632 Log(("logoMMIOWrite: The requested bank is outside the logo image! (cbLogo=%d off=%d)\n", pData->cbLogo, off));
633 return VINF_SUCCESS;
634 }
635
636 pData->u8LogoBank = u8Bank;
637 }
638
639 return VINF_SUCCESS;
640}
641
642
643/**
644 * Reset notification.
645 *
646 * @returns VBox status.
647 * @param pDevIns The device instance data.
648 */
649static DECLCALLBACK(void) pcbiosReset(PPDMDEVINS pDevIns)
650{
651 PDEVPCBIOS pData = PDMINS2DATA(pDevIns, PDEVPCBIOS);
652 LogFlow(("pcbiosReset:\n"));
653
654 pData->u8LogoBank = 0;
655 /** @todo Should we perhaps do pcbiosInitComplete() on reset? */
656
657#if 1
658 /*
659 * Paranoia: Check that the BIOS ROM hasn't changed.
660 */
661 PVM pVM = PDMDevHlpGetVM(pDevIns);
662 /* the low ROM mapping. */
663 unsigned cb = RT_MIN(g_cbPcBiosBinary, 128 * _1K);
664 const uint8_t *pb1 = (uint8_t *)MMPhysGCPhys2HCVirt(pVM, 0x00100000 - cb, cb);
665 AssertRelease(pb1);
666 const uint8_t *pb2 = &g_abPcBiosBinary[g_cbPcBiosBinary - cb];
667 if (memcmp(pb1, pb2, cb))
668 {
669 AssertMsg2("low ROM mismatch! cb=%#x\n", cb);
670 for (unsigned off = 0; off < cb; off++)
671 if (pb1[off] != pb2[off])
672 AssertMsg2("%05x: %02x expected %02x\n", off, pb1[off], pb2[off]);
673 AssertReleaseFailed();
674 }
675
676 /* the high ROM mapping. */
677 pb1 = (uint8_t *)MMPhysGCPhys2HCVirt(pVM, (uint32_t)-g_cbPcBiosBinary, g_cbPcBiosBinary);
678 AssertRelease(pb1);
679 pb2 = &g_abPcBiosBinary[0];
680 if (memcmp(pb1, pb2, g_cbPcBiosBinary))
681 {
682 AssertMsg2("high ROM mismatch! g_cbPcBiosBinary=%#x\n", g_cbPcBiosBinary);
683 for (unsigned off = 0; off < g_cbPcBiosBinary; off++)
684 if (pb1[off] != pb2[off])
685 AssertMsg2("%05x: %02x expected %02x\n", off, pb1[off], pb2[off]);
686 AssertReleaseFailed();
687 }
688#endif
689}
690
691
692/**
693 * Destruct a device instance.
694 *
695 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
696 * resources can be freed correctly.
697 *
698 * @param pDevIns The device instance data.
699 */
700static DECLCALLBACK(int) pcbiosDestruct(PPDMDEVINS pDevIns)
701{
702 PDEVPCBIOS pData = PDMINS2DATA(pDevIns, PDEVPCBIOS);
703 LogFlow(("pcbiosDestruct:\n"));
704
705 /*
706 * Free MM heap pointers.
707 */
708 if (pData->pu8LanBoot)
709 {
710 MMR3HeapFree(pData->pu8LanBoot);
711 pData->pu8LanBoot = NULL;
712 }
713
714 if (pData->pszLanBootFile)
715 {
716 MMR3HeapFree(pData->pszLanBootFile);
717 pData->pszLanBootFile = NULL;
718 }
719
720 if (pData->pu8Logo)
721 {
722 MMR3HeapFree(pData->pu8Logo);
723 pData->pu8Logo = NULL;
724 }
725
726 if (pData->pszLogoFile)
727 {
728 MMR3HeapFree(pData->pszLogoFile);
729 pData->pszLogoFile = NULL;
730 }
731
732 return VINF_SUCCESS;
733}
734
735
736/**
737 * Convert config value to DEVPCBIOSBOOT.
738 *
739 * @returns VBox status code.
740 * @param pCfgHandle Configuration handle.
741 * @param pszParam The name of the value to read.
742 * @param penmBoot Where to store the boot method.
743 */
744static int pcbiosBootFromCfg(PPDMDEVINS pDevIns, PCFGMNODE pCfgHandle, const char *pszParam, DEVPCBIOSBOOT *penmBoot)
745{
746 char *psz;
747 int rc = CFGMR3QueryStringAlloc(pCfgHandle, pszParam, &psz);
748 if (VBOX_FAILURE(rc))
749 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
750 N_("Configuration error: Querying \"%s\" as a string failed"),
751 pszParam);
752 if (!strcmp(psz, "DVD") || !strcmp(psz, "CDROM"))
753 *penmBoot = DEVPCBIOSBOOT_DVD;
754 else if (!strcmp(psz, "IDE"))
755 *penmBoot = DEVPCBIOSBOOT_HD;
756 else if (!strcmp(psz, "FLOPPY"))
757 *penmBoot = DEVPCBIOSBOOT_FLOPPY;
758 else if (!strcmp(psz, "LAN"))
759 *penmBoot = DEVPCBIOSBOOT_LAN;
760 else if (!strcmp(psz, "NONE"))
761 *penmBoot = DEVPCBIOSBOOT_NONE;
762 else
763 {
764 PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
765 N_("Configuration error: The \"%s\" value \"%s\" is unknown.\n"),
766 pszParam, psz);
767 rc = VERR_INTERNAL_ERROR;
768 }
769 MMR3HeapFree(psz);
770 return rc;
771}
772
773#define STRCPY(p, s) do { memcpy (p, s, sizeof(s)); p += sizeof(s); } while (0)
774static void pcbiosPlantDMITable(uint8_t *table)
775{
776 char *pszStr = (char*)table;
777 int iStrNr;
778
779 PDMIBIOSINF pBIOSInf = (PDMIBIOSINF)pszStr;
780 pszStr = (char*)(pBIOSInf+1);
781 iStrNr = 1;
782 pBIOSInf->header.u8Type = 0; /* BIOS Information */
783 pBIOSInf->header.u8Length = sizeof(*pBIOSInf);
784 pBIOSInf->header.u16Handle = 0x0000;
785 pBIOSInf->u8Vendor = iStrNr++;
786 STRCPY(pszStr, "InnoTek Systemberatung GmbH");
787 pBIOSInf->u8Version = iStrNr++;
788 STRCPY(pszStr, "VirtualBox");
789 pBIOSInf->u16Start = 0xE000;
790 pBIOSInf->u8Release = iStrNr++;
791 STRCPY(pszStr, "12/01/2006");
792 pBIOSInf->u8ROMSize = 1; /* 128K */
793 pBIOSInf->u64Characteristics = BIT(4) /* ISA is supported */
794 | BIT(7) /* PCI is supported */
795 | BIT(15) /* Boot from CD is supported */
796 | BIT(16) /* Selectable Boot is supported */
797 | BIT(27) /* Int 9h, 8042 Keyboard services supported */
798 | BIT(30) /* Int 10h, CGA/Mono Video Services supported */
799 /* any more?? */
800 ;
801 pBIOSInf->u8CharacteristicsByte1 = BIT(0) /* ACPI is supported */
802 /* any more?? */
803 ;
804 pBIOSInf->u8CharacteristicsByte2 = 0
805 /* any more?? */
806 ;
807 *pszStr++ = '\0';
808
809
810 PDMISYSTEMINF pSystemInf = (PDMISYSTEMINF)pszStr;
811 pszStr = (char*)(pSystemInf+1);
812 iStrNr = 1;
813 pSystemInf->header.u8Type = 1; /* System Information */
814 pSystemInf->header.u8Length = sizeof(*pSystemInf);
815 pSystemInf->header.u16Handle = 0x0001;
816 pSystemInf->u8Manufacturer = iStrNr++;
817 STRCPY(pszStr, "InnoTek Systemberatung GmbH");
818 pSystemInf->u8ProductName = iStrNr++;
819 STRCPY(pszStr, "VirtualBox");
820 pSystemInf->u8Version = iStrNr++;
821 STRCPY(pszStr, "1.2");
822 pSystemInf->u8SerialNumber = iStrNr++;
823 STRCPY(pszStr, "0");
824 pSystemInf->u8WakeupType = 6; /* Power Switch */
825 pSystemInf->u8SKUNumber = 0;
826 pSystemInf->u8Family = iStrNr++;
827 STRCPY(pszStr, "Virtual Machine");
828 *pszStr++ = '\0';
829
830 AssertMsg(pszStr - (char*)table == VBOX_DMI_TABLE_SIZE,
831 ("VBOX_DMI_TABLE_SIZE=%d, actual DMI table size is %d",
832 VBOX_DMI_TABLE_SIZE, pszStr - (char*)table));
833}
834
835AssertCompile(VBOX_DMI_TABLE_ENTR == 2);
836
837
838/**
839 * Construct a device instance for a VM.
840 *
841 * @returns VBox status.
842 * @param pDevIns The device instance data.
843 * If the registration structure is needed, pDevIns->pDevReg points to it.
844 * @param iInstance Instance number. Use this to figure out which registers and such to use.
845 * The device number is also found in pDevIns->iInstance, but since it's
846 * likely to be freqently used PDM passes it as parameter.
847 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
848 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
849 * iInstance it's expected to be used a bit in this function.
850 */
851static DECLCALLBACK(int) pcbiosConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
852{
853 unsigned i;
854 PDEVPCBIOS pData = PDMINS2DATA(pDevIns, PDEVPCBIOS);
855 int rc;
856 int cb;
857 // char *psz;
858
859 Assert(iInstance == 0);
860
861 /*
862 * Validate configuration.
863 */
864 if (!CFGMR3AreValuesValid(pCfgHandle,
865 "BootDevice0\0"
866 "BootDevice1\0"
867 "BootDevice2\0"
868 "BootDevice3\0"
869 "RamSize\0"
870 "HardDiskDevice\0"
871 "FloppyDevice\0"
872 "FadeIn\0"
873 "FadeOut\0"
874 "LogoTime\0"
875 "LogoFile\0"
876 "ShowBootMenu\0"
877 "DelayBoot\0"))
878 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
879 N_("Invalid configuraton for device pcbios device"));
880
881 /*
882 * Init the data.
883 */
884 rc = CFGMR3QueryU64(pCfgHandle, "RamSize", &pData->cbRam);
885 if (VBOX_FAILURE(rc))
886 return PDMDEV_SET_ERROR(pDevIns, rc,
887 N_("Configuration error: Querying \"RamSize\" as integer failed"));
888
889 static const char * const s_apszBootDevices[] = { "BootDevice0", "BootDevice1", "BootDevice2", "BootDevice3" };
890 Assert(ELEMENTS(s_apszBootDevices) == ELEMENTS(pData->aenmBootDevice));
891 for (i = 0; i < ELEMENTS(pData->aenmBootDevice); i++)
892 {
893 rc = pcbiosBootFromCfg(pDevIns, pCfgHandle, s_apszBootDevices[i], &pData->aenmBootDevice[i]);
894 if (VBOX_FAILURE(rc))
895 return rc;
896 }
897
898 rc = CFGMR3QueryStringAlloc(pCfgHandle, "HardDiskDevice", &pData->pszHDDevice);
899 if (VBOX_FAILURE(rc))
900 return PDMDEV_SET_ERROR(pDevIns, rc,
901 N_("Configuration error: Querying \"HardDiskDevice\" as a string failed"));
902
903 rc = CFGMR3QueryStringAlloc(pCfgHandle, "FloppyDevice", &pData->pszFDDevice);
904 if (VBOX_FAILURE(rc))
905 return PDMDEV_SET_ERROR(pDevIns, rc,
906 N_("Configuration error: Querying \"FloppyDevice\" as a string failed"));
907
908 /*
909 * Register I/O Ports and PC BIOS.
910 */
911 rc = PDMDevHlpIOPortRegister(pDevIns, 0x400, 4, NULL, pcbiosIOPortWrite, pcbiosIOPortRead,
912 NULL, NULL, "Bochs PC BIOS - Panic & Debug");
913 if (VBOX_FAILURE(rc))
914 return rc;
915 rc = PDMDevHlpIOPortRegister(pDevIns, 0x8900, 1, NULL, pcbiosIOPortWrite, pcbiosIOPortRead,
916 NULL, NULL, "Bochs PC BIOS - Shutdown");
917 if (VBOX_FAILURE(rc))
918 return rc;
919
920 pcbiosPlantDMITable(pData->au8DMIPage);
921
922 rc = PDMDevHlpROMRegister(pDevIns, VBOX_DMI_TABLE_BASE, 0x1000, pData->au8DMIPage, "DMI tables");
923 if (VBOX_FAILURE(rc))
924 return rc;
925
926 /*
927 * Map the BIOS into memory.
928 * There are two mappings:
929 * 1. 0x000e0000 to 0x000fffff contains the last 128 kb of the bios.
930 * The bios code might be 64 kb in size, and will then start at 0xf0000.
931 * 2. 0xfffxxxxx to 0xffffffff contains the entire bios.
932 */
933 AssertReleaseMsg(g_cbPcBiosBinary >= _64K, ("g_cbPcBiosBinary=%#x\n", g_cbPcBiosBinary));
934 AssertReleaseMsg(RT_ALIGN_Z(g_cbPcBiosBinary, _64K) == g_cbPcBiosBinary,
935 ("g_cbPcBiosBinary=%#x\n", g_cbPcBiosBinary));
936 cb = RT_MIN(g_cbPcBiosBinary, 128 * _1K);
937 rc = PDMDevHlpROMRegister(pDevIns, 0x00100000 - cb, cb,
938 &g_abPcBiosBinary[g_cbPcBiosBinary - cb], "PC BIOS - 0xfffff");
939 if (VBOX_FAILURE(rc))
940 return rc;
941 rc = PDMDevHlpROMRegister(pDevIns, (uint32_t)-g_cbPcBiosBinary, g_cbPcBiosBinary,
942 &g_abPcBiosBinary[0], "PC BIOS - 0xffffffff");
943 if (VBOX_FAILURE(rc))
944 return rc;
945
946 /*
947 * Register the MMIO region for the BIOS Logo: 0x000d0000 to 0x000dffff (64k)
948 */
949 rc = PDMDevHlpMMIORegister(pDevIns, 0x000d0000, 0x00010000, 0,
950 logoMMIOWrite, logoMMIORead, NULL, "PC BIOS - Logo Buffer");
951 if (VBOX_FAILURE(rc))
952 return rc;
953
954 /*
955 * Construct the logo header.
956 */
957 LOGOHDR LogoHdr = { LOGOHDR_MAGIC, 0, 0, 0, 0, 0 };
958
959 rc = CFGMR3QueryU8(pCfgHandle, "FadeIn", &LogoHdr.u8FadeIn);
960 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
961 LogoHdr.u8FadeIn = 1;
962 else if (VBOX_FAILURE(rc))
963 return PDMDEV_SET_ERROR(pDevIns, rc,
964 N_("Configuration error: Querying \"FadeIn\" as integer failed"));
965
966 rc = CFGMR3QueryU8(pCfgHandle, "FadeOut", &LogoHdr.u8FadeOut);
967 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
968 LogoHdr.u8FadeOut = 1;
969 else if (VBOX_FAILURE(rc))
970 return PDMDEV_SET_ERROR(pDevIns, rc,
971 N_("Configuration error: Querying \"FadeOut\" as integer failed"));
972
973 rc = CFGMR3QueryU16(pCfgHandle, "LogoTime", &LogoHdr.u16LogoMillies);
974 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
975 LogoHdr.u16LogoMillies = 1;
976 else if (VBOX_FAILURE(rc))
977 return PDMDEV_SET_ERROR(pDevIns, rc,
978 N_("Configuration error: Querying \"LogoTime\" as integer failed"));
979
980 rc = CFGMR3QueryU8(pCfgHandle, "ShowBootMenu", &LogoHdr.u8ShowBootMenu);
981 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
982 LogoHdr.u8ShowBootMenu = 0;
983 else if (VBOX_FAILURE(rc))
984 return PDMDEV_SET_ERROR(pDevIns, rc,
985 N_("Configuration error: Querying \"ShowBootMenu\" as integer failed"));
986
987 /*
988 * Get the Logo file name.
989 */
990 rc = CFGMR3QueryStringAlloc(pCfgHandle, "LogoFile", &pData->pszLogoFile);
991 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
992 pData->pszLogoFile = NULL;
993 else if (VBOX_FAILURE(rc))
994 return PDMDEV_SET_ERROR(pDevIns, rc,
995 N_("Configuration error: Querying \"LogoFile\" as a string failed"));
996 else if (!*pData->pszLogoFile)
997 {
998 MMR3HeapFree(pData->pszLogoFile);
999 pData->pszLogoFile = NULL;
1000 }
1001
1002 /*
1003 * Determine the logo size, open any specified logo file in the process.
1004 */
1005 LogoHdr.cbLogo = g_cbPcDefBiosLogo;
1006 RTFILE FileLogo = NIL_RTFILE;
1007 if (pData->pszLogoFile)
1008 {
1009 rc = RTFileOpen(&FileLogo, pData->pszLogoFile,
1010 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
1011 if (VBOX_SUCCESS(rc))
1012 {
1013 uint64_t cbFile;
1014 rc = RTFileGetSize(FileLogo, &cbFile);
1015 if (VBOX_SUCCESS(rc))
1016 {
1017 if ( cbFile > 0
1018 && cbFile < ((LOGO_BANK_LAST + 1) * LOGO_BANK_SIZE) - sizeof(LogoHdr))
1019 LogoHdr.cbLogo = (uint32_t)cbFile;
1020 else
1021 rc = VERR_TOO_MUCH_DATA;
1022 }
1023 }
1024 if (VBOX_FAILURE(rc))
1025 {
1026 /*
1027 * Ignore failure and fall back to the default logo.
1028 */
1029 LogRel(("pcbiosConstruct: Failed to open logo file '%s', rc=%Vrc!\n", pData->pszLogoFile, rc));
1030 RTFileClose(FileLogo);
1031 FileLogo = NIL_RTFILE;
1032 MMR3HeapFree(pData->pszLogoFile);
1033 pData->pszLogoFile = NULL;
1034 }
1035 }
1036
1037 /*
1038 * Allocate buffer for the logo data.
1039 * RT_MAX() is applied to let us fall back to default logo on read failure.
1040 */
1041 pData->cbLogo = sizeof(LogoHdr) + LogoHdr.cbLogo;
1042 pData->pu8Logo = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, RT_MAX(pData->cbLogo, g_cbPcDefBiosLogo + sizeof(LogoHdr)));
1043 if (pData->pu8Logo)
1044 {
1045 /*
1046 * Write the logo header.
1047 */
1048 PLOGOHDR pLogoHdr = (PLOGOHDR)pData->pu8Logo;
1049 *pLogoHdr = LogoHdr;
1050
1051 /*
1052 * Write the logo bitmap.
1053 */
1054 if (pData->pszLogoFile)
1055 {
1056 rc = RTFileRead(FileLogo, pLogoHdr + 1, LogoHdr.cbLogo, NULL);
1057 if (VBOX_FAILURE(rc))
1058 {
1059 AssertMsgFailed(("RTFileRead(,,%d,NULL) -> %Vrc\n", LogoHdr.cbLogo, rc));
1060 pLogoHdr->cbLogo = LogoHdr.cbLogo = g_cbPcDefBiosLogo;
1061 memcpy(pLogoHdr + 1, g_abPcDefBiosLogo, LogoHdr.cbLogo);
1062 }
1063 }
1064 else
1065 memcpy(pLogoHdr + 1, g_abPcDefBiosLogo, LogoHdr.cbLogo);
1066
1067 /*
1068 * Call reset to set values and stuff.
1069 */
1070 pcbiosReset(pDevIns);
1071 rc = VINF_SUCCESS;
1072 }
1073 else
1074 rc = VERR_NO_MEMORY;
1075
1076 /* cleanup */
1077 if (FileLogo != NIL_RTFILE)
1078 RTFileClose(FileLogo);
1079
1080 /*
1081 * Get the LAN boot ROM file name.
1082 */
1083 rc = CFGMR3QueryStringAlloc(pCfgHandle, "LanBootRom", &pData->pszLanBootFile);
1084 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1085 {
1086 pData->pszLanBootFile = NULL;
1087 rc = VINF_SUCCESS;
1088 }
1089 else if (VBOX_FAILURE(rc))
1090 return PDMDEV_SET_ERROR(pDevIns, rc,
1091 N_("Configuration error: Querying \"LanBootRom\" as a string failed"));
1092 else if (!*pData->pszLanBootFile)
1093 {
1094 MMR3HeapFree(pData->pszLanBootFile);
1095 pData->pszLanBootFile = NULL;
1096 }
1097
1098 const uint8_t *pu8LanBoot = NULL;
1099 uint64_t cbFileLanBoot;
1100#ifdef VBOX_DO_NOT_LINK_LANBOOT
1101 /*
1102 * Determine the LAN boot ROM size, open specified ROM file in the process.
1103 */
1104 RTFILE FileLanBoot = NIL_RTFILE;
1105 if (pData->pszLanBootFile)
1106 {
1107 rc = RTFileOpen(&FileLanBoot, pData->pszLanBootFile,
1108 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
1109 if (VBOX_SUCCESS(rc))
1110 {
1111 rc = RTFileGetSize(FileLanBoot, &cbFileLanBoot);
1112 if (VBOX_SUCCESS(rc))
1113 {
1114 if ( RT_ALIGN(cbFileLanBoot, _4K) != cbFileLanBoot
1115 || cbFileLanBoot > _32K)
1116 rc = VERR_TOO_MUCH_DATA;
1117 }
1118 }
1119 if (VBOX_FAILURE(rc))
1120 {
1121 /*
1122 * Ignore failure and fall back to no LAN boot ROM.
1123 */
1124 Log(("pcbiosConstruct: Failed to open LAN boot ROM file '%s', rc=%Vrc!\n", pData->pszLanBootFile, rc));
1125 RTFileClose(FileLanBoot);
1126 FileLanBoot = NIL_RTFILE;
1127 MMR3HeapFree(pData->pszLanBootFile);
1128 pData->pszLanBootFile = NULL;
1129 }
1130 }
1131
1132 /*
1133 * Get the LAN boot ROM data.
1134 */
1135 if (pData->pszLanBootFile)
1136 {
1137 /*
1138 * Allocate buffer for the LAN boot ROM data.
1139 */
1140 pu8LanBoot = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, cbFileLanBoot);
1141 pData->pu8LanBoot = pu8LanBoot;
1142 if (pu8LanBoot)
1143 {
1144 rc = RTFileRead(FileLanBoot, pData->pu8LanBoot, cbFileLanBoot, NULL);
1145 if (VBOX_FAILURE(rc))
1146 {
1147 AssertMsgFailed(("RTFileRead(,,%d,NULL) -> %Vrc\n", cbFileLanBoot, rc));
1148 MMR3HeapFree(pu8LanBoot);
1149 pu8LanBoot = NULL;
1150 pData->pu8LanBoot = NULL;
1151 }
1152 rc = VINF_SUCCESS;
1153 }
1154 else
1155 rc = VERR_NO_MEMORY;
1156 }
1157 else
1158 pData->pu8LanBoot = NULL;
1159
1160 /* cleanup */
1161 if (FileLanBoot != NIL_RTFILE)
1162 RTFileClose(FileLanBoot);
1163
1164#else /* !VBOX_DO_NOT_LINK_LANBOOT */
1165 pData->pu8LanBoot = NULL;
1166 pu8LanBoot = g_abNetBiosBinary;
1167 cbFileLanBoot = g_cbNetBiosBinary;
1168#endif /* !VBOX_DO_NOT_LINK_LANBOOT */
1169
1170 /*
1171 * Map the Network Boot ROM into memory.
1172 * Currently there is a fixed mapping: 0x000c8000 to 0x000cffff contains
1173 * the (up to) 32 kb ROM image.
1174 */
1175 if (pu8LanBoot)
1176 rc = PDMDevHlpROMRegister(pDevIns, VBOX_LANBOOT_SEG << 4, cbFileLanBoot, pu8LanBoot, "Net Boot ROM");
1177
1178 rc = CFGMR3QueryU8(pCfgHandle, "DelayBoot", &pData->uBootDelay);
1179 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1180 {
1181 pData->uBootDelay = 0;
1182 rc = VINF_SUCCESS;
1183 }
1184 else
1185 {
1186 if (VBOX_FAILURE(rc))
1187 return PDMDEV_SET_ERROR(pDevIns, rc,
1188 N_("Configuration error: Querying \"DelayBoot\" as integer failed"));
1189 if (pData->uBootDelay > 15)
1190 pData->uBootDelay = 15;
1191 }
1192
1193 return rc;
1194}
1195
1196
1197/**
1198 * The device registration structure.
1199 */
1200const PDMDEVREG g_DevicePcBios =
1201{
1202 /* u32Version */
1203 PDM_DEVREG_VERSION,
1204 /* szDeviceName */
1205 "pcbios",
1206 /* szGCMod */
1207 "",
1208 /* szR0Mod */
1209 "",
1210 /* pszDescription */
1211 "Bochs PC BIOS",
1212 /* fFlags */
1213 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64,
1214 /* fClass */
1215 PDM_DEVREG_CLASS_ARCH_BIOS,
1216 /* cMaxInstances */
1217 1,
1218 /* cbInstance */
1219 sizeof(DEVPCBIOS),
1220 /* pfnConstruct */
1221 pcbiosConstruct,
1222 /* pfnDestruct */
1223 pcbiosDestruct,
1224 /* pfnRelocate */
1225 NULL,
1226 /* pfnIOCtl */
1227 NULL,
1228 /* pfnPowerOn */
1229 NULL,
1230 /* pfnReset */
1231 pcbiosReset,
1232 /* pfnSuspend */
1233 NULL,
1234 /* pfnResume */
1235 NULL,
1236 /* pfnAttach */
1237 NULL,
1238 /* pfnDetach */
1239 NULL,
1240 /* pfnQueryInterface. */
1241 NULL,
1242 /* pfnInitComplete. */
1243 pcbiosInitComplete
1244};
1245
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