aboutsummaryrefslogtreecommitdiff
path: root/later/schedule.S
blob: a46654c51b6a87cdd06af8af3afa6f0684a5df4b (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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
.section ".text"
.globl schedule
// TODO: Implement Scheduler for IRQ


// Save Context
// reg = struct cpu_context*
.macro save_context reg
	str r4,  [\reg, #0x00]
	str r5,  [\reg, #0x04]
	str r6,  [\reg, #0x08]
	str r7,  [\reg, #0x0c]
	str r8,  [\reg, #0x10]
	str r9,  [\reg, #0x14]
	str r10, [\reg, #0x18]
	str r11, [\reg, #0x1c]
	str r12, [\reg, #0x20]
	str lr,  [\reg, #0x24]
.endm
// Restore Context
// reg = struct cpu_context*
.macro restore_context reg
	ldr r4, [\reg, #0x00]
	ldr r5, [\reg, #0x04]
	ldr r6, [\reg, #0x08]
	ldr r7, [\reg, #0x0c]
	ldr r8, [\reg, #0x10]
	ldr r9, [\reg, #0x14]
	ldr r10, [\reg, #0x18]
	ldr r11, [\reg, #0x1c]
	ldr r12, [\reg, #0x20]
	ldr lr , [\reg, #0x24]
.endm

// Implemented the scheduler in Assembly since the C defined was messing around with the program stacks
//  This way, I can be confident that the stacks will be unchanged
schedule:
	ldr r3, =scheduler
	// Preserve context
	ldr r0, [r3, #4]
	// r0 = struct cpu_context*
	save_context r0
	// Get the next available thread
	push {r1-r3, lr}
	bl get_next_thread
	pop {r1-r3, lr}
	ldr r1,  [r3, #0] 
	// r3 = struct Scheduler*
	// r0 = struct LL* next_thread_ll
	// r1 = struct LL* current_thread_ll
	// Check if there is a valid currently running thread
	cmp r1, #0
	beq schedule.current_thread_nexists
schedule.current_thread_exists:
	cmp r0, r1
	beq schedule.run_current
	cmp r0, #0
	moveq r0, r1 // Make the current running thread the next running thread if no next running thread
	// Next is not the same as the current
	// Preserve stack of current
	ldr r2,  [r1, #0x8] // struct Thread* current
	ldrh r1, [r2, #0x0e]
	cmp r1, #2 // THREAD_WAITING
	beq schedule.temp_status
	cmp r1, #1 // THREAD_RUNNING
	bne schedule.dont_modify_status
schedule.temp_status:
	mov r1, #0 // THREAD_READY
	strh r1, [r2, #0x0e]
schedule.dont_modify_status:
	str sp,  [r2, #0x4] // void* stack // Preserve stack
	// Preserve program counter of current
	str lr,  [r2, #0x0] // void* thread // Preserve pc
	ldr r2,  [r0, #0x8] // struct Thread* next
	// Set new stack pointer
	ldr sp,  [r2, #0x4]
	// Set the thread as running
	mov r1, #1 // THREAD_RUNNING
	strh r1,  [r2, #0x0e] // unsigned short status
	add r2,  r2, #0x18
	// Set new running thread
	str r0,  [r3, #0x0] // struct LL* next_thread_ll // Set new running thread
	// Set new context
	str r2,  [r3, #0x4] // struct cpu_context* ctx // Set new context
	b schedule.run_current
schedule.current_thread_nexists:
	// r0 = struct LL* next_thread_ll
	// r1 = 0 = struct LL* current_thread_ll
	cmp r0, #0
	beq schedule.no_next_thread
	ldr r1, [r0, #0x8]
	// r1 =  struct Thread* next_thread
	// Store system stack pointer
	ldr r2, =svcsp
	push {r1}
	ldr r1, [r2]
	cmp r1, #0
	pop {r1}
	bne schedule.dont_overwrite_sys_stack
	// Store if zero system stack
	str sp, [r2]
schedule.dont_overwrite_sys_stack:
	// Move stack to next thread's stack pointer
	ldr sp, [r1, #0x4] // void* stack
	// Store the running thread ll entry
	str r0, [r3, #0x0] // struct LL* rthread_ll
	ldr r2, [r0, #0x8] // struct Thread* thread
	mov r0, #1 // THREAD_RUNNING
	strh r0, [r2, #0x0e]
	// Set context
	add r1, r1, #0x18 // struct cpu_context*
	str r1, [r3, #0x4] // store to scheduler.ctx
schedule.run_current:
	// Restore context
	ldr r2,  [r3, #0x4] // struct cpu_context* ctx // Set new context
	restore_context r2
	// Run
	ldr r1, [r3, #0]
	// r1 = struct LL* rthread_ll
	ldr r1, [r1, #0x8]
	// r1 = struct Thread* rthread
	ldr r0, [r1, #0x0]
	// r0 = void* thread
	bx r0
schedule.no_next_thread:
	// r0 = 0 = struct LL* next_thread_ll
	// r1 = 0 = struct LL* current_thread_ll
	// No thread to run
	// Restore sys context
	ldr r0, =svccpu
	str r0, [r3, #0x4] // Store context
	ldr r0, =svcsp
	ldr r1, [r0]
	cmp r1, #0
	beq schedule.exit
	mov sp, r1 // Restore stack pointer
	mov r1, #0
	str r1, [r0] // Clear stack pointer
schedule.exit:
	// Restore register context
	ldr r2,  [r3, #0x4] // struct cpu_context* ctx // Set new context
	restore_context r2
	bx lr