Add ATA PIO IRQ handler, documentation

Still WIP, doesn't look like IRQ handler works yet.
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);
 }