ARM64 Linux各种栈-1-分类

在 ARM64 Linux 内核中,栈的管理分为多种类型,每种栈都有其特定的用途和实现机制。以下是详细的分类说明:


一、用户栈(User Stack)

1. 简介

用途:用户态进程执行时的栈空间。
特点:位于用户空间虚拟地址的高地址区域(向下增长)
通过 mmap 动态分配,默认大小 8MB(可通过 ulimit -s 调整) //Arm64上应该不对..
分配方式:

arch_pick_mmap_layout(struct mm_struct *mm) { //mmap.c
    mm->mmap_base = TASK_UNMAPPED_BASE; // 0x0000_7fff_ffc0_0000
}


二、内核栈(Kernel Stack)

1. 简介

用途:进程在内核态执行时的私有栈(系统调用、异常处理)
特点:固定大小 16KB(THREAD_SIZE = 16384,定义于 arch/arm64/include/asm/thread_info.h)
包含 struct thread_info 元数据(位于栈底)

分配方式:

dup_task_struct(struct task_struct *tsk) { //fork.c
    stack = alloc_thread_stack_node(tsk, node); // 通过 vmalloc 分配
}


2. 调试

cat /sys/kernel/debug/kmemleak //查看内核栈使用量

"kernel stack overflow" //内核栈溢出在 arm64/kernel/traps.c 中有打印


三、中断栈(IRQ Stack)

1. 简介

用途:处理硬件中断的专用栈(避免内核栈溢出)
特点:每个 CPU 独占 32KB 中断栈(定义于 arch/arm64/include/asm/irq.h),支持嵌套中断处理(最多支持4级嵌套)

内存布局:
--------------------------------------------
栈类型 大小 地址范围示例
--------------------------------------------
Primary IRQ 32KB ffff8000_7fff_0000
Secondary 32KB ffff8000_7fff_8000
--------------------------------------------

切换逻辑(arch/arm64/kernel/entry.S):

kernel_ventry:
    msr sp_el0, x21        // 保存用户态SP
    ldr x21, [tsk, #TSK_STACK] // 加载内核栈
    msr sp_el1, x21       // 切换到内核栈


四、信号栈(Signal Stack)

1. 简介

用途:用户态信号处理函数的替代执行栈.
特点:通过 sigaltstack() 系统调用显式设置。默认禁用,启用后大小为 2MB(SIGSTKSZ = 2097152)
内核管理:

__setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs) { //signal.c arm64上没这个函数,是x86上的
    if (on_sig_stack(regs->sp)) // 检查是否在信号栈上
        altstack = current->sas_ss_sp;
}


五、异常栈(Exception Stack)

1. 简介

用途:处理系统异常(如缺页、指令异常)
特点:复用当前上下文的内核栈。通过 ESR_EL1 寄存器判断异常类型
处理流程:
A[异常触发] --> B[读取ESR_EL1]
B --> C{异常类型?}
C -->|Data Abort| D[do_mem_abort]
C -->|Instruction Abort| E[do_el0_ia]
C -->|其他| F[panic]


六、特殊场景栈-启动栈(Boot Stack)

1. 简介

用途:内核启动早期的临时栈。
特点:定义于链接脚本(arch/arm64/kernel/vmlinux.lds.S),大小4KB,仅用于初始化阶段。

__initdata_begin = .;
. = ALIGN(4096);
.boot.stack : { *(.boot.stack) } //启动栈段


七、特殊场景栈-调试栈(Debug Stack)

1. 简介

用途:KGDB/KDB 调试器专用栈
特点:独立于其他栈空间
通过 CONFIG_DEBUG_STACK 启用 //注: 这个配置宏在4.14和5.4上都不存在

void debug_stack_set(void) { //process.c
    set_percpu_stack(cpu, debug_stack); //切换调试栈
}


九、总结

1. 栈类型对比

-------------------------------------------------------------
栈类型    大小    归属        生命周期      关键宏定义
-------------------------------------------------------------
用户栈    动态    用户进程    进程生存期    TASK_SIZE
内核栈    16KB    进程        进程生存期    THREAD_SIZE
中断栈    32KB    Per-CPU     内核运行期    IRQ_STACK_SIZE
信号栈    2MB     用户进程    显式设置后    SIGSTKSZ
启动栈    4KB     全局        启动阶段      __initdata_begin
-------------------------------------------------------------

 

posted on 2025-05-20 17:25  Hello-World3  阅读(155)  评论(0)    收藏  举报

导航