summaryrefslogtreecommitdiff
path: root/sys/arch/arm32/boot/swiv.S
blob: 6e42afaa9d51055af362f6c5cb662bfd106e830b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include "regs.h"

	.text

SWIReturnInst:
	ldr	pc, [sp, #0*4]

	.global	_swix
_swix:
	orr	r0, r0, #0x20000

	.global	_swi
_swi:

/*
 * Construct a stack frame that looks something like this:
 *       returnval
 *       LDMIA   r12!, {r0..rn}
 *       SWI     xxxxxx
 *       LDR     pc, [sp]
 *       saved r4-r11,lr
 *       saved r1
 *       saved input values (r2...rn)
 */

	mov	pc, lr

	stmfd	sp!, {r1-r3}		/* Save r1 and put 1st two variadic args on stack */
	bic	r2, r0, #0xff000000
	orr	r2, r2, #0xef000000	/* Construct SWI instruction */
	adr	r0, SWIReturn
	tst	r1, #0x20000		/* bit for write flags */
	adrne	r0, SWIReturnFlags
	bic	r1, r1, #0xff000000	/* Construct LDMIA R12!, {regs} instruction, if */
	bics	r1, r1, #0x00ff0000	/* {regs} = {} (IE no input regs) we must not */
	orrne	r1, r1, #0xe8000000	/* use an LDMIA R12!, {} instruction as this is an */
	orrne	r1, r1, #0x00bc0000	/* invalid instruction, we use a suitable NOP instead */
	moveq	r1, #0			/* 0 = opcode for ANDEQ r0, r0, r0 (a suitable NOP) */
	ldr	r3, SWIReturnInst
	stmfd	sp!, {r0-r9, r11, lr}	/* Save regs and set up SWI call routine (in R0-R3) */
	add	r12, sp, #(12+1)*4	/* Point R12 at input regs on stack. */
	add	pc, sp, #4		/* Call routine on stack */
SWIReturnFlags:
	ldr	r11, [r12], #4
	str	pc, [r11]		/* write flags */
SWIReturn:
	ldr	lr, [sp, #(12+0)*4]	/* Fetch reg mask again */
	movs	lr, lr, asl #1		/* Shift out setting C if R0 to be written, N */
	ldrcs	r11, [r12], #4		/* if R1 to be written. */
	strcs	r0, [r11]
	ldrmi	r11, [r12], #4
	strmi	r1, [r11]
	movs	lr, lr, asl #2		/* Shift 2 bits each time for the next 2 regs */
	ldrcs	r11, [r12], #4
	strcs	r2, [r11]
	ldrmi	r11, [r12], #4
	strmi	r3, [r11]
	movs	lr, lr, asl #2
	ldrcs	r11, [r12], #4
	strcs	r4, [r11]
	ldrmi	r11, [r12], #4
	strmi	r5, [r11]
	movs	lr, lr, asl #2
	ldrcs	r11, [r12], #4
	strcs	r6, [r11]
	ldrmi	r11, [r12], #4
	strmi	r7, [r11]
	movs	lr, lr, asl #2
	ldrcs	r11, [r12], #4
	strcs	r8, [r11]
	ldrmi	r11, [r12], #4
	strmi	r9, [r11]
	ldr	r1, [sp, #2*4]
	tst	r1, #0x20000		/* X-bit clear */
	cmpeq	pc, #0x80000000		/* SET V flag if so, so R0 not cleared */
	movvc	r0, #0			/* Clear R0 if no error (or X-bit clear) */
	add	sp, sp, #4*4		/* Drop SWI call routine */
	ldmia	sp!, {r4-r9,r11,lr}
	add	sp, sp, #3*4		/* Drop saved R1 and 1st two variadic args. */
	movs	pc, lr