All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Andreas Färber" <afaerber@suse.de>
To: Eduardo Habkost <ehabkost@redhat.com>,
	Igor Mammedov <imammedo@redhat.com>
Cc: aliguori@us.ibm.com, gleb@redhat.com, qemu-devel@nongnu.org,
	blauwirbel@gmail.com, anthony@codemonkey.ws,
	"kvm@vger.kernel.org list" <kvm@vger.kernel.org>,
	pbonzini@redhat.com, rth@twiddle.net
Subject: Re: [Qemu-devel] [PATCH 3/5] target-i386: Slim conversion to X86CPU subclasses
Date: Fri, 08 Feb 2013 17:54:50 +0100	[thread overview]
Message-ID: <51152DDA.5070309@suse.de> (raw)
In-Reply-To: <20130208145231.GK4138@otherpad.lan.raisama.net>

Am 08.02.2013 15:52, schrieb Eduardo Habkost:
> On Fri, Feb 08, 2013 at 01:58:42PM +0100, Igor Mammedov wrote:
>> On Fri, 08 Feb 2013 12:16:17 +0100
>> Andreas Färber <afaerber@suse.de> wrote:
>>> Am 08.02.2013 10:03, schrieb Igor Mammedov:
>>>> On Thu, 7 Feb 2013 13:08:19 -0200
>>>> Eduardo Habkost <ehabkost@redhat.com> wrote:
>>>>
>>>>> On Tue, Feb 05, 2013 at 05:39:22PM +0100, Igor Mammedov wrote:
>>>>>> @@ -2236,6 +2083,44 @@ static void x86_cpu_initfn(Object *obj)
>>>>>>      }
>>>>>>  }
>>>>>>  
>>>>>> +static void x86_cpu_def_class_init(ObjectClass *oc, void *data)
>>>>>> +{
>>>>>> +    X86CPUClass *xcc = X86_CPU_CLASS(oc);
>>>>>> +    ObjectClass *hoc = object_class_by_name(TYPE_HOST_X86_CPU);
>>>>>> +    X86CPUClass *hostcc;
>>>>>> +    x86_def_t *def = data;
>>>>>> +    int i;
>>>>>> +    static const char *versioned_models[] = { "qemu32", "qemu64", "athlon" };
>>>>>> +
>>>>>> +    memcpy(&xcc->info, def, sizeof(x86_def_t));
>>>>>> +
>>>>>> +    /* host cpu class is available if KVM is enabled,
>>>>>> +     * get kvm overrides from it */
>>>>>> +    if (hoc) {
>>>>>> +        hostcc = X86_CPU_CLASS(hoc);
>>>>>> +        /* sysenter isn't supported in compatibility mode on AMD,
>>>>>> +         * syscall isn't supported in compatibility mode on Intel.
>>>>>> +         * Normally we advertise the actual CPU vendor, but you can
>>>>>> +         * override this using the 'vendor' property if you want to use
>>>>>> +         * KVM's sysenter/syscall emulation in compatibility mode and
>>>>>> +         * when doing cross vendor migration
>>>>>> +         */
>>>>>> +        memcpy(xcc->info.vendor, hostcc->info.vendor,
>>>>>> +               sizeof(xcc->info.vendor));
>>>>>> +    }
>>>>>
>>>>> Again, we have the same problem we had before, but now in the non-host
>>>>> classes. What if class_init is called before KVM is initialized? I
>>>>> believe we will be forced to move this hack to the instance init
>>>>> function.
>>>> I believe, the in the case where non-host CPU classes might be initialized
>>>> before KVM "-cpu ?" we do not care what their defaults are, since we only
>>>> would use class names there and then exit.
>>>>
>>>> For case where classes could be inspected over QMP, OQM, KVM would be already
>>>> initialized if enabled and we would get proper initialization order without
>>>> hack.
> 
> Who guarantees that KVM will be already initialized when we get a QMP
> monitor? We can't do that today because of limitations in the QEMU main
> code, but I believe we want to get rid of this limitation eventually,
> instead of making it harder to get rid of.
> 
> If we could initialize KVM before QMP is initialized, we could simply
> initialize KVM before class_init is called, instead. It would be easier
> to reason about, and it would make the limitations of our code very
> clear to anybody reading the code in main().

That wouldn't work (currently) due to -device and -object being command
line options just like -enable-kvm, -disable-kvm and -machine accel=.

>>>
>>> I think you're missing Eduardo's and my point:
>>>
>>> diff --git a/vl.c b/vl.c
>>> index a8dc73d..6b9378e 100644
>>> --- a/vl.c
>>> +++ b/vl.c
>>> @@ -2844,6 +2844,7 @@ int main(int argc, char **argv, char **envp)
>>>      }
>>>
>>>      module_call_init(MODULE_INIT_QOM);
>>> +    object_class_foreach(walkerfn, TYPE_OBJECT, false, NULL);
>>>
>>>      qemu_add_opts(&qemu_drive_opts);
>>>      qemu_add_opts(&qemu_chardev_opts);
>>>
>>> Anyone may iterate over QOM classes at any time after their type
>>> registration, which is before the first round of option parsing.
>>> Sometime later, after option parsing, there's the -cpu ? handling in
>>> vl.c:3854, then vl.c:4018:configure_accelerator().
>>>
>>> Like I said, mostly a theoretical issue today.
>> Question is if we should drop this theoretical issue for 1.5?
> 
> I wouldn't call it just theoretical. It is something that will surely
> hit us back. The people working on QMP or on the main() code 6 months
> from now will no idea that our class_init code is broken and will
> explode if class_init is called too early.

