『阿男的Linux内核世界』*16 从User Space到Kernel Space(四)*

『阿男的Linux内核世界』*16 从User Space到Kernel Space(四)*

这次我们学习Linux的各种中断处理的入口,也就是entry。关于Linux的中断入口,Kernel代码自带的文档就写得非常好,位于Documentation/x86/entry_64.txt^1,大家可以仔细看看。阿男这里引用这个文档的摘要:

The x86 architecture has quite a few different ways to jump into
kernel code.  Most of these entry points are registered in
arch/x86/kernel/traps.c and implemented in arch/x86/entry/entry_64.S
for 64-bit, arch/x86/entry/entry_32.S for 32-bit and finally
arch/x86/entry/entry_64_compat.S which implements the 32-bit compatibility
syscall entry points and thus provides for 32-bit processes the
ability to execute syscalls when running on 64-bit kernels.

The IDT vector assignments are listed in arch/x86/include/asm/irq_vectors.h.

Some of these entries are:

 - system_call: syscall instruction from 64-bit code.

 - entry_INT80_compat: int 0x80 from 32-bit or 64-bit code; compat syscall
   either way.

 - entry_INT80_compat, ia32_sysenter: syscall and sysenter from 32-bit
   code

 - interrupt: An array of entries.  Every IDT vector that doesn't
   explicitly point somewhere else gets set to the corresponding
   value in interrupts.  These point to a whole array of
   magically-generated functions that make their way to do_IRQ with
   the interrupt number as a parameter.

 - APIC interrupts: Various special-purpose interrupts for things
   like TLB shootdown.

 - Architecturally-defined exceptions like divide_error.

因为我们看的是x86_64架构文档,因此必然描述的是x86_64架构的中断入口处理。文档告诉我们,Linux作为操作系统,需要支持Intel CPU的几种中断进入形式,分别有system_callentry_INT80_compatinterruptAPIC interruptsArchitecturally-defined exceptions这些。

阿男给大家大概讲讲,首先system_call就是Intel的64位CPU提供的特有的汇编指令systemcall,这个指令就是专门用来替代之前的int 0x80指令,在硬件层面更为高效。至于为什么高效,这篇文章里不展开讲,有机会阿男给大家专门写文章介绍。

然后是entry_INT80_compat,也就是说64位的CPU架构下,Intel的CPU也是向前兼容int 0x80指令的,所以Linux Kernel也是要支持起来这样的system call调用指令,这样32位的代码,或者是版本比较低的64位编译器编译出来的代码里面还是使用int 0x80指令,这样的程序不会无法使用。

接下来是interruptAPIC interrupts共同用来处理硬件中断。关于硬件中断,阿男在后续的文章里面细讲。

最后是Architecturally-defined exceptions,这个就是和CPU相关的一些错误导致的中断,比如让CPU做除以0的计算导致CPU的错误状态,等等。

讲完分类,我们可以讲讲入口的实现。因为中断和硬件架构相关,所以实现代码肯定也是根据架构分类,我们还是看x86_64架构的的相关实现。

x86_64架构的entry定义位于arch/x86/entry/entry_64.S^2,因为文件的扩展名是.S,也就意味着这必定是个汇编代码。这个代码里面既包含system calls的入口实现:

/*
 * 64-bit SYSCALL instruction entry. Up to 6 arguments in registers.
 *
 * This is the only entry point used for 64-bit system calls.  The
 * hardware interface is reasonably well designed and the register to
 * argument mapping Linux uses fits well with the registers that are
 * available when SYSCALL is used.
 *
 * SYSCALL instructions can be found inlined in libc implementations as
 * well as some other programs and libraries.  There are also a handful
 * of SYSCALL instructions in the vDSO used, for example, as a
 * clock_gettimeofday fallback.
 *
 * 64-bit SYSCALL saves rip to rcx, clears rflags.RF, then saves rflags to r11,
 * then loads new ss, cs, and rip from previously programmed MSRs.
 * rflags gets masked by a value from another MSR (so CLD and CLAC
 * are not needed). SYSCALL does not save anything on the stack
 * and does not change rsp.
 *
 * Registers on entry:
 * rax  system call number
 * rcx  return address
 * r11  saved rflags (note: r11 is callee-clobbered register in C ABI)
 * rdi  arg0
 * rsi  arg1
 * rdx  arg2
 * r10  arg3 (needs to be moved to rcx to conform to C ABI)
 * r8   arg4
 * r9   arg5
 * (note: r12-r15, rbp, rbx are callee-preserved in C ABI)
 *
 * Only called from user space.
 *
 * When user can change pt_regs->foo always force IRET. That is because
 * it deals with uncanonical addresses better. SYSRET has trouble
 * with them due to bugs in both AMD and Intel CPUs.
 */

ENTRY(entry_SYSCALL_64)

从上面的文档中我们可以看到,Linux的system call是通过寄存器传递system call的参数,这一点和FreeBSD这种UNIX内核使用stack来传递system calls的参数的方式是不同的。此外这个代码中也有硬件的相关中断入口处理代码:

/* Call softirq on interrupt stack. Interrupts are off. */
ENTRY(do_softirq_own_stack)
	pushq	%rbp
	mov	%rsp, %rbp
	incl	PER_CPU_VAR(irq_count)
	cmove	PER_CPU_VAR(irq_stack_ptr), %rsp
	push	%rbp				/* frame pointer backlink */
	call	__do_softirq
	leaveq
	decl	PER_CPU_VAR(irq_count)
	ret
END(do_softirq_own_stack)

关于硬件中断,阿男后续会给大家细讲。

转载于:https://my.oschina.net/u/3195023/blog/824646

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值