Blame view

kernel/linux-rt-4.4.41/arch/x86/platform/efi/efi_thunk_64.S 3.01 KB
5113f6f70   김현기   kernel add
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
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
  /*
   * Copyright (C) 2014 Intel Corporation; author Matt Fleming
   *
   * Support for invoking 32-bit EFI runtime services from a 64-bit
   * kernel.
   *
   * The below thunking functions are only used after ExitBootServices()
   * has been called. This simplifies things considerably as compared with
   * the early EFI thunking because we can leave all the kernel state
   * intact (GDT, IDT, etc) and simply invoke the the 32-bit EFI runtime
   * services from __KERNEL32_CS. This means we can continue to service
   * interrupts across an EFI mixed mode call.
   *
   * We do however, need to handle the fact that we're running in a full
   * 64-bit virtual address space. Things like the stack and instruction
   * addresses need to be accessible by the 32-bit firmware, so we rely on
   * using the identity mappings in the EFI page table to access the stack
   * and kernel text (see efi_setup_page_tables()).
   */
  
  #include <linux/linkage.h>
  #include <asm/page_types.h>
  #include <asm/segment.h>
  
  	.text
  	.code64
  ENTRY(efi64_thunk)
  	push	%rbp
  	push	%rbx
  
  	/*
  	 * Switch to 1:1 mapped 32-bit stack pointer.
  	 */
  	movq	%rsp, efi_saved_sp(%rip)
  	movq	efi_scratch+25(%rip), %rsp
  
  	/*
  	 * Calculate the physical address of the kernel text.
  	 */
  	movq	$__START_KERNEL_map, %rax
  	subq	phys_base(%rip), %rax
  
  	/*
  	 * Push some physical addresses onto the stack. This is easier
  	 * to do now in a code64 section while the assembler can address
  	 * 64-bit values. Note that all the addresses on the stack are
  	 * 32-bit.
  	 */
  	subq	$16, %rsp
  	leaq	efi_exit32(%rip), %rbx
  	subq	%rax, %rbx
  	movl	%ebx, 8(%rsp)
  
  	leaq	__efi64_thunk(%rip), %rbx
  	subq	%rax, %rbx
  	call	*%rbx
  
  	movq	efi_saved_sp(%rip), %rsp
  	pop	%rbx
  	pop	%rbp
  	retq
  ENDPROC(efi64_thunk)
  
  /*
   * We run this function from the 1:1 mapping.
   *
   * This function must be invoked with a 1:1 mapped stack.
   */
  ENTRY(__efi64_thunk)
  	movl	%ds, %eax
  	push	%rax
  	movl	%es, %eax
  	push	%rax
  	movl	%ss, %eax
  	push	%rax
  
  	subq	$32, %rsp
  	movl	%esi, 0x0(%rsp)
  	movl	%edx, 0x4(%rsp)
  	movl	%ecx, 0x8(%rsp)
  	movq	%r8, %rsi
  	movl	%esi, 0xc(%rsp)
  	movq	%r9, %rsi
  	movl	%esi,  0x10(%rsp)
  
  	leaq	1f(%rip), %rbx
  	movq	%rbx, func_rt_ptr(%rip)
  
  	/* Switch to 32-bit descriptor */
  	pushq	$__KERNEL32_CS
  	leaq	efi_enter32(%rip), %rax
  	pushq	%rax
  	lretq
  
  1:	addq	$32, %rsp
  
  	pop	%rbx
  	movl	%ebx, %ss
  	pop	%rbx
  	movl	%ebx, %es
  	pop	%rbx
  	movl	%ebx, %ds
  
  	/*
  	 * Convert 32-bit status code into 64-bit.
  	 */
  	test	%rax, %rax
  	jz	1f
  	movl	%eax, %ecx
  	andl	$0x0fffffff, %ecx
  	andl	$0xf0000000, %eax
  	shl	$32, %rax
  	or	%rcx, %rax
  1:
  	ret
  ENDPROC(__efi64_thunk)
  
  ENTRY(efi_exit32)
  	movq	func_rt_ptr(%rip), %rax
  	push	%rax
  	mov	%rdi, %rax
  	ret
  ENDPROC(efi_exit32)
  
  	.code32
  /*
   * EFI service pointer must be in %edi.
   *
   * The stack should represent the 32-bit calling convention.
   */
  ENTRY(efi_enter32)
  	movl	$__KERNEL_DS, %eax
  	movl	%eax, %ds
  	movl	%eax, %es
  	movl	%eax, %ss
  
  	call	*%edi
  
  	/* We must preserve return value */
  	movl	%eax, %edi
  
  	movl	72(%esp), %eax
  	pushl	$__KERNEL_CS
  	pushl	%eax
  
  	lret
  ENDPROC(efi_enter32)
  
  	.data
  	.balign	8
  func_rt_ptr:		.quad 0
  efi_saved_sp:		.quad 0