18b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Copyright (C) 2007-2008 The Android Open Source Project 28b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** 38b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** This software is licensed under the terms of the GNU General Public 48b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** License version 2, as published by the Free Software Foundation, and 58b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** may be copied, distributed, and modified under those terms. 68b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** 78b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** This program is distributed in the hope that it will be useful, 88b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** but WITHOUT ANY WARRANTY; without even the implied warranty of 98b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** GNU General Public License for more details. 118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project*/ 1228a09b6fe8d8f3e92ffee9263609a6da881b8818David 'Digit' Turner#include "migration/qemu-file.h" 13f0665425f3d93ce5c43147e00d8d5259708f0176David 'Digit' Turner#include "nand_reg.h" 14d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian#include "hw/android/goldfish/device.h" 15f0665425f3d93ce5c43147e00d8d5259708f0176David 'Digit' Turner#include "hw/android/goldfish/nand.h" 16f5bc01c356e1fa924ed07aadf589b3663873593eDavid 'Digit' Turner#include "hw/android/goldfish/vmem.h" 170e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner#include "hw/hw.h" 188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "android/utils/tempfile.h" 19e1e03df288d5a44bfbffbd86588395c7cbbc27dfDavid 'Digit' Turner#include "android/qemu-debug.h" 208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "android/android.h" 218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define DEBUG 1 238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#if DEBUG 24acbee3546b9a380a4eb33daef3dccfac87c56b0bXavier Ducrohet# define D(...) VERBOSE_PRINT(init,__VA_ARGS__) 25acbee3546b9a380a4eb33daef3dccfac87c56b0bXavier Ducrohet# define D_ACTIVE VERBOSE_CHECK(init) 268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project# define T(...) VERBOSE_PRINT(nand_limits,__VA_ARGS__) 278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project# define T_ACTIVE VERBOSE_CHECK(nand_limits) 288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#else 298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project# define D(...) ((void)0) 308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project# define D_ACTIVE 0 318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project# define T(...) ((void)0) 328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project# define T_ACTIVE 0 338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif 348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* lseek uses 64-bit offsets on Darwin. */ 368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* prefer lseek64 on Linux */ 378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef __APPLE__ 388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project# define llseek lseek 398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#elif defined(__linux__) 408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project# define llseek lseek64 418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif 428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define XLOG xlog 448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void 468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectxlog( const char* format, ... ) 478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project va_list args; 498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project va_start(args, format); 508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project fprintf(stderr, "NAND: "); 518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project vfprintf(stderr, format, args); 528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project va_end(args); 538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 55c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije/* Information on a single device/nand image used by the emulator 56c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije */ 578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct { 58c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije char* devname; /* name for this device (not null-terminated, use len below) */ 598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project size_t devname_len; 60c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije uint8_t* data; /* buffer for read/write actions to underlying image */ 618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int fd; 628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t flags; 638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t page_size; 648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t extra_size; 65c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije uint32_t erase_size; /* size of the data buffer mentioned above */ 66c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije uint64_t max_size; /* Capacity limit for the image. The actual underlying 67c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije * file may be smaller. */ 688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} nand_dev; 698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectnand_threshold android_nand_write_threshold; 718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectnand_threshold android_nand_read_threshold; 728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef CONFIG_NAND_THRESHOLD 748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* update a threshold, return 1 if limit is hit, 0 otherwise */ 768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void 778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectnand_threshold_update( nand_threshold* t, uint32_t len ) 788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (t->counter < t->limit) { 808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint64_t avail = t->limit - t->counter; 818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (avail > len) 828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project avail = len; 838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (t->counter == 0) { 85e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine T("%s: starting threshold counting to %lld", 868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project __FUNCTION__, t->limit); 878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project t->counter += avail; 898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (t->counter >= t->limit) { 908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* threshold reach, send a signal to an external process */ 91e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine T( "%s: sending signal %d to pid %d !", 928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project __FUNCTION__, t->signal, t->pid ); 938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project kill( t->pid, t->signal ); 958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return; 988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define NAND_UPDATE_READ_THRESHOLD(len) \ 1018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project nand_threshold_update( &android_nand_read_threshold, (uint32_t)(len) ) 1028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define NAND_UPDATE_WRITE_THRESHOLD(len) \ 1048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project nand_threshold_update( &android_nand_write_threshold, (uint32_t)(len) ) 1058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#else /* !NAND_THRESHOLD */ 1078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define NAND_UPDATE_READ_THRESHOLD(len) \ 1098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project do {} while (0) 1108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define NAND_UPDATE_WRITE_THRESHOLD(len) \ 1128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project do {} while (0) 1138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif /* !NAND_THRESHOLD */ 1158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic nand_dev *nand_devs = NULL; 1178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic uint32_t nand_dev_count = 0; 1188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 119c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije/* The controller is the single access point for all NAND images currently 120c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije * attached to the system. 121c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije */ 1228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct { 1238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t base; 1248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project // register state 126c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije uint32_t dev; /* offset in nand_devs for the device that is 127c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije * currently being accessed */ 1288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t addr_low; 1298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t addr_high; 1308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t transfer_size; 131d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian uint64_t data; 132f1f1f5ff5b87d4f754572e0f05398842f0cde059Jiang Yunhong uint32_t batch_addr_low; 133f1f1f5ff5b87d4f754572e0f05398842f0cde059Jiang Yunhong uint32_t batch_addr_high; 1348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t result; 135c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije} nand_dev_controller_state; 1368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 137c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije/* update this everytime you change the nand_dev_controller_state structure 138c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije * 1: initial version, saving only nand_dev_controller_state fields 139c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije * 2: saving actual disk contents as well 140a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock * 3: use the correct data length and truncate to avoid padding. 141c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije */ 142d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian#define NAND_DEV_STATE_SAVE_VERSION 5 143d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian#define NAND_DEV_STATE_SAVE_VERSION_LEGACY 4 1448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 145c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije#define QFIELD_STRUCT nand_dev_controller_state 146c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten ThijeQFIELD_BEGIN(nand_dev_controller_state_fields) 1478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project QFIELD_INT32(dev), 1488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project QFIELD_INT32(addr_low), 1498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project QFIELD_INT32(addr_high), 1508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project QFIELD_INT32(transfer_size), 151d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian QFIELD_INT64(data), 152663d101937e86e2551fdca2cdd10db5b1fcbc7e7Jiang, Yunhong QFIELD_INT32(batch_addr_low), 153663d101937e86e2551fdca2cdd10db5b1fcbc7e7Jiang, Yunhong QFIELD_INT32(batch_addr_high), 1548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project QFIELD_INT32(result), 1558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source ProjectQFIELD_END 1568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 157d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian// Legacy encoding support, split the structure in two halves, with 158d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian// a 32-bit |data| field in the middle to be loaded explictly. 159d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun TianQFIELD_BEGIN(nand_dev_controller_state_legacy_1_fields) 160d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian QFIELD_INT32(dev), 161d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian QFIELD_INT32(addr_low), 162d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian QFIELD_INT32(addr_high), 163d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian QFIELD_INT32(transfer_size), 164d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun TianQFIELD_END 165d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian 166d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun TianQFIELD_BEGIN(nand_dev_controller_state_legacy_2_fields) 167d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian QFIELD_INT32(batch_addr_low), 168d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian QFIELD_INT32(batch_addr_high), 169d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian QFIELD_INT32(result), 170d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun TianQFIELD_END 1718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 172a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock/* EINTR-proof read - due to SIGALRM in use elsewhere */ 1738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int do_read(int fd, void* buf, size_t size) 1748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 1758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int ret; 1768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project do { 1778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ret = read(fd, buf, size); 1788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } while (ret < 0 && errno == EINTR); 1798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return ret; 1818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 1828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 183a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock/* EINTR-proof write - due to SIGALRM in use elsewhere */ 1848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int do_write(int fd, const void* buf, size_t size) 1858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 1868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int ret; 1878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project do { 1888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ret = write(fd, buf, size); 1898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } while (ret < 0 && errno == EINTR); 1908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return ret; 1928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 1938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 194a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock/* EINTR-proof lseek - due to SIGALRM in use elsewhere */ 195ad05f2c46b62b2a34e498caec852f74f58c602c9Chris Dearmanstatic off_t do_lseek(int fd, off_t offset, int whence) 196a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock{ 197ad05f2c46b62b2a34e498caec852f74f58c602c9Chris Dearman off_t ret; 198a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock do { 199a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock ret = lseek(fd, offset, whence); 200ad05f2c46b62b2a34e498caec852f74f58c602c9Chris Dearman } while (ret == -1 && errno == EINTR); 201a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock 202a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock return ret; 203a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock} 204a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock 205a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock/* EINTR-proof ftruncate - due to SIGALRM in use elsewhere */ 206a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstockstatic int do_ftruncate(int fd, size_t size) 207a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock{ 208a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock int ret; 209a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock do { 210a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock ret = ftruncate(fd, size); 211a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock } while (ret < 0 && errno == EINTR); 212a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock 213a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock return ret; 214a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock} 215a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock 216c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije#define NAND_DEV_SAVE_DISK_BUF_SIZE 2048 217c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije 218c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije 219c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije/** 220c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije * Copies the current contents of a disk image into the snapshot file. 221c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije * 222c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije * TODO optimize this using some kind of copy-on-write mechanism for 223c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije * unchanged disk sections. 224c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije */ 225c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thijestatic void nand_dev_save_disk_state(QEMUFile *f, nand_dev *dev) 226c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije{ 227c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije int buf_size = NAND_DEV_SAVE_DISK_BUF_SIZE; 228c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije uint8_t buffer[NAND_DEV_SAVE_DISK_BUF_SIZE] = {0}; 229ad05f2c46b62b2a34e498caec852f74f58c602c9Chris Dearman off_t lseek_ret; 230c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije int ret; 231c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije uint64_t total_copied = 0; 232c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije 233a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock /* Size of file to restore, hence size of data block following. 234a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock * TODO Work out whether to use lseek64 here. */ 235a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock 236ad05f2c46b62b2a34e498caec852f74f58c602c9Chris Dearman lseek_ret = do_lseek(dev->fd, 0, SEEK_END); 237ad05f2c46b62b2a34e498caec852f74f58c602c9Chris Dearman if (lseek_ret == -1) { 238c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner qemu_file_set_error(f, -errno); 239a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock XLOG("%s EOF seek failed: %s\n", __FUNCTION__, strerror(errno)); 240a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock return; 241a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock } 242ad05f2c46b62b2a34e498caec852f74f58c602c9Chris Dearman const uint64_t total_size = lseek_ret; 243c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije qemu_put_be64(f, total_size); 244c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije 245c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije /* copy all data from the stream to the stored image */ 246ad05f2c46b62b2a34e498caec852f74f58c602c9Chris Dearman lseek_ret = do_lseek(dev->fd, 0, SEEK_SET); 247ad05f2c46b62b2a34e498caec852f74f58c602c9Chris Dearman if (lseek_ret == -1) { 248c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner qemu_file_set_error(f, -errno); 249c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije XLOG("%s seek failed: %s\n", __FUNCTION__, strerror(errno)); 250c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije return; 251c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije } 252c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije do { 253c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije ret = do_read(dev->fd, buffer, buf_size); 254c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije if (ret < 0) { 255c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner qemu_file_set_error(f, -errno); 256c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije XLOG("%s read failed: %s\n", __FUNCTION__, strerror(errno)); 257c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije return; 258c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije } 259c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije qemu_put_buffer(f, buffer, ret); 260c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije 261c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije total_copied += ret; 262c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije } 263a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock while (ret == buf_size && total_copied < dev->max_size); 264a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock 265a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock /* TODO Maybe check that we've written total_size bytes */ 266c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije} 267c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije 268c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije 269c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije/** 270c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije * Saves the state of all disks managed by this controller to a snapshot file. 271c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije */ 272c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thijestatic void nand_dev_save_disks(QEMUFile *f) 273c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije{ 274c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije int i; 275c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije for (i = 0; i < nand_dev_count; i++) { 276c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije nand_dev_save_disk_state(f, nand_devs + i); 277c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije } 278c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije} 279c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije 280c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije/** 281c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije * Overwrites the contents of the disk image managed by this device with the 282c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije * contents as they were at the point the snapshot was made. 283c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije */ 284c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thijestatic int nand_dev_load_disk_state(QEMUFile *f, nand_dev *dev) 285c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije{ 286c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije int buf_size = NAND_DEV_SAVE_DISK_BUF_SIZE; 287c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije uint8_t buffer[NAND_DEV_SAVE_DISK_BUF_SIZE] = {0}; 288ad05f2c46b62b2a34e498caec852f74f58c602c9Chris Dearman off_t lseek_ret; 289c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije int ret; 290c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije 291a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock /* File size for restore and truncate */ 292c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije uint64_t total_size = qemu_get_be64(f); 293c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije if (total_size > dev->max_size) { 294c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije XLOG("%s, restore failed: size required (%lld) exceeds device limit (%lld)\n", 295c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije __FUNCTION__, total_size, dev->max_size); 296c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije return -EIO; 297c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije } 298c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije 299c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije /* overwrite disk contents with snapshot contents */ 300c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije uint64_t next_offset = 0; 301ad05f2c46b62b2a34e498caec852f74f58c602c9Chris Dearman lseek_ret = do_lseek(dev->fd, 0, SEEK_SET); 302ad05f2c46b62b2a34e498caec852f74f58c602c9Chris Dearman if (lseek_ret == -1) { 303c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije XLOG("%s seek failed: %s\n", __FUNCTION__, strerror(errno)); 304c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije return -EIO; 305c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije } 306c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije while (next_offset < total_size) { 307c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije /* snapshot buffer may not be an exact multiple of buf_size 308c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije * if necessary, adjust buffer size for last copy operation */ 309c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije if (total_size - next_offset < buf_size) { 310c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije buf_size = total_size - next_offset; 311c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije } 312c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije 313c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije ret = qemu_get_buffer(f, buffer, buf_size); 314c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije if (ret != buf_size) { 315c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije XLOG("%s read failed: expected %d bytes but got %d\n", 316c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije __FUNCTION__, buf_size, ret); 317c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije return -EIO; 318c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije } 319c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije ret = do_write(dev->fd, buffer, buf_size); 320c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije if (ret != buf_size) { 321c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije XLOG("%s, write failed: %s\n", __FUNCTION__, strerror(errno)); 322c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije return -EIO; 323c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije } 324c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije 325c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije next_offset += buf_size; 326c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije } 327c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije 328a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock ret = do_ftruncate(dev->fd, total_size); 329a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock if (ret < 0) { 330a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock XLOG("%s ftruncate failed: %s\n", __FUNCTION__, strerror(errno)); 331a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock return -EIO; 332a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock } 333a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock 334c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije return 0; 335c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije} 336c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije 337c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije/** 338c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije * Restores the state of all disks managed by this driver from a snapshot file. 339c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije */ 340c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thijestatic int nand_dev_load_disks(QEMUFile *f) 341c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije{ 342c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije int i, ret; 343c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije for (i = 0; i < nand_dev_count; i++) { 344c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije ret = nand_dev_load_disk_state(f, nand_devs + i); 345c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije if (ret) 346c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije return ret; // abort on error 347c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije } 348c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije 349c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije return 0; 350c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije} 351c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije 352c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thijestatic void nand_dev_controller_state_save(QEMUFile *f, void *opaque) 353c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije{ 354c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije nand_dev_controller_state* s = opaque; 355c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije 356c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije qemu_put_struct(f, nand_dev_controller_state_fields, s); 357c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije 358c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije /* The guest will continue writing to the disk image after the state has 359c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije * been saved. To guarantee that the state is identical after resume, save 360c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije * a copy of the current disk state in the snapshot. 361c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije */ 362c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije nand_dev_save_disks(f); 363c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije} 364c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije 365c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thijestatic int nand_dev_controller_state_load(QEMUFile *f, void *opaque, int version_id) 366c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije{ 367c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije nand_dev_controller_state* s = opaque; 368c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije int ret; 369c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije 370d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian if (version_id == NAND_DEV_STATE_SAVE_VERSION) { 371d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian ret = qemu_get_struct(f, nand_dev_controller_state_fields, s); 372d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian } else if (version_id == NAND_DEV_STATE_SAVE_VERSION_LEGACY) { 373d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian ret = qemu_get_struct(f, nand_dev_controller_state_legacy_1_fields, s); 374d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian if (!ret) { 375d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian // Read 32-bit data field directly. 376d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian s->data = (uint64_t)qemu_get_be32(f); 377d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian ret = qemu_get_struct( 378d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian f, nand_dev_controller_state_legacy_2_fields, s); 379d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian } 380d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian } else { 381d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian // Invalid encoding. 382d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian ret = -1; 383d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian } 384d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian return ret ? ret : nand_dev_load_disks(f); 385c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije} 386c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije 387d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tianstatic uint32_t nand_dev_read_file(nand_dev *dev, target_ulong data, uint64_t addr, uint32_t total_len) 3888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 3898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t len = total_len; 3908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project size_t read_len = dev->erase_size; 3918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int eof = 0; 3928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project NAND_UPDATE_READ_THRESHOLD(total_len); 3948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 395a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock do_lseek(dev->fd, addr, SEEK_SET); 3968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project while(len > 0) { 3978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(read_len < dev->erase_size) { 3988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memset(dev->data, 0xff, dev->erase_size); 3998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project read_len = dev->erase_size; 4008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project eof = 1; 4018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(len < read_len) 4038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project read_len = len; 4048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(!eof) { 4058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project read_len = do_read(dev->fd, dev->data, read_len); 4068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 407aaef275467ba13162d52ef6f690fd97f9733eb58David 'Digit' Turner safe_memory_rw_debug(current_cpu, data, dev->data, read_len, 1); 4088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project data += read_len; 4098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project len -= read_len; 4108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return total_len; 4128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 4138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 414d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tianstatic uint32_t nand_dev_write_file(nand_dev *dev, target_ulong data, uint64_t addr, uint32_t total_len) 4158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 4168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t len = total_len; 4178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project size_t write_len = dev->erase_size; 4188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int ret; 4198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 4208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project NAND_UPDATE_WRITE_THRESHOLD(total_len); 4218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 422a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock do_lseek(dev->fd, addr, SEEK_SET); 4238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project while(len > 0) { 4248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(len < write_len) 4258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project write_len = len; 426aaef275467ba13162d52ef6f690fd97f9733eb58David 'Digit' Turner safe_memory_rw_debug(current_cpu, data, dev->data, write_len, 0); 4278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ret = do_write(dev->fd, dev->data, write_len); 4288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(ret < write_len) { 4298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project XLOG("nand_dev_write_file, write failed: %s\n", strerror(errno)); 4308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 4318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project data += write_len; 4338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project len -= write_len; 4348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return total_len - len; 4368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 4378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 4388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic uint32_t nand_dev_erase_file(nand_dev *dev, uint64_t addr, uint32_t total_len) 4398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 4408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t len = total_len; 4418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project size_t write_len = dev->erase_size; 4428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int ret; 4438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 444a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock do_lseek(dev->fd, addr, SEEK_SET); 4458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memset(dev->data, 0xff, dev->erase_size); 4468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project while(len > 0) { 4478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(len < write_len) 4488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project write_len = len; 4498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ret = do_write(dev->fd, dev->data, write_len); 4508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(ret < write_len) { 4518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project XLOG( "nand_dev_write_file, write failed: %s\n", strerror(errno)); 4528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 4538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project len -= write_len; 4558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return total_len - len; 4578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 4588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 4598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* this is a huge hack required to make the PowerPC emulator binary usable 4608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * on Mac OS X. If you define this function as 'static', the emulated kernel 4618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * will panic when attempting to mount the /data partition. 4628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 4638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * worse, if you do *not* define the function as static on Linux-x86, the 4648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * emulated kernel will also panic !? 4658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 4668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * I still wonder if this is a compiler bug, or due to some nasty thing the 4678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * emulator does with CPU registers during execution of the translated code. 4688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */ 4698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#if !(defined __APPLE__ && defined __powerpc__) 4708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic 4718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif 472c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thijeuint32_t nand_dev_do_cmd(nand_dev_controller_state *s, uint32_t cmd) 4738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 4748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t size; 4758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint64_t addr; 4768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project nand_dev *dev; 4778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 478f1f1f5ff5b87d4f754572e0f05398842f0cde059Jiang Yunhong if (cmd == NAND_CMD_WRITE_BATCH || cmd == NAND_CMD_READ_BATCH || 479f1f1f5ff5b87d4f754572e0f05398842f0cde059Jiang Yunhong cmd == NAND_CMD_ERASE_BATCH) { 480f1f1f5ff5b87d4f754572e0f05398842f0cde059Jiang Yunhong struct batch_data bd; 481d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian struct batch_data_64 bd64; 482f1f1f5ff5b87d4f754572e0f05398842f0cde059Jiang Yunhong uint64_t bd_addr = ((uint64_t)s->batch_addr_high << 32) | s->batch_addr_low; 483d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian if (goldfish_guest_is_64bit()) { 484d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian cpu_physical_memory_read(bd_addr, (void*)&bd64, sizeof(struct batch_data_64)); 485d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian s->dev = bd64.dev; 486d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian s->addr_low = bd64.addr_low; 487d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian s->addr_high = bd64.addr_high; 488d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian s->transfer_size = bd64.transfer_size; 489d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian s->data = bd64.data; 490d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian } else { 491d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian cpu_physical_memory_read(bd_addr, (void*)&bd, sizeof(struct batch_data)); 492d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian s->dev = bd.dev; 493d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian s->addr_low = bd.addr_low; 494d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian s->addr_high = bd.addr_high; 495d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian s->transfer_size = bd.transfer_size; 496d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian s->data = bd.data; 497d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian } 498f1f1f5ff5b87d4f754572e0f05398842f0cde059Jiang Yunhong } 4998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project addr = s->addr_low | ((uint64_t)s->addr_high << 32); 5008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project size = s->transfer_size; 5018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(s->dev >= nand_dev_count) 5028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 0; 5038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project dev = nand_devs + s->dev; 5048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 5058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project switch(cmd) { 5068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case NAND_CMD_GET_DEV_NAME: 5078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(size > dev->devname_len) 5088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project size = dev->devname_len; 509aaef275467ba13162d52ef6f690fd97f9733eb58David 'Digit' Turner safe_memory_rw_debug(current_cpu, s->data, (uint8_t*)dev->devname, size, 1); 5108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return size; 511f1f1f5ff5b87d4f754572e0f05398842f0cde059Jiang Yunhong case NAND_CMD_READ_BATCH: 5128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case NAND_CMD_READ: 513c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije if(addr >= dev->max_size) 5148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 0; 515c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije if(size > dev->max_size - addr) 516c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije size = dev->max_size - addr; 5178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(dev->fd >= 0) 5188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return nand_dev_read_file(dev, s->data, addr, size); 519aaef275467ba13162d52ef6f690fd97f9733eb58David 'Digit' Turner safe_memory_rw_debug(current_cpu, s->data, &dev->data[addr], size, 1); 5208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return size; 521f1f1f5ff5b87d4f754572e0f05398842f0cde059Jiang Yunhong case NAND_CMD_WRITE_BATCH: 5228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case NAND_CMD_WRITE: 5238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(dev->flags & NAND_DEV_FLAG_READ_ONLY) 5248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 0; 525c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije if(addr >= dev->max_size) 5268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 0; 527c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije if(size > dev->max_size - addr) 528c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije size = dev->max_size - addr; 5298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(dev->fd >= 0) 5308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return nand_dev_write_file(dev, s->data, addr, size); 531aaef275467ba13162d52ef6f690fd97f9733eb58David 'Digit' Turner safe_memory_rw_debug(current_cpu, s->data, &dev->data[addr], size, 0); 5328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return size; 533f1f1f5ff5b87d4f754572e0f05398842f0cde059Jiang Yunhong case NAND_CMD_ERASE_BATCH: 5348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case NAND_CMD_ERASE: 5358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(dev->flags & NAND_DEV_FLAG_READ_ONLY) 5368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 0; 537c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije if(addr >= dev->max_size) 5388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 0; 539c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije if(size > dev->max_size - addr) 540c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije size = dev->max_size - addr; 5418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(dev->fd >= 0) 5428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return nand_dev_erase_file(dev, addr, size); 5438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memset(&dev->data[addr], 0xff, size); 5448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return size; 5458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case NAND_CMD_BLOCK_BAD_GET: // no bad block support 5468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 0; 5478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case NAND_CMD_BLOCK_BAD_SET: 5488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(dev->flags & NAND_DEV_FLAG_READ_ONLY) 5498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 0; 5508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 0; 5518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project default: 5528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project cpu_abort(cpu_single_env, "nand_dev_do_cmd: Bad command %x\n", cmd); 5538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 0; 5548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 5558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 5568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 5578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* I/O write */ 558bcde1092aca184dbd7860078af020de7d1e4e22fDavid 'Digit' Turnerstatic void nand_dev_write(void *opaque, hwaddr offset, uint32_t value) 5598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 560c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije nand_dev_controller_state *s = (nand_dev_controller_state *)opaque; 5618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 5628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project switch (offset) { 5638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case NAND_DEV: 5648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->dev = value; 5658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(s->dev >= nand_dev_count) { 5668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project cpu_abort(cpu_single_env, "nand_dev_write: Bad dev %x\n", value); 5678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 5688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 5698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case NAND_ADDR_HIGH: 5708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->addr_high = value; 5718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 5728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case NAND_ADDR_LOW: 5738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->addr_low = value; 5748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 575f1f1f5ff5b87d4f754572e0f05398842f0cde059Jiang Yunhong case NAND_BATCH_ADDR_LOW: 576f1f1f5ff5b87d4f754572e0f05398842f0cde059Jiang Yunhong s->batch_addr_low = value; 577f1f1f5ff5b87d4f754572e0f05398842f0cde059Jiang Yunhong break; 578f1f1f5ff5b87d4f754572e0f05398842f0cde059Jiang Yunhong case NAND_BATCH_ADDR_HIGH: 579f1f1f5ff5b87d4f754572e0f05398842f0cde059Jiang Yunhong s->batch_addr_high = value; 580f1f1f5ff5b87d4f754572e0f05398842f0cde059Jiang Yunhong break; 5818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case NAND_TRANSFER_SIZE: 5828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->transfer_size = value; 5838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 5848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case NAND_DATA: 585d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian uint64_set_low(&s->data, value); 586d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian break; 587d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian case NAND_DATA_HIGH: 588d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian uint64_set_high(&s->data, value); 5898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 5908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case NAND_COMMAND: 5918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->result = nand_dev_do_cmd(s, value); 592f1f1f5ff5b87d4f754572e0f05398842f0cde059Jiang Yunhong if (value == NAND_CMD_WRITE_BATCH || value == NAND_CMD_READ_BATCH || 593f1f1f5ff5b87d4f754572e0f05398842f0cde059Jiang Yunhong value == NAND_CMD_ERASE_BATCH) { 594f1f1f5ff5b87d4f754572e0f05398842f0cde059Jiang Yunhong struct batch_data bd; 595d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian struct batch_data_64 bd64; 596f1f1f5ff5b87d4f754572e0f05398842f0cde059Jiang Yunhong uint64_t bd_addr = ((uint64_t)s->batch_addr_high << 32) | s->batch_addr_low; 597d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian if (goldfish_guest_is_64bit()) { 598d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian bd64.result = s->result; 599d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian cpu_physical_memory_write(bd_addr, (void*)&bd64, sizeof(struct batch_data_64)); 600d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian } else { 601d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian bd.result = s->result; 602d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian cpu_physical_memory_write(bd_addr, (void*)&bd, sizeof(struct batch_data)); 603d6ed3e25287d85bbf35ec1f95c7ed819bf9af42eJun Tian } 604f1f1f5ff5b87d4f754572e0f05398842f0cde059Jiang Yunhong } 6058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 6068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project default: 6078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project cpu_abort(cpu_single_env, "nand_dev_write: Bad offset %x\n", offset); 6088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 6098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 6108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 6118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* I/O read */ 613bcde1092aca184dbd7860078af020de7d1e4e22fDavid 'Digit' Turnerstatic uint32_t nand_dev_read(void *opaque, hwaddr offset) 6148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 615c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije nand_dev_controller_state *s = (nand_dev_controller_state *)opaque; 6168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project nand_dev *dev; 6178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project switch (offset) { 6198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case NAND_VERSION: 6208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return NAND_VERSION_CURRENT; 6218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case NAND_NUM_DEV: 6228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return nand_dev_count; 6238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case NAND_RESULT: 6248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return s->result; 6258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 6268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(s->dev >= nand_dev_count) 6288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 0; 6298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project dev = nand_devs + s->dev; 6318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project switch (offset) { 6338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case NAND_DEV_FLAGS: 6348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return dev->flags; 6358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case NAND_DEV_NAME_LEN: 6378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return dev->devname_len; 6388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case NAND_DEV_PAGE_SIZE: 6408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return dev->page_size; 6418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case NAND_DEV_EXTRA_SIZE: 6438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return dev->extra_size; 6448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case NAND_DEV_ERASE_SIZE: 6468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return dev->erase_size; 6478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case NAND_DEV_SIZE_LOW: 649c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije return (uint32_t)dev->max_size; 6508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case NAND_DEV_SIZE_HIGH: 652c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije return (uint32_t)(dev->max_size >> 32); 6538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project default: 6558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project cpu_abort(cpu_single_env, "nand_dev_read: Bad offset %x\n", offset); 6568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 0; 6578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 6588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 6598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic CPUReadMemoryFunc *nand_dev_readfn[] = { 6618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project nand_dev_read, 6628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project nand_dev_read, 6638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project nand_dev_read 6648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}; 6658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic CPUWriteMemoryFunc *nand_dev_writefn[] = { 6678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project nand_dev_write, 6688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project nand_dev_write, 6698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project nand_dev_write 6708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}; 6718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* initialize the QFB device */ 6738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid nand_dev_init(uint32_t base) 6748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 6758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int iomemtype; 6768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project static int instance_id = 0; 677c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije nand_dev_controller_state *s; 6788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 679aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner s = (nand_dev_controller_state *)g_malloc0(sizeof(nand_dev_controller_state)); 6805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner iomemtype = cpu_register_io_memory(nand_dev_readfn, nand_dev_writefn, s); 6818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project cpu_register_physical_memory(base, 0x00000fff, iomemtype); 6828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->base = base; 6838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6845cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner register_savevm(NULL, 6855cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner "nand_dev", 6865cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner instance_id++, 6875cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner NAND_DEV_STATE_SAVE_VERSION, 6885cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner nand_dev_controller_state_save, 6895cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner nand_dev_controller_state_load, 6905cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner s); 6918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 6928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int arg_match(const char *a, const char *b, size_t b_len) 6948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 6958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project while(*a && b_len--) { 6968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(*a++ != *b++) 6978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 0; 6988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 6998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return b_len == 0; 7008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 7018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 7028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid nand_add_dev(const char *arg) 7038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 7048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint64_t dev_size = 0; 7058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project const char *next_arg; 7068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project const char *value; 7078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project size_t arg_len, value_len; 7088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project nand_dev *new_devs, *dev; 7098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project char *devname = NULL; 7108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project size_t devname_len = 0; 7118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project char *initfilename = NULL; 7128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project char *rwfilename = NULL; 7138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int initfd = -1; 7148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int rwfd = -1; 7158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int read_only = 0; 7168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int pad; 7178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ssize_t read_size; 7188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t page_size = 2048; 7198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t extra_size = 64; 7208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t erase_pages = 64; 7218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 722c480cca8d2007f5df62a7431beda310911b963e6David 'Digit' Turner VERBOSE_PRINT(init, "%s: %s", __FUNCTION__, arg); 723c480cca8d2007f5df62a7431beda310911b963e6David 'Digit' Turner 7248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project while(arg) { 7258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project next_arg = strchr(arg, ','); 7268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project value = strchr(arg, '='); 7278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(next_arg != NULL) { 7288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project arg_len = next_arg - arg; 7298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project next_arg++; 7308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(value >= next_arg) 7318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project value = NULL; 7328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 7338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project else 7348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project arg_len = strlen(arg); 7358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(value != NULL) { 7368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project size_t new_arg_len = value - arg; 7378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project value_len = arg_len - new_arg_len - 1; 7388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project arg_len = new_arg_len; 7398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project value++; 7408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 7418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project else 7428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project value_len = 0; 7438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 7448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(devname == NULL) { 7458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(value != NULL) 7468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto bad_arg_and_value; 7478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project devname_len = arg_len; 748e8ab08c1ee27349cb81cd5e8849a01a85da16775David 'Digit' Turner devname = malloc(arg_len+1); 7498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(devname == NULL) 7508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto out_of_memory; 7518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memcpy(devname, arg, arg_len); 752e8ab08c1ee27349cb81cd5e8849a01a85da16775David 'Digit' Turner devname[arg_len] = 0; 7538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 7548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project else if(value == NULL) { 7558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(arg_match("readonly", arg, arg_len)) { 7568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project read_only = 1; 7578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 7588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project else { 7598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project XLOG("bad arg: %.*s\n", arg_len, arg); 7608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project exit(1); 7618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 7628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 7638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project else { 7648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(arg_match("size", arg, arg_len)) { 7658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project char *ep; 7668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project dev_size = strtoull(value, &ep, 0); 7678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(ep != value + value_len) 7688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto bad_arg_and_value; 7698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 7708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project else if(arg_match("pagesize", arg, arg_len)) { 7718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project char *ep; 7728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project page_size = strtoul(value, &ep, 0); 7738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(ep != value + value_len) 7748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto bad_arg_and_value; 7758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 7768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project else if(arg_match("extrasize", arg, arg_len)) { 7778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project char *ep; 7788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project extra_size = strtoul(value, &ep, 0); 7798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(ep != value + value_len) 7808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto bad_arg_and_value; 7818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 7828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project else if(arg_match("erasepages", arg, arg_len)) { 7838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project char *ep; 7848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project erase_pages = strtoul(value, &ep, 0); 7858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(ep != value + value_len) 7868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto bad_arg_and_value; 7878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 7888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project else if(arg_match("initfile", arg, arg_len)) { 7898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project initfilename = malloc(value_len + 1); 7908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(initfilename == NULL) 7918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto out_of_memory; 7928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memcpy(initfilename, value, value_len); 7938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project initfilename[value_len] = '\0'; 7948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 7958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project else if(arg_match("file", arg, arg_len)) { 7968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project rwfilename = malloc(value_len + 1); 7978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(rwfilename == NULL) 7988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto out_of_memory; 7998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memcpy(rwfilename, value, value_len); 8008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project rwfilename[value_len] = '\0'; 8018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 8028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project else { 8038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto bad_arg_and_value; 8048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 8058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 8068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 8078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project arg = next_arg; 8088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 8098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 8108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (rwfilename == NULL) { 8118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* we create a temporary file to store everything */ 8128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project TempFile* tmp = tempfile_create(); 8138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 8148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (tmp == NULL) { 8152779beecc7410f29102125e87e8174597acb2fe5Raphael XLOG("could not create temp file for %.*s NAND disk image: %s\n", 8168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project devname_len, devname, strerror(errno)); 8178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project exit(1); 8188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 8198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project rwfilename = (char*) tempfile_path(tmp); 8208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (VERBOSE_CHECK(init)) 8218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project dprint( "mapping '%.*s' NAND image to %s", devname_len, devname, rwfilename); 8228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 8238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 8248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(rwfilename) { 82590a3681c1b2332093821a24c244bc3a86dbb1967Vladimir Chtchetkine if (initfilename) { 82690a3681c1b2332093821a24c244bc3a86dbb1967Vladimir Chtchetkine /* Overwrite with content of the 'initfilename'. */ 82790a3681c1b2332093821a24c244bc3a86dbb1967Vladimir Chtchetkine if (read_only) { 82890a3681c1b2332093821a24c244bc3a86dbb1967Vladimir Chtchetkine /* Cannot be readonly when initializing the device from another file. */ 82990a3681c1b2332093821a24c244bc3a86dbb1967Vladimir Chtchetkine XLOG("incompatible read only option is requested while initializing %.*s from %s\n", 83090a3681c1b2332093821a24c244bc3a86dbb1967Vladimir Chtchetkine devname_len, devname, initfilename); 83190a3681c1b2332093821a24c244bc3a86dbb1967Vladimir Chtchetkine exit(1); 83290a3681c1b2332093821a24c244bc3a86dbb1967Vladimir Chtchetkine } 83390a3681c1b2332093821a24c244bc3a86dbb1967Vladimir Chtchetkine rwfd = open(rwfilename, O_BINARY | O_TRUNC | O_RDWR); 83490a3681c1b2332093821a24c244bc3a86dbb1967Vladimir Chtchetkine } else { 83590a3681c1b2332093821a24c244bc3a86dbb1967Vladimir Chtchetkine rwfd = open(rwfilename, O_BINARY | (read_only ? O_RDONLY : O_RDWR)); 83690a3681c1b2332093821a24c244bc3a86dbb1967Vladimir Chtchetkine } 837e8ab08c1ee27349cb81cd5e8849a01a85da16775David 'Digit' Turner if(rwfd < 0) { 8388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project XLOG("could not open file %s, %s\n", rwfilename, strerror(errno)); 8398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project exit(1); 8408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 8418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* this could be a writable temporary file. use atexit_close_fd to ensure 8428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * that it is properly cleaned up at exit on Win32 8438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */ 8448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (!read_only) 8458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project atexit_close_fd(rwfd); 8468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 8478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 8488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(initfilename) { 8498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project initfd = open(initfilename, O_BINARY | O_RDONLY); 8508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(initfd < 0) { 8518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project XLOG("could not open file %s, %s\n", initfilename, strerror(errno)); 8528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project exit(1); 8538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 8548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(dev_size == 0) { 855a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock dev_size = do_lseek(initfd, 0, SEEK_END); 856a658bc8efde7e572172ea80d8e185ed0741d95d6Tim Baverstock do_lseek(initfd, 0, SEEK_SET); 8578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 8588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 8598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 8608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project new_devs = realloc(nand_devs, sizeof(nand_devs[0]) * (nand_dev_count + 1)); 8618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(new_devs == NULL) 8628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto out_of_memory; 8638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project nand_devs = new_devs; 8648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project dev = &new_devs[nand_dev_count]; 8658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 8668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project dev->page_size = page_size; 8678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project dev->extra_size = extra_size; 8688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project dev->erase_size = erase_pages * (page_size + extra_size); 8698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project pad = dev_size % dev->erase_size; 8708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (pad != 0) { 8718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project dev_size += (dev->erase_size - pad); 872acbee3546b9a380a4eb33daef3dccfac87c56b0bXavier Ducrohet D("rounding devsize up to a full eraseunit, now %llx\n", dev_size); 8738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 8748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project dev->devname = devname; 8758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project dev->devname_len = devname_len; 876c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije dev->max_size = dev_size; 8778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project dev->data = malloc(dev->erase_size); 8788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(dev->data == NULL) 8798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto out_of_memory; 8808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project dev->flags = read_only ? NAND_DEV_FLAG_READ_ONLY : 0; 881f1f1f5ff5b87d4f754572e0f05398842f0cde059Jiang Yunhong#ifdef TARGET_I386 882f1f1f5ff5b87d4f754572e0f05398842f0cde059Jiang Yunhong dev->flags |= NAND_DEV_FLAG_BATCH_CAP; 883f1f1f5ff5b87d4f754572e0f05398842f0cde059Jiang Yunhong#endif 8848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 8858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (initfd >= 0) { 8868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project do { 8878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project read_size = do_read(initfd, dev->data, dev->erase_size); 8888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(read_size < 0) { 8898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project XLOG("could not read file %s, %s\n", initfilename, strerror(errno)); 8908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project exit(1); 8918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 8928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(do_write(rwfd, dev->data, read_size) != read_size) { 893fd59c330bec77e7b9241e478efb1e1c508480d1dDavid 'Digit' Turner XLOG("could not write file %s, %s\n", rwfilename, strerror(errno)); 8948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project exit(1); 8958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 8968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } while(read_size == dev->erase_size); 8978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project close(initfd); 8988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 8998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project dev->fd = rwfd; 9008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 9018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project nand_dev_count++; 9028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 9038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return; 9048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 9058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectout_of_memory: 9068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project XLOG("out of memory\n"); 9078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project exit(1); 9088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 9098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectbad_arg_and_value: 9108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project XLOG("bad arg: %.*s=%.*s\n", arg_len, arg, value_len, value); 9118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project exit(1); 9128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 9138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 914e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine#ifdef CONFIG_NAND_LIMITS 915e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine 916e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkinestatic uint64_t 917e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkineparse_nand_rw_limit( const char* value ) 918e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine{ 919e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine char* end; 920e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine uint64_t val = strtoul( value, &end, 0 ); 921e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine 922e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine if (end == value) { 923e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine derror( "bad parameter value '%s': expecting unsigned integer", value ); 924e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine exit(1); 925e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine } 926e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine 927e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine switch (end[0]) { 928e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine case 'K': val <<= 10; break; 929e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine case 'M': val <<= 20; break; 930e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine case 'G': val <<= 30; break; 931e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine case 0: break; 932e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine default: 933e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine derror( "bad read/write limit suffix: use K, M or G" ); 934e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine exit(1); 935e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine } 936e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine return val; 937e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine} 938e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine 939e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkinevoid 940e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkineparse_nand_limits(char* limits) 941e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine{ 942e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine int pid = -1, signal = -1; 943e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine int64_t reads = 0, writes = 0; 944e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine char* item = limits; 945e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine 946e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine /* parse over comma-separated items */ 947e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine while (item && *item) { 948e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine char* next = strchr(item, ','); 949e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine char* end; 950e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine 951e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine if (next == NULL) { 952e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine next = item + strlen(item); 953e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine } else { 954e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine *next++ = 0; 955e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine } 956e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine 957e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine if ( !memcmp(item, "pid=", 4) ) { 958e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine pid = strtol(item+4, &end, 10); 959e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine if (end == NULL || *end) { 960e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine derror( "bad parameter, expecting pid=<number>, got '%s'", 961e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine item ); 962e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine exit(1); 963e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine } 964e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine if (pid <= 0) { 965e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine derror( "bad parameter: process identifier must be > 0" ); 966e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine exit(1); 967e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine } 968e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine } 969e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine else if ( !memcmp(item, "signal=", 7) ) { 970e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine signal = strtol(item+7,&end, 10); 971e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine if (end == NULL || *end) { 972e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine derror( "bad parameter: expecting signal=<number>, got '%s'", 973e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine item ); 974e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine exit(1); 975e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine } 976e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine if (signal <= 0) { 977e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine derror( "bad parameter: signal number must be > 0" ); 978e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine exit(1); 979e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine } 980e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine } 981e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine else if ( !memcmp(item, "reads=", 6) ) { 982e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine reads = parse_nand_rw_limit(item+6); 983e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine } 984e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine else if ( !memcmp(item, "writes=", 7) ) { 985e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine writes = parse_nand_rw_limit(item+7); 986e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine } 987e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine else { 988e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine derror( "bad parameter '%s' (see -help-nand-limits)", item ); 989e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine exit(1); 990e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine } 991e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine item = next; 992e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine } 993e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine if (pid < 0) { 994e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine derror( "bad paramater: missing pid=<number>" ); 995e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine exit(1); 996e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine } 997e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine else if (signal < 0) { 998e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine derror( "bad parameter: missing signal=<number>" ); 999e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine exit(1); 1000e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine } 1001e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine else if (reads == 0 && writes == 0) { 1002e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine dwarning( "no read or write limit specified. ignoring -nand-limits" ); 1003e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine } else { 1004e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine nand_threshold* t; 1005e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine 1006e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine t = &android_nand_read_threshold; 1007e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine t->pid = pid; 1008e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine t->signal = signal; 1009e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine t->counter = 0; 1010e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine t->limit = reads; 1011e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine 1012e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine t = &android_nand_write_threshold; 1013e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine t->pid = pid; 1014e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine t->signal = signal; 1015e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine t->counter = 0; 1016e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine t->limit = writes; 1017e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine } 1018e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine} 1019e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine#endif /* CONFIG_NAND_LIMITS */ 1020