diff mbox

[v5,10/12] hw/mips: malta: Add KVM support

Message ID 1403043037-1271-11-git-send-email-james.hogan@imgtec.com
State New
Headers show

Commit Message

James Hogan June 17, 2014, 10:10 p.m. UTC
In KVM mode the bootrom is loaded and executed from the last 1MB of
DRAM.

Based on "[PATCH 12/12] KVM/MIPS: General KVM support and support for
SMP Guests" by Sanjay Lal <sanjayl@kymasys.com>.

Signed-off-by: James Hogan <james.hogan@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Sanjay Lal <sanjayl@kymasys.com>
---
Changes in v5:
 - Kseg0 doesn't actually change size, so use cpu_mips_kseg0_to_phys()
   rather than having the KVM specific cpu_mips_kvm_um_kseg0_to_phys().

Changes in v3:
 - Remove unnecessary includes, especially linux/kvm.h which isn't a
   good idea on non-Linux (Peter Maydell).

Changes in v2:
 - Removal of cps / GIC / SMP support
 - Minimal bootloader modified to execute safely from RAM
 - Remove "Writing bootloader to final 1MB of RAM" printf
---
 hw/mips/mips_malta.c | 73 ++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 53 insertions(+), 20 deletions(-)

Comments

Aurelien Jarno June 19, 2014, 4:27 p.m. UTC | #1
On Tue, Jun 17, 2014 at 11:10:35PM +0100, James Hogan wrote:
> In KVM mode the bootrom is loaded and executed from the last 1MB of
> DRAM.

What is the reason for that? I am not opposed to that, but if it is
really needed, it means that loading a bootloader into the flash area
(for example YAMON) won't work and that this should be forbidden to the
user.

