EXT2 Problems
Posted: Sun Nov 20, 2016 8:04 am
Hello osdev forum
It's my os, Agola. I've done the simple ata support recently and I started to implementing ext2 filesystem.
Everything looks good until inode table, after it everything gets too complicated for me. I can't understand fully the relation of inodes - files - directories. I can read the entries of root directory inodes, but don't know how to go far.
Is there a detailed but easier to read (feeling like a dumb ) documentation for ext2?
Also I think there is some problems in my code, for example there is strange characters at end of the /boot directory:
I can't understand some things on these datas, too. Why the block of inode table is really too far from starting block? And why the inode of "." , ".." and "boot" is same?
Is inodes per block group = 2016 normal? (Because of 8192/128 = 64)
And what is the characters after the "boot"?
How can I read the text.txt for example?
This is my ext2 code: (Currently on kernel main, will transfer to ext2.c after fully learning ext2...) I ported newlib to Agola, and using a i686-agola target gcc.
And this is my ata read / write code:
Thanks for helping
Also note: I tested ata driver many times, I think there is no problem on it.
It's my os, Agola. I've done the simple ata support recently and I started to implementing ext2 filesystem.
Everything looks good until inode table, after it everything gets too complicated for me. I can't understand fully the relation of inodes - files - directories. I can read the entries of root directory inodes, but don't know how to go far.
Is there a detailed but easier to read (feeling like a dumb ) documentation for ext2?
Also I think there is some problems in my code, for example there is strange characters at end of the /boot directory:
I can't understand some things on these datas, too. Why the block of inode table is really too far from starting block? And why the inode of "." , ".." and "boot" is same?
Is inodes per block group = 2016 normal? (Because of 8192/128 = 64)
And what is the characters after the "boot"?
How can I read the text.txt for example?
This is my ext2 code: (Currently on kernel main, will transfer to ext2.c after fully learning ext2...) I ported newlib to Agola, and using a i686-agola target gcc.
Code: Select all
#include <stdio.h>
#include <malloc.h>
#include <stdbool.h>
#include <kernel/tty.h>
#include <kernel/gdt.h>
#include <kernel/idt.h>
#include <kernel/isr.h>
#include <kernel/irq.h>
#include <kernel/atapio.h>
unsigned char superblock[1024];
unsigned char block_group_descriptor[512];
typedef struct superblock
{
uint32_t number_of_inodes;
uint32_t number_of_blocks;
uint32_t blocks_reserved_superuser;
uint32_t unallocated_blocks;
uint32_t unallocated_inodes;
uint32_t block_number_of_superblock;
uint32_t block_size;
uint32_t fragment_size;
uint32_t number_of_blocks_in_block_group;
uint32_t number_of_fragments_in_block_group;
uint32_t number_of_inodes_in_block_group;
uint32_t last_mount_time;
uint32_t last_write_time;
uint16_t volume_mount_count_after_last_check;
uint16_t max_mount_count_before_last_check;
uint16_t ext2_signature;
uint16_t filesystem_state;
uint16_t error_handling_methods;
uint16_t minor_version;
uint32_t last_check_time;
uint32_t interval_forced_check;
uint32_t os_id;
uint32_t major_version;
uint16_t user_id;
uint16_t group_id;
} superblock_t;
typedef struct block_group_descriptor
{
uint32_t block_of_block_usage_bitmap;
uint32_t block_of_inode_usage_bitmap;
uint32_t block_of_inode_table;
uint16_t number_unallocated_blocks;
uint16_t number_unallocated_inodes;
uint16_t number_directories;
} block_group_descriptor_t;
typedef struct inode
{
uint16_t type_and_permissions;
uint16_t user_id;
uint32_t size;
uint32_t last_access_time;
uint32_t creation_time;
uint32_t last_modification_time;
uint32_t deletion_time;
uint16_t group_id;
uint16_t count_hard_links;
uint32_t count_disk_sectors;
uint32_t flags;
uint32_t os_specific_value_1;
uint32_t dbp[12];
uint32_t singly_indirect_block_pointer;
uint32_t doubly_indirect_block_pointer;
uint32_t triply_indirect_block_pointer;
uint32_t generation_number;
uint32_t reserved_1;
uint32_t reserved_2;
uint32_t block_address_of_fragments;
uint8_t os_specific_value_2[12];
} inode_t;
typedef struct directory
{
uint32_t inode;
uint16_t size;
uint8_t name_length;
uint8_t type_indicator;
char name[];
} __attribute__ ((packed)) directory_t;
#define FS_CLEAN 1
#define FS_HAS_ERRORS 2
#define FS_IGNORE_ERROR
#define FS_REMOUNT_READONLY
#define FS_KERNEL_PANIC
#define FS_FIFO 0x1000
#define FS_CHARACTER_DEVICE 0x2000
#define FS_DIRECTORY 0x4000
#define FS_BLOCK_DEVICE 0x6000
#define FS_REGULAR_FILE 0x8000
#define FS_SYMBOLIC_LINK 0xA000
#define FS_UNIX_SOCKET 0xC000
#define LINUX 0
#define GNU_HURD 1
#define MASIX 2
#define FREEBSD 3
#define OTHER 4
const unsigned int EXT2_START = 1048576;
void kernel_main(void) {
gdt_install();
idt_install();
isr_install();
irq_install();
asm volatile ("sti");
terminal_initialize(TERMINAL_COLOR_LIGHT_GREY, TERMINAL_COLOR_BLACK);
setbuf(stdout, NULL);
printf("Reading superblock and block group descriptor...\n\n");
superblock_t superblock;
block_group_descriptor_t block_group_descriptor;
atapio_read(EXT2_START + 1024, sizeof(superblock_t), &superblock);
atapio_read(EXT2_START + 2048, sizeof(block_group_descriptor_t), &block_group_descriptor);
printf("Superblock:\nEXT2 signature: %X, Filesystem state: %s, Inodes per block group: %d\n\n", superblock.ext2_signature, (superblock.filesystem_state == 1) ? "Clean" : "Has errors", superblock.number_of_inodes_in_block_group);
printf("Block group descriptor:\nBlock of inode table: %d\n\n", block_group_descriptor.block_of_inode_table);
printf("Reading root from inode table:\n\n");
inode_t *inode_table = (inode_t*) malloc(128 * superblock.number_of_inodes_in_block_group);
atapio_read(EXT2_START + (block_group_descriptor.block_of_inode_table) * 1024, sizeof(inode_t) * superblock.number_of_inodes_in_block_group, inode_table);
printf("Getting directories of root\n\n");
uint8_t *block = (uint8_t*) malloc(1024);
atapio_read(EXT2_START + (inode_table[1].dbp[0] * 1024), 1024, block);
unsigned int offset = 0;
unsigned int times = 0;
directory_t* directory;
while(offset < 1024)
{
directory = (directory_t*)((uintptr_t)block + offset);
offset += directory->size;
printf("%s %s Inode:%d\n", directory->name, directory->type_indicator == 2 ? "<DIR>" : "<FILE>", directory->size);
}
}
Code: Select all
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <kernel/io.h>
#define ATAPIO_REG_DATA 0x1F0
#define ATAPIO_REG_ERROR 0x1F1
#define ATAPIO_SECT_COUNT 0x1F2
#define ATAPIO_LBA_LOW 0x1F3
#define ATAPIO_LBA_MID 0x1F4
#define ATAPIO_LBA_HIGH 0x1F5
#define ATAPIO_DRIVE_HEAD 0x1F6
#define ATAPIO_COMMAND_STATUS 0x1F7
typedef struct
{
unsigned int err : 1;
unsigned int idx : 1;
unsigned int corr : 1;
unsigned int drq : 1;
unsigned int srv : 1;
unsigned int df : 1;
unsigned int rdy : 1;
unsigned int bsy : 1;
} atapio_status_t;
unsigned long round_up_to_multiple_of_n(unsigned long value, unsigned long n)
{
return ((value + (n - 1)) / n) * n;
}
unsigned long round_down_to_multiple_of_n(unsigned long value, unsigned long n)
{
return value - (value % n);
}
atapio_status_t atapio_read_status()
{
atapio_status_t atapio_status;
memcpy(&atapio_status, inb(ATAPIO_COMMAND_STATUS), sizeof(atapio_status_t));
return atapio_status;
}
void atapio_wait_ready()
{
while(atapio_read_status().bsy);
}
void atapio_wait_drq()
{
while(!(atapio_read_status().drq));
}
void atapio_400ns_delay()
{
for (int x = 0; x < 4; x++) inb(ATAPIO_COMMAND_STATUS);
}
void atapio_read_lba48(uint64_t lba, uint16_t count, uint8_t *buffer)
{
unsigned int i = 0;
outb(ATAPIO_DRIVE_HEAD, 0x40);
outb(ATAPIO_SECT_COUNT, (unsigned char)((count >> 8) & 0xFF));
outb(ATAPIO_LBA_LOW, (unsigned char)((lba >> 24) & 0xFF));
outb(ATAPIO_LBA_MID, (unsigned char)((lba >> 32) & 0xFF));
outb(ATAPIO_LBA_HIGH, (unsigned char)((lba >> 40) & 0xFF));
outb(ATAPIO_SECT_COUNT, (unsigned char)(count & 0xFF));
outb(ATAPIO_LBA_LOW, (unsigned char)(lba & 0xFF));
outb(ATAPIO_LBA_MID, (unsigned char)((lba >> 8) & 0xFF));
outb(ATAPIO_LBA_HIGH, (unsigned char)((lba >> 16) & 0xFF));
atapio_wait_ready();
outb(ATAPIO_COMMAND_STATUS, 0x24);
while (count--)
{
atapio_wait_drq();
insw (ATAPIO_REG_DATA, buffer, 256);
atapio_wait_ready();
atapio_400ns_delay();
buffer += 512;
}
}
void atapio_write_lba48(uint64_t lba, uint16_t count, uint8_t *buffer)
{
unsigned int i = 0;
outb(ATAPIO_DRIVE_HEAD, 0x40);
outb(ATAPIO_SECT_COUNT, (unsigned char)((count >> 8) & 0xFF));
outb(ATAPIO_LBA_LOW, (unsigned char)((lba >> 24) & 0xFF));
outb(ATAPIO_LBA_MID, (unsigned char)((lba >> 32) & 0xFF));
outb(ATAPIO_LBA_HIGH, (unsigned char)((lba >> 40) & 0xFF));
outb(ATAPIO_SECT_COUNT, (unsigned char)(count & 0xFF));
outb(ATAPIO_LBA_LOW, (unsigned char)(lba & 0xFF));
outb(ATAPIO_LBA_MID, (unsigned char)((lba >> 8) & 0xFF));
outb(ATAPIO_LBA_HIGH, (unsigned char)((lba >> 16) & 0xFF));
atapio_wait_ready();
outb(ATAPIO_COMMAND_STATUS, 0x34);
while (count--)
{
atapio_wait_drq();
while (i < 256)
{
uint16_t to_write = (buffer[i * 2 + 1] << 8) | buffer[i * 2];
outw(ATAPIO_REG_DATA, to_write);
i++;
};
atapio_wait_ready();
atapio_400ns_delay();
outb(ATAPIO_COMMAND_STATUS, 0xE7);
}
}
void atapio_read(uint64_t from, uint64_t bytes, uint8_t *buffer)
{
unsigned long needed_blocks = 0;
unsigned long needed_bytes = 0;
unsigned long lba = 0;
if (bytes == 0) return;
if (from > 512) lba = round_down_to_multiple_of_n(from, 512) / 512;
else lba = 0;
bytes += (from - (512 * lba));
if (bytes > 512) needed_bytes = round_up_to_multiple_of_n(bytes, 512);
else needed_bytes = 512;
needed_blocks = needed_bytes / 512;
uint8_t *read_buffer = (uint8_t*) malloc(needed_bytes);
atapio_read_lba48(lba, needed_blocks, read_buffer);
memcpy(buffer, read_buffer + (from - (512 * lba)), bytes - (from - (512 * lba)));
free(read_buffer);
}
void atapio_write(uint64_t to, uint64_t bytes, uint8_t *buffer)
{
unsigned long needed_blocks = 0;
unsigned long needed_bytes = 0;
unsigned long lba = 0;
if (bytes == 0) return;
if (to > 512) lba = round_down_to_multiple_of_n(to, 512) / 512;
else lba = 0;
bytes += (to - (512 * lba));
if (bytes > 512) needed_bytes = round_up_to_multiple_of_n(bytes, 512);
else needed_bytes = 512;
needed_blocks = needed_bytes / 512;
uint8_t *write_buffer = (uint8_t*) malloc(needed_bytes);
atapio_read_lba48(lba, needed_blocks, write_buffer);
memcpy(write_buffer + (to - (512 * lba)), buffer, bytes - (to - (512 * lba)));
atapio_write_lba48(lba, needed_blocks, write_buffer);
free(write_buffer);
}
Also note: I tested ata driver many times, I think there is no problem on it.