Merge branch 'arm-devs.for-upstream' of git://git.linaro.org/people/pmaydell/qemu-arm
* 'arm-devs.for-upstream' of git://git.linaro.org/people/pmaydell/qemu-arm: (28 commits) hw/sd.c: add SD card save/load support vmstate: Add support for saving/loading bitmaps hw/sd.c: Fix erase for high capacity cards pflash_cfi01: Fix debug mode printfery pflash_cfi0x: QOMified pflash_cfi01: remove unused total_len field pflash_cfi0x: remove unused base field hw/versatile_i2c: Use LOG_GUEST_ERROR hw/arm_l2x0: Use LOG_GUEST_ERROR hw/arm_sysctl: Use LOG_GUEST_ERROR hw/armv7m_nvic: Use LOG_GUEST_ERROR and LOG_UNIMP hw/arm_timer: Use LOG_GUEST_ERROR and LOG_UNIMP hw/arm_gic: Use LOG_GUEST_ERROR hw/arm11mpcore: Use LOG_GUEST_ERROR rather than hw_error() hw/pl190: Use LOG_UNIMP rather than hw_error() hw/pl110: Use LOG_GUEST_ERROR rather than hw_error() hw/pl080: Use LOG_GUEST_ERROR and LOG_UNIMP hw/pl061: Use LOG_GUEST_ERROR hw/pl050: Use LOG_GUEST_ERROR hw/exynos4_boards: Don't prematurely explode QEMUMachineInitArgs ...
This commit is contained in:
commit
735c1eeb85
@ -44,7 +44,9 @@ static uint64_t mpcore_scu_read(void *opaque, hwaddr offset,
|
|||||||
case 0x0c: /* Invalidate all. */
|
case 0x0c: /* Invalidate all. */
|
||||||
return 0;
|
return 0;
|
||||||
default:
|
default:
|
||||||
hw_error("mpcore_priv_read: Bad offset %x\n", (int)offset);
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"mpcore_priv_read: Bad offset %x\n", (int)offset);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +63,8 @@ static void mpcore_scu_write(void *opaque, hwaddr offset,
|
|||||||
/* This is a no-op as cache is not emulated. */
|
/* This is a no-op as cache is not emulated. */
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
hw_error("mpcore_priv_read: Bad offset %x\n", (int)offset);
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"mpcore_priv_read: Bad offset %x\n", (int)offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
12
hw/arm_gic.c
12
hw/arm_gic.c
@ -324,7 +324,8 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset)
|
|||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
bad_reg:
|
bad_reg:
|
||||||
hw_error("gic_dist_readb: Bad offset %x\n", (int)offset);
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"gic_dist_readb: Bad offset %x\n", (int)offset);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -487,7 +488,8 @@ static void gic_dist_writeb(void *opaque, hwaddr offset,
|
|||||||
gic_update(s);
|
gic_update(s);
|
||||||
return;
|
return;
|
||||||
bad_reg:
|
bad_reg:
|
||||||
hw_error("gic_dist_writeb: Bad offset %x\n", (int)offset);
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"gic_dist_writeb: Bad offset %x\n", (int)offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gic_dist_writew(void *opaque, hwaddr offset,
|
static void gic_dist_writew(void *opaque, hwaddr offset,
|
||||||
@ -556,7 +558,8 @@ static uint32_t gic_cpu_read(GICState *s, int cpu, int offset)
|
|||||||
case 0x18: /* Highest Pending Interrupt */
|
case 0x18: /* Highest Pending Interrupt */
|
||||||
return s->current_pending[cpu];
|
return s->current_pending[cpu];
|
||||||
default:
|
default:
|
||||||
hw_error("gic_cpu_read: Bad offset %x\n", (int)offset);
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"gic_cpu_read: Bad offset %x\n", (int)offset);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -577,7 +580,8 @@ static void gic_cpu_write(GICState *s, int cpu, int offset, uint32_t value)
|
|||||||
case 0x10: /* End Of Interrupt */
|
case 0x10: /* End Of Interrupt */
|
||||||
return gic_complete_irq(s, cpu, value & 0x3ff);
|
return gic_complete_irq(s, cpu, value & 0x3ff);
|
||||||
default:
|
default:
|
||||||
hw_error("gic_cpu_write: Bad offset %x\n", (int)offset);
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"gic_cpu_write: Bad offset %x\n", (int)offset);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
gic_update(s);
|
gic_update(s);
|
||||||
|
@ -87,7 +87,8 @@ static uint64_t l2x0_priv_read(void *opaque, hwaddr offset,
|
|||||||
case 0xF80:
|
case 0xF80:
|
||||||
return 0;
|
return 0;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "l2x0_priv_read: Bad offset %x\n", (int)offset);
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"l2x0_priv_read: Bad offset %x\n", (int)offset);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -128,7 +129,8 @@ static void l2x0_priv_write(void *opaque, hwaddr offset,
|
|||||||
case 0xF80:
|
case 0xF80:
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "l2x0_priv_write: Bad offset %x\n", (int)offset);
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"l2x0_priv_write: Bad offset %x\n", (int)offset);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -184,7 +184,9 @@ static uint64_t arm_sysctl_read(void *opaque, hwaddr offset,
|
|||||||
return s->sys_cfgstat;
|
return s->sys_cfgstat;
|
||||||
default:
|
default:
|
||||||
bad_reg:
|
bad_reg:
|
||||||
printf ("arm_sysctl_read: Bad register offset 0x%x\n", (int)offset);
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"arm_sysctl_read: Bad register offset 0x%x\n",
|
||||||
|
(int)offset);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -339,7 +341,9 @@ static void arm_sysctl_write(void *opaque, hwaddr offset,
|
|||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
bad_reg:
|
bad_reg:
|
||||||
printf ("arm_sysctl_write: Bad register offset 0x%x\n", (int)offset);
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"arm_sysctl_write: Bad register offset 0x%x\n",
|
||||||
|
(int)offset);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,8 @@ static uint32_t arm_timer_read(void *opaque, hwaddr offset)
|
|||||||
return 0;
|
return 0;
|
||||||
return s->int_level;
|
return s->int_level;
|
||||||
default:
|
default:
|
||||||
hw_error("%s: Bad offset %x\n", __func__, (int)offset);
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"%s: Bad offset %x\n", __func__, (int)offset);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -131,7 +132,8 @@ static void arm_timer_write(void *opaque, hwaddr offset,
|
|||||||
arm_timer_recalibrate(s, 0);
|
arm_timer_recalibrate(s, 0);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
hw_error("%s: Bad offset %x\n", __func__, (int)offset);
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"%s: Bad offset %x\n", __func__, (int)offset);
|
||||||
}
|
}
|
||||||
arm_timer_update(s);
|
arm_timer_update(s);
|
||||||
}
|
}
|
||||||
@ -223,10 +225,14 @@ static uint64_t sp804_read(void *opaque, hwaddr offset,
|
|||||||
/* Integration Test control registers, which we won't support */
|
/* Integration Test control registers, which we won't support */
|
||||||
case 0xf00: /* TimerITCR */
|
case 0xf00: /* TimerITCR */
|
||||||
case 0xf04: /* TimerITOP (strictly write only but..) */
|
case 0xf04: /* TimerITOP (strictly write only but..) */
|
||||||
|
qemu_log_mask(LOG_UNIMP,
|
||||||
|
"%s: integration test registers unimplemented\n",
|
||||||
|
__func__);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
hw_error("%s: Bad offset %x\n", __func__, (int)offset);
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"%s: Bad offset %x\n", __func__, (int)offset);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,7 +252,8 @@ static void sp804_write(void *opaque, hwaddr offset,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Technically we could be writing to the Test Registers, but not likely */
|
/* Technically we could be writing to the Test Registers, but not likely */
|
||||||
hw_error("%s: Bad offset %x\n", __func__, (int)offset);
|
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %x\n",
|
||||||
|
__func__, (int)offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const MemoryRegionOps sp804_ops = {
|
static const MemoryRegionOps sp804_ops = {
|
||||||
@ -300,7 +307,7 @@ static uint64_t icp_pit_read(void *opaque, hwaddr offset,
|
|||||||
/* ??? Don't know the PrimeCell ID for this device. */
|
/* ??? Don't know the PrimeCell ID for this device. */
|
||||||
n = offset >> 8;
|
n = offset >> 8;
|
||||||
if (n > 2) {
|
if (n > 2) {
|
||||||
hw_error("%s: Bad timer %d\n", __func__, n);
|
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad timer %d\n", __func__, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
return arm_timer_read(s->timer[n], offset & 0xff);
|
return arm_timer_read(s->timer[n], offset & 0xff);
|
||||||
@ -314,7 +321,7 @@ static void icp_pit_write(void *opaque, hwaddr offset,
|
|||||||
|
|
||||||
n = offset >> 8;
|
n = offset >> 8;
|
||||||
if (n > 2) {
|
if (n > 2) {
|
||||||
hw_error("%s: Bad timer %d\n", __func__, n);
|
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad timer %d\n", __func__, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
arm_timer_write(s->timer[n], offset & 0xff, value);
|
arm_timer_write(s->timer[n], offset & 0xff, value);
|
||||||
|
@ -138,9 +138,8 @@ void armv7m_nvic_complete_irq(void *opaque, int irq)
|
|||||||
gic_complete_irq(&s->gic, 0, irq);
|
gic_complete_irq(&s->gic, 0, irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t nvic_readl(void *opaque, uint32_t offset)
|
static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
|
||||||
{
|
{
|
||||||
nvic_state *s = (nvic_state *)opaque;
|
|
||||||
uint32_t val;
|
uint32_t val;
|
||||||
int irq;
|
int irq;
|
||||||
|
|
||||||
@ -216,14 +215,6 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset)
|
|||||||
case 0xd14: /* Configuration Control. */
|
case 0xd14: /* Configuration Control. */
|
||||||
/* TODO: Implement Configuration Control bits. */
|
/* TODO: Implement Configuration Control bits. */
|
||||||
return 0;
|
return 0;
|
||||||
case 0xd18: case 0xd1c: case 0xd20: /* System Handler Priority. */
|
|
||||||
irq = offset - 0xd14;
|
|
||||||
val = 0;
|
|
||||||
val |= s->gic.priority1[irq++][0];
|
|
||||||
val |= s->gic.priority1[irq++][0] << 8;
|
|
||||||
val |= s->gic.priority1[irq++][0] << 16;
|
|
||||||
val |= s->gic.priority1[irq][0] << 24;
|
|
||||||
return val;
|
|
||||||
case 0xd24: /* System Handler Status. */
|
case 0xd24: /* System Handler Status. */
|
||||||
val = 0;
|
val = 0;
|
||||||
if (s->gic.irq_state[ARMV7M_EXCP_MEM].active) val |= (1 << 0);
|
if (s->gic.irq_state[ARMV7M_EXCP_MEM].active) val |= (1 << 0);
|
||||||
@ -243,7 +234,7 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset)
|
|||||||
return val;
|
return val;
|
||||||
case 0xd28: /* Configurable Fault Status. */
|
case 0xd28: /* Configurable Fault Status. */
|
||||||
/* TODO: Implement Fault Status. */
|
/* TODO: Implement Fault Status. */
|
||||||
hw_error("Not implemented: Configurable Fault Status.");
|
qemu_log_mask(LOG_UNIMP, "Configurable Fault Status unimplemented\n");
|
||||||
return 0;
|
return 0;
|
||||||
case 0xd2c: /* Hard Fault Status. */
|
case 0xd2c: /* Hard Fault Status. */
|
||||||
case 0xd30: /* Debug Fault Status. */
|
case 0xd30: /* Debug Fault Status. */
|
||||||
@ -251,7 +242,8 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset)
|
|||||||
case 0xd38: /* Bus Fault Address. */
|
case 0xd38: /* Bus Fault Address. */
|
||||||
case 0xd3c: /* Aux Fault Status. */
|
case 0xd3c: /* Aux Fault Status. */
|
||||||
/* TODO: Implement fault status registers. */
|
/* TODO: Implement fault status registers. */
|
||||||
goto bad_reg;
|
qemu_log_mask(LOG_UNIMP, "Fault status registers unimplemented\n");
|
||||||
|
return 0;
|
||||||
case 0xd40: /* PFR0. */
|
case 0xd40: /* PFR0. */
|
||||||
return 0x00000030;
|
return 0x00000030;
|
||||||
case 0xd44: /* PRF1. */
|
case 0xd44: /* PRF1. */
|
||||||
@ -280,14 +272,13 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset)
|
|||||||
return 0x01310102;
|
return 0x01310102;
|
||||||
/* TODO: Implement debug registers. */
|
/* TODO: Implement debug registers. */
|
||||||
default:
|
default:
|
||||||
bad_reg:
|
qemu_log_mask(LOG_GUEST_ERROR, "NVIC: Bad read offset 0x%x\n", offset);
|
||||||
hw_error("NVIC: Bad read offset 0x%x\n", offset);
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nvic_writel(void *opaque, uint32_t offset, uint32_t value)
|
static void nvic_writel(nvic_state *s, uint32_t offset, uint32_t value)
|
||||||
{
|
{
|
||||||
nvic_state *s = (nvic_state *)opaque;
|
|
||||||
uint32_t oldval;
|
uint32_t oldval;
|
||||||
switch (offset) {
|
switch (offset) {
|
||||||
case 0x10: /* SysTick Control and Status. */
|
case 0x10: /* SysTick Control and Status. */
|
||||||
@ -345,27 +336,17 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value)
|
|||||||
case 0xd0c: /* Application Interrupt/Reset Control. */
|
case 0xd0c: /* Application Interrupt/Reset Control. */
|
||||||
if ((value >> 16) == 0x05fa) {
|
if ((value >> 16) == 0x05fa) {
|
||||||
if (value & 2) {
|
if (value & 2) {
|
||||||
hw_error("VECTCLRACTIVE not implemented");
|
qemu_log_mask(LOG_UNIMP, "VECTCLRACTIVE unimplemented\n");
|
||||||
}
|
}
|
||||||
if (value & 5) {
|
if (value & 5) {
|
||||||
hw_error("System reset");
|
qemu_log_mask(LOG_UNIMP, "AIRCR system reset unimplemented\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0xd10: /* System Control. */
|
case 0xd10: /* System Control. */
|
||||||
case 0xd14: /* Configuration Control. */
|
case 0xd14: /* Configuration Control. */
|
||||||
/* TODO: Implement control registers. */
|
/* TODO: Implement control registers. */
|
||||||
goto bad_reg;
|
qemu_log_mask(LOG_UNIMP, "NVIC: SCR and CCR unimplemented\n");
|
||||||
case 0xd18: case 0xd1c: case 0xd20: /* System Handler Priority. */
|
|
||||||
{
|
|
||||||
int irq;
|
|
||||||
irq = offset - 0xd14;
|
|
||||||
s->gic.priority1[irq++][0] = value & 0xff;
|
|
||||||
s->gic.priority1[irq++][0] = (value >> 8) & 0xff;
|
|
||||||
s->gic.priority1[irq++][0] = (value >> 16) & 0xff;
|
|
||||||
s->gic.priority1[irq][0] = (value >> 24) & 0xff;
|
|
||||||
gic_update(&s->gic);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case 0xd24: /* System Handler Control. */
|
case 0xd24: /* System Handler Control. */
|
||||||
/* TODO: Real hardware allows you to set/clear the active bits
|
/* TODO: Real hardware allows you to set/clear the active bits
|
||||||
@ -380,47 +361,71 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value)
|
|||||||
case 0xd34: /* Mem Manage Address. */
|
case 0xd34: /* Mem Manage Address. */
|
||||||
case 0xd38: /* Bus Fault Address. */
|
case 0xd38: /* Bus Fault Address. */
|
||||||
case 0xd3c: /* Aux Fault Status. */
|
case 0xd3c: /* Aux Fault Status. */
|
||||||
goto bad_reg;
|
qemu_log_mask(LOG_UNIMP,
|
||||||
|
"NVIC: fault status registers unimplemented\n");
|
||||||
|
break;
|
||||||
case 0xf00: /* Software Triggered Interrupt Register */
|
case 0xf00: /* Software Triggered Interrupt Register */
|
||||||
if ((value & 0x1ff) < s->num_irq) {
|
if ((value & 0x1ff) < s->num_irq) {
|
||||||
gic_set_pending_private(&s->gic, 0, value & 0x1ff);
|
gic_set_pending_private(&s->gic, 0, value & 0x1ff);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
bad_reg:
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
hw_error("NVIC: Bad write offset 0x%x\n", offset);
|
"NVIC: Bad write offset 0x%x\n", offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t nvic_sysreg_read(void *opaque, hwaddr addr,
|
static uint64_t nvic_sysreg_read(void *opaque, hwaddr addr,
|
||||||
unsigned size)
|
unsigned size)
|
||||||
{
|
{
|
||||||
/* At the moment we only support the ID registers for byte/word access.
|
nvic_state *s = (nvic_state *)opaque;
|
||||||
* This is not strictly correct as a few of the other registers also
|
|
||||||
* allow byte access.
|
|
||||||
*/
|
|
||||||
uint32_t offset = addr;
|
uint32_t offset = addr;
|
||||||
if (offset >= 0xfe0) {
|
int i;
|
||||||
|
uint32_t val;
|
||||||
|
|
||||||
|
switch (offset) {
|
||||||
|
case 0xd18 ... 0xd23: /* System Handler Priority. */
|
||||||
|
val = 0;
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
val |= s->gic.priority1[(offset - 0xd14) + i][0] << (i * 8);
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
case 0xfe0 ... 0xfff: /* ID. */
|
||||||
if (offset & 3) {
|
if (offset & 3) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return nvic_id[(offset - 0xfe0) >> 2];
|
return nvic_id[(offset - 0xfe0) >> 2];
|
||||||
}
|
}
|
||||||
if (size == 4) {
|
if (size == 4) {
|
||||||
return nvic_readl(opaque, offset);
|
return nvic_readl(s, offset);
|
||||||
}
|
}
|
||||||
hw_error("NVIC: Bad read of size %d at offset 0x%x\n", size, offset);
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"NVIC: Bad read of size %d at offset 0x%x\n", size, offset);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nvic_sysreg_write(void *opaque, hwaddr addr,
|
static void nvic_sysreg_write(void *opaque, hwaddr addr,
|
||||||
uint64_t value, unsigned size)
|
uint64_t value, unsigned size)
|
||||||
{
|
{
|
||||||
|
nvic_state *s = (nvic_state *)opaque;
|
||||||
uint32_t offset = addr;
|
uint32_t offset = addr;
|
||||||
if (size == 4) {
|
int i;
|
||||||
nvic_writel(opaque, offset, value);
|
|
||||||
|
switch (offset) {
|
||||||
|
case 0xd18 ... 0xd23: /* System Handler Priority. */
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
s->gic.priority1[(offset - 0xd14) + i][0] =
|
||||||
|
(value >> (i * 8)) & 0xff;
|
||||||
|
}
|
||||||
|
gic_update(&s->gic);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
hw_error("NVIC: Bad write of size %d at offset 0x%x\n", size, offset);
|
if (size == 4) {
|
||||||
|
nvic_writel(s, offset, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"NVIC: Bad write of size %d at offset 0x%x\n", size, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const MemoryRegionOps nvic_sysreg_ops = {
|
static const MemoryRegionOps nvic_sysreg_ops = {
|
||||||
|
@ -93,11 +93,8 @@ static void lan9215_init(uint32_t base, qemu_irq irq)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Exynos4210State *exynos4_boards_init_common(
|
static Exynos4210State *exynos4_boards_init_common(QEMUMachineInitArgs *args,
|
||||||
const char *kernel_filename,
|
Exynos4BoardType board_type)
|
||||||
const char *kernel_cmdline,
|
|
||||||
const char *initrd_filename,
|
|
||||||
Exynos4BoardType board_type)
|
|
||||||
{
|
{
|
||||||
if (smp_cpus != EXYNOS4210_NCPUS) {
|
if (smp_cpus != EXYNOS4210_NCPUS) {
|
||||||
fprintf(stderr, "%s board supports only %d CPU cores. Ignoring smp_cpus"
|
fprintf(stderr, "%s board supports only %d CPU cores. Ignoring smp_cpus"
|
||||||
@ -110,9 +107,9 @@ static Exynos4210State *exynos4_boards_init_common(
|
|||||||
exynos4_board_binfo.board_id = exynos4_board_id[board_type];
|
exynos4_board_binfo.board_id = exynos4_board_id[board_type];
|
||||||
exynos4_board_binfo.smp_bootreg_addr =
|
exynos4_board_binfo.smp_bootreg_addr =
|
||||||
exynos4_board_smp_bootreg_addr[board_type];
|
exynos4_board_smp_bootreg_addr[board_type];
|
||||||
exynos4_board_binfo.kernel_filename = kernel_filename;
|
exynos4_board_binfo.kernel_filename = args->kernel_filename;
|
||||||
exynos4_board_binfo.initrd_filename = initrd_filename;
|
exynos4_board_binfo.initrd_filename = args->initrd_filename;
|
||||||
exynos4_board_binfo.kernel_cmdline = kernel_cmdline;
|
exynos4_board_binfo.kernel_cmdline = args->kernel_cmdline;
|
||||||
exynos4_board_binfo.gic_cpu_if_addr =
|
exynos4_board_binfo.gic_cpu_if_addr =
|
||||||
EXYNOS4210_SMP_PRIVATE_BASE_ADDR + 0x100;
|
EXYNOS4210_SMP_PRIVATE_BASE_ADDR + 0x100;
|
||||||
|
|
||||||
@ -122,9 +119,9 @@ static Exynos4210State *exynos4_boards_init_common(
|
|||||||
" initrd_filename: %s\n",
|
" initrd_filename: %s\n",
|
||||||
exynos4_board_ram_size[board_type] / 1048576,
|
exynos4_board_ram_size[board_type] / 1048576,
|
||||||
exynos4_board_ram_size[board_type],
|
exynos4_board_ram_size[board_type],
|
||||||
kernel_filename,
|
args->kernel_filename,
|
||||||
kernel_cmdline,
|
args->kernel_cmdline,
|
||||||
initrd_filename);
|
args->initrd_filename);
|
||||||
|
|
||||||
return exynos4210_init(get_system_memory(),
|
return exynos4210_init(get_system_memory(),
|
||||||
exynos4_board_ram_size[board_type]);
|
exynos4_board_ram_size[board_type]);
|
||||||
@ -132,22 +129,15 @@ static Exynos4210State *exynos4_boards_init_common(
|
|||||||
|
|
||||||
static void nuri_init(QEMUMachineInitArgs *args)
|
static void nuri_init(QEMUMachineInitArgs *args)
|
||||||
{
|
{
|
||||||
const char *kernel_filename = args->kernel_filename;
|
exynos4_boards_init_common(args, EXYNOS4_BOARD_NURI);
|
||||||
const char *kernel_cmdline = args->kernel_cmdline;
|
|
||||||
const char *initrd_filename = args->initrd_filename;
|
|
||||||
exynos4_boards_init_common(kernel_filename, kernel_cmdline,
|
|
||||||
initrd_filename, EXYNOS4_BOARD_NURI);
|
|
||||||
|
|
||||||
arm_load_kernel(arm_env_get_cpu(first_cpu), &exynos4_board_binfo);
|
arm_load_kernel(arm_env_get_cpu(first_cpu), &exynos4_board_binfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void smdkc210_init(QEMUMachineInitArgs *args)
|
static void smdkc210_init(QEMUMachineInitArgs *args)
|
||||||
{
|
{
|
||||||
const char *kernel_filename = args->kernel_filename;
|
Exynos4210State *s = exynos4_boards_init_common(args,
|
||||||
const char *kernel_cmdline = args->kernel_cmdline;
|
EXYNOS4_BOARD_SMDKC210);
|
||||||
const char *initrd_filename = args->initrd_filename;
|
|
||||||
Exynos4210State *s = exynos4_boards_init_common(kernel_filename,
|
|
||||||
kernel_cmdline, initrd_filename, EXYNOS4_BOARD_SMDKC210);
|
|
||||||
|
|
||||||
lan9215_init(SMDK_LAN9118_BASE_ADDR,
|
lan9215_init(SMDK_LAN9118_BASE_ADDR,
|
||||||
qemu_irq_invert(s->irq_table[exynos4210_get_irq(37, 1)]));
|
qemu_irq_invert(s->irq_table[exynos4210_get_irq(37, 1)]));
|
||||||
|
@ -95,10 +95,8 @@ static struct arm_boot_info mainstone_binfo = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void mainstone_common_init(MemoryRegion *address_space_mem,
|
static void mainstone_common_init(MemoryRegion *address_space_mem,
|
||||||
ram_addr_t ram_size,
|
QEMUMachineInitArgs *args,
|
||||||
const char *kernel_filename,
|
enum mainstone_model_e model, int arm_id)
|
||||||
const char *kernel_cmdline, const char *initrd_filename,
|
|
||||||
const char *cpu_model, enum mainstone_model_e model, int arm_id)
|
|
||||||
{
|
{
|
||||||
uint32_t sector_len = 256 * 1024;
|
uint32_t sector_len = 256 * 1024;
|
||||||
hwaddr mainstone_flash_base[] = { MST_FLASH_0, MST_FLASH_1 };
|
hwaddr mainstone_flash_base[] = { MST_FLASH_0, MST_FLASH_1 };
|
||||||
@ -108,6 +106,7 @@ static void mainstone_common_init(MemoryRegion *address_space_mem,
|
|||||||
int i;
|
int i;
|
||||||
int be;
|
int be;
|
||||||
MemoryRegion *rom = g_new(MemoryRegion, 1);
|
MemoryRegion *rom = g_new(MemoryRegion, 1);
|
||||||
|
const char *cpu_model = args->cpu_model;
|
||||||
|
|
||||||
if (!cpu_model)
|
if (!cpu_model)
|
||||||
cpu_model = "pxa270-c5";
|
cpu_model = "pxa270-c5";
|
||||||
@ -164,22 +163,16 @@ static void mainstone_common_init(MemoryRegion *address_space_mem,
|
|||||||
smc91c111_init(&nd_table[0], MST_ETH_PHYS,
|
smc91c111_init(&nd_table[0], MST_ETH_PHYS,
|
||||||
qdev_get_gpio_in(mst_irq, ETHERNET_IRQ));
|
qdev_get_gpio_in(mst_irq, ETHERNET_IRQ));
|
||||||
|
|
||||||
mainstone_binfo.kernel_filename = kernel_filename;
|
mainstone_binfo.kernel_filename = args->kernel_filename;
|
||||||
mainstone_binfo.kernel_cmdline = kernel_cmdline;
|
mainstone_binfo.kernel_cmdline = args->kernel_cmdline;
|
||||||
mainstone_binfo.initrd_filename = initrd_filename;
|
mainstone_binfo.initrd_filename = args->initrd_filename;
|
||||||
mainstone_binfo.board_id = arm_id;
|
mainstone_binfo.board_id = arm_id;
|
||||||
arm_load_kernel(mpu->cpu, &mainstone_binfo);
|
arm_load_kernel(mpu->cpu, &mainstone_binfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mainstone_init(QEMUMachineInitArgs *args)
|
static void mainstone_init(QEMUMachineInitArgs *args)
|
||||||
{
|
{
|
||||||
ram_addr_t ram_size = args->ram_size;
|
mainstone_common_init(get_system_memory(), args, mainstone, 0x196);
|
||||||
const char *cpu_model = args->cpu_model;
|
|
||||||
const char *kernel_filename = args->kernel_filename;
|
|
||||||
const char *kernel_cmdline = args->kernel_cmdline;
|
|
||||||
const char *initrd_filename = args->initrd_filename;
|
|
||||||
mainstone_common_init(get_system_memory(), ram_size, kernel_filename,
|
|
||||||
kernel_cmdline, initrd_filename, cpu_model, mainstone, 0x196);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static QEMUMachine mainstone2_machine = {
|
static QEMUMachine mainstone2_machine = {
|
||||||
|
39
hw/nseries.c
39
hw/nseries.c
@ -1284,17 +1284,15 @@ static int n810_atag_setup(const struct arm_boot_info *info, void *p)
|
|||||||
return n8x0_atag_setup(p, 810);
|
return n8x0_atag_setup(p, 810);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void n8x0_init(ram_addr_t ram_size, const char *boot_device,
|
static void n8x0_init(QEMUMachineInitArgs *args,
|
||||||
const char *kernel_filename,
|
struct arm_boot_info *binfo, int model)
|
||||||
const char *kernel_cmdline, const char *initrd_filename,
|
|
||||||
const char *cpu_model, struct arm_boot_info *binfo, int model)
|
|
||||||
{
|
{
|
||||||
MemoryRegion *sysmem = get_system_memory();
|
MemoryRegion *sysmem = get_system_memory();
|
||||||
struct n800_s *s = (struct n800_s *) g_malloc0(sizeof(*s));
|
struct n800_s *s = (struct n800_s *) g_malloc0(sizeof(*s));
|
||||||
int sdram_size = binfo->ram_size;
|
int sdram_size = binfo->ram_size;
|
||||||
DisplayState *ds;
|
DisplayState *ds;
|
||||||
|
|
||||||
s->mpu = omap2420_mpu_init(sysmem, sdram_size, cpu_model);
|
s->mpu = omap2420_mpu_init(sysmem, sdram_size, args->cpu_model);
|
||||||
|
|
||||||
/* Setup peripherals
|
/* Setup peripherals
|
||||||
*
|
*
|
||||||
@ -1338,17 +1336,18 @@ static void n8x0_init(ram_addr_t ram_size, const char *boot_device,
|
|||||||
n8x0_usb_setup(s);
|
n8x0_usb_setup(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kernel_filename) {
|
if (args->kernel_filename) {
|
||||||
/* Or at the linux loader. */
|
/* Or at the linux loader. */
|
||||||
binfo->kernel_filename = kernel_filename;
|
binfo->kernel_filename = args->kernel_filename;
|
||||||
binfo->kernel_cmdline = kernel_cmdline;
|
binfo->kernel_cmdline = args->kernel_cmdline;
|
||||||
binfo->initrd_filename = initrd_filename;
|
binfo->initrd_filename = args->initrd_filename;
|
||||||
arm_load_kernel(s->mpu->cpu, binfo);
|
arm_load_kernel(s->mpu->cpu, binfo);
|
||||||
|
|
||||||
qemu_register_reset(n8x0_boot_init, s);
|
qemu_register_reset(n8x0_boot_init, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (option_rom[0].name && (boot_device[0] == 'n' || !kernel_filename)) {
|
if (option_rom[0].name &&
|
||||||
|
(args->boot_device[0] == 'n' || !args->kernel_filename)) {
|
||||||
int rom_size;
|
int rom_size;
|
||||||
uint8_t nolo_tags[0x10000];
|
uint8_t nolo_tags[0x10000];
|
||||||
/* No, wait, better start at the ROM. */
|
/* No, wait, better start at the ROM. */
|
||||||
@ -1400,28 +1399,12 @@ static struct arm_boot_info n810_binfo = {
|
|||||||
|
|
||||||
static void n800_init(QEMUMachineInitArgs *args)
|
static void n800_init(QEMUMachineInitArgs *args)
|
||||||
{
|
{
|
||||||
ram_addr_t ram_size = args->ram_size;
|
return n8x0_init(args, &n800_binfo, 800);
|
||||||
const char *cpu_model = args->cpu_model;
|
|
||||||
const char *kernel_filename = args->kernel_filename;
|
|
||||||
const char *kernel_cmdline = args->kernel_cmdline;
|
|
||||||
const char *initrd_filename = args->initrd_filename;
|
|
||||||
const char *boot_device = args->boot_device;
|
|
||||||
return n8x0_init(ram_size, boot_device,
|
|
||||||
kernel_filename, kernel_cmdline, initrd_filename,
|
|
||||||
cpu_model, &n800_binfo, 800);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void n810_init(QEMUMachineInitArgs *args)
|
static void n810_init(QEMUMachineInitArgs *args)
|
||||||
{
|
{
|
||||||
ram_addr_t ram_size = args->ram_size;
|
return n8x0_init(args, &n810_binfo, 810);
|
||||||
const char *cpu_model = args->cpu_model;
|
|
||||||
const char *kernel_filename = args->kernel_filename;
|
|
||||||
const char *kernel_cmdline = args->kernel_cmdline;
|
|
||||||
const char *initrd_filename = args->initrd_filename;
|
|
||||||
const char *boot_device = args->boot_device;
|
|
||||||
return n8x0_init(ram_size, boot_device,
|
|
||||||
kernel_filename, kernel_cmdline, initrd_filename,
|
|
||||||
cpu_model, &n810_binfo, 810);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static QEMUMachine n800_machine = {
|
static QEMUMachine n800_machine = {
|
||||||
|
@ -97,11 +97,7 @@ static struct arm_boot_info sx1_binfo = {
|
|||||||
.board_id = 0x265,
|
.board_id = 0x265,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void sx1_init(ram_addr_t ram_size,
|
static void sx1_init(QEMUMachineInitArgs *args, const int version)
|
||||||
const char *boot_device,
|
|
||||||
const char *kernel_filename, const char *kernel_cmdline,
|
|
||||||
const char *initrd_filename, const char *cpu_model,
|
|
||||||
const int version)
|
|
||||||
{
|
{
|
||||||
struct omap_mpu_state_s *mpu;
|
struct omap_mpu_state_s *mpu;
|
||||||
MemoryRegion *address_space = get_system_memory();
|
MemoryRegion *address_space = get_system_memory();
|
||||||
@ -121,7 +117,7 @@ static void sx1_init(ram_addr_t ram_size,
|
|||||||
flash_size = flash2_size;
|
flash_size = flash2_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
mpu = omap310_mpu_init(address_space, sx1_binfo.ram_size, cpu_model);
|
mpu = omap310_mpu_init(address_space, sx1_binfo.ram_size, args->cpu_model);
|
||||||
|
|
||||||
/* External Flash (EMIFS) */
|
/* External Flash (EMIFS) */
|
||||||
memory_region_init_ram(flash, "omap_sx1.flash0-0", flash_size);
|
memory_region_init_ram(flash, "omap_sx1.flash0-0", flash_size);
|
||||||
@ -192,16 +188,16 @@ static void sx1_init(ram_addr_t ram_size,
|
|||||||
OMAP_CS1_BASE, &cs[1]);
|
OMAP_CS1_BASE, &cs[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!kernel_filename && !fl_idx) {
|
if (!args->kernel_filename && !fl_idx) {
|
||||||
fprintf(stderr, "Kernel or Flash image must be specified\n");
|
fprintf(stderr, "Kernel or Flash image must be specified\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Load the kernel. */
|
/* Load the kernel. */
|
||||||
if (kernel_filename) {
|
if (args->kernel_filename) {
|
||||||
sx1_binfo.kernel_filename = kernel_filename;
|
sx1_binfo.kernel_filename = args->kernel_filename;
|
||||||
sx1_binfo.kernel_cmdline = kernel_cmdline;
|
sx1_binfo.kernel_cmdline = args->kernel_cmdline;
|
||||||
sx1_binfo.initrd_filename = initrd_filename;
|
sx1_binfo.initrd_filename = args->initrd_filename;
|
||||||
arm_load_kernel(mpu->cpu, &sx1_binfo);
|
arm_load_kernel(mpu->cpu, &sx1_binfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,26 +207,12 @@ static void sx1_init(ram_addr_t ram_size,
|
|||||||
|
|
||||||
static void sx1_init_v1(QEMUMachineInitArgs *args)
|
static void sx1_init_v1(QEMUMachineInitArgs *args)
|
||||||
{
|
{
|
||||||
ram_addr_t ram_size = args->ram_size;
|
sx1_init(args, 1);
|
||||||
const char *cpu_model = args->cpu_model;
|
|
||||||
const char *kernel_filename = args->kernel_filename;
|
|
||||||
const char *kernel_cmdline = args->kernel_cmdline;
|
|
||||||
const char *initrd_filename = args->initrd_filename;
|
|
||||||
const char *boot_device = args->boot_device;
|
|
||||||
sx1_init(ram_size, boot_device, kernel_filename,
|
|
||||||
kernel_cmdline, initrd_filename, cpu_model, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sx1_init_v2(QEMUMachineInitArgs *args)
|
static void sx1_init_v2(QEMUMachineInitArgs *args)
|
||||||
{
|
{
|
||||||
ram_addr_t ram_size = args->ram_size;
|
sx1_init(args, 2);
|
||||||
const char *cpu_model = args->cpu_model;
|
|
||||||
const char *kernel_filename = args->kernel_filename;
|
|
||||||
const char *kernel_cmdline = args->kernel_cmdline;
|
|
||||||
const char *initrd_filename = args->initrd_filename;
|
|
||||||
const char *boot_device = args->boot_device;
|
|
||||||
sx1_init(ram_size, boot_device, kernel_filename,
|
|
||||||
kernel_cmdline, initrd_filename, cpu_model, 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static QEMUMachine sx1_machine_v2 = {
|
static QEMUMachine sx1_machine_v2 = {
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
#include "qemu-timer.h"
|
#include "qemu-timer.h"
|
||||||
#include "exec-memory.h"
|
#include "exec-memory.h"
|
||||||
#include "host-utils.h"
|
#include "host-utils.h"
|
||||||
|
#include "sysbus.h"
|
||||||
|
|
||||||
#define PFLASH_BUG(fmt, ...) \
|
#define PFLASH_BUG(fmt, ...) \
|
||||||
do { \
|
do { \
|
||||||
@ -60,23 +61,28 @@ do { \
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct pflash_t {
|
struct pflash_t {
|
||||||
|
SysBusDevice busdev;
|
||||||
BlockDriverState *bs;
|
BlockDriverState *bs;
|
||||||
hwaddr base;
|
uint32_t nb_blocs;
|
||||||
hwaddr sector_len;
|
uint64_t sector_len;
|
||||||
hwaddr total_len;
|
uint8_t width;
|
||||||
int width;
|
uint8_t be;
|
||||||
int wcycle; /* if 0, the flash is read normally */
|
int wcycle; /* if 0, the flash is read normally */
|
||||||
int bypass;
|
int bypass;
|
||||||
int ro;
|
int ro;
|
||||||
uint8_t cmd;
|
uint8_t cmd;
|
||||||
uint8_t status;
|
uint8_t status;
|
||||||
uint16_t ident[4];
|
uint16_t ident0;
|
||||||
|
uint16_t ident1;
|
||||||
|
uint16_t ident2;
|
||||||
|
uint16_t ident3;
|
||||||
uint8_t cfi_len;
|
uint8_t cfi_len;
|
||||||
uint8_t cfi_table[0x52];
|
uint8_t cfi_table[0x52];
|
||||||
hwaddr counter;
|
hwaddr counter;
|
||||||
unsigned int writeblock_size;
|
unsigned int writeblock_size;
|
||||||
QEMUTimer *timer;
|
QEMUTimer *timer;
|
||||||
MemoryRegion mem;
|
MemoryRegion mem;
|
||||||
|
char *name;
|
||||||
void *storage;
|
void *storage;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -168,15 +174,16 @@ static uint32_t pflash_read (pflash_t *pfl, hwaddr offset,
|
|||||||
case 0x90:
|
case 0x90:
|
||||||
switch (boff) {
|
switch (boff) {
|
||||||
case 0:
|
case 0:
|
||||||
ret = pfl->ident[0] << 8 | pfl->ident[1];
|
ret = pfl->ident0 << 8 | pfl->ident1;
|
||||||
DPRINTF("%s: Manufacturer Code %04x\n", __func__, ret);
|
DPRINTF("%s: Manufacturer Code %04x\n", __func__, ret);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
ret = pfl->ident[2] << 8 | pfl->ident[3];
|
ret = pfl->ident2 << 8 | pfl->ident3;
|
||||||
DPRINTF("%s: Device ID Code %04x\n", __func__, ret);
|
DPRINTF("%s: Device ID Code %04x\n", __func__, ret);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
DPRINTF("%s: Read Device Information boff=%x\n", __func__, boff);
|
DPRINTF("%s: Read Device Information boff=%x\n", __func__,
|
||||||
|
(unsigned)boff);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -279,9 +286,8 @@ static void pflash_write(pflash_t *pfl, hwaddr offset,
|
|||||||
p = pfl->storage;
|
p = pfl->storage;
|
||||||
offset &= ~(pfl->sector_len - 1);
|
offset &= ~(pfl->sector_len - 1);
|
||||||
|
|
||||||
DPRINTF("%s: block erase at " TARGET_FMT_plx " bytes "
|
DPRINTF("%s: block erase at " TARGET_FMT_plx " bytes %x\n",
|
||||||
TARGET_FMT_plx "\n",
|
__func__, offset, (unsigned)pfl->sector_len);
|
||||||
__func__, offset, pfl->sector_len);
|
|
||||||
|
|
||||||
if (!pfl->ro) {
|
if (!pfl->ro) {
|
||||||
memset(p + offset, 0xff, pfl->sector_len);
|
memset(p + offset, 0xff, pfl->sector_len);
|
||||||
@ -543,19 +549,13 @@ static const MemoryRegionOps pflash_cfi01_ops_le = {
|
|||||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||||
};
|
};
|
||||||
|
|
||||||
pflash_t *pflash_cfi01_register(hwaddr base,
|
static int pflash_cfi01_init(SysBusDevice *dev)
|
||||||
DeviceState *qdev, const char *name,
|
|
||||||
hwaddr size,
|
|
||||||
BlockDriverState *bs, uint32_t sector_len,
|
|
||||||
int nb_blocs, int width,
|
|
||||||
uint16_t id0, uint16_t id1,
|
|
||||||
uint16_t id2, uint16_t id3, int be)
|
|
||||||
{
|
{
|
||||||
pflash_t *pfl;
|
pflash_t *pfl = FROM_SYSBUS(typeof(*pfl), dev);
|
||||||
hwaddr total_len;
|
uint64_t total_len;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
total_len = sector_len * nb_blocs;
|
total_len = pfl->sector_len * pfl->nb_blocs;
|
||||||
|
|
||||||
/* XXX: to be fixed */
|
/* XXX: to be fixed */
|
||||||
#if 0
|
#if 0
|
||||||
@ -564,27 +564,22 @@ pflash_t *pflash_cfi01_register(hwaddr base,
|
|||||||
return NULL;
|
return NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pfl = g_malloc0(sizeof(pflash_t));
|
|
||||||
|
|
||||||
memory_region_init_rom_device(
|
memory_region_init_rom_device(
|
||||||
&pfl->mem, be ? &pflash_cfi01_ops_be : &pflash_cfi01_ops_le, pfl,
|
&pfl->mem, pfl->be ? &pflash_cfi01_ops_be : &pflash_cfi01_ops_le, pfl,
|
||||||
name, size);
|
pfl->name, total_len);
|
||||||
vmstate_register_ram(&pfl->mem, qdev);
|
vmstate_register_ram(&pfl->mem, DEVICE(pfl));
|
||||||
pfl->storage = memory_region_get_ram_ptr(&pfl->mem);
|
pfl->storage = memory_region_get_ram_ptr(&pfl->mem);
|
||||||
memory_region_add_subregion(get_system_memory(), base, &pfl->mem);
|
sysbus_init_mmio(dev, &pfl->mem);
|
||||||
|
|
||||||
pfl->bs = bs;
|
|
||||||
if (pfl->bs) {
|
if (pfl->bs) {
|
||||||
/* read the initial flash content */
|
/* read the initial flash content */
|
||||||
ret = bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9);
|
ret = bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9);
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
memory_region_del_subregion(get_system_memory(), &pfl->mem);
|
vmstate_unregister_ram(&pfl->mem, DEVICE(pfl));
|
||||||
vmstate_unregister_ram(&pfl->mem, qdev);
|
|
||||||
memory_region_destroy(&pfl->mem);
|
memory_region_destroy(&pfl->mem);
|
||||||
g_free(pfl);
|
return 1;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
bdrv_attach_dev_nofail(pfl->bs, pfl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pfl->bs) {
|
if (pfl->bs) {
|
||||||
@ -594,17 +589,9 @@ pflash_t *pflash_cfi01_register(hwaddr base,
|
|||||||
}
|
}
|
||||||
|
|
||||||
pfl->timer = qemu_new_timer_ns(vm_clock, pflash_timer, pfl);
|
pfl->timer = qemu_new_timer_ns(vm_clock, pflash_timer, pfl);
|
||||||
pfl->base = base;
|
|
||||||
pfl->sector_len = sector_len;
|
|
||||||
pfl->total_len = total_len;
|
|
||||||
pfl->width = width;
|
|
||||||
pfl->wcycle = 0;
|
pfl->wcycle = 0;
|
||||||
pfl->cmd = 0;
|
pfl->cmd = 0;
|
||||||
pfl->status = 0;
|
pfl->status = 0;
|
||||||
pfl->ident[0] = id0;
|
|
||||||
pfl->ident[1] = id1;
|
|
||||||
pfl->ident[2] = id2;
|
|
||||||
pfl->ident[3] = id3;
|
|
||||||
/* Hardcoded CFI table */
|
/* Hardcoded CFI table */
|
||||||
pfl->cfi_len = 0x52;
|
pfl->cfi_len = 0x52;
|
||||||
/* Standard "QRY" string */
|
/* Standard "QRY" string */
|
||||||
@ -653,7 +640,7 @@ pflash_t *pflash_cfi01_register(hwaddr base,
|
|||||||
pfl->cfi_table[0x28] = 0x02;
|
pfl->cfi_table[0x28] = 0x02;
|
||||||
pfl->cfi_table[0x29] = 0x00;
|
pfl->cfi_table[0x29] = 0x00;
|
||||||
/* Max number of bytes in multi-bytes write */
|
/* Max number of bytes in multi-bytes write */
|
||||||
if (width == 1) {
|
if (pfl->width == 1) {
|
||||||
pfl->cfi_table[0x2A] = 0x08;
|
pfl->cfi_table[0x2A] = 0x08;
|
||||||
} else {
|
} else {
|
||||||
pfl->cfi_table[0x2A] = 0x0B;
|
pfl->cfi_table[0x2A] = 0x0B;
|
||||||
@ -664,10 +651,10 @@ pflash_t *pflash_cfi01_register(hwaddr base,
|
|||||||
/* Number of erase block regions (uniform) */
|
/* Number of erase block regions (uniform) */
|
||||||
pfl->cfi_table[0x2C] = 0x01;
|
pfl->cfi_table[0x2C] = 0x01;
|
||||||
/* Erase block region 1 */
|
/* Erase block region 1 */
|
||||||
pfl->cfi_table[0x2D] = nb_blocs - 1;
|
pfl->cfi_table[0x2D] = pfl->nb_blocs - 1;
|
||||||
pfl->cfi_table[0x2E] = (nb_blocs - 1) >> 8;
|
pfl->cfi_table[0x2E] = (pfl->nb_blocs - 1) >> 8;
|
||||||
pfl->cfi_table[0x2F] = sector_len >> 8;
|
pfl->cfi_table[0x2F] = pfl->sector_len >> 8;
|
||||||
pfl->cfi_table[0x30] = sector_len >> 16;
|
pfl->cfi_table[0x30] = pfl->sector_len >> 16;
|
||||||
|
|
||||||
/* Extended */
|
/* Extended */
|
||||||
pfl->cfi_table[0x31] = 'P';
|
pfl->cfi_table[0x31] = 'P';
|
||||||
@ -689,6 +676,75 @@ pflash_t *pflash_cfi01_register(hwaddr base,
|
|||||||
|
|
||||||
pfl->cfi_table[0x3f] = 0x01; /* Number of protection fields */
|
pfl->cfi_table[0x3f] = 0x01; /* Number of protection fields */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Property pflash_cfi01_properties[] = {
|
||||||
|
DEFINE_PROP_DRIVE("drive", struct pflash_t, bs),
|
||||||
|
DEFINE_PROP_UINT32("num-blocks", struct pflash_t, nb_blocs, 0),
|
||||||
|
DEFINE_PROP_UINT64("sector-length", struct pflash_t, sector_len, 0),
|
||||||
|
DEFINE_PROP_UINT8("width", struct pflash_t, width, 0),
|
||||||
|
DEFINE_PROP_UINT8("big-endian", struct pflash_t, be, 0),
|
||||||
|
DEFINE_PROP_UINT16("id0", struct pflash_t, ident0, 0),
|
||||||
|
DEFINE_PROP_UINT16("id1", struct pflash_t, ident1, 0),
|
||||||
|
DEFINE_PROP_UINT16("id2", struct pflash_t, ident2, 0),
|
||||||
|
DEFINE_PROP_UINT16("id3", struct pflash_t, ident3, 0),
|
||||||
|
DEFINE_PROP_STRING("name", struct pflash_t, name),
|
||||||
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
|
};
|
||||||
|
|
||||||
|
static void pflash_cfi01_class_init(ObjectClass *klass, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||||
|
|
||||||
|
k->init = pflash_cfi01_init;
|
||||||
|
dc->props = pflash_cfi01_properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const TypeInfo pflash_cfi01_info = {
|
||||||
|
.name = "cfi.pflash01",
|
||||||
|
.parent = TYPE_SYS_BUS_DEVICE,
|
||||||
|
.instance_size = sizeof(struct pflash_t),
|
||||||
|
.class_init = pflash_cfi01_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void pflash_cfi01_register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&pflash_cfi01_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(pflash_cfi01_register_types)
|
||||||
|
|
||||||
|
pflash_t *pflash_cfi01_register(hwaddr base,
|
||||||
|
DeviceState *qdev, const char *name,
|
||||||
|
hwaddr size,
|
||||||
|
BlockDriverState *bs,
|
||||||
|
uint32_t sector_len, int nb_blocs, int width,
|
||||||
|
uint16_t id0, uint16_t id1,
|
||||||
|
uint16_t id2, uint16_t id3, int be)
|
||||||
|
{
|
||||||
|
DeviceState *dev = qdev_create(NULL, "cfi.pflash01");
|
||||||
|
SysBusDevice *busdev = sysbus_from_qdev(dev);
|
||||||
|
pflash_t *pfl = (pflash_t *)object_dynamic_cast(OBJECT(dev),
|
||||||
|
"cfi.pflash01");
|
||||||
|
|
||||||
|
if (bs && qdev_prop_set_drive(dev, "drive", bs)) {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
qdev_prop_set_uint32(dev, "num-blocks", nb_blocs);
|
||||||
|
qdev_prop_set_uint64(dev, "sector-length", sector_len);
|
||||||
|
qdev_prop_set_uint8(dev, "width", width);
|
||||||
|
qdev_prop_set_uint8(dev, "big-endian", !!be);
|
||||||
|
qdev_prop_set_uint16(dev, "id0", id0);
|
||||||
|
qdev_prop_set_uint16(dev, "id1", id1);
|
||||||
|
qdev_prop_set_uint16(dev, "id2", id2);
|
||||||
|
qdev_prop_set_uint16(dev, "id3", id3);
|
||||||
|
qdev_prop_set_string(dev, "name", name);
|
||||||
|
qdev_init_nofail(dev);
|
||||||
|
|
||||||
|
sysbus_mmio_map(busdev, 0, base);
|
||||||
return pfl;
|
return pfl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
#include "block.h"
|
#include "block.h"
|
||||||
#include "exec-memory.h"
|
#include "exec-memory.h"
|
||||||
#include "host-utils.h"
|
#include "host-utils.h"
|
||||||
|
#include "sysbus.h"
|
||||||
|
|
||||||
//#define PFLASH_DEBUG
|
//#define PFLASH_DEBUG
|
||||||
#ifdef PFLASH_DEBUG
|
#ifdef PFLASH_DEBUG
|
||||||
@ -55,19 +56,26 @@ do { \
|
|||||||
#define PFLASH_LAZY_ROMD_THRESHOLD 42
|
#define PFLASH_LAZY_ROMD_THRESHOLD 42
|
||||||
|
|
||||||
struct pflash_t {
|
struct pflash_t {
|
||||||
|
SysBusDevice busdev;
|
||||||
BlockDriverState *bs;
|
BlockDriverState *bs;
|
||||||
hwaddr base;
|
|
||||||
uint32_t sector_len;
|
uint32_t sector_len;
|
||||||
|
uint32_t nb_blocs;
|
||||||
uint32_t chip_len;
|
uint32_t chip_len;
|
||||||
int mappings;
|
uint8_t mappings;
|
||||||
int width;
|
uint8_t width;
|
||||||
|
uint8_t be;
|
||||||
int wcycle; /* if 0, the flash is read normally */
|
int wcycle; /* if 0, the flash is read normally */
|
||||||
int bypass;
|
int bypass;
|
||||||
int ro;
|
int ro;
|
||||||
uint8_t cmd;
|
uint8_t cmd;
|
||||||
uint8_t status;
|
uint8_t status;
|
||||||
uint16_t ident[4];
|
/* FIXME: implement array device properties */
|
||||||
uint16_t unlock_addr[2];
|
uint16_t ident0;
|
||||||
|
uint16_t ident1;
|
||||||
|
uint16_t ident2;
|
||||||
|
uint16_t ident3;
|
||||||
|
uint16_t unlock_addr0;
|
||||||
|
uint16_t unlock_addr1;
|
||||||
uint8_t cfi_len;
|
uint8_t cfi_len;
|
||||||
uint8_t cfi_table[0x52];
|
uint8_t cfi_table[0x52];
|
||||||
QEMUTimer *timer;
|
QEMUTimer *timer;
|
||||||
@ -80,6 +88,7 @@ struct pflash_t {
|
|||||||
MemoryRegion orig_mem;
|
MemoryRegion orig_mem;
|
||||||
int rom_mode;
|
int rom_mode;
|
||||||
int read_counter; /* used for lazy switch-back to rom mode */
|
int read_counter; /* used for lazy switch-back to rom mode */
|
||||||
|
char *name;
|
||||||
void *storage;
|
void *storage;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -190,16 +199,17 @@ static uint32_t pflash_read (pflash_t *pfl, hwaddr offset,
|
|||||||
switch (boff) {
|
switch (boff) {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
case 0x01:
|
case 0x01:
|
||||||
ret = pfl->ident[boff & 0x01];
|
ret = boff & 0x01 ? pfl->ident1 : pfl->ident0;
|
||||||
break;
|
break;
|
||||||
case 0x02:
|
case 0x02:
|
||||||
ret = 0x00; /* Pretend all sectors are unprotected */
|
ret = 0x00; /* Pretend all sectors are unprotected */
|
||||||
break;
|
break;
|
||||||
case 0x0E:
|
case 0x0E:
|
||||||
case 0x0F:
|
case 0x0F:
|
||||||
if (pfl->ident[2 + (boff & 0x01)] == (uint8_t)-1)
|
ret = boff & 0x01 ? pfl->ident3 : pfl->ident2;
|
||||||
|
if (ret == (uint8_t)-1) {
|
||||||
goto flash_read;
|
goto flash_read;
|
||||||
ret = pfl->ident[2 + (boff & 0x01)];
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
goto flash_read;
|
goto flash_read;
|
||||||
@ -283,9 +293,9 @@ static void pflash_write (pflash_t *pfl, hwaddr offset,
|
|||||||
pfl->cmd = 0x98;
|
pfl->cmd = 0x98;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (boff != pfl->unlock_addr[0] || cmd != 0xAA) {
|
if (boff != pfl->unlock_addr0 || cmd != 0xAA) {
|
||||||
DPRINTF("%s: unlock0 failed " TARGET_FMT_plx " %02x %04x\n",
|
DPRINTF("%s: unlock0 failed " TARGET_FMT_plx " %02x %04x\n",
|
||||||
__func__, boff, cmd, pfl->unlock_addr[0]);
|
__func__, boff, cmd, pfl->unlock_addr0);
|
||||||
goto reset_flash;
|
goto reset_flash;
|
||||||
}
|
}
|
||||||
DPRINTF("%s: unlock sequence started\n", __func__);
|
DPRINTF("%s: unlock sequence started\n", __func__);
|
||||||
@ -293,7 +303,7 @@ static void pflash_write (pflash_t *pfl, hwaddr offset,
|
|||||||
case 1:
|
case 1:
|
||||||
/* We started an unlock sequence */
|
/* We started an unlock sequence */
|
||||||
check_unlock1:
|
check_unlock1:
|
||||||
if (boff != pfl->unlock_addr[1] || cmd != 0x55) {
|
if (boff != pfl->unlock_addr1 || cmd != 0x55) {
|
||||||
DPRINTF("%s: unlock1 failed " TARGET_FMT_plx " %02x\n", __func__,
|
DPRINTF("%s: unlock1 failed " TARGET_FMT_plx " %02x\n", __func__,
|
||||||
boff, cmd);
|
boff, cmd);
|
||||||
goto reset_flash;
|
goto reset_flash;
|
||||||
@ -302,7 +312,7 @@ static void pflash_write (pflash_t *pfl, hwaddr offset,
|
|||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
/* We finished an unlock sequence */
|
/* We finished an unlock sequence */
|
||||||
if (!pfl->bypass && boff != pfl->unlock_addr[0]) {
|
if (!pfl->bypass && boff != pfl->unlock_addr0) {
|
||||||
DPRINTF("%s: command failed " TARGET_FMT_plx " %02x\n", __func__,
|
DPRINTF("%s: command failed " TARGET_FMT_plx " %02x\n", __func__,
|
||||||
boff, cmd);
|
boff, cmd);
|
||||||
goto reset_flash;
|
goto reset_flash;
|
||||||
@ -400,7 +410,7 @@ static void pflash_write (pflash_t *pfl, hwaddr offset,
|
|||||||
case 5:
|
case 5:
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case 0x10:
|
case 0x10:
|
||||||
if (boff != pfl->unlock_addr[0]) {
|
if (boff != pfl->unlock_addr0) {
|
||||||
DPRINTF("%s: chip erase: invalid address " TARGET_FMT_plx "\n",
|
DPRINTF("%s: chip erase: invalid address " TARGET_FMT_plx "\n",
|
||||||
__func__, offset);
|
__func__, offset);
|
||||||
goto reset_flash;
|
goto reset_flash;
|
||||||
@ -575,50 +585,38 @@ static const MemoryRegionOps pflash_cfi02_ops_le = {
|
|||||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||||
};
|
};
|
||||||
|
|
||||||
pflash_t *pflash_cfi02_register(hwaddr base,
|
static int pflash_cfi02_init(SysBusDevice *dev)
|
||||||
DeviceState *qdev, const char *name,
|
|
||||||
hwaddr size,
|
|
||||||
BlockDriverState *bs, uint32_t sector_len,
|
|
||||||
int nb_blocs, int nb_mappings, int width,
|
|
||||||
uint16_t id0, uint16_t id1,
|
|
||||||
uint16_t id2, uint16_t id3,
|
|
||||||
uint16_t unlock_addr0, uint16_t unlock_addr1,
|
|
||||||
int be)
|
|
||||||
{
|
{
|
||||||
pflash_t *pfl;
|
pflash_t *pfl = FROM_SYSBUS(typeof(*pfl), dev);
|
||||||
int32_t chip_len;
|
uint32_t chip_len;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
chip_len = sector_len * nb_blocs;
|
chip_len = pfl->sector_len * pfl->nb_blocs;
|
||||||
/* XXX: to be fixed */
|
/* XXX: to be fixed */
|
||||||
#if 0
|
#if 0
|
||||||
if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) &&
|
if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) &&
|
||||||
total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024))
|
total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024))
|
||||||
return NULL;
|
return NULL;
|
||||||
#endif
|
#endif
|
||||||
pfl = g_malloc0(sizeof(pflash_t));
|
|
||||||
memory_region_init_rom_device(
|
memory_region_init_rom_device(&pfl->orig_mem, pfl->be ?
|
||||||
&pfl->orig_mem, be ? &pflash_cfi02_ops_be : &pflash_cfi02_ops_le, pfl,
|
&pflash_cfi02_ops_be : &pflash_cfi02_ops_le,
|
||||||
name, size);
|
pfl, pfl->name, chip_len);
|
||||||
vmstate_register_ram(&pfl->orig_mem, qdev);
|
vmstate_register_ram(&pfl->orig_mem, DEVICE(pfl));
|
||||||
pfl->storage = memory_region_get_ram_ptr(&pfl->orig_mem);
|
pfl->storage = memory_region_get_ram_ptr(&pfl->orig_mem);
|
||||||
pfl->base = base;
|
|
||||||
pfl->chip_len = chip_len;
|
pfl->chip_len = chip_len;
|
||||||
pfl->mappings = nb_mappings;
|
|
||||||
pfl->bs = bs;
|
|
||||||
if (pfl->bs) {
|
if (pfl->bs) {
|
||||||
/* read the initial flash content */
|
/* read the initial flash content */
|
||||||
ret = bdrv_read(pfl->bs, 0, pfl->storage, chip_len >> 9);
|
ret = bdrv_read(pfl->bs, 0, pfl->storage, chip_len >> 9);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
g_free(pfl);
|
g_free(pfl);
|
||||||
return NULL;
|
return 1;
|
||||||
}
|
}
|
||||||
bdrv_attach_dev_nofail(pfl->bs, pfl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pflash_setup_mappings(pfl);
|
pflash_setup_mappings(pfl);
|
||||||
pfl->rom_mode = 1;
|
pfl->rom_mode = 1;
|
||||||
memory_region_add_subregion(get_system_memory(), pfl->base, &pfl->mem);
|
sysbus_init_mmio(dev, &pfl->mem);
|
||||||
|
|
||||||
if (pfl->bs) {
|
if (pfl->bs) {
|
||||||
pfl->ro = bdrv_is_read_only(pfl->bs);
|
pfl->ro = bdrv_is_read_only(pfl->bs);
|
||||||
@ -627,17 +625,9 @@ pflash_t *pflash_cfi02_register(hwaddr base,
|
|||||||
}
|
}
|
||||||
|
|
||||||
pfl->timer = qemu_new_timer_ns(vm_clock, pflash_timer, pfl);
|
pfl->timer = qemu_new_timer_ns(vm_clock, pflash_timer, pfl);
|
||||||
pfl->sector_len = sector_len;
|
|
||||||
pfl->width = width;
|
|
||||||
pfl->wcycle = 0;
|
pfl->wcycle = 0;
|
||||||
pfl->cmd = 0;
|
pfl->cmd = 0;
|
||||||
pfl->status = 0;
|
pfl->status = 0;
|
||||||
pfl->ident[0] = id0;
|
|
||||||
pfl->ident[1] = id1;
|
|
||||||
pfl->ident[2] = id2;
|
|
||||||
pfl->ident[3] = id3;
|
|
||||||
pfl->unlock_addr[0] = unlock_addr0;
|
|
||||||
pfl->unlock_addr[1] = unlock_addr1;
|
|
||||||
/* Hardcoded CFI table (mostly from SG29 Spansion flash) */
|
/* Hardcoded CFI table (mostly from SG29 Spansion flash) */
|
||||||
pfl->cfi_len = 0x52;
|
pfl->cfi_len = 0x52;
|
||||||
/* Standard "QRY" string */
|
/* Standard "QRY" string */
|
||||||
@ -693,10 +683,10 @@ pflash_t *pflash_cfi02_register(hwaddr base,
|
|||||||
/* Number of erase block regions (uniform) */
|
/* Number of erase block regions (uniform) */
|
||||||
pfl->cfi_table[0x2C] = 0x01;
|
pfl->cfi_table[0x2C] = 0x01;
|
||||||
/* Erase block region 1 */
|
/* Erase block region 1 */
|
||||||
pfl->cfi_table[0x2D] = nb_blocs - 1;
|
pfl->cfi_table[0x2D] = pfl->nb_blocs - 1;
|
||||||
pfl->cfi_table[0x2E] = (nb_blocs - 1) >> 8;
|
pfl->cfi_table[0x2E] = (pfl->nb_blocs - 1) >> 8;
|
||||||
pfl->cfi_table[0x2F] = sector_len >> 8;
|
pfl->cfi_table[0x2F] = pfl->sector_len >> 8;
|
||||||
pfl->cfi_table[0x30] = sector_len >> 16;
|
pfl->cfi_table[0x30] = pfl->sector_len >> 16;
|
||||||
|
|
||||||
/* Extended */
|
/* Extended */
|
||||||
pfl->cfi_table[0x31] = 'P';
|
pfl->cfi_table[0x31] = 'P';
|
||||||
@ -716,5 +706,81 @@ pflash_t *pflash_cfi02_register(hwaddr base,
|
|||||||
pfl->cfi_table[0x3b] = 0x00;
|
pfl->cfi_table[0x3b] = 0x00;
|
||||||
pfl->cfi_table[0x3c] = 0x00;
|
pfl->cfi_table[0x3c] = 0x00;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Property pflash_cfi02_properties[] = {
|
||||||
|
DEFINE_PROP_DRIVE("drive", struct pflash_t, bs),
|
||||||
|
DEFINE_PROP_UINT32("num-blocks", struct pflash_t, nb_blocs, 0),
|
||||||
|
DEFINE_PROP_UINT32("sector-length", struct pflash_t, sector_len, 0),
|
||||||
|
DEFINE_PROP_UINT8("width", struct pflash_t, width, 0),
|
||||||
|
DEFINE_PROP_UINT8("mappings", struct pflash_t, mappings, 0),
|
||||||
|
DEFINE_PROP_UINT8("big-endian", struct pflash_t, be, 0),
|
||||||
|
DEFINE_PROP_UINT16("id0", struct pflash_t, ident0, 0),
|
||||||
|
DEFINE_PROP_UINT16("id1", struct pflash_t, ident1, 0),
|
||||||
|
DEFINE_PROP_UINT16("id2", struct pflash_t, ident2, 0),
|
||||||
|
DEFINE_PROP_UINT16("id3", struct pflash_t, ident3, 0),
|
||||||
|
DEFINE_PROP_UINT16("unlock-addr0", struct pflash_t, unlock_addr0, 0),
|
||||||
|
DEFINE_PROP_UINT16("unlock-addr1", struct pflash_t, unlock_addr1, 0),
|
||||||
|
DEFINE_PROP_STRING("name", struct pflash_t, name),
|
||||||
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
|
};
|
||||||
|
|
||||||
|
static void pflash_cfi02_class_init(ObjectClass *klass, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||||
|
|
||||||
|
k->init = pflash_cfi02_init;
|
||||||
|
dc->props = pflash_cfi02_properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo pflash_cfi02_info = {
|
||||||
|
.name = "cfi.pflash02",
|
||||||
|
.parent = TYPE_SYS_BUS_DEVICE,
|
||||||
|
.instance_size = sizeof(struct pflash_t),
|
||||||
|
.class_init = pflash_cfi02_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void pflash_cfi02_register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&pflash_cfi02_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(pflash_cfi02_register_types)
|
||||||
|
|
||||||
|
pflash_t *pflash_cfi02_register(hwaddr base,
|
||||||
|
DeviceState *qdev, const char *name,
|
||||||
|
hwaddr size,
|
||||||
|
BlockDriverState *bs, uint32_t sector_len,
|
||||||
|
int nb_blocs, int nb_mappings, int width,
|
||||||
|
uint16_t id0, uint16_t id1,
|
||||||
|
uint16_t id2, uint16_t id3,
|
||||||
|
uint16_t unlock_addr0, uint16_t unlock_addr1,
|
||||||
|
int be)
|
||||||
|
{
|
||||||
|
DeviceState *dev = qdev_create(NULL, "cfi.pflash02");
|
||||||
|
SysBusDevice *busdev = sysbus_from_qdev(dev);
|
||||||
|
pflash_t *pfl = (pflash_t *)object_dynamic_cast(OBJECT(dev),
|
||||||
|
"cfi.pflash02");
|
||||||
|
|
||||||
|
if (bs && qdev_prop_set_drive(dev, "drive", bs)) {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
qdev_prop_set_uint32(dev, "num-blocks", nb_blocs);
|
||||||
|
qdev_prop_set_uint32(dev, "sector-length", sector_len);
|
||||||
|
qdev_prop_set_uint8(dev, "width", width);
|
||||||
|
qdev_prop_set_uint8(dev, "mappings", nb_mappings);
|
||||||
|
qdev_prop_set_uint8(dev, "big-endian", !!be);
|
||||||
|
qdev_prop_set_uint16(dev, "id0", id0);
|
||||||
|
qdev_prop_set_uint16(dev, "id1", id1);
|
||||||
|
qdev_prop_set_uint16(dev, "id2", id2);
|
||||||
|
qdev_prop_set_uint16(dev, "id3", id3);
|
||||||
|
qdev_prop_set_uint16(dev, "unlock-addr0", unlock_addr0);
|
||||||
|
qdev_prop_set_uint16(dev, "unlock-addr1", unlock_addr1);
|
||||||
|
qdev_prop_set_string(dev, "name", name);
|
||||||
|
qdev_init_nofail(dev);
|
||||||
|
|
||||||
|
sysbus_mmio_map(busdev, 0, base);
|
||||||
return pfl;
|
return pfl;
|
||||||
}
|
}
|
||||||
|
@ -95,7 +95,8 @@ static uint64_t pl050_read(void *opaque, hwaddr offset,
|
|||||||
case 4: /* KMIIR */
|
case 4: /* KMIIR */
|
||||||
return s->pending | 2;
|
return s->pending | 2;
|
||||||
default:
|
default:
|
||||||
hw_error("pl050_read: Bad offset %x\n", (int)offset);
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"pl050_read: Bad offset %x\n", (int)offset);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -123,7 +124,8 @@ static void pl050_write(void *opaque, hwaddr offset,
|
|||||||
s->clk = value;
|
s->clk = value;
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
hw_error("pl050_write: Bad offset %x\n", (int)offset);
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"pl050_write: Bad offset %x\n", (int)offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static const MemoryRegionOps pl050_ops = {
|
static const MemoryRegionOps pl050_ops = {
|
||||||
|
@ -164,7 +164,8 @@ static uint64_t pl061_read(void *opaque, hwaddr offset,
|
|||||||
case 0x528: /* Analog mode select */
|
case 0x528: /* Analog mode select */
|
||||||
return s->amsel;
|
return s->amsel;
|
||||||
default:
|
default:
|
||||||
hw_error("pl061_read: Bad offset %x\n", (int)offset);
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"pl061_read: Bad offset %x\n", (int)offset);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -239,7 +240,8 @@ static void pl061_write(void *opaque, hwaddr offset,
|
|||||||
s->amsel = value & 0xff;
|
s->amsel = value & 0xff;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
hw_error("pl061_write: Bad offset %x\n", (int)offset);
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"pl061_write: Bad offset %x\n", (int)offset);
|
||||||
}
|
}
|
||||||
pl061_update(s);
|
pl061_update(s);
|
||||||
}
|
}
|
||||||
|
11
hw/pl080.c
11
hw/pl080.c
@ -281,7 +281,8 @@ static uint64_t pl080_read(void *opaque, hwaddr offset,
|
|||||||
return s->sync;
|
return s->sync;
|
||||||
default:
|
default:
|
||||||
bad_offset:
|
bad_offset:
|
||||||
hw_error("pl080_read: Bad offset %x\n", (int)offset);
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"pl080_read: Bad offset %x\n", (int)offset);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -327,12 +328,13 @@ static void pl080_write(void *opaque, hwaddr offset,
|
|||||||
case 10: /* SoftLBReq */
|
case 10: /* SoftLBReq */
|
||||||
case 11: /* SoftLSReq */
|
case 11: /* SoftLSReq */
|
||||||
/* ??? Implement these. */
|
/* ??? Implement these. */
|
||||||
hw_error("pl080_write: Soft DMA not implemented\n");
|
qemu_log_mask(LOG_UNIMP, "pl080_write: Soft DMA not implemented\n");
|
||||||
break;
|
break;
|
||||||
case 12: /* Configuration */
|
case 12: /* Configuration */
|
||||||
s->conf = value;
|
s->conf = value;
|
||||||
if (s->conf & (PL080_CONF_M1 | PL080_CONF_M1)) {
|
if (s->conf & (PL080_CONF_M1 | PL080_CONF_M1)) {
|
||||||
hw_error("pl080_write: Big-endian DMA not implemented\n");
|
qemu_log_mask(LOG_UNIMP,
|
||||||
|
"pl080_write: Big-endian DMA not implemented\n");
|
||||||
}
|
}
|
||||||
pl080_run(s);
|
pl080_run(s);
|
||||||
break;
|
break;
|
||||||
@ -341,7 +343,8 @@ static void pl080_write(void *opaque, hwaddr offset,
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
bad_offset:
|
bad_offset:
|
||||||
hw_error("pl080_write: Bad offset %x\n", (int)offset);
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"pl080_write: Bad offset %x\n", (int)offset);
|
||||||
}
|
}
|
||||||
pl080_update(s);
|
pl080_update(s);
|
||||||
}
|
}
|
||||||
|
@ -349,7 +349,8 @@ static uint64_t pl110_read(void *opaque, hwaddr offset,
|
|||||||
case 12: /* LCDLPCURR */
|
case 12: /* LCDLPCURR */
|
||||||
return s->lpbase;
|
return s->lpbase;
|
||||||
default:
|
default:
|
||||||
hw_error("pl110_read: Bad offset %x\n", (int)offset);
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"pl110_read: Bad offset %x\n", (int)offset);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -417,7 +418,8 @@ static void pl110_write(void *opaque, hwaddr offset,
|
|||||||
pl110_update(s);
|
pl110_update(s);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
hw_error("pl110_write: Bad offset %x\n", (int)offset);
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"pl110_write: Bad offset %x\n", (int)offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,7 +199,7 @@ static void pl190_write(void *opaque, hwaddr offset,
|
|||||||
break;
|
break;
|
||||||
case 0xc0: /* ITCR */
|
case 0xc0: /* ITCR */
|
||||||
if (val) {
|
if (val) {
|
||||||
hw_error("pl190: Test mode not implemented\n");
|
qemu_log_mask(LOG_UNIMP, "pl190: Test mode not implemented\n");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -44,11 +44,8 @@ static const int realview_board_id[] = {
|
|||||||
0x76d
|
0x76d
|
||||||
};
|
};
|
||||||
|
|
||||||
static void realview_init(ram_addr_t ram_size,
|
static void realview_init(QEMUMachineInitArgs *args,
|
||||||
const char *boot_device,
|
enum realview_board_type board_type)
|
||||||
const char *kernel_filename, const char *kernel_cmdline,
|
|
||||||
const char *initrd_filename, const char *cpu_model,
|
|
||||||
enum realview_board_type board_type)
|
|
||||||
{
|
{
|
||||||
ARMCPU *cpu = NULL;
|
ARMCPU *cpu = NULL;
|
||||||
CPUARMState *env;
|
CPUARMState *env;
|
||||||
@ -73,6 +70,7 @@ static void realview_init(ram_addr_t ram_size,
|
|||||||
uint32_t proc_id = 0;
|
uint32_t proc_id = 0;
|
||||||
uint32_t sys_id;
|
uint32_t sys_id;
|
||||||
ram_addr_t low_ram_size;
|
ram_addr_t low_ram_size;
|
||||||
|
ram_addr_t ram_size = args->ram_size;
|
||||||
|
|
||||||
switch (board_type) {
|
switch (board_type) {
|
||||||
case BOARD_EB:
|
case BOARD_EB:
|
||||||
@ -89,7 +87,7 @@ static void realview_init(ram_addr_t ram_size,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
for (n = 0; n < smp_cpus; n++) {
|
for (n = 0; n < smp_cpus; n++) {
|
||||||
cpu = cpu_arm_init(cpu_model);
|
cpu = cpu_arm_init(args->cpu_model);
|
||||||
if (!cpu) {
|
if (!cpu) {
|
||||||
fprintf(stderr, "Unable to find CPU definition\n");
|
fprintf(stderr, "Unable to find CPU definition\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
@ -321,9 +319,9 @@ static void realview_init(ram_addr_t ram_size,
|
|||||||
memory_region_add_subregion(sysmem, SMP_BOOT_ADDR, ram_hack);
|
memory_region_add_subregion(sysmem, SMP_BOOT_ADDR, ram_hack);
|
||||||
|
|
||||||
realview_binfo.ram_size = ram_size;
|
realview_binfo.ram_size = ram_size;
|
||||||
realview_binfo.kernel_filename = kernel_filename;
|
realview_binfo.kernel_filename = args->kernel_filename;
|
||||||
realview_binfo.kernel_cmdline = kernel_cmdline;
|
realview_binfo.kernel_cmdline = args->kernel_cmdline;
|
||||||
realview_binfo.initrd_filename = initrd_filename;
|
realview_binfo.initrd_filename = args->initrd_filename;
|
||||||
realview_binfo.nb_cpus = smp_cpus;
|
realview_binfo.nb_cpus = smp_cpus;
|
||||||
realview_binfo.board_id = realview_board_id[board_type];
|
realview_binfo.board_id = realview_board_id[board_type];
|
||||||
realview_binfo.loader_start = (board_type == BOARD_PB_A8 ? 0x70000000 : 0);
|
realview_binfo.loader_start = (board_type == BOARD_PB_A8 ? 0x70000000 : 0);
|
||||||
@ -332,62 +330,34 @@ static void realview_init(ram_addr_t ram_size,
|
|||||||
|
|
||||||
static void realview_eb_init(QEMUMachineInitArgs *args)
|
static void realview_eb_init(QEMUMachineInitArgs *args)
|
||||||
{
|
{
|
||||||
ram_addr_t ram_size = args->ram_size;
|
if (!args->cpu_model) {
|
||||||
const char *cpu_model = args->cpu_model;
|
args->cpu_model = "arm926";
|
||||||
const char *kernel_filename = args->kernel_filename;
|
|
||||||
const char *kernel_cmdline = args->kernel_cmdline;
|
|
||||||
const char *initrd_filename = args->initrd_filename;
|
|
||||||
const char *boot_device = args->boot_device;
|
|
||||||
if (!cpu_model) {
|
|
||||||
cpu_model = "arm926";
|
|
||||||
}
|
}
|
||||||
realview_init(ram_size, boot_device, kernel_filename, kernel_cmdline,
|
realview_init(args, BOARD_EB);
|
||||||
initrd_filename, cpu_model, BOARD_EB);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void realview_eb_mpcore_init(QEMUMachineInitArgs *args)
|
static void realview_eb_mpcore_init(QEMUMachineInitArgs *args)
|
||||||
{
|
{
|
||||||
ram_addr_t ram_size = args->ram_size;
|
if (!args->cpu_model) {
|
||||||
const char *cpu_model = args->cpu_model;
|
args->cpu_model = "arm11mpcore";
|
||||||
const char *kernel_filename = args->kernel_filename;
|
|
||||||
const char *kernel_cmdline = args->kernel_cmdline;
|
|
||||||
const char *initrd_filename = args->initrd_filename;
|
|
||||||
const char *boot_device = args->boot_device;
|
|
||||||
if (!cpu_model) {
|
|
||||||
cpu_model = "arm11mpcore";
|
|
||||||
}
|
}
|
||||||
realview_init(ram_size, boot_device, kernel_filename, kernel_cmdline,
|
realview_init(args, BOARD_EB_MPCORE);
|
||||||
initrd_filename, cpu_model, BOARD_EB_MPCORE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void realview_pb_a8_init(QEMUMachineInitArgs *args)
|
static void realview_pb_a8_init(QEMUMachineInitArgs *args)
|
||||||
{
|
{
|
||||||
ram_addr_t ram_size = args->ram_size;
|
if (!args->cpu_model) {
|
||||||
const char *cpu_model = args->cpu_model;
|
args->cpu_model = "cortex-a8";
|
||||||
const char *kernel_filename = args->kernel_filename;
|
|
||||||
const char *kernel_cmdline = args->kernel_cmdline;
|
|
||||||
const char *initrd_filename = args->initrd_filename;
|
|
||||||
const char *boot_device = args->boot_device;
|
|
||||||
if (!cpu_model) {
|
|
||||||
cpu_model = "cortex-a8";
|
|
||||||
}
|
}
|
||||||
realview_init(ram_size, boot_device, kernel_filename, kernel_cmdline,
|
realview_init(args, BOARD_PB_A8);
|
||||||
initrd_filename, cpu_model, BOARD_PB_A8);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void realview_pbx_a9_init(QEMUMachineInitArgs *args)
|
static void realview_pbx_a9_init(QEMUMachineInitArgs *args)
|
||||||
{
|
{
|
||||||
ram_addr_t ram_size = args->ram_size;
|
if (!args->cpu_model) {
|
||||||
const char *cpu_model = args->cpu_model;
|
args->cpu_model = "cortex-a9";
|
||||||
const char *kernel_filename = args->kernel_filename;
|
|
||||||
const char *kernel_cmdline = args->kernel_cmdline;
|
|
||||||
const char *initrd_filename = args->initrd_filename;
|
|
||||||
const char *boot_device = args->boot_device;
|
|
||||||
if (!cpu_model) {
|
|
||||||
cpu_model = "cortex-a9";
|
|
||||||
}
|
}
|
||||||
realview_init(ram_size, boot_device, kernel_filename, kernel_cmdline,
|
realview_init(args, BOARD_PBX_A9);
|
||||||
initrd_filename, cpu_model, BOARD_PBX_A9);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static QEMUMachine realview_eb_machine = {
|
static QEMUMachine realview_eb_machine = {
|
||||||
|
106
hw/sd.c
106
hw/sd.c
@ -55,24 +55,28 @@ typedef enum {
|
|||||||
sd_illegal = -2,
|
sd_illegal = -2,
|
||||||
} sd_rsp_type_t;
|
} sd_rsp_type_t;
|
||||||
|
|
||||||
|
enum SDCardModes {
|
||||||
|
sd_inactive,
|
||||||
|
sd_card_identification_mode,
|
||||||
|
sd_data_transfer_mode,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SDCardStates {
|
||||||
|
sd_inactive_state = -1,
|
||||||
|
sd_idle_state = 0,
|
||||||
|
sd_ready_state,
|
||||||
|
sd_identification_state,
|
||||||
|
sd_standby_state,
|
||||||
|
sd_transfer_state,
|
||||||
|
sd_sendingdata_state,
|
||||||
|
sd_receivingdata_state,
|
||||||
|
sd_programming_state,
|
||||||
|
sd_disconnect_state,
|
||||||
|
};
|
||||||
|
|
||||||
struct SDState {
|
struct SDState {
|
||||||
enum {
|
uint32_t mode; /* current card mode, one of SDCardModes */
|
||||||
sd_inactive,
|
int32_t state; /* current card state, one of SDCardStates */
|
||||||
sd_card_identification_mode,
|
|
||||||
sd_data_transfer_mode,
|
|
||||||
} mode;
|
|
||||||
enum {
|
|
||||||
sd_inactive_state = -1,
|
|
||||||
sd_idle_state = 0,
|
|
||||||
sd_ready_state,
|
|
||||||
sd_identification_state,
|
|
||||||
sd_standby_state,
|
|
||||||
sd_transfer_state,
|
|
||||||
sd_sendingdata_state,
|
|
||||||
sd_receivingdata_state,
|
|
||||||
sd_programming_state,
|
|
||||||
sd_disconnect_state,
|
|
||||||
} state;
|
|
||||||
uint32_t ocr;
|
uint32_t ocr;
|
||||||
uint8_t scr[8];
|
uint8_t scr[8];
|
||||||
uint8_t cid[16];
|
uint8_t cid[16];
|
||||||
@ -83,21 +87,22 @@ struct SDState {
|
|||||||
uint32_t vhs;
|
uint32_t vhs;
|
||||||
bool wp_switch;
|
bool wp_switch;
|
||||||
unsigned long *wp_groups;
|
unsigned long *wp_groups;
|
||||||
|
int32_t wpgrps_size;
|
||||||
uint64_t size;
|
uint64_t size;
|
||||||
int blk_len;
|
uint32_t blk_len;
|
||||||
uint32_t erase_start;
|
uint32_t erase_start;
|
||||||
uint32_t erase_end;
|
uint32_t erase_end;
|
||||||
uint8_t pwd[16];
|
uint8_t pwd[16];
|
||||||
int pwd_len;
|
uint32_t pwd_len;
|
||||||
int function_group[6];
|
uint8_t function_group[6];
|
||||||
|
|
||||||
bool spi;
|
bool spi;
|
||||||
int current_cmd;
|
uint8_t current_cmd;
|
||||||
/* True if we will handle the next command as an ACMD. Note that this does
|
/* True if we will handle the next command as an ACMD. Note that this does
|
||||||
* *not* track the APP_CMD status bit!
|
* *not* track the APP_CMD status bit!
|
||||||
*/
|
*/
|
||||||
bool expecting_acmd;
|
bool expecting_acmd;
|
||||||
int blk_written;
|
uint32_t blk_written;
|
||||||
uint64_t data_start;
|
uint64_t data_start;
|
||||||
uint32_t data_offset;
|
uint32_t data_offset;
|
||||||
uint8_t data[512];
|
uint8_t data[512];
|
||||||
@ -421,8 +426,9 @@ static void sd_reset(SDState *sd, BlockDriverState *bdrv)
|
|||||||
if (sd->wp_groups)
|
if (sd->wp_groups)
|
||||||
g_free(sd->wp_groups);
|
g_free(sd->wp_groups);
|
||||||
sd->wp_switch = bdrv ? bdrv_is_read_only(bdrv) : false;
|
sd->wp_switch = bdrv ? bdrv_is_read_only(bdrv) : false;
|
||||||
sd->wp_groups = bitmap_new(sect);
|
sd->wpgrps_size = sect;
|
||||||
memset(sd->function_group, 0, sizeof(int) * 6);
|
sd->wp_groups = bitmap_new(sd->wpgrps_size);
|
||||||
|
memset(sd->function_group, 0, sizeof(sd->function_group));
|
||||||
sd->erase_start = 0;
|
sd->erase_start = 0;
|
||||||
sd->erase_end = 0;
|
sd->erase_end = 0;
|
||||||
sd->size = size;
|
sd->size = size;
|
||||||
@ -446,6 +452,38 @@ static const BlockDevOps sd_block_ops = {
|
|||||||
.change_media_cb = sd_cardchange,
|
.change_media_cb = sd_cardchange,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const VMStateDescription sd_vmstate = {
|
||||||
|
.name = "sd-card",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_UINT32(mode, SDState),
|
||||||
|
VMSTATE_INT32(state, SDState),
|
||||||
|
VMSTATE_UINT8_ARRAY(cid, SDState, 16),
|
||||||
|
VMSTATE_UINT8_ARRAY(csd, SDState, 16),
|
||||||
|
VMSTATE_UINT16(rca, SDState),
|
||||||
|
VMSTATE_UINT32(card_status, SDState),
|
||||||
|
VMSTATE_PARTIAL_BUFFER(sd_status, SDState, 1),
|
||||||
|
VMSTATE_UINT32(vhs, SDState),
|
||||||
|
VMSTATE_BITMAP(wp_groups, SDState, 0, wpgrps_size),
|
||||||
|
VMSTATE_UINT32(blk_len, SDState),
|
||||||
|
VMSTATE_UINT32(erase_start, SDState),
|
||||||
|
VMSTATE_UINT32(erase_end, SDState),
|
||||||
|
VMSTATE_UINT8_ARRAY(pwd, SDState, 16),
|
||||||
|
VMSTATE_UINT32(pwd_len, SDState),
|
||||||
|
VMSTATE_UINT8_ARRAY(function_group, SDState, 6),
|
||||||
|
VMSTATE_UINT8(current_cmd, SDState),
|
||||||
|
VMSTATE_BOOL(expecting_acmd, SDState),
|
||||||
|
VMSTATE_UINT32(blk_written, SDState),
|
||||||
|
VMSTATE_UINT64(data_start, SDState),
|
||||||
|
VMSTATE_UINT32(data_offset, SDState),
|
||||||
|
VMSTATE_UINT8_ARRAY(data, SDState, 512),
|
||||||
|
VMSTATE_BUFFER_UNSAFE(buf, SDState, 1, 512),
|
||||||
|
VMSTATE_BOOL(enable, SDState),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/* We do not model the chip select pin, so allow the board to select
|
/* We do not model the chip select pin, so allow the board to select
|
||||||
whether card should be in SSI or MMC/SD mode. It is also up to the
|
whether card should be in SSI or MMC/SD mode. It is also up to the
|
||||||
board to ensure that ssi transfers only occur when the chip select
|
board to ensure that ssi transfers only occur when the chip select
|
||||||
@ -463,6 +501,7 @@ SDState *sd_init(BlockDriverState *bs, bool is_spi)
|
|||||||
bdrv_attach_dev_nofail(sd->bdrv, sd);
|
bdrv_attach_dev_nofail(sd->bdrv, sd);
|
||||||
bdrv_set_dev_ops(sd->bdrv, &sd_block_ops, sd);
|
bdrv_set_dev_ops(sd->bdrv, &sd_block_ops, sd);
|
||||||
}
|
}
|
||||||
|
vmstate_register(NULL, -1, &sd_vmstate, sd);
|
||||||
return sd;
|
return sd;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -476,19 +515,28 @@ void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert)
|
|||||||
|
|
||||||
static void sd_erase(SDState *sd)
|
static void sd_erase(SDState *sd)
|
||||||
{
|
{
|
||||||
int i, start, end;
|
int i;
|
||||||
|
uint64_t erase_start = sd->erase_start;
|
||||||
|
uint64_t erase_end = sd->erase_end;
|
||||||
|
|
||||||
if (!sd->erase_start || !sd->erase_end) {
|
if (!sd->erase_start || !sd->erase_end) {
|
||||||
sd->card_status |= ERASE_SEQ_ERROR;
|
sd->card_status |= ERASE_SEQ_ERROR;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
start = sd_addr_to_wpnum(sd->erase_start);
|
if (extract32(sd->ocr, OCR_CCS_BITN, 1)) {
|
||||||
end = sd_addr_to_wpnum(sd->erase_end);
|
/* High capacity memory card: erase units are 512 byte blocks */
|
||||||
|
erase_start *= 512;
|
||||||
|
erase_end *= 512;
|
||||||
|
}
|
||||||
|
|
||||||
|
erase_start = sd_addr_to_wpnum(erase_start);
|
||||||
|
erase_end = sd_addr_to_wpnum(erase_end);
|
||||||
sd->erase_start = 0;
|
sd->erase_start = 0;
|
||||||
sd->erase_end = 0;
|
sd->erase_end = 0;
|
||||||
sd->csd[14] |= 0x40;
|
sd->csd[14] |= 0x40;
|
||||||
|
|
||||||
for (i = start; i <= end; i++) {
|
for (i = erase_start; i <= erase_end; i++) {
|
||||||
if (test_bit(i, sd->wp_groups)) {
|
if (test_bit(i, sd->wp_groups)) {
|
||||||
sd->card_status |= WP_ERASE_SKIP;
|
sd->card_status |= WP_ERASE_SKIP;
|
||||||
}
|
}
|
||||||
@ -567,7 +615,7 @@ static void sd_lock_command(SDState *sd)
|
|||||||
sd->card_status |= LOCK_UNLOCK_FAILED;
|
sd->card_status |= LOCK_UNLOCK_FAILED;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bitmap_zero(sd->wp_groups, sd_addr_to_wpnum(sd->size) + 1);
|
bitmap_zero(sd->wp_groups, sd->wpgrps_size);
|
||||||
sd->csd[14] &= ~0x10;
|
sd->csd[14] &= ~0x10;
|
||||||
sd->card_status &= ~CARD_IS_LOCKED;
|
sd->card_status &= ~CARD_IS_LOCKED;
|
||||||
sd->pwd_len = 0;
|
sd->pwd_len = 0;
|
||||||
|
1
hw/sd.h
1
hw/sd.h
@ -50,6 +50,7 @@
|
|||||||
#define READY_FOR_DATA (1 << 8)
|
#define READY_FOR_DATA (1 << 8)
|
||||||
#define APP_CMD (1 << 5)
|
#define APP_CMD (1 << 5)
|
||||||
#define AKE_SEQ_ERROR (1 << 3)
|
#define AKE_SEQ_ERROR (1 << 3)
|
||||||
|
#define OCR_CCS_BITN 30
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
sd_none = -1,
|
sd_none = -1,
|
||||||
|
45
hw/spitz.c
45
hw/spitz.c
@ -879,15 +879,14 @@ static struct arm_boot_info spitz_binfo = {
|
|||||||
.ram_size = 0x04000000,
|
.ram_size = 0x04000000,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void spitz_common_init(ram_addr_t ram_size,
|
static void spitz_common_init(QEMUMachineInitArgs *args,
|
||||||
const char *kernel_filename,
|
enum spitz_model_e model, int arm_id)
|
||||||
const char *kernel_cmdline, const char *initrd_filename,
|
|
||||||
const char *cpu_model, enum spitz_model_e model, int arm_id)
|
|
||||||
{
|
{
|
||||||
PXA2xxState *mpu;
|
PXA2xxState *mpu;
|
||||||
DeviceState *scp0, *scp1 = NULL;
|
DeviceState *scp0, *scp1 = NULL;
|
||||||
MemoryRegion *address_space_mem = get_system_memory();
|
MemoryRegion *address_space_mem = get_system_memory();
|
||||||
MemoryRegion *rom = g_new(MemoryRegion, 1);
|
MemoryRegion *rom = g_new(MemoryRegion, 1);
|
||||||
|
const char *cpu_model = args->cpu_model;
|
||||||
|
|
||||||
if (!cpu_model)
|
if (!cpu_model)
|
||||||
cpu_model = (model == terrier) ? "pxa270-c5" : "pxa270-c0";
|
cpu_model = (model == terrier) ? "pxa270-c5" : "pxa270-c0";
|
||||||
@ -928,9 +927,9 @@ static void spitz_common_init(ram_addr_t ram_size,
|
|||||||
/* A 4.0 GB microdrive is permanently sitting in CF slot 0. */
|
/* A 4.0 GB microdrive is permanently sitting in CF slot 0. */
|
||||||
spitz_microdrive_attach(mpu, 0);
|
spitz_microdrive_attach(mpu, 0);
|
||||||
|
|
||||||
spitz_binfo.kernel_filename = kernel_filename;
|
spitz_binfo.kernel_filename = args->kernel_filename;
|
||||||
spitz_binfo.kernel_cmdline = kernel_cmdline;
|
spitz_binfo.kernel_cmdline = args->kernel_cmdline;
|
||||||
spitz_binfo.initrd_filename = initrd_filename;
|
spitz_binfo.initrd_filename = args->initrd_filename;
|
||||||
spitz_binfo.board_id = arm_id;
|
spitz_binfo.board_id = arm_id;
|
||||||
arm_load_kernel(mpu->cpu, &spitz_binfo);
|
arm_load_kernel(mpu->cpu, &spitz_binfo);
|
||||||
sl_bootparam_write(SL_PXA_PARAM_BASE);
|
sl_bootparam_write(SL_PXA_PARAM_BASE);
|
||||||
@ -938,46 +937,22 @@ static void spitz_common_init(ram_addr_t ram_size,
|
|||||||
|
|
||||||
static void spitz_init(QEMUMachineInitArgs *args)
|
static void spitz_init(QEMUMachineInitArgs *args)
|
||||||
{
|
{
|
||||||
ram_addr_t ram_size = args->ram_size;
|
spitz_common_init(args, spitz, 0x2c9);
|
||||||
const char *cpu_model = args->cpu_model;
|
|
||||||
const char *kernel_filename = args->kernel_filename;
|
|
||||||
const char *kernel_cmdline = args->kernel_cmdline;
|
|
||||||
const char *initrd_filename = args->initrd_filename;
|
|
||||||
spitz_common_init(ram_size, kernel_filename,
|
|
||||||
kernel_cmdline, initrd_filename, cpu_model, spitz, 0x2c9);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void borzoi_init(QEMUMachineInitArgs *args)
|
static void borzoi_init(QEMUMachineInitArgs *args)
|
||||||
{
|
{
|
||||||
ram_addr_t ram_size = args->ram_size;
|
spitz_common_init(args, borzoi, 0x33f);
|
||||||
const char *cpu_model = args->cpu_model;
|
|
||||||
const char *kernel_filename = args->kernel_filename;
|
|
||||||
const char *kernel_cmdline = args->kernel_cmdline;
|
|
||||||
const char *initrd_filename = args->initrd_filename;
|
|
||||||
spitz_common_init(ram_size, kernel_filename,
|
|
||||||
kernel_cmdline, initrd_filename, cpu_model, borzoi, 0x33f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void akita_init(QEMUMachineInitArgs *args)
|
static void akita_init(QEMUMachineInitArgs *args)
|
||||||
{
|
{
|
||||||
ram_addr_t ram_size = args->ram_size;
|
spitz_common_init(args, akita, 0x2e8);
|
||||||
const char *cpu_model = args->cpu_model;
|
|
||||||
const char *kernel_filename = args->kernel_filename;
|
|
||||||
const char *kernel_cmdline = args->kernel_cmdline;
|
|
||||||
const char *initrd_filename = args->initrd_filename;
|
|
||||||
spitz_common_init(ram_size, kernel_filename,
|
|
||||||
kernel_cmdline, initrd_filename, cpu_model, akita, 0x2e8);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void terrier_init(QEMUMachineInitArgs *args)
|
static void terrier_init(QEMUMachineInitArgs *args)
|
||||||
{
|
{
|
||||||
ram_addr_t ram_size = args->ram_size;
|
spitz_common_init(args, terrier, 0x33f);
|
||||||
const char *cpu_model = args->cpu_model;
|
|
||||||
const char *kernel_filename = args->kernel_filename;
|
|
||||||
const char *kernel_cmdline = args->kernel_cmdline;
|
|
||||||
const char *initrd_filename = args->initrd_filename;
|
|
||||||
spitz_common_init(ram_size, kernel_filename,
|
|
||||||
kernel_cmdline, initrd_filename, cpu_model, terrier, 0x33f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static QEMUMachine akitapda_machine = {
|
static QEMUMachine akitapda_machine = {
|
||||||
|
@ -40,7 +40,8 @@ static uint64_t versatile_i2c_read(void *opaque, hwaddr offset,
|
|||||||
if (offset == 0) {
|
if (offset == 0) {
|
||||||
return (s->out & 1) | (s->in << 1);
|
return (s->out & 1) | (s->in << 1);
|
||||||
} else {
|
} else {
|
||||||
hw_error("%s: Bad offset 0x%x\n", __func__, (int)offset);
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"%s: Bad offset 0x%x\n", __func__, (int)offset);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -58,7 +59,8 @@ static void versatile_i2c_write(void *opaque, hwaddr offset,
|
|||||||
s->out &= ~value;
|
s->out &= ~value;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
hw_error("%s: Bad offset 0x%x\n", __func__, (int)offset);
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"%s: Bad offset 0x%x\n", __func__, (int)offset);
|
||||||
}
|
}
|
||||||
bitbang_i2c_set(s->bitbang, BITBANG_I2C_SCL, (s->out & 1) != 0);
|
bitbang_i2c_set(s->bitbang, BITBANG_I2C_SCL, (s->out & 1) != 0);
|
||||||
s->in = bitbang_i2c_set(s->bitbang, BITBANG_I2C_SDA, (s->out & 2) != 0);
|
s->in = bitbang_i2c_set(s->bitbang, BITBANG_I2C_SDA, (s->out & 2) != 0);
|
||||||
|
@ -167,11 +167,7 @@ static int vpb_sic_init(SysBusDevice *dev)
|
|||||||
|
|
||||||
static struct arm_boot_info versatile_binfo;
|
static struct arm_boot_info versatile_binfo;
|
||||||
|
|
||||||
static void versatile_init(ram_addr_t ram_size,
|
static void versatile_init(QEMUMachineInitArgs *args, int board_id)
|
||||||
const char *boot_device,
|
|
||||||
const char *kernel_filename, const char *kernel_cmdline,
|
|
||||||
const char *initrd_filename, const char *cpu_model,
|
|
||||||
int board_id)
|
|
||||||
{
|
{
|
||||||
ARMCPU *cpu;
|
ARMCPU *cpu;
|
||||||
MemoryRegion *sysmem = get_system_memory();
|
MemoryRegion *sysmem = get_system_memory();
|
||||||
@ -189,15 +185,15 @@ static void versatile_init(ram_addr_t ram_size,
|
|||||||
int done_smc = 0;
|
int done_smc = 0;
|
||||||
DriveInfo *dinfo;
|
DriveInfo *dinfo;
|
||||||
|
|
||||||
if (!cpu_model) {
|
if (!args->cpu_model) {
|
||||||
cpu_model = "arm926";
|
args->cpu_model = "arm926";
|
||||||
}
|
}
|
||||||
cpu = cpu_arm_init(cpu_model);
|
cpu = cpu_arm_init(args->cpu_model);
|
||||||
if (!cpu) {
|
if (!cpu) {
|
||||||
fprintf(stderr, "Unable to find CPU definition\n");
|
fprintf(stderr, "Unable to find CPU definition\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
memory_region_init_ram(ram, "versatile.ram", ram_size);
|
memory_region_init_ram(ram, "versatile.ram", args->ram_size);
|
||||||
vmstate_register_ram_global(ram);
|
vmstate_register_ram_global(ram);
|
||||||
/* ??? RAM should repeat to fill physical memory space. */
|
/* ??? RAM should repeat to fill physical memory space. */
|
||||||
/* SDRAM at address zero. */
|
/* SDRAM at address zero. */
|
||||||
@ -340,40 +336,22 @@ static void versatile_init(ram_addr_t ram_size,
|
|||||||
fprintf(stderr, "qemu: Error registering flash memory.\n");
|
fprintf(stderr, "qemu: Error registering flash memory.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
versatile_binfo.ram_size = ram_size;
|
versatile_binfo.ram_size = args->ram_size;
|
||||||
versatile_binfo.kernel_filename = kernel_filename;
|
versatile_binfo.kernel_filename = args->kernel_filename;
|
||||||
versatile_binfo.kernel_cmdline = kernel_cmdline;
|
versatile_binfo.kernel_cmdline = args->kernel_cmdline;
|
||||||
versatile_binfo.initrd_filename = initrd_filename;
|
versatile_binfo.initrd_filename = args->initrd_filename;
|
||||||
versatile_binfo.board_id = board_id;
|
versatile_binfo.board_id = board_id;
|
||||||
arm_load_kernel(cpu, &versatile_binfo);
|
arm_load_kernel(cpu, &versatile_binfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vpb_init(QEMUMachineInitArgs *args)
|
static void vpb_init(QEMUMachineInitArgs *args)
|
||||||
{
|
{
|
||||||
ram_addr_t ram_size = args->ram_size;
|
versatile_init(args, 0x183);
|
||||||
const char *cpu_model = args->cpu_model;
|
|
||||||
const char *kernel_filename = args->kernel_filename;
|
|
||||||
const char *kernel_cmdline = args->kernel_cmdline;
|
|
||||||
const char *initrd_filename = args->initrd_filename;
|
|
||||||
const char *boot_device = args->boot_device;
|
|
||||||
versatile_init(ram_size,
|
|
||||||
boot_device,
|
|
||||||
kernel_filename, kernel_cmdline,
|
|
||||||
initrd_filename, cpu_model, 0x183);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vab_init(QEMUMachineInitArgs *args)
|
static void vab_init(QEMUMachineInitArgs *args)
|
||||||
{
|
{
|
||||||
ram_addr_t ram_size = args->ram_size;
|
versatile_init(args, 0x25e);
|
||||||
const char *cpu_model = args->cpu_model;
|
|
||||||
const char *kernel_filename = args->kernel_filename;
|
|
||||||
const char *kernel_cmdline = args->kernel_cmdline;
|
|
||||||
const char *initrd_filename = args->initrd_filename;
|
|
||||||
const char *boot_device = args->boot_device;
|
|
||||||
versatile_init(ram_size,
|
|
||||||
boot_device,
|
|
||||||
kernel_filename, kernel_cmdline,
|
|
||||||
initrd_filename, cpu_model, 0x25e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static QEMUMachine versatilepb_machine = {
|
static QEMUMachine versatilepb_machine = {
|
||||||
|
@ -348,12 +348,7 @@ static const VEDBoardInfo a15_daughterboard = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void vexpress_common_init(const VEDBoardInfo *daughterboard,
|
static void vexpress_common_init(const VEDBoardInfo *daughterboard,
|
||||||
ram_addr_t ram_size,
|
QEMUMachineInitArgs *args)
|
||||||
const char *boot_device,
|
|
||||||
const char *kernel_filename,
|
|
||||||
const char *kernel_cmdline,
|
|
||||||
const char *initrd_filename,
|
|
||||||
const char *cpu_model)
|
|
||||||
{
|
{
|
||||||
DeviceState *dev, *sysctl, *pl041;
|
DeviceState *dev, *sysctl, *pl041;
|
||||||
qemu_irq pic[64];
|
qemu_irq pic[64];
|
||||||
@ -366,7 +361,8 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard,
|
|||||||
MemoryRegion *sram = g_new(MemoryRegion, 1);
|
MemoryRegion *sram = g_new(MemoryRegion, 1);
|
||||||
const hwaddr *map = daughterboard->motherboard_map;
|
const hwaddr *map = daughterboard->motherboard_map;
|
||||||
|
|
||||||
daughterboard->init(daughterboard, ram_size, cpu_model, pic, &proc_id);
|
daughterboard->init(daughterboard, args->ram_size, args->cpu_model,
|
||||||
|
pic, &proc_id);
|
||||||
|
|
||||||
/* Motherboard peripherals: the wiring is the same but the
|
/* Motherboard peripherals: the wiring is the same but the
|
||||||
* addresses vary between the legacy and A-Series memory maps.
|
* addresses vary between the legacy and A-Series memory maps.
|
||||||
@ -454,10 +450,10 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard,
|
|||||||
|
|
||||||
/* VE_DAPROM: not modelled */
|
/* VE_DAPROM: not modelled */
|
||||||
|
|
||||||
vexpress_binfo.ram_size = ram_size;
|
vexpress_binfo.ram_size = args->ram_size;
|
||||||
vexpress_binfo.kernel_filename = kernel_filename;
|
vexpress_binfo.kernel_filename = args->kernel_filename;
|
||||||
vexpress_binfo.kernel_cmdline = kernel_cmdline;
|
vexpress_binfo.kernel_cmdline = args->kernel_cmdline;
|
||||||
vexpress_binfo.initrd_filename = initrd_filename;
|
vexpress_binfo.initrd_filename = args->initrd_filename;
|
||||||
vexpress_binfo.nb_cpus = smp_cpus;
|
vexpress_binfo.nb_cpus = smp_cpus;
|
||||||
vexpress_binfo.board_id = VEXPRESS_BOARD_ID;
|
vexpress_binfo.board_id = VEXPRESS_BOARD_ID;
|
||||||
vexpress_binfo.loader_start = daughterboard->loader_start;
|
vexpress_binfo.loader_start = daughterboard->loader_start;
|
||||||
@ -469,28 +465,12 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard,
|
|||||||
|
|
||||||
static void vexpress_a9_init(QEMUMachineInitArgs *args)
|
static void vexpress_a9_init(QEMUMachineInitArgs *args)
|
||||||
{
|
{
|
||||||
ram_addr_t ram_size = args->ram_size;
|
vexpress_common_init(&a9_daughterboard, args);
|
||||||
const char *cpu_model = args->cpu_model;
|
|
||||||
const char *kernel_filename = args->kernel_filename;
|
|
||||||
const char *kernel_cmdline = args->kernel_cmdline;
|
|
||||||
const char *initrd_filename = args->initrd_filename;
|
|
||||||
const char *boot_device = args->boot_device;
|
|
||||||
vexpress_common_init(&a9_daughterboard,
|
|
||||||
ram_size, boot_device, kernel_filename,
|
|
||||||
kernel_cmdline, initrd_filename, cpu_model);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vexpress_a15_init(QEMUMachineInitArgs *args)
|
static void vexpress_a15_init(QEMUMachineInitArgs *args)
|
||||||
{
|
{
|
||||||
ram_addr_t ram_size = args->ram_size;
|
vexpress_common_init(&a15_daughterboard, args);
|
||||||
const char *cpu_model = args->cpu_model;
|
|
||||||
const char *kernel_filename = args->kernel_filename;
|
|
||||||
const char *kernel_cmdline = args->kernel_cmdline;
|
|
||||||
const char *initrd_filename = args->initrd_filename;
|
|
||||||
const char *boot_device = args->boot_device;
|
|
||||||
vexpress_common_init(&a15_daughterboard,
|
|
||||||
ram_size, boot_device, kernel_filename,
|
|
||||||
kernel_cmdline, initrd_filename, cpu_model);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static QEMUMachine vexpress_a9_machine = {
|
static QEMUMachine vexpress_a9_machine = {
|
||||||
|
41
savevm.c
41
savevm.c
@ -86,6 +86,7 @@
|
|||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "qmp-commands.h"
|
#include "qmp-commands.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
|
#include "bitops.h"
|
||||||
|
|
||||||
#define SELF_ANNOUNCE_ROUNDS 5
|
#define SELF_ANNOUNCE_ROUNDS 5
|
||||||
|
|
||||||
@ -1132,6 +1133,46 @@ const VMStateInfo vmstate_info_unused_buffer = {
|
|||||||
.put = put_unused_buffer,
|
.put = put_unused_buffer,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* bitmaps (as defined by bitmap.h). Note that size here is the size
|
||||||
|
* of the bitmap in bits. The on-the-wire format of a bitmap is 64
|
||||||
|
* bit words with the bits in big endian order. The in-memory format
|
||||||
|
* is an array of 'unsigned long', which may be either 32 or 64 bits.
|
||||||
|
*/
|
||||||
|
/* This is the number of 64 bit words sent over the wire */
|
||||||
|
#define BITS_TO_U64S(nr) DIV_ROUND_UP(nr, 64)
|
||||||
|
static int get_bitmap(QEMUFile *f, void *pv, size_t size)
|
||||||
|
{
|
||||||
|
unsigned long *bmp = pv;
|
||||||
|
int i, idx = 0;
|
||||||
|
for (i = 0; i < BITS_TO_U64S(size); i++) {
|
||||||
|
uint64_t w = qemu_get_be64(f);
|
||||||
|
bmp[idx++] = w;
|
||||||
|
if (sizeof(unsigned long) == 4 && idx < BITS_TO_LONGS(size)) {
|
||||||
|
bmp[idx++] = w >> 32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void put_bitmap(QEMUFile *f, void *pv, size_t size)
|
||||||
|
{
|
||||||
|
unsigned long *bmp = pv;
|
||||||
|
int i, idx = 0;
|
||||||
|
for (i = 0; i < BITS_TO_U64S(size); i++) {
|
||||||
|
uint64_t w = bmp[idx++];
|
||||||
|
if (sizeof(unsigned long) == 4 && idx < BITS_TO_LONGS(size)) {
|
||||||
|
w |= ((uint64_t)bmp[idx++]) << 32;
|
||||||
|
}
|
||||||
|
qemu_put_be64(f, w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const VMStateInfo vmstate_info_bitmap = {
|
||||||
|
.name = "bitmap",
|
||||||
|
.get = get_bitmap,
|
||||||
|
.put = put_bitmap,
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct CompatEntry {
|
typedef struct CompatEntry {
|
||||||
char idstr[256];
|
char idstr[256];
|
||||||
int instance_id;
|
int instance_id;
|
||||||
|
13
vmstate.h
13
vmstate.h
@ -139,6 +139,7 @@ extern const VMStateInfo vmstate_info_uint64;
|
|||||||
extern const VMStateInfo vmstate_info_timer;
|
extern const VMStateInfo vmstate_info_timer;
|
||||||
extern const VMStateInfo vmstate_info_buffer;
|
extern const VMStateInfo vmstate_info_buffer;
|
||||||
extern const VMStateInfo vmstate_info_unused_buffer;
|
extern const VMStateInfo vmstate_info_unused_buffer;
|
||||||
|
extern const VMStateInfo vmstate_info_bitmap;
|
||||||
|
|
||||||
#define type_check_array(t1,t2,n) ((t1(*)[n])0 - (t2*)0)
|
#define type_check_array(t1,t2,n) ((t1(*)[n])0 - (t2*)0)
|
||||||
#define type_check_pointer(t1,t2) ((t1**)0 - (t2*)0)
|
#define type_check_pointer(t1,t2) ((t1**)0 - (t2*)0)
|
||||||
@ -411,6 +412,18 @@ extern const VMStateInfo vmstate_info_unused_buffer;
|
|||||||
.flags = VMS_BUFFER, \
|
.flags = VMS_BUFFER, \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* _field_size should be a int32_t field in the _state struct giving the
|
||||||
|
* size of the bitmap _field in bits.
|
||||||
|
*/
|
||||||
|
#define VMSTATE_BITMAP(_field, _state, _version, _field_size) { \
|
||||||
|
.name = (stringify(_field)), \
|
||||||
|
.version_id = (_version), \
|
||||||
|
.size_offset = vmstate_offset_value(_state, _field_size, int32_t),\
|
||||||
|
.info = &vmstate_info_bitmap, \
|
||||||
|
.flags = VMS_VBUFFER|VMS_POINTER, \
|
||||||
|
.offset = offsetof(_state, _field), \
|
||||||
|
}
|
||||||
|
|
||||||
/* _f : field name
|
/* _f : field name
|
||||||
_f_n : num of elements field_name
|
_f_n : num of elements field_name
|
||||||
_n : num of elements
|
_n : num of elements
|
||||||
|
Loading…
x
Reference in New Issue
Block a user