• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
42 static void
xlog(const char * format,...)43 xlog( 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 typedef struct {
53     char*      devname;
54     size_t     devname_len;
55     char*      data;
56     int        fd;
57     uint32_t   flags;
58     uint32_t   page_size;
59     uint32_t   extra_size;
60     uint32_t   erase_size;
61     uint64_t   size;
62 } nand_dev;
63 
64 nand_threshold    android_nand_write_threshold;
65 nand_threshold    android_nand_read_threshold;
66 
67 #ifdef CONFIG_NAND_THRESHOLD
68 
69 /* update a threshold, return 1 if limit is hit, 0 otherwise */
70 static void
nand_threshold_update(nand_threshold * t,uint32_t len)71 nand_threshold_update( nand_threshold*  t, uint32_t  len )
72 {
73     if (t->counter < t->limit) {
74         uint64_t  avail = t->limit - t->counter;
75         if (avail > len)
76             avail = len;
77 
78         if (t->counter == 0) {
79             T("%s: starting threshold counting to %lld",
80               __FUNCTION__, t->limit);
81         }
82         t->counter += avail;
83         if (t->counter >= t->limit) {
84             /* threshold reach, send a signal to an external process */
85             T( "%s: sending signal %d to pid %d !",
86                __FUNCTION__, t->signal, t->pid );
87 
88             kill( t->pid, t->signal );
89         }
90     }
91     return;
92 }
93 
94 #define  NAND_UPDATE_READ_THRESHOLD(len)  \
95     nand_threshold_update( &android_nand_read_threshold, (uint32_t)(len) )
96 
97 #define  NAND_UPDATE_WRITE_THRESHOLD(len)  \
98     nand_threshold_update( &android_nand_write_threshold, (uint32_t)(len) )
99 
100 #else /* !NAND_THRESHOLD */
101 
102 #define  NAND_UPDATE_READ_THRESHOLD(len)  \
103     do {} while (0)
104 
105 #define  NAND_UPDATE_WRITE_THRESHOLD(len)  \
106     do {} while (0)
107 
108 #endif /* !NAND_THRESHOLD */
109 
110 static nand_dev *nand_devs = NULL;
111 static uint32_t nand_dev_count = 0;
112 
113 typedef struct {
114     uint32_t base;
115 
116     // register state
117     uint32_t dev;
118     uint32_t addr_low;
119     uint32_t addr_high;
120     uint32_t transfer_size;
121     uint32_t data;
122     uint32_t result;
123 } nand_dev_state;
124 
125 /* update this everytime you change the nand_dev_state structure */
126 #define  NAND_DEV_STATE_SAVE_VERSION  1
127 
128 #define  QFIELD_STRUCT  nand_dev_state
129 QFIELD_BEGIN(nand_dev_state_fields)
QFIELD_INT32(dev)130     QFIELD_INT32(dev),
131     QFIELD_INT32(addr_low),
132     QFIELD_INT32(addr_high),
133     QFIELD_INT32(transfer_size),
134     QFIELD_INT32(data),
135     QFIELD_INT32(result),
136 QFIELD_END
137 
138 static void  nand_dev_state_save(QEMUFile*  f, void*  opaque)
139 {
140     nand_dev_state*  s = opaque;
141 
142     qemu_put_struct(f, nand_dev_state_fields, s);
143 }
144 
nand_dev_state_load(QEMUFile * f,void * opaque,int version_id)145 static int   nand_dev_state_load(QEMUFile*  f, void*  opaque, int  version_id)
146 {
147     nand_dev_state*  s = opaque;
148 
149     if (version_id != NAND_DEV_STATE_SAVE_VERSION)
150         return -1;
151 
152     return qemu_get_struct(f, nand_dev_state_fields, s);
153 }
154 
155 
do_read(int fd,void * buf,size_t size)156 static int  do_read(int  fd, void*  buf, size_t  size)
157 {
158     int  ret;
159     do {
160         ret = read(fd, buf, size);
161     } while (ret < 0 && errno == EINTR);
162 
163     return ret;
164 }
165 
do_write(int fd,const void * buf,size_t size)166 static int  do_write(int  fd, const void*  buf, size_t  size)
167 {
168     int  ret;
169     do {
170         ret = write(fd, buf, size);
171     } while (ret < 0 && errno == EINTR);
172 
173     return ret;
174 }
175 
nand_dev_read_file(nand_dev * dev,uint32_t data,uint64_t addr,uint32_t total_len)176 static uint32_t nand_dev_read_file(nand_dev *dev, uint32_t data, uint64_t addr, uint32_t total_len)
177 {
178     uint32_t len = total_len;
179     size_t read_len = dev->erase_size;
180     int eof = 0;
181 
182     NAND_UPDATE_READ_THRESHOLD(total_len);
183 
184     lseek(dev->fd, addr, SEEK_SET);
185     while(len > 0) {
186         if(read_len < dev->erase_size) {
187             memset(dev->data, 0xff, dev->erase_size);
188             read_len = dev->erase_size;
189             eof = 1;
190         }
191         if(len < read_len)
192             read_len = len;
193         if(!eof) {
194             read_len = do_read(dev->fd, dev->data, read_len);
195         }
196         cpu_memory_rw_debug(cpu_single_env, data, dev->data, read_len, 1);
197         data += read_len;
198         len -= read_len;
199     }
200     return total_len;
201 }
202 
nand_dev_write_file(nand_dev * dev,uint32_t data,uint64_t addr,uint32_t total_len)203 static uint32_t nand_dev_write_file(nand_dev *dev, uint32_t data, uint64_t addr, uint32_t total_len)
204 {
205     uint32_t len = total_len;
206     size_t write_len = dev->erase_size;
207     int ret;
208 
209     NAND_UPDATE_WRITE_THRESHOLD(total_len);
210 
211     lseek(dev->fd, addr, SEEK_SET);
212     while(len > 0) {
213         if(len < write_len)
214             write_len = len;
215         cpu_memory_rw_debug(cpu_single_env, data, dev->data, write_len, 0);
216         ret = do_write(dev->fd, dev->data, write_len);
217         if(ret < write_len) {
218             XLOG("nand_dev_write_file, write failed: %s\n", strerror(errno));
219             break;
220         }
221         data += write_len;
222         len -= write_len;
223     }
224     return total_len - len;
225 }
226 
nand_dev_erase_file(nand_dev * dev,uint64_t addr,uint32_t total_len)227 static uint32_t nand_dev_erase_file(nand_dev *dev, uint64_t addr, uint32_t total_len)
228 {
229     uint32_t len = total_len;
230     size_t write_len = dev->erase_size;
231     int ret;
232 
233     lseek(dev->fd, addr, SEEK_SET);
234     memset(dev->data, 0xff, dev->erase_size);
235     while(len > 0) {
236         if(len < write_len)
237             write_len = len;
238         ret = do_write(dev->fd, dev->data, write_len);
239         if(ret < write_len) {
240             XLOG( "nand_dev_write_file, write failed: %s\n", strerror(errno));
241             break;
242         }
243         len -= write_len;
244     }
245     return total_len - len;
246 }
247 
248 /* this is a huge hack required to make the PowerPC emulator binary usable
249  * on Mac OS X. If you define this function as 'static', the emulated kernel
250  * will panic when attempting to mount the /data partition.
251  *
252  * worse, if you do *not* define the function as static on Linux-x86, the
253  * emulated kernel will also panic !?
254  *
255  * I still wonder if this is a compiler bug, or due to some nasty thing the
256  * emulator does with CPU registers during execution of the translated code.
257  */
258 #if !(defined __APPLE__ && defined __powerpc__)
259 static
260 #endif
nand_dev_do_cmd(nand_dev_state * s,uint32_t cmd)261 uint32_t nand_dev_do_cmd(nand_dev_state *s, uint32_t cmd)
262 {
263     uint32_t size;
264     uint64_t addr;
265     nand_dev *dev;
266 
267     addr = s->addr_low | ((uint64_t)s->addr_high << 32);
268     size = s->transfer_size;
269     if(s->dev >= nand_dev_count)
270         return 0;
271     dev = nand_devs + s->dev;
272 
273     switch(cmd) {
274     case NAND_CMD_GET_DEV_NAME:
275         if(size > dev->devname_len)
276             size = dev->devname_len;
277         cpu_memory_rw_debug(cpu_single_env, s->data, dev->devname, size, 1);
278         return size;
279     case NAND_CMD_READ:
280         if(addr >= dev->size)
281             return 0;
282         if(size + addr > dev->size)
283             size = dev->size - addr;
284         if(dev->fd >= 0)
285             return nand_dev_read_file(dev, s->data, addr, size);
286         cpu_memory_rw_debug(cpu_single_env,s->data, &dev->data[addr], size, 1);
287         return size;
288     case NAND_CMD_WRITE:
289         if(dev->flags & NAND_DEV_FLAG_READ_ONLY)
290             return 0;
291         if(addr >= dev->size)
292             return 0;
293         if(size + addr > dev->size)
294             size = dev->size - addr;
295         if(dev->fd >= 0)
296             return nand_dev_write_file(dev, s->data, addr, size);
297         cpu_memory_rw_debug(cpu_single_env,s->data, &dev->data[addr], size, 0);
298         return size;
299     case NAND_CMD_ERASE:
300         if(dev->flags & NAND_DEV_FLAG_READ_ONLY)
301             return 0;
302         if(addr >= dev->size)
303             return 0;
304         if(size + addr > dev->size)
305             size = dev->size - addr;
306         if(dev->fd >= 0)
307             return nand_dev_erase_file(dev, addr, size);
308         memset(&dev->data[addr], 0xff, size);
309         return size;
310     case NAND_CMD_BLOCK_BAD_GET: // no bad block support
311         return 0;
312     case NAND_CMD_BLOCK_BAD_SET:
313         if(dev->flags & NAND_DEV_FLAG_READ_ONLY)
314             return 0;
315         return 0;
316     default:
317         cpu_abort(cpu_single_env, "nand_dev_do_cmd: Bad command %x\n", cmd);
318         return 0;
319     }
320 }
321 
322 /* I/O write */
nand_dev_write(void * opaque,target_phys_addr_t offset,uint32_t value)323 static void nand_dev_write(void *opaque, target_phys_addr_t offset, uint32_t value)
324 {
325     nand_dev_state *s = (nand_dev_state *)opaque;
326 
327     switch (offset) {
328     case NAND_DEV:
329         s->dev = value;
330         if(s->dev >= nand_dev_count) {
331             cpu_abort(cpu_single_env, "nand_dev_write: Bad dev %x\n", value);
332         }
333         break;
334     case NAND_ADDR_HIGH:
335         s->addr_high = value;
336         break;
337     case NAND_ADDR_LOW:
338         s->addr_low = value;
339         break;
340     case NAND_TRANSFER_SIZE:
341         s->transfer_size = value;
342         break;
343     case NAND_DATA:
344         s->data = value;
345         break;
346     case NAND_COMMAND:
347         s->result = nand_dev_do_cmd(s, value);
348         break;
349     default:
350         cpu_abort(cpu_single_env, "nand_dev_write: Bad offset %x\n", offset);
351         break;
352     }
353 }
354 
355 /* I/O read */
nand_dev_read(void * opaque,target_phys_addr_t offset)356 static uint32_t nand_dev_read(void *opaque, target_phys_addr_t offset)
357 {
358     nand_dev_state *s = (nand_dev_state *)opaque;
359     nand_dev *dev;
360 
361     switch (offset) {
362     case NAND_VERSION:
363         return NAND_VERSION_CURRENT;
364     case NAND_NUM_DEV:
365         return nand_dev_count;
366     case NAND_RESULT:
367         return s->result;
368     }
369 
370     if(s->dev >= nand_dev_count)
371         return 0;
372 
373     dev = nand_devs + s->dev;
374 
375     switch (offset) {
376     case NAND_DEV_FLAGS:
377         return dev->flags;
378 
379     case NAND_DEV_NAME_LEN:
380         return dev->devname_len;
381 
382     case NAND_DEV_PAGE_SIZE:
383         return dev->page_size;
384 
385     case NAND_DEV_EXTRA_SIZE:
386         return dev->extra_size;
387 
388     case NAND_DEV_ERASE_SIZE:
389         return dev->erase_size;
390 
391     case NAND_DEV_SIZE_LOW:
392         return (uint32_t)dev->size;
393 
394     case NAND_DEV_SIZE_HIGH:
395         return (uint32_t)(dev->size >> 32);
396 
397     default:
398         cpu_abort(cpu_single_env, "nand_dev_read: Bad offset %x\n", offset);
399         return 0;
400     }
401 }
402 
403 static CPUReadMemoryFunc *nand_dev_readfn[] = {
404    nand_dev_read,
405    nand_dev_read,
406    nand_dev_read
407 };
408 
409 static CPUWriteMemoryFunc *nand_dev_writefn[] = {
410    nand_dev_write,
411    nand_dev_write,
412    nand_dev_write
413 };
414 
415 /* initialize the QFB device */
nand_dev_init(uint32_t base)416 void nand_dev_init(uint32_t base)
417 {
418     int iomemtype;
419     static int  instance_id = 0;
420     nand_dev_state *s;
421 
422     s = (nand_dev_state *)qemu_mallocz(sizeof(nand_dev_state));
423     iomemtype = cpu_register_io_memory(nand_dev_readfn, nand_dev_writefn, s);
424     cpu_register_physical_memory(base, 0x00000fff, iomemtype);
425     s->base = base;
426 
427     register_savevm( "nand_dev", instance_id++, NAND_DEV_STATE_SAVE_VERSION,
428                       nand_dev_state_save, nand_dev_state_load, s);
429 }
430 
arg_match(const char * a,const char * b,size_t b_len)431 static int arg_match(const char *a, const char *b, size_t b_len)
432 {
433     while(*a && b_len--) {
434         if(*a++ != *b++)
435             return 0;
436     }
437     return b_len == 0;
438 }
439 
nand_add_dev(const char * arg)440 void nand_add_dev(const char *arg)
441 {
442     uint64_t dev_size = 0;
443     const char *next_arg;
444     const char *value;
445     size_t arg_len, value_len;
446     nand_dev *new_devs, *dev;
447     char *devname = NULL;
448     size_t devname_len = 0;
449     char *initfilename = NULL;
450     char *rwfilename = NULL;
451     int initfd = -1;
452     int rwfd = -1;
453     int read_only = 0;
454     int pad;
455     ssize_t read_size;
456     uint32_t page_size = 2048;
457     uint32_t extra_size = 64;
458     uint32_t erase_pages = 64;
459 
460     while(arg) {
461         next_arg = strchr(arg, ',');
462         value = strchr(arg, '=');
463         if(next_arg != NULL) {
464             arg_len = next_arg - arg;
465             next_arg++;
466             if(value >= next_arg)
467                 value = NULL;
468         }
469         else
470             arg_len = strlen(arg);
471         if(value != NULL) {
472             size_t new_arg_len = value - arg;
473             value_len = arg_len - new_arg_len - 1;
474             arg_len = new_arg_len;
475             value++;
476         }
477         else
478             value_len = 0;
479 
480         if(devname == NULL) {
481             if(value != NULL)
482                 goto bad_arg_and_value;
483             devname_len = arg_len;
484             devname = malloc(arg_len);
485             if(devname == NULL)
486                 goto out_of_memory;
487             memcpy(devname, arg, arg_len);
488         }
489         else if(value == NULL) {
490             if(arg_match("readonly", arg, arg_len)) {
491                 read_only = 1;
492             }
493             else {
494                 XLOG("bad arg: %.*s\n", arg_len, arg);
495                 exit(1);
496             }
497         }
498         else {
499             if(arg_match("size", arg, arg_len)) {
500                 char *ep;
501                 dev_size = strtoull(value, &ep, 0);
502                 if(ep != value + value_len)
503                     goto bad_arg_and_value;
504             }
505             else if(arg_match("pagesize", arg, arg_len)) {
506                 char *ep;
507                 page_size = strtoul(value, &ep, 0);
508                 if(ep != value + value_len)
509                     goto bad_arg_and_value;
510             }
511             else if(arg_match("extrasize", arg, arg_len)) {
512                 char *ep;
513                 extra_size = strtoul(value, &ep, 0);
514                 if(ep != value + value_len)
515                     goto bad_arg_and_value;
516             }
517             else if(arg_match("erasepages", arg, arg_len)) {
518                 char *ep;
519                 erase_pages = strtoul(value, &ep, 0);
520                 if(ep != value + value_len)
521                     goto bad_arg_and_value;
522             }
523             else if(arg_match("initfile", arg, arg_len)) {
524                 initfilename = malloc(value_len + 1);
525                 if(initfilename == NULL)
526                     goto out_of_memory;
527                 memcpy(initfilename, value, value_len);
528                 initfilename[value_len] = '\0';
529             }
530             else if(arg_match("file", arg, arg_len)) {
531                 rwfilename = malloc(value_len + 1);
532                 if(rwfilename == NULL)
533                     goto out_of_memory;
534                 memcpy(rwfilename, value, value_len);
535                 rwfilename[value_len] = '\0';
536             }
537             else {
538                 goto bad_arg_and_value;
539             }
540         }
541 
542         arg = next_arg;
543     }
544 
545     if (rwfilename == NULL) {
546         /* we create a temporary file to store everything */
547         TempFile*    tmp = tempfile_create();
548 
549         if (tmp == NULL) {
550             XLOG("could not create temp file for %.*s NAND disk image: %s",
551                   devname_len, devname, strerror(errno));
552             exit(1);
553         }
554         rwfilename = (char*) tempfile_path(tmp);
555         if (VERBOSE_CHECK(init))
556             dprint( "mapping '%.*s' NAND image to %s", devname_len, devname, rwfilename);
557     }
558 
559     if(rwfilename) {
560         rwfd = open(rwfilename, O_BINARY | (read_only ? O_RDONLY : O_RDWR));
561         if(rwfd < 0 && read_only) {
562             XLOG("could not open file %s, %s\n", rwfilename, strerror(errno));
563             exit(1);
564         }
565         /* this could be a writable temporary file. use atexit_close_fd to ensure
566          * that it is properly cleaned up at exit on Win32
567          */
568         if (!read_only)
569             atexit_close_fd(rwfd);
570     }
571 
572     if(initfilename) {
573         initfd = open(initfilename, O_BINARY | O_RDONLY);
574         if(initfd < 0) {
575             XLOG("could not open file %s, %s\n", initfilename, strerror(errno));
576             exit(1);
577         }
578         if(dev_size == 0) {
579             dev_size = lseek(initfd, 0, SEEK_END);
580             lseek(initfd, 0, SEEK_SET);
581         }
582     }
583 
584     new_devs = realloc(nand_devs, sizeof(nand_devs[0]) * (nand_dev_count + 1));
585     if(new_devs == NULL)
586         goto out_of_memory;
587     nand_devs = new_devs;
588     dev = &new_devs[nand_dev_count];
589 
590     dev->page_size = page_size;
591     dev->extra_size = extra_size;
592     dev->erase_size = erase_pages * (page_size + extra_size);
593     pad = dev_size % dev->erase_size;
594     if (pad != 0) {
595         dev_size += (dev->erase_size - pad);
596         D("rounding devsize up to a full eraseunit, now %llx\n", dev_size);
597     }
598     dev->devname = devname;
599     dev->devname_len = devname_len;
600     dev->size = dev_size;
601     dev->data = malloc(dev->erase_size);
602     if(dev->data == NULL)
603         goto out_of_memory;
604     dev->flags = read_only ? NAND_DEV_FLAG_READ_ONLY : 0;
605 
606     if (initfd >= 0) {
607         do {
608             read_size = do_read(initfd, dev->data, dev->erase_size);
609             if(read_size < 0) {
610                 XLOG("could not read file %s, %s\n", initfilename, strerror(errno));
611                 exit(1);
612             }
613             if(do_write(rwfd, dev->data, read_size) != read_size) {
614                 XLOG("could not write file %s, %s\n", initfilename, strerror(errno));
615                 exit(1);
616             }
617         } while(read_size == dev->erase_size);
618         close(initfd);
619     }
620     dev->fd = rwfd;
621 
622     nand_dev_count++;
623 
624     return;
625 
626 out_of_memory:
627     XLOG("out of memory\n");
628     exit(1);
629 
630 bad_arg_and_value:
631     XLOG("bad arg: %.*s=%.*s\n", arg_len, arg, value_len, value);
632     exit(1);
633 }
634 
635