From f721e3ac031f892af46f255a47d7f54a91317b30 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Tue, 3 Mar 2009 18:28:35 -0800 Subject: auto import from //depot/cupcake/@135843 --- hw/goldfish_nand.c | 636 ----------------------------------------------------- 1 file changed, 636 deletions(-) delete mode 100644 hw/goldfish_nand.c (limited to 'hw/goldfish_nand.c') diff --git a/hw/goldfish_nand.c b/hw/goldfish_nand.c deleted file mode 100644 index 61b075e..0000000 --- a/hw/goldfish_nand.c +++ /dev/null @@ -1,636 +0,0 @@ -/* Copyright (C) 2007-2008 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ -#include "qemu_file.h" -#include "goldfish_nand_reg.h" -#include "goldfish_nand.h" -#include "android/utils/tempfile.h" -#include "qemu_debug.h" -#include "android/android.h" - -#define DEBUG 1 -#if DEBUG -# define D(...) VERBOSE_PRINT(nand,__VA_ARGS__) -# define D_ACTIVE VERBOSE_CHECK(nand) -# define T(...) VERBOSE_PRINT(nand_limits,__VA_ARGS__) -# define T_ACTIVE VERBOSE_CHECK(nand_limits) -#else -# define D(...) ((void)0) -# define D_ACTIVE 0 -# define T(...) ((void)0) -# define T_ACTIVE 0 -#endif - -/* lseek uses 64-bit offsets on Darwin. */ -/* prefer lseek64 on Linux */ -#ifdef __APPLE__ -# define llseek lseek -#elif defined(__linux__) -# define llseek lseek64 -#endif - -#define XLOG xlog - -static void -xlog( const char* format, ... ) -{ - va_list args; - va_start(args, format); - fprintf(stderr, "NAND: "); - vfprintf(stderr, format, args); - va_end(args); -} - -typedef struct { - char* devname; - size_t devname_len; - char* data; - int fd; - uint32_t flags; - uint32_t page_size; - uint32_t extra_size; - uint32_t erase_size; - uint64_t size; -} nand_dev; - -nand_threshold android_nand_write_threshold; -nand_threshold android_nand_read_threshold; - -#ifdef CONFIG_NAND_THRESHOLD - -/* update a threshold, return 1 if limit is hit, 0 otherwise */ -static void -nand_threshold_update( nand_threshold* t, uint32_t len ) -{ - if (t->counter < t->limit) { - uint64_t avail = t->limit - t->counter; - if (avail > len) - avail = len; - - if (t->counter == 0) { - T("%s: starting threshold counting to %lld", - __FUNCTION__, t->limit); - } - t->counter += avail; - if (t->counter >= t->limit) { - /* threshold reach, send a signal to an external process */ - T( "%s: sending signal %d to pid %d !", - __FUNCTION__, t->signal, t->pid ); - - kill( t->pid, t->signal ); - } - } - return; -} - -#define NAND_UPDATE_READ_THRESHOLD(len) \ - nand_threshold_update( &android_nand_read_threshold, (uint32_t)(len) ) - -#define NAND_UPDATE_WRITE_THRESHOLD(len) \ - nand_threshold_update( &android_nand_write_threshold, (uint32_t)(len) ) - -#else /* !NAND_THRESHOLD */ - -#define NAND_UPDATE_READ_THRESHOLD(len) \ - do {} while (0) - -#define NAND_UPDATE_WRITE_THRESHOLD(len) \ - do {} while (0) - -#endif /* !NAND_THRESHOLD */ - -static nand_dev *nand_devs = NULL; -static uint32_t nand_dev_count = 0; - -typedef struct { - uint32_t base; - - // register state - uint32_t dev; - uint32_t addr_low; - uint32_t addr_high; - uint32_t transfer_size; - uint32_t data; - uint32_t result; -} nand_dev_state; - -/* update this everytime you change the nand_dev_state structure */ -#define NAND_DEV_STATE_SAVE_VERSION 1 - -#define QFIELD_STRUCT nand_dev_state -QFIELD_BEGIN(nand_dev_state_fields) - QFIELD_INT32(dev), - QFIELD_INT32(addr_low), - QFIELD_INT32(addr_high), - QFIELD_INT32(transfer_size), - QFIELD_INT32(data), - QFIELD_INT32(result), -QFIELD_END - -static void nand_dev_state_save(QEMUFile* f, void* opaque) -{ - nand_dev_state* s = opaque; - - qemu_put_struct(f, nand_dev_state_fields, s); -} - -static int nand_dev_state_load(QEMUFile* f, void* opaque, int version_id) -{ - nand_dev_state* s = opaque; - - if (version_id != NAND_DEV_STATE_SAVE_VERSION) - return -1; - - return qemu_get_struct(f, nand_dev_state_fields, s); -} - - -static int do_read(int fd, void* buf, size_t size) -{ - int ret; - do { - ret = read(fd, buf, size); - } while (ret < 0 && errno == EINTR); - - return ret; -} - -static int do_write(int fd, const void* buf, size_t size) -{ - int ret; - do { - ret = write(fd, buf, size); - } while (ret < 0 && errno == EINTR); - - return ret; -} - -static uint32_t nand_dev_read_file(nand_dev *dev, uint32_t data, uint64_t addr, uint32_t total_len) -{ - uint32_t len = total_len; - size_t read_len = dev->erase_size; - int eof = 0; - - NAND_UPDATE_READ_THRESHOLD(total_len); - - lseek(dev->fd, addr, SEEK_SET); - while(len > 0) { - if(read_len < dev->erase_size) { - memset(dev->data, 0xff, dev->erase_size); - read_len = dev->erase_size; - eof = 1; - } - if(len < read_len) - read_len = len; - if(!eof) { - read_len = do_read(dev->fd, dev->data, read_len); - } - pmemcpy(data, dev->data, read_len); - data += read_len; - len -= read_len; - } - return total_len; -} - -static uint32_t nand_dev_write_file(nand_dev *dev, uint32_t data, uint64_t addr, uint32_t total_len) -{ - uint32_t len = total_len; - size_t write_len = dev->erase_size; - int ret; - - NAND_UPDATE_WRITE_THRESHOLD(total_len); - - lseek(dev->fd, addr, SEEK_SET); - while(len > 0) { - if(len < write_len) - write_len = len; - vmemcpy(data, dev->data, write_len); - ret = do_write(dev->fd, dev->data, write_len); - if(ret < write_len) { - XLOG("nand_dev_write_file, write failed: %s\n", strerror(errno)); - break; - } - data += write_len; - len -= write_len; - } - return total_len - len; -} - -static uint32_t nand_dev_erase_file(nand_dev *dev, uint64_t addr, uint32_t total_len) -{ - uint32_t len = total_len; - size_t write_len = dev->erase_size; - int ret; - - lseek(dev->fd, addr, SEEK_SET); - memset(dev->data, 0xff, dev->erase_size); - while(len > 0) { - if(len < write_len) - write_len = len; - ret = do_write(dev->fd, dev->data, write_len); - if(ret < write_len) { - XLOG( "nand_dev_write_file, write failed: %s\n", strerror(errno)); - break; - } - len -= write_len; - } - return total_len - len; -} - -/* this is a huge hack required to make the PowerPC emulator binary usable - * on Mac OS X. If you define this function as 'static', the emulated kernel - * will panic when attempting to mount the /data partition. - * - * worse, if you do *not* define the function as static on Linux-x86, the - * emulated kernel will also panic !? - * - * I still wonder if this is a compiler bug, or due to some nasty thing the - * emulator does with CPU registers during execution of the translated code. - */ -#if !(defined __APPLE__ && defined __powerpc__) -static -#endif -uint32_t nand_dev_do_cmd(nand_dev_state *s, uint32_t cmd) -{ - uint32_t size; - uint64_t addr; - nand_dev *dev; - - addr = s->addr_low | ((uint64_t)s->addr_high << 32); - size = s->transfer_size; - if(s->dev >= nand_dev_count) - return 0; - dev = nand_devs + s->dev; - - switch(cmd) { - case NAND_CMD_GET_DEV_NAME: - if(size > dev->devname_len) - size = dev->devname_len; - pmemcpy(s->data, dev->devname, size); - return size; - case NAND_CMD_READ: - if(addr >= dev->size) - return 0; - if(size + addr > dev->size) - size = dev->size - addr; - if(dev->fd >= 0) - return nand_dev_read_file(dev, s->data, addr, size); - pmemcpy(s->data, &dev->data[addr], size); - return size; - case NAND_CMD_WRITE: - if(dev->flags & NAND_DEV_FLAG_READ_ONLY) - return 0; - if(addr >= dev->size) - return 0; - if(size + addr > dev->size) - size = dev->size - addr; - if(dev->fd >= 0) - return nand_dev_write_file(dev, s->data, addr, size); - vmemcpy(s->data, &dev->data[addr], size); - return size; - case NAND_CMD_ERASE: - if(dev->flags & NAND_DEV_FLAG_READ_ONLY) - return 0; - if(addr >= dev->size) - return 0; - if(size + addr > dev->size) - size = dev->size - addr; - if(dev->fd >= 0) - return nand_dev_erase_file(dev, addr, size); - memset(&dev->data[addr], 0xff, size); - return size; - case NAND_CMD_BLOCK_BAD_GET: // no bad block support - return 0; - case NAND_CMD_BLOCK_BAD_SET: - if(dev->flags & NAND_DEV_FLAG_READ_ONLY) - return 0; - return 0; - default: - cpu_abort(cpu_single_env, "nand_dev_do_cmd: Bad command %x\n", cmd); - return 0; - } -} - -/* I/O write */ -static void nand_dev_write(void *opaque, target_phys_addr_t offset, uint32_t value) -{ - nand_dev_state *s = (nand_dev_state *)opaque; - - offset -= s->base; - switch (offset) { - case NAND_DEV: - s->dev = value; - if(s->dev >= nand_dev_count) { - cpu_abort(cpu_single_env, "nand_dev_write: Bad dev %x\n", value); - } - break; - case NAND_ADDR_HIGH: - s->addr_high = value; - break; - case NAND_ADDR_LOW: - s->addr_low = value; - break; - case NAND_TRANSFER_SIZE: - s->transfer_size = value; - break; - case NAND_DATA: - s->data = value; - break; - case NAND_COMMAND: - s->result = nand_dev_do_cmd(s, value); - break; - default: - cpu_abort(cpu_single_env, "nand_dev_write: Bad offset %x\n", offset); - break; - } -} - -/* I/O read */ -static uint32_t nand_dev_read(void *opaque, target_phys_addr_t offset) -{ - nand_dev_state *s = (nand_dev_state *)opaque; - nand_dev *dev; - - offset -= s->base; - switch (offset) { - case NAND_VERSION: - return NAND_VERSION_CURRENT; - case NAND_NUM_DEV: - return nand_dev_count; - case NAND_RESULT: - return s->result; - } - - if(s->dev >= nand_dev_count) - return 0; - - dev = nand_devs + s->dev; - - switch (offset) { - case NAND_DEV_FLAGS: - return dev->flags; - - case NAND_DEV_NAME_LEN: - return dev->devname_len; - - case NAND_DEV_PAGE_SIZE: - return dev->page_size; - - case NAND_DEV_EXTRA_SIZE: - return dev->extra_size; - - case NAND_DEV_ERASE_SIZE: - return dev->erase_size; - - case NAND_DEV_SIZE_LOW: - return (uint32_t)dev->size; - - case NAND_DEV_SIZE_HIGH: - return (uint32_t)(dev->size >> 32); - - default: - cpu_abort(cpu_single_env, "nand_dev_read: Bad offset %x\n", offset); - return 0; - } -} - -static CPUReadMemoryFunc *nand_dev_readfn[] = { - nand_dev_read, - nand_dev_read, - nand_dev_read -}; - -static CPUWriteMemoryFunc *nand_dev_writefn[] = { - nand_dev_write, - nand_dev_write, - nand_dev_write -}; - -/* initialize the QFB device */ -void nand_dev_init(uint32_t base) -{ - int iomemtype; - static int instance_id = 0; - nand_dev_state *s; - - s = (nand_dev_state *)qemu_mallocz(sizeof(nand_dev_state)); - iomemtype = cpu_register_io_memory(0, nand_dev_readfn, nand_dev_writefn, s); - cpu_register_physical_memory(base, 0x00000fff, iomemtype); - s->base = base; - - register_savevm( "nand_dev", instance_id++, NAND_DEV_STATE_SAVE_VERSION, - nand_dev_state_save, nand_dev_state_load, s); -} - -static int arg_match(const char *a, const char *b, size_t b_len) -{ - while(*a && b_len--) { - if(*a++ != *b++) - return 0; - } - return b_len == 0; -} - -void nand_add_dev(const char *arg) -{ - uint64_t dev_size = 0; - const char *next_arg; - const char *value; - size_t arg_len, value_len; - nand_dev *new_devs, *dev; - char *devname = NULL; - size_t devname_len = 0; - char *initfilename = NULL; - char *rwfilename = NULL; - int initfd = -1; - int rwfd = -1; - int read_only = 0; - int pad; - ssize_t read_size; - uint32_t page_size = 2048; - uint32_t extra_size = 64; - uint32_t erase_pages = 64; - - while(arg) { - next_arg = strchr(arg, ','); - value = strchr(arg, '='); - if(next_arg != NULL) { - arg_len = next_arg - arg; - next_arg++; - if(value >= next_arg) - value = NULL; - } - else - arg_len = strlen(arg); - if(value != NULL) { - size_t new_arg_len = value - arg; - value_len = arg_len - new_arg_len - 1; - arg_len = new_arg_len; - value++; - } - else - value_len = 0; - - if(devname == NULL) { - if(value != NULL) - goto bad_arg_and_value; - devname_len = arg_len; - devname = malloc(arg_len); - if(devname == NULL) - goto out_of_memory; - memcpy(devname, arg, arg_len); - } - else if(value == NULL) { - if(arg_match("readonly", arg, arg_len)) { - read_only = 1; - } - else { - XLOG("bad arg: %.*s\n", arg_len, arg); - exit(1); - } - } - else { - if(arg_match("size", arg, arg_len)) { - char *ep; - dev_size = strtoull(value, &ep, 0); - if(ep != value + value_len) - goto bad_arg_and_value; - } - else if(arg_match("pagesize", arg, arg_len)) { - char *ep; - page_size = strtoul(value, &ep, 0); - if(ep != value + value_len) - goto bad_arg_and_value; - } - else if(arg_match("extrasize", arg, arg_len)) { - char *ep; - extra_size = strtoul(value, &ep, 0); - if(ep != value + value_len) - goto bad_arg_and_value; - } - else if(arg_match("erasepages", arg, arg_len)) { - char *ep; - erase_pages = strtoul(value, &ep, 0); - if(ep != value + value_len) - goto bad_arg_and_value; - } - else if(arg_match("initfile", arg, arg_len)) { - initfilename = malloc(value_len + 1); - if(initfilename == NULL) - goto out_of_memory; - memcpy(initfilename, value, value_len); - initfilename[value_len] = '\0'; - } - else if(arg_match("file", arg, arg_len)) { - rwfilename = malloc(value_len + 1); - if(rwfilename == NULL) - goto out_of_memory; - memcpy(rwfilename, value, value_len); - rwfilename[value_len] = '\0'; - } - else { - goto bad_arg_and_value; - } - } - - arg = next_arg; - } - - if (rwfilename == NULL) { - /* we create a temporary file to store everything */ - TempFile* tmp = tempfile_create(); - - if (tmp == NULL) { - XLOG("could not create temp file for %.*s NAND disk image: %s", - devname_len, devname, strerror(errno)); - exit(1); - } - rwfilename = (char*) tempfile_path(tmp); - if (VERBOSE_CHECK(init)) - dprint( "mapping '%.*s' NAND image to %s", devname_len, devname, rwfilename); - } - - if(rwfilename) { - rwfd = open(rwfilename, O_BINARY | (read_only ? O_RDONLY : O_RDWR)); - if(rwfd < 0 && read_only) { - XLOG("could not open file %s, %s\n", rwfilename, strerror(errno)); - exit(1); - } - /* this could be a writable temporary file. use atexit_close_fd to ensure - * that it is properly cleaned up at exit on Win32 - */ - if (!read_only) - atexit_close_fd(rwfd); - } - - if(initfilename) { - initfd = open(initfilename, O_BINARY | O_RDONLY); - if(initfd < 0) { - XLOG("could not open file %s, %s\n", initfilename, strerror(errno)); - exit(1); - } - if(dev_size == 0) { - dev_size = lseek(initfd, 0, SEEK_END); - lseek(initfd, 0, SEEK_SET); - } - } - - new_devs = realloc(nand_devs, sizeof(nand_devs[0]) * (nand_dev_count + 1)); - if(new_devs == NULL) - goto out_of_memory; - nand_devs = new_devs; - dev = &new_devs[nand_dev_count]; - - dev->page_size = page_size; - dev->extra_size = extra_size; - dev->erase_size = erase_pages * (page_size + extra_size); - pad = dev_size % dev->erase_size; - if (pad != 0) { - dev_size += (dev->erase_size - pad); - XLOG("rounding devsize up to a full eraseunit, now %llx\n", dev_size); - } - dev->devname = devname; - dev->devname_len = devname_len; - dev->size = dev_size; - dev->data = malloc(dev->erase_size); - if(dev->data == NULL) - goto out_of_memory; - dev->flags = read_only ? NAND_DEV_FLAG_READ_ONLY : 0; - - if (initfd >= 0) { - do { - read_size = do_read(initfd, dev->data, dev->erase_size); - if(read_size < 0) { - XLOG("could not read file %s, %s\n", initfilename, strerror(errno)); - exit(1); - } - if(do_write(rwfd, dev->data, read_size) != read_size) { - XLOG("could not write file %s, %s\n", initfilename, strerror(errno)); - exit(1); - } - } while(read_size == dev->erase_size); - close(initfd); - } - dev->fd = rwfd; - - nand_dev_count++; - - return; - -out_of_memory: - XLOG("out of memory\n"); - exit(1); - -bad_arg_and_value: - XLOG("bad arg: %.*s=%.*s\n", arg_len, arg, value_len, value); - exit(1); -} - -- cgit v1.1