在Linux下系统调用是用软中断实现的,下面以一个简单的open例子简要分析一下应用层的open是如何调用到内核中的sys_open的。
t8.c
1: #include 2: #include 3: #include 4: #include 5: 6: int main(int argc, const char *argv[]) 7: { 8: int fd; 9: 10: fd = open(".", O_RDWR); 11: 12: close(fd); 13: return 0; 14: } 这里需要注意的是:open是C库提供的库函数,并不是系统调用,系统调用时在内核空间的,应用空间无法直接调用。在《Linux内核设计与实现》中说:要访问系统调用(在Linux中常称作syscall),通常通过C库中定义的函数调用来进行。 将t8.c进行静态编译,然后反汇编,看一下是如何调用open的? 1: arm-linux-gcc t8.c --static 2: arm-linux-objdump -D a.out >a.dis 下面我们截取a.dis中的一部分进行说明: 1: ...... 2: 00008228 3: 8228: e92d4800 push {fp, lr} 4: 822c: e28db004 add fp, sp, #4 ; 0x4 5: 8230: e24dd010 sub sp, sp, #16 ; 0x10 6: 8234: e50b0010 str r0, [fp, #-16] 7: 8238: e50b1014 str r1, [fp, #-20] 8: 823c: e59f0028 ldr r0, [pc, #40] ; 826c 9: 8240: e3a01002 mov r1, #2 ; 0x2 ; #define O_RDWR 00000002 10: 8244: eb002e7d bl 13c40 <__libc_open> 11: 8248: e1a03000 mov r3, r0 12: 824c: e50b3008 str r3, [fp, #-8] 13: 8250: e51b0008 ldr r0, [fp, #-8] 14: 8254: eb002e9d bl 13cd0 <__libc_close> 15: 8258: e3a03000 mov r3, #0 ; 0x0 16: 825c: e1a00003 mov r0, r3 17: 8260: e24bd004 sub sp, fp, #4 ; 0x4 18: 8264: e8bd4800 pop {fp, lr} 19: 8268: e12fff1e bx lr 20: 826c: 00064b8c .word 0x00064b8c 21: ...... 22: 00013c40 <__libc_open>: 23: 13c40: e51fc028 ldr ip, [pc, #-40] ; 13c20 <___fxstat64+0x50> 24: 13c44: e79fc00c ldr ip, [pc, ip] 25: 13c48: e33c0000 teq ip, #0 ; 0x0 26: 13c4c: 1a000006 bne 13c6c <__libc_open+0x2c> 27: 13c50: e1a0c007 mov ip, r7 28: 13c54: e3a07005 mov r7, #5 ; 0x5 #在arch/arm/include/asm/unistd.h中:#define __NR_open (__NR_SYSCALL_BASE+5) 其中,__NR_OABI_SYSCALL_BASE是0 29: 13c58: ef000000 svc 0x00000000 #产生软中断 30: 13c5c: e1a0700c mov r7, ip 31: 13c60: e3700a01 cmn r0, #4096 ; 0x1000 32: 13c64: 312fff1e bxcc lr 33: 13c68: ea0008d4 b 15fc0 <__syscall_error> 34: ...... 通过上面的代码注释,可以看到,系统调用sys_open的系统调用号是5,将系统调用号存放到寄存器R7当中,然后应用程序通过svc 0x00000000产生软中断,陷入内核空间。 也许会好奇,ARM软中断不是用SWI吗,这里怎么变成了SVC了,请看下面一段话,是从ARM官网copy的: SVC 超级用户调用。 语法 SVC{cond} #immed 其中: cond 是一个可选的条件代码(请参阅条件执行)。 immed 是一个表达式,其取值为以下范围内的一个整数: 在 ARM 指令中为 0 到 224–1(24 位值) 在 16 位 Thumb 指令中为 0-255(8 位值)。 用法 SVC 指令会引发一个异常。 这意味着处理器模式会更改为超级用户模式,CPSR 会保存到超级用户模式 SPSR,并且执行会跳转到 SVC 向量(请参阅《开发指南》中的第 6 章 处理处理器异常)。 处理器会忽略 immed。 但异常处理程序会获取它,借以确定所请求的服务。 Note 作为 ARM 汇编语言开发成果的一部分,SWI 指令已重命名为 SVC。 在此版本的 RVCT 中,SWI 指令反汇编为 SVC,并提供注释以指明这是以前的 SWI。 条件标记 此指令不更改标记。 体系结构 此 ARM 指令可用于所有版本的 ARM 体系结构。 在基于ARM的Linux中,异常向量表已经被放置在了0xFFFF0000这个位置。这个过程的完成: start_kernel ---> setup_arch ---> early_trap_init 1: void __init early_trap_init(void) 2: { 3: unsigned long vectors = CONFIG_VECTORS_BASE; // 就是0xFFFF0000 4: extern char __stubs_start[], __stubs_end[]; 5: extern char __vectors_start[], __vectors_end[]; 6: extern char __kuser_helper_start[], __kuser_helper_end[]; 7: int kuser_sz = __kuser_helper_end - __kuser_helper_start; 8: 9: /* 10: * Copy the vectors, stubs and kuser helpers (in entry-armv.S) 11: * into the vector page, mapped at 0xffff0000, and ensure these 12: * are visible to the instruction stream. 13: */ 14: memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start); 15: memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start); 16: memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz); 17: 18: /* 19: * Copy signal return handlers into the vector page, and 20: * set sigreturn to be a pointer to these. 21: */ 22: memcpy((void *)KERN_SIGRETURN_CODE, sigreturn_codes, 23: sizeof(sigreturn_codes)); 24: 25: flush_icache_range(vectors, vectors + PAGE_SIZE); 26: modify_domain(DOMAIN_USER, DOMAIN_CLIENT); 27: } 关于上面这个函数的详细解释,参见: http://www.cnblogs.com/pengdonglin137/p/3603549.html 把异常中断向量表的位置设置为0xffff0000的话,需要修改协处理器CP15的寄存器C1的第13位,将其设置为1。以Tq2440的提供的内核2.6.30.4为例看一下: arch/arm/kernel/head.S 1: adr lr, __enable_mmu @ return (PIC) address 2: add pc, r10, #PROCINFO_INITFUNC 其中,PROCINFO_INITFUNC的值是16,r10的值是__arm920_proc_info的地址: 1: __arm920_proc_info: 2: .long 0x41009200 3: .long 0xff00fff0 4: .long PMD_TYPE_SECT | 5: PMD_SECT_BUFFERABLE | 6: PMD_SECT_CACHEABLE | 7: PMD_BIT4 | 8: PMD_SECT_AP_WRITE | 9: PMD_SECT_AP_READ 10: .long PMD_TYPE_SECT | 11: PMD_BIT4 | 12: PMD_SECT_AP_WRITE | 13: PMD_SECT_AP_READ 14: b __arm920_setup 15: .long cpu_arch_name 16: .long cpu_elf_name 17: ...... 18: .size __arm920_proc_info, . - __arm920_proc_info 看一下__arm920_setup的实现(proc-arm920.S (archarmmm)): 1: .type __arm920_setup, #function 2: __arm920_setup: 3: mov r0, #0 4: mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4 5: mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 6: #ifdef CONFIG_MMU 7: mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4 8: #endif 9: adr r5, arm920_crval 10: ldmia r5, {r5, r6} @ 参看以下下面的arm920_crval的实现,本句话执行完后r5和r6分别为:0x3f3f和0x3135 11: mrc p15, 0, r0, c1, c0 @ get control register v4 获取协处理器p15的寄存器才c1 12: bic r0, r0, r5 13: orr r0, r0, r6 @ 我们只关注第13位,这里将r0的第13位设置为了1 14: mov pc, lr 15: .size __arm920_setup, . - __arm920_setup 16: 17: /* 18: * R 19: * .RVI ZFRS BLDP WCAM 20: * ..11 0001 ..11 0101 21: * 22: */ 23: .type arm920_crval, #object 24: arm920_crval:
上一篇:三星S3C6410(ARM1176)平台Android资源获取与编译(RedHat AS5)
下一篇:Exynos4412的外部中断是如何安排的?
推荐阅读最新更新时间:2024-11-17 00:08
设计资源 培训 开发板 精华推荐
- 常见的ST7571点阵液晶背板和升压电路
- 16*16点阵屏_插件
- OM13500: PCA8538评估板
- 使用 ROHM Semiconductor 的 BA00BC0WT 的参考设计
- LTC6102 的典型应用 - 精密零漂移电流检测放大器
- 使用 ON Semiconductor 的 LA5693AM 的参考设计
- 使用 Analog Devices 的 AD8318 的参考设计
- LTC3638EMSE 4V 至 125V 输入至 -15V 输出正负稳压器的典型应用电路
- 使用 ROHM Semiconductor 的 BU94607KV 的参考设计
- LTC3851,高效率 1.5V/15A 电源同步至 350kHz
- Allegro MicroSystems 在 2024 年德国慕尼黑电子展上推出先进的磁性和电感式位置感测解决方案
- 左手车钥匙,右手活体检测雷达,UWB上车势在必行!
- 狂飙十年,国产CIS挤上牌桌
- 神盾短刀电池+雷神EM-i超级电混,吉利新能源甩出了两张“王炸”
- 浅谈功能安全之故障(fault),错误(error),失效(failure)
- 智能汽车2.0周期,这几大核心产业链迎来重大机会!
- 美日研发新型电池,宁德时代面临挑战?中国新能源电池产业如何应对?
- Rambus推出业界首款HBM 4控制器IP:背后有哪些技术细节?
- 村田推出高精度汽车用6轴惯性传感器
- 福特获得预充电报警专利 有助于节约成本和应对紧急情况