1 ; =============================================================================
2 ; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems
3 ; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT
6 ; =============================================================================
13 ; -----------------------------------------------------------------------------
14 ; os_smp_reset -- Resets a CPU Core
16 ; OUT: Nothing. All registers preserved.
17 ; Note: This code resets an AP
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
33 ; -----------------------------------------------------------------------------
36 ; -----------------------------------------------------------------------------
37 ; os_smp_wakeup -- Wake up a CPU Core
39 ; OUT: Nothing. All registers preserved.
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
54 ; -----------------------------------------------------------------------------
57 ; -----------------------------------------------------------------------------
58 ; os_smp_wakeup_all -- Wake up all CPU Cores
60 ; OUT: Nothing. All registers preserved.
65 mov rdi
, [os_LocalAPICAddress
]
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
74 ; -----------------------------------------------------------------------------
77 ; -----------------------------------------------------------------------------
78 ; os_smp_get_id -- Returns the APIC ID of the CPU that ran this function
80 ; OUT: RAX = CPU's APIC ID number, All other registers perserved.
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)
92 ; -----------------------------------------------------------------------------
95 ; -----------------------------------------------------------------------------
96 ; os_smp_enqueue -- Add a workload to the processing queue
97 ; IN: RAX = Address of code to execute
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
118 mov cx, [cpuqueuefinish
]
119 shl rcx
, 4 ; Quickly multiply RCX by 16
122 stosq
; Store the code address from RAX
124 stosq
; Store the variable
126 add word [os_QueueLen
], 1
127 shr rcx
, 4 ; Quickly divide RCX by 16
129 cmp cx, [cpuqueuemax
]
130 jne os_smp_enqueue_end
131 xor cx, cx ; We wrap around
134 mov [cpuqueuefinish
], cx
139 btr word [os_QueueLock
], 0 ; Release the lock
140 call os_smp_wakeup_all
141 clc ; Carry clear for success
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
158 ; OUT: RAX = Address of code to execute (Set to 0 if queue is empty)
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
176 mov cx, [cpuqueuestart
]
177 shl rcx
, 4 ; Quickly multiply RCX by 16
180 lodsq
; Load the code address into RAX
182 lodsq
; Load the variable
186 sub word [os_QueueLen
], 1
187 shr rcx
, 4 ; Quickly divide RCX by 16
189 cmp cx, [cpuqueuemax
]
190 jne os_smp_dequeue_end
191 xor cx, cx ; We wrap around
194 mov word [cpuqueuestart
], cx
197 btr word [os_QueueLock
], 0 ; Release the lock
198 clc ; If we got here then ok
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
216 call rax
; Run the code
218 ; -----------------------------------------------------------------------------
221 ; -----------------------------------------------------------------------------
222 ; os_smp_queuelen -- Returns the number of items in the processing queue
224 ; OUT: RAX = number of items in processing queue
227 mov ax, [os_QueueLen
]
229 ; -----------------------------------------------------------------------------
232 ; -----------------------------------------------------------------------------
233 ; os_smp_numcores -- Returns the number of cores in this computer
235 ; OUT: RAX = number of cores in this computer
238 mov ax, [os_NumCores
]
240 ; -----------------------------------------------------------------------------
243 ; -----------------------------------------------------------------------------
244 ; os_smp_wait -- Wait until all other CPU Cores are finished processing
246 ; OUT: Nothing. All registers preserved.
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
269 jmp checkit
; Core is marked as Busy, check it again
280 ; -----------------------------------------------------------------------------
283 ; -----------------------------------------------------------------------------
284 ; os_smp_lock -- Attempt to lock a mutex
285 ; IN: RAX = Address of lock variable
286 ; OUT: Nothing. All registers preserved.
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.
302 btr word [rax
], 0 ; Release the lock (Bit 0 cleared to 0)
303 ret ; Lock released. Return to the caller
304 ; -----------------------------------------------------------------------------
307 ; =============================================================================