diff --git a/doc/shell.md b/doc/shell.md
index e4da0a4..2d15997 100644
--- a/doc/shell.md
+++ b/doc/shell.md
@@ -32,6 +32,7 @@ table describes those codes:
 | `01` | Unknown command           |
 | `02` | Badly formatted arguments |
 | `03` | Out of bounds             |
+| `04` | Unsupported command       |
 
 ## mptr
 
diff --git a/parts/blockdev.asm b/parts/blockdev.asm
index 84f21b7..9d92241 100644
--- a/parts/blockdev.asm
+++ b/parts/blockdev.asm
@@ -14,6 +14,7 @@
 
 ; *** CONSTS ***
 BLOCKDEV_ERR_OUT_OF_BOUNDS	.equ	0x03
+BLOCKDEV_ERR_UNSUPPORTED	.equ	0x04
 
 ; *** VARIABLES ***
 ; A memory pointer to a device table. A device table is a list of addresses
@@ -60,7 +61,6 @@ blkSel:
 
 blkBselCmd:
 	.db	"bsel", 0b001, 0, 0
-blkBsel:
 	ld	a, (hl)	; argument supplied
 	cp	BLOCKDEV_COUNT
 	jr	nc, .error	; if selection >= device count, error
@@ -71,6 +71,7 @@ blkBsel:
 	ld	a, BLOCKDEV_ERR_OUT_OF_BOUNDS
 	ret
 
+
 ; In those routines below, IY is destroyed (we don't push it to the stack). We
 ; seldom use it anyways...
 
@@ -91,20 +92,50 @@ _blkCall:
 	ld	ixh, d
 	ld	ixl, e
 	pop	de
+	; Before we call... is it zero? We don't want to call a zero.
+	push	af
+	ld	a, ixh
+	add	a, ixl
+	jr	c, .ok		; if there's a carry, it isn't zero
+	cp	0
+	jr	z, .error	; if no carry and zero, then both numbers are
+				; zero
+.ok:
+	pop	af
 	call	callIX
+	jr	.end
+
+.error:
+	pop	af
+	ld	a, BLOCKDEV_ERR_UNSUPPORTED
+.end:
 	pop	ix
 	ret
 
-; Reads one character from blockdev ID specified at A and returns its value
-; in A. Always returns a character and waits until read if it has to.
+; Reads one character from selected device and returns its value in A. Always
+; returns a character and waits until read if it has to.
 blkGetC:
 	ld	iyl, 0
 	jr	_blkCall
 
+; Writes character in A in current position in the selected device
 blkPutC:
 	ld	iyl, 2
 	jr	_blkCall
 
+blkSeekCmd:
+	.db	"seek", 0b011, 0b001, 0
+	; HL points to two bytes that contain out address. Seek expects HL
+	; to directly contain that address.
+	ld	a, (hl)
+	ex	af, af'
+	inc	hl
+	ld	a, (hl)
+	ld	l, a
+	ex	af, af'
+	ld	h, a
+	xor	a
+; Set position of selected device to the value specified in HL
 blkSeek:
 	ld	iyl, 4
 	jr	_blkCall
diff --git a/parts/mmap.asm b/parts/mmap.asm
new file mode 100644
index 0000000..e8ec582
--- /dev/null
+++ b/parts/mmap.asm
@@ -0,0 +1,54 @@
+; mmap
+;
+; Block device that maps to memory.
+;
+; *** DEFINES ***
+; MMAP_START: Memory address where the mmap begins
+
+; *** VARIABLES ***
+MMAP_PTR	.equ	MMAP_RAMSTART
+MMAP_RAMEND	.equ	MMAP_PTR+2
+
+; *** CODE ***
+
+; Increase mem pointer by one
+_mmapForward:
+	ld	hl, (MMAP_PTR)
+	inc	hl
+	ld	(MMAP_PTR), hl
+	ret
+
+; Returns absolute addr of memory pointer in HL.
+_mmapAddr:
+	push	de
+	ld	hl, (MMAP_PTR)
+	ld	de, MMAP_START
+	add	hl, de
+	jr	nc, .end
+	; we have carry? out of bounds, set to maximum
+	ld	hl, 0xffff
+.end:
+	pop	de
+	ret
+
+; if out of bounds, will continually return the last char
+mmapGetC:
+	push	hl
+	call	_mmapAddr
+	ld	a, (hl)
+	call	_mmapForward
+	pop	hl
+	ret
+
+mmapPutC:
+	push	hl
+	call	_mmapAddr
+	ld	(hl), a
+	call	_mmapForward
+	pop	hl
+	ret
+
+mmapSeek:
+	ld	(MMAP_PTR), hl
+	ret
+