diff mbox

[v1,1/3] xilinx_zynq: added smp support

Message ID db64980f8d478423bc0bd39843c245faea9f5631.1333343538.git.peter.crosthwaite@petalogix.com
State New
Headers show

Commit Message

Peter A. G. Crosthwaite April 2, 2012, 5:20 a.m. UTC
Added linux smp support for the xilinx zynq platform (2x cpus are supported)

Signed-off-by: Peter A. G. Crosthwaite <peter.crosthwaite@petalogix.com>
---
 hw/xilinx_zynq.c |   64 ++++++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 53 insertions(+), 11 deletions(-)

Comments

John Linn April 10, 2012, 5:50 p.m. UTC | #1
> -----Original Message-----
> From: Peter A. G. Crosthwaite [mailto:peter.crosthwaite@petalogix.com]
> Sent: Sunday, April 01, 2012 10:20 PM
> To: peter.crosthwaite@petalogix.com; qemu-devel@nongnu.org;
> paul@codesourcery.com; peter.maydell@linaro.org;
> edgar.iglesias@gmail.com
> Cc: Duy Le; John Linn; john.williams@petalogix.com
> Subject: [PATCH v1 1/3] xilinx_zynq: added smp support
> 
> Added linux smp support for the xilinx zynq platform (2x cpus are
> supported)
> 
> Signed-off-by: Peter A. G. Crosthwaite
> <peter.crosthwaite@petalogix.com>

Signed-off-by: John Linn <john.linn@xilinx.com>

