diff options
Diffstat (limited to 'src/VBox/Devices/PC/DevLPC.cpp')
-rw-r--r-- | src/VBox/Devices/PC/DevLPC.cpp | 363 |
1 files changed, 363 insertions, 0 deletions
diff --git a/src/VBox/Devices/PC/DevLPC.cpp b/src/VBox/Devices/PC/DevLPC.cpp new file mode 100644 index 000000000..8128c92e4 --- /dev/null +++ b/src/VBox/Devices/PC/DevLPC.cpp @@ -0,0 +1,363 @@ +/* $Id: DevLPC.cpp 29085 2010-05-05 14:03:59Z vboxsync $ */ +/** @file + * DevLPC - LPC device emulation + */ +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * -------------------------------------------------------------------- + * + * This code is based on: + * + * Low Pin Count emulation + * + * Copyright (c) 2007 Alexander Graf + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * ***************************************************************** + * + * This driver emulates an ICH-7 LPC partially. The LPC is basically the + * same as the ISA-bridge in the existing PIIX implementation, but + * more recent and includes support for HPET and Power Management. + * + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#define LOG_GROUP LOG_GROUP_DEV_LPC +#include <VBox/pdmdev.h> +#include <VBox/log.h> +#include <VBox/stam.h> +#include <iprt/assert.h> +#include <iprt/string.h> + +#include "../Builtins.h" + +#define RCBA_BASE 0xFED1C000 + +typedef struct +{ + /** PCI device structure. */ + PCIDEVICE dev; + + /** Pointer to the device instance. - R3 ptr. */ + PPDMDEVINSR3 pDevIns; + + /* So far, not much of a state */ +} LPCState; + + +#ifndef VBOX_DEVICE_STRUCT_TESTCASE + + +static uint32_t rcba_ram_readl(LPCState* s, RTGCPHYS addr) +{ + Log(("rcba_read at %llx\n", (uint64_t)addr)); + int32_t iIndex = (addr - RCBA_BASE); + uint32_t value = 0; + + /* This is the HPET config pointer, HPAS in DSDT */ + switch (iIndex) + { + case 0x3404: + Log(("rcba_read HPET_CONFIG_POINTER\n")); + value = 0xf0; /* enabled at 0xfed00000 */ + break; + case 0x3410: + /* This is the HPET config pointer */ + Log(("rcba_read GCS\n")); + value = 0; + break; + default: + Log(("Unknown RCBA read\n")); + break; + } + + return value; +} + +static void rcba_ram_writel(LPCState* s, RTGCPHYS addr, uint32_t value) +{ + Log(("rcba_write %llx = %#x\n", (uint64_t)addr, value)); + int32_t iIndex = (addr - RCBA_BASE); + + switch (iIndex) + { + case 0x3410: + Log(("rcba_write GCS\n")); + break; + default: + Log(("Unknown RCBA write\n")); + break; + } +} + +/** + * I/O handler for memory-mapped read operations. + * + * @returns VBox status code. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param GCPhysAddr Physical address (in GC) where the read starts. + * @param pv Where to store the result. + * @param cb Number of bytes read. + * @thread EMT + */ +PDMBOTHCBDECL(int) lpcMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb) +{ + LPCState *s = PDMINS_2_DATA(pDevIns, LPCState*); + switch (cb) + { + case 1: + case 2: + break; + + case 4: + { + *(uint32_t*)pv = rcba_ram_readl(s, GCPhysAddr); + break; + } + + default: + AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */ + return VERR_INTERNAL_ERROR; + } + return VINF_SUCCESS; +} + +/** + * Memory mapped I/O Handler for write operations. + * + * @returns VBox status code. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param GCPhysAddr Physical address (in GC) where the read starts. + * @param pv Where to fetch the value. + * @param cb Number of bytes to write. + * @thread EMT + */ +PDMBOTHCBDECL(int) lpcMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb) +{ + LPCState *s = PDMINS_2_DATA(pDevIns, LPCState*); + + switch (cb) + { + case 1: + case 2: + break; + case 4: + { + /** @todo: locking? */ + rcba_ram_writel(s, GCPhysAddr, *(uint32_t *)pv); + break; + } + + default: + AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */ + return VERR_INTERNAL_ERROR; + } + return VINF_SUCCESS; +} + +#ifdef IN_RING3 +/** + * Reset notification. + * + * @returns VBox status. + * @param pDevIns The device instance data. + */ +static DECLCALLBACK(void) lpcReset(PPDMDEVINS pDevIns) +{ + LPCState *pThis = PDMINS_2_DATA(pDevIns, LPCState *); + LogFlow(("lpcReset: \n")); +} + +/** + * Info handler, device version. + * + * @param pDevIns Device instance which registered the info. + * @param pHlp Callback functions for doing output. + * @param pszArgs Argument string. Optional and specific to the handler. + */ +static DECLCALLBACK(void) lpcInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs) +{ + LPCState *pThis = PDMINS_2_DATA(pDevIns, LPCState *); + LogFlow(("lpcInfo: \n")); +} + +/** + * @interface_method_impl{PDMDEVREG,pfnConstruct} + */ +static DECLCALLBACK(int) lpcConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg) +{ + LPCState *pThis = PDMINS_2_DATA(pDevIns, LPCState *); + int rc; + Assert(iInstance == 0); + + pThis->pDevIns = pDevIns; + + /* + * Register the PCI device. + */ + PCIDevSetVendorId (&pThis->dev, 0x8086); /* Intel */ + PCIDevSetDeviceId (&pThis->dev, 0x27b9); + PCIDevSetCommand (&pThis->dev, 0x0007); /* master, memory and I/O */ + PCIDevSetRevisionId (&pThis->dev, 0x02); + PCIDevSetClassSub (&pThis->dev, 0x01); /* PCI-to-ISA Bridge */ + PCIDevSetClassBase (&pThis->dev, 0x06); /* Bridge */ + PCIDevSetHeaderType (&pThis->dev, 0xf0); /* ??? */ + PCIDevSetSubSystemVendorId(&pThis->dev, 0x8086); + PCIDevSetSubSystemId (&pThis->dev, 0x7270); + PCIDevSetInterruptPin (&pThis->dev, 0x03); + PCIDevSetStatus (&pThis->dev, 0x0200); /* PCI_status_devsel_medium */ + + /** @todo: rewrite using PCI accessors */ + pThis->dev.config[0x40] = 0x01; + pThis->dev.config[0x41] = 0x0b; + + pThis->dev.config[0x4c] = 0x4d; + pThis->dev.config[0x4e] = 0x03; + pThis->dev.config[0x4f] = 0x00; + + pThis->dev.config[0x60] = 0x0a; /* PCI A -> IRQ 10 */ + pThis->dev.config[0x61] = 0x0a; /* PCI B -> IRQ 10 */ + pThis->dev.config[0x62] = 0x0b; /* PCI C -> IRQ 11 */ + pThis->dev.config[0x63] = 0x0b; /* PCI D -> IRQ 11 */ + + pThis->dev.config[0x69] = 0x02; + pThis->dev.config[0x70] = 0x80; + pThis->dev.config[0x76] = 0x0c; + pThis->dev.config[0x77] = 0x0c; + pThis->dev.config[0x78] = 0x02; + pThis->dev.config[0x79] = 0x00; + pThis->dev.config[0x80] = 0x00; + pThis->dev.config[0x82] = 0x00; + pThis->dev.config[0xa0] = 0x08; + pThis->dev.config[0xa2] = 0x00; + pThis->dev.config[0xa3] = 0x00; + pThis->dev.config[0xa4] = 0x00; + pThis->dev.config[0xa5] = 0x00; + pThis->dev.config[0xa6] = 0x00; + pThis->dev.config[0xa7] = 0x00; + pThis->dev.config[0xa8] = 0x0f; + pThis->dev.config[0xaa] = 0x00; + pThis->dev.config[0xab] = 0x00; + pThis->dev.config[0xac] = 0x00; + pThis->dev.config[0xae] = 0x00; + + + /* We need to allow direct config reading from this address */ + pThis->dev.config[0xf0] = (uint8_t)(RCBA_BASE | 1); /* enabled */ + pThis->dev.config[0xf1] = (uint8_t)(RCBA_BASE >> 8); + pThis->dev.config[0xf2] = (uint8_t)(RCBA_BASE >> 16); + pThis->dev.config[0xf3] = (uint8_t)(RCBA_BASE >> 24); + + rc = PDMDevHlpPCIRegister (pDevIns, &pThis->dev); + if (RT_FAILURE(rc)) + return rc; + + /* + * Register the MMIO regions. + */ + rc = PDMDevHlpMMIORegister(pDevIns, RCBA_BASE, 0x4000, pThis, + lpcMMIOWrite, lpcMMIORead, NULL, "LPC Memory"); + if (RT_FAILURE(rc)) + return rc; + + /* No state in the LPC right now */ + + /* + * Initialize the device state. + */ + lpcReset(pDevIns); + + /** + * @todo: Register statistics. + */ + PDMDevHlpDBGFInfoRegister(pDevIns, "lpc", "Display LPC status. (no arguments)", lpcInfo); + + return VINF_SUCCESS; +} + + +/** + * The device registration structure. + */ +const PDMDEVREG g_DeviceLPC = +{ + /* u32Version */ + PDM_DEVREG_VERSION, + /* szName */ + "lpc", + /* szRCMod */ + "VBoxDDGC.gc", + /* szR0Mod */ + "VBoxDDR0.r0", + /* pszDescription */ + " Low Pin Count (LPC) Bus", + /* fFlags */ + PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64 | PDM_DEVREG_FLAGS_PAE36, + /* fClass */ + PDM_DEVREG_CLASS_MISC, + /* cMaxInstances */ + 1, + /* cbInstance */ + sizeof(LPCState), + /* pfnConstruct */ + lpcConstruct, + /* pfnDestruct */ + NULL, + /* pfnRelocate */ + NULL, + /* pfnIOCtl */ + NULL, + /* pfnPowerOn */ + NULL, + /* pfnReset */ + lpcReset, + /* pfnSuspend */ + NULL, + /* pfnResume */ + NULL, + /* pfnAttach */ + NULL, + /* pfnDetach */ + NULL, + /* pfnQueryInterface. */ + NULL, + /* pfnInitComplete */ + NULL, + /* pfnPowerOff */ + NULL, + /* pfnSoftReset */ + NULL, + /* u32VersionEnd */ + PDM_DEVREG_VERSION +}; + +#endif /* IN_RING3 */ + +#endif /* VBOX_DEVICE_STRUCT_TESTCASE */ |