Add ATA PIO IRQ handler, documentation

Still WIP, doesn't look like IRQ handler works yet.
diff --git a/src/kernel/Jmk b/src/kernel/Jmk
index 8beb214..2e842a1 100644
--- a/src/kernel/Jmk
+++ b/src/kernel/Jmk
@@ -53,9 +53,9 @@
 			task_api.o \
 			faults.o \
 			lib(ext2) \
+			lib(ide) \
 			lib(ata_pio) \
-			lib(pci) \
-			lib(ide)
+			lib(pci)
 
 type(custom_link)
 
diff --git a/src/kernel/dri/ata_pio/ata_pio.c b/src/kernel/dri/ata_pio/ata_pio.c
index cf55b51..cd426ef 100644
--- a/src/kernel/dri/ata_pio/ata_pio.c
+++ b/src/kernel/dri/ata_pio/ata_pio.c
@@ -2,6 +2,7 @@
 
 #include <io.h>
 #include <log.h>
+#include <pic.h>
 
 /* TODO: Rewrite all of this to work with dri_ide in the case of multiple
  * devices */
@@ -51,7 +52,7 @@
 	ata_pio_wait_bsy();
 }
 
-void ata_pio_write_sectors(uint lba, uchar num_sectors, void *buffer)
+void ata_pio_write_sectors(uint lba, uchar num_sectors, ushort *buffer)
 {
 	ata_pio_wait_bsy();
 
@@ -60,8 +61,10 @@
 
 	ata_pio_wait_bsy();
 
-	asm volatile("rep outsw" :: "c"(num_sectors * 256), "d"(ATA_PORT_DATA),
-				 "S"(buffer));
+	for (int i = 0; i < (num_sectors * 256); i++)
+	{
+		outw(ATA_PORT_DATA, buffer[i]);
+	}
 }
 
 static void print_buffer()
@@ -89,3 +92,53 @@
 	// ata_pio_read_sectors(test_buffer, 0, 1);
 	// print_buffer();
 }
+
+void ata_pio_handle_irq(struct registers *regs)
+{
+	// TODO: check that this IRQ came from the hard drive
+	
+	// TODO: use a lock and inform the scheduler that the thread waiting for
+	// this can stop sleeping
+	
+	// Acknowledge the IRQ
+	uchar status = inw(ATA_PORT_STATUS);
+
+	kprintf(DEBUG "ATA PIO IRQ received %d (0x%x)\n", status, status);
+}
+
+void init_ata_pio()
+{
+	add_interrupt_handler(46, ata_pio_handle_irq);
+
+/*
+	// TODO: Consider adding this back.
+
+	// 0xA0 for master, 0xB0 for slave
+	outb(ATA_PORT_DRIVE_SEL, 0xA0);
+
+	outb(ATA_PORT_LBA_LOW, 0);
+	outb(ATA_PORT_LBA_MID, 0);
+	outb(ATA_PORT_LBA_HIGH, 0);
+
+	outb(ATA_PORT_CMD, ATA_CMD_IDENTIFY);
+
+	if (inb(ATA_PORT_STATUS))
+	{
+		kprintf(OKAY "ATA drive exists\n");
+
+		// Wait until either DRQ or ERR is set
+		uchar status;
+		while ((status = inb(ATA_PORT_STATUS)) & (ATA_DRQ | ATA_ERR))
+		{
+			if (status & ATA_ERR)
+			{
+
+			}
+		}
+	}
+	else
+	{
+		kprintf(ERROR "ATA drive does not exist\n");
+	}
+*/
+}
diff --git a/src/kernel/dri/fs/ext2/ext2.c b/src/kernel/dri/fs/ext2/ext2.c
index d0dd3bd..3d7b1bc 100644
--- a/src/kernel/dri/fs/ext2/ext2.c
+++ b/src/kernel/dri/fs/ext2/ext2.c
@@ -1,5 +1,5 @@
-#include <dri/fs/ext2/ext2.h>
 #include <dri/ata_pio/ata_pio.h>
+#include <dri/fs/ext2/ext2.h>
 #include <kint.h>
 #include <log.h>
 
@@ -12,11 +12,56 @@
 	return *sb;
 }
 
+uint ext2_num_block_groups(struct ext2_superblock *sb)
+{
+	// This is a mildly janky way of rounding up
+	uint a = (sb->total_blocks - 1) / (sb->blocks_per_block_group + 1);
+	uint b = (sb->total_inodes - 1) / (sb->inodes_per_block_group + 1);
+
+	if (a == b)
+	{
+		return a;
+	}
+	else
+	{
+		kprintf(ERROR "EXT2 cannot find number of block groups, %d and %d "
+					  "should equal.\n",
+				a, b);
+		kpanic("Corrupted filesystem");
+	}
+}
+
+uint ext2_block_size(struct ext2_superblock *sb)
+{
+	return 1024 << sb->block_size_shift;
+}
+
+void ext2_load_block_group_descriptor_table(struct ext2_superblock *sb,
+											uint num_block_groups)
+{
+	/**
+	 * The BGDT (not to be confused with the GDT) is located the block after the
+	 * superblock. On any block size EXCEPT 1024 (the minimum, remember that the
+	 * block size is specified by X where 1024 << X is the real size) this is
+	 * the second block (0-indexed, so 1). On 1024 this is the third block.
+	 */
+	uint bgdt_block = 1;
+	uint block_size = ext2_block_size(sb);
+
+	if (block_size == 1024)
+		bgdt_block = 2;
+
+	kprintf(DEBUG "BGDT block = %d block size = %d\n", bgdt_block, block_size);
+}
+
 void ext2_mount(struct fs_node *where)
 {
 	struct ext2_superblock sb = ext2_read_superblock();
 
-	kprintf(INFO "EXT2 magic = 0x%x\n", sb.signature);
+	kprintf(DEBUG "EXT2 magic = 0x%x\n", sb.signature);
+
+	uint num_block_groups = ext2_num_block_groups(&sb);
+	ext2_load_block_group_descriptor_table(&sb, num_block_groups);
 }
 
 bool ext2_valid_filesystem()
@@ -24,4 +69,4 @@
 	struct ext2_superblock sb = ext2_read_superblock();
 
 	return sb.signature == EXT2_SIGNATURE;
-}
\ No newline at end of file
+}
diff --git a/src/kernel/dri/ide/ide.c b/src/kernel/dri/ide/ide.c
index 0025970..de4144c 100644
--- a/src/kernel/dri/ide/ide.c
+++ b/src/kernel/dri/ide/ide.c
@@ -1,59 +1,65 @@
-#include <dri/ide/ide.h>
-#include <task.h>
 #include <alloc.h>
+#include <dri/ata_pio/ata_pio.h>
+#include <dri/ide/ide.h>
 #include <log.h>
+#include <task.h>
 
 struct ide_thread_data
 {
-    struct pci_device dev;
-    uchar bus, slot, func;
+	struct pci_device dev;
+	uchar bus, slot, func;
 };
 
 bool ide_supports(struct pci_device *dev)
 {
-    return dev->class == 1 && dev->subclass == 1;
+	return dev->class == 1 && dev->subclass == 1;
 }
 
 void ide_print_device(struct ide_device *dev)
 {
-    kprintf(INFO "<ide-device dma=%b>", dev->supports_dma);
+	kprintf(INFO "<ide-device dma=%b>\n", dev->supports_dma);
 }
 
 void ide_thread(struct ide_thread_data *data)
 {
-    kprintf(DEBUG "IDE driver thread starting: device=0x%x\n", data->dev.device_id);
+	struct ide_device dev;
 
-    struct ide_device dev;
+	uchar p = data->dev.prog_if;
+	dev.channel_mode[0] = p & 1;
+	dev.channel_mode_modifiable[0] = p & (1 << 1);
+	dev.channel_mode[1] = p & (1 << 2);
+	dev.channel_mode_modifiable[1] = p & (1 << 3);
+	dev.supports_dma = p & (1 << 7);
 
-    uchar p = data->dev.prog_if;
-    dev.channel_mode[0] = p & 1;
-    dev.channel_mode_modifiable[0] = p & (1 << 1);
-    dev.channel_mode[1] = p & (1 << 2);
-    dev.channel_mode_modifiable[1] = p & (1 << 3);
-    dev.supports_dma = p & (1 << 7);
+	ide_print_device(&dev);
 
-    ide_print_device(&dev);
+	// TODO: pass ATA PIO driver information about the IDE device (i.e. what
+	// ports to use)
+	init_ata_pio();
+
+	kprintf(OKAY "Set up ATA PIO\n");
+
+	free(data);
 }
 
 void ide_init(struct pci_device dev, uchar bus, uchar slot, uchar func)
 {
-    struct ide_thread_data *data = malloc(sizeof(struct ide_thread_data));
-    data->dev = dev;
-    data->bus = bus;
-    data->slot = slot;
-    data->func = func;
+	struct ide_thread_data *data = malloc(sizeof(struct ide_thread_data));
+	data->dev = dev;
+	data->bus = bus;
+	data->slot = slot;
+	data->func = func;
 
-    spawn_thread(TASK_FUNCTION(ide_thread), data);
+	ide_thread(data);
 }
 
 void ide_register()
 {
-    struct pci_device_driver dri =
-    {
-        .supports = ide_supports,
-        .init = ide_init,
-        .generic_name = "IDE Controller",
-    };
+	struct pci_device_driver dri = {
+		.supports = ide_supports,
+		.init = ide_init,
+		.generic_name = "IDE Controller",
+	};
 
-    pci_register_device_driver(dri);
+	pci_register_device_driver(dri);
 }
