diff -drupN a/drivers/mtd/sunxipart.c b/drivers/mtd/sunxipart.c --- a/drivers/mtd/sunxipart.c 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/mtd/sunxipart.c 2022-06-12 05:28:14.000000000 +0300 @@ -0,0 +1,219 @@ +/* + * SUNXI MTD partitioning + * + * Copyright © 2016 WimHuang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#define pr_fmt(fmt) "sunxipart: " fmt + +#include +#include +#include +#include +#include +#include "efi.h" + +#if IS_ENABLED(CONFIG_ARCH_SUN8IW16) || IS_ENABLED(CONFIG_ARCH_SUN8IW18) || IS_ENABLED(CONFIG_ARCH_SUN8IW19) +#define MBR_OFFSET ((1024 - 16) * 1024) +#else +#define MBR_OFFSET ((512 - 16) * 1024) +#endif +#define MBR_SIZE (16 * 1024) +#define DL_SIZE (16 * 1024) +#define MBR_MAGIC "softw411" +#define MBR_MAX_PART_COUNT 120 +#define MBR_RESERVED (MBR_SIZE - 32 - (MBR_MAX_PART_COUNT * sizeof(struct sunxi_partition))) +#define NOR_BLK_SIZE 512 + +/* partition information */ +struct sunxi_partition { + unsigned int addrhi; + unsigned int addrlo; + unsigned int lenhi; + unsigned int lenlo; + unsigned char classname[16]; + unsigned char name[16]; + unsigned int user_type; + unsigned int keydata; + unsigned int ro; + unsigned char reserved[68]; +} __packed; + +/* mbr information */ +struct sunxi_mbr { + unsigned int crc32; + unsigned int version; + unsigned char magic[8]; + unsigned int copy; + unsigned int index; + unsigned int PartCount; + unsigned int stamp[1]; + struct sunxi_partition array[MBR_MAX_PART_COUNT]; + unsigned char res[MBR_RESERVED]; +} __packed; + +/* save partition's name */ +static char partition_name[MBR_MAX_PART_COUNT][16]; + +/* to get mbr_offset from cmdline */ +static int cmdline_mbr_offset = -1; + +static int __init get_mbr_offset_from_cmdline(char *p) +{ + + pr_debug("%s(%s)\n", __func__, p); + if (p == NULL) { + cmdline_mbr_offset = -1; + } else { + cmdline_mbr_offset = memparse(p, &p); + + if (cmdline_mbr_offset < 0) + cmdline_mbr_offset = -1; + } + return 0; +} + +early_param("mbr_offset", get_mbr_offset_from_cmdline); + +static void sunxipart_add_part(struct mtd_partition *part, char *name, + uint64_t size, uint64_t offset) +{ + part->name = name; + part->size = size; + part->offset = offset; +} + +static int sunxipart_parse(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + int i, ret, nrparts, parts_size; + size_t bytes_read; + struct sunxi_mbr *sunxi_mbr; + struct mtd_partition *parts; + int mbr_offset; + sunxi_mbr = kzalloc(MBR_SIZE, GFP_KERNEL); + if (sunxi_mbr == NULL) { + pr_err("failed to alloc sunxi_mbr\n"); + return -ENOMEM; + } + + if (cmdline_mbr_offset > 0) + mbr_offset = cmdline_mbr_offset; + else + mbr_offset = MBR_OFFSET; + + ret = mtd_read(master, mbr_offset, MBR_SIZE, + &bytes_read, (uint8_t *)sunxi_mbr); + if ((ret < 0)) { + pr_err("failed to read sunxi_mbr!\n"); + kfree(sunxi_mbr); + return -EIO; + } + + if (memcmp(sunxi_mbr->magic, MBR_MAGIC, strlen(MBR_MAGIC)) == 0) { + if ((sunxi_mbr->PartCount == 0) + || (sunxi_mbr->PartCount > MBR_MAX_PART_COUNT)) { + pr_err("failed to parse sunxi_mbr)!\n"); + kfree(sunxi_mbr); + return -EINVAL; + } + + nrparts = sunxi_mbr->PartCount + 1; + parts_size = nrparts * sizeof(*parts); + parts = kzalloc(parts_size, GFP_KERNEL); + if (parts == NULL) { + pr_err("failed to alloc %d patitions\n", nrparts); + kfree(sunxi_mbr); + return -ENOMEM; + } + + strncpy(partition_name[0], "uboot", 16); + sunxipart_add_part(&parts[0], partition_name[0], + mbr_offset + MBR_SIZE, 0); + for (i = 1; i < nrparts; i++) { + strncpy(partition_name[i], sunxi_mbr->array[i - 1].name, + 16); + + sunxipart_add_part( + &parts[i], partition_name[i], + sunxi_mbr->array[i - 1].lenlo * NOR_BLK_SIZE, + sunxi_mbr->array[i - 1].addrlo * NOR_BLK_SIZE + + mbr_offset); + } + } else { + struct _gpt_header *gpt_head = + (struct _gpt_header *)((char *)sunxi_mbr + 512); + struct _gpt_entry *entry = + (struct _gpt_entry *)((char *)sunxi_mbr + 1024); + unsigned int j = 0; + + if (gpt_head->signature != GPT_HEADER_SIGNATURE) { + pr_err("failed to parse sunxi_gpt!\n"); + kfree(sunxi_mbr); + return -EINVAL; + } + nrparts = gpt_head->num_partition_entries + 1; + parts_size = nrparts * sizeof(*parts); + parts = kzalloc(parts_size, GFP_KERNEL); + if (parts == NULL) { + pr_err("failed to alloc %d patitions\n", nrparts); + kfree(sunxi_mbr); + return -ENOMEM; + } + + strncpy(partition_name[0], "uboot", 16); + sunxipart_add_part(&parts[0], partition_name[0], + mbr_offset + MBR_SIZE, 0); + for (i = 1; i < nrparts; i++) { + for (j = 0; j < 16; j++) + partition_name[i][j] = + (char)(entry[i - 1].partition_name[j]); + + pr_debug("GPT:%-12s: %-12llx %-12llx\n", + partition_name[i], entry[i - 1].starting_lba, + entry[i - 1].ending_lba); + + sunxipart_add_part(&parts[i], partition_name[i], + (entry[i - 1].ending_lba - + entry[i - 1].starting_lba + 1) * + NOR_BLK_SIZE, + entry[i - 1].starting_lba * + NOR_BLK_SIZE + + mbr_offset); + } + } + + kfree(sunxi_mbr); + *pparts = parts; + return nrparts; +} + +static struct mtd_part_parser sunxipart_mtd_parser = { + .owner = THIS_MODULE, + .parse_fn = sunxipart_parse, + .name = "sunxipart", +}; + +static int __init sunxipart_init(void) +{ + register_mtd_parser(&sunxipart_mtd_parser); + + return 0; +} + +static void __exit sunxipart_exit(void) +{ + deregister_mtd_parser(&sunxipart_mtd_parser); +} + +module_init(sunxipart_init); +module_exit(sunxipart_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("MTD partitioning for SUNXI flash memories");