linux用户态、内核态的切换,SWI指令的理解





内核态的代码可以直接操作寄存器,把自己切向用户态,但是用户态想切换进入内核态,就需要费一番周折了

参考本博客的另一篇文章《STM32/ARM术语:处理者模式/线程模式、特权级/用户级

总体思路是这样的:

异常服务函数和中断服务函数都是运行在内核态的,在普通模式下,用户如果想干一些特权功能,通过修改寄存器直接进入内核态是不可能的,只能通过异常服务函数来做(一般是通过软中断异常),只要程序员们提前约定好协议,把想做的事情放到异常服务函数中就行了。

对于用户态的各种各样的特权操作代码(也即,各种系统调用system_call的代码),都放到异常服务函数中,在服务函数中做一个约定好的类似switch case的分支操作,用户就能选择执行这些system_call了,可能有些system_call还需要参数,如何选择system_call,又如何给system_call传参呢?有两种方法:

方法1:通过SWI xxx指令的操作数xxx来选择system_call,通过Rn或栈来传递实参。常见的SWI指令,高8位是操作码SWI,低24位是操作数xxx;

方法2:约定某个Rn例如R0来选择system_call,通过其他Rn或栈来传递实参,这样SWI后面的操作数就不起作用了;

下面是方法1的例子:


    
    
  1. ;--------------这段代码一般位于启动文件中,是厂家做好的-------------------
  2. ; 异常和中断向量表开始
  3. ; 0x00: 复位Reset异常
  4. b Reset
  5. ; 0x04: NMI_Handler异常
  6. b NMI_Handler
  7. ; 0x08: 软件中断异常,跳往软件中断处理函数HandleSWI
  8. b HandleSWI ;跳转到SWI异常服务函数中去
  9. … …
  10. ;设置堆、栈的起始地址、大小等,弱定义(WEAK)各种中断/异常服务函数等···略···我们常见的STM32的启动文件例如startup_stm32f10x_hd.s中可以阅读详细代码
  11. ;-------------------------------------------------------------------------------------------------
  12. ;异常服务函数是弱定义的,因此我们可以重自定义自己的异常服务函数
  13. HandleSWI
  14. STMFD SP!, {R0-R12, LR} ; 保存现场
  15. LDR R4, [LR, #-4] ; LR - 4 为指令" swi xxx" 的地址,xxx为低24位,我们根据xxx的值来选择不同的系统调用
  16. BIC R4, R4, #0xFF000000 ; 取得ARM指令swi xxx中xxx的值,放到R4中
  17. ;下面这段 switch代码应该用汇编来写,不过用C语言能更清楚的显示出原理。
  18. ;c语言转为汇编,可参考搜索以下关键字自行学习:汇编调用C语言函数。难点可能在于汇编代码要符合编译器的规范,
  19. ;例如:第几个实参应放入第几个通用寄存器、从第几个实参开始,要入栈、返回值的传递方法等
  20. ;当然,如果你自定义的系统调用不是用C而是直接用汇编子程序来写,那么不必考虑C语言的编译规范了,直接用B、Bx、call等指令跳转就是了
  21. switch(R4)
  22. {
  23. case 0: system_call_read(R0); break;
  24. case 1: system_call_write(R0,R1); break;
  25. case 2: system_call_peek(); break;
  26. case 3: system_call_3(R0); break;
  27. case 4: system_call_4(R1); break;
  28. case 5: system_call_5(); break;
  29. default:
  30. }
  31. LDMIA SP!, {R0-R12, PC}^ ;恢复现场 中断返回, ^表示将spsr的值复制到cpsr
  32. ;-------------------------------------------------------------------------------
  33. void system_call_read( int fn)
  34. {
  35. //按照编译器的编译规范,R0的内容就是第一个形参的内容,读fn就可以读到R0的内容
  36. //如果在发生系统调用前,汇编代码传的第一个实参参不是用的R0,那么该函数就不能用纯C语言来写了,只能用汇编或者在本函数内嵌入汇编,来取得实参
  37. }
  38. //···其余系统调用的代码··略··




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值