vm: fix a null dereference on out-of-memory
[minix.git] / lib / libc / arch / arm / sys-minix / ucontext.S
blob9fd6c7ed26adcde173ca0e3365cc6d57362f4df5
1 #include <machine/asm.h>
2 #include <ucontextoffsets.h>
5 IMPORT(getuctx)
6 IMPORT(setuctx)
7 IMPORT(resumecontext)
10 /* MCF_MAGIC value from <mcontext.h> */
11 #define MCF_MAGIC       0xc0ffee
13 /* Values from <sys/ucontext.h> */
14 #define UCF_IGNFPU      0x002
15 #define UCF_IGNSIGM     0x004
18 /* EINVAL from errno.h */
19 #define EFAULT          14
20 #define EINVAL          22
22 /* int getcontext(ucontext_t *ucp)
23  *      Initialise the structure pointed to by ucp to the current user context
24  *      of the calling thread. */
25 ENTRY(getcontext)
26         /* In case a process does not use the FPU and is neither interested in
27          * saving its signal mask, then we can skip the context switch to
28          * PM and kernel altogether and only save general-purpose registers. */
30         mov r3, lr              /* Save return address:
31                                  * When setcontext or swapcontext is called,
32                                  * we jump to this address and continue
33                                  * running. */
35         /* r0 = ucp */
37         /* Check null pointer */
38         cmp r0, #0                      /* ucp == NULL? */
39         bne 3f                          /* Not null, continue */
40         mov r1, #EFAULT
41         ldr r2, =_C_LABEL(errno)
42         str r1, [r2]                    /* errno = EFAULT */
43         mov r0, #-1                     /* return -1 */
44         bx lr
46 3:      /* Check flags */
47         ldr r1, [r0, #UC_FLAGS]         /* r1 = ucp->uc_flags */
48         mov r2, #(UCF_IGNFPU | UCF_IGNSIGM)
49         cmp r1, r2                      /* is UCF_IGNFPU or UCF_IGNSIGM set? */
50         beq 1f                          /* Both are set, skip getuctx */
53         push {r0, r3}
54         bl _C_LABEL(getuctx)            /* getuctx(ucp) */
55         pop {r0, r3}
58         /* Save the context */
59         mov lr, r3              /* Restore lr */
60         str lr, [r0, #LRREG]    /* Save lr */
61         str lr, [r0, #PCREG]    /* Save real RTA in mcp struct */
62         str sp, [r0, #SPREG]    /* Save stack pointer */
63         str fp, [r0, #FPREG]            /* Save fp */
64         str r4, [r0, #REG4]             /* Save r4 */
65         str r5, [r0, #REG5]             /* Save r5 */
66         str r6, [r0, #REG6]             /* Save r6 */
67         str r7, [r0, #REG7]             /* Save r7 */
68         str r8, [r0, #REG8]             /* Save r8 */
69         str r9, [r0, #REG9]             /* Save r9 */
70         str r10, [r0, #REG10]           /* Save r10 */
72         ldr r1, =MCF_MAGIC
73         str r1, [r0, #MAGIC]    /* Set magic value */
75         mov r1, #0
76         str r1, [r0, #REG0]             /* Return 0 */
77         mov r0, #0                      /* Return 0 */
80         bx lr                   /* Restore return address */
83 /* int setcontext(const ucontext_t *ucp)
84  *      Restore the user context pointed to by ucp. A successful call to
85  *      setcontext does not return; program execution resumes at the point
86  *      specified by the ucp argument. If ucp was created with getcontext(),
87  *      program execution continues as if the corresponding call of getcontext()
88  *      had just returned. If ucp was created with makecontext(), program
89  *      execution continues with the function passed to makecontext(). */
90 ENTRY(setcontext)
91         /* In case a process does not use the FPU and is neither interested in
92          * restoring its signal mask, then we can skip the context switch to
93          * PM and kernel altogether and restore state here. */
95         /* r0 = ucp */
97         /* Check null pointer */
98         cmp r0, #0                      /* ucp == NULL? */
99         bne 3f                          /* Not null, continue */
100         mov r1, #EFAULT
101         ldr r2, =_C_LABEL(errno)
102         str r1, [r2]                    /* errno = EFAULT */
103         mov r0, #-1                     /* return -1 */
104         bx lr
106 3:      /* Check flags */
107         ldr r1, [r0, #MAGIC]            /* r1 = ucp->mc_context.mc_magic */
108         ldr r2, =MCF_MAGIC
109         cmp r1, r2              /* is the magic value set (is context valid)?*/
110         beq 4f                          /* is set, proceed */
111         mov r1, #EINVAL                 /* not set, return error code */
112         ldr r2, =_C_LABEL(errno)
113         str r1, [r2]                    /* errno = EINVAL */
114         mov r0, #-1                     /* return -1 */
115         bx lr
118 4:      ldr r1, [r0, #UC_FLAGS]         /* r1 = ucp->uc_flags */
119         mov r2, #(UCF_IGNFPU | UCF_IGNSIGM)
120         cmp r1, r2              /* Are UCF_IGNFPU and UCF_IGNSIGM flags set? */
121         beq 1f                  /* Both are set, so don't bother restoring FPU
122                                  * state and signal mask */
124         push {r0, r3}
125 0:      bl _C_LABEL(setuctx)            /* setuctx(ucp) */
126         pop {r0, r3}
128 1:      /* Restore the registers */
129         ldr r1,  [r0, #REG1]            /* Restore r1 */
130         ldr r2,  [r0, #REG2]            /* Restore r2 */
131         ldr r3,  [r0, #REG3]            /* Restore r3 */
132         ldr r4,  [r0, #REG4]            /* Restore r4 */
133         ldr r5,  [r0, #REG5]            /* Restore r5 */
134         ldr r6,  [r0, #REG6]            /* Restore r6 */
135         ldr r7,  [r0, #REG7]            /* Restore r7 */
136         ldr r8,  [r0, #REG8]            /* Restore r8 */
137         ldr r9,  [r0, #REG9]            /* Restore r9 */
138         ldr r10, [r0, #REG10]           /* Restore r10 */
139         ldr r12, [r0, #REG12]           /* Restore r12 */
140         ldr fp,  [r0, #FPREG]           /* Restore fp */
141         ldr sp,  [r0, #SPREG]           /* Restore sp */
142         ldr lr,  [r0, #LRREG]           /* Restore lr */
143         mov r4, r0
144         ldr r0,  [r4, #REG0]            /* Restore r0 */
146         ldr pc,  [r4, #PCREG]           /* Restore pc */
149 /* void ctx_start()
150  *      A wrapper to call resumecontext. Makecontext puts the ucp in r4.
151  *      This function moves the ucp into r0 so that the ucp is the first
152  *      parameter for resumecontext. The call to resumecontext will start
153  *      the next context in the linked list (or exit the program if there
154  *      is no context). */
155 ENTRY(ctx_start)
156         mov r0, r4
157         b _C_LABEL(resumecontext)