Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2290287
  • 博文数量: 218
  • 博客积分: 5767
  • 博客等级: 大校
  • 技术积分: 5883
  • 用 户 组: 普通用户
  • 注册时间: 2008-03-01 14:44
文章存档

2012年(53)

2011年(131)

2009年(1)

2008年(33)

分类: LINUX

2011-09-05 16:17:40


void __init early_trap_init(void)
{
    unsigned long vectors = CONFIG_VECTORS_BASE;
    //CONFIG_VECTORS_BASE在autoconf.h中定义(该文件自动成生),值为0xffff0000,
    extern char __stubs_start[], __stubs_end[];
    extern char __vectors_start[], __vectors_end[];
    extern char __kuser_helper_start[], __kuser_helper_end[];
    int kuser_sz = __kuser_helper_end - __kuser_helper_start;

    /*
     * 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.
     */
   /*  异常向量表拷贝到 0x0000_0000(或 0xFFFF_0000) ,
       异常处理程序的 stub 拷贝到 0x0000_0200(或 0xFFFF_0200) */
    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);

    /*
     * Do processor specific fixups for the kuser helpers
     */
    kuser_get_tls_init(vectors);

    /*
     * Copy signal return handlers into the vector page, and
     * set sigreturn to be a pointer to these.
     */
    /*  拷贝信号处理函数 */
    memcpy((void *)KERN_SIGRETURN_CODE, sigreturn_codes,
           sizeof(sigreturn_codes));
    memcpy((void *)KERN_RESTART_CODE, syscall_restart_code,
           sizeof(syscall_restart_code));
    /*  刷新 Cache,修改异常向量表占据的页面的访问权限*/
    flush_icache_range(vectors, vectors + PAGE_SIZE);
    modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
}
这个函数把定义在 arch/arm/kernel/entry-armv.S 中的异常向量表和异常处理程序的 stub 进行
重定位:异常向量表拷贝到 0xFFFF_0000,异常向量处理程序的 stub 拷贝到 0xFFFF_0200。
然后调用 modify_domain()修改了异常向量表所占据的页面的访问权限,这使得用户态无法
访问该页,只有核心态才可以访问。
 
arm处理器发生异常时总会跳转到 0xFFFF_0000(设为“高端向量配置”时)处的异常向量
表,因此进行这个重定位工作。

异常向量表,在文件arch/arm/kernel/entry-armv.S 中
static void __init kuser_get_tls_init(unsigned long vectors)
{
    /*
     * vectors + 0xfe0 = __kuser_get_tls
     * vectors + 0xfe8 = hardware TLS instruction at 0xffff0fe8
     */
    if (tls_emu || has_tls_reg)
        memcpy((void *)vectors + 0xfe0, (void *)vectors + 0xfe8, 4);
}

arch/arm/include/asm/tls.h
#ifdef CONFIG_TLS_REG_EMUL
#define tls_emu        1
#define has_tls_reg        1
#define set_tls        set_tls_none
#elif __LINUX_ARM_ARCH__ >= 7 ||                    \
    (__LINUX_ARM_ARCH__ == 6 && defined(CONFIG_CPU_32v6K))
#define tls_emu        0
#define has_tls_reg        1
#define set_tls        set_tls_v6k
#elif __LINUX_ARM_ARCH__ == 6
#define tls_emu        0
#define has_tls_reg        (elf_hwcap & HWCAP_TLS)
#define set_tls        set_tls_v6
#else
#define tls_emu        0
#define has_tls_reg        0
#define set_tls        set_tls_software
#endif
arch/arm/kernel/signal.h
#define KERN_SIGRETURN_CODE    (CONFIG_VECTORS_BASE + 0x00000500)
#define KERN_RESTART_CODE    (KERN_SIGRETURN_CODE + sizeof(sigreturn_codes))

extern const unsigned long sigreturn_codes[7];
extern const unsigned long syscall_restart_code[2];

arch/arm/include/asm/unistd.h
#define __NR_OABI_SYSCALL_BASE    0x900000

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

/*
 * This file contains the system call numbers.
 */

#define __NR_restart_syscall        (__NR_SYSCALL_BASE+  0)
#define __NR_exit            (__NR_SYSCALL_BASE+  1)
#define __NR_fork            (__NR_SYSCALL_BASE+  2)
#define __NR_read            (__NR_SYSCALL_BASE+  3)
#define __NR_write            (__NR_SYSCALL_BASE+  4)
#define __NR_open            (__NR_SYSCALL_BASE+  5)
#define __NR_close            (__NR_SYSCALL_BASE+  6)
...................................................................................................................................
#define __NR_rt_sigreturn        (__NR_SYSCALL_BASE+173)
#define __NR_rt_sigaction        (__NR_SYSCALL_BASE+174)
#define __NR_rt_sigprocmask        (__NR_SYSCALL_BASE+175)
...................................................................................................................................
#define __NR_syscall            (__NR_SYSCALL_BASE+113) /* syscall to call a syscall! */
#define __NR_wait4            (__NR_SYSCALL_BASE+114)
#define __NR_swapoff            (__NR_SYSCALL_BASE+115)
#define __NR_sysinfo            (__NR_SYSCALL_BASE+116)
#define __NR_ipc            (__NR_SYSCALL_BASE+117)
#define __NR_fsync            (__NR_SYSCALL_BASE+118)
#define __NR_sigreturn            (__NR_SYSCALL_BASE+119)
...................................................................................................................................
arch/arm/kernel/signal.c
/*
 * For ARM syscalls, we encode the syscall number into the instruction.
 */
#define SWI_SYS_SIGRETURN    (0xef000000|(__NR_sigreturn)|(__NR_OABI_SYSCALL_BASE))
#define SWI_SYS_RT_SIGRETURN    (0xef000000|(__NR_rt_sigreturn)|(__NR_OABI_SYSCALL_BASE))
#define SWI_SYS_RESTART        (0xef000000|__NR_restart_syscall|__NR_OABI_SYSCALL_BASE)

/*
 * With EABI, the syscall number has to be loaded into r7.
 */
#define MOV_R7_NR_SIGRETURN    (0xe3a07000 | (__NR_sigreturn - __NR_SYSCALL_BASE))
#define MOV_R7_NR_RT_SIGRETURN    (0xe3a07000 | (__NR_rt_sigreturn - __NR_SYSCALL_BASE))

/*
 * For Thumb syscalls, we pass the syscall number via r7.  We therefore
 * need two 16-bit instructions.
 */
#define SWI_THUMB_SIGRETURN    (0xdf00 << 16 | 0x2700 | (__NR_sigreturn - __NR_SYSCALL_BASE))
#define SWI_THUMB_RT_SIGRETURN    (0xdf00 << 16 | 0x2700 | (__NR_rt_sigreturn - __NR_SYSCALL_BASE))

const unsigned long sigreturn_codes[7] = {
    MOV_R7_NR_SIGRETURN,    SWI_SYS_SIGRETURN,    SWI_THUMB_SIGRETURN,
    MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN,
};

/*
 * Either we support OABI only, or we have EABI with the OABI
 * compat layer enabled.  In the later case we don't know if
 * user space is EABI or not, and if not we must not clobber r7.
 * Always using the OABI syscall solves that issue and works for
 * all those cases.
 */
const unsigned long syscall_restart_code[2] = {
    SWI_SYS_RESTART,    /* swi    __NR_restart_syscall */
    0xe49df004,        /* ldr    pc, [sp], #4 */
};
earl_tarp_init 函数被用来设置各种异常的处理向量,包括中断向量。所谓“向量”,就是一些被安放在固定位置的代码,当发生异常时,CPU会自动执行这些固定位置上的指令。ARM架构的CPU的异常向量基址可以是0x00000000,也可以是 0xffff0000,它由CONFIG_VECTORS_BASE决定,CONFIG_VECTORS_BASE在arch/arm/Kconfig中配置如下:
 182 config VECTORS_BASE
 183         hex
 184         default 0xffff0000 if MMU || CPU_HIGH_VECTOR
 185         default DRAM_BASE if REMAP_VECTORS_TO_RAM
 186         default 0x00000000
 187         help

arch/arm/include/asm/domain.h
#define DOMAIN_NOACCESS    0
#define DOMAIN_CLIENT    1
#define DOMAIN_MANAGER    3

#define domain_val(dom,type)    ((type) << (2*(dom)))

#ifndef __ASSEMBLY__

#ifdef CONFIG_MMU
#define set_domain(x)                    \
    do {                        \
    __asm__ __volatile__(                \
    "mcr    p15, 0, %0, c3, c0    @ set domain"    \
      : : "r" (x));                    \
    isb();                        \
    } while (0)

#define modify_domain(dom,type)                    \
    do {                            \
    struct thread_info *thread = current_thread_info();    \
    unsigned int domain = thread->cpu_domain;        \
    domain &= ~domain_val(dom, DOMAIN_MANAGER);        \
    thread->cpu_domain = domain | domain_val(dom, type);    \
    set_domain(thread->cpu_domain);                \
    } while (0)

#else
#define set_domain(x)        do { } while (0)
#define modify_domain(dom,type)    do { } while (0)
#endif

arch/arm/include/asm/thread_info.h
struct thread_info {
    unsigned long        flags;        /* low level flags */
    int            preempt_count;    /* 0 => preemptable, <0 => bug */
    mm_segment_t        addr_limit;    /* address limit */
    struct task_struct    *task;        /* main task structure */
    struct exec_domain    *exec_domain;    /* execution domain */
    __u32            cpu;        /* cpu */
    __u32            cpu_domain;    /* cpu domain */
    struct cpu_context_save    cpu_context;    /* cpu context */
    __u32            syscall;    /* syscall number */
    __u8            used_cp[16];    /* thread used copro */
    unsigned long        tp_value;
    struct crunch_state    crunchstate;
    union fp_state        fpstate __attribute__((aligned(8)));
    union vfp_state        vfpstate;
#ifdef CONFIG_ARM_THUMBEE
    unsigned long        thumbee_state;    /* ThumbEE Handler Base register */
#endif
    struct restart_block    restart_block;
};

static inline struct thread_info *current_thread_info(void) __attribute_const__;
static inline struct thread_info *current_thread_info(void)
{
    register unsigned long sp asm ("sp");
    return (struct thread_info *)(sp & ~(THREAD_SIZE - 1)); //THREAD_SIZE = 8192
}

阅读(1285) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~