Ejemplo n.º 1
0
static int load_image(struct pil_device *pil)
{
	int i, ret;
	char fw_name[30];
	struct elf32_hdr *ehdr;
	const struct elf32_phdr *phdr;
	const struct firmware *fw;
	unsigned long proxy_timeout = pil->desc->proxy_timeout;

	down_read(&pil_pm_rwsem);
	snprintf(fw_name, sizeof(fw_name), "%s.mdt", pil->desc->name);
	ret = request_firmware(&fw, fw_name, &pil->dev);
	if (ret) {
		dev_err(&pil->dev, "Failed to locate %s\n", fw_name);
		goto out;
	}

	if (fw->size < sizeof(*ehdr)) {
		dev_err(&pil->dev, "Not big enough to be an elf header\n");
		ret = -EIO;
		goto release_fw;
	}

	ehdr = (struct elf32_hdr *)fw->data;
	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
		dev_err(&pil->dev, "Not an elf header\n");
		ret = -EIO;
		goto release_fw;
	}

	if (ehdr->e_phnum == 0) {
		dev_err(&pil->dev, "No loadable segments\n");
		ret = -EIO;
		goto release_fw;
	}
	if (sizeof(struct elf32_phdr) * ehdr->e_phnum +
	    sizeof(struct elf32_hdr) > fw->size) {
		dev_err(&pil->dev, "Program headers not within mdt\n");
		ret = -EIO;
		goto release_fw;
	}

	ret = pil->desc->ops->init_image(pil->desc, fw->data, fw->size);
	if (ret) {
		dev_err(&pil->dev, "Invalid firmware metadata\n");
		goto release_fw;
	}

	phdr = (const struct elf32_phdr *)(fw->data + sizeof(struct elf32_hdr));
	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
		if (!segment_is_loadable(phdr))
			continue;

		ret = load_segment(phdr, i, pil);
		if (ret) {
			dev_err(&pil->dev, "Failed to load segment %d\n",
					i);
			goto release_fw;
		}
	}

	ret = pil_proxy_vote(pil);
	if (ret) {
		dev_err(&pil->dev, "Failed to proxy vote\n");
		goto release_fw;
	}

	ret = pil->desc->ops->auth_and_reset(pil->desc);
	if (ret) {
		dev_err(&pil->dev, "Failed to bring out of reset\n");
		proxy_timeout = 0; /* Remove proxy vote immediately on error */
		goto err_boot;
	}
	dev_info(&pil->dev, "brought %s out of reset\n", pil->desc->name);
err_boot:
	pil_proxy_unvote(pil, proxy_timeout);
release_fw:
	release_firmware(fw);
out:
	up_read(&pil_pm_rwsem);
	return ret;
}
static int load_image(struct pil_device *pil)
{
	int i, ret;
	char fw_name[30];
	struct elf32_hdr *ehdr;
	const struct elf32_phdr *phdr;
	const struct firmware *fw;
	unsigned long proxy_timeout = pil->desc->proxy_timeout;
#ifdef CONFIG_SEC_DEBUG
	static int load_count;
#endif
#ifdef CONFIG_SEC_PERIPHERAL_SECURE_CHK
	static int load_count_fwd;
	static int load_count_auth;
#endif

	down_read(&pil_pm_rwsem);
	snprintf(fw_name, sizeof(fw_name), "%s.mdt", pil->desc->name);
	ret = request_firmware(&fw, fw_name, &pil->dev);
	if (ret) {
		dev_err(&pil->dev, "%s: Failed to locate %s\n",
				pil->desc->name, fw_name);
#ifdef CONFIG_SEC_DEBUG
		load_count++;
		if (load_count > 10 && check_power_off_and_restart() == 0)
			panic("Failed to load %s image!", fw_name);
#endif
		goto out;
	}

	if (fw->size < sizeof(*ehdr)) {
		dev_err(&pil->dev, "%s: Not big enough to be an elf header\n",
				pil->desc->name);
		ret = -EIO;
		goto release_fw;
	}

	ehdr = (struct elf32_hdr *)fw->data;
	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
		dev_err(&pil->dev, "%s: Not an elf header\n", pil->desc->name);
		ret = -EIO;
		goto release_fw;
	}

	if (ehdr->e_phnum == 0) {
		dev_err(&pil->dev, "%s: No loadable segments\n",
				pil->desc->name);
		ret = -EIO;
		goto release_fw;
	}
	if (sizeof(struct elf32_phdr) * ehdr->e_phnum +
	    sizeof(struct elf32_hdr) > fw->size) {
		dev_err(&pil->dev, "%s: Program headers not within mdt\n",
				pil->desc->name);
		ret = -EIO;
		goto release_fw;
	}

	ret = pil->desc->ops->init_image(pil->desc, fw->data, fw->size);
	if (ret) {
		dev_err(&pil->dev, "%s: Invalid firmware metadata %d\n",
				pil->desc->name, ret);
#ifdef CONFIG_SEC_PERIPHERAL_SECURE_CHK
		load_count_fwd++;
		if (load_count_fwd > 10) {
			release_firmware(fw);
			up_read(&pil_pm_rwsem);
			sec_peripheral_secure_check_fail();
		} else {
			goto release_fw;
		}
#else
		goto release_fw;
#endif
	}

	phdr = (const struct elf32_phdr *)(fw->data + sizeof(struct elf32_hdr));
	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
		if (!segment_is_loadable(phdr))
			continue;

		ret = load_segment(phdr, i, pil);
		if (ret) {
			dev_err(&pil->dev, "%s: Failed to load segment %d\n",
					pil->desc->name, i);
			goto release_fw;
		}
	}

	ret = pil_proxy_vote(pil);
	if (ret) {
		dev_err(&pil->dev, "%s: Failed to proxy vote\n",
					pil->desc->name);
		goto release_fw;
	}

	ret = pil->desc->ops->auth_and_reset(pil->desc);
	if (ret) {
		dev_err(&pil->dev, "%s: Failed to bring out of reset %d\n",
				pil->desc->name, ret);
		proxy_timeout = 0; /* Remove proxy vote immediately on error */
#ifdef CONFIG_SEC_PERIPHERAL_SECURE_CHK
		load_count_auth++;
		if (load_count_auth > 10) {
			release_firmware(fw);
			up_read(&pil_pm_rwsem);
			sec_peripheral_secure_check_fail();
		} else {
			goto release_fw;
		}
#else
		goto err_boot;
#endif
	}
	dev_info(&pil->dev, "%s: Brought out of reset\n", pil->desc->name);
#ifndef CONFIG_SEC_PERIPHERAL_SECURE_CHK
err_boot:
#endif
	pil_proxy_unvote(pil, proxy_timeout);
release_fw:
	release_firmware(fw);
out:
	up_read(&pil_pm_rwsem);
	return ret;
}