Use new ARM instructions for interrupts, exceptions and system calls.
[AROS.git] / arch / arm-native / kernel / syscall.c
blob65f8c95ecf9605b44f01221d6173e6697a7315a9
1 /*
2 Copyright © 2013, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <inttypes.h>
7 #include <aros/kernel.h>
8 #include <aros/libcall.h>
10 #include <aros/arm/cpucontext.h>
12 #include <stddef.h>
13 #include <string.h>
15 #include <proto/exec.h>
16 #include <proto/kernel.h>
18 #include "kernel_cpu.h"
19 #include "kernel_intern.h"
20 #include "kernel_scheduler.h"
21 #include "kernel_intr.h"
22 #include "kernel_syscall.h"
24 extern char * __text_start;
25 extern char * __text_end;
27 #ifndef _CUSTOM
28 #define _CUSTOM NULL
29 #endif
31 #define DREGS(x)
32 #define D(x)
35 __vectorhand_swi:
37 this code currently assumes the caller is in user mode (and will break from any other mode)
39 r0 = passed to c handler, r1/r2 = temp
41 asm (
42 ".globl __vectorhand_swi \n"
43 ".type __vectorhand_swi,%function \n"
44 "__vectorhand_swi: \n"
45 VECTCOMMON_START
46 " bl handle_syscall \n"
47 VECTCOMMON_END
50 void cache_clear_e(void *addr, uint32_t length, uint32_t flags)
52 uint32_t count = 0;
54 if (addr == NULL && length == 0xffffffff)
56 count = 0x8000000;
58 else
60 void *end_addr = ((uintptr_t)addr + length + 31) & ~31;
61 addr = (void *)((uintptr_t)addr & ~31);
62 count = (uintptr_t)(end_addr - addr) >> 5;
65 D(bug("[KRN] CacheClearE from %p length %d count %d, flags %x\n", addr, length, count, flags));
67 while (count--)
69 if (flags & CACRF_ClearD)
71 __asm__ __volatile__("mcr p15, 0, %0, c7, c14, 1"::"r"(addr));
73 if (flags & CACRF_ClearI)
75 __asm__ __volatile__("mcr p15, 0, %0, c7, c5, 1"::"r"(addr));
77 if (flags & CACRF_InvalidateD)
79 __asm__ __volatile__("mcr p15, 0, %0, c7, c6, 1"::"r"(addr));
82 addr += 32;
85 __asm__ __volatile__("mcr p15, 0, %0, c7, c10, 4"::"r"(addr));
88 void handle_syscall(void *regs)
90 register unsigned int addr;
91 register unsigned int swi_no;
93 /* We determine the SWI number by reading in "tasks"
94 program counter, subtract the instruction from it and
95 obtain the value from there. we also use this to check if
96 we have been called from outwith the kernel's code (illegal!)
99 addr = ((uint32_t *)regs)[15];
100 addr -= 4;
101 swi_no = *((unsigned int *)addr) & 0x00ffffff;
103 D(bug("[KRN] ## SWI %d @ 0x%p\n", swi_no, addr));
105 if (((char*)addr < &__text_start) || ((char*)addr >= &__text_end))
107 D(bug("[KRN] ## SWI : ILLEGAL ACCESS!\n"));
108 return;
110 if (swi_no <= 0x0b || swi_no == 0x100)
112 DREGS(cpu_DumpRegs(regs));
114 switch (swi_no)
116 case SC_CLI:
118 D(bug("[KRN] ## CLI...\n"));
119 ((uint32_t *)regs)[16] |= 0x80;
120 break;
123 case SC_STI:
125 D(bug("[KRN] ## STI...\n"));
126 ((uint32_t *)regs)[16] &= ~0x80;
127 break;
130 case SC_SUPERSTATE:
132 D(bug("[KRN] ## SUPERSTATE... (0x%p ->", ((uint32_t *)regs)[16]));
133 ((uint32_t *)regs)[16] &= ~CPUMODE_MASK;
134 ((uint32_t *)regs)[16] |= (0x80 | CPUMODE_SUPERVISOR);
135 D(bug(" 0x%p)\n", ((uint32_t *)regs)[16]));
136 break;
139 case SC_ISSUPERSTATE:
141 D(bug("[KRN] ## ISSUPERSTATE... "));
142 ((uint32_t *)regs)[0] = !(((((uint32_t *)regs)[16] & CPUMODE_MASK) == CPUMODE_USER) || ((((uint32_t *)regs)[16] & CPUMODE_MASK) == CPUMODE_SYSTEM));
143 D(bug("%d\n", ((uint32_t *)regs)[0]));
144 break;
147 case SC_REBOOT:
149 D(bug("[KRN] ## REBOOT...\n"));
150 asm volatile ("mov pc, #0\n"); // Jump to the reset vector..
151 break;
154 case SC_CACHECLEARE:
156 D(bug("[KRN] ## CACHECLEARE...\n"));
157 void * address = ((void **)regs)[0];
158 uint32_t length = ((uint32_t *)regs)[1];
159 uint32_t flags = ((uint32_t *)regs)[2];
161 cache_clear_e(address, length, flags);
163 break;
167 * Execure core_SysCall only when we will go back to user mode. Default core_SysCall does
168 * not check this condition and could execute Cause() handler before IRQ is entirely handled.
170 case SC_CAUSE:
172 uint32_t mode = (((uint32_t *)regs)[16]) & 0x1f;
173 if (mode == 0x10 || mode == 0x1f)
174 core_SysCall(swi_no, regs);
175 break;
178 default:
179 core_SysCall(swi_no, regs);
180 break;
183 else
185 D(bug("[KRN] ## SWI : ILLEGAL SWI!\n"));
186 return;
189 D(bug("[KRN] ## SWI returning ..\n"));