diff options
author | Felix Geyer <debfx-pkg@fobos.de> | 2010-05-08 14:05:01 +0200 |
---|---|---|
committer | Felix Geyer <debfx-pkg@fobos.de> | 2010-05-08 14:05:01 +0200 |
commit | 33961db1e2718be932cefe0b32aae173ae760cea (patch) | |
tree | 800f8bf4b1d5e4b9505a30270f0c170342abb43d /src/VBox/Devices/PC | |
parent | 4749e3a0c5d3a159d3ae751e6780b537c860923a (diff) | |
download | virtualbox-33961db1e2718be932cefe0b32aae173ae760cea.tar.gz |
Imported Upstream version 3.1.52-dfsgupstream/3.1.52-dfsg
Diffstat (limited to 'src/VBox/Devices/PC')
-rw-r--r-- | src/VBox/Devices/PC/DevAPIC.cpp | 8 | ||||
-rw-r--r-- | src/VBox/Devices/PC/DevLPC.cpp | 363 | ||||
-rw-r--r-- | src/VBox/Devices/PC/DevSMC.cpp | 487 |
3 files changed, 854 insertions, 4 deletions
diff --git a/src/VBox/Devices/PC/DevAPIC.cpp b/src/VBox/Devices/PC/DevAPIC.cpp index ae2f24ca1..077fed364 100644 --- a/src/VBox/Devices/PC/DevAPIC.cpp +++ b/src/VBox/Devices/PC/DevAPIC.cpp @@ -1,5 +1,5 @@ #ifdef VBOX -/* $Id: DevAPIC.cpp 28800 2010-04-27 08:22:32Z vboxsync $ */ +/* $Id: DevAPIC.cpp 28954 2010-05-02 07:30:18Z vboxsync $ */ /** @file * Advanced Programmable Interrupt Controller (APIC) Device and * I/O Advanced Programmable Interrupt Controller (IO-APIC) Device. @@ -895,11 +895,11 @@ PDMBOTHCBDECL(int) apicReadMSR(PPDMDEVINS pDevIns, VMCPUID idCpu, uint32_t u32Re val = 0; break; case 0x0d: - val = apic->log_dest << 24; + val = (uint64_t)apic->log_dest << 24; break; case 0x0e: /* Bottom 28 bits are always 1 */ - val = (apic->dest_mode << 28) | 0xfffffff; + val = ((uint64_t)apic->dest_mode << 28) | 0xfffffff; break; case 0x0f: val = apic->spurious_vec; @@ -918,7 +918,7 @@ PDMBOTHCBDECL(int) apicReadMSR(PPDMDEVINS pDevIns, VMCPUID idCpu, uint32_t u32Re break; case 0x30: /* Here one of the differences with regular APIC: ICR is single 64-bit register */ - val = ((uint64_t)apic->icr[0x31] << 32) | apic->icr[0x30]; + val = ((uint64_t)apic->icr[1] << 32) | apic->icr[0]; break; case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: val = apic->lvt[index - 0x32]; 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 */ diff --git a/src/VBox/Devices/PC/DevSMC.cpp b/src/VBox/Devices/PC/DevSMC.cpp new file mode 100644 index 000000000..f5825230e --- /dev/null +++ b/src/VBox/Devices/PC/DevSMC.cpp @@ -0,0 +1,487 @@ +/* $Id: DevSMC.cpp 29085 2010-05-05 14:03:59Z vboxsync $ */ +/** + * @file + * DevSMC - SMC 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: + * + * Apple SMC controller + * + * 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 + * + * ***************************************************************** + * + * In all Intel-based Apple hardware there is an SMC chip to control the + * backlight, fans and several other generic device parameters. It also + * contains the magic keys used to dongle Mac OS X to the device. + * + * This driver was mostly created by looking at the Linux AppleSMC driver + * implementation and does not support IRQ. + * + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#define LOG_GROUP LOG_GROUP_DEV_SMC +#include <VBox/pdmdev.h> +#include <VBox/log.h> +#include <VBox/stam.h> +#include <iprt/assert.h> +#include <iprt/string.h> + +#include "../Builtins.h" + +/* data port used by Apple SMC */ +#define APPLESMC_DATA_PORT 0x300 +/* command/status port used by Apple SMC */ +#define APPLESMC_CMD_PORT 0x304 +#define APPLESMC_NR_PORTS 32 /* 0x300-0x31f */ +#define APPLESMC_MAX_DATA_LENGTH 32 + +#define APPLESMC_READ_CMD 0x10 +#define APPLESMC_WRITE_CMD 0x11 +#define APPLESMC_GET_KEY_BY_INDEX_CMD 0x12 +#define APPLESMC_GET_KEY_TYPE_CMD 0x13 + +static char osk[64]; + +/** The version of the saved state. */ +#define SMC_SAVED_STATE_VERSION 1 + +typedef struct AppleSMCData +{ + uint8_t len; + const char *key; + const char *data; +} AppleSMCData; + +/* See http://www.mactel-linux.org/wiki/AppleSMC */ +static struct AppleSMCData data[] = +{ + {6, "REV ", "\0x01\0x13\0x0f\0x00\0x00\0x03"}, + {32,"OSK0", osk }, + {32,"OSK1", osk+32 }, + {1, "NATJ", "\0" }, + {1, "MSSP", "\0" }, + {1, "MSSD", "\0x3" }, + {1, "NTOK", "\0"}, + {0, NULL, NULL } +}; + +typedef struct +{ + PPDMDEVINSR3 pDevIns; + + uint8_t cmd; + uint8_t status; + uint8_t key[4]; + uint8_t read_pos; + uint8_t data_len; + uint8_t data_pos; + uint8_t data[255]; + + char* pszDeviceKey; +} SMCState; + +#ifndef VBOX_DEVICE_STRUCT_TESTCASE + +#ifdef IN_RING3 +/** + * Saves a state of the SMC device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pSSMHandle The handle to save the state to. + */ +static DECLCALLBACK(int) smcSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle) +{ + SMCState *pThis = PDMINS_2_DATA(pDevIns, SMCState *); + + /** @todo: implement serialization */ + return VINF_SUCCESS; +} + + +/** + * Loads a SMC device state. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pSSMHandle The handle to the saved state. + * @param uVersion The data unit version number. + * @param uPass The data pass. + */ +static DECLCALLBACK(int) smcLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t uVersion, uint32_t uPass) +{ + SMCState *pThis = PDMINS_2_DATA(pDevIns, SMCState *); + + if (uVersion != SMC_SAVED_STATE_VERSION) + return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION; + Assert(uPass == SSM_PASS_FINAL); NOREF(uPass); + + /** @todo: implement serialization */ + return VINF_SUCCESS; +} + +/** + * Relocation notification. + * + * @returns VBox status. + * @param pDevIns The device instance data. + * @param offDelta The delta relative to the old address. + */ +static DECLCALLBACK(void) smcRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta) +{ + SMCState *pThis = PDMINS_2_DATA(pDevIns, SMCState *); + /* SMC device lives only in R3 now, thus nothing to relocate yet */ +} + +/** + * Reset notification. + * + * @returns VBox status. + * @param pDevIns The device instance data. + */ +static DECLCALLBACK(void) smcReset(PPDMDEVINS pDevIns) +{ + SMCState *pThis = PDMINS_2_DATA(pDevIns, SMCState *); + LogFlow(("smcReset: \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) smcInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs) +{ + SMCState *pThis = PDMINS_2_DATA(pDevIns, SMCState *); +} + + +static void applesmc_fill_data(SMCState *s) +{ + struct AppleSMCData *d; + for (d=data; d->len; d++) + { + uint32_t key_data = *((uint32_t*)d->key); + uint32_t key_current = *((uint32_t*)s->key); + if (key_data == key_current) + { + Log(("APPLESMC: Key matched (%s Len=%d Data=%s)\n", d->key, d->len, d->data)); + memcpy(s->data, d->data, d->len); + return; + } + } +} + +/** + * Port I/O Handler for IN operations. + * + * @returns VBox status code. + * + * @param pDevIns The device instance. + * @param pvUser User argument - ignored. + * @param uPort Port number used for the IN operation. + * @param pu32 Where to store the result. + * @param cb Number of bytes read. + */ +PDMBOTHCBDECL(int) smcIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb) +{ + SMCState * s = PDMINS_2_DATA(pDevIns, SMCState *); + uint8_t retval = 0; + + NOREF(pvUser); + Log(("SMC port read: %x (%d)\n", Port, cb)); + + /** @todo: status code? */ + if (cb != 1) + return VERR_IOM_IOPORT_UNUSED; + + switch (Port) + { + case APPLESMC_CMD_PORT: + { + retval = s->status; + break; + } + case APPLESMC_DATA_PORT: + { + switch (s->cmd) { + case APPLESMC_READ_CMD: + if(s->data_pos < s->data_len) + { + retval = s->data[s->data_pos]; + Log(("APPLESMC: READ_DATA[%d] = %#hhx\n", s->data_pos, retval)); + s->data_pos++; + if(s->data_pos == s->data_len) + { + s->status = 0x00; + Log(("APPLESMC: EOF\n")); + } + else + s->status = 0x05; + } + } + break; + } + } + + *pu32 = retval; + + return VINF_SUCCESS; +} + + +/** + * Port I/O Handler for OUT operations. + * + * @returns VBox status code. + * + * @param pDevIns The device instance. + * @param pvUser User argument - ignored. + * @param uPort Port number used for the IN operation. + * @param u32 The value to output. + * @param cb The value size in bytes. + */ +PDMBOTHCBDECL(int) smcIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb) +{ + SMCState* s = PDMINS_2_DATA(pDevIns, SMCState *); + + NOREF(pvUser); + + Log(("SMC port write: %x (%d) %x\n", Port, cb, u32)); + /** @todo: status code? */ + if (cb != 1) + return VINF_SUCCESS; + + switch (Port) + { + case APPLESMC_CMD_PORT: + { + switch (u32) + { + case APPLESMC_READ_CMD: + s->status = 0x0c; + break; + } + s->cmd = u32; + s->read_pos = 0; + s->data_pos = 0; + break; + } + case APPLESMC_DATA_PORT: + { + switch(s->cmd) + { + case APPLESMC_READ_CMD: + if (s->read_pos < 4) + { + s->key[s->read_pos] = u32; + s->status = 0x04; + } + else + if (s->read_pos == 4) + { + s->data_len = u32; + s->status = 0x05; + s->data_pos = 0; + Log(("APPLESMC: Key = %c%c%c%c Len = %d\n", s->key[0], s->key[1], s->key[2], s->key[3], u32)); + applesmc_fill_data(s); + } + s->read_pos++; + break; + } + } + } + return VINF_SUCCESS; +} + + +/** + * @interface_method_impl{PDMDEVREG,pfnConstruct} + */ +static DECLCALLBACK(int) smcConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg) +{ + SMCState *pThis = PDMINS_2_DATA(pDevIns, SMCState *); + int rc; + Assert(iInstance == 0); + + /* + * Store state. + */ + pThis->pDevIns = pDevIns; + + /* + * Validate and read the configuration. + */ + if (!CFGMR3AreValuesValid(pCfg, + "DeviceKey\0" + )) + return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES, + N_("Configuration error: Invalid config value(s) for the SMC device")); + + /* + * Query device key + */ + rc = CFGMR3QueryStringAlloc(pCfg, "DeviceKey", &pThis->pszDeviceKey); + if (rc == VERR_CFGM_VALUE_NOT_FOUND) + { + pThis->pszDeviceKey = RTStrDup("Invalid"); + LogRel(("Invalid SMC device key\n")); + if (!pThis->pszDeviceKey) + return VERR_NO_MEMORY; + + rc = VINF_SUCCESS; + } + else if (RT_FAILURE(rc)) + return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, + N_("Configuration error: Querying \"DeviceKey\" as a string failed")); + + memcpy(osk, pThis->pszDeviceKey, RTStrNLen(pThis->pszDeviceKey, 64)); + + /* + * Register the IO ports. + */ + rc = PDMDevHlpIOPortRegister(pDevIns, APPLESMC_DATA_PORT, 1, NULL, + smcIOPortWrite, smcIOPortRead, + NULL, NULL, "SMC Data"); + if (RT_FAILURE(rc)) + return rc; + rc = PDMDevHlpIOPortRegister(pDevIns, APPLESMC_CMD_PORT, 1, NULL, + smcIOPortWrite, smcIOPortRead, + NULL, NULL, "SMC Commands"); + if (RT_FAILURE(rc)) + return rc; + + /* Register saved state management */ + rc = PDMDevHlpSSMRegister(pDevIns, SMC_SAVED_STATE_VERSION, sizeof(*pThis), smcSaveExec, smcLoadExec); + if (RT_FAILURE(rc)) + return rc; + + /* + * Initialize the device state. + */ + smcReset(pDevIns); + + /** + * @todo: Register statistics. + */ + PDMDevHlpDBGFInfoRegister(pDevIns, "smc", "Display SMC status. (no arguments)", smcInfo); + + return VINF_SUCCESS; +} + + +/** + * 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) smcDestruct(PPDMDEVINS pDevIns) +{ + SMCState* pThis = PDMINS_2_DATA(pDevIns, SMCState*); + + /* + * Free MM heap pointers. + */ + if (pThis->pszDeviceKey) + { + MMR3HeapFree(pThis->pszDeviceKey); + pThis->pszDeviceKey = NULL; + } + + return VINF_SUCCESS; +} + +/** + * The device registration structure. + */ +const PDMDEVREG g_DeviceSMC = +{ + /* u32Version */ + PDM_DEVREG_VERSION, + /* szName */ + "smc", + /* szRCMod */ + "VBoxDDGC.gc", + /* szR0Mod */ + "VBoxDDR0.r0", + /* pszDescription */ + " System Management Controller (SMC) Device", + /* 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(SMCState), + /* pfnConstruct */ + smcConstruct, + /* pfnDestruct */ + smcDestruct, + /* pfnRelocate */ + smcRelocate, + /* pfnIOCtl */ + NULL, + /* pfnPowerOn */ + NULL, + /* pfnReset */ + smcReset, + /* 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 */ |