start_kernel()
--void timer_tick(void)
//为Kernel提供的体系架构无关的、系统相关的时钟中断处理函数,通常会在体系架构相关的时钟中断处理函数内调用它。参考1;
{
profile_tick(CPU_PROFILING);//调用profile_tick()监管内核代码
do_leds();
write_seqlock(&xtime_lock);
do_timer(1);//在do_timer()中增加jiffies_64值和调用update_times()更新系统日期和时间
write_sequnlock(&xtime_lock);
#ifndef CONFIG_SMP
update_process_times(user_mode(get_irq_regs()));
#endif
}
----update_process_times(user_mode(get_irq_regs()))
+-----------------------------------------------------------------------------------------
#define user_mode(regs) \
(((regs)->ARM_cpsr & 0xf) == 0)
}
+++-----------------------------------------------------------------------------------------
DECLARE_PER_CPU(struct pt_regs *, __irq_regs);
//这个宏的最终目的是定义了一个结构体指针__irq_regs,这个指针指向pt_regs类型结构体,这个指针是每CPU类型的,
//即每个CPU拥有一个这样的指针并指向相应的pt_regs结构体;并且这个指针被保存在名为“data..percpu”的输入段中
++++-----------------------------------------------------------------------------------------
#define DECLARE_PER_CPU(type, name) \
DECLARE_PER_CPU_SECTION(type, name, "")
//DECLARE_PER_CPU(struct pt_regs *, __irq_regs);被展开为
//===========> DECLARE_PER_CPU_SECTION(struct pt_regs *, __irq_regs, "")
+++++-----------------------------------------------------------------------------------------
#define DECLARE_PER_CPU_SECTION(type, name, sec) \
extern __PCPU_ATTRS(sec) __typeof__(type) name
//传入的sec为空,DECLARE_PER_CPU(struct pt_regs *, __irq_regs);被展开为
//===========>extern __PCPU_ATTRS(sec) __typeof__(struct pt_regs *) __irq_regs
++++++-----------------------------------------------------------------------------------------
#define __PCPU_ATTRS(sec) \
__percpu __attribute__((section(PER_CPU_BASE_SECTION sec))) \
PER_CPU_ATTRIBUTES
//参考gcc的__attribute__编译属性
//DECLARE_PER_CPU(struct pt_regs *, __irq_regs);被展开为
//============>extern __percpu __attribute__((section(PER_CPU_BASE_SECTION))) \
// PER_CPU_ATTRIBUTES __typeof__(struct pt_regs *) __irq_regs
+++++++-----------------------------------------------------------------------------------------
# define __percpu __attribute__((noderef, address_space(3)))
//参考下文说明
+++++++-----------------------------------------------------------------------------------------
#define PER_CPU_BASE_SECTION ".data..percpu"
+++-----------------------------------------------------------------------------------------
最终DECLARE_PER_CPU(struct pt_regs *, __irq_regs);被展开为
=============>extern __percpu __attribute__((section(.data..percpu))) \
PER_CPU_ATTRIBUTES __typeof__(struct pt_regs *) __irq_regs
其中PER_CPU_ATTRIBUTES为空,可能是做内核扩展时用的,发现在3.0.9内核中只有定义
#ifdef HAVE_MODEL_SMALL_ATTRIBUTE
# define PER_CPU_ATTRIBUTES __attribute__((__model__ (__small__)))
#endif
=============>extern __percpu __attribute__((section(.data..percpu))) \
__typeof__(struct pt_regs *) __irq_regs
其中__percpu限制__irq_regs是每CPU地址空间变量,
__attribute__((section("section_name"))) 其作用是将作用的函数或数据放入指定名为"section_name"输入段。
所以这个宏的最终目的是定义了一个结构体指针__irq_regs,这个指针指向pt_regs类型结构体,这个指针是每CPU类型的,
即每个CPU拥有一个这样的指针并指向相应的pt_regs结构体;并且这个指针被保存在名为“data..percpu”的输入段中,
关于输入段和输入段的解释参考下面的链接
//详细参考gcc的__attribute__编译属性
+++-----------------------------------------------------------------------------------------
# define __this_cpu_read(pcp) __pcpu_size_call_return(__this_cpu_read_, (pcp))
++++-----------------------------------------------------------------------------------------
#define __pcpu_size_call_return(stem, variable) \
({ typeof(variable) pscr_ret__; \
__verify_pcpu_ptr(&(variable)); \
switch(sizeof(variable)) { \
case 1: pscr_ret__ = stem##1(variable);break; \
case 2: pscr_ret__ =stem##2(variable);break; \
case 4: pscr_ret__ = stem##4(variable);break; \
case 8: pscr_ret__ =stem##8(variable);break; \
default: \
__bad_size_call_parameter();break; \
} \
pscr_ret__; \
})
//展开__this_cpu_read(__irq_regs)
//=========>
({ typeof(__irq_regs) pscr_ret__; \
__verify_pcpu_ptr(&(__irq_regs)); \
switch(sizeof(__irq_regs)) { \
case 1: pscr_ret__ = __this_cpu_read_1(__irq_regs);break; \
case 2: pscr_ret__ = __this_cpu_read_2(__irq_regs);break; \
case 4: pscr_ret__ = __this_cpu_read_4(__irq_regs);break; \
case 8: pscr_ret__ = __this_cpu_read_8(__irq_regs);break; \
default: \
__bad_size_call_parameter();break; \
} \
pscr_ret__; \
})
//typeof是gcc对C语言的一个扩展保留字,用于声明变量类型,比方说:
//typeof(int *) p;
//声明p为一个int类型的指针
//typeof(*x) p;
//声明p为x所指向的类型
//pscr_ret__是variable类型
参考:http://topic.csdn.net/t/20030715/13/2030100.html
+++++-----------------------------------------------------------------------------------------
# define __this_cpu_read_n(pcp) (*__this_cpu_ptr(&(pcp)));
++++++-----------------------------------------------------------------------------------------
#define __this_cpu_ptr(ptr) SHIFT_PERCPU_PTR(ptr, __my_cpu_offset)
+++++++-----------------------------------------------------------------------------------------
#define __my_cpu_offset per_cpu_offset(raw_smp_processor_id())
++++++++-----------------------------------------------------------------------------------------
#ifndef __per_cpu_offset
extern unsigned long __per_cpu_offset[NR_CPUS]; //__per_cpu_offset一个无符号长整形数组,数组元素个数就是CPU个数,用来计算SMP每个CPU的数据段地址。
#define per_cpu_offset(x) (__per_cpu_offset[x])
#endif
在该函数中,为每个CPU分配一段专有数据区,并将.data.percpu中的数据拷
贝到其中,每个CPU各有一份。由于数据从__per_cpu_start处转移到各CPU自己的专有
数据区中了,因此存取其中的变量就不能再用原先的值了,比如存取
per_cpu__runqueues就不能再用per_cpu__runqueues了,需要做一个偏移量的调整,即
需要加上各CPU自己的专有数据区首地址相对于__per_cpu_start的偏移量。在这里也就
是__per_cpu_offset[i],其中CPU i的专有数据区相对于
__per_cpu_start的偏移量为__per_cpu_offset[i]。这样,就可以方便地计算专有数据
区中各变量的新地址,比如对于per_cpu_runqueues,其新地址即变成
per_cpu_runqueues+__per_cpu_offset[i]。
参考:多处理器体系中cpu私有数据的重定位(即per_cpu)
+++++++++-----------------------------------------------------------------------------------------
#define NR_CPUS CONFIG_NR_CPUS
//CONFIG_NR_CPUS是内核被配置支持的CPU个数,而实际设备的CPU个数是在系统启动过程当中去动态监测的。也就是说你配置系统支持32个CPU那么CONFIG_NR_CPUS就等于32,而num_online_cpus()则是当前设备激活可调度的CPU个数。
参考:关于NR_CPUS的疑惑
+++++++-----------------------------------------------------------------------------------------
#define SHIFT_PERCPU_PTR(__p, __offset) ({ \
__verify_pcpu_ptr((__p)); \
RELOC_HIDE((typeof(*(__p)) __kernel __force *)(__p), (__offset)); \
})
//最后展开为
({ \
__verify_pcpu_ptr((__p)); \
RELOC_HIDE((typeof(__irq_regs) __kernel __force *)(&(__irq_regs)), (__offset)); \
})
+++++-----------------------------------------------------------------------------------------
#define __verify_pcpu_ptr(ptr) do { \
const void __percpu *__vpp_verify = (typeof(ptr))NULL; \
(void)__vpp_verify; \
} while (0)
//这个宏用来验证(*ptr)是否是percpu类型指针
参考:设置每CPU环境
++++++-----------------------------------------------------------------------------------------
# define __percpu __attribute__((noderef, address_space(3)))
//一种修饰变量、类型或者函数的属性,用来修饰一个变量时,这个变量必须是非解除参考(no dereference)的,即这个变量地址必须是有效的,而且变量所在的地址空间类型必须是0~3,0:normal space内核空间;1:用户空间;2:设备地址映射空间;3:smp时每个cpu的地址空间;4:rcu地址空间。
参考:/include/linux/compiler.h
参考:sparse 工具的介绍及简单应用
参考:GNU C 扩展之__attribute__ 机制简介(转)
参考:# define __user __attribute__((noderef, address_space(1)))
参考:(ZT)GNU C 的 __attribute__ 机制
+++-----------------------------------------------------------------------------------------
struct pt_regs {
unsigned long uregs[18];
}
//存放CPU运行环境
++++-----------------------------------------------------------------------------------------
#define ARM_cpsr uregs[16]
#define ARM_pc uregs[15]
#define ARM_lr uregs[14]
#define ARM_sp uregs[13]
#define ARM_ip uregs[12]
#define ARM_fp uregs[11]
#define ARM_r10 uregs[10]
#define ARM_r9 uregs[9]
#define ARM_r8 uregs[8]
#define ARM_r7 uregs[7]
#define ARM_r6 uregs[6]
#define ARM_r5 uregs[5]
#define ARM_r4 uregs[4]
#define ARM_r3 uregs[3]
#define ARM_r2 uregs[2]
#define ARM_r1 uregs[1]
#define ARM_r0 uregs[0]
#define ARM_ORIG_r0 uregs[17]
参考:http://www.hackvip.com/article/sort0136/sort0186/Hackvip_184477.html
价值文档:linux 时钟处理机制