blob: 61b075ef10cd347f627e531715a0846bc2f068c5 [file] [log] [blame]
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001/* 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(nand,__VA_ARGS__)
22# define D_ACTIVE VERBOSE_CHECK(nand)
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
52typedef 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
64nand_threshold android_nand_write_threshold;
65nand_threshold android_nand_read_threshold;
66
67#ifdef CONFIG_NAND_THRESHOLD
68
69/* update a threshold, return 1 if limit is hit, 0 otherwise */
70static void
71nand_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
110static nand_dev *nand_devs = NULL;
111static uint32_t nand_dev_count = 0;
112
113typedef 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
129QFIELD_BEGIN(nand_dev_state_fields)
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),
136QFIELD_END
137
138static 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
145static 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
156static 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
166static 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
176static 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 pmemcpy(data, dev->data, read_len);
197 data += read_len;
198 len -= read_len;
199 }
200 return total_len;
201}
202
203static 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 vmemcpy(data, dev->data, write_len);
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
227static 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__)
259static
260#endif
261uint32_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 pmemcpy(s->data, dev->devname, size);
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 pmemcpy(s->data, &dev->data[addr], size);
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 vmemcpy(s->data, &dev->data[addr], size);
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 */
323static 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 offset -= s->base;
328 switch (offset) {
329 case NAND_DEV:
330 s->dev = value;
331 if(s->dev >= nand_dev_count) {
332 cpu_abort(cpu_single_env, "nand_dev_write: Bad dev %x\n", value);
333 }
334 break;
335 case NAND_ADDR_HIGH:
336 s->addr_high = value;
337 break;
338 case NAND_ADDR_LOW:
339 s->addr_low = value;
340 break;
341 case NAND_TRANSFER_SIZE:
342 s->transfer_size = value;
343 break;
344 case NAND_DATA:
345 s->data = value;
346 break;
347 case NAND_COMMAND:
348 s->result = nand_dev_do_cmd(s, value);
349 break;
350 default:
351 cpu_abort(cpu_single_env, "nand_dev_write: Bad offset %x\n", offset);
352 break;
353 }
354}
355
356/* I/O read */
357static uint32_t nand_dev_read(void *opaque, target_phys_addr_t offset)
358{
359 nand_dev_state *s = (nand_dev_state *)opaque;
360 nand_dev *dev;
361
362 offset -= s->base;
363 switch (offset) {
364 case NAND_VERSION:
365 return NAND_VERSION_CURRENT;
366 case NAND_NUM_DEV:
367 return nand_dev_count;
368 case NAND_RESULT:
369 return s->result;
370 }
371
372 if(s->dev >= nand_dev_count)
373 return 0;
374
375 dev = nand_devs + s->dev;
376
377 switch (offset) {
378 case NAND_DEV_FLAGS:
379 return dev->flags;
380
381 case NAND_DEV_NAME_LEN:
382 return dev->devname_len;
383
384 case NAND_DEV_PAGE_SIZE:
385 return dev->page_size;
386
387 case NAND_DEV_EXTRA_SIZE:
388 return dev->extra_size;
389
390 case NAND_DEV_ERASE_SIZE:
391 return dev->erase_size;
392
393 case NAND_DEV_SIZE_LOW:
394 return (uint32_t)dev->size;
395
396 case NAND_DEV_SIZE_HIGH:
397 return (uint32_t)(dev->size >> 32);
398
399 default:
400 cpu_abort(cpu_single_env, "nand_dev_read: Bad offset %x\n", offset);
401 return 0;
402 }
403}
404
405static CPUReadMemoryFunc *nand_dev_readfn[] = {
406 nand_dev_read,
407 nand_dev_read,
408 nand_dev_read
409};
410
411static CPUWriteMemoryFunc *nand_dev_writefn[] = {
412 nand_dev_write,
413 nand_dev_write,
414 nand_dev_write
415};
416
417/* initialize the QFB device */
418void nand_dev_init(uint32_t base)
419{
420 int iomemtype;
421 static int instance_id = 0;
422 nand_dev_state *s;
423
424 s = (nand_dev_state *)qemu_mallocz(sizeof(nand_dev_state));
425 iomemtype = cpu_register_io_memory(0, nand_dev_readfn, nand_dev_writefn, s);
426 cpu_register_physical_memory(base, 0x00000fff, iomemtype);
427 s->base = base;
428
429 register_savevm( "nand_dev", instance_id++, NAND_DEV_STATE_SAVE_VERSION,
430 nand_dev_state_save, nand_dev_state_load, s);
431}
432
433static int arg_match(const char *a, const char *b, size_t b_len)
434{
435 while(*a && b_len--) {
436 if(*a++ != *b++)
437 return 0;
438 }
439 return b_len == 0;
440}
441
442void nand_add_dev(const char *arg)
443{
444 uint64_t dev_size = 0;
445 const char *next_arg;
446 const char *value;
447 size_t arg_len, value_len;
448 nand_dev *new_devs, *dev;
449 char *devname = NULL;
450 size_t devname_len = 0;
451 char *initfilename = NULL;
452 char *rwfilename = NULL;
453 int initfd = -1;
454 int rwfd = -1;
455 int read_only = 0;
456 int pad;
457 ssize_t read_size;
458 uint32_t page_size = 2048;
459 uint32_t extra_size = 64;
460 uint32_t erase_pages = 64;
461
462 while(arg) {
463 next_arg = strchr(arg, ',');
464 value = strchr(arg, '=');
465 if(next_arg != NULL) {
466 arg_len = next_arg - arg;
467 next_arg++;
468 if(value >= next_arg)
469 value = NULL;
470 }
471 else
472 arg_len = strlen(arg);
473 if(value != NULL) {
474 size_t new_arg_len = value - arg;
475 value_len = arg_len - new_arg_len - 1;
476 arg_len = new_arg_len;
477 value++;
478 }
479 else
480 value_len = 0;
481
482 if(devname == NULL) {
483 if(value != NULL)
484 goto bad_arg_and_value;
485 devname_len = arg_len;
486 devname = malloc(arg_len);
487 if(devname == NULL)
488 goto out_of_memory;
489 memcpy(devname, arg, arg_len);
490 }
491 else if(value == NULL) {
492 if(arg_match("readonly", arg, arg_len)) {
493 read_only = 1;
494 }
495 else {
496 XLOG("bad arg: %.*s\n", arg_len, arg);
497 exit(1);
498 }
499 }
500 else {
501 if(arg_match("size", arg, arg_len)) {
502 char *ep;
503 dev_size = strtoull(value, &ep, 0);
504 if(ep != value + value_len)
505 goto bad_arg_and_value;
506 }
507 else if(arg_match("pagesize", arg, arg_len)) {
508 char *ep;
509 page_size = strtoul(value, &ep, 0);
510 if(ep != value + value_len)
511 goto bad_arg_and_value;
512 }
513 else if(arg_match("extrasize", arg, arg_len)) {
514 char *ep;
515 extra_size = strtoul(value, &ep, 0);
516 if(ep != value + value_len)
517 goto bad_arg_and_value;
518 }
519 else if(arg_match("erasepages", arg, arg_len)) {
520 char *ep;
521 erase_pages = strtoul(value, &ep, 0);
522 if(ep != value + value_len)
523 goto bad_arg_and_value;
524 }
525 else if(arg_match("initfile", arg, arg_len)) {
526 initfilename = malloc(value_len + 1);
527 if(initfilename == NULL)
528 goto out_of_memory;
529 memcpy(initfilename, value, value_len);
530 initfilename[value_len] = '\0';
531 }
532 else if(arg_match("file", arg, arg_len)) {
533 rwfilename = malloc(value_len + 1);
534 if(rwfilename == NULL)
535 goto out_of_memory;
536 memcpy(rwfilename, value, value_len);
537 rwfilename[value_len] = '\0';
538 }
539 else {
540 goto bad_arg_and_value;
541 }
542 }
543
544 arg = next_arg;
545 }
546
547 if (rwfilename == NULL) {
548 /* we create a temporary file to store everything */
549 TempFile* tmp = tempfile_create();
550
551 if (tmp == NULL) {
552 XLOG("could not create temp file for %.*s NAND disk image: %s",
553 devname_len, devname, strerror(errno));
554 exit(1);
555 }
556 rwfilename = (char*) tempfile_path(tmp);
557 if (VERBOSE_CHECK(init))
558 dprint( "mapping '%.*s' NAND image to %s", devname_len, devname, rwfilename);
559 }
560
561 if(rwfilename) {
562 rwfd = open(rwfilename, O_BINARY | (read_only ? O_RDONLY : O_RDWR));
563 if(rwfd < 0 && read_only) {
564 XLOG("could not open file %s, %s\n", rwfilename, strerror(errno));
565 exit(1);
566 }
567 /* this could be a writable temporary file. use atexit_close_fd to ensure
568 * that it is properly cleaned up at exit on Win32
569 */
570 if (!read_only)
571 atexit_close_fd(rwfd);
572 }
573
574 if(initfilename) {
575 initfd = open(initfilename, O_BINARY | O_RDONLY);
576 if(initfd < 0) {
577 XLOG("could not open file %s, %s\n", initfilename, strerror(errno));
578 exit(1);
579 }
580 if(dev_size == 0) {
581 dev_size = lseek(initfd, 0, SEEK_END);
582 lseek(initfd, 0, SEEK_SET);
583 }
584 }
585
586 new_devs = realloc(nand_devs, sizeof(nand_devs[0]) * (nand_dev_count + 1));
587 if(new_devs == NULL)
588 goto out_of_memory;
589 nand_devs = new_devs;
590 dev = &new_devs[nand_dev_count];
591
592 dev->page_size = page_size;
593 dev->extra_size = extra_size;
594 dev->erase_size = erase_pages * (page_size + extra_size);
595 pad = dev_size % dev->erase_size;
596 if (pad != 0) {
597 dev_size += (dev->erase_size - pad);
598 XLOG("rounding devsize up to a full eraseunit, now %llx\n", dev_size);
599 }
600 dev->devname = devname;
601 dev->devname_len = devname_len;
602 dev->size = dev_size;
603 dev->data = malloc(dev->erase_size);
604 if(dev->data == NULL)
605 goto out_of_memory;
606 dev->flags = read_only ? NAND_DEV_FLAG_READ_ONLY : 0;
607
608 if (initfd >= 0) {
609 do {
610 read_size = do_read(initfd, dev->data, dev->erase_size);
611 if(read_size < 0) {
612 XLOG("could not read file %s, %s\n", initfilename, strerror(errno));
613 exit(1);
614 }
615 if(do_write(rwfd, dev->data, read_size) != read_size) {
616 XLOG("could not write file %s, %s\n", initfilename, strerror(errno));
617 exit(1);
618 }
619 } while(read_size == dev->erase_size);
620 close(initfd);
621 }
622 dev->fd = rwfd;
623
624 nand_dev_count++;
625
626 return;
627
628out_of_memory:
629 XLOG("out of memory\n");
630 exit(1);
631
632bad_arg_and_value:
633 XLOG("bad arg: %.*s=%.*s\n", arg_len, arg, value_len, value);
634 exit(1);
635}
636