source: mainline/kernel/arch/sparc64/src/trap/sun4u/trap_table.S@ 2689a0b

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 2689a0b was 40239b9, checked in by Jakub Jermar <jakub@…>, 15 years ago

Fix a couple of occurrences of obsolete branch instruction with proper SPARC V9
branches. More dispensable NOP instructions killed.

  • Property mode set to 100644
File size: 26.0 KB
Line 
1#
2# Copyright (c) 2005 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/**
30 * @file
31 * @brief This file contains kernel trap table.
32 */
33
34.register %g2, #scratch
35.register %g3, #scratch
36
37.text
38
39#include <arch/trap/trap_table.h>
40#include <arch/trap/regwin.h>
41#include <arch/trap/interrupt.h>
42#include <arch/trap/exception.h>
43#include <arch/trap/syscall.h>
44#include <arch/trap/mmu.h>
45#include <arch/mm/mmu.h>
46#include <arch/mm/page.h>
47#include <arch/stack.h>
48#include <arch/regdef.h>
49
50#define TABLE_SIZE TRAP_TABLE_SIZE
51#define ENTRY_SIZE TRAP_TABLE_ENTRY_SIZE
52
53/*
54 * Kernel trap table.
55 */
56.align TABLE_SIZE
57.global trap_table
58trap_table:
59
60/* TT = 0x08, TL = 0, instruction_access_exception */
61.org trap_table + TT_INSTRUCTION_ACCESS_EXCEPTION*ENTRY_SIZE
62.global instruction_access_exception_tl0
63instruction_access_exception_tl0:
64 wrpr %g0, PSTATE_AG_BIT | PSTATE_PRIV_BIT, %pstate
65 PREEMPTIBLE_HANDLER instruction_access_exception
66
67/* TT = 0x0a, TL = 0, instruction_access_error */
68.org trap_table + TT_INSTRUCTION_ACCESS_ERROR*ENTRY_SIZE
69.global instruction_access_error_tl0
70instruction_access_error_tl0:
71 PREEMPTIBLE_HANDLER instruction_access_error
72
73/* TT = 0x10, TL = 0, illegal_instruction */
74.org trap_table + TT_ILLEGAL_INSTRUCTION*ENTRY_SIZE
75.global illegal_instruction_tl0
76illegal_instruction_tl0:
77 PREEMPTIBLE_HANDLER illegal_instruction
78
79/* TT = 0x11, TL = 0, privileged_opcode */
80.org trap_table + TT_PRIVILEGED_OPCODE*ENTRY_SIZE
81.global privileged_opcode_tl0
82privileged_opcode_tl0:
83 PREEMPTIBLE_HANDLER privileged_opcode
84
85/* TT = 0x12, TL = 0, unimplemented_LDD */
86.org trap_table + TT_UNIMPLEMENTED_LDD*ENTRY_SIZE
87.global unimplemented_LDD_tl0
88unimplemented_LDD_tl0:
89 PREEMPTIBLE_HANDLER unimplemented_LDD
90
91/* TT = 0x13, TL = 0, unimplemented_STD */
92.org trap_table + TT_UNIMPLEMENTED_STD*ENTRY_SIZE
93.global unimplemented_STD_tl0
94unimplemented_STD_tl0:
95 PREEMPTIBLE_HANDLER unimplemented_STD
96
97/* TT = 0x20, TL = 0, fb_disabled handler */
98.org trap_table + TT_FP_DISABLED*ENTRY_SIZE
99.global fb_disabled_tl0
100fp_disabled_tl0:
101 PREEMPTIBLE_HANDLER fp_disabled
102
103/* TT = 0x21, TL = 0, fb_exception_ieee_754 handler */
104.org trap_table + TT_FP_EXCEPTION_IEEE_754*ENTRY_SIZE
105.global fb_exception_ieee_754_tl0
106fp_exception_ieee_754_tl0:
107 PREEMPTIBLE_HANDLER fp_exception_ieee_754
108
109/* TT = 0x22, TL = 0, fb_exception_other handler */
110.org trap_table + TT_FP_EXCEPTION_OTHER*ENTRY_SIZE
111.global fb_exception_other_tl0
112fp_exception_other_tl0:
113 PREEMPTIBLE_HANDLER fp_exception_other
114
115/* TT = 0x23, TL = 0, tag_overflow */
116.org trap_table + TT_TAG_OVERFLOW*ENTRY_SIZE
117.global tag_overflow_tl0
118tag_overflow_tl0:
119 PREEMPTIBLE_HANDLER tag_overflow
120
121/* TT = 0x24, TL = 0, clean_window handler */
122.org trap_table + TT_CLEAN_WINDOW*ENTRY_SIZE
123.global clean_window_tl0
124clean_window_tl0:
125 CLEAN_WINDOW_HANDLER
126
127/* TT = 0x28, TL = 0, division_by_zero */
128.org trap_table + TT_DIVISION_BY_ZERO*ENTRY_SIZE
129.global division_by_zero_tl0
130division_by_zero_tl0:
131 PREEMPTIBLE_HANDLER division_by_zero
132
133/* TT = 0x30, TL = 0, data_access_exception */
134.org trap_table + TT_DATA_ACCESS_EXCEPTION*ENTRY_SIZE
135.global data_access_exception_tl0
136data_access_exception_tl0:
137 wrpr %g0, PSTATE_AG_BIT | PSTATE_PRIV_BIT, %pstate
138 PREEMPTIBLE_HANDLER data_access_exception
139
140/* TT = 0x32, TL = 0, data_access_error */
141.org trap_table + TT_DATA_ACCESS_ERROR*ENTRY_SIZE
142.global data_access_error_tl0
143data_access_error_tl0:
144 PREEMPTIBLE_HANDLER data_access_error
145
146/* TT = 0x34, TL = 0, mem_address_not_aligned */
147.org trap_table + TT_MEM_ADDRESS_NOT_ALIGNED*ENTRY_SIZE
148.global mem_address_not_aligned_tl0
149mem_address_not_aligned_tl0:
150 PREEMPTIBLE_HANDLER mem_address_not_aligned
151
152/* TT = 0x35, TL = 0, LDDF_mem_address_not_aligned */
153.org trap_table + TT_LDDF_MEM_ADDRESS_NOT_ALIGNED*ENTRY_SIZE
154.global LDDF_mem_address_not_aligned_tl0
155LDDF_mem_address_not_aligned_tl0:
156 PREEMPTIBLE_HANDLER LDDF_mem_address_not_aligned
157
158/* TT = 0x36, TL = 0, STDF_mem_address_not_aligned */
159.org trap_table + TT_STDF_MEM_ADDRESS_NOT_ALIGNED*ENTRY_SIZE
160.global STDF_mem_address_not_aligned_tl0
161STDF_mem_address_not_aligned_tl0:
162 PREEMPTIBLE_HANDLER STDF_mem_address_not_aligned
163
164/* TT = 0x37, TL = 0, privileged_action */
165.org trap_table + TT_PRIVILEGED_ACTION*ENTRY_SIZE
166.global privileged_action_tl0
167privileged_action_tl0:
168 PREEMPTIBLE_HANDLER privileged_action
169
170/* TT = 0x38, TL = 0, LDQF_mem_address_not_aligned */
171.org trap_table + TT_LDQF_MEM_ADDRESS_NOT_ALIGNED*ENTRY_SIZE
172.global LDQF_mem_address_not_aligned_tl0
173LDQF_mem_address_not_aligned_tl0:
174 PREEMPTIBLE_HANDLER LDQF_mem_address_not_aligned
175
176/* TT = 0x39, TL = 0, STQF_mem_address_not_aligned */
177.org trap_table + TT_STQF_MEM_ADDRESS_NOT_ALIGNED*ENTRY_SIZE
178.global STQF_mem_address_not_aligned_tl0
179STQF_mem_address_not_aligned_tl0:
180 PREEMPTIBLE_HANDLER STQF_mem_address_not_aligned
181
182/* TT = 0x41, TL = 0, interrupt_level_1 handler */
183.org trap_table + TT_INTERRUPT_LEVEL_1*ENTRY_SIZE
184.global interrupt_level_1_handler_tl0
185interrupt_level_1_handler_tl0:
186 INTERRUPT_LEVEL_N_HANDLER 1
187
188/* TT = 0x42, TL = 0, interrupt_level_2 handler */
189.org trap_table + TT_INTERRUPT_LEVEL_2*ENTRY_SIZE
190.global interrupt_level_2_handler_tl0
191interrupt_level_2_handler_tl0:
192 INTERRUPT_LEVEL_N_HANDLER 2
193
194/* TT = 0x43, TL = 0, interrupt_level_3 handler */
195.org trap_table + TT_INTERRUPT_LEVEL_3*ENTRY_SIZE
196.global interrupt_level_3_handler_tl0
197interrupt_level_3_handler_tl0:
198 INTERRUPT_LEVEL_N_HANDLER 3
199
200/* TT = 0x44, TL = 0, interrupt_level_4 handler */
201.org trap_table + TT_INTERRUPT_LEVEL_4*ENTRY_SIZE
202.global interrupt_level_4_handler_tl0
203interrupt_level_4_handler_tl0:
204 INTERRUPT_LEVEL_N_HANDLER 4
205
206/* TT = 0x45, TL = 0, interrupt_level_5 handler */
207.org trap_table + TT_INTERRUPT_LEVEL_5*ENTRY_SIZE
208.global interrupt_level_5_handler_tl0
209interrupt_level_5_handler_tl0:
210 INTERRUPT_LEVEL_N_HANDLER 5
211
212/* TT = 0x46, TL = 0, interrupt_level_6 handler */
213.org trap_table + TT_INTERRUPT_LEVEL_6*ENTRY_SIZE
214.global interrupt_level_6_handler_tl0
215interrupt_level_6_handler_tl0:
216 INTERRUPT_LEVEL_N_HANDLER 6
217
218/* TT = 0x47, TL = 0, interrupt_level_7 handler */
219.org trap_table + TT_INTERRUPT_LEVEL_7*ENTRY_SIZE
220.global interrupt_level_7_handler_tl0
221interrupt_level_7_handler_tl0:
222 INTERRUPT_LEVEL_N_HANDLER 7
223
224/* TT = 0x48, TL = 0, interrupt_level_8 handler */
225.org trap_table + TT_INTERRUPT_LEVEL_8*ENTRY_SIZE
226.global interrupt_level_8_handler_tl0
227interrupt_level_8_handler_tl0:
228 INTERRUPT_LEVEL_N_HANDLER 8
229
230/* TT = 0x49, TL = 0, interrupt_level_9 handler */
231.org trap_table + TT_INTERRUPT_LEVEL_9*ENTRY_SIZE
232.global interrupt_level_9_handler_tl0
233interrupt_level_9_handler_tl0:
234 INTERRUPT_LEVEL_N_HANDLER 9
235
236/* TT = 0x4a, TL = 0, interrupt_level_10 handler */
237.org trap_table + TT_INTERRUPT_LEVEL_10*ENTRY_SIZE
238.global interrupt_level_10_handler_tl0
239interrupt_level_10_handler_tl0:
240 INTERRUPT_LEVEL_N_HANDLER 10
241
242/* TT = 0x4b, TL = 0, interrupt_level_11 handler */
243.org trap_table + TT_INTERRUPT_LEVEL_11*ENTRY_SIZE
244.global interrupt_level_11_handler_tl0
245interrupt_level_11_handler_tl0:
246 INTERRUPT_LEVEL_N_HANDLER 11
247
248/* TT = 0x4c, TL = 0, interrupt_level_12 handler */
249.org trap_table + TT_INTERRUPT_LEVEL_12*ENTRY_SIZE
250.global interrupt_level_12_handler_tl0
251interrupt_level_12_handler_tl0:
252 INTERRUPT_LEVEL_N_HANDLER 12
253
254/* TT = 0x4d, TL = 0, interrupt_level_13 handler */
255.org trap_table + TT_INTERRUPT_LEVEL_13*ENTRY_SIZE
256.global interrupt_level_13_handler_tl0
257interrupt_level_13_handler_tl0:
258 INTERRUPT_LEVEL_N_HANDLER 13
259
260/* TT = 0x4e, TL = 0, interrupt_level_14 handler */
261.org trap_table + TT_INTERRUPT_LEVEL_14*ENTRY_SIZE
262.global interrupt_level_14_handler_tl0
263interrupt_level_14_handler_tl0:
264 INTERRUPT_LEVEL_N_HANDLER 14
265
266/* TT = 0x4f, TL = 0, interrupt_level_15 handler */
267.org trap_table + TT_INTERRUPT_LEVEL_15*ENTRY_SIZE
268.global interrupt_level_15_handler_tl0
269interrupt_level_15_handler_tl0:
270 INTERRUPT_LEVEL_N_HANDLER 15
271
272/* TT = 0x60, TL = 0, interrupt_vector_trap handler */
273.org trap_table + TT_INTERRUPT_VECTOR_TRAP*ENTRY_SIZE
274.global interrupt_vector_trap_handler_tl0
275interrupt_vector_trap_handler_tl0:
276 INTERRUPT_VECTOR_TRAP_HANDLER
277
278/* TT = 0x64, TL = 0, fast_instruction_access_MMU_miss */
279.org trap_table + TT_FAST_INSTRUCTION_ACCESS_MMU_MISS*ENTRY_SIZE
280.global fast_instruction_access_mmu_miss_handler_tl0
281fast_instruction_access_mmu_miss_handler_tl0:
282 FAST_INSTRUCTION_ACCESS_MMU_MISS_HANDLER
283
284/* TT = 0x68, TL = 0, fast_data_access_MMU_miss */
285.org trap_table + TT_FAST_DATA_ACCESS_MMU_MISS*ENTRY_SIZE
286.global fast_data_access_mmu_miss_handler_tl0
287fast_data_access_mmu_miss_handler_tl0:
288 FAST_DATA_ACCESS_MMU_MISS_HANDLER 0
289
290/* TT = 0x6c, TL = 0, fast_data_access_protection */
291.org trap_table + TT_FAST_DATA_ACCESS_PROTECTION*ENTRY_SIZE
292.global fast_data_access_protection_handler_tl0
293fast_data_access_protection_handler_tl0:
294 FAST_DATA_ACCESS_PROTECTION_HANDLER 0
295
296/* TT = 0x80, TL = 0, spill_0_normal handler */
297.org trap_table + TT_SPILL_0_NORMAL*ENTRY_SIZE
298.global spill_0_normal_tl0
299spill_0_normal_tl0:
300 SPILL_NORMAL_HANDLER_KERNEL
301
302/* TT = 0x84, TL = 0, spill_1_normal handler */
303.org trap_table + TT_SPILL_1_NORMAL*ENTRY_SIZE
304.global spill_1_normal_tl0
305spill_1_normal_tl0:
306 SPILL_NORMAL_HANDLER_USERSPACE
307
308/* TT = 0x88, TL = 0, spill_2_normal handler */
309.org trap_table + TT_SPILL_2_NORMAL*ENTRY_SIZE
310.global spill_2_normal_tl0
311spill_2_normal_tl0:
312 SPILL_TO_USPACE_WINDOW_BUFFER
313
314/* TT = 0xa0, TL = 0, spill_0_other handler */
315.org trap_table + TT_SPILL_0_OTHER*ENTRY_SIZE
316.global spill_0_other_tl0
317spill_0_other_tl0:
318 SPILL_TO_USPACE_WINDOW_BUFFER
319
320/* TT = 0xc0, TL = 0, fill_0_normal handler */
321.org trap_table + TT_FILL_0_NORMAL*ENTRY_SIZE
322.global fill_0_normal_tl0
323fill_0_normal_tl0:
324 FILL_NORMAL_HANDLER_KERNEL
325
326/* TT = 0xc4, TL = 0, fill_1_normal handler */
327.org trap_table + TT_FILL_1_NORMAL*ENTRY_SIZE
328.global fill_1_normal_tl0
329fill_1_normal_tl0:
330 FILL_NORMAL_HANDLER_USERSPACE
331
332/* TT = 0x100 - 0x17f, TL = 0, trap_instruction_0 - trap_instruction_7f */
333.irp cur, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,\
334 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,\
335 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,\
336 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,\
337 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,\
338 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,\
339 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,\
340 127
341.org trap_table + (TT_TRAP_INSTRUCTION_0+\cur)*ENTRY_SIZE
342.global trap_instruction_\cur\()_tl0
343trap_instruction_\cur\()_tl0:
344 ba %xcc, trap_instruction_handler
345 mov \cur, %g2
346.endr
347
348/*
349 * Handlers for TL>0.
350 */
351
352/* TT = 0x08, TL > 0, instruction_access_exception */
353.org trap_table + (TT_INSTRUCTION_ACCESS_EXCEPTION+512)*ENTRY_SIZE
354.global instruction_access_exception_tl1
355instruction_access_exception_tl1:
356 wrpr %g0, 1, %tl
357 wrpr %g0, PSTATE_AG_BIT | PSTATE_PRIV_BIT, %pstate
358 PREEMPTIBLE_HANDLER instruction_access_exception
359
360/* TT = 0x0a, TL > 0, instruction_access_error */
361.org trap_table + (TT_INSTRUCTION_ACCESS_ERROR+512)*ENTRY_SIZE
362.global instruction_access_error_tl1
363instruction_access_error_tl1:
364 wrpr %g0, 1, %tl
365 PREEMPTIBLE_HANDLER instruction_access_error
366
367/* TT = 0x10, TL > 0, illegal_instruction */
368.org trap_table + (TT_ILLEGAL_INSTRUCTION+512)*ENTRY_SIZE
369.global illegal_instruction_tl1
370illegal_instruction_tl1:
371 wrpr %g0, 1, %tl
372 PREEMPTIBLE_HANDLER illegal_instruction
373
374/* TT = 0x24, TL > 0, clean_window handler */
375.org trap_table + (TT_CLEAN_WINDOW+512)*ENTRY_SIZE
376.global clean_window_tl1
377clean_window_tl1:
378 CLEAN_WINDOW_HANDLER
379
380/* TT = 0x28, TL > 0, division_by_zero */
381.org trap_table + (TT_DIVISION_BY_ZERO+512)*ENTRY_SIZE
382.global division_by_zero_tl1
383division_by_zero_tl1:
384 wrpr %g0, 1, %tl
385 PREEMPTIBLE_HANDLER division_by_zero
386
387/* TT = 0x30, TL > 0, data_access_exception */
388.org trap_table + (TT_DATA_ACCESS_EXCEPTION+512)*ENTRY_SIZE
389.global data_access_exception_tl1
390data_access_exception_tl1:
391 wrpr %g0, 1, %tl
392 wrpr %g0, PSTATE_AG_BIT | PSTATE_PRIV_BIT, %pstate
393 PREEMPTIBLE_HANDLER data_access_exception
394
395/* TT = 0x32, TL > 0, data_access_error */
396.org trap_table + (TT_DATA_ACCESS_ERROR+512)*ENTRY_SIZE
397.global data_access_error_tl1
398data_access_error_tl1:
399 wrpr %g0, 1, %tl
400 PREEMPTIBLE_HANDLER data_access_error
401
402/* TT = 0x34, TL > 0, mem_address_not_aligned */
403.org trap_table + (TT_MEM_ADDRESS_NOT_ALIGNED+512)*ENTRY_SIZE
404.global mem_address_not_aligned_tl1
405mem_address_not_aligned_tl1:
406 wrpr %g0, 1, %tl
407 PREEMPTIBLE_HANDLER mem_address_not_aligned
408
409/* TT = 0x68, TL > 0, fast_data_access_MMU_miss */
410.org trap_table + (TT_FAST_DATA_ACCESS_MMU_MISS+512)*ENTRY_SIZE
411.global fast_data_access_mmu_miss_handler_tl1
412fast_data_access_mmu_miss_handler_tl1:
413 FAST_DATA_ACCESS_MMU_MISS_HANDLER 1
414
415/* TT = 0x6c, TL > 0, fast_data_access_protection */
416.org trap_table + (TT_FAST_DATA_ACCESS_PROTECTION+512)*ENTRY_SIZE
417.global fast_data_access_protection_handler_tl1
418fast_data_access_protection_handler_tl1:
419 FAST_DATA_ACCESS_PROTECTION_HANDLER 1
420
421/* TT = 0x80, TL > 0, spill_0_normal handler */
422.org trap_table + (TT_SPILL_0_NORMAL+512)*ENTRY_SIZE
423.global spill_0_normal_tl1
424spill_0_normal_tl1:
425 SPILL_NORMAL_HANDLER_KERNEL
426
427/* TT = 0x88, TL > 0, spill_2_normal handler */
428.org trap_table + (TT_SPILL_2_NORMAL+512)*ENTRY_SIZE
429.global spill_2_normal_tl1
430spill_2_normal_tl1:
431 SPILL_TO_USPACE_WINDOW_BUFFER
432
433/* TT = 0xa0, TL > 0, spill_0_other handler */
434.org trap_table + (TT_SPILL_0_OTHER+512)*ENTRY_SIZE
435.global spill_0_other_tl1
436spill_0_other_tl1:
437 SPILL_TO_USPACE_WINDOW_BUFFER
438
439/* TT = 0xc0, TL > 0, fill_0_normal handler */
440.org trap_table + (TT_FILL_0_NORMAL+512)*ENTRY_SIZE
441.global fill_0_normal_tl1
442fill_0_normal_tl1:
443 FILL_NORMAL_HANDLER_KERNEL
444
445.align TABLE_SIZE
446
447
448#define NOT(x) ((x) == 0)
449
450/* Preemptible trap handler for TL=1.
451 *
452 * This trap handler makes arrangements to make calling of scheduler() from
453 * within a trap context possible. It is called from several other trap
454 * handlers.
455 *
456 * This function can be entered either with interrupt globals or alternate
457 * globals. Memory management trap handlers are obliged to switch to one of
458 * those global sets prior to calling this function. Register window management
459 * functions are not allowed to modify the alternate global registers.
460 *
461 * The kernel is designed to work on trap levels 0 - 4. For instance, the
462 * following can happen:
463 * TL0: kernel thread runs (CANSAVE=0, kernel stack not in DTLB)
464 * TL1: preemptible trap handler started after a tick interrupt
465 * TL2: preemptible trap handler did SAVE
466 * TL3: spill handler touched the kernel stack
467 * TL4: hardware or software failure
468 *
469 * Input registers:
470 * %g1 Address of function to call if this is not a syscall.
471 * %g2 First argument for the function.
472 * %g6 Pre-set as kernel stack base if trap from userspace.
473 * %g7 Pre-set as address of the userspace window buffer.
474 */
475.macro PREEMPTIBLE_HANDLER_TEMPLATE is_syscall
476 /*
477 * ASSERT(%tl == 1)
478 */
479 rdpr %tl, %g3
480 cmp %g3, 1
481 be %xcc, 1f
482 nop
483 ! this is for debugging, if we ever get here it will be easy to find
4840: ba,a %xcc, 0b
485
4861:
487.if NOT(\is_syscall)
488 rdpr %tstate, %g3
489
490 /*
491 * One of the ways this handler can be invoked is after a nested MMU trap from
492 * either spill_1_normal or fill_1_normal traps. Both of these traps manipulate
493 * the CWP register. We deal with the situation by simulating the MMU trap
494 * on TL=1 and restart the respective SAVE or RESTORE instruction once the MMU
495 * trap is resolved. However, because we are in the wrong window from the
496 * perspective of the MMU trap, we need to synchronize CWP with CWP from TL=0.
497 */
498 and %g3, TSTATE_CWP_MASK, %g4
499 wrpr %g4, 0, %cwp ! resynchronize CWP
500
501 andcc %g3, TSTATE_PRIV_BIT, %g0 ! if this trap came from the privileged mode...
502 bnz %xcc, 0f ! ...skip setting of kernel stack and primary context
503 nop
504
505.endif
506 /*
507 * Normal window spills will go to the userspace window buffer.
508 */
509 wrpr %g0, WSTATE_OTHER(0) | WSTATE_NORMAL(2), %wstate
510
511 wrpr %g0, NWINDOWS - 1, %cleanwin ! prevent unnecessary clean_window exceptions
512
513 /*
514 * Switch to kernel stack. The old stack is
515 * automatically saved in the old window's %sp
516 * and the new window's %fp.
517 */
518 save %g6, -PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE, %sp
519
520.if \is_syscall
521 /*
522 * Copy arguments for the syscall to the new window.
523 */
524 mov %i0, %o0
525 mov %i1, %o1
526 mov %i2, %o2
527 mov %i3, %o3
528 mov %i4, %o4
529 mov %i5, %o5
530.endif
531
532 /*
533 * Mark the CANRESTORE windows as OTHER windows.
534 */
535 rdpr %canrestore, %l0
536 wrpr %l0, %otherwin
537 wrpr %g0, %canrestore
538
539 /*
540 * Switch to primary context 0.
541 */
542 mov VA_PRIMARY_CONTEXT_REG, %l0
543 stxa %g0, [%l0] ASI_DMMU
544 rd %pc, %l0
545 flush %l0
546
547.if NOT(\is_syscall)
548 ba,a %xcc, 1f
5490:
550 save %sp, -PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE, %sp
551
552 /*
553 * At this moment, we are using the kernel stack
554 * and have successfully allocated a register window.
555 */
5561:
557.endif
558 /*
559 * Other window spills will go to the userspace window buffer
560 * and normal spills will go to the kernel stack.
561 */
562 wrpr %g0, WSTATE_OTHER(0) | WSTATE_NORMAL(0), %wstate
563
564 /*
565 * Copy arguments.
566 */
567 mov %g1, %l0
568.if NOT(\is_syscall)
569 mov %g2, %o0
570.else
571 ! store the syscall number on the stack as 7th argument
572 stx %g2, [%sp + STACK_WINDOW_SAVE_AREA_SIZE + STACK_BIAS + STACK_ARG6]
573.endif
574
575 /*
576 * Save TSTATE, TPC and TNPC aside.
577 */
578 rdpr %tstate, %g1
579 rdpr %tpc, %g2
580 rdpr %tnpc, %g3
581 rd %y, %g4
582
583 stx %g1, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_TSTATE]
584 stx %g2, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_TPC]
585 stx %g3, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_TNPC]
586
587 /*
588 * Save the Y register.
589 * This register is deprecated according to SPARC V9 specification
590 * and is only present for backward compatibility with previous
591 * versions of the SPARC architecture.
592 * Surprisingly, gcc makes use of this register without a notice.
593 */
594 stx %g4, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_Y]
595
596 wrpr %g0, 0, %tl
597 wrpr %g0, PSTATE_PRIV_BIT | PSTATE_PEF_BIT, %pstate
598 SAVE_GLOBALS
599
600.if NOT(\is_syscall)
601 /*
602 * Call the higher-level handler and pass istate as second parameter.
603 */
604 call %l0
605 add %sp, PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_TNPC, %o1
606.else
607 /*
608 * Call the higher-level syscall handler and enable interrupts.
609 */
610 call syscall_handler
611 wrpr %g0, PSTATE_PRIV_BIT | PSTATE_PEF_BIT | PSTATE_IE_BIT, %pstate
612 mov %o0, %i0 ! copy the value returned by the syscall
613.endif
614
615 RESTORE_GLOBALS
616 rdpr %pstate, %l1 ! we must preserve the PEF bit
617 wrpr %g0, PSTATE_AG_BIT | PSTATE_PRIV_BIT, %pstate
618 wrpr %g0, 1, %tl
619
620 /*
621 * Read TSTATE, TPC and TNPC from saved copy.
622 */
623 ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_TSTATE], %g1
624 ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_TPC], %g2
625 ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_TNPC], %g3
626
627 /*
628 * Copy PSTATE.PEF to the in-register copy of TSTATE.
629 */
630 and %l1, PSTATE_PEF_BIT, %l1
631 sllx %l1, TSTATE_PSTATE_SHIFT, %l1
632 sethi %hi(TSTATE_PEF_BIT), %g4
633 andn %g1, %g4, %g1
634 or %g1, %l1, %g1
635
636 /*
637 * Restore TSTATE, TPC and TNPC from saved copies.
638 */
639 wrpr %g1, 0, %tstate
640 wrpr %g2, 0, %tpc
641 wrpr %g3, 0, %tnpc
642
643 /*
644 * Restore Y.
645 */
646 ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_Y], %g4
647 wr %g4, %y
648
649 /*
650 * If OTHERWIN is zero, then all the userspace windows have been
651 * spilled to kernel memory (i.e. register window buffer). Moreover,
652 * if the scheduler was called in the meantime, all valid windows
653 * belonging to other threads were spilled by context_save().
654 * If OTHERWIN is non-zero, then some userspace windows are still
655 * valid. Others might have been spilled. However, the CWP pointer
656 * needs no fixing because the scheduler had not been called.
657 */
658 rdpr %otherwin, %l0
659 brnz %l0, 0f
660 nop
661
662 /*
663 * OTHERWIN == 0
664 */
665
666 /*
667 * If TSTATE.CWP + 1 == CWP, then we still do not have to fix CWP.
668 */
669 and %g1, TSTATE_CWP_MASK, %l0
670 inc %l0
671 and %l0, NWINDOWS - 1, %l0 ! %l0 mod NWINDOWS
672 rdpr %cwp, %l1
673 cmp %l0, %l1
674 bz %xcc, 0f ! CWP is ok
675 nop
676
677 /*
678 * Fix CWP.
679 * In order to recapitulate, the input registers in the current
680 * window are the output registers of the window to which we want
681 * to restore. Because the fill trap fills only input and local
682 * registers of a window, we need to preserve those output
683 * registers manually.
684 */
685 mov %sp, %g2
686 stx %i0, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I0]
687 stx %i1, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I1]
688 stx %i2, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I2]
689 stx %i3, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I3]
690 stx %i4, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I4]
691 stx %i5, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I5]
692 stx %i6, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I6]
693 stx %i7, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I7]
694 wrpr %l0, 0, %cwp
695 mov %g2, %sp
696 ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I0], %i0
697 ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I1], %i1
698 ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I2], %i2
699 ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I3], %i3
700 ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I4], %i4
701 ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I5], %i5
702 ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I6], %i6
703 ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I7], %i7
704
705 /*
706 * OTHERWIN != 0 or fall-through from the OTHERWIN == 0 case.
707 * The CWP has already been restored to the value it had after the SAVE
708 * at the beginning of this function.
709 */
7100:
711.if NOT(\is_syscall)
712 rdpr %tstate, %g1
713 andcc %g1, TSTATE_PRIV_BIT, %g0 ! if we are not returning to userspace...,
714 bnz %xcc, 1f ! ...skip restoring userspace windows
715 nop
716.endif
717
718 /*
719 * Spills and fills will be processed by the {spill,fill}_1_normal
720 * handlers.
721 */
722 wrpr %g0, WSTATE_OTHER(0) | WSTATE_NORMAL(1), %wstate
723
724 /*
725 * Set primary context according to secondary context.
726 */
727 wr %g0, ASI_DMMU, %asi
728 ldxa [VA_SECONDARY_CONTEXT_REG] %asi, %g1
729 stxa %g1, [VA_PRIMARY_CONTEXT_REG] %asi
730 rd %pc, %g1
731 flush %g1
732
733 rdpr %cwp, %g1
734 rdpr %otherwin, %g2
735
736 /*
737 * Skip all OTHERWIN windows and descend to the first window
738 * in the userspace window buffer.
739 */
740 sub %g1, %g2, %g3
741 dec %g3
742 and %g3, NWINDOWS - 1, %g3
743 wrpr %g3, 0, %cwp
744
745 /*
746 * CWP is now in the window last saved in the userspace window buffer.
747 * Fill all windows stored in the buffer.
748 */
749 clr %g4
7500: andcc %g7, UWB_ALIGNMENT - 1, %g0 ! alignment check
751 bz %xcc, 0f ! %g7 is UWB_ALIGNMENT-aligned, no more windows to refill
752 nop
753
754 add %g7, -STACK_WINDOW_SAVE_AREA_SIZE, %g7
755 ldx [%g7 + L0_OFFSET], %l0
756 ldx [%g7 + L1_OFFSET], %l1
757 ldx [%g7 + L2_OFFSET], %l2
758 ldx [%g7 + L3_OFFSET], %l3
759 ldx [%g7 + L4_OFFSET], %l4
760 ldx [%g7 + L5_OFFSET], %l5
761 ldx [%g7 + L6_OFFSET], %l6
762 ldx [%g7 + L7_OFFSET], %l7
763 ldx [%g7 + I0_OFFSET], %i0
764 ldx [%g7 + I1_OFFSET], %i1
765 ldx [%g7 + I2_OFFSET], %i2
766 ldx [%g7 + I3_OFFSET], %i3
767 ldx [%g7 + I4_OFFSET], %i4
768 ldx [%g7 + I5_OFFSET], %i5
769 ldx [%g7 + I6_OFFSET], %i6
770 ldx [%g7 + I7_OFFSET], %i7
771
772 dec %g3
773 and %g3, NWINDOWS - 1, %g3
774 wrpr %g3, 0, %cwp ! switch to the preceeding window
775
776 ba %xcc, 0b
777 inc %g4
778
7790:
780 /*
781 * Switch back to the proper current window and adjust
782 * OTHERWIN, CANRESTORE, CANSAVE and CLEANWIN.
783 */
784 wrpr %g1, 0, %cwp
785 add %g4, %g2, %g2
786 cmp %g2, NWINDOWS - 2
787 bg %xcc, 2f ! fix the CANRESTORE=NWINDOWS-1 anomaly
788 mov NWINDOWS - 2, %g1 ! use dealy slot for both cases
789 sub %g1, %g2, %g1
790
791 wrpr %g0, 0, %otherwin
792 wrpr %g1, 0, %cansave ! NWINDOWS - 2 - CANRESTORE
793 wrpr %g2, 0, %canrestore ! OTHERWIN + windows in the buffer
794 wrpr %g2, 0, %cleanwin ! avoid information leak
795
7961:
797 restore
798
799.if \is_syscall
800 done
801.else
802 retry
803.endif
804
805 /*
806 * We got here in order to avoid inconsistency of the window state registers.
807 * If the:
808 *
809 * save %g6, -PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE, %sp
810 *
811 * instruction trapped and spilled a register window into the userspace
812 * window buffer, we have just restored NWINDOWS - 1 register windows.
813 * However, CANRESTORE can be only NWINDOW - 2 at most.
814 *
815 * The solution is to manually switch to (CWP - 1) mod NWINDOWS
816 * and set the window state registers so that:
817 *
818 * CANRESTORE = NWINDOWS - 2
819 * CLEANWIN = NWINDOWS - 2
820 * CANSAVE = 0
821 * OTHERWIN = 0
822 *
823 * The RESTORE instruction is therfore to be skipped.
824 */
8252:
826 wrpr %g0, 0, %otherwin
827 wrpr %g0, 0, %cansave
828 wrpr %g1, 0, %canrestore
829 wrpr %g1, 0, %cleanwin
830
831 rdpr %cwp, %g1
832 dec %g1
833 and %g1, NWINDOWS - 1, %g1
834 wrpr %g1, 0, %cwp ! CWP--
835
836.if \is_syscall
837 done
838.else
839 retry
840.endif
841
842.endm
843
844.global preemptible_handler
845preemptible_handler:
846 PREEMPTIBLE_HANDLER_TEMPLATE 0
847
848.global trap_instruction_handler
849trap_instruction_handler:
850 PREEMPTIBLE_HANDLER_TEMPLATE 1
Note: See TracBrowser for help on using the repository browser.