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;
}
Beispiel #3
0
static int
qproc_load_segments(struct qproc *qproc, const struct firmware *fw)
{
	struct device *dev = qproc->dev;
	struct elf32_hdr *ehdr;
	struct elf32_phdr *phdr;
	int i, ret = 0;
	const u8 *elf_data = fw->data;
	const struct firmware *seg_fw;
	char fw_name[20];

	const struct mdt_hdr *mdt;
	phys_addr_t min_addr = (phys_addr_t)ULLONG_MAX;
	phys_addr_t max_addr = 0;
	size_t align = 0;
	bool relocatable = false;
	phys_addr_t paddr;


	ehdr = (struct elf32_hdr *)elf_data;
	phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);


	mdt = (struct mdt_hdr *)fw->data;
	ehdr = &mdt->hdr;

	for (i = 0; i < ehdr->e_phnum; i++) {
		phdr = &mdt->phdr[i];

		if (!segment_is_loadable(phdr))
			continue;

		if (phdr->p_paddr < min_addr) {
			min_addr = phdr->p_paddr;

			if (segment_is_relocatable(phdr)) {
				align = phdr->p_align;
				relocatable = true;
			}
		}

		if (phdr->p_paddr + phdr->p_memsz > max_addr)
			max_addr = round_up(phdr->p_paddr + phdr->p_memsz, SZ_4K);
	}

	ehdr = (struct elf32_hdr *)elf_data;
	phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
	/* go through the available ELF segments */
	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
		u32 da = phdr->p_paddr;
		u32 paddr = phdr->p_paddr;
		u32 memsz = phdr->p_memsz;
		u32 filesz = phdr->p_filesz;
		void *ptr;

		if (!segment_is_loadable(phdr))
			continue;
		/*
		if (phdr->p_type != PT_LOAD)
			continue;

		if (segment_is_hash(phdr->p_flags))
			continue;

		if (filesz == 0)
			continue;
*/
		//dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
		pr_emerg("phdr(%d): type %d paddr 0x%x memsz 0x%x filesz 0x%x\n",
					i, phdr->p_type, paddr, memsz, filesz);

		if (filesz > memsz) {
			dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
							filesz, memsz);
			ret = -EINVAL;
			break;
		}

		paddr = relocatable ?
				(phdr->p_paddr - min_addr + qproc->reloc_phys) :
				phdr->p_paddr;

		pr_emerg("Relocated-phdr(%d): type %d paddr 0x%x memsz 0x%x filesz 0x%x\n",
					i, phdr->p_type, paddr, memsz, filesz);
//		if (filesz) {
			snprintf(fw_name, sizeof(fw_name), "modem.b%02d", i);
			ret = qproc_load_segment(qproc, fw_name, phdr, paddr);
//		}
#if 0

		ptr = ioremap(da, memsz);
		if (!ptr) {
			dev_err(qproc->dev, "failed to allocate mba metadata buffer\n");
			ret = -ENOMEM;
			break;
		}

		if (filesz) {
			snprintf(fw_name, sizeof(fw_name), "modem.b%02d", i);
			ret = request_firmware(&seg_fw, fw_name, qproc->dev);
			if (ret) {
				iounmap(ptr);
				break;
			}

			memcpy(ptr, seg_fw->data, filesz);

			release_firmware(seg_fw);
		}

		if (memsz > filesz)
			memset(ptr + filesz, 0, memsz - filesz);



		wmb();
		iounmap(ptr);
#endif
	}

	return ret;
}
Beispiel #4
0
static int qproc_verify_segments(struct qproc *qproc, const struct firmware *fw)
{
	struct elf32_hdr *ehdr;
	struct elf32_phdr *phdr;
	const u8 *elf_data = fw->data;
	unsigned long timeout;
	phys_addr_t min_addr = (phys_addr_t)ULLONG_MAX;
	u32 size = 0;
	s32 val;
	int ret;
	int i;
	u32 v;

	ehdr = (struct elf32_hdr *)elf_data;
	phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);

	v = readl_relaxed(qproc->rmb_base + RMB_PMI_CODE_LENGTH);
	dev_err(qproc->dev, "RMB_PMI_CODE_LENGTH: %pa\n", &v);

	msleep(1);


