DevPcBios.cpp revision ca9921a4d12fbd97efb97bee5b2f4b9afd3db59e
236b2935f217749893b7034e59da3e3568928acevboxsync/* $Id$ */
236b2935f217749893b7034e59da3e3568928acevboxsync/** @file
236b2935f217749893b7034e59da3e3568928acevboxsync * PC BIOS Device.
236b2935f217749893b7034e59da3e3568928acevboxsync */
236b2935f217749893b7034e59da3e3568928acevboxsync
236b2935f217749893b7034e59da3e3568928acevboxsync/*
236b2935f217749893b7034e59da3e3568928acevboxsync * Copyright (C) 2006-2008 Sun Microsystems, Inc.
236b2935f217749893b7034e59da3e3568928acevboxsync *
236b2935f217749893b7034e59da3e3568928acevboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
236b2935f217749893b7034e59da3e3568928acevboxsync * available from http://www.virtualbox.org. This file is free software;
236b2935f217749893b7034e59da3e3568928acevboxsync * you can redistribute it and/or modify it under the terms of the GNU
236b2935f217749893b7034e59da3e3568928acevboxsync * General Public License (GPL) as published by the Free Software
236b2935f217749893b7034e59da3e3568928acevboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
236b2935f217749893b7034e59da3e3568928acevboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
236b2935f217749893b7034e59da3e3568928acevboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
236b2935f217749893b7034e59da3e3568928acevboxsync *
236b2935f217749893b7034e59da3e3568928acevboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
236b2935f217749893b7034e59da3e3568928acevboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
236b2935f217749893b7034e59da3e3568928acevboxsync * additional information or have any questions.
236b2935f217749893b7034e59da3e3568928acevboxsync */
157093a77f2752732368338110cb50fa6cd7717fvboxsync
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync/*******************************************************************************
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync* Header Files *
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync*******************************************************************************/
157093a77f2752732368338110cb50fa6cd7717fvboxsync#define LOG_GROUP LOG_GROUP_DEV_PC_BIOS
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync#include <VBox/pdmdev.h>
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync#include <VBox/mm.h>
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync#include <VBox/pgm.h>
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync#include <VBox/log.h>
157093a77f2752732368338110cb50fa6cd7717fvboxsync#include <iprt/assert.h>
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync#include <iprt/alloc.h>
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync#include <iprt/buildconfig.h>
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync#include <iprt/file.h>
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync#include <iprt/string.h>
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync#include <iprt/uuid.h>
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync#include <VBox/err.h>
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync#include <VBox/param.h>
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync#include "../Builtins.h"
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync#include "../Builtins2.h"
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync#include "DevPcBios.h"
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync#include "DevFwCommon.h"
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync#define NET_BOOT_DEVS 4
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync/** @page pg_devbios_cmos_assign CMOS Assignments (BIOS)
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync *
157093a77f2752732368338110cb50fa6cd7717fvboxsync * The BIOS uses a CMOS to store configuration data.
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync * It is currently used as follows:
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync *
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync * @verbatim
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync First CMOS bank (offsets 0x00 to 0x7f):
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync Base memory:
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync 0x15
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync 0x16
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync Extended memory:
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync 0x17
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync 0x18
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync 0x30
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync 0x31
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync Amount of memory above 16M and below 4GB in 64KB units:
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync 0x34
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync 0x35
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync Boot device (BOCHS bios specific):
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync 0x3d
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync 0x38
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync 0x3c
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync PXE debug:
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync 0x3f
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync Floppy drive type:
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync 0x10
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync Equipment byte:
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync 0x14
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync First HDD:
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync 0x19
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync 0x1e - 0x25
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync Second HDD:
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync 0x1a
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync 0x26 - 0x2d
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync Third HDD:
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync 0x67 - 0x6e
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync Fourth HDD:
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync 0x70 - 0x77
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync Extended:
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync 0x12
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync First Sata HDD:
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync 0x40 - 0x47
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync Second Sata HDD:
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync 0x48 - 0x4f
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync Third Sata HDD:
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync 0x50 - 0x57
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync Fourth Sata HDD:
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync 0x58 - 0x5f
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync Number of CPUs:
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync 0x60
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync RAM above 4G in 64KB units:
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync 0x61 - 0x65
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync Second CMOS bank (offsets 0x80 to 0xff):
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync Reserved for future use:
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync 0x80 - 0x81
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync First net boot device PCI bus/dev/fn:
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync 0x82 - 0x83
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync Second to third net boot devices:
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync 0x84 - 0x89
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync@endverbatim
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync *
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync * @todo Mark which bits are compatible with which BIOSes and
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync * which are our own definitions.
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync/*******************************************************************************
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync* Structures and Typedefs *
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync*******************************************************************************/
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync/**
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync * The boot device.
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsynctypedef enum DEVPCBIOSBOOT
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync{
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync DEVPCBIOSBOOT_NONE,
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync DEVPCBIOSBOOT_FLOPPY,
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync DEVPCBIOSBOOT_HD,
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync DEVPCBIOSBOOT_DVD,
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync DEVPCBIOSBOOT_LAN
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync} DEVPCBIOSBOOT;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync/**
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync * PC Bios instance data structure.
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsynctypedef struct DEVPCBIOS
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync{
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync /** Pointer back to the device instance. */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync PPDMDEVINS pDevIns;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync /** Boot devices (ordered). */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync DEVPCBIOSBOOT aenmBootDevice[4];
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync /** RAM size (in bytes). */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync uint64_t cbRam;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync /** RAM hole size (in bytes). */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync uint32_t cbRamHole;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync /** Bochs shutdown index. */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync uint32_t iShutdown;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync /** Floppy device. */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync char *pszFDDevice;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync /** Harddisk device. */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync char *pszHDDevice;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync /** Sata harddisk device. */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync char *pszSataDevice;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync /** LUN of the four harddisks which are emulated as IDE. */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync uint32_t iSataHDLUN[4];
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync /** Bios message buffer. */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync char szMsg[256];
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync /** Bios message buffer index. */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync uint32_t iMsg;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync /** The system BIOS ROM data. */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync uint8_t *pu8PcBios;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync /** The size of the system BIOS ROM. */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync uint64_t cbPcBios;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync /** The name of the BIOS ROM file. */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync char *pszPcBiosFile;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync /** The LAN boot ROM data. */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync uint8_t *pu8LanBoot;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync /** The name of the LAN boot ROM file. */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync char *pszLanBootFile;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync /** The size of the LAN boot ROM. */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync uint64_t cbLanBoot;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync /** The DMI tables. */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync uint8_t au8DMIPage[0x1000];
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync /** The boot countdown (in seconds). */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync uint8_t uBootDelay;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync /** I/O-APIC enabled? */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync uint8_t u8IOAPIC;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync /** PXE debug logging enabled? */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync uint8_t u8PXEDebug;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync /** PXE boot PCI bus/dev/fn list. */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync uint16_t au16NetBootDev[NET_BOOT_DEVS];
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync /** Number of logical CPUs in guest */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync uint16_t cCpus;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync} DEVPCBIOS, *PDEVPCBIOS;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync/* Attempt to guess the LCHS disk geometry from the MS-DOS master boot
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync * record (partition table). */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsyncstatic int biosGuessDiskLCHS(PPDMIBLOCK pBlock, PPDMMEDIAGEOMETRY pLCHSGeometry)
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync{
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync uint8_t aMBR[512], *p;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync int rc;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync uint32_t iEndHead, iEndSector, cLCHSCylinders, cLCHSHeads, cLCHSSectors;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync if (!pBlock)
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync return VERR_INVALID_PARAMETER;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync rc = pBlock->pfnRead(pBlock, 0, aMBR, sizeof(aMBR));
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync if (RT_FAILURE(rc))
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync return rc;
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync /* Test MBR magic number. */
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync if (aMBR[510] != 0x55 || aMBR[511] != 0xaa)
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync return VERR_INVALID_PARAMETER;
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync for (uint32_t i = 0; i < 4; i++)
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync {
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync /* Figure out the start of a partition table entry. */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync p = &aMBR[0x1be + i * 16];
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync iEndHead = p[5];
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync iEndSector = p[6] & 63;
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync if ((p[12] | p[13] | p[14] | p[15]) && iEndSector & iEndHead)
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync {
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync /* Assumption: partition terminates on a cylinder boundary. */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync cLCHSHeads = iEndHead + 1;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync cLCHSSectors = iEndSector;
157093a77f2752732368338110cb50fa6cd7717fvboxsync cLCHSCylinders = RT_MIN(1024, pBlock->pfnGetSize(pBlock) / (512 * cLCHSHeads * cLCHSSectors));
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync if (cLCHSCylinders >= 1)
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync {
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync pLCHSGeometry->cCylinders = cLCHSCylinders;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync pLCHSGeometry->cHeads = cLCHSHeads;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync pLCHSGeometry->cSectors = cLCHSSectors;
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync Log(("%s: LCHS=%d %d %d\n", __FUNCTION__, cLCHSCylinders, cLCHSHeads, cLCHSSectors));
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync return VINF_SUCCESS;
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync }
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync }
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync }
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync return VERR_INVALID_PARAMETER;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync}
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync/**
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync * Write to CMOS memory.
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync * This is used by the init complete code.
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync */
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsyncstatic void pcbiosCmosWrite(PPDMDEVINS pDevIns, int off, uint32_t u32Val)
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync{
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync Assert(off < 256);
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync Assert(u32Val < 256);
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync#if 1
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync int rc = PDMDevHlpCMOSWrite(pDevIns, off, u32Val);
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync AssertRC(rc);
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync#else
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync PVM pVM = PDMDevHlpGetVM(pDevIns);
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync IOMIOPortWrite(pVM, 0x70, off, 1);
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync IOMIOPortWrite(pVM, 0x71, u32Val, 1);
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync IOMIOPortWrite(pVM, 0x70, 0, 1);
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync#endif
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync}
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync/* -=-=-=-=-=-=- based on code from pc.c -=-=-=-=-=-=- */
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync/**
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync * Initializes the CMOS data for one harddisk.
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsyncstatic void pcbiosCmosInitHardDisk(PPDMDEVINS pDevIns, int offType, int offInfo, PCPDMMEDIAGEOMETRY pLCHSGeometry)
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync{
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync Log2(("%s: offInfo=%#x: LCHS=%d/%d/%d\n", __FUNCTION__, offInfo, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync if (offType)
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync pcbiosCmosWrite(pDevIns, offType, 48);
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync /* Cylinders low */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync pcbiosCmosWrite(pDevIns, offInfo + 0, RT_MIN(pLCHSGeometry->cCylinders, 1024) & 0xff);
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync /* Cylinders high */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync pcbiosCmosWrite(pDevIns, offInfo + 1, RT_MIN(pLCHSGeometry->cCylinders, 1024) >> 8);
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync /* Heads */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync pcbiosCmosWrite(pDevIns, offInfo + 2, pLCHSGeometry->cHeads);
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync /* Landing zone low */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync pcbiosCmosWrite(pDevIns, offInfo + 3, 0xff);
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync /* Landing zone high */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync pcbiosCmosWrite(pDevIns, offInfo + 4, 0xff);
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync /* Write precomp low */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync pcbiosCmosWrite(pDevIns, offInfo + 5, 0xff);
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync /* Write precomp high */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync pcbiosCmosWrite(pDevIns, offInfo + 6, 0xff);
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync /* Sectors */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync pcbiosCmosWrite(pDevIns, offInfo + 7, pLCHSGeometry->cSectors);
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync}
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync/**
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync * Set logical CHS geometry for a hard disk
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync *
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync * @returns VBox status code.
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync * @param pBase Base interface for the device.
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync * @param pHardDisk The hard disk.
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync * @param pLCHSGeometry Where to store the geometry settings.
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync */
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsyncstatic int setLogicalDiskGeometry(PPDMIBASE pBase, PPDMIBLOCKBIOS pHardDisk, PPDMMEDIAGEOMETRY pLCHSGeometry)
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync{
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync PDMMEDIAGEOMETRY LCHSGeometry;
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync int rc = VINF_SUCCESS;
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync rc = pHardDisk->pfnGetLCHSGeometry(pHardDisk, &LCHSGeometry);
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync if ( rc == VERR_PDM_GEOMETRY_NOT_SET
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync || LCHSGeometry.cCylinders == 0
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync || LCHSGeometry.cHeads == 0
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync || LCHSGeometry.cHeads > 255
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync || LCHSGeometry.cSectors == 0
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync || LCHSGeometry.cSectors > 63)
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync {
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync PPDMIBLOCK pBlock;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync pBlock = PDMIBASE_QUERY_INTERFACE(pBase, PDMIBLOCK);
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync /* No LCHS geometry, autodetect and set. */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync rc = biosGuessDiskLCHS(pBlock, &LCHSGeometry);
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync if (RT_FAILURE(rc))
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync {
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync /* Try if PCHS geometry works, otherwise fall back. */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync rc = pHardDisk->pfnGetPCHSGeometry(pHardDisk, &LCHSGeometry);
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync }
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync if ( RT_FAILURE(rc)
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync || LCHSGeometry.cCylinders == 0
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync || LCHSGeometry.cCylinders > 1024
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync || LCHSGeometry.cHeads == 0
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync || LCHSGeometry.cHeads > 16
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync || LCHSGeometry.cSectors == 0
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync || LCHSGeometry.cSectors > 63)
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync {
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync uint64_t cSectors = pBlock->pfnGetSize(pBlock) / 512;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync if (cSectors / 16 / 63 <= 1024)
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync {
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync LCHSGeometry.cCylinders = RT_MAX(cSectors / 16 / 63, 1);
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync LCHSGeometry.cHeads = 16;
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync }
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync else if (cSectors / 32 / 63 <= 1024)
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync {
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync LCHSGeometry.cCylinders = RT_MAX(cSectors / 32 / 63, 1);
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync LCHSGeometry.cHeads = 32;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync }
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync else if (cSectors / 64 / 63 <= 1024)
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync {
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync LCHSGeometry.cCylinders = cSectors / 64 / 63;
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync LCHSGeometry.cHeads = 64;
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync }
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync else if (cSectors / 128 / 63 <= 1024)
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync {
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync LCHSGeometry.cCylinders = cSectors / 128 / 63;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync LCHSGeometry.cHeads = 128;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync }
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync else
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync {
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync LCHSGeometry.cCylinders = RT_MIN(cSectors / 255 / 63, 1024);
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync LCHSGeometry.cHeads = 255;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync }
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync LCHSGeometry.cSectors = 63;
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync }
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync rc = pHardDisk->pfnSetLCHSGeometry(pHardDisk, &LCHSGeometry);
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync if (rc == VERR_VD_IMAGE_READ_ONLY)
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync {
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync LogRel(("DevPcBios: ATA failed to update LCHS geometry, read only\n"));
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync rc = VINF_SUCCESS;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync }
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync else if (rc == VERR_PDM_GEOMETRY_NOT_SET)
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync {
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync LogRel(("DevPcBios: ATA failed to update LCHS geometry, backend refused\n"));
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync rc = VINF_SUCCESS;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync }
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync }
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync *pLCHSGeometry = LCHSGeometry;
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync return rc;
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync}
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync/**
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync * Get BIOS boot code from enmBootDevice in order
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync *
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync * @todo r=bird: This is a rather silly function since the conversion is 1:1.
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsyncstatic uint8_t getBiosBootCode(PDEVPCBIOS pThis, unsigned iOrder)
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync{
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync switch (pThis->aenmBootDevice[iOrder])
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync {
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync case DEVPCBIOSBOOT_NONE:
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync return 0;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync case DEVPCBIOSBOOT_FLOPPY:
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync return 1;
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync case DEVPCBIOSBOOT_HD:
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync return 2;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync case DEVPCBIOSBOOT_DVD:
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync return 3;
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync case DEVPCBIOSBOOT_LAN:
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync return 4;
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync default:
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync AssertMsgFailed(("aenmBootDevice[%d]=%d\n", iOrder, pThis->aenmBootDevice[iOrder]));
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync return 0;
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync }
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync}
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync/**
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync * Init complete notification.
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync * This routine will write information needed by the bios to the CMOS.
236b2935f217749893b7034e59da3e3568928acevboxsync *
157093a77f2752732368338110cb50fa6cd7717fvboxsync * @returns VBOX status code.
157093a77f2752732368338110cb50fa6cd7717fvboxsync * @param pDevIns The device instance.
157093a77f2752732368338110cb50fa6cd7717fvboxsync * @see http://www.brl.ntt.co.jp/people/takehiko/interrupt/CMOS.LST.txt for
157093a77f2752732368338110cb50fa6cd7717fvboxsync * a description of standard and non-standard CMOS registers.
157093a77f2752732368338110cb50fa6cd7717fvboxsync */
157093a77f2752732368338110cb50fa6cd7717fvboxsyncstatic DECLCALLBACK(int) pcbiosInitComplete(PPDMDEVINS pDevIns)
157093a77f2752732368338110cb50fa6cd7717fvboxsync{
157093a77f2752732368338110cb50fa6cd7717fvboxsync PDEVPCBIOS pThis = PDMINS_2_DATA(pDevIns, PDEVPCBIOS);
157093a77f2752732368338110cb50fa6cd7717fvboxsync uint32_t u32;
157093a77f2752732368338110cb50fa6cd7717fvboxsync unsigned i;
157093a77f2752732368338110cb50fa6cd7717fvboxsync PVM pVM = PDMDevHlpGetVM(pDevIns);
157093a77f2752732368338110cb50fa6cd7717fvboxsync PPDMIBLOCKBIOS apHDs[4] = {0};
157093a77f2752732368338110cb50fa6cd7717fvboxsync PPDMIBLOCKBIOS apFDs[2] = {0};
157093a77f2752732368338110cb50fa6cd7717fvboxsync AssertRelease(pVM);
157093a77f2752732368338110cb50fa6cd7717fvboxsync LogFlow(("pcbiosInitComplete:\n"));
157093a77f2752732368338110cb50fa6cd7717fvboxsync
157093a77f2752732368338110cb50fa6cd7717fvboxsync /*
157093a77f2752732368338110cb50fa6cd7717fvboxsync * Memory sizes.
157093a77f2752732368338110cb50fa6cd7717fvboxsync */
157093a77f2752732368338110cb50fa6cd7717fvboxsync /* base memory. */
157093a77f2752732368338110cb50fa6cd7717fvboxsync 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 */
157093a77f2752732368338110cb50fa6cd7717fvboxsync pcbiosCmosWrite(pDevIns, 0x15, u32 & 0xff); /* 15h - Base Memory in K, Low Byte */
157093a77f2752732368338110cb50fa6cd7717fvboxsync pcbiosCmosWrite(pDevIns, 0x16, u32 >> 8); /* 16h - Base Memory in K, High Byte */
157093a77f2752732368338110cb50fa6cd7717fvboxsync
157093a77f2752732368338110cb50fa6cd7717fvboxsync /* Extended memory, up to 65MB */
157093a77f2752732368338110cb50fa6cd7717fvboxsync u32 = pThis->cbRam >= 65 * _1M ? 0xffff : ((uint32_t)pThis->cbRam - _1M) / _1K;
157093a77f2752732368338110cb50fa6cd7717fvboxsync pcbiosCmosWrite(pDevIns, 0x17, u32 & 0xff); /* 17h - Extended Memory in K, Low Byte */
157093a77f2752732368338110cb50fa6cd7717fvboxsync pcbiosCmosWrite(pDevIns, 0x18, u32 >> 8); /* 18h - Extended Memory in K, High Byte */
157093a77f2752732368338110cb50fa6cd7717fvboxsync pcbiosCmosWrite(pDevIns, 0x30, u32 & 0xff); /* 30h - Extended Memory in K, Low Byte */
157093a77f2752732368338110cb50fa6cd7717fvboxsync pcbiosCmosWrite(pDevIns, 0x31, u32 >> 8); /* 31h - Extended Memory in K, High Byte */
157093a77f2752732368338110cb50fa6cd7717fvboxsync
157093a77f2752732368338110cb50fa6cd7717fvboxsync /* Bochs BIOS specific? Anyway, it's the amount of memory above 16MB
157093a77f2752732368338110cb50fa6cd7717fvboxsync and below 4GB (as it can only hold 4GB+16M). We have to chop off the
157093a77f2752732368338110cb50fa6cd7717fvboxsync top 2MB or it conflict with what the ACPI tables return. (Should these
157093a77f2752732368338110cb50fa6cd7717fvboxsync be adjusted, we still have to chop it at 0xfffc0000 or it'll conflict
157093a77f2752732368338110cb50fa6cd7717fvboxsync with the high BIOS mapping.) */
157093a77f2752732368338110cb50fa6cd7717fvboxsync uint64_t const offRamHole = _4G - pThis->cbRamHole;
157093a77f2752732368338110cb50fa6cd7717fvboxsync if (pThis->cbRam > 16 * _1M)
157093a77f2752732368338110cb50fa6cd7717fvboxsync u32 = (uint32_t)( (RT_MIN(RT_MIN(pThis->cbRam, offRamHole), UINT32_C(0xffe00000)) - 16U * _1M) / _64K );
157093a77f2752732368338110cb50fa6cd7717fvboxsync else
157093a77f2752732368338110cb50fa6cd7717fvboxsync u32 = 0;
157093a77f2752732368338110cb50fa6cd7717fvboxsync pcbiosCmosWrite(pDevIns, 0x34, u32 & 0xff);
157093a77f2752732368338110cb50fa6cd7717fvboxsync pcbiosCmosWrite(pDevIns, 0x35, u32 >> 8);
157093a77f2752732368338110cb50fa6cd7717fvboxsync
157093a77f2752732368338110cb50fa6cd7717fvboxsync /* Bochs/VBox BIOS specific way of specifying memory above 4GB in 64KB units.
157093a77f2752732368338110cb50fa6cd7717fvboxsync Bochs got these in a different location which we've already used for SATA,
157093a77f2752732368338110cb50fa6cd7717fvboxsync it also lacks the last two. */
157093a77f2752732368338110cb50fa6cd7717fvboxsync uint64_t c64KBAbove4GB;
157093a77f2752732368338110cb50fa6cd7717fvboxsync if (pThis->cbRam <= offRamHole)
157093a77f2752732368338110cb50fa6cd7717fvboxsync c64KBAbove4GB = 0;
157093a77f2752732368338110cb50fa6cd7717fvboxsync else
157093a77f2752732368338110cb50fa6cd7717fvboxsync {
157093a77f2752732368338110cb50fa6cd7717fvboxsync c64KBAbove4GB = (pThis->cbRam - offRamHole) / _64K;
157093a77f2752732368338110cb50fa6cd7717fvboxsync /* Make sure it doesn't hit the limits of the current BIOS code. */
157093a77f2752732368338110cb50fa6cd7717fvboxsync AssertLogRelMsgReturn((c64KBAbove4GB >> (3 * 8)) < 255, ("%#RX64\n", c64KBAbove4GB), VERR_OUT_OF_RANGE);
157093a77f2752732368338110cb50fa6cd7717fvboxsync }
157093a77f2752732368338110cb50fa6cd7717fvboxsync pcbiosCmosWrite(pDevIns, 0x61, c64KBAbove4GB & 0xff);
157093a77f2752732368338110cb50fa6cd7717fvboxsync pcbiosCmosWrite(pDevIns, 0x62, (c64KBAbove4GB >> 8) & 0xff);
157093a77f2752732368338110cb50fa6cd7717fvboxsync pcbiosCmosWrite(pDevIns, 0x63, (c64KBAbove4GB >> 16) & 0xff);
157093a77f2752732368338110cb50fa6cd7717fvboxsync pcbiosCmosWrite(pDevIns, 0x64, (c64KBAbove4GB >> 24) & 0xff);
157093a77f2752732368338110cb50fa6cd7717fvboxsync pcbiosCmosWrite(pDevIns, 0x65, (c64KBAbove4GB >> 32) & 0xff);
157093a77f2752732368338110cb50fa6cd7717fvboxsync
157093a77f2752732368338110cb50fa6cd7717fvboxsync /*
157093a77f2752732368338110cb50fa6cd7717fvboxsync * Number of CPUs.
157093a77f2752732368338110cb50fa6cd7717fvboxsync */
157093a77f2752732368338110cb50fa6cd7717fvboxsync pcbiosCmosWrite(pDevIns, 0x60, pThis->cCpus & 0xff);
157093a77f2752732368338110cb50fa6cd7717fvboxsync
157093a77f2752732368338110cb50fa6cd7717fvboxsync /*
157093a77f2752732368338110cb50fa6cd7717fvboxsync * Bochs BIOS specifics - boot device.
157093a77f2752732368338110cb50fa6cd7717fvboxsync * We do both new and old (ami-style) settings.
157093a77f2752732368338110cb50fa6cd7717fvboxsync * See rombios.c line ~7215 (int19_function).
157093a77f2752732368338110cb50fa6cd7717fvboxsync */
157093a77f2752732368338110cb50fa6cd7717fvboxsync
157093a77f2752732368338110cb50fa6cd7717fvboxsync uint8_t reg3d = getBiosBootCode(pThis, 0) | (getBiosBootCode(pThis, 1) << 4);
157093a77f2752732368338110cb50fa6cd7717fvboxsync uint8_t reg38 = /* pcbiosCmosRead(pDevIns, 0x38) | */ getBiosBootCode(pThis, 2) << 4;
157093a77f2752732368338110cb50fa6cd7717fvboxsync /* This is an extension. Bochs BIOS normally supports only 3 boot devices. */
157093a77f2752732368338110cb50fa6cd7717fvboxsync uint8_t reg3c = getBiosBootCode(pThis, 3) | (pThis->uBootDelay << 4);
157093a77f2752732368338110cb50fa6cd7717fvboxsync pcbiosCmosWrite(pDevIns, 0x3d, reg3d);
157093a77f2752732368338110cb50fa6cd7717fvboxsync pcbiosCmosWrite(pDevIns, 0x38, reg38);
157093a77f2752732368338110cb50fa6cd7717fvboxsync pcbiosCmosWrite(pDevIns, 0x3c, reg3c);
157093a77f2752732368338110cb50fa6cd7717fvboxsync
157093a77f2752732368338110cb50fa6cd7717fvboxsync /*
157093a77f2752732368338110cb50fa6cd7717fvboxsync * PXE debug option.
157093a77f2752732368338110cb50fa6cd7717fvboxsync */
157093a77f2752732368338110cb50fa6cd7717fvboxsync pcbiosCmosWrite(pDevIns, 0x3f, pThis->u8PXEDebug);
236b2935f217749893b7034e59da3e3568928acevboxsync
236b2935f217749893b7034e59da3e3568928acevboxsync /*
157093a77f2752732368338110cb50fa6cd7717fvboxsync * Network boot device list.
157093a77f2752732368338110cb50fa6cd7717fvboxsync */
157093a77f2752732368338110cb50fa6cd7717fvboxsync for (i = 0; i < NET_BOOT_DEVS; ++i)
157093a77f2752732368338110cb50fa6cd7717fvboxsync {
157093a77f2752732368338110cb50fa6cd7717fvboxsync pcbiosCmosWrite(pDevIns, 0x82 + i * 2, pThis->au16NetBootDev[i] & 0xff);
236b2935f217749893b7034e59da3e3568928acevboxsync pcbiosCmosWrite(pDevIns, 0x83 + i * 2, pThis->au16NetBootDev[i] >> 8);
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync }
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync
157093a77f2752732368338110cb50fa6cd7717fvboxsync /*
157093a77f2752732368338110cb50fa6cd7717fvboxsync * Floppy drive type.
236b2935f217749893b7034e59da3e3568928acevboxsync */
236b2935f217749893b7034e59da3e3568928acevboxsync for (i = 0; i < RT_ELEMENTS(apFDs); i++)
157093a77f2752732368338110cb50fa6cd7717fvboxsync {
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync PPDMIBASE pBase;
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync int rc = PDMR3QueryLun(pVM, pThis->pszFDDevice, 0, i, &pBase);
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync if (RT_SUCCESS(rc))
236b2935f217749893b7034e59da3e3568928acevboxsync apFDs[i] = PDMIBASE_QUERY_INTERFACE(pBase, PDMIBLOCKBIOS);
236b2935f217749893b7034e59da3e3568928acevboxsync }
236b2935f217749893b7034e59da3e3568928acevboxsync u32 = 0;
236b2935f217749893b7034e59da3e3568928acevboxsync if (apFDs[0])
236b2935f217749893b7034e59da3e3568928acevboxsync 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));
}
}
}
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)
{
NOREF(pDevIns);
NOREF(pvUser);
NOREF(Port);
NOREF(pu32);
NOREF(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(("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;
}
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)
{
unsigned i;
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"
"DmiBIOSVendor\0"
"DmiBIOSVersion\0"
"DmiBIOSReleaseDate\0"
"DmiBIOSReleaseMajor\0"
"DmiBIOSReleaseMinor\0"
"DmiBIOSFirmwareMajor\0"
"DmiBIOSFirmwareMinor\0"
"DmiSystemFamily\0"
"DmiSystemProduct\0"
"DmiSystemSerial\0"
"DmiSystemUuid\0"
"DmiSystemVendor\0"
"DmiSystemVersion\0"
"DmiChassisVendor\0"
"DmiChassisVersion\0"
"DmiChassisSerial\0"
"DmiChassisAssetTag\0"
#ifdef VBOX_WITH_DMI_OEMSTRINGS
"DmiOEMVBoxVer\0"
"DmiOEMVBoxRev\0"
#endif
"DmiUseHostInfo\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"));
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 (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 (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;
/*
* 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);
rc = FwCommonPlantDMITable(pDevIns, pThis->au8DMIPage,
VBOX_DMI_TABLE_SIZE, &uuid, pCfg);
if (RT_FAILURE(rc))
return rc;
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,
PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "DMI tables");
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 u8PciDev;
uint8_t u8PciFn;
uint16_t u16BusDevFn;
char szIndex[] = "?";
Assert(pCfgNetBoot);
for (i = 0; i < NET_BOOT_DEVS; ++i)
{
szIndex[0] = '0' + i;
pCfgNetBootDevice = CFGMR3GetChild(pCfgNetBoot, szIndex);
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 = ((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;
}
const uint8_t *pu8PcBiosBinary = NULL;
uint64_t cbPcBiosBinary;
/*
* Determine the system BIOS ROM size, open specified ROM file in the process.
*/
RTFILE FilePcBios = NIL_RTFILE;
if (pThis->pszPcBiosFile)
{
rc = RTFileOpen(&FilePcBios, pThis->pszPcBiosFile,
RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
if (RT_SUCCESS(rc))
{
rc = RTFileGetSize(FilePcBios, &pThis->cbPcBios);
if (RT_SUCCESS(rc))
{
/* The following checks should be in sync the AssertReleaseMsg's below. */
if ( RT_ALIGN(pThis->cbPcBios, _64K) != pThis->cbPcBios
|| pThis->cbPcBios > 32 * _64K
|| pThis->cbPcBios < _64K)
rc = VERR_TOO_MUCH_DATA;
}
}
if (RT_FAILURE(rc))
{
/*
* In case of failure simply fall back to the built-in BIOS ROM.
*/
Log(("pcbiosConstruct: Failed to open system BIOS ROM file '%s', rc=%Rrc!\n", pThis->pszPcBiosFile, rc));
RTFileClose(FilePcBios);
FilePcBios = NIL_RTFILE;
MMR3HeapFree(pThis->pszPcBiosFile);
pThis->pszPcBiosFile = NULL;
}
}
/*
* Attempt to get the system BIOS ROM data from file.
*/
if (pThis->pszPcBiosFile)
{
/*
* Allocate buffer for the system BIOS ROM data.
*/
pThis->pu8PcBios = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, pThis->cbPcBios);
if (pThis->pu8PcBios)
{
rc = RTFileRead(FilePcBios, pThis->pu8PcBios, pThis->cbPcBios, NULL);
if (RT_FAILURE(rc))
{
AssertMsgFailed(("RTFileRead(,,%d,NULL) -> %Rrc\n", pThis->cbPcBios, rc));
MMR3HeapFree(pThis->pu8PcBios);
pThis->pu8PcBios = NULL;
}
rc = VINF_SUCCESS;
}
else
rc = VERR_NO_MEMORY;
}
else
pThis->pu8PcBios = NULL;
/* cleanup */
if (FilePcBios != NIL_RTFILE)
RTFileClose(FilePcBios);
/* If we were unable to get the data from file for whatever reason, fall
back to the built-in ROM image. */
uint32_t fFlags = 0;
if (pThis->pu8PcBios == NULL)
{
pu8PcBiosBinary = g_abPcBiosBinary;
cbPcBiosBinary = g_cbPcBiosBinary;
fFlags = PGMPHYS_ROM_FLAGS_PERMANENT_BINARY;
}
else
{
pu8PcBiosBinary = pThis->pu8PcBios;
cbPcBiosBinary = pThis->cbPcBios;
}
/*
* 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],
fFlags, "PC BIOS - 0xfffff");
if (RT_FAILURE(rc))
return rc;
rc = PDMDevHlpROMRegister(pDevIns, (uint32_t)-(int32_t)cbPcBiosBinary, cbPcBiosBinary, pu8PcBiosBinary,
fFlags, "PC BIOS - 0xffffffff");
if (RT_FAILURE(rc))
return rc;
#ifdef VBOX_WITH_VMI
/*
* Map the VMI BIOS into memory.
*/
AssertReleaseMsg(g_cbVmiBiosBinary == _4K, ("cbVmiBiosBinary=%#x\n", g_cbVmiBiosBinary));
rc = PDMDevHlpROMRegister(pDevIns, VBOX_VMI_BIOS_BASE, g_cbVmiBiosBinary, g_abVmiBiosBinary,
PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "VMI BIOS");
if (RT_FAILURE(rc))
return rc;
#endif /* VBOX_WITH_VMI */
/*
* Call reset to set values and stuff.
*/
pcbiosReset(pDevIns);
/*
* 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 ( RT_ALIGN(cbFileLanBoot, _4K) != cbFileLanBoot
|| cbFileLanBoot > _64K)
rc = VERR_TOO_MUCH_DATA;
}
}
if (RT_FAILURE(rc))
{
/*
* Ignore failure and fall back to the built-in LAN boot ROM.
*/
Log(("pcbiosConstruct: 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)
{
/*
* Allocate buffer for the LAN boot ROM data.
*/
pThis->pu8LanBoot = (uint8_t *)PDMDevHlpMMHeapAlloc(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)
{
pu8LanBootBinary = g_abNetBiosBinary;
cbLanBootBinary = g_cbNetBiosBinary;
}
else
{
pu8LanBootBinary = pThis->pu8LanBoot;
cbLanBootBinary = cbFileLanBoot;
}
/*
* Map the Network Boot ROM into memory.
* Currently there is a fixed mapping: 0x000c8000 to 0x000cffff contains
* the (up to) 32 kb ROM image.
*/
if (pu8LanBootBinary)
{
pThis->cbLanBoot = cbLanBootBinary;
rc = PDMDevHlpROMRegister(pDevIns, VBOX_LANBOOT_SEG << 4, cbLanBootBinary, pu8LanBootBinary,
PGMPHYS_ROM_FLAGS_SHADOWED, "Net Boot ROM");
if (RT_SUCCESS(rc))
{
rc = PDMDevHlpROMProtectShadow(pDevIns, VBOX_LANBOOT_SEG << 4, cbLanBootBinary, PGMROMPROT_READ_RAM_WRITE_RAM);
AssertRCReturn(rc, rc);
rc = PDMDevHlpPhysWrite(pDevIns, VBOX_LANBOOT_SEG << 4, pu8LanBootBinary, cbLanBootBinary);
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;
return rc;
}
/**
* 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
};