source: trunk/hal/tsar_mips32/core/hal_kentry.S

Last change on this file was 654, checked in by alain, 2 years ago

euh...

File size: 16.5 KB
Line 
1/*
2 * hal_kentry.S - Interrupt / Exception / Syscall kernel entry point for MIPS32
3 *
4 * AUthors   Ghassan Almaless (2007,2008,2009,2010,2011,2012)
5 *           Mohamed Lamine Karaoui (2015)
6 *           Alain Greiner (2016,2017,2018,2019)
7 *
8 * Copyright (c) UPMC Sorbonne Universites
9 *
10 * This file is part of ALMOS-MKH.
11 *
12 * ALMOS-MKH is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; version 2.0 of the License.
15 *
16 * ALMOS-MKH is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
23 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 */
25
26#define      UZ_MODE_DEXT    0             
27#define      UZ_AT           1
28#define      UZ_V0           2
29#define      UZ_V1           3
30#define      UZ_A0           4
31#define      UZ_A1           5
32#define      UZ_A2           6
33#define      UZ_A3           7
34#define      UZ_T0           8
35#define      UZ_T1           9
36#define      UZ_T2           10
37#define      UZ_T3           11
38#define      UZ_T4           12
39#define      UZ_T5           13
40#define      UZ_T6           14
41#define      UZ_T7           15
42#define      UZ_S0           16
43#define      UZ_S1           17
44#define      UZ_S2           18
45#define      UZ_S3           19
46#define      UZ_S4           20
47#define      UZ_S5           21
48#define      UZ_S6           22
49#define      UZ_S7           23
50#define      UZ_T8           24
51#define      UZ_T9           25
52
53#define      UZ_LO           26
54#define      UZ_HI           27
55
56#define      UZ_GP           28
57#define      UZ_SP           29
58#define      UZ_S8           30
59#define      UZ_RA           31
60#define      UZ_PTPR         32
61#define      UZ_EPC          33
62#define      UZ_SR           34
63#define      UZ_TH           35
64#define      UZ_CR           36
65
66#define      UZ_REGS         37
67
68#include <kernel_config.h>
69
70        .section   .kentry, "ax", @progbits
71
72        .extern    hal_do_interrupt
73        .extern    hal_do_exception
74        .extern    hal_do_syscall
75    .extern    puts
76    .extern    putx
77    .extern    putl
78
79        .org       0x180
80
81        .global    hal_kentry_enter
82    .global    hal_kentry_eret
83
84        .set       noat
85        .set       noreorder
86
87#------------------------------------------------------------------------------------
88#       Kernel Entry point for Interrupt / Exception / Syscall
89#  At kernel entry, the relevant CPU, CP0, & CP2 registers are saved
90#  in a "UZONE" implemented in  the calling thread kernel stack.
91#  All these registers are restored from the UZONE after the kernel
92#  completes the requested service.
93#
94#  Implementation note: As this code can be executed when the core is already
95#  in kernel mode (after a syscall, the core must handle interrupts, or
96#  non-fatal MMU exceptions), this code implement a two slots stack of UZONE(s).
97#------------------------------------------------------------------------------------
98
99hal_kentry_enter:
100
101#------------------------------------------------------------------------------------
102# This code made the following actions:
103# - save CP2_MMU_MODE & CP2_MMU_DEXT in $26,
104# - set local_cxy into CP2_MMU_DEXT,
105# - desactivate DATA MMU in CP2_MMU_MODE,
106# - test if the core is already in kernel mode.
107
108    mfc2    $26,    $1                  # $26 <= CP2_MMU_MODE
109        andi    $27,    $26,  0xB           # $27 <= code data MMU OFF
110        mtc2    $27,    $1                              # set data MMU OFF
111
112    mfc2    $27,    $24                 # $27 <= CP2_MMU_DEXT
113    sll     $27,    $27,  4             # $27 <= CP2_MMU_DEXT << 4
114    or      $26,    $26,  $27           # $26 <= CP2_MMU_DEXT | CP2_MMU_MODE
115
116    mfc0    $27,    $15,  1             # $27 <= core CP0_EBASE         
117    andi    $27,    $27,  0xFFF         # $27 <= gid
118    srl     $27,    $27,  2             # $27 <= local_cxy
119    mtc2    $27,    $24                 # CP2_MMU_DEXT <= local_cxy
120
121        mfc0    $27,    $12                 # $27 <= CP0_SR
122        andi    $27,    $27,  0x10          # test User Mode bit
123        beq     $27,    $0,       kernel_mode   # jump if core already in kernel
124    nop
125       
126#------------------------------------------------------------------------------------
127# This code is executed when the core is in user mode,
128# to handle a syscall, an interrupt, or an exception.
129# - copy user stack pointer in $27 to be saved in uzone.
130# - set kernel stack pointer in $29 (kernel stack empty at firts entry).
131
132user_mode:
133
134    move    $27,    $29                 # $27 <= user stack pointer
135        mfc0    $29,    $4,   2             # get pointer on thread descriptor from c0_th
136    addi    $29,    $29,  CONFIG_THREAD_DESC_SIZE
137    addi    $29,    $29,  -8            # $29 <= kernel stack pointer
138    j       unified_mode
139    nop
140
141#------------------------------------------------------------------------------------
142# This code is executed when the core is already in kernel mode,
143# (after a syscall), to handle an interrupt, or a non-fatal exception.
144# - copy current kernel stack pointer in $27.
145
146kernel_mode:
147
148    move    $27,    $29                 # $27 <= current kernel stack pointer
149    j       unified_mode
150    nop
151
152#------------------------------------------------------------------------------------   
153# This code is executed in both modes (user or kernel).
154# It executes the following actions:
155# - decrement $29 to allocate an uzone in kernel stack
156# - save GPR, CP0 and CP2 registers to uzone.
157# - set the SR in kernel mode: IRQ disabled, clear EXL.
158# The assumptions are:
159# - c2_mode contains the data MMU OFF value.
160# - $26 contains the previous c2_mode and c2_dext values.
161# - $27 contains the previous sp value (can be usp or ksp).
162# - $29 contains the current kernel stack pointer.
163
164unified_mode:
165
166        addiu   $29,    $29,  -(UZ_REGS*4)         # allocate uzone in kernel stack
167
168    sw      $26,    (UZ_MODE_DEXT*4)($29)  # save previous c2_mode and c2_dext values
169        sw      $1,         (UZ_AT*4)($29)
170        sw      $2,     (UZ_V0*4)($29)
171        sw      $3,     (UZ_V1*4)($29)
172        sw      $4,     (UZ_A0*4)($29)
173        sw      $5,     (UZ_A1*4)($29)
174        sw      $6,     (UZ_A2*4)($29)
175        sw      $7,     (UZ_A3*4)($29)
176        sw      $8,     (UZ_T0*4)($29)
177        sw      $9,     (UZ_T1*4)($29)
178        sw      $10,    (UZ_T2*4)($29)
179        sw      $11,    (UZ_T3*4)($29)
180        sw      $12,    (UZ_T4*4)($29)
181        sw      $13,    (UZ_T5*4)($29)
182        sw      $14,    (UZ_T6*4)($29)
183        sw      $15,    (UZ_T7*4)($29)
184        sw      $16,    (UZ_S0*4)($29)
185        sw      $17,    (UZ_S1*4)($29)
186        sw          $18,        (UZ_S2*4)($29)
187        sw          $19,        (UZ_S3*4)($29)
188        sw          $20,        (UZ_S4*4)($29)
189        sw          $21,        (UZ_S5*4)($29)
190        sw          $22,        (UZ_S6*4)($29)
191        sw          $23,        (UZ_S7*4)($29)
192        sw      $24,    (UZ_T8*4)($29)
193        sw      $25,    (UZ_T9*4)($29)
194
195        mflo    $1
196        sw      $1,     (UZ_LO*4)($29)         # save lo
197        mflo    $1
198        sw      $1,     (UZ_HI*4)($29)         # save hi
199
200        sw          $28,        (UZ_GP*4)($29)         # save gp
201        sw          $27,        (UZ_SP*4)($29)         # save previous sp (can be usp or ksp)
202        sw          $30,        (UZ_S8*4)($29)         # save s8
203        sw          $31,        (UZ_RA*4)($29)         # save ra
204
205        mfc0    $1,     $14
206        sw      $1,     (UZ_EPC*4)($29)        # save c0_epc
207        mfc0    $1,         $12
208        sw          $1,     (UZ_SR*4)($29)                 # save c0_sr
209        mfc0    $1,     $4,  2
210        sw      $1,         (UZ_TH*4)($29)                 # save c0_th
211        mfc0    $1,     $13   
212        sw      $1,         (UZ_CR*4)($29)                 # save c0_cr
213        mfc2    $1,     $0
214        sw      $1,     (UZ_PTPR*4)($29)           # save c2_ptpr
215
216
217    mfc0    $3,     $12                    # $3 <= c0_sr
218        srl         $3,     $3,   5
219        sll     $3,         $3,   5                    # reset 5 LSB bits
220        mtc0    $3,         $12                            # set new c0_sr
221
222#--------------------
223#if DEBUG_HAL_KENTRY
224
225    # display "enter" message
226    la      $4,     msg_enter
227    jal     puts
228    nop
229    move    $4,     $29
230    jal     putx
231    nop
232    la      $4,     msg_cycle
233    jal     puts
234    nop
235    jal     hal_time_stamp
236    nop
237    move    $4,     $2
238    jal     putd
239    nop
240    la      $4,     msg_crlf
241    jal     puts
242    nop   
243    # display saved CR value
244    la      $4,     msg_cr
245    jal     puts
246    nop
247    lw      $4,         (UZ_CR*4)($29)
248    jal     putx
249    nop
250    la      $4,     msg_crlf
251    jal     puts
252    nop   
253    # display saved SP value
254    la      $4,     msg_sp
255    jal     puts
256    nop
257    lw      $4,         (UZ_SP*4)($29)
258    jal     putx
259    nop
260    la      $4,     msg_crlf
261    jal     puts
262    nop   
263    # display saved RA value
264    la      $4,     msg_ra
265    jal     puts
266    nop
267    lw      $4,         (UZ_RA*4)($29)
268    jal     putx
269    nop
270    la      $4,     msg_crlf
271    jal     puts
272    nop   
273    # display saved TH value
274    la      $4,     msg_th
275    jal     puts
276    nop
277    lw      $4,         (UZ_TH*4)($29)
278    jal     putx
279    nop
280    la      $4,     msg_crlf
281    jal     puts
282    nop   
283    # display saved EPC value
284    la      $4,     msg_epc
285    jal     puts
286    nop
287    lw      $4,         (UZ_EPC*4)($29)
288    jal     putx
289    nop
290    la      $4,     msg_crlf
291    jal     puts
292    nop   
293    # display saved MODE & DEXT values
294    la      $4,     msg_mode
295    jal     puts
296    nop
297    lw      $4,         (UZ_MODE_DEXT*4)($29)
298    jal     putx
299    nop
300    la      $4,     msg_crlf
301    jal     puts
302    nop   
303    # display saved V0 value
304    la      $4,     msg_v0
305    jal     puts
306    nop
307    lw      $4,         (UZ_V0*4)($29)
308    jal     putx
309    nop
310    la      $4,     msg_crlf
311    jal     puts
312    nop   
313
314#endif
315#-----
316   
317#------------------------------------------------------------------------------------
318# This code handle the two-slots uzone pointers stack, and calls the relevant
319# Interrupt / Exception / Syscall handler, depending on XCODE in CP0_CR.
320# Both the hal_do_syscall() and the hal_do_exception() functions use
321# the values saved in the "uzone", but a syscall can be interrupted
322# by an interrupt, or by a non-fatal exception. Therefore, we need
323# to handle a two-slots "stack of uzones", implemented in the kernel stack,
324# using the two "current_uzone" and "previous_uzone" pointers in thread descriptor.
325# - at kernel_entry, we copy the "current_uzone" pointer to the "previous_uzone"
326#   slot, and copy the "$29" stack pointer to the "current_uzone" slot.
327# - at kernel_exit, we simply restore the "previous_uzone" value to the
328#   "current_uzone" slot.
329# For a syscall, the hal_do_syscall() function increment the uzone[EPC]
330# slot and set the return value in the uzone[V0] slot before returning.
331
332    # update "current_uzone" and "previous_uzone" pointers
333        mfc0    $4,     $4,   2             # $4 <= pointer on thread desc
334    lw      $5,     8($4)               # $5 <= current uzone pointer trom thread
335    sw      $29,    8($4)               # current uzone pointer <= $29
336    sw      $5,    12($4)               # previous uzone pointer <= current
337
338    # analyse XCODE to call relevant handler
339        mfc0    $17,    $13                 # $17 <= CR
340        andi    $17,    $17,  0x3F          # $17 <= XCODE
341        ori         $8,     $0,   0x20
342    beq     $8,     $17,  cause_sys     # go to syscall handler
343    nop
344        beq     $17,    $0,       cause_int     # go to interrupt handler
345    nop
346
347cause_excp:
348
349        jal     hal_do_exception            # call exception handler
350        nop
351        j       kentry_exit                 # jump to kentry_exit
352    nop
353
354cause_sys:
355
356        jal     hal_do_syscall              # call syscall handler                 
357    nop
358        j           kentry_exit                 # jump to kentry_exit
359        nop
360       
361cause_int:
362
363        jal     hal_do_interrupt            # call interrupt handler
364    nop
365
366# -----------------------------------------------------------------------------------
367# Kernel exit
368# - All registers saved in the uzone are restored, using the pointer on uzone,
369#   that is contained in $29.
370# - The "current_uzone" pointer in thread descriptor, that has beeen modified at
371#   kernel entry is restored from value contained in the uzone[UZ_SP] slot.
372# -----------------------------------------------------------------------------------
373
374kentry_exit:
375
376    # restore "current_uzone" pointer
377        mfc0    $4,      $4,   2            # $4 <= pointer on thread desc
378    lw      $5,   12($4)                # $5 <= previous uzone pointer from thread
379    sw      $5,    8($4)                # current uzone pointer <= previous
380
381#-------------------
382#if DEBUG_HAL_KENTRY
383
384    # display "exit" message
385    la      $4,     msg_exit
386    jal     puts
387    nop
388    move    $4,     $29
389    jal     putx
390    nop
391    la      $4,     msg_cycle
392    jal     puts
393    nop
394    jal     hal_time_stamp
395    nop
396    move    $4,     $2
397    jal     putd
398    nop
399    la      $4,     msg_crlf
400    jal     puts
401    nop   
402    # display saved CR value
403    la      $4,     msg_cr
404    jal     puts
405    nop
406    lw      $4,         (UZ_CR*4)($29)
407    jal     putx
408    nop
409    la      $4,     msg_crlf
410    jal     puts
411    nop   
412    # display saved SP value
413    la      $4,     msg_sp
414    jal     puts
415    nop
416    lw      $4,         (UZ_SP*4)($29)
417    jal     putx
418    nop
419    la      $4,     msg_crlf
420    jal     puts
421    nop   
422    # display saved RA value
423    la      $4,     msg_ra
424    jal     puts
425    nop
426    lw      $4,         (UZ_RA*4)($29)
427    jal     putx
428    nop
429    la      $4,     msg_crlf
430    jal     puts
431    nop   
432    # display saved TH value
433    la      $4,     msg_th
434    jal     puts
435    nop
436    lw      $4,         (UZ_TH*4)($29)
437    jal     putx
438    nop
439    la      $4,     msg_crlf
440    jal     puts
441    nop   
442    # display saved EPC value
443    la      $4,     msg_epc
444    jal     puts
445    nop
446    lw      $4,         (UZ_EPC*4)($29)
447    jal     putx
448    nop
449    la      $4,     msg_crlf
450    jal     puts
451    nop   
452    # display saved MODE_DEXT value
453    la      $4,     msg_mode
454    jal     puts
455    nop
456    lw      $4,         (UZ_MODE_DEXT*4)($29)
457    jal     putx
458    nop
459    la      $4,     msg_crlf
460    jal     puts
461    nop   
462    # display saved V0 value
463    la      $4,     msg_v0
464    jal     puts
465    nop
466    lw      $4,         (UZ_V0*4)($29)
467    jal     putx
468    nop
469    la      $4,     msg_crlf
470    jal     puts
471    nop   
472       
473#endif
474#-----
475   
476        # restore registers from uzone
477        or          $27,    $0, $29             # $27 <= ksp (contains &uzone)
478
479        lw          $1,     (UZ_EPC*4)($27)           
480        mtc0    $1,         $14                         # restore c0_epc from uzone
481        lw          $1,     (UZ_SR*4)($27)
482        mtc0    $1,     $12                             # restore c0_sr from uzone
483
484        lw          $26,    (UZ_HI*4)($27)
485        mthi    $26                                         # restore hi from uzone
486        lw          $26,    (UZ_LO*4)($27)
487        mtlo    $26                                         # restore lo from uzone
488
489        lw          $1,     (UZ_AT*4)($27)             
490    lw      $2,     (UZ_V0*4)($27)
491    lw      $3,     (UZ_V1*4)($27)
492        lw          $4,     (UZ_A0*4)($27)
493        lw          $5,     (UZ_A1*4)($27)
494        lw          $6,     (UZ_A2*4)($27)
495        lw          $7,     (UZ_A3*4)($27)
496        lw          $8,     (UZ_T0*4)($27)
497        lw          $9,     (UZ_T1*4)($27)
498        lw          $10,    (UZ_T2*4)($27)
499        lw          $11,    (UZ_T3*4)($27)
500        lw          $12,    (UZ_T4*4)($27)
501        lw          $13,    (UZ_T5*4)($27)
502        lw          $14,    (UZ_T6*4)($27)
503        lw          $15,    (UZ_T7*4)($27)
504        lw          $16,    (UZ_S0*4)($27)
505        lw          $17,    (UZ_S1*4)($27)
506        lw          $18,        (UZ_S2*4)($27)
507        lw          $19,    (UZ_S3*4)($27)
508        lw          $20,        (UZ_S4*4)($27)
509        lw          $21,        (UZ_S5*4)($27)
510        lw          $22,        (UZ_S6*4)($27)
511        lw          $23,        (UZ_S7*4)($27)
512        lw          $24,    (UZ_T8*4)($27)
513        lw          $25,    (UZ_T9*4)($27)     
514
515        lw          $28,        (UZ_GP*4)($27)      # restore gp_28 from uzone
516        lw          $29,        (UZ_SP*4)($27)          # restore sp_29 from uzone
517        lw          $30,        (UZ_S8*4)($27)      # restore s8_30 from uzone
518        lw          $31,        (UZ_RA*4)($27)      # restore ra_31 from uzone
519
520        lw          $26,    (UZ_MODE_DEXT*4)($27)   
521    srl     $27,    $26,  4             # $27 <= CP2_DEXT
522    mtc2    $27,    $24                 # restore c2_dest from uzone
523    andi    $27,    $26,  0xF           # $27 <= CP2_MODE
524    mtc2    $27,    $1                  # restore c2_mode from uzone
525
526# -----------------------------------------------------------------------------------
527# eret function
528# -----------------------------------------------------------------------------------
529
530hal_kentry_eret:
531    eret                                # jump to EPC, reset EXL bit
532
533    .set reorder
534    .set at
535
536#------------------------------------------------------------------------------------
537    .section .kdata
538
539msg_cr:
540    .align 2
541    .asciiz "- UZ_CR   = "
542msg_sp:
543    .align 2
544    .asciiz "- UZ_SP   = "
545msg_ra:
546    .align 2
547    .asciiz "- UZ_RA   = "
548msg_epc:
549    .align 2
550    .asciiz "- UZ_EPC  = "
551msg_th:
552    .align 2
553    .asciiz "- UZ_TH   = "
554msg_mode:
555    .align 2
556    .asciiz "- UZ_MODE = "
557msg_v0:
558    .align 2
559    .asciiz "- UZ_V0   = "
560msg_crlf:
561    .align 2
562    .asciiz "\n"
563msg_enter:
564    .align 2
565    .asciiz "\nenter kernel : &uzone = "
566msg_exit:
567    .align 2
568    .asciiz "\nexit kernel : &uzone = "
569msg_cycle:
570    .align 2
571    .asciiz " / cycle = "
572
Note: See TracBrowser for help on using the repository browser.