summaryrefslogtreecommitdiffstats
path: root/src/arch/x86/core/mpcall.S
blob: f2a3bf90fb0fc912c0279b48d03983561cb3fa74 (plain) (blame)
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/*
 * Copyright (C) 2024 Michael Brown <mbrown@fensystems.co.uk>.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 *
 * You can also choose to distribute this program under the terms of
 * the Unmodified Binary Distribution Licence (as given in the file
 * COPYING.UBDL), provided that you have satisfied its requirements.
 */

	FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )

/** @file
 *
 * Multiprocessor functions
 *
 */

	.section ".note.GNU-stack", "", @progbits
	.text

/* Selectively assemble code for 32-bit/64-bit builds */
#if defined ( __x86_64__ ) && ! defined ( PLATFORM_pcbios )
#define codemp code64
#define DI rdi
#define SP rsp
#define if32 if 0
#define if64 if 1
#else
#define codemp code32
#define DI edi
#define SP esp
#define if32 if 1
#define if64 if 0
#endif

/* Standard features CPUID leaf */
#define CPUID_FEATURES 0x00000001

/* x2APIC is supported */
#define CPUID_FEATURES_ECX_X2APIC 0x00200000

/* Extended topology enumeration CPUID leaf */
#define CPUID_XT_ENUM 0x0000000b

/*
 * Call multiprocessor function from C code
 *
 * Parameters:
 *	4(%esp)/%rdi	Multiprocessor function
 *	8(%esp)/%rsi	Opaque data pointer
 */
	.section ".text.mp_call", "ax", @progbits
	.codemp
	.globl	mp_call
mp_call:
.if64	/* Preserve registers, load incoming parameters into registers */
	pushq	%rax
	pushq	%rcx
	pushq	%rdx
	pushq	%rbx
	pushq	%rsp
	pushq	%rbp
	pushq	%rsi
	pushq	%rdi
	pushq	%r8
	pushq	%r9
	pushq	%r10
	pushq	%r11
	pushq	%r12
	pushq	%r13
	pushq	%r14
	pushq	%r15
.else
	pushal
	movl	36(%esp), %eax
	movl	40(%esp), %edx
.endif
	/* Call multiprocessor function */
	call	mp_jump

.if64	/* Restore registers and return */
	popq	%r15
	popq	%r14
	popq	%r13
	popq	%r12
	popq	%r11
	popq	%r10
	popq	%r9
	popq	%r8
	popq	%rdi
	popq	%rsi
	popq	%rbp
	leaq	8(%rsp), %rsp /* discard */
	popq	%rbx
	popq	%rdx
	popq	%rcx
	popq	%rax
.else
	popal
.endif
	ret
	.size	mp_call, . - mp_call

/*
 * Jump to multiprocessor function
 *
 * Parameters:
 *	%eax/%rdi	Multiprocessor function
 *	%edx/%rsi	Opaque data pointer
 *	%esp/%rsp	Stack, or NULL to halt AP upon completion
 *
 * Obtain the CPU identifier (i.e. the APIC ID) and perform a tail
 * call into the specified multiprocessor function.
 *
 * This code may run with no stack on an application processor.
 */
	.section ".text.mp_jump", "ax", @progbits
	.codemp
	.globl	mp_jump
mp_jump:
.if32	/* Move function parameters to available registers */
	movl	%eax, %edi
	movl	%edx, %esi
.endif

	/* Get 8-bit APIC ID and x2APIC feature bit */
	movl	$CPUID_FEATURES, %eax
	cpuid
	shrl	$24, %ebx
	movl	%ebx, %edx

	/* Get 32-bit x2APIC ID if applicable */
	testl	$CPUID_FEATURES_ECX_X2APIC, %ecx
	jz	1f
	movl	$CPUID_XT_ENUM, %eax
	xorl	%ecx, %ecx
	cpuid
1:

.if64	/* Tail call to function */
	movq	%rdi, %rax
	movq	%rsi, %rdi
	movl	%edx, %esi
	jmp	*%rax
.else
	movl	%esi, %eax
	jmp	*%edi
.endif
	.size	mp_jump, . - mp_jump

/*
 * Update maximum CPU identifier
 *
 * Parameters:
 *	%eax/%rdi	Pointer to shared maximum APIC ID
 *	%edx/%rsi	CPU identifier (APIC ID)
 *	%esp/%rsp	Stack, or NULL to halt AP upon completion
 *
 * This code may run with no stack on an application processor.
 */
	.section ".text.mp_update_max_cpuid", "ax", @progbits
	.codemp
	.globl	mp_update_max_cpuid
mp_update_max_cpuid:
.if32	/* Move function parameters to available registers */
	movl	%eax, %edi
	movl	%edx, %esi
.endif
	/* Update maximum APIC ID (atomically) */
	movl	(%DI), %eax
1:	cmpl	%esi, %eax
	jae	2f
	lock cmpxchgl %esi, (%DI)
	jnz	1b
2:
	/* Return to caller (if stack exists), or halt application processor */
	test	%SP, %SP
	jz	3f
	ret
3:	cli
	hlt
	jmp	3b
	.size	mp_update_max_cpuid, . - mp_update_max_cpuid