AKever

导航

TQ2440 自制系统调用ORW

TQ2440 自制系统调用ORW

======================

注意: 这个开发板linux系统是 linux-2.6.22.4

======================

原理图:

 

 

========================

内核简单说明

1. 在Source Insight 搜索 "vector_swi",可跟踪原理

右击-> Lookup Reference

2. 可查看到 linux-2.6.30.4\arch\arm\kernel\entry-common.S 有内容"vector_swi"

ENTRY(vector_swi)
   // 红色地带1 : 保留现场
    sub    sp, sp, #S_FRAME_SIZE
    stmia    sp, {r0 - r12}            @ Calling r0 - r12
    add    r8, sp, #S_PC
    stmdb    r8, {sp, lr}^            @ Calling sp, lr
    mrs    r8, spsr            @ called from non-FIQ mode, so ok.
    str    lr, [sp, #S_PC]            @ Save calling PC
    str    r8, [sp, #S_PSR]        @ Save CPSR
    str    r0, [sp, #S_OLD_R0]        @ Save OLD_R0
    zero_fp

    /*
     * Get the system call number.
     */

#if defined(CONFIG_OABI_COMPAT)

    /*
     * If we have CONFIG_OABI_COMPAT then we need to look at the swi
     * value to determine if it is an EABI or an old ABI call.
     */
#ifdef CONFIG_ARM_THUMB
    tst    r8, #PSR_T_BIT
    movne    r10, #0                @ no thumb OABI emulation
    ldreq    r10, [lr, #-4]            @ get SWI instruction
#else
   /** 红色地带2 
      * 1. lr寄存器-4等于发生异常的那条指令的地址(机器码) SWI地址(SWI instruction)
      * 2. 检查 SWI的机器码是不是SWI的指令,开头是否为0x0f000000( 2440手册),如果是则是SWI指令
      */
    ldr    r10, [lr, #-4]            @ get SWI instruction
    A710(    and    ip, r10, #0x0f000000        @ check for SWI        )
    A710(    teq    ip, #0x0f000000                        )
    A710(    bne    .Larm710bug                        )
#endif

#elif defined(CONFIG_AEABI)

    /*
     * Pure EABI user space always put syscall number into scno (r7).
     */
  A710(    ldr    ip, [lr, #-4]            @ get SWI instruction    )
  A710(    and    ip, ip, #0x0f000000        @ check for SWI        )
  A710(    teq    ip, #0x0f000000                        )
  A710(    bne    .Larm710bug                        )

#elif defined(CONFIG_ARM_THUMB)
... ...

#ifdef CONFIG_ALIGNMENT_TRAP
    ldr    ip, __cr_alignment
    ldr    ip, [ip]
    mcr    p15, 0, ip, c1, c0    @ update control register
#endif
    enable_irq
    /* 红色地带3
     * 2. 系统调用函数的数组(syscall)
     */
    get_thread_info tsk
    adr    tbl, sys_call_table    @ load syscall table pointer
    ldr    ip, [tsk, #TI_FLAGS]    @ check for syscall tracing
... ...

#if defined(CONFIG_OABI_COMPAT)
    /*
     * If the swi argument is zero, this is an EABI call and we do     nothing.
     *
     * If this is an old ABI call, get the syscall number into scno and
     * get the old ABI syscall table address.
     */
    bics    r10, r10, #0xff000000
    eorne    scno, r10, #__NR_OABI_SYSCALL_BASE
  ldrne    tbl, =sys_oabi_call_table
#elif !defined(CONFIG_AEABI)

  /* 红色地带4
   * 1.2. 清楚高8位,留下后面24位=val=0x900001, 有个异或过程(eor)
   */
    bic    scno, scno, #0xff000000    @ mask off SWI op-code
    eor    scno, scno, #__NR_SYSCALL_BASE    @ check OS number
#endif

    stmdb   sp!, {r4, r5}           @ push fifth and sixth args
    tst ip, #_TIF_SYSCALL_TRACE     @ are we tracing syscalls?
    bne __sys_trace

    /* 红色地带 5
     * 3. 基地址+scno(val), 左移2位
     */
    cmp scno, #NR_syscalls      @ check upper syscall limit
    adr lr, ret_fast_syscall        @ return address
    ldrcc   pc, [tbl, scno, lsl #2]     @ call sys_* routine

... ...
ENDPROC(vector_swi)
ps: 上面代码 CONFIG_OABI_COMPAT; CONFIG_AEABI部分可查找内核 .config配置文件,如果没有,即是内核用不到的代码段,上面代码注意 红色地带 代码

====================================
内核简单说明
1.Source Insight 搜索"sys_write",得到下面3个文件
linux-2.6.22.4\arch\arm\kernel\calls.S
linux-2.6.2.4\fs\read_write.c
linux-2.6.22.4\include\linux\syscalls.h
1.calls.S文件
/* 350 */    CALL(sys_timerfd)
        CALL(sys_eventfd)
        CALL(sys_hello)
#ifndef syscalls_counted
.equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
2.read_write.c
    return ret;
}

asmlinkage void sys_hello(const char __user * buf, int count)
{
    char ker_buf[100];
    if (buf)
    {
        copy_from_user(ker_buf, buf, (count < 100) ? count : 100);
        ker_buf[99] = '\0';
        printk("sys_hello: %s\n", ker_buf);
    }
}

asmlinkage ssize_t sys_pread64(unsigned int fd, char __user *buf,
3.syscalls.h
asmlinkage ssize_t sys_write(unsigned int fd, const char __user *buf,
                size_t count);

asmlinkage void sys_hello(const char __user * buf, int count);

asmlinkage ssize_t sys_writev(unsigned long fd,

 以上红色字体为内核文件新添加部分

4. 测试程序 --\test_system_call.c

#include <errno.h>
#include <unistd.h>
//#include <sysdep.h>

//#if defined(__thumb__) || defined(__ARM_EABI__)
//#define __NR_SYSCALL_BASE    0
//#else
#define __NR_SYSCALL_BASE    0x900000
//#endif

void hello(char *buf, int count)
{
    /* swi */

    asm ("mov r0, %0\n"   /* save the argment in r0 */
         "mov r1, %1\n"   /* save the argment in r0 */
         "swi %2\n"   /* do the system call */
         :    
         : "r"(buf), "r"(count), "i" (__NR_SYSCALL_BASE + 352)
         : "r0", "r1");
}

int main(int argc, char **argv)
{
    printf("in app, call hello\n");
    hello("www.100ask.net", 15);
    return 0;
}

5.  以上,将前面3个修改后的文件更新到内核并编译, 同时编译测试程序并拷贝大开发板

# make
# arm-linux-gcc -o test_system_call test_system_call.c
# cp test_system_call /opt/share

6. 如果用未修改的内核运行测试程序,则是下面情况

7. 用修改后的内核,如下

 

============================

指令地址反推

下图1 - 2440文档文件 SOFTWARE INTERRUPT(SWI)

下图2 - 反汇编文件

由上面两图可以看出:

图2 黑色部分的 ef900160    swi    0x00900160
e: 无条件执行
f : 有图1的(27-24)bit都为1, 即为f, 表示 swi指令
900160: 即是后面的val为0x00900160

 

============================

--------------- The end !! 

 

 
 

 




 

posted on 2016-10-27 17:43  AKever  阅读(210)  评论(0)    收藏  举报