From patchwork Sat Mar 2 15:18:47 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sanjay Lal X-Patchwork-Id: 2207231 Return-Path: X-Original-To: patchwork-kvm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork1.kernel.org (Postfix) with ESMTP id 3D13F3FCF2 for ; Sat, 2 Mar 2013 15:19:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752720Ab3CBPT0 (ORCPT ); Sat, 2 Mar 2013 10:19:26 -0500 Received: from kymasys.com ([64.62.140.43]:33924 "HELO kymasys.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with SMTP id S1752611Ab3CBPTY (ORCPT ); Sat, 2 Mar 2013 10:19:24 -0500 Received: from agni.kymasys.com ([75.40.23.192]) by kymasys.com for ; Sat, 2 Mar 2013 07:19:22 -0800 Received: by agni.kymasys.com (Postfix, from userid 500) id 219E963005C; Sat, 2 Mar 2013 07:18:50 -0800 (PST) From: Sanjay Lal To: qemu-devel@nongnu.org Cc: kvm@vger.kernel.org, Aurelien Jarno , Gleb Natapov , Marcelo Tosatti , Sanjay Lal Subject: [Qemu-devel][PATCH 12/12] KVM/MIPS: General KVM support and support for SMP Guests Date: Sat, 2 Mar 2013 07:18:47 -0800 Message-Id: <1362237527-23678-14-git-send-email-sanjayl@kymasys.com> X-Mailer: git-send-email 1.7.11.3 In-Reply-To: <1362237527-23678-1-git-send-email-sanjayl@kymasys.com> References: <1362237527-23678-1-git-send-email-sanjayl@kymasys.com> Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org - In KVM mode the bootrom is loaded and executed from the last 1MB of DRAM. - Use the CPS bootrom from MIPS in KVM mode. This allows bootstrapping of multiple cores. - Add suport for MIPS GIC emulation for SMP Guests. --- hw/mips_malta.c | 192 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 126 insertions(+), 66 deletions(-) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 2a150df..e04aa4a 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -48,6 +48,13 @@ #include "sysemu/blockdev.h" #include "exec/address-spaces.h" #include "sysbus.h" /* SysBusDevice */ +#include "qemu/bitmap.h" +#include "mips_gic.h" +#include "sysemu/kvm.h" +#include "linux/kvm.h" +#include "kvm_mips.h" + +#include "mips_cps_bootcode.h" //#define DEBUG_BOARD_INIT @@ -514,27 +521,36 @@ static void write_bootloader (CPUMIPSState *env, uint8_t *base, /* Small bootloader */ p = (uint32_t *)base; - stl_raw(p++, 0x0bf00160); /* j 0x1fc00580 */ - stl_raw(p++, 0x00000000); /* nop */ - /* YAMON service vector */ - stl_raw(base + 0x500, 0xbfc00580); /* start: */ - stl_raw(base + 0x504, 0xbfc0083c); /* print_count: */ - stl_raw(base + 0x520, 0xbfc00580); /* start: */ - stl_raw(base + 0x52c, 0xbfc00800); /* flush_cache: */ - stl_raw(base + 0x534, 0xbfc00808); /* print: */ - stl_raw(base + 0x538, 0xbfc00800); /* reg_cpu_isr: */ - stl_raw(base + 0x53c, 0xbfc00800); /* unred_cpu_isr: */ - stl_raw(base + 0x540, 0xbfc00800); /* reg_ic_isr: */ - stl_raw(base + 0x544, 0xbfc00800); /* unred_ic_isr: */ - stl_raw(base + 0x548, 0xbfc00800); /* reg_esr: */ - stl_raw(base + 0x54c, 0xbfc00800); /* unreg_esr: */ - stl_raw(base + 0x550, 0xbfc00800); /* getchar: */ - stl_raw(base + 0x554, 0xbfc00800); /* syscon_read: */ + if (kvm_enabled()) { + memcpy((void *)base, (void *)__boot_cps_data, sizeof(__boot_cps_data)); + /* Second part of the bootloader */ + p = (uint32_t *) (base + 0x100); + } + else { + stl_raw(p++, 0x0bf00160); /* j 0x1fc00580 */ + stl_raw(p++, 0x00000000); /* nop */ + + /* YAMON service vector */ + stl_raw(base + 0x500, 0xbfc00580); /* start: */ + stl_raw(base + 0x504, 0xbfc0083c); /* print_count: */ + stl_raw(base + 0x520, 0xbfc00580); /* start: */ + stl_raw(base + 0x52c, 0xbfc00800); /* flush_cache: */ + stl_raw(base + 0x534, 0xbfc00808); /* print: */ + stl_raw(base + 0x538, 0xbfc00800); /* reg_cpu_isr: */ + stl_raw(base + 0x53c, 0xbfc00800); /* unred_cpu_isr: */ + stl_raw(base + 0x540, 0xbfc00800); /* reg_ic_isr: */ + stl_raw(base + 0x544, 0xbfc00800); /* unred_ic_isr: */ + stl_raw(base + 0x548, 0xbfc00800); /* reg_esr: */ + stl_raw(base + 0x54c, 0xbfc00800); /* unreg_esr: */ + stl_raw(base + 0x550, 0xbfc00800); /* getchar: */ + stl_raw(base + 0x554, 0xbfc00800); /* syscon_read: */ + + p = (uint32_t *) (base + 0x580); + } /* Second part of the bootloader */ - p = (uint32_t *) (base + 0x580); stl_raw(p++, 0x24040002); /* addiu a0, zero, 2 */ stl_raw(p++, 0x3c1d0000 | (((ENVP_ADDR - 64) >> 16) & 0xffff)); /* lui sp, high(ENVP_ADDR) */ stl_raw(p++, 0x37bd0000 | ((ENVP_ADDR - 64) & 0xffff)); /* ori sp, sp, low(ENVP_ADDR) */ @@ -603,48 +619,49 @@ static void write_bootloader (CPUMIPSState *env, uint8_t *base, stl_raw(p++, 0x00000000); /* nop */ /* YAMON subroutines */ - p = (uint32_t *) (base + 0x800); - stl_raw(p++, 0x03e00008); /* jr ra */ - stl_raw(p++, 0x24020000); /* li v0,0 */ - /* 808 YAMON print */ - stl_raw(p++, 0x03e06821); /* move t5,ra */ - stl_raw(p++, 0x00805821); /* move t3,a0 */ - stl_raw(p++, 0x00a05021); /* move t2,a1 */ - stl_raw(p++, 0x91440000); /* lbu a0,0(t2) */ - stl_raw(p++, 0x254a0001); /* addiu t2,t2,1 */ - stl_raw(p++, 0x10800005); /* beqz a0,834 */ - stl_raw(p++, 0x00000000); /* nop */ - stl_raw(p++, 0x0ff0021c); /* jal 870 */ - stl_raw(p++, 0x00000000); /* nop */ - stl_raw(p++, 0x08000205); /* j 814 */ - stl_raw(p++, 0x00000000); /* nop */ - stl_raw(p++, 0x01a00008); /* jr t5 */ - stl_raw(p++, 0x01602021); /* move a0,t3 */ - /* 0x83c YAMON print_count */ - stl_raw(p++, 0x03e06821); /* move t5,ra */ - stl_raw(p++, 0x00805821); /* move t3,a0 */ - stl_raw(p++, 0x00a05021); /* move t2,a1 */ - stl_raw(p++, 0x00c06021); /* move t4,a2 */ - stl_raw(p++, 0x91440000); /* lbu a0,0(t2) */ - stl_raw(p++, 0x0ff0021c); /* jal 870 */ - stl_raw(p++, 0x00000000); /* nop */ - stl_raw(p++, 0x254a0001); /* addiu t2,t2,1 */ - stl_raw(p++, 0x258cffff); /* addiu t4,t4,-1 */ - stl_raw(p++, 0x1580fffa); /* bnez t4,84c */ - stl_raw(p++, 0x00000000); /* nop */ - stl_raw(p++, 0x01a00008); /* jr t5 */ - stl_raw(p++, 0x01602021); /* move a0,t3 */ - /* 0x870 */ - stl_raw(p++, 0x3c08b800); /* lui t0,0xb400 */ - stl_raw(p++, 0x350803f8); /* ori t0,t0,0x3f8 */ - stl_raw(p++, 0x91090005); /* lbu t1,5(t0) */ - stl_raw(p++, 0x00000000); /* nop */ - stl_raw(p++, 0x31290040); /* andi t1,t1,0x40 */ - stl_raw(p++, 0x1120fffc); /* beqz t1,878 */ - stl_raw(p++, 0x00000000); /* nop */ - stl_raw(p++, 0x03e00008); /* jr ra */ - stl_raw(p++, 0xa1040000); /* sb a0,0(t0) */ - + if (!kvm_enabled()) { + p = (uint32_t *) (base + 0x800); + stl_raw(p++, 0x03e00008); /* jr ra */ + stl_raw(p++, 0x24020000); /* li v0,0 */ + /* 808 YAMON print */ + stl_raw(p++, 0x03e06821); /* move t5,ra */ + stl_raw(p++, 0x00805821); /* move t3,a0 */ + stl_raw(p++, 0x00a05021); /* move t2,a1 */ + stl_raw(p++, 0x91440000); /* lbu a0,0(t2) */ + stl_raw(p++, 0x254a0001); /* addiu t2,t2,1 */ + stl_raw(p++, 0x10800005); /* beqz a0,834 */ + stl_raw(p++, 0x00000000); /* nop */ + stl_raw(p++, 0x0ff0021c); /* jal 870 */ + stl_raw(p++, 0x00000000); /* nop */ + stl_raw(p++, 0x08000205); /* j 814 */ + stl_raw(p++, 0x00000000); /* nop */ + stl_raw(p++, 0x01a00008); /* jr t5 */ + stl_raw(p++, 0x01602021); /* move a0,t3 */ + /* 0x83c YAMON print_count */ + stl_raw(p++, 0x03e06821); /* move t5,ra */ + stl_raw(p++, 0x00805821); /* move t3,a0 */ + stl_raw(p++, 0x00a05021); /* move t2,a1 */ + stl_raw(p++, 0x00c06021); /* move t4,a2 */ + stl_raw(p++, 0x91440000); /* lbu a0,0(t2) */ + stl_raw(p++, 0x0ff0021c); /* jal 870 */ + stl_raw(p++, 0x00000000); /* nop */ + stl_raw(p++, 0x254a0001); /* addiu t2,t2,1 */ + stl_raw(p++, 0x258cffff); /* addiu t4,t4,-1 */ + stl_raw(p++, 0x1580fffa); /* bnez t4,84c */ + stl_raw(p++, 0x00000000); /* nop */ + stl_raw(p++, 0x01a00008); /* jr t5 */ + stl_raw(p++, 0x01602021); /* move a0,t3 */ + /* 0x870 */ + stl_raw(p++, 0x3c08b800); /* lui t0,0xb400 */ + stl_raw(p++, 0x350803f8); /* ori t0,t0,0x3f8 */ + stl_raw(p++, 0x91090005); /* lbu t1,5(t0) */ + stl_raw(p++, 0x00000000); /* nop */ + stl_raw(p++, 0x31290040); /* andi t1,t1,0x40 */ + stl_raw(p++, 0x1120fffc); /* beqz t1,878 */ + stl_raw(p++, 0x00000000); /* nop */ + stl_raw(p++, 0x03e00008); /* jr ra */ + stl_raw(p++, 0xa1040000); /* sb a0,0(t0) */ + } } static void GCC_FMT_ATTR(3, 4) prom_set(uint32_t* prom_buf, int index, @@ -670,7 +687,7 @@ static void GCC_FMT_ATTR(3, 4) prom_set(uint32_t* prom_buf, int index, } /* Kernel */ -static int64_t load_kernel (void) +static int64_t load_kernel (CPUMIPSState *env) { int64_t kernel_entry, kernel_high; long initrd_size; @@ -679,6 +696,9 @@ static int64_t load_kernel (void) uint32_t *prom_buf; long prom_size; int prom_index = 0; + uint64_t (*xlate_to_phys) (void *opaque, uint64_t addr); + uint64_t (*xlate_to_kseg0) (void *opaque, uint64_t addr); + #ifdef TARGET_WORDS_BIGENDIAN big_endian = 1; @@ -686,7 +706,15 @@ static int64_t load_kernel (void) big_endian = 0; #endif - if (load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys, NULL, + if (kvm_enabled()) { + xlate_to_phys = cpu_mips_kvm_um_kseg0_to_phys; + xlate_to_kseg0 = cpu_mips_kvm_um_phys_to_kseg0; + } else { + xlate_to_phys = cpu_mips_kseg0_to_phys; + xlate_to_kseg0 = cpu_mips_phys_to_kseg0; + } + + if (load_elf(loaderparams.kernel_filename, xlate_to_phys, NULL, (uint64_t *)&kernel_entry, NULL, (uint64_t *)&kernel_high, big_endian, ELF_MACHINE, 1) < 0) { fprintf(stderr, "qemu: could not load kernel '%s'\n", @@ -725,20 +753,24 @@ static int64_t load_kernel (void) prom_set(prom_buf, prom_index++, "%s", loaderparams.kernel_filename); if (initrd_size > 0) { prom_set(prom_buf, prom_index++, "rd_start=0x%" PRIx64 " rd_size=%li %s", - cpu_mips_phys_to_kseg0(NULL, initrd_offset), initrd_size, + xlate_to_kseg0(NULL, initrd_offset), initrd_size, loaderparams.kernel_cmdline); } else { prom_set(prom_buf, prom_index++, "%s", loaderparams.kernel_cmdline); } prom_set(prom_buf, prom_index++, "memsize"); - prom_set(prom_buf, prom_index++, "%i", loaderparams.ram_size); + if (kvm_enabled()) + prom_set(prom_buf, prom_index++, "%i", (loaderparams.ram_size - 0x100000)); + else + prom_set(prom_buf, prom_index++, "%i", loaderparams.ram_size); + prom_set(prom_buf, prom_index++, "modetty0"); prom_set(prom_buf, prom_index++, "38400n8r"); prom_set(prom_buf, prom_index++, NULL); rom_add_blob_fixed("prom", prom_buf, prom_size, - cpu_mips_kseg0_to_phys(NULL, ENVP_ADDR)); + xlate_to_phys(NULL, ENVP_ADDR)); return kernel_entry; } @@ -767,6 +799,23 @@ static void main_cpu_reset(void *opaque) } malta_mips_config(cpu); + + if (kvm_enabled()) { + + /* Start running @ the point where the bootrom configures the north bridge BARs */ + env->active_tc.PC = 0x40000000 + ((loaderparams.ram_size - 0x100000)); + + + /* a0 - number of kernel arguments + * a1 - 32-bit address of the kernel arguments table + * a2 - 32-bit address of the environment variables table + * a3 - RAM size in bytes + */ + env->active_tc.gpr[4] = 0x2; + env->active_tc.gpr[5] = 0x80002000; + env->active_tc.gpr[6] = 0x80002008; + env->active_tc.gpr[7] = loaderparams.ram_size - 0x100000; + } } static void cpu_request_exit(void *opaque, int irq, int level) @@ -776,6 +825,7 @@ static void cpu_request_exit(void *opaque, int irq, int level) if (env && level) { cpu_exit(env); } + } static @@ -797,7 +847,7 @@ void mips_malta_init(QEMUMachineInitArgs *args) ISABus *isa_bus; MIPSCPU *cpu; CPUMIPSState *env; - qemu_irq *isa_irq; + qemu_irq *isa_irq, *gic_irq = NULL; qemu_irq *cpu_exit_irq; int piix4_devfn; i2c_bus *smbus; @@ -889,8 +939,13 @@ void mips_malta_init(QEMUMachineInitArgs *args) loaderparams.kernel_filename = kernel_filename; loaderparams.kernel_cmdline = kernel_cmdline; loaderparams.initrd_filename = initrd_filename; - kernel_entry = load_kernel(); + kernel_entry = load_kernel(env); write_bootloader(env, memory_region_get_ram_ptr(bios), kernel_entry); + if (kvm_enabled()) { + /* Write the bootloader code @ the end of RAM, 1MB reserved */ + printf("Writing bootloader to final 1MB of RAM\n"); + write_bootloader(env, memory_region_get_ram_ptr(ram) + loaderparams.ram_size - 0x100000, kernel_entry); + } } else { /* Load firmware from flash. */ if (!dinfo) { @@ -940,6 +995,11 @@ void mips_malta_init(QEMUMachineInitArgs *args) cpu_mips_irq_init_cpu(env); cpu_mips_clock_init(env); + /* GCR/GIC */ + if (kvm_enabled() && smp_cpus > 1) { + gic_irq = gic_init(smp_cpus, env, system_memory); + } + /* * We have a circular dependency problem: pci_bus depends on isa_irq, * isa_irq is provided by i8259, i8259 depends on ISA, ISA depends