source: mainline/kernel/arch/mips32/src/start.S

Last change on this file was 3fcea34, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 9 months ago

Simplify the SYS_THREAD_CREATE syscall interface

Removed the beefy uarg structure. Instead, the syscall gets two
parameters: %pc (program counter) and %sp (stack pointer). It starts
a thread with those values in corresponding registers, with no other
fuss whatsoever.

libc initializes threads by storing any other needed arguments on
the stack and retrieving them in thread_entry. Importantly, this
includes the address of the
thread_main function which is now
called indirectly to fix dynamic linking issues on some archs.

There's a bit of weirdness on SPARC and IA-64, because of their
stacked register handling. The current solution is that we require
some space *above* the stack pointer to be available for those
architectures. I think for SPARC, it can be made more normal.

For the remaining ones, we can (probably) just set the initial
%sp to the top edge of the stack. There's some lingering offsets
on some archs just because I didn't want to accidentally break
anything. The initial thread bringup should be functionally
unchanged from the previous state, and no binaries are currently
multithreaded except thread1 test, so there should be minimal
risk of breakage. Naturally, I tested all available emulator
builds, save for msim.

  • Property mode set to 100644
File size: 8.3 KB
Line 
1#
2# Copyright (c) 2003-2004 Jakub Jermar
3# All rights reserved.
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions
7# are met:
8#
9# - Redistributions of source code must retain the above copyright
10# notice, this list of conditions and the following disclaimer.
11# - Redistributions in binary form must reproduce the above copyright
12# notice, this list of conditions and the following disclaimer in the
13# documentation and/or other materials provided with the distribution.
14# - The name of the author may not be used to endorse or promote products
15# derived from this software without specific prior written permission.
16#
17# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27#
28
29#include <abi/asmtool.h>
30#include <arch/asm/regname.h>
31#include <arch/mm/page.h>
32#include <arch/asm/boot.h>
33#include <arch/stack.h>
34#include <arch/istate_struct.h>
35
36.text
37
38.set noat
39.set noreorder
40
41/*
42 * Which status bits are thread-local:
43 * KSU(UM), EXL, ERL, IE
44 */
45#define REG_SAVE_MASK 0x1f
46
47/*
48 * The fake ABI prologue is never executed and may not be part of the
49 * procedure's body. Instead, it should be immediately preceding the procedure's
50 * body. Its only purpose is to trick the stack trace walker into thinking that
51 * the exception is more or less just a normal function call.
52 */
53.macro FAKE_ABI_PROLOGUE
54 sub $sp, ISTATE_SIZE
55 sw $ra, ISTATE_OFFSET_EPC($sp)
56.endm
57
58/*
59 * Save registers to space defined by \r
60 * We will change status: Disable ERL, EXL, UM, IE
61 * These changes will be automatically reversed in REGISTER_LOAD
62 * %sp is NOT saved as part of these registers
63 */
64.macro REGISTERS_STORE_AND_EXC_RESET r
65 sw $at, ISTATE_OFFSET_AT(\r)
66 sw $v0, ISTATE_OFFSET_V0(\r)
67 sw $v1, ISTATE_OFFSET_V1(\r)
68 sw $a0, ISTATE_OFFSET_A0(\r)
69 sw $a1, ISTATE_OFFSET_A1(\r)
70 sw $a2, ISTATE_OFFSET_A2(\r)
71 sw $a3, ISTATE_OFFSET_A3(\r)
72 sw $t0, ISTATE_OFFSET_T0(\r)
73 sw $t1, ISTATE_OFFSET_T1(\r)
74 sw $t2, ISTATE_OFFSET_T2(\r)
75 sw $t3, ISTATE_OFFSET_T3(\r)
76 sw $t4, ISTATE_OFFSET_T4(\r)
77 sw $t5, ISTATE_OFFSET_T5(\r)
78 sw $t6, ISTATE_OFFSET_T6(\r)
79 sw $t7, ISTATE_OFFSET_T7(\r)
80 sw $t8, ISTATE_OFFSET_T8(\r)
81 sw $t9, ISTATE_OFFSET_T9(\r)
82 sw $s0, ISTATE_OFFSET_S0(\r)
83 sw $s1, ISTATE_OFFSET_S1(\r)
84 sw $s2, ISTATE_OFFSET_S2(\r)
85 sw $s3, ISTATE_OFFSET_S3(\r)
86 sw $s4, ISTATE_OFFSET_S4(\r)
87 sw $s5, ISTATE_OFFSET_S5(\r)
88 sw $s6, ISTATE_OFFSET_S6(\r)
89 sw $s7, ISTATE_OFFSET_S7(\r)
90 sw $s8, ISTATE_OFFSET_S8(\r)
91
92 mflo $at
93 sw $at, ISTATE_OFFSET_LO(\r)
94 mfhi $at
95 sw $at, ISTATE_OFFSET_HI(\r)
96
97 sw $gp, ISTATE_OFFSET_GP(\r)
98 sw $ra, ISTATE_OFFSET_RA(\r)
99 sw $k0, ISTATE_OFFSET_KT0(\r)
100 sw $k1, ISTATE_OFFSET_KT1(\r)
101
102 mfc0 $t0, $status
103 mfc0 $t1, $epc
104
105 /* save only KSU, EXL, ERL, IE */
106 and $t2, $t0, REG_SAVE_MASK
107
108 /* clear KSU, EXL, ERL, IE */
109 li $t3, ~(REG_SAVE_MASK)
110 and $t0, $t0, $t3
111
112 sw $t2, ISTATE_OFFSET_STATUS(\r)
113 sw $t1, ISTATE_OFFSET_EPC(\r)
114 mtc0 $t0, $status
115.endm
116
117.macro REGISTERS_LOAD r
118 /*
119 * Update only UM, EXR, IE from status, the rest
120 * is controlled by OS and not bound to task.
121 */
122 mfc0 $t0, $status
123 lw $t1, ISTATE_OFFSET_STATUS(\r)
124
125 /* mask UM, EXL, ERL, IE */
126 li $t2, ~REG_SAVE_MASK
127 and $t0, $t0, $t2
128
129 /* copy UM, EXL, ERL, IE from saved status */
130 or $t0, $t0, $t1
131 mtc0 $t0, $status
132
133 lw $v0, ISTATE_OFFSET_V0(\r)
134 lw $v1, ISTATE_OFFSET_V1(\r)
135 lw $a0, ISTATE_OFFSET_A0(\r)
136 lw $a1, ISTATE_OFFSET_A1(\r)
137 lw $a2, ISTATE_OFFSET_A2(\r)
138 lw $a3, ISTATE_OFFSET_A3(\r)
139 lw $t0, ISTATE_OFFSET_T0(\r)
140 lw $t1, ISTATE_OFFSET_T1(\r)
141 lw $t2, ISTATE_OFFSET_T2(\r)
142 lw $t3, ISTATE_OFFSET_T3(\r)
143 lw $t4, ISTATE_OFFSET_T4(\r)
144 lw $t5, ISTATE_OFFSET_T5(\r)
145 lw $t6, ISTATE_OFFSET_T6(\r)
146 lw $t7, ISTATE_OFFSET_T7(\r)
147 lw $t8, ISTATE_OFFSET_T8(\r)
148 lw $t9, ISTATE_OFFSET_T9(\r)
149
150 lw $gp, ISTATE_OFFSET_GP(\r)
151 lw $ra, ISTATE_OFFSET_RA(\r)
152 lw $k1, ISTATE_OFFSET_KT1(\r)
153
154 lw $at, ISTATE_OFFSET_LO(\r)
155 mtlo $at
156 lw $at, ISTATE_OFFSET_HI(\r)
157 mthi $at
158
159 lw $at, ISTATE_OFFSET_EPC(\r)
160 mtc0 $at, $epc
161
162 lw $at, ISTATE_OFFSET_AT(\r)
163 lw $sp, ISTATE_OFFSET_SP(\r)
164.endm
165
166/*
167 * Move kernel stack pointer address to register $k0.
168 * If we are in user mode, load the appropriate stack address.
169 */
170.macro KERNEL_STACK_TO_K0
171 /* if we are in user mode */
172 mfc0 $k0, $status
173 andi $k0, 0x10
174
175 beq $k0, $0, 1f
176 move $k0, $sp
177
178 /* move $k0 pointer to kernel stack */
179 la $k0, supervisor_sp
180
181 /* move $k0 (supervisor_sp) */
182 lw $k0, ($k0)
183
184 1:
185.endm
186
187.org 0x0
188SYMBOL(kernel_image_start)
189 /* load temporary stack */
190 lui $sp, %hi(end_stack)
191 ori $sp, $sp, %lo(end_stack)
192
193 /* not sure about this, but might be needed for PIC code */
194 lui $gp, 0x8000
195
196 /* $a1 contains physical address of bootinfo_t */
197 jal mips32_pre_main
198 addiu $sp, -ABI_STACK_FRAME
199
200 j main_bsp
201 nop
202
203.space TEMP_STACK_SIZE
204end_stack:
205
206SYMBOL(tlb_refill_entry)
207 j tlb_refill_handler
208 nop
209
210SYMBOL(cache_error_entry)
211 j cache_error_handler
212 nop
213
214SYMBOL(exception_entry)
215 j exception_handler
216 nop
217
218 FAKE_ABI_PROLOGUE
219exception_handler:
220 KERNEL_STACK_TO_K0
221
222 sub $k0, ISTATE_SIZE
223 sw $sp, ISTATE_OFFSET_SP($k0)
224 move $sp, $k0
225
226 mfc0 $k0, $cause
227
228 sra $k0, $k0, 0x2 /* cp0_exc_cause() part 1 */
229 andi $k0, $k0, 0x1f /* cp0_exc_cause() part 2 */
230 sub $k0, 8 /* 8 = SYSCALL */
231
232 beqz $k0, syscall_shortcut
233 add $k0, 8 /* revert $k0 back to correct exc number */
234
235 REGISTERS_STORE_AND_EXC_RESET $sp
236
237 move $a1, $sp
238 move $a0, $k0
239 jal exc_dispatch /* exc_dispatch(excno, register_space) */
240 addiu $sp, -ABI_STACK_FRAME
241 addiu $sp, ABI_STACK_FRAME
242
243 REGISTERS_LOAD $sp
244 /* the $sp is automatically restored to former value */
245 eret
246
247/** Syscall entry
248 *
249 * Registers:
250 *
251 * @param $v0 Syscall number.
252 * @param $a0 1st argument.
253 * @param $a1 2nd argument.
254 * @param $a2 3rd argument.
255 * @param $a3 4th argument.
256 * @param $t0 5th argument.
257 * @param $t1 6th argument.
258 *
259 * @return The return value will be stored in $v0.
260 *
261 */
262syscall_shortcut:
263 mfc0 $t3, $epc
264 mfc0 $t2, $status
265 sw $t3, ISTATE_OFFSET_EPC($sp) /* save EPC */
266
267 and $t4, $t2, REG_SAVE_MASK /* save only KSU, EXL, ERL, IE */
268 li $t5, ~(0x1f)
269 and $t2, $t2, $t5 /* clear KSU, EXL, ERL */
270 ori $t2, $t2, 0x1 /* set IE */
271
272 sw $t4, ISTATE_OFFSET_STATUS($sp)
273 mtc0 $t2, $status
274
275 /*
276 * Call the higher level system call handler.
277 *
278 */
279 sw $t0, ISTATE_OFFSET_T0($sp) /* save the 5th argument on the stack */
280 sw $t1, ISTATE_OFFSET_T1($sp) /* save the 6th argument on the stack */
281
282 jal syscall_handler
283 sw $v0, ISTATE_OFFSET_V0($sp) /* save the syscall number on the stack */
284
285 /* restore status */
286 mfc0 $t2, $status
287 lw $t3, ISTATE_OFFSET_STATUS($sp)
288
289 /*
290 * Change back to EXL = 1 (from last exception), otherwise
291 * an interrupt could rewrite the CP0 - EPC.
292 *
293 */
294 li $t4, ~REG_SAVE_MASK /* mask UM, EXL, ERL, IE */
295 and $t2, $t2, $t4
296 or $t2, $t2, $t3 /* copy saved UM, EXL, ERL, IE */
297 mtc0 $t2, $status
298
299 /* restore epc + 4 */
300 lw $t2, ISTATE_OFFSET_EPC($sp)
301 addi $t2, $t2, 4
302 mtc0 $t2, $epc
303
304 lw $sp, ISTATE_OFFSET_SP($sp) /* restore $sp */
305 eret
306
307 FAKE_ABI_PROLOGUE
308tlb_refill_handler:
309 KERNEL_STACK_TO_K0
310 sub $k0, ISTATE_SIZE
311 REGISTERS_STORE_AND_EXC_RESET $k0
312 sw $sp, ISTATE_OFFSET_SP($k0)
313 move $sp, $k0
314
315 move $a0, $sp
316 jal tlb_refill
317 addiu $sp, -ABI_STACK_FRAME
318 addiu $sp, ABI_STACK_FRAME
319
320 REGISTERS_LOAD $sp
321 eret
322
323 FAKE_ABI_PROLOGUE
324cache_error_handler:
325 KERNEL_STACK_TO_K0
326 sub $k0, ISTATE_SIZE
327 REGISTERS_STORE_AND_EXC_RESET $k0
328 sw $sp, ISTATE_OFFSET_SP($k0)
329 move $sp, $k0
330
331 move $a0, $sp
332 jal cache_error
333 addiu $sp, -ABI_STACK_FRAME
334 addiu $sp, ABI_STACK_FRAME
335
336 REGISTERS_LOAD $sp
337 eret
338
339FUNCTION_BEGIN(userspace_asm)
340 move $sp, $a0
341 xor $a0, $a0, $a0 /* $a0 is defined to hold pcb_ptr, set it to 0 */
342 xor $fp, $fp, $fp // FIXME: wipe all userspace-accessible registers
343 xor $ra, $ra, $ra
344 eret
345FUNCTION_END(userspace_asm)
Note: See TracBrowser for help on using the repository browser.