ARM instructions are always LE, even in big endian mode. Remember that when fetching...
[AROS.git] / arch / arm-native / kernel / syscall.c
blob629af8a16c1883400ba83ff1667fbfd94b8d23aa
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 = (void*)(((uintptr_t)addr + length + 31) & ~31);
61 addr = (void *)((uintptr_t)addr & ~31);
62 count = (uintptr_t)(end_addr - addr) >> 5;
65 D(bug("[Kernel] 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!)
98 Keep in mind ARM instructions are *always* little endian, remmeber
99 it when extracting SWI number...
102 addr = ((uint32_t *)regs)[15];
103 addr -= 4;
104 swi_no = AROS_LE2LONG(*((unsigned int *)addr)) & 0x00ffffff;
106 D(bug("[Kernel] ## SWI %d @ 0x%p\n", swi_no, addr));
108 if (((char*)addr < &__text_start) || ((char*)addr >= &__text_end))
110 D(bug("[Kernel] ## SWI : ILLEGAL ACCESS!\n"));
111 return;
113 if (swi_no <= 0x0b || swi_no == 0x100)
115 DREGS(cpu_DumpRegs(regs));
117 switch (swi_no)
119 case SC_CLI:
121 D(bug("[Kernel] ## CLI...\n"));
122 ((uint32_t *)regs)[16] |= (1 << 7);
123 break;
126 case SC_STI:
128 D(bug("[Kernel] ## STI...\n"));
129 ((uint32_t *)regs)[16] &= ~(1 << 7);
130 break;
133 case SC_SUPERSTATE:
135 D(bug("[Kernel] ## SUPERSTATE... (0x%p ->", ((uint32_t *)regs)[16]));
136 ((uint32_t *)regs)[16] &= ~(CPUMODE_MASK);
137 ((uint32_t *)regs)[16] |= (0x80 | CPUMODE_SYSTEM);
138 D(bug(" 0x%p)\n", ((uint32_t *)regs)[16]));
139 break;
142 case SC_GETCPUNUMBER:
144 ((uint32_t *)regs)[0] = GetCPUNumber();
145 break;
148 case SC_ISSUPERSTATE:
150 D(bug("[Kernel] ## ISSUPERSTATE... "));
151 ((uint32_t *)regs)[0] = !(((((uint32_t *)regs)[16] & CPUMODE_MASK) == CPUMODE_USER));
152 D(bug("%d\n", ((uint32_t *)regs)[0]));
153 break;
156 case SC_REBOOT:
158 D(bug("[Kernel] ## REBOOT...\n"));
159 asm volatile ("mov pc, #0\n"); // Jump to the reset vector..
160 break;
163 case SC_CACHECLEARE:
165 D(bug("[Kernel] ## CACHECLEARE...\n"));
166 void * address = ((void **)regs)[0];
167 uint32_t length = ((uint32_t *)regs)[1];
168 uint32_t flags = ((uint32_t *)regs)[2];
170 cache_clear_e(address, length, flags);
172 break;
176 * Execure core_SysCall only when we will go back to user mode. Default core_SysCall does
177 * not check this condition and could execute Cause() handler before IRQ is entirely handled.
180 default:
182 uint32_t mode = (((uint32_t *)regs)[16]) & 0x1f;
183 if (mode == 0x10 || mode == 0x1f)
184 core_SysCall(swi_no, regs);
185 break;
189 else
191 D(bug("[Kernel] ## SWI : ILLEGAL SWI!\n"));
192 return;
195 D(bug("[Kernel] ## SWI returning ..\n"));