1/* Copyright (C) 2007-2008 The Android Open Source Project
2**
3** This software is licensed under the terms of the GNU General Public
4** License version 2, as published by the Free Software Foundation, and
5** may be copied, distributed, and modified under those terms.
6**
7** This program is distributed in the hope that it will be useful,
8** but WITHOUT ANY WARRANTY; without even the implied warranty of
9** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10** GNU General Public License for more details.
11*/
12#include "migration/qemu-file.h"
13#include "nand_reg.h"
14#include "hw/android/goldfish/device.h"
15#include "hw/android/goldfish/nand.h"
16#include "hw/android/goldfish/vmem.h"
17#include "hw/hw.h"
18#include "android/utils/tempfile.h"
19#include "android/qemu-debug.h"
20#include "android/android.h"
21
22#define  DEBUG  1
23#if DEBUG
24#  define  D(...)    VERBOSE_PRINT(init,__VA_ARGS__)
25#  define  D_ACTIVE  VERBOSE_CHECK(init)
26#  define  T(...)    VERBOSE_PRINT(nand_limits,__VA_ARGS__)
27#  define  T_ACTIVE  VERBOSE_CHECK(nand_limits)
28#else
29#  define  D(...)    ((void)0)
30#  define  D_ACTIVE  0
31#  define  T(...)    ((void)0)
32#  define  T_ACTIVE  0
33#endif
34
35/* lseek uses 64-bit offsets on Darwin. */
36/* prefer lseek64 on Linux              */
37#ifdef __APPLE__
38#  define  llseek  lseek
39#elif defined(__linux__)
40#  define  llseek  lseek64
41#endif
42
43#define  XLOG  xlog
44
45static void
46xlog( const char*  format, ... )
47{
48    va_list  args;
49    va_start(args, format);
50    fprintf(stderr, "NAND: ");
51    vfprintf(stderr, format, args);
52    va_end(args);
53}
54
55/* Information on a single device/nand image used by the emulator
56 */
57typedef struct {
58    char*      devname;      /* name for this device (not null-terminated, use len below) */
59    size_t     devname_len;
60    uint8_t*   data;         /* buffer for read/write actions to underlying image */
61    int        fd;
62    uint32_t   flags;
63    uint32_t   page_size;
64    uint32_t   extra_size;
65    uint32_t   erase_size;   /* size of the data buffer mentioned above */
66    uint64_t   max_size;     /* Capacity limit for the image. The actual underlying
67                              * file may be smaller. */
68} nand_dev;
69
70nand_threshold    android_nand_write_threshold;
71nand_threshold    android_nand_read_threshold;
72
73#ifdef CONFIG_NAND_THRESHOLD
74
75/* update a threshold, return 1 if limit is hit, 0 otherwise */
76static void
77nand_threshold_update( nand_threshold*  t, uint32_t  len )
78{
79    if (t->counter < t->limit) {
80        uint64_t  avail = t->limit - t->counter;
81        if (avail > len)
82            avail = len;
83
84        if (t->counter == 0) {
85            T("%s: starting threshold counting to %lld",
86              __FUNCTION__, t->limit);
87        }
88        t->counter += avail;
89        if (t->counter >= t->limit) {
90            /* threshold reach, send a signal to an external process */
91            T( "%s: sending signal %d to pid %d !",
92               __FUNCTION__, t->signal, t->pid );
93
94            kill( t->pid, t->signal );
95        }
96    }
97    return;
98}
99
100#define  NAND_UPDATE_READ_THRESHOLD(len)  \
101    nand_threshold_update( &android_nand_read_threshold, (uint32_t)(len) )
102
103#define  NAND_UPDATE_WRITE_THRESHOLD(len)  \
104    nand_threshold_update( &android_nand_write_threshold, (uint32_t)(len) )
105
106#else /* !NAND_THRESHOLD */
107
108#define  NAND_UPDATE_READ_THRESHOLD(len)  \
109    do {} while (0)
110
111#define  NAND_UPDATE_WRITE_THRESHOLD(len)  \
112    do {} while (0)
113
114#endif /* !NAND_THRESHOLD */
115
116static nand_dev *nand_devs = NULL;
117static uint32_t nand_dev_count = 0;
118
119/* The controller is the single access point for all NAND images currently
120 * attached to the system.
121 */
122typedef struct {
123    uint32_t base;
124
125    // register state
126    uint32_t dev;            /* offset in nand_devs for the device that is
127                              * currently being accessed */
128    uint32_t addr_low;
129    uint32_t addr_high;
130    uint32_t transfer_size;
131    uint64_t data;
132    uint32_t batch_addr_low;
133    uint32_t batch_addr_high;
134    uint32_t result;
135} nand_dev_controller_state;
136
137/* update this everytime you change the nand_dev_controller_state structure
138 * 1: initial version, saving only nand_dev_controller_state fields
139 * 2: saving actual disk contents as well
140 * 3: use the correct data length and truncate to avoid padding.
141 */
142#define  NAND_DEV_STATE_SAVE_VERSION  5
143#define  NAND_DEV_STATE_SAVE_VERSION_LEGACY  4
144
145#define  QFIELD_STRUCT  nand_dev_controller_state
146QFIELD_BEGIN(nand_dev_controller_state_fields)
147    QFIELD_INT32(dev),
148    QFIELD_INT32(addr_low),
149    QFIELD_INT32(addr_high),
150    QFIELD_INT32(transfer_size),
151    QFIELD_INT64(data),
152    QFIELD_INT32(batch_addr_low),
153    QFIELD_INT32(batch_addr_high),
154    QFIELD_INT32(result),
155QFIELD_END
156
157// Legacy encoding support, split the structure in two halves, with
158// a 32-bit |data| field in the middle to be loaded explictly.
159QFIELD_BEGIN(nand_dev_controller_state_legacy_1_fields)
160    QFIELD_INT32(dev),
161    QFIELD_INT32(addr_low),
162    QFIELD_INT32(addr_high),
163    QFIELD_INT32(transfer_size),
164QFIELD_END
165
166QFIELD_BEGIN(nand_dev_controller_state_legacy_2_fields)
167    QFIELD_INT32(batch_addr_low),
168    QFIELD_INT32(batch_addr_high),
169    QFIELD_INT32(result),
170QFIELD_END
171
172/* EINTR-proof read - due to SIGALRM in use elsewhere */
173static int  do_read(int  fd, void*  buf, size_t  size)
174{
175    int  ret;
176    do {
177        ret = read(fd, buf, size);
178    } while (ret < 0 && errno == EINTR);
179
180    return ret;
181}
182
183/* EINTR-proof write - due to SIGALRM in use elsewhere */
184static int  do_write(int  fd, const void*  buf, size_t  size)
185{
186    int  ret;
187    do {
188        ret = write(fd, buf, size);
189    } while (ret < 0 && errno == EINTR);
190
191    return ret;
192}
193
194/* EINTR-proof lseek - due to SIGALRM in use elsewhere */
195static off_t do_lseek(int  fd, off_t offset, int whence)
196{
197    off_t ret;
198    do {
199        ret = lseek(fd, offset, whence);
200    } while (ret == -1 && errno == EINTR);
201
202    return ret;
203}
204
205/* EINTR-proof ftruncate - due to SIGALRM in use elsewhere */
206static int  do_ftruncate(int  fd, size_t  size)
207{
208    int  ret;
209    do {
210        ret = ftruncate(fd, size);
211    } while (ret < 0 && errno == EINTR);
212
213    return ret;
214}
215
216#define NAND_DEV_SAVE_DISK_BUF_SIZE 2048
217
218
219/**
220 * Copies the current contents of a disk image into the snapshot file.
221 *
222 * TODO optimize this using some kind of copy-on-write mechanism for
223 *      unchanged disk sections.
224 */
225static void  nand_dev_save_disk_state(QEMUFile *f, nand_dev *dev)
226{
227    int buf_size = NAND_DEV_SAVE_DISK_BUF_SIZE;
228    uint8_t buffer[NAND_DEV_SAVE_DISK_BUF_SIZE] = {0};
229    off_t lseek_ret;
230    int ret;
231    uint64_t total_copied = 0;
232
233    /* Size of file to restore, hence size of data block following.
234     * TODO Work out whether to use lseek64 here. */
235
236    lseek_ret = do_lseek(dev->fd, 0, SEEK_END);
237    if (lseek_ret == -1) {
238      qemu_file_set_error(f, -errno);
239      XLOG("%s EOF seek failed: %s\n", __FUNCTION__, strerror(errno));
240      return;
241    }
242    const uint64_t total_size = lseek_ret;
243    qemu_put_be64(f, total_size);
244
245    /* copy all data from the stream to the stored image */
246    lseek_ret = do_lseek(dev->fd, 0, SEEK_SET);
247    if (lseek_ret == -1) {
248        qemu_file_set_error(f, -errno);
249        XLOG("%s seek failed: %s\n", __FUNCTION__, strerror(errno));
250        return;
251    }
252    do {
253        ret = do_read(dev->fd, buffer, buf_size);
254        if (ret < 0) {
255            qemu_file_set_error(f, -errno);
256            XLOG("%s read failed: %s\n", __FUNCTION__, strerror(errno));
257            return;
258        }
259        qemu_put_buffer(f, buffer, ret);
260
261        total_copied += ret;
262    }
263    while (ret == buf_size && total_copied < dev->max_size);
264
265    /* TODO Maybe check that we've written total_size bytes */
266}
267
268
269/**
270 * Saves the state of all disks managed by this controller to a snapshot file.
271 */
272static void nand_dev_save_disks(QEMUFile *f)
273{
274    int i;
275    for (i = 0; i < nand_dev_count; i++) {
276        nand_dev_save_disk_state(f, nand_devs + i);
277    }
278}
279
280/**
281 * Overwrites the contents of the disk image managed by this device with the
282 * contents as they were at the point the snapshot was made.
283 */
284static int  nand_dev_load_disk_state(QEMUFile *f, nand_dev *dev)
285{
286    int buf_size = NAND_DEV_SAVE_DISK_BUF_SIZE;
287    uint8_t buffer[NAND_DEV_SAVE_DISK_BUF_SIZE] = {0};
288    off_t lseek_ret;
289    int ret;
290
291    /* File size for restore and truncate */
292    uint64_t total_size = qemu_get_be64(f);
293    if (total_size > dev->max_size) {
294        XLOG("%s, restore failed: size required (%lld) exceeds device limit (%lld)\n",
295             __FUNCTION__, total_size, dev->max_size);
296        return -EIO;
297    }
298
299    /* overwrite disk contents with snapshot contents */
300    uint64_t next_offset = 0;
301    lseek_ret = do_lseek(dev->fd, 0, SEEK_SET);
302    if (lseek_ret == -1) {
303        XLOG("%s seek failed: %s\n", __FUNCTION__, strerror(errno));
304        return -EIO;
305    }
306    while (next_offset < total_size) {
307        /* snapshot buffer may not be an exact multiple of buf_size
308         * if necessary, adjust buffer size for last copy operation */
309        if (total_size - next_offset < buf_size) {
310            buf_size = total_size - next_offset;
311        }
312
313        ret = qemu_get_buffer(f, buffer, buf_size);
314        if (ret != buf_size) {
315            XLOG("%s read failed: expected %d bytes but got %d\n",
316                 __FUNCTION__, buf_size, ret);
317            return -EIO;
318        }
319        ret = do_write(dev->fd, buffer, buf_size);
320        if (ret != buf_size) {
321            XLOG("%s, write failed: %s\n", __FUNCTION__, strerror(errno));
322            return -EIO;
323        }
324
325        next_offset += buf_size;
326    }
327
328    ret = do_ftruncate(dev->fd, total_size);
329    if (ret < 0) {
330        XLOG("%s ftruncate failed: %s\n", __FUNCTION__, strerror(errno));
331        return -EIO;
332    }
333
334    return 0;
335}
336
337/**
338 * Restores the state of all disks managed by this driver from a snapshot file.
339 */
340static int nand_dev_load_disks(QEMUFile *f)
341{
342    int i, ret;
343    for (i = 0; i < nand_dev_count; i++) {
344        ret = nand_dev_load_disk_state(f, nand_devs + i);
345        if (ret)
346            return ret; // abort on error
347    }
348
349    return 0;
350}
351
352static void  nand_dev_controller_state_save(QEMUFile *f, void  *opaque)
353{
354    nand_dev_controller_state* s = opaque;
355
356    qemu_put_struct(f, nand_dev_controller_state_fields, s);
357
358    /* The guest will continue writing to the disk image after the state has
359     * been saved. To guarantee that the state is identical after resume, save
360     * a copy of the current disk state in the snapshot.
361     */
362    nand_dev_save_disks(f);
363}
364
365static int   nand_dev_controller_state_load(QEMUFile *f, void  *opaque, int  version_id)
366{
367    nand_dev_controller_state*  s = opaque;
368    int ret;
369
370    if (version_id == NAND_DEV_STATE_SAVE_VERSION) {
371        ret = qemu_get_struct(f, nand_dev_controller_state_fields, s);
372    } else if (version_id == NAND_DEV_STATE_SAVE_VERSION_LEGACY) {
373        ret = qemu_get_struct(f, nand_dev_controller_state_legacy_1_fields, s);
374        if (!ret) {
375            // Read 32-bit data field directly.
376            s->data = (uint64_t)qemu_get_be32(f);
377            ret = qemu_get_struct(
378                    f, nand_dev_controller_state_legacy_2_fields, s);
379        }
380    } else {
381        // Invalid encoding.
382        ret = -1;
383    }
384    return ret ? ret : nand_dev_load_disks(f);
385}
386
387static uint32_t nand_dev_read_file(nand_dev *dev, target_ulong data, uint64_t addr, uint32_t total_len)
388{
389    uint32_t len = total_len;
390    size_t read_len = dev->erase_size;
391    int eof = 0;
392
393    NAND_UPDATE_READ_THRESHOLD(total_len);
394
395    do_lseek(dev->fd, addr, SEEK_SET);
396    while(len > 0) {
397        if(read_len < dev->erase_size) {
398            memset(dev->data, 0xff, dev->erase_size);
399            read_len = dev->erase_size;
400            eof = 1;
401        }
402        if(len < read_len)
403            read_len = len;
404        if(!eof) {
405            read_len = do_read(dev->fd, dev->data, read_len);
406        }
407        safe_memory_rw_debug(current_cpu, data, dev->data, read_len, 1);
408        data += read_len;
409        len -= read_len;
410    }
411    return total_len;
412}
413
414static uint32_t nand_dev_write_file(nand_dev *dev, target_ulong data, uint64_t addr, uint32_t total_len)
415{
416    uint32_t len = total_len;
417    size_t write_len = dev->erase_size;
418    int ret;
419
420    NAND_UPDATE_WRITE_THRESHOLD(total_len);
421
422    do_lseek(dev->fd, addr, SEEK_SET);
423    while(len > 0) {
424        if(len < write_len)
425            write_len = len;
426        safe_memory_rw_debug(current_cpu, data, dev->data, write_len, 0);
427        ret = do_write(dev->fd, dev->data, write_len);
428        if(ret < write_len) {
429            XLOG("nand_dev_write_file, write failed: %s\n", strerror(errno));
430            break;
431        }
432        data += write_len;
433        len -= write_len;
434    }
435    return total_len - len;
436}
437
438static uint32_t nand_dev_erase_file(nand_dev *dev, uint64_t addr, uint32_t total_len)
439{
440    uint32_t len = total_len;
441    size_t write_len = dev->erase_size;
442    int ret;
443
444    do_lseek(dev->fd, addr, SEEK_SET);
445    memset(dev->data, 0xff, dev->erase_size);
446    while(len > 0) {
447        if(len < write_len)
448            write_len = len;
449        ret = do_write(dev->fd, dev->data, write_len);
450        if(ret < write_len) {
451            XLOG( "nand_dev_write_file, write failed: %s\n", strerror(errno));
452            break;
453        }
454        len -= write_len;
455    }
456    return total_len - len;
457}
458
459/* this is a huge hack required to make the PowerPC emulator binary usable
460 * on Mac OS X. If you define this function as 'static', the emulated kernel
461 * will panic when attempting to mount the /data partition.
462 *
463 * worse, if you do *not* define the function as static on Linux-x86, the
464 * emulated kernel will also panic !?
465 *
466 * I still wonder if this is a compiler bug, or due to some nasty thing the
467 * emulator does with CPU registers during execution of the translated code.
468 */
469#if !(defined __APPLE__ && defined __powerpc__)
470static
471#endif
472uint32_t nand_dev_do_cmd(nand_dev_controller_state *s, uint32_t cmd)
473{
474    uint32_t size;
475    uint64_t addr;
476    nand_dev *dev;
477
478    if (cmd == NAND_CMD_WRITE_BATCH || cmd == NAND_CMD_READ_BATCH ||
479        cmd == NAND_CMD_ERASE_BATCH) {
480        struct batch_data bd;
481        struct batch_data_64 bd64;
482        uint64_t bd_addr = ((uint64_t)s->batch_addr_high << 32) | s->batch_addr_low;
483        if (goldfish_guest_is_64bit()) {
484            cpu_physical_memory_read(bd_addr, (void*)&bd64, sizeof(struct batch_data_64));
485            s->dev = bd64.dev;
486            s->addr_low = bd64.addr_low;
487            s->addr_high = bd64.addr_high;
488            s->transfer_size = bd64.transfer_size;
489            s->data = bd64.data;
490        } else {
491            cpu_physical_memory_read(bd_addr, (void*)&bd, sizeof(struct batch_data));
492            s->dev = bd.dev;
493            s->addr_low = bd.addr_low;
494            s->addr_high = bd.addr_high;
495            s->transfer_size = bd.transfer_size;
496            s->data = bd.data;
497        }
498    }
499    addr = s->addr_low | ((uint64_t)s->addr_high << 32);
500    size = s->transfer_size;
501    if(s->dev >= nand_dev_count)
502        return 0;
503    dev = nand_devs + s->dev;
504
505    switch(cmd) {
506    case NAND_CMD_GET_DEV_NAME:
507        if(size > dev->devname_len)
508            size = dev->devname_len;
509        safe_memory_rw_debug(current_cpu, s->data, (uint8_t*)dev->devname, size, 1);
510        return size;
511    case NAND_CMD_READ_BATCH:
512    case NAND_CMD_READ:
513        if(addr >= dev->max_size)
514            return 0;
515        if(size > dev->max_size - addr)
516            size = dev->max_size - addr;
517        if(dev->fd >= 0)
518            return nand_dev_read_file(dev, s->data, addr, size);
519        safe_memory_rw_debug(current_cpu, s->data, &dev->data[addr], size, 1);
520        return size;
521    case NAND_CMD_WRITE_BATCH:
522    case NAND_CMD_WRITE:
523        if(dev->flags & NAND_DEV_FLAG_READ_ONLY)
524            return 0;
525        if(addr >= dev->max_size)
526            return 0;
527        if(size > dev->max_size - addr)
528            size = dev->max_size - addr;
529        if(dev->fd >= 0)
530            return nand_dev_write_file(dev, s->data, addr, size);
531        safe_memory_rw_debug(current_cpu, s->data, &dev->data[addr], size, 0);
532        return size;
533    case NAND_CMD_ERASE_BATCH:
534    case NAND_CMD_ERASE:
535        if(dev->flags & NAND_DEV_FLAG_READ_ONLY)
536            return 0;
537        if(addr >= dev->max_size)
538            return 0;
539        if(size > dev->max_size - addr)
540            size = dev->max_size - addr;
541        if(dev->fd >= 0)
542            return nand_dev_erase_file(dev, addr, size);
543        memset(&dev->data[addr], 0xff, size);
544        return size;
545    case NAND_CMD_BLOCK_BAD_GET: // no bad block support
546        return 0;
547    case NAND_CMD_BLOCK_BAD_SET:
548        if(dev->flags & NAND_DEV_FLAG_READ_ONLY)
549            return 0;
550        return 0;
551    default:
552        cpu_abort(cpu_single_env, "nand_dev_do_cmd: Bad command %x\n", cmd);
553        return 0;
554    }
555}
556
557/* I/O write */
558static void nand_dev_write(void *opaque, hwaddr offset, uint32_t value)
559{
560    nand_dev_controller_state *s = (nand_dev_controller_state *)opaque;
561
562    switch (offset) {
563    case NAND_DEV:
564        s->dev = value;
565        if(s->dev >= nand_dev_count) {
566            cpu_abort(cpu_single_env, "nand_dev_write: Bad dev %x\n", value);
567        }
568        break;
569    case NAND_ADDR_HIGH:
570        s->addr_high = value;
571        break;
572    case NAND_ADDR_LOW:
573        s->addr_low = value;
574        break;
575    case NAND_BATCH_ADDR_LOW:
576        s->batch_addr_low = value;
577        break;
578    case NAND_BATCH_ADDR_HIGH:
579        s->batch_addr_high = value;
580        break;
581    case NAND_TRANSFER_SIZE:
582        s->transfer_size = value;
583        break;
584    case NAND_DATA:
585        uint64_set_low(&s->data, value);
586        break;
587    case NAND_DATA_HIGH:
588        uint64_set_high(&s->data, value);
589        break;
590    case NAND_COMMAND:
591        s->result = nand_dev_do_cmd(s, value);
592        if (value == NAND_CMD_WRITE_BATCH || value == NAND_CMD_READ_BATCH ||
593            value == NAND_CMD_ERASE_BATCH) {
594            struct batch_data bd;
595            struct batch_data_64 bd64;
596            uint64_t bd_addr = ((uint64_t)s->batch_addr_high << 32) | s->batch_addr_low;
597            if (goldfish_guest_is_64bit()) {
598                bd64.result = s->result;
599                cpu_physical_memory_write(bd_addr, (void*)&bd64, sizeof(struct batch_data_64));
600            } else {
601                bd.result = s->result;
602                cpu_physical_memory_write(bd_addr, (void*)&bd, sizeof(struct batch_data));
603            }
604        }
605        break;
606    default:
607        cpu_abort(cpu_single_env, "nand_dev_write: Bad offset %x\n", offset);
608        break;
609    }
610}
611
612/* I/O read */
613static uint32_t nand_dev_read(void *opaque, hwaddr offset)
614{
615    nand_dev_controller_state *s = (nand_dev_controller_state *)opaque;
616    nand_dev *dev;
617
618    switch (offset) {
619    case NAND_VERSION:
620        return NAND_VERSION_CURRENT;
621    case NAND_NUM_DEV:
622        return nand_dev_count;
623    case NAND_RESULT:
624        return s->result;
625    }
626
627    if(s->dev >= nand_dev_count)
628        return 0;
629
630    dev = nand_devs + s->dev;
631
632    switch (offset) {
633    case NAND_DEV_FLAGS:
634        return dev->flags;
635
636    case NAND_DEV_NAME_LEN:
637        return dev->devname_len;
638
639    case NAND_DEV_PAGE_SIZE:
640        return dev->page_size;
641
642    case NAND_DEV_EXTRA_SIZE:
643        return dev->extra_size;
644
645    case NAND_DEV_ERASE_SIZE:
646        return dev->erase_size;
647
648    case NAND_DEV_SIZE_LOW:
649        return (uint32_t)dev->max_size;
650
651    case NAND_DEV_SIZE_HIGH:
652        return (uint32_t)(dev->max_size >> 32);
653
654    default:
655        cpu_abort(cpu_single_env, "nand_dev_read: Bad offset %x\n", offset);
656        return 0;
657    }
658}
659
660static CPUReadMemoryFunc *nand_dev_readfn[] = {
661   nand_dev_read,
662   nand_dev_read,
663   nand_dev_read
664};
665
666static CPUWriteMemoryFunc *nand_dev_writefn[] = {
667   nand_dev_write,
668   nand_dev_write,
669   nand_dev_write
670};
671
672/* initialize the QFB device */
673void nand_dev_init(uint32_t base)
674{
675    int iomemtype;
676    static int  instance_id = 0;
677    nand_dev_controller_state *s;
678
679    s = (nand_dev_controller_state *)g_malloc0(sizeof(nand_dev_controller_state));
680    iomemtype = cpu_register_io_memory(nand_dev_readfn, nand_dev_writefn, s);
681    cpu_register_physical_memory(base, 0x00000fff, iomemtype);
682    s->base = base;
683
684    register_savevm(NULL,
685                    "nand_dev",
686                    instance_id++,
687                    NAND_DEV_STATE_SAVE_VERSION,
688                    nand_dev_controller_state_save,
689                    nand_dev_controller_state_load,
690                    s);
691}
692
693static int arg_match(const char *a, const char *b, size_t b_len)
694{
695    while(*a && b_len--) {
696        if(*a++ != *b++)
697            return 0;
698    }
699    return b_len == 0;
700}
701
702void nand_add_dev(const char *arg)
703{
704    uint64_t dev_size = 0;
705    const char *next_arg;
706    const char *value;
707    size_t arg_len, value_len;
708    nand_dev *new_devs, *dev;
709    char *devname = NULL;
710    size_t devname_len = 0;
711    char *initfilename = NULL;
712    char *rwfilename = NULL;
713    int initfd = -1;
714    int rwfd = -1;
715    int read_only = 0;
716    int pad;
717    ssize_t read_size;
718    uint32_t page_size = 2048;
719    uint32_t extra_size = 64;
720    uint32_t erase_pages = 64;
721
722    VERBOSE_PRINT(init, "%s: %s", __FUNCTION__, arg);
723
724    while(arg) {
725        next_arg = strchr(arg, ',');
726        value = strchr(arg, '=');
727        if(next_arg != NULL) {
728            arg_len = next_arg - arg;
729            next_arg++;
730            if(value >= next_arg)
731                value = NULL;
732        }
733        else
734            arg_len = strlen(arg);
735        if(value != NULL) {
736            size_t new_arg_len = value - arg;
737            value_len = arg_len - new_arg_len - 1;
738            arg_len = new_arg_len;
739            value++;
740        }
741        else
742            value_len = 0;
743
744        if(devname == NULL) {
745            if(value != NULL)
746                goto bad_arg_and_value;
747            devname_len = arg_len;
748            devname = malloc(arg_len+1);
749            if(devname == NULL)
750                goto out_of_memory;
751            memcpy(devname, arg, arg_len);
752            devname[arg_len] = 0;
753        }
754        else if(value == NULL) {
755            if(arg_match("readonly", arg, arg_len)) {
756                read_only = 1;
757            }
758            else {
759                XLOG("bad arg: %.*s\n", arg_len, arg);
760                exit(1);
761            }
762        }
763        else {
764            if(arg_match("size", arg, arg_len)) {
765                char *ep;
766                dev_size = strtoull(value, &ep, 0);
767                if(ep != value + value_len)
768                    goto bad_arg_and_value;
769            }
770            else if(arg_match("pagesize", arg, arg_len)) {
771                char *ep;
772                page_size = strtoul(value, &ep, 0);
773                if(ep != value + value_len)
774                    goto bad_arg_and_value;
775            }
776            else if(arg_match("extrasize", arg, arg_len)) {
777                char *ep;
778                extra_size = strtoul(value, &ep, 0);
779                if(ep != value + value_len)
780                    goto bad_arg_and_value;
781            }
782            else if(arg_match("erasepages", arg, arg_len)) {
783                char *ep;
784                erase_pages = strtoul(value, &ep, 0);
785                if(ep != value + value_len)
786                    goto bad_arg_and_value;
787            }
788            else if(arg_match("initfile", arg, arg_len)) {
789                initfilename = malloc(value_len + 1);
790                if(initfilename == NULL)
791                    goto out_of_memory;
792                memcpy(initfilename, value, value_len);
793                initfilename[value_len] = '\0';
794            }
795            else if(arg_match("file", arg, arg_len)) {
796                rwfilename = malloc(value_len + 1);
797                if(rwfilename == NULL)
798                    goto out_of_memory;
799                memcpy(rwfilename, value, value_len);
800                rwfilename[value_len] = '\0';
801            }
802            else {
803                goto bad_arg_and_value;
804            }
805        }
806
807        arg = next_arg;
808    }
809
810    if (rwfilename == NULL) {
811        /* we create a temporary file to store everything */
812        TempFile*    tmp = tempfile_create();
813
814        if (tmp == NULL) {
815            XLOG("could not create temp file for %.*s NAND disk image: %s\n",
816                  devname_len, devname, strerror(errno));
817            exit(1);
818        }
819        rwfilename = (char*) tempfile_path(tmp);
820        if (VERBOSE_CHECK(init))
821            dprint( "mapping '%.*s' NAND image to %s", devname_len, devname, rwfilename);
822    }
823
824    if(rwfilename) {
825        if (initfilename) {
826            /* Overwrite with content of the 'initfilename'. */
827            if (read_only) {
828                /* Cannot be readonly when initializing the device from another file. */
829                XLOG("incompatible read only option is requested while initializing %.*s from %s\n",
830                     devname_len, devname, initfilename);
831                exit(1);
832            }
833            rwfd = open(rwfilename, O_BINARY | O_TRUNC | O_RDWR);
834        } else {
835            rwfd = open(rwfilename, O_BINARY | (read_only ? O_RDONLY : O_RDWR));
836        }
837        if(rwfd < 0) {
838            XLOG("could not open file %s, %s\n", rwfilename, strerror(errno));
839            exit(1);
840        }
841        /* this could be a writable temporary file. use atexit_close_fd to ensure
842         * that it is properly cleaned up at exit on Win32
843         */
844        if (!read_only)
845            atexit_close_fd(rwfd);
846    }
847
848    if(initfilename) {
849        initfd = open(initfilename, O_BINARY | O_RDONLY);
850        if(initfd < 0) {
851            XLOG("could not open file %s, %s\n", initfilename, strerror(errno));
852            exit(1);
853        }
854        if(dev_size == 0) {
855            dev_size = do_lseek(initfd, 0, SEEK_END);
856            do_lseek(initfd, 0, SEEK_SET);
857        }
858    }
859
860    new_devs = realloc(nand_devs, sizeof(nand_devs[0]) * (nand_dev_count + 1));
861    if(new_devs == NULL)
862        goto out_of_memory;
863    nand_devs = new_devs;
864    dev = &new_devs[nand_dev_count];
865
866    dev->page_size = page_size;
867    dev->extra_size = extra_size;
868    dev->erase_size = erase_pages * (page_size + extra_size);
869    pad = dev_size % dev->erase_size;
870    if (pad != 0) {
871        dev_size += (dev->erase_size - pad);
872        D("rounding devsize up to a full eraseunit, now %llx\n", dev_size);
873    }
874    dev->devname = devname;
875    dev->devname_len = devname_len;
876    dev->max_size = dev_size;
877    dev->data = malloc(dev->erase_size);
878    if(dev->data == NULL)
879        goto out_of_memory;
880    dev->flags = read_only ? NAND_DEV_FLAG_READ_ONLY : 0;
881#ifdef TARGET_I386
882    dev->flags |= NAND_DEV_FLAG_BATCH_CAP;
883#endif
884
885    if (initfd >= 0) {
886        do {
887            read_size = do_read(initfd, dev->data, dev->erase_size);
888            if(read_size < 0) {
889                XLOG("could not read file %s, %s\n", initfilename, strerror(errno));
890                exit(1);
891            }
892            if(do_write(rwfd, dev->data, read_size) != read_size) {
893                XLOG("could not write file %s, %s\n", rwfilename, strerror(errno));
894                exit(1);
895            }
896        } while(read_size == dev->erase_size);
897        close(initfd);
898    }
899    dev->fd = rwfd;
900
901    nand_dev_count++;
902
903    return;
904
905out_of_memory:
906    XLOG("out of memory\n");
907    exit(1);
908
909bad_arg_and_value:
910    XLOG("bad arg: %.*s=%.*s\n", arg_len, arg, value_len, value);
911    exit(1);
912}
913
914#ifdef CONFIG_NAND_LIMITS
915
916static uint64_t
917parse_nand_rw_limit( const char*  value )
918{
919    char*     end;
920    uint64_t  val = strtoul( value, &end, 0 );
921
922    if (end == value) {
923        derror( "bad parameter value '%s': expecting unsigned integer", value );
924        exit(1);
925    }
926
927    switch (end[0]) {
928        case 'K':  val <<= 10; break;
929        case 'M':  val <<= 20; break;
930        case 'G':  val <<= 30; break;
931        case 0: break;
932        default:
933            derror( "bad read/write limit suffix: use K, M or G" );
934            exit(1);
935    }
936    return val;
937}
938
939void
940parse_nand_limits(char*  limits)
941{
942    int      pid = -1, signal = -1;
943    int64_t  reads = 0, writes = 0;
944    char*    item = limits;
945
946    /* parse over comma-separated items */
947    while (item && *item) {
948        char*  next = strchr(item, ',');
949        char*  end;
950
951        if (next == NULL) {
952            next = item + strlen(item);
953        } else {
954            *next++ = 0;
955        }
956
957        if ( !memcmp(item, "pid=", 4) ) {
958            pid = strtol(item+4, &end, 10);
959            if (end == NULL || *end) {
960                derror( "bad parameter, expecting pid=<number>, got '%s'",
961                        item );
962                exit(1);
963            }
964            if (pid <= 0) {
965                derror( "bad parameter: process identifier must be > 0" );
966                exit(1);
967            }
968        }
969        else if ( !memcmp(item, "signal=", 7) ) {
970            signal = strtol(item+7,&end, 10);
971            if (end == NULL || *end) {
972                derror( "bad parameter: expecting signal=<number>, got '%s'",
973                        item );
974                exit(1);
975            }
976            if (signal <= 0) {
977                derror( "bad parameter: signal number must be > 0" );
978                exit(1);
979            }
980        }
981        else if ( !memcmp(item, "reads=", 6) ) {
982            reads = parse_nand_rw_limit(item+6);
983        }
984        else if ( !memcmp(item, "writes=", 7) ) {
985            writes = parse_nand_rw_limit(item+7);
986        }
987        else {
988            derror( "bad parameter '%s' (see -help-nand-limits)", item );
989            exit(1);
990        }
991        item = next;
992    }
993    if (pid < 0) {
994        derror( "bad paramater: missing pid=<number>" );
995        exit(1);
996    }
997    else if (signal < 0) {
998        derror( "bad parameter: missing signal=<number>" );
999        exit(1);
1000    }
1001    else if (reads == 0 && writes == 0) {
1002        dwarning( "no read or write limit specified. ignoring -nand-limits" );
1003    } else {
1004        nand_threshold*  t;
1005
1006        t  = &android_nand_read_threshold;
1007        t->pid     = pid;
1008        t->signal  = signal;
1009        t->counter = 0;
1010        t->limit   = reads;
1011
1012        t  = &android_nand_write_threshold;
1013        t->pid     = pid;
1014        t->signal  = signal;
1015        t->counter = 0;
1016        t->limit   = writes;
1017    }
1018}
1019#endif /* CONFIG_NAND_LIMITS */
1020