diff options
Diffstat (limited to 'hw/arm_boot.c')
-rw-r--r-- | hw/arm_boot.c | 54 |
1 files changed, 43 insertions, 11 deletions
diff --git a/hw/arm_boot.c b/hw/arm_boot.c index bf509a8eb9..35ca22ff47 100644 --- a/hw/arm_boot.c +++ b/hw/arm_boot.c @@ -28,8 +28,20 @@ static uint32_t bootloader[] = { 0 /* Kernel entry point. Set by integratorcp_init. */ }; -/* Entry point for secondary CPUs. Enable interrupt controller and - Issue WFI until start address is written to system controller. */ +/* Handling for secondary CPU boot in a multicore system. + * Unlike the uniprocessor/primary CPU boot, this is platform + * dependent. The default code here is based on the secondary + * CPU boot protocol used on realview/vexpress boards, with + * some parameterisation to increase its flexibility. + * QEMU platform models for which this code is not appropriate + * should override write_secondary_boot and secondary_cpu_reset_hook + * instead. + * + * This code enables the interrupt controllers for the secondary + * CPUs and then puts all the secondary CPUs into a loop waiting + * for an interprocessor interrupt and polling a configurable + * location for the kernel secondary CPU entry point. + */ static uint32_t smpboot[] = { 0xe59f201c, /* ldr r2, privbase */ 0xe59f001c, /* ldr r0, startaddr */ @@ -44,6 +56,26 @@ static uint32_t smpboot[] = { 0 /* bootreg: Boot register address is held here */ }; +static void default_write_secondary(CPUState *env, + const struct arm_boot_info *info) +{ + int n; + smpboot[ARRAY_SIZE(smpboot) - 1] = info->smp_bootreg_addr; + smpboot[ARRAY_SIZE(smpboot) - 2] = info->smp_priv_base; + for (n = 0; n < ARRAY_SIZE(smpboot); n++) { + smpboot[n] = tswap32(smpboot[n]); + } + rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot), + info->smp_loader_start); +} + +static void default_reset_secondary(CPUState *env, + const struct arm_boot_info *info) +{ + stl_phys_notdirty(info->smp_bootreg_addr, 0); + env->regs[15] = info->smp_loader_start; +} + #define WRITE_WORD(p, value) do { \ stl_phys_notdirty(p, value); \ p += 4; \ @@ -197,8 +229,7 @@ static void do_cpu_reset(void *opaque) info->loader_start); } } else { - stl_phys_notdirty(info->smp_bootreg_addr, 0); - env->regs[15] = info->smp_loader_start; + info->secondary_cpu_reset_hook(env, info); } } } @@ -220,6 +251,13 @@ void arm_load_kernel(CPUState *env, struct arm_boot_info *info) exit(1); } + if (!info->secondary_cpu_reset_hook) { + info->secondary_cpu_reset_hook = default_reset_secondary; + } + if (!info->write_secondary_boot) { + info->write_secondary_boot = default_write_secondary; + } + if (info->nb_cpus == 0) info->nb_cpus = 1; @@ -273,13 +311,7 @@ void arm_load_kernel(CPUState *env, struct arm_boot_info *info) rom_add_blob_fixed("bootloader", bootloader, sizeof(bootloader), info->loader_start); if (info->nb_cpus > 1) { - smpboot[ARRAY_SIZE(smpboot) - 1] = info->smp_bootreg_addr; - smpboot[ARRAY_SIZE(smpboot) - 2] = info->smp_priv_base; - for (n = 0; n < ARRAY_SIZE(smpboot); n++) { - smpboot[n] = tswap32(smpboot[n]); - } - rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot), - info->smp_loader_start); + info->write_secondary_boot(env, info); } info->initrd_size = initrd_size; } |