Home | History | Annotate | Download | only in updater
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 /* Read/write/erase SPI flash through Linux kernel MTD interface */
     17 
     18 #define LOG_TAG "fwtool"
     19 
     20 #include <errno.h>
     21 #include <fcntl.h>
     22 #include <stdint.h>
     23 #include <stdlib.h>
     24 #include <string.h>
     25 #include <sys/mman.h>
     26 #include <sys/stat.h>
     27 #include <sys/types.h>
     28 #include <unistd.h>
     29 
     30 #include "edify/expr.h"
     31 #include "flash_device.h"
     32 #include "update_log.h"
     33 
     34 struct file_data {
     35 	int fd;
     36 	uint8_t *data;
     37 	struct stat info;
     38 };
     39 
     40 static void *file_blob_open(struct file_data *dev, const Value *param)
     41 {
     42 	dev->fd = -1; /* No backing file */
     43 	dev->data = const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(&param->data[0]));
     44 
     45 	dev->info.st_size = param->data.size();
     46 
     47 	return dev;
     48 }
     49 
     50 static void *file_open(const void *params)
     51 {
     52 	struct file_data *dev = static_cast<struct file_data*>(calloc(1, sizeof(struct file_data)));
     53 	if (!dev)
     54 		return NULL;
     55 
     56 	const Value *value = static_cast<const Value*>(params);
     57 	if (value->type == VAL_BLOB)
     58 		return file_blob_open(dev, value);
     59 
     60 	if (value->type != VAL_STRING)
     61 		goto out_free;
     62 
     63 	dev->fd = open(value->data.c_str(), O_RDWR);
     64 	if (dev->fd == -1) {
     65 		ALOGE("Cannot open file %s : %d\n", value->data.c_str(), errno);
     66 		goto out_free;
     67 	}
     68 
     69 	if (fstat(dev->fd, &dev->info)) {
     70 		ALOGE("Cannot get file info for %s : %d\n", value->data.c_str(), errno);
     71 		goto out_close;
     72 	}
     73 
     74 	dev->data = static_cast<uint8_t*>(mmap(NULL, dev->info.st_size, PROT_READ | PROT_WRITE,
     75 			 MAP_SHARED, dev->fd, 0));
     76 	if (dev->data == (void *)-1) {
     77 		ALOGE("Cannot mmap %s : %d\n", value->data.c_str(), errno);
     78 		goto out_close;
     79 	}
     80 
     81 	ALOGD("File %s: size %lld blksize %ld\n", value->data.c_str(),
     82 		(long long)dev->info.st_size, (long)dev->info.st_blksize);
     83 
     84 	return dev;
     85 
     86 out_close:
     87 	close(dev->fd);
     88 out_free:
     89 	free(dev);
     90 
     91 	return NULL;
     92 }
     93 
     94 static void file_close(void *hnd)
     95 {
     96 	struct file_data *dev = static_cast<struct file_data*>(hnd);
     97 
     98 	if (dev->fd > 0) {
     99 		munmap(dev->data, dev->info.st_size);
    100 		close(dev->fd);
    101 	}
    102 	free(dev);
    103 }
    104 
    105 static int file_read(void *hnd, off_t offset, void *buffer, size_t count)
    106 {
    107 	struct file_data *dev = static_cast<struct file_data*>(hnd);
    108 
    109 	if (offset + (off_t)count > dev->info.st_size) {
    110 		ALOGW("Invalid offset/size %ld + %zd > %lld\n",
    111 			offset, count, (long long)dev->info.st_size);
    112 		return -EINVAL;
    113 	}
    114 
    115 	memcpy(buffer, dev->data + offset, count);
    116 
    117 	return 0;
    118 }
    119 
    120 static int file_write(void *hnd, off_t offset, void *buffer, size_t count)
    121 {
    122 	struct file_data *dev = static_cast<struct file_data*>(hnd);
    123 
    124 	if (offset + (off_t)count > dev->info.st_size) {
    125 		ALOGW("Invalid offset/size %ld + %zd > %lld\n",
    126 			offset, count, (long long)dev->info.st_size);
    127 		return -EINVAL;
    128 	}
    129 
    130 	memcpy(dev->data + offset, buffer, count);
    131 
    132 	return 0;
    133 }
    134 
    135 static int file_erase(void *hnd, off_t offset, size_t count)
    136 {
    137 	struct file_data *dev = static_cast<struct file_data*>(hnd);
    138 
    139 	if (offset + (off_t)count > dev->info.st_size) {
    140 		ALOGW("Invalid offset/size %ld + %zd > %lld\n",
    141 			offset, count, (long long)dev->info.st_size);
    142 		return -EINVAL;
    143 	}
    144 
    145 	memset(dev->data + offset, '\xff', count);
    146 
    147 	return 0;
    148 }
    149 
    150 static size_t file_get_size(void *hnd)
    151 {
    152 	struct file_data *dev = static_cast<struct file_data*>(hnd);
    153 
    154 	return dev ? dev->info.st_size : 0;
    155 }
    156 
    157 static size_t file_get_write_size(void *hnd)
    158 {
    159 	struct file_data *dev = static_cast<struct file_data*>(hnd);
    160 
    161 	return dev && dev->fd > 0 ? dev->info.st_blksize : 0;
    162 }
    163 
    164 static size_t file_get_erase_size(void *hnd)
    165 {
    166 	struct file_data *dev = static_cast<struct file_data*>(hnd);
    167 
    168 	return dev && dev->fd > 0 ? dev->info.st_blksize : 0;
    169 }
    170 
    171 static off_t file_get_fmap_offset(void *hnd)
    172 {
    173 	struct file_data *dev = static_cast<struct file_data*>(hnd);
    174 
    175 	return dev->info.st_size;
    176 }
    177 
    178 const struct flash_device_ops flash_file_ops = {
    179 	.name = "file",
    180 	.open = file_open,
    181 	.close = file_close,
    182 	.read = file_read,
    183 	.write = file_write,
    184 	.erase = file_erase,
    185 	.get_size = file_get_size,
    186 	.get_write_size = file_get_write_size,
    187 	.get_erase_size = file_get_erase_size,
    188 	.get_fmap_offset = file_get_fmap_offset,
    189 };
    190