Blame view

Documentation/x86/entry_64.txt 3.6 KB
8b4777a4b   Andy Lutomirski   x86-64: Document ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
  This file documents some of the kernel entries in
  arch/x86/kernel/entry_64.S.  A lot of this explanation is adapted from
  an email from Ingo Molnar:
  
  http://lkml.kernel.org/r/<20110529191055.GC9835%40elte.hu>
  
  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/kernel/entry_64.S
  and arch/x86/ia32/ia32entry.S.
  
  The IDT vector assignments are listed in arch/x86/include/irq_vectors.h.
  
  Some of these entries are:
  
   - system_call: syscall instruction from 64-bit code.
  
   - ia32_syscall: int 0x80 from 32-bit or 64-bit code; compat syscall
     either way.
  
   - ia32_syscall, 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.
8b4777a4b   Andy Lutomirski   x86-64: Document ...
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
   - APIC interrupts: Various special-purpose interrupts for things
     like TLB shootdown.
  
   - Architecturally-defined exceptions like divide_error.
  
  There are a few complexities here.  The different x86-64 entries
  have different calling conventions.  The syscall and sysenter
  instructions have their own peculiar calling conventions.  Some of
  the IDT entries push an error code onto the stack; others don't.
  IDT entries using the IST alternative stack mechanism need their own
  magic to get the stack frames right.  (You can find some
  documentation in the AMD APM, Volume 2, Chapter 8 and the Intel SDM,
  Volume 3, Chapter 6.)
  
  Dealing with the swapgs instruction is especially tricky.  Swapgs
  toggles whether gs is the kernel gs or the user gs.  The swapgs
  instruction is rather fragile: it must nest perfectly and only in
  single depth, it should only be used if entering from user mode to
  kernel mode and then when returning to user-space, and precisely
  so. If we mess that up even slightly, we crash.
  
  So when we have a secondary entry, already in kernel mode, we *must
  not* use SWAPGS blindly - nor must we forget doing a SWAPGS when it's
  not switched/swapped yet.
  
  Now, there's a secondary complication: there's a cheap way to test
  which mode the CPU is in and an expensive way.
  
  The cheap way is to pick this info off the entry frame on the kernel
  stack, from the CS of the ptregs area of the kernel stack:
  
  	xorl %ebx,%ebx
  	testl $3,CS+8(%rsp)
  	je error_kernelspace
  	SWAPGS
  
  The expensive (paranoid) way is to read back the MSR_GS_BASE value
  (which is what SWAPGS modifies):
  
  	movl $1,%ebx
  	movl $MSR_GS_BASE,%ecx
  	rdmsr
  	testl %edx,%edx
  	js 1f   /* negative -> in kernel */
  	SWAPGS
  	xorl %ebx,%ebx
  1:	ret
  
  and the whole paranoid non-paranoid macro complexity is about whether
  to suffer that RDMSR cost.
  
  If we are at an interrupt or user-trap/gate-alike boundary then we can
  use the faster check: the stack will be a reliable indicator of
  whether SWAPGS was already done: if we see that we are a secondary
  entry interrupting kernel mode execution, then we know that the GS
  base has already been switched. If it says that we interrupted
  user-space execution then we must do the SWAPGS.
  
  But if we are in an NMI/MCE/DEBUG/whatever super-atomic entry context,
  which might have triggered right after a normal entry wrote CS to the
  stack but before we executed SWAPGS, then the only safe way to check
  for GS is the slower method: the RDMSR.
  
  So we try only to mark those entry methods 'paranoid' that absolutely
  need the more expensive check for the GS base - and we generate all
  'normal' entry points with the regular (faster) entry macros.