|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH 3/3] x86/spec-ctrl: Add support for modifying SSBD AMD VIA LS_CFG MSR
>>> On 20.07.18 at 16:57, <brian.woods@xxxxxxx> wrote:
> --- a/xen/arch/x86/cpu/amd.c
> +++ b/xen/arch/x86/cpu/amd.c
> @@ -607,16 +607,10 @@ static void init_amd(struct cpuinfo_x86 *c)
> case 0x17: bit = 10; break;
> }
>
> - if (bit >= 0)
> - ssbd_amd_ls_cfg_mask = 1ull << bit;
> - }
>
> - if (ssbd_amd_ls_cfg_mask && !rdmsr_safe(MSR_AMD64_LS_CFG, value)) {
> - if (!boot_cpu_has(X86_FEATURE_SSBD_AMD_LS_CFG))
> + if (bit >= 0 && !rdmsr_safe(MSR_AMD64_LS_CFG, value)) {
> + ssbd_amd_ls_cfg_mask = 1ull << bit;
> setup_force_cpu_cap(X86_FEATURE_SSBD_AMD_LS_CFG);
> - if (opt_ssbd) {
> - value |= ssbd_amd_ls_cfg_mask;
> - wrmsr_safe(MSR_AMD64_LS_CFG, value);
> }
> }
Code structure wise this looks to undo a fair part of what patch
1 has done. It would be nice to limit code churn.
> --- a/xen/arch/x86/setup.c
> +++ b/xen/arch/x86/setup.c
> @@ -1579,6 +1579,8 @@ void __init noreturn __start_xen(unsigned long mbi_p)
>
> arch_init_memory();
>
> + ssbd_amd_ls_cfg_init();
Why can't this be called from init_speculation_mitigations()?
> @@ -497,6 +497,201 @@ static __init int parse_xpti(const char *s)
> }
> custom_param("xpti", parse_xpti);
>
> +/*
> + * For family 15h and 16h, there are no SMT enabled processors, so there
> + * is no need for locking, just need to set an MSR bit. For 17h, it
> + * depends if SMT is enabled. If SMT, are two threads share a single
> + * MSR so there needs to be a lock and a virtual bit for each thread.
> + */
> +
> +/* used for non SMT mitigations (no shared MSRs) */
> +static void ssbd_amd_ls_cfg_set_nonsmt(bool enable_ssbd)
> +{
> + unsigned long ls_cfg;
Please be consistent with types: ssbd_amd_ls_cfg_mask is
uint64_t, in which case variables like the one here should be too.
> + if ( enable_ssbd )
> + {
> + rdmsrl(MSR_AMD64_LS_CFG, ls_cfg);
> + if ( !(ls_cfg & ssbd_amd_ls_cfg_mask) )
> + {
> + ls_cfg |= ssbd_amd_ls_cfg_mask;
> + wrmsrl(MSR_AMD64_LS_CFG, ls_cfg);
> + }
> + }
> + else
> + {
> + rdmsrl(MSR_AMD64_LS_CFG, ls_cfg);
> + if (ls_cfg & ssbd_amd_ls_cfg_mask)
Missing blanks.
> + {
> + ls_cfg &= ~ssbd_amd_ls_cfg_mask;
> + wrmsrl(MSR_AMD64_LS_CFG, ls_cfg);
> + }
> + }
> +}
Please simplify this to have just a single rdmsrl() and wrmsrl()
each in the function.
> +/* used for family 17h with SMT enabled (shared MSRs) */
> +static void ssbd_amd_ls_cfg_set_smt(bool enable_ssbd)
> +{
> + __u32 socket, core, thread;
> + uint64_t enable_mask;
You really should notice such anomalies / inconsistencies yourself:
You properly use uint64_t here, so why not also uint32_t on the
preceding line? That said - why a fixed width type anyway for
those variables - unsigned int looks to be just fine there.
> +void ssbd_amd_ls_cfg_set(bool enable_ssbd)
> +{
> + if ( !ssbd_amd_ls_cfg_mask ||
> + !boot_cpu_has(X86_FEATURE_SSBD_AMD_LS_CFG) ) {
> + dprintk(XENLOG_ERR, "SSBD AMD LS CFG: Invalid mask\n");
> + return;
> + }
> +
> + if ( ssbd_amd_smt_en )
> + ssbd_amd_ls_cfg_set_smt(enable_ssbd);
> + else
> + ssbd_amd_ls_cfg_set_nonsmt(enable_ssbd);
> +}
This function is called from exactly one place, with the
parameter set to true. Makes me wonder what the actual
purpose of this patch is.
> +/*
> + * used to init the boot cpu, we don't need to lock anything because
> + * it's just the boot CPU
> + */
Still I wonder whether less code duplication wouldn't be better.
> +static __init void ssbd_amd_ls_cfg_set_init(void)
> +{
> + __u32 socket, core, thread;
> + unsigned long long ls_cfg;
> + struct ssbd_amd_ls_cfg_smt_status *status;
> + struct cpuinfo_x86 *c = &boot_cpu_data;
> +
> + if ( ssbd_amd_smt_en )
> + {
> + socket = c->phys_proc_id;
> + core = c->cpu_core_id;
> + thread = c->apicid && (c->x86_num_siblings - 1);
> +
> + status = ssbd_amd_smt_status[socket] + core;
> + status->mask |= (1ull << thread);
This hides very well an assumption of there only ever being two
threads. Please don't. I'm also having a hard time seeing why
c->apicid being (non-)zero matters. Or wait - do you mean &
instead of && above (then also in ssbd_amd_ls_cfg_set_smt())?
> + }
> +
> + rdmsrl(MSR_AMD64_LS_CFG, ls_cfg);
> + if ( !(ls_cfg & ssbd_amd_ls_cfg_mask) )
> + {
> + ls_cfg |= ssbd_amd_ls_cfg_mask;
> + wrmsrl(MSR_AMD64_LS_CFG, ls_cfg);
> + }
> +}
> +
> +__init void ssbd_amd_ls_cfg_init(void)
Most noticeable here, but applicable elsewhere: The canonical
placement is
void __init ssbd_amd_ls_cfg_init(void)
> +{
> + int cores_per_socket, threads_per_core;
> + struct cpuinfo_x86 *c = &boot_cpu_data;
> + int core,socket;
unsigned int please for anything that can't go negative. And a
blank is missing after the comma here, while there's one too
many on the line before.
You also don't look to be altering the data c points to - please
make this a pointer to const (and check whether there are
other places wanting such a transformation).
> + if ( !ssbd_amd_ls_cfg_mask ||
> + !boot_cpu_has(X86_FEATURE_SSBD_AMD_LS_CFG) )
> + goto ssbd_amd_ls_cfg_init_fail;
> +
> + switch ( c->x86 )
> + {
> + case 0x15:
> + case 0x16:
> + break;
> + case 0x17:
Blank lines between case blocks please.
> + cores_per_socket = c->x86_max_cores;
> + threads_per_core = c->x86_num_siblings;
> +
> + if ( (cores_per_socket < 1) || (threads_per_core < 1) )
> + {
> + dprintk(XENLOG_ERR,
> + "SSBD AMD LS CFG: error in topology decoding\n");
> + goto ssbd_amd_ls_cfg_init_fail;
> + }
> +
> + if ( threads_per_core > 1 )
> + {
> + ssbd_amd_smt_en = true;
> + for ( socket = 0; socket < SSBD_AMD_MAX_SOCKET; socket++ )
I find such a hard-coded upper bound quite concerning. Is nr_sockets
not correct in the AMD case? If so, that would want fixing, such that
you can use the variable here.
> + {
> + ssbd_amd_smt_status[socket] =
> + (struct ssbd_amd_ls_cfg_smt_status*)
> + xmalloc_array (struct ssbd_amd_ls_cfg_smt_status,
> + cores_per_socket);
Style: Blank before * and no blank before (.
> + if ( ssbd_amd_smt_status[socket] == NULL )
> + {
> + dprintk(XENLOG_ERR,
> + "SSBD AMD LS CFG: error in status allocing\n");
> + goto ssbd_amd_ls_cfg_init_fail;
> + }
> + }
> +
> + for ( socket = 0; socket < SSBD_AMD_MAX_SOCKET; socket++ )
> + {
> + for ( core = 0; core < cores_per_socket; core++ )
> + {
> + spin_lock_init(&(ssbd_amd_smt_status[socket] +
> core)->lock);
> + (ssbd_amd_smt_status[socket] + core)->mask = 0;
Perhaps better
spin_lock_init(&ssbd_amd_smt_status[socket][core].lock);
ssbd_amd_smt_status[socket][core].mask = 0;
?
> + }
> + }
> + }
> + break;
> + default:
> + goto ssbd_amd_ls_cfg_init_fail;
> + }
> +
> + if ( xen_ssbd_amd_ls_cfg_en )
> + ssbd_amd_ls_cfg_set_init();
> +
> + return;
> +
> +ssbd_amd_ls_cfg_init_fail:
Labels indented by at least one blank please.
> + for ( socket = 0; socket < SSBD_AMD_MAX_SOCKET; socket++ )
> + if ( ssbd_amd_smt_status[socket] != NULL )
> + xfree(ssbd_amd_smt_status[socket]);
> +
> + setup_clear_cpu_cap(X86_FEATURE_SSBD_AMD_LS_CFG);
> + xen_ssbd_amd_ls_cfg_en = false;
Btw - why the xen_ prefix for the variable?
> + return;
> +}
Pointless "return" at end of function.
Jan
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |