* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#include "qemu-common.h"
+#include "qemu/osdep.h"
+#include "qapi/error.h"
#include "hw/hw.h"
#include "hw/block/flash.h"
#include "hw/irq.h"
-#include "sysemu/blockdev.h"
+#include "sysemu/block-backend.h"
#include "exec/memory.h"
-#include "exec/address-spaces.h"
#include "hw/sysbus.h"
#include "qemu/error-report.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
/* 11 for 2kB-page OneNAND ("2nd generation") and 10 for 1kB-page chips */
#define PAGE_SHIFT 11
hwaddr base;
qemu_irq intr;
qemu_irq rdy;
- BlockDriverState *bdrv;
- BlockDriverState *bdrv_cur;
+ BlockBackend *blk;
+ BlockBackend *blk_cur;
uint8_t *image;
uint8_t *otp;
uint8_t *current;
qemu_set_irq(s->intr, ((s->intstatus >> 15) ^ (~s->config[0] >> 6)) & 1);
}
-static void onenand_pre_save(void *opaque)
+static int onenand_pre_save(void *opaque)
{
OneNANDState *s = opaque;
if (s->current == s->otp) {
} else {
s->current_direction = 0;
}
+
+ return 0;
}
static int onenand_post_load(void *opaque, int version_id)
s->wpstatus = 0x0002;
s->cycle = 0;
s->otpmode = 0;
- s->bdrv_cur = s->bdrv;
+ s->blk_cur = s->blk;
s->current = s->image;
s->secs_cur = s->secs;
/* Lock the whole flash */
memset(s->blockwp, ONEN_LOCK_LOCKED, s->blocks);
- if (s->bdrv_cur && bdrv_read(s->bdrv_cur, 0, s->boot[0], 8) < 0) {
+ if (s->blk_cur && blk_pread(s->blk_cur, 0, s->boot[0],
+ 8 << BDRV_SECTOR_BITS) < 0) {
hw_error("%s: Loading the BootRAM failed.\n", __func__);
}
}
static inline int onenand_load_main(OneNANDState *s, int sec, int secn,
void *dest)
{
- if (s->bdrv_cur)
- return bdrv_read(s->bdrv_cur, sec, dest, secn) < 0;
- else if (sec + secn > s->secs_cur)
+ assert(UINT32_MAX >> BDRV_SECTOR_BITS > sec);
+ assert(UINT32_MAX >> BDRV_SECTOR_BITS > secn);
+ if (s->blk_cur) {
+ return blk_pread(s->blk_cur, sec << BDRV_SECTOR_BITS, dest,
+ secn << BDRV_SECTOR_BITS) < 0;
+ } else if (sec + secn > s->secs_cur) {
return 1;
+ }
memcpy(dest, s->current + (sec << 9), secn << 9);
int result = 0;
if (secn > 0) {
- uint32_t size = (uint32_t)secn * 512;
+ uint32_t size = secn << BDRV_SECTOR_BITS;
+ uint32_t offset = sec << BDRV_SECTOR_BITS;
+ assert(UINT32_MAX >> BDRV_SECTOR_BITS > sec);
+ assert(UINT32_MAX >> BDRV_SECTOR_BITS > secn);
const uint8_t *sp = (const uint8_t *)src;
uint8_t *dp = 0;
- if (s->bdrv_cur) {
+ if (s->blk_cur) {
dp = g_malloc(size);
- if (!dp || bdrv_read(s->bdrv_cur, sec, dp, secn) < 0) {
+ if (!dp || blk_pread(s->blk_cur, offset, dp, size) < 0) {
result = 1;
}
} else {
if (sec + secn > s->secs_cur) {
result = 1;
} else {
- dp = (uint8_t *)s->current + (sec << 9);
+ dp = (uint8_t *)s->current + offset;
}
}
if (!result) {
for (i = 0; i < size; i++) {
dp[i] &= sp[i];
}
- if (s->bdrv_cur) {
- result = bdrv_write(s->bdrv_cur, sec, dp, secn) < 0;
+ if (s->blk_cur) {
+ result = blk_pwrite(s->blk_cur, offset, dp, size, 0) < 0;
}
}
- if (dp && s->bdrv_cur) {
+ if (dp && s->blk_cur) {
g_free(dp);
}
}
{
uint8_t buf[512];
- if (s->bdrv_cur) {
- if (bdrv_read(s->bdrv_cur, s->secs_cur + (sec >> 5), buf, 1) < 0)
+ if (s->blk_cur) {
+ uint32_t offset = (s->secs_cur + (sec >> 5)) << BDRV_SECTOR_BITS;
+ if (blk_pread(s->blk_cur, offset, buf, BDRV_SECTOR_SIZE) < 0) {
return 1;
+ }
memcpy(dest, buf + ((sec & 31) << 4), secn << 4);
- } else if (sec + secn > s->secs_cur)
+ } else if (sec + secn > s->secs_cur) {
return 1;
- else
+ } else {
memcpy(dest, s->current + (s->secs_cur << 9) + (sec << 4), secn << 4);
-
+ }
+
return 0;
}
if (secn > 0) {
const uint8_t *sp = (const uint8_t *)src;
uint8_t *dp = 0, *dpp = 0;
- if (s->bdrv_cur) {
+ uint32_t offset = (s->secs_cur + (sec >> 5)) << BDRV_SECTOR_BITS;
+ assert(UINT32_MAX >> BDRV_SECTOR_BITS > s->secs_cur + (sec >> 5));
+ if (s->blk_cur) {
dp = g_malloc(512);
- if (!dp || bdrv_read(s->bdrv_cur,
- s->secs_cur + (sec >> 5),
- dp, 1) < 0) {
+ if (!dp
+ || blk_pread(s->blk_cur, offset, dp, BDRV_SECTOR_SIZE) < 0) {
result = 1;
} else {
dpp = dp + ((sec & 31) << 4);
for (i = 0; i < (secn << 4); i++) {
dpp[i] &= sp[i];
}
- if (s->bdrv_cur) {
- result = bdrv_write(s->bdrv_cur, s->secs_cur + (sec >> 5),
- dp, 1) < 0;
+ if (s->blk_cur) {
+ result = blk_pwrite(s->blk_cur, offset, dp,
+ BDRV_SECTOR_SIZE, 0) < 0;
}
}
g_free(dp);
static inline int onenand_erase(OneNANDState *s, int sec, int num)
{
uint8_t *blankbuf, *tmpbuf;
+
blankbuf = g_malloc(512);
- if (!blankbuf) {
- return 1;
- }
tmpbuf = g_malloc(512);
- if (!tmpbuf) {
- g_free(blankbuf);
- return 1;
- }
memset(blankbuf, 0xff, 512);
for (; num > 0; num--, sec++) {
- if (s->bdrv_cur) {
+ if (s->blk_cur) {
int erasesec = s->secs_cur + (sec >> 5);
- if (bdrv_write(s->bdrv_cur, sec, blankbuf, 1) < 0) {
+ if (blk_pwrite(s->blk_cur, sec << BDRV_SECTOR_BITS, blankbuf,
+ BDRV_SECTOR_SIZE, 0) < 0) {
goto fail;
}
- if (bdrv_read(s->bdrv_cur, erasesec, tmpbuf, 1) < 0) {
+ if (blk_pread(s->blk_cur, erasesec << BDRV_SECTOR_BITS, tmpbuf,
+ BDRV_SECTOR_SIZE) < 0) {
goto fail;
}
memcpy(tmpbuf + ((sec & 31) << 4), blankbuf, 1 << 4);
- if (bdrv_write(s->bdrv_cur, erasesec, tmpbuf, 1) < 0) {
+ if (blk_pwrite(s->blk_cur, erasesec << BDRV_SECTOR_BITS, tmpbuf,
+ BDRV_SECTOR_SIZE, 0) < 0) {
goto fail;
}
} else {
s->intstatus |= ONEN_INT;
for (b = 0; b < s->blocks; b ++) {
- if (b >= s->blocks) {
- s->status |= ONEN_ERR_CMD;
- break;
- }
if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN)
break;
case 0x65: /* OTP Access */
s->intstatus |= ONEN_INT;
- s->bdrv_cur = NULL;
+ s->blk_cur = NULL;
s->current = s->otp;
s->secs_cur = 1 << (BLOCK_SHIFT - 9);
s->addr[ONEN_BUF_BLOCK] = 0;
default:
s->status |= ONEN_ERR_CMD;
s->intstatus |= ONEN_INT;
- fprintf(stderr, "%s: unknown OneNAND command %x\n",
- __func__, s->command);
+ qemu_log_mask(LOG_GUEST_ERROR, "unknown OneNAND command %x\n",
+ s->command);
}
onenand_intr_update(s);
int offset = addr >> s->shift;
switch (offset) {
- case 0x0000 ... 0xc000:
+ case 0x0000 ... 0xbffe:
return lduw_le_p(s->boot[0] + addr);
case 0xf000: /* Manufacturer ID */
case 0xff02: /* ECC Result of spare area data */
case 0xff03: /* ECC Result of main area data */
case 0xff04: /* ECC Result of spare area data */
- hw_error("%s: imeplement ECC\n", __FUNCTION__);
+ qemu_log_mask(LOG_UNIMP,
+ "onenand: ECC result registers unimplemented\n");
return 0x0000;
}
- fprintf(stderr, "%s: unknown OneNAND register %x\n",
- __FUNCTION__, offset);
+ qemu_log_mask(LOG_GUEST_ERROR, "read of unknown OneNAND register 0x%x\n",
+ offset);
return 0;
}
break;
default:
- fprintf(stderr, "%s: unknown OneNAND boot command %"PRIx64"\n",
- __FUNCTION__, value);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "unknown OneNAND boot command %" PRIx64 "\n",
+ value);
}
break;
break;
default:
- fprintf(stderr, "%s: unknown OneNAND register %x\n",
- __FUNCTION__, offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "write to unknown OneNAND register 0x%x\n",
+ offset);
}
}
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static int onenand_initfn(SysBusDevice *sbd)
+static void onenand_realize(DeviceState *dev, Error **errp)
{
- DeviceState *dev = DEVICE(sbd);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
OneNANDState *s = ONE_NAND(dev);
uint32_t size = 1 << (24 + ((s->id.dev >> 4) & 7));
void *ram;
+ Error *local_err = NULL;
s->base = (hwaddr)-1;
s->rdy = NULL;
? (1 << (6 + ((s->id.dev >> 4) & 7))) : 0;
memory_region_init_io(&s->iomem, OBJECT(s), &onenand_ops, s, "onenand",
0x10000 << s->shift);
- if (!s->bdrv) {
+ if (!s->blk) {
s->image = memset(g_malloc(size + (size >> 5)),
0xff, size + (size >> 5));
} else {
- if (bdrv_is_read_only(s->bdrv)) {
- error_report("Can't use a read-only drive");
- return -1;
+ if (blk_is_read_only(s->blk)) {
+ error_setg(errp, "Can't use a read-only drive");
+ return;
}
- s->bdrv_cur = s->bdrv;
+ blk_set_perm(s->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE,
+ BLK_PERM_ALL, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ s->blk_cur = s->blk;
}
s->otp = memset(g_malloc((64 + 2) << PAGE_SHIFT),
0xff, (64 + 2) << PAGE_SHIFT);
- memory_region_init_ram(&s->ram, OBJECT(s), "onenand.ram",
- 0xc000 << s->shift, &error_abort);
+ memory_region_init_ram_nomigrate(&s->ram, OBJECT(s), "onenand.ram",
+ 0xc000 << s->shift, &error_fatal);
vmstate_register_ram_global(&s->ram);
ram = memory_region_get_ram_ptr(&s->ram);
s->boot[0] = ram + (0x0000 << s->shift);
| ((s->id.dev & 0xff) << 8)
| (s->id.ver & 0xff),
&vmstate_onenand, s);
- return 0;
}
static Property onenand_properties[] = {
DEFINE_PROP_UINT16("device_id", OneNANDState, id.dev, 0),
DEFINE_PROP_UINT16("version_id", OneNANDState, id.ver, 0),
DEFINE_PROP_INT32("shift", OneNANDState, shift, 0),
- DEFINE_PROP_DRIVE("drive", OneNANDState, bdrv),
+ DEFINE_PROP_DRIVE("drive", OneNANDState, blk),
DEFINE_PROP_END_OF_LIST(),
};
static void onenand_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = onenand_initfn;
+ dc->realize = onenand_realize;
dc->reset = onenand_system_reset;
dc->props = onenand_properties;
}