* remove "\r" nonsense
[mascara-docs.git] / amd64 / bareMetalOS-0.5.2 / baremetal0.5.2 / os / syscalls / smp.asm
blobbe6c128675b24f383ddb4faa0dec98f972576934
1 ; =============================================================================
2 ; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems
3 ; Copyright (C) 2008-2011 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, RSI = Variable
98 ; OUT: Nothing
99 os_smp_enqueue:
100 push rdi
101 push rsi
102 push rcx
103 push rax
105 os_smp_enqueue_spin:
106 bt word [os_QueueLock], 0 ; Check if the mutex is free
107 jc os_smp_enqueue_spin ; If not check it again
108 lock ; The mutex was free, lock the bus
109 bts word [os_QueueLock], 0 ; Try to grab the mutex
110 jc os_smp_enqueue_spin ; Jump if we were unsuccessful
112 cmp word [os_QueueLen], 256 ; aka cpuqueuemax
113 je os_smp_enqueue_fail
115 xor ecx, ecx
116 mov rdi, cpuqueue
117 mov cx, [cpuqueuefinish]
118 shl rcx, 4 ; Quickly multiply RCX by 16
119 add rdi, rcx
121 stosq ; Store the code address from RAX
122 mov rax, rsi
123 stosq ; Store the variable
125 add word [os_QueueLen], 1
126 shr rcx, 4 ; Quickly divide RCX by 16
127 add cx, 1
128 cmp cx, [cpuqueuemax]
129 jne os_smp_enqueue_end
130 xor cx, cx ; We wrap around
131 xchg bx, bx
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), RDI = Variable
159 os_smp_dequeue:
160 push rsi
161 push rcx
163 os_smp_dequeue_spin:
164 bt word [os_QueueLock], 0 ; Check if the mutex is free
165 jc os_smp_dequeue_spin ; If not check it again
166 lock ; The mutex was free, lock the bus
167 bts word [os_QueueLock], 0 ; Try to grab the mutex
168 jc os_smp_dequeue_spin ; Jump if we were unsuccessful
170 cmp word [os_QueueLen], 0
171 je os_smp_dequeue_fail
173 xor ecx, ecx
174 mov rsi, cpuqueue
175 mov cx, [cpuqueuestart]
176 shl rcx, 4 ; Quickly multiply RCX by 16
177 add rsi, rcx
179 lodsq ; Load the code address into RAX
180 push rax
181 lodsq ; Load the variable
182 mov rdi, rax
183 pop rax
185 sub word [os_QueueLen], 1
186 shr rcx, 4 ; Quickly divide RCX by 16
187 add cx, 1
188 cmp cx, [cpuqueuemax]
189 jne os_smp_dequeue_end
190 xor cx, cx ; We wrap around
192 os_smp_dequeue_end:
193 mov word [cpuqueuestart], cx
194 pop rcx
195 pop rsi
196 btr word [os_QueueLock], 0 ; Release the lock
197 clc ; If we got here then ok
200 os_smp_dequeue_fail:
201 xor rax, rax
202 pop rcx
203 pop rsi
204 btr word [os_QueueLock], 0 ; Release the lock
207 ; -----------------------------------------------------------------------------
210 ; -----------------------------------------------------------------------------
211 ; os_smp_run -- Call the code address stored in RAX
212 ; IN: RAX = Address of code to execute
213 ; OUT: Nothing
214 os_smp_run:
215 call rax
217 ; -----------------------------------------------------------------------------
220 ; -----------------------------------------------------------------------------
221 ; os_smp_queuelen -- Returns the number of items in the processing queue
222 ; IN: Nothing
223 ; OUT: RAX = number of items in processing queue
224 os_smp_queuelen:
225 xor eax, eax
226 mov ax, [os_QueueLen]
228 ; -----------------------------------------------------------------------------
231 ; -----------------------------------------------------------------------------
232 ; os_smp_numcores -- Returns the number of cores in this computer
233 ; IN: Nothing
234 ; OUT: RAX = number of cores in this computer
235 os_smp_numcores:
236 xor eax, eax
237 mov ax, [os_NumCores]
239 ; -----------------------------------------------------------------------------
242 ; -----------------------------------------------------------------------------
243 ; os_smp_wait -- Wait until all other CPU Cores are finished processing
244 ; IN: Nothing
245 ; OUT: Nothing. All registers preserved.
246 os_smp_wait:
247 push rsi
248 push rcx
249 push rbx
250 push rax
252 call os_smp_get_id
253 mov rbx, rax
255 xor eax, eax
256 xor ecx, ecx
257 mov rsi, cpustatus
259 checkit:
260 lodsb
261 cmp rbx, rcx ; Check to see if it is looking at itself
262 je skipit ; If so then skip as it shouild be marked as busy
263 bt ax, 0 ; Check the Present bit
264 jnc skipit ; If carry is not set then the CPU does not exist
265 bt ax, 1 ; Check the Ready/Busy bit
266 jnc skipit ; If carry is not set then the CPU is Ready
267 sub rsi, 1
268 jmp checkit ; Core is marked as Busy, check it again
269 skipit:
270 add rcx, 1
271 cmp rcx, 256
272 jne checkit
274 pop rax
275 pop rbx
276 pop rcx
277 pop rsi
279 ; -----------------------------------------------------------------------------
282 ; -----------------------------------------------------------------------------
283 ; os_smp_lock -- Attempt to lock a mutex
284 ; IN: RAX = Address of lock variable
285 ; OUT: Nothing. All registers preserved.
286 os_smp_lock:
287 bt word [rax], 0 ; Check if the mutex is free (Bit 0 cleared to 0)
288 jc os_smp_lock ; If not check it again
289 lock ; The mutex was free, lock the bus
290 bts word [rax], 0 ; Try to grab the mutex (Bit 0 set to 1)
291 jc os_smp_lock ; Jump if we were unsuccessful
292 ret ; Lock acquired. Return to the caller
293 ; -----------------------------------------------------------------------------
296 ; -----------------------------------------------------------------------------
297 ; os_smp_unlock -- Unlock a mutex
298 ; IN: RAX = Address of lock variable
299 ; OUT: Nothing. All registers preserved.
300 os_smp_unlock:
301 btr word [rax], 0 ; Release the lock (Bit 0 cleared to 0)
302 ret ; Lock released. Return to the caller
303 ; -----------------------------------------------------------------------------
306 ; =============================================================================
307 ; EOF