All of lore.kernel.org
 help / color / mirror / Atom feed
From: Eduardo Habkost <ehabkost@redhat.com>
To: Thomas Huth <thuth@redhat.com>
Cc: qemu-devel@nongnu.org, Markus Armbruster <armbru@redhat.com>,
	Peter Maydell <peter.maydell@linaro.org>,
	Paolo Bonzini <pbonzini@redhat.com>,
	Daniel Berrange <berrange@redhat.com>,
	Laurent Vivier <laurent@vivier.eu>,
	Max Filippov <jcmvbkbc@gmail.com>
Subject: Re: [Qemu-devel] [PATCH] hw/core/null-machine: Add the possibility to instantiate a CPU, RAM and kernel
Date: Mon, 16 Jan 2017 18:07:13 -0200	[thread overview]
Message-ID: <20170116200713.GE3491@thinpad.lan.raisama.net> (raw)
In-Reply-To: <fc0f7df0-f1b3-1e03-6d64-8c234d8b33d9@redhat.com>

On Mon, Jan 16, 2017 at 08:52:28PM +0100, Thomas Huth wrote:
> On 16.01.2017 18:25, Eduardo Habkost wrote:
> > On Sat, Jan 14, 2017 at 07:51:02AM +0100, Thomas Huth wrote:
> >> Sometimes it is useful to have just a machine with CPU and RAM, without
> >> any further hardware in it, e.g. if you just want to do some instruction
> >> debugging for TCG with a remote GDB attached to QEMU, or run some embedded
> >> code with the "-semihosting" QEMU parameter. qemu-system-m68k already
> >> features a "dummy" machine, and xtensa a "sim" machine for exactly this
> >> purpose.
> >> All target architectures have nowadays also a "none" machine, which would
> >> be a perfect match for this, too - but it currently does not allow to add
> >> CPU, RAM or a kernel yet. Thus let's add these possibilities in a generic
> >> way to the "none" machine, too, so that we hopefully do not need additional
> >> "dummy" machines in the future anymore (and maybe can also get rid of the
> >> already existing "dummy"/"sim" machines one day).
> >> Note that the default behaviour of the "none" machine is not changed, i.e.
> >> no CPU and no RAM is instantiated by default. You've explicitely got to
> >> specify the CPU model with "-cpu" and the amount of RAM with "-m" to get
> >> these new features.
> >>
> >> Signed-off-by: Thomas Huth <thuth@redhat.com>
> > 
> > This sounds nice, but I would like initialization code used by
> > "-machine none" to be generic code usable by other machines,
> > whenever possible.
> > 
> > The CPU and RAM creation probably is simple enough to not deserve
> > a generic wrapper by now. But the kernel loader probably could be
> > made reusable in the first version, so existing machines that
> > already have similar logic could reuse it.
> > 
> > I would love to make all machines automatically use new generic
> > code to create CPUs, allocate RAM, and load a kernel. But
> > probably this would be hard to do in a single step due to subtle
> > initialization ordering requirements in each machine init
> > function.
> > 
> > More specific comments below:
> > 
> >> ---
> >>  hw/core/Makefile.objs  |  2 +-
> >>  hw/core/null-machine.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++-
> >>  2 files changed, 81 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs
> >> index a4c94e5..0b6c0f1 100644
> >> --- a/hw/core/Makefile.objs
> >> +++ b/hw/core/Makefile.objs
> >> @@ -12,7 +12,6 @@ common-obj-$(CONFIG_XILINX_AXI) += stream.o
> >>  common-obj-$(CONFIG_PTIMER) += ptimer.o
> >>  common-obj-$(CONFIG_SOFTMMU) += sysbus.o
> >>  common-obj-$(CONFIG_SOFTMMU) += machine.o
> >> -common-obj-$(CONFIG_SOFTMMU) += null-machine.o
> >>  common-obj-$(CONFIG_SOFTMMU) += loader.o
> >>  common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o
> >>  common-obj-$(CONFIG_SOFTMMU) += register.o
> >> @@ -20,3 +19,4 @@ common-obj-$(CONFIG_SOFTMMU) += or-irq.o
> >>  common-obj-$(CONFIG_PLATFORM_BUS) += platform-bus.o
> >>  
> >>  obj-$(CONFIG_SOFTMMU) += generic-loader.o
> >> +obj-$(CONFIG_SOFTMMU) += null-machine.o
> > 
> > I'd like to keep null-machine.o in common-obj-y, if possible. We
> > already have an arch_type variable provided by arch_init.c, maybe
> > it could also provide arch_endianness?
> 
> Yes, that sounds like an idea. Or maybe it's feasible to tweak
> load_elf(), so it can also be called with the endianess parameter set to
> "-1", meaning the caller does not care whether the endianess is big or
> little?
> 
> >> diff --git a/hw/core/null-machine.c b/hw/core/null-machine.c
> >> index 0351ba7..b2468ed 100644
> >> --- a/hw/core/null-machine.c
> >> +++ b/hw/core/null-machine.c
> >> @@ -13,18 +13,97 @@
> >>  
> >>  #include "qemu/osdep.h"
> >>  #include "qemu-common.h"
> >> +#include "qemu/error-report.h"
> >>  #include "hw/hw.h"
> >>  #include "hw/boards.h"
> >> +#include "hw/loader.h"
> >> +#include "sysemu/sysemu.h"
> >> +#include "exec/address-spaces.h"
> >> +#include "cpu.h"
> >> +#include "elf.h"
> >> +
> >> +#ifdef TARGET_WORDS_BIGENDIAN
> >> +#define LOAD_ELF_ENDIAN_FLAG 1
> >> +#else
> >> +#define LOAD_ELF_ENDIAN_FLAG 0
> >> +#endif
> >> +
> >> +static hwaddr cpu_initial_pc;
> > 
> > Other architectures and machines probably have something similar
> > to cpu_initial_pc, so this could be probably be moved to an
> > existing generic struct. But I am not sure if this would be a
> > MachineState field or CPUState field.
> 
> I'm also not sure whether this makes sense right from the start ... the
> intial PC handling seems to be slightly different for each board, so
> trying to generalize this variable sounds quite complicated ... so
> that's maybe rather something for a later clean-up patch instead.

