VirtualBox

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

Last change on this file since 44 was 31, checked in by vboxsync, 18 years ago

Move etherboot BIOS from 0xc8000...0xcffff to 0xcb000...0xcffff as it does not need more than 20KB and the VGA BIOS needs more than 32KB in future versions.

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