diff --git a/hw/arm_gic.c b/hw/arm_gic.c index 7f67c5276d..54e99f4d66 100644 --- a/hw/arm_gic.c +++ b/hw/arm_gic.c @@ -650,6 +650,79 @@ static void gic_reset(gic_state *s) #endif } +static void gic_save(QEMUFile *f, void *opaque) +{ + gic_state *s = (gic_state *)opaque; + int i; + int j; + + qemu_put_be32(f, s->enabled); + for (i = 0; i < NCPU; i++) { + qemu_put_be32(f, s->cpu_enabled[i]); +#ifndef NVIC + qemu_put_be32(f, s->irq_target[i]); +#endif + for (j = 0; j < 32; j++) + qemu_put_be32(f, s->priority1[j][i]); + for (j = 0; j < GIC_NIRQ; j++) + qemu_put_be32(f, s->last_active[j][i]); + qemu_put_be32(f, s->priority_mask[i]); + qemu_put_be32(f, s->running_irq[i]); + qemu_put_be32(f, s->running_priority[i]); + qemu_put_be32(f, s->current_pending[i]); + } + for (i = 0; i < GIC_NIRQ - 32; i++) { + qemu_put_be32(f, s->priority2[i]); + } + for (i = 0; i < GIC_NIRQ; i++) { + qemu_put_byte(f, s->irq_state[i].enabled); + qemu_put_byte(f, s->irq_state[i].pending); + qemu_put_byte(f, s->irq_state[i].active); + qemu_put_byte(f, s->irq_state[i].level); + qemu_put_byte(f, s->irq_state[i].model); + qemu_put_byte(f, s->irq_state[i].trigger); + } +} + +static int gic_load(QEMUFile *f, void *opaque, int version_id) +{ + gic_state *s = (gic_state *)opaque; + int i; + int j; + + if (version_id != 1) + return -EINVAL; + + s->enabled = qemu_get_be32(f); + for (i = 0; i < NCPU; i++) { + s->cpu_enabled[i] = qemu_get_be32(f); +#ifndef NVIC + s->irq_target[i] = qemu_get_be32(f); +#endif + for (j = 0; j < 32; j++) + s->priority1[j][i] = qemu_get_be32(f); + for (j = 0; j < GIC_NIRQ; j++) + s->last_active[j][i] = qemu_get_be32(f); + s->priority_mask[i] = qemu_get_be32(f); + s->running_irq[i] = qemu_get_be32(f); + s->running_priority[i] = qemu_get_be32(f); + s->current_pending[i] = qemu_get_be32(f); + } + for (i = 0; i < GIC_NIRQ - 32; i++) { + s->priority2[i] = qemu_get_be32(f); + } + for (i = 0; i < GIC_NIRQ; i++) { + s->irq_state[i].enabled = qemu_get_byte(f); + s->irq_state[i].pending = qemu_get_byte(f); + s->irq_state[i].active = qemu_get_byte(f); + s->irq_state[i].level = qemu_get_byte(f); + s->irq_state[i].model = qemu_get_byte(f); + s->irq_state[i].trigger = qemu_get_byte(f); + } + + return 0; +} + static gic_state *gic_init(uint32_t base, qemu_irq *parent_irq) { gic_state *s; @@ -669,5 +742,6 @@ static gic_state *gic_init(uint32_t base, qemu_irq *parent_irq) iomemtype); s->base = base; gic_reset(s); + register_savevm("arm_gic", -1, 1, gic_save, gic_load, s); return s; } diff --git a/hw/arm_timer.c b/hw/arm_timer.c index 540d3dea1b..5150fe9a5a 100644 --- a/hw/arm_timer.c +++ b/hw/arm_timer.c @@ -143,6 +143,29 @@ static void arm_timer_tick(void *opaque) arm_timer_update(s); } +static void arm_timer_save(QEMUFile *f, void *opaque) +{ + arm_timer_state *s = (arm_timer_state *)opaque; + qemu_put_be32(f, s->control); + qemu_put_be32(f, s->limit); + qemu_put_be32(f, s->int_level); + qemu_put_ptimer(f, s->timer); +} + +static int arm_timer_load(QEMUFile *f, void *opaque, int version_id) +{ + arm_timer_state *s = (arm_timer_state *)opaque; + + if (version_id != 1) + return -EINVAL; + + s->control = qemu_get_be32(f); + s->limit = qemu_get_be32(f); + s->int_level = qemu_get_be32(f); + qemu_get_ptimer(f, s->timer); + return 0; +} + static void *arm_timer_init(uint32_t freq, qemu_irq irq) { arm_timer_state *s; @@ -155,7 +178,7 @@ static void *arm_timer_init(uint32_t freq, qemu_irq irq) bh = qemu_bh_new(arm_timer_tick, s); s->timer = ptimer_init(bh); - /* ??? Save/restore. */ + register_savevm("arm_timer", -1, 1, arm_timer_save, arm_timer_load, s); return s; } @@ -218,6 +241,25 @@ static CPUWriteMemoryFunc *sp804_writefn[] = { sp804_write }; +static void sp804_save(QEMUFile *f, void *opaque) +{ + sp804_state *s = (sp804_state *)opaque; + qemu_put_be32(f, s->level[0]); + qemu_put_be32(f, s->level[1]); +} + +static int sp804_load(QEMUFile *f, void *opaque, int version_id) +{ + sp804_state *s = (sp804_state *)opaque; + + if (version_id != 1) + return -EINVAL; + + s->level[0] = qemu_get_be32(f); + s->level[1] = qemu_get_be32(f); + return 0; +} + void sp804_init(uint32_t base, qemu_irq irq) { int iomemtype; @@ -235,7 +277,7 @@ void sp804_init(uint32_t base, qemu_irq irq) iomemtype = cpu_register_io_memory(0, sp804_readfn, sp804_writefn, s); cpu_register_physical_memory(base, 0x00001000, iomemtype); - /* ??? Save/restore. */ + register_savevm("sp804", -1, 1, sp804_save, sp804_load, s); } @@ -303,6 +345,7 @@ void icp_pit_init(uint32_t base, qemu_irq *pic, int irq) iomemtype = cpu_register_io_memory(0, icp_pit_readfn, icp_pit_writefn, s); cpu_register_physical_memory(base, 0x00001000, iomemtype); - /* ??? Save/restore. */ + /* This device has no state to save/restore. The component timers will + save themselves. */ } diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c index 37596d0ccb..26e4c2f2fd 100644 --- a/hw/armv7m_nvic.c +++ b/hw/armv7m_nvic.c @@ -368,6 +368,31 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value) } } +static void nvic_save(QEMUFile *f, void *opaque) +{ + nvic_state *s = (nvic_state *)opaque; + + qemu_put_be32(f, s->systick.control); + qemu_put_be32(f, s->systick.reload); + qemu_put_be64(f, s->systick.tick); + qemu_put_timer(f, s->systick.timer); +} + +static int nvic_load(QEMUFile *f, void *opaque, int version_id) +{ + nvic_state *s = (nvic_state *)opaque; + + if (version_id != 1) + return -EINVAL; + + s->systick.control = qemu_get_be32(f); + s->systick.reload = qemu_get_be32(f); + s->systick.tick = qemu_get_be64(f); + qemu_get_timer(f, s->systick.timer); + + return 0; +} + qemu_irq *armv7m_nvic_init(CPUState *env) { nvic_state *s; @@ -381,5 +406,6 @@ qemu_irq *armv7m_nvic_init(CPUState *env) if (env->v7m.nvic) cpu_abort(env, "CPU can only have one NVIC\n"); env->v7m.nvic = s; + register_savevm("armv7m_nvic", -1, 1, nvic_save, nvic_load, s); return s->gic->in; } diff --git a/hw/pl011.c b/hw/pl011.c index 6676644991..bbef0a4c6d 100644 --- a/hw/pl011.c +++ b/hw/pl011.c @@ -238,6 +238,57 @@ static CPUWriteMemoryFunc *pl011_writefn[] = { pl011_write }; +static void pl011_save(QEMUFile *f, void *opaque) +{ + pl011_state *s = (pl011_state *)opaque; + int i; + + qemu_put_be32(f, s->readbuff); + qemu_put_be32(f, s->flags); + qemu_put_be32(f, s->lcr); + qemu_put_be32(f, s->cr); + qemu_put_be32(f, s->dmacr); + qemu_put_be32(f, s->int_enabled); + qemu_put_be32(f, s->int_level); + for (i = 0; i < 16; i++) + qemu_put_be32(f, s->read_fifo[i]); + qemu_put_be32(f, s->ilpr); + qemu_put_be32(f, s->ibrd); + qemu_put_be32(f, s->fbrd); + qemu_put_be32(f, s->ifl); + qemu_put_be32(f, s->read_pos); + qemu_put_be32(f, s->read_count); + qemu_put_be32(f, s->read_trigger); +} + +static int pl011_load(QEMUFile *f, void *opaque, int version_id) +{ + pl011_state *s = (pl011_state *)opaque; + int i; + + if (version_id != 1) + return -EINVAL; + + s->readbuff = qemu_get_be32(f); + s->flags = qemu_get_be32(f); + s->lcr = qemu_get_be32(f); + s->cr = qemu_get_be32(f); + s->dmacr = qemu_get_be32(f); + s->int_enabled = qemu_get_be32(f); + s->int_level = qemu_get_be32(f); + for (i = 0; i < 16; i++) + s->read_fifo[i] = qemu_get_be32(f); + s->ilpr = qemu_get_be32(f); + s->ibrd = qemu_get_be32(f); + s->fbrd = qemu_get_be32(f); + s->ifl = qemu_get_be32(f); + s->read_pos = qemu_get_be32(f); + s->read_count = qemu_get_be32(f); + s->read_trigger = qemu_get_be32(f); + + return 0; +} + void pl011_init(uint32_t base, qemu_irq irq, CharDriverState *chr, enum pl011_type type) { @@ -260,6 +311,6 @@ void pl011_init(uint32_t base, qemu_irq irq, qemu_chr_add_handlers(chr, pl011_can_receive, pl011_receive, pl011_event, s); } - /* ??? Save/restore. */ + register_savevm("pl011_uart", -1, 1, pl011_save, pl011_load, s); } diff --git a/hw/pl022.c b/hw/pl022.c index 54a581b882..a9d20c517b 100644 --- a/hw/pl022.c +++ b/hw/pl022.c @@ -244,6 +244,55 @@ static CPUWriteMemoryFunc *pl022_writefn[] = { pl022_write }; +static void pl022_save(QEMUFile *f, void *opaque) +{ + pl022_state *s = (pl022_state *)opaque; + int i; + + qemu_put_be32(f, s->cr0); + qemu_put_be32(f, s->cr1); + qemu_put_be32(f, s->bitmask); + qemu_put_be32(f, s->sr); + qemu_put_be32(f, s->cpsr); + qemu_put_be32(f, s->is); + qemu_put_be32(f, s->im); + qemu_put_be32(f, s->tx_fifo_head); + qemu_put_be32(f, s->rx_fifo_head); + qemu_put_be32(f, s->tx_fifo_len); + qemu_put_be32(f, s->rx_fifo_len); + for (i = 0; i < 8; i++) { + qemu_put_be16(f, s->tx_fifo[i]); + qemu_put_be16(f, s->rx_fifo[i]); + } +} + +static int pl022_load(QEMUFile *f, void *opaque, int version_id) +{ + pl022_state *s = (pl022_state *)opaque; + int i; + + if (version_id != 1) + return -EINVAL; + + s->cr0 = qemu_get_be32(f); + s->cr1 = qemu_get_be32(f); + s->bitmask = qemu_get_be32(f); + s->sr = qemu_get_be32(f); + s->cpsr = qemu_get_be32(f); + s->is = qemu_get_be32(f); + s->im = qemu_get_be32(f); + s->tx_fifo_head = qemu_get_be32(f); + s->rx_fifo_head = qemu_get_be32(f); + s->tx_fifo_len = qemu_get_be32(f); + s->rx_fifo_len = qemu_get_be32(f); + for (i = 0; i < 8; i++) { + s->tx_fifo[i] = qemu_get_be16(f); + s->rx_fifo[i] = qemu_get_be16(f); + } + + return 0; +} + void pl022_init(uint32_t base, qemu_irq irq, int (*xfer_cb)(void *, int), void * opaque) { @@ -259,7 +308,7 @@ void pl022_init(uint32_t base, qemu_irq irq, int (*xfer_cb)(void *, int), s->xfer_cb = xfer_cb; s->opaque = opaque; pl022_reset(s); - /* ??? Save/restore. */ + register_savevm("pl022_ssp", -1, 1, pl022_save, pl022_load, s); } diff --git a/hw/pl061.c b/hw/pl061.c index 3ac0a4c100..6db5e393b1 100644 --- a/hw/pl061.c +++ b/hw/pl061.c @@ -240,6 +240,62 @@ static CPUWriteMemoryFunc *pl061_writefn[] = { pl061_write }; +static void pl061_save(QEMUFile *f, void *opaque) +{ + pl061_state *s = (pl061_state *)opaque; + + qemu_put_be32(f, s->locked); + qemu_put_be32(f, s->data); + qemu_put_be32(f, s->old_data); + qemu_put_be32(f, s->dir); + qemu_put_be32(f, s->isense); + qemu_put_be32(f, s->ibe); + qemu_put_be32(f, s->iev); + qemu_put_be32(f, s->im); + qemu_put_be32(f, s->istate); + qemu_put_be32(f, s->afsel); + qemu_put_be32(f, s->dr2r); + qemu_put_be32(f, s->dr4r); + qemu_put_be32(f, s->dr8r); + qemu_put_be32(f, s->odr); + qemu_put_be32(f, s->pur); + qemu_put_be32(f, s->pdr); + qemu_put_be32(f, s->slr); + qemu_put_be32(f, s->den); + qemu_put_be32(f, s->cr); + qemu_put_be32(f, s->float_high); +} + +static int pl061_load(QEMUFile *f, void *opaque, int version_id) +{ + pl061_state *s = (pl061_state *)opaque; + if (version_id != 1) + return -EINVAL; + + s->locked = qemu_get_be32(f); + s->data = qemu_get_be32(f); + s->old_data = qemu_get_be32(f); + s->dir = qemu_get_be32(f); + s->isense = qemu_get_be32(f); + s->ibe = qemu_get_be32(f); + s->iev = qemu_get_be32(f); + s->im = qemu_get_be32(f); + s->istate = qemu_get_be32(f); + s->afsel = qemu_get_be32(f); + s->dr2r = qemu_get_be32(f); + s->dr4r = qemu_get_be32(f); + s->dr8r = qemu_get_be32(f); + s->odr = qemu_get_be32(f); + s->pur = qemu_get_be32(f); + s->pdr = qemu_get_be32(f); + s->slr = qemu_get_be32(f); + s->den = qemu_get_be32(f); + s->cr = qemu_get_be32(f); + s->float_high = qemu_get_be32(f); + + return 0; +} + /* Returns an array of inputs. */ qemu_irq *pl061_init(uint32_t base, qemu_irq irq, qemu_irq **out) { @@ -256,7 +312,7 @@ qemu_irq *pl061_init(uint32_t base, qemu_irq irq, qemu_irq **out) if (out) *out = s->out; - /* ??? Save/restore. */ + register_savevm("pl061_gpio", -1, 1, pl061_save, pl061_load, s); return qemu_allocate_irqs(pl061_set_irq, s, 8); } diff --git a/hw/ssd0303.c b/hw/ssd0303.c index 1b178f2621..7f03237683 100644 --- a/hw/ssd0303.c +++ b/hw/ssd0303.c @@ -261,6 +261,49 @@ static void ssd0303_invalidate_display(void * opaque) s->redraw = 1; } +static void ssd0303_save(QEMUFile *f, void *opaque) +{ + ssd0303_state *s = (ssd0303_state *)opaque; + + qemu_put_be32(f, s->row); + qemu_put_be32(f, s->col); + qemu_put_be32(f, s->start_line); + qemu_put_be32(f, s->mirror); + qemu_put_be32(f, s->flash); + qemu_put_be32(f, s->enabled); + qemu_put_be32(f, s->inverse); + qemu_put_be32(f, s->redraw); + qemu_put_be32(f, s->mode); + qemu_put_be32(f, s->cmd_state); + qemu_put_buffer(f, s->framebuffer, sizeof(s->framebuffer)); + + i2c_slave_save(f, &s->i2c); +} + +static int ssd0303_load(QEMUFile *f, void *opaque, int version_id) +{ + ssd0303_state *s = (ssd0303_state *)opaque; + + if (version_id != 1) + return -EINVAL; + + s->row = qemu_get_be32(f); + s->col = qemu_get_be32(f); + s->start_line = qemu_get_be32(f); + s->mirror = qemu_get_be32(f); + s->flash = qemu_get_be32(f); + s->enabled = qemu_get_be32(f); + s->inverse = qemu_get_be32(f); + s->redraw = qemu_get_be32(f); + s->mode = qemu_get_be32(f); + s->cmd_state = qemu_get_be32(f); + qemu_get_buffer(f, s->framebuffer, sizeof(s->framebuffer)); + + i2c_slave_load(f, &s->i2c); + + return 0; +} + void ssd0303_init(DisplayState *ds, i2c_bus *bus, int address) { ssd0303_state *s; @@ -274,4 +317,5 @@ void ssd0303_init(DisplayState *ds, i2c_bus *bus, int address) ssd0303_invalidate_display, NULL, NULL, s); qemu_console_resize(s->console, 96 * MAGNIFY, 16 * MAGNIFY); + register_savevm("ssd0303_oled", -1, 1, ssd0303_save, ssd0303_load, s); } diff --git a/hw/ssd0323.c b/hw/ssd0323.c index 3071596f0b..11afca0c63 100644 --- a/hw/ssd0323.c +++ b/hw/ssd0323.c @@ -273,6 +273,53 @@ static void ssd0323_cd(void *opaque, int n, int level) s->mode = level ? SSD0323_DATA : SSD0323_CMD; } +static void ssd0323_save(QEMUFile *f, void *opaque) +{ + ssd0323_state *s = (ssd0323_state *)opaque; + int i; + + qemu_put_be32(f, s->cmd_len); + qemu_put_be32(f, s->cmd); + for (i = 0; i < 8; i++) + qemu_put_be32(f, s->cmd_data[i]); + qemu_put_be32(f, s->row); + qemu_put_be32(f, s->row_start); + qemu_put_be32(f, s->row_end); + qemu_put_be32(f, s->col); + qemu_put_be32(f, s->col_start); + qemu_put_be32(f, s->col_end); + qemu_put_be32(f, s->redraw); + qemu_put_be32(f, s->remap); + qemu_put_be32(f, s->mode); + qemu_put_buffer(f, s->framebuffer, sizeof(s->framebuffer)); +} + +static int ssd0323_load(QEMUFile *f, void *opaque, int version_id) +{ + ssd0323_state *s = (ssd0323_state *)opaque; + int i; + + if (version_id != 1) + return -EINVAL; + + s->cmd_len = qemu_get_be32(f); + s->cmd = qemu_get_be32(f); + for (i = 0; i < 8; i++) + s->cmd_data[i] = qemu_get_be32(f); + s->row = qemu_get_be32(f); + s->row_start = qemu_get_be32(f); + s->row_end = qemu_get_be32(f); + s->col = qemu_get_be32(f); + s->col_start = qemu_get_be32(f); + s->col_end = qemu_get_be32(f); + s->redraw = qemu_get_be32(f); + s->remap = qemu_get_be32(f); + s->mode = qemu_get_be32(f); + qemu_get_buffer(f, s->framebuffer, sizeof(s->framebuffer)); + + return 0; +} + void *ssd0323_init(DisplayState *ds, qemu_irq *cmd_p) { ssd0323_state *s; @@ -290,5 +337,7 @@ void *ssd0323_init(DisplayState *ds, qemu_irq *cmd_p) cmd = qemu_allocate_irqs(ssd0323_cd, s, 1); *cmd_p = *cmd; + register_savevm("ssd0323_oled", -1, 1, ssd0323_save, ssd0323_load, s); + return s; } diff --git a/hw/ssi-sd.c b/hw/ssi-sd.c index 8b45fc4d1d..1c57f1f2d8 100644 --- a/hw/ssi-sd.c +++ b/hw/ssi-sd.c @@ -190,6 +190,43 @@ int ssi_sd_xfer(void *opaque, int val) return 0xff; } +static void ssi_sd_save(QEMUFile *f, void *opaque) +{ + ssi_sd_state *s = (ssi_sd_state *)opaque; + int i; + + qemu_put_be32(f, s->mode); + qemu_put_be32(f, s->cmd); + for (i = 0; i < 4; i++) + qemu_put_be32(f, s->cmdarg[i]); + for (i = 0; i < 5; i++) + qemu_put_be32(f, s->response[i]); + qemu_put_be32(f, s->arglen); + qemu_put_be32(f, s->response_pos); + qemu_put_be32(f, s->stopping); +} + +static int ssi_sd_load(QEMUFile *f, void *opaque, int version_id) +{ + ssi_sd_state *s = (ssi_sd_state *)opaque; + int i; + + if (version_id != 1) + return -EINVAL; + + s->mode = qemu_get_be32(f); + s->cmd = qemu_get_be32(f); + for (i = 0; i < 4; i++) + s->cmdarg[i] = qemu_get_be32(f); + for (i = 0; i < 5; i++) + s->response[i] = qemu_get_be32(f); + s->arglen = qemu_get_be32(f); + s->response_pos = qemu_get_be32(f); + s->stopping = qemu_get_be32(f); + + return 0; +} + void *ssi_sd_init(BlockDriverState *bs) { ssi_sd_state *s; @@ -197,6 +234,7 @@ void *ssi_sd_init(BlockDriverState *bs) s = (ssi_sd_state *)qemu_mallocz(sizeof(ssi_sd_state)); s->mode = SSI_SD_CMD; s->sd = sd_init(bs, 1); + register_savevm("ssi_sd", -1, 1, ssi_sd_save, ssi_sd_load, s); return s; } diff --git a/hw/stellaris.c b/hw/stellaris.c index a32f86fe90..999cb50593 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -286,6 +286,65 @@ static CPUWriteMemoryFunc *gptm_writefn[] = { gptm_write }; +static void gptm_save(QEMUFile *f, void *opaque) +{ + gptm_state *s = (gptm_state *)opaque; + + qemu_put_be32(f, s->config); + qemu_put_be32(f, s->mode[0]); + qemu_put_be32(f, s->mode[1]); + qemu_put_be32(f, s->control); + qemu_put_be32(f, s->state); + qemu_put_be32(f, s->mask); + qemu_put_be32(f, s->mode[0]); + qemu_put_be32(f, s->mode[0]); + qemu_put_be32(f, s->load[0]); + qemu_put_be32(f, s->load[1]); + qemu_put_be32(f, s->match[0]); + qemu_put_be32(f, s->match[1]); + qemu_put_be32(f, s->prescale[0]); + qemu_put_be32(f, s->prescale[1]); + qemu_put_be32(f, s->match_prescale[0]); + qemu_put_be32(f, s->match_prescale[1]); + qemu_put_be32(f, s->rtc); + qemu_put_be64(f, s->tick[0]); + qemu_put_be64(f, s->tick[1]); + qemu_put_timer(f, s->timer[0]); + qemu_put_timer(f, s->timer[1]); +} + +static int gptm_load(QEMUFile *f, void *opaque, int version_id) +{ + gptm_state *s = (gptm_state *)opaque; + + if (version_id != 1) + return -EINVAL; + + s->config = qemu_get_be32(f); + s->mode[0] = qemu_get_be32(f); + s->mode[1] = qemu_get_be32(f); + s->control = qemu_get_be32(f); + s->state = qemu_get_be32(f); + s->mask = qemu_get_be32(f); + s->mode[0] = qemu_get_be32(f); + s->mode[0] = qemu_get_be32(f); + s->load[0] = qemu_get_be32(f); + s->load[1] = qemu_get_be32(f); + s->match[0] = qemu_get_be32(f); + s->match[1] = qemu_get_be32(f); + s->prescale[0] = qemu_get_be32(f); + s->prescale[1] = qemu_get_be32(f); + s->match_prescale[0] = qemu_get_be32(f); + s->match_prescale[1] = qemu_get_be32(f); + s->rtc = qemu_get_be32(f); + s->tick[0] = qemu_get_be64(f); + s->tick[1] = qemu_get_be64(f); + qemu_get_timer(f, s->timer[0]); + qemu_get_timer(f, s->timer[1]); + + return 0; +} + static void stellaris_gptm_init(uint32_t base, qemu_irq irq, qemu_irq trigger) { int iomemtype; @@ -302,7 +361,7 @@ static void stellaris_gptm_init(uint32_t base, qemu_irq irq, qemu_irq trigger) cpu_register_physical_memory(base, 0x00001000, iomemtype); s->timer[0] = qemu_new_timer(vm_clock, gptm_tick, &s->opaque[0]); s->timer[1] = qemu_new_timer(vm_clock, gptm_tick, &s->opaque[1]); - /* ??? Save/restore. */ + register_savevm("stellaris_gptm", -1, 1, gptm_save, gptm_load, s); } @@ -452,6 +511,11 @@ static uint32_t ssys_read(void *opaque, target_phys_addr_t offset) } } +static void ssys_calculate_system_clock(ssys_state *s) +{ + system_clock_scale = 5 * (((s->rcc >> 23) & 0xf) + 1); +} + static void ssys_write(void *opaque, target_phys_addr_t offset, uint32_t value) { ssys_state *s = (ssys_state *)opaque; @@ -484,7 +548,7 @@ static void ssys_write(void *opaque, target_phys_addr_t offset, uint32_t value) s->int_status |= (1 << 6); } s->rcc = value; - system_clock_scale = 5 * (((s->rcc >> 23) & 0xf) + 1); + ssys_calculate_system_clock(s); break; case 0x100: /* RCGC0 */ s->rcgc[0] = value; @@ -548,6 +612,58 @@ static void ssys_reset(void *opaque) s->dcgc[0] = 1; } +static void ssys_save(QEMUFile *f, void *opaque) +{ + ssys_state *s = (ssys_state *)opaque; + + qemu_put_be32(f, s->pborctl); + qemu_put_be32(f, s->ldopctl); + qemu_put_be32(f, s->int_mask); + qemu_put_be32(f, s->int_status); + qemu_put_be32(f, s->resc); + qemu_put_be32(f, s->rcc); + qemu_put_be32(f, s->rcgc[0]); + qemu_put_be32(f, s->rcgc[1]); + qemu_put_be32(f, s->rcgc[2]); + qemu_put_be32(f, s->scgc[0]); + qemu_put_be32(f, s->scgc[1]); + qemu_put_be32(f, s->scgc[2]); + qemu_put_be32(f, s->dcgc[0]); + qemu_put_be32(f, s->dcgc[1]); + qemu_put_be32(f, s->dcgc[2]); + qemu_put_be32(f, s->clkvclr); + qemu_put_be32(f, s->ldoarst); +} + +static int ssys_load(QEMUFile *f, void *opaque, int version_id) +{ + ssys_state *s = (ssys_state *)opaque; + + if (version_id != 1) + return -EINVAL; + + s->pborctl = qemu_get_be32(f); + s->ldopctl = qemu_get_be32(f); + s->int_mask = qemu_get_be32(f); + s->int_status = qemu_get_be32(f); + s->resc = qemu_get_be32(f); + s->rcc = qemu_get_be32(f); + s->rcgc[0] = qemu_get_be32(f); + s->rcgc[1] = qemu_get_be32(f); + s->rcgc[2] = qemu_get_be32(f); + s->scgc[0] = qemu_get_be32(f); + s->scgc[1] = qemu_get_be32(f); + s->scgc[2] = qemu_get_be32(f); + s->dcgc[0] = qemu_get_be32(f); + s->dcgc[1] = qemu_get_be32(f); + s->dcgc[2] = qemu_get_be32(f); + s->clkvclr = qemu_get_be32(f); + s->ldoarst = qemu_get_be32(f); + ssys_calculate_system_clock(s); + + return 0; +} + static void stellaris_sys_init(uint32_t base, qemu_irq irq, stellaris_board_info * board, uint8_t *macaddr) @@ -567,7 +683,7 @@ static void stellaris_sys_init(uint32_t base, qemu_irq irq, ssys_writefn, s); cpu_register_physical_memory(base, 0x00001000, iomemtype); ssys_reset(s); - /* ??? Save/restore. */ + register_savevm("stellaris_sys", -1, 1, ssys_save, ssys_load, s); } @@ -737,6 +853,37 @@ static CPUWriteMemoryFunc *stellaris_i2c_writefn[] = { stellaris_i2c_write }; +static void stellaris_i2c_save(QEMUFile *f, void *opaque) +{ + stellaris_i2c_state *s = (stellaris_i2c_state *)opaque; + + qemu_put_be32(f, s->msa); + qemu_put_be32(f, s->mcs); + qemu_put_be32(f, s->mdr); + qemu_put_be32(f, s->mtpr); + qemu_put_be32(f, s->mimr); + qemu_put_be32(f, s->mris); + qemu_put_be32(f, s->mcr); +} + +static int stellaris_i2c_load(QEMUFile *f, void *opaque, int version_id) +{ + stellaris_i2c_state *s = (stellaris_i2c_state *)opaque; + + if (version_id != 1) + return -EINVAL; + + s->msa = qemu_get_be32(f); + s->mcs = qemu_get_be32(f); + s->mdr = qemu_get_be32(f); + s->mtpr = qemu_get_be32(f); + s->mimr = qemu_get_be32(f); + s->mris = qemu_get_be32(f); + s->mcr = qemu_get_be32(f); + + return 0; +} + static void stellaris_i2c_init(uint32_t base, qemu_irq irq, i2c_bus *bus) { stellaris_i2c_state *s; @@ -752,6 +899,8 @@ static void stellaris_i2c_init(uint32_t base, qemu_irq irq, i2c_bus *bus) cpu_register_physical_memory(base, 0x00001000, iomemtype); /* ??? For now we only implement the master interface. */ stellaris_i2c_reset(s); + register_savevm("stellaris_i2c", -1, 1, + stellaris_i2c_save, stellaris_i2c_load, s); } /* Analogue to Digital Converter. This is only partially implemented, @@ -785,6 +934,7 @@ typedef struct } fifo[4]; uint32_t ssmux[4]; uint32_t ssctl[4]; + uint32_t noise; qemu_irq irq; } stellaris_adc_state; @@ -833,17 +983,16 @@ static void stellaris_adc_update(stellaris_adc_state *s) static void stellaris_adc_trigger(void *opaque, int irq, int level) { stellaris_adc_state *s = (stellaris_adc_state *)opaque; - /* Some applications use the ADC as a random number source, so introduce - some variation into the signal. */ - static uint32_t noise = 0; if ((s->actss & 1) == 0) { return; } - noise = noise * 314159 + 1; + /* Some applications use the ADC as a random number source, so introduce + some variation into the signal. */ + s->noise = s->noise * 314159 + 1; /* ??? actual inputs not implemented. Return an arbitrary value. */ - stellaris_adc_fifo_write(s, 0, 0x200 + ((noise >> 16) & 7)); + stellaris_adc_fifo_write(s, 0, 0x200 + ((s->noise >> 16) & 7)); s->ris |= 1; stellaris_adc_update(s); } @@ -983,6 +1132,61 @@ static CPUWriteMemoryFunc *stellaris_adc_writefn[] = { stellaris_adc_write }; +static void stellaris_adc_save(QEMUFile *f, void *opaque) +{ + stellaris_adc_state *s = (stellaris_adc_state *)opaque; + int i; + int j; + + qemu_put_be32(f, s->actss); + qemu_put_be32(f, s->ris); + qemu_put_be32(f, s->im); + qemu_put_be32(f, s->emux); + qemu_put_be32(f, s->ostat); + qemu_put_be32(f, s->ustat); + qemu_put_be32(f, s->sspri); + qemu_put_be32(f, s->sac); + for (i = 0; i < 4; i++) { + qemu_put_be32(f, s->fifo[i].state); + for (j = 0; j < 16; j++) { + qemu_put_be32(f, s->fifo[i].data[j]); + } + qemu_put_be32(f, s->ssmux[i]); + qemu_put_be32(f, s->ssctl[i]); + } + qemu_put_be32(f, s->noise); +} + +static int stellaris_adc_load(QEMUFile *f, void *opaque, int version_id) +{ + stellaris_adc_state *s = (stellaris_adc_state *)opaque; + int i; + int j; + + if (version_id != 1) + return -EINVAL; + + s->actss = qemu_get_be32(f); + s->ris = qemu_get_be32(f); + s->im = qemu_get_be32(f); + s->emux = qemu_get_be32(f); + s->ostat = qemu_get_be32(f); + s->ustat = qemu_get_be32(f); + s->sspri = qemu_get_be32(f); + s->sac = qemu_get_be32(f); + for (i = 0; i < 4; i++) { + s->fifo[i].state = qemu_get_be32(f); + for (j = 0; j < 16; j++) { + s->fifo[i].data[j] = qemu_get_be32(f); + } + s->ssmux[i] = qemu_get_be32(f); + s->ssctl[i] = qemu_get_be32(f); + } + s->noise = qemu_get_be32(f); + + return 0; +} + static qemu_irq stellaris_adc_init(uint32_t base, qemu_irq irq) { stellaris_adc_state *s; @@ -998,6 +1202,8 @@ static qemu_irq stellaris_adc_init(uint32_t base, qemu_irq irq) cpu_register_physical_memory(base, 0x00001000, iomemtype); stellaris_adc_reset(s); qi = qemu_allocate_irqs(stellaris_adc_trigger, s, 1); + register_savevm("stellaris_adc", -1, 1, + stellaris_adc_save, stellaris_adc_load, s); return qi[0]; } @@ -1029,6 +1235,25 @@ static int stellaris_ssi_bus_xfer(void *opaque, int val) return s->xfer_cb[s->current_dev](s->opaque[s->current_dev], val); } +static void stellaris_ssi_bus_save(QEMUFile *f, void *opaque) +{ + stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque; + + qemu_put_be32(f, s->current_dev); +} + +static int stellaris_ssi_bus_load(QEMUFile *f, void *opaque, int version_id) +{ + stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque; + + if (version_id != 1) + return -EINVAL; + + s->current_dev = qemu_get_be32(f); + + return 0; +} + static void *stellaris_ssi_bus_init(qemu_irq *irqp, ssi_xfer_cb cb0, void *opaque0, ssi_xfer_cb cb1, void *opaque1) @@ -1043,6 +1268,8 @@ static void *stellaris_ssi_bus_init(qemu_irq *irqp, s->opaque[1] = opaque1; qi = qemu_allocate_irqs(stellaris_ssi_bus_select, s, 1); *irqp = *qi; + register_savevm("stellaris_ssi_bus", -1, 1, + stellaris_ssi_bus_save, stellaris_ssi_bus_load, s); return s; } diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c index 31711b9d66..8057f80f31 100644 --- a/hw/stellaris_enet.c +++ b/hw/stellaris_enet.c @@ -326,6 +326,67 @@ static void stellaris_enet_reset(stellaris_enet_state *s) s->tx_frame_len = -1; } +static void stellaris_enet_save(QEMUFile *f, void *opaque) +{ + stellaris_enet_state *s = (stellaris_enet_state *)opaque; + int i; + + qemu_put_be32(f, s->ris); + qemu_put_be32(f, s->im); + qemu_put_be32(f, s->rctl); + qemu_put_be32(f, s->tctl); + qemu_put_be32(f, s->thr); + qemu_put_be32(f, s->mctl); + qemu_put_be32(f, s->mdv); + qemu_put_be32(f, s->mtxd); + qemu_put_be32(f, s->mrxd); + qemu_put_be32(f, s->np); + qemu_put_be32(f, s->tx_frame_len); + qemu_put_be32(f, s->tx_fifo_len); + qemu_put_buffer(f, s->tx_fifo, sizeof(s->tx_fifo)); + for (i = 0; i < 31; i++) { + qemu_put_be32(f, s->rx[i].len); + qemu_put_buffer(f, s->rx[i].data, sizeof(s->rx[i].data)); + + } + qemu_put_be32(f, s->next_packet); + qemu_put_be32(f, s->rx_fifo - s->rx[s->next_packet].data); + qemu_put_be32(f, s->rx_fifo_len); +} + +static int stellaris_enet_load(QEMUFile *f, void *opaque, int version_id) +{ + stellaris_enet_state *s = (stellaris_enet_state *)opaque; + int i; + + if (version_id != 1) + return -EINVAL; + + s->ris = qemu_get_be32(f); + s->im = qemu_get_be32(f); + s->rctl = qemu_get_be32(f); + s->tctl = qemu_get_be32(f); + s->thr = qemu_get_be32(f); + s->mctl = qemu_get_be32(f); + s->mdv = qemu_get_be32(f); + s->mtxd = qemu_get_be32(f); + s->mrxd = qemu_get_be32(f); + s->np = qemu_get_be32(f); + s->tx_frame_len = qemu_get_be32(f); + s->tx_fifo_len = qemu_get_be32(f); + qemu_get_buffer(f, s->tx_fifo, sizeof(s->tx_fifo)); + for (i = 0; i < 31; i++) { + s->rx[i].len = qemu_get_be32(f); + qemu_get_buffer(f, s->rx[i].data, sizeof(s->rx[i].data)); + + } + s->next_packet = qemu_get_be32(f); + s->rx_fifo = s->rx[s->next_packet].data + qemu_get_be32(f); + s->rx_fifo_len = qemu_get_be32(f); + + return 0; +} + void stellaris_enet_init(NICInfo *nd, uint32_t base, qemu_irq irq) { stellaris_enet_state *s; @@ -344,4 +405,6 @@ void stellaris_enet_init(NICInfo *nd, uint32_t base, qemu_irq irq) stellaris_enet_can_receive, s); stellaris_enet_reset(s); + register_savevm("stellaris_enet", -1, 1, + stellaris_enet_save, stellaris_enet_load, s); } diff --git a/hw/stellaris_input.c b/hw/stellaris_input.c index 461868b2ee..aef4ce0c63 100644 --- a/hw/stellaris_input.c +++ b/hw/stellaris_input.c @@ -47,6 +47,31 @@ static void stellaris_gamepad_put_key(void * opaque, int keycode) s->extension = 0; } +static void stellaris_gamepad_save(QEMUFile *f, void *opaque) +{ + gamepad_state *s = (gamepad_state *)opaque; + int i; + + qemu_put_be32(f, s->extension); + for (i = 0; i < s->num_buttons; i++) + qemu_put_byte(f, s->buttons[i].pressed); +} + +static int stellaris_gamepad_load(QEMUFile *f, void *opaque, int version_id) +{ + gamepad_state *s = (gamepad_state *)opaque; + int i; + + if (version_id != 1) + return -EINVAL; + + s->extension = qemu_get_be32(f); + for (i = 0; i < s->num_buttons; i++) + s->buttons[i].pressed = qemu_get_byte(f); + + return 0; +} + /* Returns an array 5 ouput slots. */ void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode) { @@ -61,6 +86,8 @@ void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode) } s->num_buttons = n; qemu_add_kbd_event_handler(stellaris_gamepad_put_key, s); + register_savevm("stellaris_gamepad", -1, 1, + stellaris_gamepad_save, stellaris_gamepad_load, s); }