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