> ---
>  hw/xilinx_zynq.c |   64
++++++++++++++++++++++++++++++++++++++++++++--
> -------
>  1 files changed, 53 insertions(+), 11 deletions(-)
> 
> diff --git a/hw/xilinx_zynq.c b/hw/xilinx_zynq.c
> index 7290c64..56d0b96 100644
> --- a/hw/xilinx_zynq.c
> +++ b/hw/xilinx_zynq.c
> @@ -30,6 +30,42 @@
> 
>  #define IRQ_OFFSET 32 /* pic interrupts start from index 32 */
> 
> +#define SMP_BOOT_ADDR 0x0fff0000
> +
> +static void zynq_reset_secondary(CPUARMState *env,
> +                                    const struct arm_boot_info *info)
> +{
> +    env->regs[15] = SMP_BOOT_ADDR;
> +}
> +
> +/* Entry point for secondary CPU */
> +static uint32_t zynq_smpboot[] = {
> +    0xe59f0020, /* ldr     r0, privbase */
> +    0xe3a004FF, /* mov     r0 = 0xFFFFFFF0 */
> +    0xe38008FF, /* orr     ...*/
> +    0xe3800CFF, /* orr     .... */
> +    0xe38000F0, /* orr     ..... */
> +    0xe320f002, /* wfe */
> +    0xe5901000, /* ldr     r1, [r0] */
> +    0xe1110001, /* tst     r1, r1 */
> +    0x0afffffb, /* beq     <wfe> */
> +    0xe12fff11, /* bx      r1 */
> +    0,
> +    0
> +};
> +
> +static void zynq_write_secondary_boot(CPUARMState *env,
> +                                    const struct arm_boot_info *info)
> +{
> +    int n;
> +
> +    for (n = 0; n < ARRAY_SIZE(zynq_smpboot); n++) {
> +        zynq_smpboot[n] = tswap32(zynq_smpboot[n]);
> +    }
> +    rom_add_blob_fixed("smpboot", zynq_smpboot, sizeof(zynq_smpboot),
> +            SMP_BOOT_ADDR);
> +}
> +
>  static struct arm_boot_info zynq_binfo = {};
> 
>  static void gem_init(NICInfo *nd, uint32_t base, qemu_irq irq)
> @@ -60,19 +96,21 @@ static void zynq_init(ram_addr_t ram_size, const
> char *boot_device,
>      qemu_irq pic[64];
>      NICInfo *nd;
>      int n;
> -    qemu_irq cpu_irq;
> +    qemu_irq cpu_irq[2];
> 
>      if (!cpu_model) {
>          cpu_model = "cortex-a9";
>      }
> 
> -    env = cpu_init(cpu_model);
> -    if (!env) {
> -        fprintf(stderr, "Unable to find CPU definition\n");
> -        exit(1);
> +    for (n = 0; n < smp_cpus; n++) {
> +        env = cpu_init(cpu_model);
> +        if (!env) {
> +            fprintf(stderr, "Unable to find CPU definition\n");
> +            exit(1);
> +        }
> +        irqp = arm_pic_init_cpu(env);
> +        cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ];
>      }
> -    irqp = arm_pic_init_cpu(env);
> -    cpu_irq = irqp[ARM_PIC_CPU_IRQ];
> 
>      /* max 2GB ram */
>      if (ram_size > 0x80000000) {
> @@ -103,11 +141,13 @@ static void zynq_init(ram_addr_t ram_size, const
> char *boot_device,
>      sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0xF8000000);
> 
>      dev = qdev_create(NULL, "a9mpcore_priv");
> -    qdev_prop_set_uint32(dev, "num-cpu", 1);
> +    qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
>      qdev_init_nofail(dev);
>      busdev = sysbus_from_qdev(dev);
>      sysbus_mmio_map(busdev, 0, 0xF8F00000);
> -    sysbus_connect_irq(busdev, 0, cpu_irq);
> +    for (n = 0; n < smp_cpus; n++) {
> +        sysbus_connect_irq(busdev, n, cpu_irq[n]);
> +    }
> 
>      for (n = 0; n < 64; n++) {
>          pic[n] = qdev_get_gpio_in(dev, n);
> @@ -134,7 +174,9 @@ static void zynq_init(ram_addr_t ram_size, const
> char *boot_device,
>      zynq_binfo.kernel_filename = kernel_filename;
>      zynq_binfo.kernel_cmdline = kernel_cmdline;
>      zynq_binfo.initrd_filename = initrd_filename;
> -    zynq_binfo.nb_cpus = 1;
> +    zynq_binfo.nb_cpus = smp_cpus;
> +    zynq_binfo.write_secondary_boot = zynq_write_secondary_boot;
> +    zynq_binfo.secondary_cpu_reset_hook = zynq_reset_secondary;
>      zynq_binfo.board_id = 0xd32;
>      zynq_binfo.loader_start = 0;
>      arm_load_kernel(first_cpu, &zynq_binfo);
> @@ -145,7 +187,7 @@ static QEMUMachine zynq_machine = {
>      .desc = "Xilinx Zynq Platform Baseboard for Cortex-A9",
>      .init = zynq_init,
>      .use_scsi = 1,
> -    .max_cpus = 1,
> +    .max_cpus = 2,
>      .no_sdcard = 1
>  };
> 
> --
> 1.7.3.2
> 


This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.
Peter A. G. Crosthwaite April 20, 2012, 6:18 a.m. UTC | #2
Ping!

I realise there were issues with the other patches in this series, but
this one on its own is self contained and valuable in its own right.
Can we get a review accordingly?

Regards,
Peter

On Wed, Apr 11, 2012 at 3:50 AM, John Linn <John.Linn@xilinx.com> wrote:
>> -----Original Message-----
>> From: Peter A. G. Crosthwaite [mailto:peter.crosthwaite@petalogix.com]
>> Sent: Sunday, April 01, 2012 10:20 PM
>> To: peter.crosthwaite@petalogix.com; qemu-devel@nongnu.org;
>> paul@codesourcery.com; peter.maydell@linaro.org;
>> edgar.iglesias@gmail.com
>> Cc: Duy Le; John Linn; john.williams@petalogix.com
>> Subject: [PATCH v1 1/3] xilinx_zynq: added smp support
>>
>> Added linux smp support for the xilinx zynq platform (2x cpus are
>> supported)
>>
>> Signed-off-by: Peter A. G. Crosthwaite
>> <peter.crosthwaite@petalogix.com>
>
> Signed-off-by: John Linn <john.linn@xilinx.com>
>
>> ---
>>  hw/xilinx_zynq.c |   64
> ++++++++++++++++++++++++++++++++++++++++++++--
>> -------
>>  1 files changed, 53 insertions(+), 11 deletions(-)
>>
>> diff --git a/hw/xilinx_zynq.c b/hw/xilinx_zynq.c
>> index 7290c64..56d0b96 100644
>> --- a/hw/xilinx_zynq.c
>> +++ b/hw/xilinx_zynq.c
>> @@ -30,6 +30,42 @@
>>
>>  #define IRQ_OFFSET 32 /* pic interrupts start from index 32 */
>>
>> +#define SMP_BOOT_ADDR 0x0fff0000
>> +
>> +static void zynq_reset_secondary(CPUARMState *env,
>> +                                    const struct arm_boot_info *info)
>> +{
>> +    env->regs[15] = SMP_BOOT_ADDR;
>> +}
>> +
>> +/* Entry point for secondary CPU */
>> +static uint32_t zynq_smpboot[] = {
>> +    0xe59f0020, /* ldr     r0, privbase */
>> +    0xe3a004FF, /* mov     r0 = 0xFFFFFFF0 */
>> +    0xe38008FF, /* orr     ...*/
>> +    0xe3800CFF, /* orr     .... */
>> +    0xe38000F0, /* orr     ..... */
>> +    0xe320f002, /* wfe */
>> +    0xe5901000, /* ldr     r1, [r0] */
>> +    0xe1110001, /* tst     r1, r1 */
>> +    0x0afffffb, /* beq     <wfe> */
>> +    0xe12fff11, /* bx      r1 */
>> +    0,
>> +    0
>> +};
>> +
>> +static void zynq_write_secondary_boot(CPUARMState *env,
>> +                                    const struct arm_boot_info *info)
>> +{
>> +    int n;
>> +
>> +    for (n = 0; n < ARRAY_SIZE(zynq_smpboot); n++) {
>> +        zynq_smpboot[n] = tswap32(zynq_smpboot[n]);
>> +    }
>> +    rom_add_blob_fixed("smpboot", zynq_smpboot, sizeof(zynq_smpboot),
>> +            SMP_BOOT_ADDR);
>> +}
>> +
>>  static struct arm_boot_info zynq_binfo = {};
>>
>>  static void gem_init(NICInfo *nd, uint32_t base, qemu_irq irq)
>> @@ -60,19 +96,21 @@ static void zynq_init(ram_addr_t ram_size, const
>> char *boot_device,
>>      qemu_irq pic[64];
>>      NICInfo *nd;
>>      int n;
>> -    qemu_irq cpu_irq;
>> +    qemu_irq cpu_irq[2];
>>
>>      if (!cpu_model) {
>>          cpu_model = "cortex-a9";
>>      }
>>
>> -    env = cpu_init(cpu_model);
>> -    if (!env) {
>> -        fprintf(stderr, "Unable to find CPU definition\n");
>> -        exit(1);
>> +    for (n = 0; n < smp_cpus; n++) {
>> +        env = cpu_init(cpu_model);
>> +        if (!env) {
>> +            fprintf(stderr, "Unable to find CPU definition\n");
>> +            exit(1);
>> +        }
>> +        irqp = arm_pic_init_cpu(env);
>> +        cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ];
>>      }
>> -    irqp = arm_pic_init_cpu(env);
>> -    cpu_irq = irqp[ARM_PIC_CPU_IRQ];
>>
>>      /* max 2GB ram */
>>      if (ram_size > 0x80000000) {
>> @@ -103,11 +141,13 @@ static void zynq_init(ram_addr_t ram_size, const
>> char *boot_device,
>>      sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0xF8000000);
>>
>>      dev = qdev_create(NULL, "a9mpcore_priv");
>> -    qdev_prop_set_uint32(dev, "num-cpu", 1);
>> +    qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
>>      qdev_init_nofail(dev);
>>      busdev = sysbus_from_qdev(dev);
>>      sysbus_mmio_map(busdev, 0, 0xF8F00000);
>> -    sysbus_connect_irq(busdev, 0, cpu_irq);
>> +    for (n = 0; n < smp_cpus; n++) {
>> +        sysbus_connect_irq(busdev, n, cpu_irq[n]);
>> +    }
>>
>>      for (n = 0; n < 64; n++) {
>>          pic[n] = qdev_get_gpio_in(dev, n);
>> @@ -134,7 +174,9 @@ static void zynq_init(ram_addr_t ram_size, const
>> char *boot_device,
>>      zynq_binfo.kernel_filename = kernel_filename;
>>      zynq_binfo.kernel_cmdline = kernel_cmdline;
>>      zynq_binfo.initrd_filename = initrd_filename;
>> -    zynq_binfo.nb_cpus = 1;
>> +    zynq_binfo.nb_cpus = smp_cpus;
>> +    zynq_binfo.write_secondary_boot = zynq_write_secondary_boot;
>> +    zynq_binfo.secondary_cpu_reset_hook = zynq_reset_secondary;
>>      zynq_binfo.board_id = 0xd32;
>>      zynq_binfo.loader_start = 0;
>>      arm_load_kernel(first_cpu, &zynq_binfo);
>> @@ -145,7 +187,7 @@ static QEMUMachine zynq_machine = {
>>      .desc = "Xilinx Zynq Platform Baseboard for Cortex-A9",
>>      .init = zynq_init,
>>      .use_scsi = 1,
>> -    .max_cpus = 1,
>> +    .max_cpus = 2,
>>      .no_sdcard = 1
>>  };
>>
>> --
>> 1.7.3.2
>>
>
>
> This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.
>
>
Peter Maydell April 20, 2012, 11:29 a.m. UTC | #3
On 2 April 2012 06:20, Peter A. G. Crosthwaite
<peter.crosthwaite@petalogix.com> wrote:
> Added linux smp support for the xilinx zynq platform (2x cpus are supported)
>
> Signed-off-by: Peter A. G. Crosthwaite <peter.crosthwaite@petalogix.com>
> ---
>  hw/xilinx_zynq.c |   64 ++++++++++++++++++++++++++++++++++++++++++++---------
>  1 files changed, 53 insertions(+), 11 deletions(-)
>
> diff --git a/hw/xilinx_zynq.c b/hw/xilinx_zynq.c
> index 7290c64..56d0b96 100644
> --- a/hw/xilinx_zynq.c
> +++ b/hw/xilinx_zynq.c
> @@ -30,6 +30,42 @@
>
>  #define IRQ_OFFSET 32 /* pic interrupts start from index 32 */
>
> +#define SMP_BOOT_ADDR 0x0fff0000
> +
> +static void zynq_reset_secondary(CPUARMState *env,
> +                                    const struct arm_boot_info *info)
> +{
> +    env->regs[15] = SMP_BOOT_ADDR;
> +}
> +
> +/* Entry point for secondary CPU */
> +static uint32_t zynq_smpboot[] = {
> +    0xe59f0020, /* ldr     r0, privbase */
> +    0xe3a004FF, /* mov     r0 = 0xFFFFFFF0 */
> +    0xe38008FF, /* orr     ...*/
> +    0xe3800CFF, /* orr     .... */
> +    0xe38000F0, /* orr     ..... */

These four insns are a rather longwinded way of saying
    0xe3e0000f /* ldr r0, =0xfffffff0 (mvn r0, #15) */
aren't they?

> +    0xe320f002, /* wfe */
> +    0xe5901000, /* ldr     r1, [r0] */
> +    0xe1110001, /* tst     r1, r1 */
> +    0x0afffffb, /* beq     <wfe> */
> +    0xe12fff11, /* bx      r1 */
> +    0,
> +    0
> +};

Who is responsible for resetting the 0xFFFFFFF0
location so that on reset the secondary CPUs don't
immediately leave their pen? It looks from a quick glance
like this is in the on-chip RAM, is that right?
(If it is in RAM, then maybe you should be using the
default_reset_secondary() rather than your own version?)

-- PMM
John Linn April 20, 2012, 2:35 p.m. UTC | #4
> -----Original Message-----
> From: Peter Crosthwaite [mailto:peter.crosthwaite@petalogix.com]
> Sent: Thursday, April 19, 2012 11:18 PM
> To: John Linn
> Cc: qemu-devel@nongnu.org; paul@codesourcery.com;
> peter.maydell@linaro.org; edgar.iglesias@gmail.com; Duy Le;
> john.williams@petalogix.com
> Subject: Re: [PATCH v1 1/3] xilinx_zynq: added smp support
> 
> Ping!
> 
> I realise there were issues with the other patches in this series, but
> this one on its own is self contained and valuable in its own right.
> Can we get a review accordingly?

Sure.

-- John

> 
> Regards,
> Peter
> 
> On Wed, Apr 11, 2012 at 3:50 AM, John Linn <John.Linn@xilinx.com> wrote:
> >> -----Original Message-----
> >> From: Peter A. G. Crosthwaite
> [mailto:peter.crosthwaite@petalogix.com]
> >> Sent: Sunday, April 01, 2012 10:20 PM
> >> To: peter.crosthwaite@petalogix.com; qemu-devel@nongnu.org;
> >> paul@codesourcery.com; peter.maydell@linaro.org;
> >> edgar.iglesias@gmail.com
> >> Cc: Duy Le; John Linn; john.williams@petalogix.com
> >> Subject: [PATCH v1 1/3] xilinx_zynq: added smp support
> >>
> >> Added linux smp support for the xilinx zynq platform (2x cpus are
> >> supported)
> >>
> >> Signed-off-by: Peter A. G. Crosthwaite
> >> <peter.crosthwaite@petalogix.com>
> >
> > Signed-off-by: John Linn <john.linn@xilinx.com>
> >
> >> ---
> >>  hw/xilinx_zynq.c |   64
> > ++++++++++++++++++++++++++++++++++++++++++++--
> >> -------
> >>  1 files changed, 53 insertions(+), 11 deletions(-)
> >>
> >> diff --git a/hw/xilinx_zynq.c b/hw/xilinx_zynq.c
> >> index 7290c64..56d0b96 100644
> >> --- a/hw/xilinx_zynq.c
> >> +++ b/hw/xilinx_zynq.c
> >> @@ -30,6 +30,42 @@
> >>
> >>  #define IRQ_OFFSET 32 /* pic interrupts start from index 32 */
> >>
> >> +#define SMP_BOOT_ADDR 0x0fff0000
> >> +
> >> +static void zynq_reset_secondary(CPUARMState *env,
> >> +                                    const struct arm_boot_info
> *info)
> >> +{
> >> +    env->regs[15] = SMP_BOOT_ADDR;
> >> +}
> >> +
> >> +/* Entry point for secondary CPU */
> >> +static uint32_t zynq_smpboot[] = {
> >> +    0xe59f0020, /* ldr     r0, privbase */
> >> +    0xe3a004FF, /* mov     r0 = 0xFFFFFFF0 */
> >> +    0xe38008FF, /* orr     ...*/
> >> +    0xe3800CFF, /* orr     .... */
> >> +    0xe38000F0, /* orr     ..... */
> >> +    0xe320f002, /* wfe */
> >> +    0xe5901000, /* ldr     r1, [r0] */
> >> +    0xe1110001, /* tst     r1, r1 */
> >> +    0x0afffffb, /* beq     <wfe> */
> >> +    0xe12fff11, /* bx      r1 */
> >> +    0,
> >> +    0
> >> +};
> >> +
> >> +static void zynq_write_secondary_boot(CPUARMState *env,
> >> +                                    const struct arm_boot_info
> *info)
> >> +{
> >> +    int n;
> >> +
> >> +    for (n = 0; n < ARRAY_SIZE(zynq_smpboot); n++) {
> >> +        zynq_smpboot[n] = tswap32(zynq_smpboot[n]);
> >> +    }
> >> +    rom_add_blob_fixed("smpboot", zynq_smpboot,
> sizeof(zynq_smpboot),
> >> +            SMP_BOOT_ADDR);
> >> +}
> >> +
> >>  static struct arm_boot_info zynq_binfo = {};
> >>
> >>  static void gem_init(NICInfo *nd, uint32_t base, qemu_irq irq)
> >> @@ -60,19 +96,21 @@ static void zynq_init(ram_addr_t ram_size, const
> >> char *boot_device,
> >>      qemu_irq pic[64];
> >>      NICInfo *nd;
> >>      int n;
> >> -    qemu_irq cpu_irq;
> >> +    qemu_irq cpu_irq[2];
> >>
> >>      if (!cpu_model) {
> >>          cpu_model = "cortex-a9";
> >>      }
> >>
> >> -    env = cpu_init(cpu_model);
> >> -    if (!env) {
> >> -        fprintf(stderr, "Unable to find CPU definition\n");
> >> -        exit(1);
> >> +    for (n = 0; n < smp_cpus; n++) {
> >> +        env = cpu_init(cpu_model);
> >> +        if (!env) {
> >> +            fprintf(stderr, "Unable to find CPU definition\n");
> >> +            exit(1);
> >> +        }
> >> +        irqp = arm_pic_init_cpu(env);
> >> +        cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ];
> >>      }
> >> -    irqp = arm_pic_init_cpu(env);
> >> -    cpu_irq = irqp[ARM_PIC_CPU_IRQ];
> >>
> >>      /* max 2GB ram */
> >>      if (ram_size > 0x80000000) {
> >> @@ -103,11 +141,13 @@ static void zynq_init(ram_addr_t ram_size,
> const
> >> char *boot_device,
> >>      sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0xF8000000);
> >>
> >>      dev = qdev_create(NULL, "a9mpcore_priv");
> >> -    qdev_prop_set_uint32(dev, "num-cpu", 1);
> >> +    qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
> >>      qdev_init_nofail(dev);
> >>      busdev = sysbus_from_qdev(dev);
> >>      sysbus_mmio_map(busdev, 0, 0xF8F00000);
> >> -    sysbus_connect_irq(busdev, 0, cpu_irq);
> >> +    for (n = 0; n < smp_cpus; n++) {
> >> +        sysbus_connect_irq(busdev, n, cpu_irq[n]);
> >> +    }
> >>
> >>      for (n = 0; n < 64; n++) {
> >>          pic[n] = qdev_get_gpio_in(dev, n);
> >> @@ -134,7 +174,9 @@ static void zynq_init(ram_addr_t ram_size, const
> >> char *boot_device,
> >>      zynq_binfo.kernel_filename = kernel_filename;
> >>      zynq_binfo.kernel_cmdline = kernel_cmdline;
> >>      zynq_binfo.initrd_filename = initrd_filename;
> >> -    zynq_binfo.nb_cpus = 1;
> >> +    zynq_binfo.nb_cpus = smp_cpus;
> >> +    zynq_binfo.write_secondary_boot = zynq_write_secondary_boot;
> >> +    zynq_binfo.secondary_cpu_reset_hook = zynq_reset_secondary;
> >>      zynq_binfo.board_id = 0xd32;
> >>      zynq_binfo.loader_start = 0;
> >>      arm_load_kernel(first_cpu, &zynq_binfo);
> >> @@ -145,7 +187,7 @@ static QEMUMachine zynq_machine = {
> >>      .desc = "Xilinx Zynq Platform Baseboard for Cortex-A9",
> >>      .init = zynq_init,
> >>      .use_scsi = 1,
> >> -    .max_cpus = 1,
> >> +    .max_cpus = 2,
> >>      .no_sdcard = 1
> >>  };
> >>
> >> --
> >> 1.7.3.2
> >>
> >
> >
> > This email and any attachments are intended for the sole use of the
> named recipient(s) and contain(s) confidential information that may be
> proprietary, privileged or copyrighted under applicable law. If you are
> not the intended recipient, do not read, copy, or forward this email
> message or any attachments. Delete this email message and any
> attachments immediately.
> >
> >


This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.
diff mbox

Patch

diff --git a/hw/xilinx_zynq.c b/hw/xilinx_zynq.c
index 7290c64..56d0b96 100644
--- a/hw/xilinx_zynq.c
+++ b/hw/xilinx_zynq.c
@@ -30,6 +30,42 @@ 
 
 #define IRQ_OFFSET 32 /* pic interrupts start from index 32 */
 
+#define SMP_BOOT_ADDR 0x0fff0000
+
+static void zynq_reset_secondary(CPUARMState *env,
+                                    const struct arm_boot_info *info)
+{
+    env->regs[15] = SMP_BOOT_ADDR;
+}
+
+/* Entry point for secondary CPU */
+static uint32_t zynq_smpboot[] = {
+    0xe59f0020, /* ldr     r0, privbase */
+    0xe3a004FF, /* mov     r0 = 0xFFFFFFF0 */
+    0xe38008FF, /* orr     ...*/
+    0xe3800CFF, /* orr     .... */
+    0xe38000F0, /* orr     ..... */
+    0xe320f002, /* wfe */
+    0xe5901000, /* ldr     r1, [r0] */
+    0xe1110001, /* tst     r1, r1 */
+    0x0afffffb, /* beq     <wfe> */
+    0xe12fff11, /* bx      r1 */
+    0,
+    0
+};
+
+static void zynq_write_secondary_boot(CPUARMState *env,
+                                    const struct arm_boot_info *info)
+{
+    int n;
+
+    for (n = 0; n < ARRAY_SIZE(zynq_smpboot); n++) {
+        zynq_smpboot[n] = tswap32(zynq_smpboot[n]);
+    }
+    rom_add_blob_fixed("smpboot", zynq_smpboot, sizeof(zynq_smpboot),
+            SMP_BOOT_ADDR);
+}
+
 static struct arm_boot_info zynq_binfo = {};
 
 static void gem_init(NICInfo *nd, uint32_t base, qemu_irq irq)
@@ -60,19 +96,21 @@  static void zynq_init(ram_addr_t ram_size, const char *boot_device,
     qemu_irq pic[64];
     NICInfo *nd;
     int n;
-    qemu_irq cpu_irq;
+    qemu_irq cpu_irq[2];
 
     if (!cpu_model) {
         cpu_model = "cortex-a9";
     }
 
-    env = cpu_init(cpu_model);
-    if (!env) {
-        fprintf(stderr, "Unable to find CPU definition\n");
-        exit(1);
+    for (n = 0; n < smp_cpus; n++) {
+        env = cpu_init(cpu_model);
+        if (!env) {
+            fprintf(stderr, "Unable to find CPU definition\n");
+            exit(1);
+        }
+        irqp = arm_pic_init_cpu(env);
+        cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ];
     }
-    irqp = arm_pic_init_cpu(env);
-    cpu_irq = irqp[ARM_PIC_CPU_IRQ];
 
     /* max 2GB ram */
     if (ram_size > 0x80000000) {
@@ -103,11 +141,13 @@  static void zynq_init(ram_addr_t ram_size, const char *boot_device,
     sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0xF8000000);
 
     dev = qdev_create(NULL, "a9mpcore_priv");
-    qdev_prop_set_uint32(dev, "num-cpu", 1);
+    qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
     qdev_init_nofail(dev);
     busdev = sysbus_from_qdev(dev);
     sysbus_mmio_map(busdev, 0, 0xF8F00000);
-    sysbus_connect_irq(busdev, 0, cpu_irq);
+    for (n = 0; n < smp_cpus; n++) {
+        sysbus_connect_irq(busdev, n, cpu_irq[n]);
+    }
 
     for (n = 0; n < 64; n++) {
         pic[n] = qdev_get_gpio_in(dev, n);
@@ -134,7 +174,9 @@  static void zynq_init(ram_addr_t ram_size, const char *boot_device,
     zynq_binfo.kernel_filename = kernel_filename;
     zynq_binfo.kernel_cmdline = kernel_cmdline;
     zynq_binfo.initrd_filename = initrd_filename;
-    zynq_binfo.nb_cpus = 1;
+    zynq_binfo.nb_cpus = smp_cpus;
+    zynq_binfo.write_secondary_boot = zynq_write_secondary_boot;
+    zynq_binfo.secondary_cpu_reset_hook = zynq_reset_secondary;
     zynq_binfo.board_id = 0xd32;
     zynq_binfo.loader_start = 0;
     arm_load_kernel(first_cpu, &zynq_binfo);
@@ -145,7 +187,7 @@  static QEMUMachine zynq_machine = {
     .desc = "Xilinx Zynq Platform Baseboard for Cortex-A9",
     .init = zynq_init,
     .use_scsi = 1,
-    .max_cpus = 1,
+    .max_cpus = 2,
     .no_sdcard = 1
 };