svn commit: r188156 - in head/sys: conf dev/cfi sys

Sam Leffler sam at FreeBSD.org
Thu Feb 5 10:12:08 PST 2009


Author: sam
Date: Thu Feb  5 18:12:07 2009
New Revision: 188156
URL: http://svn.freebsd.org/changeset/base/188156

Log:
  Add support for frobbing Intel StrataFlash Protection Registers:
  o add CFI_SUPPORT_STRATAFLASH compile option to enable support
  o add new ioctls to get/set the factory and user/oem segments of the PR
    and to get/set Protection Lock Register that fuses the user segment
  o add #defines for bits in the status register
  o update cfi_wait_ready to take an offset so it can be used to wait for
    PR write completion and replace constants w/ symbolic names
  
  Note: writing the user segment isn't correct; committing now to get review.
  
  Sponsored by:	Carlson Wireless
  Reviewed by:	imp, Chris Anderson

Modified:
  head/sys/conf/options
  head/sys/dev/cfi/cfi_core.c
  head/sys/dev/cfi/cfi_dev.c
  head/sys/dev/cfi/cfi_reg.h
  head/sys/dev/cfi/cfi_var.h
  head/sys/sys/cfictl.h

Modified: head/sys/conf/options
==============================================================================
--- head/sys/conf/options	Thu Feb  5 17:51:46 2009	(r188155)
+++ head/sys/conf/options	Thu Feb  5 18:12:07 2009	(r188156)
@@ -804,3 +804,7 @@ TDMA_TXRATE_11A_DEFAULT	opt_tdma.h
 # Virtualize the network stack
 VIMAGE			opt_global.h
 VIMAGE_GLOBALS		opt_global.h
+
+# Common Flash Interface (CFI) options
+CFI_SUPPORT_STRATAFLASH	opt_cfi.h
+CFI_ARMEDANDDANGEROUS	opt_cfi.h

Modified: head/sys/dev/cfi/cfi_core.c
==============================================================================
--- head/sys/dev/cfi/cfi_core.c	Thu Feb  5 17:51:46 2009	(r188155)
+++ head/sys/dev/cfi/cfi_core.c	Thu Feb  5 18:12:07 2009	(r188156)
@@ -30,6 +30,8 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
+#include "opt_cfi.h"
+
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/bus.h>
@@ -70,7 +72,6 @@ cfi_read(struct cfi_softc *sc, u_int ofs
 		val = ~0;
 		break;
 	}
-
 	return (val);
 }
 
@@ -300,10 +301,10 @@ cfi_detach(device_t dev)
 }
 
 static int
-cfi_wait_ready(struct cfi_softc *sc, u_int timeout)
+cfi_wait_ready(struct cfi_softc *sc, u_int ofs, u_int timeout)
 {
 	int done, error;
-	uint32_t st0, st;
+	uint32_t st0 = 0, st = 0;
 
 	done = 0;
 	error = 0;
@@ -315,21 +316,27 @@ cfi_wait_ready(struct cfi_softc *sc, u_i
 		switch (sc->sc_cmdset) {
 		case CFI_VEND_INTEL_ECS:
 		case CFI_VEND_INTEL_SCS:
-			st = cfi_read(sc, sc->sc_wrofs);
-			done = (st & 0x80);
+			st = cfi_read(sc, ofs);
+			done = (st & CFI_INTEL_STATUS_WSMS);
 			if (done) {
-				if (st & 0x02)
+				/* NB: bit 0 is reserved */
+				st &= ~(CFI_INTEL_XSTATUS_RSVD |
+					CFI_INTEL_STATUS_WSMS |
+					CFI_INTEL_STATUS_RSVD);
+				if (st & CFI_INTEL_STATUS_DPS)
 					error = EPERM;
-				else if (st & 0x10)
+				else if (st & CFI_INTEL_STATUS_PSLBS)
 					error = EIO;
-				else if (st & 0x20)
+				else if (st & CFI_INTEL_STATUS_ECLBS)
 					error = ENXIO;
+				else if (st)
+					error = EACCES;
 			}
 			break;
 		case CFI_VEND_AMD_SCS:
 		case CFI_VEND_AMD_ECS:
-			st0 = cfi_read(sc, sc->sc_wrofs);
-			st = cfi_read(sc, sc->sc_wrofs);
+			st0 = cfi_read(sc, ofs);
+			st = cfi_read(sc, ofs);
 			done = ((st & 0x40) == (st0 & 0x40)) ? 1 : 0;
 			break;
 		}
@@ -337,7 +344,7 @@ cfi_wait_ready(struct cfi_softc *sc, u_i
 	if (!done && !error)
 		error = ETIMEDOUT;
 	if (error)
-		printf("\nerror=%d\n", error);
+		printf("\nerror=%d (st 0x%x st0 0x%x)\n", error, st, st0);
 	return (error);
 }
 
@@ -369,7 +376,7 @@ cfi_write_block(struct cfi_softc *sc)
 		/* Better safe than sorry... */
 		return (ENODEV);
 	}
-	error = cfi_wait_ready(sc, sc->sc_erase_timeout);
+	error = cfi_wait_ready(sc, sc->sc_wrofs, sc->sc_erase_timeout);
 	if (error)
 		goto out;
 
@@ -411,7 +418,7 @@ cfi_write_block(struct cfi_softc *sc)
 
 		intr_restore(intr);
 
-		error = cfi_wait_ready(sc, sc->sc_write_timeout);
+		error = cfi_wait_ready(sc, sc->sc_wrofs, sc->sc_write_timeout);
 		if (error)
 			goto out;
 	}
