Re: arch/x86/include/asm/processor.h:698:16: sparse: sparse: incorrect type in initializer (different address spaces)

Thomas Gleixner
2024-03-02T15:44:40Z

On Sat, Mar 02 2024 at 12:37, Thomas Gleixner wrote:
> Bah. sparse is actually right. I completely missed the fact that this is
> an UP build which has:
>
> extern struct cpuinfo_x86 boot_cpu_data;
>
> #define cpu_info boot_cpu_data
>
> So any access with this_cpu*(), per_cpu*() etc. is actually incorrect from
> sparse's point of view.
>
> From a compiler point of view it just works because __percpu dissolves
> and the whole thing produces correct code magically.
>
> Most places in x86 use cpu_data(cpu) to access per cpu data which is
> defined as per_cpu(cpu_info, cpu) for SMP and boot_cpu_info for UP.
>
> That's fine, but there are places like the MCE code which really needs
> raw_cpu_ptr(). Sure we can write ugly wrappers for that and for some
> other accessors. But that's all just wrong and ugly.
>
> The proper solution would be to force SMP for x86, but Linus shot it
> down when I wanted to do that last time.
>
> Let me think about it.

The below addresses _all_ percpu related sparse warnings except
the ones in arch/x86/cpu/bugs.o but that's a sparse problem:

The following is handled correctly:

DECLARE_PER_CPU(u64, foo);
this_cpu_read(foo);

But this is not:

DECLARE_PER_CPU(u64, foo);
DEFINE_PER_CPU(u64, foo);
this_cpu_read(foo);

arch/x86/kernel/cpu/bugs.c:71:9: sparse: warning: incorrect type in initializer (different address spaces)
arch/x86/kernel/cpu/bugs.c:71:9: sparse: expected void const [noderef] __percpu *__vpp_verify
arch/x86/kernel/cpu/bugs.c:71:9: sparse: got unsigned long long *

Commenting out the DEFINE_PER_CPU(u64, x86_spec_ctrl_current) in that
file makes sparse happy, but that's obviously not a solution :)

This problem is unrelated to the UP cpu_info issue, which made me look
at this mess in the first place. It happens on SMP too and both on 32
and 64 bit.

The other __percpu related sparse warnings are valid.

- The UP cpu_info mechanics are just a horrible hackery.

The cure is to "waste" one 'struct cpu_info' size of memory and
provide the per CPU cpu_info in the same way as on SMP with
DEFINE_PER_CPU() and copy the boot_cpu_data over at the same point
in the boot process.

With that the unholy #define hack goes away and _all_ per CPU
accessors can now be used. That allows to get rid of the cpu_data()
indirection which is just annoying for SMP because it creates
suboptimal code.

- smp-msr and amd uncore lack __percpu annotations in data structures
and function arguments. That's not UP specific and just plain wrong.

While at it I fixed also the valid_user_address() complaint which lacks
a __force in the type cast.

The UP muck is only compiled and not boot tested. There might be a few
things which need to be adjusted, but from a quick scan I did not see
anything obvious.

I'll go and split it up into reviewable chunks and actually test UP
unless someone beats me to it and is brave enough to give the below a
test ride.

Thanks,

tglx
---
arch/alpha/kernel/smp.c | 5 -----
arch/arc/kernel/smp.c | 5 -----
arch/csky/kernel/smp.c | 4 ----
arch/hexagon/kernel/smp.c | 4 ----
arch/openrisc/kernel/smp.c | 4 ----
arch/riscv/kernel/smpboot.c | 4 ----
arch/sparc/kernel/smp_64.c | 4 ----
arch/x86/events/amd/uncore.c | 2 +-
arch/x86/include/asm/desc.h | 4 ++--
arch/x86/include/asm/msr.h | 20 ++++++++++----------
arch/x86/include/asm/processor.h | 5 -----
arch/x86/include/asm/smp.h | 5 -----
arch/x86/include/asm/uaccess_64.h | 2 +-
arch/x86/kernel/setup.c | 13 +++++++++++++
arch/x86/kernel/smpboot.c | 5 +++++
arch/x86/lib/msr-smp.c | 9 ++++-----
arch/x86/lib/msr.c | 2 +-
include/linux/smp.h | 13 ++++++-------
init/main.c | 4 ++++
19 files changed, 47 insertions(+), 67 deletions(-)

