Remove building with NOCRYPTO option
[minix.git] / minix / kernel / arch / earm / mpx.S
blobc7371e988390dc6b03309b668dfdbaa5592219e3
1 /* This file is part of the lowest layer of the MINIX kernel.  (The other part 
2  * is "proc.c".)  The lowest layer does process switching and message handling. 
3  *
4  * Kernel is entered either because of kernel-calls, ipc-calls, interrupts or
5  * exceptions. TSS is set so that the kernel stack is loaded. The user context is
6  * saved to the proc table and the handler of the event is called. Once the
7  * handler is done, switch_to_user() function is called to pick a new process,
8  * finish what needs to be done for the next process to run, sets its context
9  * and switch to userspace.
10  */
12 #include "kernel/kernel.h" /* configures the kernel */
14 /* sections */
16 #include <machine/vm.h>
17 #include "kernel/kernel.h"
18 #include <minix/config.h>
19 #include <minix/const.h>
20 #include <minix/com.h>
21 #include <machine/asm.h>
22 #include <machine/interrupt.h>
23 #include "archconst.h"
24 #include "kernel/const.h"
25 #include "kernel/proc.h"
26 #include "sconst.h"
27 #include <machine/multiboot.h>
28 #include <machine/ipcconst.h>
29 #include <machine/cpu.h>
30 #include <arm/armreg.h>
31 #include "bsp_intr.h"
33 #include "arch_proto.h" /* K_STACK_SIZE */
35 IMPORT(svc_stack)
38  * Adjust lr, push pc/psr when exception triggered and switch to SVC mode
39  * The 'lr_offset' argument holds the adjustment.
40  *
41  * When an instruction causes the ARM core to enter the exception handler
42  * the value of pc is stored in the link register (lr). By default on ARM
43  * the program counter is 3 instruction a head of the current instruction
44  * being executed (because of the 3 stage pipeline). Depending on where in
45  * the pipeline the exception happens lr will need to de adjusted to find
46  * the proper return address.
47  */
48 .macro switch_to_svc lr_offset
49         sub     lr, lr, #\lr_offset     /* do the adjustment */
50         srsdb   sp!, #PSR_SVC32_MODE    /* store the saved the return */
51                                         /* address and program status */
52                                         /* register onto the kernel stack */
53                                         /* Also modify the stack pointer. */
54         cps     #PSR_SVC32_MODE         /* do the switch to SVC. */
55 .endm
58  * Test if the exception/interrupt occurred in the kernel.
59  * Jump to 'label' argument if it occurred in the kernel.
60  *
61  * NOTE: switch_to_svc must be called first */
62 .macro test_int_in_kernel, label
63         push    {r3}
64         ldr     r3, [sp, #8]                    /* get spsr. */
65         orr     r3, r3, #(PSR_F | PSR_I)        /* mask interrupts on return. */
66         str     r3, [sp, #8]                    /* store spsr. */
67         and     r3, r3, #PSR_MODE               /* mask the ARM mode. */
68         cmp     r3, #PSR_USR32_MODE             /* compare it to user mode. */
69         pop     {r3}
70         bne     \label                          /* In-kernel handling. */
71 .endm
73 /* Save the register context to the proc structure */
74 .macro save_process_ctx
75         add     sp, sp, #8              /* We expect srsdb pushed cpsr and lr on */
76                                         /* the stack. */
77         ldr     lr, [sp]                /* lr = proc_ptr. */
78         stm     lr, {r0-r14}^           /* store the user mode registers */
79                                         /* proc_ptr->p_reg.r0-r14 = r0-r14. */
80         ldr     r12, [sp, #-8]          /* r12 = pc stored on the stack. */
81         str     r12, [lr, #PCREG]       /* proc_ptr->p_reg.pc = r12. */
82         ldr     r12, [sp, #-4]          /* r12 = cpsr stored on the stack. */
83         str     r12, [lr, #PSREG]       /* proc_ptr->p_reg.psr = r12. */
84 .endm
86 .macro exception_handler exc_name, exc_num, lr_offset
87 ENTRY(\exc_name\()_entry)
88         switch_to_svc \lr_offset
89         test_int_in_kernel \exc_name\()_entry_nested
91 \exc_name\()entry_from_user:
92         save_process_ctx
94         ldr     fp, [sp]        /* save the pointer to the current process. */
95         add     r4, fp, #PCREG  /* save the exception pc (saved lr_user) */
96                                 /* r4-r9 are callee save. */
98         /* stop user process cycles */
99         mov     r0, fp          /* first param: caller proc ptr. */
100         mov     fp, #0          /* for stack trace. */
101         bl      _C_LABEL(context_stop)
103         /*
104          * push a pointer to the interrupt state pushed by the cpu and the
105          * vector number pushed by the vector handler just before calling
106          * exception_entry and call the exception handler.
107          */
108         mov     r0, #0          /* it is not a nested exception. */
109         mov     r1, r4          /* saved lr. */
110         mov     r2, #\exc_num   /* vector number */
111         bl      _C_LABEL(exception_handler)
112         b       _C_LABEL(switch_to_user)
114 \exc_name\()_entry_nested:
115         push    {r0-r12, lr}
116         mov     r0, #1          /* it is a nested exception. */
117         add     r1, sp, #56     /* saved lr */
118         mov     r2, #\exc_num   /* vector number */
119         bl      _C_LABEL(exception_handler)
120         pop     {r0-r12, lr}
121         rfeia   sp!
122 .endm
125 /* Exception handlers */
126 exception_handler data_abort DATA_ABORT_VECTOR 8
127 exception_handler prefetch_abort PREFETCH_ABORT_VECTOR 4
128 exception_handler undefined_inst UNDEFINED_INST_VECTOR 4
131 ENTRY(irq_entry)
132         switch_to_svc 4
133         test_int_in_kernel irq_entry_from_kernel
135 irq_entry_from_user:
136         save_process_ctx
138         /* save the pointer to the current process */
139         ldr     fp, [sp]
141         push    {fp}                            /* save caller proc ptr. */
142         sub     sp, sp, #4                      /* maintain stack alignment. */
144         /* stop user process cycles */
145         mov     r0, fp                          /* first param: caller proc ptr. */
146         mov     fp, #0                          /* for stack trace. */
147         bl      _C_LABEL(context_stop)
149         /* call handler */
150         bl      _C_LABEL(bsp_irq_handle)        /* bsp_irq_handle(void) */
152         add     sp, sp, #4
153         pop     {fp}                            /* caller proc ptr. */
154         dsb                                     /* data synchronization barrier. */
156         b       _C_LABEL(switch_to_user)
158 irq_entry_from_kernel:
159         push    {r0-r12, lr}
160         bl      _C_LABEL(context_stop_idle)
162         /* call handler */
163         bl      _C_LABEL(bsp_irq_handle)        /* bsp_irq_handle(void). */
165         /* data synchronization barrier */ dsb 
166         pop     {r0-r12, lr}
167         rfeia   sp!
171  * supervisor call (SVC) kernel entry point
172  */
173 ENTRY(svc_entry)
174         /*  Store the LR and the SPSR of the current mode onto the SVC stack */
175         srsdb   sp!, #PSR_SVC32_MODE
176         save_process_ctx
178         /* save the pointer to the current process */
179         ldr     fp, [sp]
181         cmp     r3, #KERVEC_INTR
182         beq     kernel_call_entry
183         cmp     r3, #IPCVEC_INTR
184         beq     ipc_entry
186         /* return -1 to the current process as an invalid SWI was called .*/
187         mov     r0, #-1
188         str     r0, [fp, #REG0]
189         b       _C_LABEL(switch_to_user)
192  * kernel call is only from a process to kernel
193  */
194 ENTRY(kernel_call_entry)
195         /*
196          * pass the syscall arguments from userspace to the handler. 
197          * save_process_ctx() does not clobber these registers, they are still
198          * set as the userspace has set them.
199          */
200         push    {fp}                    /* save caller proc ptr. */
201         push    {r0}                    /* save msg ptr so it's not clobbered. */
203         /* stop user process cycles */
204         mov     r0, fp                  /* first param: caller proc ptr */
205         mov     fp, #0                  /* for stack trace */
206         bl      _C_LABEL(context_stop)
208         pop     {r0}                    /* first param: msg ptr. */
209         pop     {r1}                    /* second param: caller proc ptr. */
210         bl      _C_LABEL(kernel_call)
212         b       _C_LABEL(switch_to_user)
215  * IPC is only from a process to kernel
216  */
217 ENTRY(ipc_entry)
218         /*
219          * pass the syscall arguments from userspace to the handler.
220          * save_process_ctx() does not clobber these registers, they are still
221          * set as the userspace have set them
222          */
223         push    {fp}                    /* save caller proc ptr. */
224         push    {r0-r2}                 /* save regs so they're not clobbered. */
226         /* stop user process cycles */
227         mov     r0, fp                  /* first param: caller proc ptr. */
228         mov     fp, #0                  /* for stack trace. */
229         bl      _C_LABEL(context_stop)
231         pop     {r0-r2} /* restore regs */
232         bl      _C_LABEL(do_ipc)
234         /* restore the current process pointer and save the return value */
235         pop     {fp}                    /* caller proc ptr. */
236         str     r0, [fp, #REG0]
238         b       _C_LABEL(switch_to_user)
240 ENTRY(invalid_svc)
241         b       .
243 ENTRY(restore_user_context)
244         /* sp holds the proc ptr */
245         mov sp, r0
247         /* Set SPSR and LR for return */
248         ldr r0, [sp, #PSREG]
249         msr spsr_fsxc, r0               /* flags , status, extension control. */
250         ldr lr, [sp, #PCREG]
252         /* Restore user-mode registers from proc struct */
253         ldm sp, {r0-r14}^
255         ldr sp, =_C_LABEL(svc_stack)
256         ldr sp, [sp]
258         /* To user mode! */
259         movs pc, lr             /* preferred way of returning from svc */
261 /*===========================================================================*/
262 /*                              data                                         */
263 /*===========================================================================*/
265 .data
266 .short  0x526F  /* this must be the first data entry (magic #) */
267 .bss
268 .data
269 .balign 4
270 k_initial_stack:
271 .space  K_STACK_SIZE
272 LABEL(__k_unpaged_k_initial_stktop)
275  * the kernel stack
276  */
277 k_boot_stack:
278 .space  K_STACK_SIZE    /* kernel stack */ /* FIXME use macro here */
279 LABEL(k_boot_stktop)    /* top of kernel stack */
281 .balign K_STACK_SIZE
282 LABEL(k_stacks_start)
284 /* two pages for each stack, one for data, other as a sandbox */
285 .space  2 * (K_STACK_SIZE * CONFIG_MAX_CPUS)
287 LABEL(k_stacks_end)
289 /* top of kernel stack */