@@ -422,3 +429,145 @@ cfi_write_block(struct cfi_softc *sc)
 	cfi_write(sc, 0, CFI_BCS_READ_ARRAY);
 	return (error);
 }
+
+#ifdef CFI_SUPPORT_STRATAFLASH
+/*
+ * Intel StrataFlash Protection Register Support.
+ *
+ * The memory includes a 128-bit Protection Register that can be
+ * used for security.  There are two 64-bit segments; one is programmed
+ * at the factory with a unique 64-bit number which is immutable.
+ * The other segment is left blank for User (OEM) programming.
+ * Once the User/OEM segment is programmed it can be locked
+ * to prevent future programming by writing bit 0 of the Protection
+ * Lock Register (PLR).  The PLR can written only once.
+ */
+
+static uint16_t
+cfi_get16(struct cfi_softc *sc, int off)
+{
+	uint16_t v = bus_space_read_2(sc->sc_tag, sc->sc_handle, off<<1);
+	return v;
+}
+
+static void
+cfi_put16(struct cfi_softc *sc, int off, uint16_t v)
+{
+	bus_space_write_2(sc->sc_tag, sc->sc_handle, off<<1, v);
+}
+
+/*
+ * Read the factory-defined 64-bit segment of the PR.
+ */
+int 
+cfi_intel_get_factory_pr(struct cfi_softc *sc, uint64_t *id)
+{
+	if (sc->sc_cmdset != CFI_VEND_INTEL_ECS)
+		return EOPNOTSUPP;
+	KASSERT(sc->sc_width == 2, ("sc_width %d", sc->sc_width));
+
+	cfi_write(sc, 0, CFI_INTEL_READ_ID);
+	*id = ((uint64_t)cfi_get16(sc, CFI_INTEL_PR(0)))<<48 |
+	      ((uint64_t)cfi_get16(sc, CFI_INTEL_PR(1)))<<32 |
+	      ((uint64_t)cfi_get16(sc, CFI_INTEL_PR(2)))<<16 |
+	      ((uint64_t)cfi_get16(sc, CFI_INTEL_PR(3)));
+	cfi_write(sc, 0, CFI_BCS_READ_ARRAY);
+	return 0;
+}
+
+/*
+ * Read the User/OEM 64-bit segment of the PR.
+ */
+int 
+cfi_intel_get_oem_pr(struct cfi_softc *sc, uint64_t *id)
+{
+	if (sc->sc_cmdset != CFI_VEND_INTEL_ECS)
+		return EOPNOTSUPP;
+	KASSERT(sc->sc_width == 2, ("sc_width %d", sc->sc_width));
+
+	cfi_write(sc, 0, CFI_INTEL_READ_ID);
+	*id = ((uint64_t)cfi_get16(sc, CFI_INTEL_PR(4)))<<48 |
+	      ((uint64_t)cfi_get16(sc, CFI_INTEL_PR(5)))<<32 |
+	      ((uint64_t)cfi_get16(sc, CFI_INTEL_PR(6)))<<16 |
+	      ((uint64_t)cfi_get16(sc, CFI_INTEL_PR(7)));
+	cfi_write(sc, 0, CFI_BCS_READ_ARRAY);
+	return 0;
+}
+
+/*
+ * Write the User/OEM 64-bit segment of the PR.
+ */
+int
+cfi_intel_set_oem_pr(struct cfi_softc *sc, uint64_t id)
+{
+	register_t intr;
+	int i, error;
+
+	if (sc->sc_cmdset != CFI_VEND_INTEL_ECS)
+		return EOPNOTSUPP;
+	KASSERT(sc->sc_width == 2, ("sc_width %d", sc->sc_width));
+
+	for (i = 7; i >= 4; i--, id >>= 16) {
+		intr = intr_disable();
+		cfi_write(sc, 0, CFI_INTEL_PP_SETUP);
+		cfi_put16(sc, CFI_INTEL_PR(i), id&0xffff);
+		intr_restore(intr);
+		error = cfi_wait_ready(sc, CFI_BCS_READ_STATUS,
+		    sc->sc_write_timeout);
+		if (error)
+			break;
+	}
+	cfi_write(sc, 0, CFI_BCS_READ_ARRAY);
+	return error;
+}
+
+/*
+ * Read the contents of the Protection Lock Register.
+ */
+int 
+cfi_intel_get_plr(struct cfi_softc *sc, uint32_t *plr)
+{
+	if (sc->sc_cmdset != CFI_VEND_INTEL_ECS)
+		return EOPNOTSUPP;
+	KASSERT(sc->sc_width == 2, ("sc_width %d", sc->sc_width));
+
+	cfi_write(sc, 0, CFI_INTEL_READ_ID);
+	*plr = cfi_get16(sc, CFI_INTEL_PLR);
+	cfi_write(sc, 0, CFI_BCS_READ_ARRAY);
+	return 0;
+}
+
+/*
+ * Write the Protection Lock Register to lock down the
+ * user-settable segment of the Protection Register.
+ * NOTE: this operation is not reversible.
+ */
+int 
+cfi_intel_set_plr(struct cfi_softc *sc)
+{
+#ifdef CFI_ARMEDANDDANGEROUS
+	register_t intr;
+#endif
+	int error;
+
+	if (sc->sc_cmdset != CFI_VEND_INTEL_ECS)
+		return EOPNOTSUPP;
+	KASSERT(sc->sc_width == 2, ("sc_width %d", sc->sc_width));
+
+#ifdef CFI_ARMEDANDDANGEROUS
+	/* worthy of console msg */
+	device_printf(sc->sc_dev, "set PLR\n");
+	intr = intr_disable();
+	cfi_write(sc, 0, CFI_INTEL_PP_SETUP);
+	cfi_put16(sc, CFI_INTEL_PLR, 0xFFFD);
+	intr_restore(intr);
+	error = cfi_wait_ready(sc, CFI_BCS_READ_STATUS, sc->sc_write_timeout);
+	cfi_write(sc, 0, CFI_BCS_READ_ARRAY);
+#else
+	device_printf(sc->sc_dev, "%s: PLR not set, "
+	    "CFI_ARMEDANDDANGEROUS not configured\n", __func__);
+	error = ENXIO;
+#endif
+	return error;
+}
+#endif /* CFI_SUPPORT_STRATAFLASH */

