changeset 10334:2f82b01640c4

6855414 Deliver SPARC support for TPM 6865428 pkcs11_tpm should be installed by default, or it won't be used
author Wyllys Ingersoll <wyllys.ingersoll@sun.com>
date Mon, 17 Aug 2009 20:56:15 -0700
parents 818ccd4c7d55
children bebd52b78199
files usr/src/cmd/cmd-crypto/Makefile usr/src/cmd/cmd-crypto/etc/pkcs11.conf usr/src/cmd/devfsadm/misc_link.c usr/src/lib/pkcs11/Makefile usr/src/lib/pkcs11/pkcs11_tpm/common/api_interface.c usr/src/lib/pkcs11/pkcs11_tpm/common/apiutil.c usr/src/lib/pkcs11/pkcs11_tpm/common/new_host.c usr/src/lib/pkcs11/pkcs11_tpm/common/tpmtok_int.h usr/src/lib/pkcs11/pkcs11_tpm/common/utility.c usr/src/lib/pkcs11/pkcs11_tpm/sparc/Makefile usr/src/lib/pkcs11/pkcs11_tpm/sparcv9/Makefile usr/src/pkgdefs/Makefile usr/src/pkgdefs/SUNWcsl/prototype_com usr/src/pkgdefs/SUNWcsl/prototype_i386 usr/src/pkgdefs/SUNWcsl/prototype_sparc usr/src/pkgdefs/SUNWcsu/prototype_com usr/src/pkgdefs/SUNWcsu/prototype_i386 usr/src/pkgdefs/SUNWtpm/pkginfo.tmpl usr/src/pkgdefs/SUNWtpm/postinstall.tmpl usr/src/pkgdefs/SUNWtpm/preremove.tmpl usr/src/pkgdefs/SUNWtpm/prototype_com usr/src/pkgdefs/SUNWtpm/prototype_i386 usr/src/pkgdefs/SUNWtpm/prototype_sparc usr/src/pkgdefs/common_files/i.pkcs11confbase usr/src/uts/common/Makefile.files usr/src/uts/common/Makefile.rules usr/src/uts/common/io/tpm/tpm.c usr/src/uts/common/io/tpm/tpm.conf usr/src/uts/common/io/tpm/tpm_ddi.h usr/src/uts/common/io/tpm/tpm_hcall.s usr/src/uts/common/io/tpm/tpm_tis.h usr/src/uts/sun4v/Makefile.sun4v.shared usr/src/uts/sun4v/sys/hsvc.h usr/src/uts/sun4v/sys/hypervisor_api.h
diffstat 34 files changed, 912 insertions(+), 268 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/cmd-crypto/Makefile	Mon Aug 17 20:49:16 2009 -0700
+++ b/usr/src/cmd/cmd-crypto/Makefile	Mon Aug 17 20:56:15 2009 -0700
@@ -30,12 +30,8 @@
 	digest \
 	elfsign \
 	pktool \
-	kmfcfg
-
-#
-# tpmadm is x86 only until we have SPARC support for the TSS and TPM
-#
-i386_SUBDIRS = tpmadm
+	kmfcfg \
+	tpmadm
 
 $(CLOSED_BUILD)SUBDIRS1 += \
 	$(CLOSED)/cmd/cmd-crypto/kcfd
--- a/usr/src/cmd/cmd-crypto/etc/pkcs11.conf	Mon Aug 17 20:49:16 2009 -0700
+++ b/usr/src/cmd/cmd-crypto/etc/pkcs11.conf	Mon Aug 17 20:56:15 2009 -0700
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# 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
 # or http://www.opensolaris.org/os/licensing.
@@ -19,12 +18,9 @@
 #
 # CDDL HEADER END
 #
-#
-# Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
 # /etc/crypto/pkcs11.conf
 #
 # Do NOT edit this file by hand.  An administrator should use cryptoadm(1m)
@@ -43,4 +39,5 @@
 metaslot:metaslot_status=enabled;metaslot_auto_key_migrate=enabled;metaslot_token=Sun Software PKCS#11 softtoken;metaslot_slot=Sun Crypto Softtoken
 /usr/lib/security/$ISA/pkcs11_kernel.so
 /usr/lib/security/$ISA/pkcs11_softtoken.so
+/usr/lib/security/$ISA/pkcs11_tpm.so
 # End SUNWcsr
--- a/usr/src/cmd/devfsadm/misc_link.c	Mon Aug 17 20:49:16 2009 -0700
+++ b/usr/src/cmd/devfsadm/misc_link.c	Mon Aug 17 20:56:15 2009 -0700
@@ -184,7 +184,10 @@
 	},
 	{ "pseudo", "ddi_pseudo", "fm",
 	    TYPE_EXACT | DRV_RE, ILEVEL_1, minor_name,
-	}
+	},
+	{ "pseudo", "ddi_pseudo", "tpm",
+	    TYPE_EXACT | DRV_EXACT, ILEVEL_0, minor_name
+	},
 };
 
 DEVFSADM_CREATE_INIT_V0(misc_cbt);
@@ -217,7 +220,10 @@
 	},
 	{ "pseudo", "^pfil$",
 	    RM_PRE | RM_ALWAYS, ILEVEL_0, devfsadm_rm_all
-	}
+	},
+	{ "pseudo", "^tpm$",
+	    RM_PRE | RM_ALWAYS, ILEVEL_0, devfsadm_rm_all
+	},
 };
 
 /* Rules for gpio devices */
--- a/usr/src/lib/pkcs11/Makefile	Mon Aug 17 20:49:16 2009 -0700
+++ b/usr/src/lib/pkcs11/Makefile	Mon Aug 17 20:56:15 2009 -0700
@@ -39,17 +39,13 @@
 	libkcfd
 
 #
-# The PKCS11 TPM provider is only available for x86.
-#
-i386_SUBDIRS = pkcs11_tpm
-
-#
 # Don't build these for OpenSolaris, since they will be replaced by
 # binaries that are signed by ON Gatekeepers.
 #
 $(CLOSED_BUILD)SUBDIRS += \
 			pkcs11_kernel	\
-			pkcs11_softtoken
+			pkcs11_softtoken \
+			pkcs11_tpm
 
 $(CLOSED_BUILD)SUBDIRS += $($(MACH)_SUBDIRS)
 
--- a/usr/src/lib/pkcs11/pkcs11_tpm/common/api_interface.c	Mon Aug 17 20:49:16 2009 -0700
+++ b/usr/src/lib/pkcs11/pkcs11_tpm/common/api_interface.c	Mon Aug 17 20:56:15 2009 -0700
@@ -402,7 +402,8 @@
 	LOG("CloseAllSessions");
 	if (API_Initialized() == FALSE)
 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
-	if (slotID > NUMBER_SLOTS_MANAGED)
+
+	if (!global_shm->token_available || (slotID > NUMBER_SLOTS_MANAGED))
 		return (CKR_SLOT_ID_INVALID);
 	/*
 	 * Proc Mutex is locked when we remove from the seesion list in
@@ -1346,17 +1347,22 @@
 	pInfo->cryptokiVersion.major = 2;
 	pInfo->cryptokiVersion.minor = 20;
 
-	if (open_tss_context(&hContext))
-		return (CKR_FUNCTION_FAILED);
-
-	(void) token_get_tpm_info(hContext, &td);
+	if (open_tss_context(&hContext) == 0) {
+		/*
+		 * Only populate the TPM info if we can establish
+		 * a context, but don't return failure because
+		 * the framework needs to know some of the info.
+		 */
+		(void) token_get_tpm_info(hContext, &td);
 
-	(void) Tspi_Context_Close(hContext);
+		(void) Tspi_Context_Close(hContext);
 
-	(void) memcpy(pInfo->manufacturerID, &(td.token_info.manufacturerID),
-	    sizeof (pInfo->manufacturerID) - 1);
+		(void) memcpy(pInfo->manufacturerID,
+		    &(td.token_info.manufacturerID),
+		    sizeof (pInfo->manufacturerID) - 1);
 
-	pInfo->flags = td.token_info.flags;
+		pInfo->flags = td.token_info.flags;
+	}
 	(void) strcpy((char *)pInfo->libraryDescription,
 	    "PKCS11 Interface for TPM");
 
