-
Notifications
You must be signed in to change notification settings - Fork 0
/
3140.s
104 lines (84 loc) · 2.89 KB
/
3140.s
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
AREA myData, DATA, READWRITE
;global variable in assembly
OrigStackPointer DCD 0x00
AREA myProg, CODE, READONLY
;export assembly functions
EXPORT process_terminated
EXPORT process_begin
EXPORT process_blocked
EXPORT PIT0_IRQHandler
EXPORT SVC_Handler
;import C functions
IMPORT process_select
PRESERVE8
TFLG EQU 0x4003710C ; TFLG address
CTRL EQU 0x40037108 ; Ctrl address
SHCSR EQU 0xE000ED20
SVC_Handler
LDR R1, [SP,#24] ; Read PC of SVC instruction
LDRB R0, [R1,#-2] ; Get #N from SVC instruction
ADR R1, SVC_Table
LDR PC, [R1,R0,LSL #2] ; Branch to Nth SVC routine
SVC_Table
DCD SVC0_begin
DCD SVC1_terminate
DCD PIT0_IRQHandler ; Use system tick as SVC2 handler
SVC0_begin
PUSH {R4-R11,LR}
;******* Store Original Stack Pointer ********
LDR R1, =OrigStackPointer
STR SP, [R1]
;********************************************
SVC1_terminate
MOVS R0, #0
B do_process_select
process_terminated
CPSIE i ; Enable global interrupts, just in case
SVC #1 ; SVC1 = process terminated
; This SVC shouldn't ever return, as it would mean the process was scheduled again
process_begin
CPSIE i ; Enable global interrupts (for SVC)
SVC #0 ; Syscall into scheduler
BX LR
process_blocked
CPSIE i ; Enable global interrupts, just in case
SVC #2 ; SVC2 = process blocked
BX LR
PIT0_IRQHandler ; Timer Interrupt
CPSID i ; Disable all interrupts
PUSH {R4-R11,LR} ; save registers
;----store scheduling timer state----
LDR R1, =CTRL
LDR R0, [R1]
PUSH {R0}
;---clear the interrupt flag----
LDR R4, =TFLG
MOVS R1, #1
STR R1, [R4]
;-------------------------------
;move sp to r0 to prepare for process_select
MOV R0, SP
do_process_select
;******* Load Original Stack Pointer ********
; We want the process select function to run on the "main" stack
; This helps reduce funkiness when a process stack is too small and process_select overwrites other memory
LDR R1, =OrigStackPointer
LDR SP, [R1]
;********************************************
BL process_select ;Process_select returns 0 if there are no processes left
CMP R0, #0
BNE resume_process ;take branch if there are more processes
; Disable scheduling timer before returning to initial caller
LDR R1, =CTRL
MOVS R0, #0
STR R0, [R1]
POP {R4-R11,PC} ; Restore calle-save state and return
resume_process
MOV SP, R0 ;switch stacks
;---- restore scheduling timer state
POP {R0}
LDR R1, =CTRL
STR R0, [R1]
CPSIE I ; Enable global interrupts before returning from handler
POP {R4-R11,PC} ; Restore registers that aren't saved by interrupt, and return from interrupt
END