> Based on "[PATCH 12/12] KVM/MIPS: General KVM support and support for
> SMP Guests" by Sanjay Lal <sanjayl@kymasys.com>.
> 
> Signed-off-by: James Hogan <james.hogan@imgtec.com>
> Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
> Cc: Peter Maydell <peter.maydell@linaro.org>
> Cc: Sanjay Lal <sanjayl@kymasys.com>
> ---
> Changes in v5:
>  - Kseg0 doesn't actually change size, so use cpu_mips_kseg0_to_phys()
>    rather than having the KVM specific cpu_mips_kvm_um_kseg0_to_phys().
> 
> Changes in v3:
>  - Remove unnecessary includes, especially linux/kvm.h which isn't a
>    good idea on non-Linux (Peter Maydell).
> 
> Changes in v2:
>  - Removal of cps / GIC / SMP support
>  - Minimal bootloader modified to execute safely from RAM
>  - Remove "Writing bootloader to final 1MB of RAM" printf
> ---
>  hw/mips/mips_malta.c | 73 ++++++++++++++++++++++++++++++++++++++--------------
>  1 file changed, 53 insertions(+), 20 deletions(-)
> 
> diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c
> index f4a7d4712952..8bc5392b4223 100644
> --- a/hw/mips/mips_malta.c
> +++ b/hw/mips/mips_malta.c
> @@ -51,6 +51,7 @@
>  #include "sysemu/qtest.h"
>  #include "qemu/error-report.h"
>  #include "hw/empty_slot.h"
> +#include "sysemu/kvm.h"
>  
>  //#define DEBUG_BOARD_INIT
>  
> @@ -603,29 +604,31 @@ static void network_init(PCIBus *pci_bus)
>  */
>  
>  static void write_bootloader (CPUMIPSState *env, uint8_t *base,
> -                              int64_t kernel_entry)
> +                              int64_t run_addr, int64_t kernel_entry)
>  {
>      uint32_t *p;
>  
>      /* Small bootloader */
>      p = (uint32_t *)base;
> -    stl_p(p++, 0x0bf00160);                                      /* j 0x1fc00580 */
> +
> +    stl_p(p++, 0x08000000 |                                      /* j 0x1fc00580 */
> +                 ((run_addr + 0x580) & 0x0fffffff) >> 2);
>      stl_p(p++, 0x00000000);                                      /* nop */
>  
>      /* YAMON service vector */
> -    stl_p(base + 0x500, 0xbfc00580);      /* start: */
> -    stl_p(base + 0x504, 0xbfc0083c);      /* print_count: */
> -    stl_p(base + 0x520, 0xbfc00580);      /* start: */
> -    stl_p(base + 0x52c, 0xbfc00800);      /* flush_cache: */
> -    stl_p(base + 0x534, 0xbfc00808);      /* print: */
> -    stl_p(base + 0x538, 0xbfc00800);      /* reg_cpu_isr: */
> -    stl_p(base + 0x53c, 0xbfc00800);      /* unred_cpu_isr: */
> -    stl_p(base + 0x540, 0xbfc00800);      /* reg_ic_isr: */
> -    stl_p(base + 0x544, 0xbfc00800);      /* unred_ic_isr: */
> -    stl_p(base + 0x548, 0xbfc00800);      /* reg_esr: */
> -    stl_p(base + 0x54c, 0xbfc00800);      /* unreg_esr: */
> -    stl_p(base + 0x550, 0xbfc00800);      /* getchar: */
> -    stl_p(base + 0x554, 0xbfc00800);      /* syscon_read: */
> +    stl_p(base + 0x500, run_addr + 0x0580);      /* start: */
> +    stl_p(base + 0x504, run_addr + 0x083c);      /* print_count: */
> +    stl_p(base + 0x520, run_addr + 0x0580);      /* start: */
> +    stl_p(base + 0x52c, run_addr + 0x0800);      /* flush_cache: */
> +    stl_p(base + 0x534, run_addr + 0x0808);      /* print: */
> +    stl_p(base + 0x538, run_addr + 0x0800);      /* reg_cpu_isr: */
> +    stl_p(base + 0x53c, run_addr + 0x0800);      /* unred_cpu_isr: */
> +    stl_p(base + 0x540, run_addr + 0x0800);      /* reg_ic_isr: */
> +    stl_p(base + 0x544, run_addr + 0x0800);      /* unred_ic_isr: */
> +    stl_p(base + 0x548, run_addr + 0x0800);      /* reg_esr: */
> +    stl_p(base + 0x54c, run_addr + 0x0800);      /* unreg_esr: */
> +    stl_p(base + 0x550, run_addr + 0x0800);      /* getchar: */
> +    stl_p(base + 0x554, run_addr + 0x0800);      /* syscon_read: */
>  
>  
>      /* Second part of the bootloader */
> @@ -701,7 +704,7 @@ static void write_bootloader (CPUMIPSState *env, uint8_t *base,
>      p = (uint32_t *) (base + 0x800);
>      stl_p(p++, 0x03e00008);                                     /* jr ra */
>      stl_p(p++, 0x24020000);                                     /* li v0,0 */
> -   /* 808 YAMON print */
> +    /* 808 YAMON print */
>      stl_p(p++, 0x03e06821);                                     /* move t5,ra */
>      stl_p(p++, 0x00805821);                                     /* move t3,a0 */
>      stl_p(p++, 0x00a05021);                                     /* move t2,a1 */
> @@ -774,6 +777,7 @@ static int64_t load_kernel (void)
>      uint32_t *prom_buf;
>      long prom_size;
>      int prom_index = 0;
> +    uint64_t (*xlate_to_kseg0) (void *opaque, uint64_t addr);
>  
>  #ifdef TARGET_WORDS_BIGENDIAN
>      big_endian = 1;
> @@ -788,6 +792,11 @@ static int64_t load_kernel (void)
>                  loaderparams.kernel_filename);
>          exit(1);
>      }
> +    if (kvm_enabled()) {
> +        xlate_to_kseg0 = cpu_mips_kvm_um_phys_to_kseg0;
> +    } else {
> +        xlate_to_kseg0 = cpu_mips_phys_to_kseg0;
> +    }
>  
>      /* load initrd */
>      initrd_size = 0;
> @@ -820,7 +829,7 @@ 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);
> @@ -829,6 +838,7 @@ static int64_t load_kernel (void)
>      prom_set(prom_buf, prom_index++, "memsize");
>      prom_set(prom_buf, prom_index++, "%i",
>               MIN(loaderparams.ram_size, 256 << 20));
> +
>      prom_set(prom_buf, prom_index++, "modetty0");
>      prom_set(prom_buf, prom_index++, "38400n8r");
>      prom_set(prom_buf, prom_index++, NULL);
> @@ -863,6 +873,11 @@ static void main_cpu_reset(void *opaque)
>      }
>  
>      malta_mips_config(cpu);
> +
> +    if (kvm_enabled()) {
> +        /* Start running from the bootloader we wrote to end of RAM */
> +        env->active_tc.PC = 0x40000000 + loaderparams.ram_size;
> +    }
>  }
>  
>  static void cpu_request_exit(void *opaque, int irq, int level)
> @@ -878,6 +893,7 @@ static
>  void mips_malta_init(MachineState *machine)
>  {
>      ram_addr_t ram_size = machine->ram_size;
> +    ram_addr_t ram_low_size;
>      const char *cpu_model = machine->cpu_model;
>      const char *kernel_filename = machine->kernel_filename;
>      const char *kernel_cmdline = machine->kernel_cmdline;
> @@ -892,7 +908,7 @@ void mips_malta_init(MachineState *machine)
>      target_long bios_size = FLASH_SIZE;
>      const size_t smbus_eeprom_size = 8 * 256;
>      uint8_t *smbus_eeprom_buf = g_malloc0(smbus_eeprom_size);
> -    int64_t kernel_entry;
> +    int64_t kernel_entry, bootloader_run_addr;
>      PCIBus *pci_bus;
>      ISABus *isa_bus;
>      MIPSCPU *cpu;
> @@ -1011,13 +1027,30 @@ void mips_malta_init(MachineState *machine)
>      bios = pflash_cfi01_get_memory(fl);
>      fl_idx++;
>      if (kernel_filename) {
> +        ram_low_size = MIN(ram_size, 256 << 20);
> +        /* For KVM T&E we reserve 1MB of RAM for running bootloader */
> +        if (kvm_enabled()) {
> +            ram_low_size -= 0x100000;
> +            bootloader_run_addr = 0x40000000 + ram_low_size;
> +        } else {
> +            bootloader_run_addr = 0xbfc00000;
> +        }
> +
>          /* Write a small bootloader to the flash location. */
> -        loaderparams.ram_size = MIN(ram_size, 256 << 20);
> +        loaderparams.ram_size = ram_low_size;
>          loaderparams.kernel_filename = kernel_filename;
>          loaderparams.kernel_cmdline = kernel_cmdline;
>          loaderparams.initrd_filename = initrd_filename;
>          kernel_entry = load_kernel();
> -        write_bootloader(env, memory_region_get_ram_ptr(bios), kernel_entry);
> +
> +        write_bootloader(env, memory_region_get_ram_ptr(bios),
> +                         bootloader_run_addr, kernel_entry);
> +        if (kvm_enabled()) {
> +            /* Write the bootloader code @ the end of RAM, 1MB reserved */
> +            write_bootloader(env, memory_region_get_ram_ptr(ram_low_preio) +
> +                                    ram_low_size,
> +                             bootloader_run_addr, kernel_entry);
> +        }
>      } else {
>          /* Load firmware from flash. */
>          if (!dinfo) {
> -- 
> 1.9.3
> 
> 
>
Sanjay Lal June 19, 2014, 7:34 p.m. UTC | #2
On Jun 19, 2014, at 9:27 AM, Aurelien Jarno <aurelien@aurel32.net> wrote:

> On Tue, Jun 17, 2014 at 11:10:35PM +0100, James Hogan wrote:
>> In KVM mode the bootrom is loaded and executed from the last 1MB of
>> DRAM.
> 
> What is the reason for that? I am not opposed to that, but if it is
> really needed, it means that loading a bootloader into the flash area
> (for example YAMON) won't work and that this should be forbidden to the
> user.
> 

In trap and emulate mode, both the kernel and userland run in user mode on the processor. Virtual addresses >= 0x80000000 are only accessible in kernel mode, and the default flash area (VA: 0xbfc00000/PA: 0x1fc00000) falls in this range.

We therefore decided to relocate the bootloader to the last 1MB of RAM.  This area is excluded from the RAM ranges supplied to the kernel, so it should not be accessible to the user.

Regards
Sanjay
Aurelien Jarno June 19, 2014, 9:47 p.m. UTC | #3
On Thu, Jun 19, 2014 at 12:34:24PM -0700, Sanjay Lal wrote:
> 
> On Jun 19, 2014, at 9:27 AM, Aurelien Jarno <aurelien@aurel32.net> wrote:
> 
> > On Tue, Jun 17, 2014 at 11:10:35PM +0100, James Hogan wrote:
> >> In KVM mode the bootrom is loaded and executed from the last 1MB of
> >> DRAM.
> > 
> > What is the reason for that? I am not opposed to that, but if it is
> > really needed, it means that loading a bootloader into the flash area
> > (for example YAMON) won't work and that this should be forbidden to the
> > user.
> > 
> 
> In trap and emulate mode, both the kernel and userland run in user mode on the processor. Virtual addresses >= 0x80000000 are only accessible in kernel mode, and the default flash area (VA: 0xbfc00000/PA: 0x1fc00000) falls in this range.
> 
> We therefore decided to relocate the bootloader to the last 1MB of RAM.  This area is excluded from the RAM ranges supplied to the kernel, so it should not be accessible to the user.
> 

Thanks for the explanation. It means we should disable the support for
booting from the flash (using -pflash) in KVM mode, as it would simply
not work.
Paolo Bonzini June 20, 2014, 6:07 a.m. UTC | #4
----- Messaggio originale -----
> Da: "Aurelien Jarno" <aurelien@aurel32.net>
> A: "Sanjay Lal" <sanjayl@kymasys.com>
> Cc: "James Hogan" <james.hogan@imgtec.com>, qemu-devel@nongnu.org, "Peter Maydell" <peter.maydell@linaro.org>,
> kvm@vger.kernel.org, "Gleb Natapov" <gleb@redhat.com>, "Paolo Bonzini" <pbonzini@redhat.com>
> Inviato: Giovedì, 19 giugno 2014 23:47:34
> Oggetto: Re: [Qemu-devel] [PATCH v5 10/12] hw/mips: malta: Add KVM support
> 
> On Thu, Jun 19, 2014 at 12:34:24PM -0700, Sanjay Lal wrote:
> > 
> > On Jun 19, 2014, at 9:27 AM, Aurelien Jarno <aurelien@aurel32.net> wrote:
> > 
> > > On Tue, Jun 17, 2014 at 11:10:35PM +0100, James Hogan wrote:
> > >> In KVM mode the bootrom is loaded and executed from the last 1MB of
> > >> DRAM.
> > > 
> > > What is the reason for that? I am not opposed to that, but if it is
> > > really needed, it means that loading a bootloader into the flash area
> > > (for example YAMON) won't work and that this should be forbidden to the
> > > user.
> > > 
> > 
> > In trap and emulate mode, both the kernel and userland run in user mode on
> > the processor. Virtual addresses >= 0x80000000 are only accessible in
> > kernel mode, and the default flash area (VA: 0xbfc00000/PA: 0x1fc00000)
> > falls in this range.
> > 
> > We therefore decided to relocate the bootloader to the last 1MB of RAM.
> > This area is excluded from the RAM ranges supplied to the kernel, so it
> > should not be accessible to the user.
> > 
> 
> Thanks for the explanation. It means we should disable the support for
> booting from the flash (using -pflash) in KVM mode, as it would simply
> not work.

My idea was to add a machines-specific option umkernel=on, and require it
in order to run KVM.  Later we can add umkernel=on support for TCG as well,
while umkernel=off with KVM requires virtualization extensions.

The same option can disable pflash boot.

What do you think?

Paolo
James Hogan June 20, 2014, 8:46 a.m. UTC | #5
Hi,

On 20/06/14 07:07, Paolo Bonzini wrote:
> ----- Messaggio originale -----
>> Da: "Aurelien Jarno" <aurelien@aurel32.net>
>> A: "Sanjay Lal" <sanjayl@kymasys.com>
>> Cc: "James Hogan" <james.hogan@imgtec.com>, qemu-devel@nongnu.org, "Peter Maydell" <peter.maydell@linaro.org>,
>> kvm@vger.kernel.org, "Gleb Natapov" <gleb@redhat.com>, "Paolo Bonzini" <pbonzini@redhat.com>
>> Inviato: Giovedì, 19 giugno 2014 23:47:34
>> Oggetto: Re: [Qemu-devel] [PATCH v5 10/12] hw/mips: malta: Add KVM support
>>
>> On Thu, Jun 19, 2014 at 12:34:24PM -0700, Sanjay Lal wrote:
>>>
>>> On Jun 19, 2014, at 9:27 AM, Aurelien Jarno <aurelien@aurel32.net> wrote:
>>>
>>>> On Tue, Jun 17, 2014 at 11:10:35PM +0100, James Hogan wrote:
>>>>> In KVM mode the bootrom is loaded and executed from the last 1MB of
>>>>> DRAM.
>>>>
>>>> What is the reason for that? I am not opposed to that, but if it is
>>>> really needed, it means that loading a bootloader into the flash area
>>>> (for example YAMON) won't work and that this should be forbidden to the
>>>> user.
>>>>
>>>
>>> In trap and emulate mode, both the kernel and userland run in user mode on
>>> the processor. Virtual addresses >= 0x80000000 are only accessible in
>>> kernel mode, and the default flash area (VA: 0xbfc00000/PA: 0x1fc00000)
>>> falls in this range.
>>>
>>> We therefore decided to relocate the bootloader to the last 1MB of RAM.
>>> This area is excluded from the RAM ranges supplied to the kernel, so it
>>> should not be accessible to the user.

I did recently try relocating the bootloader to the reset address in the
T&E KSeg0 (i.e. PA=0x1fc00000, VA=0x5fc00000), but the current MIPS KVM
implementation in the kernel has some limitations when it comes to
memory regions. It allocates a linear guest_pmap array (for GPA->RPA
page mapping) based only on the first memory region committed, so if you
set e.g. mem=64MB then physical memory according to guest_pmap won't
reach the reset address and it fails to map it. The kernel needs fixing
to use a more flexible physical page table structure first really.

>> Thanks for the explanation. It means we should disable the support for
>> booting from the flash (using -pflash) in KVM mode, as it would simply
>> not work.
> 
> My idea was to add a machines-specific option umkernel=on, and require it
> in order to run KVM.  Later we can add umkernel=on support for TCG as well,

FYI I tried this and it was a fairly small change (fixing CP0_EBase
initialisation and switching a couple of kvm_enabled() checks to
something like mips_um_ksegs_enabled()). Needs more testing though.

> while umkernel=off with KVM requires virtualization extensions.
> 
> The same option can disable pflash boot.
> 
> What do you think?

I think with an executable flash region / reset address the pflash
option could be made to work, but of course you'd probably need a
relocated flash image too, which may make the option less useful (and it
presumably isn't like a kernel ELF where you can detect what address
it's linked).

For now disabling Malta non kernel loads in KVM mode makes sense I think.

Thanks
James
Aurelien Jarno June 20, 2014, 9:10 a.m. UTC | #6
On Fri, Jun 20, 2014 at 02:07:05AM -0400, Paolo Bonzini wrote:
> 
> 
> ----- Messaggio originale -----
> > Da: "Aurelien Jarno" <aurelien@aurel32.net>
> > A: "Sanjay Lal" <sanjayl@kymasys.com>
> > Cc: "James Hogan" <james.hogan@imgtec.com>, qemu-devel@nongnu.org, "Peter Maydell" <peter.maydell@linaro.org>,
> > kvm@vger.kernel.org, "Gleb Natapov" <gleb@redhat.com>, "Paolo Bonzini" <pbonzini@redhat.com>
> > Inviato: Giovedì, 19 giugno 2014 23:47:34
> > Oggetto: Re: [Qemu-devel] [PATCH v5 10/12] hw/mips: malta: Add KVM support
> > 
> > On Thu, Jun 19, 2014 at 12:34:24PM -0700, Sanjay Lal wrote:
> > > 
> > > On Jun 19, 2014, at 9:27 AM, Aurelien Jarno <aurelien@aurel32.net> wrote:
> > > 
> > > > On Tue, Jun 17, 2014 at 11:10:35PM +0100, James Hogan wrote:
> > > >> In KVM mode the bootrom is loaded and executed from the last 1MB of
> > > >> DRAM.
> > > > 
> > > > What is the reason for that? I am not opposed to that, but if it is
> > > > really needed, it means that loading a bootloader into the flash area
> > > > (for example YAMON) won't work and that this should be forbidden to the
> > > > user.
> > > > 
> > > 
> > > In trap and emulate mode, both the kernel and userland run in user mode on
> > > the processor. Virtual addresses >= 0x80000000 are only accessible in
> > > kernel mode, and the default flash area (VA: 0xbfc00000/PA: 0x1fc00000)
> > > falls in this range.
> > > 
> > > We therefore decided to relocate the bootloader to the last 1MB of RAM.
> > > This area is excluded from the RAM ranges supplied to the kernel, so it
> > > should not be accessible to the user.
> > > 
> > 
> > Thanks for the explanation. It means we should disable the support for
> > booting from the flash (using -pflash) in KVM mode, as it would simply
> > not work.
> 
> My idea was to add a machines-specific option umkernel=on, and require it
> in order to run KVM.  Later we can add umkernel=on support for TCG as well,
> while umkernel=off with KVM requires virtualization extensions.
> 
> The same option can disable pflash boot.
> 
> What do you think?

For what I understand the current KVM support in MIPS uses trap and
emulate and thus doesn't need hardware support, just a recent kernel
with the option enabled. That's why I do wonder if there is a real point
in supporting UM kernels in TCG mode.
Paolo Bonzini June 20, 2014, 10:38 a.m. UTC | #7
Il 20/06/2014 11:10, Aurelien Jarno ha scritto:
> > My idea was to add a machines-specific option umkernel=on, and require it
> > in order to run KVM.  Later we can add umkernel=on support for TCG as well,
> > while umkernel=off with KVM requires virtualization extensions.
> >
> > The same option can disable pflash boot.
> >
> > What do you think?
>
> For what I understand the current KVM support in MIPS uses trap and
> emulate and thus doesn't need hardware support, just a recent kernel
> with the option enabled.

Yes, but work to support virtualization extensions is underway.  Patches 
were posted a few months ago.

> That's why I do wonder if there is a real point
> in supporting UM kernels in TCG mode.

Debugging, mainly.  It is sometimes useful to compare TCG with KVM on 
x86, and I suppose it could be the same on MIPS.

Paolo
Aurelien Jarno June 20, 2014, 11:19 a.m. UTC | #8
On Fri, Jun 20, 2014 at 12:38:30PM +0200, Paolo Bonzini wrote:
> Il 20/06/2014 11:10, Aurelien Jarno ha scritto:
> >> My idea was to add a machines-specific option umkernel=on, and require it
> >> in order to run KVM.  Later we can add umkernel=on support for TCG as well,
> >> while umkernel=off with KVM requires virtualization extensions.
> >>
> >> The same option can disable pflash boot.
> >>
> >> What do you think?
> >
> >For what I understand the current KVM support in MIPS uses trap and
> >emulate and thus doesn't need hardware support, just a recent kernel
> >with the option enabled.
> 
> Yes, but work to support virtualization extensions is underway.
> Patches were posted a few months ago.
> 
> >That's why I do wonder if there is a real point
> >in supporting UM kernels in TCG mode.
> 
> Debugging, mainly.  It is sometimes useful to compare TCG with KVM
> on x86, and I suppose it could be the same on MIPS.

Ok, then we can indeed add a umkernel option, which is always enabled
with KVM, and which disable the flash (and why not other devices) in
that case.

At some point it might be a good idea to add a specific machine for
emulation/virtualization, like it is done on ARM, which do not have to
handle this kind of devices, and which does not have all the current
limitations of the Malta board.
James Hogan June 20, 2014, 11:28 a.m. UTC | #9
On 20/06/14 12:19, Aurelien Jarno wrote:
> On Fri, Jun 20, 2014 at 12:38:30PM +0200, Paolo Bonzini wrote:
>> Il 20/06/2014 11:10, Aurelien Jarno ha scritto:
>>>> My idea was to add a machines-specific option umkernel=on, and require it
>>>> in order to run KVM.  Later we can add umkernel=on support for TCG as well,
>>>> while umkernel=off with KVM requires virtualization extensions.
>>>>
>>>> The same option can disable pflash boot.
>>>>
>>>> What do you think?
>>>
>>> For what I understand the current KVM support in MIPS uses trap and
>>> emulate and thus doesn't need hardware support, just a recent kernel
>>> with the option enabled.
>>
>> Yes, but work to support virtualization extensions is underway.
>> Patches were posted a few months ago.
>>
>>> That's why I do wonder if there is a real point
>>> in supporting UM kernels in TCG mode.
>>
>> Debugging, mainly.  It is sometimes useful to compare TCG with KVM
>> on x86, and I suppose it could be the same on MIPS.
> 
> Ok, then we can indeed add a umkernel option, which is always enabled
> with KVM, and which disable the flash (and why not other devices) in
> that case.
> 
> At some point it might be a good idea to add a specific machine for
> emulation/virtualization, like it is done on ARM, which do not have to
> handle this kind of devices, and which does not have all the current
> limitations of the Malta board.

FYI Cavium have been working on a para-virtualised machine which they
use with their VZ KVM implementation. They're using lkvm, but I expect
it will make sense to port that to QEMU too.

lkvm patchset (applied):
https://www.mail-archive.com/kvm%40vger.kernel.org/msg102792.html

linux kernel patchset (merged in v3.16-rc1):
https://www.mail-archive.com/kvm%40vger.kernel.org/msg102806.html

Cheers
James
diff mbox

Patch

diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c
index f4a7d4712952..8bc5392b4223 100644
--- a/hw/mips/mips_malta.c
+++ b/hw/mips/mips_malta.c
@@ -51,6 +51,7 @@ 
 #include "sysemu/qtest.h"
 #include "qemu/error-report.h"
 #include "hw/empty_slot.h"
+#include "sysemu/kvm.h"
 
 //#define DEBUG_BOARD_INIT
 
@@ -603,29 +604,31 @@  static void network_init(PCIBus *pci_bus)
 */
 
 static void write_bootloader (CPUMIPSState *env, uint8_t *base,
-                              int64_t kernel_entry)
+                              int64_t run_addr, int64_t kernel_entry)
 {
     uint32_t *p;
 
     /* Small bootloader */
     p = (uint32_t *)base;
-    stl_p(p++, 0x0bf00160);                                      /* j 0x1fc00580 */
+
+    stl_p(p++, 0x08000000 |                                      /* j 0x1fc00580 */
+                 ((run_addr + 0x580) & 0x0fffffff) >> 2);
     stl_p(p++, 0x00000000);                                      /* nop */
 
     /* YAMON service vector */
-    stl_p(base + 0x500, 0xbfc00580);      /* start: */
-    stl_p(base + 0x504, 0xbfc0083c);      /* print_count: */
-    stl_p(base + 0x520, 0xbfc00580);      /* start: */
-    stl_p(base + 0x52c, 0xbfc00800);      /* flush_cache: */
-    stl_p(base + 0x534, 0xbfc00808);      /* print: */
-    stl_p(base + 0x538, 0xbfc00800);      /* reg_cpu_isr: */
-    stl_p(base + 0x53c, 0xbfc00800);      /* unred_cpu_isr: */
-    stl_p(base + 0x540, 0xbfc00800);      /* reg_ic_isr: */
-    stl_p(base + 0x544, 0xbfc00800);      /* unred_ic_isr: */
-    stl_p(base + 0x548, 0xbfc00800);      /* reg_esr: */
-    stl_p(base + 0x54c, 0xbfc00800);      /* unreg_esr: */
-    stl_p(base + 0x550, 0xbfc00800);      /* getchar: */
-    stl_p(base + 0x554, 0xbfc00800);      /* syscon_read: */
+    stl_p(base + 0x500, run_addr + 0x0580);      /* start: */
+    stl_p(base + 0x504, run_addr + 0x083c);      /* print_count: */
+    stl_p(base + 0x520, run_addr + 0x0580);      /* start: */
+    stl_p(base + 0x52c, run_addr + 0x0800);      /* flush_cache: */
+    stl_p(base + 0x534, run_addr + 0x0808);      /* print: */
+    stl_p(base + 0x538, run_addr + 0x0800);      /* reg_cpu_isr: */
+    stl_p(base + 0x53c, run_addr + 0x0800);      /* unred_cpu_isr: */
+    stl_p(base + 0x540, run_addr + 0x0800);      /* reg_ic_isr: */
+    stl_p(base + 0x544, run_addr + 0x0800);      /* unred_ic_isr: */
+    stl_p(base + 0x548, run_addr + 0x0800);      /* reg_esr: */
+    stl_p(base + 0x54c, run_addr + 0x0800);      /* unreg_esr: */
+    stl_p(base + 0x550, run_addr + 0x0800);      /* getchar: */
+    stl_p(base + 0x554, run_addr + 0x0800);      /* syscon_read: */
 
 
     /* Second part of the bootloader */
@@ -701,7 +704,7 @@  static void write_bootloader (CPUMIPSState *env, uint8_t *base,
     p = (uint32_t *) (base + 0x800);
     stl_p(p++, 0x03e00008);                                     /* jr ra */
     stl_p(p++, 0x24020000);                                     /* li v0,0 */
-   /* 808 YAMON print */
+    /* 808 YAMON print */
     stl_p(p++, 0x03e06821);                                     /* move t5,ra */
     stl_p(p++, 0x00805821);                                     /* move t3,a0 */
     stl_p(p++, 0x00a05021);                                     /* move t2,a1 */
@@ -774,6 +777,7 @@  static int64_t load_kernel (void)
     uint32_t *prom_buf;
     long prom_size;
     int prom_index = 0;
+    uint64_t (*xlate_to_kseg0) (void *opaque, uint64_t addr);
 
 #ifdef TARGET_WORDS_BIGENDIAN
     big_endian = 1;
@@ -788,6 +792,11 @@  static int64_t load_kernel (void)
                 loaderparams.kernel_filename);
         exit(1);
     }
+    if (kvm_enabled()) {
+        xlate_to_kseg0 = cpu_mips_kvm_um_phys_to_kseg0;
+    } else {
+        xlate_to_kseg0 = cpu_mips_phys_to_kseg0;
+    }
 
     /* load initrd */
     initrd_size = 0;
@@ -820,7 +829,7 @@  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);
@@ -829,6 +838,7 @@  static int64_t load_kernel (void)
     prom_set(prom_buf, prom_index++, "memsize");
     prom_set(prom_buf, prom_index++, "%i",
              MIN(loaderparams.ram_size, 256 << 20));
+
     prom_set(prom_buf, prom_index++, "modetty0");
     prom_set(prom_buf, prom_index++, "38400n8r");
     prom_set(prom_buf, prom_index++, NULL);
@@ -863,6 +873,11 @@  static void main_cpu_reset(void *opaque)
     }
 
     malta_mips_config(cpu);
+
+    if (kvm_enabled()) {
+        /* Start running from the bootloader we wrote to end of RAM */
+        env->active_tc.PC = 0x40000000 + loaderparams.ram_size;
+    }
 }
 
 static void cpu_request_exit(void *opaque, int irq, int level)
