forked from lolo859/vystem
75 lines
2.3 KiB
C
75 lines
2.3 KiB
C
// SPDX-License-Identifier: MPL-2.0
|
|
#ifndef SH_LIB_SMP_H
|
|
#define SH_LIB_SMP_H
|
|
#include "std/type.h"
|
|
#include "std/status.h"
|
|
#include "cpu/ap.h"
|
|
#include "cpu/serial.h"
|
|
#include "cpu/asm.h"
|
|
// Write GS base register
|
|
inline void sh_smp_write_gs_base(sh_uint64 value) {
|
|
sh_uint32 low=(sh_uint32)(value);
|
|
sh_uint32 high=(sh_uint32)(value>>32);
|
|
__asm__ volatile ("wrmsr"::"c"(0xC0000101),"a"(low),"d"(high));
|
|
}
|
|
// Return CPU struct of this CPU
|
|
inline sh_ap_CPU_STRUCT *sh_smp_gs_base() {
|
|
sh_uint32 low,high;
|
|
__asm__ volatile ("rdmsr":"=a"(low),"=d"(high):"c"(0xC0000101));
|
|
return (sh_ap_CPU_STRUCT*)(((sh_uint64)high<<32)|low);
|
|
}
|
|
// Lock structure, unlocked lock have lapic_id to SH_UINT32_MAX
|
|
typedef struct {
|
|
volatile sh_uint32 spinlock;
|
|
sh_uint32 lapic_id;
|
|
} sh_SPIN_LOCK;
|
|
// Create an unlocked lock, intended for creation of global variables.
|
|
#define SH_LOCK() {.spinlock=0,.lapic_id=SH_UINT32_MAX}
|
|
// Create an unlocked lock, intended for creation of local variables
|
|
#define SH_LOCK_LOCAL() ((sh_SPIN_LOCK){.spinlock=0,.lapic_id=SH_UINT32_MAX})
|
|
// Lock a spinlock
|
|
inline void sh_spin_lock(sh_SPIN_LOCK *lock) {
|
|
while (__atomic_test_and_set(&lock->spinlock,__ATOMIC_ACQUIRE)) {
|
|
while (lock->spinlock) {
|
|
__asm__ volatile ("pause");
|
|
}
|
|
}
|
|
if (sh_smp_gs_base()==SH_NULLPTR) {
|
|
sh_serial_send_byte('!');
|
|
while (SH_TRUE) {}
|
|
}
|
|
lock->lapic_id=sh_smp_gs_base()->lapic_id;
|
|
}
|
|
// Unlock a spinlock
|
|
inline void sh_spin_unlock(sh_SPIN_LOCK *lock) {
|
|
lock->lapic_id=SH_UINT32_MAX;
|
|
__atomic_clear(&lock->spinlock,__ATOMIC_RELEASE);
|
|
}
|
|
// Try to lock a spinlock, doesn't wait for it to be unlocked, return SH_TRUE if lock is now owned by us
|
|
inline sh_bool sh_spin_trylock(sh_SPIN_LOCK *lock) {
|
|
if (__atomic_test_and_set(&lock->spinlock,__ATOMIC_ACQUIRE)) return SH_FALSE;
|
|
lock->lapic_id=sh_smp_gs_base()->lapic_id;
|
|
return SH_TRUE;
|
|
}
|
|
// Return which CPU is locking the lock
|
|
inline sh_uint32 sh_spin_wholock(sh_SPIN_LOCK *lock) {
|
|
return lock->lapic_id;
|
|
}
|
|
// Set CPU count (aka max_cpu_id+1)
|
|
void sh_smp_set_cpu_count(sh_int16 cpu_count);
|
|
// Return CPU count, return -1 if this value isn't initialized
|
|
sh_int16 sh_smp_get_cpu_count();
|
|
// Memory barrier
|
|
inline void sh_mb() {
|
|
sh_asm_mfence();
|
|
}
|
|
// Read memory barrier
|
|
inline void sh_rmb() {
|
|
sh_asm_lfence();
|
|
}
|
|
// Write memory barrier
|
|
inline void sh_wmb() {
|
|
sh_asm_sfence();
|
|
}
|
|
#endif
|