diff --git a/Makefile b/Makefile
index d0a8377..5bdea49 100644
--- a/Makefile
+++ b/Makefile
@@ -27,7 +27,7 @@ $(BUILD)/tetros.lib: $(LIB_SRC)
 		env RUSTFLAGS="-C soft-float" \
 		cargo rustc \
 			--manifest-path="./Cargo.toml" \
-			-Z build-std=core,alloc \
+			-Z build-std=core \
 			-Z build-std-features=compiler-builtins-mem \
 			--target "./targets/x86-unknown-none.json" \
 			--lib \
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..06ab1c0
--- /dev/null
+++ b/README.md
@@ -0,0 +1,5 @@
+-   fix asm loader
+-   clock
+-   input
+-   music
+-   document everything
diff --git a/tetros/Cargo.lock b/tetros/Cargo.lock
index 9657937..cda49db 100644
--- a/tetros/Cargo.lock
+++ b/tetros/Cargo.lock
@@ -35,15 +35,6 @@ dependencies = [
  "spin",
 ]
 
-[[package]]
-name = "linked_list_allocator"
-version = "0.10.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286"
-dependencies = [
- "spinning_top",
-]
-
 [[package]]
 name = "lock_api"
 version = "0.4.12"
@@ -84,21 +75,11 @@ dependencies = [
  "lock_api",
 ]
 
-[[package]]
-name = "spinning_top"
-version = "0.2.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b9eb1a2f4c41445a3a0ff9abc5221c5fcd28e1f13cd7c0397706f9ac938ddb0"
-dependencies = [
- "lock_api",
-]
-
 [[package]]
 name = "tetros"
 version = "1.0.0"
 dependencies = [
  "lazy_static",
- "linked_list_allocator",
  "spin",
  "uart_16550",
 ]
diff --git a/tetros/Cargo.toml b/tetros/Cargo.toml
index 6970936..7589804 100644
--- a/tetros/Cargo.toml
+++ b/tetros/Cargo.toml
@@ -64,7 +64,6 @@ identity_op = "allow"
 
 
 [dependencies]
-linked_list_allocator = "0.10.5"
 spin = "0.9.8"
 uart_16550 = "0.3.2"
 
diff --git a/tetros/src/lib.rs b/tetros/src/lib.rs
index 3793d65..a26dba0 100644
--- a/tetros/src/lib.rs
+++ b/tetros/src/lib.rs
@@ -1,14 +1,10 @@
 #![no_std]
-#![feature(alloc_error_handler)]
 #![feature(int_roundings)]
 #![feature(lang_items)]
 #![allow(internal_features)]
 
-extern crate alloc;
-
 use drivers::vga::Vga13h;
-use linked_list_allocator::LockedHeap;
-use os::{memory_map::memory_map, thunk::ThunkData};
+use os::thunk::ThunkData;
 use spin::Mutex;
 use tetrisboard::TetrisBoard;
 
@@ -18,9 +14,6 @@ mod tetrisboard;
 #[macro_use]
 mod drivers;
 
-#[global_allocator]
-static ALLOCATOR: LockedHeap = LockedHeap::empty();
-
 pub(crate) static VGA: Mutex<Vga13h> = Mutex::new(unsafe { Vga13h::new() });
 
 #[no_mangle]
@@ -48,12 +41,6 @@ pub unsafe extern "C" fn start(
 		data.with(thunk10);
 	}
 
-	{
-		// Initialize allocator
-		let (heap_start, heap_size) = memory_map(thunk15).expect("No memory for heap");
-		ALLOCATOR.lock().init(heap_start as *mut u8, heap_size);
-	}
-
 	// Clear screen
 	let mut v = VGA.lock();
 
