|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v5 5/8] microcode: split out apply_microcode() from cpu_request_microcode()
On Tue, Jan 29, 2019 at 10:58:11AM +0100, Roger Pau Monné wrote:
>On Mon, Jan 28, 2019 at 03:06:47PM +0800, Chao Gao wrote:
>> During late microcode update, apply_microcode() is invoked in
>> cpu_request_microcode(). To make late microcode update more reliable,
>> we want to put the apply_microcode() into stop_machine context. So
>> we split out it from cpu_request_microcode(). As a consequence,
>> apply_microcode() should be invoked explicitly in the common code.
>>
>> Also with the global ucode cache, microcode parsing only needs
>> to be done once; cpu_request_microcode() is also moved out of
>> microcode_update_cpu().
>>
>> On AMD side, svm_host_osvw_init() is supposed to be called after
>> microcode update. As apply_micrcode() won't be called by
>> cpu_request_microcode() now, svm_host_osvw_init() is also moved to the
>> end of apply_microcode().
>>
>> Signed-off-by: Chao Gao <chao.gao@xxxxxxxxx>
>> ---
>> xen/arch/x86/microcode.c | 80
>> +++++++++++++++++++++++++-----------------
>> xen/arch/x86/microcode_amd.c | 23 +++++++-----
>> xen/arch/x86/microcode_intel.c | 20 ++---------
>> 3 files changed, 64 insertions(+), 59 deletions(-)
>>
>> diff --git a/xen/arch/x86/microcode.c b/xen/arch/x86/microcode.c
>> index 0c77e90..936f0b8 100644
>> --- a/xen/arch/x86/microcode.c
>> +++ b/xen/arch/x86/microcode.c
>> @@ -254,47 +254,42 @@ struct microcode_patch *find_patch(unsigned int cpu)
>> return NULL;
>> }
>>
>> -int microcode_resume_cpu(unsigned int cpu)
>> +/*
>> + * Return the number of ucode patch inserted to the global cache.
>> + * Return negtive value on error.
>> + */
>> +static int parse_microcode_blob(const void *buffer, size_t len)
>> {
>> - int err;
>> + unsigned int cpu = smp_processor_id();
>> struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu);
>> -
>> - if ( !microcode_ops )
>> - return 0;
>> + int ret;
>>
>> spin_lock(µcode_mutex);
>> -
>> - err = microcode_ops->collect_cpu_info(cpu, &uci->cpu_sig);
>> - if ( err )
>> - {
>> + ret = microcode_ops->collect_cpu_info(cpu, &uci->cpu_sig);
>> + if ( likely(!ret) )
>> + ret = microcode_ops->cpu_request_microcode(cpu, buffer, len);
>> + else
>> microcode_fini_cpu(cpu);
>> - spin_unlock(µcode_mutex);
>> - return err;
>> - }
>> -
>> - err = microcode_ops->apply_microcode(cpu);
>> spin_unlock(µcode_mutex);
>>
>> - return err;
>> + return ret;
>> }
>>
>> -static int microcode_update_cpu(const void *buf, size_t size)
>> +static int microcode_update_cpu(void)
>> {
>> - int err;
>> - unsigned int cpu = smp_processor_id();
>> - struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu);
>> + int ret;
>>
>> spin_lock(µcode_mutex);
>> -
>> - err = microcode_ops->collect_cpu_info(cpu, &uci->cpu_sig);
>> - if ( likely(!err) )
>> - err = microcode_ops->cpu_request_microcode(cpu, buf, size);
>> - else
>> - microcode_fini_cpu(cpu);
>> -
>> + ret = microcode_ops->apply_microcode(smp_processor_id());
>
>I've realized that most of this helpers take a cpu id parameter
>(apply_microcode, collect_cpu_info and cpu_request_microcode), but
>that at least on Intel they are required to be called on the current
>CPU, at which point I wonder about their purpose. IMO they just make
>the interface more messy, without adding any functionality.
I agree with you and will remove the 'cpu' parameter from the interfaces
you mentioned above.
>
>> spin_unlock(µcode_mutex);
>>
>> - return err;
>> + return ret;
>> +}
>> +
>> +int microcode_resume_cpu(unsigned int cpu)
>> +{
>> + BUG_ON(cpu != smp_processor_id());
>
>Same here, what's the point of passing a cpu id as parameter when
>there's only one valid value?
>
>> + return microcode_ops ? microcode_update_cpu() : 0;
>> }
>>
>> static long do_microcode_update(void *_info)
>> @@ -304,7 +299,7 @@ static long do_microcode_update(void *_info)
>>
>> BUG_ON(info->cpu != smp_processor_id());
>>
>> - error = microcode_update_cpu(info->buffer, info->buffer_size);
>> + error = microcode_update_cpu();
>> if ( error )
>> info->error = error;
>>
>> @@ -339,10 +334,6 @@ int microcode_update(XEN_GUEST_HANDLE_PARAM(const_void)
>> buf, unsigned long len)
>> return ret;
>> }
>>
>> - info->buffer_size = len;
>> - info->error = 0;
>> - info->cpu = cpumask_first(&cpu_online_map);
>> -
>> if ( microcode_ops->start_update )
>> {
>> ret = microcode_ops->start_update();
>> @@ -353,6 +344,18 @@ int microcode_update(XEN_GUEST_HANDLE_PARAM(const_void)
>> buf, unsigned long len)
>> }
>> }
>>
>> + ret = parse_microcode_blob(info->buffer, len);
>> + if ( ret <= 0 )
>> + {
>> + printk(XENLOG_ERR "No valid or newer ucode found. Update abort!\n");
>> + xfree(info);
>> + return -EINVAL;
>> + }
>> +
>> + info->buffer_size = len;
>> + info->error = 0;
>> + info->cpu = cpumask_first(&cpu_online_map);
>
>It looks like you can also get rid of the cpu field in microcode_info,
>since it's always smp_processor_id?
Yes. Will remove the 'cpu' field.
>
>> +
>> return continue_hypercall_on_cpu(info->cpu, do_microcode_update, info);
>> }
>>
>> @@ -396,13 +399,24 @@ int __init early_microcode_update_cpu(bool
>> start_update)
>> }
>> if ( data )
>> {
>> + static bool parsed = false;
>> +
>> if ( start_update && microcode_ops->start_update )
>> rc = microcode_ops->start_update();
>>
>> if ( rc )
>> return rc;
>>
>> - return microcode_update_cpu(data, len);
>> + if ( !parsed )
>> + {
>> + rc = parse_microcode_blob(data, len);
>> + parsed = true;
>> +
>> + if ( rc <= 0 )
>> + return -EINVAL;
>> + }
>> +
>> + return microcode_update_cpu();
>
>Hm, the usage of parsed here is kind of dangerous. I assume this works
>fine because early_microcode_update_cpu is called from the BSP in
>early_microcode_init, and then concurrent calls done by the APs always
>see parsed as true.
I think APs are woken up one-by-one. See the call site of cpu_up in
__start_xen.
>
>I would however recommend that you move the parsing to
>early_microcode_init, and that early_microcode_update_cpu always
>assume the blob has been parsed.
>
>If that doesn't work for some reason, I would then recommend that you
>gate the parsing based on cpu_id, so "smp_processor_id() == 0"
Do you think it is better:
remove the parsed flag and check whether current cpu is bsp in
early_microcode_init(); bsp calls the early_microcode_update_cpu(). APs
just call microcode_update_cpu().
>
>> }
>> else
>> return -ENOMEM;
>> diff --git a/xen/arch/x86/microcode_amd.c b/xen/arch/x86/microcode_amd.c
>> index d86a596..80e274e 100644
>> --- a/xen/arch/x86/microcode_amd.c
>> +++ b/xen/arch/x86/microcode_amd.c
>> @@ -297,6 +297,10 @@ static int apply_microcode(unsigned int cpu)
>>
>> uci->cpu_sig.rev = rev;
>>
>> +#if CONFIG_HVM
>> + svm_host_osvw_init();
>> +#endif
>> +
>> return 0;
>> }
>>
>> @@ -463,6 +467,7 @@ static int cpu_request_microcode(unsigned int cpu, const
>> void *buf,
>> struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu);
>> unsigned int current_cpu_id;
>> unsigned int equiv_cpu_id;
>> + unsigned int matched_cnt = 0;
>>
>> /* We should bind the task to the CPU */
>> BUG_ON(cpu != raw_smp_processor_id());
>> @@ -564,11 +569,15 @@ static int cpu_request_microcode(unsigned int cpu,
>> const void *buf,
>> * this ucode patch before checking whether it matches with
>> * current CPU.
>> */
>> - if ( save_patch(microcode_patch) && microcode_fits(mc_amd, cpu) )
>> + if ( save_patch(microcode_patch) )
>> {
>> - error = apply_microcode(cpu);
>> - if ( error )
>> - break;
>> + matched_cnt++;
>> + if ( microcode_fits(mc_amd, cpu) )
>> + {
>> + error = apply_microcode(cpu);
>> + if ( error )
>> + break;
>> + }
>
>In the commit message you mention that apply_microcode won't be called
>by cpu_request_microcode, yet it seems it's called?
lines below "matched_cnt++" should be removed. They slipped in when I
did a rebasing.
Thanks
Chao
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |