Chinaunix首页 | 论坛 | 博客
  • 博客访问: 403837
  • 博文数量: 53
  • 博客积分: 1910
  • 博客等级: 中尉
  • 技术积分: 1130
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-10 14:56
文章分类

全部博文(53)

文章存档

2013年(1)

2012年(17)

2011年(33)

2010年(2)

分类: LINUX

2010-05-13 18:39:03

(转载请注名出处)
/*******************************************************************************/
         native linux syscall:
         dump 一个 arm eabi toolchain 的libc 找到epoll create syscall 代码
               libc.a => ../bin/arm-linux-objdump -D libc.a  >> ~/samsung/libc_dump.txt
               典型的eabi syscall ,以r7 做scno (syscall number)
               epoll_create 的 r7 = 250
               使用软中断指令,执行syscall      
               swi 0     /*__NR_epoll_create */
                
               swi 后,lr(R14) 放的是 swi x 下面那条指令地址 ( 这个lr 可以用来获得ABI syscall 时的number
               通过取lr-4 就是swi x (机器码为0xefxxxxxx) 来完成)
                 
                  
              
----------------------------------------------------------------------------------
        因为在trap init 已经把向量进行初始化,如下    
               trap_init (trap.c)
/*
  * Copy the vectors, stubs and kuser helpers (in entry-armv.S)
  * into the vector page, mapped at 0xffff0000, and ensure these
  * are visible to the instruction stream.
  */
 memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
 memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
 memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);
----------------------------------------------------------------------------------
       当执行swi 后 ,指令跳到     ldr pc, .LCvswi + stubs_offset   
              .globl __vectors_start  (arch\arm\kernel\entry-armv.S)
     __vectors_start:
                swi SYS_ERROR0
         b vector_und + stubs_offset
            ldr pc, .LCvswi + stubs_offset          (swi xxx goto this !!!)
              b vector_pabt + stubs_offset
            b vector_dabt + stubs_offset
            b vector_addrexcptn + stubs_offset
             b vector_irq + stubs_offset
            b vector_fiq + stubs_offset
-----------------------------------------------------------------------------------
       执行到  vector_swi ,或因为是 EABI ,所以根据r7(scno) 的syscall number 去调用
              .LCvswi:
 .word vector_swi
              ENTRY(vector_swi)  (entry-common.S)
              adr tbl, sys_call_table  @ load syscall table pointer (calls.S)
              ......
              cmp scno, #NR_syscalls  @ check upper syscall limit
              adr lr, ret_fast_syscall  @ return address
              ldrcc pc, [tbl, scno, lsl #2]  @ call sys_* routine
              ......
              bcs arm_syscall
----------------------------------------------------------------------------------
              asmlinkage int arm_syscall(int no, struct pt_regs *regs)  (trap.c)
      native linux syscall 基本就是这样一个过程     
 
/******************************************************************************/
 
 
      那么对于oklinux 来讲:
   首先 一个epoll_create EABI syscall  ,同样是先设置r7=250 ,然后执行swi 0 ,产生一软中断异常
   可以在l4 kernel arch目录下找到traps.spp ,其中
        BEGIN_PROC_TRAPS(arm_high_vector)
        b       arm_reset_exception
        ...
        b       arm_swi_syscall
        ...
        END_PROC_TRAPS(arm_high_vector)
  这部分代码也会在l4 kernel init 时讲它copy 到地址高端0xFFFF0000
  swi 后执行到  b       arm_swi_syscall

 
  继续跟arm_swi_syscall:
       BEGIN_PROC_TRAPS(arm_swi_syscall)
       str     lr,     [sp, #-8]!       /* 将syscall swi  0 这条指令下面那条指令地址 保存下来*/
       stmdb   sp,     {sp, lr}^        /*  保留 user mode 下的lr ,sp */ 
       nop
       ldr     lr,    [sp, #-8]!        /* Get user's SP [syscall no] */ /* 其实这句话对 linux syscall 不成立*/
                                                                         /* 他只是对l4 kernel 的syscall 来讲可以根据sp 可以获得 syscall no,可以看ipc.spp了解 */
       str     r12,    [sp, #SC_SP]     /* Save r12 to SP (user SP was in r12) - for sys_ipc */
       /* Check whether this is an IPC syscall */
       /*  l4 kerne ipc syscall  */
       cmp     lr,     #(0xffffff00 + SYSCALL_ipc)    /* 对这个条件linux syscall 必定不满足,那么就跳到 check_other_syscalls */
        /* Not IPC syscall? */
       bne     check_other_syscalls
  check_other_syscalls :
 LABEL(check_other_syscalls)
       bcc     arm_swi_exception
  arm_swi_exception: 
      这段代码比较复杂,但主要是l4 kernel 发 excption ipc
      其中  orr     tag,    tag,    #EXCEPT_IPC_SYS_TAG_LO          /* SETUP_E1 */ ,将tag 设置13 ,供后面判断用
 
 在syscall_loop.c 中 有个函数syscall_loop:
   
    该函数是个循环,上来设置accptor ,notify bit 后就跳到 return_to_user
    因为是第1次,那么reply_user_ipc  不成立,那么就跑到L4_Wait (&from);等着
    当发生syscall 时,冲arm_swi_exception 发出的excetion ipc 被 l4_wait 接收到
    判断from.raw == curinfo->user_handle.raw  条件成立, 这句没看懂 ,为什么该等式成立就是syscall ???
    成立并且 curinfo->tag = tag; 
    L4_MsgStore (curinfo->tag, &curinfo->regs.msg); 取出ipc 的msg ,store到 curinfo->regs.msg
    然后回到循环开头,根据 L4_Label(curinfo->tag)判断 如果tag 表示 L4_ARCH_EXCEPTION: 
     0xfffb,  l4 manul  P107 A-13.1 Exception Protocol 中有关于exception 的描述
   
    L4_ARCH_IS_SYSCALL(curinfo->tag) ,就是判断前面arm_swi_exception EXCEPT_IPC_SYS_TAG_LO 是否满足
    l4_arch_lookup_syscall(include\asm-l4\arm\syscalls_inline.h) => 查 l4_arm_abi_syscalls 表
     返回     return l4_arm_abi_syscalls[call].sys_num;   
    查表是这样的: 查l4_arm_abi_syscalls 数组 返回   sys_num,
    然后 l4_syscall_table 数组 以 sys_num 为下标 找到该函数 调用
    比如 epoll_create:
       经过两次转换 : __NR_epoll_create =>   __L4_sys_epoll_create =>  sys_epoll_create  !!!!!!
                                              (l4_arm_abi_syscalls表)  (l4_syscall_table表)

 最后关于syscall_loop 什么时候运行,
     在oklinux kernel 部分主要两部分,
    首先init 进程run_init_process(init\main.c)
     call 到kernel_execve(arch\l4\kernel\glue.c)=> execve => execve=>
            => __execve =>  (arch\l4\kernel\process.c)
     在_execve 中sys_execve 执行后 会call 到syscall_loop
    还有就是kernel\kmod.c (kernel module)
     
  
   在oklinux user mode 部分
   copy thread 时 new_process_handler,也会call 到syscall_loop
   
   这样就是在当前的task  后面跑 syscall_loop, 在syscall_loop ,wait 时
  task 继续执行,task 执行过程中 发生syscall_loop 就切到syscall_loop ,
  判断后 进行syscall
 
 
  最后补充一个细节问题:
    在 l4_arch_lookup_syscall 里有句
   call = ARM_syscall(regs) & 0x00ffffff;   是用来获得syscall num 的
   根据eabi 里规定 syscall num 是放在r7 里的
   ARM_syscall  在ptrace.h中定义为 #define ARM_syscall(regs) ARM_r7(regs)
   然后#define ARM_r7(regs)  L4_MsgWord(®s->msg, 3)
   开始没明白为什么l4 -x2 ,和实际代码中r7 都是放在mr4的
   为什么现在要到msg,3 中去取,(以为是mr3)
  
   而在:
   l4 -x2 manual 中关于Virtual Registers [ARM] 里
   ipc 时 mr0-mr4 分别对应 r3 -r7 , 其中r7对应mr4
  
   另外traps.spp 中ipc_complete_switch_to_noex 中 可以看到 ,完成ipc 后也是将
   mr4(r7) copy 到当前 utcb 的mr4的位置 ,代码如下:
        cmp     r10,    #2
        strge   mr2,    [r12, #8]       // MR2
        strgt   mr3,    [r12, #12]      // MR3 
        cmp     r10,    #4
        strge   mr4,    [r12, #16]      // MR4  //其中mr4 在前面有 #define mr4   r7 ,16 offset 对应到mr[4]
        strgt   mr5,    [r12, #20]      // MR5
 
   为什么这里 取 r7 要通过L4_MsgWord(®s->msg, 3)
   今天突然想起msg 中msg[0] 是放tag的,真正的msg 是从msg[1]开始的
   所以L4_MsgWord 去取msg 3 其实对应到 utcb mr4
  
   然后打开L4_MsgWord
   L4_INLINE L4_Word_t
   L4_MsgWord(L4_Msg_t *msg, L4_Word_t u)
  {
    return msg->msg[u + 1];
  }
 
  u =3 时 其实是取 msg[4] ,这样就可以解释得通了
 
关于上面syscall_loop 运行时间的修正:
   总是在main_thread  (kernel thread) 中运行,
    1. 所以每次 new_process_handler  (stub),kernel thread 切换kernel function 时调用
    2. kernel_execve 当在kernel 启动时创建init时
   这样oklinux kernel 所有执行路径都有syscall_loop 挂在后面
 
 
阅读(1866) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~