# SMP services ## Introduction The SMP services provide various abstractions related to SMP programming. It is defined inside `shelter/lib/include/std/smp.h` and implemented in `shelter/lib/src/std/smp.c` ## GS register Regarding the GS register, two functions are provided: - `sh_smp_write_gs_base(sh_uint64 value)`: Write the `IA32_GS_BASE` MSR. with a value, return nothing - `sh_smp_gs_base()`: take no argument and return a `sh_ap_CPU_STRUCT*` ## Spinlocks The SMP services provide a basic implementation for a spinlock, which look like this: ``` C typedef struct { volatile sh_uint32 spinlock; sh_uint32 lapic_id; } sh_SPIN_LOCK; ``` Two macros are provided to initialize an unlocked spinlock: - `SH_LOCK()`: intended for spinlocks stored as global variables - `SH_LOCK_LOCAL()`: intended for spinlocks stored as local variables or into structs This spinlock implementation requires `sh_smp_gs_base()` to return a valid pointer to a CPU struct. It uses the atomics primitives provided by compilers. Spinlock operations provide full memory ordering guarantees. Four functions are provided for spinlock manipulation: - `sh_spin_lock(sh_SPIN_LOCK *lock)`: lock a spinlock, block until the lock is acquired. Return nothing - `sh_spin_unlock(sh_SPIN_LOCK *lock)`: unlock a spinlock, return nothing - `sh_spin_trylock(sh_SPIN_LOCK *lock)`: Attempt to acquire the lock without blocking., return `SH_TRUE` if successfull, `SH_FALSE` otherwise. - `sh_spin_wholock(sh_SPIN_LOCK *lock)`: return the LAPIC id of the CPU locking the spinlock. Return `SH_UINT32_MAX` if the spinlock isn't owned by any CPU Current implementation doesn't disable interrupts while holding locks. ## CPU count SMP services can store the amount of CPU cores using the following functions: - `sh_smp_set_cpu_count(sh_int16 cpu_count)`: set the count of CPU. It is only called one time by `sh_ap_prepare_for_smp_launch()` - `sh_smp_get_cpu_count()`: return the count of CPU, return `-1` if value isn't initialized ## Memory barrier The SMP services provide the following primitives: Function name | Role --------------|----- `sh_mb()` | Full memory barrier `sh_rmb()` | Read memory barrier `sh_wmb()` | Write memory barrier Current x86_64 implementation uses mfence/lfence/sfence.