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; }