From owner-svn-src-all@FreeBSD.ORG Thu Feb 5 18:12:08 2009 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id F02BC106564A; Thu, 5 Feb 2009 18:12:07 +0000 (UTC) (envelope-from sam@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id DE2058FC18; Thu, 5 Feb 2009 18:12:07 +0000 (UTC) (envelope-from sam@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n15IC7nI033738; Thu, 5 Feb 2009 18:12:07 GMT (envelope-from sam@svn.freebsd.org) Received: (from sam@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n15IC7Tp033732; Thu, 5 Feb 2009 18:12:07 GMT (envelope-from sam@svn.freebsd.org) Message-Id: <200902051812.n15IC7Tp033732@svn.freebsd.org> From: Sam Leffler Date: Thu, 5 Feb 2009 18:12:07 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r188156 - in head/sys: conf dev/cfi sys X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 05 Feb 2009 18:12:08 -0000 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 __FBSDID("$FreeBSD$"); +#include "opt_cfi.h" + #include #include #include @@ -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 __FBSDID("$FreeBSD$"); +#include "opt_cfi.h" + #include #include #include @@ -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_ */