1 /* 2 * Parser for TRX format partitions 3 * 4 * Copyright (C) 2012 - 2017 Rafał Miłecki <rafal@milecki.pl> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 * 10 */ 11 12 #include <linux/module.h> 13 #include <linux/slab.h> 14 #include <linux/mtd/mtd.h> 15 #include <linux/mtd/partitions.h> 16 17 #define TRX_PARSER_MAX_PARTS 4 18 19 /* Magics */ 20 #define TRX_MAGIC 0x30524448 21 #define UBI_EC_MAGIC 0x23494255 /* UBI# */ 22 23 struct trx_header { 24 uint32_t magic; 25 uint32_t length; 26 uint32_t crc32; 27 uint16_t flags; 28 uint16_t version; 29 uint32_t offset[3]; 30 } __packed; 31 32 static const char *parser_trx_data_part_name(struct mtd_info *master, 33 size_t offset) 34 { 35 uint32_t buf; 36 size_t bytes_read; 37 int err; 38 39 err = mtd_read(master, offset, sizeof(buf), &bytes_read, 40 (uint8_t *)&buf); 41 if (err && !mtd_is_bitflip(err)) { 42 pr_err("mtd_read error while parsing (offset: 0x%zX): %d\n", 43 offset, err); 44 goto out_default; 45 } 46 47 if (buf == UBI_EC_MAGIC) 48 return "ubi"; 49 50 out_default: 51 return "rootfs"; 52 } 53 54 static int parser_trx_parse(struct mtd_info *mtd, 55 const struct mtd_partition **pparts, 56 struct mtd_part_parser_data *data) 57 { 58 struct mtd_partition *parts; 59 struct mtd_partition *part; 60 struct trx_header trx; 61 size_t bytes_read; 62 uint8_t curr_part = 0, i = 0; 63 int err; 64 65 parts = kcalloc(TRX_PARSER_MAX_PARTS, sizeof(struct mtd_partition), 66 GFP_KERNEL); 67 if (!parts) 68 return -ENOMEM; 69 70 err = mtd_read(mtd, 0, sizeof(trx), &bytes_read, (uint8_t *)&trx); 71 if (err) { 72 pr_err("MTD reading error: %d\n", err); 73 kfree(parts); 74 return err; 75 } 76 77 if (trx.magic != TRX_MAGIC) { 78 kfree(parts); 79 return -ENOENT; 80 } 81 82 /* We have LZMA loader if there is address in offset[2] */ 83 if (trx.offset[2]) { 84 part = &parts[curr_part++]; 85 part->name = "loader"; 86 part->offset = trx.offset[i]; 87 i++; 88 } 89 90 if (trx.offset[i]) { 91 part = &parts[curr_part++]; 92 part->name = "linux"; 93 part->offset = trx.offset[i]; 94 i++; 95 } 96 97 if (trx.offset[i]) { 98 part = &parts[curr_part++]; 99 part->name = parser_trx_data_part_name(mtd, trx.offset[i]); 100 part->offset = trx.offset[i]; 101 i++; 102 } 103 104 /* 105 * Assume that every partition ends at the beginning of the one it is 106 * followed by. 107 */ 108 for (i = 0; i < curr_part; i++) { 109 u64 next_part_offset = (i < curr_part - 1) ? 110 parts[i + 1].offset : mtd->size; 111 112 parts[i].size = next_part_offset - parts[i].offset; 113 } 114 115 *pparts = parts; 116 return i; 117 }; 118 119 static const struct of_device_id mtd_parser_trx_of_match_table[] = { 120 { .compatible = "brcm,trx" }, 121 {}, 122 }; 123 MODULE_DEVICE_TABLE(of, mtd_parser_trx_of_match_table); 124 125 static struct mtd_part_parser mtd_parser_trx = { 126 .parse_fn = parser_trx_parse, 127 .name = "trx", 128 .of_match_table = mtd_parser_trx_of_match_table, 129 }; 130 module_mtd_part_parser(mtd_parser_trx); 131 132 MODULE_LICENSE("GPL v2"); 133 MODULE_DESCRIPTION("Parser for TRX format partitions"); 134