DevPcBios.cpp revision d3cd4892aaf3a0fb79c295c9afb9626d4d0fd0b5
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami/* $Id$ */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami/** @file
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami * PC BIOS Device.
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami/*
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami * Copyright (C) 2006-2008 Oracle Corporation
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami *
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami * This file is part of VirtualBox Open Source Edition (OSE), as
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami * available from http://www.virtualbox.org. This file is free software;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami * you can redistribute it and/or modify it under the terms of the GNU
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami * General Public License (GPL) as published by the Free Software
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami * Foundation, in version 2 as it comes in the "COPYING" file of the
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami/*******************************************************************************
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami* Header Files *
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami*******************************************************************************/
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami#define LOG_GROUP LOG_GROUP_DEV_PC_BIOS
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami#include <VBox/vmm/pdmdev.h>
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami#include <VBox/vmm/mm.h>
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami#include <VBox/vmm/pgm.h>
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami#include <VBox/log.h>
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami#include <iprt/asm.h>
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami#include <iprt/assert.h>
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami#include <iprt/buildconfig.h>
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami#include <iprt/file.h>
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami#include <iprt/mem.h>
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami#include <iprt/string.h>
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami#include <iprt/uuid.h>
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami#include <VBox/err.h>
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami#include <VBox/param.h>
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami#include "VBoxDD.h"
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami#include "VBoxDD2.h"
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami#include "DevPcBios.h"
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami#include "DevFwCommon.h"
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami#define NET_BOOT_DEVS 4
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami/** @page pg_devbios_cmos_assign CMOS Assignments (BIOS)
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami *
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami * The BIOS uses a CMOS to store configuration data.
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami * It is currently used as follows:
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami *
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami * @verbatim
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami First CMOS bank (offsets 0x00 to 0x7f):
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami Floppy drive type:
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami 0x10
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami Hard disk type (old):
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami 0x12
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami Equipment byte:
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami 0x14
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami Base memory:
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami 0x15
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami 0x16
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami Extended memory:
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami 0x17
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami 0x18
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami 0x30
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami 0x31
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami First IDE HDD:
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami 0x19
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami 0x1e - 0x25
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami Second IDE HDD:
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami 0x1a
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami 0x26 - 0x2d
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami Checksum of 0x10-0x2d:
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami 0x2e
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami 0x2f
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami Amount of memory above 16M and below 4GB in 64KB units:
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami 0x34
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami 0x35
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami Boot device (BOCHS BIOS specific):
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami 0x38
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami 0x3c
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami 0x3d
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami PXE debug:
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami 0x3f
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami First SATA HDD:
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami 0x40 - 0x47
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami Second SATA HDD:
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami 0x48 - 0x4f
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami Third SATA HDD:
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami 0x50 - 0x57
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami Fourth SATA HDD:
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami 0x58 - 0x5f
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami Number of CPUs:
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami 0x60
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami RAM above 4G in 64KB units:
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami 0x61 - 0x65
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami Third IDE HDD:
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami 0x67 - 0x6e
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami Fourth IDE HDD:
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami 0x70 - 0x77
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami Second CMOS bank (offsets 0x80 to 0xff):
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami Reserved for internal use by PXE ROM:
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami 0x80 - 0x81
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami First net boot device PCI bus/dev/fn:
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami 0x82 - 0x83
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami Second to third net boot devices:
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami 0x84 - 0x89
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami@endverbatim
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami *
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami * @todo Mark which bits are compatible with which BIOSes and
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami * which are our own definitions.
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami/*******************************************************************************
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami* Structures and Typedefs *
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami*******************************************************************************/
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami/**
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami * The boot device.
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahramitypedef enum DEVPCBIOSBOOT
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami{
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami DEVPCBIOSBOOT_NONE,
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami DEVPCBIOSBOOT_FLOPPY,
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami DEVPCBIOSBOOT_HD,
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami DEVPCBIOSBOOT_DVD,
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami DEVPCBIOSBOOT_LAN
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami} DEVPCBIOSBOOT;
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami/**
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami * PC Bios instance data structure.
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami */
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahramitypedef struct DEVPCBIOS
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami{
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami /** Pointer back to the device instance. */
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami PPDMDEVINS pDevIns;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami /** Boot devices (ordered). */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami DEVPCBIOSBOOT aenmBootDevice[4];
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami /** RAM size (in bytes). */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami uint64_t cbRam;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami /** RAM hole size (in bytes). */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami uint32_t cbRamHole;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami /** Bochs shutdown index. */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami uint32_t iShutdown;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami /** Floppy device. */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami char *pszFDDevice;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami /** Harddisk device. */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami char *pszHDDevice;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami /** Sata harddisk device. */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami char *pszSataDevice;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami /** LUN of the four harddisks which are emulated as IDE. */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami uint32_t iSataHDLUN[4];
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami /** Bios message buffer. */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami char szMsg[256];
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami /** Bios message buffer index. */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami uint32_t iMsg;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami /** The system BIOS ROM data. */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami uint8_t *pu8PcBios;
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami /** The size of the system BIOS ROM. */
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami uint32_t cbPcBios;
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami /** The name of the BIOS ROM file. */
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami char *pszPcBiosFile;
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami /** The LAN boot ROM data. */
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami uint8_t *pu8LanBoot;
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami /** The name of the LAN boot ROM file. */
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami char *pszLanBootFile;
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami /** The size of the LAN boot ROM. */
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami uint64_t cbLanBoot;
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami /** The DMI tables. */
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami uint8_t au8DMIPage[0x1000];
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami /** The boot countdown (in seconds). */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami uint8_t uBootDelay;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami /** I/O-APIC enabled? */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami uint8_t u8IOAPIC;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami /** PXE debug logging enabled? */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami uint8_t u8PXEDebug;
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami /** PXE boot PCI bus/dev/fn list. */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami uint16_t au16NetBootDev[NET_BOOT_DEVS];
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami /** Number of logical CPUs in guest */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami uint16_t cCpus;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami uint32_t u32McfgBase;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami uint32_t cbMcfgLength;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami} DEVPCBIOS, *PDEVPCBIOS;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami/* Attempt to guess the LCHS disk geometry from the MS-DOS master boot
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami * record (partition table). */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahramistatic int biosGuessDiskLCHS(PPDMIBLOCK pBlock, PPDMMEDIAGEOMETRY pLCHSGeometry)
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami{
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami uint8_t aMBR[512], *p;
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami int rc;
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami uint32_t iEndHead, iEndSector, cLCHSCylinders, cLCHSHeads, cLCHSSectors;
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami if (!pBlock)
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami return VERR_INVALID_PARAMETER;
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami rc = pBlock->pfnRead(pBlock, 0, aMBR, sizeof(aMBR));
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami if (RT_FAILURE(rc))
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami return rc;
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami /* Test MBR magic number. */
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami if (aMBR[510] != 0x55 || aMBR[511] != 0xaa)
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami return VERR_INVALID_PARAMETER;
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami for (uint32_t i = 0; i < 4; i++)
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami {
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami /* Figure out the start of a partition table entry. */
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami p = &aMBR[0x1be + i * 16];
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami iEndHead = p[5];
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami iEndSector = p[6] & 63;
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami if ((p[12] | p[13] | p[14] | p[15]) && iEndSector & iEndHead)
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami {
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami /* Assumption: partition terminates on a cylinder boundary. */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami cLCHSHeads = iEndHead + 1;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami cLCHSSectors = iEndSector;
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami cLCHSCylinders = RT_MIN(1024, pBlock->pfnGetSize(pBlock) / (512 * cLCHSHeads * cLCHSSectors));
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami if (cLCHSCylinders >= 1)
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami {
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami pLCHSGeometry->cCylinders = cLCHSCylinders;
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami pLCHSGeometry->cHeads = cLCHSHeads;
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami pLCHSGeometry->cSectors = cLCHSSectors;
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami Log(("%s: LCHS=%d %d %d\n", __FUNCTION__, cLCHSCylinders, cLCHSHeads, cLCHSSectors));
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami return VINF_SUCCESS;
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami }
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami }
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami }
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami return VERR_INVALID_PARAMETER;
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami}
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami/**
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami * Write to CMOS memory.
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami * This is used by the init complete code.
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahramistatic void pcbiosCmosWrite(PPDMDEVINS pDevIns, int off, uint32_t u32Val)
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami{
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami Assert(off < 256);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami Assert(u32Val < 256);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami int rc = PDMDevHlpCMOSWrite(pDevIns, off, u32Val);
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami AssertRC(rc);
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami}
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami/**
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami * Read from CMOS memory.
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami * This is used by the init complete code.
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami */
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahramistatic uint8_t pcbiosCmosRead(PPDMDEVINS pDevIns, int off)
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami{
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami uint8_t u8val;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami Assert(off < 256);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami int rc = PDMDevHlpCMOSRead(pDevIns, off, &u8val);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami AssertRC(rc);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami return u8val;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami}
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami/* -=-=-=-=-=-=- based on code from pc.c -=-=-=-=-=-=- */
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami/**
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami * Initializes the CMOS data for one harddisk.
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahramistatic void pcbiosCmosInitHardDisk(PPDMDEVINS pDevIns, int offType, int offInfo, PCPDMMEDIAGEOMETRY pLCHSGeometry)
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami{
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami Log2(("%s: offInfo=%#x: LCHS=%d/%d/%d\n", __FUNCTION__, offInfo, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami if (offType)
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami pcbiosCmosWrite(pDevIns, offType, 47);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami /* Cylinders low */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami pcbiosCmosWrite(pDevIns, offInfo + 0, RT_MIN(pLCHSGeometry->cCylinders, 1024) & 0xff);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami /* Cylinders high */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami pcbiosCmosWrite(pDevIns, offInfo + 1, RT_MIN(pLCHSGeometry->cCylinders, 1024) >> 8);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami /* Heads */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami pcbiosCmosWrite(pDevIns, offInfo + 2, pLCHSGeometry->cHeads);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami /* Landing zone low */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami pcbiosCmosWrite(pDevIns, offInfo + 3, 0xff);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami /* Landing zone high */
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami pcbiosCmosWrite(pDevIns, offInfo + 4, 0xff);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami /* Write precomp low */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami pcbiosCmosWrite(pDevIns, offInfo + 5, 0xff);
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami /* Write precomp high */
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami pcbiosCmosWrite(pDevIns, offInfo + 6, 0xff);
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami /* Sectors */
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami pcbiosCmosWrite(pDevIns, offInfo + 7, pLCHSGeometry->cSectors);
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami}
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami/**
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami * Set logical CHS geometry for a hard disk
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami *
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami * @returns VBox status code.
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami * @param pBase Base interface for the device.
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami * @param pHardDisk The hard disk.
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami * @param pLCHSGeometry Where to store the geometry settings.
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami */
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahramistatic int setLogicalDiskGeometry(PPDMIBASE pBase, PPDMIBLOCKBIOS pHardDisk, PPDMMEDIAGEOMETRY pLCHSGeometry)
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami{
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami PDMMEDIAGEOMETRY LCHSGeometry;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami int rc = VINF_SUCCESS;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami rc = pHardDisk->pfnGetLCHSGeometry(pHardDisk, &LCHSGeometry);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami if ( rc == VERR_PDM_GEOMETRY_NOT_SET
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami || LCHSGeometry.cCylinders == 0
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami || LCHSGeometry.cHeads == 0
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami || LCHSGeometry.cHeads > 255
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami || LCHSGeometry.cSectors == 0
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami || LCHSGeometry.cSectors > 63)
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami {
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami PPDMIBLOCK pBlock;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami pBlock = PDMIBASE_QUERY_INTERFACE(pBase, PDMIBLOCK);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami /* No LCHS geometry, autodetect and set. */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami rc = biosGuessDiskLCHS(pBlock, &LCHSGeometry);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami if (RT_FAILURE(rc))
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami {
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami /* Try if PCHS geometry works, otherwise fall back. */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami rc = pHardDisk->pfnGetPCHSGeometry(pHardDisk, &LCHSGeometry);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami }
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami if ( RT_FAILURE(rc)
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami || LCHSGeometry.cCylinders == 0
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami || LCHSGeometry.cCylinders > 1024
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami || LCHSGeometry.cHeads == 0
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami || LCHSGeometry.cHeads > 16
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami || LCHSGeometry.cSectors == 0
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami || LCHSGeometry.cSectors > 63)
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami {
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami uint64_t cSectors = pBlock->pfnGetSize(pBlock) / 512;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami if (cSectors / 16 / 63 <= 1024)
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami {
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami LCHSGeometry.cCylinders = RT_MAX(cSectors / 16 / 63, 1);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami LCHSGeometry.cHeads = 16;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami }
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami else if (cSectors / 32 / 63 <= 1024)
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami {
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami LCHSGeometry.cCylinders = RT_MAX(cSectors / 32 / 63, 1);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami LCHSGeometry.cHeads = 32;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami }
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami else if (cSectors / 64 / 63 <= 1024)
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami {
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami LCHSGeometry.cCylinders = cSectors / 64 / 63;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami LCHSGeometry.cHeads = 64;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami }
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami else if (cSectors / 128 / 63 <= 1024)
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami {
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami LCHSGeometry.cCylinders = cSectors / 128 / 63;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami LCHSGeometry.cHeads = 128;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami }
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami else
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami {
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami LCHSGeometry.cCylinders = RT_MIN(cSectors / 255 / 63, 1024);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami LCHSGeometry.cHeads = 255;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami }
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami LCHSGeometry.cSectors = 63;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami }
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami rc = pHardDisk->pfnSetLCHSGeometry(pHardDisk, &LCHSGeometry);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami if (rc == VERR_VD_IMAGE_READ_ONLY)
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami {
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami LogRel(("DevPcBios: ATA failed to update LCHS geometry, read only\n"));
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami rc = VINF_SUCCESS;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami }
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami else if (rc == VERR_PDM_GEOMETRY_NOT_SET)
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami {
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami LogRel(("DevPcBios: ATA failed to update LCHS geometry, backend refused\n"));
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami rc = VINF_SUCCESS;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami }
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami }
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami *pLCHSGeometry = LCHSGeometry;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami return rc;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami}
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami/**
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami * Get BIOS boot code from enmBootDevice in order
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami *
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami * @todo r=bird: This is a rather silly function since the conversion is 1:1.
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahramistatic uint8_t getBiosBootCode(PDEVPCBIOS pThis, unsigned iOrder)
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami{
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami switch (pThis->aenmBootDevice[iOrder])
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami {
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami case DEVPCBIOSBOOT_NONE:
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami return 0;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami case DEVPCBIOSBOOT_FLOPPY:
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami return 1;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami case DEVPCBIOSBOOT_HD:
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami return 2;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami case DEVPCBIOSBOOT_DVD:
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami return 3;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami case DEVPCBIOSBOOT_LAN:
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami return 4;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami default:
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami AssertMsgFailed(("aenmBootDevice[%d]=%d\n", iOrder, pThis->aenmBootDevice[iOrder]));
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami return 0;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami }
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami}
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami/**
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami * Init complete notification.
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami * This routine will write information needed by the bios to the CMOS.
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami *
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami * @returns VBOX status code.
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami * @param pDevIns The device instance.
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami * @see http://www.brl.ntt.co.jp/people/takehiko/interrupt/CMOS.LST.txt for
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami * a description of standard and non-standard CMOS registers.
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahramistatic DECLCALLBACK(int) pcbiosInitComplete(PPDMDEVINS pDevIns)
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami{
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami PDEVPCBIOS pThis = PDMINS_2_DATA(pDevIns, PDEVPCBIOS);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami uint32_t u32;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami unsigned i;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami PVM pVM = PDMDevHlpGetVM(pDevIns);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami PPDMIBLOCKBIOS apHDs[4] = {0};
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami PPDMIBLOCKBIOS apFDs[2] = {0};
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami AssertRelease(pVM);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami LogFlow(("pcbiosInitComplete:\n"));
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami /*
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami * Memory sizes.
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami */
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami /* base memory. */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami u32 = pThis->cbRam > 640 ? 640 : (uint32_t)pThis->cbRam / _1K; /* <-- this test is wrong, but it doesn't matter since we never assign less than 1MB */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami pcbiosCmosWrite(pDevIns, 0x15, u32 & 0xff); /* 15h - Base Memory in K, Low Byte */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami pcbiosCmosWrite(pDevIns, 0x16, u32 >> 8); /* 16h - Base Memory in K, High Byte */
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami /* Extended memory, up to 65MB */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami u32 = pThis->cbRam >= 65 * _1M ? 0xffff : ((uint32_t)pThis->cbRam - _1M) / _1K;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami pcbiosCmosWrite(pDevIns, 0x17, u32 & 0xff); /* 17h - Extended Memory in K, Low Byte */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami pcbiosCmosWrite(pDevIns, 0x18, u32 >> 8); /* 18h - Extended Memory in K, High Byte */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami pcbiosCmosWrite(pDevIns, 0x30, u32 & 0xff); /* 30h - Extended Memory in K, Low Byte */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami pcbiosCmosWrite(pDevIns, 0x31, u32 >> 8); /* 31h - Extended Memory in K, High Byte */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami /* Bochs BIOS specific? Anyway, it's the amount of memory above 16MB
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami and below 4GB (as it can only hold 4GB+16M). We have to chop off the
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami top 2MB or it conflict with what the ACPI tables return. (Should these
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami be adjusted, we still have to chop it at 0xfffc0000 or it'll conflict
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami with the high BIOS mapping.) */
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami uint64_t const offRamHole = _4G - pThis->cbRamHole;
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami if (pThis->cbRam > 16 * _1M)
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami u32 = (uint32_t)( (RT_MIN(RT_MIN(pThis->cbRam, offRamHole), UINT32_C(0xffe00000)) - 16U * _1M) / _64K );
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami else
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami u32 = 0;
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami pcbiosCmosWrite(pDevIns, 0x34, u32 & 0xff);
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami pcbiosCmosWrite(pDevIns, 0x35, u32 >> 8);
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami /* Bochs/VBox BIOS specific way of specifying memory above 4GB in 64KB units.
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami Bochs got these in a different location which we've already used for SATA,
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami it also lacks the last two. */
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami uint64_t c64KBAbove4GB;
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami if (pThis->cbRam <= offRamHole)
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami c64KBAbove4GB = 0;
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami else
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami {
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami c64KBAbove4GB = (pThis->cbRam - offRamHole) / _64K;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami /* Make sure it doesn't hit the limits of the current BIOS code. */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami AssertLogRelMsgReturn((c64KBAbove4GB >> (3 * 8)) < 255, ("%#RX64\n", c64KBAbove4GB), VERR_OUT_OF_RANGE);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami }
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami pcbiosCmosWrite(pDevIns, 0x61, c64KBAbove4GB & 0xff);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami pcbiosCmosWrite(pDevIns, 0x62, (c64KBAbove4GB >> 8) & 0xff);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami pcbiosCmosWrite(pDevIns, 0x63, (c64KBAbove4GB >> 16) & 0xff);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami pcbiosCmosWrite(pDevIns, 0x64, (c64KBAbove4GB >> 24) & 0xff);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami pcbiosCmosWrite(pDevIns, 0x65, (c64KBAbove4GB >> 32) & 0xff);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami /*
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami * Number of CPUs.
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami pcbiosCmosWrite(pDevIns, 0x60, pThis->cCpus & 0xff);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami /*
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami * Bochs BIOS specifics - boot device.
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami * We do both new and old (ami-style) settings.
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami * See rombios.c line ~7215 (int19_function).
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami uint8_t reg3d = getBiosBootCode(pThis, 0) | (getBiosBootCode(pThis, 1) << 4);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami uint8_t reg38 = /* pcbiosCmosRead(pDevIns, 0x38) | */ getBiosBootCode(pThis, 2) << 4;
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami /* This is an extension. Bochs BIOS normally supports only 3 boot devices. */
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami uint8_t reg3c = getBiosBootCode(pThis, 3) | (pThis->uBootDelay << 4);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami pcbiosCmosWrite(pDevIns, 0x3d, reg3d);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami pcbiosCmosWrite(pDevIns, 0x38, reg38);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami pcbiosCmosWrite(pDevIns, 0x3c, reg3c);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami /*
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami * PXE debug option.
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami */
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami pcbiosCmosWrite(pDevIns, 0x3f, pThis->u8PXEDebug);
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami /*
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami * Network boot device list.
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami */
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami for (i = 0; i < NET_BOOT_DEVS; ++i)
5253169e90b276216b53d82f9ba4c56334db5740Ali Bahrami {
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami pcbiosCmosWrite(pDevIns, 0x82 + i * 2, pThis->au16NetBootDev[i] & 0xff);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami pcbiosCmosWrite(pDevIns, 0x83 + i * 2, pThis->au16NetBootDev[i] >> 8);
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami }
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami /*
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami * Floppy drive type.
75ce41a57ff334bd8fe2cb9ed51eea835892f944Ali Bahrami */
for (i = 0; i < RT_ELEMENTS(apFDs); i++)
{
PPDMIBASE pBase;
int rc = PDMR3QueryLun(pVM, pThis->pszFDDevice, 0, i, &pBase);
if (RT_SUCCESS(rc))
apFDs[i] = PDMIBASE_QUERY_INTERFACE(pBase, PDMIBLOCKBIOS);
}
u32 = 0;
if (apFDs[0])
switch (apFDs[0]->pfnGetType(apFDs[0]))
{
case PDMBLOCKTYPE_FLOPPY_360: u32 |= 1 << 4; break;
case PDMBLOCKTYPE_FLOPPY_1_20: u32 |= 2 << 4; break;
case PDMBLOCKTYPE_FLOPPY_720: u32 |= 3 << 4; break;
case PDMBLOCKTYPE_FLOPPY_1_44: u32 |= 4 << 4; break;
case PDMBLOCKTYPE_FLOPPY_2_88: u32 |= 5 << 4; break;
default: AssertFailed(); break;
}
if (apFDs[1])
switch (apFDs[1]->pfnGetType(apFDs[1]))
{
case PDMBLOCKTYPE_FLOPPY_360: u32 |= 1; break;
case PDMBLOCKTYPE_FLOPPY_1_20: u32 |= 2; break;
case PDMBLOCKTYPE_FLOPPY_720: u32 |= 3; break;
case PDMBLOCKTYPE_FLOPPY_1_44: u32 |= 4; break;
case PDMBLOCKTYPE_FLOPPY_2_88: u32 |= 5; break;
default: AssertFailed(); break;
}
pcbiosCmosWrite(pDevIns, 0x10, u32); /* 10h - Floppy Drive Type */
/*
* Equipment byte.
*/
u32 = !!apFDs[0] + !!apFDs[1];
switch (u32)
{
case 1: u32 = 0x01; break; /* floppy installed, 2 drives. */
default:u32 = 0; break; /* floppy not installed. */
}
u32 |= RT_BIT(1); /* math coprocessor installed */
u32 |= RT_BIT(2); /* keyboard enabled (or mouse?) */
u32 |= RT_BIT(3); /* display enabled (monitory type is 0, i.e. vga) */
pcbiosCmosWrite(pDevIns, 0x14, u32); /* 14h - Equipment Byte */
/*
* Harddisks.
*/
for (i = 0; i < RT_ELEMENTS(apHDs); i++)
{
PPDMIBASE pBase;
int rc = PDMR3QueryLun(pVM, pThis->pszHDDevice, 0, i, &pBase);
if (RT_SUCCESS(rc))
apHDs[i] = PDMIBASE_QUERY_INTERFACE(pBase, PDMIBLOCKBIOS);
if ( apHDs[i]
&& ( apHDs[i]->pfnGetType(apHDs[i]) != PDMBLOCKTYPE_HARD_DISK
|| !apHDs[i]->pfnIsVisible(apHDs[i])))
apHDs[i] = NULL;
if (apHDs[i])
{
PDMMEDIAGEOMETRY LCHSGeometry;
int rc2 = setLogicalDiskGeometry(pBase, apHDs[i], &LCHSGeometry);
AssertRC(rc2);
if (i < 4)
{
/* Award BIOS extended drive types for first to fourth disk.
* Used by the BIOS for setting the logical geometry. */
int offType, offInfo;
switch (i)
{
case 0:
offType = 0x19;
offInfo = 0x1e;
break;
case 1:
offType = 0x1a;
offInfo = 0x26;
break;
case 2:
offType = 0x00;
offInfo = 0x67;
break;
case 3:
default:
offType = 0x00;
offInfo = 0x70;
break;
}
pcbiosCmosInitHardDisk(pDevIns, offType, offInfo,
&LCHSGeometry);
}
LogRel(("DevPcBios: ATA LUN#%d LCHS=%u/%u/%u\n", i, LCHSGeometry.cCylinders, LCHSGeometry.cHeads, LCHSGeometry.cSectors));
}
}
/* 0Fh means extended and points to 19h, 1Ah */
u32 = (apHDs[0] ? 0xf0 : 0) | (apHDs[1] ? 0x0f : 0);
pcbiosCmosWrite(pDevIns, 0x12, u32);
/*
* Sata Harddisks.
*/
if (pThis->pszSataDevice)
{
/* Clear pointers to IDE controller. */
for (i = 0; i < RT_ELEMENTS(apHDs); i++)
apHDs[i] = NULL;
for (i = 0; i < RT_ELEMENTS(apHDs); i++)
{
PPDMIBASE pBase;
int rc = PDMR3QueryLun(pVM, pThis->pszSataDevice, 0, pThis->iSataHDLUN[i], &pBase);
if (RT_SUCCESS(rc))
apHDs[i] = PDMIBASE_QUERY_INTERFACE(pBase, PDMIBLOCKBIOS);
if ( apHDs[i]
&& ( apHDs[i]->pfnGetType(apHDs[i]) != PDMBLOCKTYPE_HARD_DISK
|| !apHDs[i]->pfnIsVisible(apHDs[i])))
apHDs[i] = NULL;
if (apHDs[i])
{
PDMMEDIAGEOMETRY LCHSGeometry;
rc = setLogicalDiskGeometry(pBase, apHDs[i], &LCHSGeometry);
AssertRC(rc);
if (i < 4)
{
/* Award BIOS extended drive types for first to fourth disk.
* Used by the BIOS for setting the logical geometry. */
int offInfo;
switch (i)
{
case 0:
offInfo = 0x40;
break;
case 1:
offInfo = 0x48;
break;
case 2:
offInfo = 0x50;
break;
case 3:
default:
offInfo = 0x58;
break;
}
pcbiosCmosInitHardDisk(pDevIns, 0x00, offInfo,
&LCHSGeometry);
}
LogRel(("DevPcBios: SATA LUN#%d LCHS=%u/%u/%u\n", i, LCHSGeometry.cCylinders, LCHSGeometry.cHeads, LCHSGeometry.cSectors));
}
}
}
/* Calculate and store AT-style CMOS checksum. */
uint16_t cksum = 0;
for (i = 0x10; i < 0x2e; ++i)
cksum += pcbiosCmosRead(pDevIns, i);
pcbiosCmosWrite(pDevIns, 0x2e, cksum >> 8);
pcbiosCmosWrite(pDevIns, 0x2f, cksum & 0xff);
LogFlow(("%s: returns VINF_SUCCESS\n", __FUNCTION__));
return VINF_SUCCESS;
}
/**
* Port I/O Handler for IN operations.
*
* @returns VBox status code.
*
* @param pDevIns The device instance.
* @param pvUser User argument - ignored.
* @param Port Port number used for the IN operation.
* @param pu32 Where to store the result.
* @param cb Number of bytes read.
*/
static DECLCALLBACK(int) pcbiosIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
{
return VERR_IOM_IOPORT_UNUSED;
}
/**
* Port I/O Handler for OUT operations.
*
* @returns VBox status code.
*
* @param pDevIns The device instance.
* @param pvUser User argument - ignored.
* @param Port Port number used for the IN operation.
* @param u32 The value to output.
* @param cb The value size in bytes.
*/
static DECLCALLBACK(int) pcbiosIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
{
/*
* Bochs BIOS Panic
*/
if ( cb == 2
&& ( Port == 0x400
|| Port == 0x401))
{
Log(("pcbios: PC BIOS panic at rombios.c(%d)\n", u32));
AssertReleaseMsgFailed(("PC BIOS panic at rombios.c(%d)\n", u32));
return VERR_INTERNAL_ERROR;
}
/*
* Bochs BIOS char printing.
*/
if ( cb == 1
&& ( Port == 0x402
|| Port == 0x403))
{
PDEVPCBIOS pThis = PDMINS_2_DATA(pDevIns, PDEVPCBIOS);
/* The raw version. */
switch (u32)
{
case '\r': Log2(("pcbios: <return>\n")); break;
case '\n': Log2(("pcbios: <newline>\n")); break;
case '\t': Log2(("pcbios: <tab>\n")); break;
default: Log2(("pcbios: %c (%02x)\n", u32, u32)); break;
}
/* The readable, buffered version. */
if (u32 == '\n' || u32 == '\r')
{
pThis->szMsg[pThis->iMsg] = '\0';
if (pThis->iMsg)
Log(("pcbios: %s\n", pThis->szMsg));
pThis->iMsg = 0;
}
else
{
if (pThis->iMsg >= sizeof(pThis->szMsg)-1)
{
pThis->szMsg[pThis->iMsg] = '\0';
Log(("pcbios: %s\n", pThis->szMsg));
pThis->iMsg = 0;
}
pThis->szMsg[pThis->iMsg] = (char )u32;
pThis->szMsg[++pThis->iMsg] = '\0';
}
return VINF_SUCCESS;
}
/*
* Bochs BIOS shutdown request.
*/
if (cb == 1 && Port == 0x8900)
{
static const unsigned char szShutdown[] = "Shutdown";
PDEVPCBIOS pThis = PDMINS_2_DATA(pDevIns, PDEVPCBIOS);
if (u32 == szShutdown[pThis->iShutdown])
{
pThis->iShutdown++;
if (pThis->iShutdown == 8)
{
pThis->iShutdown = 0;
LogRel(("DevPcBios: 8900h shutdown request.\n"));
return PDMDevHlpVMPowerOff(pDevIns);
}
}
else
pThis->iShutdown = 0;
return VINF_SUCCESS;
}
/* not in use. */
return VINF_SUCCESS;
}
/**
* Reset notification.
*
* @returns VBox status.
* @param pDevIns The device instance data.
*/
static DECLCALLBACK(void) pcbiosReset(PPDMDEVINS pDevIns)
{
PDEVPCBIOS pThis = PDMINS_2_DATA(pDevIns, PDEVPCBIOS);
LogFlow(("pcbiosReset:\n"));
if (pThis->u8IOAPIC)
FwCommonPlantMpsFloatPtr(pDevIns);
/*
* Re-shadow the LAN ROM image and make it RAM/RAM.
*
* This is normally done by the BIOS code, but since we're currently lacking
* the chipset support for this we do it here (and in the constructor).
*/
uint32_t cPages = RT_ALIGN_64(pThis->cbLanBoot, PAGE_SIZE) >> PAGE_SHIFT;
RTGCPHYS GCPhys = VBOX_LANBOOT_SEG << 4;
while (cPages > 0)
{
uint8_t abPage[PAGE_SIZE];
int rc;
/* Read the (original) ROM page and write it back to the RAM page. */
rc = PDMDevHlpROMProtectShadow(pDevIns, GCPhys, PAGE_SIZE, PGMROMPROT_READ_ROM_WRITE_RAM);
AssertLogRelRC(rc);
rc = PDMDevHlpPhysRead(pDevIns, GCPhys, abPage, PAGE_SIZE);
AssertLogRelRC(rc);
if (RT_FAILURE(rc))
memset(abPage, 0xcc, sizeof(abPage));
rc = PDMDevHlpPhysWrite(pDevIns, GCPhys, abPage, PAGE_SIZE);
AssertLogRelRC(rc);
/* Switch to the RAM/RAM mode. */
rc = PDMDevHlpROMProtectShadow(pDevIns, GCPhys, PAGE_SIZE, PGMROMPROT_READ_RAM_WRITE_RAM);
AssertLogRelRC(rc);
/* Advance */
GCPhys += PAGE_SIZE;
cPages--;
}
}
/**
* Destruct a device instance.
*
* Most VM resources are freed by the VM. This callback is provided so that any non-VM
* resources can be freed correctly.
*
* @param pDevIns The device instance data.
*/
static DECLCALLBACK(int) pcbiosDestruct(PPDMDEVINS pDevIns)
{
PDEVPCBIOS pThis = PDMINS_2_DATA(pDevIns, PDEVPCBIOS);
LogFlow(("pcbiosDestruct:\n"));
PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
/*
* Free MM heap pointers.
*/
if (pThis->pu8PcBios)
{
MMR3HeapFree(pThis->pu8PcBios);
pThis->pu8PcBios = NULL;
}
if (pThis->pszPcBiosFile)
{
MMR3HeapFree(pThis->pszPcBiosFile);
pThis->pszPcBiosFile = NULL;
}
if (pThis->pu8LanBoot)
{
MMR3HeapFree(pThis->pu8LanBoot);
pThis->pu8LanBoot = NULL;
}
if (pThis->pszLanBootFile)
{
MMR3HeapFree(pThis->pszLanBootFile);
pThis->pszLanBootFile = NULL;
}
if (pThis->pszHDDevice)
{
MMR3HeapFree(pThis->pszHDDevice);
pThis->pszHDDevice = NULL;
}
if (pThis->pszFDDevice)
{
MMR3HeapFree(pThis->pszFDDevice);
pThis->pszFDDevice = NULL;
}
if (pThis->pszSataDevice)
{
MMR3HeapFree(pThis->pszSataDevice);
pThis->pszSataDevice = NULL;
}
return VINF_SUCCESS;
}
/**
* Convert config value to DEVPCBIOSBOOT.
*
* @returns VBox status code.
* @param pCfg Configuration handle.
* @param pszParam The name of the value to read.
* @param penmBoot Where to store the boot method.
*/
static int pcbiosBootFromCfg(PPDMDEVINS pDevIns, PCFGMNODE pCfg, const char *pszParam, DEVPCBIOSBOOT *penmBoot)
{
char *psz;
int rc = CFGMR3QueryStringAlloc(pCfg, pszParam, &psz);
if (RT_FAILURE(rc))
return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
N_("Configuration error: Querying \"%s\" as a string failed"),
pszParam);
if (!strcmp(psz, "DVD") || !strcmp(psz, "CDROM"))
*penmBoot = DEVPCBIOSBOOT_DVD;
else if (!strcmp(psz, "IDE"))
*penmBoot = DEVPCBIOSBOOT_HD;
else if (!strcmp(psz, "FLOPPY"))
*penmBoot = DEVPCBIOSBOOT_FLOPPY;
else if (!strcmp(psz, "LAN"))
*penmBoot = DEVPCBIOSBOOT_LAN;
else if (!strcmp(psz, "NONE"))
*penmBoot = DEVPCBIOSBOOT_NONE;
else
{
PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
N_("Configuration error: The \"%s\" value \"%s\" is unknown"),
pszParam, psz);
rc = VERR_INTERNAL_ERROR;
}
MMR3HeapFree(psz);
return rc;
}
/**
* @interface_method_impl{PDMDEVREG,pfnConstruct}
*/
static DECLCALLBACK(int) pcbiosConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
{
PDEVPCBIOS pThis = PDMINS_2_DATA(pDevIns, PDEVPCBIOS);
int rc;
int cb;
Assert(iInstance == 0);
PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
/*
* Validate configuration.
*/
if (!CFGMR3AreValuesValid(pCfg,
"BootDevice0\0"
"BootDevice1\0"
"BootDevice2\0"
"BootDevice3\0"
"RamSize\0"
"RamHoleSize\0"
"HardDiskDevice\0"
"SataHardDiskDevice\0"
"SataPrimaryMasterLUN\0"
"SataPrimarySlaveLUN\0"
"SataSecondaryMasterLUN\0"
"SataSecondarySlaveLUN\0"
"FloppyDevice\0"
"DelayBoot\0"
"BiosRom\0"
"LanBootRom\0"
"PXEDebug\0"
"UUID\0"
"IOAPIC\0"
"NumCPUs\0"
"McfgBase\0"
"McfgLength\0"
"DmiBIOSFirmwareMajor\0"
"DmiBIOSFirmwareMinor\0"
"DmiBIOSReleaseDate\0"
"DmiBIOSReleaseMajor\0"
"DmiBIOSReleaseMinor\0"
"DmiBIOSVendor\0"
"DmiBIOSVersion\0"
"DmiSystemFamily\0"
"DmiSystemProduct\0"
"DmiSystemSerial\0"
"DmiSystemSKU\0"
"DmiSystemUuid\0"
"DmiSystemVendor\0"
"DmiSystemVersion\0"
"DmiBoardAssetTag\0"
"DmiBoardBoardType\0"
"DmiBoardLocInChass\0"
"DmiBoardProduct\0"
"DmiBoardSerial\0"
"DmiBoardVendor\0"
"DmiBoardVersion\0"
"DmiChassisAssetTag\0"
"DmiChassisSerial\0"
"DmiChassisVendor\0"
"DmiChassisVersion\0"
"DmiProcManufacturer\0"
"DmiProcVersion\0"
"DmiOEMVBoxVer\0"
"DmiOEMVBoxRev\0"
"DmiUseHostInfo\0"
"DmiExposeMemoryTable\0"
"DmiExposeProcInf\0"
))
return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
N_("Invalid configuration for device pcbios device"));
/*
* Init the data.
*/
rc = CFGMR3QueryU64(pCfg, "RamSize", &pThis->cbRam);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Querying \"RamSize\" as integer failed"));
rc = CFGMR3QueryU32Def(pCfg, "RamHoleSize", &pThis->cbRamHole, MM_RAM_HOLE_SIZE_DEFAULT);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Querying \"RamHoleSize\" as integer failed"));
rc = CFGMR3QueryU16Def(pCfg, "NumCPUs", &pThis->cCpus, 1);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Querying \"NumCPUs\" as integer failed"));
rc = CFGMR3QueryU32Def(pCfg, "McfgBase", &pThis->u32McfgBase, 0);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Querying \"\" as integer failed"));
rc = CFGMR3QueryU32Def(pCfg, "McfgLength", &pThis->cbMcfgLength, 0);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Querying \"McfgLength\" as integer failed"));
LogRel(("[SMP] BIOS with %u CPUs\n", pThis->cCpus));
rc = CFGMR3QueryU8Def(pCfg, "IOAPIC", &pThis->u8IOAPIC, 1);
if (RT_FAILURE (rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Failed to read \"IOAPIC\""));
static const char * const s_apszBootDevices[] = { "BootDevice0", "BootDevice1", "BootDevice2", "BootDevice3" };
Assert(RT_ELEMENTS(s_apszBootDevices) == RT_ELEMENTS(pThis->aenmBootDevice));
for (unsigned i = 0; i < RT_ELEMENTS(pThis->aenmBootDevice); i++)
{
rc = pcbiosBootFromCfg(pDevIns, pCfg, s_apszBootDevices[i], &pThis->aenmBootDevice[i]);
if (RT_FAILURE(rc))
return rc;
}
rc = CFGMR3QueryStringAlloc(pCfg, "HardDiskDevice", &pThis->pszHDDevice);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Querying \"HardDiskDevice\" as a string failed"));
rc = CFGMR3QueryStringAlloc(pCfg, "FloppyDevice", &pThis->pszFDDevice);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Querying \"FloppyDevice\" as a string failed"));
rc = CFGMR3QueryStringAlloc(pCfg, "SataHardDiskDevice", &pThis->pszSataDevice);
if (rc == VERR_CFGM_VALUE_NOT_FOUND)
pThis->pszSataDevice = NULL;
else if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Querying \"SataHardDiskDevice\" as a string failed"));
if (pThis->pszSataDevice)
{
static const char * const s_apszSataDisks[] =
{ "SataPrimaryMasterLUN", "SataPrimarySlaveLUN", "SataSecondaryMasterLUN", "SataSecondarySlaveLUN" };
Assert(RT_ELEMENTS(s_apszSataDisks) == RT_ELEMENTS(pThis->iSataHDLUN));
for (unsigned i = 0; i < RT_ELEMENTS(pThis->iSataHDLUN); i++)
{
rc = CFGMR3QueryU32(pCfg, s_apszSataDisks[i], &pThis->iSataHDLUN[i]);
if (rc == VERR_CFGM_VALUE_NOT_FOUND)
pThis->iSataHDLUN[i] = i;
else if (RT_FAILURE(rc))
return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
N_("Configuration error: Querying \"%s\" as a string failed"), s_apszSataDisks);
}
}
/*
* Register I/O Ports and PC BIOS.
*/
rc = PDMDevHlpIOPortRegister(pDevIns, 0x400, 4, NULL, pcbiosIOPortWrite, pcbiosIOPortRead,
NULL, NULL, "Bochs PC BIOS - Panic & Debug");
if (RT_FAILURE(rc))
return rc;
rc = PDMDevHlpIOPortRegister(pDevIns, 0x8900, 1, NULL, pcbiosIOPortWrite, pcbiosIOPortRead,
NULL, NULL, "Bochs PC BIOS - Shutdown");
if (RT_FAILURE(rc))
return rc;
/*
* Read the PXE debug logging option.
*/
rc = CFGMR3QueryU8Def(pCfg, "PXEDebug", &pThis->u8PXEDebug, false);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Querying \"PXEDebug\" as integer failed"));
/* Clear the net boot device list. All bits set invokes old behavior,
* as if no second CMOS bank was present.
*/
memset(&pThis->au16NetBootDev, 0xff, sizeof(pThis->au16NetBootDev));
/*
* Determine the network boot order.
*/
PCFGMNODE pCfgNetBoot = CFGMR3GetChild(pCfg, "NetBoot");
if (pCfgNetBoot == NULL)
{
/* Do nothing. */
rc = VINF_SUCCESS;
}
else
{
PCFGMNODE pCfgNetBootDevice;
uint8_t u8PciBus;
uint8_t u8PciDev;
uint8_t u8PciFn;
uint16_t u16BusDevFn;
char szIndex[] = "?";
Assert(pCfgNetBoot);
for (unsigned i = 0; i < NET_BOOT_DEVS; ++i)
{
szIndex[0] = '0' + i;
pCfgNetBootDevice = CFGMR3GetChild(pCfgNetBoot, szIndex);
rc = CFGMR3QueryU8(pCfgNetBootDevice, "PCIBusNo", &u8PciBus);
if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
{
/* Do nothing and stop iterating. */
rc = VINF_SUCCESS;
break;
}
else if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Querying \"Netboot/x/PCIBusNo\" as integer failed"));
rc = CFGMR3QueryU8(pCfgNetBootDevice, "PCIDeviceNo", &u8PciDev);
if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
{
/* Do nothing and stop iterating. */
rc = VINF_SUCCESS;
break;
}
else if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Querying \"Netboot/x/PCIDeviceNo\" as integer failed"));
rc = CFGMR3QueryU8(pCfgNetBootDevice, "PCIFunctionNo", &u8PciFn);
if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
{
/* Do nothing and stop iterating. */
rc = VINF_SUCCESS;
break;
}
else if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Querying \"Netboot/x/PCIFunctionNo\" as integer failed"));
u16BusDevFn = (((uint16_t)u8PciBus) << 8) | ((u8PciDev & 0x1F) << 3) | (u8PciFn & 0x7);
pThis->au16NetBootDev[i] = u16BusDevFn;
}
}
/*
* Get the system BIOS ROM file name.
*/
rc = CFGMR3QueryStringAlloc(pCfg, "BiosRom", &pThis->pszPcBiosFile);
if (rc == VERR_CFGM_VALUE_NOT_FOUND)
{
pThis->pszPcBiosFile = NULL;
rc = VINF_SUCCESS;
}
else if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Querying \"BiosRom\" as a string failed"));
else if (!*pThis->pszPcBiosFile)
{
MMR3HeapFree(pThis->pszPcBiosFile);
pThis->pszPcBiosFile = NULL;
}
if (pThis->pszPcBiosFile)
{
/*
* Load the BIOS ROM.
*/
RTFILE hFilePcBios;
rc = RTFileOpen(&hFilePcBios, pThis->pszPcBiosFile,
RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
if (RT_SUCCESS(rc))
{
/* Figure the size and check restrictions. */
uint64_t cbPcBios;
rc = RTFileGetSize(hFilePcBios, &cbPcBios);
if (RT_SUCCESS(rc))
{
pThis->cbPcBios = (uint32_t)cbPcBios;
if ( RT_ALIGN(pThis->cbPcBios, _64K) == pThis->cbPcBios
&& pThis->cbPcBios == cbPcBios
&& pThis->cbPcBios <= 32 * _64K
&& pThis->cbPcBios >= _64K)
{
pThis->pu8PcBios = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, pThis->cbPcBios);
if (pThis->pu8PcBios)
{
rc = RTFileRead(hFilePcBios, pThis->pu8PcBios, pThis->cbPcBios, NULL);
if (RT_FAILURE(rc))
rc = PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
N_("Error reading the BIOS image ('%s)"), pThis->pszPcBiosFile);
}
else
rc = PDMDevHlpVMSetError(pDevIns, VERR_NO_MEMORY, RT_SRC_POS,
N_("Failed to allocate %#x bytes for loading the BIOS image"),
pThis->cbPcBios);
}
else
rc = PDMDevHlpVMSetError(pDevIns, VERR_OUT_OF_RANGE, RT_SRC_POS,
N_("Invalid system BIOS file size ('%s'): %#llx (%llu)"),
pThis->pszPcBiosFile, cbPcBios, cbPcBios);
}
else
rc = PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
N_("Failed to query the system BIOS file size ('%s')"),
pThis->pszPcBiosFile);
RTFileClose(hFilePcBios);
}
else
rc = PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
N_("Failed to open system BIOS file '%s'"), pThis->pszPcBiosFile);
if (RT_FAILURE(rc))
return rc;
LogRel(("DevPcBios: Using BIOS ROM '%s' with a size of %#x bytes\n", pThis->pszPcBiosFile, pThis->cbPcBios));
}
else
{
/*
* Use the embedded BIOS ROM image.
*/
pThis->pu8PcBios = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, g_cbPcBiosBinary);
if (pThis->pu8PcBios)
{
pThis->cbPcBios = g_cbPcBiosBinary;
memcpy(pThis->pu8PcBios, g_abPcBiosBinary, pThis->cbPcBios);
}
else
return PDMDevHlpVMSetError(pDevIns, VERR_NO_MEMORY, RT_SRC_POS,
N_("Failed to allocate %#x bytes for loading the embedded BIOS image"),
g_cbPcBiosBinary);
}
const uint8_t *pu8PcBiosBinary = pThis->pu8PcBios;
uint32_t cbPcBiosBinary = pThis->cbPcBios;
/*
* Query the machine's UUID for SMBIOS/DMI use.
*/
RTUUID uuid;
rc = CFGMR3QueryBytes(pCfg, "UUID", &uuid, sizeof(uuid));
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Querying \"UUID\" failed"));
/* Convert the UUID to network byte order. Not entirely straightforward as parts are MSB already... */
uuid.Gen.u32TimeLow = RT_H2BE_U32(uuid.Gen.u32TimeLow);
uuid.Gen.u16TimeMid = RT_H2BE_U16(uuid.Gen.u16TimeMid);
uuid.Gen.u16TimeHiAndVersion = RT_H2BE_U16(uuid.Gen.u16TimeHiAndVersion);
uint16_t cbDmiTables = 0;
rc = FwCommonPlantDMITable(pDevIns, pThis->au8DMIPage, VBOX_DMI_TABLE_SIZE,
&uuid, pCfg, pThis->cCpus, &cbDmiTables);
if (RT_FAILURE(rc))
return rc;
for (unsigned i = 0; i < pThis->cbPcBios; i += 16)
{
/* If the DMI table is located at the expected place, patch the DMI table length and the checksum. */
if ( pThis->pu8PcBios[i + 0x00] == '_'
&& pThis->pu8PcBios[i + 0x01] == 'D'
&& pThis->pu8PcBios[i + 0x02] == 'M'
&& pThis->pu8PcBios[i + 0x03] == 'I'
&& pThis->pu8PcBios[i + 0x04] == '_'
&& *(uint16_t*)&pThis->pu8PcBios[i + 0x06] == 0)
{
*(uint16_t*)&pThis->pu8PcBios[i + 0x06] = cbDmiTables;
uint8_t u8Sum = 0;
for (unsigned j = 0; j < pThis->cbPcBios; j++)
if (j != i + 0x05)
u8Sum += pThis->pu8PcBios[j];
pThis->pu8PcBios[i + 0x05] = -u8Sum;
break;
}
}
if (pThis->u8IOAPIC)
FwCommonPlantMpsTable(pDevIns, pThis->au8DMIPage + VBOX_DMI_TABLE_SIZE,
_4K - VBOX_DMI_TABLE_SIZE, pThis->cCpus);
rc = PDMDevHlpROMRegister(pDevIns, VBOX_DMI_TABLE_BASE, _4K, pThis->au8DMIPage, _4K,
PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "DMI tables");
if (RT_FAILURE(rc))
return rc;
/*
* Map the BIOS into memory.
* There are two mappings:
* 1. 0x000e0000 to 0x000fffff contains the last 128 kb of the bios.
* The bios code might be 64 kb in size, and will then start at 0xf0000.
* 2. 0xfffxxxxx to 0xffffffff contains the entire bios.
*/
AssertReleaseMsg(cbPcBiosBinary >= _64K, ("cbPcBiosBinary=%#x\n", cbPcBiosBinary));
AssertReleaseMsg(RT_ALIGN_Z(cbPcBiosBinary, _64K) == cbPcBiosBinary,
("cbPcBiosBinary=%#x\n", cbPcBiosBinary));
cb = RT_MIN(cbPcBiosBinary, 128 * _1K); /* Effectively either 64 or 128K. */
rc = PDMDevHlpROMRegister(pDevIns, 0x00100000 - cb, cb, &pu8PcBiosBinary[cbPcBiosBinary - cb], cb,
PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "PC BIOS - 0xfffff");
if (RT_FAILURE(rc))
return rc;
rc = PDMDevHlpROMRegister(pDevIns, (uint32_t)-(int32_t)cbPcBiosBinary, cbPcBiosBinary, pu8PcBiosBinary, cbPcBiosBinary,
PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "PC BIOS - 0xffffffff");
if (RT_FAILURE(rc))
return rc;
/*
* Get the LAN boot ROM file name.
*/
rc = CFGMR3QueryStringAlloc(pCfg, "LanBootRom", &pThis->pszLanBootFile);
if (rc == VERR_CFGM_VALUE_NOT_FOUND)
{
pThis->pszLanBootFile = NULL;
rc = VINF_SUCCESS;
}
else if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Querying \"LanBootRom\" as a string failed"));
else if (!*pThis->pszLanBootFile)
{
MMR3HeapFree(pThis->pszLanBootFile);
pThis->pszLanBootFile = NULL;
}
uint64_t cbFileLanBoot;
const uint8_t *pu8LanBootBinary = NULL;
uint64_t cbLanBootBinary;
/*
* Determine the LAN boot ROM size, open specified ROM file in the process.
*/
RTFILE FileLanBoot = NIL_RTFILE;
if (pThis->pszLanBootFile)
{
rc = RTFileOpen(&FileLanBoot, pThis->pszLanBootFile,
RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
if (RT_SUCCESS(rc))
{
rc = RTFileGetSize(FileLanBoot, &cbFileLanBoot);
if (RT_SUCCESS(rc))
{
if (cbFileLanBoot > _64K - (VBOX_LANBOOT_SEG << 4 & 0xffff))
rc = VERR_TOO_MUCH_DATA;
}
}
if (RT_FAILURE(rc))
{
/*
* Ignore failure and fall back to the built-in LAN boot ROM.
*/
LogRel(("DevPcBios: Failed to open LAN boot ROM file '%s', rc=%Rrc!\n", pThis->pszLanBootFile, rc));
RTFileClose(FileLanBoot);
FileLanBoot = NIL_RTFILE;
MMR3HeapFree(pThis->pszLanBootFile);
pThis->pszLanBootFile = NULL;
}
}
/*
* Get the LAN boot ROM data.
*/
if (pThis->pszLanBootFile)
{
LogRel(("DevPcBios: Using LAN ROM '%s' with a size of %#x bytes\n", pThis->pszLanBootFile, cbFileLanBoot));
/*
* Allocate buffer for the LAN boot ROM data.
*/
pThis->pu8LanBoot = (uint8_t *)PDMDevHlpMMHeapAllocZ(pDevIns, cbFileLanBoot);
if (pThis->pu8LanBoot)
{
rc = RTFileRead(FileLanBoot, pThis->pu8LanBoot, cbFileLanBoot, NULL);
if (RT_FAILURE(rc))
{
AssertMsgFailed(("RTFileRead(,,%d,NULL) -> %Rrc\n", cbFileLanBoot, rc));
MMR3HeapFree(pThis->pu8LanBoot);
pThis->pu8LanBoot = NULL;
}
rc = VINF_SUCCESS;
}
else
rc = VERR_NO_MEMORY;
}
else
pThis->pu8LanBoot = NULL;
/* cleanup */
if (FileLanBoot != NIL_RTFILE)
RTFileClose(FileLanBoot);
/* If we were unable to get the data from file for whatever reason, fall
* back to the built-in LAN boot ROM image.
*/
if (pThis->pu8LanBoot == NULL)
{
#ifdef VBOX_WITH_PXE_ROM
pu8LanBootBinary = g_abNetBiosBinary;
cbLanBootBinary = g_cbNetBiosBinary;
#endif
}
else
{
pu8LanBootBinary = pThis->pu8LanBoot;
cbLanBootBinary = cbFileLanBoot;
}
/*
* Map the Network Boot ROM into memory.
* Currently there is a fixed mapping: 0x000e2000 to 0x000effff contains
* the (up to) 56 kb ROM image. The mapping size is fixed to trouble with
* the saved state (in PGM).
*/
if (pu8LanBootBinary)
{
pThis->cbLanBoot = cbLanBootBinary;
rc = PDMDevHlpROMRegister(pDevIns, VBOX_LANBOOT_SEG << 4,
RT_MAX(cbLanBootBinary, _64K - (VBOX_LANBOOT_SEG << 4 & 0xffff)),
pu8LanBootBinary, cbLanBootBinary,
PGMPHYS_ROM_FLAGS_SHADOWED, "Net Boot ROM");
AssertRCReturn(rc, rc);
}
rc = CFGMR3QueryU8Def(pCfg, "DelayBoot", &pThis->uBootDelay, 0);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Querying \"DelayBoot\" as integer failed"));
if (pThis->uBootDelay > 15)
pThis->uBootDelay = 15;
/*
* Call reset plant tables and shadow the PXE ROM.
*/
pcbiosReset(pDevIns);
return VINF_SUCCESS;
}
/**
* The device registration structure.
*/
const PDMDEVREG g_DevicePcBios =
{
/* u32Version */
PDM_DEVREG_VERSION,
/* szName */
"pcbios",
/* szRCMod */
"",
/* szR0Mod */
"",
/* pszDescription */
"PC BIOS Device",
/* fFlags */
PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64,
/* fClass */
PDM_DEVREG_CLASS_ARCH_BIOS,
/* cMaxInstances */
1,
/* cbInstance */
sizeof(DEVPCBIOS),
/* pfnConstruct */
pcbiosConstruct,
/* pfnDestruct */
pcbiosDestruct,
/* pfnRelocate */
NULL,
/* pfnIOCtl */
NULL,
/* pfnPowerOn */
NULL,
/* pfnReset */
pcbiosReset,
/* pfnSuspend */
NULL,
/* pfnResume */
NULL,
/* pfnAttach */
NULL,
/* pfnDetach */
NULL,
/* pfnQueryInterface. */
NULL,
/* pfnInitComplete. */
pcbiosInitComplete,
/* pfnPowerOff */
NULL,
/* pfnSoftReset */
NULL,
/* u32VersionEnd */
PDM_DEVREG_VERSION
};