diff --git a/Cargo.lock b/Cargo.lock
index d9b163fe4..55ced166a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -23,6 +23,12 @@ version = "1.0.71"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
 
+[[package]]
+name = "az"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973"
+
 [[package]]
 name = "basic-toml"
 version = "0.1.2"
@@ -135,6 +141,16 @@ version = "1.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
 
+[[package]]
+name = "embedded-graphics-core"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba9ecd261f991856250d2207f6d8376946cd9f412a2165d3b75bc87a0bc7a044"
+dependencies = [
+ "az",
+ "byteorder",
+]
+
 [[package]]
 name = "errno"
 version = "0.3.1"
@@ -550,6 +566,7 @@ name = "uefi"
 version = "0.21.0"
 dependencies = [
  "bitflags 2.3.1",
+ "embedded-graphics-core",
  "log",
  "ptr_meta",
  "ucs2",
@@ -583,6 +600,7 @@ name = "uefi-services"
 version = "0.18.0"
 dependencies = [
  "cfg-if",
+ "embedded-graphics-core",
  "log",
  "qemu-exit",
  "uefi",
diff --git a/uefi/Cargo.toml b/uefi/Cargo.toml
index 4f6858ade..4d7985d4e 100644
--- a/uefi/Cargo.toml
+++ b/uefi/Cargo.toml
@@ -12,7 +12,7 @@ license = "MPL-2.0"
 rust-version = "1.68"
 
 [features]
-default = ["panic-on-logger-errors"]
+default = ["panic-on-logger-errors", "draw_target"]
 alloc = []
 global_allocator = []
 logger = []
@@ -20,11 +20,14 @@ logger = []
 # were observed on the VirtualBox UEFI implementation (see uefi-rs#121).
 # In those cases, this feature can be excluded by removing the default features.
 panic-on-logger-errors = []
+# DrawTarget for GOP protocol
+draw_target = ["embedded-graphics-core"]
 # Generic gate to code that uses unstable features of Rust. You usually need a nightly toolchain.
 unstable = []
 
 [dependencies]
 bitflags = "2.0.0"
+embedded-graphics-core = { version = "0.4.0", optional = true }
 log = { version = "0.4.5", default-features = false }
 ptr_meta = { version = "0.2.0", default-features = false }
 ucs2 = "0.3.2"
diff --git a/uefi/src/proto/console/draw_target.rs b/uefi/src/proto/console/draw_target.rs
new file mode 100644
index 000000000..4dd033e8c
--- /dev/null
+++ b/uefi/src/proto/console/draw_target.rs
@@ -0,0 +1,54 @@
+use embedded_graphics_core::prelude::{DrawTarget, OriginDimensions, Size, PixelColor, Pixel, IntoStorage};
+
+use super::gop::GraphicsOutput;
+
+// FIXME: offer conversions from C to current pixel color format?
+struct GraphicsDisplay<C: PixelColor> {
+    color: C,
+    gop: GraphicsOutput
+}
+
+impl OriginDimensions for GraphicsOutput {
+    fn size(&self) -> embedded_graphics_core::prelude::Size {
+        let (width, height) = self.current_mode_info().resolution();
+
+        Size::from((width as u32, height as u32))
+    }
+}
+
+impl<C: PixelColor> OriginDimensions for GraphicsDisplay<C> {
+    fn size(&self) -> Size {
+        self.gop.size()
+    }
+}
+
+impl<C: PixelColor + IntoStorage> DrawTarget for GraphicsDisplay<C> {
+    type Color = C;
+    type Error = uefi::Error;
+
+    fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
+        where
+            I: IntoIterator<Item = embedded_graphics_core::Pixel<Self::Color>> {
+        let stride = self.gop.current_mode_info().stride() as u64;
+        for Pixel(point, color) in pixels.into_iter() {
+            let bytes = color.into_storage();
+            let (x, y) = (point.x as u64, point.y as u64);
+            let index: usize = (((y * stride) + x) * 4)
+                .try_into()
+                .map_err(|_|
+                    uefi::Error::from(
+                        uefi::Status::UNSUPPORTED
+                    )
+                )?;
+
+            unsafe {
+                self.gop.frame_buffer().write_value(index, bytes);
+            }
+        }
+
+        Ok(())
+    }
+
+    // FIXME: provide a blt technique for fill_solid
+    // FIXME: fallback to blt when pixelformat is blt-only.
+}
diff --git a/uefi/src/proto/console/mod.rs b/uefi/src/proto/console/mod.rs
index 636eb77b4..b7a37f662 100644
--- a/uefi/src/proto/console/mod.rs
+++ b/uefi/src/proto/console/mod.rs
@@ -7,3 +7,5 @@ pub mod gop;
 pub mod pointer;
 pub mod serial;
 pub mod text;
+#[cfg(feature = "draw_target")]
+pub mod draw_target;