We should try to find a reliable solution here or at least add
appropriate comments to the module_call_init() call in vl.c.

>>> Originally I had considered making kvm_init() re-entrant and calling it
>>> from the offending class_init. But we must support the distro case of
>>> compiling with CONFIG_KVM but the user's hardware not supporting KVM or
>>> kvm module not being loaded or the user having insufficient priviledges
>>> to access /dev/kvm.
>> working without KVM is not issue, it just works with normal defaults. Applying
>> KVM specific defaults to already initialized classes is.

Right, but applying KVM-specific defaults is much easier once KVM is
initialized. :)

> 
> My big question is: why exactly we want to initialize this stuff inside
> class_init? Can't we (please!) put the KVM-specific logic inside
> instance_init?

Then we're pretty much back to my v3 plus Igor's error handling change,
right? Modulo whether to register the host class in kvm_arch_init() or
always.

> If "default vendor set in in built-in CPU model table" (TCG-only) has a
> different meaning from "vendor set by command-line/global-property"
> (affects TCG and KVM), it means we have two different knobs with two
> diferent semantics. Hence my suggestion of adding two properties:
> "tcg-vendor" and "vendor".

I don't quite understand why we would need a "tcg-vendor" property. Are
you trying to address setting or getting the value? If it's setting we
should just bypass the property in our internal code, using Igor's
vendor_str2words helper.

>>>> Instead of adding hack, I'd rather enforce valid initialization order and
>>>> abort in initfn() if type was initialized without KVM present and KVM is
>>>> enabled at initfn() time. Something along the lines:
>>>>
>>>> static x86_cpu_builtin_class_initialized_without_kvm;
>>>>
>>>> x86_cpu_def_class_init() {
>>>>     ...
>>>>     if (!kvm_enabled() && !x86_cpu_builtin_class_initialized_without_kvm) {
>>>>         x86_cpu_builtin_class_initialized_without_kvm = true;
>>>>     }
>>>>     ...
>>>> }
>>>>
>>>> initfn() {
>>>>     ...
>>>>     if (kvm_enabled() && x86_cpu_builtin_class_initialized_without_kvm) {
>>>>         abort();
>>>>     }
>>>>     ...
>>>> }
>>>
>> Continuing on theoretical issue:
>>> We could add an inited field to X86CPUClass that gets checked at initfn
>>> time (only ever getting set to true by the pre-defined models). Then it
>>> would be per model. And if we add a prototype for the ..._class_init we
>>> could even call it late as proposed for -cpu host if we take some
>>              ^^^^^^^^^^^^ is a tricky part, for global properties to work it
>> would require, calling this hook after kvm_init() is succeeds and before
>> any initfn() is called in general or as minimum before Device.initfn(). And it
>> anyway will not make all CPU classes to have correct defaults in KVM mode,
>> since only CPU class of created CPU instance will be fixed up.
>>
>> 1. One way to make sure that built-in CPU classes have fixed up defaults is to
>> iterate over them in kvm_arch_init() and possibly calling their class_init()
>> again to reinitialize. It's still hack (due fixing something up), but it would
>> give at least correct KVM mode defaults, regardless of the order classes are
>> initialized.
> 
> Can't we do that more easily with the tcg-vendor/vendor properties?

