diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 6b2c6b91f9625..525e2e1615ca2 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -323,6 +323,8 @@ source "drivers/gpu/drm/amd/amdgpu/Kconfig"
 
 source "drivers/gpu/drm/nouveau/Kconfig"
 
+source "drivers/gpu/drm/rvkms/Kconfig"
+
 source "drivers/gpu/drm/i915/Kconfig"
 
 source "drivers/gpu/drm/xe/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 68cc9258ffc4b..ebedcab4dece0 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -172,6 +172,7 @@ obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/
 obj-$(CONFIG_DRM_VGEM)	+= vgem/
 obj-$(CONFIG_DRM_VKMS)	+= vkms/
 obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/
+obj-$(CONFIG_DRM_RVKMS) += rvkms/
 obj-$(CONFIG_DRM_EXYNOS) +=exynos/
 obj-$(CONFIG_DRM_ROCKCHIP) +=rockchip/
 obj-$(CONFIG_DRM_GMA500) += gma500/
diff --git a/drivers/gpu/drm/rvkms/Kconfig b/drivers/gpu/drm/rvkms/Kconfig
new file mode 100644
index 0000000000000..551422803b9a6
--- /dev/null
+++ b/drivers/gpu/drm/rvkms/Kconfig
@@ -0,0 +1,3 @@
+config DRM_RVKMS
+        tristate "Rust VKMS PoC driver (EXPERIMENTAL)"
+        depends on RUST && DRM && DRM_GEM_SHMEM_HELPER=y
diff --git a/drivers/gpu/drm/rvkms/Makefile b/drivers/gpu/drm/rvkms/Makefile
new file mode 100644
index 0000000000000..18e06fc3343c6
--- /dev/null
+++ b/drivers/gpu/drm/rvkms/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_DRM_RVKMS) += rvkms.o
diff --git a/drivers/gpu/drm/rvkms/connector.rs b/drivers/gpu/drm/rvkms/connector.rs
new file mode 100644
index 0000000000000..97b94054fbe1f
--- /dev/null
+++ b/drivers/gpu/drm/rvkms/connector.rs
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0
+use super::{Rvkms, RvkmsDevice, MAX_RES, DEFAULT_RES};
+use kernel::{
+    prelude::*,
+    drm::{
+        device::Device,
+        kms::{
+            connector::{self, ConnectorGuard, DriverConnectorOps},
+            ModeConfigGuard
+        }
+    },
+    prelude::*
+};
+use core::marker::PhantomPinned;
+
+#[pin_data]
+pub(crate) struct DriverConnector {
+    #[pin]
+    _p: PhantomPinned
+}
+
+pub(crate) type Connector = connector::Connector<DriverConnector>;
+
+#[vtable]
+impl connector::DriverConnector for DriverConnector {
+    #[unique]
+    const OPS: &'static DriverConnectorOps;
+
+    type State = ConnectorState;
+    type Driver = Rvkms;
+    type Args = ();
+
+    fn new(dev: &Device<Self::Driver>, args: Self::Args) -> impl PinInit<Self, Error> {
+        try_pin_init!(Self { _p: PhantomPinned })
+    }
+
+    fn get_modes(
+        connector: ConnectorGuard<'_, Self>,
+        _guard: &ModeConfigGuard<'_, Self::Driver>
+    ) -> i32 {
+        let count = connector.add_modes_noedid(MAX_RES);
+
+        connector.set_preferred_mode(DEFAULT_RES);
+        count
+    }
+}
+
+#[derive(Clone, Default)]
+pub(crate) struct ConnectorState;
+
+impl connector::DriverConnectorState for ConnectorState {
+    type Connector = DriverConnector;
+}
diff --git a/drivers/gpu/drm/rvkms/crtc.rs b/drivers/gpu/drm/rvkms/crtc.rs
new file mode 100644
index 0000000000000..c3a90c76e4a5e
--- /dev/null
+++ b/drivers/gpu/drm/rvkms/crtc.rs
@@ -0,0 +1,253 @@
+// TODO: License and stuff
+// Contain's rvkms's drm_crtc implementation
+use core::marker::*;
+use super::{Rvkms, plane::*};
+use kernel::{
+    prelude::*,
+    drm::{
+        device::Device,
+        kms::{
+            atomic::*,
+            crtc::{self, RawCrtcState, DriverCrtcOps},
+            ModeObject,
+            KmsRef,
+            vblank::*,
+        }
+    },
+    sync::{
+        lock::Guard,
+        SpinLockIrq,
+        LockedBy,
+    },
+    hrtimer::*,
+    time::*,
+    irq::*,
+    sync::Arc,
+    new_spinlock_irq,
+    impl_has_timer
+};
+
+pub(crate) type Crtc = crtc::Crtc<RvkmsCrtc>;
+pub(crate) type CrtcState = crtc::CrtcState<RvkmsCrtcState>;
+
+#[derive(Default)]
+pub(crate) struct VblankState {
+    /// A reference to the current VblankTimer
+    timer: Option<Arc<VblankTimer>>,
+
+    /// A reference to a handle for the current VblankTimer
+    handle: Option<ArcTimerHandle<VblankTimer>>,
+
+    /// The current frame duration in ns
+    ///
+    /// Stored separately here so it can be read safely without the vblank lock
+    period_ns: i32,
+}
+
+#[pin_data]
+pub(crate) struct RvkmsCrtc {
+    /// The current vblank emulation state
+    ///
+    /// This is uninitalized when the CRTC is disabled to prevent circular references
+    #[pin]
+    vblank_state: SpinLockIrq<VblankState>
+}
+
+#[vtable]
+impl crtc::DriverCrtc for RvkmsCrtc {
+    #[unique]
+    const OPS: &'static DriverCrtcOps;
+
+    type Args = ();
+    type State = RvkmsCrtcState;
+    type Driver = Rvkms;
+    type VblankImpl = Self;
+
+    fn new(device: &Device<Self::Driver>, args: &Self::Args) -> impl PinInit<Self, Error> {
+        try_pin_init!(Self {
+            vblank_state <- new_spinlock_irq!(VblankState::default(), "vblank_handle_lock")
+        })
+    }
+
+    fn atomic_check(
+        crtc: &Crtc,
+        old_state: &CrtcState,
+        mut new_state: crtc::BorrowedCrtcState<'_, CrtcState>,
+        state: &AtomicStateComposer<Self::Driver>
+    ) -> Result {
+        state.add_affected_planes(crtc)?;
+
+        // Create a vblank timer when enabling a CRTC, and destroy said timer when disabling to
+        // resolve the circular reference to CRTC it creates
+        if old_state.active() != new_state.active() {
+            new_state.vblank_timer = if new_state.active() {
+                Some(VblankTimer::new(crtc)?)
+            } else {
+                None
+            };
+        }
+
+        Ok(())
+    }
+
+    fn atomic_flush(
+        crtc: &Crtc,
+        _old_state: &CrtcState,
+        mut new_state: crtc::BorrowedCrtcState<'_, CrtcState>,
+        _state: &AtomicStateMutator<Self::Driver>
+    ) {
+        if let Some(event) = new_state.get_pending_vblank_event() {
+            if let Ok(vbl_ref) = crtc.vblank_get() {
+                event.arm(vbl_ref);
+            } else {
+                event.send();
+            }
+        }
+    }
+
+    fn atomic_enable(
+        crtc: &Crtc,
+        old_state: &CrtcState,
+        new_state: crtc::BorrowedCrtcState<'_, CrtcState>,
+        _state: &AtomicStateMutator<Self::Driver>
+    ) {
+        with_irqs_disabled(|irq| {
+            // Store a reference to the newly created vblank timer for this CRTC
+            crtc.vblank_state.lock_with(irq).timer = new_state.vblank_timer.clone()
+        });
+
+        crtc.vblank_on();
+    }
+
+    fn atomic_disable(
+        crtc: &Crtc,
+        _old_state: &CrtcState,
+        _new_state: crtc::BorrowedCrtcState<'_, CrtcState>,
+        _state: &AtomicStateMutator<Self::Driver>
+    ) {
+        crtc.vblank_off();
+
+        // Since we just explicitly disabled vblanks, destroy the vblank state to resolve circular
+        // reference to this CRTC that it holds. Note that dropping the handle will cause us to wait
+        // for the timer to finish, so we return it from with_irqs_disabled so that it is only
+        // dropped once the vblank_state lock has been released
+        drop(with_irqs_disabled(|irq| {
+            let mut state = crtc.vblank_state.lock_with(irq);
+
+            (state.timer.take(), state.handle.take())
+        }));
+    }
+}
+
+impl VblankSupport for RvkmsCrtc {
+    type Crtc = Self;
+
+    fn enable_vblank(
+        crtc: &Crtc,
+        vblank: &VblankGuard<'_, Self::Crtc>,
+        irq: IrqDisabled<'_>,
+    ) -> Result {
+        let period_ns = vblank.frame_duration();
+        let mut vbl_state = crtc.vblank_state.lock_with(irq);
+
+        if let Some(timer) = vbl_state.timer.clone() {
+            vbl_state.period_ns = period_ns;
+            vbl_state.handle = Some(timer.schedule(period_ns as _));
+        }
+
+        Ok(())
+    }
+
+    fn disable_vblank(crtc: &Crtc, _vbl_guard: &VblankGuard<'_, Self::Crtc>, irq: IrqDisabled<'_>) {
+        let handle = crtc.vblank_state.lock_with(irq).handle.take();
+
+        // Now that we're outside of the vblank lock, we can safely drop the handle
+        drop(handle);
+    }
+
+    fn get_vblank_timestamp(crtc: &Crtc, _handling_vblank_irq: bool) -> Option<VblankTimestamp> {
+        let time = with_irqs_disabled(|irq| {
+            let vbl_state = crtc.vblank_state.lock_with(irq);
+
+            // Return the expiration of our vblank timer if we have one (if not, vblanks are
+            // disabled)
+            vbl_state.timer.as_ref().map(|t| {
+                // To prevent races, we roll the hrtimer forward before we do any interrupt
+                // processing - this is how real hw works (the interrupt is only generated after all
+                // the vblank registers are updated) and what the vblank core expects. Therefore we
+                // need to always correct the timestamps by one frame.
+                t.timer.expires() - Ktime::from_ns(vbl_state.period_ns)
+            })
+        });
+
+        Some(VblankTimestamp {
+            // …otherwise, just use the current time
+            time: time.unwrap_or_else(|| Ktime::ktime_get()),
+            max_error: 0
+        })
+    }
+}
+
+#[derive(Clone, Default)]
+pub(crate) struct RvkmsCrtcState {
+    vblank_timer: Option<Arc<VblankTimer>>
+}
+
+impl crtc::DriverCrtcState for RvkmsCrtcState {
+    type Crtc = RvkmsCrtc;
+}
+
+/// The main hrtimer structure for emulating vblanks.
+#[pin_data]
+pub(crate) struct VblankTimer {
+    /// The actual hrtimer used for sending out vblanks
+    #[pin]
+    timer: Timer<Self>,
+
+    /// An owned reference to the CRTC that this [`VblankTimer`] belongs to
+    crtc: KmsRef<Crtc>,
+}
+
+impl_has_timer! {
+    impl HasTimer<Self> for VblankTimer { self.timer }
+}
+
+impl VblankTimer {
+    pub(crate) fn new(crtc: &Crtc) -> Result<Arc<Self>> {
+        Arc::pin_init(
+            pin_init!(Self {
+                timer <- Timer::<Self>::new::<Arc<Self>>(),
+                crtc: crtc.into(),
+            }),
+            GFP_KERNEL
+        )
+    }
+}
+
+impl TimerCallback for VblankTimer {
+    type CallbackTarget<'a> = Arc<Self>;
+
+    fn run(
+        this: Self::CallbackTarget<'_>,
+        context: TimerCallbackContext<'_, Self>
+    ) -> TimerRestart
+    where
+        Self: Sized
+    {
+        with_irqs_disabled(|irq| {
+            let period_ns = this.crtc.vblank_state.lock_with(irq).period_ns;
+
+            let overrun = context.forward_now(Ktime::from_ns(period_ns));
+            if overrun != 1 {
+                dev_warn!(
+                    this.crtc.drm_dev().as_ref(),
+                    "vblank timer overrun (expected 1, got {overrun})\n"
+                );
+            }
+
+            this.crtc.handle_vblank();
+        });
+
+        TimerRestart::Restart
+    }
+}
diff --git a/drivers/gpu/drm/rvkms/encoder.rs b/drivers/gpu/drm/rvkms/encoder.rs
new file mode 100644
index 0000000000000..f426ef10bcd7e
--- /dev/null
+++ b/drivers/gpu/drm/rvkms/encoder.rs
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0
+use core::marker::PhantomPinned;
+use kernel::{
+    drm::{device::Device, kms::encoder},
+    prelude::*,
+    types::ARef,
+};
+use crate::{Rvkms, connector::Connector};
+
+#[pin_data]
+pub(crate) struct DriverEncoder {
+    connector: ARef<Connector>,
+    #[pin]
+    _p: PhantomPinned,
+}
+
+pub(crate) type Encoder = encoder::Encoder<DriverEncoder>;
+
+#[vtable]
+impl encoder::DriverEncoder for DriverEncoder {
+    #[unique]
+    const OPS: &'static encoder::DriverEncoderOps;
+
+    type Driver = Rvkms;
+    type Args = ARef<Connector>;
+
+    fn new(device: &Device<Self::Driver>, args: Self::Args) -> impl PinInit<Self, Error> {
+        try_pin_init!(Self {
+            connector: args,
+            _p: PhantomPinned
+        })
+    }
+}
diff --git a/drivers/gpu/drm/rvkms/file.rs b/drivers/gpu/drm/rvkms/file.rs
new file mode 100644
index 0000000000000..baa9297673ecc
--- /dev/null
+++ b/drivers/gpu/drm/rvkms/file.rs
@@ -0,0 +1,22 @@
+use super::Rvkms;
+
+use kernel::{
+    drm::{
+        self,
+        device::Device as DrmDevice
+    },
+    prelude::*,
+};
+use core::option::*;
+
+pub(crate) struct File;
+
+impl drm::file::DriverFile for File {
+    type Driver = Rvkms;
+
+    fn open(device: &DrmDevice<Self::Driver>) -> Result<Pin<Box<Self>>> {
+        pr_info!("Someone opened a file! But I do not yet know which one...\n");
+
+        Box::pin_init(init!(File { }), GFP_KERNEL)
+    }
+}
diff --git a/drivers/gpu/drm/rvkms/gem.rs b/drivers/gpu/drm/rvkms/gem.rs
new file mode 100644
index 0000000000000..950ef33758657
--- /dev/null
+++ b/drivers/gpu/drm/rvkms/gem.rs
@@ -0,0 +1,30 @@
+use crate::{Rvkms, RvkmsDevice};
+use core::sync::atomic::{AtomicU64, Ordering};
+use kernel::{
+    drm::{self, gem},
+    prelude::*,
+};
+
+static GEM_ID: AtomicU64 = AtomicU64::new(0);
+
+/// GEM Object implementation
+#[pin_data]
+pub(crate) struct DriverObject {
+    /// ID for debugging
+    id: u64,
+}
+
+pub(crate) type Object = gem::shmem::Object<DriverObject>;
+
+impl gem::BaseDriverObject<Object> for DriverObject {
+    fn new(dev: &RvkmsDevice, size: usize) -> impl PinInit<Self, Error> {
+        let id = GEM_ID.fetch_add(1, Ordering::Relaxed);
+
+        pr_debug!("DriverObject::new id={id}\n");
+        DriverObject { id }
+    }
+}
+
+impl gem::shmem::DriverObject for DriverObject {
+    type Driver = Rvkms;
+}
diff --git a/drivers/gpu/drm/rvkms/output.rs b/drivers/gpu/drm/rvkms/output.rs
new file mode 100644
index 0000000000000..b110e2d5d8a8b
--- /dev/null
+++ b/drivers/gpu/drm/rvkms/output.rs
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0
+use crate::{
+    crtc::Crtc,
+    plane::Plane,
+    connector::Connector,
+    encoder::Encoder,
+    RvkmsDevice,
+    Rvkms
+};
+use kernel::{
+    drm::{
+        fourcc::*,
+        kms::{
+            connector::DRM_MODE_CONNECTOR_VIRTUAL,
+            encoder::DRM_MODE_ENCODER_VIRTUAL,
+            plane::{self, PlaneType},
+            framebuffer::*,
+            UnregisteredKmsDevice,
+        },
+    },
+    sync::Arc,
+    prelude::*,
+    types::ARef,
+};
+
+const FORMATS: FormatList<1> = FormatList::new([XRGB888]);
+
+pub(crate) fn create_output(dev: &UnregisteredKmsDevice<'_, Rvkms>, index: u8) -> Result {
+    let possible_crtcs = 1 << index;
+
+    let primary = Plane::new(
+        dev,
+        possible_crtcs,
+        &FORMATS,
+        Option::<&ModifierList<0>>::None,
+        PlaneType::PRIMARY,
+        None,
+        ()
+    )?;
+
+    let crtc = Crtc::new(dev, primary, Option::<&Plane>::None, None, ())?;
+
+    let connector = Connector::new(dev, DRM_MODE_CONNECTOR_VIRTUAL, ())?;
+
+    let encoder = Encoder::new(
+        dev,
+        DRM_MODE_ENCODER_VIRTUAL,
+        possible_crtcs,
+        0,
+        None,
+        connector.clone()
+    )?;
+
+    connector.attach_encoder(encoder)
+}
diff --git a/drivers/gpu/drm/rvkms/plane.rs b/drivers/gpu/drm/rvkms/plane.rs
new file mode 100644
index 0000000000000..2722845a32e9a
--- /dev/null
+++ b/drivers/gpu/drm/rvkms/plane.rs
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0
+use core::marker::PhantomPinned;
+use super::{Rvkms, crtc::{RvkmsCrtc, Crtc}};
+use kernel::{
+    prelude::*,
+    drm::{
+        device::Device,
+        kms::{
+            atomic::*,
+            plane::{
+                self,
+                AsRawPlaneState,
+                FromRawPlaneState,
+                DriverPlaneState,
+                RawPlane,
+                RawPlaneState,
+                BorrowedPlaneState,
+                DriverPlaneOps,
+            },
+            ModeObject
+        }
+    },
+};
+
+#[pin_data]
+pub(crate) struct RvkmsPlane {
+    #[pin]
+    _p: PhantomPinned,
+}
+
+pub(crate) type Plane = plane::Plane<RvkmsPlane>;
+pub(crate) type PlaneState = plane::PlaneState<RvkmsPlaneState>;
+
+#[vtable]
+impl plane::DriverPlane for RvkmsPlane {
+    #[unique]
+    const OPS: &'static DriverPlaneOps;
+
+    type State = RvkmsPlaneState;
+    type Driver = Rvkms;
+    type Args = ();
+
+    fn new(device: &Device<Self::Driver>, args: Self::Args) -> impl PinInit<Self, Error> {
+        try_pin_init!(Self { _p: PhantomPinned })
+    }
+
+    fn atomic_check(
+        plane: &Plane,
+        mut new_state: BorrowedPlaneState<'_, PlaneState>,
+        _old_state: &PlaneState,
+        state: &AtomicStateComposer<Self::Driver>
+    ) -> Result {
+        if new_state.framebuffer().is_none() {
+            return Ok(());
+        }
+
+        if let Some(crtc) = new_state.crtc() {
+            let crtc_state = state.add_crtc_state(crtc)?;
+            new_state.atomic_helper_check(&crtc_state, true, true)
+        } else {
+            // TODO: We should be printing a warning here if we have no CRTC but do have an fb
+            return Ok(());
+        }
+    }
+
+    fn atomic_update(
+        _plane: &Plane,
+        _new_state: BorrowedPlaneState<'_, PlaneState>,
+        _old_state: &PlaneState,
+        _state: &AtomicStateMutator<Self::Driver>,
+    ) {
+        // TODO, no-op for now
+    }
+}
+
+#[derive(Clone, Default)]
+pub(crate) struct RvkmsPlaneState;
+
+impl DriverPlaneState for RvkmsPlaneState {
+    type Plane = RvkmsPlane;
+}
diff --git a/drivers/gpu/drm/rvkms/rvkms.rs b/drivers/gpu/drm/rvkms/rvkms.rs
new file mode 100644
index 0000000000000..2c72c0ec6989d
--- /dev/null
+++ b/drivers/gpu/drm/rvkms/rvkms.rs
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0
+mod connector;
+mod crtc;
+mod file;
+mod gem;
+mod plane;
+mod output;
+mod encoder;
+
+use alloc::boxed::Box;
+
+use core::{option::*, marker::*};
+
+use kernel::{
+    c_str,
+    str::CStr,
+    device,
+    driver,
+    drm::{
+        self,
+        drv,
+        kms::{
+            Kms,
+            ModeConfigInfo,
+            UnregisteredKmsDevice,
+            atomic::*,
+            fbdev::*,
+        },
+    },
+    platform,
+    prelude::*,
+    sync::Arc,
+};
+
+/// Convienence type alias for the DRM device type for this driver
+pub(crate) type RvkmsDevice = drm::device::Device<Rvkms>;
+
+/// The name of the driver
+const NAME: &'static CStr = c_str!("rvkms");
+
+/// Driver metadata
+const INFO: drv::DriverInfo = drv::DriverInfo {
+    major: 0,
+    minor: 0,
+    patchlevel: 0,
+    name: &NAME,
+    desc: c_str!("Rust VKMS PoC"),
+    date: c_str!("20240115"),
+};
+
+/// The minimum supported resolution
+const MIN_RES: (i32, i32) = (10, 10);
+
+/// The maximum supported resolution
+const MAX_RES: (i32, i32) = (8192, 8192);
+
+/// The "preferred" resolution
+const DEFAULT_RES: (i32, i32) = (1024, 768);
+
+pub(crate) struct Data {
+}
+
+/// DRM Driver implementation for `RvkmsDriver`
+#[vtable]
+impl drv::Driver for Rvkms {
+    type Data = Arc<Data>;
+    type Object = gem::Object;
+    type File = file::File;
+    type Kms = Self;
+
+    const INFO: drv::DriverInfo = INFO;
+    const FEATURES:u32 = drv::FEAT_GEM | drv::FEAT_MODESET | drv::FEAT_ATOMIC;
+
+    kernel::declare_drm_ioctls! {}
+}
+
+#[vtable]
+impl Kms for Rvkms {
+    type Driver = Self;
+    type Fbdev = FbdevShmem<Self>;
+
+    fn mode_config_info(
+        _dev: &device::Device,
+        _drm_data: <<Self::Driver as drv::Driver>::Data as kernel::types::ForeignOwnable>::Borrowed<'_>,
+    ) -> Result<ModeConfigInfo> {
+        Ok(MODE_CONFIG_INFO)
+    }
+
+    fn create_objects(drm: &UnregisteredKmsDevice<'_, Self::Driver>) -> Result {
+        output::create_output(drm, 0)
+    }
+
+    fn atomic_commit_tail<'a>(
+        mut state: AtomicCommitTail<'a, Self::Driver>,
+        modeset_token: ModesetsReadyToken<'_>,
+        plane_update_token: PlaneUpdatesReadyToken<'_>,
+    ) -> CommittedAtomicState<'a, Self::Driver> {
+        let modeset_token = state.commit_modeset_disables(modeset_token);
+
+        let plane_update_token = state.commit_planes(plane_update_token, Default::default());
+
+        let modeset_token = state.commit_modeset_enables(modeset_token);
+
+        state.fake_vblank();
+
+        let state = state.commit_hw_done(modeset_token, plane_update_token);
+
+        state.wait_for_flip_done();
+
+        state
+    }
+}
+
+impl platform::Driver for Rvkms {
+    type Data = Arc<Data>;
+    type IdInfo = ();
+
+    fn probe(pdev: &mut platform::Device, id_info: Option<&Self::IdInfo>) -> Result<Self::Data> {
+        // XXX: do not fret, the mutable reference here is temporary (poke dakr if it isn't)
+        let dev: &device::Device = pdev.as_ref();
+        dev.pr_info(format_args!("RVKMS probing\n"));
+
+        let data = Arc::new(Data { }, GFP_KERNEL)?;
+        let drm = drv::Registration::<Rvkms>::new_foreign_owned(dev, data.clone(), 0)?;
+
+        Ok(data)
+    }
+}
+
+pub(crate) struct Rvkms {
+    drv_reg: Pin<Box<platform::Registration<Self>>>,
+    pdev: platform::Device,
+}
+
+const MODE_CONFIG_INFO: ModeConfigInfo = ModeConfigInfo {
+    min_resolution: MIN_RES,
+    max_resolution: MAX_RES,
+    max_cursor: (512, 512),
+    preferred_depth: 0,
+};
+
+impl kernel::Module for Rvkms {
+    fn init(name: &'static CStr, module: &'static ThisModule) -> kernel::error::Result<Self> {
+        pr_info!("RVKMS module loaded\n");
+
+        // Register the driver (FIXME: this should be static
+        let drv_reg = Box::try_pin_init(
+            platform::Registration::<Self>::new(name, module),
+            GFP_KERNEL
+        )?;
+
+        let pdev = platform::Device::create_simple(&NAME, 0)?;
+        let dev: &device::Device = pdev.as_ref();
+
+        Ok(Self {
+            drv_reg,
+            pdev,
+        })
+    }
+}
+
+module! {
+    type: Rvkms,
+    name: "rvkms",
+    author: "Lyude Paul",
+    description: "Rust VKMS Proof of Concept driver",
+    license: "GPL v2",
+}
