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