Skip to content

Commit 5f0852c

Browse files
committed
Add spinlock implementation using RV32A atomics
Introduce a simple spinlock implementation based on test-and-set using RV32A atomic instructions. The spinlock API includes basic locking, IRQ-safe variants, and versions that save and restore interrupt state. To support atomic instructions, the Makefile is updated to enable the 'A' extension by changing the -march flag. This is the first step toward enabling multi-core task scheduling support on RISC-V SMP systems.
1 parent d6232aa commit 5f0852c

File tree

2 files changed

+76
-2
lines changed

2 files changed

+76
-2
lines changed

arch/riscv/build.mk

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ DEFINES := -DF_CPU=$(F_CLK) \
1717
-DF_TIMER=$(F_TICK) \
1818
-include config.h
1919

20-
ASFLAGS = -march=rv32imzicsr -mabi=ilp32
20+
ASFLAGS = -march=rv32imzaicsr -mabi=ilp32
2121
CFLAGS += -Wall -Wextra -Wshadow -Wno-unused-parameter -Werror
2222
CFLAGS += -O2 -std=gnu99
23-
CFLAGS += -march=rv32imzicsr -mabi=ilp32
23+
CFLAGS += -march=rv32imazicsr -mabi=ilp32
2424
CFLAGS += -mstrict-align -ffreestanding -nostdlib -fomit-frame-pointer
2525
CFLAGS += $(INC_DIRS) $(DEFINES) -fdata-sections -ffunction-sections
2626
ARFLAGS = r

arch/riscv/spinlock.h

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#pragma once
2+
3+
#include <hal.h>
4+
5+
/* Spinlock structure */
6+
typedef struct {
7+
volatile uint32_t lock;
8+
} spinlock_t;
9+
10+
#define SPINLOCK_INITIALIZER { 0 }
11+
12+
/* Save and restore interrupt state */
13+
static inline uint32_t intr_save(void)
14+
{
15+
uint32_t mstatus_val = read_csr(mstatus);
16+
_di();
17+
return mstatus_val;
18+
}
19+
20+
static inline void intr_restore(uint32_t mstatus_val)
21+
{
22+
write_csr(mstatus, mstatus_val);
23+
}
24+
25+
/* CPU relax */
26+
static inline void cpu_relax(void)
27+
{
28+
asm volatile("nop");
29+
}
30+
31+
/* Basic spinlock API */
32+
static inline void spin_lock(spinlock_t *lock)
33+
{
34+
while (__sync_lock_test_and_set(&lock->lock, 1)) {
35+
while (lock->lock)
36+
cpu_relax();
37+
}
38+
}
39+
40+
static inline void spin_unlock(spinlock_t *lock)
41+
{
42+
__sync_lock_release(&lock->lock);
43+
}
44+
45+
static inline int spin_trylock(spinlock_t *lock)
46+
{
47+
return (__sync_lock_test_and_set(&lock->lock, 1) == 0);
48+
}
49+
50+
/* IRQ-safe spinlock (no state saving) */
51+
static inline void spin_lock_irq(spinlock_t *lock)
52+
{
53+
_di();
54+
spin_lock(lock);
55+
}
56+
57+
static inline void spin_unlock_irq(spinlock_t *lock)
58+
{
59+
spin_unlock(lock);
60+
_ei();
61+
}
62+
63+
/* IRQ-safe spinlock (with state saving) */
64+
static inline void spin_lock_irqsave(spinlock_t *lock, uint32_t *flags)
65+
{
66+
*flags = intr_save();
67+
spin_lock(lock);
68+
}
69+
70+
static inline void spin_unlock_irqrestore(spinlock_t *lock, uint32_t flags)
71+
{
72+
spin_unlock(lock);
73+
intr_restore(flags);
74+
}

0 commit comments

Comments
 (0)