55 lines
2.2 KiB
Markdown
55 lines
2.2 KiB
Markdown
# 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.
|