diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..75ec94ea06d856cda7a23f76b1f2a47178a1fb1c
--- /dev/null
+++ b/.devcontainer/Dockerfile
@@ -0,0 +1,26 @@
+ARG VARIANT=focal
+FROM mcr.microsoft.com/vscode/devcontainers/base:${VARIANT}
+
+ARG USER=vscode
+ARG GNU_ARM_VERSION=10-2020-q4-major
+ARG GNU_ARM_DIRECTORY=/opt/toolchains
+
+RUN apt update -y && \
+    apt upgrade -y && \
+    apt install -y build-essential clang-format clang-tidy git \
+    openocd picocom libncurses5 \
+    meson ninja-build python3 python3-pip python3-setuptools python3-wheel \
+    usbutils
+
+RUN mkdir -p /dev/bus/usb && \
+    usermod -aG plugdev $USER
+
+RUN mkdir -p ${GNU_ARM_DIRECTORY} && \
+    wget -qO- "https://developer.arm.com/-/media/Files/downloads/gnu-rm/10-2020q4/gcc-arm-none-eabi-${GNU_ARM_VERSION}-x86_64-linux.tar.bz2" | tar -xj -C "${GNU_ARM_DIRECTORY}"
+
+ENV PATH="${GNU_ARM_DIRECTORY}/gcc-arm-none-eabi-${GNU_ARM_VERSION}/bin:$PATH"
+ENV XDG_DATA_DIRS="/workspaces/unicorn-hal/"
+ENV XDG_DATA_HOME="/workspaces/unicorn-hal/"
+
+USER $USER
+RUN pip3 install --user meson --upgrade
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
new file mode 100644
index 0000000000000000000000000000000000000000..8b18f0c0dd2583a75101b930a8ac8372fa74e77a
--- /dev/null
+++ b/.devcontainer/devcontainer.json
@@ -0,0 +1,33 @@
+{
+    "name": "Machine PM - Embedded Development",
+    "dockerFile": "./Dockerfile",
+    "extensions": [
+        // Meson extension
+        "asabil.meson",
+        // Cortex Debug
+        "marus25.cortex-debug",
+        // C++ extension
+        "ms-vscode.cpptools",
+        // IntelliSense extension
+        "visualstudioexptteam.vscodeintellicode",
+        "mhutchie.git-graph",
+        "editorconfig.editorconfig",
+        "zixuanwang.linkerscript",
+        "dan-c-underwood.arm"
+    ],
+    "mounts": [
+        "source=${localEnv:HOME}/.ssh,target=/home/vscode/.ssh,type=bind",
+        "source=/dev/,target=/dev/,type=bind",
+        "source=/etc/udev/rules.d,target=/etc/udev/rules.d,type=bind"
+    ],
+    "workspaceFolder": "/workspaces/unicorn-hal",
+    "remoteUser": "vscode",
+    "runArgs": [
+        "--cap-add=SYS_PTRACE",
+        "--security-opt",
+        "seccomp=unconfined",
+        "--device-cgroup-rule=a 166:* rwm",
+        "--device-cgroup-rule=a 189:* rwm",
+    ],
+    "postCreateCommand": "./.devcontainer/entrypoint.sh",
+}
\ No newline at end of file
diff --git a/.devcontainer/entrypoint.sh b/.devcontainer/entrypoint.sh
new file mode 100644
index 0000000000000000000000000000000000000000..f5b292032d33cb75d13406b7df02241304c11e82
--- /dev/null
+++ b/.devcontainer/entrypoint.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/bash
+
+FILE=/etc/udev/rules.d/60-openocd.rules
+if [ ! -f "$FILE" ]; then
+	mkdir -p /etc/udev/rules.d/
+	sudo cp /lib/udev/rules.d/60-openocd.rules /etc/udev/rules.d/
+fi
+
+