> It looks we are burning too much brain cycles trying to force a model
> that's really unintuitive to the outside, where the default-value of a
> class property depends on the options given to the QEMU command-line. We
> don't have to do that.
>
> The point of initializing stuff in class_init is to make introspection
> easy. If we make the classes change how they look like depending on the
> command-line configuration, the classes and the class introspection
> system get less useful.

+1

>> 2. But more correct way from POV of OOP would be one without any fixups, i.e.
>> create extra KVM-builtin-CPU-classes that are derived from host class.
>> and in object_class_by_name() lookup for them if kvm is enabled. But we could
>> do this as follow-up to #1.
>>  
>>> precautions and add explanatory comments.
>>>
>>>>> If we still want the default vendor to be a static property in the
>>>>> class, we can do that if we set the default in a "tcg-vendor" property
>>>>> instead of a "vendor" property (that would be empty/unset by default),
>>>>> and x86_cpu_initfn() could do this:
>>>>>
>>>>>     vendor = object_property_get_str(cpu, "vendor");
>>>>>     tcg_vendor = object_property_get_str(cpu, "tcg-vendor");
>>>>>     if (vendor && vendor[0]) {
>>>>>       cpu->cpuid_vendor = vendor;
>>>>>     } else if (kvm_enabled()) {
>>>>>       cpu->cpuid_vendor = get_host_vendor();
>>>>>     } else {
>>>>>       cpu->cpuid_vendor = tcg_vendor;
>>>>>     }
>>>>>
>>>>>> +
>>>>>> +    /* Look for specific models that have the QEMU version in .model_id */
>>>>>> +    for (i = 0; i < ARRAY_SIZE(versioned_models); i++) {
>>>>>> +        if (strcmp(versioned_models[i], def->name) == 0) {
>>>>>> +            pstrcpy(xcc->info.model_id, sizeof(xcc->info.model_id),
>>>>>> +                    "QEMU Virtual CPU version ");
>>>>>> +            pstrcat(xcc->info.model_id, sizeof(xcc->info.model_id),
>>>>>> +                    qemu_get_version());
>>>>>> +            break;
>>>>>> +        }
>>>>>> +    }
>>>>>> +}
>>>>>> +
>>>> [...]
>>>>
>>>>>> --- a/target-i386/kvm.c
>>>>>> +++ b/target-i386/kvm.c
>>>>>> @@ -735,6 +735,69 @@ static int kvm_get_supported_msrs(KVMState *s)
>>>>>>      return ret;
>>>>>>  }
>>>>>>  
>>>> [...]
>>>>
>>>>>>  int kvm_arch_init(KVMState *s)
>>>>>>  {
>>>>>>      QemuOptsList *list = qemu_find_opts("machine");
>>>>>> @@ -743,6 +806,12 @@ int kvm_arch_init(KVMState *s)
>>>>>>      int ret;
>>>>>>      struct utsname utsname;
>>>>>>  
>>>>>> +    static const TypeInfo host_x86_cpu_type_info = {
>>>>>> +        .name = TYPE_HOST_X86_CPU,
>>>>>> +        .parent = TYPE_X86_CPU,
>>>>>> +        .class_init = kvm_host_cpu_class_init,
>>>>>> +    };
>>>>>> +
>>>>>>      ret = kvm_get_supported_msrs(s);
>>>>>>      if (ret < 0) {
>>>>>>          return ret;
>>>>>> @@ -797,6 +866,9 @@ int kvm_arch_init(KVMState *s)
>>>>>>              }
>>>>>>          }
>>>>>>      }
>>>>>> +
>>>>>> +    type_register(&host_x86_cpu_type_info);
>>>>>
>>>>> Are we really allowed to register QOM classes that late?
>>>>>
>>>>> If QOM design allows us to register the class very late (I would like to
>>>>> confirm that), this approach sounds really clean and sane to me.
>>>>> Pre-KVM-init class introspection of the "host" class would be completely
>>>>> useless anyway (because all data in the "host" class depend on data
>>>>> available only post-KVM-init anyway).
>>>>
>>>> Looking at type_register() impl. it seems safe to do so + relying on QBL for
>>>> type_table_add() safety. So it's really design question for QOM experts.
>>>>
>>>> Antnony, Paolo, Andreas
>>>>  what do you think?
>>>
>>> I already answered Eduardo on IRC that in general I see no restriction
>>> not to register a type late.
>>>
>>> The issue is that in this case we cannot rely on accessing the class
>>> from another class_init that is registered before it, which you were
>>> doing somewhere for hoc etc. (BTW please rename to host_oc if we go that
>>> route).
>> If we are accessing host class somewhere, then we would like to access its
>> initialized state, not a dummy state which gives us nothing.

