Add ATA PIO IRQ handler, documentation
Still WIP, doesn't look like IRQ handler works yet.
diff --git a/doc/Makefile b/doc/Makefile
index 5afd552..6f05775 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -14,10 +14,15 @@
.PHONY: help Makefile
+watch:
+ sphinx-autobuild "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+dox: doxygen
+doxygen:
+ doxygen lisp.doxyfile
+ doxygen kernel.doxyfile
+
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
-
-watch:
- sphinx-autobuild "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
diff --git a/doc/architecture.rst b/doc/architecture.rst
index a515f34..b946a54 100644
--- a/doc/architecture.rst
+++ b/doc/architecture.rst
@@ -45,11 +45,8 @@
interface with a certain device (or class of devices). The relevant fields of
``struct pci_device_driver`` are shown here:
-.. code-block::
-
- bool (* supports)(struct pci_device *dev);
- void (* init)(struct pci_device dev, uchar bus, uchar slot, uchar func);
- char *generic_name;
+.. doxygenstruct:: pci_device_driver
+ :project: Kernel
A PCI device driver must pass an instance of this structure to
``pci_register_device_driver`` (in ``include/kernel/dri/pci/pci.h``. If
diff --git a/doc/kernel.doxyfile b/doc/kernel.doxyfile
index d75e0a8..5d5f1e1 100644
--- a/doc/kernel.doxyfile
+++ b/doc/kernel.doxyfile
@@ -467,7 +467,7 @@
# normally produced when WARNINGS is set to YES.
# The default value is: NO.
-EXTRACT_ALL = NO
+EXTRACT_ALL = YES
# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
# be included in the documentation.
@@ -862,7 +862,7 @@
# be searched for input files as well.
# The default value is: NO.
-RECURSIVE = NO
+RECURSIVE = YES
# The EXCLUDE tag can be used to specify files and/or directories that should be
# excluded from the INPUT source files. This way you can easily exclude a
diff --git a/doc/lisp.doxyfile b/doc/lisp.doxyfile
index fad1c79..8b843a2 100644
--- a/doc/lisp.doxyfile
+++ b/doc/lisp.doxyfile
@@ -467,7 +467,7 @@
# normally produced when WARNINGS is set to YES.
# The default value is: NO.
-EXTRACT_ALL = NO
+EXTRACT_ALL = YES
# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
# be included in the documentation.
@@ -862,7 +862,7 @@
# be searched for input files as well.
# The default value is: NO.
-RECURSIVE = NO
+RECURSIVE = YES
# The EXCLUDE tag can be used to specify files and/or directories that should be
# excluded from the INPUT source files. This way you can easily exclude a
diff --git a/include/kernel/dri/ata_pio/ata_pio.h b/include/kernel/dri/ata_pio/ata_pio.h
index c509f52..667ed3b 100644
--- a/include/kernel/dri/ata_pio/ata_pio.h
+++ b/include/kernel/dri/ata_pio/ata_pio.h
@@ -29,6 +29,7 @@
ATA_PORT_LBA_LOW,
ATA_PORT_LBA_MID,
ATA_PORT_LBA_HIGH,
+ ATA_PORT_STATUS = ATA_PORT_CMD,
};
// Commands
@@ -36,12 +37,15 @@
{
ATA_CMD_READ = 0x20,
ATA_CMD_WRITE = 0x30,
+ ATA_CMD_IDENTIFY = 0xec,
};
void ata_pio_wait_bsy();
void ata_pio_wait_drq();
void ata_pio_read_sectors(void *buffer, uint lba, uchar num_sectors);
-void ata_pio_write_sectors(uint lba, uchar num_sectors, void *buffer);
+void ata_pio_write_sectors(uint lba, uchar num_sectors, ushort *buffer);
uint ata_pio_get_error();
void test_ata_pio();
+
+void init_ata_pio();
\ No newline at end of file
diff --git a/include/kernel/io.h b/include/kernel/io.h
index 718bb20..be82998 100644
--- a/include/kernel/io.h
+++ b/include/kernel/io.h
@@ -3,34 +3,95 @@
#include "kint.h"
#include "registers.h"
+/**
+ * IO port for keyboard commands.
+ */
#define KBD_CMD_PORT 0x64
+
+/**
+ * IO port for keyboard data
+ */
#define KBD_DATA_PORT 0x60
-struct kbd_scan_code_info
-{
- bool pressed;
- bool escape;
- char key;
-};
-
-extern struct kbd_scan_code_info scan_code_table[0xff];
-
+/**
+ * Write a byte to a port
+ */
void outb(ushort port, uchar val);
+
+/**
+ * Write a double word to a port.
+ */
void outl(ushort port, uint val);
+
+/**
+ * Read a byte from a port.
+ */
uchar inb(ushort port);
+
+/**
+ * Read a word from a port.
+ */
ushort inw(ushort port);
+
+/**
+ * Write a word to a port.
+ */
+void outw(ushort port, ushort val);
+
+/**
+ * Just waste some time.
+ */
+void nop();
+
+/**
+ * Read a double word from a port
+ */
uint inl(ushort port);
-/* Random string.h stuff, TODO: move to own header */
+/**
+ * Set n bytes of s to c.
+ */
void *memset(void *s, int c, size_t n);
+
+/**
+ * Copy n bytes from src to dest.
+ */
void *memcpy(void *dest, const void *src, size_t n);
+
+/**
+ * Copy null terminated string src to dest.
+ */
void strcpy(char *dest, char *src);
+
+/**
+ * Compare two strings. This might not work like the libc function, so be
+ * careful.
+ * @returns 0 if equal, non-0 otherwise.
+ */
int strcmp(char *a, char *b);
+/**
+ * @returns the length of null-terminated string a.
+ */
uint strlen(char *a);
bool isdigit(char c);
+/**
+ * Ignores trailing non-digit characters.
+ * @returns 0 if string is not a valid decimal integer
+ */
uint parse_int(char *string);
+/**
+ * Read a scan code from the keyboard
+ */
uchar kbd_scan_code();
+
+/**
+ * Keyboard IRQ handler
+ */
void kbd_handle_input(struct registers *registers);
+
+/**
+ * Set up keyboard driver.
+ */
void init_kbd();
diff --git a/src/kernel/pic.h b/include/kernel/pic.h
similarity index 100%
rename from src/kernel/pic.h
rename to include/kernel/pic.h
diff --git a/include/kernel/registers.h b/include/kernel/registers.h
index 687bd0e..8abe32f 100644
--- a/include/kernel/registers.h
+++ b/include/kernel/registers.h
@@ -2,6 +2,9 @@
#include "kint.h"
+/**
+ * Represents the full execution state before an interrupt.
+ */
struct registers
{
uint ds;
diff --git a/include/kernel/task.h b/include/kernel/task.h
index 87b412b..b0d0f97 100644
--- a/include/kernel/task.h
+++ b/include/kernel/task.h
@@ -7,6 +7,9 @@
extern bool tasks_initialized;
+/**
+ * A process. For now there is only one, the kernel.
+ */
struct process
{
bool exists;
@@ -20,12 +23,15 @@
// NOTE: must be PAGE ALIGNED
uint last_stack_pos;
};
-
+/**
+ * The smallest schedulable unit, a thread of a process.
+ */
struct task
{
int id;
struct process *proc;
- uint stack_top_p; // stack frame PHYSICAL address
+ /// Physical address of the top of the stack.
+ uint stack_top_p;
uint esp, ebp, eip;
};
@@ -53,7 +59,23 @@
#define TASK_FUNCTION(f) ((task_function_t)(f))
void spawn_thread(task_function_t function, void *data);
+
+/**
+ * Halt the current thread.
+ */
void kill_this_thread();
+
+/**
+ * Force a task switch. Only call in a safe environment (ISR).
+ */
extern void switch_task();
+
+/**
+ * Switch to a specific task. Only call in a safe environment (ISR).
+ */
void switch_to_task(struct task *task);
+
+/**
+ * Internal. Do not call.
+ */
void _sys_init_tasks_h(struct registers *regs);
diff --git a/include/kernel/vfs.h b/include/kernel/vfs.h
index 1da0d6e..40a8e87 100644
--- a/include/kernel/vfs.h
+++ b/include/kernel/vfs.h
@@ -6,18 +6,27 @@
struct fs_node
{
- char name[128]; /* file name */
- uint inode; /* identifier */
- uint flags; /* type of node */
- uint mask; /* permissions */
- uint gid; /* group id */
- uint uid; /* user id */
- size_t size; /* size in bytes */
- uint dri_res; /* reserved for driver */
+ /** file name */
+ char name[128];
+ /** identifier */
+ uint inode;
+ /** type of node */
+ uint flags;
+ /** permissions */
+ uint mask;
+ /** group id */
+ uint gid;
+ /** user id */
+ uint uid;
+ /** size in bytes */
+ size_t size;
+ /** reserved for driver */
+ uint dri_res;
struct fs_vtable *vtable;
- struct fs_node *mount; /* used for mounts */
+ /** used for mounts */
+ struct fs_node *mount;
};
struct fs_dirent
@@ -26,13 +35,13 @@
uint inode;
};
-typedef uint (* fs_read_t)(struct fs_node *node, size_t offset, size_t size, uchar *buffer);
-typedef uint (* fs_write_t)(struct fs_node *node, size_t offset, size_t size, uchar *buffer);
-typedef void (* fs_open_t)(struct fs_node *node);
-typedef void (* fs_close_t)(struct fs_node *node);
+typedef uint (*fs_read_t)(struct fs_node *node, size_t offset, size_t size, uchar *buffer);
+typedef uint (*fs_write_t)(struct fs_node *node, size_t offset, size_t size, uchar *buffer);
+typedef void (*fs_open_t)(struct fs_node *node);
+typedef void (*fs_close_t)(struct fs_node *node);
-typedef bool (* fs_readdir_t)(struct fs_node *node, uint index, struct fs_dirent *dirent);
-typedef struct fs_node *(* fs_finddir_t)(struct fs_node *node, char *name);
+typedef bool (*fs_readdir_t)(struct fs_node *node, uint index, struct fs_dirent *dirent);
+typedef struct fs_node *(*fs_finddir_t)(struct fs_node *node, char *name);
struct fs_vtable
{
@@ -52,8 +61,8 @@
FS_BLOCKDEVICE,
FS_PIPE,
FS_SYMLINK,
-
- FS_MOUNT = 8, /* Can be or'd with others */
+
+ FS_MOUNT = 8, /* Can be or'd with others */
};
extern struct fs_node root, dev, initrd;
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);