#if 1
	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
		phys_addr_t da = phdr->p_paddr;
		u32 memsz = phdr->p_memsz;


		if (!segment_is_loadable(phdr))
			continue;
		/*
		if (phdr->p_type != PT_LOAD)
			continue;
*/
		dev_err(qproc->dev, "0x%x %d %d\n", phdr->p_paddr, segment_is_hash(phdr->p_flags), !!(phdr->p_flags & BIT(27)));

		/*
		if (segment_is_hash(phdr->p_flags))
			continue;

		if (memsz == 0)
			continue;
		*/
		if (da < min_addr)
			min_addr = da;

		size += memsz;
	}

	dev_err(qproc->dev, "verify: %pa:%pa\n", &min_addr, &size);
	v = readl_relaxed(qproc->rmb_base + RMB_PMI_CODE_LENGTH);
	dev_err(qproc->dev, "RMB_PMI_CODE_LENGTH: %pa\n", &v);
#if 0
if (v == 0) {
	writel_relaxed(min_addr, qproc->rmb_base + RMB_PMI_CODE_START);
	writel(CMD_LOAD_READY, qproc->rmb_base + RMB_MBA_COMMAND);
}
	writel(size, qproc->rmb_base + RMB_PMI_CODE_LENGTH);
#endif
#endif

	v = readl_relaxed(qproc->rmb_base + RMB_PMI_CODE_LENGTH);
	dev_err(qproc->dev, "RMB_PMI_CODE_LENGTH: %pa\n", &v);
	
	printk("DEBUG:pil: status... %08x\n", readl_relaxed(qproc->rmb_base + RMB_MBA_STATUS));

	timeout = jiffies + 10 * HZ;
	for (;;) {
		msleep(1);

		val = readl(qproc->rmb_base + RMB_MBA_STATUS);
		if (val == STATUS_AUTH_COMPLETE || val < 0)
			break;

		if (time_after(jiffies, timeout))
			break;
	}
	if (val == 0) {
		dev_err(qproc->dev, "MBA authentication of headers timed out\n");
		ret = -ETIMEDOUT;
		goto out;
	} else if (val < 0) {
		dev_err(qproc->dev, "MBA returned error %d for segments\n", val);
		ret = -EINVAL;
		goto out;
	}

	ret = 0;
out:
	return ret;


}
Beispiel #5
0
static int
old_qproc_load_segments(struct qproc *qproc, const struct firmware *fw)
{
	struct device *dev = qproc->dev;
	struct elf32_hdr *ehdr;
	struct elf32_phdr *phdr;
	int i, ret = 0;
	const u8 *elf_data = fw->data;
	const struct firmware *seg_fw;
	char fw_name[20];

	ehdr = (struct elf32_hdr *)elf_data;
	phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);



	/* go through the available ELF segments */
	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
		u32 da = phdr->p_paddr;
		u32 memsz = phdr->p_memsz;
		u32 filesz = phdr->p_filesz;
		void *ptr;

		if (!segment_is_loadable(phdr))
			continue;
		/*
		if (phdr->p_type != PT_LOAD)
			continue;

		if (segment_is_hash(phdr->p_flags))
			continue;

		if (filesz == 0)
			continue;
*/
		//dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
		pr_emerg("phdr(%d): type %d da 0x%x memsz 0x%x filesz 0x%x\n",
					i, phdr->p_type, da, memsz, filesz);

		if (filesz > memsz) {
			dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
							filesz, memsz);
			ret = -EINVAL;
			break;
		}

		ptr = ioremap(da, memsz);
		if (!ptr) {
			dev_err(qproc->dev, "failed to allocate mba metadata buffer\n");
			ret = -ENOMEM;
			break;
		}

		if (filesz) {
			snprintf(fw_name, sizeof(fw_name), "modem.b%02d", i);
			ret = request_firmware(&seg_fw, fw_name, qproc->dev);
			if (ret) {
				iounmap(ptr);
				break;
			}

			memcpy(ptr, seg_fw->data, filesz);

			release_firmware(seg_fw);
		}

		if (memsz > filesz)
			memset(ptr + filesz, 0, memsz - filesz);



		wmb();
		iounmap(ptr);
	}

	return ret;
}