Yeah. I would love to avoid adding another static variable to
QEMU, but maybe this is good enough to avoid making the changes
too intrusive.

Anyway, I believe it will be possible to replace
machine_none_load_kernel() with a simple instantiation of
TYPE_GENERIC_LOADER, which already takes care of CPU reset.

> 
> >> +static uint64_t translate_phys_addr(void *opaque, uint64_t addr)
> >> +{
> >> +    return cpu_get_phys_page_debug(CPU(opaque), addr);
> >> +}
> >> +
> >> +static void machine_none_load_kernel(CPUState *cpu, const char *kernel_fname,
> >> +                                     ram_addr_t ram_size)
> >> +{
> >> +    uint64_t elf_entry;
> >> +    int kernel_size;
> >> +
> >> +    if (!ram_size) {
> >> +        error_report("You need RAM for loading a kernel");
> >> +        return;
> >> +    }
> >> +
> >> +    kernel_size = load_elf(kernel_fname, translate_phys_addr, cpu, &elf_entry,
> >> +                           NULL, NULL, LOAD_ELF_ENDIAN_FLAG, EM_NONqE, 0, 0);
> >> +    cpu_initial_pc = elf_entry;
> >> +    if (kernel_size < 0) {
> >> +        kernel_size = load_uimage(kernel_fname, &cpu_initial_pc, NULL, NULL,
> >> +                                  NULL, NULL);
> >> +    }
> >> +    if (kernel_size < 0) {
> >> +        kernel_size = load_image_targphys(kernel_fname, 0, ram_size);
> >> +    }
> >> +    if (kernel_size < 0) {
> >> +        error_report("Could not load kernel '%s'", kernel_fname);
> >> +        return;
> >> +    }
> >> +}
> > 
> > Do you know how many different architectures will be able to use
> > this generic ELF loading logic as-is?
> 
> I've only tried m68k and xtensa so far, and it worked there. OpenRISC
> "or32-sim" machine looks very similar, too. Most other board look
> slightly different, either lacking the "load_uimage" or
> "load_image_targphys" (but the generic code might still work there), or
> having some other magic code inbetween...

