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();
+}