--- a/arch/alpha/kernel/smp.c
+++ b/arch/alpha/kernel/smp.c
@@ -467,11 +467,6 @@ smp_prepare_cpus(unsigned int max_cpus)
smp_num_cpus = smp_num_probed;
}

-void
-smp_prepare_boot_cpu(void)
-{
-}
-
int
__cpu_up(unsigned int cpu, struct task_struct *tidle)
{
--- a/arch/arc/kernel/smp.c
+++ b/arch/arc/kernel/smp.c
@@ -39,11 +39,6 @@ struct plat_smp_ops __weak plat_smp_ops
/* XXX: per cpu ? Only needed once in early secondary boot */
struct task_struct *secondary_idle_tsk;

-/* Called from start_kernel */
-void __init smp_prepare_boot_cpu(void)
-{
-}
-
static int __init arc_get_cpu_map(const char *name, struct cpumask *cpumask)
{
unsigned long dt_root = of_get_flat_dt_root();
--- a/arch/csky/kernel/smp.c
+++ b/arch/csky/kernel/smp.c
@@ -152,10 +152,6 @@ void arch_irq_work_raise(void)
}
#endif

-void __init smp_prepare_boot_cpu(void)
-{
-}
-
void __init smp_prepare_cpus(unsigned int max_cpus)
{
}
--- a/arch/hexagon/kernel/smp.c
+++ b/arch/hexagon/kernel/smp.c
@@ -114,10 +114,6 @@ void send_ipi(const struct cpumask *cpum
local_irq_restore(flags);
}

-void __init smp_prepare_boot_cpu(void)
-{
-}
-
/*
* interrupts should already be disabled from the VM
* SP should already be correct; need to set THREADINFO_REG
--- a/arch/openrisc/kernel/smp.c
+++ b/arch/openrisc/kernel/smp.c
@@ -57,10 +57,6 @@ static void boot_secondary(unsigned int
spin_unlock(&boot_lock);
}

-void __init smp_prepare_boot_cpu(void)
-{
-}
-
void __init smp_init_cpus(void)
{
struct device_node *cpu;
--- a/arch/riscv/kernel/smpboot.c
+++ b/arch/riscv/kernel/smpboot.c
@@ -42,10 +42,6 @@

static DECLARE_COMPLETION(cpu_running);

-void __init smp_prepare_boot_cpu(void)
-{
-}
-
void __init smp_prepare_cpus(unsigned int max_cpus)
{
int cpuid;
--- a/arch/sparc/kernel/smp_64.c
+++ b/arch/sparc/kernel/smp_64.c
@@ -1206,10 +1206,6 @@ void __init smp_prepare_cpus(unsigned in
{
}

-void smp_prepare_boot_cpu(void)
-{
-}
-
void __init smp_setup_processor_id(void)
{
if (tlb_type == spitfire)
--- a/arch/x86/events/amd/uncore.c
+++ b/arch/x86/events/amd/uncore.c
@@ -71,7 +71,7 @@ union amd_uncore_info {
};

struct amd_uncore {
- union amd_uncore_info * __percpu info;
+ union amd_uncore_info __percpu *info;
struct amd_uncore_pmu *pmus;
unsigned int num_pmus;
bool init_done;
--- a/arch/x86/include/asm/desc.h
+++ b/arch/x86/include/asm/desc.h
@@ -51,13 +51,13 @@ DECLARE_INIT_PER_CPU(gdt_page);
/* Provide the original GDT */
static inline struct desc_struct *get_cpu_gdt_rw(unsigned int cpu)
{
- return per_cpu(gdt_page, cpu).gdt;
+ return per_cpu(gdt_page.gdt, cpu);
}

/* Provide the current original GDT */
static inline struct desc_struct *get_current_gdt_rw(void)
{
- return this_cpu_ptr(&gdt_page)->gdt;
+ return this_cpu_ptr(gdt_page.gdt);
}

/* Provide the fixmap address of the remapped GDT */
--- a/arch/x86/include/asm/msr.h
+++ b/arch/x86/include/asm/msr.h
@@ -13,10 +13,10 @@
#include <asm/shared/msr.h>

struct msr_info {
- u32 msr_no;
- struct msr reg;
- struct msr *msrs;
- int err;
+ u32 msr_no;
+ struct msr reg;
+ struct msr __percpu *msrs;
+ int err;
};

struct msr_regs_info {
@@ -315,8 +315,8 @@ int rdmsr_on_cpu(unsigned int cpu, u32 m
int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h);
int rdmsrl_on_cpu(unsigned int cpu, u32 msr_no, u64 *q);
int wrmsrl_on_cpu(unsigned int cpu, u32 msr_no, u64 q);
-void rdmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs);
-void wrmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs);
+void rdmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr __percpu *msrs);
+void wrmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr __percpu *msrs);
int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h);
int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h);
int rdmsrl_safe_on_cpu(unsigned int cpu, u32 msr_no, u64 *q);
@@ -345,14 +345,14 @@ static inline int wrmsrl_on_cpu(unsigned
return 0;
}
static inline void rdmsr_on_cpus(const struct cpumask *m, u32 msr_no,
- struct msr *msrs)
+ struct msr __percpu *msrs)
{
- rdmsr_on_cpu(0, msr_no, &(msrs[0].l), &(msrs[0].h));
+ rdmsr_on_cpu(0, msr_no, this_cpu_ptr(&msrs->l), this_cpu_ptr(&msrs->h));
}
static inline void wrmsr_on_cpus(const struct cpumask *m, u32 msr_no,
- struct msr *msrs)
+ struct msr __percpu *msrs)
{
- wrmsr_on_cpu(0, msr_no, msrs[0].l, msrs[0].h);
+ wrmsr_on_cpu(0, msr_no, this_cpu_read(msrs->l), this_cpu_read(msrs->h));
}
static inline int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no,
u32 *l, u32 *h)
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -186,13 +186,8 @@ extern struct cpuinfo_x86 new_cpu_data;
extern __u32 cpu_caps_cleared[NCAPINTS + NBUGINTS];
extern __u32 cpu_caps_set[NCAPINTS + NBUGINTS];

