diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/conf/options | 4 | ||||
-rw-r--r-- | sys/dev/cfi/cfi_core.c | 175 | ||||
-rw-r--r-- | sys/dev/cfi/cfi_dev.c | 22 | ||||
-rw-r--r-- | sys/dev/cfi/cfi_reg.h | 22 | ||||
-rw-r--r-- | sys/dev/cfi/cfi_var.h | 7 | ||||
-rw-r--r-- | sys/sys/cfictl.h | 6 |
6 files changed, 221 insertions, 15 deletions
diff --git a/sys/conf/options b/sys/conf/options index 64504fd..4caff30 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -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 diff --git a/sys/dev/cfi/cfi_core.c b/sys/dev/cfi/cfi_core.c index c25e446f..4f2eebc 100644 --- a/sys/dev/cfi/cfi_core.c +++ b/sys/dev/cfi/cfi_core.c @@ -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_int timeout) 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_int timeout) 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 */ diff --git a/sys/dev/cfi/cfi_dev.c b/sys/dev/cfi/cfi_dev.c index b8db1d2..89069cb 100644 --- a/sys/dev/cfi/cfi_dev.c +++ b/sys/dev/cfi/cfi_dev.c @@ -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 cmd, caddr_t data, int fflag, 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 cmd, caddr_t data, int fflag, 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; diff --git a/sys/dev/cfi/cfi_reg.h b/sys/dev/cfi/cfi_reg.h index fe4d730..d492678 100644 --- a/sys/dev/cfi/cfi_reg.h +++ b/sys/dev/cfi/cfi_reg.h @@ -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 diff --git a/sys/dev/cfi/cfi_var.h b/sys/dev/cfi/cfi_var.h index 5c99702..d2a778b 100644 --- a/sys/dev/cfi/cfi_var.h +++ b/sys/dev/cfi/cfi_var.h @@ -74,4 +74,11 @@ uint32_t cfi_read(struct cfi_softc *, u_int); 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_ */ diff --git a/sys/sys/cfictl.h b/sys/sys/cfictl.h index ef6d5d1..a5439e0 100644 --- a/sys/sys/cfictl.h +++ b/sys/sys/cfictl.h @@ -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_ */ |