内核在没有开启MMU之前,内核堆栈的设置在arch/arm/boot/compressed/head.S中。

代码片段:

restart: adr r0, LC0                    /* 获取标号LC0的地址 */

ldmia r0, {r1, r2, r3, r6, r10, r11, r12} /*  读取LC0地址处的内容到寄存器列表中的寄存器中 */

ldr sp, [r0, #28]             /* 偏移28即跳过上面7个32位的偏移,把.L_user_stack_end标号地址加载到sp中,即设定堆栈, */

.align 2

.type LC0, #object

LC0:  .word LC0   @ r1

.word __bss_start  @ r2

.word _end   @ r3

.word _edata   @ r6

.word input_data_end - 4 @ r10 (inflated size location)

.word _got_start  @ r11

.word _got_end  @ ip

.word .L_user_stack_end @ sp          /* 会 */

.size LC0, . - LC0

.......

.align

.section ".stack", "aw", %nobits

.L_user_stack: .space 4096

.L_user_stack_end:

从这里看到启动的时候使用的堆栈大小为4KB,起始地址在.L_user_stack_end开始。

---------------------------------------------------------------------------------------------------------------------

开启MMU和cache之后:参考arch/arm/kernel/head-common.S

__mmap_switched:

adr r3, __mmap_switched_data

ldmia r3!, {r4, r5, r6, r7}             /* 读取__mmap_switched_data标号处的前4个32位数据,同时更新r3寄存器里的地址 */

cmp r4, r5    @ Copy data segment if needed

1: cmpne r5, r6

ldrne fp, [r4], #4

strne fp, [r5], #4

bne 1b

mov fp, #0    @ Clear BSS (and zero fp)

1: cmp r6, r7

strcc fp, [r6],#4

bcc 1b

ARM( ldmia r3, {r4, r5, r6, r7, sp})          /* 这里sp堆栈设定为 init_thread_union + THREAD_START_SP这个值 */

THUMB( ldmia r3, {r4, r5, r6, r7} )

THUMB( ldr sp, [r3, #16]  )

str r9, [r4]   @ Save processor ID

str r1, [r5]   @ Save machine type

str r2, [r6]   @ Save atags pointer

bic r4, r0, #CR_A   @ Clear 'A' bit

stmia r7, {r0, r4}   @ Save control register values

b start_kernel

ENDPROC(__mmap_switched)

.align 2

.type __mmap_switched_data, %object

__mmap_switched_data:

.long __data_loc   @ r4

.long _sdata    @ r5

.long __bss_start   @ r6

.long _end    @ r7

.long processor_id   @ r4

.long __machine_arch_type  @ r5

.long __atags_pointer   @ r6

.long cr_alignment   @ r7

.long init_thread_union + THREAD_START_SP @ sp

.size __mmap_switched_data, . - __mmap_switched_data

而init_thread_union定义在init_task.c中,是0号进程的,也是swapper进程,然后进入start_kernel执行。

进入start_kernel后,setup_arch-->setup_processor-->cpu_init这个函数里会设定irq,和abort,以及undefined异常的堆栈。

/*

* 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"

:

: "r" (stk),

PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),

"I" (offsetof(struct stack, irq[0])),                               /* 偏移0x0 */

PLC (PSR_F_BIT | PSR_I_BIT | ABT_MODE),

"I" (offsetof(struct stack, abt[0])),                               /* 偏移0xc */

PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),

"I" (offsetof(struct stack, und[0])),                             /* 偏移0x18 */

PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)

: "r14");

从这里看出,每个异常的堆栈只有12个字节大小,为什么呢?

我们接着看一下异常处理中对堆栈的使用情况,我们以irq为例分析一下。

异常处理代码在arch/arm/kernel/entry-armv.S中:

/*

* Interrupt dispatcher

*/

vector_stub irq, IRQ_MODE, 4

.long __irq_usr   @  0  (USR_26 / USR_32)

.long __irq_invalid   @  1  (FIQ_26 / FIQ_32)

.long __irq_invalid   @  2  (IRQ_26 / IRQ_32)

.long __irq_svc   @  3  (SVC_26 / SVC_32)

.long __irq_invalid   @  4

.long __irq_invalid   @  5

.long __irq_invalid   @  6

.long __irq_invalid   @  7

.long __irq_invalid   @  8

.long __irq_invalid   @  9

.long __irq_invalid   @  a

.long __irq_invalid   @  b

.long __irq_invalid   @  c

.long __irq_invalid   @  d

.long __irq_invalid   @  e

.long __irq_invalid   @  f

这里中断向量表的入口。

.macro vector_stub, name, mode, correction=0

.align 5

vector_\name:

.if \correction

sub lr, lr, #\correction

.endif

@

@ Save r0, lr_ (parent PC) and spsr_

@ (parent CPSR)

@

stmia sp, {r0, lr}  @ save r0, lr                /* 这里sp是sp_irq,这里使用了8个字节*/

mrs lr, spsr

str lr, [sp, #8]  @ save spsr                    /* 这里sp是sp_irq,这里使用了4个字节 */

@

@ Prepare for SVC32 mode.  IRQs remain disabled.

@

mrs r0, cpsr

eor r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)

msr spsr_cxsf, r0                /* 这里会重新进入内核的SVC_MODE模式 r0 ^(IRQ_MODE ^SVC_MODE)  会清除IRQ模式,并设置SVC模式 */

@

@ the branch table must immediately follow this code

@

and lr, lr, #0x0f

THUMB( adr r0, 1f   )