No one is doubting that. It in turn means that either class_init may not
fail/skip parts, or we need to restrict access to such classes to a
mechanism that ensures they get fully initialized if they weren't.

> Absolutely.
> 
> (Just like the built-in classes, that should be always properly
> initialized by class_init.  ;-)

I've been thinking about whether this is a more general issue that we
could solve at QOM level, like the base_class_init for qdev props, but I
haven't come up with a usable idea. (Paolo?)

I agree with Eduardo that we should not try to override class values
based on accel=kvm. Global properties don't operate on classes but on
the properties, which get set up at device-instance_init time only.
If there's an issue with the vendor it seems easier to fix that than to
play games with class_init as we seem to be going in circles...

That would leave us with the problematic -cpu host class and with
analyzing any remaining instance_init problems.

And not to forget -object and, once Anthony drops his unloved no_user
flag, -device.

Regards,
Andreas

-- 
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer; HRB 16746 AG Nürnberg

  parent reply	other threads:[~2013-02-08 16:54 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <1360082364-12475-1-git-send-email-imammedo@redhat.com>
     [not found] ` <1360082364-12475-4-git-send-email-imammedo@redhat.com>
     [not found]   ` <20130207150819.GD9964@otherpad.lan.raisama.net>
     [not found]     ` <20130208100329.2105a649@thinkpad.mammed.net>
2013-02-08 11:16       ` [PATCH 3/5] target-i386: Slim conversion to X86CPU subclasses Andreas Färber
2013-02-08 12:58         ` Igor Mammedov
2013-02-08 14:52           ` Eduardo Habkost
2013-02-08 15:08             ` Eduardo Habkost
2013-02-08 16:54             ` Andreas Färber [this message]
2013-02-08 18:13               ` Eduardo Habkost
2013-02-11  1:52                 ` Igor Mammedov
2013-02-12 14:48                   ` Eduardo Habkost
2013-02-13 15:20                     ` Igor Mammedov
2013-02-13 22:19                       ` Eduardo Habkost

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=51152DDA.5070309@suse.de \
    --to=afaerber@suse.de \
    --cc=aliguori@us.ibm.com \
    --cc=anthony@codemonkey.ws \
    --cc=blauwirbel@gmail.com \
    --cc=ehabkost@redhat.com \
    --cc=gleb@redhat.com \
    --cc=imammedo@redhat.com \
    --cc=kvm@vger.kernel.org \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=rth@twiddle.net \
    /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.