@@ -1372,12 +1378,12 @@
 	CK_MECHANISM_INFO_PTR	pInfo)
 {
 	CK_RV rv;
-	if (API_Initialized() == FALSE) {
+	if (API_Initialized() == FALSE)
 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
-	}
-	if (slotID > NUMBER_SLOTS_MANAGED) {
+
+	if (!global_shm->token_available || (slotID > NUMBER_SLOTS_MANAGED))
 		return (CKR_SLOT_ID_INVALID);
-	}
+
 	if (FuncList.ST_GetMechanismInfo) {
 		rv = FuncList.ST_GetMechanismInfo(slotID, type, pInfo);
 	} else {
@@ -1393,13 +1399,13 @@
 {
 	CK_RV rv;
 
-	if (API_Initialized() == FALSE) {
+	if (API_Initialized() == FALSE)
 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
-	}
+
 	if (! pulCount)
 		return (CKR_ARGUMENTS_BAD);
 
-	if (slotID > NUMBER_SLOTS_MANAGED)
+	if (!global_shm->token_available || (slotID > NUMBER_SLOTS_MANAGED))
 		return (CKR_SLOT_ID_INVALID);
 
 	if (FuncList.ST_GetMechanismList) {
@@ -1499,13 +1505,13 @@
 C_GetSlotInfo(CK_SLOT_ID slotID,
 	CK_SLOT_INFO_PTR pInfo)
 {
-	if (API_Initialized() == FALSE) {
+	if (API_Initialized() == FALSE)
 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
-	}
-	if (!pInfo) {
+
+	if (!pInfo)
 		return (CKR_FUNCTION_FAILED);
-	}
-	if (slotID != TPM_SLOTID)
+
+	if (!global_shm->token_available || (slotID > NUMBER_SLOTS_MANAGED))
 		return (CKR_SLOT_ID_INVALID);
 
 	copy_slot_info(slotID, pInfo);
@@ -1528,6 +1534,13 @@
 		return (CKR_FUNCTION_FAILED);
 
 	count = 0;
+	/*
+	 * If we can't talk to the TPM, present no slots
+	 */
+	if (!global_shm->token_available) {
+		*pulCount = 0;
+		return (CKR_OK);
+	}
 
 	copy_slot_info(TPM_SLOTID, &slotInfo);
 	if ((slotInfo.flags & CKF_TOKEN_PRESENT))
@@ -1551,15 +1564,15 @@
 {
 	CK_RV rv;
 
-	if (API_Initialized() == FALSE) {
+	if (API_Initialized() == FALSE)
 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
-	}
-	if (! pInfo) {
+
+	if (!pInfo)
 		return (CKR_ARGUMENTS_BAD);
-	}
-	if (slotID > NUMBER_SLOTS_MANAGED) {
+
+	if (!global_shm->token_available || (slotID > NUMBER_SLOTS_MANAGED))
 		return (CKR_SLOT_ID_INVALID);
-	}
+
 	slotID = TPM_SLOTID;
 	if (FuncList.ST_GetTokenInfo) {
 		rv = FuncList.ST_GetTokenInfo(slotID, pInfo);
@@ -1651,24 +1664,23 @@
 	CK_RV rv;
 	ST_SESSION_T rSession;
 
-	if (API_Initialized() == FALSE) {
+	if (API_Initialized() == FALSE)
 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
-	}
-	if (! pPin && ulPinLen) {
+
+	if (! pPin && ulPinLen)
 		return (CKR_ARGUMENTS_BAD);
-	}
-	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
+
+	if (! Valid_Session((Session_Struct_t *)hSession, &rSession))
 		return (CKR_SESSION_HANDLE_INVALID);
-	}
 
-	if (rSession.slotID > NUMBER_SLOTS_MANAGED) {
+	if (rSession.slotID > NUMBER_SLOTS_MANAGED)
 		return (CKR_SLOT_ID_INVALID);
-	}
-	if (FuncList.ST_InitPIN) {
+
+	if (FuncList.ST_InitPIN)
 		rv = FuncList.ST_InitPIN(rSession, pPin, ulPinLen);
-	} else {
+	else
 		rv = CKR_FUNCTION_NOT_SUPPORTED;
-	}
+
 	return (rv);
 }
 
@@ -1680,20 +1692,23 @@
 {
 	CK_RV rv;
 
-	if (API_Initialized() == FALSE) {
+	if (API_Initialized() == FALSE)
 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
-	}
-	if (! pPin && ulPinLen) {
+
+	if (! pPin && ulPinLen)
+		return (CKR_ARGUMENTS_BAD);
+
+	if (! pLabel)
 		return (CKR_ARGUMENTS_BAD);
-	}
-	if (! pLabel) {
-		return (CKR_ARGUMENTS_BAD);
-	}
-	if (FuncList.ST_InitToken) {
+
+	if (!global_shm->token_available)
+		return (CKR_SLOT_ID_INVALID);
+
+	if (FuncList.ST_InitToken)
 		rv = FuncList.ST_InitToken(slotID, pPin, ulPinLen, pLabel);
-	} else {
+	else
 		rv = CKR_FUNCTION_NOT_SUPPORTED;
-	}
+
 	return (rv);
 }
 
@@ -1752,22 +1767,22 @@
 	CK_RV rv;
 	Session_Struct_t  *apiSessp;
 
-	if (API_Initialized() == FALSE) {
+	if (API_Initialized() == FALSE)
 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
-	}
-	if (slotID > NUMBER_SLOTS_MANAGED) {
+
+	if (!global_shm->token_available || (slotID > NUMBER_SLOTS_MANAGED))
 		return (CKR_SLOT_ID_INVALID);
-	}
-	if (! phSession) {
+
+	if (! phSession)
 		return (CKR_FUNCTION_FAILED);
-	}
-	if ((flags & CKF_SERIAL_SESSION) == 0) {
+
+	if ((flags & CKF_SERIAL_SESSION) == 0)
 		return (CKR_SESSION_PARALLEL_NOT_SUPPORTED);
-	}
+
 	if ((apiSessp = (Session_Struct_t *)malloc(
-	    sizeof (Session_Struct_t))) == NULL) {
+	    sizeof (Session_Struct_t))) == NULL)
 		return (CKR_HOST_MEMORY);
-	}
+
 	if (FuncList.ST_OpenSession) {
 		rv = FuncList.ST_OpenSession(slotID, flags,
 		    &(apiSessp->RealHandle));
--- a/usr/src/lib/pkcs11/pkcs11_tpm/common/apiutil.c	Mon Aug 17 20:49:16 2009 -0700
+++ b/usr/src/lib/pkcs11/pkcs11_tpm/common/apiutil.c	Mon Aug 17 20:56:15 2009 -0700
@@ -453,7 +453,7 @@
 int
 API_Initialized()
 {
-	return (Anchor != NULL);
+	return (Anchor != NULL && global_shm != NULL);
 }
 
 void
--- a/usr/src/lib/pkcs11/pkcs11_tpm/common/new_host.c	Mon Aug 17 20:49:16 2009 -0700
+++ b/usr/src/lib/pkcs11/pkcs11_tpm/common/new_host.c	Mon Aug 17 20:56:15 2009 -0700
@@ -156,11 +156,23 @@
 		initedpid = getpid();
 		SC_SetFunctionList();
 
+		if (flist != NULL)
+			(*flist) = function_list;
+
 		/* Always call the token_specific_init function.... */
 		rc = token_specific.t_init((char *)Correlator, SlotNumber,
 		    &hContext);
-		if (rc != 0)
+		if (rc != 0) {
+			/*
+			 * The token could not be initialized, return OK, but
+			 * present no slots.
+			 */
+			rc = CKR_OK;
 			goto done;
+		} else {
+			/* Mark the token as available */
+			global_shm->token_available = TRUE;
+		}
 	}
 
 	rc = load_token_data(hContext, nv_token_data);
@@ -179,8 +191,6 @@
 
 	init_slot_info(nv_token_data);
 
-	if (flist != NULL)
-		(*flist) = function_list;
 done:
 	if (hContext)
 		Tspi_Context_Close(hContext);
--- a/usr/src/lib/pkcs11/pkcs11_tpm/common/tpmtok_int.h	Mon Aug 17 20:49:16 2009 -0700
+++ b/usr/src/lib/pkcs11/pkcs11_tpm/common/tpmtok_int.h	Mon Aug 17 20:56:15 2009 -0700
@@ -414,6 +414,7 @@
 	CK_ULONG	num_publ_tok_obj;
 	CK_BBOOL	priv_loaded;
 	CK_BBOOL	publ_loaded;
+	CK_BBOOL	token_available;
 	TOK_OBJ_ENTRY  publ_tok_objs[ MAX_TOK_OBJS ];
 	TOK_OBJ_ENTRY  priv_tok_objs[ MAX_TOK_OBJS ];
 } LW_SHM_TYPE;
--- a/usr/src/lib/pkcs11/pkcs11_tpm/common/utility.c	Mon Aug 17 20:49:16 2009 -0700
+++ b/usr/src/lib/pkcs11/pkcs11_tpm/common/utility.c	Mon Aug 17 20:56:15 2009 -0700
@@ -596,7 +596,7 @@
 	if (global_shm != NULL)
 		return (CKR_OK);
 
-	global_shm = (LW_SHM_TYPE *)malloc(sizeof (LW_SHM_TYPE));
+	global_shm = (LW_SHM_TYPE *)calloc(1, sizeof (LW_SHM_TYPE));
 	if (global_shm == NULL) {
 		return (CKR_HOST_MEMORY);
 	}
@@ -605,14 +605,6 @@
 	xproclock = (void *)&global_shm->mutex;
 	(void) XProcLock(xproclock);
 
-	global_shm->num_publ_tok_obj = 0;
-	global_shm->num_priv_tok_obj = 0;
-
-	(void) memset(&global_shm->publ_tok_objs, 0x0,
-	    2048 * sizeof (TOK_OBJ_ENTRY));
-	(void) memset(&global_shm->priv_tok_objs, 0x0,
-	    2048 * sizeof (TOK_OBJ_ENTRY));
-
 	(void) XProcUnLock(xproclock);
 
 	return (CKR_OK);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/pkcs11/pkcs11_tpm/sparc/Makefile	Mon Aug 17 20:56:15 2009 -0700
@@ -0,0 +1,27 @@
+#
+# 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
+# or http://www.opensolaris.org/os/licensing.
+# 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.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/pkcs11/pkcs11_tpm/sparcv9/Makefile	Mon Aug 17 20:56:15 2009 -0700
@@ -0,0 +1,30 @@
+#
+# 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
+# or http://www.opensolaris.org/os/licensing.
+# 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.
+#
+
+include ../Makefile.com
+include $(SRC)/lib/Makefile.lib.64
+
+TSSLIB=$(TSSLIB64)
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) 
--- a/usr/src/pkgdefs/Makefile	Mon Aug 17 20:49:16 2009 -0700
+++ b/usr/src/pkgdefs/Makefile	Mon Aug 17 20:56:15 2009 -0700
@@ -158,7 +158,6 @@
 	SUNWrwd	\
 	SUNWrwn	\
 	SUNWsi3124 \
-	SUNWtpm \
 	SUNWuath \
 	SUNWural \
 	SUNWurtw \
@@ -493,6 +492,7 @@
 	SUNWtnfc  \
 	SUNWtnfd  \
 	SUNWtoo  \
+	SUNWtpm \
 	SUNWtsg  \
 	SUNWtsr  \
 	SUNWtsu  \
--- a/usr/src/pkgdefs/SUNWcsl/prototype_com	Mon Aug 17 20:49:16 2009 -0700
+++ b/usr/src/pkgdefs/SUNWcsl/prototype_com	Mon Aug 17 20:56:15 2009 -0700
@@ -358,6 +358,8 @@
 s none usr/lib/security/pkcs11_kernel.so=./pkcs11_kernel.so.1
 f none usr/lib/security/pkcs11_softtoken.so.1 755 root bin
 s none usr/lib/security/pkcs11_softtoken.so=./pkcs11_softtoken.so.1
