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