diff --git a/include/sem.h b/include/sem.h
new file mode 100644
index 0000000000000000000000000000000000000000..16d176ddbec780e2c91d3e5b6ead3d7bbed2a365
--- /dev/null
+++ b/include/sem.h
@@ -0,0 +1,19 @@
+#if !defined(SEM_H)
+#define SEM_H
+
+#include "context.h"
+
+#define SEM_MAGIC 0xCAFEBABE
+
+typedef struct sem_s
+{
+ int cpt;
+ ctx_t *first_ctx;
+ int magic;
+} sem_t;
+
+int sem_init(sem_t *sem, int val);
+void sem_up(sem_t *sem);
+void sem_down(sem_t *sem);
+
+#endif
diff --git a/src/sem.c b/src/sem.c
new file mode 100644
index 0000000000000000000000000000000000000000..061caf4f5f3929918405b1de8f4272717480a348
--- /dev/null
+++ b/src/sem.c
@@ -0,0 +1,44 @@
+#include "sem.h"
+#include "context.h"
+#include "utils.h"
+
+extern ctx_t *current_ctx;
+
+int sem_init(sem_t *sem, int val)
+{
+ assert(sem->magic != SEM_MAGIC);
+
+ sem->magic = SEM_MAGIC;
+ sem->cpt = val;
+ sem->first_ctx = NULL;
+
+ return 0;
+}
+
+void sem_up(sem_t *sem)
+{
+ assert(sem->magic == SEM_MAGIC);
+
+ irq_disable();
+ if ((++sem->cpt) <= 0)
+ {
+ sem->first_ctx->status = CTX_EXEC;
+ sem->first_ctx = sem->first_ctx->sem_next_ctx;
+ }
+ irq_enable();
+}
+
+void sem_down(sem_t *sem)
+{
+ assert(sem->magic == SEM_MAGIC);
+
+ irq_disable();
+ if ((++sem->cpt) < 0)
+ {
+ current_ctx->status = CTX_WAIT;
+ current_ctx->sem_next_ctx = sem->first_ctx;
+ sem->first_ctx = current_ctx;
+ yield();
+ }
+ irq_enable();
+}