forked from lolo859/vystem
Vystem 0.2
This commit is contained in:
74
shelter/lib/include/std/smp.h
Normal file
74
shelter/lib/include/std/smp.h
Normal file
@@ -0,0 +1,74 @@
|
||||
// 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
|
||||
Reference in New Issue
Block a user