diff --git a/src/kernel/io.c b/src/kernel/io.c
index c53ef17..0ba13ae 100644
--- a/src/kernel/io.c
+++ b/src/kernel/io.c
@@ -26,22 +26,32 @@
 ushort inw(ushort port)
 {
 	ushort ret;
-	asm volatile("inw %1, %0" : "=a"(ret) : "dN"(port));
+	asm("inw %1, %0" : "=a"(ret) : "dN"(port));
 	return ret;
 }
 
 void outl(ushort port, uint val)
 {
-	asm volatile("outl %1, %0" : : "dN"(port), "a"(val));
+	asm("outl %1, %0" : : "dN"(port), "a"(val));
 }
 
 uint inl(ushort port)
 {
 	uint ret;
-	asm volatile("inl %1, %0" : "=a"(ret) : "dN"(port));
+	asm("inl %1, %0" : "=a"(ret) : "dN"(port));
 	return ret;
 }
 
+void outw(ushort port, ushort val)
+{
+	asm("outw %1, %0" :: "dN"(port), "a"(val));
+}
+
+void __attribute__((noinline)) nop()
+{
+	asm("nop");
+}
+
 void *memset(void *s, int c, size_t n)
 {
 	for (size_t i = 0; i < n; i++)
diff --git a/src/kernel/kbd.h b/src/kernel/kbd.h
index 98d6fd7..805d4ab 100644
--- a/src/kernel/kbd.h
+++ b/src/kernel/kbd.h
@@ -2,15 +2,24 @@
 
 #include "kint.h"
 
+/**
+ * A scan code -> keyboard char mapping
+ */
 struct kbd_scan_codes
 {
 	bool ascii;
 	int symbol;
+	/**
+	 * Uppercase version of symbol
+	 */
 	int up_symbol;
 	uchar prefix;
 	bool brk;
 };
 
+/**
+ * Non-char keyboard keys, assigned values above 7-bit ascii range (>128)
+ */
 enum kbd_keys
 {
 	FIRST_KBD_KEY = 129,
diff --git a/src/kernel/main.c b/src/kernel/main.c
index 04dc9a7..098d37b 100644
--- a/src/kernel/main.c
+++ b/src/kernel/main.c
@@ -84,7 +84,7 @@
 
 	pci_load();
 
-	kprintf(OKAY "Loaded PCI devices\n");
+	kprintf(OKAY "Loaded PCI device drivers\n");
 
 #ifdef TEST_THREADS
 	spawn_thread(other_thread, NULL);
@@ -101,13 +101,13 @@
 	test_ata_pio();
 #endif
 
-#ifdef TEST_EXT2
 	if (ext2_valid_filesystem())
 	{
-		kprintf(INFO "Mounting EXT2 to /\n");
-		ext2_mount(&root);
+		kprintf(OKAY "EXT2 filesystem is valid, again = %b\n", ext2_valid_filesystem());
+
+		//kprintf(INFO "Mounting EXT2 to /\n");
+		//ext2_mount(&root);
 	}
-#endif
 
 	while (true)
 		asm("hlt");
diff --git a/src/kernel/pic.c b/src/kernel/pic.c
index 5d33213..e4ed88c 100644
--- a/src/kernel/pic.c
+++ b/src/kernel/pic.c
@@ -51,6 +51,7 @@
 
 void pic_remap()
 {
+	// I don't remember what this does.
 	outb(0x20, 0x11);
 	outb(0xA0, 0x11);
 	outb(0x21, 0x20);
diff --git a/src/kernel/pic.h b/src/kernel/pic.h
deleted file mode 100644
index de11f3f..0000000
--- a/src/kernel/pic.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#pragma once
-
-#include "kint.h"
-#include "registers.h"
-
-#define PIC1 0x20
-#define PIC2 0xa0
-#define PIC1_COMMAND PIC1
-#define PIC1_DATA (PIC1 + 1)
-#define PIC2_COMMAND PIC2
-#define PIC2_DATA (PIC2 + 1)
-
-#define PIC_EOI 0x20 // End of input
-
-#define IRQ_TO_INT(irq) ((irq) + 32)
-
-void pic_send_eoi(uchar interrupt);
-void add_interrupt_handler(uchar interrupt, void (*handler)(struct registers *));
-
-void pic_remap();