@@ -878,6 +893,7 @@  static
 void mips_malta_init(MachineState *machine)
 {
     ram_addr_t ram_size = machine->ram_size;
+    ram_addr_t ram_low_size;
     const char *cpu_model = machine->cpu_model;
     const char *kernel_filename = machine->kernel_filename;
     const char *kernel_cmdline = machine->kernel_cmdline;
@@ -892,7 +908,7 @@  void mips_malta_init(MachineState *machine)
     target_long bios_size = FLASH_SIZE;
     const size_t smbus_eeprom_size = 8 * 256;
     uint8_t *smbus_eeprom_buf = g_malloc0(smbus_eeprom_size);
-    int64_t kernel_entry;
+    int64_t kernel_entry, bootloader_run_addr;
     PCIBus *pci_bus;
     ISABus *isa_bus;
     MIPSCPU *cpu;
@@ -1011,13 +1027,30 @@  void mips_malta_init(MachineState *machine)
     bios = pflash_cfi01_get_memory(fl);
     fl_idx++;
     if (kernel_filename) {
+        ram_low_size = MIN(ram_size, 256 << 20);
+        /* For KVM T&E we reserve 1MB of RAM for running bootloader */
+        if (kvm_enabled()) {
+            ram_low_size -= 0x100000;
+            bootloader_run_addr = 0x40000000 + ram_low_size;
+        } else {
+            bootloader_run_addr = 0xbfc00000;
+        }
+
         /* Write a small bootloader to the flash location. */
-        loaderparams.ram_size = MIN(ram_size, 256 << 20);
+        loaderparams.ram_size = ram_low_size;
         loaderparams.kernel_filename = kernel_filename;
         loaderparams.kernel_cmdline = kernel_cmdline;
         loaderparams.initrd_filename = initrd_filename;
         kernel_entry = load_kernel();
-        write_bootloader(env, memory_region_get_ram_ptr(bios), kernel_entry);
+
+        write_bootloader(env, memory_region_get_ram_ptr(bios),
+                         bootloader_run_addr, kernel_entry);
+        if (kvm_enabled()) {
+            /* Write the bootloader code @ the end of RAM, 1MB reserved */
+            write_bootloader(env, memory_region_get_ram_ptr(ram_low_preio) +
+                                    ram_low_size,
+                             bootloader_run_addr, kernel_entry);
+        }
     } else {
         /* Load firmware from flash. */
         if (!dinfo) {