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. */
|
||||
return 0;
|
||||
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. */
|
||||
break;
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -487,7 +488,8 @@ static void gic_dist_writeb(void *opaque, hwaddr offset,
|
||||
gic_update(s);
|
||||
return;
|
||||
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,
|
||||
@ -556,7 +558,8 @@ static uint32_t gic_cpu_read(GICState *s, int cpu, int offset)
|
||||
case 0x18: /* Highest Pending Interrupt */
|
||||
return s->current_pending[cpu];
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -577,7 +580,8 @@ static void gic_cpu_write(GICState *s, int cpu, int offset, uint32_t value)
|
||||
case 0x10: /* End Of Interrupt */
|
||||
return gic_complete_irq(s, cpu, value & 0x3ff);
|
||||
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;
|
||||
}
|
||||
gic_update(s);
|
||||
|
@ -87,7 +87,8 @@ static uint64_t l2x0_priv_read(void *opaque, hwaddr offset,
|
||||
case 0xF80:
|
||||
return 0;
|
||||
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;
|
||||
}
|
||||
return 0;
|
||||
@ -128,7 +129,8 @@ static void l2x0_priv_write(void *opaque, hwaddr offset,
|
||||
case 0xF80:
|
||||
return;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -184,7 +184,9 @@ static uint64_t arm_sysctl_read(void *opaque, hwaddr offset,
|
||||
return s->sys_cfgstat;
|
||||
default:
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -339,7 +341,9 @@ static void arm_sysctl_write(void *opaque, hwaddr offset,
|
||||
return;
|
||||
default:
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +64,8 @@ static uint32_t arm_timer_read(void *opaque, hwaddr offset)
|
||||
return 0;
|
||||
return s->int_level;
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -131,7 +132,8 @@ static void arm_timer_write(void *opaque, hwaddr offset,
|
||||
arm_timer_recalibrate(s, 0);
|
||||
break;
|
||||
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);
|
||||
}
|
||||
@ -223,10 +225,14 @@ static uint64_t sp804_read(void *opaque, hwaddr offset,
|
||||
/* Integration Test control registers, which we won't support */
|
||||
case 0xf00: /* TimerITCR */
|
||||
case 0xf04: /* TimerITOP (strictly write only but..) */
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
"%s: integration test registers unimplemented\n",
|
||||
__func__);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -246,7 +252,8 @@ static void sp804_write(void *opaque, hwaddr offset,
|
||||
}
|
||||
|
||||
/* 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 = {
|
||||
@ -300,7 +307,7 @@ static uint64_t icp_pit_read(void *opaque, hwaddr offset,
|
||||
/* ??? Don't know the PrimeCell ID for this device. */
|
||||
n = offset >> 8;
|
||||
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);
|
||||
@ -314,7 +321,7 @@ static void icp_pit_write(void *opaque, hwaddr offset,
|
||||
|
||||
n = offset >> 8;
|
||||
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);
|
||||
|
@ -138,9 +138,8 @@ void armv7m_nvic_complete_irq(void *opaque, int 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;
|
||||
int irq;
|
||||
|
||||
@ -216,14 +215,6 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset)
|
||||
case 0xd14: /* Configuration Control. */
|
||||
/* TODO: Implement Configuration Control bits. */
|
||||
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. */
|
||||
val = 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;
|
||||
case 0xd28: /* Configurable 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;
|
||||
case 0xd2c: /* Hard 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 0xd3c: /* Aux Fault Status. */
|
||||
/* TODO: Implement fault status registers. */
|
||||
goto bad_reg;
|
||||
qemu_log_mask(LOG_UNIMP, "Fault status registers unimplemented\n");
|
||||
return 0;
|
||||
case 0xd40: /* PFR0. */
|
||||
return 0x00000030;
|
||||
case 0xd44: /* PRF1. */
|
||||
@ -280,14 +272,13 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset)
|
||||
return 0x01310102;
|
||||
/* TODO: Implement debug registers. */
|
||||
default:
|
||||
bad_reg:
|
||||
hw_error("NVIC: Bad read offset 0x%x\n", offset);
|
||||
qemu_log_mask(LOG_GUEST_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;
|
||||
switch (offset) {
|
||||
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. */
|
||||
if ((value >> 16) == 0x05fa) {
|
||||
if (value & 2) {
|
||||
hw_error("VECTCLRACTIVE not implemented");
|
||||
qemu_log_mask(LOG_UNIMP, "VECTCLRACTIVE unimplemented\n");
|
||||
}
|
||||
if (value & 5) {
|
||||
hw_error("System reset");
|
||||
qemu_log_mask(LOG_UNIMP, "AIRCR system reset unimplemented\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xd10: /* System Control. */
|
||||
case 0xd14: /* Configuration Control. */
|
||||
/* TODO: Implement control registers. */
|
||||
goto bad_reg;
|
||||
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);
|
||||
}
|
||||
qemu_log_mask(LOG_UNIMP, "NVIC: SCR and CCR unimplemented\n");
|
||||
break;
|
||||
case 0xd24: /* System Handler Control. */
|
||||
/* 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 0xd38: /* Bus Fault Address. */
|
||||
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 */
|
||||
if ((value & 0x1ff) < s->num_irq) {
|
||||
gic_set_pending_private(&s->gic, 0, value & 0x1ff);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
bad_reg:
|
||||
hw_error("NVIC: Bad write offset 0x%x\n", offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"NVIC: Bad write offset 0x%x\n", offset);
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t nvic_sysreg_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
/* At the moment we only support the ID registers for byte/word access.
|
||||
* This is not strictly correct as a few of the other registers also
|
||||
* allow byte access.
|
||||
*/
|
||||
nvic_state *s = (nvic_state *)opaque;
|
||||
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) {
|
||||
return 0;
|
||||
}
|
||||
return nvic_id[(offset - 0xfe0) >> 2];
|
||||
}
|
||||
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,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
nvic_state *s = (nvic_state *)opaque;
|
||||
uint32_t offset = addr;
|
||||
if (size == 4) {
|
||||
nvic_writel(opaque, offset, value);
|
||||
int i;
|
||||
|
||||
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;
|
||||
}
|
||||
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 = {
|
||||
|
@ -93,11 +93,8 @@ static void lan9215_init(uint32_t base, qemu_irq irq)
|
||||
}
|
||||
}
|
||||
|
||||
static Exynos4210State *exynos4_boards_init_common(
|
||||
const char *kernel_filename,
|
||||
const char *kernel_cmdline,
|
||||
const char *initrd_filename,
|
||||
Exynos4BoardType board_type)
|
||||
static Exynos4210State *exynos4_boards_init_common(QEMUMachineInitArgs *args,
|
||||
Exynos4BoardType board_type)
|
||||
{
|
||||
if (smp_cpus != EXYNOS4210_NCPUS) {
|
||||
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.smp_bootreg_addr =
|
||||
exynos4_board_smp_bootreg_addr[board_type];
|
||||
exynos4_board_binfo.kernel_filename = kernel_filename;
|
||||
exynos4_board_binfo.initrd_filename = initrd_filename;
|
||||
exynos4_board_binfo.kernel_cmdline = kernel_cmdline;
|
||||
exynos4_board_binfo.kernel_filename = args->kernel_filename;
|
||||
exynos4_board_binfo.initrd_filename = args->initrd_filename;
|
||||
exynos4_board_binfo.kernel_cmdline = args->kernel_cmdline;
|
||||
exynos4_board_binfo.gic_cpu_if_addr =
|
||||
EXYNOS4210_SMP_PRIVATE_BASE_ADDR + 0x100;
|
||||
|
||||
@ -122,9 +119,9 @@ static Exynos4210State *exynos4_boards_init_common(
|
||||
" initrd_filename: %s\n",
|
||||
exynos4_board_ram_size[board_type] / 1048576,
|
||||
exynos4_board_ram_size[board_type],
|
||||
kernel_filename,
|
||||
kernel_cmdline,
|
||||
initrd_filename);
|
||||
args->kernel_filename,
|
||||
args->kernel_cmdline,
|
||||
args->initrd_filename);
|
||||
|
||||
return exynos4210_init(get_system_memory(),
|
||||
exynos4_board_ram_size[board_type]);
|
||||
@ -132,22 +129,15 @@ static Exynos4210State *exynos4_boards_init_common(
|
||||
|
||||
static void nuri_init(QEMUMachineInitArgs *args)
|
||||
{
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
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);
|
||||
exynos4_boards_init_common(args, EXYNOS4_BOARD_NURI);
|
||||
|
||||
arm_load_kernel(arm_env_get_cpu(first_cpu), &exynos4_board_binfo);
|
||||
}
|
||||
|
||||
static void smdkc210_init(QEMUMachineInitArgs *args)
|
||||
{
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
Exynos4210State *s = exynos4_boards_init_common(kernel_filename,
|
||||
kernel_cmdline, initrd_filename, EXYNOS4_BOARD_SMDKC210);
|
||||
Exynos4210State *s = exynos4_boards_init_common(args,
|
||||
EXYNOS4_BOARD_SMDKC210);
|
||||
|
||||
lan9215_init(SMDK_LAN9118_BASE_ADDR,
|
||||
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,
|
||||
ram_addr_t ram_size,
|
||||
const char *kernel_filename,
|
||||
const char *kernel_cmdline, const char *initrd_filename,
|
||||
const char *cpu_model, enum mainstone_model_e model, int arm_id)
|
||||
QEMUMachineInitArgs *args,
|
||||
enum mainstone_model_e model, int arm_id)
|
||||
{
|
||||
uint32_t sector_len = 256 * 1024;
|
||||
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 be;
|
||||
MemoryRegion *rom = g_new(MemoryRegion, 1);
|
||||
const char *cpu_model = args->cpu_model;
|
||||
|
||||
if (!cpu_model)
|
||||
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,
|
||||
qdev_get_gpio_in(mst_irq, ETHERNET_IRQ));
|
||||
|
||||
mainstone_binfo.kernel_filename = kernel_filename;
|
||||
mainstone_binfo.kernel_cmdline = kernel_cmdline;
|
||||
mainstone_binfo.initrd_filename = initrd_filename;
|
||||
mainstone_binfo.kernel_filename = args->kernel_filename;
|
||||
mainstone_binfo.kernel_cmdline = args->kernel_cmdline;
|
||||
mainstone_binfo.initrd_filename = args->initrd_filename;
|
||||
mainstone_binfo.board_id = arm_id;
|
||||
arm_load_kernel(mpu->cpu, &mainstone_binfo);
|
||||
}
|
||||
|
||||
static void mainstone_init(QEMUMachineInitArgs *args)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
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);
|
||||
mainstone_common_init(get_system_memory(), args, mainstone, 0x196);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void n8x0_init(ram_addr_t ram_size, const char *boot_device,
|
||||
const char *kernel_filename,
|
||||
const char *kernel_cmdline, const char *initrd_filename,
|
||||
const char *cpu_model, struct arm_boot_info *binfo, int model)
|
||||
static void n8x0_init(QEMUMachineInitArgs *args,
|
||||
struct arm_boot_info *binfo, int model)
|
||||
{
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
struct n800_s *s = (struct n800_s *) g_malloc0(sizeof(*s));
|
||||
int sdram_size = binfo->ram_size;
|
||||
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
|
||||
*
|
||||
@ -1338,17 +1336,18 @@ static void n8x0_init(ram_addr_t ram_size, const char *boot_device,
|
||||
n8x0_usb_setup(s);
|
||||
}
|
||||
|
||||
if (kernel_filename) {
|
||||
if (args->kernel_filename) {
|
||||
/* Or at the linux loader. */
|
||||
binfo->kernel_filename = kernel_filename;
|
||||
binfo->kernel_cmdline = kernel_cmdline;
|
||||
binfo->initrd_filename = initrd_filename;
|
||||
binfo->kernel_filename = args->kernel_filename;
|
||||
binfo->kernel_cmdline = args->kernel_cmdline;
|
||||
binfo->initrd_filename = args->initrd_filename;
|
||||
arm_load_kernel(s->mpu->cpu, binfo);
|
||||
|
||||
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;
|
||||
uint8_t nolo_tags[0x10000];
|
||||
/* No, wait, better start at the ROM. */
|
||||
@ -1400,28 +1399,12 @@ static struct arm_boot_info n810_binfo = {
|
||||
|
||||
static void n800_init(QEMUMachineInitArgs *args)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
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);
|
||||
return n8x0_init(args, &n800_binfo, 800);
|
||||
}
|
||||
|
||||
static void n810_init(QEMUMachineInitArgs *args)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
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);
|
||||
return n8x0_init(args, &n810_binfo, 810);
|
||||
}
|
||||
|
||||
static QEMUMachine n800_machine = {
|
||||
|
@ -97,11 +97,7 @@ static struct arm_boot_info sx1_binfo = {
|
||||
.board_id = 0x265,
|
||||
};
|
||||
|
||||
static void sx1_init(ram_addr_t ram_size,
|
||||
const char *boot_device,
|
||||
const char *kernel_filename, const char *kernel_cmdline,
|
||||
const char *initrd_filename, const char *cpu_model,
|
||||
const int version)
|
||||
static void sx1_init(QEMUMachineInitArgs *args, const int version)
|
||||
{
|
||||
struct omap_mpu_state_s *mpu;
|
||||
MemoryRegion *address_space = get_system_memory();
|
||||
@ -121,7 +117,7 @@ static void sx1_init(ram_addr_t ram_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) */
|
||||
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]);
|
||||
}
|
||||
|
||||
if (!kernel_filename && !fl_idx) {
|
||||
if (!args->kernel_filename && !fl_idx) {
|
||||
fprintf(stderr, "Kernel or Flash image must be specified\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Load the kernel. */
|
||||
if (kernel_filename) {
|
||||
sx1_binfo.kernel_filename = kernel_filename;
|
||||
sx1_binfo.kernel_cmdline = kernel_cmdline;
|
||||
sx1_binfo.initrd_filename = initrd_filename;
|
||||
if (args->kernel_filename) {
|
||||
sx1_binfo.kernel_filename = args->kernel_filename;
|
||||
sx1_binfo.kernel_cmdline = args->kernel_cmdline;
|
||||
sx1_binfo.initrd_filename = args->initrd_filename;
|
||||
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)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
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);
|
||||
sx1_init(args, 1);
|
||||
}
|
||||
|
||||
static void sx1_init_v2(QEMUMachineInitArgs *args)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
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);
|
||||
sx1_init(args, 2);
|
||||
}
|
||||
|
||||
static QEMUMachine sx1_machine_v2 = {
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "qemu-timer.h"
|
||||
#include "exec-memory.h"
|
||||
#include "host-utils.h"
|
||||
#include "sysbus.h"
|
||||
|
||||
#define PFLASH_BUG(fmt, ...) \
|
||||
do { \
|
||||
@ -60,23 +61,28 @@ do { \
|
||||
#endif
|
||||
|
||||
struct pflash_t {
|
||||
SysBusDevice busdev;
|
||||
BlockDriverState *bs;
|
||||
hwaddr base;
|
||||
hwaddr sector_len;
|
||||
hwaddr total_len;
|
||||
int width;
|
||||
uint32_t nb_blocs;
|
||||
uint64_t sector_len;
|
||||
uint8_t width;
|
||||
uint8_t be;
|
||||
int wcycle; /* if 0, the flash is read normally */
|
||||
int bypass;
|
||||
int ro;
|
||||
uint8_t cmd;
|
||||
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_table[0x52];
|
||||
hwaddr counter;
|
||||
unsigned int writeblock_size;
|
||||
QEMUTimer *timer;
|
||||
MemoryRegion mem;
|
||||
char *name;
|
||||
void *storage;
|
||||
};
|
||||
|
||||
@ -168,15 +174,16 @@ static uint32_t pflash_read (pflash_t *pfl, hwaddr offset,
|
||||
case 0x90:
|
||||
switch (boff) {
|
||||
case 0:
|
||||
ret = pfl->ident[0] << 8 | pfl->ident[1];
|
||||
ret = pfl->ident0 << 8 | pfl->ident1;
|
||||
DPRINTF("%s: Manufacturer Code %04x\n", __func__, ret);
|
||||
break;
|
||||
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);
|
||||
break;
|
||||
default:
|
||||
DPRINTF("%s: Read Device Information boff=%x\n", __func__, boff);
|
||||
DPRINTF("%s: Read Device Information boff=%x\n", __func__,
|
||||
(unsigned)boff);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
@ -279,9 +286,8 @@ static void pflash_write(pflash_t *pfl, hwaddr offset,
|
||||
p = pfl->storage;
|
||||
offset &= ~(pfl->sector_len - 1);
|
||||
|
||||
DPRINTF("%s: block erase at " TARGET_FMT_plx " bytes "
|
||||
TARGET_FMT_plx "\n",
|
||||
__func__, offset, pfl->sector_len);
|
||||
DPRINTF("%s: block erase at " TARGET_FMT_plx " bytes %x\n",
|
||||
__func__, offset, (unsigned)pfl->sector_len);
|
||||
|
||||
if (!pfl->ro) {
|
||||
memset(p + offset, 0xff, pfl->sector_len);
|
||||
@ -543,19 +549,13 @@ static const MemoryRegionOps pflash_cfi01_ops_le = {
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
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)
|
||||
static int pflash_cfi01_init(SysBusDevice *dev)
|
||||
{
|
||||
pflash_t *pfl;
|
||||
hwaddr total_len;
|
||||
pflash_t *pfl = FROM_SYSBUS(typeof(*pfl), dev);
|
||||
uint64_t total_len;
|
||||
int ret;
|
||||
|
||||
total_len = sector_len * nb_blocs;
|
||||
total_len = pfl->sector_len * pfl->nb_blocs;
|
||||
|
||||
/* XXX: to be fixed */
|
||||
#if 0
|
||||
@ -564,27 +564,22 @@ pflash_t *pflash_cfi01_register(hwaddr base,
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
pfl = g_malloc0(sizeof(pflash_t));
|
||||
|
||||
memory_region_init_rom_device(
|
||||
&pfl->mem, be ? &pflash_cfi01_ops_be : &pflash_cfi01_ops_le, pfl,
|
||||
name, size);
|
||||
vmstate_register_ram(&pfl->mem, qdev);
|
||||
&pfl->mem, pfl->be ? &pflash_cfi01_ops_be : &pflash_cfi01_ops_le, pfl,
|
||||
pfl->name, total_len);
|
||||
vmstate_register_ram(&pfl->mem, DEVICE(pfl));
|
||||
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) {
|
||||
/* read the initial flash content */
|
||||
ret = bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9);
|
||||
|
||||
if (ret < 0) {
|
||||
memory_region_del_subregion(get_system_memory(), &pfl->mem);
|
||||
vmstate_unregister_ram(&pfl->mem, qdev);
|
||||
vmstate_unregister_ram(&pfl->mem, DEVICE(pfl));
|
||||
memory_region_destroy(&pfl->mem);
|
||||
g_free(pfl);
|
||||
return NULL;
|
||||
return 1;
|
||||
}
|
||||
bdrv_attach_dev_nofail(pfl->bs, pfl);
|
||||
}
|
||||
|
||||
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->base = base;
|
||||
pfl->sector_len = sector_len;
|
||||
pfl->total_len = total_len;
|
||||
pfl->width = width;
|
||||
pfl->wcycle = 0;
|
||||
pfl->cmd = 0;
|
||||
pfl->status = 0;
|
||||
pfl->ident[0] = id0;
|
||||
pfl->ident[1] = id1;
|
||||
pfl->ident[2] = id2;
|
||||
pfl->ident[3] = id3;
|
||||
/* Hardcoded CFI table */
|
||||
pfl->cfi_len = 0x52;
|
||||
/* Standard "QRY" string */
|
||||
@ -653,7 +640,7 @@ pflash_t *pflash_cfi01_register(hwaddr base,
|
||||
pfl->cfi_table[0x28] = 0x02;
|
||||
pfl->cfi_table[0x29] = 0x00;
|
||||
/* Max number of bytes in multi-bytes write */
|
||||
if (width == 1) {
|
||||
if (pfl->width == 1) {
|
||||
pfl->cfi_table[0x2A] = 0x08;
|
||||
} else {
|
||||
pfl->cfi_table[0x2A] = 0x0B;
|
||||
@ -664,10 +651,10 @@ pflash_t *pflash_cfi01_register(hwaddr base,
|
||||
/* Number of erase block regions (uniform) */
|
||||
pfl->cfi_table[0x2C] = 0x01;
|
||||
/* Erase block region 1 */
|
||||
pfl->cfi_table[0x2D] = nb_blocs - 1;
|
||||
pfl->cfi_table[0x2E] = (nb_blocs - 1) >> 8;
|
||||
pfl->cfi_table[0x2F] = sector_len >> 8;
|
||||
pfl->cfi_table[0x30] = sector_len >> 16;
|
||||
pfl->cfi_table[0x2D] = pfl->nb_blocs - 1;
|
||||
pfl->cfi_table[0x2E] = (pfl->nb_blocs - 1) >> 8;
|
||||
pfl->cfi_table[0x2F] = pfl->sector_len >> 8;
|
||||
pfl->cfi_table[0x30] = pfl->sector_len >> 16;
|
||||
|
||||
/* Extended */
|
||||
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 */
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include "block.h"
|
||||
#include "exec-memory.h"
|
||||
#include "host-utils.h"
|
||||
#include "sysbus.h"
|
||||
|
||||
//#define PFLASH_DEBUG
|
||||
#ifdef PFLASH_DEBUG
|
||||
@ -55,19 +56,26 @@ do { \
|
||||
#define PFLASH_LAZY_ROMD_THRESHOLD 42
|
||||
|
||||
struct pflash_t {
|
||||
SysBusDevice busdev;
|
||||
BlockDriverState *bs;
|
||||
hwaddr base;
|
||||
uint32_t sector_len;
|
||||
uint32_t nb_blocs;
|
||||
uint32_t chip_len;
|
||||
int mappings;
|
||||
int width;
|
||||
uint8_t mappings;
|
||||
uint8_t width;
|
||||
uint8_t be;
|
||||
int wcycle; /* if 0, the flash is read normally */
|
||||
int bypass;
|
||||
int ro;
|
||||
uint8_t cmd;
|
||||
uint8_t status;
|
||||
uint16_t ident[4];
|
||||
uint16_t unlock_addr[2];
|
||||
/* FIXME: implement array device properties */
|
||||
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_table[0x52];
|
||||
QEMUTimer *timer;
|
||||
@ -80,6 +88,7 @@ struct pflash_t {
|
||||
MemoryRegion orig_mem;
|
||||
int rom_mode;
|
||||
int read_counter; /* used for lazy switch-back to rom mode */
|
||||
char *name;
|
||||
void *storage;
|
||||
};
|
||||
|
||||
@ -190,16 +199,17 @@ static uint32_t pflash_read (pflash_t *pfl, hwaddr offset,
|
||||
switch (boff) {
|
||||
case 0x00:
|
||||
case 0x01:
|
||||
ret = pfl->ident[boff & 0x01];
|
||||
ret = boff & 0x01 ? pfl->ident1 : pfl->ident0;
|
||||
break;
|
||||
case 0x02:
|
||||
ret = 0x00; /* Pretend all sectors are unprotected */
|
||||
break;
|
||||
case 0x0E:
|
||||
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;
|
||||
ret = pfl->ident[2 + (boff & 0x01)];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto flash_read;
|
||||
@ -283,9 +293,9 @@ static void pflash_write (pflash_t *pfl, hwaddr offset,
|
||||
pfl->cmd = 0x98;
|
||||
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",
|
||||
__func__, boff, cmd, pfl->unlock_addr[0]);
|
||||
__func__, boff, cmd, pfl->unlock_addr0);
|
||||
goto reset_flash;
|
||||
}
|
||||
DPRINTF("%s: unlock sequence started\n", __func__);
|
||||
@ -293,7 +303,7 @@ static void pflash_write (pflash_t *pfl, hwaddr offset,
|
||||
case 1:
|
||||
/* We started an unlock sequence */
|
||||
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__,
|
||||
boff, cmd);
|
||||
goto reset_flash;
|
||||
@ -302,7 +312,7 @@ static void pflash_write (pflash_t *pfl, hwaddr offset,
|
||||
break;
|
||||
case 2:
|
||||
/* 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__,
|
||||
boff, cmd);
|
||||
goto reset_flash;
|
||||
@ -400,7 +410,7 @@ static void pflash_write (pflash_t *pfl, hwaddr offset,
|
||||
case 5:
|
||||
switch (cmd) {
|
||||
case 0x10:
|
||||
if (boff != pfl->unlock_addr[0]) {
|
||||
if (boff != pfl->unlock_addr0) {
|
||||
DPRINTF("%s: chip erase: invalid address " TARGET_FMT_plx "\n",
|
||||
__func__, offset);
|
||||
goto reset_flash;
|
||||
@ -575,50 +585,38 @@ static const MemoryRegionOps pflash_cfi02_ops_le = {
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
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)
|
||||
static int pflash_cfi02_init(SysBusDevice *dev)
|
||||
{
|
||||
pflash_t *pfl;
|
||||
int32_t chip_len;
|
||||
pflash_t *pfl = FROM_SYSBUS(typeof(*pfl), dev);
|
||||
uint32_t chip_len;
|
||||
int ret;
|
||||
|
||||
chip_len = sector_len * nb_blocs;
|
||||
chip_len = pfl->sector_len * pfl->nb_blocs;
|
||||
/* XXX: to be fixed */
|
||||
#if 0
|
||||
if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) &&
|
||||
total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024))
|
||||
return NULL;
|
||||
#endif
|
||||
pfl = g_malloc0(sizeof(pflash_t));
|
||||
memory_region_init_rom_device(
|
||||
&pfl->orig_mem, be ? &pflash_cfi02_ops_be : &pflash_cfi02_ops_le, pfl,
|
||||
name, size);
|
||||
vmstate_register_ram(&pfl->orig_mem, qdev);
|
||||
|
||||
memory_region_init_rom_device(&pfl->orig_mem, pfl->be ?
|
||||
&pflash_cfi02_ops_be : &pflash_cfi02_ops_le,
|
||||
pfl, pfl->name, chip_len);
|
||||
vmstate_register_ram(&pfl->orig_mem, DEVICE(pfl));
|
||||
pfl->storage = memory_region_get_ram_ptr(&pfl->orig_mem);
|
||||
pfl->base = base;
|
||||
pfl->chip_len = chip_len;
|
||||
pfl->mappings = nb_mappings;
|
||||
pfl->bs = bs;
|
||||
if (pfl->bs) {
|
||||
/* read the initial flash content */
|
||||
ret = bdrv_read(pfl->bs, 0, pfl->storage, chip_len >> 9);
|
||||
if (ret < 0) {
|
||||
g_free(pfl);
|
||||
return NULL;
|
||||
return 1;
|
||||
}
|
||||
bdrv_attach_dev_nofail(pfl->bs, pfl);
|
||||
}
|
||||
|
||||
pflash_setup_mappings(pfl);
|
||||
pfl->rom_mode = 1;
|
||||
memory_region_add_subregion(get_system_memory(), pfl->base, &pfl->mem);
|
||||
sysbus_init_mmio(dev, &pfl->mem);
|
||||
|
||||
if (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->sector_len = sector_len;
|
||||
pfl->width = width;
|
||||
pfl->wcycle = 0;
|
||||
pfl->cmd = 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) */
|
||||
pfl->cfi_len = 0x52;
|
||||
/* Standard "QRY" string */
|
||||
@ -693,10 +683,10 @@ pflash_t *pflash_cfi02_register(hwaddr base,
|
||||
/* Number of erase block regions (uniform) */
|
||||
pfl->cfi_table[0x2C] = 0x01;
|
||||
/* Erase block region 1 */
|
||||
pfl->cfi_table[0x2D] = nb_blocs - 1;
|
||||
pfl->cfi_table[0x2E] = (nb_blocs - 1) >> 8;
|
||||
pfl->cfi_table[0x2F] = sector_len >> 8;
|
||||
pfl->cfi_table[0x30] = sector_len >> 16;
|
||||
pfl->cfi_table[0x2D] = pfl->nb_blocs - 1;
|
||||
pfl->cfi_table[0x2E] = (pfl->nb_blocs - 1) >> 8;
|
||||
pfl->cfi_table[0x2F] = pfl->sector_len >> 8;
|
||||
pfl->cfi_table[0x30] = pfl->sector_len >> 16;
|
||||
|
||||
/* Extended */
|
||||
pfl->cfi_table[0x31] = 'P';
|
||||
@ -716,5 +706,81 @@ pflash_t *pflash_cfi02_register(hwaddr base,
|
||||
pfl->cfi_table[0x3b] = 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;
|
||||
}
|
||||
|
@ -95,7 +95,8 @@ static uint64_t pl050_read(void *opaque, hwaddr offset,
|
||||
case 4: /* KMIIR */
|
||||
return s->pending | 2;
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -123,7 +124,8 @@ static void pl050_write(void *opaque, hwaddr offset,
|
||||
s->clk = value;
|
||||
return;
|
||||
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 = {
|
||||
|
@ -164,7 +164,8 @@ static uint64_t pl061_read(void *opaque, hwaddr offset,
|
||||
case 0x528: /* Analog mode select */
|
||||
return s->amsel;
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -239,7 +240,8 @@ static void pl061_write(void *opaque, hwaddr offset,
|
||||
s->amsel = value & 0xff;
|
||||
break;
|
||||
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);
|
||||
}
|
||||
|
11
hw/pl080.c
11
hw/pl080.c
@ -281,7 +281,8 @@ static uint64_t pl080_read(void *opaque, hwaddr offset,
|
||||
return s->sync;
|
||||
default:
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -327,12 +328,13 @@ static void pl080_write(void *opaque, hwaddr offset,
|
||||
case 10: /* SoftLBReq */
|
||||
case 11: /* SoftLSReq */
|
||||
/* ??? Implement these. */
|
||||
hw_error("pl080_write: Soft DMA not implemented\n");
|
||||
qemu_log_mask(LOG_UNIMP, "pl080_write: Soft DMA not implemented\n");
|
||||
break;
|
||||
case 12: /* Configuration */
|
||||
s->conf = value;
|
||||
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);
|
||||
break;
|
||||
@ -341,7 +343,8 @@ static void pl080_write(void *opaque, hwaddr offset,
|
||||
break;
|
||||
default:
|
||||
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);
|
||||
}
|
||||
|
@ -349,7 +349,8 @@ static uint64_t pl110_read(void *opaque, hwaddr offset,
|
||||
case 12: /* LCDLPCURR */
|
||||
return s->lpbase;
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -417,7 +418,8 @@ static void pl110_write(void *opaque, hwaddr offset,
|
||||
pl110_update(s);
|
||||
break;
|
||||
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;
|
||||
case 0xc0: /* ITCR */
|
||||
if (val) {
|
||||
hw_error("pl190: Test mode not implemented\n");
|
||||
qemu_log_mask(LOG_UNIMP, "pl190: Test mode not implemented\n");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -44,11 +44,8 @@ static const int realview_board_id[] = {
|
||||
0x76d
|
||||
};
|
||||
|
||||
static void realview_init(ram_addr_t ram_size,
|
||||
const char *boot_device,
|
||||
const char *kernel_filename, const char *kernel_cmdline,
|
||||
const char *initrd_filename, const char *cpu_model,
|
||||
enum realview_board_type board_type)
|
||||
static void realview_init(QEMUMachineInitArgs *args,
|
||||
enum realview_board_type board_type)
|
||||
{
|
||||
ARMCPU *cpu = NULL;
|
||||
CPUARMState *env;
|
||||
@ -73,6 +70,7 @@ static void realview_init(ram_addr_t ram_size,
|
||||
uint32_t proc_id = 0;
|
||||
uint32_t sys_id;
|
||||
ram_addr_t low_ram_size;
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
|
||||
switch (board_type) {
|
||||
case BOARD_EB:
|
||||
@ -89,7 +87,7 @@ static void realview_init(ram_addr_t ram_size,
|
||||
break;
|
||||
}
|
||||
for (n = 0; n < smp_cpus; n++) {
|
||||
cpu = cpu_arm_init(cpu_model);
|
||||
cpu = cpu_arm_init(args->cpu_model);
|
||||
if (!cpu) {
|
||||
fprintf(stderr, "Unable to find CPU definition\n");
|
||||
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);
|
||||
|
||||
realview_binfo.ram_size = ram_size;
|
||||
realview_binfo.kernel_filename = kernel_filename;
|
||||
realview_binfo.kernel_cmdline = kernel_cmdline;
|
||||
realview_binfo.initrd_filename = initrd_filename;
|
||||
realview_binfo.kernel_filename = args->kernel_filename;
|
||||
realview_binfo.kernel_cmdline = args->kernel_cmdline;
|
||||
realview_binfo.initrd_filename = args->initrd_filename;
|
||||
realview_binfo.nb_cpus = smp_cpus;
|
||||
realview_binfo.board_id = realview_board_id[board_type];
|
||||
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)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
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;
|
||||
if (!cpu_model) {
|
||||
cpu_model = "arm926";
|
||||
if (!args->cpu_model) {
|
||||
args->cpu_model = "arm926";
|
||||
}
|
||||
realview_init(ram_size, boot_device, kernel_filename, kernel_cmdline,
|
||||
initrd_filename, cpu_model, BOARD_EB);
|
||||
realview_init(args, BOARD_EB);
|
||||
}
|
||||
|
||||
static void realview_eb_mpcore_init(QEMUMachineInitArgs *args)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
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;
|
||||
if (!cpu_model) {
|
||||
cpu_model = "arm11mpcore";
|
||||
if (!args->cpu_model) {
|
||||
args->cpu_model = "arm11mpcore";
|
||||
}
|
||||
realview_init(ram_size, boot_device, kernel_filename, kernel_cmdline,
|
||||
initrd_filename, cpu_model, BOARD_EB_MPCORE);
|
||||
realview_init(args, BOARD_EB_MPCORE);
|
||||
}
|
||||
|
||||
static void realview_pb_a8_init(QEMUMachineInitArgs *args)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
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;
|
||||
if (!cpu_model) {
|
||||
cpu_model = "cortex-a8";
|
||||
if (!args->cpu_model) {
|
||||
args->cpu_model = "cortex-a8";
|
||||
}
|
||||
realview_init(ram_size, boot_device, kernel_filename, kernel_cmdline,
|
||||
initrd_filename, cpu_model, BOARD_PB_A8);
|
||||
realview_init(args, BOARD_PB_A8);
|
||||
}
|
||||
|
||||
static void realview_pbx_a9_init(QEMUMachineInitArgs *args)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
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;
|
||||
if (!cpu_model) {
|
||||
cpu_model = "cortex-a9";
|
||||
if (!args->cpu_model) {
|
||||
args->cpu_model = "cortex-a9";
|
||||
}
|
||||
realview_init(ram_size, boot_device, kernel_filename, kernel_cmdline,
|
||||
initrd_filename, cpu_model, BOARD_PBX_A9);
|
||||
realview_init(args, BOARD_PBX_A9);
|
||||
}
|
||||
|
||||
static QEMUMachine realview_eb_machine = {
|
||||
|
106
hw/sd.c
106
hw/sd.c
@ -55,24 +55,28 @@ typedef enum {
|
||||
sd_illegal = -2,
|
||||
} 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 {
|
||||
enum {
|
||||
sd_inactive,
|
||||
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 mode; /* current card mode, one of SDCardModes */
|
||||
int32_t state; /* current card state, one of SDCardStates */
|
||||
uint32_t ocr;
|
||||
uint8_t scr[8];
|
||||
uint8_t cid[16];
|
||||
@ -83,21 +87,22 @@ struct SDState {
|
||||
uint32_t vhs;
|
||||
bool wp_switch;
|
||||
unsigned long *wp_groups;
|
||||
int32_t wpgrps_size;
|
||||
uint64_t size;
|
||||
int blk_len;
|
||||
uint32_t blk_len;
|
||||
uint32_t erase_start;
|
||||
uint32_t erase_end;
|
||||
uint8_t pwd[16];
|
||||
int pwd_len;
|
||||
int function_group[6];
|
||||
uint32_t pwd_len;
|
||||
uint8_t function_group[6];
|
||||
|
||||
bool spi;
|
||||
int current_cmd;
|
||||
uint8_t current_cmd;
|
||||
/* True if we will handle the next command as an ACMD. Note that this does
|
||||
* *not* track the APP_CMD status bit!
|
||||
*/
|
||||
bool expecting_acmd;
|
||||
int blk_written;
|
||||
uint32_t blk_written;
|
||||
uint64_t data_start;
|
||||
uint32_t data_offset;
|
||||
uint8_t data[512];
|
||||
@ -421,8 +426,9 @@ static void sd_reset(SDState *sd, BlockDriverState *bdrv)
|
||||
if (sd->wp_groups)
|
||||
g_free(sd->wp_groups);
|
||||
sd->wp_switch = bdrv ? bdrv_is_read_only(bdrv) : false;
|
||||
sd->wp_groups = bitmap_new(sect);
|
||||
memset(sd->function_group, 0, sizeof(int) * 6);
|
||||
sd->wpgrps_size = sect;
|
||||
sd->wp_groups = bitmap_new(sd->wpgrps_size);
|
||||
memset(sd->function_group, 0, sizeof(sd->function_group));
|
||||
sd->erase_start = 0;
|
||||
sd->erase_end = 0;
|
||||
sd->size = size;
|
||||
@ -446,6 +452,38 @@ static const BlockDevOps sd_block_ops = {
|
||||
.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
|
||||
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
|
||||
@ -463,6 +501,7 @@ SDState *sd_init(BlockDriverState *bs, bool is_spi)
|
||||
bdrv_attach_dev_nofail(sd->bdrv, sd);
|
||||
bdrv_set_dev_ops(sd->bdrv, &sd_block_ops, sd);
|
||||
}
|
||||
vmstate_register(NULL, -1, &sd_vmstate, 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)
|
||||
{
|
||||
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) {
|
||||
sd->card_status |= ERASE_SEQ_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
start = sd_addr_to_wpnum(sd->erase_start);
|
||||
end = sd_addr_to_wpnum(sd->erase_end);
|
||||
if (extract32(sd->ocr, OCR_CCS_BITN, 1)) {
|
||||
/* 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_end = 0;
|
||||
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)) {
|
||||
sd->card_status |= WP_ERASE_SKIP;
|
||||
}
|
||||
@ -567,7 +615,7 @@ static void sd_lock_command(SDState *sd)
|
||||
sd->card_status |= LOCK_UNLOCK_FAILED;
|
||||
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->card_status &= ~CARD_IS_LOCKED;
|
||||
sd->pwd_len = 0;
|
||||
|
1
hw/sd.h
1
hw/sd.h
@ -50,6 +50,7 @@
|
||||
#define READY_FOR_DATA (1 << 8)
|
||||
#define APP_CMD (1 << 5)
|
||||
#define AKE_SEQ_ERROR (1 << 3)
|
||||
#define OCR_CCS_BITN 30
|
||||
|
||||
typedef enum {
|
||||
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,
|
||||
};
|
||||
|
||||
static void spitz_common_init(ram_addr_t ram_size,
|
||||
const char *kernel_filename,
|
||||
const char *kernel_cmdline, const char *initrd_filename,
|
||||
const char *cpu_model, enum spitz_model_e model, int arm_id)
|
||||
static void spitz_common_init(QEMUMachineInitArgs *args,
|
||||
enum spitz_model_e model, int arm_id)
|
||||
{
|
||||
PXA2xxState *mpu;
|
||||
DeviceState *scp0, *scp1 = NULL;
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
MemoryRegion *rom = g_new(MemoryRegion, 1);
|
||||
const char *cpu_model = args->cpu_model;
|
||||
|
||||
if (!cpu_model)
|
||||
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. */
|
||||
spitz_microdrive_attach(mpu, 0);
|
||||
|
||||
spitz_binfo.kernel_filename = kernel_filename;
|
||||
spitz_binfo.kernel_cmdline = kernel_cmdline;
|
||||
spitz_binfo.initrd_filename = initrd_filename;
|
||||
spitz_binfo.kernel_filename = args->kernel_filename;
|
||||
spitz_binfo.kernel_cmdline = args->kernel_cmdline;
|
||||
spitz_binfo.initrd_filename = args->initrd_filename;
|
||||
spitz_binfo.board_id = arm_id;
|
||||
arm_load_kernel(mpu->cpu, &spitz_binfo);
|
||||
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)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
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);
|
||||
spitz_common_init(args, spitz, 0x2c9);
|
||||
}
|
||||
|
||||
static void borzoi_init(QEMUMachineInitArgs *args)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
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);
|
||||
spitz_common_init(args, borzoi, 0x33f);
|
||||
}
|
||||
|
||||
static void akita_init(QEMUMachineInitArgs *args)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
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);
|
||||
spitz_common_init(args, akita, 0x2e8);
|
||||
}
|
||||
|
||||
static void terrier_init(QEMUMachineInitArgs *args)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
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);
|
||||
spitz_common_init(args, terrier, 0x33f);
|
||||
}
|
||||
|
||||
static QEMUMachine akitapda_machine = {
|
||||
|
@ -40,7 +40,8 @@ static uint64_t versatile_i2c_read(void *opaque, hwaddr offset,
|
||||
if (offset == 0) {
|
||||
return (s->out & 1) | (s->in << 1);
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
@ -58,7 +59,8 @@ static void versatile_i2c_write(void *opaque, hwaddr offset,
|
||||
s->out &= ~value;
|
||||
break;
|
||||
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);
|
||||
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 void versatile_init(ram_addr_t ram_size,
|
||||
const char *boot_device,
|
||||
const char *kernel_filename, const char *kernel_cmdline,
|
||||
const char *initrd_filename, const char *cpu_model,
|
||||
int board_id)
|
||||
static void versatile_init(QEMUMachineInitArgs *args, int board_id)
|
||||
{
|
||||
ARMCPU *cpu;
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
@ -189,15 +185,15 @@ static void versatile_init(ram_addr_t ram_size,
|
||||
int done_smc = 0;
|
||||
DriveInfo *dinfo;
|
||||
|
||||
if (!cpu_model) {
|
||||
cpu_model = "arm926";
|
||||
if (!args->cpu_model) {
|
||||
args->cpu_model = "arm926";
|
||||
}
|
||||
cpu = cpu_arm_init(cpu_model);
|
||||
cpu = cpu_arm_init(args->cpu_model);
|
||||
if (!cpu) {
|
||||
fprintf(stderr, "Unable to find CPU definition\n");
|
||||
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);
|
||||
/* ??? RAM should repeat to fill physical memory space. */
|
||||
/* 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");
|
||||
}
|
||||
|
||||
versatile_binfo.ram_size = ram_size;
|
||||
versatile_binfo.kernel_filename = kernel_filename;
|
||||
versatile_binfo.kernel_cmdline = kernel_cmdline;
|
||||
versatile_binfo.initrd_filename = initrd_filename;
|
||||
versatile_binfo.ram_size = args->ram_size;
|
||||
versatile_binfo.kernel_filename = args->kernel_filename;
|
||||
versatile_binfo.kernel_cmdline = args->kernel_cmdline;
|
||||
versatile_binfo.initrd_filename = args->initrd_filename;
|
||||
versatile_binfo.board_id = board_id;
|
||||
arm_load_kernel(cpu, &versatile_binfo);
|
||||
}
|
||||
|
||||
static void vpb_init(QEMUMachineInitArgs *args)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
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);
|
||||
versatile_init(args, 0x183);
|
||||
}
|
||||
|
||||
static void vab_init(QEMUMachineInitArgs *args)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
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);
|
||||
versatile_init(args, 0x25e);
|
||||
}
|
||||
|
||||
static QEMUMachine versatilepb_machine = {
|
||||
|
@ -348,12 +348,7 @@ static const VEDBoardInfo a15_daughterboard = {
|
||||
};
|
||||
|
||||
static void vexpress_common_init(const VEDBoardInfo *daughterboard,
|
||||
ram_addr_t ram_size,
|
||||
const char *boot_device,
|
||||
const char *kernel_filename,
|
||||
const char *kernel_cmdline,
|
||||
const char *initrd_filename,
|
||||
const char *cpu_model)
|
||||
QEMUMachineInitArgs *args)
|
||||
{
|
||||
DeviceState *dev, *sysctl, *pl041;
|
||||
qemu_irq pic[64];
|
||||
@ -366,7 +361,8 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard,
|
||||
MemoryRegion *sram = g_new(MemoryRegion, 1);
|
||||
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
|
||||
* 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 */
|
||||
|
||||
vexpress_binfo.ram_size = ram_size;
|
||||
vexpress_binfo.kernel_filename = kernel_filename;
|
||||
vexpress_binfo.kernel_cmdline = kernel_cmdline;
|
||||
vexpress_binfo.initrd_filename = initrd_filename;
|
||||
vexpress_binfo.ram_size = args->ram_size;
|
||||
vexpress_binfo.kernel_filename = args->kernel_filename;
|
||||
vexpress_binfo.kernel_cmdline = args->kernel_cmdline;
|
||||
vexpress_binfo.initrd_filename = args->initrd_filename;
|
||||
vexpress_binfo.nb_cpus = smp_cpus;
|
||||
vexpress_binfo.board_id = VEXPRESS_BOARD_ID;
|
||||
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)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
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);
|
||||
vexpress_common_init(&a9_daughterboard, args);
|
||||
}
|
||||
|
||||
static void vexpress_a15_init(QEMUMachineInitArgs *args)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
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);
|
||||
vexpress_common_init(&a15_daughterboard, args);
|
||||
}
|
||||
|
||||
static QEMUMachine vexpress_a9_machine = {
|
||||
|
41
savevm.c
41
savevm.c
@ -86,6 +86,7 @@
|
||||
#include "memory.h"
|
||||
#include "qmp-commands.h"
|
||||
#include "trace.h"
|
||||
#include "bitops.h"
|
||||
|
||||
#define SELF_ANNOUNCE_ROUNDS 5
|
||||
|
||||
@ -1132,6 +1133,46 @@ const VMStateInfo vmstate_info_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 {
|
||||
char idstr[256];
|
||||
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_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_pointer(t1,t2) ((t1**)0 - (t2*)0)
|
||||
@ -411,6 +412,18 @@ extern const VMStateInfo vmstate_info_unused_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_n : num of elements field_name
|
||||
_n : num of elements
|
||||
|
Loading…
Reference in New Issue
Block a user