/*#define DEBUG*/
#include <sys/types.h>
#include <fs/ext2types.h>
#include <debug.h>
#define PATH_MAX 255
extern void pread_sector(uint32_t lba, uint8_t *dst);
typedef struct ext2_info_struct {
ext2_superblock *sb;
uint32_t first_block;
int block_size;
} ext2_info;
static void pio_read(uint32_t lba_start, uint32_t size, void *dst) {
uint32_t num_blocks = size >> 9;
for (uint32_t i = 0; i < num_blocks; i++) {
pread_sector(lba_start + i, dst + (i << 9));
}
}
static void fs_read_inode(ext2_info *fs, uint32_t inode, ext2_inode *dst);
static void fs_inode_read_block(ext2_info *fs, ext2_inode *inode, uint32_t block_index, void *dst);
static uint32_t fs_lookup(ext2_info *fs, ext2_inode *dir, const char *name);
static uint32_t fs_find(ext2_info *fs, const char *path);
static inline int strncmp(const char *a, const char *b, int len) {
const char *end = a + len - 1;
for(; a < end && *a == *b && *a; a++, b++) {
}
return (unsigned char)*a - (unsigned char)*b;
}
static inline void memcpy(void *dst, const void *src, uint32_t size) {
const uint8_t *end = src + size;
uint8_t *d = dst;
const uint8_t *s = src;
for(;s < end;s++) {
*d++ = *s;
}
}
void boot2_main(void) {
kprint("\n\n\n=================\n");
int part_begin = 10;
uint8_t sb_buf[1024];
ext2_superblock *sb = (void *)&sb_buf;
pread_sector(part_begin + 2, (void *)sb);
pread_sector(part_begin + 3, ((void *)sb)+512);
ext2_info fs;
fs.first_block = 10;
fs.sb = sb;
fs.block_size = 1024 << sb->s_log_block_size;
khexprint("magic", sb->s_blocks_count);
khexprint("block_size", fs.block_size);
khexprint("s_inodes_per_group", sb->s_inodes_per_group);
if (sb->s_inode_size == 0) {
sb->s_inode_size = 128;
}
khexprint("s_inode_size", sb->s_inode_size);
khexprint("blockdescsize", sizeof(ext2_block_group_desc));
uint32_t ikernel = fs_find(&fs, "/boot/kernel");
khexprint("lookup", ikernel);
ext2_inode ino_kernel;
fs_read_inode(&fs, ikernel, &ino_kernel);
uint32_t blocks = (ino_kernel.i_size + fs.block_size - 1) / fs.block_size;
void *dst = (void *)0x100000;
for(uint32_t i = 0; i < blocks; i++) {
fs_inode_read_block(&fs, &ino_kernel, i, dst);
dst += fs.block_size;
}
asm volatile ("ljmp $0x08,$0x100000" : : );
}
static void
fs_read_block(ext2_info *fs, uint32_t block_address, void *dst) {
pio_read(fs->first_block + (fs->block_size >> 9) * block_address, fs->block_size, dst);
}
static void
fs_inode_read_block_direct(ext2_info *fs, ext2_inode *inode, uint32_t block_index, void *dst) {
uint32_t block_address = inode->i_block[block_index];
fs_read_block(fs, block_address, dst);
}
static void
fs_inode_read_block_indirect(ext2_info *fs, ext2_inode *inode, uint32_t block_index, void *dst) {
uint8_t buf[EXT2_MAX_BLOCK_SIZE];
uint32_t block_address = inode->i_block[12];
fs_read_block(fs, block_address, buf);
uint32_t indirect_block_index = block_index - 12;
uint32_t real_block_address = ((uint32_t *)buf)[indirect_block_index];
fs_read_block(fs, real_block_address, dst);
}
static void
fs_inode_read_block(ext2_info *fs, ext2_inode *inode, uint32_t block_index, void *dst) {
if (block_index > 10) {
khexprint("ERROR maybe indirect block?", block_index);
while(1) {};
}
fs_inode_read_block_direct(fs, inode, block_index, dst);
}
static uint32_t
fs_inode_table_address(ext2_info *fs, uint32_t block_group) {
uint32_t bg_desc_block = fs->sb->s_first_data_block + 1;
uint8_t buf[8192];
fs_read_block(fs, bg_desc_block, buf);
ext2_block_group_desc *bg_desc = (void *)buf;
//khexprint("inode table block", bg_desc[block_group].bg_inode_table);
return bg_desc[block_group].bg_inode_table;
}
void fs_read_inode(ext2_info *fs, uint32_t inode, ext2_inode *dst) {
uint32_t block_group = (inode - 1) / fs->sb->s_inodes_per_group;
int inode_index = (inode - 1) % fs->sb->s_inodes_per_group;
int inodes_per_block = fs->block_size / fs->sb->s_inode_size;
uint32_t inode_table_start = fs_inode_table_address(fs, block_group);
uint32_t inode_table_offset = inode_index / inodes_per_block;
uint32_t index_in_table = inode_index % inodes_per_block;
khexprint("read inode", inode);
khexprint("inode table start", inode_table_start);
khexprint("inode table offset", inode_table_offset);
khexprint("inode table index", index_in_table);
uint32_t read_block_index = inode_table_start + inode_table_offset;
khexprint("read block", read_block_index);
uint8_t buf[8192];
fs_read_block(fs, read_block_index, (void *)buf);
uint8_t *inode_start = buf + (fs->sb->s_inode_size * index_in_table);
memcpy(dst, inode_start, sizeof(ext2_inode));
/*for(unsigned int i=0;i<(sizeof(ext2_inode)); i++) {*/
/*[>khexprint("copy inode data", ((uint32_t)i) << 24 | inode_start[i]);<]*/
/**((uint8_t *)(dst + i)) = inode_start[i];*/
/*}*/
}
static inline uint32_t inode_block_count(ext2_info *fs, ext2_inode *inode) {
return inode->i_blocks / (2 << fs->sb->s_log_block_size);
}
static uint32_t fs_lookup(ext2_info *fs, ext2_inode *dir, const char *name) {
uint8_t buf[8192];
void *bufend = buf + 8192;
for (uint32_t i = 0; i < inode_block_count(fs, dir); i++) {
khexprint("lookup in block", i);
fs_inode_read_block(fs, dir, i, buf);
void *p = (void *)buf;
while(p < bufend) {
uint32_t entry_inode = *(uint32_t *)p;
uint16_t rec_len = *(uint16_t *)(p + 4);
uint16_t name_len = *(uint16_t *)(p + 6);
char *entry_name = (char *)(p + 8);
if (entry_inode) {
if (strncmp(name, entry_name, name_len) == 0) {
return entry_inode;
}
} else {
kprint("skip empty entry\n");
}
if (rec_len == 0) {
kprint("rec_len is 0\n");
while (1){};
}
p += rec_len;
}
}
kprint("lookup failed\n");
return 0;
}
static uint32_t fs_find(ext2_info *fs, const char *name) {
char buf_path[PATH_MAX];
ext2_inode ino;
uint32_t next_inode_num = EXT2_ROOT_INO;
const char *cstart = name + 1;
const char *cend = cstart;
while (*cend) {
cend = cstart;
while (*cend && *cend != '/') { cend++; };
memcpy(buf_path, cstart, (cend - cstart));
buf_path[cend - cstart] = 0;
cstart = cend + 1;
kprint("component: ");
kprint(buf_path);
kprint("\n");
fs_read_inode(fs, next_inode_num, &ino);
next_inode_num = fs_lookup(fs, &ino, buf_path);
}
return next_inode_num;
}