cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

parser_imagetag.c (5961B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * BCM63XX CFE image tag parser
      4 *
      5 * Copyright © 2006-2008  Florian Fainelli <florian@openwrt.org>
      6 *			  Mike Albon <malbon@openwrt.org>
      7 * Copyright © 2009-2010  Daniel Dickinson <openwrt@cshore.neomailbox.net>
      8 * Copyright © 2011-2013  Jonas Gorski <jonas.gorski@gmail.com>
      9 */
     10
     11#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     12
     13#include <linux/bcm963xx_tag.h>
     14#include <linux/crc32.h>
     15#include <linux/module.h>
     16#include <linux/kernel.h>
     17#include <linux/sizes.h>
     18#include <linux/slab.h>
     19#include <linux/vmalloc.h>
     20#include <linux/mtd/mtd.h>
     21#include <linux/mtd/partitions.h>
     22#include <linux/of.h>
     23
     24/* Ensure strings read from flash structs are null terminated */
     25#define STR_NULL_TERMINATE(x) \
     26	do { char *_str = (x); _str[sizeof(x) - 1] = 0; } while (0)
     27
     28static int bcm963xx_read_imagetag(struct mtd_info *master, const char *name,
     29	loff_t tag_offset, struct bcm_tag *buf)
     30{
     31	int ret;
     32	size_t retlen;
     33	u32 computed_crc;
     34
     35	ret = mtd_read(master, tag_offset, sizeof(*buf), &retlen, (void *)buf);
     36	if (ret)
     37		return ret;
     38
     39	if (retlen != sizeof(*buf))
     40		return -EIO;
     41
     42	computed_crc = crc32_le(IMAGETAG_CRC_START, (u8 *)buf,
     43				offsetof(struct bcm_tag, header_crc));
     44	if (computed_crc == buf->header_crc) {
     45		STR_NULL_TERMINATE(buf->board_id);
     46		STR_NULL_TERMINATE(buf->tag_version);
     47
     48		pr_info("%s: CFE image tag found at 0x%llx with version %s, board type %s\n",
     49			name, tag_offset, buf->tag_version, buf->board_id);
     50
     51		return 0;
     52	}
     53
     54	pr_warn("%s: CFE image tag at 0x%llx CRC invalid (expected %08x, actual %08x)\n",
     55		name, tag_offset, buf->header_crc, computed_crc);
     56	return -EINVAL;
     57}
     58
     59static int bcm963xx_parse_imagetag_partitions(struct mtd_info *master,
     60					const struct mtd_partition **pparts,
     61					struct mtd_part_parser_data *data)
     62{
     63	/* CFE, NVRAM and global Linux are always present */
     64	int nrparts = 0, curpart = 0;
     65	struct bcm_tag *buf = NULL;
     66	struct mtd_partition *parts;
     67	int ret;
     68	unsigned int rootfsaddr, kerneladdr, spareaddr, offset;
     69	unsigned int rootfslen, kernellen, sparelen, totallen;
     70	int i;
     71	bool rootfs_first = false;
     72
     73	buf = vmalloc(sizeof(struct bcm_tag));
     74	if (!buf)
     75		return -ENOMEM;
     76
     77	/* Get the tag */
     78	ret = bcm963xx_read_imagetag(master, "rootfs", 0, buf);
     79	if (!ret) {
     80		STR_NULL_TERMINATE(buf->flash_image_start);
     81		if (kstrtouint(buf->flash_image_start, 10, &rootfsaddr) ||
     82				rootfsaddr < BCM963XX_EXTENDED_SIZE) {
     83			pr_err("invalid rootfs address: %*ph\n",
     84				(int)sizeof(buf->flash_image_start),
     85				buf->flash_image_start);
     86			ret = -EINVAL;
     87			goto out;
     88		}
     89
     90		STR_NULL_TERMINATE(buf->kernel_address);
     91		if (kstrtouint(buf->kernel_address, 10, &kerneladdr) ||
     92				kerneladdr < BCM963XX_EXTENDED_SIZE) {
     93			pr_err("invalid kernel address: %*ph\n",
     94				(int)sizeof(buf->kernel_address),
     95				buf->kernel_address);
     96			ret = -EINVAL;
     97			goto out;
     98		}
     99
    100		STR_NULL_TERMINATE(buf->kernel_length);
    101		if (kstrtouint(buf->kernel_length, 10, &kernellen)) {
    102			pr_err("invalid kernel length: %*ph\n",
    103				(int)sizeof(buf->kernel_length),
    104				buf->kernel_length);
    105			ret = -EINVAL;
    106			goto out;
    107		}
    108
    109		STR_NULL_TERMINATE(buf->total_length);
    110		if (kstrtouint(buf->total_length, 10, &totallen)) {
    111			pr_err("invalid total length: %*ph\n",
    112				(int)sizeof(buf->total_length),
    113				buf->total_length);
    114			ret = -EINVAL;
    115			goto out;
    116		}
    117
    118		/*
    119		 * Addresses are flash absolute, so convert to partition
    120		 * relative addresses. Assume either kernel or rootfs will
    121		 * directly follow the image tag.
    122		 */
    123		if (rootfsaddr < kerneladdr)
    124			offset = rootfsaddr - sizeof(struct bcm_tag);
    125		else
    126			offset = kerneladdr - sizeof(struct bcm_tag);
    127
    128		kerneladdr = kerneladdr - offset;
    129		rootfsaddr = rootfsaddr - offset;
    130		spareaddr = roundup(totallen, master->erasesize);
    131
    132		if (rootfsaddr < kerneladdr) {
    133			/* default Broadcom layout */
    134			rootfslen = kerneladdr - rootfsaddr;
    135			rootfs_first = true;
    136		} else {
    137			/* OpenWrt layout */
    138			rootfsaddr = kerneladdr + kernellen;
    139			rootfslen = spareaddr - rootfsaddr;
    140		}
    141	} else {
    142		goto out;
    143	}
    144	sparelen = master->size - spareaddr;
    145
    146	/* Determine number of partitions */
    147	if (rootfslen > 0)
    148		nrparts++;
    149
    150	if (kernellen > 0)
    151		nrparts++;
    152
    153	parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL);
    154	if (!parts) {
    155		ret = -ENOMEM;
    156		goto out;
    157	}
    158
    159	/* Start building partition list */
    160	if (kernellen > 0) {
    161		int kernelpart = curpart;
    162
    163		if (rootfslen > 0 && rootfs_first)
    164			kernelpart++;
    165		parts[kernelpart].name = "kernel";
    166		parts[kernelpart].offset = kerneladdr;
    167		parts[kernelpart].size = kernellen;
    168		curpart++;
    169	}
    170
    171	if (rootfslen > 0) {
    172		int rootfspart = curpart;
    173
    174		if (kernellen > 0 && rootfs_first)
    175			rootfspart--;
    176		parts[rootfspart].name = "rootfs";
    177		parts[rootfspart].offset = rootfsaddr;
    178		parts[rootfspart].size = rootfslen;
    179		if (sparelen > 0  && !rootfs_first)
    180			parts[rootfspart].size += sparelen;
    181		curpart++;
    182	}
    183
    184	for (i = 0; i < nrparts; i++)
    185		pr_info("Partition %d is %s offset %llx and length %llx\n", i,
    186			parts[i].name, parts[i].offset,	parts[i].size);
    187
    188	pr_info("Spare partition is offset %x and length %x\n",	spareaddr,
    189		sparelen);
    190
    191	*pparts = parts;
    192	ret = 0;
    193
    194out:
    195	vfree(buf);
    196
    197	if (ret)
    198		return ret;
    199
    200	return nrparts;
    201}
    202
    203static const struct of_device_id parse_bcm963xx_imagetag_match_table[] = {
    204	{ .compatible = "brcm,bcm963xx-imagetag" },
    205	{},
    206};
    207MODULE_DEVICE_TABLE(of, parse_bcm963xx_imagetag_match_table);
    208
    209static struct mtd_part_parser bcm963xx_imagetag_parser = {
    210	.parse_fn = bcm963xx_parse_imagetag_partitions,
    211	.name = "bcm963xx-imagetag",
    212	.of_match_table = parse_bcm963xx_imagetag_match_table,
    213};
    214module_mtd_part_parser(bcm963xx_imagetag_parser);
    215
    216MODULE_LICENSE("GPL");
    217MODULE_AUTHOR("Daniel Dickinson <openwrt@cshore.neomailbox.net>");
    218MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
    219MODULE_AUTHOR("Mike Albon <malbon@openwrt.org>");
    220MODULE_AUTHOR("Jonas Gorski <jonas.gorski@gmail.com>");
    221MODULE_DESCRIPTION("MTD parser for BCM963XX CFE Image Tag partitions");