percpu相关-SHIFT_PERCPU_PTR this_cpu_ptr(ptr)等

 

include/linux/percpu-defs.h

1、 SHIFT_PERCPU_PTR

230 ~ 231 定义了 SHIFT_PERCPU_PTR ,输入 __p  和 __offset ,直接使用 RELOC_HIDE 对两者进行相加。  RELOC_HIDE  见  https://www.cnblogs.com/zhangzhiwei122/p/16053900.html

2、per_cpu_ptr(ptr,cpu)

233 ~ 236  利用 per_cpu_offset 将cpu 转换为  offset,然后使用 shift_percpu_ptr 得到 offset 之后的对象的指针。 per_cpu_offset 定义在 include/asm-generic/percpu.h

 3、raw_cpu_ptr(ptr)

使用 当前cpu 的offset 来偏移 ptr

4、this_cpu_ptr(ptr)

raw_cpu_ptr 的直接调用。或 CONFIG_DEBUG_PREEMPT

 225/*
 226 * Add an offset to a pointer but keep the pointer as-is.  Use RELOC_HIDE()
 227 * to prevent the compiler from making incorrect assumptions about the
 228 * pointer value.  The weird cast keeps both GCC and sparse happy.
 229 */
 230#define SHIFT_PERCPU_PTR(__p, __offset)                                 \
 231        RELOC_HIDE((typeof(*(__p)) __kernel __force *)(__p), (__offset))
 232
 233#define per_cpu_ptr(ptr, cpu)                                           \
 234({                                                                      \
 235        __verify_pcpu_ptr(ptr);                                         \
 236        SHIFT_PERCPU_PTR((ptr), per_cpu_offset((cpu)));                 \
 237})
 238
 239#define raw_cpu_ptr(ptr)                                                \
 240({                                                                      \
 241        __verify_pcpu_ptr(ptr);                                         \
 242        arch_raw_cpu_ptr(ptr);                                          \
 243})
 244
 245#ifdef CONFIG_DEBUG_PREEMPT
 246#define this_cpu_ptr(ptr)                                               \
 247({                                                                      \
 248        __verify_pcpu_ptr(ptr);                                         \
 249        SHIFT_PERCPU_PTR(ptr, my_cpu_offset);                           \
 250})
 251#else
 252#define this_cpu_ptr(ptr) raw_cpu_ptr(ptr)
 253#endif

 

include/asm-generic/percpu.h

1、per_cpu_offset

使用 __per_cpu_offset 数组,得到 指定cpu 的offset

21 行 - per_cpu_offset  ,以 cpu 为 index, 取 __per_cpu_offset 数组的值

  11/*
  12 * per_cpu_offset() is the offset that has to be added to a
  13 * percpu variable to get to the instance for a certain processor.
  14 *
  15 * Most arches use the __per_cpu_offset array for those offsets but
  16 * some arches have their own ways of determining the offset (x86_64, s390).
  17 */
  18#ifndef __per_cpu_offset
  19extern unsigned long __per_cpu_offset[NR_CPUS];
  20
  21#define per_cpu_offset(x) (__per_cpu_offset[x])
  22#endif

 my_cpu_offset

30 ~ 37  ,利用 raw_smp_processor_id 得到 当前运行  cpu id [0,1,2,……] ,然后使用 per_cpu_offset 得到 当前cpu 变量区域 的offset .

arch_raw_cpu_ptr(ptr)

43 ~ 45  利用  my_cpu_offset 得到 当前 cpu 的offset,然后使用  SHIFT_PERCPU_PTR (ptr, offset)对 ptr 进行偏移。

  24/*
  25 * Determine the offset for the currently active processor.
  26 * An arch may define __my_cpu_offset to provide a more effective
  27 * means of obtaining the offset to the per cpu variables of the
  28 * current processor.
  29 */
  30#ifndef __my_cpu_offset
  31#define __my_cpu_offset per_cpu_offset(raw_smp_processor_id())
  32#endif
  33#ifdef CONFIG_DEBUG_PREEMPT
  34#define my_cpu_offset per_cpu_offset(smp_processor_id())
  35#else
  36#define my_cpu_offset __my_cpu_offset
  37#endif
  38
  39/*
  40 * Arch may define arch_raw_cpu_ptr() to provide more efficient address
  41 * translations for raw_cpu_ptr().
  42 */
  43#ifndef arch_raw_cpu_ptr
  44#define arch_raw_cpu_ptr(ptr) SHIFT_PERCPU_PTR(ptr, __my_cpu_offset)
  45#endif

 注意:asm-generic/percpu.h 之所以是 generic 的,就是可以被 特定 arch 实现覆盖的。 30 ~ 32 中,只有等 __my_cpu_offset 没有arch 实现时,采用 generic 的实现,arm64下面有自己的实现

__my_cpu_offset 在arm64下

30 行的  #ifndef __my_cpu_offset , 在arm64 下面这个宏被定义 。

arch/arm64/include/asm/percpu.h

14 ~ 20 行,set_my_cpu_offset 是,直接写入到 CPU 的 tpidr_el1 寄存器里面。

31 ~ 44 ,__my_cpu_offset 读取时,直接从 cpu 的 tpidr_el1 寄存器里面读出。

tpidr_el1 寄存器信息,见 https://www.cnblogs.com/zhangzhiwei122/p/16051676.html 最下面

https://developer.arm.com/documentation/ddi0595/2021-12/AArch64-Registers/TPIDR-EL1--EL1-Software-Thread-ID-Register?lang=en

  14static inline void set_my_cpu_offset(unsigned long off)
  15{
  16        asm volatile(ALTERNATIVE("msr tpidr_el1, %0",
  17                                 "msr tpidr_el2, %0",
  18                                 ARM64_HAS_VIRT_HOST_EXTN)
  19                        :: "r" (off) : "memory");
  20}
  
  30
  31static inline unsigned long __kern_my_cpu_offset(void)
  32{
  33        unsigned long off;
  34
  35        /*
  36         * We want to allow caching the value, so avoid using volatile and
  37         * instead use a fake stack read to hazard against barrier().
  38         */
  39        asm(ALTERNATIVE("mrs %0, tpidr_el1",
  40                        "mrs %0, tpidr_el2",
  41                        ARM64_HAS_VIRT_HOST_EXTN)
  42                : "=r" (off) :
  43                "Q" (*(const unsigned long *)current_stack_pointer));
  44
  45        return off;
  46}
  47
  48#ifdef __KVM_NVHE_HYPERVISOR__
  49#define __my_cpu_offset __hyp_my_cpu_offset()
  50#else
  51#define __my_cpu_offset __kern_my_cpu_offset()
  52#endif

 

posted @ 2022-03-25 12:28  张志伟122  阅读(731)  评论(0编辑  收藏  举报