Linux内核——用户堆栈和内核堆栈

2020-12-24  本文已影响0人  懒无趣

定义

每个进程都有用户堆栈和内核堆栈两个堆栈。进程在用户态时使用用户堆栈,陷入到内核态时便使用内核堆栈。

切换过程

  1. 用户进程X正常运行时,堆栈寄存器ESP指向的的用户堆栈地址。
  2. 当进程X调用某系统调用时(int 0x80),CPU会首先将用户堆栈地址保存到内核堆栈内(还有EIP,FLAG等寄存器),然后将ESP指针指向内核堆栈地址(还有将内态的EIP,FLAG等也一并存入相应的寄存器中,切换到用户态进程),这时便切换到来内核堆栈中。
  3. 当系统调用完成后,再将用户堆栈地址从内核堆栈中出栈存储ESP寄存器中,此时便切换到了用户堆栈。

中断过程

  1. X函数调用syscall_x (用户态)
  2. int 0x80 (保存部分寄存器,内核态)
  3. syscall_call (SAVE_ALL保存全部现场,内核态)
  4. iret后(用户态)

中断代码(简易)

ENTRY(system_call)
    RING0_INT_FRAME
    ASM_CLAC
    push_cfi %eax #保存系统调用号
    SAVE_ALL #保存现场⚠️
    GET_THREAD_INFO(%ebp)
    testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%epb) 
    jnz syscall_trace_entry
  cmpl $(nr_syscalls), %eax #检查传入到系统调用号是否合法
    jae syscall_badsys
  syscall_call:
    call *sys_call_table(,%eas,4) #执行相应的系统调用函数
    movl %eax,PT_EAX(%ebp) #保存结果到eax寄存器
  syscall_exit:
    testl $_TIF_ALLWORK_MASK,%ecx #检查是否有其他任务处理
    jne syscall_exit_work #进行进程调度
  restore_all
    TRACE_IRQS_IRET #恢复现场
  irq_return:
    INTERRUPT_RETURN #iret 将ESP,EIP,FLAG等寄存器恢复为用户态
上一篇下一篇

猜你喜欢

热点阅读