diff --git a/tetros/src/os/memory_map.rs b/tetros/src/os/memory_map.rs
deleted file mode 100644
index 84e9160..0000000
--- a/tetros/src/os/memory_map.rs
+++ /dev/null
@@ -1,101 +0,0 @@
-use core::{cmp, mem, ptr};
-
-use super::{thunk::ThunkData, AREAS, AREAS_LEN};
-use crate::os::{OsMemoryEntry, OsMemoryKind, MEMORY_MAP_ADDR};
-
-fn area_add(area: OsMemoryEntry) {
-	unsafe {
-		for existing_area in &mut AREAS[0..AREAS_LEN] {
-			if existing_area.kind == area.kind {
-				if existing_area.base.unchecked_add(existing_area.size) == area.base {
-					existing_area.size += area.size;
-					return;
-				}
-				if area.base.unchecked_add(area.size) == existing_area.base {
-					existing_area.base = area.base;
-					return;
-				}
-			}
-		}
-		*AREAS.get_mut(AREAS_LEN).expect("AREAS overflowed!") = area;
-		AREAS_LEN += 1;
-	}
-}
-
-#[repr(C, packed)]
-struct MemoryMapEntry {
-	pub base: u64,
-	pub size: u64,
-	pub kind: u32,
-}
-
-pub struct MemoryMapIter {
-	thunk15: extern "C" fn(),
-	data: ThunkData,
-	first: bool,
-}
-
-impl MemoryMapIter {
-	pub fn new(thunk15: extern "C" fn()) -> Self {
-		Self {
-			thunk15,
-			data: ThunkData::new(),
-			first: true,
-		}
-	}
-}
-
-impl Iterator for MemoryMapIter {
-	type Item = OsMemoryEntry;
-	fn next(&mut self) -> Option<Self::Item> {
-		if self.first {
-			self.first = false;
-		} else if self.data.ebx == 0 {
-			return None;
-		}
-
-		self.data.eax = 0xE820;
-		self.data.ecx = mem::size_of::<MemoryMapEntry>() as u32;
-		self.data.edx = 0x534D4150;
-		self.data.edi = MEMORY_MAP_ADDR as u32;
-
-		unsafe {
-			self.data.with(self.thunk15);
-		}
-
-		//TODO: return error?
-		assert_eq!({ self.data.eax }, 0x534D4150);
-		assert_eq!({ self.data.ecx }, mem::size_of::<MemoryMapEntry>() as u32);
-
-		let entry = unsafe { ptr::read(MEMORY_MAP_ADDR as *const MemoryMapEntry) };
-		Some(Self::Item {
-			base: entry.base,
-			size: entry.size,
-			kind: match entry.kind {
-				0 => OsMemoryKind::Null,
-				1 => OsMemoryKind::Free,
-				3 => OsMemoryKind::Reclaim,
-				_ => OsMemoryKind::Reserved,
-			},
-		})
-	}
-}
-
-pub unsafe fn memory_map(thunk15: extern "C" fn()) -> Option<(usize, usize)> {
-	let mut heap_limits = None;
-	for entry in MemoryMapIter::new(thunk15) {
-		let heap_start = 1 * 1024 * 1024;
-		if { entry.kind } == OsMemoryKind::Free
-			&& entry.base <= heap_start as u64
-			&& (entry.base + entry.size) >= heap_start as u64
-		{
-			let heap_end = cmp::min(entry.base + entry.size, usize::MAX as u64) as usize;
-			if heap_end >= heap_start {
-				heap_limits = Some((heap_start, heap_end - heap_start));
-			}
-		}
-
-		area_add(entry);
-	}
-	heap_limits
-}
diff --git a/tetros/src/os/mod.rs b/tetros/src/os/mod.rs
index 11e5fbb..99795d2 100644
--- a/tetros/src/os/mod.rs
+++ b/tetros/src/os/mod.rs
@@ -1,36 +1,6 @@
-pub mod memory_map;
 pub mod thunk;
 
 #[macro_use]
 pub mod panic;
 
-// Real mode memory allocation, for use with thunk
-// 0x500 to 0x7BFF is free
-const MEMORY_MAP_ADDR: usize = 0x1380; // 24 bytes, ends at 0x1397
 const THUNK_STACK_ADDR: usize = 0x7C00; // Grows downwards
-
-static mut AREAS: [OsMemoryEntry; 1024] = [OsMemoryEntry {
-	base: 0,
-	size: 0,
-	kind: OsMemoryKind::Null,
-}; 1024];
-static mut AREAS_LEN: usize = 0;
-
-// Keep synced with BootloaderMemoryKind in kernel
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-#[repr(u64)]
-pub enum OsMemoryKind {
-	Null = 0,
-	Free = 1,
-	Reclaim = 2,
-	Reserved = 3,
-}
-
-// Keep synced with BootloaderMemoryEntry in kernel
-#[derive(Clone, Copy, Debug)]
-#[repr(C, packed(8))]
-pub struct OsMemoryEntry {
-	pub base: u64,
-	pub size: u64,
-	pub kind: OsMemoryKind,
-}
diff --git a/tetros/src/os/panic.rs b/tetros/src/os/panic.rs
index 688398d..fea6607 100644
--- a/tetros/src/os/panic.rs
+++ b/tetros/src/os/panic.rs
@@ -1,6 +1,5 @@
 //! Intrinsics for panic handling
 
-use core::alloc::Layout;
 use core::arch::asm;
 use core::panic::PanicInfo;
 
@@ -22,13 +21,6 @@ pub fn rust_begin_unwind(info: &PanicInfo<'_>) -> ! {
 	}
 }
 
-#[alloc_error_handler]
-#[no_mangle]
-#[allow(improper_ctypes_definitions)] // Layout is not repr(C)
-pub extern "C" fn rust_oom(_layout: Layout) -> ! {
-	panic!("memory allocation failed");
-}
-
 #[allow(non_snake_case)]
 #[no_mangle]
 /// Required to handle panics