[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

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.