+f none usr/lib/security/pkcs11_tpm.so.1 755 root bin
+s none usr/lib/security/pkcs11_tpm.so=./pkcs11_tpm.so.1
 d none usr/lib/scsi 755 root bin
 f none usr/lib/scsi/libscsi.so.1 755 root bin
 s none usr/lib/scsi/libscsi.so=./libscsi.so.1
--- a/usr/src/pkgdefs/SUNWcsl/prototype_i386	Mon Aug 17 20:49:16 2009 -0700
+++ b/usr/src/pkgdefs/SUNWcsl/prototype_i386	Mon Aug 17 20:56:15 2009 -0700
@@ -152,8 +152,6 @@
 s none usr/lib/security/amd64/pkcs11_softtoken.so=./pkcs11_softtoken.so.1
 f none usr/lib/security/amd64/pkcs11_tpm.so.1 755 root bin
 s none usr/lib/security/amd64/pkcs11_tpm.so=./pkcs11_tpm.so.1
-f none usr/lib/security/pkcs11_tpm.so.1 755 root bin
-s none usr/lib/security/pkcs11_tpm.so=./pkcs11_tpm.so.1
 s none usr/lib/64=amd64
 d none usr/lib/amd64 755 root bin
 f none usr/lib/amd64/libadutils.so.1 755 root bin
--- a/usr/src/pkgdefs/SUNWcsl/prototype_sparc	Mon Aug 17 20:49:16 2009 -0700
+++ b/usr/src/pkgdefs/SUNWcsl/prototype_sparc	Mon Aug 17 20:56:15 2009 -0700
@@ -144,6 +144,8 @@
 s none usr/lib/security/sparcv9/pkcs11_kernel.so=./pkcs11_kernel.so.1
 f none usr/lib/security/sparcv9/pkcs11_softtoken.so.1 755 root bin
 s none usr/lib/security/sparcv9/pkcs11_softtoken.so=./pkcs11_softtoken.so.1
+f none usr/lib/security/sparcv9/pkcs11_tpm.so.1 755 root bin
+s none usr/lib/security/sparcv9/pkcs11_tpm.so=./pkcs11_tpm.so.1
 s none usr/lib/64=sparcv9
 d none usr/lib/sparcv9 755 root bin
 f none usr/lib/sparcv9/libadutils.so.1 755 root bin
--- a/usr/src/pkgdefs/SUNWcsu/prototype_com	Mon Aug 17 20:49:16 2009 -0700
+++ b/usr/src/pkgdefs/SUNWcsu/prototype_com	Mon Aug 17 20:56:15 2009 -0700
@@ -281,6 +281,7 @@
 f none usr/bin/tip 4511 uucp bin
 l none usr/bin/touch=../../usr/bin/settime
 f none usr/bin/tplot 555 root bin
+f none usr/bin/tpmadm 555 root bin
 f none usr/bin/tput 555 root bin
 f none usr/bin/tr 555 root bin
 f none usr/bin/true 555 root bin
--- a/usr/src/pkgdefs/SUNWcsu/prototype_i386	Mon Aug 17 20:49:16 2009 -0700
+++ b/usr/src/pkgdefs/SUNWcsu/prototype_i386	Mon Aug 17 20:56:15 2009 -0700
@@ -63,7 +63,6 @@
 f none usr/bin/i86/setuname 555 root bin
 f none usr/bin/i86/uptime 4555 root bin
 l none usr/bin/i86/w=uptime
-f none usr/bin/tpmadm 555 root bin
 f none usr/kernel/drv/dump 755 root sys
 f none usr/kernel/drv/fssnap 755 root sys
 f none usr/kernel/drv/kstat 755 root sys
--- a/usr/src/pkgdefs/SUNWtpm/pkginfo.tmpl	Mon Aug 17 20:49:16 2009 -0700
+++ b/usr/src/pkgdefs/SUNWtpm/pkginfo.tmpl	Mon Aug 17 20:56:15 2009 -0700
@@ -32,14 +32,14 @@
 #       this value will break upgrade until ONVERS is incremented to 11.12
 #
 PKG="SUNWtpm"
-NAME="Sun TPM pseudo driver"
-ARCH="i386"
+NAME="Trusted Platform Module driver"
+ARCH="ISA"
 CATEGORY="system"
 BASEDIR=/
 SUNW_PKGVERS="1.0"
 SUNW_PKGTYPE="root"
 CLASSES="none"
-DESC="Sun TPM pseudo driver"
+DESC="Trusted Platform Module driver"
 SUNW_PRODNAME="SunOS"
 SUNW_PRODVERS="RELEASE/VERSION"
 VERSION="ONVERS.0,REV=0.0.0"
--- a/usr/src/pkgdefs/SUNWtpm/postinstall.tmpl	Mon Aug 17 20:49:16 2009 -0700
+++ b/usr/src/pkgdefs/SUNWtpm/postinstall.tmpl	Mon Aug 17 20:56:15 2009 -0700
@@ -28,7 +28,6 @@
 DRVPERM='* 0600 root sys'
 ADD_DRV=/usr/sbin/add_drv
 
-DEVLINKTB=${BASEDIR}/etc/devlink.tab
 ACPITABLE=${BASEDIR}/boot/solaris/devicedb/master
 TMP=/tmp/$$
 
@@ -36,12 +35,7 @@
 ISA_TYPE_SPARC="sparc"
 ISA_TYPE="$ARCH"
 
-#
-# TPM support is only available on x86 platforms.
-#
-if [ "${ISA_TYPE}" != "${ISA_TYPE_I386}" ]; then
-	exit 0
-fi
+MACH=`/usr/bin/uname -m`
 
 #
 # Check if the BASEDIR option is needed
@@ -49,11 +43,9 @@
 if [ "${BASEDIR:=/}" = "/" ]; then
 	ADD_DRV_FLAGS=""
 	NAME_TO_MAJOR="/etc/name_to_major"
-	DEVLINK_TAB="/etc/devlink.tab"
 else
 	ADD_DRV_FLAGS="-b ${BASEDIR}"
 	NAME_TO_MAJOR="${BASEDIR}/etc/name_to_major"
-	DEVLINK_TAB="${BASEDIR}/etc/devlink.tab"
 fi
 
 add_driver()
@@ -73,20 +65,6 @@
 }
 
 #
-# add_devlink - adds an entry to ${DEVLINKTB}
-#
-add_devlink()
-{
-	PATTERN="$1"
-	LINK="$2"
-	PLINK="`echo $LINK | sed 's/[$*^|\]/\\\&/g'`"
-	grep -v "^$PATTERN	$PLINK$" ${DEVLINKTB} >$TMP.devlink
-	echo "$PATTERN\t$LINK" >>$TMP.devlink
-	cp $TMP.devlink ${DEVLINKTB}
-	rm -f $TMP.devlink
-}
-
-#
 # Update ACPI table if the entry is not already present.
 #
 add_acpi()
@@ -97,11 +75,17 @@
 	fi
 }
 
-# Add entry to /etc/devlink.tab if not there already
-# Note: the tab after ${DRV} here is important.
-
-add_devlink 'type=ddi_pseudo;name=tpm' '\\D'
-add_acpi
-add_driver
+if [ "${ISA_TYPE}" = "${ISA_TYPE_I386}" ]; then
+	add_acpi
+	add_driver
+else 
+	if [ "${ISA_TYPE}" = "${ISA_TYPE_SPARC}" -a "${MACH}" = "sun4v" ]; then
+		#
+		# sun4v TPM device has a unique identifier
+		#
+		ADD_DRV_FLAGS="${ADD_DRV_FLAGS} -i 'SUNW,sun4v-ptpm'"
+		add_driver
+	fi
+fi
 
 exit 0
--- a/usr/src/pkgdefs/SUNWtpm/preremove.tmpl	Mon Aug 17 20:49:16 2009 -0700
+++ b/usr/src/pkgdefs/SUNWtpm/preremove.tmpl	Mon Aug 17 20:56:15 2009 -0700
@@ -30,6 +30,7 @@
 
 DRV=tpm
 REM_DRV=/usr/sbin/rem_drv
+
 #
 # Check if the BASEDIR option is needed
 #
@@ -43,14 +44,17 @@
 
 ${REM_DRV} ${REM_DRV_FLAGS} ${DRV}
 
-# Remove our entry from /etc/devlink.tab
-# Note: the tab after ${DRV} here is important.
+if [ "${ARCH}" = "i386" ]; then
+	# Remove our entry from /etc/devlink.tab
+	# Note: the tab after ${DRV} here is important.
 
-grep -v "^type=ddi_pseudo;name=${DRV}	" ${DEVLINK_TAB} >$TMP.devlink
+	grep -v "^type=ddi_pseudo;name=${DRV}	" ${DEVLINK_TAB} >$TMP.devlink
 
-# Must use 'cp' here in order to preserve the original
-# mode, owner and group of devlink.tab
+	# Must use 'cp' here in order to preserve the original
+	# mode, owner and group of devlink.tab
 
-cp $TMP.devlink ${DEVLINK_TAB}
-rm -f $TMP.devlink
+	cp $TMP.devlink ${DEVLINK_TAB}
+	rm -f $TMP.devlink
+fi
+
 exit 0
--- a/usr/src/pkgdefs/SUNWtpm/prototype_com	Mon Aug 17 20:49:16 2009 -0700
+++ b/usr/src/pkgdefs/SUNWtpm/prototype_com	Mon Aug 17 20:56:15 2009 -0700
@@ -39,13 +39,7 @@
 #!<param>=<value>			# puts parameter in pkg environment
 #
 #
-# List files which are i386 specific here
-#
 # source locations relative to the prototype file
 #
 # SUNWtpm
 #
-d none kernel 0755 root sys
-d none kernel/drv 0755 root sys
-f none kernel/drv/tpm 755 root sys
-f none kernel/drv/tpm.conf 644 root sys
--- a/usr/src/pkgdefs/SUNWtpm/prototype_i386	Mon Aug 17 20:49:16 2009 -0700
+++ b/usr/src/pkgdefs/SUNWtpm/prototype_i386	Mon Aug 17 20:56:15 2009 -0700
@@ -42,5 +42,9 @@
 #
 # SUNWtpm
 #
+d none kernel 0755 root sys
+d none kernel/drv 0755 root sys
+f none kernel/drv/tpm 755 root sys
+f none kernel/drv/tpm.conf 644 root sys
 d none kernel/drv/amd64 0755 root sys
 f none kernel/drv/amd64/tpm 755 root sys
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWtpm/prototype_sparc	Mon Aug 17 20:56:15 2009 -0700
@@ -0,0 +1,50 @@
+#
+# 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
+# or http://www.opensolaris.org/os/licensing.
+# 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.
+#
+# This required package information file contains a list of package contents.
+# The 'pkgmk' command uses this file to identify the contents of a package
+# and their location on the development machine when building the package.
+# Can be created via a text editor or through use of the 'pkgproto' command.
+
+# packaging files
+#!search <pathname pathname ...>	# where to find pkg objects
+#!include <filename>			# include another 'prototype' file
+#!default <mode> <owner> <group>	# default used if not specified on entry
+#!<param>=<value>			# puts parameter in pkg environment
+#
+
+!include prototype_com
+
+#
+# List files which are sparc specific here
+#
+# source locations relative to the prototype file
+#
+# SUNWtpm
+#
+d none platform 0755 root sys
+d none platform/sun4v 0755 root sys
+d none platform/sun4v/kernel 0755 root sys
+d none platform/sun4v/kernel/drv 0755 root sys
+d none platform/sun4v/kernel/drv/sparcv9 0755 root sys
+f none platform/sun4v/kernel/drv/sparcv9/tpm 755 root sys
--- a/usr/src/pkgdefs/common_files/i.pkcs11confbase	Mon Aug 17 20:49:16 2009 -0700
+++ b/usr/src/pkgdefs/common_files/i.pkcs11confbase	Mon Aug 17 20:56:15 2009 -0700
@@ -20,10 +20,9 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
 
 while read src dest
 do
@@ -53,6 +52,21 @@
 
 		mv -f ${dest}.$$ ${dest}
 
+		#
+		# Check if destination already has pkcs11_tpm
+		#
+		egrep 'pkcs11_tpm' $dest > /dev/null 2>& 1
+		if [ $? != 0 ] ; then
+                        pkcs11tpm="/usr/lib/security/\$ISA/pkcs11_tpm.so"
+                        export pkcs11tpm
+			if [ $? = 0 ] ; then
+				nawk '/^# End SUNWcsr/ \
+                        		{ print ENVIRON["pkcs11tpm"] } \
+                        		{ print } \
+				' ${dest} > ${dest}.$$
+				mv -f ${dest}.$$ ${dest}
+			fi
+		fi
 	fi
 done
 exit 0
--- a/usr/src/uts/common/Makefile.files	Mon Aug 17 20:49:16 2009 -0700
+++ b/usr/src/uts/common/Makefile.files	Mon Aug 17 20:56:15 2009 -0700
@@ -1927,4 +1927,4 @@
 #
 NULLDRIVER_OBJS =	nulldriver.o
 
-TPM_OBJS =	tpm.o
+TPM_OBJS =	tpm.o tpm_hcall.o
--- a/usr/src/uts/common/Makefile.rules	Mon Aug 17 20:49:16 2009 -0700
+++ b/usr/src/uts/common/Makefile.rules	Mon Aug 17 20:56:15 2009 -0700
@@ -1404,6 +1404,9 @@
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
 
+$(OBJS_DIR)/%.o:		$(UTSBASE)/common/io/tpm/%.s
+	$(COMPILE.s) -o $@ $<
+
 #
 # SVM
 #
@@ -2440,5 +2443,8 @@
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/tpm/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
+$(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/tpm/%.s
+	@($(LHEAD) $(LINT.c) $< $(LTAIL))
+
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/vr/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
--- a/usr/src/uts/common/io/tpm/tpm.c	Mon Aug 17 20:49:16 2009 -0700
+++ b/usr/src/uts/common/io/tpm/tpm.c	Mon Aug 17 20:56:15 2009 -0700
@@ -42,9 +42,17 @@
 #include <sys/cred.h>		/* used by open,close,read */
 #include <sys/uio.h>		/* used by read */
 #include <sys/stat.h>		/* defines S_IFCHR */
+#include <sys/crypto/common.h>
+#include <sys/crypto/impl.h>
+#include <sys/crypto/spi.h>
 
 #include <sys/byteorder.h>	/* for ntohs, ntohl, htons, htonl */
 
+#ifdef sun4v
+#include <sys/hypervisor_api.h>
+#include <sys/hsvc.h>
+#endif
+
 #include <tss/platform.h> 	/* from SUNWtss */
 #include <tss/tpm.h> 		/* from SUNWtss */
 
@@ -88,6 +96,7 @@
 #define	TEN_MILLISECONDS	10000	/* 10 milliseconds */
 #define	FOUR_HUNDRED_MILLISECONDS 400000	/* 4 hundred milliseconds */
 
+#define	DEFAULT_LOCALITY 0
 /*
  * TPM input/output buffer offsets
  */
@@ -137,7 +146,7 @@
 
 /* Auxilliary */
 static int receive_data(tpm_state_t *, uint8_t *, size_t);
-static inline int tpm_lock(tpm_state_t *);
+static inline int tpm_io_lock(tpm_state_t *);
 static inline void tpm_unlock(tpm_state_t *);
 static void tpm_cleanup(dev_info_t *, tpm_state_t *);
 
@@ -211,9 +220,160 @@
 	NULL
 };
 
+#ifdef KCF_TPM_RNG_PROVIDER
+
+#define	IDENT_TPMRNG	"TPM Random Number Generator"
+/*
+ * CSPI information (entry points, provider info, etc.)
+ */
+static void tpmrng_provider_status(crypto_provider_handle_t, uint_t *);
+
+static crypto_control_ops_t tpmrng_control_ops = {
+	tpmrng_provider_status
+};
+
+static int tpmrng_seed_random(crypto_provider_handle_t, crypto_session_id_t,
+    uchar_t *, size_t, uint_t, uint32_t, crypto_req_handle_t);
+
+static int tpmrng_generate_random(crypto_provider_handle_t,
+    crypto_session_id_t, uchar_t *, size_t, crypto_req_handle_t);
+
+static crypto_random_number_ops_t tpmrng_random_number_ops = {
+	tpmrng_seed_random,
+	tpmrng_generate_random
+};
+
+static int tpmrng_ext_info(crypto_provider_handle_t,
+	crypto_provider_ext_info_t *,
+	crypto_req_handle_t);
+
+static crypto_provider_management_ops_t tpmrng_extinfo_op = {
+	tpmrng_ext_info,
+	NULL,
+	NULL,
+	NULL
+};
+
+static int tpmrng_register(tpm_state_t *);
+static int tpmrng_unregister(tpm_state_t *);
+
+static crypto_ops_t tpmrng_crypto_ops = {
+	&tpmrng_control_ops,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	&tpmrng_random_number_ops,
+	NULL,
+	NULL,
+	NULL,
+	&tpmrng_extinfo_op,
+	NULL,
+	NULL
+};
+
+static crypto_provider_info_t tpmrng_prov_info = {
+	CRYPTO_SPI_VERSION_2,
+	"TPM Random Number Provider",
+	CRYPTO_HW_PROVIDER,
+	NULL,
+	NULL,
+	&tpmrng_crypto_ops,
+	0,
+	NULL,
+	0,
+	NULL
+};
+#endif /* KCF_TPM_RNG_PROVIDER */
+
 static void *statep = NULL;
 
 /*
+ * 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.
+ */
+#define	TPM_EXCLUSIVE_LOCK(tpm)  { \
+	mutex_enter(&tpm->pm_mutex); \
+	while (tpm->suspended) \
+		cv_wait(&tpm->suspend_cv, &tpm->pm_mutex); \
+	mutex_exit(&tpm->pm_mutex); }
+
+/*
+ * TPM accessor functions
+ */
+#ifdef sun4v
+
+extern uint64_t
+hcall_tpm_get(uint64_t, uint64_t, uint64_t, uint64_t *);
+
+extern uint64_t
+hcall_tpm_put(uint64_t, uint64_t, uint64_t, uint64_t);
+
+static inline uint8_t
+tpm_get8(tpm_state_t *tpm, unsigned long offset)
+{
+	uint64_t value;
+
+	ASSERT(tpm != NULL);
+	(void) hcall_tpm_get(tpm->locality, offset, sizeof (uint8_t), &value);
+	return ((uint8_t)value);
+}
+
+static inline uint32_t
+tpm_get32(tpm_state_t *tpm, unsigned long offset)
+{
+	uint64_t value;
+
+	ASSERT(tpm != NULL);
+	(void) hcall_tpm_get(tpm->locality, offset, sizeof (uint32_t), &value);
+	return ((uint32_t)value);
+}
+
+static inline void
+tpm_put8(tpm_state_t *tpm, unsigned long offset, uint8_t value)
+{
+	ASSERT(tpm != NULL);
+	(void) hcall_tpm_put(tpm->locality, offset, sizeof (uint8_t), value);
+}
+
+#else
+
+static inline uint8_t
+tpm_get8(tpm_state_t *tpm, unsigned long offset)
+{
+	ASSERT(tpm != NULL);
+
+	return (ddi_get8(tpm->handle,
+	    (uint8_t *)(TPM_LOCALITY_OFFSET(tpm->locality) |
+	    (uintptr_t)tpm->addr + offset)));
+}
+
+static inline uint32_t
+tpm_get32(tpm_state_t *tpm, unsigned long offset)
+{
+	ASSERT(tpm != NULL);
+	return (ddi_get32(tpm->handle,
+	    (uint32_t *)(TPM_LOCALITY_OFFSET(tpm->locality) |
+	    (uintptr_t)tpm->addr + offset)));
+}
+
+static inline void
+tpm_put8(tpm_state_t *tpm, unsigned long offset, uint8_t value)
+{
+	ASSERT(tpm != NULL);
+	ddi_put8(tpm->handle,
+	    (uint8_t *)(TPM_LOCALITY_OFFSET(tpm->locality) |
+	    (uintptr_t)tpm->addr + offset), value);
+}
+
+#endif /* sun4v */
+
+/*
  * TPM commands to get the TPM's properties, e.g.,timeout
  */
 /*ARGSUSED*/
@@ -580,8 +740,13 @@
 	/* Check the return code */
 	ret = load32(buf, TPM_RETURN_OFFSET);
 	if (ret != TPM_SUCCESS) {
-		cmn_err(CE_WARN, "%s: command failed with ret code: %x",
-		    myname, ret);
+		if (ret == TPM_E_DEACTIVATED)
+			cmn_err(CE_WARN, "%s: TPM is deactivated", myname);
+		else if (ret == TPM_E_DISABLED)
+			cmn_err(CE_WARN, "%s: TPM is disabled", myname);
+		else
+			cmn_err(CE_WARN, "%s: TPM error code 0x%0x",
+			    myname, ret);
 		return (DDI_FAILURE);
 	}
 
@@ -612,12 +777,8 @@
 		 * burstcnt is stored as a little endian value
 		 * 'ntohs' doesn't work since the value is not word-aligned
 		 */
-		burstcnt = ddi_get8(tpm->handle,
-		    (uint8_t *)(tpm->addr+
-		    TPM_STS_(tpm->locality)+1));
-		burstcnt += ddi_get8(tpm->handle,
-		    (uint8_t *)(tpm->addr+
-		    TPM_STS_(tpm->locality)+2)) << 8;
+		burstcnt = tpm_get8(tpm, TPM_STS + 1);
+		burstcnt += tpm_get8(tpm, TPM_STS + 2) << 8;
 
 		if (burstcnt)
 			return (burstcnt);
@@ -636,11 +797,7 @@
  */
 static void
 tpm_set_ready(tpm_state_t *tpm) {
-	ASSERT(tpm != NULL);
-
-	ddi_put8(tpm->handle,
-	    (uint8_t *)(tpm->addr+TPM_STS_(tpm->locality)),
-	    TPM_STS_CMD_READY);
+	tpm_put8(tpm, TPM_STS, TPM_STS_CMD_READY);
 }
 
 static int
@@ -657,7 +814,7 @@
 	while (size < bufsiz &&
 		(tpm_wait_for_stat(tpm,
 		    (TPM_STS_DATA_AVAIL|TPM_STS_VALID),
-		    (ddi_get_lbolt() + tpm->timeout_c)) == DDI_SUCCESS)) {
+		    tpm->timeout_c) == DDI_SUCCESS)) {
 		/*
 		 * Burstcount should be available within TIMEOUT_D
 		 * after STS is set to valid
@@ -665,18 +822,14 @@
 		 */
 		burstcnt = tpm_get_burstcount(tpm);
 		for (; burstcnt > 0 && size < bufsiz; burstcnt--) {
-			buf[size++] = ddi_get8(tpm->handle,
-			    (uint8_t *)(tpm->addr +
-			    TPM_DATA_FIFO_(tpm->locality)));
+			buf[size++] = tpm_get8(tpm, TPM_DATA_FIFO);
 		}
 	}
 	stsbits = tis_get_status(tpm);
 	/* check to see if we need to retry (just once) */
 	if (size < bufsiz && !(stsbits & TPM_STS_DATA_AVAIL) && retried == 0) {
 		/* issue responseRetry (TIS 1.2 pg 54) */
-		ddi_put8(tpm->handle,
-		    (uint8_t *)(tpm->addr+TPM_STS_(tpm->locality)),
-		    TPM_STS_RESPONSE_RETRY);
+		tpm_put8(tpm, TPM_STS, TPM_STS_RESPONSE_RETRY);
 		/* update the retry counter so we only retry once */
 		retried++;
 		/* reset the size to 0 and reread the entire response */
@@ -734,8 +887,7 @@
 	}
 
 	/* The TPM MUST set the state to stsValid within TIMEOUT_C */
-	ret = tpm_wait_for_stat(tpm, TPM_STS_VALID,
-	    ddi_get_lbolt() + tpm->timeout_c);
+	ret = tpm_wait_for_stat(tpm, TPM_STS_VALID, tpm->timeout_c);
 
 	status = tis_get_status(tpm);
 	if (ret != DDI_SUCCESS) {
@@ -783,21 +935,12 @@
 		return (DDI_FAILURE);
 	}
 
