您的位置:首页 > 运维架构 > Linux

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

2017-01-14 00:00 302 查看
『阿男的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_call
entry_INT80_compat
interrupt
APIC interrupts
Architecturally-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
指令,这样的程序不会无法使用。

接下来是
interrupt
APIC 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)

关于硬件中断,阿男后续会给大家细讲。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息