目录

  • 1、linux kernel中的中断irq的栈stack
    • (1)、arm32体系的irq的栈
    • (2)、arm64体系的irq的栈
  • 2、linux kernel中的栈stack
    • (1)、概念介绍:内核栈、内核空间进程栈、用户空间进程栈
    • (2)、内核栈 的实现
    • (2)、内核进程栈、用户进程栈 的实现
  • 3、总结

★★★ 友情链接 : 个人博客导读首页—点击此处 ★★★

1、linux kernel中的中断irq的栈stack

(1)、arm32体系的irq的栈

如下结构体描述了IRQ mode的栈,很小,只有12bytes。那是因为在linux kernel arm32体系中,真正的中断处理都在svc mode。
发生中断时,先进入irq mode,再进入svc mode完成大部分工作.

(kernel-4.14/arch/arm/kernel/setup.c)
struct stack {u32 irq[3];u32 abt[3];u32 und[3];u32 fiq[3];
} ____cacheline_aligned;#ifndef CONFIG_CPU_V7M
static struct stack stacks[NR_CPUS];
#endif}

如下描述了调用cpu_init来设置栈的过程,

(kernel-4.14/arch/arm/kernel/setup.c)
/** cpu_init - initialise one CPU.** cpu_init sets up the per-CPU stacks.*/
void notrace cpu_init(void)
{#ifndef CONFIG_CPU_V7Munsigned int cpu = smp_processor_id();struct stack *stk = &stacks[cpu];if (cpu >= NR_CPUS) {pr_crit("CPU%u: bad primary CPU number\n", cpu);BUG();}/** This only works on resume and secondary cores. For booting on the* boot cpu, smp_prepare_boot_cpu is called after percpu area setup.*/set_my_cpu_offset(per_cpu_offset(cpu));cpu_proc_init();/** Define the placement constraint for the inline asm directive below.* In Thumb-2, msr with an immediate value is not allowed.*/
#ifdef CONFIG_THUMB2_KERNEL
#define PLC "r"
#else
#define PLC "I"
#endif/** setup stacks for re-entrant exception handlers*/__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, %5\n\t""add   r14, %0, %6\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
}
(2)、arm64体系的irq的栈

先看下irq_handler的中断函数处理的过程

/** Interrupt handling.*/.macro  irq_handlerldr_l    x1, handle_arch_irq   -----将handle地址保存在x1mov    x0, spirq_stack_entry   ------ 切换栈,也就是将svc栈切换程irq栈. 在此之前,SP还是EL1_SP,在此函数中,将EL1_SP保存,再将IRQ栈的地址写入到SP寄存器blr x1     ——————执行中断处理函数irq_stack_exit   ------ 恢复EL1_SP(svc栈).endm
 .macro  irq_stack_entrymov  x19, sp         // preserve the original sp    //将svc mode下的栈地址(也就是EL1_SP)保存到x19/** Compare sp with the base of the task stack.* If the top ~(THREAD_SIZE - 1) bits match, we are on a task stack,* and should switch to the irq stack.*/
#ifdef CONFIG_THREAD_INFO_IN_TASKldr    x25, [tsk, TSK_STACK]eor    x25, x25, x19and    x25, x25, #~(THREAD_SIZE - 1)cbnz   x25, 9998f
#elseand    x25, x19, #~(THREAD_SIZE - 1)cmp    x25, tskb.ne    9998f
#endifadr_this_cpu x25, irq_stack, x26mov   x26, #IRQ_STACK_START_SP     //IRQ_STACK_START_SP这是irq mode的栈地址add  x26, x25, x26/* switch to the irq stack */mov   sp, x26     //将irq栈地址,写入到sp/** Add a dummy stack frame, this non-standard format is fixed up* by unwind_frame()*/stp     x29, x19, [sp, #-16]!mov    x29, sp9998:.endm
/** x19 should be preserved between irq_stack_entry and* irq_stack_exit.*/
.macro  irq_stack_exit
mov sp, x19     //x19保存着svc mode下的栈,也就是EL1_SP
.endm

那么irq的栈在哪设置的,多大呢?

在irq.h中定义了,irq栈的地址和size

#define IRQ_STACK_SIZE           THREAD_SIZE
#define IRQ_STACK_START_SP      THREAD_START_SP

thread_info.h中定义了大小

#define THREAD_SIZE      16384     //也就是irq栈的大小大概15k
#define THREAD_START_SP     (THREAD_SIZE - 16)    //也就是irq栈的首地址是从"0地址+15k"这个地方开始的

2、linux kernel中的栈stack

(1)、概念介绍:内核栈、内核空间进程栈、用户空间进程栈

用户空间进程栈、内核空间进程栈
对于一个应用程序而言,可以运行在用户空间,也可以通过系统调用进入内核空间。在用户空间,使用的是用户栈,也就是我们软件工程师编写用户空间程序的时候,保存局部变量的stack。陷入内核后,当然不能用用户栈了,这时候就需要使用到内核栈。所谓内核栈其实就是处于SVC mode时候使用的栈。

内核栈
在linux最开始启动的时候,系统只有一个进程(更准确的说是kernel thread),就是PID等于0的那个进程,叫做swapper进程(或者叫做idle进程)。

(2)、内核栈 的实现

内核栈是静态定义的,如下:

(kernel-4.14/arch/arm/include/asm/thread_info.h)#define init_thread_info   (init_thread_union.thread_info)#define init_stack       (init_thread_union.stack)
(kernel-4.14/include/linux/sched.h)
union thread_union {#ifndef CONFIG_THREAD_INFO_IN_TASKstruct thread_info thread_info;
#endifunsigned long stack[THREAD_SIZE/sizeof(long)];
};
(2)、内核进程栈、用户进程栈 的实现