THUMB( ldr lr, [r0, lr, lsl #2] )

mov r0, sp                           /* 这里的sp是sp_svc */

ARM( ldr lr, [pc, lr, lsl #2] )

movs pc, lr   @ branch to handler in SVC mode

ENDPROC(vector_\name)

.align 2

@ handler addresses follow this label

1:

.endm

从上面的代码看出的确irq异常只需要使用12个字节的堆栈就可以了。

--------------------------------------------------------------------------------------------------

待续。。。

linux内核堆栈空间设置,linux内核堆栈设置过程相关推荐

  1. linux 显示系统空间不足,Linux系统boot空间不足解决办法

    产生boot空间不足的原因 因为linux内核一直在更新,更新后,旧的内核就不在使用,但旧的内核文件还在boot里面,占据着空间,更新几次过后boot分区就会被占满,显示boot磁盘空间不足. 解决办 ...

  2. linux 针对目录空间配额,linux磁盘配额quota

    Linux是一个多用户多任务的操作系统,在使用中可能会有几个人对服务器有操作,几个用户共同使用一个共享磁盘的情况,因为我们的硬盘是有限的,我们需要对用户的空间进行限制.这里使用磁盘配额,可以很方便的对 ...

  3. linux fdisk 磁盘空间使用率,linux查看磁盘剩余空间以及cpu使用情况

    1.查看CPU个数 cat /proc/cpuinfo | grep "physical id" | uniq top可以实时的查看cpu的使用情况 2.查看CPU核数 cat / ...

  4. Linux资源独立空间独立,LINUX网站空间 架设独立网店首选

    LINUX网站空间 架设独立网店首选 随着网购热潮的兴起,不少企业和SOHU 一族不再仅仅是局限于借助TAOBAO.EBAY等这些B2C.C2C 电子商务平台来销售自己的产品,而是着手架设真正属于自己 ...

  5. linux 增加交换空间,在linux上增加swap交换空间

    增加交换空间有两种方法: 严格的说,在系统安装完后只有一种方法可以增加swap,那就是本文的第二种方法, 至于第一种方法应该是安装系统时设置交换区. 1.使用分区: 在安装OS时划分出专门的交换分区, ...

  6. linux svn磁盘空间满,Linux svn checkout时候总报设备上没有空间

    但是df -h查看磁盘 [[email protected] data]# df -h 文件系统 容量  已用 可用 已用% 挂载点 /dev/sda3 19G  2.1G   16G  12% / ...

  7. 查询linux磁盘剩余空间脚本,linux磁盘空间报警脚本

    今天分享个简单的监控磁盘空间脚本.其实shell脚本写起来不难,关键是你有整个脚本的思路! 好.大概思路是这样: 我现在想要监控/分区的空间使用量,若超过10%的话,发送一个报警短信! 首先,我们要如 ...

  8. dev hdb2在linux中表示,linux查看磁盘空间

    营销树今天精心准备的是<linux查看磁盘空间>,下面是详解! linux如何查看磁盘剩余空间 [root@Linuxvar]#df-hl文件系统容量已用可用已用%挂载点/dev/hdb2 ...

  9. Linux查看磁盘空间命令(df、du)

    Linux查看磁盘空间命令 Linux 查看磁盘空间可以使用 df 和 du 命令. 1.df df以磁盘分区为单位查看文件系统,可以获取硬盘被占用了多少空间,目前还剩下多少空间等信息: df 使用d ...

  10. 《庖丁解牛Linux内核》笔记之:调用堆栈

    <庖丁解牛Linux内核>笔记之:调用堆栈 参考视频 基础知识介绍 在基础知识里讲过在使用cal调用函数时,会在之前的堆栈上创建一个新的堆栈,这里想讨论的就是如何实现调用函数时的参数传递. ...

最新文章

  1. eclipse 配置打开工作空间
  2. 卷积神经网络、比较MLPS和CNNS、滤波器、CNN各层的作用、在Pytorch可视化CNN
  3. 网口扫盲一:网卡初步认识
  4. linux简介ubuntu,Linux文件系统简介(基于Ubuntu)
  5. php里面的MySql
  6. 这项技术竟然一个字也不放过!
  7. 重置 Mac 上的 NVRAM 或 PRAM
  8. linux系列之常用运维命令整理笔录
  9. VASP 系列001. 高通量计算 Python 库 pymatgen 安装和一些使用(用 pymatgen 画 HSE 能带的细节和输出图片字体的简单调整)
  10. 【论文解读】MacBERT: 中文自然语言预训练模型
  11. 做QQ群霸屏的,我们盯上你了
  12. Visual Studio 鼠标放代码上出现英文提示如何改为中文?
  13. php redis 操作
  14. 软件工程第4次作业------石墨文档Android客户端案例分析
  15. 《数学之美》第一章读后感
  16. EDF Renewables和壳牌投资新泽西海上风电场
  17. TLP(Transmission Line Pulse)
  18. JSON实例简单教程
  19. 教您如何采集阿里飞猪各旅行专营店的主图及视频
  20. Deep Feedback Network for Recommendation用于推荐系统的深度反馈网络

热门文章

  1. CDH环境HDFS权限问题
  2. Python判断html的元素,python判断网页元素是否存在的方法
  3. 网络带宽和下载速度的换算方法
  4. 《中国云计算数据中心运营指南》
  5. [Perl] Data::Dumper模块的用法简介
  6. Metasploit扫描3389
  7. robots协议限制爬虫
  8. C# 如何生成CHM帮助文件
  9. 哪款 Linux 才是更好的 CentOS 替代品?
  10. aws----文件存储efs的全面了解