1 ; =============================================================================
2 ; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems
3 ; Copyright (C) 2008-2011 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, RSI = Variable
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
117 mov cx, [cpuqueuefinish
]
118 shl rcx
, 4 ; Quickly multiply RCX by 16
121 stosq
; Store the code address from RAX
123 stosq
; Store the variable
125 add word [os_QueueLen
], 1
126 shr rcx
, 4 ; Quickly divide RCX by 16
128 cmp cx, [cpuqueuemax
]
129 jne os_smp_enqueue_end
130 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), RDI = Variable
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
175 mov cx, [cpuqueuestart
]
176 shl rcx
, 4 ; Quickly multiply RCX by 16
179 lodsq
; Load the code address into RAX
181 lodsq
; Load the variable
185 sub word [os_QueueLen
], 1
186 shr rcx
, 4 ; Quickly divide RCX by 16
188 cmp cx, [cpuqueuemax
]
189 jne os_smp_dequeue_end
190 xor cx, cx ; We wrap around
193 mov word [cpuqueuestart
], cx
196 btr word [os_QueueLock
], 0 ; Release the lock
197 clc ; If we got here then ok
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
217 ; -----------------------------------------------------------------------------
220 ; -----------------------------------------------------------------------------
221 ; os_smp_queuelen -- Returns the number of items in the processing queue
223 ; OUT: RAX = number of items in processing queue
226 mov ax, [os_QueueLen
]
228 ; -----------------------------------------------------------------------------
231 ; -----------------------------------------------------------------------------
232 ; os_smp_numcores -- Returns the number of cores in this computer
234 ; OUT: RAX = number of cores in this computer
237 mov ax, [os_NumCores
]
239 ; -----------------------------------------------------------------------------
242 ; -----------------------------------------------------------------------------
243 ; os_smp_wait -- Wait until all other CPU Cores are finished processing
245 ; OUT: Nothing. All registers preserved.
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
268 jmp checkit
; Core is marked as Busy, check it again
279 ; -----------------------------------------------------------------------------
282 ; -----------------------------------------------------------------------------
283 ; os_smp_lock -- Attempt to lock a mutex
284 ; IN: RAX = Address of lock variable
285 ; OUT: Nothing. All registers preserved.
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.
301 btr word [rax
], 0 ; Release the lock (Bit 0 cleared to 0)
302 ret ; Lock released. Return to the caller
303 ; -----------------------------------------------------------------------------
306 ; =============================================================================