commit 3014676a7f3803961c64c177f9dc6ea3eaec157f
parent 69e2d993a545881d6e15a59b29e88d82b9e223fd
Author: oblique <psyberbits@gmail.com>
Date: Sun, 18 Aug 2013 06:44:46 +0300
Use the same calling convetion that Linux kernel use for syscalls.
SWI/SVC handler use Linux ARM EABI calling convention:
r0 - r6 registers are used for the syscall arguments, it can take up to 7 arguments.
r7 register is used for the syscall number.
"swi #0" is used from calling the syscall.
Diffstat:
4 files changed, 82 insertions(+), 44 deletions(-)
diff --git a/kernel/interrupts.S b/kernel/interrupts.S
@@ -1,4 +1,5 @@
#include <p_modes.h>
+#include <errno.h>
.section .text
.global vector_table_init
@@ -73,29 +74,39 @@ reset:
undefined_insn:
movs pc, lr
-/* system call number is the swi number
- * if system call takes less than 7 arguments
- * we use r0 until r5 from userland to pass them
- * if it takes more than 6 arguments we pass a
- * pointer of the arguments at r0
- */
+@@ SWI/SVC handler use Linux ARM EABI calling convention:
+@@ r0 - r6 registers are used for the syscall arguments, it can take up to 7 arguments.
+@@ r7 register is used for the syscall number.
swi_ex:
- stmfd sp!, { r6 - r12, lr }
- mrs r6, spsr
- str r6, [sp, #-4]!
-
- ldr r6, [lr, #-4]
- bic r6, r6, #0xff000000
-
- stmfd sp!, { r4, r5 }
+ @@ save r8 - r12, lr registers
+ stmfd sp!, { r8 - r12, lr }
+ @@ save spsr register
+ mrs r8, spsr
+ str r8, [sp, #-4]!
+
+ @@ calculate the number of system calls
+ ldr r8, =syscall_table_end
+ ldr r8, [r8]
+ lsr r8, r8, #2
+
+ @@ if syscall number is out of syscall table boundaries then return -ENOSYS
+ cmp r7, r8
+ movcs r0, #-ENOSYS
+ bcs 2f
+
+ @@ prepare arguments and call the system call
+ stmfd sp!, { r4 - r6 }
ldr lr, =1f
- ldr r7, =syscall_table
- ldr pc, [r7, r6, lsl #2]
+ ldr r8, =syscall_table
+ ldr pc, [r8, r7, lsl #2]
+
+ @@ return from SWI/SVC exception handler
1:
- add sp, sp, #8
- ldr r6, [sp], #4
- msr spsr, r6
- ldmfd sp!, { r6 - r12, pc }^
+ add sp, sp, #(4 * 3)
+2:
+ ldr r8, [sp], #4
+ msr spsr, r8
+ ldmfd sp!, { r8 - r12, pc }^
prefetch_abort:
@@ save registers
diff --git a/kernel/start.S b/kernel/start.S
@@ -67,28 +67,46 @@ _start:
b 1b
3:
- /* example of calling a system call with at least 6 arguments */
+ @@ example of calling a system call with 1 argument
+ mov r0, #1
+ @@ the syscall number is 0
+ mov r7, #0
+ swi #0
+
+ @@ example of calling a system call with 4 arguments
+ mov r0, #1
+ mov r1, #2
+ mov r2, #3
+ mov r3, #4
+ @@ the syscall number is 0
+ mov r7, #1
+ swi #0
+
+ @@ example of calling a system call with 5 arguments
mov r0, #1
mov r1, #2
mov r2, #3
mov r3, #4
mov r4, #5
- mov r5, #6
+ @@ the syscall number is 0
+ mov r7, #2
swi #0
- /* example of calling a system call with more than 6 arguments */
- mov r0, #7
- str r0, [sp, #-4]!
+ @@ example of calling a system call with 7 arguments
mov r0, #1
mov r1, #2
mov r2, #3
mov r3, #4
mov r4, #5
mov r5, #6
- stmfd sp!, { r0 - r5 }
- mov r0, sp
- swi #1
- add sp, sp, #(7 * 4)
+ mov r6, #7
+ @@ the syscall number is 0
+ mov r7, #3
+ swi #0
+
+ @@ out of boundary syscall number example
+ mov r7, #1000
+ swi #0
ldr r0, =kmain
mov r1, #0
diff --git a/kernel/syscall_table.S b/kernel/syscall_table.S
@@ -1,5 +1,10 @@
.section .text
.globl syscall_table
+.globl syscall_table_end
syscall_table:
- .word sys_test_6_args
+ .word sys_test_1_args
+ .word sys_test_4_args
+ .word sys_test_5_args
.word sys_test_7_args
+syscall_table_end:
+ .word . - syscall_table
diff --git a/kernel/syscalls.c b/kernel/syscalls.c
@@ -1,26 +1,30 @@
#include <kernel.h>
long
-sys_test_6_args(u32 a1, u32 a2, u32 a3, u32 a4, u32 a5, u32 a6)
+sys_test_1_args(u32 a1)
{
- kprintf("sys_test_6_args(%d, %d, %d, %d, %d, %d)\n", a1, a2, a3, a4, a5, a6);
+ kprintf("sys_test_1_args(%d)\n", a1);
return 0;
}
-struct __test_7_args {
- u32 a1;
- u32 a2;
- u32 a3;
- u32 a4;
- u32 a5;
- u32 a6;
- u32 a7;
-};
long
-sys_test_7_args(struct __test_7_args *a)
+sys_test_4_args(u32 a1, u32 a2, u32 a3, u32 a4)
{
- kprintf("sys_test_7_args(%d, %d, %d, %d, %d, %d, %d)\n",
- a->a1, a->a2, a->a3, a->a4, a->a5, a->a6, a->a7);
+ kprintf("sys_test_4_args(%d, %d, %d, %d)\n", a1, a2, a3, a4);
+ return 0;
+}
+
+long
+sys_test_5_args(u32 a1, u32 a2, u32 a3, u32 a4, u32 a5)
+{
+ kprintf("sys_test_5_args(%d, %d, %d, %d, %d)\n", a1, a2, a3, a4, a5);
+ return 0;
+}
+
+long
+sys_test_7_args(u32 a1, u32 a2, u32 a3, u32 a4, u32 a5, u32 a6, u32 a7)
+{
+ kprintf("sys_test_7_args(%d, %d, %d, %d, %d, %d, %d)\n", a1, a2, a3, a4, a5, a6, a7);
return 0;
}