* mikeOS 16 bit and amd64 baremetal
[mascara-docs.git] / amd64 / bareMetalOS-0.5.3 / os / syscalls / smp.asm
blobd1be87102cd4bcbc153f489ad1749e085143c2ef
1 ; =============================================================================
2 ; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems
3 ; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT
5 ; SMP Functions
6 ; =============================================================================
8 align 16
9 db 'DEBUG: SMP '
10 align 16
13 ; -----------------------------------------------------------------------------
14 ; os_smp_reset -- Resets a CPU Core
15 ; IN: AL = CPU #
16 ; OUT: Nothing. All registers preserved.
17 ; Note: This code resets an AP
18 ; For setup use only.
19 os_smp_reset:
20 push rdi
21 push rax
23 mov rdi, [os_LocalAPICAddress]
24 shl eax, 24 ; AL holds the CPU #, shift left 24 bits to get it into 31:24, 23:0 are reserved
25 mov [rdi+0x0310], eax ; Write to the high bits first
26 xor eax, eax ; Clear EAX, namely bits 31:24
27 mov al, 0x81 ; Execute interrupt 0x81
28 mov [rdi+0x0300], eax ; Then write to the low bits
30 pop rax
31 pop rdi
32 ret
33 ; -----------------------------------------------------------------------------
36 ; -----------------------------------------------------------------------------
37 ; os_smp_wakeup -- Wake up a CPU Core
38 ; IN: AL = CPU #
39 ; OUT: Nothing. All registers preserved.
40 os_smp_wakeup:
41 push rdi
42 push rax
44 mov rdi, [os_LocalAPICAddress]
45 shl eax, 24 ; AL holds the CPU #, shift left 24 bits to get it into 31:24, 23:0 are reserved
46 mov [rdi+0x0310], eax ; Write to the high bits first
47 xor eax, eax ; Clear EAX, namely bits 31:24
48 mov al, 0x80 ; Execute interrupt 0x80
49 mov [rdi+0x0300], eax ; Then write to the low bits
51 pop rax
52 pop rdi
53 ret
54 ; -----------------------------------------------------------------------------
57 ; -----------------------------------------------------------------------------
58 ; os_smp_wakeup_all -- Wake up all CPU Cores
59 ; IN: Nothing.
60 ; OUT: Nothing. All registers preserved.
61 os_smp_wakeup_all:
62 push rdi
63 push rax
65 mov rdi, [os_LocalAPICAddress]
66 xor eax, eax
67 mov [rdi+0x0310], eax ; Write to the high bits first
68 mov eax, 0x000C0080 ; Execute interrupt 0x80
69 mov [rdi+0x0300], eax ; Then write to the low bits
71 pop rax
72 pop rdi
73 ret
74 ; -----------------------------------------------------------------------------
77 ; -----------------------------------------------------------------------------
78 ; os_smp_get_id -- Returns the APIC ID of the CPU that ran this function
79 ; IN: Nothing
80 ; OUT: RAX = CPU's APIC ID number, All other registers perserved.
81 os_smp_get_id:
82 push rsi
84 xor eax, eax
85 mov rsi, [os_LocalAPICAddress]
86 add rsi, 0x20 ; Add the offset for the APIC ID location
87 lodsd ; APIC ID is stored in bits 31:24
88 shr rax, 24 ; AL now holds the CPU's APIC ID (0 - 255)
90 pop rsi
91 ret
92 ; -----------------------------------------------------------------------------
95 ; -----------------------------------------------------------------------------
96 ; os_smp_enqueue -- Add a workload to the processing queue
97 ; IN: RAX = Address of code to execute
98 ; RSI = Variable
99 ; OUT: Nothing
100 os_smp_enqueue:
101 push rdi
102 push rsi
103 push rcx
104 push rax
106 os_smp_enqueue_spin:
107 bt word [os_QueueLock], 0 ; Check if the mutex is free
108 jc os_smp_enqueue_spin ; If not check it again
109 lock ; The mutex was free, lock the bus
110 bts word [os_QueueLock], 0 ; Try to grab the mutex
111 jc os_smp_enqueue_spin ; Jump if we were unsuccessful
113 cmp word [os_QueueLen], 256 ; aka cpuqueuemax
114 je os_smp_enqueue_fail
116 xor ecx, ecx
117 mov rdi, cpuqueue
118 mov cx, [cpuqueuefinish]
119 shl rcx, 4 ; Quickly multiply RCX by 16
120 add rdi, rcx
122 stosq ; Store the code address from RAX
123 mov rax, rsi
124 stosq ; Store the variable
126 add word [os_QueueLen], 1
127 shr rcx, 4 ; Quickly divide RCX by 16
128 add cx, 1
129 cmp cx, [cpuqueuemax]
130 jne os_smp_enqueue_end
131 xor cx, cx ; We wrap around
133 os_smp_enqueue_end:
134 mov [cpuqueuefinish], cx
135 pop rax
136 pop rcx
137 pop rsi
138 pop rdi
139 btr word [os_QueueLock], 0 ; Release the lock
140 call os_smp_wakeup_all
141 clc ; Carry clear for success
144 os_smp_enqueue_fail:
145 pop rax
146 pop rcx
147 pop rsi
148 pop rdi
149 btr word [os_QueueLock], 0 ; Release the lock
150 stc ; Carry set for failure (Queue full)
152 ; -----------------------------------------------------------------------------
155 ; -----------------------------------------------------------------------------
156 ; os_smp_dequeue -- Dequeue a workload from the processing queue
157 ; IN: Nothing
158 ; OUT: RAX = Address of code to execute (Set to 0 if queue is empty)
159 ; RDI = Variable
160 os_smp_dequeue:
161 push rsi
162 push rcx
164 os_smp_dequeue_spin:
165 bt word [os_QueueLock], 0 ; Check if the mutex is free
166 jc os_smp_dequeue_spin ; If not check it again
167 lock ; The mutex was free, lock the bus
168 bts word [os_QueueLock], 0 ; Try to grab the mutex
169 jc os_smp_dequeue_spin ; Jump if we were unsuccessful
171 cmp word [os_QueueLen], 0
172 je os_smp_dequeue_fail
174 xor ecx, ecx
175 mov rsi, cpuqueue
176 mov cx, [cpuqueuestart]
177 shl rcx, 4 ; Quickly multiply RCX by 16
178 add rsi, rcx
180 lodsq ; Load the code address into RAX
181 push rax
182 lodsq ; Load the variable
183 mov rdi, rax
184 pop rax
186 sub word [os_QueueLen], 1
187 shr rcx, 4 ; Quickly divide RCX by 16
188 add cx, 1
189 cmp cx, [cpuqueuemax]
190 jne os_smp_dequeue_end
191 xor cx, cx ; We wrap around
193 os_smp_dequeue_end:
194 mov word [cpuqueuestart], cx
195 pop rcx
196 pop rsi
197 btr word [os_QueueLock], 0 ; Release the lock
198 clc ; If we got here then ok
201 os_smp_dequeue_fail:
202 xor rax, rax
203 pop rcx
204 pop rsi
205 btr word [os_QueueLock], 0 ; Release the lock
208 ; -----------------------------------------------------------------------------
211 ; -----------------------------------------------------------------------------
212 ; os_smp_run -- Call the code address stored in RAX
213 ; IN: RAX = Address of code to execute
214 ; OUT: Nothing
215 os_smp_run:
216 call rax ; Run the code
218 ; -----------------------------------------------------------------------------
221 ; -----------------------------------------------------------------------------
222 ; os_smp_queuelen -- Returns the number of items in the processing queue
223 ; IN: Nothing
224 ; OUT: RAX = number of items in processing queue
225 os_smp_queuelen:
226 xor eax, eax
227 mov ax, [os_QueueLen]
229 ; -----------------------------------------------------------------------------
232 ; -----------------------------------------------------------------------------
233 ; os_smp_numcores -- Returns the number of cores in this computer
234 ; IN: Nothing
235 ; OUT: RAX = number of cores in this computer
236 os_smp_numcores:
237 xor eax, eax
238 mov ax, [os_NumCores]
240 ; -----------------------------------------------------------------------------
243 ; -----------------------------------------------------------------------------
244 ; os_smp_wait -- Wait until all other CPU Cores are finished processing
245 ; IN: Nothing
246 ; OUT: Nothing. All registers preserved.
247 os_smp_wait:
248 push rsi
249 push rcx
250 push rbx
251 push rax
253 call os_smp_get_id
254 mov rbx, rax
256 xor eax, eax
257 xor ecx, ecx
258 mov rsi, cpustatus
260 checkit:
261 lodsb
262 cmp rbx, rcx ; Check to see if it is looking at itself
263 je skipit ; If so then skip as it shouild be marked as busy
264 bt ax, 0 ; Check the Present bit
265 jnc skipit ; If carry is not set then the CPU does not exist
266 bt ax, 1 ; Check the Ready/Busy bit
267 jnc skipit ; If carry is not set then the CPU is Ready
268 sub rsi, 1
269 jmp checkit ; Core is marked as Busy, check it again
270 skipit:
271 add rcx, 1
272 cmp rcx, 256
273 jne checkit
275 pop rax
276 pop rbx
277 pop rcx
278 pop rsi
280 ; -----------------------------------------------------------------------------
283 ; -----------------------------------------------------------------------------
284 ; os_smp_lock -- Attempt to lock a mutex
285 ; IN: RAX = Address of lock variable
286 ; OUT: Nothing. All registers preserved.
287 os_smp_lock:
288 bt word [rax], 0 ; Check if the mutex is free (Bit 0 cleared to 0)
289 jc os_smp_lock ; If not check it again
290 lock ; The mutex was free, lock the bus
291 bts word [rax], 0 ; Try to grab the mutex (Bit 0 set to 1)
292 jc os_smp_lock ; Jump if we were unsuccessful
293 ret ; Lock acquired. Return to the caller
294 ; -----------------------------------------------------------------------------
297 ; -----------------------------------------------------------------------------
298 ; os_smp_unlock -- Unlock a mutex
299 ; IN: RAX = Address of lock variable
300 ; OUT: Nothing. All registers preserved.
301 os_smp_unlock:
302 btr word [rax], 0 ; Release the lock (Bit 0 cleared to 0)
303 ret ; Lock released. Return to the caller
304 ; -----------------------------------------------------------------------------
307 ; =============================================================================
308 ; EOF