-#ifdef CONFIG_SMP
DECLARE_PER_CPU_READ_MOSTLY(struct cpuinfo_x86, cpu_info);
#define cpu_data(cpu) per_cpu(cpu_info, cpu)
-#else
-#define cpu_info boot_cpu_data
-#define cpu_data(cpu) boot_cpu_data
-#endif

extern const struct seq_operations cpuinfo_op;

--- a/arch/x86/include/asm/smp.h
+++ b/arch/x86/include/asm/smp.h
@@ -59,11 +59,6 @@ static inline void stop_other_cpus(void)
smp_ops.stop_other_cpus(1);
}

-static inline void smp_prepare_boot_cpu(void)
-{
- smp_ops.smp_prepare_boot_cpu();
-}
-
static inline void smp_prepare_cpus(unsigned int max_cpus)
{
smp_ops.smp_prepare_cpus(max_cpus);
--- a/arch/x86/include/asm/uaccess_64.h
+++ b/arch/x86/include/asm/uaccess_64.h
@@ -54,7 +54,7 @@ static inline unsigned long __untagged_a
* half and a user half. When cast to a signed type, user pointers
* are positive and kernel pointers are negative.
*/
-#define valid_user_address(x) ((long)(x) >= 0)
+#define valid_user_address(x) ((__force long)(x) >= 0)

/*
* User pointers can have tag bits on x86-64. This scheme tolerates
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -1211,6 +1211,19 @@ void __init i386_reserve_resources(void)

#endif /* CONFIG_X86_32 */

+#ifndef CONFIG_SMP
+DEFINE_PER_CPU_READ_MOSTLY(struct cpuinfo_x86, cpu_info);
+EXPORT_PER_CPU_SYMBOL(cpu_info);
+
+void __init smp_prepare_boot_cpu(void)
+{
+ struct cpuinfo_x86 *c = &cpu_data(0);
+
+ *c = boot_cpu_data;
+ c->initialized = true;
+}
+#endif
+
static struct notifier_block kernel_offset_notifier = {
.notifier_call = dump_kernel_offset
};
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -1187,6 +1187,11 @@ void __init smp_prepare_cpus_common(void
set_cpu_sibling_map(0);
}

+void __init smp_prepare_boot_cpu(void)
+{
+ smp_ops.smp_prepare_boot_cpu();
+}
+
#ifdef CONFIG_X86_64
/* Establish whether parallel bringup can be supported. */
bool __init arch_cpuhp_init_parallel_bringup(void)
--- a/arch/x86/lib/msr-smp.c
+++ b/arch/x86/lib/msr-smp.c
@@ -9,10 +9,9 @@ static void __rdmsr_on_cpu(void *info)
{
struct msr_info *rv = info;
struct msr *reg;
- int this_cpu = raw_smp_processor_id();

if (rv->msrs)
- reg = per_cpu_ptr(rv->msrs, this_cpu);
+ reg = this_cpu_ptr(rv->msrs);
else
reg = &rv->reg;

@@ -97,7 +96,7 @@ int wrmsrl_on_cpu(unsigned int cpu, u32
EXPORT_SYMBOL(wrmsrl_on_cpu);

static void __rwmsr_on_cpus(const struct cpumask *mask, u32 msr_no,
- struct msr *msrs,
+ struct msr __percpu *msrs,
void (*msr_func) (void *info))
{
struct msr_info rv;
@@ -124,7 +123,7 @@ static void __rwmsr_on_cpus(const struct
* @msrs: array of MSR values
*
*/
-void rdmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs)
+void rdmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr __percpu *msrs)
{
__rwmsr_on_cpus(mask, msr_no, msrs, __rdmsr_on_cpu);
}
@@ -138,7 +137,7 @@ EXPORT_SYMBOL(rdmsr_on_cpus);
* @msrs: array of MSR values
*
*/
-void wrmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs)
+void wrmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr __percpu *msrs)
{
__rwmsr_on_cpus(mask, msr_no, msrs, __wrmsr_on_cpu);
}
--- a/arch/x86/lib/msr.c
+++ b/arch/x86/lib/msr.c
@@ -8,7 +8,7 @@

struct msr *msrs_alloc(void)
{
- struct msr *msrs = NULL;
+ struct msr __percpu *msrs = NULL;

msrs = alloc_percpu(struct msr);
if (!msrs) {
--- a/include/linux/smp.h
+++ b/include/linux/smp.h
@@ -105,6 +105,12 @@ static inline void on_each_cpu_cond(smp_
on_each_cpu_cond_mask(cond_func, func, info, wait, cpu_online_mask);
}

+/*
+ * Architecture specific boot CPU setup. Defined as empty weak function in
+ * init/main.c. Architectures can override it.
+ */
+void smp_prepare_boot_cpu(void);
+
#ifdef CONFIG_SMP

#include <linux/preempt.h>
@@ -171,12 +177,6 @@ void generic_smp_call_function_single_in
#define generic_smp_call_function_interrupt \
generic_smp_call_function_single_interrupt

-/*
- * Mark the boot cpu "online" so that it can call console drivers in
- * printk() and can access its per-cpu storage.
- */
-void smp_prepare_boot_cpu(void);
-
extern unsigned int setup_max_cpus;
extern void __init setup_nr_cpu_ids(void);
extern void __init smp_init(void);
@@ -203,7 +203,6 @@ static inline void up_smp_call_function(
(up_smp_call_function(func, info))

static inline void smp_send_reschedule(int cpu) { }
-#define smp_prepare_boot_cpu() do {} while (0)
#define smp_call_function_many(mask, func, info, wait) \
(up_smp_call_function(func, info))
static inline void call_function_init(void) { }
--- a/init/main.c
+++ b/init/main.c
@@ -776,6 +776,10 @@ void __init __weak smp_setup_processor_i
{
}

+void __init __weak smp_prepare_boot_cpu(void)
+{
+}
+
# if THREAD_SIZE >= PAGE_SIZE
void __init __weak thread_stack_cache_init(void)
{