Modified: head/sys/dev/cfi/cfi_dev.c
==============================================================================
--- head/sys/dev/cfi/cfi_dev.c	Thu Feb  5 17:51:46 2009	(r188155)
+++ head/sys/dev/cfi/cfi_dev.c	Thu Feb  5 18:12:07 2009	(r188156)
@@ -30,6 +30,8 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
+#include "opt_cfi.h"
+
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/bus.h>
@@ -255,14 +257,13 @@ cfi_devioctl(struct cdev *dev, u_long cm
 	sc = dev->si_drv1;
 	error = 0;
 
-	switch(cmd) {
+	switch (cmd) {
 	case CFIOCQRY:
 		if (sc->sc_writing) {
 			error = cfi_block_finish(sc);
 			if (error)
 				break;
 		}
-
 		rq = (struct cfiocqry *)data;
 		if (rq->offset >= sc->sc_size / sc->sc_width)
 			return (ESPIPE);
@@ -274,6 +275,23 @@ cfi_devioctl(struct cdev *dev, u_long cm
 			error = copyout(&val, rq->buffer++, 1);
 		}
 		break;
+#ifdef CFI_SUPPORT_STRATAFLASH
+	case CFIOCGFACTORYPR:
+		error = cfi_intel_get_factory_pr(sc, (uint64_t *)data);
+		break;
+	case CFIOCGOEMPR:
+		error = cfi_intel_get_oem_pr(sc, (uint64_t *)data);
+		break;
+	case CFIOCSOEMPR:
+		error = cfi_intel_set_oem_pr(sc, *(uint64_t *)data);
+		break;
+	case CFIOCGPLR:
+		error = cfi_intel_get_plr(sc, (uint32_t *)data);
+		break;
+	case CFIOCSPLR:
+		error = cfi_intel_set_plr(sc);
+		break;
+#endif /* CFI_SUPPORT_STRATAFLASH */
 	default:
 		error = ENOIOCTL;
 		break;

Modified: head/sys/dev/cfi/cfi_reg.h
==============================================================================
--- head/sys/dev/cfi/cfi_reg.h	Thu Feb  5 17:51:46 2009	(r188155)
+++ head/sys/dev/cfi/cfi_reg.h	Thu Feb  5 18:12:07 2009	(r188156)
@@ -104,6 +104,28 @@ struct cfi_qry {
 #define	CFI_BCS_CONFIRM		0xd0
 #define	CFI_BCS_READ_ARRAY	0xff
 
+/* Intel commands. */
+#define	CFI_INTEL_READ_ID	0x90	/* Read Identifier */
+#define	CFI_INTEL_PP_SETUP	0xc0	/* Protection Program Setup */
+
+/* NB: these are addresses for 16-bit accesses */
+#define	CFI_INTEL_PLR		0x80	/* Protection Lock Register */
+#define	CFI_INTEL_PR(n)		(0x81+(n)) /* Protection Register */
+
+/* Status register definitions */
+#define	CFI_INTEL_STATUS_WSMS	0x0080	/* Write Machine Status */
+#define	CFI_INTEL_STATUS_ESS	0x0040	/* Erase Suspend Status */
+#define	CFI_INTEL_STATUS_ECLBS	0x0020	/* Erase and Clear Lock-Bit Status */
+#define	CFI_INTEL_STATUS_PSLBS	0x0010	/* Program and Set Lock-Bit Status */
+#define	CFI_INTEL_STATUS_VPENS	0x0008	/* Programming Voltage Status */
+#define	CFI_INTEL_STATUS_PSS	0x0004	/* Program Suspend Status */
+#define	CFI_INTEL_STATUS_DPS	0x0002	/* Device Protect Status */
+#define	CFI_INTEL_STATUS_RSVD	0x0001	/* reserved */
+
+/* eXtended Status register definitions */
+#define	CFI_INTEL_XSTATUS_WBS	0x8000	/* Write Buffer Status */
+#define	CFI_INTEL_XSTATUS_RSVD	0x7f00	/* reserved */
+
 /* AMD commands. */
 #define	CFI_AMD_BLOCK_ERASE	0x30
 #define	CFI_AMD_UNLOCK_ACK	0x55

Modified: head/sys/dev/cfi/cfi_var.h
==============================================================================
--- head/sys/dev/cfi/cfi_var.h	Thu Feb  5 17:51:46 2009	(r188155)
+++ head/sys/dev/cfi/cfi_var.h	Thu Feb  5 18:12:07 2009	(r188156)
@@ -74,4 +74,11 @@ uint32_t cfi_read(struct cfi_softc *, u_
 uint8_t cfi_read_qry(struct cfi_softc *, u_int);
 int cfi_write_block(struct cfi_softc *);
 
+#ifdef CFI_SUPPORT_STRATAFLASH
+int	cfi_intel_get_factory_pr(struct cfi_softc *sc, uint64_t *);
+int	cfi_intel_get_oem_pr(struct cfi_softc *sc, uint64_t *);
+int	cfi_intel_set_oem_pr(struct cfi_softc *sc, uint64_t);
+int	cfi_intel_get_plr(struct cfi_softc *sc, uint32_t *);
+int	cfi_intel_set_plr(struct cfi_softc *sc);
+#endif /* CFI_SUPPORT_STRATAFLASH */
 #endif /* _DEV_CFI_VAR_H_ */

Modified: head/sys/sys/cfictl.h
==============================================================================
--- head/sys/sys/cfictl.h	Thu Feb  5 17:51:46 2009	(r188155)
+++ head/sys/sys/cfictl.h	Thu Feb  5 18:12:07 2009	(r188156)
@@ -44,4 +44,10 @@ struct cfiocqry {
 
 #define	CFIOCQRY	_IOWR('q', 0, struct cfiocqry)
 
+/* Intel StrataFlash Protection Register support */
+#define	CFIOCGFACTORYPR	_IOR('q', 1, uint64_t)	/* get factory protection reg */
+#define	CFIOCGOEMPR	_IOR('q', 2, uint64_t)	/* get oem protection reg */
+#define	CFIOCSOEMPR	_IOW('q', 3, uint64_t)	/* set oem protection reg */
+#define	CFIOCGPLR	_IOR('q', 4, uint32_t)	/* get protection lock reg */
+#define	CFIOCSPLR	_IO('q', 5)		/* set protection log reg */
 #endif	/* _SYS_CFICTL_H_ */


More information about the svn-src-head mailing list