aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/mmc/mmc-dev-parts.txt13
-rw-r--r--drivers/mmc/card/block.c121
-rw-r--r--drivers/mmc/core/mmc.c14
-rw-r--r--include/linux/mmc/card.h10
-rw-r--r--include/linux/mmc/mmc.h6
5 files changed, 153 insertions, 11 deletions
diff --git a/Documentation/mmc/mmc-dev-parts.txt b/Documentation/mmc/mmc-dev-parts.txt
index 2db28b8e662f..f08d078d43cf 100644
--- a/Documentation/mmc/mmc-dev-parts.txt
+++ b/Documentation/mmc/mmc-dev-parts.txt
@@ -25,3 +25,16 @@ echo 0 > /sys/block/mmcblkXbootY/force_ro
25To re-enable read-only access: 25To re-enable read-only access:
26 26
27echo 1 > /sys/block/mmcblkXbootY/force_ro 27echo 1 > /sys/block/mmcblkXbootY/force_ro
28
29The boot partitions can also be locked read only until the next power on,
30with:
31
32echo 1 > /sys/block/mmcblkXbootY/ro_lock_until_next_power_on
33
34This is a feature of the card and not of the kernel. If the card does
35not support boot partition locking, the file will not exist. If the
36feature has been disabled on the card, the file will be read-only.
37
38The boot partitions can also be locked permanently, but this feature is
39not accessible through sysfs in order to avoid accidental or malicious
40bricking.
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index ad0fb8d74dda..0c959c96005e 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -107,6 +107,8 @@ struct mmc_blk_data {
107 */ 107 */
108 unsigned int part_curr; 108 unsigned int part_curr;
109 struct device_attribute force_ro; 109 struct device_attribute force_ro;
110 struct device_attribute power_ro_lock;
111 int area_type;
110}; 112};
111 113
112static DEFINE_MUTEX(open_lock); 114static DEFINE_MUTEX(open_lock);
@@ -165,6 +167,70 @@ static void mmc_blk_put(struct mmc_blk_data *md)
165 mutex_unlock(&open_lock); 167 mutex_unlock(&open_lock);
166} 168}
167 169
170static ssize_t power_ro_lock_show(struct device *dev,
171 struct device_attribute *attr, char *buf)
172{
173 int ret;
174 struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
175 struct mmc_card *card = md->queue.card;
176 int locked = 0;
177
178 if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PERM_WP_EN)
179 locked = 2;
180 else if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_EN)
181 locked = 1;
182
183 ret = snprintf(buf, PAGE_SIZE, "%d\n", locked);
184
185 return ret;
186}
187
188static ssize_t power_ro_lock_store(struct device *dev,
189 struct device_attribute *attr, const char *buf, size_t count)
190{
191 int ret;
192 struct mmc_blk_data *md, *part_md;
193 struct mmc_card *card;
194 unsigned long set;
195
196 if (kstrtoul(buf, 0, &set))
197 return -EINVAL;
198
199 if (set != 1)
200 return count;
201
202 md = mmc_blk_get(dev_to_disk(dev));
203 card = md->queue.card;
204
205 mmc_claim_host(card->host);
206
207 ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP,
208 card->ext_csd.boot_ro_lock |
209 EXT_CSD_BOOT_WP_B_PWR_WP_EN,
210 card->ext_csd.part_time);
211 if (ret)
212 pr_err("%s: Locking boot partition ro until next power on failed: %d\n", md->disk->disk_name, ret);
213 else
214 card->ext_csd.boot_ro_lock |= EXT_CSD_BOOT_WP_B_PWR_WP_EN;
215
216 mmc_release_host(card->host);
217
218 if (!ret) {
219 pr_info("%s: Locking boot partition ro until next power on\n",
220 md->disk->disk_name);
221 set_disk_ro(md->disk, 1);
222
223 list_for_each_entry(part_md, &md->part, part)
224 if (part_md->area_type == MMC_BLK_DATA_AREA_BOOT) {
225 pr_info("%s: Locking boot partition ro until next power on\n", part_md->disk->disk_name);
226 set_disk_ro(part_md->disk, 1);
227 }
228 }
229
230 mmc_blk_put(md);
231 return count;
232}
233
168static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr, 234static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr,
169 char *buf) 235 char *buf)
170{ 236{
@@ -1347,7 +1413,8 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
1347 struct device *parent, 1413 struct device *parent,
1348 sector_t size, 1414 sector_t size,
1349 bool default_ro, 1415 bool default_ro,
1350 const char *subname) 1416 const char *subname,
1417 int area_type)
1351{ 1418{
1352 struct mmc_blk_data *md; 1419 struct mmc_blk_data *md;
1353 int devidx, ret; 1420 int devidx, ret;
@@ -1372,11 +1439,12 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
1372 if (!subname) { 1439 if (!subname) {
1373 md->name_idx = find_first_zero_bit(name_use, max_devices); 1440 md->name_idx = find_first_zero_bit(name_use, max_devices);
1374 __set_bit(md->name_idx, name_use); 1441 __set_bit(md->name_idx, name_use);
1375 } 1442 } else
1376 else
1377 md->name_idx = ((struct mmc_blk_data *) 1443 md->name_idx = ((struct mmc_blk_data *)
1378 dev_to_disk(parent)->private_data)->name_idx; 1444 dev_to_disk(parent)->private_data)->name_idx;
1379 1445
1446 md->area_type = area_type;
1447
1380 /* 1448 /*
1381 * Set the read-only status based on the supported commands 1449 * Set the read-only status based on the supported commands
1382 * and the write protect switch. 1450 * and the write protect switch.
@@ -1470,7 +1538,8 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
1470 size = card->csd.capacity << (card->csd.read_blkbits - 9); 1538 size = card->csd.capacity << (card->csd.read_blkbits - 9);
1471 } 1539 }
1472 1540
1473 md = mmc_blk_alloc_req(card, &card->dev, size, false, NULL); 1541 md = mmc_blk_alloc_req(card, &card->dev, size, false, NULL,
1542 MMC_BLK_DATA_AREA_MAIN);
1474 return md; 1543 return md;
1475} 1544}
1476 1545
@@ -1479,13 +1548,14 @@ static int mmc_blk_alloc_part(struct mmc_card *card,
1479 unsigned int part_type, 1548 unsigned int part_type,
1480 sector_t size, 1549 sector_t size,
1481 bool default_ro, 1550 bool default_ro,
1482 const char *subname) 1551 const char *subname,
1552 int area_type)
1483{ 1553{
1484 char cap_str[10]; 1554 char cap_str[10];
1485 struct mmc_blk_data *part_md; 1555 struct mmc_blk_data *part_md;
1486 1556
1487 part_md = mmc_blk_alloc_req(card, disk_to_dev(md->disk), size, default_ro, 1557 part_md = mmc_blk_alloc_req(card, disk_to_dev(md->disk), size, default_ro,
1488 subname); 1558 subname, area_type);
1489 if (IS_ERR(part_md)) 1559 if (IS_ERR(part_md))
1490 return PTR_ERR(part_md); 1560 return PTR_ERR(part_md);
1491 part_md->part_type = part_type; 1561 part_md->part_type = part_type;
@@ -1518,7 +1588,8 @@ static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md)
1518 card->part[idx].part_cfg, 1588 card->part[idx].part_cfg,
1519 card->part[idx].size >> 9, 1589 card->part[idx].size >> 9,
1520 card->part[idx].force_ro, 1590 card->part[idx].force_ro,
1521 card->part[idx].name); 1591 card->part[idx].name,
1592 card->part[idx].area_type);
1522 if (ret) 1593 if (ret)
1523 return ret; 1594 return ret;
1524 } 1595 }
@@ -1547,9 +1618,16 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
1547 1618
1548static void mmc_blk_remove_req(struct mmc_blk_data *md) 1619static void mmc_blk_remove_req(struct mmc_blk_data *md)
1549{ 1620{
1621 struct mmc_card *card;
1622
1550 if (md) { 1623 if (md) {
1624 card = md->queue.card;
1551 if (md->disk->flags & GENHD_FL_UP) { 1625 if (md->disk->flags & GENHD_FL_UP) {
1552 device_remove_file(disk_to_dev(md->disk), &md->force_ro); 1626 device_remove_file(disk_to_dev(md->disk), &md->force_ro);
1627 if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) &&
1628 card->ext_csd.boot_ro_lockable)
1629 device_remove_file(disk_to_dev(md->disk),
1630 &md->power_ro_lock);
1553 1631
1554 /* Stop new requests from getting into the queue */ 1632 /* Stop new requests from getting into the queue */
1555 del_gendisk(md->disk); 1633 del_gendisk(md->disk);
@@ -1578,6 +1656,7 @@ static void mmc_blk_remove_parts(struct mmc_card *card,
1578static int mmc_add_disk(struct mmc_blk_data *md) 1656static int mmc_add_disk(struct mmc_blk_data *md)
1579{ 1657{
1580 int ret; 1658 int ret;
1659 struct mmc_card *card = md->queue.card;
1581 1660
1582 add_disk(md->disk); 1661 add_disk(md->disk);
1583 md->force_ro.show = force_ro_show; 1662 md->force_ro.show = force_ro_show;
@@ -1587,7 +1666,33 @@ static int mmc_add_disk(struct mmc_blk_data *md)
1587 md->force_ro.attr.mode = S_IRUGO | S_IWUSR; 1666 md->force_ro.attr.mode = S_IRUGO | S_IWUSR;
1588 ret = device_create_file(disk_to_dev(md->disk), &md->force_ro); 1667 ret = device_create_file(disk_to_dev(md->disk), &md->force_ro);
1589 if (ret) 1668 if (ret)
1590 del_gendisk(md->disk); 1669 goto force_ro_fail;
1670
1671 if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) &&
1672 card->ext_csd.boot_ro_lockable) {
1673 mode_t mode;
1674
1675 if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_DIS)
1676 mode = S_IRUGO;
1677 else
1678 mode = S_IRUGO | S_IWUSR;
1679
1680 md->power_ro_lock.show = power_ro_lock_show;
1681 md->power_ro_lock.store = power_ro_lock_store;
1682 md->power_ro_lock.attr.mode = mode;
1683 md->power_ro_lock.attr.name =
1684 "ro_lock_until_next_power_on";
1685 ret = device_create_file(disk_to_dev(md->disk),
1686 &md->power_ro_lock);
1687 if (ret)
1688 goto power_ro_lock_fail;
1689 }
1690 return ret;
1691
1692power_ro_lock_fail:
1693 device_remove_file(disk_to_dev(md->disk), &md->force_ro);
1694force_ro_fail:
1695 del_gendisk(md->disk);
1591 1696
1592 return ret; 1697 return ret;
1593} 1698}
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index fc1059bb6a08..006e932a3ae3 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -348,7 +348,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
348 part_size = ext_csd[EXT_CSD_BOOT_MULT] << 17; 348 part_size = ext_csd[EXT_CSD_BOOT_MULT] << 17;
349 mmc_part_add(card, part_size, 349 mmc_part_add(card, part_size,
350 EXT_CSD_PART_CONFIG_ACC_BOOT0 + idx, 350 EXT_CSD_PART_CONFIG_ACC_BOOT0 + idx,
351 "boot%d", idx, true); 351 "boot%d", idx, true,
352 MMC_BLK_DATA_AREA_BOOT);
352 } 353 }
353 } 354 }
354 } 355 }
@@ -435,7 +436,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
435 hc_wp_grp_sz); 436 hc_wp_grp_sz);
436 mmc_part_add(card, part_size << 19, 437 mmc_part_add(card, part_size << 19,
437 EXT_CSD_PART_CONFIG_ACC_GP0 + idx, 438 EXT_CSD_PART_CONFIG_ACC_GP0 + idx,
438 "gp%d", idx, false); 439 "gp%d", idx, false,
440 MMC_BLK_DATA_AREA_GP);
439 } 441 }
440 } 442 }
441 card->ext_csd.sec_trim_mult = 443 card->ext_csd.sec_trim_mult =
@@ -446,6 +448,14 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
446 ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]; 448 ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT];
447 card->ext_csd.trim_timeout = 300 * 449 card->ext_csd.trim_timeout = 300 *
448 ext_csd[EXT_CSD_TRIM_MULT]; 450 ext_csd[EXT_CSD_TRIM_MULT];
451
452 /*
453 * Note that the call to mmc_part_add above defaults to read
454 * only. If this default assumption is changed, the call must
455 * take into account the value of boot_locked below.
456 */
457 card->ext_csd.boot_ro_lock = ext_csd[EXT_CSD_BOOT_WP];
458 card->ext_csd.boot_ro_lockable = true;
449 } 459 }
450 460
451 if (card->ext_csd.rev >= 5) { 461 if (card->ext_csd.rev >= 5) {
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 6402d9224d6a..9478a6bf1bb1 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -71,6 +71,8 @@ struct mmc_ext_csd {
71 bool hpi_en; /* HPI enablebit */ 71 bool hpi_en; /* HPI enablebit */
72 bool hpi; /* HPI support bit */ 72 bool hpi; /* HPI support bit */
73 unsigned int hpi_cmd; /* cmd used as HPI */ 73 unsigned int hpi_cmd; /* cmd used as HPI */
74 unsigned int boot_ro_lock; /* ro lock support */
75 bool boot_ro_lockable;
74 u8 raw_partition_support; /* 160 */ 76 u8 raw_partition_support; /* 160 */
75 u8 raw_erased_mem_count; /* 181 */ 77 u8 raw_erased_mem_count; /* 181 */
76 u8 raw_ext_csd_structure; /* 194 */ 78 u8 raw_ext_csd_structure; /* 194 */
@@ -187,6 +189,10 @@ struct mmc_part {
187 unsigned int part_cfg; /* partition type */ 189 unsigned int part_cfg; /* partition type */
188 char name[MAX_MMC_PART_NAME_LEN]; 190 char name[MAX_MMC_PART_NAME_LEN];
189 bool force_ro; /* to make boot parts RO by default */ 191 bool force_ro; /* to make boot parts RO by default */
192 unsigned int area_type;
193#define MMC_BLK_DATA_AREA_MAIN (1<<0)
194#define MMC_BLK_DATA_AREA_BOOT (1<<1)
195#define MMC_BLK_DATA_AREA_GP (1<<2)
190}; 196};
191 197
192/* 198/*
@@ -265,12 +271,14 @@ struct mmc_card {
265 * This function fill contents in mmc_part. 271 * This function fill contents in mmc_part.
266 */ 272 */
267static inline void mmc_part_add(struct mmc_card *card, unsigned int size, 273static inline void mmc_part_add(struct mmc_card *card, unsigned int size,
268 unsigned int part_cfg, char *name, int idx, bool ro) 274 unsigned int part_cfg, char *name, int idx, bool ro,
275 int area_type)
269{ 276{
270 card->part[card->nr_parts].size = size; 277 card->part[card->nr_parts].size = size;
271 card->part[card->nr_parts].part_cfg = part_cfg; 278 card->part[card->nr_parts].part_cfg = part_cfg;
272 sprintf(card->part[card->nr_parts].name, name, idx); 279 sprintf(card->part[card->nr_parts].name, name, idx);
273 card->part[card->nr_parts].force_ro = ro; 280 card->part[card->nr_parts].force_ro = ro;
281 card->part[card->nr_parts].area_type = area_type;
274 card->nr_parts++; 282 card->nr_parts++;
275} 283}
276 284
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 0e7135697d11..665548e639e8 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -280,6 +280,7 @@ struct _mmc_csd {
280#define EXT_CSD_RST_N_FUNCTION 162 /* R/W */ 280#define EXT_CSD_RST_N_FUNCTION 162 /* R/W */
281#define EXT_CSD_SANITIZE_START 165 /* W */ 281#define EXT_CSD_SANITIZE_START 165 /* W */
282#define EXT_CSD_WR_REL_PARAM 166 /* RO */ 282#define EXT_CSD_WR_REL_PARAM 166 /* RO */
283#define EXT_CSD_BOOT_WP 173 /* R/W */
283#define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */ 284#define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */
284#define EXT_CSD_PART_CONFIG 179 /* R/W */ 285#define EXT_CSD_PART_CONFIG 179 /* R/W */
285#define EXT_CSD_ERASED_MEM_CONT 181 /* RO */ 286#define EXT_CSD_ERASED_MEM_CONT 181 /* RO */
@@ -321,6 +322,11 @@ struct _mmc_csd {
321 322
322#define EXT_CSD_WR_REL_PARAM_EN (1<<2) 323#define EXT_CSD_WR_REL_PARAM_EN (1<<2)
323 324
325#define EXT_CSD_BOOT_WP_B_PWR_WP_DIS (0x40)
326#define EXT_CSD_BOOT_WP_B_PERM_WP_DIS (0x10)
327#define EXT_CSD_BOOT_WP_B_PERM_WP_EN (0x04)
328#define EXT_CSD_BOOT_WP_B_PWR_WP_EN (0x01)
329
324#define EXT_CSD_PART_CONFIG_ACC_MASK (0x7) 330#define EXT_CSD_PART_CONFIG_ACC_MASK (0x7)
325#define EXT_CSD_PART_CONFIG_ACC_BOOT0 (0x1) 331#define EXT_CSD_PART_CONFIG_ACC_BOOT0 (0x1)
326#define EXT_CSD_PART_CONFIG_ACC_GP0 (0x4) 332#define EXT_CSD_PART_CONFIG_ACC_GP0 (0x4)