-	/* Be in the right locality (aren't we always in locality 0?) */
-	if (tis_request_locality(tpm, 0) != DDI_SUCCESS) {
-		cmn_err(CE_WARN, "%s: tis_request_locality didn't enter "
-		    "locality 0", myname);
-		return (DDI_FAILURE);
-	}
-
 	/* Put the TPM in ready state */
 	status = tis_get_status(tpm);
 
 	if (!(status & TPM_STS_CMD_READY)) {
 		tpm_set_ready(tpm);
-		ret = tpm_wait_for_stat(tpm,
-		    TPM_STS_CMD_READY,
-		    (ddi_get_lbolt() + tpm->timeout_b));
+		ret = tpm_wait_for_stat(tpm, TPM_STS_CMD_READY, tpm->timeout_b);
 		if (ret != DDI_SUCCESS) {
 			cmn_err(CE_WARN, "%s: could not put the TPM "
 			    "in the command ready state:"
@@ -823,14 +966,12 @@
 		}
 
 		for (; burstcnt > 0 && count < bufsiz - 1; burstcnt--) {
-			ddi_put8(tpm->handle, (uint8_t *)(tpm->addr+
-			    TPM_DATA_FIFO_(tpm->locality)), buf[count]);
+			tpm_put8(tpm, TPM_DATA_FIFO, buf[count]);
 			count++;
 		}
 		/* Wait for TPM to indicate that it is ready for more data */
 		ret = tpm_wait_for_stat(tpm,
-		    (TPM_STS_VALID | TPM_STS_DATA_EXPECT),
-		    (ddi_get_lbolt() + tpm->timeout_c));
+		    (TPM_STS_VALID | TPM_STS_DATA_EXPECT), tpm->timeout_c);
 		if (ret != DDI_SUCCESS) {
 			cmn_err(CE_WARN, "%s: TPM didn't enter stsvalid "
 			    "state after sending the data:", myname);
@@ -840,13 +981,11 @@
 	/* We can't exit the loop above unless we wrote bufsiz-1 bytes */
 
 	/* Write last byte */
-	ddi_put8(tpm->handle, (uint8_t *)(tpm->addr +
-	    TPM_DATA_FIFO_(tpm->locality)), buf[count]);
+	tpm_put8(tpm, TPM_DATA_FIFO, buf[count]);
 	count++;
 
 	/* Wait for the TPM to enter Valid State */
-	ret = tpm_wait_for_stat(tpm,
-	    TPM_STS_VALID, (ddi_get_lbolt() + tpm->timeout_c));
+	ret = tpm_wait_for_stat(tpm, TPM_STS_VALID, tpm->timeout_c);
 	if (ret == DDI_FAILURE) {
 		cmn_err(CE_WARN, "%s: tpm didn't enter Valid state", myname);
 		goto FAIL;
@@ -865,14 +1004,13 @@
 	 * Final step: Writing TPM_STS_GO to TPM_STS
 	 * register will actually send the command.
 	 */
-	ddi_put8(tpm->handle, (uint8_t *)(tpm->addr+TPM_STS_(tpm->locality)),
-	    TPM_STS_GO);
+	tpm_put8(tpm, TPM_STS, TPM_STS_GO);
 
 	/* Ordinal/Command_code is located in buf[6..9] */
 	ordinal = load32(buf, TPM_COMMAND_CODE_OFFSET);
 
 	ret = tpm_wait_for_stat(tpm, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
-	    ddi_get_lbolt() + tpm_get_ordinal_duration(tpm, ordinal));
+	    tpm_get_ordinal_duration(tpm, ordinal));
 	if (ret == DDI_FAILURE) {
 		status = tis_get_status(tpm);
 		if (!(status & TPM_STS_DATA_AVAIL) ||
@@ -904,17 +1042,14 @@
 	ASSERT(tpm != NULL && locality >= 0 && locality < 5);
 
 	if (force ||
-	    (ddi_get8(tpm->handle,
-		(uchar_t *)(tpm->addr+TPM_ACCESS_(locality)))
-	    & (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID))
-	    == (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) {
+	    (tpm_get8(tpm, TPM_ACCESS) &
+	    (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) ==
+	    (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) {
 		/*
 		 * Writing 1 to active locality bit in TPM_ACCESS
 		 * register reliquishes the control of the locality
 		 */
-		ddi_put8(tpm->handle,
-		    (uint8_t *)(tpm->addr+TPM_ACCESS_(locality)),
-		    TPM_ACCESS_ACTIVE_LOCALITY);
+		tpm_put8(tpm, TPM_ACCESS, TPM_ACCESS_ACTIVE_LOCALITY);
 	}
 }
 
@@ -925,17 +1060,25 @@
 static int
 tis_check_active_locality(tpm_state_t *tpm, char locality) {
 	uint8_t access_bits;
+	uint8_t old_locality;
 
 	ASSERT(tpm != NULL && locality >= 0 && locality < 5);
 
-	access_bits = ddi_get8(tpm->handle,
-	    (uint8_t *)(tpm->addr+TPM_ACCESS_(locality)));
+	old_locality = tpm->locality;
+	tpm->locality = locality;
+
+	/* Just check to see if the requested localit works */
+	access_bits = tpm_get8(tpm, TPM_ACCESS);
 	access_bits &= (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID);
 
-	if (access_bits == (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID))
+	/* this was just a check, not a request to switch */
+	tpm->locality = old_locality;
+
+	if (access_bits == (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) {
 		return (DDI_SUCCESS);
-	else
+	} else {
 		return (DDI_FAILURE);
+	}
 }
 
 /* Request the TPM to be in the given locality */
@@ -955,8 +1098,7 @@
 		return (DDI_SUCCESS);
 	}
 
-	ddi_put8(tpm->handle, tpm->addr+TPM_ACCESS_(locality),
-	    TPM_ACCESS_REQUEST_USE);
+	tpm_put8(tpm, TPM_ACCESS, TPM_ACCESS_REQUEST_USE);
 	timeout = ddi_get_lbolt() + tpm->timeout_a;
 
 	/* Using polling */
@@ -964,8 +1106,8 @@
 		!= DDI_SUCCESS) {
 		if (ddi_get_lbolt() >= timeout) {
 			cmn_err(CE_WARN, "%s (interrupt-disabled) "
-			    "tis_request_locality timed out",
-			    myname);
+			    "tis_request_locality timed out (timeout_a = %ld)",
+			    myname, tpm->timeout_a);
 			return (DDI_FAILURE);
 		}
 		delay(tpm->timeout_poll);
@@ -978,21 +1120,21 @@
 /* Read the status register */
 static uint8_t
 tis_get_status(tpm_state_t *tpm) {
-	return (ddi_get8(tpm->handle,
-	    (uint8_t *)(tpm->addr+TPM_STS_(tpm->locality))));
+	return (tpm_get8(tpm, TPM_STS));
 }
 
 static int
-tpm_wait_for_stat(tpm_state_t *tpm, uint8_t mask, clock_t absolute_timeout) {
+tpm_wait_for_stat(tpm_state_t *tpm, uint8_t mask, clock_t timeout) {
 	char *myname = "tpm_wait_for_stat";
+	clock_t absolute_timeout = ddi_get_lbolt() + timeout;
 
 	/* Using polling */
 	while ((tis_get_status(tpm) & mask) != mask) {
 		if (ddi_get_lbolt() >= absolute_timeout) {
 			/* Timeout reached */
 			cmn_err(CE_WARN, "%s: using "
-			    "polling:reached timeout",
-			    myname);
+			    "polling - reached timeout (%ld usecs)",
+			    myname, drv_hztousec(timeout));
 			return (DDI_FAILURE);
 		}
 		delay(tpm->timeout_poll);
@@ -1012,7 +1154,6 @@
 	uint32_t intf_caps;
 	int ret;
 	char *myname = "tis_init";
-	uintptr_t aptr = (uintptr_t)tpm->addr;
 
 	/*
 	 * Temporarily set up timeouts before we get the real timeouts
@@ -1035,8 +1176,7 @@
 	tpm->duration[TPM_UNDEFINED] = drv_usectohz(TPM_DEFAULT_DURATION);
 
 	/* Find out supported capabilities */
-	intf_caps = ddi_get32(tpm->handle,
-	    (uint32_t *)(aptr + TPM_INTF_CAP_(0)));
+	intf_caps = tpm_get32(tpm, TPM_INTF_CAP);
 
 	/* Upper 3 bytes should always return 0 */
 	if (intf_caps & 0x7FFFFF00) {
@@ -1063,9 +1203,10 @@
 	 * Before we start writing anything to TPM's registers,
 	 * make sure we are in locality 0
 	 */
-	ret = tis_request_locality(tpm, 0);
+	ret = tis_request_locality(tpm, DEFAULT_LOCALITY);
 	if (ret != DDI_SUCCESS) {
-		cmn_err(CE_WARN, "%s: Unable to request locality 0", myname);
+		cmn_err(CE_WARN, "%s: Unable to request locality %d", myname,
+		    DEFAULT_LOCALITY);
 		return (DDI_FAILURE);
 	} /* Now we can refer to the locality as tpm->locality */
 
@@ -1114,8 +1255,10 @@
 
 	ret = ddi_soft_state_init(&statep, sizeof (tpm_state_t), 1);
 	if (ret)
+{
+		cmn_err(CE_WARN, "ddi_soft_state_init failed: %d", ret);
 		return (ret);
-
+}
 	ret = mod_install(&tpm_ml);
 	if (ret != 0) {
 		cmn_err(CE_WARN, "_init: mod_install returned non-zero");
@@ -1141,10 +1284,11 @@
 _fini()
 {
 	int ret;
+
 	ret = mod_remove(&tpm_ml);
-	if (ret != 0) {
+	if (ret != 0)
 		return (ret);
-	}
+
 	ddi_soft_state_fini(&statep);
 
 	return (ret);
@@ -1166,40 +1310,58 @@
 	return (DDI_SUCCESS);
 }
 
+#ifdef sun4v
+static uint64_t hsvc_tpm_minor = 0;
+static hsvc_info_t hsvc_tpm = {
+	HSVC_REV_1, NULL, HSVC_GROUP_TPM, 1, 0, NULL
+};
+#endif
+
 /*
  * Sun DDI/DDK entry points
  */
 static int
 tpm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 {
-	int ret, idx;
+	int ret;
 	int instance;
-	int nregs;
+#ifndef sun4v
+	int idx, nregs;
+#endif
 	char *myname = "tpm_attach";
 	tpm_state_t *tpm = NULL;
 
 	ASSERT(dip != NULL);
 
 	instance = ddi_get_instance(dip);
+	if (instance < 0)
+		return (DDI_FAILURE);
 
 	/* Nothing out of ordinary here */
 	switch (cmd) {
 	case DDI_ATTACH:
-		ret = ddi_soft_state_zalloc(statep, instance);
-		if (ret != DDI_SUCCESS) {
-			cmn_err(CE_WARN, "%s could not allocate tpm_state_t",
+		if (ddi_soft_state_zalloc(statep, instance) == DDI_SUCCESS) {
+			tpm = ddi_get_soft_state(statep, instance);
+			if (tpm == NULL) {
+				cmn_err(CE_WARN,
+				    "%s: cannot get state information.",
+				    myname);
+				return (DDI_FAILURE);
+			}
+			tpm->dip = dip;
+		} else {
+			cmn_err(CE_WARN,
+			    "%s: cannot allocate state information.",
 			    myname);
-			goto FAIL;
+			return (DDI_FAILURE);
 		}
-		tpm = ddi_get_soft_state(statep, instance);
-		tpm->dip = dip;
 		break;
 	case DDI_RESUME:
 		tpm = ddi_get_soft_state(statep, instance);
 		if (tpm == NULL) {
-			cmn_err(CE_WARN, "%s: tpm_state_t is NULL",
+			cmn_err(CE_WARN, "%s: cannot get state information.",
 			    myname);
-			goto FAIL;
+			return (DDI_FAILURE);
 		}
 		return (tpm_resume(tpm));
 	default:
@@ -1211,6 +1373,15 @@
 	/* Zeroize the flag, which is used to keep track of what is allocated */
 	tpm->flags = 0;
 
+#ifdef sun4v
+	ret = hsvc_register(&hsvc_tpm, &hsvc_tpm_minor);
+	if (ret != 0) {
+		cmn_err(CE_WARN, "%s: failed to register with "
+		    "hypervisor: 0x%0x", myname, ret);
+		goto FAIL;
+	}
+	tpm->flags |= TPM_HSVC_REGISTERED;
+#else
 	tpm->accattr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
 	tpm->accattr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
 	tpm->accattr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
@@ -1248,17 +1419,19 @@
 		goto FAIL;
 	}
 	tpm->flags |= TPM_DIDREGSMAP;
-
+#endif
 	/* Enable TPM device according to the TIS specification */
 	ret = tis_init(tpm);
 	if (ret != DDI_SUCCESS) {
-		cmn_err(CE_WARN, "%s: tis_init() failed ret: %d",
+		cmn_err(CE_WARN, "%s: tis_init() failed with error %d",
 		    myname, ret);
 
 		/* We need to clean up the ddi_regs_map_setup call */
-		ddi_regs_map_free(&tpm->handle);
-		tpm->handle = NULL;
-		tpm->flags &= ~TPM_DIDREGSMAP;
+		if (tpm->flags & TPM_DIDREGSMAP) {
+			ddi_regs_map_free(&tpm->handle);
+			tpm->handle = NULL;
+			tpm->flags &= ~TPM_DIDREGSMAP;
+		}
 		goto FAIL;
 	}
 
@@ -1280,10 +1453,6 @@
 	/* Initialize the buffer and the lock associated with it */
 	tpm->bufsize = TPM_IO_BUF_SIZE;
 	tpm->iobuf = kmem_zalloc((sizeof (uint8_t))*(tpm->bufsize), KM_SLEEP);
-	if (tpm->iobuf == NULL) {
-		cmn_err(CE_WARN, "%s: failed to allocate iobuf", myname);
-		goto FAIL;
-	}
 	tpm->flags |= TPM_DID_IO_ALLOC;
 
 	mutex_init(&tpm->iobuf_lock, NULL, MUTEX_DRIVER, NULL);
@@ -1301,8 +1470,16 @@
 	}
 	tpm->flags |= TPM_DIDMINOR;
 
+#ifdef KCF_TPM_RNG_PROVIDER
+	/* register RNG with kcf */
+	if (tpmrng_register(tpm) != DDI_SUCCESS)
+		cmn_err(CE_WARN, "%s: tpm RNG failed to register with kcf",
+		    myname);
+#endif
+
 	return (DDI_SUCCESS);
 FAIL:
+	cmn_err(CE_WARN, "%s: tpm failed to attach", myname);
 	if (tpm != NULL) {
 		tpm_cleanup(dip, tpm);
 		ddi_soft_state_free(statep, instance);
@@ -1322,6 +1499,16 @@
 	if (tpm == NULL)
 		return;
 
+#ifdef KCF_TPM_RNG_PROVIDER
+	(void) tpmrng_unregister(tpm);
+#endif
+
+#ifdef sun4v
+	if (tpm->flags & TPM_HSVC_REGISTERED) {
+		(void) hsvc_unregister(&hsvc_tpm);
+		tpm->flags &= ~(TPM_HSVC_REGISTERED);
+	}
+#endif
 	if (tpm->flags & TPM_DID_MUTEX) {
 		mutex_destroy(&tpm->dev_lock);
 		tpm->flags &= ~(TPM_DID_MUTEX);
@@ -1378,6 +1565,9 @@
 	ASSERT(dip != NULL);
 
 	instance = ddi_get_instance(dip);
+	if (instance < 0)
+		return (DDI_FAILURE);
+
 	if ((tpm = ddi_get_soft_state(statep, instance)) == NULL) {
 		cmn_err(CE_WARN, "%s: stored pointer to tpm state is NULL",
 		    myname);
@@ -1463,10 +1653,7 @@
 		    myname, otyp, OTYP_CHR);
 		return (EINVAL);
 	}
-	mutex_enter(&tpm->pm_mutex);
-	while (tpm->suspended)
-		cv_wait(&tpm->suspend_cv, &tpm->pm_mutex);
-	mutex_exit(&tpm->pm_mutex);
+	TPM_EXCLUSIVE_LOCK(tpm);
 
 	mutex_enter(&tpm->dev_lock);
 	if (tpm->dev_held) {
@@ -1502,10 +1689,7 @@
 		    myname, otyp, OTYP_CHR);
 		return (EINVAL);
 	}
-	mutex_enter(&tpm->pm_mutex);
-	while (tpm->suspended)
-		cv_wait(&tpm->suspend_cv, &tpm->pm_mutex);
-	mutex_exit(&tpm->pm_mutex);
+	TPM_EXCLUSIVE_LOCK(tpm);
 
 	ASSERT(tpm->dev_held);
 
@@ -1538,13 +1722,10 @@
 		return (EFAULT);
 	}
 
-	mutex_enter(&tpm->pm_mutex);
-	while (tpm->suspended)
-		cv_wait(&tpm->suspend_cv, &tpm->pm_mutex);
-	mutex_exit(&tpm->pm_mutex);
+	TPM_EXCLUSIVE_LOCK(tpm);
 
 	/* Receive the data after requiring the lock */
-	ret = tpm_lock(tpm);
+	ret = tpm_io_lock(tpm);
 
 	/* Timeout reached */
 	if (ret == ETIME)
@@ -1614,10 +1795,7 @@
 		return (EFAULT);
 	}
 
-	mutex_enter(&tpm->pm_mutex);
-	while (tpm->suspended)
-		cv_wait(&tpm->suspend_cv, &tpm->pm_mutex);
-	mutex_exit(&tpm->pm_mutex);
+	TPM_EXCLUSIVE_LOCK(tpm);
 
 	len = uiop->uio_resid;
 	if (len == 0) {
@@ -1626,7 +1804,7 @@
 	}
 
 	/* Get the lock for using iobuf */
-	ret = tpm_lock(tpm);
+	ret = tpm_io_lock(tpm);
 	/* Timeout Reached */
 	if (ret == ETIME)
 		return (ret);
@@ -1682,7 +1860,7 @@
  * This is to deal with the contentions for the iobuf
  */
 static inline int
-tpm_lock(tpm_state_t *tpm)
+tpm_io_lock(tpm_state_t *tpm)
 {
 	int ret;
 	clock_t timeout;
@@ -1698,8 +1876,10 @@
 		if (ret <= 0) {
 			/* Timeout reached */
 			mutex_exit(&tpm->iobuf_lock);
-			cmn_err(CE_WARN, "tpm_lock:iorequest timed out");
-			return (ETIME);
+#ifdef DEBUG
+			cmn_err(CE_WARN, "tpm_io_lock:iorequest timed out");
+#endif
+			return (CRYPTO_BUSY);
 		}
 	}
 	tpm->iobuf_inuse = 1;
@@ -1720,3 +1900,244 @@
 	cv_broadcast(&tpm->iobuf_cv);
 	mutex_exit(&tpm->iobuf_lock);
 }
+
+#ifdef KCF_TPM_RNG_PROVIDER
+/*
+ * Random number generator entry points
+ */
+static void
+strncpy_spacepad(uchar_t *s1, char *s2, int n)
+{
+	int s2len = strlen(s2);
+	(void) strncpy((char *)s1, s2, n);
+	if (s2len < n)
+		(void) memset(s1 + s2len, ' ', n - s2len);
+}
+
+/*ARGSUSED*/
+static int
+tpmrng_ext_info(crypto_provider_handle_t prov,
+	crypto_provider_ext_info_t *ext_info,
+	crypto_req_handle_t cfreq)
+{
+	tpm_state_t *tpm = (tpm_state_t *)prov;
+	char buf[64];
+
+	if (tpm == NULL)
+		return (DDI_FAILURE);
+
+	strncpy_spacepad(ext_info->ei_manufacturerID,
+	    (char *)tpm->vers_info.tpmVendorID,
+	    sizeof (ext_info->ei_manufacturerID));
+
+	strncpy_spacepad(ext_info->ei_model, "0",
+	    sizeof (ext_info->ei_model));
+	strncpy_spacepad(ext_info->ei_serial_number, "0",
+	    sizeof (ext_info->ei_serial_number));
+
+	ext_info->ei_flags = CRYPTO_EXTF_RNG | CRYPTO_EXTF_SO_PIN_LOCKED;
+	ext_info->ei_max_session_count = CRYPTO_EFFECTIVELY_INFINITE;
+	ext_info->ei_max_pin_len = 0;
+	ext_info->ei_min_pin_len = 0;
+	ext_info->ei_total_public_memory = CRYPTO_UNAVAILABLE_INFO;
+	ext_info->ei_free_public_memory = CRYPTO_UNAVAILABLE_INFO;
+	ext_info->ei_total_private_memory = CRYPTO_UNAVAILABLE_INFO;
+	ext_info->ei_free_public_memory = CRYPTO_UNAVAILABLE_INFO;
+	ext_info->ei_time[0] = 0;
+
+	ext_info->ei_hardware_version.cv_major = tpm->vers_info.version.major;
+	ext_info->ei_hardware_version.cv_minor = tpm->vers_info.version.minor;
+	ext_info->ei_firmware_version.cv_major =
+	    tpm->vers_info.version.revMajor;
+	ext_info->ei_firmware_version.cv_minor =
+	    tpm->vers_info.version.revMinor;
+
+	(void) snprintf(buf, sizeof (buf), "tpmrng TPM RNG");
+
+	strncpy_spacepad(ext_info->ei_label, buf,
+	    sizeof (ext_info->ei_label));
+#undef	BUFSZ
+	return (CRYPTO_SUCCESS);
+
+}
+
+static int
+tpmrng_register(tpm_state_t *tpm)
+{
+	int		ret;
+	char 		ID[64];
+	crypto_mech_name_t	*rngmech;
+
+	ASSERT(tpm != NULL);
+
+	(void) snprintf(ID, sizeof (ID), "tpmrng %s", IDENT_TPMRNG);
+
+	tpmrng_prov_info.pi_provider_description = ID;
+	tpmrng_prov_info.pi_provider_dev.pd_hw = tpm->dip;
+	tpmrng_prov_info.pi_provider_handle = tpm;
+
+	ret = crypto_register_provider(&tpmrng_prov_info, &tpm->n_prov);
+	if (ret != CRYPTO_SUCCESS) {
+		tpm->n_prov = NULL;
+		return (DDI_FAILURE);
+	}
+
+	crypto_provider_notification(tpm->n_prov, CRYPTO_PROVIDER_READY);
+
+	rngmech = kmem_zalloc(strlen("random") + 1, KM_SLEEP);
+	(void) memcpy(rngmech, "random", 6);
+	ret = crypto_load_dev_disabled("tpm", ddi_get_instance(tpm->dip),
+	    1, rngmech);
+	if (ret != CRYPTO_SUCCESS) {
+		cmn_err(CE_WARN, "crypto_load_dev_disabled failed (%d)", ret);
+	}
+	return (DDI_SUCCESS);
+}
+
+static int
+tpmrng_unregister(tpm_state_t *tpm)
+{
+	int ret;
+	ASSERT(tpm != NULL);
+	if (tpm->n_prov) {
+		ret = crypto_unregister_provider(tpm->n_prov);
+		tpm->n_prov = NULL;
+		if (ret != CRYPTO_SUCCESS)
+			return (DDI_FAILURE);
+	}
+	return (DDI_SUCCESS);
+}
+
+/*ARGSUSED*/
+static void
+tpmrng_provider_status(crypto_provider_handle_t provider, uint_t *status)
+{
+	*status = CRYPTO_PROVIDER_READY;
+}
+
+/*ARGSUSED*/
+static int
+tpmrng_seed_random(crypto_provider_handle_t provider, crypto_session_id_t sid,
+    uchar_t *buf, size_t len, uint_t entropy_est, uint32_t flags,
+    crypto_req_handle_t req)
+{
+	int ret;
+	tpm_state_t *tpm;
+	uint32_t len32;
+	/* Max length of seed is 256 bytes, add 14 for header. */
+	uint8_t cmdbuf[270] = {
+		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) */
+	};
+	uint32_t buflen;
+
+	if (len == 0 || len > 255 || buf == NULL)
+		return (CRYPTO_ARGUMENTS_BAD);
+
+	tpm = (tpm_state_t *)provider;
+	if (tpm == NULL)
+		return (CRYPTO_INVALID_CONTEXT);
+
+	/* Acquire lock for exclusive use of TPM */
+	TPM_EXCLUSIVE_LOCK(tpm);
+
+	ret = tpm_io_lock(tpm);
+	/* Timeout reached */
+	if (ret == CRYPTO_BUSY)
+		return (ret);
+
+	/* TPM only handles 32 bit length, so truncate if too big. */
+	len32 = (uint32_t)len;
+	buflen = len32 + 14;
+
+	/* The length must be in network order */
+	buflen = htonl(buflen);
+	bcopy(&buflen, cmdbuf + 2, sizeof (uint32_t));
+
+	/* Convert it back */
+	buflen = ntohl(buflen);
+
+	/* length must be in network order */
+	len32 = htonl(len32);
+	bcopy(&len32, cmdbuf + 10, sizeof (uint32_t));
+
+	/* convert it back */
+	len32 = ntohl(len32);
+
+	bcopy(buf,  cmdbuf + 14, len32);
+
+	ret = itpm_command(tpm, cmdbuf, buflen);
+	tpm_unlock(tpm);
+
+	if (ret != DDI_SUCCESS) {
+#ifdef DEBUG
+		cmn_err(CE_WARN, "tpmrng_seed_random failed");
+#endif
+		return (CRYPTO_FAILED);
+	}
+
+	return (CRYPTO_SUCCESS);
+}
+
+/* ARGSUSED */
+static int
+tpmrng_generate_random(crypto_provider_handle_t provider,
+    crypto_session_id_t sid, uchar_t *buf, size_t len, crypto_req_handle_t req)
+{
+	int ret;
+	tpm_state_t *tpm;
+	uint8_t hdr[14] = {
+		0, 193,		/* TPM_TAG_RQU COMMAND */
+		0, 0, 0, 14,	/* paramsize in bytes */
+		0, 0, 0, TPM_ORD_GetRandom,
+		0, 0, 0, 0
+	};
+	uint8_t *cmdbuf = NULL;
+	uint32_t len32 = (uint32_t)len;
+	uint32_t buflen = len32 + sizeof (hdr);
+
+	if (len == 0 || buf == NULL)
+		return (CRYPTO_ARGUMENTS_BAD);
+
+	tpm = (tpm_state_t *)provider;
+	if (tpm == NULL)
+		return (CRYPTO_INVALID_CONTEXT);
+
+	TPM_EXCLUSIVE_LOCK(tpm);
+
+	ret = tpm_io_lock(tpm);
+	/* Timeout reached */
+	if (ret == CRYPTO_BUSY)
+		return (ret);
+
+	cmdbuf = kmem_zalloc(buflen, KM_SLEEP);
+	bcopy(hdr, cmdbuf, sizeof (hdr));
+
+	/* Length is written in network byte order */
+	len32 = htonl(len32);
+	bcopy(&len32, cmdbuf + 10, sizeof (uint32_t));
+
+	ret = itpm_command(tpm, cmdbuf, buflen);
+	if (ret != DDI_SUCCESS) {
+#ifdef DEBUG
+		cmn_err(CE_WARN, "tpmrng_generate_random failed");
+#endif
+		kmem_free(cmdbuf, buflen);
+		tpm_unlock(tpm);
+		return (CRYPTO_FAILED);
+	}
+
+	/* Find out how many bytes were really returned */
+	len32 = load32(cmdbuf, 10);
+
+	/* Copy the random bytes back to the callers buffer */
+	bcopy(cmdbuf + 14, buf, len32);
+
+	kmem_free(cmdbuf, buflen);
+	tpm_unlock(tpm);
+
+	return (CRYPTO_SUCCESS);
+}
+#endif /* KCF_TPM_RNG_PROVIDER */
--- a/usr/src/uts/common/io/tpm/tpm.conf	Mon Aug 17 20:49:16 2009 -0700
+++ b/usr/src/uts/common/io/tpm/tpm.conf	Mon Aug 17 20:56:15 2009 -0700
@@ -1,1 +1,1 @@
-ddi-forceattach=1;
+name="tpm" parent="pseudo" instance=0;
--- a/usr/src/uts/common/io/tpm/tpm_ddi.h	Mon Aug 17 20:49:16 2009 -0700
+++ b/usr/src/uts/common/io/tpm/tpm_ddi.h	Mon Aug 17 20:56:15 2009 -0700
@@ -52,7 +52,10 @@
 	TPM_DID_IO_MUTEX = 0x200,
 	TPM_DID_IO_CV = 0x400,
 	TPM_DID_MUTEX = 0x800,
-	TPM_DID_SOFT_STATE = 0x1000
+	TPM_DID_SOFT_STATE = 0x1000,
+#ifdef sun4v
+	TPM_HSVC_REGISTERED = 0x2000
+#endif
 };
 
 typedef struct tpm_state tpm_state_t;
@@ -104,6 +107,9 @@
 	kmutex_t	pm_mutex;
 	kcondvar_t	suspend_cv;
 	uint32_t	suspended;
+
+	/* For RNG */
+	crypto_kcf_provider_handle_t	n_prov;
 };
 
 #endif	/* _TPM_DDI_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/tpm/tpm_hcall.s	Mon Aug 17 20:56:15 2009 -0700
@@ -0,0 +1,83 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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.
+ */
+
+/*
+ * Hypervisor calls used by tpm driver
+ */
+
+#include <sys/asm_linkage.h>
+
+#if defined(sun4v)
+#include <sys/hypervisor_api.h>
+
+#if defined(lint) || defined(__lint)
+
+/*ARGSUSED*/
+uint64_t
+hcall_tpm_get(uint64_t locality, uint64_t offset, uint64_t size,
+    uint64_t *value)
+{
+	return (0);
+}
+
+/*ARGSUSED*/
+uint64_t
+hcall_tpm_put(uint64_t locality, uint64_t offset, uint64_t size,
+    uint64_t value)
+{
+	return (0);
+}
+
+#else  /* lint || __lint */
+
+/*
+ * hcall_tpm_get(uint64_t locality, uint64_t offset, uint64_t size,
+ *     uint64_t *value)
+ */
+	ENTRY(hcall_tpm_get)
+	mov	%o3, %g1
+	mov	HV_TPM_GET, %o5
+	ta	FAST_TRAP
+	stx	%o1, [%g1]
+	retl
+	nop
+	SET_SIZE(hcall_tpm_get)
+
+/*
+ * uint64_t
+ * hcall_tpm_put(uint64_t locality, uint64_t offset, uint64_t size,
+ *     uint64_t value)
+ */
+	ENTRY(hcall_tpm_put)
+	mov	HV_TPM_PUT, %o5
+	ta	FAST_TRAP
+	retl
+	nop
+	SET_SIZE(hcall_tpm_put)
+
+#endif /* lint || __lint */
+
+#endif /* defined(sun4v) */
--- a/usr/src/uts/common/io/tpm/tpm_tis.h	Mon Aug 17 20:49:16 2009 -0700
+++ b/usr/src/uts/common/io/tpm/tpm_tis.h	Mon Aug 17 20:56:15 2009 -0700
@@ -36,25 +36,26 @@
 #define	TIS_MEM_BASE	0xFED40000
 #define	TIS_MEM_LEN    	0x5000
 
-/* Different locality(x)'s Offsets for TPM Registers (TIS 1.2 pg33-36) */
+#define	TPM_LOCALITY_OFFSET(x)	((x) << 12)
+
 /* Used to gain ownership */
-#define	TPM_ACCESS_(x)		(0x0000 | ((x)<<12))
+#define	TPM_ACCESS		0x0000
 /* Enable Interrupts */
-#define	TPM_INT_ENABLE_(x)	(0x0008 | ((x)<<12))
+#define	TPM_INT_ENABLE		0x0008
 /* Interrupt vector (SIRQ values) */
-#define	TPM_INT_VECTOR_(x)	(0x000C | ((x)<<12))
+#define	TPM_INT_VECTOR		0x000C
 /* What caused interrupt */
-#define	TPM_INT_STATUS_(x)	(0x0010 | ((x)<<12))
+#define	TPM_INT_STATUS		0x0010
 /* Supported Interrupts */
-#define	TPM_INTF_CAP_(x)	(0x0014 | ((x)<<12))
+#define	TPM_INTF_CAP		0x0014
 /* Status Register */
-#define	TPM_STS_(x)		(0x0018 | ((x)<<12))
+#define	TPM_STS			0x0018
 /* I/O FIFO */
-#define	TPM_DATA_FIFO_(x)   	(0x0024 | ((x)<<12))
+#define	TPM_DATA_FIFO   	0x0024
 /* Vendor and Device ID */
-#define	TPM_DID_VID_(x)		(0x0F00 | ((x)<<12))
+#define	TPM_DID_VID		0x0F00
 /* Revision ID */
-#define	TPM_RID_(x)		(0x0F04 | ((x)<<12))
+#define	TPM_RID			0x0F04
 
 /* The number of all ordinals */
 #define	TSC_ORDINAL_MAX		12
--- a/usr/src/uts/sun4v/Makefile.sun4v.shared	Mon Aug 17 20:49:16 2009 -0700
+++ b/usr/src/uts/sun4v/Makefile.sun4v.shared	Mon Aug 17 20:56:15 2009 -0700
@@ -344,6 +344,7 @@
 DRV_KMODS	+= qcn
 DRV_KMODS	+= rootnex
 DRV_KMODS       += su
+DRV_KMODS	+= tpm
 DRV_KMODS	+= trapstat
 DRV_KMODS	+= vcc
 DRV_KMODS	+= vdc
--- a/usr/src/uts/sun4v/sys/hsvc.h	Mon Aug 17 20:49:16 2009 -0700
+++ b/usr/src/uts/sun4v/sys/hsvc.h	Mon Aug 17 20:56:15 2009 -0700
@@ -48,6 +48,7 @@
 #define	HSVC_GROUP_VSC			0x0102
 #define	HSVC_GROUP_NCS			0x0103
 #define	HSVC_GROUP_RNG			0x0104
+#define	HSVC_GROUP_TPM			0x0107
 #define	HSVC_GROUP_NIAGARA_CPU		0x0200
 #define	HSVC_GROUP_FIRE_PERF		0x0201
 #define	HSVC_GROUP_NIAGARA2_CPU		0x0202
--- a/usr/src/uts/sun4v/sys/hypervisor_api.h	Mon Aug 17 20:49:16 2009 -0700
+++ b/usr/src/uts/sun4v/sys/hypervisor_api.h	Mon Aug 17 20:56:15 2009 -0700
@@ -167,6 +167,9 @@
 #define	MMU_STAT_AREA		0xfc
 #endif /* SET_MMU_STATS */
 
+#define	HV_TPM_GET		0x176
+#define	HV_TPM_PUT		0x177
+
 #define	HV_TM_ENABLE		0x180
 
 #define	HV_RA2PA		0x200