source: trunk/hal/tsar_mips32/__cpu_kentry.S @ 28

Last change on this file since 28 was 1, checked in by alain, 8 years ago

First import

File size: 9.6 KB
Line 
1/*
2 * __cpu_kentry.S - unified kernel entry point
3 *
4 * Author Ghassan Almaless  (2007,2008,2009,2010,2011,2012)
5 *
6 * Copyright (c) UPMC Sorbonne Universites
7 *
8 * This file is part of ALMOS-kernel.
9 *
10 * ALMOS-kernel is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2.0 of the License.
13 *
14 * ALMOS-kernel is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with ALMOS-kernel; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24#include <cpu-regs.h>
25#define _ALMOS_ASM_
26#include <boot-info.h>
27
28#---------------------------------------------------------------------------------
29# This file defines the unique kernel entry point in case of
30# Exception / Interrupt/Syscall for a MIPS32 processor core.
31# The base address of the segment containing this code TODO [AG]
32#---------------------------------------------------------------------------------
33
34        .section   .kentry,"ax",@progbits
35        .extern cpu_do_interrupt
36        .extern cpu_do_exception
37        .extern cpu_do_syscall
38        .extern cpu_kentry
39        .extern cpu_kexit
40        .org 0x180
41        .ent kentry
42        .global kentry
43        .global kentry_load
44        .set noat
45        .set noreorder
46
47#define SAVE_SIZE      REGS_NR*4
48
49#FIXME: PROC_WIDTH support only 4 proc clusters!
50
51#define PROC_WIDTH 2
52#define XY_WIDTH  8
53#define XY_MASK   0xFF
54#define MMU_MD_MASK  0xF
55       
56#-------------------------------------------------------------------------------
57# Kernel Entry point
58#-------------------------------------------------------------------------------
59kentry:
60        mfc0    $26,    $12               # read SR
61        andi    $26,    $26,    0x10      # KSU bitmask
62        beq     $26,    $0,     KERNEL_MODE
63        ori     $26,    $0,     0x3                   # MMU OFF value
64       
65
66LOAD_KERNEL_STACK:
67        mtc2    $26,    $1                            # set MMU OFF
68        nop
69        mfc0    $26,    $4,               # read current thread pointer ($26)
70        sw      $27,    (TLS_K1*4)($26)   # save user value
71
72        #$27 register can now be used
73        sw      $29,    (SP*4)($26)       # save user stack
74        lw          $29,        (KSP*4)($26)      # read kernel stack
75
76        ori     $27,    $0,     0xF                   # MMU old value: assumed ON
77        sw      $27,    (MMU_MD*4)($26)   # save MMU MODE
78
79        j       UNIFIED_MODE
80        or          $27,    $0,     $26       # pointer to uzone ($27)
81       
82#Use only $26 to save two values: MMU_MODE (4 bits) and XY_DATA_EXT (8bits)
83#$26 content (in hex): 0x00000MXY (M is the value of MMU_MODE and XY is ...)
84#N.B: MMU MODE is also modified by cpu_do_exception
85
86KERNEL_MODE:
87        #get old PADDR_EXT (in $26 at bits 0-7) 
88        and     $26,    $26,    $0        # $26 <= 0x00000000
89        mfc2    $26,    $24                           # $26 <= 0x??????XY
90        andi    $26,    $26,    XY_MASK   # $26 <= 0x000000XY
91        #set PADDR_EXT to point to local mem
92        mfc0    $27,    $15,    1             # read ebase
93        andi    $27,    $27,    0xFFF     # extract arch cpu id         
94        srl     $27,    $27,  PROC_WIDTH  # extract cluster xy
95        mtc2    $27,    $24                           # set XY PADDR_EXT
96
97        #get old MMU MODE (in $26 at bits 8-11)
98        mfc2    $27,    $1                            # get MMU MODE old value
99        andi    $27,    $27,  MMU_MD_MASK # $27 <= 0x0000000M
100        sll     $27,    $27,    XY_WIDTH  # $27 <= 0x00000M00
101        or      $26,    $26,    $27       # $26 <= 0x00000MXY <= (0x000000XY or 0x00000M00)
102        #set MMU OFF
103        ori     $27,    $0,     0x3                   # MMU OFF value
104        mtc2    $27,    $1                # set MMU OFF
105
106        #save old stack, MMU_MODE and PADDR_EXT
107        addiu   $27,    $29,    -(SAVE_SIZE)    # allocate a region on stack ($27)
108        sw      $29,    (SP*4)($27)             # save old stack ($29 can be used)
109
110        srl     $29,    $26,    XY_WIDTH        # $29 <= 0x0000000M
111        sw      $29,    (MMU_MD*4)($27)         # save MMU MODE
112        andi    $26,    $26,    XY_MASK         # $26 <= 0x000000XY
113        sw          $26,        (DP_EXT*4)($27)         # save old DATA PADDR EXT (0x000000XY)
114
115        or      $29,    $27,    $0                  # set new stack
116        mfc0    $26,    $4,     2                   # $26 <= this thread pointer
117       
118# $27: zone for saving the cpu registers
119# $26: current thread pointer ($this)
120# $29: kstack
121
122UNIFIED_MODE:   
123        sw      $1,         (AT*4)($27)
124        sw      $2,         (V0*4)($27)
125        sw      $3,         (V1*4)($27)
126        sw          $4,     (A0*4)($27)
127        sw          $5,     (A1*4)($27)
128        sw          $6,     (A2*4)($27)
129        sw          $7,     (A3*4)($27)
130        sw          $8,     (T0*4)($27)
131        sw          $9,     (T1*4)($27)
132        sw          $10,    (T2*4)($27)
133        sw          $11,    (T3*4)($27)
134        sw          $12,        (T4*4)($27)
135        sw          $13,        (T5*4)($27)
136        sw          $14,        (T6*4)($27)
137        sw          $15,        (T7*4)($27)
138        sw          $24,        (T8*4)($27)
139        sw          $25,        (T9*4)($27)
140        sw          $16,        (S0*4)($27)
141        sw          $17,        (S1*4)($27)
142        sw          $18,        (S2*4)($27)
143        sw          $19,        (S3*4)($27)
144        sw      $20,    (S4*4)($27)
145        sw      $21,    (S5*4)($27)
146        sw      $22,    (S6*4)($27)
147        sw      $23,    (S7*4)($27)
148        sw          $30,        (S8*4)($27)
149        sw      $28,    (GP*4)($27)
150        sw      $31,    (RA*4)($27)                 # save RA
151
152        mfc0    $16,    $14                 # Read EPC
153        sw          $16,        (EPC*4)($27)            # Save EPC
154        mflo    $14                         # read LO
155        sw          $14,        (LO*4)($27)         # save LO
156        mfhi    $15                         # read HI
157        sw          $15,        (HI*4)($27)             # save HI
158
159        mfc0    $18,    $12                             # Read current SR
160        sw      $18,    (SR*4)($27)                 # Save SR
161        srl         $3,     $18,        5           # put SR in kernel mode, IRQ disabled, clear exl
162        sll         $3,     $3,     5           # ...
163        mtc0    $3,     $12                 # Set new SR
164
165        mfc0    $17,    $13                     # read CR
166        sw          $17,        (CR*4)($27)                 # Save CR
167        andi    $1,     $17,    0x3F            # $1 <= XCODE from CP0_CR
168
169#if CPU_IN_KERNEL
170        # First signal that we are entering the kernel
171        mfc0    $4,         $15,        1           # $4 <= cpu_id     
172        andi    $4,     $4,     0x3                 # mask all but CPU_local_id
173        mfc0    $5,     $4,     2                   # read current thread pointer
174        jal                         cpu_kentry
175        addiu   $29,    $29,    -8
176        addiu   $29,    $29,    8
177#endif
178
179        # Second, depending on XCODE, call the apropriate function
180        ori         $8,     $0,     0x20                # cause syscall
181        beq         $8,     $1,     cause_sys   
182        or      $19,    $0,         $27         # for kentry_exit
183        mfc0    $5,         $15,        1                       
184        andi    $5,     $5,     0x1FF           # $5 (arg1) <= CPU(X,Y,lid)
185        or      $4,         $0,     $26         # $4 (arg0) <= this thread
186        beq     $1,     $0,     cause_int
187        or      $6,     $0,         $27             # $6 (arg2) <= regs_tbl
188       
189# Exceptions Handler
190# ---------------------------------------------
191        la          $1,     cpu_do_exception
192        jalr    $1     
193        addiu   $29,    $29,   -3*4     
194        j       kentry_exit
195        addiu   $29,    $29,    3*4
196
197# System Call Handler
198# ------------------------------------------------
199cause_sys:
200        la      $14,    cpu_do_syscall
201        addiu   $29,    $29,    -4
202        jalr    $14
203        or      $4,     $0,     $27
204        j       kentry_exit
205        or      $19,    $0,     $2
206       
207# Interrupts Handler
208# ----------------------------------------------
209cause_int:
210        la      $1,     cpu_do_interrupt
211        srl     $7,     $17,    10              # extract IP state, 4th arg
212        addiu   $29,    $29,    -4*4            # cpu_interrupt has 4 arg
213        jal     $1
214        andi    $7,     $7,     0x3F            # 6 HW IRQ LINES, 2th arg is irq_state
215
216# Kentry exit
217# ----------------------------------------------
218kentry_exit:
219#if CPU_IN_KERNEL
220        # First signal that we are exiting from the kernel
221        mfc0    $4,     $15,    1               # arg is cpu_id
222        andi    $4,     $4,     0x3             # mask all but CPU_local_id
223        mfc0    $5,     $4,     2               # read current thread pointer
224        jal     cpu_kexit
225        addiu   $29,    $29,    -8
226        addiu   $29,    $29,    8
227#endif
228        # Then load context ...
229        or      $27,    $0,     $19
230        lw      $1,     (AT*4)($27)             
231        lw      $2,     (V0*4)($27)
232        lw      $3,     (V1*4)($27)
233        lw      $4,     (A0*4)($27)
234        lw      $5,     (A1*4)($27)
235        lw      $6,     (A2*4)($27)
236        lw      $7,     (A3*4)($27)
237        lw      $8,     (T0*4)($27)
238        lw      $9,     (T1*4)($27)
239        lw      $10,    (T2*4)($27)
240        lw      $11,    (T3*4)($27)
241        lw      $12,    (T4*4)($27)
242        lw      $13,    (T5*4)($27)
243        lw      $14,    (T6*4)($27)
244        lw      $15,    (T7*4)($27)
245        lw      $24,    (T8*4)($27)
246        lw      $25,    (T9*4)($27)     
247        lw      $18,    (S2*4)($27)
248        lw      $19,    (S3*4)($27)
249        lw      $20,    (S4*4)($27)
250        lw      $21,    (S5*4)($27)
251        lw      $22,    (S6*4)($27)
252        lw      $23,    (S7*4)($27)
253        lw      $30,    (S8*4)($27)
254        lw      $28,    (GP*4)($27)
255        lw      $31,    (RA*4)($27)
256        lw      $16,    (EPC*4)($27)            # load EPC
257        lw      $29,    (SP*4)($27)             # restore SP
258        lw      $17,    (SR*4)($27)             # load SR
259        mfc0    $26,    $12                     # Read current SR
260        andi    $17,    $17,    0x1F
261        mtc0    $16,    $14                     # restore EPC
262        or      $26,    $26,    $17
263        lw      $16,    (LO*4)($27)             # load LO
264        mtc0    $26,    $12                     # setup new SR
265        lw      $17,    (HI*4)($27)             # load HI
266        mtlo    $16                             # restore LO
267        mthi    $17                             # restore HI   
268
269        lw      $16,    (S0*4)($27)
270        lw      $17,    (S1*4)($27)
271
272#TODO: optimize
273        lw      $26,    (MMU_MD*4)($27)         # load MMU MODE
274        andi    $26,    $26,    0xc
275        beq     $26,    $0,     OUT_MMU_3       # both MSB are 0 (the first two LSB are always set)
276        andi    $26,    $26,    0x8
277        beq     $26,    $0,     OUT_MMU_7       # first MSB is 0 (bit 2 is set)
278        lw      $26,    (DP_EXT*4)($27)         # load DP_EXT
279
280# Possible value for MMU:
281#In kernel mode : 0x7/0x3
282#In user mode : 0xF
283
284# DP_EXT can either be local or remote
285#Once these register set we can no longer
286#access global data
287
288        #If MMU mode was 0xF
289        lw      $27,    (TLS_K1*4)($27)         
290        mtc2    $26,    $24                     # restore DP EXT
291        ori     $26,    $0,     0xF             # MMU 0xF value
292        mtc2    $26,    $1                      # set MMU MODE
293        j       OUT_KENTRY
294        nop
295
296OUT_MMU_7:
297        #If MMU mode was 0x7 (uspace)
298        lw      $27,    (TLS_K1*4)($27)         
299        mtc2    $26,    $24                     # restore DP EXT
300        ori         $26,        $0,     0x7             # MMU 0x7 value
301        mtc2    $26,    $1                      # set MMU MODE
302        j       OUT_KENTRY
303        nop
304
305OUT_MMU_3:
306        #If MMU mode was 0x3
307        lw      $26,    (DP_EXT*4)($27)         # load DP_EXT
308        lw      $27,    (TLS_K1*4)($27)         
309        mtc2    $26,    $24                     # restore DP EXT
310        ori     $26,    $0,     0x3             # MMU 0x3 value
311        mtc2    $26,    $1                      # set MMU MODE
312        nop
313
314OUT_KENTRY:
315        nop
316        eret
317
318
319  .end kentry
320  .set reorder
321  .set at
322
323        .ent kentry_load
324kentry_load:
325        #theses nops are required to load the eret instruction
326        #while we are in virtual mode (processor pipeline) ?
327        mtc2     $26,    $1            # set MMU MODE
328        nop                     
329        nop
330        eret
331  .end kentry_load
332
333#-------------------------------------------------------------------------------
334
Note: See TracBrowser for help on using the repository browser.