Linux kernel在内核线程,或用户线程时都会分配一个page frame,具体代码如下:

(kernel-4.14/kernel/fork.c)
static struct task_struct *dup_task_struct(struct task_struct *orig, int node)
{......stack = alloc_thread_stack_node(tsk, node);if (!stack)goto free_tsk;
......
}

底部是struct thread_info数据结构,顶部(高地址)就是该进程的栈了。
当进程切换的时候,整个硬件和软件的上下文都会进行切换,这里就包括了svc mode的sp寄存器的值被切换到调度算法选定的新的进程的内核栈上来

3、总结

linux kernel arm32中定义的irq栈,其实就在一个static struct stack结构体变量中,大小为12bytes. irq_hander使用svc栈
linux kernel arm64中定义的irq栈,在内存"首地址"处,大小16k. irq_hander使用irq栈

linux kernel中的栈的介绍相关推荐

  1. linux kernel中的进程栈

    1.linux中的user mode的进程栈 在thread_info.h中,设置进程栈的大小为16k #define THREAD_SIZE 16384 #define THREAD_START_S ...

  2. Linux kernel 中模块化的平台驱动代码介绍

    介绍 在linux kernel中通过module_platform_driver来实现模块化平台驱动.大量的设备驱动程序都基于该种方式来实现,使用频次非常的高,在linux kernel 5.4.1 ...

  3. 内存访问顺序 - part2: 屏障及Linux kernel中屏障的使用

    文章目录 屏障是什么 Linux Kernel 中的屏障 Linux 屏障 API 一般的屏障 强制性屏障 SMP 条件屏障 隐式屏障 其他屏障 屏障的开销 未来的文章 本文翻译自 Memory ac ...

  4. Linux kernel中常见的宏整理

    0x00 宏的基本知识 // object-like #define 宏名 替换列表 换行符 //function-like #define 宏名 ([标识符列表]) 替换列表 换行符 替换列表和标识 ...

  5. Linux Kernel中AEP的现状和发展

    阿里 石洋内核月谈Yesterday AEP简介 AEP是Intel推出的一种新型的非易失Optane Memory设备,又被称作Apache Pass,所以一般习惯称作AEP.在这之前也有类似的设备 ...

  6. linux kernel中的cmdline的详细介绍

    cmdline 1.向linux kernel添加cmdline的四种方式 (1). 在dts中的bootargs中添加 (2).在BoardConfig中添加 (3).在uboot中添加 (4).在 ...

  7. Intel 计划在Linux kernel中引入 User Interrupts,效率是eventfd的10倍

    文章目录 未来Eventfd的替代品 User Interrupts 详细介绍什么是 User Interrupts 底层是如何工作的? 内核管理相关的数据结构 User IPI 应用接口 具体的例子 ...

  8. Linux Kernel Namespace实现: namespace API介绍

    1)前言 随着docker的出现, Linux container这种轻量级虚拟化方案越来越在产业里得到大规模的部署和应用. 而Namespace是Linux Container的基础, 了解name ...

  9. linux socket 中的backlog参数介绍

    问题 我们在linux上服务器起了一个serversocket,并且设置了backlog为2,并没有让serversock.accept() 在客户端上,我们一个一个的启动了连接socket, 当连接 ...

最新文章

  1. Go 分布式学习利器(9)-- Go语言 结构体的行为定义和实现
  2. 008 Android之Service
  3. mysql+firewall_mysql - ERROR 1123(HY000):无法初始化函数'mysql_firewall'; 插件初始化功能失败 - 堆栈内存溢出...
  4. 2020牛客国庆集训派对day4 Emergency Evacuation
  5. 第五章(1)Libgdx应用框架之生命周期
  6. 超融合带来的IT人员问题 企业是否看到?
  7. 操作系统-Windows操作系统的线程调度了解这些
  8. C++网络编程实例之多个客户端交互(多线程)
  9. 181007扇贝有道每日一句
  10. 补锅之校内测(桶哥系列)
  11. 2021-08-16
  12. 客户端SDK测试是什么?如何测?
  13. HDU-1253-胜利大逃亡
  14. OMP schedule子句的用法
  15. 进程资源和进程状态 TASK_RUNNING TASK_INTERRUPTIBLE TASK_UNINTERRUPTIBLE
  16. 2022年湖南省基金从业资格(证券投资基金基础知识)练习题及答案
  17. 头条:每6个中国人就有1个中招的!
  18. Python打开读文件:UnicodeDecodeError: ‘utf-8‘ codec can‘t decode byte 0xed in position 7014: invalid conti
  19. ASP.NET中的配置文件
  20. 从零开始搭建你的Web服务器

热门文章

  1. Python之fastparquet:fastparquet的简介、安装、使用方法之详细攻略
  2. 成功解决Exception: Graph file doesn't exist, path=F:\File_Python\Python_example\Human_Posture_Detection\
  3. Dataset之WebVision:WebVision数据集简介、下载、使用方法之详细攻略
  4. Matlab之mdl:风力发电系统仿真模型power_wind_dfig文件
  5. Tomcat 中文乱码 设置UTF-8编码 问题解决办法
  6. Linux下修改Swap分区大小
  7. 浅析Java.lang.ProcessBuilder类
  8. py文件控制台执行时,报错:引入的模块不存在
  9. Interview with BOA
  10. shell处理mysql增、删、改、查