I assume we will want to make "-machine none -kernel ..." work on
those other architectures too, eventually.

In this case, we need to keep in mind that this implementation is
just a generic default implementation, but that may be overridden
by arch-specific implementations in the future. (Probably through
a CPUClass::load_kernel hook?)

> 
> > Probably other machines already have very similar logic, so it
> > would be nice if we could make this reusable so other machines
> > don't need to duplicate it.
> 
> I can have a try...
> 
> >> +static void machine_none_cpu_reset(void *opaque)
> >> +{
> >> +    CPUState *cpu = CPU(opaque);
> >> +
> >> +    cpu_reset(cpu);
> >> +    cpu_set_pc(cpu, cpu_initial_pc);
> >> +}
> >>  
> >>  static void machine_none_init(MachineState *machine)
> >>  {
> >> +    ram_addr_t ram_size = machine->ram_size;
> >> +    MemoryRegion *ram;
> >> +    CPUState *cpu = NULL;
> >> +
> >> +    /* Initialize CPU (if a model has been specified) */
> >> +    if (machine->cpu_model) {
> >> +        cpu = cpu_init(machine->cpu_model);
> >> +        if (!cpu) {
> >> +            error_report("Unable to initialize CPU");
> >> +            exit(1);
> >> +        }
> >> +        qemu_register_reset(machine_none_cpu_reset, cpu);
> >> +        cpu_reset(cpu);
> >> +    }
> > 
> > This looks like a sign that we need a generic wrapper to create
> > CPUs. Probably lots of other machines do something very similar.
> > But I think this is something for later.
> 
> I don't think that this sequence can be generalized in a wrapper
> function so easily: Most other machines apparently do some additional
> magic between cpu_init() and qemu_register_reset() ... so if we really
> want to generalize this, this is certainly a task for a separate clean
> up patch later.

Agreed.

> 
> >>  static void machine_none_machine_init(MachineClass *mc)
> >>  {
> >>      mc->desc = "empty machine";
> >>      mc->init = machine_none_init;
> >> -    mc->max_cpus = 0;
> > 
> > Does this line removal has any visible effect? vl.c already
> > interprets max_cpus==0 as the same as max_cpus==1.
> > 
> > Maybe we should set max_cpus=1 explicitly to make it clear that
> > this new code doesn't work if smp_cpus > 1.
> 
> You're right, max_cpus = 1 would make more sense here ... I'll change my
> patch accordingly.
> 
>  Thomas
> 

-- 
Eduardo

      reply	other threads:[~2017-01-16 20:07 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-01-14  6:51 [Qemu-devel] [PATCH] hw/core/null-machine: Add the possibility to instantiate a CPU, RAM and kernel Thomas Huth
2017-01-14 11:03 ` Laurent Vivier
2017-01-16  7:59   ` Thomas Huth
2017-01-16 18:53     ` Alistair Francis
2017-01-16 19:25       ` Eduardo Habkost
2017-01-16 19:27         ` Peter Maydell
2017-01-16 19:44           ` Eduardo Habkost
2017-01-17  9:29             ` Peter Maydell
2017-01-17 12:36               ` Eduardo Habkost
2017-01-17 13:02                 ` Thomas Huth
2017-01-16 17:25 ` Eduardo Habkost
2017-01-16 19:52   ` Thomas Huth
2017-01-16 20:07     ` Eduardo Habkost [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170116200713.GE3491@thinpad.lan.raisama.net \
    --to=ehabkost@redhat.com \
    --cc=armbru@redhat.com \
    --cc=berrange@redhat.com \
    --cc=jcmvbkbc@gmail.com \
    --cc=laurent@vivier.eu \
    --cc=pbonzini@redhat.com \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-devel@nongnu.org \
    --cc=thuth@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.