Esempio n. 1
0
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, &sect);

		/* 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, &sect);

		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;
	}
}
Esempio n. 3
0
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, &sect);

    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, &sect);

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