diff mbox

[V2,4/4] hw/machine: qemu machine opts as properties to QemuMachineState

Message ID 1401108058-27348-5-git-send-email-marcel.a@redhat.com
State New
Headers show

Commit Message

Marcel Apfelbaum May 26, 2014, 12:40 p.m. UTC
Make machine's QemuOpts QOM properties of machine. The properties
are automatically filled in. This opens the possiblity to create
opts per machine rather than global.

Signed-off-by: Marcel Apfelbaum <marcel.a@redhat.com>
---
 hw/core/machine.c   | 256 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/hw/boards.h |   6 +-
 vl.c                |  10 +-
 3 files changed, 266 insertions(+), 6 deletions(-)

Comments

Eduardo Habkost May 30, 2014, 7:25 p.m. UTC | #1
On Mon, May 26, 2014 at 03:40:58PM +0300, Marcel Apfelbaum wrote:
[...]
> +static void machine_initfn(Object *obj)
> +{
> +    object_property_add_str(obj, "accel",
> +                            machine_get_accel, machine_set_accel, NULL);
> +    object_property_add_bool(obj, "kernel_irqchip",
> +                             machine_get_kernel_irqchip,
> +                             machine_set_kernel_irqchip,
> +                             NULL);

In the case of kernel_irqchip, the information contained in MachineState
is not a superset of the information contained on
qemu_get_machine_opts().

See hw/ppc/{e500,spapr}.c. They use kernel_irqchip like this:

    bool irqchip_allowed = qemu_opt_get_bool(machine_opts,
                                            "kernel_irqchip", true);
    bool irqchip_required = qemu_opt_get_bool(machine_opts,
                                              "kernel_irqchip", false);

    if (irqchip_allowed) {
        dev = ppce500_init_mpic_kvm(params, irqs);
    }

    if (irqchip_required && !dev) {
        fprintf(stderr, "%s: irqchip requested but unavailable\n",
                __func__);
        abort();
    }

This means kernel_irqchip have three possible states: "disabled", "required",
and "allowed".

This means that MachineState.kernel_irqchip is not usable by current
code that uses the kernel_irqchip option. I suppose we plan to address
this on MachineState, too, to not get stuck with a global
qemu_get_machine_opts() forever?
Eduardo Habkost May 30, 2014, 7:45 p.m. UTC | #2
On Mon, May 26, 2014 at 03:40:58PM +0300, Marcel Apfelbaum wrote:
> Make machine's QemuOpts QOM properties of machine. The properties
> are automatically filled in. This opens the possiblity to create
> opts per machine rather than global.
> 
> Signed-off-by: Marcel Apfelbaum <marcel.a@redhat.com>
> ---
>  hw/core/machine.c   | 256 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  include/hw/boards.h |   6 +-
>  vl.c                |  10 +-
>  3 files changed, 266 insertions(+), 6 deletions(-)
> 
> diff --git a/hw/core/machine.c b/hw/core/machine.c
> index d3ffef7..dbcf2a1 100644
> --- a/hw/core/machine.c
> +++ b/hw/core/machine.c
> @@ -11,6 +11,260 @@
>   */
>  
>  #include "hw/boards.h"
> +#include "qapi/visitor.h"
> +
> +static char *machine_get_accel(Object *obj, Error **errp)
> +{
> +    MachineState *ms = MACHINE(obj);
> +    return g_strdup(ms->accel);
> +}
> +
> +static void machine_set_accel(Object *obj, const char *value, Error **errp)
> +{
> +    MachineState *ms = MACHINE(obj);
> +    ms->accel = g_strdup(value);
> +}

You are not freeing the old value here and on the other string setters.

(Do we have some existing common wrapper to automatically free the old
value and set the new one, or every setter should duplicate the same
free/strdup logic?)
Marcel Apfelbaum June 1, 2014, 8:07 a.m. UTC | #3
On Fri, 2014-05-30 at 16:45 -0300, Eduardo Habkost wrote:
> On Mon, May 26, 2014 at 03:40:58PM +0300, Marcel Apfelbaum wrote:
> > Make machine's QemuOpts QOM properties of machine. The properties
> > are automatically filled in. This opens the possiblity to create
> > opts per machine rather than global.
> > 
> > Signed-off-by: Marcel Apfelbaum <marcel.a@redhat.com>
> > ---
> >  hw/core/machine.c   | 256 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> >  include/hw/boards.h |   6 +-
> >  vl.c                |  10 +-
> >  3 files changed, 266 insertions(+), 6 deletions(-)
> > 
> > diff --git a/hw/core/machine.c b/hw/core/machine.c
> > index d3ffef7..dbcf2a1 100644
> > --- a/hw/core/machine.c
> > +++ b/hw/core/machine.c
> > @@ -11,6 +11,260 @@
> >   */
> >  
> >  #include "hw/boards.h"
> > +#include "qapi/visitor.h"
> > +
> > +static char *machine_get_accel(Object *obj, Error **errp)
> > +{
> > +    MachineState *ms = MACHINE(obj);
> > +    return g_strdup(ms->accel);
> > +}
> > +
> > +static void machine_set_accel(Object *obj, const char *value, Error **errp)
> > +{
> > +    MachineState *ms = MACHINE(obj);
> > +    ms->accel = g_strdup(value);
> > +}
> 
> You are not freeing the old value here and on the other string setters.
It seems to be the caller responsibility.
> 
> (Do we have some existing common wrapper to automatically free the old
> value and set the new one, or every setter should duplicate the same
> free/strdup logic?)
We don't have yet, from what I know, and this is for the moment the QMP way
to handle string attributes.

Thanks,
Marcel 
>
Marcel Apfelbaum June 1, 2014, 8:21 a.m. UTC | #4
On Fri, 2014-05-30 at 16:25 -0300, Eduardo Habkost wrote:
> On Mon, May 26, 2014 at 03:40:58PM +0300, Marcel Apfelbaum wrote:
> [...]
> > +static void machine_initfn(Object *obj)
> > +{
> > +    object_property_add_str(obj, "accel",
> > +                            machine_get_accel, machine_set_accel, NULL);
> > +    object_property_add_bool(obj, "kernel_irqchip",
> > +                             machine_get_kernel_irqchip,
> > +                             machine_set_kernel_irqchip,
> > +                             NULL);
> 
> In the case of kernel_irqchip, the information contained in MachineState
> is not a superset of the information contained on
> qemu_get_machine_opts().
> 
> See hw/ppc/{e500,spapr}.c. They use kernel_irqchip like this:
> 
>     bool irqchip_allowed = qemu_opt_get_bool(machine_opts,
>                                             "kernel_irqchip", true);
>     bool irqchip_required = qemu_opt_get_bool(machine_opts,
>                                               "kernel_irqchip", false);
> 
>     if (irqchip_allowed) {
>         dev = ppce500_init_mpic_kvm(params, irqs);
>     }
> 
>     if (irqchip_required && !dev) {
>         fprintf(stderr, "%s: irqchip requested but unavailable\n",
>                 __func__);
>         abort();
>     }
> 
> This means kernel_irqchip have three possible states: "disabled", "required",
> and "allowed".
I already had a patch adding "property_is_set" to QMP, but was not accepted
as there is no way yet to "unset" a property. (I can point you to the series)

> 
> This means that MachineState.kernel_irqchip is not usable by current
> code that uses the kernel_irqchip option. I suppose we plan to address
> this on MachineState, too, to not get stuck with a global
> qemu_get_machine_opts() forever?
I completely agree with you and I already had a patch tackling it,
based on "property_is_set", but was no accepted yet, obviously.
I was instructed to set the default value in the machine init function
and some way (I don't remember now) to emulate  required/allowed.

I do plan to get back to this.

Thanks,
Marcel
>
Eduardo Habkost June 2, 2014, 3:21 p.m. UTC | #5
On Sun, Jun 01, 2014 at 11:21:49AM +0300, Marcel Apfelbaum wrote:
> On Fri, 2014-05-30 at 16:25 -0300, Eduardo Habkost wrote:
> > On Mon, May 26, 2014 at 03:40:58PM +0300, Marcel Apfelbaum wrote:
> > [...]
> > > +static void machine_initfn(Object *obj)
> > > +{
> > > +    object_property_add_str(obj, "accel",
> > > +                            machine_get_accel, machine_set_accel, NULL);
> > > +    object_property_add_bool(obj, "kernel_irqchip",
> > > +                             machine_get_kernel_irqchip,
> > > +                             machine_set_kernel_irqchip,
> > > +                             NULL);
> > 
> > In the case of kernel_irqchip, the information contained in MachineState
> > is not a superset of the information contained on
> > qemu_get_machine_opts().
> > 
> > See hw/ppc/{e500,spapr}.c. They use kernel_irqchip like this:
> > 
> >     bool irqchip_allowed = qemu_opt_get_bool(machine_opts,
> >                                             "kernel_irqchip", true);
> >     bool irqchip_required = qemu_opt_get_bool(machine_opts,
> >                                               "kernel_irqchip", false);
> > 
> >     if (irqchip_allowed) {
> >         dev = ppce500_init_mpic_kvm(params, irqs);
> >     }
> > 
> >     if (irqchip_required && !dev) {
> >         fprintf(stderr, "%s: irqchip requested but unavailable\n",
> >                 __func__);
> >         abort();
> >     }
> > 
> > This means kernel_irqchip have three possible states: "disabled", "required",
> > and "allowed".
> I already had a patch adding "property_is_set" to QMP, but was not accepted
> as there is no way yet to "unset" a property. (I can point you to the series)
> 
> > 
> > This means that MachineState.kernel_irqchip is not usable by current
> > code that uses the kernel_irqchip option. I suppose we plan to address
> > this on MachineState, too, to not get stuck with a global
> > qemu_get_machine_opts() forever?
> I completely agree with you and I already had a patch tackling it,
> based on "property_is_set", but was no accepted yet, obviously.
> I was instructed to set the default value in the machine init function
> and some way (I don't remember now) to emulate  required/allowed.

I don't see a need to change to the object model and API. Just add
MachineState-specific properties/fields that are capable of representing
the state we need.

I see two simple solutions:

* Two boolean properties: require-kernel-irqchip and
disable-kernel-irqchip. The default being both set to false (meaning
irqchip is enabled automatically if available). We may still have a
third kernel_irqchip property for compatibility, that will change both
require-kernel-irqchip and disable-kernel-irqchip at the same time when
set.

* A string kernel_irqchip property which accepts three values: "on",
"off", and "auto".

Example of partial implementation of the first approach, below. I still
didn't add the two extra properties, and just let the code access the
require_kernel_irqchip and disable_kernel_irqchip fields directly.

Note that this is on top of some other changes I have been experimenting
with, changing the accelerator init functions to get MachineState as
argument. Git tree containing all work in progress can be seen at:
https://github.com/ehabkost/qemu-hacks/commits/work/machine-irqchip-tristate

    diff --git a/hw/core/machine.c b/hw/core/machine.c
    index cbba679..0797bc1 100644
    --- a/hw/core/machine.c
    +++ b/hw/core/machine.c
    @@ -31,14 +31,15 @@ static bool machine_get_kernel_irqchip(Object *obj, Error **errp)
     {
         MachineState *ms = MACHINE(obj);
     
    -    return ms->kernel_irqchip;
    +    return !ms->disable_kernel_irqchip;
     }
     
     static void machine_set_kernel_irqchip(Object *obj, bool value, Error **errp)
     {
         MachineState *ms = MACHINE(obj);
     
    -    ms->kernel_irqchip = value;
    +    ms->require_kernel_irqchip = value;
    +    ms->disable_kernel_irqchip = !value;
     }
     
     static void machine_get_kvm_shadow_mem(Object *obj, Visitor *v,
    diff --git a/include/hw/boards.h b/include/hw/boards.h
    index 0389933..4a2daee 100644
    --- a/include/hw/boards.h
    +++ b/include/hw/boards.h
    @@ -99,7 +99,8 @@ struct MachineState {
         /*< public >*/
     
         char *accel;
    -    bool kernel_irqchip;
    +    bool require_kernel_irqchip;
    +    bool disable_kernel_irqchip;
         int kvm_shadow_mem;
         char *dtb;
         char *dumpdtb;
    diff --git a/kvm-all.c b/kvm-all.c
    index d2f4d7f..120bf70 100644
    --- a/kvm-all.c
    +++ b/kvm-all.c
    @@ -1315,11 +1315,11 @@ int kvm_irqchip_remove_irqfd_notifier(KVMState *s, EventNotifier *n, int virq)
                false);
     }
     
    -static int kvm_irqchip_create(KVMState *s)
    +static int kvm_irqchip_create(MachineState *ms, KVMState *s)
     {
         int ret;
     
    -    if (!qemu_opt_get_bool(qemu_get_machine_opts(), "kernel_irqchip", true) ||
    +    if (ms->disable_kernel_irqchip ||
             (!kvm_check_extension(s, KVM_CAP_IRQCHIP) &&
              (kvm_vm_enable_cap(s, KVM_CAP_S390_IRQCHIP, 0) < 0))) {
             return 0;
    @@ -1545,7 +1545,7 @@ void kvm_init(MachineState *ms, Error **errp)
             goto err;
         }
     
    -    ret = kvm_irqchip_create(s);
    +    ret = kvm_irqchip_create(ms, s);
         if (ret < 0) {
             error_setg_errno(&err, -ret, "kvm_irqchip_create failed");
             goto err;
Marcel Apfelbaum June 5, 2014, 11:49 a.m. UTC | #6
On Mon, 2014-06-02 at 12:21 -0300, Eduardo Habkost wrote:
> On Sun, Jun 01, 2014 at 11:21:49AM +0300, Marcel Apfelbaum wrote:
> > On Fri, 2014-05-30 at 16:25 -0300, Eduardo Habkost wrote:
> > > On Mon, May 26, 2014 at 03:40:58PM +0300, Marcel Apfelbaum wrote:
> > > [...]
> > > > +static void machine_initfn(Object *obj)
> > > > +{
> > > > +    object_property_add_str(obj, "accel",
> > > > +                            machine_get_accel, machine_set_accel, NULL);
> > > > +    object_property_add_bool(obj, "kernel_irqchip",
> > > > +                             machine_get_kernel_irqchip,
> > > > +                             machine_set_kernel_irqchip,
> > > > +                             NULL);
> > > 
> > > In the case of kernel_irqchip, the information contained in MachineState
> > > is not a superset of the information contained on
> > > qemu_get_machine_opts().
> > > 
> > > See hw/ppc/{e500,spapr}.c. They use kernel_irqchip like this:
> > > 
> > >     bool irqchip_allowed = qemu_opt_get_bool(machine_opts,
> > >                                             "kernel_irqchip", true);
> > >     bool irqchip_required = qemu_opt_get_bool(machine_opts,
> > >                                               "kernel_irqchip", false);
> > > 
> > >     if (irqchip_allowed) {
> > >         dev = ppce500_init_mpic_kvm(params, irqs);
> > >     }
> > > 
> > >     if (irqchip_required && !dev) {
> > >         fprintf(stderr, "%s: irqchip requested but unavailable\n",
> > >                 __func__);
> > >         abort();
> > >     }
> > > 
> > > This means kernel_irqchip have three possible states: "disabled", "required",
> > > and "allowed".
> > I already had a patch adding "property_is_set" to QMP, but was not accepted
> > as there is no way yet to "unset" a property. (I can point you to the series)
> > 
> > > 
> > > This means that MachineState.kernel_irqchip is not usable by current
> > > code that uses the kernel_irqchip option. I suppose we plan to address
> > > this on MachineState, too, to not get stuck with a global
> > > qemu_get_machine_opts() forever?
> > I completely agree with you and I already had a patch tackling it,
> > based on "property_is_set", but was no accepted yet, obviously.
> > I was instructed to set the default value in the machine init function
> > and some way (I don't remember now) to emulate  required/allowed.
> 
> I don't see a need to change to the object model and API. Just add
> MachineState-specific properties/fields that are capable of representing
> the state we need.
> 
> I see two simple solutions:
> 
> * Two boolean properties: require-kernel-irqchip and
> disable-kernel-irqchip. The default being both set to false (meaning
> irqchip is enabled automatically if available). We may still have a
> third kernel_irqchip property for compatibility, that will change both
> require-kernel-irqchip and disable-kernel-irqchip at the same time when
> set.
> 
> * A string kernel_irqchip property which accepts three values: "on",
> "off", and "auto".
> 
> Example of partial implementation of the first approach, below. I still
> didn't add the two extra properties, and just let the code access the
> require_kernel_irqchip and disable_kernel_irqchip fields directly.
> 
> Note that this is on top of some other changes I have been experimenting
> with, changing the accelerator init functions to get MachineState as
> argument. Git tree containing all work in progress can be seen at:
> https://github.com/ehabkost/qemu-hacks/commits/work/machine-irqchip-tristate

Hi Eduardo, thanks for the example.

I would also chose with the first solution, but use {require, allowed}
instead of {required, disabled}, but in the end is the same logic.

Thanks,
Marcel

> 
>     diff --git a/hw/core/machine.c b/hw/core/machine.c
>     index cbba679..0797bc1 100644
>     --- a/hw/core/machine.c
>     +++ b/hw/core/machine.c
>     @@ -31,14 +31,15 @@ static bool machine_get_kernel_irqchip(Object *obj, Error **errp)
>      {
>          MachineState *ms = MACHINE(obj);
>      
>     -    return ms->kernel_irqchip;
>     +    return !ms->disable_kernel_irqchip;
>      }
>      
>      static void machine_set_kernel_irqchip(Object *obj, bool value, Error **errp)
>      {
>          MachineState *ms = MACHINE(obj);
>      
>     -    ms->kernel_irqchip = value;
>     +    ms->require_kernel_irqchip = value;
>     +    ms->disable_kernel_irqchip = !value;
>      }
>      
>      static void machine_get_kvm_shadow_mem(Object *obj, Visitor *v,
>     diff --git a/include/hw/boards.h b/include/hw/boards.h
>     index 0389933..4a2daee 100644
>     --- a/include/hw/boards.h
>     +++ b/include/hw/boards.h
>     @@ -99,7 +99,8 @@ struct MachineState {
>          /*< public >*/
>      
>          char *accel;
>     -    bool kernel_irqchip;
>     +    bool require_kernel_irqchip;
>     +    bool disable_kernel_irqchip;
>          int kvm_shadow_mem;
>          char *dtb;
>          char *dumpdtb;
>     diff --git a/kvm-all.c b/kvm-all.c
>     index d2f4d7f..120bf70 100644
>     --- a/kvm-all.c
>     +++ b/kvm-all.c
>     @@ -1315,11 +1315,11 @@ int kvm_irqchip_remove_irqfd_notifier(KVMState *s, EventNotifier *n, int virq)
>                 false);
>      }
>      
>     -static int kvm_irqchip_create(KVMState *s)
>     +static int kvm_irqchip_create(MachineState *ms, KVMState *s)
>      {
>          int ret;
>      
>     -    if (!qemu_opt_get_bool(qemu_get_machine_opts(), "kernel_irqchip", true) ||
>     +    if (ms->disable_kernel_irqchip ||
>              (!kvm_check_extension(s, KVM_CAP_IRQCHIP) &&
>               (kvm_vm_enable_cap(s, KVM_CAP_S390_IRQCHIP, 0) < 0))) {
>              return 0;
>     @@ -1545,7 +1545,7 @@ void kvm_init(MachineState *ms, Error **errp)
>              goto err;
>          }
>      
>     -    ret = kvm_irqchip_create(s);
>     +    ret = kvm_irqchip_create(ms, s);
>          if (ret < 0) {
>              error_setg_errno(&err, -ret, "kvm_irqchip_create failed");
>              goto err;
>
diff mbox

Patch

diff --git a/hw/core/machine.c b/hw/core/machine.c
index d3ffef7..dbcf2a1 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -11,6 +11,260 @@ 
  */
 
 #include "hw/boards.h"
+#include "qapi/visitor.h"
+
+static char *machine_get_accel(Object *obj, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    return g_strdup(ms->accel);
+}
+
+static void machine_set_accel(Object *obj, const char *value, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    ms->accel = g_strdup(value);
+}
+
+static bool machine_get_kernel_irqchip(Object *obj, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    return ms->kernel_irqchip;
+}
+
+static void machine_set_kernel_irqchip(Object *obj, bool value, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    ms->kernel_irqchip = value;
+}
+
+static void machine_get_kvm_shadow_mem(Object *obj, Visitor *v,
+                                       void *opaque, const char *name,
+                                       Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    int64_t value = ms->kvm_shadow_mem;
+
+    visit_type_int(v, &value, name, errp);
+}
+
+static void machine_set_kvm_shadow_mem(Object *obj, Visitor *v,
+                                       void *opaque, const char *name,
+                                       Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    Error *error = NULL;
+    int64_t value;
+
+    visit_type_int(v, &value, name, &error);
+    if (error) {
+        error_propagate(errp, error);
+        return;
+    }
+
+    ms->kvm_shadow_mem = value;
+}
+
+static char *machine_get_kernel(Object *obj, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    return g_strdup(ms->kernel_filename);
+}
+
+static void machine_set_kernel(Object *obj, const char *value, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    ms->kernel_filename = g_strdup(value);
+}
+
+static char *machine_get_initrd(Object *obj, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    return g_strdup(ms->initrd_filename);
+}
+
+static void machine_set_initrd(Object *obj, const char *value, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    ms->initrd_filename = g_strdup(value);
+}
+
+static char *machine_get_append(Object *obj, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    return g_strdup(ms->kernel_cmdline);
+}
+
+static void machine_set_append(Object *obj, const char *value, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    ms->kernel_cmdline = g_strdup(value);
+}
+
+static char *machine_get_dtb(Object *obj, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    return g_strdup(ms->dtb);
+}
+
+static void machine_set_dtb(Object *obj, const char *value, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    ms->dtb = g_strdup(value);
+}
+
+static char *machine_get_dumpdtb(Object *obj, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    return g_strdup(ms->dumpdtb);
+}
+
+static void machine_set_dumpdtb(Object *obj, const char *value, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    ms->dumpdtb = g_strdup(value);
+}
+
+static void machine_get_phandle_start(Object *obj, Visitor *v,
+                                       void *opaque, const char *name,
+                                       Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    int64_t value = ms->phandle_start;
+
+    visit_type_int(v, &value, name, errp);
+}
+
+static void machine_set_phandle_start(Object *obj, Visitor *v,
+                                       void *opaque, const char *name,
+                                       Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    Error *error = NULL;
+    int64_t value;
+
+    visit_type_int(v, &value, name, &error);
+    if (error) {
+        error_propagate(errp, error);
+        return;
+    }
+
+    ms->phandle_start = value;
+}
+
+static char *machine_get_dt_compatible(Object *obj, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    return g_strdup(ms->dt_compatible);
+}
+
+static void machine_set_dt_compatible(Object *obj, const char *value, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    ms->dt_compatible = g_strdup(value);
+}
+
+static bool machine_get_dump_guest_core(Object *obj, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    return ms->dump_guest_core;
+}
+
+static void machine_set_dump_guest_core(Object *obj, bool value, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    ms->dump_guest_core = value;
+}
+
+static bool machine_get_mem_merge(Object *obj, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    return ms->mem_merge;
+}
+
+static void machine_set_mem_merge(Object *obj, bool value, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    ms->mem_merge = value;
+}
+
+static bool machine_get_usb(Object *obj, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    return ms->usb;
+}
+
+static void machine_set_usb(Object *obj, bool value, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    ms->usb = value;
+}
+
+static char *machine_get_firmware(Object *obj, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    return g_strdup(ms->firmware);
+}
+
+static void machine_set_firmware(Object *obj, const char *value, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    ms->firmware = g_strdup(value);
+}
+
+static void machine_initfn(Object *obj)
+{
+    object_property_add_str(obj, "accel",
+                            machine_get_accel, machine_set_accel, NULL);
+    object_property_add_bool(obj, "kernel_irqchip",
+                             machine_get_kernel_irqchip,
+                             machine_set_kernel_irqchip,
+                             NULL);
+    object_property_add(obj, "kvm_shadow_mem", "int",
+                        machine_get_kvm_shadow_mem,
+                        machine_set_kvm_shadow_mem,
+                        NULL, NULL, NULL);
+    object_property_add_str(obj, "kernel",
+                            machine_get_kernel, machine_set_kernel, NULL);
+    object_property_add_str(obj, "initrd",
+                            machine_get_initrd, machine_set_initrd, NULL);
+    object_property_add_str(obj, "append",
+                            machine_get_append, machine_set_append, NULL);
+    object_property_add_str(obj, "dtb",
+                            machine_get_dtb, machine_set_dtb, NULL);
+    object_property_add_str(obj, "dumpdtb",
+                            machine_get_dumpdtb, machine_set_dumpdtb, NULL);
+    object_property_add(obj, "phandle_start", "int",
+                        machine_get_phandle_start,
+                        machine_set_phandle_start,
+                        NULL, NULL, NULL);
+    object_property_add_str(obj, "dt_compatible",
+                            machine_get_dt_compatible,
+                            machine_set_dt_compatible,
+                            NULL);
+    object_property_add_bool(obj, "dump-guest-core",
+                             machine_get_dump_guest_core,
+                             machine_set_dump_guest_core,
+                             NULL);
+    object_property_add_bool(obj, "mem-merge",
+                             machine_get_mem_merge, machine_set_mem_merge, NULL);
+    object_property_add_bool(obj, "usb", machine_get_usb, machine_set_usb, NULL);
+    object_property_add_str(obj, "firmware",
+                            machine_get_firmware, machine_set_firmware, NULL);
+}
+
+static void qemu_machine_finalize(Object *obj)
+{
+    MachineState *ms = MACHINE(obj);
+
+    g_free(ms->accel);
+    g_free(ms->kernel_filename);
+    g_free(ms->initrd_filename);
+    g_free(ms->kernel_cmdline);
+    g_free(ms->dtb);
+    g_free(ms->dumpdtb);
+    g_free(ms->dt_compatible);
+    g_free(ms->firmware);
+}
 
 static const TypeInfo machine_info = {
     .name = TYPE_MACHINE,
@@ -18,6 +272,8 @@  static const TypeInfo machine_info = {
     .abstract = true,
     .class_size = sizeof(MachineClass),
     .instance_size = sizeof(MachineState),
+    .instance_init = machine_initfn,
+    .instance_finalize = qemu_machine_finalize,
 };
 
 static void machine_register_types(void)
diff --git a/include/hw/boards.h b/include/hw/boards.h
index b62de4a..2d2e2be 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -114,9 +114,9 @@  struct MachineState {
 
     ram_addr_t ram_size;
     const char *boot_order;
-    const char *kernel_filename;
-    const char *kernel_cmdline;
-    const char *initrd_filename;
+    char *kernel_filename;
+    char *kernel_cmdline;
+    char *initrd_filename;
     const char *cpu_model;
 };
 
diff --git a/vl.c b/vl.c
index 2153b9e..676df6e 100644
--- a/vl.c
+++ b/vl.c
@@ -4215,6 +4215,12 @@  int main(int argc, char **argv, char **envp)
         exit(0);
     }
 
+    machine_opts = qemu_get_machine_opts();
+    if (qemu_opt_foreach(machine_opts, object_set_property, current_machine, 1) < 0) {
+        object_unref(OBJECT(current_machine));
+        exit(1);
+    }
+
     configure_accelerator(machine_class);
 
     if (qtest_chrdev) {
@@ -4259,6 +4265,7 @@  int main(int argc, char **argv, char **envp)
 
     if (!kernel_cmdline) {
         kernel_cmdline = "";
+        current_machine->kernel_cmdline = (char *)kernel_cmdline;
     }
 
     linux_boot = (kernel_filename != NULL);
@@ -4423,9 +4430,6 @@  int main(int argc, char **argv, char **envp)
 
     current_machine->ram_size = ram_size;
     current_machine->boot_order = boot_order;
-    current_machine->kernel_filename = kernel_filename;
-    current_machine->kernel_cmdline = kernel_cmdline;
-    current_machine->initrd_filename = initrd_filename;
     current_machine->cpu_model = cpu_model;
 
     machine_class->init(current_machine);