blob: 3a1e18383c8fbda50b2b6c9d221f8b07ba4391f2 [file] [log] [blame]
#include <dri/ata_pio/ata_pio.h>
#include <dri/fs/ext2/ext2.h>
#include <kint.h>
#include <log.h>
#include <io.h>
inline uint ext2_block_size(struct ext2_superblock *sb)
{
return 1024 << sb->block_size_shift;
}
void ext2_read_block(struct ext2_superblock *sb, void *buffer, uint block)
{
uint block_size = ext2_block_size(sb) / 512;
uint block_start = block_size * block;
ata_pio_read_sectors(buffer, block_start, block_size);
}
struct ext2_superblock ext2_read_superblock()
{
uchar buffer[512 * 2];
ata_pio_read_sectors(buffer, 2, 2);
struct ext2_superblock *sb = (void *)(buffer);
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");
}
}
struct ext2_block_group_descriptor ext2_load_block_group_descriptor(
struct ext2_superblock *sb, uint block_group)
{
/**
* 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;
const uint bgd_size = sizeof(struct ext2_block_group_descriptor);
// Disk page that the BGD is on relative to the initial FILE SYSTEM block
uint hd_page = block_group / (512 / bgd_size);
// The offset from the beginning of that page the BGD is at
uint bgd_offset = block_group % (512 / bgd_size);
struct ext2_block_group_descriptor descriptors[512 / bgd_size];
kassert(sizeof(descriptors) == 512, "Wrong BGD size");
uint lba = (block_size / 512) * bgdt_block + hd_page;
ata_pio_read_sectors(&descriptors, lba, 1);
return descriptors[bgd_offset];
}
static void print_entry(uint inode, const char *name, void *data)
{
kprintf("%d\t %s\n", inode, name);
}
void ext2_mount(struct fs_node *where)
{
struct ext2_superblock sb = ext2_read_superblock();
kprintf(DEBUG "EXT2 magic = 0x%x\n", sb.signature);
// Read the root inode 2
struct ext2_inode root;
if (ext2_find_inode(&sb, 2, &root))
{
kprintf(OKAY "Found root inode 2 (size=0x%x, num_blocks=0x%x)\n", root.size, root.num_blocks);
// kprintf(DEBUG "Root.mode = 0x%x\n", root.mode & 0xf000);
kassert((root.mode & 0xf000) == EXT2_S_IFDIR, "Root (inode 2) is not a directory.");
kprintf("ls /\n");
kprintf("inode\t name\n");
kprintf("--------------------\n");
ext2_dir_ls(&sb, &root, print_entry, NULL);
}
else
{
kprintf(WARN "Failed to find root inode 2\n");
}
}
bool ext2_valid_filesystem()
{
struct ext2_superblock sb = ext2_read_superblock();
kprintf(DEBUG "superblock signature is %d (0x%x)\n", sb.signature, sb.signature);
return sb.signature == EXT2_SIGNATURE;
}
void ext2_write_superblock(struct ext2_superblock *sb)
{
ushort *wp = (ushort *)sb;
ata_pio_write_sectors(2, 2, wp);
}
void ext2_corrupt_superblock_for_fun()
{
struct ext2_superblock sb = ext2_read_superblock();
sb.signature = 0xDEAD;
ext2_write_superblock(&sb);
}
bool ext2_find_inode(struct ext2_superblock *sb, uint number, struct ext2_inode *inode)
{
if (number == 0)
return false;
uint block_group = (number - 1) / sb->inodes_per_block_group;
uint local_index = (number - 1) % sb->inodes_per_block_group;
// Load this from the block group descriptor table
struct ext2_block_group_descriptor descriptor =
ext2_load_block_group_descriptor(sb, block_group);
kprintf(DEBUG "Descriptor inode_table = 0x%x\n", descriptor.inode_table_start_block);
// We need to figure out what FS block the inode is on, we know how many
// inodes there are total in this BGD and the number per page, so this is
// simple.
const uint block_size = ext2_block_size(sb);
const uint inodes_per_block = block_size / sizeof(struct ext2_inode);
uint inode_block = local_index / inodes_per_block;
uint inode_index = local_index % inodes_per_block;
struct ext2_inode inodes[block_size / sizeof(struct ext2_inode)];
ext2_read_block(sb, inodes, descriptor.inode_table_start_block +
inode_block);
*inode = inodes[inode_index];
return true;
}
bool ext2_dir_ls(struct ext2_superblock *sb,
struct ext2_inode *dir,
void (*cb)(uint inode,
const char *name,
void *data),
void *data)
{
if ((dir->mode & 0xf000) != EXT2_S_IFDIR)
return false;
for (int i = 0; i < dir->num_blocks; i++)
{
uchar buffer[ext2_block_size(sb)];
ext2_read_inode_block(sb, dir, buffer, i);
struct ext2_dirent *ent = (void *)buffer;
// While there are files in this block
while (ent < buffer + ext2_block_size(sb))
{
if (ent->inode == 0)
return true;
if (cb)
{
char name[257];
memcpy(name, ent->name, ent->name_len);
name[ent->name_len] = '\0';
cb(ent->inode, name, data);
}
ent = (void *)(((uint)(void *)ent) + ent->rec_len);
}
// We ran out of files in this block, continue to the next one. This
// works because files cannot span blocks
}
return true;
}
bool ext2_read_inode_block(struct ext2_superblock *sb,
struct ext2_inode *inode,
void *buffer,
uint block)
{
if (block >= 12)
{
kprintf(ERROR "Sorry, EXT2 can only access the first 12 (direct) blocks "
"of an inode for now. Indirect look-up will be added later\n");
kpanic("Invalid inode block");
}
uint block_address = inode->blocks[block];
ext2_read_block(sb, buffer, block_address);
}