地址空间标识符ASID

地址空间标识符ASID处理器给进程分配 ASID 时 如果 ASID 分配完了 那么把全局 ASID 加 1 重新从 1 开始分配 ASID 针对每个处理器 使用该处理器的 reserved asids 保存该处理器正在执行的进程的 ASID 并且把该处理器的 ac

大家好,欢迎来到IT知识分享网。

目录

目的

以ASID为8位长度叙述

引入版本号好处

当进程调度时


目的

        为了减少在进程切换时清空页表缓存的需要,ARM64处理器的页表缓存使用非全局位区分内核和进程的页表项。

  • nG位为0 表示内核页表项;
  • 使用地址空间标识符(Address Space Identifier,ASID)区分不同进程的页表项。
  • ASID的长度可以是8位、16位;
  • 寄存器TTBR0_EL1(转换表基准寄存器0)或TTBR1_EL1(转换表基准寄存器1)都可以用来存放ASID寄存器TCR_EL1的A1位决定使用哪个寄存器存放当前进程的ASID,通常使用TTBR0_EL1寄存器TTBR0_EL1的位[63:48]存放当前ASID,[47:1]存放当前进程的页全局目录物理地址(如果是8位,[63:56]是保留位;)

以ASID为8位长度叙述

ASID只有256个值,其中0是保留值;进程数量超过255,两个ASID可能相同,内核引入版本号,解决。具体步骤如下:

1)每个进程有64位软件ASID,低8位存放硬件ASID,高56位存放ASID版本号;

2)64位全局变量asid_generation的高56位保存全局ASID版本号;

3)当进程被调度时,比较进程ASID版本号和全局ASID版本号,如果版本号相同,那么直接使用上次分配的硬件ASID,否则重新给进程分配硬件ASID。

  • 如果存在空闲的硬件ASID,那么选择一个分配给进程;
  • 如果没有空闲的硬件ASID,把全局ASID版本号加1,重新从1开始分配硬件ASIDA.因为刚分配的ASID可能和某个进程的硬件ASID相同,只是ASID版本号不同,页表缓存可能包含了这个进程的页表项,所以必须把所有处理器的页表缓存清空。

引入版本号好处

        避免每次进程切换都需要清空页表缓存,只需要在硬件ASID回滚时,把处理器的页表缓存清空。

内存描述符成员id存放内核给进程分配的ASID

typedef struct{ atomic64_t id; }mm_context_t;

//asid_bits保存ASID长度 static u32 asid_bits; static DEFINE_RAW_SPINLOCK(cpu_asid_lock); //asid_generation高56位保存全局ASID版本号 static atomic64_t asid_generation; //位图asid_map记录哪些ASID被分配 static unsigned long *asid_map; //active_asids 保存处理器正在使用的ASID static DEFINE_PER_CPU(atomic64_t, active_asids); //存放预留的ASID,用来在全局变量ASID加1时保存处理器正在执行的进程的ASID static DEFINE_PER_CPU(u64, reserved_asids); static cpumask_t tlb_flush_pending;

处理器给进程分配ASID时,如果ASID分配完了,那么把全局ASID加1,重新从1开始分配ASID,针对每个处理器,使用该处理器的reserved_asids保存该处理器正在执行的进程的ASID,并且把该处理器的active_asids设置0。active_asids为0 具有特殊意义,说明全局ASID版本号变化,ASID从255回到1

当全局ASID加1时,每个处理器都需要清空页表缓存,位图tlb_flush_pending保存需要清空页表缓存的处理器集合。

当进程调度时

void check_and_switch_context(struct mm_struct *mm, struct task_struct *tsk) { unsigned long flags; unsigned int cpu = smp_processor_id(); u64 asid; if (unlikely(mm->context.vmalloc_seq != init_mm.context.vmalloc_seq)) __check_vmalloc_seq(mm); /* * We cannot update the pgd and the ASID atomicly with classic * MMU, so switch exclusively to global mappings to avoid * speculative page table walking with the wrong TTBR. */ cpu_set_reserved_ttbr0(); asid = atomic64_read(&mm->context.id); if (!((asid ^ atomic64_read(&asid_generation)) >> ASID_BITS) && atomic64_xchg(&per_cpu(active_asids, cpu), asid)) goto switch_mm_fastpath; //禁止硬件中断并申请自旋锁 raw_spin_lock_irqsave(&cpu_asid_lock, flags); /* Check that our ASID belongs to the current generation. */ //重新比较版本号,如果不同重新分配 asid = atomic64_read(&mm->context.id); if ((asid ^ atomic64_read(&asid_generation)) >> ASID_BITS) { asid = new_context(mm, cpu); atomic64_set(&mm->context.id, asid); } //tlb_flush_pending 当前处理器对应的位被设置,那么把当前处理器的页表缓存清空 //把全局ASID版本号加1时,需要把所有处理器的页表缓存清空,在位图tlb_flush_pending中把所有处理器对应的位设置 if (cpumask_test_and_clear_cpu(cpu, &tlb_flush_pending)) { local_flush_bp_all(); local_flush_tlb_all(); } //把单当前处理器的active_asids设置为ASID atomic64_set(&per_cpu(active_asids, cpu), asid); cpumask_set_cpu(cpu, mm_cpumask(mm)); //释放自旋锁并开启硬中断 raw_spin_unlock_irqrestore(&cpu_asid_lock, flags); switch_mm_fastpath://快速路径 cpu_switch_mm(mm->pgd, mm); }

1、如果进程的ASID与全局ASID版本号相同,那么调用函数atomic64_xchg 把当前处理器的active_asid设置成进程的ASID,并且返回active_asids的旧值。

2、如果active_asidsde 旧值不是0,那么执行快速路径

3、如果旧值是0,说明其他处理器在分配ASID时把全局ASID版本号加1了,那么执行慢速路径。

4、调用函数cpu_switch_mm设置寄存器TTBR0_EL1


免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/138329.html

(0)
上一篇 2025-06-13 19:00
下一篇 2025-06-13 19:10

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信