diff --git a/src/acpi/hpet.rs b/src/acpi/hpet.rs
index 9f76caa6e7679f137d92a8fedf90d52af7e90e9d..664b6bb8d69cd8b32a4ee0770ec4f1ef7fefed71 100644
--- a/src/acpi/hpet.rs
+++ b/src/acpi/hpet.rs
@@ -9,7 +9,7 @@ pub struct GenericAddressStructure {
     bit_width: u8,
     bit_offset: u8,
     access_size: u8,
-    address: u64,
+    pub address: u64,
 }
 
 #[repr(packed)]
diff --git a/src/acpi/mod.rs b/src/acpi/mod.rs
index e67715de9272a4532359b457a4f90727e75a123f..f2791169c6cbfee2c5158e071f1618538b2286fc 100644
--- a/src/acpi/mod.rs
+++ b/src/acpi/mod.rs
@@ -22,7 +22,7 @@ use self::hpet::Hpet;
 
 use self::aml::{is_aml_table, parse_aml_table, AmlNamespace, AmlError};
 
-mod hpet;
+pub mod hpet;
 mod dmar;
 mod fadt;
 mod madt;
diff --git a/src/device/hpet.rs b/src/device/hpet.rs
new file mode 100644
index 0000000000000000000000000000000000000000..3f88f36896f473f5d651ead3c4a503977a145b0d
--- /dev/null
+++ b/src/device/hpet.rs
@@ -0,0 +1,82 @@
+use core::intrinsics::{volatile_load, volatile_store};
+
+use memory::Frame;
+use paging::{entry, ActivePageTable, PhysicalAddress, Page, VirtualAddress};
+
+use acpi::hpet::Hpet;
+
+pub static mut HPET: HpetDevice = HpetDevice {
+    capability_addr: 0,
+    general_config_addr: 0,
+    general_interrupt_addr: 0,
+    main_counter_addr: 0,
+    t0_config_capability_addr: 0,
+    t0_comparator_addr: 0
+};
+
+static LEG_RT_CNF: u64 = 2;
+static ENABLE_CNF: u64 = 1;
+
+static TN_VAL_SET_CNF: u64 = 0x40;
+static TN_TYPE_CNF: u64 = 0x08;
+static TN_INT_ENB_CNF: u64 = 0x04;
+
+pub struct HpetDevice {
+    capability_addr: usize,
+    general_config_addr: usize,
+    general_interrupt_addr: usize,
+    main_counter_addr: usize,
+    t0_config_capability_addr: usize,
+    t0_comparator_addr: usize
+}
+
+pub unsafe fn init(hpet: &Hpet, active_table: &mut ActivePageTable) {
+    HPET.init(hpet, active_table);
+}
+
+impl HpetDevice {
+    unsafe fn init(&mut self, hpet: &Hpet, active_table: &mut ActivePageTable) {
+        let base_address = hpet.base_address.address as usize;
+
+        self.capability_addr = base_address;
+        self.general_config_addr = base_address + 0x10;
+        self.general_interrupt_addr = base_address + 0x20;
+        self.main_counter_addr = base_address + 0xF0;
+
+        self.t0_config_capability_addr = base_address + 0x100;
+        self.t0_comparator_addr = base_address + 0x108;
+
+        {
+            let page = Page::containing_address(VirtualAddress::new(base_address));
+            let frame = Frame::containing_address(PhysicalAddress::new(base_address));
+            let result = active_table.map_to(page, frame, entry::PRESENT | entry::WRITABLE | entry::NO_EXECUTE);
+            result.flush(active_table);
+        }
+
+        println!("HPET mapped");
+
+        let counter_clk_period_fs = self.get_counter_clock_period();
+        let desired_fs_period: u64 = 2250286 * 1000000;
+
+        let clk_periods_per_kernel_tick: u64 = desired_fs_period / counter_clk_period_fs;
+
+        let enable_word: u64 = volatile_load(self.general_config_addr as *const u64)
+            | LEG_RT_CNF | ENABLE_CNF;
+
+        volatile_store(self.general_config_addr as *mut u64, enable_word);
+        // Enable interrupts from the HPET
+
+        let t0_config_word: u64 = TN_VAL_SET_CNF | TN_TYPE_CNF | TN_INT_ENB_CNF;
+        volatile_store(self.t0_config_capability_addr as *mut u64, t0_config_word);
+
+        volatile_store(self.t0_comparator_addr as *mut u64, clk_periods_per_kernel_tick);
+    }
+
+    pub fn get_counter_clock_period(&self) -> u64 {
+        unsafe { volatile_load(self.capability_addr as *const u64) >> 32 }
+    }
+    
+    pub fn get_main_counter(&self) -> u64 {
+        unsafe { volatile_load(self.main_counter_addr as *const u64) }
+    }
+}
diff --git a/src/device/mod.rs b/src/device/mod.rs
index ef27ccb240586d4e76b7d8200d9128dfa29a8ab1..5825ff55d68aef857353addbc7610c6e1b4e3e38 100644
--- a/src/device/mod.rs
+++ b/src/device/mod.rs
@@ -1,17 +1,35 @@
 use paging::ActivePageTable;
+use acpi::ACPI_TABLE;
+use syscall::io::{Pio, Io};
 
 pub mod cpu;
 pub mod local_apic;
 pub mod pic;
 pub mod rtc;
 pub mod serial;
+pub mod hpet;
 
 pub unsafe fn init(active_table: &mut ActivePageTable){
     pic::init();
     local_apic::init(active_table);
 }
 
-pub unsafe fn init_noncore() {
+pub unsafe fn init_noncore(active_table: &mut ActivePageTable) {
+    {
+        if let Some(ref hpet) = ACPI_TABLE.lock().hpet {
+            // Disable the PIT
+            // TODO: Move PIT driver to kernel, and just don't enable it in the first place if we have an HPET
+            let mut pit_cmd = Pio::<u8>::new(0x43);
+            let mut pit_c0 = Pio::<u8>::new(0x40);
+
+            pit_cmd.write(0x30);
+            pit_c0.write(0);
+            pit_c0.write(0);
+
+            hpet::init(hpet, active_table);
+        }
+    }
+    
     rtc::init();
     serial::init();
 }
diff --git a/src/start.rs b/src/start.rs
index faac4b42540e64aeab158027fd0c943d9a302e07..c7a6dd435cea68f07d78e33554bf0f7333df801a 100644
--- a/src/start.rs
+++ b/src/start.rs
@@ -107,7 +107,7 @@ pub unsafe extern fn kstart(kernel_base: usize, kernel_size: usize, stack_base:
         acpi::init(&mut active_table);
 
         // Initialize all of the non-core devices not otherwise needed to complete initialization
-        device::init_noncore();
+        device::init_noncore(&mut active_table);
 
         // Initialize memory functions after core has loaded
         memory::init_noncore();