/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* TPM 1.2 Driver for the TPMs that follow TIS v1.2
*/
#ifdef sun4v
#include <sys/hypervisor_api.h>
#endif
#include "tpm_tis.h"
#include "tpm_ddi.h"
#include "tpm_duration.h"
typedef enum {
TPM_TAG_OFFSET = 0,
/*
* This is to address some TPMs that does not report the correct duration
* and timeouts. In our experience with the production TPMs, we encountered
* time errors such as GetCapability command from TPM reporting the timeout
* and durations in milliseconds rather than microseconds. Some other TPMs
* report the value 0's
*
* Short Duration is based on section 11.3.4 of TIS speciciation, that
* TPM_GetCapability (short duration) commands should not be longer than 750ms
* and that section 11.3.7 states that TPM_ContinueSelfTest (medium duration)
* should not be longer than 1 second.
*/
/*
* In order to test the 'millisecond bug', we test if DURATIONS and TIMEOUTS
* are unreasonably low...such as 10 milliseconds (TPM isn't that fast).
* and 400 milliseconds for long duration
*/
#define DEFAULT_LOCALITY 0
/*
*/
typedef enum {
typedef enum {
typedef enum {
/*
* Internal TPM command functions
*/
/*
* Internal TIS related functions
*/
static int tis_check_active_locality(tpm_state_t *, char);
static int tis_request_locality(tpm_state_t *, char);
static void tis_release_locality(tpm_state_t *, char, int);
static int tis_init(tpm_state_t *);
/* Auxilliary */
static inline int tpm_io_lock(tpm_state_t *);
static inline void tpm_unlock(tpm_state_t *);
/*
*/
/* Declaration of autoconfig functions */
static int tpm_quiesce(dev_info_t *);
/* End of autoconfig functions */
/* Declaration of driver entry point functions */
/* End of driver entry point functions */
/* cb_ops structure */
nodev, /* no strategy - nodev returns ENXIO */
nodev, /* no print */
nodev, /* no dump */
nodev, /* no ioctl */
nodev, /* no devmap */
nodev, /* no mmap */
nodev, /* no segmap */
nochpoll, /* returns ENXIO for non-pollable devices */
NULL, /* streamtab struc */
D_MP, /* compatibility flags */
CB_REV, /* cb_ops revision number */
nodev, /* no aread */
nodev /* no awrite */
};
/* dev_ops structure */
0, /* reference count */
nulldev, /* no identify - nulldev returns 0 */
nodev, /* no reset - nodev returns ENXIO */
nodev, /* no power */
};
/* modldrv structure */
&mod_driverops, /* Type: This is a driver */
"TPM 1.2 driver", /* Name of the module. */
};
/* modlinkage structure */
&modldrv,
};
#ifdef KCF_TPM_RNG_PROVIDER
/*
* CSPI information (entry points, provider info, etc.)
*/
};
static int tpmrng_generate_random(crypto_provider_handle_t,
};
static int tpmrng_ext_info(crypto_provider_handle_t,
NULL,
NULL,
};
static int tpmrng_register(tpm_state_t *);
static int tpmrng_unregister(tpm_state_t *);
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
};
"TPM Random Number Provider",
NULL,
NULL,
0,
NULL,
0,
};
#endif /* KCF_TPM_RNG_PROVIDER */
/*
* Inline code to get exclusive lock on the TPM device and to make sure
* the device is not suspended. This grabs the primary TPM mutex (pm_mutex)
* and then checks the suspend status. If suspended, it will wait until
* the device is "resumed" before releasing the pm_mutex and continuing.
*/
/*
* TPM accessor functions
*/
#ifdef sun4v
extern uint64_t
extern uint64_t
static inline uint8_t
{
}
static inline uint32_t
{
}
static inline void
{
}
#else
static inline uint8_t
{
}
static inline uint32_t
{
}
static inline void
{
}
#endif /* sun4v */
/*
* TPM commands to get the TPM's properties, e.g.,timeout
*/
/*ARGSUSED*/
static int
{
return (DDI_SUCCESS);
}
static uint32_t
{
}
/*
* Get the actual timeouts supported by the TPM by issuing TPM_GetCapability
* with the subcommand TPM_CAP_PROP_TIS_TIMEOUT
* TPM_GetCapability (TPM Main Part 3 Rev. 94, pg.38)
*/
static int
{
int ret;
/* The buffer size (30) needs room for 4 timeout values (uint32_t) */
0, 193, /* TPM_TAG_RQU_COMMAND */
0, 0, 0, 22, /* paramsize in bytes */
0, 0, 0, 101, /* TPM_ORD_GetCapability */
0, 0, 0, 5, /* TPM_CAP_Prop */
0, 0, 0, 4, /* SUB_CAP size in bytes */
0, 0, 1, 21 /* TPM_CAP_PROP_TIS_TIMEOUT(0x115) */
};
if (ret != DDI_SUCCESS) {
#ifdef DEBUG
#endif
return (DDI_FAILURE);
}
/*
* Get the length of the returned buffer
* Make sure that there are 4 timeout values returned
* length of the capability response is stored in data[10-13]
* Also the TPM is in network byte order
*/
#ifdef DEBUG
"instead len = %d",
#endif
return (DDI_FAILURE);
}
/* Get the four timeout's: a,b,c,d (they are 4 bytes long each) */
if (timeout == 0) {
} else if (timeout < TEN_MILLISECONDS) {
/* timeout is in millisecond range (should be microseconds) */
timeout *= 1000;
}
if (timeout == 0) {
} else if (timeout < TEN_MILLISECONDS) {
/* timeout is in millisecond range (should be microseconds) */
timeout *= 1000;
}
if (timeout == 0) {
} else if (timeout < TEN_MILLISECONDS) {
/* timeout is in millisecond range (should be microseconds) */
timeout *= 1000;
}
if (timeout == 0) {
} else if (timeout < TEN_MILLISECONDS) {
/* timeout is in millisecond range (should be microseconds) */
timeout *= 1000;
}
return (DDI_SUCCESS);
}
/*
* Get the actual timeouts supported by the TPM by issuing TPM_GetCapability
* with the subcommand TPM_CAP_PROP_TIS_DURATION
* TPM_GetCapability (TPM Main Part 3 Rev. 94, pg.38)
*/
static int
int ret;
0, 193, /* TPM_TAG_RQU_COMMAND */
0, 0, 0, 22, /* paramsize in bytes */
0, 0, 0, 101, /* TPM_ORD_GetCapability */
0, 0, 0, 5, /* TPM_CAP_Prop */
0, 0, 0, 4, /* SUB_CAP size in bytes */
0, 0, 1, 32 /* TPM_CAP_PROP_TIS_DURATION(0x120) */
};
if (ret != DDI_SUCCESS) {
#ifdef DEBUG
#endif
return (DDI_FAILURE);
}
/*
* Get the length of the returned buffer
* Make sure that there are 3 duration values (S,M,L: in that order)
* length of the capability response is stored in data[10-13]
* Also the TPM is in network byte order
*/
#ifdef DEBUG
"instead, it's %d",
#endif
return (DDI_FAILURE);
}
if (duration == 0) {
} else if (duration < TEN_MILLISECONDS) {
duration *= 1000;
}
if (duration == 0) {
} else if (duration < TEN_MILLISECONDS) {
duration *= 1000;
}
if (duration == 0) {
} else if (duration < FOUR_HUNDRED_MILLISECONDS) {
duration *= 1000;
}
/* Just make the undefined duration be the same as the LONG */
return (DDI_SUCCESS);
}
/*
* Get the actual timeouts supported by the TPM by issuing TPM_GetCapability
* with the subcommand TPM_CAP_PROP_TIS_DURATION
* TPM_GetCapability (TPM Main Part 3 Rev. 94, pg.38)
*/
static int
int ret;
/* If this buf is too small, the "vendor specific" data won't fit */
0, 193, /* TPM_TAG_RQU_COMMAND */
0, 0, 0, 18, /* paramsize in bytes */
0, 0, 0, 101, /* TPM_ORD_GetCapability */
0, 0, 0, 0x1A, /* TPM_CAP_VERSION_VAL */
0, 0, 0, 0, /* SUB_CAP size in bytes */
};
if (ret != DDI_SUCCESS) {
#ifdef DEBUG
#endif
return (DDI_FAILURE);
}
/*
* Get the length of the returned buffer.
*/
if (len < TPM_CAP_VERSION_INFO_SIZE) {
#ifdef DEBUG
" than %d, instead, it's %d",
#endif
return (DDI_FAILURE);
}
"SpecLevel %d, errataRev %d, VendorId '%s'",
vendorId);
/*
* This driver only supports TPM Version 1.2
*/
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* To prevent the TPM from complaining that certain functions are not tested
* we run this command when the driver attaches.
* For details see Section 4.2 of TPM Main Part 3 Command Specification
*/
static int
int ret;
0, 193, /* TPM_TAG_RQU COMMAND */
0, 0, 0, 10, /* paramsize in bytes */
0, 0, 0, 83 /* TPM_ORD_ContinueSelfTest */
};
/* Need a longer timeout */
if (ret != DDI_SUCCESS) {
#ifdef DEBUG
#endif
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* Auxilary Functions
*/
/*
* Find out how long we should wait for the TPM command to complete a command
*/
static clock_t
{
/* Default and failure case for IFX */
/* Is it a TSC_ORDINAL? */
if (ordinal & TSC_ORDINAL_MASK) {
if (ordinal > TSC_ORDINAL_MAX) {
#ifdef DEBUG
"!%s: tsc ordinal: %d exceeds MAX: %d",
#endif
return (0);
}
} else {
if (ordinal > TPM_ORDINAL_MAX) {
#ifdef DEBUG
"!%s: ordinal %d exceeds MAX: %d",
#endif
return (0);
}
}
if (index > TPM_DURATION_MAX_IDX) {
#ifdef DEBUG
#endif
return (0);
}
}
/*
* Internal TPM Transmit Function:
* Calls implementation specific sendto and receive
* The code assumes that the buffer is in network byte order
*/
static int
{
int ret;
/* The byte order is network byte order so convert it */
#ifdef DEBUG
#endif
return (DDI_FAILURE);
}
/* Send the command */
if (ret != DDI_SUCCESS) {
#ifdef DEBUG
#endif
return (DDI_FAILURE);
}
/*
* Now receive the data from the tpm
* Should at least receive "the common" 10 bytes (TPM_HEADER_SIZE)
*/
if (ret < TPM_HEADER_SIZE) {
#ifdef DEBUG
#endif
return (DDI_FAILURE);
}
/* Check the return code */
if (ret != TPM_SUCCESS) {
if (ret == TPM_E_DEACTIVATED)
else if (ret == TPM_E_DISABLED)
else
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* Whenever the driver wants to write to the DATA_IO register, it must need
* to figure out the burstcount. This is the amount of bytes it can write
* before having to wait for long LPC bus cycle
*
* Returns: 0 if error, burst count if sucess
*/
static uint16_t
/*
* Spec says timeout should be TIMEOUT_D
* burst count is TPM_STS bits 8..23
*/
do {
/*
* burstcnt is stored as a little endian value
* 'ntohs' doesn't work since the value is not word-aligned
*/
if (burstcnt)
return (burstcnt);
} while (ddi_get_lbolt() < stop);
return (0);
}
/*
* Writing 1 to TPM_STS_CMD_READY bit in TPM_STS will do the following:
* 1. The TPM will clears IO buffers if any
* 2. The TPM will enters either Idle or Ready state within TIMEOUT_B
* (checked in the calling function)
*/
static void
}
static int
int size = 0;
int retried = 0;
/* A number of consecutive bytes that can be written to TPM */
/*
* Burstcount should be available within TIMEOUT_D
* after STS is set to valid
* burstcount is dynamic, so have to get it each time
*/
}
}
/* check to see if we need to retry (just once) */
/* issue responseRetry (TIS 1.2 pg 54) */
/* update the retry counter so we only retry once */
retried++;
/* reset the size to 0 and reread the entire response */
size = 0;
goto retry;
}
return (size);
}
/* Receive the data from the TPM */
static int
int ret;
int size = 0;
if (bufsiz < TPM_HEADER_SIZE) {
/* There should be at least tag, paramsize, return code */
#ifdef DEBUG
"the header which is %d bytes long",
#endif
goto OUT;
}
/* Read tag(2 bytes), paramsize(4), and result(4) */
if (size < TPM_HEADER_SIZE) {
#ifdef DEBUG
#endif
goto OUT;
}
/* Get 'paramsize'(4 bytes)--it includes tag and paramsize */
#ifdef DEBUG
"than the requested size: paramSize=%d bufsiz=%d result=%d",
#endif
goto OUT;
}
/* Read in the rest of the data from the TPM */
#ifdef DEBUG
#endif
goto OUT;
}
/* The TPM MUST set the state to stsValid within TIMEOUT_C */
if (ret != DDI_SUCCESS) {
#ifdef DEBUG
#endif
goto OUT;
}
/* There is still more data? */
if (status & TPM_STS_DATA_AVAIL) {
#ifdef DEBUG
#endif
goto OUT;
}
/*
* Release the control of the TPM after we are done with it
* it...so others can also get a chance to send data
*/
OUT:
return (size);
}
/*
* Send the data (TPM commands) to the Data IO register
*/
static int
int ret;
if (bufsiz == 0) {
#ifdef DEBUG
#endif
return (DDI_FAILURE);
}
/* Put the TPM in ready state */
if (!(status & TPM_STS_CMD_READY)) {
if (ret != DDI_SUCCESS) {
#ifdef DEBUG
"in the command ready state:"
"tpm_wait_for_stat returned error",
myname);
#endif
goto FAIL;
}
}
/*
* Now we are ready to send command
* TPM's burstcount dictates how many bytes we can write at a time
* Burstcount is dynamic if INTF_CAPABILITY for static burstcount is
* not set.
*/
if (burstcnt == 0) {
#ifdef DEBUG
myname);
#endif
ret = DDI_FAILURE;
goto FAIL;
}
count++;
}
/* Wait for TPM to indicate that it is ready for more data */
if (ret != DDI_SUCCESS) {
#ifdef DEBUG
"state", myname);
#endif
goto FAIL;
}
}
/* We can't exit the loop above unless we wrote bufsiz-1 bytes */
/* Write last byte */
count++;
/* Wait for the TPM to enter Valid State */
if (ret == DDI_FAILURE) {
#ifdef DEBUG
myname);
#endif
goto FAIL;
}
/* The TPM should NOT be expecing more data at this point */
if ((status & TPM_STS_DATA_EXPECT) != 0) {
#ifdef DEBUG
#endif
ret = DDI_FAILURE;
goto FAIL;
}
/*
* Final step: Writing TPM_STS_GO to TPM_STS
* register will actually send the command.
*/
/* Ordinal/Command_code is located in buf[6..9] */
if (ret == DDI_FAILURE) {
#ifdef DEBUG
if (!(status & TPM_STS_DATA_AVAIL) ||
!(status & TPM_STS_VALID)) {
"(ordinal = %d timeout = %ld status = 0x%0x)",
status);
} else {
"(DATA_AVAIL | VALID) failed status = 0x%0X",
}
#endif
goto FAIL;
}
return (DDI_SUCCESS);
FAIL:
return (ret);
}
/*
* Clear XrequestUse and Xactivelocality, where X is the current locality
*/
static void
if (force ||
/*
* Writing 1 to active locality bit in TPM_ACCESS
* register reliquishes the control of the locality
*/
}
}
/*
* Checks whether the given locality is active
* Use TPM_ACCESS register and the masks TPM_ACCESS_VALID,TPM_ACTIVE_LOCALITY
*/
static int
/* Just check to see if the requested locality works */
/* this was just a check, not a request to switch */
return (DDI_SUCCESS);
} else {
return (DDI_FAILURE);
}
}
/* Request the TPM to be in the given locality */
static int
int ret;
if (ret == DDI_SUCCESS) {
/* Locality is already active */
return (DDI_SUCCESS);
}
/* Using polling */
!= DDI_SUCCESS) {
if (ddi_get_lbolt() >= timeout) {
#ifdef DEBUG
"tis_request_locality timed out (timeout_a = %ld)",
#endif
return (DDI_FAILURE);
}
}
return (DDI_SUCCESS);
}
/* Read the status register */
static uint8_t
}
static int
/* Using polling */
if (ddi_get_lbolt() >= absolute_timeout) {
/* Timeout reached */
#ifdef DEBUG
"polling - reached timeout (%ld usecs)",
#endif
return (DDI_FAILURE);
}
}
return (DDI_SUCCESS);
}
/*
* Initialize TPM device
* 1. Find out supported interrupt capabilities
* 2. Set up interrupt handler if supported (some BIOSes don't support
* interrupts for TPMS, in which case we set up polling)
* 3. Determine timeouts and commands duration
*/
static int
int ret;
/*
* Temporarily set up timeouts before we get the real timeouts
* by issuing TPM_CAP commands (but to issue TPM_CAP commands,
* you need TIMEOUTs defined...chicken and egg problem here.
* TPM timeouts: Convert the milliseconds to clock cycles
*/
/*
* Do the same with the duration (real duration will be filled out
* when we call TPM_GetCapability to get the duration values from
* the TPM itself).
*/
/* Find out supported capabilities */
/* Upper 3 bytes should always return 0 */
if (intf_caps & 0x7FFFFF00) {
return (DDI_FAILURE);
}
/* These two interrupts are mandatory */
if (!(intf_caps & TPM_INTF_INT_LOCALITY_CHANGE_INT)) {
"!%s: Mandatory capability Locality Change Int "
"not supported", myname);
return (DDI_FAILURE);
}
if (!(intf_caps & TPM_INTF_INT_DATA_AVAIL_INT)) {
"not supported.", myname);
return (DDI_FAILURE);
}
/*
* Before we start writing anything to TPM's registers,
* make sure we are in locality 0
*/
if (ret != DDI_SUCCESS) {
return (DDI_FAILURE);
} /* Now we can refer to the locality as tpm->locality */
tpm->intr_enabled = 0;
/* Get the real timeouts from the TPM */
if (ret != DDI_SUCCESS) {
return (DDI_FAILURE);
}
if (ret != DDI_SUCCESS) {
return (DDI_FAILURE);
}
/* This gets the TPM version information */
if (ret != DDI_SUCCESS) {
return (DDI_FAILURE);
}
/*
* Unless the TPM completes the test of its commands,
* it can return an error when the untested commands are called
*/
if (ret != DDI_SUCCESS) {
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* Module Entry points
*/
int
_init(void)
{
int ret;
if (ret) {
#ifdef DEBUG
#endif
return (ret);
}
if (ret != 0) {
#ifdef DEBUG
#endif
return (ret);
}
return (ret);
}
int
{
int ret;
#ifdef DEBUG
if (ret == 0)
#endif
return (ret);
}
int
_fini()
{
int ret;
if (ret != 0)
return (ret);
return (ret);
}
/* End of driver configuration functions */
static int
{
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
#ifdef sun4v
};
#endif
/*
*/
static int
{
int ret;
int instance;
#ifndef sun4v
#endif
if (instance < 0)
return (DDI_FAILURE);
/* Nothing out of ordinary here */
switch (cmd) {
case DDI_ATTACH:
#ifdef DEBUG
"!%s: cannot get state information.",
myname);
#endif
return (DDI_FAILURE);
}
} else {
#ifdef DEBUG
"!%s: cannot allocate state information.",
myname);
#endif
return (DDI_FAILURE);
}
break;
case DDI_RESUME:
#ifdef DEBUG
myname);
#endif
return (DDI_FAILURE);
}
return (tpm_resume(tpm));
default:
#ifdef DEBUG
#endif
ret = DDI_FAILURE;
goto FAIL;
}
/* Zeroize the flag, which is used to keep track of what is allocated */
#ifdef sun4v
if (ret != 0) {
goto FAIL;
}
#else
idx = 0;
if (ret != DDI_SUCCESS)
goto FAIL;
/*
* TPM vendors put the TPM registers in different
* slots in their register lists. They are not always
* the 1st set of registers, for instance.
* Loop until we find the set that matches the expected
* register size (0x5000).
*/
goto FAIL;
/* The TIS spec says the TPM registers must be 0x5000 bytes */
if (regsize == 0x5000)
break;
}
ret = DDI_FAILURE;
goto FAIL;
}
if (ret != DDI_SUCCESS) {
goto FAIL;
}
#endif
/* Enable TPM device according to the TIS specification */
if (ret != DDI_SUCCESS) {
#ifdef DEBUG
#endif
/* We need to clean up the ddi_regs_map_setup call */
}
goto FAIL;
}
/* Initialize the inter-process lock */
"pm-hardware-state", "needs-suspend-resume");
/* Initialize the buffer and the lock associated with it */
/* Create minor node */
DDI_PSEUDO, 0);
if (ret != DDI_SUCCESS) {
#ifdef DEBUG
#endif
goto FAIL;
}
#ifdef KCF_TPM_RNG_PROVIDER
/* register RNG with kcf */
myname);
#endif
return (DDI_SUCCESS);
FAIL:
}
return (DDI_FAILURE);
}
/*
* Called by tpm_detach and tpm_attach (only on failure)
* Free up the resources that are allocated
*/
static void
{
return;
#ifdef KCF_TPM_RNG_PROVIDER
(void) tpmrng_unregister(tpm);
#endif
#ifdef sun4v
(void) hsvc_unregister(&hsvc_tpm);
}
#endif
}
}
}
}
/* Free the mapped addresses */
}
/* Remove minor node */
}
}
static int
{
return (DDI_FAILURE);
return (DDI_SUCCESS);
}
return (DDI_SUCCESS);
}
static int
{
int instance;
if (instance < 0)
return (DDI_FAILURE);
#ifdef DEBUG
myname);
#endif
return (ENXIO);
}
switch (cmd) {
case DDI_DETACH:
/* Body is after the switch stmt */
break;
case DDI_SUSPEND:
return (tpm_suspend(tpm));
default:
#ifdef DEBUG
#endif
return (DDI_FAILURE);
}
/* Since we are freeing tpm structure, we need to gain the lock */
/* Free the soft state */
return (DDI_SUCCESS);
}
/*ARGSUSED*/
static int
{
int instance;
#ifdef DEBUG
myname);
#endif
return (DDI_FAILURE);
}
switch (cmd) {
case DDI_INFO_DEVT2DEVINFO:
break;
case DDI_INFO_DEVT2INSTANCE:
*resultp = 0;
break;
default:
#ifdef DEBUG
#endif
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* Driver entry points
*/
/*ARGSUSED*/
static int
{
int instance;
#ifdef DEBUG
myname);
#endif
return (ENXIO);
}
#ifdef DEBUG
#endif
return (EINVAL);
}
#ifdef DEBUG
myname);
#endif
return (EBUSY);
}
/* The device is free so mark it busy */
return (0);
}
/*ARGSUSED*/
static int
{
int instance;
#ifdef DEBUG
myname);
#endif
return (ENXIO);
}
#ifdef DEBUG
#endif
return (EINVAL);
}
return (0);
}
/*ARGSUSED*/
static int
{
int ret;
int instance;
#ifdef DEBUG
myname);
#endif
return (ENXIO);
}
#ifdef DEBUG
#endif
return (EFAULT);
}
/* Receive the data after requiring the lock */
/* Timeout reached */
if (ret)
return (ret);
#ifdef DEBUG
"than tpm->bufsize:read in:%d, bufsiz:%d",
#endif
goto OUT;
}
if (ret < TPM_HEADER_SIZE) {
#ifdef DEBUG
#endif
goto OUT;
}
#ifdef DEBUG
"expected size=%d, actually read=%d",
#endif
goto OUT;
}
/* Send the buffer from the kernel to the userspace */
if (ret) {
#ifdef DEBUG
#endif
goto OUT;
}
/* Zeroize the buffer... */
ret = DDI_SUCCESS;
OUT:
/* We are done now: wake up the waiting threads */
return (ret);
}
/*ARGSUSED*/
static int
{
int ret;
int instance;
#ifdef DEBUG
myname);
#endif
return (ENXIO);
}
#ifdef DEBUG
#endif
return (EFAULT);
}
if (len == 0) {
#ifdef DEBUG
#endif
return (0);
}
/* Get the lock for using iobuf */
/* Timeout Reached */
if (ret)
return (ret);
/* Copy the header and parse the structure to find out the size... */
if (ret) {
#ifdef DEBUG
"while getting the the header",
myname);
#endif
goto OUT;
}
/* Get the buffersize from the command buffer structure */
/* Copy the command to the contiguous buffer */
#ifdef DEBUG
"the tpm input buffer size %d",
#endif
goto OUT;
}
/* Copy the buffer from the userspace to kernel */
if (ret) {
#ifdef DEBUG
"while getting the rest of the command", myname);
#endif
goto OUT;
}
/* Send the command */
if (ret != DDI_SUCCESS) {
#ifdef DEBUG
#endif
goto OUT;
}
/* Zeroize the buffer... */
ret = DDI_SUCCESS;
OUT:
return (ret);
}
/*
* This is to deal with the contentions for the iobuf
*/
static inline int
{
int ret;
/* Wait until the iobuf becomes free with the timeout */
while (tpm->iobuf_inuse) {
if (ret <= 0) {
/* Timeout reached */
#ifdef DEBUG
#endif
return (ETIME);
}
}
return (0);
}
/*
* This is to deal with the contentions for the iobuf
*/
static inline void
{
/* Wake up the waiting threads */
tpm->iobuf_inuse = 0;
}
#ifdef KCF_TPM_RNG_PROVIDER
/*
* Random number generator entry points
*/
static void
{
if (s2len < n)
}
/*ARGSUSED*/
static int
{
return (DDI_FAILURE);
sizeof (ext_info->ei_manufacturerID));
sizeof (ext_info->ei_serial_number));
ext_info->ei_max_pin_len = 0;
ext_info->ei_min_pin_len = 0;
return (CRYPTO_SUCCESS);
}
static int
{
int ret;
if (ret != CRYPTO_SUCCESS) {
return (DDI_FAILURE);
}
1, rngmech);
#ifdef DEBUG
if (ret != CRYPTO_SUCCESS)
#endif
return (DDI_SUCCESS);
}
static int
{
int ret;
if (ret != CRYPTO_SUCCESS)
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*ARGSUSED*/
static void
{
}
/*ARGSUSED*/
static int
{
int ret;
/* Max length of seed is 256 bytes, add 14 for header. */
0, 193, /* TPM_TAG_RQU COMMAND */
0, 0, 0, 0x0A, /* paramsize in bytes */
0, 0, 0, TPM_ORD_StirRandom,
0, 0, 0, 0 /* number of input bytes (< 256) */
};
return (CRYPTO_ARGUMENTS_BAD);
return (CRYPTO_INVALID_CONTEXT);
/* Acquire lock for exclusive use of TPM */
/* Timeout reached */
if (ret)
return (CRYPTO_BUSY);
/* TPM only handles 32 bit length, so truncate if too big. */
/* The length must be in network order */
/* Convert it back */
/* length must be in network order */
/* convert it back */
if (ret != DDI_SUCCESS) {
#ifdef DEBUG
#endif
return (CRYPTO_FAILED);
}
return (CRYPTO_SUCCESS);
}
/* ARGSUSED */
static int
{
int ret;
0, 193, /* TPM_TAG_RQU COMMAND */
0, 0, 0, 14, /* paramsize in bytes */
0, 0, 0, TPM_ORD_GetRandom,
0, 0, 0, 0
};
return (CRYPTO_ARGUMENTS_BAD);
return (CRYPTO_INVALID_CONTEXT);
/* Timeout reached */
if (ret)
return (CRYPTO_BUSY);
/* Length is written in network byte order */
if (ret != DDI_SUCCESS) {
#ifdef DEBUG
#endif
return (CRYPTO_FAILED);
}
/* Find out how many bytes were really returned */
/* Copy the random bytes back to the callers buffer */
return (CRYPTO_SUCCESS);
}
#endif /* KCF_TPM_RNG_PROVIDER */