[vbox-dev] Virtual TPM device

Nikolay Igotti Nikolay.Igotti at Sun.COM
Sat Oct 17 08:21:49 GMT 2009


  Hi Alberto,

Thanks for the patch. Few recommendations:
- for socket communication (as any other platform-dependent 
functionality) it's recommended to use IPRT functions
-why did you choose socket approach, not direct use of /dev/tpm ?
- when adding new device, one should also provide means to configure VM 
with or without this device
- in general, devices shall be as self-contained, as possible (and not 
rely on external libs or daemons to function).
Is it possible to have real software model of TPM chip in driver?
Ideally, driver shall work in one of two modes:
- full emulation
- passthrough to external hardware (real TPM, or some other software 
emulator)
and mode (along with other parameters) should be configurable via CFGM, 
of course.

Nikolay.


Alberto Borsetta пишет:
> Hello to all
>
> I've developed a Virtual TPM device for VirtualBox. I have worked with
> 3.0.6 release but i think it's easy to patch also the current release.
> The device implemente an Atmel TPM (there are the device driver for
> Linux and for Windows Vista/Seven) and use the TPM emulator available
> to http://tpm-emulator.berlios.de
> If you would like to test and use the vTPM device, you have to install
> the TPM emulator (be shure to change the constant TPM_COMMAND_TIMEOUT
> in tpmd.c file from 30 to 300 or more) and start it, the start a
> Virtual Machine with an OS which has the Atmel device driver and a TSS
> (TrouSerS in linux). I have test the vTPM device with the IBM
> testsuite and with tpm manager.
> Now I'm trying to change the bios to make possible the remote
> attestation and use trusted grub.
> Thanks to all for testing the system
>
>                 Alberto Borsetta
>
>
>
> diff -ruN a/.dep.inc b/.dep.inc
> --- a/.dep.inc    1970-01-01 01:00:00.000000000 +0100
> +++ b/.dep.inc    2009-10-02 10:53:16.000000000 +0200
> @@ -0,0 +1,5 @@
> +# This code depends on make tool being used
> +DEPFILES=$(wildcard $(addsuffix .d, ${OBJECTFILES}))
> +ifneq (${DEPFILES},)
> +include ${DEPFILES}
> +endif
> diff -ruN a/include/VBox/log.h b/include/VBox/log.h
> --- a/include/VBox/log.h    2009-04-27 19:54:17.000000000 +0200
> +++ b/include/VBox/log.h    2009-09-24 21:42:04.000000000 +0200
> @@ -129,6 +129,8 @@
>      LOG_GROUP_DEV_PIT,
>      /** RTC Device group. */
>      LOG_GROUP_DEV_RTC,
> +    /** TPM Device group */
> +    LOG_GROUP_DEV_TPM,
>      /** Serial Device group */
>      LOG_GROUP_DEV_SERIAL,
>      /** System Management Controller Device group. */
> @@ -163,6 +165,8 @@
>      LOG_GROUP_DRV_HOST_FLOPPY,
>      /** Host Parallel Driver group */
>      LOG_GROUP_DRV_HOST_PARALLEL,
> +    /** TPM Driver Group */
> +    LOG_GROUP_DRV_TPM,
>      /** Host Serial Driver Group */
>      LOG_GROUP_DRV_HOST_SERIAL,
>      /** The internal networking transport driver group. */
> diff -ruN a/include/VBox/pdmdev.h b/include/VBox/pdmdev.h
> --- a/include/VBox/pdmdev.h    2009-04-27 19:54:17.000000000 +0200
> +++ b/include/VBox/pdmdev.h    2009-09-23 12:23:48.000000000 +0200
> @@ -391,6 +391,8 @@
>  #define PDM_DEVREG_CLASS_SERIAL                 RT_BIT(16)
>  /** Parallel controller device */
>  #define PDM_DEVREG_CLASS_PARALLEL               RT_BIT(17)
> +/** TPM device. */
> +#define PDM_DEVREG_CLASS_TPM                    RT_BIT(18)
>  /** Misc devices (always last). */
>  #define PDM_DEVREG_CLASS_MISC                   RT_BIT(31)
>  /** @} */
> diff -ruN a/include/VBox/pdmifs.h b/include/VBox/pdmifs.h
> --- a/include/VBox/pdmifs.h    2009-04-27 19:54:17.000000000 +0200
> +++ b/include/VBox/pdmifs.h    2009-10-01 22:27:12.000000000 +0200
> @@ -69,8 +69,12 @@
>      /** PDMICHARPORT            - The char notify interface.
>   (Down)  Coupled with PDMINTERFACE_CHAR. */
>      PDMINTERFACE_CHAR_PORT,
>      /** PDMICHAR                - The char driver interface.
>   (Up)    Coupled with PDMINTERFACE_CHAR_PORT. */
> -    PDMINTERFACE_CHAR,
> -    /** PDMISTREAM              - The stream driver interface
>   (Up)    No coupling.
> +    PDMINTERFACE_CHAR,
> +    /** PDMITPMPORT             - The TPM notify interface.
>   (Down)  Coupled with PDMINTERFACE_TPM. */
> +    PDMINTERFACE_TPM_PORT,
> +    /** PDMITPM                 - The TPM driver interface.
>   (Up)    Coupled with PDMINTERFACE_TPM_PORT. */
> +    PDMINTERFACE_TPM,
> +    /** PDMISTREAM              - The stream driver interface
>   (Up)    No coupling.
>       * Used by a char driver to implement PDMINTERFACE_CHAR. */
>      PDMINTERFACE_STREAM,
>      /** PDMIBLOCKPORT           - The block notify interface
>   (Down)  Coupled with PDMINTERFACE_BLOCK. */
> @@ -1501,6 +1505,68 @@
>      DECLR3CALLBACKMEMBER(int,
> pfnNotifyStatusLinesChanged,(PPDMICHARPORT pInterface, uint32_t
> fNewStatusLines));
>  } PDMICHARPORT;
>
> +/** Pointer to a TPM device interface. */
> +typedef struct PDMITPMPORT *PPDMITPMPORT;
> +/**
> + * TPM port interface.
> + * Pair with PDMITPM.
> + */
> +typedef struct PDMITPMPORT
> +{
> +    /**
> +     * Deliver data read to the device/driver.
> +     *
> +     * @returns VBox status code.
> +     * @param   pInterface      Pointer to the interface structure
> containing the called function pointer.
> +     * @param   pvBuf           Where the read bits are stored.
> +     * @param   pcbRead         Number of bytes available for
> reading/having been read.
> +     * @thread  Any thread.
> +     */
> +    DECLR3CALLBACKMEMBER(int, pfnNotifyRead,(PPDMITPMPORT pInterface,
> const void *pvBuf, size_t *pcbRead));
> +
> +    /**
> +     * Notify the device/driver when the status lines changed.
> +     *
> +     * @returns VBox status code.
> +     * @param   pInterface      Pointer to the interface structure
> containing the called function pointer.
> +     * @param   fNewStatusLine  New state of the status line pins.
> +     * @thread  Any thread.
> +     */
> +    DECLR3CALLBACKMEMBER(int,
> pfnNotifyStatusLinesChanged,(PPDMITPMPORT pInterface, uint32_t
> fNewStatusLines));
> +} PDMITPMPORT;
> +
> +/** Pointer to a char interface. */
> +typedef struct PDMITPM *PPDMITPM;
> +/**
> + * TPM interface.
> + * Pair with PDMITPMPORT.
> + */
> +typedef struct PDMITPM
> +{
> +
> +    /**
> +     * Read bits.
> +     *
> +     * @returns VBox status code.
> +     * @param   pInterface      Pointer to the interface structure
> containing the called function pointer.
> +     * @param   pvBuf           Where to store the read bits.
> +     * @param   cbRead          Number of bytes to read/bytes actually read.
> +     * @thread  Any thread.
> +     */
> +    DECLR3CALLBACKMEMBER(int, pfnRead,(PPDMITPM pInterface, void
> *pvBuf, size_t *cbRead));
> +
> +    /**
> +     * Write bits.
> +     *
> +     * @returns VBox status code.
> +     * @param   pInterface      Pointer to the interface structure
> containing the called function pointer.
> +     * @param   pvBuf           Where to store the write bits.
> +     * @param   cbWrite         Number of bytes to write.
> +     * @thread  Any thread.
> +     */
> +    DECLR3CALLBACKMEMBER(int, pfnWrite,(PPDMITPM pInterface, const
> void *pvBuf, size_t *cbWrite));
> +
> +} PDMITPM;
>
>  /** Pointer to a char interface. */
>  typedef struct PDMICHAR *PPDMICHAR;
> diff -ruN a/Makefile.kmk b/Makefile.kmk
> --- a/Makefile.kmk    2009-04-27 21:01:29.000000000 +0200
> +++ b/Makefile.kmk    2009-09-23 12:17:44.000000000 +0200
> @@ -377,6 +377,7 @@
>      src/VBox/Devices/Networking \
>      src/VBox/Devices/PC \
>      src/VBox/Devices/PC/BIOS \
> +    src/VBox/Devices/TPM \
>      src/VBox/Devices/Parallel \
>      src/VBox/Devices/Serial \
>      src/VBox/Devices/Storage \
> diff -ruN a/src/VBox/Devices/Builtins.cpp b/src/VBox/Devices/Builtins.cpp
> --- a/src/VBox/Devices/Builtins.cpp    2009-10-08 10:19:26.000000000 +0200
> +++ b/src/VBox/Devices/Builtins.cpp    2009-09-21 16:36:00.000000000 +0200
> @@ -153,6 +153,9 @@
>      rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceSerialPort);
>      if (RT_FAILURE(rc))
>          return rc;
> +    rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceTPMPort);
> +    if (RT_FAILURE(rc))
> +        return rc;
>      rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceParallelPort);
>      if (RT_FAILURE(rc))
>          return rc;
> @@ -267,6 +270,9 @@
>      rc = pCallbacks->pfnRegister(pCallbacks, &g_DrvHostSerial);
>      if (RT_FAILURE(rc))
>          return rc;
> +    rc = pCallbacks->pfnRegister(pCallbacks, &g_DrvTPM);
> +    if (RT_FAILURE(rc))
> +        return rc;
>  #endif
>
>  #if defined(VBOX_WITH_PDM_ASYNC_COMPLETION)
> diff -ruN a/src/VBox/Devices/Builtins.h b/src/VBox/Devices/Builtins.h
> --- a/src/VBox/Devices/Builtins.h    2009-10-08 10:20:06.000000000 +0200
> +++ b/src/VBox/Devices/Builtins.h    2009-09-26 11:00:43.000000000 +0200
> @@ -61,6 +61,7 @@
>  extern const PDMDEVREG g_DeviceDMA;
>  extern const PDMDEVREG g_DeviceFloppyController;
>  extern const PDMDEVREG g_DeviceSerialPort;
> +extern const PDMDEVREG g_DeviceTPMPort;
>  extern const PDMDEVREG g_DeviceParallelPort;
>  #ifdef VBOX_WITH_AHCI
>  extern const PDMDEVREG g_DeviceAHCI;
> @@ -106,6 +107,7 @@
>  extern const PDMDRVREG g_DrvNamedPipe;
>  extern const PDMDRVREG g_DrvHostParallel;
>  extern const PDMDRVREG g_DrvHostSerial;
> +extern const PDMDRVREG g_DrvTPM;
>
>  #ifdef VBOX_WITH_USB
>  extern const PDMUSBREG g_UsbDevProxy;
> diff -ruN a/src/VBox/Devices/Makefile.kmk b/src/VBox/Devices/Makefile.kmk
> --- a/src/VBox/Devices/Makefile.kmk    2009-09-15 23:40:03.000000000 +0200
> +++ b/src/VBox/Devices/Makefile.kmk    2009-09-26 10:57:49.000000000 +0200
> @@ -278,6 +278,7 @@
>      PC/DevDMA.cpp \
>      Storage/fdc.c \
>      Serial/DevSerial.cpp \
> +    TPM/DevTPM.cpp \
>      Parallel/DevParallel.cpp
>
>  ifdef VBOX_WITH_E1000
> @@ -427,6 +428,7 @@
>      Storage/DevATA.cpp \
>      Network/DevPCNet.cpp \
>      Serial/DevSerial.cpp \
> +    TPM/DevTPM.cpp \
>      Parallel/DevParallel.cpp
>
>  ifdef VBOX_WITH_E1000
> @@ -503,6 +505,7 @@
>      Storage/DevATA.cpp \
>      Network/DevPCNet.cpp \
>      Serial/DevSerial.cpp \
> +    TPM/DevTPM.cpp \
>      Parallel/DevParallel.cpp
>
>  ifdef VBOX_WITH_E1000
> @@ -625,6 +628,7 @@
>      PC/DrvACPI.cpp \
>      Serial/DrvChar.cpp \
>      Serial/DrvNamedPipe.cpp \
> +    TPM/DrvTPM.cpp \
>      Storage/DrvBlock.cpp \
>      Storage/DrvHostBase.cpp \
>      Storage/DrvHostDVD.cpp \
> @@ -695,6 +699,7 @@
>      , $(Drivers_SOURCES)) \
>      Audio/coreaudio.c
>  Drivers_SOURCES.darwin = \
> +    TPM/DrvTPM.cpp \
>      Serial/DrvHostSerial.cpp
>  endif # darwin
>
> @@ -734,6 +739,7 @@
>      Network/DrvTAP.cpp \
>      Audio/ossaudio.c \
>      Parallel/DrvHostParallel.cpp \
> +    TPM/DrvTPM.cpp \
>      Serial/DrvHostSerial.cpp
>
>  ifeq ($(KBUILD_TARGET),os2)
> @@ -750,6 +756,7 @@
>      Audio/solaudio.c \
>      Storage/DrvHostBase.cpp \
>      Storage/DrvHostDVD.cpp \
> +    TPM/DrvTPM.cpp \
>      Serial/DrvHostSerial.cpp
>   ifdef VBOX_WITH_CROSSBOW
>    Drivers_SOURCES += Network/solaris/vbox-libdlpi.cpp
> @@ -762,6 +769,7 @@
>
>  Drivers_SOURCES.win   = \
>      Audio/dsoundaudio.c \
> +    TPM/DrvTPM.cpp \
>      Serial/DrvHostSerial.cpp
>
>  if defined(VBOX_WITH_NETFLT)
> diff -ruN a/src/VBox/Devices/TPM/DevTPM.cpp b/src/VBox/Devices/TPM/DevTPM.cpp
> --- a/src/VBox/Devices/TPM/DevTPM.cpp    1970-01-01 01:00:00.000000000 +0100
> +++ b/src/VBox/Devices/TPM/DevTPM.cpp    2009-10-03 01:27:57.000000000 +0200
> @@ -0,0 +1,748 @@
> +/*******************************************************************************
> +*   Header Files
>          *
> +*******************************************************************************/
> +#define LOG_GROUP LOG_GROUP_DEV_TPM
> +#include <VBox/pdmdev.h>
> +#include <iprt/assert.h>
> +#include <iprt/uuid.h>
> +#include <iprt/string.h>
> +#include <iprt/semaphore.h>
> +#include <iprt/critsect.h>
> +
> +#include "../Builtins.h"
> +
> +/*******************************************************************************
> +*   Defined Constants And Macros
>          *
> +*******************************************************************************/
> +
> +#define TPM_SAVED_STATE_VERSION        1
> +
> +#define TPM_MAX_PKT            2048
> +
> +#define TPM_ADDR            0x4E
> +/* just choose a free port */
> +#define TPM_PORT_LO             0x00
> +#define TPM_PORT_HI             0x67
> +#define TPM_PORT ((TPM_PORT_HI << 8) | TPM_PORT_LO)
> +
> +/* write status bits */
> +enum tpm_atmel_write_status {
> +        ATML_STATUS_ABORT = 0x01,
> +        ATML_STATUS_LASTBYTE = 0x04
> +};
> +
> +/* read status bits */
> +enum tpm_atmel_read_status {
> +        ATML_STATUS_BUSY = 0x01,
> +        ATML_STATUS_DATA_AVAIL = 0x02,
> +        ATML_STATUS_REWRITE = 0x04,
> +        ATML_STATUS_READY = 0x08
> +};
> +
> +/*******************************************************************************
> +*   Structures and Typedefs
>          *
> +*******************************************************************************/
> +
> +typedef struct TPMSTATE {
> +
> +    /** Access critical section. */
> +    PDMCRITSECT                     CritSect;
> +    /** Pointer to the device instance - R3 Ptr. */
> +    PPDMDEVINSR3                    pDevInsR3;
> +    /** Pointer to the device instance - R0 Ptr. */
> +    PPDMDEVINSR0                    pDevInsR0;
> +    /** Pointer to the device instance - RC Ptr. */
> +    PPDMDEVINSRC                    pDevInsRC;
> +    RTRCPTR                         Alignment0; /**< Alignment. */
> +    /** The base interface. */
> +    PDMIBASE                        IBase;
> +    /** The character port interface. */
> +    PDMITPMPORT                     ICharPort;
> +    /** Pointer to the attached base driver. */
> +    R3PTRTYPE(PPDMIBASE)            pDrvBase;
> +    /** Pointer to the attached character driver. */
> +    R3PTRTYPE(PPDMITPM)             pDrvTPM;
> +
> +    RTSEMEVENT                      ReceiveSem;
> +
> +    bool                            fGCEnabled;
> +    bool                            fR0Enabled;
> +    bool                            fYieldOnLSRRead;
> +
> +    unsigned char             last_init_input;
> +    unsigned char             last_status_input;
> +    unsigned char                   send_data[TPM_MAX_PKT];
> +    unsigned char                   recv_data[TPM_MAX_PKT];
> +    unsigned int                    send_data_index;
> +    unsigned int                    recv_data_pos;
> +    unsigned int                    recv_data_length;
> +    /* boolean flags */
> +    int                             data_to_send;
> +    int                             data_to_recv;
> +
> +} tpmState;
> +
> +
> +#ifndef VBOX_DEVICE_STRUCT_TESTCASE
> +
> +#define PDMIBASE_2_TPMSTATE(pInstance)       ( (tpmState
> *)((uintptr_t)(pInterface) - RT_OFFSETOF(tpmState, IBase)) )
> +
> +#define PDMICHARPORT_2_TPMSTATE(pInstance)   ( (tpmState
> *)((uintptr_t)(pInterface) - RT_OFFSETOF(tpmState, ICharPort)) )
> +
> +/*******************************************************************************/
> +/*                          Internal Functions
>          */
> +/*******************************************************************************/
> +
> +__BEGIN_DECLS
> +PDMBOTHCBDECL(int) TPMIOPortRead(PPDMDEVINS pDevIns, void *pvUser,
> RTIOPORT Port, uint32_t *pu32, unsigned cb);
> +PDMBOTHCBDECL(int) TPMIOPortWrite(PPDMDEVINS pDevIns, void *pvUser,
> RTIOPORT Port, uint32_t u32, unsigned cb);
> +PDMBOTHCBDECL(int) TPMinitPortRead(PPDMDEVINS pDevIns, void *pvUser,
> RTIOPORT Port, uint32_t *pu32, unsigned cb);
> +PDMBOTHCBDECL(int) TPMinitPortWrite(PPDMDEVINS pDevIns, void *pvUser,
> RTIOPORT Port, uint32_t u32, unsigned cb);
> +__END_DECLS
> +
> +#ifdef IN_RING3
> +
> +/**
> + * Read a byte from tpm internal buffer
> + */
> +
> +static uint32_t tpm_ioport_read_data(void *opaque, uint32_t addr)
> +{
> +    tpmState* s=(tpmState*)opaque;
> +    if (s->recv_data_pos >= s->recv_data_length) {
> +        return 0;
> +    }
> +    return s->recv_data[s->recv_data_pos++];
> +}
> +
> +/**
> + * Write a byte to tpm internal buffer
> + */
> +
> +static void tpm_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
> +{
> +    tpmState* s=(tpmState*)opaque;
> +    if (s->data_to_recv) {
> +        return;
> +    }
> +    s->send_data[s->send_data_index++] = (char) (val & 0xFF);
> +    s->data_to_send = 1;
> +}
> +
> +/**
> + * Read status data from tpm
> + */
> +
> +static uint32_t tpm_ioport_read_status(void *opaque, uint32_t addr)
> +{
> +    tpmState*      s=(tpmState*)opaque;
> +    unsigned char status;
> +
> +    status = 0;
> +/*
> + * This is a bit unclean: On the first status request we trigger sending
> + * the data to the tpm.
> + */
> +    if (s->data_to_send) {
> +        if (s->pDrvTPM->pfnWrite(s->pDrvTPM, s->send_data,
> &s->send_data_index) != VINF_SUCCESS) {
> +            LogRel(("TPM: Failed to write data to tpm!\n"));
> +            return ATML_STATUS_BUSY;
> +        }
> +        s->send_data_index = 0;
> +        s->recv_data_pos = 0;
> +        s->recv_data_length = 0;
> +        s->data_to_send = 0;
> +        s->data_to_recv = 1;
> +    }
> +    if (s->data_to_recv) {
> +        if (s->pDrvTPM->pfnRead(s->pDrvTPM, s->recv_data,
> &s->recv_data_length) != VINF_SUCCESS) {
> +            LogRel(("TPM: Failed to read data from tpm!\n"));
> +            return ATML_STATUS_BUSY;
> +        }
> +        s->recv_data_pos = 0;
> +        s->data_to_recv = 0;
> +    }
> +
> +    if (s->recv_data_length > s->recv_data_pos)
> +        status |= ATML_STATUS_DATA_AVAIL;
> +    if (s->data_to_recv)
> +        status |= ATML_STATUS_BUSY;
> +    if (!status)
> +        status = ATML_STATUS_READY;
> +
> +    return status;
> +}
> +
> +/**
> + * Write status data to tpm
> + */
> +
> +static void tpm_ioport_write_status(void *opaque, uint32_t addr, uint32_t val)
> +{
> +    tpmState* s=(tpmState*)opaque;
> +    s->last_status_input = (char) (val & 0xFF);
> +}
> +
> +/**
> + * Read init data from tpm
> + */
> +
> +static uint32_t tpm_ioport_read_init(void *opaque, uint32_t addr, int *pRC)
> +{
> +    tpmState* s=(tpmState*)opaque;
> +
> +    *pRC = VINF_SUCCESS;
> +    switch (s->last_init_input) {
> +    /* see atmel_verify_tpm11() in the linux device driver sources */
> +        case 0:
> +        case 1:
> +            return 1;
> +        case 4:
> +            return 'A';
> +        case 5:
> +            return 'T';
> +        case 6:
> +            return 'M';
> +        case 7:
> +            return 'L';
> +        case 8:
> +            return TPM_PORT_LO;
> +        case 9:
> +            return TPM_PORT_HI;
> +    }
> +
> +    return 0;
> +}
> +
> +/**
> + * Write init data to tpm
> + */
> +
> +static void tpm_ioport_write_init(void *opaque, uint32_t addr, uint32_t val)
> +{
> +    tpmState* s=(tpmState*)opaque;
> +    s->last_init_input = (char) (val & 0xFF);
> +}
> +
> +/**
> + * Read data from tpm
> + */
> +
> +static uint32_t tpm_ioport_read(void *opaque, uint32_t addr, int *pRC)
> +{
> +    tpmState* s=(tpmState*)opaque;
> +    uint32_t ret = ~0U;
> +
> +    *pRC = VINF_SUCCESS;
> +
> +    addr &= 1;
> +    switch(addr) {
> +    default:
> +    case 0:
> +    ret = tpm_ioport_read_data(s, addr);
> +        break;
> +    case 1:
> +    ret = tpm_ioport_read_status(s, addr);
> +        break;
> +    }
> +
> +    return ret;
> +}
> +
> +/**
> + * Write data to tpm
> + */
> +
> +static int tpm_ioport_write(void *opaque, uint32_t addr, uint32_t val)
> +{
> +    tpmState*     s=(tpmState*)opaque;
> +    unsigned char ch;
> +
> +    addr &= 1;
> +
> +    switch(addr) {
> +    default:
> +    case 0:
> +        tpm_ioport_write_data(s, addr, val);
> +        break;
> +    case 1:
> +    tpm_ioport_write_status(s, addr, val);
> +        break;
> +    }
> +    return VINF_SUCCESS;
> +}
> +
> +/****************************************************************************/
> +/*                      VirtualBox code start                               */
> +/****************************************************************************/
> +
> +/**
> + * Implements the TPM port interface
> + */
> +
> +static DECLCALLBACK(int) TPMNotifyRead(PPDMITPMPORT pInterface, const
> void *pvBuf, size_t *pcbRead)
> +{
> +    return VINF_SUCCESS;
> +}
> +
> +static DECLCALLBACK(int) TPMNotifyStatusLinesChanged(PPDMITPMPORT
> pInterface, uint32_t newStatusLines)
> +{
> +    return VINF_SUCCESS;
> +}
> +
> +/**
> + * Port I/O Handler for IN operations.
> + *
> + * @returns VBox status code.
> + *
> + * @param   pDevIns     The device instance.
> + * @param   pvUser      User argument.
> + * @param   Port        Port number used for the IN operation.
> + * @param   u32         The value in input.
> + * @param   cb          The value size in bytes.
> + */
> +PDMBOTHCBDECL(int) TPMIOPortRead(PPDMDEVINS pDevIns, void *pvUser,
> +                                    RTIOPORT Port, uint32_t *pu32, unsigned cb)
> +{
> +    tpmState     *s = PDMINS_2_DATA(pDevIns, tpmState *);
> +    int          rc = VINF_SUCCESS;
> +
> +    if (cb == 1)
> +    {
> +        rc = PDMCritSectEnter(&s->CritSect, VINF_IOM_HC_IOPORT_READ);
> +        if (rc == VINF_SUCCESS)
> +        {
> +            *pu32 = tpm_ioport_read(s, Port, &rc);
> +            LogRel(("%s: port=%#06x val=%#04x\n", __FUNCTION__, Port, *pu32));
> +            PDMCritSectLeave(&s->CritSect);
> +        }
> +    }
> +    else
> +        rc = VERR_IOM_IOPORT_UNUSED;
> +
> +    return rc;
> +}
> +
> +/**
> + * Port I/O Handler for OUT operations.
> + *
> + * @returns VBox status code.
> + *
> + * @param   pDevIns     The device instance.
> + * @param   pvUser      User argument.
> + * @param   Port        Port number used for the OUT operation.
> + * @param   u32         The value to output.
> + * @param   cb          The value size in bytes.
> + */
> +PDMBOTHCBDECL(int) TPMIOPortWrite(PPDMDEVINS pDevIns, void *pvUser,
> +                                     RTIOPORT Port, uint32_t u32, unsigned cb)
> +{
> +    tpmState     *s = PDMINS_2_DATA(pDevIns, tpmState *);
> +    int          rc = VINF_SUCCESS;
> +
> +    if (cb == 1)
> +    {
> +        rc = PDMCritSectEnter(&s->CritSect, VINF_IOM_HC_IOPORT_WRITE);
> +        if (rc == VINF_SUCCESS)
> +        {
> +            LogRel(("%s: port=%#06x val=%#04x\n", __FUNCTION__, Port, u32));
> +            rc = tpm_ioport_write(s, Port, u32);
> +            PDMCritSectLeave(&s->CritSect);
> +        }
> +    }
> +    else
> +        LogRel(("%s: failed to write data. port=%#06x cb=%d
> u32=%#04x", __FUNCTION__, Port, cb, u32));
> +
> +    return rc;
> +}
> +
> +/**
> + * Port I/O Handler for read init operations.
> + *
> + * @returns VBox status code.
> + *
> + * @param   pDevIns     The device instance.
> + * @param   pvUser      User argument.
> + * @param   Port        Port number used for the IN operation.
> + * @param   u32         The value in input.
> + * @param   cb          The value size in bytes.
> + */
> +PDMBOTHCBDECL(int) TPMinitPortRead(PPDMDEVINS pDevIns, void *pvUser,
> RTIOPORT Port, uint32_t *pu32, unsigned cb)
> +{
> +    tpmState     *s = PDMINS_2_DATA(pDevIns, tpmState *);
> +    int          rc = VINF_SUCCESS;
> +
> +    if (cb == 1)
> +    {
> +        rc = PDMCritSectEnter(&s->CritSect, VINF_IOM_HC_IOPORT_READ);
> +        if (rc == VINF_SUCCESS)
> +        {
> +            *pu32 = tpm_ioport_read_init(s, Port, &rc);
> +            LogRel(("%s: port=%#06x val=%#04x\n", __FUNCTION__, Port, *pu32));
> +            PDMCritSectLeave(&s->CritSect);
> +        }
> +    }
> +    else
> +        rc = VERR_IOM_IOPORT_UNUSED;
> +
> +    return rc;
> +}
> +
> +/**
> + * Port I/O Handler for write init operations.
> + *
> + * @returns VBox status code.
> + *
> + * @param   pDevIns     The device instance.
> + * @param   pvUser      User argument.
> + * @param   Port        Port number used for the OUT operation.
> + * @param   u32         The value to output.
> + * @param   cb          The value size in bytes.
> + */
> +PDMBOTHCBDECL(int) TPMinitPortWrite(PPDMDEVINS pDevIns, void *pvUser,
> RTIOPORT Port, uint32_t u32, unsigned cb)
> +{
> +    tpmState     *s = PDMINS_2_DATA(pDevIns, tpmState *);
> +    int          rc = VINF_SUCCESS;
> +
> +    if (cb == 1)
> +    {
> +        rc = PDMCritSectEnter(&s->CritSect, VINF_IOM_HC_IOPORT_WRITE);
> +        if (rc == VINF_SUCCESS)
> +        {
> +            LogRel(("%s: port=%#06x val=%#04x\n", __FUNCTION__, Port, u32));
> +            tpm_ioport_write_init(s, Port, u32);
> +            PDMCritSectLeave(&s->CritSect);
> +        }
> +    }
> +    else
> +        LogRel(("%s: failed to write init. port=%#x cb=%d u32=%#x\n",
> __FUNCTION__, Port, cb, u32));
> +
> +    return rc;
> +}
> +
> +/**
> + * Loads a saved TPM port device state.
> + *
> + * @returns VBox status code.
> + * @param   pDevIns     The device instance.
> + * @param   pSSMHandle  The handle to the saved state.
> + * @param   u32Version  The data unit version number.
> + */
> +static DECLCALLBACK(int) TPMLoadExec(PPDMDEVINS pDevIns,
> +                                        PSSMHANDLE pSSMHandle,
> +                                        uint32_t u32Version)
> +{
> +    tpmState *s = PDMINS_2_DATA(pDevIns, tpmState *);
> +
> +    if (u32Version != TPM_SAVED_STATE_VERSION)
> +        return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
> +
> +    SSMR3GetU8(pSSMHandle, &s->last_init_input);
> +    SSMR3GetU8(pSSMHandle, &s->last_status_input);
> +
> +    SSMR3GetMem(pSSMHandle, &s->send_data, TPM_MAX_PKT);
> +    SSMR3GetMem(pSSMHandle, &s->recv_data, TPM_MAX_PKT);
> +
> +    SSMR3GetU32(pSSMHandle, &s->send_data_index);
> +    SSMR3GetU32(pSSMHandle, &s->recv_data_pos);
> +    SSMR3GetU32(pSSMHandle, &s->recv_data_length);
> +
> +    SSMR3GetS32(pSSMHandle, &s->data_to_send);
> +    SSMR3GetS32(pSSMHandle, &s->data_to_recv);
> +
> +    return VINF_SUCCESS;
> +}
> +
> +/**
> + * Saves a state of the TPM port device.
> + *
> + * @returns VBox status code.
> + * @param   pDevIns     The device instance.
> + * @param   pSSMHandle  The handle to save the state to.
> + */
> +static DECLCALLBACK(int) TPMSaveExec(PPDMDEVINS pDevIns,
> +                                        PSSMHANDLE pSSMHandle)
> +{
> +    tpmState *s = PDMINS_2_DATA(pDevIns, tpmState *);
> +
> +    SSMR3PutU8(pSSMHandle, s->last_init_input);
> +    SSMR3PutU8(pSSMHandle, s->last_status_input);
> +
> +    SSMR3PutMem(pSSMHandle, s->send_data, TPM_MAX_PKT);
> +    SSMR3PutMem(pSSMHandle, s->recv_data, TPM_MAX_PKT);
> +
> +    SSMR3PutU32(pSSMHandle, s->send_data_index);
> +    SSMR3PutU32(pSSMHandle, s->recv_data_pos);
> +    SSMR3PutU32(pSSMHandle, s->recv_data_length);
> +
> +    SSMR3PutS32(pSSMHandle, s->data_to_send);
> +    SSMR3PutS32(pSSMHandle, s->data_to_recv);
> +
> +    return SSMR3PutU32(pSSMHandle, ~0); /* sanity/terminator */
> +}
> +
> +/**
> + * @copydoc FNPDMDEVRELOCATE
> + */
> +static DECLCALLBACK(void) TPMRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
> +{
> +    tpmState *s = PDMINS_2_DATA(pDevIns, tpmState *);
> +    s->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
> +}
> +
> +
> +/**
> + * @copyfrom PIBASE::pfnqueryInterface
> + */
> +static DECLCALLBACK(void *) TPMQueryInterface(PPDMIBASE pInterface,
> PDMINTERFACE enmInterface)
> +{
> +    tpmState *s = PDMIBASE_2_TPMSTATE(pInterface);
> +    switch (enmInterface)
> +    {
> +        case PDMINTERFACE_BASE:
> +            return &s->IBase;
> +        case PDMINTERFACE_TPM_PORT:
> +            return &s->ICharPort;
> +        default:
> +            return NULL;
> +    }
> +}
> +
> +/**
> + * 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.
> + *
> + * @returns VBox status.
> + * @param   pDevIns     The device instance data.
> + */
> +static DECLCALLBACK(int) TPMDestruct(PPDMDEVINS pDevIns)
> +{
> +    tpmState *s = PDMINS_2_DATA(pDevIns, tpmState *);
> +
> +    RTSemEventDestroy(s->ReceiveSem);
> +    s->ReceiveSem = NIL_RTSEMEVENT;
> +
> +    PDMR3CritSectDelete(&s->CritSect);
> +    return VINF_SUCCESS;
> +}
> +
> +/**
> + * Construct a device instance for a VM.
> + *
> + * @returns VBox status.
> + * @param   pDevIns     The device instance data.
> + *                      If the registration structure is needed,
> pDevIns->pDevReg points to it.
> + * @param   iInstance   Instance number. Use this to figure out which
> registers and such to use.
> + *                      The device number is also found in
> pDevIns->iInstance, but since it's
> + *                      likely to be freqently used PDM passes it as parameter.
> + * @param   pCfgHandle  Configuration node handle for the device. Use
> this to obtain the configuration
> + *                      of the device instance. It's also found in
> pDevIns->pCfgHandle, but like
> + *                      iInstance it's expected to be used a bit in
> this function.
> + */
> +static DECLCALLBACK(int) TPMConstruct(PPDMDEVINS pDevIns,
> +                                         int iInstance,
> +                                         PCFGMNODE pCfgHandle)
> +{
> +    int            rc;
> +    tpmState          *s = PDMINS_2_DATA(pDevIns, tpmState*);
> +
> +    Assert(iInstance < 4);
> +
> +    /*
> +     * Initialize the instance data.
> +     */
> +
> +    s->pDevInsR3 = pDevIns;
> +    s->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
> +    s->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
> +    s->ReceiveSem = NIL_RTSEMEVENT;
> +
> +    /* IBase */
> +    s->IBase.pfnQueryInterface = TPMQueryInterface;
> +
> +    /* ICharPort */
> +    s->ICharPort.pfnNotifyRead = TPMNotifyRead;
> +    s->ICharPort.pfnNotifyStatusLinesChanged = TPMNotifyStatusLinesChanged;
> +
> +    /*
> +     * Initialize critical section and the semaphore.
> +     * This must of course be done before attaching drivers or
> anything else which can call us back..
> +     */
> +
> +    char szName[24];
> +    RTStrPrintf(szName, sizeof(szName), "TPM#%d", iInstance);
> +    rc = PDMDevHlpCritSectInit(pDevIns, &s->CritSect, szName);
> +    if (RT_FAILURE(rc))
> +        return rc;
> +
> +    rc = RTSemEventCreate(&s->ReceiveSem);
> +    AssertRC(rc);
> +
> +    /*
> +     * Register the I/O ports.
> +     */
> +
> +    rc = PDMDevHlpIOPortRegister(pDevIns, TPM_PORT, 8, 0,
> +                                 TPMIOPortWrite, TPMIOPortRead,
> +                                 NULL, NULL, "TPM");
> +    if (RT_FAILURE(rc))
> +    {
> +    LogRel(("%s: failed to register tpm IO port. rc=%Rrc\n",
> __FUNCTION__, rc));
> +        return rc;
> +    }
> +
> +    if (s->fGCEnabled)
> +        rc = PDMDevHlpIOPortRegisterGC(pDevIns, TPM_PORT, 8, 0,
> "TPMIOPortWrite",
> +                                      "TPMIOPortRead", NULL, NULL, "TPM");
> +
> +    if (s->fR0Enabled)
> +        rc = PDMDevHlpIOPortRegisterR0(pDevIns, TPM_PORT, 8, 0,
> "TPMIOPortWrite",
> +                                      "TPMIOPortRead", NULL, NULL, "TPM");
> +
> +    /*
> +     * Register the init ports.
> +     */
> +
> +    rc = PDMDevHlpIOPortRegister(pDevIns, TPM_ADDR, 8, 0,
> +                                 TPMinitPortWrite, TPMinitPortRead,
> +                                 NULL, NULL, "TPM_init");
> +    if (RT_FAILURE(rc))
> +    {
> +    LogRel(("%s: failed to register tpm init port. rc=%Rrc\n",
> __FUNCTION__, rc));
> +        return rc;
> +    }
> +
> +    if (s->fGCEnabled)
> +        rc = PDMDevHlpIOPortRegisterGC(pDevIns, TPM_ADDR, 8, 0,
> "TPMinitPortWrite",
> +                                      "TPMinitPortRead", NULL, NULL,
> "TPM_init");
> +
> +    if (s->fR0Enabled)
> +        rc = PDMDevHlpIOPortRegisterR0(pDevIns, TPM_ADDR, 8, 0,
> "TPMinitPortWrite",
> +                                      "TPMinitPortRead", NULL, NULL,
> "TPM_init");
> +
> +    /*
> +     * Saved state.
> +     */
> +
> +    rc = PDMDevHlpSSMRegister(
> +        pDevIns,                /* pDevIns */
> +        pDevIns->pDevReg->szDeviceName, /* pszName */
> +        iInstance,              /* u32Instance */
> +        TPM_SAVED_STATE_VERSION, /* u32Version */
> +        sizeof (*s),        /* cbGuess */
> +        NULL,                   /* pfnSavePrep */
> +        TPMSaveExec,            /* pfnSaveExec */
> +        NULL,                   /* pfnSaveDone */
> +        NULL,                   /* pfnLoadPrep */
> +        TPMLoadExec,            /* pfnLoadExec */
> +        NULL                    /* pfnLoadDone */
> +        );
> +    if (RT_FAILURE(rc))
> +    {
> +    LogRel(("%s: failed to register tpm saved state manager port.
> rc=%Rrc\n", __FUNCTION__, rc));
> +        return rc;
> +    }
> +
> +    /*
> +     * Attach the char driver and get the interfaces.
> +     * For now no run-time changes are supported.
> +     */
> +
> +    rc = PDMDevHlpDriverAttach(pDevIns, 0, &s->IBase, &s->pDrvBase,
> "TPM Char");
> +    if (RT_SUCCESS(rc))
> +    {
> +        s->pDrvTPM = (PDMITPM
> *)s->pDrvBase->pfnQueryInterface(s->pDrvBase, PDMINTERFACE_TPM);
> +        if (!s->pDrvTPM)
> +        {
> +            LogRel(("%s: failed to configure char interface\n", __FUNCTION__));
> +            return VERR_PDM_MISSING_INTERFACE;
> +        }
> +    }
> +    else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
> +    {
> +        s->pDrvBase = NULL;
> +        s->pDrvTPM  = NULL;
> +        LogRel(("%s: no tpm unit available\n", __FUNCTION__));
> +    }
> +    else
> +    {
> +        LogRel(("%s: failed to attach to char driver. rc=%Rrc\n",
> __FUNCTION__, rc));
> +        return rc;
> +    }
> +
> +    /*
> +     * Initialize tpmState
> +     */
> +
> +    s->last_init_input = 0;
> +    s->last_status_input = 0;
> +    s->send_data_index = 0;
> +    s->recv_data_length = 0;
> +    s->recv_data_pos = 0;
> +    s->data_to_send = 0;
> +    s->data_to_recv = 0;
> +
> +    return VINF_SUCCESS;
> +}
> +
> +/**
> + * The device registration structure.
> + */
> +const PDMDEVREG g_DeviceTPMPort =
> +{
> +    /* u32Version */
> +    PDM_DEVREG_VERSION,
> +    /* szDeviceName */
> +    "TPM",
> +    /* szRCMod */
> +    "VBoxDDGC.gc",
> +    /* szR0Mod */
> +    "VBoxDDR0.r0",
> +    /* pszDescription */
> +    "Trusted Platform Module",
> +    /* fFlags */
> +    PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
> +    /* fClass */
> +    PDM_DEVREG_CLASS_TPM,
> +    /* cMaxInstances */
> +    1,
> +    /* cbInstance */
> +    sizeof(tpmState),
> +    /* pfnConstruct */
> +    TPMConstruct,
> +    /* pfnDestruct */
> +    TPMDestruct,
> +    /* pfnRelocate */
> +    TPMRelocate,
> +    /* pfnIOCtl */
> +    NULL,
> +    /* pfnPowerOn */
> +    NULL,
> +    /* pfnReset */
> +    NULL,
> +    /* 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 -ruN a/src/VBox/Devices/TPM/DrvTPM.cpp b/src/VBox/Devices/TPM/DrvTPM.cpp
> --- a/src/VBox/Devices/TPM/DrvTPM.cpp    1970-01-01 01:00:00.000000000 +0100
> +++ b/src/VBox/Devices/TPM/DrvTPM.cpp    2009-10-10 13:59:06.000000000 +0200
> @@ -0,0 +1,300 @@
> +/** @file DrvTPM.cpp
> + *
> + * VBox TPM Driver
> + */
> +
> +
> +/*******************************************************************************
> +*   Header Files
>          *
> +*******************************************************************************/
> +
> +#define LOG_GROUP            LOG_GROUP_DRV_TPM
> +
> +#define TPM_MAX_PKT            2048
> +
> +#include <VBox/pdmdrv.h>
> +#include <iprt/assert.h>
> +#include <iprt/file.h>
> +#include <iprt/stream.h>
> +#include <iprt/alloc.h>
> +#include <iprt/string.h>
> +#include <iprt/semaphore.h>
> +
> +#include "../Builtins.h"
> +
> +#include <errno.h>
> +#include <unistd.h>
> +#include <sys/types.h>
> +#include <sys/socket.h>
> +#include <sys/un.h>
> +
> +/*******************************************************************************
> +*   Structures and Typedefs
>          *
> +*******************************************************************************/
> +
> +/**
> + * TPM driver instance data.
> + */
> +typedef struct TPMDRV
> +{
> +    /** Pointer to the driver instance. */
> +    PPDMDRVINS          pDrvIns;
> +    /** Pointer to the char port interface of the driver/device above us. */
> +    PPDMITPMPORT        pCharPort;
> +    /** Our host device interface. */
> +    PDMITPM             IStream;
> +    /** Our host device port interface. */
> +    PDMITPMPORT         ICharPort;
> +    /** Pointer to the TPM file name. */
> +    char                *pszLocation;
> +    /** Socket handle of the local socket. */
> +    RTSOCKET            LocalSocket;
> +} tpmDrv;
> +
> +
> +#define PDMITPM_2_DRVTPM(pInterface) ( (tpmDrv
> *)((uintptr_t)pInterface - RT_OFFSETOF(tpmDrv, IStream)) )
> +
> +#define PDMIBASE_2_DRVINS(pInterface)   (
> (PPDMDRVINS)((uintptr_t)pInterface - RT_OFFSETOF(PDMDRVINS, IBase)) )
> +
> +/*******************************************************************************
> +*   Internal Functions
>          *
> +*******************************************************************************/
> +
> +/**
> + * @copydoc PDMISTREAM::pfnRead
> + */
> +static DECLCALLBACK(int) drvTPMRead(PPDMITPM pInterface, void *pvBuf,
> size_t *pcbRead)
> +{
> +    int rc = VINF_SUCCESS;
> +    tpmDrv* s = PDMITPM_2_DRVTPM(pInterface);
> +    LogRel(("%s: pvBuf=%p *pcbRead=%#x (%s)\n", __FUNCTION__, pvBuf,
> *pcbRead, s->pszLocation));
> +
> +    Assert(pvBuf);
> +
> +    if (s->LocalSocket != NIL_RTSOCKET)
> +    {
> +        ssize_t cbReallyRead;
> +        cbReallyRead = recv(s->LocalSocket, pvBuf, TPM_MAX_PKT, 0);
> +        LogRel(("%s: read from tpm %d bytes\n", __FUNCTION__, cbReallyRead));
> +        if (cbReallyRead == 0)
> +        {
> +            RTSOCKET tmp = s->LocalSocket;
> +            s->LocalSocket = NIL_RTSOCKET;
> +            close(tmp);
> +        }
> +        else if (cbReallyRead == -1)
> +        {
> +            cbReallyRead = 0;
> +            rc = RTErrConvertFromErrno(errno);
> +        }
> +        *pcbRead = cbReallyRead;
> +    }
> +    else
> +    {
> +        RTThreadSleep(100);
> +        *pcbRead = 0;
> +    }
> +
> +    LogRel(("%s: *pcbRead=%zu returns %Rrc\n", __FUNCTION__, *pcbRead, rc));
> +    return rc;
> +}
> +
> +/**
> + * @copydoc PDMISTREAM::pfnWrite
> + */
> +static DECLCALLBACK(int) drvTPMWrite(PPDMITPM pInterface, const void
> *pvBuf, size_t *pcbWrite)
> +{
> +    int rc = VINF_SUCCESS;
> +    tpmDrv* s = PDMITPM_2_DRVTPM(pInterface);
> +    LogRel(("%s: pvBuf=%p *pcbWrite=%#x (%s)\n", __FUNCTION__, pvBuf,
> *pcbWrite, s->pszLocation));
> +
> +    Assert(pvBuf);
> +
> +    if (s->LocalSocket != NIL_RTSOCKET)
> +    {
> +        ssize_t cbWritten;
> +        cbWritten = send(s->LocalSocket, pvBuf, *pcbWrite, 0);
> +        LogRel(("%s: write to tpm %d bytes\n", __FUNCTION__, cbWritten));
> +        if (cbWritten == 0)
> +        {
> +            RTSOCKET tmp = s->LocalSocket;
> +            s->LocalSocket = NIL_RTSOCKET;
> +            close(tmp);
> +        }
> +        else if (cbWritten == -1)
> +        {
> +            cbWritten = 0;
> +            rc = RTErrConvertFromErrno(errno);
> +        }
> +        *pcbWrite = cbWritten;
> +    }
> +
> +    LogRel(("%s: returns %Rrc\n", __FUNCTION__, rc));
> +    return rc;
> +}
> +
> +/**
> + * Queries an interface to the driver.
> + *
> + * @returns Pointer to interface.
> + * @returns NULL if the interface was not supported by the driver.
> + * @param   pInterface          Pointer to this interface structure.
> + * @param   enmInterface        The requested interface identification.
> + * @thread  Any thread.
> + */
> +static DECLCALLBACK(void *) drvTPMQueryInterface(PPDMIBASE
> pInterface, PDMINTERFACE enmInterface)
> +{
> +    PPDMDRVINS pDrvIns = PDMIBASE_2_DRVINS(pInterface);
> +    tpmDrv* pDrv       = PDMINS_2_DATA(pDrvIns, tpmDrv *);
> +    switch (enmInterface)
> +    {
> +        case PDMINTERFACE_BASE:
> +            return &pDrvIns->IBase;
> +        case PDMINTERFACE_TPM:
> +            return &pDrv->IStream;
> +        default:
> +            return NULL;
> +    }
> +}
> +
> +/**
> + * Construct a TPM stream driver instance.
> + *
> + * @returns VBox status.
> + * @param   pDrvIns     The driver instance data.
> + *                      If the registration structure is needed,
> pDrvIns->pDrvReg points to it.
> + * @param   pCfgHandle  Configuration node handle for the driver. Use
> this to obtain the configuration
> + *                      of the driver instance. It's also found in
> pDrvIns->pCfgHandle, but like
> + *                      iInstance it's expected to be used a bit in
> this function.
> + */
> +static DECLCALLBACK(int) drvTPMConstruct(PPDMDRVINS pDrvIns,
> PCFGMNODE pCfgHandle)
> +{
> +    char *pszLocation = NULL;
> +    tpmDrv* s = PDMINS_2_DATA(pDrvIns, tpmDrv *);
> +
> +    /*
> +     * Init the static parts.
> +     */
> +
> +    s->pDrvIns                        = pDrvIns;
> +    s->pszLocation                    = NULL;
> +    s->LocalSocket                    = NIL_RTSOCKET;
> +    /* IBase */
> +    pDrvIns->IBase.pfnQueryInterface  = drvTPMQueryInterface;
> +    /* IStream */
> +    s->IStream.pfnRead                = drvTPMRead;
> +    s->IStream.pfnWrite               = drvTPMWrite;
> +
> +    /*
> +     * Read the configuration.
> +     */
> +
> +    s->pszLocation = pszLocation = "/var/run/tpm/tpmd_socket:0";
> +
> +    int sock;
> +    struct sockaddr_un addr;
> +
> +    /*
> +     * Create the local socket.
> +     */
> +
> +    if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
> +        return PDMDrvHlpVMSetError(pDrvIns,
> RTErrConvertFromErrno(errno), RT_SRC_POS, N_("TPM#%d failed to create
> local socket"), pDrvIns->iInstance);
> +
> +    memset(&addr, 0, sizeof(addr));
> +    addr.sun_family = AF_UNIX;
> +    strncpy(addr.sun_path, pszLocation, sizeof(addr.sun_path)-1);
> +
> +    /*
> +     * Connect to the local socket.
> +     */
> +
> +    if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1)
> +       return PDMDrvHlpVMSetError(pDrvIns,
> RTErrConvertFromErrno(errno), RT_SRC_POS, N_("TPM#%d failed to connect
> to local socket %s"), pDrvIns->iInstance, pszLocation);
> +    s->LocalSocket = sock;
> +
> +    /*
> +     * Get the ICharPort interface of the above driver/device.
> +     */
> +
> +    s->pCharPort =
> (PPDMITPMPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase,
> PDMINTERFACE_TPM_PORT);
> +    if (!s->pCharPort)
> +        return PDMDrvHlpVMSetError(pDrvIns,
> VERR_PDM_MISSING_INTERFACE_ABOVE, RT_SRC_POS, N_("TPM#%d has no TPM
> port interface above"),
> +                                   pDrvIns->iInstance);
> +
> +    LogRel(("%s: location %s \n", __FUNCTION__, pszLocation));
> +
> +    return VINF_SUCCESS;
> +}
> +
> +/**
> + * Destruct a TPM stream driver instance.
> + *
> + * Most VM resources are freed by the VM. This callback is provided so that
> + * any non-VM resources can be freed correctly.
> + *
> + * @param   pDrvIns     The driver instance data.
> + */
> +static DECLCALLBACK(void) drvTPMDestruct(PPDMDRVINS pDrvIns)
> +{
> +    tpmDrv* s = PDMINS_2_DATA(pDrvIns, tpmDrv *);
> +    LogRel(("%s: %s\n", __FUNCTION__, s->pszLocation));
> +
> +    if (s->pszLocation)
> +        MMR3HeapFree(s->pszLocation);
> +}
> +
> +/**
> + * Power off a TPM stream driver instance.
> + *
> + * This does most of the destruction work, to avoid ordering dependencies.
> + *
> + * @param   pDrvIns     The driver instance data.
> + */
> +static DECLCALLBACK(void) drvTPMPowerOff(PPDMDRVINS pDrvIns)
> +{
> +    tpmDrv* s = PDMINS_2_DATA(pDrvIns, tpmDrv *);
> +    LogFlow(("%s: %s\n", __FUNCTION__, s->pszLocation));
> +
> +    if (s->LocalSocket != NIL_RTSOCKET)
> +      close(s->LocalSocket);
> +}
> +
> +/**
> + * TPM driver registration record.
> + */
> +const PDMDRVREG g_DrvTPM =
> +{
> +    /* u32Version */
> +    PDM_DRVREG_VERSION,
> +    /* szDriverName */
> +    "TPM",
> +    /* pszDescription */
> +    "TPM stream driver.",
> +    /* fFlags */
> +    PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
> +    /* fClass. */
> +    PDM_DRVREG_CLASS_STREAM,
> +    /* cMaxInstances */
> +    ~0,
> +    /* cbInstance */
> +    sizeof(tpmDrv),
> +    /* pfnConstruct */
> +    drvTPMConstruct,
> +    /* pfnDestruct */
> +    drvTPMDestruct,
> +    /* pfnIOCtl */
> +    NULL,
> +    /* pfnPowerOn */
> +    NULL,
> +    /* pfnReset */
> +    NULL,
> +    /* pfnSuspend */
> +    NULL,
> +    /* pfnResume */
> +    NULL,
> +    /* pfnDetach */
> +    NULL,
> +    /* pfnPowerOff */
> +    drvTPMPowerOff,
> +};
> diff -ruN a/src/VBox/Devices/vl_vbox.h b/src/VBox/Devices/vl_vbox.h
> --- a/src/VBox/Devices/vl_vbox.h    2009-04-27 19:56:56.000000000 +0200
> +++ b/src/VBox/Devices/vl_vbox.h    2009-09-25 17:50:03.000000000 +0200
> @@ -77,8 +77,6 @@
>  typedef PCIDEVICE               PCIDevice;
>  typedef RTGCUINTREG             target_ulong;
>
> -
> -
>  /*
>   * Timers.
>   */
> diff -ruN a/src/VBox/Main/ConsoleImpl2.cpp b/src/VBox/Main/ConsoleImpl2.cpp
> --- a/src/VBox/Main/ConsoleImpl2.cpp    2009-04-27 19:57:14.000000000 +0200
> +++ b/src/VBox/Main/ConsoleImpl2.cpp    2009-09-30 15:56:53.000000000 +0200
> @@ -2032,6 +2032,18 @@
>
>      }
>
> +     /*
> +     * TPM Device
> +     */
> +    rc = CFGMR3InsertNode(pDevices, "TPM", &pDev);
>   RC_CHECK();
> +
> +    rc = CFGMR3InsertNode(pDev, "0", &pInst);
>   RC_CHECK();
> +    rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
>   RC_CHECK();
> +    rc = CFGMR3InsertNode(pInst,     "LUN#0", &pLunL0);
>   RC_CHECK();
> +    rc = CFGMR3InsertString(pLunL0,  "Driver", "TPM");
>   RC_CHECK();
> +    rc = CFGMR3InsertNode(pLunL0,    "AttachedDriver", &pLunL1);
>   RC_CHECK();
> +    rc = CFGMR3InsertString(pLunL1,  "Driver", "TPM");
>   RC_CHECK();
> +
>      /*
>       * Serial (UART) Ports
>       */
>
> _______________________________________________
> vbox-dev mailing list
> vbox-dev at virtualbox.org
> http://vbox.innotek.de/mailman/listinfo/vbox-dev
>   





More information about the vbox-dev mailing list