int open_cmdline(struct inode *i, struct file *f) { struct cmdline_priv *p; int ret ; p = kzalloc(sizeof(*p), GFP_KERNEL); if (i->i_private) p->osip_id = (int) i->i_private; f->private_data = 0; access_osip_record(osip_find_cmdline, (void *)p); /* need to open it again */ p->bdev = get_emmc_bdev(); if (!p->bdev) { pr_err("%s:access_osip_record failed!\n", __func__); ret = -ENODEV; goto free; } ret = blkdev_get(p->bdev, f->f_mode); if (ret < 0) { pr_err("%s: blk_dev_get failed!\n", __func__); goto put; } if (p->lba >= get_capacity(p->bdev->bd_disk)) { pr_err("%s: %d out of disk bound!\n", __func__, p->lba); ret = -EINVAL; goto put; } p->cmdline = read_dev_sector(p->bdev, p->lba, &p->sect); if (!p->cmdline) { pr_err("%s:read_dev_sector failed!\n", __func__); ret = -ENODEV; goto put; } f->private_data = p; return 0; put: blkdev_put(p->bdev, f->f_mode); free: kfree(p); return -ENODEV; }
int intel_scu_ipc_write_umip(u8 *data, int len, int offset) { int i, ret = 0, offset_align; int remainder, len_align = 0; u32 dptr, sptr, cmd; u8 cs, tbl_cs = 0, *buf = NULL; Sector sect; struct block_device *bdev; char *buffer = NULL; int *holderId = NULL; int sect_no; u8 checksum; if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_CLOVERVIEW) { /* Opening the mmcblk0boot0 */ bdev = get_emmc_bdev(); if (bdev == NULL) { pr_err("%s: get_emmc failed!\n", __func__); return -ENODEV; } /* make sure the block device is open rw */ ret = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, holderId); if (ret < 0) { pr_err("%s: blk_dev_get failed!\n", __func__); return -ret; } /* get memmap of the UMIP header */ sect_no = offset / SECTOR_SIZE; remainder = offset % SECTOR_SIZE; buffer = read_dev_sector(bdev, sect_no + UMIP_HEADER_HEADROOM_SECTOR, §); /* Shouldn't need to access UMIP sector 0/1 */ if (sect_no < UMIP_TOTAL_HEADER_SECTOR_NO) { pr_err("invalid umip offset\n"); ret = -EINVAL; goto bd_put; } else if (data == NULL || buffer == NULL) { pr_err("buffer is empty\n"); ret = -ENODEV; goto bd_put; } else if (len > (SECTOR_SIZE - remainder)) { pr_err("too much data to write\n"); ret = -EINVAL; goto bd_put; } lock_page(sect.v); memcpy(buffer + remainder, data, len); checksum = calc_checksum(buffer, SECTOR_SIZE); set_page_dirty(sect.v); unlock_page(sect.v); sync_blockdev(bdev); put_dev_sector(sect); /* * Updating the checksum, sector 0 (starting from UMIP * offset 0x08), we maintains 4 bytes for tracking each of * sector changes individually. For example, the dword at * offset 0x08 is used to checksum data integrity of sector * number 2, and so on so forth. It's worthnoting that only * the first byte in each 4 bytes stores checksum. * For detail, please check CTP FAS UMIP header definition */ buffer = read_dev_sector(bdev, UMIP_HEADER_SECTOR + UMIP_HEADER_HEADROOM_SECTOR, §); if (buffer == NULL) { pr_err("buffer is empty\n"); ret = -ENODEV; goto bd_put; } lock_page(sect.v); memcpy(buffer + 4 * (sect_no - UMIP_TOTAL_HEADER_SECTOR_NO) + UMIP_START_CHKSUM_ADDR, &checksum, 1/* one byte */); /* Change UMIP prologue chksum to zero */ *(buffer + UMIP_HEADER_CHKSUM_ADDR) = 0; for (i = 0; i < UMIP_TOTAL_CHKSUM_ENTRY; i++) { tbl_cs ^= *(u8 *)(buffer + 4 * i + UMIP_START_CHKSUM_ADDR); } /* Finish up with re-calcuating UMIP prologue checksum */ cs = dword_to_byte_chksum(xorblock((u32 *)buffer, SECTOR_SIZE)); *(buffer + UMIP_HEADER_CHKSUM_ADDR) = tbl_cs ^ cs; set_page_dirty(sect.v); unlock_page(sect.v); sync_blockdev(bdev); bd_put: if (buffer) put_dev_sector(sect); blkdev_put(bdev, FMODE_READ|FMODE_WRITE); return ret; } else { if (!intel_mip_base) return -ENODEV; if (offset + len > IPC_MIP_MAX_ADDR) return -EINVAL; rpmsg_global_lock(); offset_align = offset & (~0x3); len_align = (len + (offset - offset_align) + 3) & (~0x3); if (len != len_align) { buf = kzalloc(len_align, GFP_KERNEL); if (!buf) { pr_err("Alloc memory failed\n"); ret = -ENOMEM; goto fail; } ret = read_mip(buf, len_align, offset_align, 0); if (ret) goto fail; memcpy(buf + offset - offset_align, data, len); } else { buf = data; } dptr = offset_align; sptr = len_align / 4; cmd = IPC_CMD_UMIP_WR << 12 | IPCMSG_MIP_ACCESS; memcpy(intel_mip_base, buf, len_align); ret = rpmsg_send_raw_command(mip_instance, cmd, 0, NULL, NULL, 0, 0, sptr, dptr); fail: if (buf && len_align != len) kfree(buf); rpmsg_global_unlock(); return ret; } }
static int access_osip_record(osip_callback_t callback, void *cb_data) { Sector sect; struct block_device *bdev; char *buffer; struct OSIP_header *osip; struct OSIP_header *osip_backup; int ret = 0; int dirty = 0; bdev = get_emmc_bdev(); if (bdev == NULL) { pr_err("%s: get_emmc failed!\n", __func__); return -ENODEV; } /* make sure the block device is open rw */ ret = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, NULL); if (ret < 0) { pr_err("%s: blk_dev_get failed!\n", __func__); return -ret; } /* get memmap of the OSIP header */ buffer = read_dev_sector(bdev, 0, §); if (buffer == NULL) { ret = -ENODEV; goto bd_put; } osip = (struct OSIP_header *) buffer; /* some sanity checks */ if (osip->header_size <= 0 || osip->header_size > PAGE_SIZE) { pr_err("%s: corrupted osip!\n", __func__); ret = -EINVAL; goto put_sector; } if (calc_checksum(osip, osip->header_size) != 0) { pr_err("%s: corrupted osip!\n", __func__); ret = -EINVAL; goto put_sector; } /* store the OSIP backup which will be used to recover in PrOS */ osip_backup = kmalloc(sizeof(struct OSIP_header), GFP_KERNEL); if (osip_backup == NULL) goto put_sector; memcpy(osip_backup, osip, sizeof(struct OSIP_header)); lock_page(sect.v); dirty = callback(osip, cb_data); if (dirty) { memcpy(buffer + OSIP_BACKUP_OFFSET, osip_backup, sizeof(struct OSIP_header)); osip->header_checksum = 0; osip->header_checksum = calc_checksum(osip, osip->header_size); set_page_dirty(sect.v); } unlock_page(sect.v); sync_blockdev(bdev); kfree(osip_backup); put_sector: put_dev_sector(sect); bd_put: blkdev_put(bdev, FMODE_READ|FMODE_WRITE); return 0; }
int intel_scu_ipc_read_mip(u8 *data, int len, int offset, int issigned) { int ret = 0; Sector sect; struct block_device *bdev; char *buffer = NULL; int *holderId = NULL; int sect_no, remainder; /* Only SMIP read for Cloverview is supported */ if ((intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_CLOVERVIEW) && (issigned != 1)) { /* CTP read UMIP from eMMC */ /* Opening the mmcblk0boot0 */ bdev = get_emmc_bdev(); if (bdev == NULL) { pr_err("%s: get_emmc failed!\n", __func__); return -ENODEV; } /* make sure the block device is open read only */ ret = blkdev_get(bdev, FMODE_READ, holderId); if (ret < 0) { pr_err("%s: blk_dev_get failed!\n", __func__); return -ret; } /* Get sector number of where data located */ sect_no = offset / SECTOR_SIZE; remainder = offset % SECTOR_SIZE; buffer = read_dev_sector(bdev, sect_no + UMIP_HEADER_HEADROOM_SECTOR, §); /* Shouldn't need to access UMIP sector 0/1 */ if (sect_no < UMIP_TOTAL_HEADER_SECTOR_NO) { pr_err("invalid umip offset\n"); ret = -EINVAL; goto bd_put; } else if (data == NULL || buffer == NULL) { pr_err("buffer is empty\n"); ret = -ENODEV; goto bd_put; } else if (len > (SECTOR_SIZE - remainder)) { pr_err("not enough data to read\n"); ret = -EINVAL; goto bd_put; } memcpy(data, buffer + remainder, len); bd_put: if (buffer) put_dev_sector(sect); blkdev_put(bdev, FMODE_READ); return ret; } else { if (!intel_mip_base) return -ENODEV; if (offset + len > IPC_MIP_MAX_ADDR) return -EINVAL; rpmsg_global_lock(); ret = read_mip(data, len, offset, issigned); rpmsg_global_unlock(); return ret; } }