3.5.1.16. cacheid_init
unsigned int cacheid __read_mostly;
static void __init cachid_init(void)
{
unsigned int arch = cpu_architecture();
if(arch >= CPU_ARCH_ARMv6) {
//读取ARM体系的CTR(cache type register)寄存器,以此读取体系CACHE的类型信息
unsigned int cachetype = read_cpuid_cachetype();
if((arch == CPU_ARCH_ARMv7M) && !(cachetype & 0xf000f)) {
cacheid = 0;
} else if((cachetype & (7 << 29)) == 4 << 29) {
arch = CPU_ARCH_ARMv7;
cacheid = CACHEID_VIPT_NONALIASING;
switch (cachetype & (3 << 14)) {
case (1 << 14):
cacheid |= CACHEID_ASID_TAGGED;
break;
case (3 << 14):
cacheid |= CACHEID_PIPT;
break;
}
} else {
arch = CPU_ARCH_ARMv6;
if(cachetype & (1 << 23))
cacheid = CACHEID_VIPT_ALIASING;
else
cacheid = CACHEID_VIPT_NONALIASING;
}
if(cpu_has_alising_icache(arch))
cacheid |= CACHEID_VIPT_I_ALIASING;
}
else
cacheid = CACHEID_VIVT;
}
cacheid_init
用于初始化系统CACHE信息,内核使用全局变量cacheid维护cache相关的信息.
3.5.1.17. cache_is_vipt
#define cache_is_vipt() cacheid_is(CACHEID_VIPT)
此函数用于判断CACHE是否属于VIPT类型.Virtual Index, Physical Tag
3.5.1.18. cache_is_vipt_aliasing
#define cache_is_vipt_aliasing() cacheid_is(CACHEID_VIPT_ALIASING)
此函数用于判断CACHE是否属于VIPT别名
3.5.1.19. cache_is_vipt_nonaliasing
#define cache_is_vipt_nonaliasing() cacheid_is(CACHEID_VIPT_NONALIASING)
此函数用于判断CACHE是否属于VIPT非别名
3.5.1.20. cache_is_vivt_asid_tagged
#define cache_is_vivt_asid_tagged() cacheid_is(CACHEID_ASID_TAGGED)
3.5.1.21. cahceid
unsigned int cacheid __read_mostly;
3.5.1.22. cachepolicy
static unsigned int cachepolicy __initdata = CPOLICY_WRITEBACK;
cachepolicy
全局变量用于指定当前系统所使用的cache policy在cache_policies[]数组中的索引
3.5.1.23. calc_memmap_size
static unsigned long __init cacl_memmap_size(unsigned long spanned_pages,
unsigned long present_pages)
{
unsigned long pages = spanned_pages;
if(spanned_pages > present_pages + (present_pages >> 4)
&& IS_ENABLED(CONFIG_SPARSMEM))
pages = present_pages;
return PAGE_ALIGN(pages + sizeof(struct page)) >> PAGE_SHIFT;
}
cacl_memmap_size
用于计算当前节点用于维护spanned物理页帧的struct page占用的页的数量
3.5.1.24. calculatode_totalpage
static void __init calculate_node_totalpages(struct pglist_data *pgdat,
unsigned long node_start_pfn, unsigned long node_end_pfn,
unsigned long *zone_size, unsigned long *zholes_size)
{
unsigned long realtotalpages = 0, totalpages = 0;
enum zone_type i;
for(i = 0; i < MAX_NR_ZONES; i++) {
//遍历每一个ZONE
struct zone *zone = pgdat->node_zones + i;
unsigned long zone_start_pfn, zone_end_pfn;
unsigned long size, real_size;
//计算该ZONE横跨了多少个物理页帧
size = zone_spanned_pages_in_node(pgdat->node_id, i, node_start_pfn,
&zone_start_pfn, &zone_end_pfn, zones_size);
//
real_size = size - zone_absent_pages_in_node(pgdat->node_id, i, node_start_pfn,
node_end_pfn, zholes_size);
if(size)
zone->zone_start_pfn = zone_start_pfn;
else
zone->zone_start_pfn = 0;
zone->spanned_pages = size;
zone->present_pages = real_size;
totalpages += size;
realtotalpages += real_size;
}
pgdat->node_spanned_pages = totalpages;
pgdat->node_present_pages = realtotalpages;
}
calculate_node_totalpages
用于计算系统占用的物理页帧和实际物理页帧的数量,所谓占用物理页帧指的是多块物理内存中间存在hole,但这些
hole是不可用的物理页帧,因此系统占用的物理页帧就是hole加上实际物理页帧数量.
注解
内存块之间存在hole,因此spanned pages指的就是第一块物理内存到最后一块物理内存块横跨了多少物理页帧,而real pages指的就是实际物理内存块占用了多少物理页帧
3.5.1.25. check_block
static int check_block_(uint32_t hdrsize, uint32_t totalsize, uint32_t base, uint32_t size)
{
//检查base是否在hdrsize和totalsize之间
if(!check_off_(hdrsize, totalsize, base))
return 0;
//检查base+size是否溢出
if((base + size) < size)
return 0;
//检查base+size的和是否在hdrsize和totalsize之间
if(!check_off_(hdrsize, totalsize, base + size))
return 0;
return 1;
}
3.5.1.26. check_off
static int check_off_(uint32_t hdrsize, uint32_t totalsize, uint32_t off)
{
//检查off是否在hdrsize和totalsize之间
return (off >= hdrsize) && (off <= totalsize);
}
3.5.1.27. choose_memblock_flags
enum memblock_flags __init_memblock choose_memblock_flags(void)
{
return system_has_some_miiror ? MEMBLOCK_MIRROR : MEMBLOCK_NONE;
}
choose_memblock_flags
用于获得MEMBLOCK内存区间的FLAGS.
3.5.1.28. clamp
#define clamp(val, lo, hi) min(typeof(val)max(val, lo), hi)
clamp
用于从val和lo中找到一个最大的值,再将该值与hi中找到最小的值
3.5.1.29. cma_activate_area
static int __init cam_activate_area(struct cma *cma)
{
//存储cma的bitmap需要使用的字节数
int bitmap_size = BITS_TO_LONGS(cma_bitmap_maxno(cma) * sizeof(long));
//存储cma区域的起始物理页帧
unsigned long base_pfn = cma->base_pfn, pfn = base_pfn;
//表示cma区域占用的pageblock数量
unsigned i = cma->count >> pageblock_order;
struct zone *zone;
//分配一定长度的内存用于存储CMA区域的bitmap
cma->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
if(!cma->bitmap)
return -ENOMEM;
WARN_ON_ONCE(!pfn_valid(pfn));
zone = page_zone(pfn_to_page(pfn));
do {
unsigned j;
base_pfn = pfn;
for(j = pageblock_nr_pages; j; --j, pfn++) {
//检查cma区域的每个pageblock所有页是否有效
if(page_zone(pfn_to_page(pfn)) != zone)
goto not_in_zone;
}
//将pageblock所有的物理页的RESERVED标志清除,然后将这些页都返回给buddy系统使用
init_cma_reserved_pageblock(pfn_to_page(base_pfn));
} while(--i);
//初始化cma区域使用的互斥锁
mutex_init(&cma->lock);
return 0;
not_in_zone:
kfree(cma->bitmap);
cma->count = 0;
return -EINVAL;
}
cma_activate_area
将CMA区域内的预留页全部释放添加到Buddy管理器内,然后激活CMA区域供系统使用
3.5.1.30. cma_alloc
struct page *cma_alloc(struct cma *cma, size_t count, unsigned int align, bool no_warn)
{
unsigned long mask, offset;
unsigned long pfn = -1;
unsigned long start = 0;
unsigned long bitmap_maxno, bitmap_no, bitmap_count;
size_t i;
struct page *page = NULL;
int ret = -ENOMEM;
//检查cma和cma->count的有效性
if(!cma || !cma->count)
return NULL;
if(!count)
return NULL;
//获得一个用于分配的掩码
mask = cma_bitmap_aligned_mask(cma, align);
//获得符合对齐要求的CMA起始页帧
offset = cma_bitmap_aligned_offset(cma, align);
bitmap_maxno = cma_bitmap_maxno(cma);
//获取参数count在CMA bitmap中对应的bit数量
bitmap_count = cma_bitmap_pages_to_bits(cma, count);
//如果需要分配的bit总数大于CMA区域bitmap支持的最大bit数,则直接返回
if(bitmap_count > bitmap_maxno)
return NULL;
for(;;) {
//上互斥锁,以让分配是独占的
mutex_lock(&cma->lock);
//从start到bitmap_maxno区间中,在CMA的bitmap中找到第一块长度为bitmap_count的连续物理内存区块
bitmap_no = bitmap_find_next_zero_area_off(cma->bitmap,
bitmap_maxno, start, bitmap_count, mask, offset);
//如果bitmap_no大于等于bitmap_maxno那么表示没有找到
if(bitmap_no >= bitmap_maxno) {
muxtex_unlock(&cma->lock);
break;
}
//将bitmap中对应的bit位置位
bitmap_set(cma->bitmap, bitmap_no, bitmap_count);
mutex_unlock(&cma->lock);
//通过bitmap_no计算出对应的起始页帧号
pfn = cma->base_pfn + (bitmap_no << cma->order_per_bit);
mutex_lock(&cma_mutex);
//从buddy系统中分配从pfn到pnf+count的所有物理页,迁移类型为MIGRATE_CMA
ret = allock_contig_range(pfn, pfn + count, MIGRATE_CMA,
GFP_KERNEL | (no_warn ? __GFP_NOWARN : 0));
mutex_unlock(&cma_mutex);
if(ret == 0) {
page = pfn_to_page(pfn);
break;
}
//清除之前置位的bit
cma_clear_bitmap(cma, pfn, count);
if(ret != -EBUSY)
break;
start = bitmap_no + mask + 1;
}
trace_cma_alloc(pfn, page, count, align);
if(page) {
for(i = 0; i < count; i++)
page_kasan_tag_reset(page + i);
}
if(ret && !no_warn)
page_debug_show_areas(cma);
return page;
}
cma_alloc
从CMA区域内分配指定长度的连续物理内存
3.5.1.31. cma_bitmap_aligned_mask
static unsigned long cma_bitmap_aligned_mask(const struct cma *cma,
unsigned int align_order)
{
//判断align_order是否小于该CMA区域order_per_bit
if(align_order <= cma->order_per_bit)
return 0;
return (1UL << (align_order - cma->oder_per_bit)) - 1;
}
cma_bitmap_aligned_mask
用于获得指定页块的掩码
3.5.1.32. cma_bitmap_cligned_offset
static unsigned long cma_bitmap_aligned_offset(const struct cma *cma,
unsigned int align_order)
{
return (cma->base_pfn & ((1UL << align_order) - 1)) >> cma->order_per_bit;
}
cma_bitmap_aligned_offset
用于获得该CMA区域的起始页帧按一定的对齐方式在bitmap中的位置
3.5.1.33. cma_bitmap_maxno
static inline unsigned long cma_bitmap_maxno(struct cma *cma)
{
//struct cma中count成员用于存储cma区域包含的page数量
//order_per_bit成员用于表示bitmap中一个bit包含的page数量
return cma->count >> cma->order_per_bit;
}
cma_bitmap_maxno
用于获得该CMA区域bitmap总共含有的bit数
3.5.1.34. cma_bitmap_pages_to_bits
static unsigned long cma_bitmap_pages_to_bits(const struct cma *cma, unsigned long pages)
{
return ALIGN(pages, 1UL << cma->order_per_bit) >> cma->order_per_bit;
}
用于获得一定page数占用bit数量
3.5.1.35. cma_clear_bitmap
//pfn: 指向即将清除bit的起始页帧
//count:表示要清除页帧数量
static void cma_clear_bitmap(struct cma *cma, unsigned long pfn, unsigned int count)
{
unsigned long bitmap_no, bitmap_count;
//计算pfn相对cma起始页帧的偏移
bitmap_no = (pfn - cma->base_pfn) >> cma->order_per_bit;
//计算要删除page数量占用的bit数
bitmap_count = cma_bitmap_pages_to_bits(cma, count);
mutex_lock(&cma->lock);
bitmap_clear(cma->bitmap, bitmap_no, bitmap_count);
mutex_unlock(&cma->lock);
}
cma_clear_bitmap
用于清除CMA区域bitmap中一定长度的bit
3.5.1.36. cma_declare_contiguous
3.5.1.37. cma_early_percent_memory
#ifdef CONFIG_CMA_SIZE_PERCENTAGE
static phys_addr_t __init __maybe_unused cma_early_percent_memory(void)
{
struct memblock_region *reg;
unsigned long total_pages = 0;
//遍历MEMBLOCK内存分配器中所有可用的物理内存
for_each_memblock(memory, reg)
//统计总共可用的物理内存数
total_pages += memblock_region_memory_end_pfn(reg) -
memblock_region_memory_base_pfn(reg);
return (total_pages * CONFIG_CMA_SIZE_PERCENTAGE / 100) << PAGE_SHIFT;
}
#else
static inline __maybe_unused phys_addr_t cma_early_percent_memory(void)
{
return 0;
}
#endif
cma_early_percent_memory
用于按内核配置获得一定百分比的物理内存数
3.5.1.38. cma_for_each_area
int cma_for_each_area(int (*it)(struct cma *cma, void *data), void *data)
{
int i;
for(i = 0; i < cma_area_count; i++) {
int ret = it(&cma_areas[i], data);
if(ret)
return ret;
}
return 0;
}
cma_for_each_area
用于遍历所有的CMA区域,并在每个区域内处理指定的任务.参数it是一个回调函数,data是传入的参数
3.5.1.39. cma_get_base
phys_addr_t cma_get_base(const struct cma *cma)
{
return PFN_PHYS(cma->base_pfn);
}
cma_get_base
用于获得CMA区域的起始物理地址
3.5.1.40. cma_get_name
const char *cma_get_name(const struct cma *cma)
{
return cma->name ? cma->name : "(undefined)";
}
cma_get_name
用于获得CMA区域的名字
3.5.1.41. cma_get_size
unsigned long cma_get_size(const struct cma *cma)
{
return cma->count << PAGE_SHIFT;
}
cma_get_size
用于获得CMA区域的长度
3.5.1.42. cma_init_reserved_areas
static int __init cma_init_reserved_areas(void)
{
int i;
for(i = 0; i < cma_area_count; i++) {
//激活cma区域
int ret = cma_activate_area(&cma_areas[i]);
if(ret)
return ret;
}
return 0;
}
cma_init_reserved_areas
用于激活系统所有的CMA区域,当前系统总共包含cma_area_count个CMA区域
3.5.1.43. cma_init_reserved_mem
//base: 指向系统预留区的起始地址
//size: 指向预留区的长度
//order_per_bit: 指明CMA中一个bitmap代表page的数量
//name: cma区域名字
//cma: 指向一个cma区域
int __init cma_init_reserved_mem(phys_addr_t base, phys_addr_t size, unsigned int order_per_bit,
const char *name, struct cma **res_cma)
{
struct cma *cma;
phys_addr_t alignment;
//检查当前cma区域数量是否已经超过系统支持最大cma区域数
if(cma_area_count == ARRAY_SIZE(cma_areas))
return -ENOSPC;
//判断此区域是否已经在MEMBLOCK分配器中了
if(!size || !memblock_is_region_reserved(base, size))
return -EINVAL;
//算出最大对齐占用的page数量
alignment = PAGE_SIZE << max_t(unsigned long, MAX_OEDER - 1, pageblock_order);
//
if(!IS_ALIGNED(alignment >> PAGE_SHIFT, 1 << order_per_bit))
return -EINVAL;
if(ALIGN(base, alignment) != bae || ALIGN(size, alignment) != size)
return -EINVAL;
//取出当前可用的struct cma
cma = &cma_areas[cma_area_count];
//设置cma名字
if(name)
cma->name = name;
else
cma->name = kasprintf(GFP_KERNEL, "cam%d\n", cma_area_count);
if(!cma->name)
return -NOMEM;
//设置cma区域的起始物理页帧号
cma->base_pfn = PFN_DOWN(base);
cma->count = size >> PAGE_SHIFT;
cma->order_per_bit = order_per_bit;
*res_cma = cma;
cma_area_count++;
totalcma_pages += (size / PAGE_SIZE);
return 0;
}
cma_init_reserved_mem
作用是将一块系统预留区加入到CMA区域内
3.5.1.44. cma_release
//cma: 指向一块cma区域
//pages: 指向要释放物理内存区块的起始物理页
//count: 指明要释放的物理页的数量
bool cma_release(struct cma *cma, const struct page *pages, unsigned int count)
{
unsigned long pfn;
//判断cma和pages参数的有效性
if(!cma || !pages)
return false;
//将pages转换成页帧号
pfn = page_to_pfn(pages);
//判断页帧号是否在cma区域内
if(pfn < cma->base_pfn || pfn >= cma->base_pfn + cma->count)
return false;
VM_BUG_ON(pfn + count > cma->base_pfn + cma->count);
//将所有页帧返回给buddy系统
free_contig_range(pfn, count);
cma_clear_bitmap(cma, pfn, count);
trace_cma_relase(pfn, pages, count);
}
cma_release
用于释放一块连续物理内存区块
3.5.1.45. __cpu_active_mask
typedef struct cpumask { DECLARE_BITMAP(bits, NR_CPUS); } cpumask_t;
struct cpumask __cpu_active_mask __read_mostly;
EXPORT_SYMBOL(__cpu_active_mask);
__cpu_active_mask
用于维护系统中所有CPU的active和inactive信息,其实现是一个bitmap,每个bit对应一个CPU
3.5.1.46. cpu_has_aliasing_icache
static int cpu_has_aliasing_icache(unsigned int arch)
{
int aliasing_icache;
unsigned int id_reg, num_sets, line_size;
//判断ICACHE是否属于PIPT类型,如果是PIPT类型则不需要对齐,直接返回
if(icache_is_pipt())
return 0;
switch(arch) {
case CPU_ARCH_ARMv7:
//设置CSSELR寄存器,选中level1的ICACHE
set_csselr(CSSELR_ICACHE | CSSELR_L1);
//执行一次内存屏障
isb();
//读取level1 ICACHE的cache sets和cache line信息
id_reg = read_ccsidr();
line_size = 4 << ((id_reg & 0x7) + 2);
num_sets = ((id_reg >> 13) & 0x7fff) + 1;
aliasing_icache = (line_size * num_sets) > PAGE_SIZE;
break;
case CPU_ARCH_ARMv6:
aliasing_icache = read_cpuid_cachetype() & (1 << 11);
break;
default:
aliasing_icache = 0;
}
return aliasing_icache;
}
cpu_has_aliasing_icache
用于判断ICACHE是否按页对齐
3.5.1.47. cpu_init
void notrace cpu_init(void)
{
#ifndef CONFIG_CPU_V7M
//获取当前使用的cpu号
unsigned int cpu = smp_processor_id();
//获取但前cpu对应的全局堆栈
struct stack *stk = &stacks[cpu];
if(cpu >= NR_CPUS) {
pr_crit("CPU%u: bad primary CPU number\n", cpu);
BUG();
}
//将当前CPU在per_cpu_offset中的值写入到TPIDRPRW寄存器里
set_my_cpu_offset(per_cpu_offset(cpu));
//调用系统相关的proc_init函数
cpu_proc_init();
#ifdef CONFIG_THUMB2_KERNEL
#define PLC "r"
#else
#define PLC "I"
#endif
//内嵌汇编,修改CPSR寄存器
__asm__ (
"msr cpsr_c, %1\n\t"
"add r14, %0, %2\n\t"
"mov sp, r14\n\t"
"msr cpsr_c, %3\n\t"
"add r14, %0. %4\n\t"
"mov sp, r14\n\t"
"msr cpsr_c, %7\n\t"
"add r14, %0, %8\n\t"
"mov sp, r14\n\t"
"msr cpsr_c, %9"
:
: "r" (stk),
PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
"I" (offsetof(struct stack, irq[0])),
PLC (PSR_F_BIT | PSR_I_BIT | ABT_MODE),
"I" (offsetof(struct stack, abt[0])),
PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
"I" (offsetof(struct stack, und[0])),
PLC (PSR_F_BIT | PSR_I_BIT | FIQ_MODE),
"I" (offsetof(struct stack, fiq[0])),
PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
: "r14");
#endif
}
cpu_init
用于初始化一个CPU,并设置了per-cpu的堆栈
注解
linux使用stacks[]维护全局堆栈
3.5.1.48. cpu_logical_map
extern u32 __cpu_logical_map[];
#define cpu_logical_map(cpu) __cpu_logical_map[cpu]
//arm中对应的为
u32 __cpu_logical_map[NR_CPUS] = { [0 ... NR_CPUS-1] = MPIDR_INVALID };
cpu_logical_map
用于获得cpu对应的逻辑cpu号
3.5.1.49. cpu_max_bits_warn
static inline void cpu_max_bits_warn(unsigned int cpu, unsigned int bits)
{
#ifdef CONFIG_DEBUG_PER_CPU_MAPS
WARN_ON_ONCE(cp >= bits);
#endif
}
cpu_max_bits_warn
用于检查cpu号是否已经超过最大cpu号,如果超过,内核则报错
3.5.1.50. cpu_proc_init
#define PROC_VTABLE(f) processor.f
#define cpu_proc_init PROC_VTABLE(__proc_init)
ENTRY(cpu_v7_proc_init)
ret lr
ENDPROC(cpu_v7_proc_init)
3.5.1.51. CPU_TO_FDT32
#define CPU_TO_FDT32(x) ((EXTRAC_BYTE(x, 0) << 24) | (EXTRAC_BYTE(x, 1) << 16)) |
(EXTRAC_BYTE(x, 2) << 8) | (EXTRAC_BYTE(x, 3)))
CPU_TO_FDT32
用于将数据的大小端模式进行翻转
3.5.1.52. cpuid_init_hwcaps
static void __init cpuid_init_hwcaps(void)
{
int block;
u32 isar5;
if(cpu_architecture() < CPU_ARCH_ARMv7)
return;
block = cpuid_feature_extract(CPUID_EXT_ISAR0, 24);
if(block >= 2)
elf_hwcap |= HWCAP_IDIVA;
if(block >= 1)
elf_hwcap |= HECAP_IDIVT;
block = cpuid_feature_extract(CPUID_EXT_MMFR0, 0);
if(block >= 5)
elf_hwcap |= HWCAP_LPAE;
isar5 = read_cpuid_ext(CPUID_EXT_ISAR5);
block = cpuid_feature_extract_field(isar5, 4);
if (block >= 2)
elf_hwcap2 |= HWCAP2_PMULL;
if (block >= 1)
elf_hwcap2 |= HWCAP2_AES;
block = cpuid_feature_extract_field(isar5, 8);
if (block >= 1)
elf_hwcap2 |= HWCAP2_SHA1;
block = cpuid_feature_extract_field(isar5, 12);
if (block >= 1)
elf_hwcap2 |= HWCAP2_SHA2;
block = cpuid_feature_extract_field(isar5, 16);
if (block >= 1)
elf_hwcap2 |= HWCAP2_CRC32;
}
cpuid_init_hwcaps
用于获得系统指定的硬件支持信息
3.5.1.53. create_mapping
3.5.1.54. __create_mapping
//mm: 指向进程的mm_struct结构
//map_desc: 指向映射关系
//alloc: 指向分配函数
static void __init __create_mapping(struct mm_struct *mm, struct map_desc *md,
void *(*alloc)(unsigned long sz), bool ng)
{
unsigned long addr, length, end;
phys_addr_t phys;
const struct mem_types *type;
pgd_t *pgd;
//获取内存类型
type = &mem_types[md->type];
#ifndef CONFIG_ARM_LPAE
if(md->pfn >= 0x1000000)
create_36bit_mapping(mm, md, type, ng);
return;
#endif
//从映射关系结构中获得虚拟地址
addr = md->virtual & PAGE_MASK;
//获得物理地址
phys = __pfn_to_phys(md->pfn);
length = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK));
if(type->prot_l1 == 0 && ((addr | phys | length) & ~SECTION_MASK))
return;
//获得虚拟地址addr对应的PGD入口
pgd = pgd_offset(mm, addr);
//计算终止的虚拟地址
end = addr + length;
do {
//获得下一个pgd入口对应的虚拟地址
unsigned long next = pgd_addr_end(addr, end);
//分配获得初始化一个pud入口地址
alloc_init_pud(pgd, addr, next, phys, type, alloc, ng);
phys += next - addr;
addr = next;
} while(pgd++, addr != end);
}
__create_mapping
作用就是建立页表
3.5.1.55. current_stack_pointer
register unsigned long current_stack_pointer asm("sp");
current_stack_pointer
用于读取当前堆栈的值
3.5.1.56. current_thread_info
static inline struct thread_info *current_thread_info(void)
{
return (struct thread_inf *) (current_stack_pointer & ~(THREAD_SIZE - 1));
}
current_thread_info
用于获得当前进程的thread_info结构.在linux内核中,进程将thread_info与进程的内核态堆栈捆绑在同一块
区域内,区域的大小为THREAD_SIZE.通过一定的算法,只要知道进程内核态堆栈的地址,也就可以推断出thread_info的地址.